Skip to content

Commit 2ab842d

Browse files
authored
refactor: starlark reimplementation of pip_repository (#1043)
Previously we were using pip_parse python scripts. This has a few drawbacks: * Requires system python to be present. * Usage of a Python script makes it harder to reason as there is an extra layer of abstraction. * Extending/reusing code between multi_pip_parse and pip_parse is hard. Now we use Starlark to parse the requirements.txt into requirements.bzl.
1 parent 64d9d6f commit 2ab842d

File tree

15 files changed

+257
-669
lines changed

15 files changed

+257
-669
lines changed

docs/pip.md

Lines changed: 1 addition & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/pip_repository.md

Lines changed: 26 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

examples/pip_parse_vendored/BUILD.bazel

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ genrule(
2020
# Replace the bazel 6.0.0 specific comment with something that bazel 5.4.0 would produce.
2121
# This enables this example to be run as a test under bazel 5.4.0.
2222
"""sed -e 's#@//#//#'""",
23-
"""tr "'" '"' """,
2423
"""sed 's#"@python39_.*//:bin/python3"#interpreter#' >$@""",
2524
]),
2625
)

examples/pip_parse_vendored/requirements.bzl

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,29 +14,20 @@ all_whl_requirements = ["@pip_certifi//:whl", "@pip_charset_normalizer//:whl", "
1414
_packages = [("pip_certifi", "certifi==2022.12.7 --hash=sha256:35824b4c3a97115964b408844d64aa14db1cc518f6562e8d7261699d1350a9e3 --hash=sha256:4ad3232f5e926d6718ec31cfc1fcadfde020920e278684144551c91769c7bc18"), ("pip_charset_normalizer", "charset-normalizer==2.1.1 --hash=sha256:5a3d016c7c547f69d6f81fb0db9449ce888b418b5b9952cc5e6e66843e9dd845 --hash=sha256:83e9a75d1911279afd89352c68b45348559d1fc0506b054b346651b5e7fee29f"), ("pip_idna", "idna==3.4 --hash=sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4 --hash=sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"), ("pip_requests", "requests==2.28.1 --hash=sha256:7c5599b102feddaa661c826c56ab4fee28bfd17f5abca1ebbe3e7f19d7c97983 --hash=sha256:8fefa2a1a1365bf5520aac41836fbee479da67864514bdb821f31ce07ce65349"), ("pip_urllib3", "urllib3==1.26.13 --hash=sha256:47cc05d99aaa09c9e72ed5809b60e7ba354e64b59c9c173ac3018642d8bb41fc --hash=sha256:c083dd0dce68dbfbe1129d5271cb90f9447dea7d52097c6e0126120c521ddea8")]
1515
_config = {"download_only": False, "enable_implicit_namespace_pkgs": False, "environment": {}, "extra_pip_args": [], "isolated": True, "pip_data_exclude": [], "python_interpreter": "python3", "python_interpreter_target": interpreter, "quiet": True, "repo": "pip", "repo_prefix": "pip_", "timeout": 600}
1616
_annotations = {}
17-
_bzlmod = False
1817

1918
def _clean_name(name):
2019
return name.replace("-", "_").replace(".", "_").lower()
2120

2221
def requirement(name):
23-
if _bzlmod:
24-
return "@@pip//:" + _clean_name(name) + "_pkg"
2522
return "@pip_" + _clean_name(name) + "//:pkg"
2623

2724
def whl_requirement(name):
28-
if _bzlmod:
29-
return "@@pip//:" + _clean_name(name) + "_whl"
3025
return "@pip_" + _clean_name(name) + "//:whl"
3126

3227
def data_requirement(name):
33-
if _bzlmod:
34-
return "@@pip//:" + _clean_name(name) + "_data"
3528
return "@pip_" + _clean_name(name) + "//:data"
3629

3730
def dist_info_requirement(name):
38-
if _bzlmod:
39-
return "@@pip//:" + _clean_name(name) + "_dist_info"
4031
return "@pip_" + _clean_name(name) + "//:dist_info"
4132

4233
def entry_point(pkg, script = None):
@@ -46,7 +37,7 @@ def entry_point(pkg, script = None):
4637

4738
def _get_annotation(requirement):
4839
# This expects to parse `setuptools==58.2.0 --hash=sha256:2551203ae6955b9876741a26ab3e767bb3242dafe86a32a749ea0d78b6792f11`
49-
# down wo `setuptools`.
40+
# down to `setuptools`.
5041
name = requirement.split(" ")[0].split("=")[0].split("[")[0]
5142
return _annotations.get(name)
5243

python/extensions.bzl

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,8 @@
1414

1515
"Module extensions for use with bzlmod"
1616

17-
load("@rules_python//python:pip.bzl", "pip_parse")
1817
load("@rules_python//python:repositories.bzl", "python_register_toolchains")
19-
load("@rules_python//python/pip_install:pip_repository.bzl", "locked_requirements_label", "pip_repository_attrs", "use_isolated", "whl_library")
18+
load("@rules_python//python/pip_install:pip_repository.bzl", "locked_requirements_label", "pip_repository_attrs", "pip_repository_bzlmod", "use_isolated", "whl_library")
2019
load("@rules_python//python/pip_install:repositories.bzl", "pip_install_dependencies")
2120
load("@rules_python//python/pip_install:requirements_parser.bzl", parse_requirements = "parse")
2221
load("@rules_python//python/private:coverage_deps.bzl", "install_coverage_deps")
@@ -68,22 +67,17 @@ def _pip_impl(module_ctx):
6867

6968
# Parse the requirements file directly in starlark to get the information
7069
# needed for the whl_libary declarations below. This is needed to contain
71-
# the pip_parse logic to a single module extension.
70+
# the pip_repository logic to a single module extension.
7271
requirements_lock_content = module_ctx.read(requrements_lock)
7372
parse_result = parse_requirements(requirements_lock_content)
7473
requirements = parse_result.requirements
7574
extra_pip_args = attr.extra_pip_args + parse_result.options
7675

7776
# Create the repository where users load the `requirement` macro. Under bzlmod
7877
# this does not create the install_deps() macro.
79-
pip_parse(
78+
pip_repository_bzlmod(
8079
name = attr.name,
8180
requirements_lock = attr.requirements_lock,
82-
bzlmod = True,
83-
timeout = attr.timeout,
84-
python_interpreter = attr.python_interpreter,
85-
python_interpreter_target = attr.python_interpreter_target,
86-
quiet = attr.quiet,
8781
)
8882

8983
for name, requirement_line in requirements:
@@ -114,7 +108,7 @@ def _pip_parse_ext_attrs():
114108
"name": attr.string(mandatory = True),
115109
}, **pip_repository_attrs)
116110

