10000 wheel: support for 'plugin' type entry_points (#349) · rahulmutt/rules_python@a8d133a · GitHub
[go: up one dir, main page]

Skip to content

Commit a8d133a

Browse files
authored
wheel: support for 'plugin' type entry_points (bazel-contrib#349)
* wheel: support for 'plugin' type entry_points See https://packaging.python.org/guides/creating-and-discovering-plugins/\#using-package-metadata
1 parent 29fb032 commit a8d133a

File tree

4 files changed

+58
-24
lines changed

4 files changed

+58
-24
lines changed

experimental/examples/wheel/BUILD

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,10 @@ py_wheel(
7777
description_file = "README.md",
7878
# Package data. We're building "example_customized-0.0.1-py3-none-any.whl"
7979
distribution = "example_customized",
80+
entry_points = {
81+
"console_scripts": ["another = foo.bar:baz"],
82+
"group2": ["second = second.main:s", "first = first.main:f"]
83+
},
8084
homepage = "www.example.com",
8185
license = "Apache 2.0",
8286
python_tag = "py3",

experimental/examples/wheel/wheel_test.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,12 +70,13 @@ def test_customized_wheel(self):
7070
'example_customized-0.0.1.dist-info/WHEEL')
7171
metadata_contents = zf.read(
7272
'example_customized-0.0.1.dist-info/METADATA')
73+
entry_point_contents = zf.read('example_customized-0.0.1.dist-info/entry_points.txt')
7374
# The entries are guaranteed to be sorted.
7475
self.assertEquals(record_contents, b"""\
7576
example_customized-0.0.1.dist-info/METADATA,sha256=TeeEmokHE2NWjkaMcVJuSAq4_AXUoIad2-SLuquRmbg,372
7677
example_customized-0.0.1.dist-info/RECORD,,
7778
example_customized-0.0.1.dist-info/WHEEL,sha256=F01lGfVCzcXUzzQHzUkBmXAcu_TXd5zqMLrvrspncJo,85
78-
example_customized-0.0.1.dist-info/entry_points.txt,sha256=olLJ8FK88aft2pcdj4BD05F8Xyz83Mo51I93tRGT2Yk,74
79+
example_customized-0.0.1.dist-info/entry_points.txt,sha256=mEWsq4sMoyqR807QV8Z3KPocGfKvtgTo1lBFTRb6b78,150
7980
experimental/examples/wheel/lib/data.txt,sha256=9vJKEdfLu8bZRArKLroPZJh1XKkK3qFMXiM79MBL2Sg,12
8081
experimental/examples/wheel/lib/module_with_data.py,sha256=K_IGAq_CHcZX0HUyINpD1hqSKIEdCn58d9E9nhWF2EA,636
8182
experimental/examples/wheel/lib/simple_module.py,sha256=72-91Dm6NB_jw-7wYQt7shzdwvk5RB0LujIah8g7kr8,636
@@ -101,6 +102,14 @@ def test_customized_wheel(self):
101102
102103
This is a sample description of a wheel.
103104
""")
105+
self.assertEquals(entry_point_contents, b"""\
106+
[console_scripts]
107+
another = foo.bar:baz
108+
customized_wheel = experimental.examples.wheel.main:main
109+
110+
[group2]
111+
first = first.main:f
112+
second = second.main:s""")
104113

105114
def test_custom_package_root_wheel(self):
106115
filename = os.path.join(os.environ['TEST_SRCDIR'],

experimental/python/wheel.bzl

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -99,11 +99,11 @@ def _py_wheel_impl(ctx):
9999
other_inputs = []
100100

101101
# Wrap the inputs into a file to reduce command line length.
102-
packageinputfile = ctx.actions.declare_file(ctx.attr.name + '_target_wrapped_inputs.txt')
103-
content = ''
102+
packageinputfile = ctx.actions.declare_file(ctx.attr.name + "_target_wrapped_inputs.txt")
103+
content = ""
104104
for input_file in inputs_to_package.to_list():
105-
content += _input_file_to_arg(input_file) + '\n'
106-
ctx.actions.write(output = packageinputfile, content=content)
105+
content += _input_file_to_arg(input_file) + "\n"
106+
ctx.actions.write(output = packageinputfile, content = content)
107107
other_inputs.append(packageinputfile)
108108

109109
args = ctx.actions.args()
@@ -140,8 +140,30 @@ def _py_wheel_impl(ctx):
140140
for r in requirements:
141141
args.add("--extra_requires", r + ";" + option)
142142

143-
for name, ref in ctx.attr.console_scripts.items():
144-
args.add("--console_script", name + " = " + ref)
143+
# Merge console_scripts into entry_points.
144+
entrypoints = dict(ctx.attr.entry_points) # Copy so we can mutate it
145+
if ctx.attr.console_scripts:
146+
# Copy a console_scripts group that may already exist, so we can mutate it.
147+
console_scripts = list(entrypoints.get("console_scripts", []))
148+
entrypoints["console_scripts"] = console_scripts
149+
for name, ref in ctx.attr.console_scripts.items():
150+
console_scripts.append("{name} = {ref}".format(name = name, ref = ref))
151+
152+
# If any entry_points are provided, construct the file here and add it to the files to be packaged.
153+
# see: https://packaging.python.org/specifications/entry-points/
154+
if entrypoints:
155+
lines = []
156+
for group, entries in sorted(entrypoints.items()):
157+
if lines:
158+
# Blank line between groups
159+
lines.append("")
160+
lines.append("[{group}]".format(group = group))
161+
lines += sorted(entries)
162+
entry_points_file = ctx.actions.declare_file(ctx.attr.name + "_entry_points.txt")
163+
content = "\n".join(lines)
164+
ctx.actions.write(output = entry_points_file, content = content)
165+
other_inputs.append(entry_points_file)
166+
args.add("--entry_points_file", entry_points_file)
145167

146168
if ctx.attr.description_file:
147169
description_file = ctx.file.description_file
@@ -208,7 +230,14 @@ _requirement_attrs = {
208230
_entrypoint_attrs = {
209231
"console_scripts": attr.string_dict(
210232
doc = """\
211-
console_script entry points, e.g. 'experimental.examples.wheel.main:main'.
233+
Deprecated console_script entry points, e.g. {'main': 'experimental.examples.wheel.main:main'}.
234+
235+
Deprecated: prefer the `entry_points` attribute, which supports `console_scripts` as well as other entry points.
236+
""",
237+
),
238+
"entry_points": attr.string_list_dict(
239+
doc = """\
240+
entry_points, e.g. {'console_scripts': ['main = experimental.examples.wheel.main:main']}.
212241
""",
213242
),
214243
}
@@ -281,7 +310,7 @@ Targets to be included in the distribution.
281310
The targets to package are usually `py_library` rules or filesets (for packaging data files).
282311
283312
Note it's usually better to package `py_library` targets and use
284-
`console_scripts` attribute to specify entry points than to package
313+
`entry_points` attribute to specify `console_scripts` than to package
285314
`py_binary` rules. `py_binary` targets would wrap a executable script that
286315
tries to locate `.runfiles` directory which is not packaged in the wheel.
287316
""",

experimental/rules_python/wheelmaker.py

Lines changed: 7 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ def add_string(self, filename, contents):
9292

9393
def add_file(self, package_filename, real_filename):
9494
"""Add given file to the distribution."""
95+
9596
def arcname_from(name):
9697
# Always use unix path separators.
9798
normalized_arcname = name.replace(os.path.sep, '/')
@@ -157,15 +158,6 @@ def add_metadata(self, extra_headers, description, classifiers, requires,
157158
metadata += "\n"
158159
self.add_string(self.distinfo_path('METADATA'), metadata)
159160

160-
def add_entry_points(self, console_scripts):
161-
"""Write entry_points.txt file to the distribution."""
162-
# https://packaging.python.org/specifications/entry-points/
163-
if not console_scripts:
164-
return
165-
lines = ["[console_scripts]"] + console_scripts
166-
contents = '\n'.join(lines)
167-
self.add_string(self.distinfo_path('entry_points.txt'), contents)
168-
169161
def add_recordfile(self):
170162
"""Write RECORD file to the distribution."""
171163
record_path = self.distinfo_path('RECORD')
@@ -235,6 +227,8 @@ def main():
235227
"Can be supplied multiple times")
236228
wheel_group.add_argument('--description_file',
237229
help="Path to the file with package description")
230+
wheel_group.add_argument('--entry_points_file',
231+
help="Path to a correctly-formatted entry_points.txt file")
238232

239233
contents_group = parser.add_argument_group("Wheel contents")
240234
contents_group.add_argument(
@@ -246,10 +240,6 @@ def main():
246240
'--input_file_list', action='append',
247241
help='A file that has all the input files defined as a list to avoid the long command'
248242
)
249-
contents_group.add_argument(
250-
'--console_script', action='append',
251-
help="Defines a 'console_script' entry point. "
252-
"Can be supplied multiple times.")
253243

254244
requirements_group = parser.add_argument_group("Package requirements")
255245
requirements_group.add_argument(
@@ -314,14 +304,16 @@ def main():
314304
classifiers = arguments.classifier or []
315305
requires = arguments.requires or []
316306
extra_headers = arguments.header or []
317-
console_scripts = arguments.console_script or []
318307

319308
maker.add_metadata(extra_headers=extra_headers,
320309
description=description,
321310
classifiers=classifiers,
322311
requires=requires,
323312
extra_requires=extra_requires)
324-
maker.add_entry_points(console_scripts=console_scripts)
313+
314+
if arguments.entry_points_file:
315+
maker.add_file(maker.distinfo_path("entry_points.txt"), arguments.entry_points_file)
316+
325317
maker.add_recordfile()
326318

327319

0 commit comments

Comments
 (0)
0