refactor: move the remaining PyPI related functions to private/pypi (#2006)
A continuation of #2003, this time we finish moving the `pip_compile`
stuff.
Summary:
- move multi_pip_parse to private/pypi and re-export
- remove unused files leftover from #2003
- move repositories.bzl to private/pypi/deps.bzl
- move pip_compile to private/pypi
- move the pip_install tools to private
diff --git a/python/BUILD.bazel b/python/BUILD.bazel
index 29b495b..96b2282 100644
--- a/python/BUILD.bazel
+++ b/python/BUILD.bazel
@@ -39,6 +39,7 @@
"//python/constraints:distribution",
"//python/entry_points:distribution",
"//python/extensions:distribution",
+ "//python/pip_install:distribution",
"//python/private:distribution",
"//python/runfiles:distribution",
],
@@ -96,12 +97,12 @@
name = "pip_bzl",
srcs = ["pip.bzl"],
deps = [
- "//python/pip_install:pip_repository_bzl",
- "//python/pip_install:repositories_bzl",
- "//python/pip_install:requirements_bzl",
- "//python/private:bzlmod_enabled_bzl",
- "//python/private:full_version_bzl",
- "//python/private/pypi:render_pkg_aliases_bzl",
+ "//python/private:normalize_name_bzl",
+ "//python/private/pypi:multi_pip_parse_bzl",
+ "//python/private/pypi:package_annotation_bzl",
+ "//python/private/pypi:pip_compile_bzl",
+ "//python/private/pypi:pip_repository_bzl",
+ "//python/private/pypi:whl_library_alias_bzl",
"//python/private/whl_filegroup:whl_filegroup_bzl",
],
)
@@ -210,7 +211,6 @@
srcs = ["repositories.bzl"],
deps = [
":versions_bzl",
- "//python/pip_install:repositories_bzl",
"//python/private:auth_bzl",
"//python/private:bazel_tools_bzl",
"//python/private:bzlmod_enabled_bzl",
@@ -219,6 +219,7 @@
"//python/private:internal_config_repo_bzl",
"//python/private:repo_utils_bzl",
"//python/private:toolchains_repo_bzl",
+ "//python/private/pypi:deps_bzl",
],
)
diff --git a/python/pip.bzl b/python/pip.bzl
index f1c74dd..a1a6720 100644
--- a/python/pip.bzl
+++ b/python/pip.bzl
@@ -19,250 +19,27 @@
for internal use only.
"""
-load("//python/pip_install:requirements.bzl", _compile_pip_requirements = "compile_pip_requirements")
-load("//python/private:bzlmod_enabled.bzl", "BZLMOD_ENABLED")
-load("//python/private:full_version.bzl", "full_version")
load("//python/private:normalize_name.bzl", "normalize_name")
+load("//python/private/pypi:multi_pip_parse.bzl", _multi_pip_parse = "multi_pip_parse")
load("//python/private/pypi:package_annotation.bzl", _package_annotation = "package_annotation")
+load("//python/private/pypi:pip_compile.bzl", "pip_compile")
load("//python/private/pypi:pip_repository.bzl", "pip_repository")
-load("//python/private/pypi:render_pkg_aliases.bzl", "NO_MATCH_ERROR_MESSAGE_TEMPLATE")
+load("//python/private/pypi:whl_library_alias.bzl", _whl_library_alias = "whl_library_alias")
load("//python/private/whl_filegroup:whl_filegroup.bzl", _whl_filegroup = "whl_filegroup")
-compile_pip_requirements = _compile_pip_requirements
+compile_pip_requirements = pip_compile
package_annotation = _package_annotation
pip_parse = pip_repository
whl_filegroup = _whl_filegroup
-def _multi_pip_parse_impl(rctx):
- rules_python = rctx.attr._rules_python_workspace.workspace_name
- load_statements = []
- install_deps_calls = []
- process_requirements_calls = []
- for python_version, pypi_repository in rctx.attr.pip_parses.items():
- sanitized_python_version = python_version.replace(".", "_")
- load_statement = """\
-load(
- "@{pypi_repository}//:requirements.bzl",
- _{sanitized_python_version}_install_deps = "install_deps",
- _{sanitized_python_version}_all_requirements = "all_requirements",
-)""".format(
- pypi_repository = pypi_repository,
- sanitized_python_version = sanitized_python_version,
- )
- load_statements.append(load_statement)
- process_requirements_call = """\
-_process_requirements(
- pkg_labels = _{sanitized_python_version}_all_requirements,
- python_version = "{python_version}",
- repo_prefix = "{pypi_repository}_",
-)""".format(
- pypi_repository = pypi_repository,
- python_version = python_version,
- sanitized_python_version = sanitized_python_version,
- )
- process_requirements_calls.append(process_requirements_call)
- install_deps_call = """ _{sanitized_python_version}_install_deps(**whl_library_kwargs)""".format(
- sanitized_python_version = sanitized_python_version,
- )
- install_deps_calls.append(install_deps_call)
-
- # NOTE @aignas 2023-10-31: I am not sure it is possible to render aliases
- # for all of the packages using the `render_pkg_aliases` function because
- # we need to know what the list of packages for each version is and then
- # we would be creating directories for each.
- macro_tmpl = "@%s_{}//:{}" % rctx.attr.name
-
- requirements_bzl = """\
-# Generated by python/pip.bzl
-
-load("@{rules_python}//python:pip.bzl", "whl_library_alias", "pip_utils")
-{load_statements}
-
-_wheel_names = []
-_version_map = dict()
-def _process_requirements(pkg_labels, python_version, repo_prefix):
- for pkg_label in pkg_labels:
- wheel_name = Label(pkg_label).package
- if not wheel_name:
- # We are dealing with the cases where we don't have aliases.
- workspace_name = Label(pkg_label).workspace_name
- wheel_name = workspace_name[len(repo_prefix):]
-
- _wheel_names.append(wheel_name)
- if not wheel_name in _version_map:
- _version_map[wheel_name] = dict()
- _version_map[wheel_name][python_version] = repo_prefix
-
-{process_requirements_calls}
-
-def requirement(name):
- return "{macro_tmpl}".format(pip_utils.normalize_name(name), "pkg")
-
-def whl_requirement(name):
- return "{macro_tmpl}".format(pip_utils.normalize_name(name), "whl")
-
-def data_requirement(name):
- return "{macro_tmpl}".format(pip_utils.normalize_name(name), "data")
-
-def dist_info_requirement(name):
- return "{macro_tmpl}".format(pip_utils.normalize_name(name), "dist_info")
-
-def install_deps(**whl_library_kwargs):
-{install_deps_calls}
- for wheel_name in _wheel_names:
- whl_library_alias(
- name = "{name}_" + wheel_name,
- wheel_name = wheel_name,
- default_version = "{default_version}",
- version_map = _version_map[wheel_name],
- )
-""".format(
- name = rctx.attr.name,
- install_deps_calls = "\n".join(install_deps_calls),
- load_statements = "\n".join(load_statements),
- macro_tmpl = macro_tmpl,
- process_requirements_calls = "\n".join(process_requirements_calls),
- rules_python = rules_python,
- default_version = rctx.attr.default_version,
- )
- rctx.file("requirements.bzl", requirements_bzl)
- rctx.file("BUILD.bazel", "exports_files(['requirements.bzl'])")
-
-_multi_pip_parse = repository_rule(
- _multi_pip_parse_impl,
- attrs = {
- "default_version": attr.string(),
- "pip_parses": attr.string_dict(),
- "_rules_python_workspace": attr.label(default = Label("//:WORKSPACE")),
- },
-)
-
-def _whl_library_alias_impl(rctx):
- rules_python = rctx.attr._rules_python_workspace.workspace_name
- if rctx.attr.default_version:
- default_repo_prefix = rctx.attr.version_map[rctx.attr.default_version]
- else:
- default_repo_prefix = None
- version_map = rctx.attr.version_map.items()
- build_content = ["# Generated by python/pip.bzl"]
- for alias_name in ["pkg", "whl", "data", "dist_info"]:
- build_content.append(_whl_library_render_alias_target(
- alias_name = alias_name,
- default_repo_prefix = default_repo_prefix,
- rules_python = rules_python,
- version_map = version_map,
- wheel_name = rctx.attr.wheel_name,
- ))
- rctx.file("BUILD.bazel", "\n".join(build_content))
-
-def _whl_library_render_alias_target(
- alias_name,
- default_repo_prefix,
- rules_python,
- version_map,
- wheel_name):
- # The template below adds one @, but under bzlmod, the name
- # is canonical, so we have to add a second @.
- if BZLMOD_ENABLED:
- rules_python = "@" + rules_python
-
- alias = ["""\
-alias(
- name = "{alias_name}",
- actual = select({{""".format(alias_name = alias_name)]
- for [python_version, repo_prefix] in version_map:
- alias.append("""\
- "@{rules_python}//python/config_settings:is_python_{full_python_version}": "{actual}",""".format(
- full_python_version = full_version(python_version),
- actual = "@{repo_prefix}{wheel_name}//:{alias_name}".format(
- repo_prefix = repo_prefix,
- wheel_name = wheel_name,
- alias_name = alias_name,
- ),
- rules_python = rules_python,
- ))
- if default_repo_prefix:
- default_actual = "@{repo_prefix}{wheel_name}//:{alias_name}".format(
- repo_prefix = default_repo_prefix,
- wheel_name = wheel_name,
- alias_name = alias_name,
- )
- alias.append(' "//conditions:default": "{default_actual}",'.format(
- default_actual = default_actual,
- ))
-
- alias.append(" },") # Close select expression condition dict
- if not default_repo_prefix:
- supported_versions = sorted([python_version for python_version, _ in version_map])
- alias.append(' no_match_error="""{}""",'.format(
- NO_MATCH_ERROR_MESSAGE_TEMPLATE.format(
- supported_versions = ", ".join(supported_versions),
- rules_python = rules_python,
- ),
- ))
- alias.append(" ),") # Close the select expression
- alias.append(' visibility = ["//visibility:public"],')
- alias.append(")") # Close the alias() expression
- return "\n".join(alias)
-
-whl_library_alias = repository_rule(
- _whl_library_alias_impl,
- attrs = {
- "default_version": attr.string(
- mandatory = False,
- doc = "Optional Python version in major.minor format, e.g. '3.10'." +
- "The Python version of the wheel to use when the versions " +
- "from `version_map` don't match. This allows the default " +
- "(version unaware) rules to match and select a wheel. If " +
- "not specified, then the default rules won't be able to " +
- "resolve a wheel and an error will occur.",
- ),
- "version_map": attr.string_dict(mandatory = True),
- "wheel_name": attr.string(mandatory = True),
- "_rules_python_workspace": attr.label(default = Label("//:WORKSPACE")),
- },
-)
-
-def multi_pip_parse(name, default_version, python_versions, python_interpreter_target, requirements_lock, **kwargs):
- """NOT INTENDED FOR DIRECT USE!
-
- This is intended to be used by the multi_pip_parse implementation in the template of the
- multi_toolchain_aliases repository rule.
-
- Args:
- name: the name of the multi_pip_parse repository.
- default_version: the default Python version.
- python_versions: all Python toolchain versions currently registered.
- python_interpreter_target: a dictionary which keys are Python versions and values are resolved host interpreters.
- requirements_lock: a dictionary which keys are Python versions and values are locked requirements files.
- **kwargs: extra arguments passed to all wrapped pip_parse.
-
- Returns:
- The internal implementation of multi_pip_parse repository rule.
- """
- pip_parses = {}
- for python_version in python_versions:
- if not python_version in python_interpreter_target:
- fail("Missing python_interpreter_target for Python version %s in '%s'" % (python_version, name))
- if not python_version in requirements_lock:
- fail("Missing requirements_lock for Python version %s in '%s'" % (python_version, name))
-
- pip_parse_name = name + "_" + python_version.replace(".", "_")
- pip_parse(
- name = pip_parse_name,
- python_interpreter_target = python_interpreter_target[python_version],
- requirements_lock = requirements_lock[python_version],
- **kwargs
- )
- pip_parses[python_version] = pip_parse_name
-
- return _multi_pip_parse(
- name = name,
- default_version = default_version,
- pip_parses = pip_parses,
- )
-
# Extra utilities visible to rules_python users.
pip_utils = struct(
normalize_name = normalize_name,
)
+
+# The following are only exported here because they are used from
+# multi_toolchain_aliases repository_rule, not intended for public use.
+#
+# See ./private/toolchains_repo.bzl
+multi_pip_parse = _multi_pip_parse
+whl_library_alias = _whl_library_alias
diff --git a/python/pip_install/BUILD.bazel b/python/pip_install/BUILD.bazel
index 1894c4d..683199f 100644
--- a/python/pip_install/BUILD.bazel
+++ b/python/pip_install/BUILD.bazel
@@ -32,43 +32,21 @@
bzl_library(
name = "requirements_bzl",
srcs = ["requirements.bzl"],
- deps = [
- ":repositories_bzl",
- "//python:defs_bzl",
- ],
+ deps = ["//python/private/pypi:pip_compile_bzl"],
)
bzl_library(
name = "repositories_bzl",
srcs = ["repositories.bzl"],
deps = [
- "//:version_bzl",
- "//python/private:bazel_tools_bzl",
- "@bazel_skylib//lib:versions",
+ "//python/private/pypi:deps_bzl",
],
)
filegroup(
name = "distribution",
- srcs = glob(["*.bzl"]) + [
- "BUILD.bazel",
- "pip_repository_requirements.bzl.tmpl",
- "//python/pip_install/tools/dependency_resolver:distribution",
- "//python/pip_install/tools/wheel_installer:distribution",
- ],
- visibility = ["//:__pkg__"],
-)
-
-filegroup(
- name = "repositories",
- srcs = ["repositories.bzl"],
- visibility = ["//tools/private/update_deps:__pkg__"],
-)
-
-filegroup(
- name = "requirements_txt",
- srcs = ["tools/requirements.txt"],
- visibility = ["//tools/private/update_deps:__pkg__"],
+ srcs = glob(["**"]),
+ visibility = ["//python:__pkg__"],
)
filegroup(
diff --git a/python/pip_install/pip_repository_requirements.bzl.tmpl b/python/pip_install/pip_repository_requirements.bzl.tmpl
deleted file mode 100644
index 2f4bcd6..0000000
--- a/python/pip_install/pip_repository_requirements.bzl.tmpl
+++ /dev/null
@@ -1,72 +0,0 @@
-"""Starlark representation of locked requirements.
-
-@generated by rules_python pip_parse repository rule.
-"""
-
-%%IMPORTS%%
-
-all_requirements = %%ALL_REQUIREMENTS%%
-
-all_whl_requirements_by_package = %%ALL_WHL_REQUIREMENTS_BY_PACKAGE%%
-
-all_whl_requirements = all_whl_requirements_by_package.values()
-
-all_data_requirements = %%ALL_DATA_REQUIREMENTS%%
-
-_packages = %%PACKAGES%%
-_config = %%CONFIG%%
-_annotations = %%ANNOTATIONS%%
-
-def requirement(name):
- return "%%MACRO_TMPL%%".format(pip_utils.normalize_name(name), "pkg")
-
-def whl_requirement(name):
- return "%%MACRO_TMPL%%".format(pip_utils.normalize_name(name), "whl")
-
-def data_requirement(name):
- return "%%MACRO_TMPL%%".format(pip_utils.normalize_name(name), "data")
-
-def dist_info_requirement(name):
- return "%%MACRO_TMPL%%".format(pip_utils.normalize_name(name), "dist_info")
-
-def _get_annotation(requirement):
- # This expects to parse `setuptools==58.2.0 --hash=sha256:2551203ae6955b9876741a26ab3e767bb3242dafe86a32a749ea0d78b6792f11`
- # down to `setuptools`.
- name = requirement.split(" ")[0].split("=")[0].split("[")[0]
- return _annotations.get(name)
-
-def install_deps(**whl_library_kwargs):
- """Repository rule macro. Install dependencies from `pip_parse`.
-
- Args:
- **whl_library_kwargs: Additional arguments which will flow to underlying
- `whl_library` calls. See pip_repository.bzl for details.
- """
-
- # Set up the requirement groups
- all_requirement_groups = %%ALL_REQUIREMENT_GROUPS%%
-
- requirement_group_mapping = {
- requirement: group_name
- for group_name, group_requirements in all_requirement_groups.items()
- for requirement in group_requirements
- }
-
- # %%GROUP_LIBRARY%%
-
- # Install wheels which may be participants in a group
- whl_config = dict(_config)
- whl_config.update(whl_library_kwargs)
-
- for name, requirement in _packages:
- group_name = requirement_group_mapping.get(name.replace("%%NAME%%_", ""))
- group_deps = all_requirement_groups.get(group_name, [])
-
- whl_library(
- name = name,
- requirement = requirement,
- group_name = group_name,
- group_deps = group_deps,
- annotation = _get_annotation(requirement),
- **whl_config
- )
diff --git a/python/pip_install/repositories.bzl b/python/pip_install/repositories.bzl
index 3f91860..5231d1f 100644
--- a/python/pip_install/repositories.bzl
+++ b/python/pip_install/repositories.bzl
@@ -14,131 +14,6 @@
""
-load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
-load("@bazel_tools//tools/build_defs/repo:utils.bzl", "maybe")
+load("//python/private/pypi:deps.bzl", "pypi_deps")
-_RULE_DEPS = [
- # START: maintained by 'bazel run //tools/private/update_deps:update_pip_deps'
- (
- "pypi__build",
- "https://files.pythonhosted.org/packages/e2/03/f3c8ba0a6b6e30d7d18c40faab90807c9bb5e9a1e3b2fe2008af624a9c97/build-1.2.1-py3-none-any.whl",
- "75e10f767a433d9a86e50d83f418e83efc18ede923ee5ff7df93b6cb0306c5d4",
- ),
- (
- "pypi__click",
- "https://files.pythonhosted.org/packages/00/2e/d53fa4befbf2cfa713304affc7ca780ce4fc1fd8710527771b58311a3229/click-8.1.7-py3-none-any.whl",
- "ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28",
- ),
- (
- "pypi__colorama",
- "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl",
- "4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6",
- ),
- (
- "pypi__importlib_metadata",
- "https://files.pythonhosted.org/packages/2d/0a/679461c511447ffaf176567d5c496d1de27cbe34a87df6677d7171b2fbd4/importlib_metadata-7.1.0-py3-none-any.whl",
- "30962b96c0c223483ed6cc7280e7f0199feb01a0e40cfae4d4450fc6fab1f570",
- ),
- (
- "pypi__installer",
- "https://files.pythonhosted.org/packages/e5/ca/1172b6638d52f2d6caa2dd262ec4c811ba59eee96d54a7701930726bce18/installer-0.7.0-py3-none-any.whl",
- "05d1933f0a5ba7d8d6296bb6d5018e7c94fa473ceb10cf198a92ccea19c27b53",
- ),
- (
- "pypi__more_itertools",
- "https://files.pythonhosted.org/packages/50/e2/8e10e465ee3987bb7c9ab69efb91d867d93959095f4807db102d07995d94/more_itertools-10.2.0-py3-none-any.whl",
- "686b06abe565edfab151cb8fd385a05651e1fdf8f0a14191e4439283421f8684",
- ),
- (
- "pypi__packaging",
- "https://files.pythonhosted.org/packages/49/df/1fceb2f8900f8639e278b056416d49134fb8d84c5942ffaa01ad34782422/packaging-24.0-py3-none-any.whl",
- "2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5",
- ),
- (
- "pypi__pep517",
- "https://files.pythonhosted.org/packages/25/6e/ca4a5434eb0e502210f591b97537d322546e4833dcb4d470a48c375c5540/pep517-0.13.1-py3-none-any.whl",
- "31b206f67165b3536dd577c5c3f1518e8fbaf38cbc57efff8369a392feff1721",
- ),
- (
- "pypi__pip",
- "https://files.pythonhosted.org/packages/8a/6a/19e9fe04fca059ccf770861c7d5721ab4c2aebc539889e97c7977528a53b/pip-24.0-py3-none-any.whl",
- "ba0d021a166865d2265246961bec0152ff124de910c5cc39f1156ce3fa7c69dc",
- ),
- (
- "pypi__pip_tools",
- "https://files.pythonhosted.org/packages/0d/dc/38f4ce065e92c66f058ea7a368a9c5de4e702272b479c0992059f7693941/pip_tools-7.4.1-py3-none-any.whl",
- "4c690e5fbae2f21e87843e89c26191f0d9454f362d8acdbd695716493ec8b3a9",
- ),
- (
- "pypi__pyproject_hooks",
- "https://files.pythonhosted.org/packages/ae/f3/431b9d5fe7d14af7a32340792ef43b8a714e7726f1d7b69cc4e8e7a3f1d7/pyproject_hooks-1.1.0-py3-none-any.whl",
- "7ceeefe9aec63a1064c18d939bdc3adf2d8aa1988a510afec15151578b232aa2",
- ),
- (
- "pypi__setuptools",
- "https://files.pythonhosted.org/packages/de/88/70c5767a0e43eb4451c2200f07d042a4bcd7639276003a9c54a68cfcc1f8/setuptools-70.0.0-py3-none-any.whl",
- "54faa7f2e8d2d11bcd2c07bed282eef1046b5c080d1c32add737d7b5817b1ad4",
- ),
- (
- "pypi__tomli",
- "https://files.pythonhosted.org/packages/97/75/10a9ebee3fd790d20926a90a2547f0bf78f371b2f13aa822c759680ca7b9/tomli-2.0.1-py3-none-any.whl",
- "939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc",
- ),
- (
- "pypi__wheel",
- "https://files.pythonhosted.org/packages/7d/cd/d7460c9a869b16c3dd4e1e403cce337df165368c71d6af229a74699622ce/wheel-0.43.0-py3-none-any.whl",
- "55c570405f142630c6b9f72fe09d9b67cf1477fcf543ae5b8dcb1f5b7377da81",
- ),
- (
- "pypi__zipp",
- "https://files.pythonhosted.org/packages/da/55/a03fd7240714916507e1fcf7ae355bd9d9ed2e6db492595f1a67f61681be/zipp-3.18.2-py3-none-any.whl",
- "dce197b859eb796242b0622af1b8beb0a722d52aa2f57133ead08edd5bf5374e",
- ),
- # END: maintained by 'bazel run //tools/private/update_deps:update_pip_deps'
-]
-
-_GENERIC_WHEEL = """\
-package(default_visibility = ["//visibility:public"])
-
-load("@rules_python//python:defs.bzl", "py_library")
-
-py_library(
- name = "lib",
- srcs = glob(["**/*.py"]),
- data = glob(["**/*"], exclude=[
- # These entries include those put into user-installed dependencies by
- # data_exclude in /python/pip_install/tools/bazel.py
- # to avoid non-determinism following pip install's behavior.
- "**/*.py",
- "**/*.pyc",
- "**/*.pyc.*", # During pyc creation, temp files named *.pyc.NNN are created
- "**/* *",
- "**/*.dist-info/RECORD",
- "BUILD",
- "WORKSPACE",
- ]),
- # This makes this directory a top-level in the python import
- # search path for anything that depends on this.
- imports = ["."],
-)
-"""
-
-# Collate all the repository names so they can be easily consumed
-all_requirements = [name for (name, _, _) in _RULE_DEPS]
-
-def requirement(pkg):
- return Label("@pypi__" + pkg + "//:lib")
-
-def pip_install_dependencies():
- """
- Fetch dependencies these rules depend on. Workspaces that use the pip_parse rule can call this.
- """
- for (name, url, sha256) in _RULE_DEPS:
- maybe(
- http_archive,
- name,
- url = url,
- sha256 = sha256,
- type = "zip",
- build_file_content = _GENERIC_WHEEL,
- )
+pip_install_dependencies = pypi_deps
diff --git a/python/pip_install/requirements.bzl b/python/pip_install/requirements.bzl
index 5caf762..6ae3f8f 100644
--- a/python/pip_install/requirements.bzl
+++ b/python/pip_install/requirements.bzl
@@ -14,149 +14,6 @@
"""Rules to verify and update pip-compile locked requirements.txt"""
-load("//python:defs.bzl", _py_binary = "py_binary", _py_test = "py_test")
-load("//python/pip_install:repositories.bzl", "requirement")
+load("//python/private/pypi:pip_compile.bzl", "pip_compile")
-def compile_pip_requirements(
- name,
- src = None,
- extra_args = [],
- extra_deps = [],
- generate_hashes = True,
- py_binary = _py_binary,
- py_test = _py_test,
- requirements_in = None,
- requirements_txt = None,
- requirements_darwin = None,
- requirements_linux = None,
- requirements_windows = None,
- visibility = ["//visibility:private"],
- tags = None,
- **kwargs):
- """Generates targets for managing pip dependencies with pip-compile.
-
- By default this rules generates a filegroup named "[name]" which can be included in the data
- of some other compile_pip_requirements rule that references these requirements
- (e.g. with `-r ../other/requirements.txt`).
-
- It also generates two targets for running pip-compile:
-
- - validate with `bazel test [name]_test`
- - update with `bazel run [name].update`
-
- If you are using a version control system, the requirements.txt generated by this rule should
- be checked into it to ensure that all developers/users have the same dependency versions.
-
- Args:
- name: base name for generated targets, typically "requirements".
- src: file containing inputs to dependency resolution. If not specified,
- defaults to `pyproject.toml`. Supported formats are:
- * a requirements text file, usually named `requirements.in`
- * A `.toml` file, where the `project.dependencies` list is used as per
- [PEP621](https://peps.python.org/pep-0621/).
- extra_args: passed to pip-compile.
- extra_deps: extra dependencies passed to pip-compile.
- generate_hashes: whether to put hashes in the requirements_txt file.
- py_binary: the py_binary rule to be used.
- py_test: the py_test rule to be used.
- requirements_in: file expressing desired dependencies. Deprecated, use src instead.
- requirements_txt: result of "compiling" the requirements.in file.
- requirements_linux: File of linux specific resolve output to check validate if requirement.in has changes.
- requirements_darwin: File of darwin specific resolve output to check validate if requirement.in has changes.
- requirements_windows: File of windows specific resolve output to check validate if requirement.in has changes.
- tags: tagging attribute common to all build rules, passed to both the _test and .update rules.
- visibility: passed to both the _test and .update rules.
- **kwargs: other bazel attributes passed to the "_test" rule.
- """
- if requirements_in and src:
- fail("Only one of 'src' and 'requirements_in' attributes can be used")
- else:
- src = requirements_in or src or "pyproject.toml"
-
- requirements_txt = name + ".txt" if requirements_txt == None else requirements_txt
-
- # "Default" target produced by this macro
- # Allow a compile_pip_requirements rule to include another one in the data
- # for a requirements file that does `-r ../other/requirements.txt`
- native.filegroup(
- name = name,
- srcs = kwargs.pop("data", []) + [requirements_txt],
- visibility = visibility,
- )
-
- data = [name, requirements_txt, src] + [f for f in (requirements_linux, requirements_darwin, requirements_windows) if f != None]
-
- # Use the Label constructor so this is expanded in the context of the file
- # where it appears, which is to say, in @rules_python
- pip_compile = Label("//python/pip_install/tools/dependency_resolver:dependency_resolver.py")
-
- loc = "$(rlocationpath {})"
-
- args = [
- loc.format(src),
- loc.format(requirements_txt),
- "//%s:%s.update" % (native.package_name(), name),
- "--resolver=backtracking",
- "--allow-unsafe",
- ]
- if generate_hashes:
- args.append("--generate-hashes")
- if requirements_linux:
- args.append("--requirements-linux={}".format(loc.format(requirements_linux)))
- if requirements_darwin:
- args.append("--requirements-darwin={}".format(loc.format(requirements_darwin)))
- if requirements_windows:
- args.append("--requirements-windows={}".format(loc.format(requirements_windows)))
- args.extend(extra_args)
-
- deps = [
- requirement("build"),
- requirement("click"),
- requirement("colorama"),
- requirement("importlib_metadata"),
- requirement("more_itertools"),
- requirement("packaging"),
- requirement("pep517"),
- requirement("pip"),
- requirement("pip_tools"),
- requirement("pyproject_hooks"),
- requirement("setuptools"),
- requirement("tomli"),
- requirement("zipp"),
- Label("//python/runfiles:runfiles"),
- ] + extra_deps
-
- tags = tags or []
- tags.append("requires-network")
- tags.append("no-remote-exec")
- tags.append("no-sandbox")
- attrs = {
- "args": args,
- "data": data,
- "deps": deps,
- "main": pip_compile,
- "srcs": [pip_compile],
- "tags": tags,
- "visibility": visibility,
- }
-
- # cheap way to detect the bazel version
- _bazel_version_4_or_greater = "propeller_optimize" in dir(native)
-
- # Bazel 4.0 added the "env" attribute to py_test/py_binary
- if _bazel_version_4_or_greater:
- attrs["env"] = kwargs.pop("env", {})
-
- py_binary(
- name = name + ".update",
- **attrs
- )
-
- timeout = kwargs.pop("timeout", "short")
-
- py_test(
- name = name + "_test",
- timeout = timeout,
- # kwargs could contain test-specific attributes like size or timeout
- **dict(attrs, **kwargs)
- )
+compile_pip_requirements = pip_compile
diff --git a/python/pip_install/tools/dependency_resolver/BUILD.bazel b/python/pip_install/tools/dependency_resolver/BUILD.bazel
deleted file mode 100644
index 467b009..0000000
--- a/python/pip_install/tools/dependency_resolver/BUILD.bazel
+++ /dev/null
@@ -1,19 +0,0 @@
-exports_files(["dependency_resolver.py"])
-
-filegroup(
- name = "distribution",
- srcs = glob(
- ["*"],
- exclude = ["*_test.py"],
- ),
- visibility = ["//python/pip_install:__subpackages__"],
-)
-
-filegroup(
- name = "py_srcs",
- srcs = glob(
- include = ["**/*.py"],
- exclude = ["**/*_test.py"],
- ),
- visibility = ["//:__subpackages__"],
-)
diff --git a/python/pip_install/tools/wheel_installer/BUILD.bazel b/python/pip_install/tools/wheel_installer/BUILD.bazel
deleted file mode 100644
index 0c24d5a..0000000
--- a/python/pip_install/tools/wheel_installer/BUILD.bazel
+++ /dev/null
@@ -1,91 +0,0 @@
-load("//python:defs.bzl", "py_binary", "py_library", "py_test")
-load("//python/pip_install:repositories.bzl", "requirement")
-
-py_library(
- name = "lib",
- srcs = [
- "arguments.py",
- "namespace_pkgs.py",
- "wheel.py",
- "wheel_installer.py",
- ],
- visibility = ["//third_party/rules_pycross/pycross/private:__subpackages__"],
- deps = [
- requirement("installer"),
- requirement("pip"),
- requirement("packaging"),
- requirement("setuptools"),
- ],
-)
-
-py_binary(
- name = "wheel_installer",
- srcs = [
- "wheel_installer.py",
- ],
- deps = [":lib"],
-)
-
-py_test(
- name = "arguments_test",
- size = "small",
- srcs = [
- "arguments_test.py",
- ],
- deps = [
- ":lib",
- ],
-)
-
-py_test(
- name = "namespace_pkgs_test",
- size = "small",
- srcs = [
- "namespace_pkgs_test.py",
- ],
- deps = [
- ":lib",
- ],
-)
-
-py_test(
- name = "wheel_test",
- size = "small",
- srcs = [
- "wheel_test.py",
- ],
- data = ["//examples/wheel:minimal_with_py_package"],
- deps = [
- ":lib",
- ],
-)
-
-py_test(
- name = "wheel_installer_test",
- size = "small",
- srcs = [
- "wheel_installer_test.py",
- ],
- data = ["//examples/wheel:minimal_with_py_package"],
- deps = [
- ":lib",
- ],
-)
-
-filegroup(
- name = "distribution",
- srcs = glob(
- ["*"],
- exclude = ["*_test.py"],
- ),
- visibility = ["//python/pip_install:__subpackages__"],
-)
-
-filegroup(
- name = "py_srcs",
- srcs = glob(
- include = ["**/*.py"],
- exclude = ["**/*_test.py"],
- ),
- visibility = ["//:__subpackages__"],
-)
diff --git a/python/pip_install/tools/wheel_installer/arguments_test.py b/python/pip_install/tools/wheel_installer/arguments_test.py
deleted file mode 100644
index fa018da..0000000
--- a/python/pip_install/tools/wheel_installer/arguments_test.py
+++ /dev/null
@@ -1,69 +0,0 @@
-# Copyright 2023 The Bazel Authors. All rights reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-import argparse
-import json
-import unittest
-
-from python.pip_install.tools.wheel_installer import arguments, wheel
-
-
-class ArgumentsTestCase(unittest.TestCase):
- def test_arguments(self) -> None:
- parser = arguments.parser()
- repo_name = "foo"
- repo_prefix = "pypi_"
- index_url = "--index_url=pypi.org/simple"
- extra_pip_args = [index_url]
- requirement = "foo==1.0.0 --hash=sha256:deadbeef"
- args_dict = vars(
- parser.parse_args(
- args=[
- f'--requirement="{requirement}"',
- f"--extra_pip_args={json.dumps({'arg': extra_pip_args})}",
- ]
- )
- )
- args_dict = arguments.deserialize_structured_args(args_dict)
- self.assertIn("requirement", args_dict)
- self.assertIn("extra_pip_args", args_dict)
- self.assertEqual(args_dict["pip_data_exclude"], [])
- self.assertEqual(args_dict["enable_implicit_namespace_pkgs"], False)
- self.assertEqual(args_dict["extra_pip_args"], extra_pip_args)
-
- def test_deserialize_structured_args(self) -> None:
- serialized_args = {
- "pip_data_exclude": json.dumps({"arg": ["**.foo"]}),
- "environment": json.dumps({"arg": {"PIP_DO_SOMETHING": "True"}}),
- }
- args = arguments.deserialize_structured_args(serialized_args)
- self.assertEqual(args["pip_data_exclude"], ["**.foo"])
- self.assertEqual(args["environment"], {"PIP_DO_SOMETHING": "True"})
- self.assertEqual(args["extra_pip_args"], [])
-
- def test_platform_aggregation(self) -> None:
- parser = arguments.parser()
- args = parser.parse_args(
- args=[
- "--platform=linux_*",
- "--platform=osx_*",
- "--platform=windows_*",
- "--requirement=foo",
- ]
- )
- self.assertEqual(set(wheel.Platform.all()), arguments.get_platforms(args))
-
-
-if __name__ == "__main__":
- unittest.main()
diff --git a/python/pip_install/tools/wheel_installer/namespace_pkgs_test.py b/python/pip_install/tools/wheel_installer/namespace_pkgs_test.py
deleted file mode 100644
index 4aa0fea..0000000
--- a/python/pip_install/tools/wheel_installer/namespace_pkgs_test.py
+++ /dev/null
@@ -1,192 +0,0 @@
-# Copyright 2023 The Bazel Authors. All rights reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-import os
-import pathlib
-import shutil
-import tempfile
-import unittest
-from typing import Optional, Set
-
-from python.pip_install.tools.wheel_installer import namespace_pkgs
-
-
-class TempDir:
- def __init__(self) -> None:
- self.dir = tempfile.mkdtemp()
-
- def root(self) -> str:
- return self.dir
-
- def add_dir(self, rel_path: str) -> None:
- d = pathlib.Path(self.dir, rel_path)
- d.mkdir(parents=True)
-
- def add_file(self, rel_path: str, contents: Optional[str] = None) -> None:
- f = pathlib.Path(self.dir, rel_path)
- f.parent.mkdir(parents=True, exist_ok=True)
- if contents:
- with open(str(f), "w") as writeable_f:
- writeable_f.write(contents)
- else:
- f.touch()
-
- def remove(self) -> None:
- shutil.rmtree(self.dir)
-
-
-class TestImplicitNamespacePackages(unittest.TestCase):
- def assertPathsEqual(self, actual: Set[pathlib.Path], expected: Set[str]) -> None:
- self.assertEqual(actual, {pathlib.Path(p) for p in expected})
-
- def test_in_current_directory(self) -> None:
- directory = TempDir()
- directory.add_file("foo/bar/biz.py")
- directory.add_file("foo/bee/boo.py")
- directory.add_file("foo/buu/__init__.py")
- directory.add_file("foo/buu/bii.py")
- cwd = os.getcwd()
- os.chdir(directory.root())
- expected = {
- "foo",
- "foo/bar",
- "foo/bee",
- }
- try:
- actual = namespace_pkgs.implicit_namespace_packages(".")
- self.assertPathsEqual(actual, expected)
- finally:
- os.chdir(cwd)
- directory.remove()
-
- def test_finds_correct_namespace_packages(self) -> None:
- directory = TempDir()
- directory.add_file("foo/bar/biz.py")
- directory.add_file("foo/bee/boo.py")
- directory.add_file("foo/buu/__init__.py")
- directory.add_file("foo/buu/bii.py")
-
- expected = {
- directory.root() + "/foo",
- directory.root() + "/foo/bar",
- directory.root() + "/foo/bee",
- }
- actual = namespace_pkgs.implicit_namespace_packages(directory.root())
- self.assertPathsEqual(actual, expected)
-
- def test_ignores_empty_directories(self) -> None:
- directory = TempDir()
- directory.add_file("foo/bar/biz.py")
- directory.add_dir("foo/cat")
-
- expected = {
- directory.root() + "/foo",
- directory.root() + "/foo/bar",
- }
- actual = namespace_pkgs.implicit_namespace_packages(directory.root())
- self.assertPathsEqual(actual, expected)
-
- def test_empty_case(self) -> None:
- directory = TempDir()
- directory.add_file("foo/__init__.py")
- directory.add_file("foo/bar/__init__.py")
- directory.add_file("foo/bar/biz.py")
-
- actual = namespace_pkgs.implicit_namespace_packages(directory.root())
- self.assertEqual(actual, set())
-
- def test_ignores_non_module_files_in_directories(self) -> None:
- directory = TempDir()
- directory.add_file("foo/__init__.pyi")
- directory.add_file("foo/py.typed")
-
- actual = namespace_pkgs.implicit_namespace_packages(directory.root())
- self.assertEqual(actual, set())
-
- def test_parent_child_relationship_of_namespace_pkgs(self):
- directory = TempDir()
- directory.add_file("foo/bar/biff/my_module.py")
- directory.add_file("foo/bar/biff/another_module.py")
-
- expected = {
- directory.root() + "/foo",
- directory.root() + "/foo/bar",
- directory.root() + "/foo/bar/biff",
- }
- actual = namespace_pkgs.implicit_namespace_packages(directory.root())
- self.assertPathsEqual(actual, expected)
-
- def test_parent_child_relationship_of_namespace_and_standard_pkgs(self):
- directory = TempDir()
- directory.add_file("foo/bar/biff/__init__.py")
- directory.add_file("foo/bar/biff/another_module.py")
-
- expected = {
- directory.root() + "/foo",
- directory.root() + "/foo/bar",
- }
- actual = namespace_pkgs.implicit_namespace_packages(directory.root())
- self.assertPathsEqual(actual, expected)
-
- def test_parent_child_relationship_of_namespace_and_nested_standard_pkgs(self):
- directory = TempDir()
- directory.add_file("foo/bar/__init__.py")
- directory.add_file("foo/bar/biff/another_module.py")
- directory.add_file("foo/bar/biff/__init__.py")
- directory.add_file("foo/bar/boof/big_module.py")
- directory.add_file("foo/bar/boof/__init__.py")
- directory.add_file("fim/in_a_ns_pkg.py")
-
- expected = {
- directory.root() + "/foo",
- directory.root() + "/fim",
- }
- actual = namespace_pkgs.implicit_namespace_packages(directory.root())
- self.assertPathsEqual(actual, expected)
-
- def test_recognized_all_nonstandard_module_types(self):
- directory = TempDir()
- directory.add_file("ayy/my_module.pyc")
- directory.add_file("bee/ccc/dee/eee.so")
- directory.add_file("eff/jee/aych.pyd")
-
- expected = {
- directory.root() + "/ayy",
- directory.root() + "/bee",
- directory.root() + "/bee/ccc",
- directory.root() + "/bee/ccc/dee",
- directory.root() + "/eff",
- directory.root() + "/eff/jee",
- }
- actual = namespace_pkgs.implicit_namespace_packages(directory.root())
- self.assertPathsEqual(actual, expected)
-
- def test_skips_ignored_directories(self):
- directory = TempDir()
- directory.add_file("foo/boo/my_module.py")
- directory.add_file("foo/bar/another_module.py")
-
- expected = {
- directory.root() + "/foo",
- directory.root() + "/foo/bar",
- }
- actual = namespace_pkgs.implicit_namespace_packages(
- directory.root(),
- ignored_dirnames=[directory.root() + "/foo/boo"],
- )
- self.assertPathsEqual(actual, expected)
-
-
-if __name__ == "__main__":
- unittest.main()
diff --git a/python/pip_install/tools/wheel_installer/wheel_installer_test.py b/python/pip_install/tools/wheel_installer/wheel_installer_test.py
deleted file mode 100644
index 74b9c30..0000000
--- a/python/pip_install/tools/wheel_installer/wheel_installer_test.py
+++ /dev/null
@@ -1,105 +0,0 @@
-# Copyright 2023 The Bazel Authors. All rights reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-import json
-import os
-import shutil
-import tempfile
-import unittest
-from pathlib import Path
-
-from python.pip_install.tools.wheel_installer import wheel, wheel_installer
-
-
-class TestRequirementExtrasParsing(unittest.TestCase):
- def test_parses_requirement_for_extra(self) -> None:
- cases = [
- ("name[foo]", ("name", frozenset(["foo"]))),
- ("name[ Foo123 ]", ("name", frozenset(["Foo123"]))),
- (" name1[ foo ] ", ("name1", frozenset(["foo"]))),
- ("Name[foo]", ("name", frozenset(["foo"]))),
- ("name_foo[bar]", ("name-foo", frozenset(["bar"]))),
- (
- "name [fred,bar] @ http://foo.com ; python_version=='2.7'",
- ("name", frozenset(["fred", "bar"])),
- ),
- (
- "name[quux, strange];python_version<'2.7' and platform_version=='2'",
- ("name", frozenset(["quux", "strange"])),
- ),
- (
- "name; (os_name=='a' or os_name=='b') and os_name=='c'",
- (None, None),
- ),
- (
- "name@http://foo.com",
- (None, None),
- ),
- ]
-
- for case, expected in cases:
- with self.subTest():
- self.assertTupleEqual(
- wheel_installer._parse_requirement_for_extra(case), expected
- )
-
-
-class TestWhlFilegroup(unittest.TestCase):
- def setUp(self) -> None:
- self.wheel_name = "example_minimal_package-0.0.1-py3-none-any.whl"
- self.wheel_dir = tempfile.mkdtemp()
- self.wheel_path = os.path.join(self.wheel_dir, self.wheel_name)
- shutil.copy(os.path.join("examples", "wheel", self.wheel_name), self.wheel_dir)
-
- def tearDown(self):
- shutil.rmtree(self.wheel_dir)
-
- def test_wheel_exists(self) -> None:
- wheel_installer._extract_wheel(
- Path(self.wheel_path),
- installation_dir=Path(self.wheel_dir),
- extras={},
- enable_implicit_namespace_pkgs=False,
- platforms=[],
- )
-
- want_files = [
- "metadata.json",
- "site-packages",
- self.wheel_name,
- ]
- self.assertEqual(
- sorted(want_files),
- sorted(
- [
- str(p.relative_to(self.wheel_dir))
- for p in Path(self.wheel_dir).glob("*")
- ]
- ),
- )
- with open("{}/metadata.json".format(self.wheel_dir)) as metadata_file:
- metadata_file_content = json.load(metadata_file)
-
- want = dict(
- version="0.0.1",
- name="example-minimal-package",
- deps=[],
- deps_by_platform={},
- entry_points=[],
- )
- self.assertEqual(want, metadata_file_content)
-
-
-if __name__ == "__main__":
- unittest.main()
diff --git a/python/pip_install/tools/wheel_installer/wheel_test.py b/python/pip_install/tools/wheel_installer/wheel_test.py
deleted file mode 100644
index 3ddfaf7..0000000
--- a/python/pip_install/tools/wheel_installer/wheel_test.py
+++ /dev/null
@@ -1,492 +0,0 @@
-import unittest
-from random import shuffle
-from unittest import mock
-
-from python.pip_install.tools.wheel_installer import wheel
-
-
-class DepsTest(unittest.TestCase):
- def test_simple(self):
- deps = wheel.Deps("foo", requires_dist=["bar"])
-
- got = deps.build()
-
- self.assertIsInstance(got, wheel.FrozenDeps)
- self.assertEqual(["bar"], got.deps)
- self.assertEqual({}, got.deps_select)
-
- def test_can_add_os_specific_deps(self):
- deps = wheel.Deps(
- "foo",
- requires_dist=[
- "bar",
- "an_osx_dep; sys_platform=='darwin'",
- "posix_dep; os_name=='posix'",
- "win_dep; os_name=='nt'",
- ],
- platforms={
- wheel.Platform(os=wheel.OS.linux, arch=wheel.Arch.x86_64),
- wheel.Platform(os=wheel.OS.osx, arch=wheel.Arch.x86_64),
- wheel.Platform(os=wheel.OS.osx, arch=wheel.Arch.aarch64),
- wheel.Platform(os=wheel.OS.windows, arch=wheel.Arch.x86_64),
- },
- )
-
- got = deps.build()
-
- self.assertEqual(["bar"], got.deps)
- self.assertEqual(
- {
- "@platforms//os:linux": ["posix_dep"],
- "@platforms//os:osx": ["an_osx_dep", "posix_dep"],
- "@platforms//os:windows": ["win_dep"],
- },
- got.deps_select,
- )
-
- def test_can_add_os_specific_deps_with_specific_python_version(self):
- deps = wheel.Deps(
- "foo",
- requires_dist=[
- "bar",
- "an_osx_dep; sys_platform=='darwin'",
- "posix_dep; os_name=='posix'",
- "win_dep; os_name=='nt'",
- ],
- platforms={
- wheel.Platform(
- os=wheel.OS.linux, arch=wheel.Arch.x86_64, minor_version=8
- ),
- wheel.Platform(
- os=wheel.OS.osx, arch=wheel.Arch.x86_64, minor_version=8
- ),
- wheel.Platform(
- os=wheel.OS.osx, arch=wheel.Arch.aarch64, minor_version=8
- ),
- wheel.Platform(
- os=wheel.OS.windows, arch=wheel.Arch.x86_64, minor_version=8
- ),
- },
- )
-
- got = deps.build()
-
- self.assertEqual(["bar"], got.deps)
- self.assertEqual(
- {
- "@platforms//os:linux": ["posix_dep"],
- "@platforms//os:osx": ["an_osx_dep", "posix_dep"],
- "@platforms//os:windows": ["win_dep"],
- },
- got.deps_select,
- )
-
- def test_deps_are_added_to_more_specialized_platforms(self):
- got = wheel.Deps(
- "foo",
- requires_dist=[
- "m1_dep; sys_platform=='darwin' and platform_machine=='arm64'",
- "mac_dep; sys_platform=='darwin'",
- ],
- platforms={
- wheel.Platform(os=wheel.OS.osx, arch=wheel.Arch.x86_64),
- wheel.Platform(os=wheel.OS.osx, arch=wheel.Arch.aarch64),
- },
- ).build()
-
- self.assertEqual(
- wheel.FrozenDeps(
- deps=[],
- deps_select={
- "osx_aarch64": ["m1_dep", "mac_dep"],
- "@platforms//os:osx": ["mac_dep"],
- },
- ),
- got,
- )
-
- def test_deps_from_more_specialized_platforms_are_propagated(self):
- got = wheel.Deps(
- "foo",
- requires_dist=[
- "a_mac_dep; sys_platform=='darwin'",
- "m1_dep; sys_platform=='darwin' and platform_machine=='arm64'",
- ],
- platforms={
- wheel.Platform(os=wheel.OS.osx, arch=wheel.Arch.x86_64),
- wheel.Platform(os=wheel.OS.osx, arch=wheel.Arch.aarch64),
- },
- ).build()
-
- self.assertEqual([], got.deps)
- self.assertEqual(
- {
- "osx_aarch64": ["a_mac_dep", "m1_dep"],
- "@platforms//os:osx": ["a_mac_dep"],
- },
- got.deps_select,
- )
-
- def test_non_platform_markers_are_added_to_common_deps(self):
- got = wheel.Deps(
- "foo",
- requires_dist=[
- "bar",
- "baz; implementation_name=='cpython'",
- "m1_dep; sys_platform=='darwin' and platform_machine=='arm64'",
- ],
- platforms={
- wheel.Platform(os=wheel.OS.linux, arch=wheel.Arch.x86_64),
- wheel.Platform(os=wheel.OS.osx, arch=wheel.Arch.x86_64),
- wheel.Platform(os=wheel.OS.osx, arch=wheel.Arch.aarch64),
- wheel.Platform(os=wheel.OS.windows, arch=wheel.Arch.x86_64),
- },
- ).build()
-
- self.assertEqual(["bar", "baz"], got.deps)
- self.assertEqual(
- {
- "osx_aarch64": ["m1_dep"],
- },
- got.deps_select,
- )
-
- def test_self_is_ignored(self):
- deps = wheel.Deps(
- "foo",
- requires_dist=[
- "bar",
- "req_dep; extra == 'requests'",
- "foo[requests]; extra == 'ssl'",
- "ssl_lib; extra == 'ssl'",
- ],
- extras={"ssl"},
- )
-
- got = deps.build()
-
- self.assertEqual(["bar", "req_dep", "ssl_lib"], got.deps)
- self.assertEqual({}, got.deps_select)
-
- def test_self_dependencies_can_come_in_any_order(self):
- deps = wheel.Deps(
- "foo",
- requires_dist=[
- "bar",
- "baz; extra == 'feat'",
- "foo[feat2]; extra == 'all'",
- "foo[feat]; extra == 'feat2'",
- "zdep; extra == 'all'",
- ],
- extras={"all"},
- )
-
- got = deps.build()
-
- self.assertEqual(["bar", "baz", "zdep"], got.deps)
- self.assertEqual({}, got.deps_select)
-
- def test_can_get_deps_based_on_specific_python_version(self):
- requires_dist = [
- "bar",
- "baz; python_version < '3.8'",
- "posix_dep; os_name=='posix' and python_version >= '3.8'",
- ]
-
- py38_deps = wheel.Deps(
- "foo",
- requires_dist=requires_dist,
- platforms=[
- wheel.Platform(
- os=wheel.OS.linux, arch=wheel.Arch.x86_64, minor_version=8
- ),
- ],
- ).build()
- py37_deps = wheel.Deps(
- "foo",
- requires_dist=requires_dist,
- platforms=[
- wheel.Platform(
- os=wheel.OS.linux, arch=wheel.Arch.x86_64, minor_version=7
- ),
- ],
- ).build()
-
- self.assertEqual(["bar", "baz"], py37_deps.deps)
- self.assertEqual({}, py37_deps.deps_select)
- self.assertEqual(["bar"], py38_deps.deps)
- self.assertEqual({"@platforms//os:linux": ["posix_dep"]}, py38_deps.deps_select)
-
- @mock.patch(
- "python.pip_install.tools.wheel_installer.wheel.host_interpreter_minor_version"
- )
- def test_can_get_version_select(self, mock_host_interpreter_version):
- requires_dist = [
- "bar",
- "baz; python_version < '3.8'",
- "baz_new; python_version >= '3.8'",
- "posix_dep; os_name=='posix'",
- "posix_dep_with_version; os_name=='posix' and python_version >= '3.8'",
- ]
- mock_host_interpreter_version.return_value = 7
-
- self.maxDiff = None
-
- deps = wheel.Deps(
- "foo",
- requires_dist=requires_dist,
- platforms=[
- wheel.Platform(os=os, arch=wheel.Arch.x86_64, minor_version=minor)
- for minor in [7, 8, 9]
- for os in [wheel.OS.linux, wheel.OS.windows]
- ],
- )
- got = deps.build()
-
- self.assertEqual(["bar"], got.deps)
- self.assertEqual(
- {
- "//conditions:default": ["baz"],
- "@//python/config_settings:is_python_3.7": ["baz"],
- "@//python/config_settings:is_python_3.8": ["baz_new"],
- "@//python/config_settings:is_python_3.9": ["baz_new"],
- "@platforms//os:linux": ["baz", "posix_dep"],
- "cp37_linux_anyarch": ["baz", "posix_dep"],
- "cp38_linux_anyarch": [
- "baz_new",
- "posix_dep",
- "posix_dep_with_version",
- ],
- "cp39_linux_anyarch": [
- "baz_new",
- "posix_dep",
- "posix_dep_with_version",
- ],
- },
- got.deps_select,
- )
-
- @mock.patch(
- "python.pip_install.tools.wheel_installer.wheel.host_interpreter_minor_version"
- )
- def test_deps_spanning_all_target_py_versions_are_added_to_common(
- self, mock_host_version
- ):
- requires_dist = [
- "bar",
- "baz (<2,>=1.11) ; python_version < '3.8'",
- "baz (<2,>=1.14) ; python_version >= '3.8'",
- ]
- mock_host_version.return_value = 8
-
- deps = wheel.Deps(
- "foo",
- requires_dist=requires_dist,
- platforms=wheel.Platform.from_string(["cp37_*", "cp38_*", "cp39_*"]),
- )
- got = deps.build()
-
- self.assertEqual(["bar", "baz"], got.deps)
- self.assertEqual({}, got.deps_select)
-
- @mock.patch(
- "python.pip_install.tools.wheel_installer.wheel.host_interpreter_minor_version"
- )
- def test_deps_are_not_duplicated(self, mock_host_version):
- mock_host_version.return_value = 7
-
- # See an example in
- # https://files.pythonhosted.org/packages/76/9e/db1c2d56c04b97981c06663384f45f28950a73d9acf840c4006d60d0a1ff/opencv_python-4.9.0.80-cp37-abi3-win32.whl.metadata
- requires_dist = [
- "bar >=0.1.0 ; python_version < '3.7'",
- "bar >=0.2.0 ; python_version >= '3.7'",
- "bar >=0.4.0 ; python_version >= '3.6' and platform_system == 'Linux' and platform_machine == 'aarch64'",
- "bar >=0.4.0 ; python_version >= '3.9'",
- "bar >=0.5.0 ; python_version <= '3.9' and platform_system == 'Darwin' and platform_machine == 'arm64'",
- "bar >=0.5.0 ; python_version >= '3.10' and platform_system == 'Darwin'",
- "bar >=0.5.0 ; python_version >= '3.10'",
- "bar >=0.6.0 ; python_version >= '3.11'",
- ]
-
- deps = wheel.Deps(
- "foo",
- requires_dist=requires_dist,
- platforms=wheel.Platform.from_string(["cp37_*", "cp310_*"]),
- )
- got = deps.build()
-
- self.assertEqual(["bar"], got.deps)
- self.assertEqual({}, got.deps_select)
-
- @mock.patch(
- "python.pip_install.tools.wheel_installer.wheel.host_interpreter_minor_version"
- )
- def test_deps_are_not_duplicated_when_encountering_platform_dep_first(
- self, mock_host_version
- ):
- mock_host_version.return_value = 7
-
- # Note, that we are sorting the incoming `requires_dist` and we need to ensure that we are not getting any
- # issues even if the platform-specific line comes first.
- requires_dist = [
- "bar >=0.4.0 ; python_version >= '3.6' and platform_system == 'Linux' and platform_machine == 'aarch64'",
- "bar >=0.5.0 ; python_version >= '3.9'",
- ]
-
- deps = wheel.Deps(
- "foo",
- requires_dist=requires_dist,
- platforms=wheel.Platform.from_string(["cp37_*", "cp310_*"]),
- )
- got = deps.build()
-
- self.assertEqual(["bar"], got.deps)
- self.assertEqual({}, got.deps_select)
-
-
-class MinorVersionTest(unittest.TestCase):
- def test_host(self):
- host = wheel.host_interpreter_minor_version()
- self.assertIsNotNone(host)
-
-
-class PlatformTest(unittest.TestCase):
- def test_can_get_host(self):
- host = wheel.Platform.host()
- self.assertIsNotNone(host)
- self.assertEqual(1, len(wheel.Platform.from_string("host")))
- self.assertEqual(host, wheel.Platform.from_string("host"))
-
- def test_can_get_linux_x86_64_without_py_version(self):
- got = wheel.Platform.from_string("linux_x86_64")
- want = wheel.Platform(os=wheel.OS.linux, arch=wheel.Arch.x86_64)
- self.assertEqual(want, got[0])
-
- def test_can_get_specific_from_string(self):
- got = wheel.Platform.from_string("cp33_linux_x86_64")
- want = wheel.Platform(
- os=wheel.OS.linux, arch=wheel.Arch.x86_64, minor_version=3
- )
- self.assertEqual(want, got[0])
-
- def test_can_get_all_for_py_version(self):
- cp39 = wheel.Platform.all(minor_version=9)
- self.assertEqual(18, len(cp39), f"Got {cp39}")
- self.assertEqual(cp39, wheel.Platform.from_string("cp39_*"))
-
- def test_can_get_all_for_os(self):
- linuxes = wheel.Platform.all(wheel.OS.linux, minor_version=9)
- self.assertEqual(6, len(linuxes))
- self.assertEqual(linuxes, wheel.Platform.from_string("cp39_linux_*"))
-
- def test_can_get_all_for_os_for_host_python(self):
- linuxes = wheel.Platform.all(wheel.OS.linux)
- self.assertEqual(6, len(linuxes))
- self.assertEqual(linuxes, wheel.Platform.from_string("linux_*"))
-
- def test_specific_version_specializations(self):
- any_py33 = wheel.Platform(minor_version=3)
-
- # When
- all_specializations = list(any_py33.all_specializations())
-
- want = (
- [any_py33]
- + [
- wheel.Platform(arch=arch, minor_version=any_py33.minor_version)
- for arch in wheel.Arch
- ]
- + [
- wheel.Platform(os=os, minor_version=any_py33.minor_version)
- for os in wheel.OS
- ]
- + wheel.Platform.all(minor_version=any_py33.minor_version)
- )
- self.assertEqual(want, all_specializations)
-
- def test_aarch64_specializations(self):
- any_aarch64 = wheel.Platform(arch=wheel.Arch.aarch64)
- all_specializations = list(any_aarch64.all_specializations())
- want = [
- wheel.Platform(os=None, arch=wheel.Arch.aarch64),
- wheel.Platform(os=wheel.OS.linux, arch=wheel.Arch.aarch64),
- wheel.Platform(os=wheel.OS.osx, arch=wheel.Arch.aarch64),
- wheel.Platform(os=wheel.OS.windows, arch=wheel.Arch.aarch64),
- ]
- self.assertEqual(want, all_specializations)
-
- def test_linux_specializations(self):
- any_linux = wheel.Platform(os=wheel.OS.linux)
- all_specializations = list(any_linux.all_specializations())
- want = [
- wheel.Platform(os=wheel.OS.linux, arch=None),
- wheel.Platform(os=wheel.OS.linux, arch=wheel.Arch.x86_64),
- wheel.Platform(os=wheel.OS.linux, arch=wheel.Arch.x86_32),
- wheel.Platform(os=wheel.OS.linux, arch=wheel.Arch.aarch64),
- wheel.Platform(os=wheel.OS.linux, arch=wheel.Arch.ppc),
- wheel.Platform(os=wheel.OS.linux, arch=wheel.Arch.s390x),
- wheel.Platform(os=wheel.OS.linux, arch=wheel.Arch.arm),
- ]
- self.assertEqual(want, all_specializations)
-
- def test_osx_specializations(self):
- any_osx = wheel.Platform(os=wheel.OS.osx)
- all_specializations = list(any_osx.all_specializations())
- # NOTE @aignas 2024-01-14: even though in practice we would only have
- # Python on osx aarch64 and osx x86_64, we return all arch posibilities
- # to make the code simpler.
- want = [
- wheel.Platform(os=wheel.OS.osx, arch=None),
- wheel.Platform(os=wheel.OS.osx, arch=wheel.Arch.x86_64),
- wheel.Platform(os=wheel.OS.osx, arch=wheel.Arch.x86_32),
- wheel.Platform(os=wheel.OS.osx, arch=wheel.Arch.aarch64),
- wheel.Platform(os=wheel.OS.osx, arch=wheel.Arch.ppc),
- wheel.Platform(os=wheel.OS.osx, arch=wheel.Arch.s390x),
- wheel.Platform(os=wheel.OS.osx, arch=wheel.Arch.arm),
- ]
- self.assertEqual(want, all_specializations)
-
- def test_platform_sort(self):
- platforms = [
- wheel.Platform(os=wheel.OS.linux, arch=None),
- wheel.Platform(os=wheel.OS.linux, arch=wheel.Arch.x86_64),
- wheel.Platform(os=wheel.OS.osx, arch=None),
- wheel.Platform(os=wheel.OS.osx, arch=wheel.Arch.x86_64),
- wheel.Platform(os=wheel.OS.osx, arch=wheel.Arch.aarch64),
- ]
- shuffle(platforms)
- platforms.sort()
- want = [
- wheel.Platform(os=wheel.OS.linux, arch=None),
- wheel.Platform(os=wheel.OS.linux, arch=wheel.Arch.x86_64),
- wheel.Platform(os=wheel.OS.osx, arch=None),
- wheel.Platform(os=wheel.OS.osx, arch=wheel.Arch.x86_64),
- wheel.Platform(os=wheel.OS.osx, arch=wheel.Arch.aarch64),
- ]
-
- self.assertEqual(want, platforms)
-
- def test_wheel_os_alias(self):
- self.assertEqual("osx", str(wheel.OS.osx))
- self.assertEqual(str(wheel.OS.darwin), str(wheel.OS.osx))
-
- def test_wheel_arch_alias(self):
- self.assertEqual("x86_64", str(wheel.Arch.x86_64))
- self.assertEqual(str(wheel.Arch.amd64), str(wheel.Arch.x86_64))
-
- def test_wheel_platform_alias(self):
- give = wheel.Platform(
- os=wheel.OS.darwin,
- arch=wheel.Arch.amd64,
- )
- alias = wheel.Platform(
- os=wheel.OS.osx,
- arch=wheel.Arch.x86_64,
- )
-
- self.assertEqual("osx_x86_64", str(give))
- self.assertEqual(str(alias), str(give))
-
-
-if __name__ == "__main__":
- unittest.main()
diff --git a/python/private/bzlmod/internal_deps.bzl b/python/private/bzlmod/internal_deps.bzl
index 62ca71f..e0eca9e 100644
--- a/python/private/bzlmod/internal_deps.bzl
+++ b/python/private/bzlmod/internal_deps.bzl
@@ -9,12 +9,12 @@
"Python toolchain module extension for internal rule use"
load("@bazel_skylib//lib:modules.bzl", "modules")
-load("//python/pip_install:repositories.bzl", "pip_install_dependencies")
load("//python/private:internal_config_repo.bzl", "internal_config_repo")
+load("//python/private/pypi:deps.bzl", "pypi_deps")
def _internal_deps():
internal_config_repo(name = "rules_python_internal")
- pip_install_dependencies()
+ pypi_deps()
internal_deps = modules.as_extension(
_internal_deps,
diff --git a/python/private/normalize_name.bzl b/python/private/normalize_name.bzl
index aaeca80..7898222 100644
--- a/python/private/normalize_name.bzl
+++ b/python/private/normalize_name.bzl
@@ -38,7 +38,6 @@
https://packaging.python.org/en/latest/specifications/name-normalization/
"""
-# Keep in sync with ../pip_install/tools/lib/bazel.py
def normalize_name(name):
"""normalize a PyPI package name and return a valid bazel label.
diff --git a/python/private/pypi/BUILD.bazel b/python/private/pypi/BUILD.bazel
index 1530837..e7ae735 100644
--- a/python/private/pypi/BUILD.bazel
+++ b/python/private/pypi/BUILD.bazel
@@ -21,7 +21,13 @@
filegroup(
name = "distribution",
- srcs = glob(["**"]),
+ srcs = glob(
+ ["**"],
+ exclude = ["requirements.txt"],
+ ) + [
+ "//python/private/pypi/dependency_resolver:distribution",
+ "//python/private/pypi/whl_installer:distribution",
+ ],
visibility = ["//python/private:__pkg__"],
)
@@ -29,7 +35,16 @@
filegroup(
name = "bzl",
srcs = glob(["**/*.bzl"]),
- visibility = ["//python/private:__pkg__"],
+ visibility = [
+ "//python/private:__pkg__",
+ "//tools/private:__pkg__",
+ ],
+)
+
+filegroup(
+ name = "requirements_txt",
+ srcs = ["requirements.txt"],
+ visibility = ["//tools/private/update_deps:__pkg__"],
)
# Keep sorted by library name and keep the files named by the main symbol they export
@@ -67,6 +82,14 @@
)
bzl_library(
+ name = "deps_bzl",
+ srcs = ["deps.bzl"],
+ deps = [
+ "//python/private:bazel_tools_bzl",
+ ],
+)
+
+bzl_library(
name = "flags_bzl",
srcs = ["flags.bzl"],
deps = ["//python/private:enum_bzl"],
@@ -119,6 +142,12 @@
)
bzl_library(
+ name = "multi_pip_parse_bzl",
+ srcs = ["multi_pip_parse.bzl"],
+ deps = ["pip_repository_bzl"],
+)
+
+bzl_library(
name = "package_annotation_bzl",
srcs = ["package_annotation.bzl"],
)
@@ -159,6 +188,15 @@
)
bzl_library(
+ name = "pip_compile_bzl",
+ srcs = ["pip_compile.bzl"],
+ deps = [
+ ":deps_bzl",
+ "//python:defs_bzl",
+ ],
+)
+
+bzl_library(
name = "pip_repository_bzl",
srcs = ["pip_repository.bzl"],
deps = [
@@ -204,17 +242,26 @@
)
bzl_library(
+ name = "whl_library_alias_bzl",
+ srcs = ["whl_library_alias.bzl"],
+ deps = [
+ ":render_pkg_aliases_bzl",
+ "//python/private:full_version_bzl",
+ ],
+)
+
+bzl_library(
name = "whl_library_bzl",
srcs = ["whl_library.bzl"],
deps = [
":attrs_bzl",
+ ":deps_bzl",
":generate_whl_library_build_bazel_bzl",
":parse_whl_name_bzl",
":patch_whl_bzl",
":whl_target_platforms_bzl",
"//python:repositories_bzl",
"//python:versions_bzl",
- "//python/pip_install:repositories_bzl",
"//python/private:auth_bzl",
"//python/private:envsubst_bzl",
"//python/private:repo_utils_bzl",
diff --git a/python/private/pypi/dependency_resolver/BUILD.bazel b/python/private/pypi/dependency_resolver/BUILD.bazel
new file mode 100644
index 0000000..9531b55
--- /dev/null
+++ b/python/private/pypi/dependency_resolver/BUILD.bazel
@@ -0,0 +1,7 @@
+exports_files(["dependency_resolver.py"])
+
+filegroup(
+ name = "distribution",
+ srcs = glob(["**"]),
+ visibility = ["//python/private/pypi:__subpackages__"],
+)
diff --git a/python/pip_install/tools/dependency_resolver/__init__.py b/python/private/pypi/dependency_resolver/__init__.py
similarity index 100%
rename from python/pip_install/tools/dependency_resolver/__init__.py
rename to python/private/pypi/dependency_resolver/__init__.py
diff --git a/python/pip_install/tools/dependency_resolver/dependency_resolver.py b/python/private/pypi/dependency_resolver/dependency_resolver.py
similarity index 100%
rename from python/pip_install/tools/dependency_resolver/dependency_resolver.py
rename to python/private/pypi/dependency_resolver/dependency_resolver.py
diff --git a/python/private/pypi/deps.bzl b/python/private/pypi/deps.bzl
new file mode 100644
index 0000000..81bef7a
--- /dev/null
+++ b/python/private/pypi/deps.bzl
@@ -0,0 +1,143 @@
+# Copyright 2023 The Bazel Authors. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+""
+
+load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
+load("@bazel_tools//tools/build_defs/repo:utils.bzl", "maybe")
+
+_RULE_DEPS = [
+ # START: maintained by 'bazel run //tools/private/update_deps:update_pip_deps'
+ (
+ "pypi__build",
+ "https://files.pythonhosted.org/packages/e2/03/f3c8ba0a6b6e30d7d18c40faab90807c9bb5e9a1e3b2fe2008af624a9c97/build-1.2.1-py3-none-any.whl",
+ "75e10f767a433d9a86e50d83f418e83efc18ede923ee5ff7df93b6cb0306c5d4",
+ ),
+ (
+ "pypi__click",
+ "https://files.pythonhosted.org/packages/00/2e/d53fa4befbf2cfa713304affc7ca780ce4fc1fd8710527771b58311a3229/click-8.1.7-py3-none-any.whl",
+ "ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28",
+ ),
+ (
+ "pypi__colorama",
+ "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl",
+ "4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6",
+ ),
+ (
+ "pypi__importlib_metadata",
+ "https://files.pythonhosted.org/packages/2d/0a/679461c511447ffaf176567d5c496d1de27cbe34a87df6677d7171b2fbd4/importlib_metadata-7.1.0-py3-none-any.whl",
+ "30962b96c0c223483ed6cc7280e7f0199feb01a0e40cfae4d4450fc6fab1f570",
+ ),
+ (
+ "pypi__installer",
+ "https://files.pythonhosted.org/packages/e5/ca/1172b6638d52f2d6caa2dd262ec4c811ba59eee96d54a7701930726bce18/installer-0.7.0-py3-none-any.whl",
+ "05d1933f0a5ba7d8d6296bb6d5018e7c94fa473ceb10cf198a92ccea19c27b53",
+ ),
+ (
+ "pypi__more_itertools",
+ "https://files.pythonhosted.org/packages/50/e2/8e10e465ee3987bb7c9ab69efb91d867d93959095f4807db102d07995d94/more_itertools-10.2.0-py3-none-any.whl",
+ "686b06abe565edfab151cb8fd385a05651e1fdf8f0a14191e4439283421f8684",
+ ),
+ (
+ "pypi__packaging",
+ "https://files.pythonhosted.org/packages/49/df/1fceb2f8900f8639e278b056416d49134fb8d84c5942ffaa01ad34782422/packaging-24.0-py3-none-any.whl",
+ "2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5",
+ ),
+ (
+ "pypi__pep517",
+ "https://files.pythonhosted.org/packages/25/6e/ca4a5434eb0e502210f591b97537d322546e4833dcb4d470a48c375c5540/pep517-0.13.1-py3-none-any.whl",
+ "31b206f67165b3536dd577c5c3f1518e8fbaf38cbc57efff8369a392feff1721",
+ ),
+ (
+ "pypi__pip",
+ "https://files.pythonhosted.org/packages/8a/6a/19e9fe04fca059ccf770861c7d5721ab4c2aebc539889e97c7977528a53b/pip-24.0-py3-none-any.whl",
+ "ba0d021a166865d2265246961bec0152ff124de910c5cc39f1156ce3fa7c69dc",
+ ),
+ (
+ "pypi__pip_tools",
+ "https://files.pythonhosted.org/packages/0d/dc/38f4ce065e92c66f058ea7a368a9c5de4e702272b479c0992059f7693941/pip_tools-7.4.1-py3-none-any.whl",
+ "4c690e5fbae2f21e87843e89c26191f0d9454f362d8acdbd695716493ec8b3a9",
+ ),
+ (
+ "pypi__pyproject_hooks",
+ "https://files.pythonhosted.org/packages/ae/f3/431b9d5fe7d14af7a32340792ef43b8a714e7726f1d7b69cc4e8e7a3f1d7/pyproject_hooks-1.1.0-py3-none-any.whl",
+ "7ceeefe9aec63a1064c18d939bdc3adf2d8aa1988a510afec15151578b232aa2",
+ ),
+ (
+ "pypi__setuptools",
+ "https://files.pythonhosted.org/packages/de/88/70c5767a0e43eb4451c2200f07d042a4bcd7639276003a9c54a68cfcc1f8/setuptools-70.0.0-py3-none-any.whl",
+ "54faa7f2e8d2d11bcd2c07bed282eef1046b5c080d1c32add737d7b5817b1ad4",
+ ),
+ (
+ "pypi__tomli",
+ "https://files.pythonhosted.org/packages/97/75/10a9ebee3fd790d20926a90a2547f0bf78f371b2f13aa822c759680ca7b9/tomli-2.0.1-py3-none-any.whl",
+ "939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc",
+ ),
+ (
+ "pypi__wheel",
+ "https://files.pythonhosted.org/packages/7d/cd/d7460c9a869b16c3dd4e1e403cce337df165368c71d6af229a74699622ce/wheel-0.43.0-py3-none-any.whl",
+ "55c570405f142630c6b9f72fe09d9b67cf1477fcf543ae5b8dcb1f5b7377da81",
+ ),
+ (
+ "pypi__zipp",
+ "https://files.pythonhosted.org/packages/da/55/a03fd7240714916507e1fcf7ae355bd9d9ed2e6db492595f1a67f61681be/zipp-3.18.2-py3-none-any.whl",
+ "dce197b859eb796242b0622af1b8beb0a722d52aa2f57133ead08edd5bf5374e",
+ ),
+ # END: maintained by 'bazel run //tools/private/update_deps:update_pip_deps'
+]
+
+_GENERIC_WHEEL = """\
+package(default_visibility = ["//visibility:public"])
+
+load("@rules_python//python:defs.bzl", "py_library")
+
+py_library(
+ name = "lib",
+ srcs = glob(["**/*.py"]),
+ data = glob(["**/*"], exclude=[
+ # These entries include those put into user-installed dependencies by
+ # data_exclude to avoid non-determinism.
+ "**/*.py",
+ "**/*.pyc",
+ "**/*.pyc.*", # During pyc creation, temp files named *.pyc.NNN are created
+ "**/* *",
+ "**/*.dist-info/RECORD",
+ "BUILD",
+ "WORKSPACE",
+ ]),
+ # This makes this directory a top-level in the python import
+ # search path for anything that depends on this.
+ imports = ["."],
+)
+"""
+
+# Collate all the repository names so they can be easily consumed
+all_requirements = [name for (name, _, _) in _RULE_DEPS]
+
+def requirement(pkg):
+ return Label("@pypi__" + pkg + "//:lib")
+
+def pypi_deps():
+ """
+ Fetch dependencies these rules depend on. Workspaces that use the pip_parse rule can call this.
+ """
+ for (name, url, sha256) in _RULE_DEPS:
+ maybe(
+ http_archive,
+ name,
+ url = url,
+ sha256 = sha256,
+ type = "zip",
+ build_file_content = _GENERIC_WHEEL,
+ )
diff --git a/python/private/pypi/multi_pip_parse.bzl b/python/private/pypi/multi_pip_parse.bzl
new file mode 100644
index 0000000..fe9e2db
--- /dev/null
+++ b/python/private/pypi/multi_pip_parse.bzl
@@ -0,0 +1,160 @@
+# Copyright 2024 The Bazel Authors. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""A pip_parse implementation for version aware toolchains in WORKSPACE."""
+
+load(":pip_repository.bzl", pip_parse = "pip_repository")
+
+def _multi_pip_parse_impl(rctx):
+ rules_python = rctx.attr._rules_python_workspace.workspace_name
+ load_statements = []
+ install_deps_calls = []
+ process_requirements_calls = []
+ for python_version, pypi_repository in rctx.attr.pip_parses.items():
+ sanitized_python_version = python_version.replace(".", "_")
+ load_statement = """\
+load(
+ "@{pypi_repository}//:requirements.bzl",
+ _{sanitized_python_version}_install_deps = "install_deps",
+ _{sanitized_python_version}_all_requirements = "all_requirements",
+)""".format(
+ pypi_repository = pypi_repository,
+ sanitized_python_version = sanitized_python_version,
+ )
+ load_statements.append(load_statement)
+ process_requirements_call = """\
+_process_requirements(
+ pkg_labels = _{sanitized_python_version}_all_requirements,
+ python_version = "{python_version}",
+ repo_prefix = "{pypi_repository}_",
+)""".format(
+ pypi_repository = pypi_repository,
+ python_version = python_version,
+ sanitized_python_version = sanitized_python_version,
+ )
+ process_requirements_calls.append(process_requirements_call)
+ install_deps_call = """ _{sanitized_python_version}_install_deps(**whl_library_kwargs)""".format(
+ sanitized_python_version = sanitized_python_version,
+ )
+ install_deps_calls.append(install_deps_call)
+
+ # NOTE @aignas 2023-10-31: I am not sure it is possible to render aliases
+ # for all of the packages using the `render_pkg_aliases` function because
+ # we need to know what the list of packages for each version is and then
+ # we would be creating directories for each.
+ macro_tmpl = "@%s_{}//:{}" % rctx.attr.name
+
+ requirements_bzl = """\
+# Generated by python/pip.bzl
+
+load("@{rules_python}//python:pip.bzl", "whl_library_alias", "pip_utils")
+{load_statements}
+
+_wheel_names = []
+_version_map = dict()
+def _process_requirements(pkg_labels, python_version, repo_prefix):
+ for pkg_label in pkg_labels:
+ wheel_name = Label(pkg_label).package
+ if not wheel_name:
+ # We are dealing with the cases where we don't have aliases.
+ workspace_name = Label(pkg_label).workspace_name
+ wheel_name = workspace_name[len(repo_prefix):]
+
+ _wheel_names.append(wheel_name)
+ if not wheel_name in _version_map:
+ _version_map[wheel_name] = dict()
+ _version_map[wheel_name][python_version] = repo_prefix
+
+{process_requirements_calls}
+
+def requirement(name):
+ return "{macro_tmpl}".format(pip_utils.normalize_name(name), "pkg")
+
+def whl_requirement(name):
+ return "{macro_tmpl}".format(pip_utils.normalize_name(name), "whl")
+
+def data_requirement(name):
+ return "{macro_tmpl}".format(pip_utils.normalize_name(name), "data")
+
+def dist_info_requirement(name):
+ return "{macro_tmpl}".format(pip_utils.normalize_name(name), "dist_info")
+
+def install_deps(**whl_library_kwargs):
+{install_deps_calls}
+ for wheel_name in _wheel_names:
+ whl_library_alias(
+ name = "{name}_" + wheel_name,
+ wheel_name = wheel_name,
+ default_version = "{default_version}",
+ version_map = _version_map[wheel_name],
+ )
+""".format(
+ name = rctx.attr.name,
+ install_deps_calls = "\n".join(install_deps_calls),
+ load_statements = "\n".join(load_statements),
+ macro_tmpl = macro_tmpl,
+ process_requirements_calls = "\n".join(process_requirements_calls),
+ rules_python = rules_python,
+ default_version = rctx.attr.default_version,
+ )
+ rctx.file("requirements.bzl", requirements_bzl)
+ rctx.file("BUILD.bazel", "exports_files(['requirements.bzl'])")
+
+_multi_pip_parse = repository_rule(
+ _multi_pip_parse_impl,
+ attrs = {
+ "default_version": attr.string(),
+ "pip_parses": attr.string_dict(),
+ "_rules_python_workspace": attr.label(default = Label("//:WORKSPACE")),
+ },
+)
+
+def multi_pip_parse(name, default_version, python_versions, python_interpreter_target, requirements_lock, **kwargs):
+ """NOT INTENDED FOR DIRECT USE!
+
+ This is intended to be used by the multi_pip_parse implementation in the template of the
+ multi_toolchain_aliases repository rule.
+
+ Args:
+ name: the name of the multi_pip_parse repository.
+ default_version: the default Python version.
+ python_versions: all Python toolchain versions currently registered.
+ python_interpreter_target: a dictionary which keys are Python versions and values are resolved host interpreters.
+ requirements_lock: a dictionary which keys are Python versions and values are locked requirements files.
+ **kwargs: extra arguments passed to all wrapped pip_parse.
+
+ Returns:
+ The internal implementation of multi_pip_parse repository rule.
+ """
+ pip_parses = {}
+ for python_version in python_versions:
+ if not python_version in python_interpreter_target:
+ fail("Missing python_interpreter_target for Python version %s in '%s'" % (python_version, name))
+ if not python_version in requirements_lock:
+ fail("Missing requirements_lock for Python version %s in '%s'" % (python_version, name))
+
+ pip_parse_name = name + "_" + python_version.replace(".", "_")
+ pip_parse(
+ name = pip_parse_name,
+ python_interpreter_target = python_interpreter_target[python_version],
+ requirements_lock = requirements_lock[python_version],
+ **kwargs
+ )
+ pip_parses[python_version] = pip_parse_name
+
+ return _multi_pip_parse(
+ name = name,
+ default_version = default_version,
+ pip_parses = pip_parses,
+ )
diff --git a/python/private/pypi/pip_compile.bzl b/python/private/pypi/pip_compile.bzl
new file mode 100644
index 0000000..7389e72
--- /dev/null
+++ b/python/private/pypi/pip_compile.bzl
@@ -0,0 +1,167 @@
+# Copyright 2023 The Bazel Authors. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""
+Rules to verify and update pip-compile locked requirements.txt.
+
+NOTE @aignas 2024-06-23: We are using the implementation specific name here to
+make it possible to have multiple tools inside the `pypi` directory
+"""
+
+load("//python:defs.bzl", _py_binary = "py_binary", _py_test = "py_test")
+load(":deps.bzl", "requirement")
+
+def pip_compile(
+ name,
+ src = None,
+ extra_args = [],
+ extra_deps = [],
+ generate_hashes = True,
+ py_binary = _py_binary,
+ py_test = _py_test,
+ requirements_in = None,
+ requirements_txt = None,
+ requirements_darwin = None,
+ requirements_linux = None,
+ requirements_windows = None,
+ visibility = ["//visibility:private"],
+ tags = None,
+ **kwargs):
+ """Generates targets for managing pip dependencies with pip-compile.
+
+ By default this rules generates a filegroup named "[name]" which can be included in the data
+ of some other compile_pip_requirements rule that references these requirements
+ (e.g. with `-r ../other/requirements.txt`).
+
+ It also generates two targets for running pip-compile:
+
+ - validate with `bazel test [name]_test`
+ - update with `bazel run [name].update`
+
+ If you are using a version control system, the requirements.txt generated by this rule should
+ be checked into it to ensure that all developers/users have the same dependency versions.
+
+ Args:
+ name: base name for generated targets, typically "requirements".
+ src: file containing inputs to dependency resolution. If not specified,
+ defaults to `pyproject.toml`. Supported formats are:
+ * a requirements text file, usually named `requirements.in`
+ * A `.toml` file, where the `project.dependencies` list is used as per
+ [PEP621](https://peps.python.org/pep-0621/).
+ extra_args: passed to pip-compile.
+ extra_deps: extra dependencies passed to pip-compile.
+ generate_hashes: whether to put hashes in the requirements_txt file.
+ py_binary: the py_binary rule to be used.
+ py_test: the py_test rule to be used.
+ requirements_in: file expressing desired dependencies. Deprecated, use src instead.
+ requirements_txt: result of "compiling" the requirements.in file.
+ requirements_linux: File of linux specific resolve output to check validate if requirement.in has changes.
+ requirements_darwin: File of darwin specific resolve output to check validate if requirement.in has changes.
+ requirements_windows: File of windows specific resolve output to check validate if requirement.in has changes.
+ tags: tagging attribute common to all build rules, passed to both the _test and .update rules.
+ visibility: passed to both the _test and .update rules.
+ **kwargs: other bazel attributes passed to the "_test" rule.
+ """
+ if requirements_in and src:
+ fail("Only one of 'src' and 'requirements_in' attributes can be used")
+ else:
+ src = requirements_in or src or "pyproject.toml"
+
+ requirements_txt = name + ".txt" if requirements_txt == None else requirements_txt
+
+ # "Default" target produced by this macro
+ # Allow a compile_pip_requirements rule to include another one in the data
+ # for a requirements file that does `-r ../other/requirements.txt`
+ native.filegroup(
+ name = name,
+ srcs = kwargs.pop("data", []) + [requirements_txt],
+ visibility = visibility,
+ )
+
+ data = [name, requirements_txt, src] + [f for f in (requirements_linux, requirements_darwin, requirements_windows) if f != None]
+
+ # Use the Label constructor so this is expanded in the context of the file
+ # where it appears, which is to say, in @rules_python
+ pip_compile = Label("//python/private/pypi/dependency_resolver:dependency_resolver.py")
+
+ loc = "$(rlocationpath {})"
+
+ args = [
+ loc.format(src),
+ loc.format(requirements_txt),
+ "//%s:%s.update" % (native.package_name(), name),
+ "--resolver=backtracking",
+ "--allow-unsafe",
+ ]
+ if generate_hashes:
+ args.append("--generate-hashes")
+ if requirements_linux:
+ args.append("--requirements-linux={}".format(loc.format(requirements_linux)))
+ if requirements_darwin:
+ args.append("--requirements-darwin={}".format(loc.format(requirements_darwin)))
+ if requirements_windows:
+ args.append("--requirements-windows={}".format(loc.format(requirements_windows)))
+ args.extend(extra_args)
+
+ deps = [
+ requirement("build"),
+ requirement("click"),
+ requirement("colorama"),
+ requirement("importlib_metadata"),
+ requirement("more_itertools"),
+ requirement("packaging"),
+ requirement("pep517"),
+ requirement("pip"),
+ requirement("pip_tools"),
+ requirement("pyproject_hooks"),
+ requirement("setuptools"),
+ requirement("tomli"),
+ requirement("zipp"),
+ Label("//python/runfiles:runfiles"),
+ ] + extra_deps
+
+ tags = tags or []
+ tags.append("requires-network")
+ tags.append("no-remote-exec")
+ tags.append("no-sandbox")
+ attrs = {
+ "args": args,
+ "data": data,
+ "deps": deps,
+ "main": pip_compile,
+ "srcs": [pip_compile],
+ "tags": tags,
+ "visibility": visibility,
+ }
+
+ # cheap way to detect the bazel version
+ _bazel_version_4_or_greater = "propeller_optimize" in dir(native)
+
+ # Bazel 4.0 added the "env" attribute to py_test/py_binary
+ if _bazel_version_4_or_greater:
+ attrs["env"] = kwargs.pop("env", {})
+
+ py_binary(
+ name = name + ".update",
+ **attrs
+ )
+
+ timeout = kwargs.pop("timeout", "short")
+
+ py_test(
+ name = name + "_test",
+ timeout = timeout,
+ # kwargs could contain test-specific attributes like size or timeout
+ **dict(attrs, **kwargs)
+ )
diff --git a/python/pip_install/tools/requirements.txt b/python/private/pypi/requirements.txt
similarity index 100%
rename from python/pip_install/tools/requirements.txt
rename to python/private/pypi/requirements.txt
diff --git a/python/private/pypi/whl_installer/BUILD.bazel b/python/private/pypi/whl_installer/BUILD.bazel
new file mode 100644
index 0000000..58231ce
--- /dev/null
+++ b/python/private/pypi/whl_installer/BUILD.bazel
@@ -0,0 +1,36 @@
+load("//python:defs.bzl", "py_binary", "py_library")
+load("//python/private/pypi:deps.bzl", "requirement")
+
+py_library(
+ name = "lib",
+ srcs = [
+ "arguments.py",
+ "namespace_pkgs.py",
+ "wheel.py",
+ "wheel_installer.py",
+ ],
+ visibility = [
+ "//tests:__subpackages__",
+ "//third_party/rules_pycross/pycross/private:__subpackages__",
+ ],
+ deps = [
+ requirement("installer"),
+ requirement("pip"),
+ requirement("packaging"),
+ requirement("setuptools"),
+ ],
+)
+
+py_binary(
+ name = "wheel_installer",
+ srcs = [
+ "wheel_installer.py",
+ ],
+ deps = [":lib"],
+)
+
+filegroup(
+ name = "distribution",
+ srcs = glob(["*"]),
+ visibility = ["//python/private/pypi:__subpackages__"],
+)
diff --git a/python/pip_install/tools/wheel_installer/arguments.py b/python/private/pypi/whl_installer/arguments.py
similarity index 97%
rename from python/pip_install/tools/wheel_installer/arguments.py
rename to python/private/pypi/whl_installer/arguments.py
index 71133c2..173d3a3 100644
--- a/python/pip_install/tools/wheel_installer/arguments.py
+++ b/python/private/pypi/whl_installer/arguments.py
@@ -17,7 +17,7 @@
import pathlib
from typing import Any, Dict, Set
-from python.pip_install.tools.wheel_installer import wheel
+from python.private.pypi.whl_installer import wheel
def parser(**kwargs: Any) -> argparse.ArgumentParser:
diff --git a/python/pip_install/tools/wheel_installer/namespace_pkgs.py b/python/private/pypi/whl_installer/namespace_pkgs.py
similarity index 100%
rename from python/pip_install/tools/wheel_installer/namespace_pkgs.py
rename to python/private/pypi/whl_installer/namespace_pkgs.py
diff --git a/python/pip_install/tools/wheel_installer/wheel.py b/python/private/pypi/whl_installer/wheel.py
similarity index 100%
rename from python/pip_install/tools/wheel_installer/wheel.py
rename to python/private/pypi/whl_installer/wheel.py
diff --git a/python/pip_install/tools/wheel_installer/wheel_installer.py b/python/private/pypi/whl_installer/wheel_installer.py
similarity index 98%
rename from python/pip_install/tools/wheel_installer/wheel_installer.py
rename to python/private/pypi/whl_installer/wheel_installer.py
index 801ef95..ef8181c 100644
--- a/python/pip_install/tools/wheel_installer/wheel_installer.py
+++ b/python/private/pypi/whl_installer/wheel_installer.py
@@ -27,7 +27,7 @@
from pip._vendor.packaging.utils import canonicalize_name
-from python.pip_install.tools.wheel_installer import arguments, namespace_pkgs, wheel
+from python.private.pypi.whl_installer import arguments, namespace_pkgs, wheel
def _configure_reproducible_wheels() -> None:
diff --git a/python/private/pypi/whl_library.bzl b/python/private/pypi/whl_library.bzl
index cae0db3..77cbd4e 100644
--- a/python/private/pypi/whl_library.bzl
+++ b/python/private/pypi/whl_library.bzl
@@ -16,12 +16,12 @@
load("//python:repositories.bzl", "is_standalone_interpreter")
load("//python:versions.bzl", "WINDOWS_NAME")
-load("//python/pip_install:repositories.bzl", "all_requirements")
load("//python/private:auth.bzl", "AUTH_ATTRS", "get_auth")
load("//python/private:envsubst.bzl", "envsubst")
load("//python/private:repo_utils.bzl", "REPO_DEBUG_ENV_VAR", "repo_utils")
load("//python/private:toolchains_repo.bzl", "get_host_os_arch")
load(":attrs.bzl", "ATTRS", "use_isolated")
+load(":deps.bzl", "all_requirements")
load(":generate_whl_library_build_bazel.bzl", "generate_whl_library_build_bazel")
load(":parse_whl_name.bzl", "parse_whl_name")
load(":patch_whl.bzl", "patch_whl")
@@ -241,7 +241,7 @@
args = [
python_interpreter,
"-m",
- "python.pip_install.tools.wheel_installer.wheel_installer",
+ "python.private.pypi.whl_installer.wheel_installer",
"--requirement",
rctx.attr.requirement,
]
diff --git a/python/private/pypi/whl_library_alias.bzl b/python/private/pypi/whl_library_alias.bzl
new file mode 100644
index 0000000..263d7ec
--- /dev/null
+++ b/python/private/pypi/whl_library_alias.bzl
@@ -0,0 +1,99 @@
+# Copyright 2024 The Bazel Authors. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""whl_library aliases for multi_pip_parse."""
+
+load("//python/private:full_version.bzl", "full_version")
+load(":render_pkg_aliases.bzl", "NO_MATCH_ERROR_MESSAGE_TEMPLATE")
+
+def _whl_library_alias_impl(rctx):
+ rules_python = rctx.attr._rules_python_workspace.workspace_name
+ if rctx.attr.default_version:
+ default_repo_prefix = rctx.attr.version_map[rctx.attr.default_version]
+ else:
+ default_repo_prefix = None
+ version_map = rctx.attr.version_map.items()
+ build_content = ["# Generated by python/pip.bzl"]
+ for alias_name in ["pkg", "whl", "data", "dist_info"]:
+ build_content.append(_whl_library_render_alias_target(
+ alias_name = alias_name,
+ default_repo_prefix = default_repo_prefix,
+ rules_python = rules_python,
+ version_map = version_map,
+ wheel_name = rctx.attr.wheel_name,
+ ))
+ rctx.file("BUILD.bazel", "\n".join(build_content))
+
+def _whl_library_render_alias_target(
+ alias_name,
+ default_repo_prefix,
+ rules_python,
+ version_map,
+ wheel_name):
+ alias = ["""\
+alias(
+ name = "{alias_name}",
+ actual = select({{""".format(alias_name = alias_name)]
+ for [python_version, repo_prefix] in version_map:
+ alias.append("""\
+ "@{rules_python}//python/config_settings:is_python_{full_python_version}": "{actual}",""".format(
+ full_python_version = full_version(python_version),
+ actual = "@{repo_prefix}{wheel_name}//:{alias_name}".format(
+ repo_prefix = repo_prefix,
+ wheel_name = wheel_name,
+ alias_name = alias_name,
+ ),
+ rules_python = rules_python,
+ ))
+ if default_repo_prefix:
+ default_actual = "@{repo_prefix}{wheel_name}//:{alias_name}".format(
+ repo_prefix = default_repo_prefix,
+ wheel_name = wheel_name,
+ alias_name = alias_name,
+ )
+ alias.append(' "//conditions:default": "{default_actual}",'.format(
+ default_actual = default_actual,
+ ))
+
+ alias.append(" },") # Close select expression condition dict
+ if not default_repo_prefix:
+ supported_versions = sorted([python_version for python_version, _ in version_map])
+ alias.append(' no_match_error="""{}""",'.format(
+ NO_MATCH_ERROR_MESSAGE_TEMPLATE.format(
+ supported_versions = ", ".join(supported_versions),
+ rules_python = rules_python,
+ ),
+ ))
+ alias.append(" ),") # Close the select expression
+ alias.append(' visibility = ["//visibility:public"],')
+ alias.append(")") # Close the alias() expression
+ return "\n".join(alias)
+
+whl_library_alias = repository_rule(
+ _whl_library_alias_impl,
+ attrs = {
+ "default_version": attr.string(
+ mandatory = False,
+ doc = "Optional Python version in major.minor format, e.g. '3.10'." +
+ "The Python version of the wheel to use when the versions " +
+ "from `version_map` don't match. This allows the default " +
+ "(version unaware) rules to match and select a wheel. If " +
+ "not specified, then the default rules won't be able to " +
+ "resolve a wheel and an error will occur.",
+ ),
+ "version_map": attr.string_dict(mandatory = True),
+ "wheel_name": attr.string(mandatory = True),
+ "_rules_python_workspace": attr.label(default = Label("//:WORKSPACE")),
+ },
+)
diff --git a/python/repositories.bzl b/python/repositories.bzl
index 245aae2..d58feef 100644
--- a/python/repositories.bzl
+++ b/python/repositories.bzl
@@ -19,7 +19,6 @@
load("@bazel_tools//tools/build_defs/repo:http.bzl", _http_archive = "http_archive")
load("@bazel_tools//tools/build_defs/repo:utils.bzl", "maybe")
-load("//python/pip_install:repositories.bzl", "pip_install_dependencies")
load("//python/private:auth.bzl", "get_auth")
load("//python/private:bzlmod_enabled.bzl", "BZLMOD_ENABLED")
load("//python/private:coverage_deps.bzl", "coverage_dep")
@@ -33,6 +32,7 @@
"toolchain_aliases",
"toolchains_repo",
)
+load("//python/private/pypi:deps.bzl", "pypi_deps")
load(
":versions.bzl",
"DEFAULT_RELEASE_BASE_URL",
@@ -68,7 +68,7 @@
sha256 = "2037875b9a4456dce4a79d112a8ae885bbc4aad968e6587dca6e64f3a0900cdf",
strip_prefix = "rules_cc-0.0.9",
)
- pip_install_dependencies()
+ pypi_deps()
########
# Remaining content of the file is only used to support toolchains.