117-
# Like the pip_parse macro, we end up setting this manually so
111+
# Like the pip_repository rule, we end up setting this manually so
118112
# don't allow users to override it.
119113
attrs.pop("repo_prefix")
120114

python/pip.bzl

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ def pip_install(requirements = None, name = "pip", **kwargs):
4747
print("pip_install is deprecated. Please switch to pip_parse. pip_install will be removed in a future release.")
4848
pip_parse(requirements = requirements, name = name, **kwargs)
4949

50-
def pip_parse(requirements = None, requirements_lock = None, name = "pip_parsed_deps", bzlmod = False, **kwargs):
50+
def pip_parse(requirements = None, requirements_lock = None, name = "pip_parsed_deps", **kwargs):
5151
"""Accepts a locked/compiled requirements file and installs the dependencies listed within.
5252
5353
Those dependencies become available in a generated `requirements.bzl` file.
@@ -143,14 +143,9 @@ def pip_parse(requirements = None, requirements_lock = None, name = "pip_parsed_
143143
requirements (Label): Deprecated. See requirements_lock.
144144
name (str, optional): The name of the generated repository. The generated repositories
145145
containing each requirement will be of the form `<name>_<requirement-name>`.
146-
bzlmod (bool, optional): Whether this rule is being run under a bzlmod module extension.
147146
**kwargs (dict): Additional arguments to the [`pip_repository`](./pip_repository.md) repository rule.
148147
"""
149-
150-
# Don't try to fetch dependencies under bzlmod because they are already fetched via the internal_deps
151-
# module extention, and because the maybe-install pattern doesn't work under bzlmod.
152-
if not bzlmod:
153-
pip_install_dependencies()
148+
pip_install_dependencies()
154149

155150
# Temporary compatibility shim.
156151
# pip_install was previously document to use requirements while pip_parse was using requirements_lock.
@@ -160,8 +155,6 @@ def pip_parse(requirements = None, requirements_lock = None, name = "pip_parsed_
160155
pip_repository(
161156
name = name,
162157
requirements_lock = reqs_to_use,
163-
repo_prefix = "{}_".format(name),
164-
bzlmod = bzlmod,
165158
**kwargs
166159
)
167160

python/pip_install/BUILD.bazel

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ filegroup(
44
"BUILD.bazel",
55
"//python/pip_install/tools/dependency_resolver:distribution",
66
"//python/pip_install/tools/lib:distribution",
7-
"//python/pip_install/tools/lock_file_generator:distribution",
87
"//python/pip_install/tools/wheel_installer:distribution",
98
"//python/pip_install/private:distribution",
109
],
@@ -24,7 +23,6 @@ filegroup(
2423
srcs = [
2524
"//python/pip_install/tools/dependency_resolver:py_srcs",
2625
"//python/pip_install/tools/lib:py_srcs",
27-
"//python/pip_install/tools/lock_file_generator:py_srcs",
2826
"//python/pip_install/tools/wheel_installer:py_srcs",
2927
],
3028
visibility = ["//python/pip_install/private:__pkg__"],

0 commit comments

Comments
 (0)