From e8bfb48f19a75ad46dc2ec7b78c88b73a9f62ab7 Mon Sep 17 00:00:00 2001 From: xmc Date: Mon, 14 Jan 2019 10:52:27 -0800 Subject: [PATCH 1/5] update doc for attr python_interpreter --- README.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 0a0540a17e..03bcf0b3ee 100644 --- a/README.md +++ b/README.md @@ -97,8 +97,16 @@ load("@rules_python//python:pip.bzl", "pip_import") # This rule translates the specified requirements.txt into # @my_deps//:requirements.bzl, which itself exposes a pip_install method. pip_import( - name = "my_deps", - requirements = "//path/to:requirements.txt", + name = "my_deps", + requirements = "//path/to:requirements.txt", +) + +# Python interpreter can be specify optionally to support customized version, +# such as "python3" or "python3.7" +pip_import( + name = "my_deps", + requirements = "//path/to:requirements.txt", + python_interpreter = 'python3.7', ) # Load the pip_install symbol for my_deps, and create the dependencies' From 79b923cb583873fa7e577623ee7ee86d02797c5d Mon Sep 17 00:00:00 2001 From: XMC Date: Mon, 14 Jan 2019 09:34:12 -0800 Subject: [PATCH 2/5] Add attr python_interpreter to pip.bzl/whl.bzl This commit also added --python_interpreter argument to piptool.py to support this attribute. Example usage: pip_import( name = 'pip_deps', requirements = '//:requirements.txt', python_interpreter = 'python3.7', ) --- packaging/piptool.py | 5 +++++ packaging/whl.py | 47 ++++++++++++++++++++++++++++++++++++++++---- python/pip.bzl | 5 ++++- python/whl.bzl | 3 ++- 4 files changed, 54 insertions(+), 6 deletions(-) diff --git a/packaging/piptool.py b/packaging/piptool.py index 2544032ee8..1689b7f13a 100644 --- a/packaging/piptool.py +++ b/packaging/piptool.py @@ -86,6 +86,9 @@ def pip_main(argv): parser = argparse.ArgumentParser( description='Import Python dependencies into Bazel.') +parser.add_argument('--python_interpreter', action='store', + help=('The python python interpreter to use ')) + parser.add_argument('--name', action='store', help=('The namespace of the import.')) @@ -177,10 +180,12 @@ def whl_library(wheel): if "{repo_name}" not in native.existing_rules(): whl_library( name = "{repo_name}", + python_interpreter = "{python_interpreter}", whl = "@{name}//:{path}", requirements = "@{name}//:requirements.bzl", extras = [{extras}] )""".format(name=args.name, repo_name=wheel.repository_name(), + python_interpreter=args.python_interpreter, path=wheel.basename(), extras=','.join([ '"%s"' % extra diff --git a/packaging/whl.py b/packaging/whl.py index 63a6d62b8f..fbbd9316e3 100644 --- a/packaging/whl.py +++ b/packaging/whl.py @@ -14,12 +14,17 @@ """The whl modules defines classes for interacting with Python packages.""" import argparse +import collections +import email.parser import json import os import pkg_resources import re import zipfile +EXTRA_RE = re.compile("""^(?P.*?)(;\s*(?P.*?)(extra == '(?P.*?)')?)$""") +MayRequiresKey = collections.namedtuple('MayRequiresKey', ('condition', 'extra')) + class Wheel(object): @@ -66,7 +71,7 @@ def metadata(self): pass # fall back to METADATA file (https://www.python.org/dev/peps/pep-0427/) with whl.open(self._dist_info() + '/METADATA') as f: - return self._parse_metadata(f.read().decode("utf-8")) + return self._parse_metadata(f) def name(self): return self.metadata().get('name') @@ -111,9 +116,43 @@ def expand(self, directory): # _parse_metadata parses METADATA files according to https://www.python.org/dev/peps/pep-0314/ def _parse_metadata(self, content): - # TODO: handle fields other than just name - name_pattern = re.compile('Name: (.*)') - return { 'name': name_pattern.search(content).group(1) } + metadata = {} + pkg_info = email.parser.Parser().parse(content) + metadata['name'] = pkg_info.get('Name') + extras = pkg_info.get_all('Provides-Extra') + if extras: + metadata['extras'] = list(set(extras)) + + reqs_dist = pkg_info.get_all('Requires-Dist') or [] + requires = collections.defaultdict(set) + for value in sorted(reqs_dist): + extra_match = EXTRA_RE.search(value) + if extra_match: + groupdict = extra_match.groupdict() + condition = groupdict['condition'] + extra = groupdict['extra'] + package = groupdict['package'] + if condition.endswith(' and '): + condition = condition[:-5] + else: + condition, extra = None, None + package = value + key = MayRequiresKey(condition, extra) + requires[key].add(package) + + if requires: + metadata['run_requires'] = [] + for key, value in requires.items(): + requirement = { + 'requires': list(value) + } + if key.extra: + requirement['extra'] = key.extra + if key.condition: + requirement['environment'] = key.condition + metadata['run_requires'].append(requirement) + + return metadata parser = argparse.ArgumentParser( diff --git a/python/pip.bzl b/python/pip.bzl index b69eb9366e..e0702c25f7 100644 --- a/python/pip.bzl +++ b/python/pip.bzl @@ -24,8 +24,10 @@ def _pip_import_impl(repository_ctx): # To see the output, pass: quiet=False result = repository_ctx.execute([ - "python", + repository_ctx.attr.python_interpreter, repository_ctx.path(repository_ctx.attr._script), + "--python_interpreter", + repository_ctx.attr.python_interpreter, "--name", repository_ctx.attr.name, "--input", @@ -41,6 +43,7 @@ def _pip_import_impl(repository_ctx): pip_import = repository_rule( attrs = { + "python_interpreter": attr.string(default="python"), "requirements": attr.label( mandatory = True, allow_single_file = True, diff --git a/python/whl.bzl b/python/whl.bzl index 3f869c29ec..2eebfee49f 100644 --- a/python/whl.bzl +++ b/python/whl.bzl @@ -17,7 +17,7 @@ def _whl_impl(repository_ctx): """Core implementation of whl_library.""" args = [ - "python", + repository_ctx.attr.python_interpreter, repository_ctx.path(repository_ctx.attr._script), "--whl", repository_ctx.path(repository_ctx.attr.whl), @@ -37,6 +37,7 @@ def _whl_impl(repository_ctx): whl_library = repository_rule( attrs = { + "python_interpreter": attr.string(default="python"), "whl": attr.label( mandatory = True, allow_single_file = True, From 5783ce3917ea0e19052f5cdaf76721feed30d5c9 Mon Sep 17 00:00:00 2001 From: Guillaume Pratte Date: Wed, 6 Nov 2019 12:47:21 -0500 Subject: [PATCH 3/5] Adjust whl.py for Python 2 and 3 --- packaging/whl.py | 10 ++++++++-- tools/piptool.par | Bin 5889389 -> 5895581 bytes tools/whltool.par | Bin 1396283 -> 1400027 bytes 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/packaging/whl.py b/packaging/whl.py index fbbd9316e3..7dd8845ea7 100644 --- a/packaging/whl.py +++ b/packaging/whl.py @@ -21,6 +21,7 @@ import pkg_resources import re import zipfile +import sys EXTRA_RE = re.compile("""^(?P.*?)(;\s*(?P.*?)(extra == '(?P.*?)')?)$""") MayRequiresKey = collections.namedtuple('MayRequiresKey', ('condition', 'extra')) @@ -49,7 +50,7 @@ def version(self): def repository_name(self): # Returns the canonical name of the Bazel repository for this package. - canonical = 'pypi__{}_{}'.format(self.distribution(), self.version()) + canonical = 'pypi__py{}__{}_{}'.format(sys.version_info.major, self.distribution(), self.version()) # Escape any illegal characters with underscore. return re.sub('[-.+]', '_', canonical) @@ -117,7 +118,12 @@ def expand(self, directory): # _parse_metadata parses METADATA files according to https://www.python.org/dev/peps/pep-0314/ def _parse_metadata(self, content): metadata = {} - pkg_info = email.parser.Parser().parse(content) + content_str = content.read() + try: + pkg_info = email.parser.Parser().parsestr(content_str) + except: + pkg_info = email.parser.BytesParser().parsebytes(content_str) + metadata['name'] = pkg_info.get('Name') extras = pkg_info.get_all('Provides-Extra') if extras: diff --git a/tools/piptool.par b/tools/piptool.par index f0e0f224e58ee789bf99f2e583a0120536a9d52d..4c658f88719e931d24b3645ff71e80c5e87ee446 100755 GIT binary patch delta 31758 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 SXnR$%n?}8YlJ=00;r{@;d4`|> delta 26877 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 N4Z#lp5=&V4_FpCciQ@nO delta 6212 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 From 1f367c8779a480b1719b358f161e9a9142d7aa50 Mon Sep 17 00:00:00 2001 From: Guillaume Pratte Date: Thu, 13 Jun 2019 14:18:16 -0400 Subject: [PATCH 4/5] Set quiet=False to see pip's output --- python/pip.bzl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/pip.bzl b/python/pip.bzl index e0702c25f7..8554386997 100644 --- a/python/pip.bzl +++ b/python/pip.bzl @@ -36,7 +36,7 @@ def _pip_import_impl(repository_ctx): repository_ctx.path("requirements.bzl"), "--directory", repository_ctx.path(""), - ]) + ], quiet=False) if result.return_code: fail("pip_import failed: %s (%s)" % (result.stdout, result.stderr)) From e6d0f1b195d5b367d4b1f1a944d114b0fa6d7434 Mon Sep 17 00:00:00 2001 From: Andrew Dunham Date: Wed, 4 Mar 2020 09:01:26 -0800 Subject: [PATCH 5/5] packaging/piptool: sort wheels and extras for deterministic output (#279) --- packaging/piptool.py | 10 ++++++++-- tools/piptool.par | Bin 5895581 -> 5897301 bytes tools/whltool.par | Bin 1400027 -> 1401409 bytes 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/packaging/piptool.py b/packaging/piptool.py index 1689b7f13a..9fef4c7ece 100644 --- a/packaging/piptool.py +++ b/packaging/piptool.py @@ -101,6 +101,12 @@ def pip_main(argv): parser.add_argument('--directory', action='store', help=('The directory into which to put .whl files.')) + +def sort_wheels(whls): + """Sorts a list of wheels deterministically.""" + return sorted(whls, key=lambda w: w.distribution() + '_' + w.version()) + + def determine_possible_extras(whls): """Determines the list of possible "extras" for each .whl @@ -149,7 +155,7 @@ def is_possible(distro, extra): return { whl: [ extra - for extra in whl.extras() + for extra in sorted(whl.extras()) if is_possible(whl.distribution(), extra) ] for whl in whls @@ -170,7 +176,7 @@ def list_whls(): if fname.endswith('.whl'): yield os.path.join(root, fname) - whls = [Wheel(path) for path in list_whls()] + whls = sort_wheels(Wheel(path) for path in list_whls()) possible_extras = determine_possible_extras(whls) def whl_library(wheel): diff --git a/tools/piptool.par b/tools/piptool.par index 4c658f88719e931d24b3645ff71e80c5e87ee446..85dff20a2b0521ecd0915ec925edee24f601fc3d 100755 GIT binary patch delta 10418 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 diff --git a/tools/whltool.par b/tools/whltool.par index 6fff8a0c9d843eb500f7f48d132c61fbe63943b9..3d255ae6f11b230d64d7d93d9052f7c8e6b5ade5 100755 GIT binary patch delta 1884 zcmZuyU2GIp6z*>Sw$r7w_KqzDajRd@%mx@?cE#)fXQ$3p}ZyPsX1FBrU>YaK{RL%T7uS~Eocv7K}Vnjok2WU7jy;dgYKXwcqHik1ig1< zeb-x8|9EjvQym-oBX078qxaEk3y2+b{mQg8E{- z%oSw_Prto{AKhHE4aYW_4*GYuu`H*= z?0L+~1&i6IcoO?g7|#l>!;Tnb?31sL+PO+22Lwk4a-kSn6-8SW+j=4(> zrdtqFi`cVc?@kRLr}CmlbIzhiF+J^C%wRqgXi|&%@=*6NwSBLw$+t`%noJDIo5@j} zrUhp~MgV?ZH%{SFp4!-Uu;tkE)WbG4DCfGo31ILFuE~mLcbrs|+6x?BUwKsAzox{* z`;)!v#n}s;J>u^9&VG@*ie7CwV47Uqx{97^(-Z~ciOS9&P$JSnGVpmilOdJ4Yv@u0 zD$e04s(VKMD5Oc)dVwZKA%1XhaGU|vV%sv>(hNKC(lUBEI;seKJu)EvUPh`o^F$m8 zys@)YY+XUa;^J#jMNF-red5~{v^Ca1cxMHTwrH@e+*v{AqvE3*Xj3~G<|D(Lh;MG7 z)E-%c%=Wxv7A-pE>IO|bR7Kb)uW09(MWJaPr6FGOM|38p5|YB?8T}P%Y4wmS5tn{J z(+a77K`M{mMB5`h@C6`b-Lju|Y?3^wh;yrGIDFsSDtb~bDi>E#tTna%~)-AE@8Z#WBCi6eSCx;7ZugOe|er4KwiMv`#Ga*bozBaDae zVLQ*}n2#B7V>8g6M~$K{)X3#PoBM6Kk-*K+kl1V6mPyq+LRL zI)k^4Rqqu*%wwMCcnNYeq)ygBJ$)XO47K864iffp&MDfaM(}W>Oj$L?x;M}9emq;H zJ?nbTyr&mZji?mvlbw=%+^&azx6gUHZRE+j->dzL5@KjAqs8FRE6cf~hR+|I5jpE% z8NSZ!P%^d9R5;OK9u_Ez*O&v+O3crPaV7)Wd_;20*a+o)VG*|fo4V?7mC~uIhm6!2@{)IE%U(|cT=HhX{M8;h#muh zj+D6chX=E8>ieLw8bl3f#x-?lc|8vE;v%FD-KR=522s@PveB@rVyW~%@V;6pHNeob zuP$VoXUy~+BVWDgxqlO!Y{ zBW~FO6b&dMP=Xv?ITD{J2P=;ES-gw1e$_d`}bqAlZcH`RqJ}#DJsXK zs&PVD`==%@&#D<^Fs?T7;+(5{;-_QkCb4B!jrR;Rt$mgv>9{I7+SScsDWfKuUx(d+ Rc6C5}nNhpjPVZA8^k1AZZw>$e delta 682 zcmY+CUr19?9LIN^+uYrpQ-7x($~+t$bNOdj;KOo=)g-B`v^|KEaodjV!o0J4?}B!+G;ASzb!c z3Q5!mr>GS!;T9fIC%i%yKH(SjA|M(>P&A4r(fk}9tTv24n=60obvUZ$n8Sf_g|yn=nLYdBY^-?AU>R1@-<;)4TM*wbTFG$wd@W7GR-3~tgOS0MjDUP za5zRY18M<+26YB9^8KU^A3}+6eMJo`yUxBbSQ-Ot=_EUBUots5nqZ8AG zY%$N%#*C8TleCjgu#gcA84S;DKv(p48fxY^)r;Dcn&$>Jbwy)(M z&|>Mk&{y-9SvGs>aW3BlKK62Osu;>SgW1e{-NUhtC^d}wz# X??H&wXBc1N1K4P<9HfZ6x