9
9
from python .pip_install .extract_wheels .lib import (
10
10
annotation ,
11
11
namespace_pkgs ,
12
- purelib ,
13
12
wheel ,
14
13
)
15
14
21
20
22
21
23
22
def generate_entry_point_contents (
24
- entry_point : str , shebang : str = "#!/usr/bin/env python3"
23
+ module : str , attribute : str , shebang : str = "#!/usr/bin/env python3"
25
24
) -> str :
26
25
"""Generate the contents of an entry point script.
27
26
28
27
Args:
29
- entry_point (str): The name of the entry point as show in the
30
- `console_scripts` section of `entry_point.txt` .
28
+ module (str): The name of the module to use.
29
+ attribute (str): The name of the attribute to call .
31
30
shebang (str, optional): The shebang to use for the entry point python
32
31
file.
33
32
34
33
Returns:
35
34
str: A string of python code.
36
35
"""
37
- module , method = entry_point .split (":" , 1 )
38
36
return textwrap .dedent (
39
37
"""\
40
38
{shebang}
41
39
import sys
42
- from {module} import {method }
40
+ from {module} import {attribute }
43
41
if __name__ == "__main__":
44
- sys.exit({method }())
42
+ sys.exit({attribute }())
45
43
""" .format (
46
- shebang = shebang , module = module , method = method
44
+ shebang = shebang , module = module , attribute = attribute
47
45
)
48
46
)
49
47
50
48
51
- def generate_entry_point_rule (script : str , pkg : str ) -> str :
49
+ def generate_entry_point_rule (name : str , script : str , pkg : str ) -> str :
52
50
"""Generate a Bazel `py_binary` rule for an entry point script.
53
51
54
52
Note that the script is used to determine the name of the target. The name of
55
53
entry point targets should be uniuqe to avoid conflicts with existing sources or
56
54
directories within a wheel.
57
55
58
56
Args:
57
+ name (str): The name of the generated py_binary.
59
58
script (str): The path to the entry point's python file.
60
59
pkg (str): The package owning the entry point. This is expected to
61
60
match up with the `py_library` defined for each repository.
@@ -64,7 +63,6 @@ def generate_entry_point_rule(script: str, pkg: str) -> str:
64
63
Returns:
65
64
str: A `py_binary` instantiation.
66
65
"""
67
- name = os .path .splitext (script )[0 ]
68
66
return textwrap .dedent (
69
67
"""\
70
68
py_binary(
@@ -138,27 +136,18 @@ def generate_build_file_contents(
138
136
there may be no Python sources whatsoever (e.g. packages written in Cython: like `pymssql`).
139
137
"""
140
138
141
- dist_info_ignores = [
142
- # RECORD is known to contain sha256 checksums of files which might include the checksums
143
- # of generated files produced when wheels are installed. The file is ignored to avoid
144
- # Bazel caching issues.
145
- "**/*.dist-info/RECORD" ,
146
- ]
147
-
148
139
data_exclude = list (
149
140
set (
150
141
[
151
- "*.whl" ,
152
- "**/__pycache__/**" ,
153
142
"**/* *" ,
154
143
"**/*.py" ,
155
144
"**/*.pyc" ,
156
- "BUILD.bazel" ,
157
- "WORKSPACE" ,
158
- f"{ WHEEL_ENTRY_POINT_PREFIX } *.py" ,
145
+ # RECORD is known to contain sha256 checksums of files which might include the checksums
146
+ # of generated files produced when wheels are installed. The file is ignored to avoid
147
+ # Bazel caching issues.
148
+ "**/*.dist-info/RECORD" ,
159
149
]
160
150
+ data_exclude
161
- + dist_info_ignores
162
151
)
163
152
)
164
153
@@ -173,12 +162,12 @@ def generate_build_file_contents(
173
162
174
163
filegroup(
175
164
name = "{dist_info_label}",
176
- srcs = glob(["*.dist-info/**"], allow_empty = True),
165
+ srcs = glob(["site-packages/ *.dist-info/**"], allow_empty = True),
177
166
)
178
167
179
168
filegroup(
180
169
name = "{data_label}",
181
- srcs = glob(["*. data/**"], allow_empty = True),
170
+ srcs = glob(["data/**"], allow_empty = True),
182
171
)
183
172
184
173
filegroup(
@@ -189,11 +178,11 @@ def generate_build_file_contents(
189
178
190
179
py_library(
191
180
name = "{name}",
192
- srcs = glob(["**/*.py"], exclude={srcs_exclude}, allow_empty = True),
193
- data = {data} + glob(["**/*"], exclude={data_exclude}),
181
+ srcs = glob(["site-packages/ **/*.py"], exclude={srcs_exclude}, allow_empty = True),
182
+ data = {data} + glob(["site-packages/ **/*"], exclude={data_exclude}),
194
183
# This makes this directory a top-level in the python import
195
184
# search path for anything that depends on this.
196
- imports = [". "],
185
+ imports = ["site-packages "],
197
186
deps = [{dependencies}],
198
187
tags = [{tags}],
199
188
)
@@ -378,9 +367,6 @@ def extract_wheel(
378
367
shutil .copy (whl .path , directory )
379
368
whl .unzip (directory )
380
369
381
- # Note: Order of operations matters here
382
- purelib .spread_purelib_into_root (directory )
383
-
384
370
if not enable_implicit_namespace_pkgs :
385
371
setup_namespace_pkg_compatibility (directory )
386
372
@@ -408,14 +394,19 @@ def extract_wheel(
408
394
409
395
directory_path = Path (directory )
410
396
entry_points = []
411
- for name , entry_point in sorted (whl .entry_points ().items ()):
412
- entry_point_script = f"{ WHEEL_ENTRY_POINT_PREFIX } _{ name } .py"
413
- (directory_path / entry_point_script ).write_text (
414
- generate_entry_point_contents (entry_point )
397
+ for name , (module , attribute ) in sorted (whl .entry_points ().items ()):
398
+ # There is an extreme edge-case with entry_points that end with `.py`
399
+ # See: https://github.com/bazelbuild/bazel/blob/09c621e4cf5b968f4c6cdf905ab142d5961f9ddc/src/test/java/com/google/devtools/build/lib/rules/python/PyBinaryConfiguredTargetTest.java#L174
400
+ entry_point_without_py = name [:- 3 ] if name .endswith (".py" ) else name
401
+ entry_point_target_name = f"{ WHEEL_ENTRY_POINT_PREFIX } _{ entry_point_without_py } "
402
+ entry_point_script_name = f"{ entry_point_target_name } .py"
403
+ (directory_path / entry_point_script_name ).write_text (
404
+ generate_entry_point_contents (module , attribute )
415
405
)
416
406
entry_points .append (
417
407
generate_entry_point_rule (
418
- entry_point_script ,
408
+ entry_point_target_name ,
409
+ entry_point_script_name ,
419
410
library_name ,
420
411
)
421
412
)
@@ -449,7 +440,7 @@ def extract_wheel(
449
440
data_exclude = data_exclude ,
450
441
data = data ,
451
442
srcs_exclude = srcs_exclude ,
452
- tags = ["pypi_name=" + whl .name , "pypi_version=" + whl .metadata . version ],
443
+ tags = ["pypi_name=" + whl .name , "pypi_version=" + whl .version ],
453
444
additional_content = additional_content ,
454
445
)
455
446
build_file .write (contents )
0 commit comments