Skip to content

Commit

Permalink
feat(pypi) Handle local version in requirement parsing
Browse files Browse the repository at this point in the history
  • Loading branch information
ewianda committed Nov 15, 2024
1 parent 155efce commit 3002d39
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 5 deletions.
4 changes: 2 additions & 2 deletions .bazelrc
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
# (Note, we cannot use `common --deleted_packages` because the bazel version command doesn't support it)
# To update these lines, execute
# `bazel run @rules_bazel_integration_test//tools:update_deleted_packages`
build --deleted_packages=examples/build_file_generation,examples/build_file_generation/random_number_generator,examples/bzlmod,examples/bzlmod_build_file_generation,examples/bzlmod_build_file_generation/other_module/other_module/pkg,examples/bzlmod_build_file_generation/runfiles,examples/bzlmod/entry_points,examples/bzlmod/entry_points/tests,examples/bzlmod/libs/my_lib,examples/bzlmod/other_module,examples/bzlmod/other_module/other_module/pkg,examples/bzlmod/patches,examples/bzlmod/py_proto_library,examples/bzlmod/py_proto_library/example.com/another_proto,examples/bzlmod/py_proto_library/example.com/proto,examples/bzlmod/runfiles,examples/bzlmod/tests,examples/bzlmod/tests/other_module,examples/bzlmod/whl_mods,examples/multi_python_versions/libs/my_lib,examples/multi_python_versions/requirements,examples/multi_python_versions/tests,examples/pip_parse,examples/pip_parse_vendored,examples/pip_repository_annotations,examples/py_proto_library,examples/py_proto_library/example.com/another_proto,examples/py_proto_library/example.com/proto,gazelle,gazelle/manifest,gazelle/manifest/generate,gazelle/manifest/hasher,gazelle/manifest/test,gazelle/modules_mapping,gazelle/python,gazelle/pythonconfig,gazelle/python/private,tests/integration/compile_pip_requirements,tests/integration/compile_pip_requirements_test_from_external_repo,tests/integration/custom_commands,tests/integration/ignore_root_user_error,tests/integration/ignore_root_user_error/submodule,tests/integration/local_toolchains,tests/integration/pip_parse,tests/integration/pip_parse/empty,tests/integration/py_cc_toolchain_registered
query --deleted_packages=examples/build_file_generation,examples/build_file_generation/random_number_generator,examples/bzlmod,examples/bzlmod_build_file_generation,examples/bzlmod_build_file_generation/other_module/other_module/pkg,examples/bzlmod_build_file_generation/runfiles,examples/bzlmod/entry_points,examples/bzlmod/entry_points/tests,examples/bzlmod/libs/my_lib,examples/bzlmod/other_module,examples/bzlmod/other_module/other_module/pkg,examples/bzlmod/patches,examples/bzlmod/py_proto_library,examples/bzlmod/py_proto_library/example.com/another_proto,examples/bzlmod/py_proto_library/example.com/proto,examples/bzlmod/runfiles,examples/bzlmod/tests,examples/bzlmod/tests/other_module,examples/bzlmod/whl_mods,examples/multi_python_versions/libs/my_lib,examples/multi_python_versions/requirements,examples/multi_python_versions/tests,examples/pip_parse,examples/pip_parse_vendored,examples/pip_repository_annotations,examples/py_proto_library,examples/py_proto_library/example.com/another_proto,examples/py_proto_library/example.com/proto,gazelle,gazelle/manifest,gazelle/manifest/generate,gazelle/manifest/hasher,gazelle/manifest/test,gazelle/modules_mapping,gazelle/python,gazelle/pythonconfig,gazelle/python/private,tests/integration/compile_pip_requirements,tests/integration/compile_pip_requirements_test_from_external_repo,tests/integration/custom_commands,tests/integration/ignore_root_user_error,tests/integration/ignore_root_user_error/submodule,tests/integration/local_toolchains,tests/integration/pip_parse,tests/integration/pip_parse/empty,tests/integration/py_cc_toolchain_registered
build --deleted_packages=examples/build_file_generation,examples/build_file_generation/random_number_generator,examples/bzlmod,examples/bzlmod/entry_points,examples/bzlmod/entry_points/tests,examples/bzlmod/libs/my_lib,examples/bzlmod/other_module,examples/bzlmod/other_module/other_module/pkg,examples/bzlmod/patches,examples/bzlmod/py_proto_library,examples/bzlmod/py_proto_library/example.com/another_proto,examples/bzlmod/py_proto_library/example.com/proto,examples/bzlmod/runfiles,examples/bzlmod/tests,examples/bzlmod/tests/other_module,examples/bzlmod/whl_mods,examples/bzlmod_build_file_generation,examples/bzlmod_build_file_generation/other_module/other_module/pkg,examples/bzlmod_build_file_generation/runfiles,examples/multi_python_versions/libs/my_lib,examples/multi_python_versions/requirements,examples/multi_python_versions/tests,examples/pip_parse,examples/pip_parse_vendored,examples/pip_repository_annotations,examples/py_proto_library,examples/py_proto_library/example.com/another_proto,examples/py_proto_library/example.com/proto,gazelle,gazelle/manifest,gazelle/manifest/generate,gazelle/manifest/hasher,gazelle/manifest/test,gazelle/modules_mapping,gazelle/python,gazelle/python/private,gazelle/pythonconfig,tests/integration/compile_pip_requirements,tests/integration/compile_pip_requirements_test_from_external_repo,tests/integration/custom_commands,tests/integration/ignore_root_user_error,tests/integration/ignore_root_user_error/submodule,tests/integration/local_toolchains,tests/integration/pip_parse,tests/integration/pip_parse/empty,tests/integration/py_cc_toolchain_registered
query --deleted_packages=examples/build_file_generation,examples/build_file_generation/random_number_generator,examples/bzlmod,examples/bzlmod/entry_points,examples/bzlmod/entry_points/tests,examples/bzlmod/libs/my_lib,examples/bzlmod/other_module,examples/bzlmod/other_module/other_module/pkg,examples/bzlmod/patches,examples/bzlmod/py_proto_library,examples/bzlmod/py_proto_library/example.com/another_proto,examples/bzlmod/py_proto_library/example.com/proto,examples/bzlmod/runfiles,examples/bzlmod/tests,examples/bzlmod/tests/other_module,examples/bzlmod/whl_mods,examples/bzlmod_build_file_generation,examples/bzlmod_build_file_generation/other_module/other_module/pkg,examples/bzlmod_build_file_generation/runfiles,examples/multi_python_versions/libs/my_lib,examples/multi_python_versions/requirements,examples/multi_python_versions/tests,examples/pip_parse,examples/pip_parse_vendored,examples/pip_repository_annotations,examples/py_proto_library,examples/py_proto_library/example.com/another_proto,examples/py_proto_library/example.com/proto,gazelle,gazelle/manifest,gazelle/manifest/generate,gazelle/manifest/hasher,gazelle/manifest/test,gazelle/modules_mapping,gazelle/python,gazelle/python/private,gazelle/pythonconfig,tests/integration/compile_pip_requirements,tests/integration/compile_pip_requirements_test_from_external_repo,tests/integration/custom_commands,tests/integration/ignore_root_user_error,tests/integration/ignore_root_user_error/submodule,tests/integration/local_toolchains,tests/integration/pip_parse,tests/integration/pip_parse/empty,tests/integration/py_cc_toolchain_registered

