Adds the "Requires-Python" metadata support. Fixes #378 (#379)
* Adds the "Requires-Python" metadata support. Fixes #378
This adds support for allowing people to specify which versions
of python a wheel should run on. This was added in PEP 440
* Move 'Requires-Python' to a conditional
* Add python test to check metadata
Co-authored-by: Alex Eagle <eagle@post.harvard.edu>
diff --git a/experimental/examples/wheel/BUILD b/experimental/examples/wheel/BUILD
index 06371fe..d721e4c 100644
--- a/experimental/examples/wheel/BUILD
+++ b/experimental/examples/wheel/BUILD
@@ -135,6 +135,17 @@
],
)
+py_wheel(
+ name = "python_requires_in_a_package",
+ distribution = "example_python_requires_in_a_package",
+ python_tag = "py3",
+ python_requires = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*",
+ version = "0.0.1",
+ deps = [
+ ":example_pkg",
+ ],
+)
+
py_test(
name = "wheel_test",
srcs = ["wheel_test.py"],
@@ -145,5 +156,6 @@
":customized",
":minimal_with_py_library",
":minimal_with_py_package",
+ ":python_requires_in_a_package"
],
)
diff --git a/experimental/examples/wheel/wheel_test.py b/experimental/examples/wheel/wheel_test.py
index 318367b..b392457 100644
--- a/experimental/examples/wheel/wheel_test.py
+++ b/experimental/examples/wheel/wheel_test.py
@@ -70,7 +70,8 @@
'example_customized-0.0.1.dist-info/WHEEL')
metadata_contents = zf.read(
'example_customized-0.0.1.dist-info/METADATA')
- entry_point_contents = zf.read('example_customized-0.0.1.dist-info/entry_points.txt')
+ entry_point_contents = zf.read(
+ 'example_customized-0.0.1.dist-info/entry_points.txt')
# The entries are guaranteed to be sorted.
self.assertEquals(record_contents, b"""\
example_customized-0.0.1.dist-info/METADATA,sha256=TeeEmokHE2NWjkaMcVJuSAq4_AXUoIad2-SLuquRmbg,372
@@ -162,6 +163,24 @@
'example_custom_package_root_multi_prefix_reverse_order-0.0.1.dist-info/METADATA',
'example_custom_package_root_multi_prefix_reverse_order-0.0.1.dist-info/RECORD'])
+ def test_python_requires_wheel(self):
+ filename = os.path.join(os.environ['TEST_SRCDIR'],
+ 'rules_python', 'experimental',
+ 'examples', 'wheel',
+ 'example_python_requires_in_a_package-0.0.1-py3-none-any.whl')
+ with zipfile.ZipFile(filename) as zf:
+ metadata_contents = zf.read(
+ 'example_python_requires_in_a_package-0.0.1.dist-info/METADATA')
+ # The entries are guaranteed to be sorted.
+ self.assertEquals(metadata_contents, b"""\
+Metadata-Version: 2.1
+Name: example_python_requires_in_a_package
+Version: 0.0.1
+Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*
+
+UNKNOWN
+""")
+
if __name__ == '__main__':
unittest.main()
diff --git a/experimental/python/wheel.bzl b/experimental/python/wheel.bzl
index 79cbc97..3de218f 100644
--- a/experimental/python/wheel.bzl
+++ b/experimental/python/wheel.bzl
@@ -110,6 +110,7 @@
args.add("--name", ctx.attr.distribution)
args.add("--version", ctx.attr.version)
args.add("--python_tag", ctx.attr.python_tag)
+ args.add("--python_requires", ctx.attr.python_requires)
args.add("--abi", ctx.attr.abi)
args.add("--platform", ctx.attr.platform)
args.add("--out", outfile.path)
@@ -249,6 +250,7 @@
"description_file": attr.label(allow_single_file = True),
"homepage": attr.string(default = ""),
"license": attr.string(default = ""),
+ "python_requires": attr.string(default = ""),
"strip_path_prefixes": attr.string_list(
default = [],
doc = "path prefixes to strip from files added to the generated package",
diff --git a/experimental/tools/wheelmaker.py b/experimental/tools/wheelmaker.py
index 38fb122..799eed7 100644
--- a/experimental/tools/wheelmaker.py
+++ b/experimental/tools/wheelmaker.py
@@ -129,8 +129,8 @@
wheel_contents += "Tag: %s\n" % tag
self.add_string(self.distinfo_path('WHEEL'), wheel_contents)
- def add_metadata(self, extra_headers, description, classifiers, requires,
- extra_requires):
+ def add_metadata(self, extra_headers, description, classifiers, python_requires,
+ requires, extra_requires):
"""Write METADATA file to the distribution."""
# https://www.python.org/dev/peps/pep-0566/
# https://packaging.python.org/specifications/core-metadata/
@@ -141,6 +141,8 @@
metadata.extend(extra_headers)
for classifier in classifiers:
metadata.append("Classifier: %s" % classifier)
+ if python_requires:
+ metadata.append("Requires-Python: %s" % python_requires)
for requirement in requires:
metadata.append("Requires-Dist: %s" % requirement)
@@ -225,6 +227,8 @@
wheel_group.add_argument('--classifier', action='append',
help="Classifiers to embed in package metadata. "
"Can be supplied multiple times")
+ wheel_group.add_argument('--python_requires',
+ help="Version of python that the wheel will work with")
wheel_group.add_argument('--description_file',
help="Path to the file with package description")
wheel_group.add_argument('--entry_points_file',
@@ -302,17 +306,20 @@
req, option = extra.rsplit(';', 1)
extra_requires[option].append(req)
classifiers = arguments.classifier or []
+ python_requires = arguments.python_requires or ""
requires = arguments.requires or []
extra_headers = arguments.header or []
maker.add_metadata(extra_headers=extra_headers,
description=description,
classifiers=classifiers,
+ python_requires=python_requires,
requires=requires,
extra_requires=extra_requires)
if arguments.entry_points_file:
- maker.add_file(maker.distinfo_path("entry_points.txt"), arguments.entry_points_file)
+ maker.add_file(maker.distinfo_path(
+ "entry_points.txt"), arguments.entry_points_file)
maker.add_recordfile()