test --test_output=errors

Expand Down
4 changes: 2 additions & 2 deletions examples/bzlmod/MODULE.bazel.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 14 additions & 1 deletion python/private/pypi/parse_requirements.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,19 @@ load(":index_sources.bzl", "index_sources")
load(":parse_requirements_txt.bzl", "parse_requirements_txt")
load(":whl_target_platforms.bzl", "select_whls")

def _extract_version(entry):
"""Extract the version part from the requirement string.
entry: The requirement string.
"""
version_start = entry.find("==")
if version_start != -1:
# Extract everything after '==' until the next space or end of the string
version = entry[version_start + 2:].split(" ")[0]
return version
return None

def parse_requirements(
ctx,
*,
Expand Down Expand Up @@ -92,7 +105,7 @@ def parse_requirements(
# are returned as just the base package name. e.g., `foo[bar]` results
# in an entry like `("foo", "foo[bar] == 1.0 ...")`.
requirements_dict = {
normalize_name(entry[0]): entry
(entry[0], _extract_version(entry[1])): entry
for entry in sorted(
parse_result.requirements,
# Get the longest match and fallback to original WORKSPACE sorting,
Expand Down
47 changes: 47 additions & 0 deletions tests/pypi/parse_requirements/parse_requirements_tests.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ load("//python/private/pypi:parse_requirements.bzl", "parse_requirements", "sele

def _mock_ctx():
testdata = {
"requirements_different_package_version": """\
foo==0.0.1+local --hash=sha256:deadbeef
foo==0.0.1 --hash=sha256:deadb00f
""",
"requirements_direct": """\
foo[extra] @ https://some-url
""",
Expand Down Expand Up @@ -382,6 +386,49 @@ def _test_env_marker_resolution(env):

_tests.append(_test_env_marker_resolution)

# <list [struct(distribution = "foo", extra_pip_args = [], is_exposed = True, requirement_line = "foo==0.0.1 --hash=sha256:deadb00f", sdist = None, srcs = struct(requirement = "foo==0.0.1", shas = ["deadb00f"], version = "0.0.1"), target_platforms = ["linux_x86_64"], whls = []), struct(distribution = "foo", extra_pip_args = [], is_exposed = True, requirement_line = "foo==0.0.1+local --hash=sha256:deadbeef", sdist = None, srcs = struct(requirement = "foo==0.0.1+local", shas = ["deadbeef"], version = "0.0.1+local"), target_platforms = ["linux_x86_64"], whls = [])]>
def _test_different_package_version(env):
got = parse_requirements(
ctx = _mock_ctx(),
requirements_by_platform = {
"requirements_different_package_version": ["linux_x86_64"],
},
)
env.expect.that_dict(got).contains_exactly({
"foo": [
struct(
distribution = "foo",
extra_pip_args = [],
requirement_line = "foo==0.0.1 --hash=sha256:deadb00f",
srcs = struct(
requirement = "foo==0.0.1",
shas = ["deadb00f"],
version = "0.0.1",
),
target_platforms = ["linux_x86_64"],
whls = [],
sdist = None,
is_exposed = True,
),
struct(
distribution = "foo",
extra_pip_args = [],
requirement_line = "foo==0.0.1+local --hash=sha256:deadbeef",
srcs = struct(
requirement = "foo==0.0.1+local",
shas = ["deadbeef"],
version = "0.0.1+local",
),
target_platforms = ["linux_x86_64"],
whls = [],
sdist = None,
is_exposed = True,
),
],
})

_tests.append(_test_different_package_version)

def parse_requirements_test_suite(name):
"""Create the test suite.
Expand Down

0 comments on commit 3002d39

Please sign in to comment.