Skip to content

Commit 10d8f0f

Browse files
committed
Merging in commit 5f78b4a
in order to address Issue bazelbuild#14
1 parent 3e167dc commit 10d8f0f

File tree

1 file changed

+69
-23
lines changed

1 file changed

+69
-23
lines changed

rules_python/whl.py

+69-23
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,17 @@
1919
import re
2020
import zipfile
2121

22+
# Putting this a package's __init__.py causes it to set __path__ so that it is
23+
# possible to import modules and subpackages from other directories on sys.path.
24+
INITPY_CONTENTS = '''
25+
try:
26+
import pkg_resources
27+
pkg_resources.declare_namespace(__name__)
28+
except ImportError:
29+
import pkgutil
30+
__path__ = pkgutil.extend_path(__path__, __name__)
31+
'''
32+
2233

2334
class Wheel(object):
2435

@@ -62,7 +73,7 @@ def metadata(self):
6273
with whl.open(os.path.join(self._dist_info(), 'metadata.json')) as f:
6374
return json.loads(f.read().decode("utf-8"))
6475
except KeyError:
65-
pass
76+
pass
6677
# fall back to METADATA file (https://www.python.org/dev/peps/pep-0427/)
6778
with whl.open(os.path.join(self._dist_info(), 'METADATA')) as f:
6879
return self._parse_metadata(f.read().decode("utf-8"))
@@ -102,29 +113,66 @@ def extras(self):
102113

103114
def expand(self, directory):
104115
with zipfile.ZipFile(self.path(), 'r') as whl:
116+
names = set(whl.namelist())
105117
whl.extractall(directory)
106118

119+
# Workaround for https://github.com/bazelbuild/rules_python/issues/14
120+
for initpy in self.get_init_paths(names):
121+
with open(os.path.join(directory, initpy), 'w') as f:
122+
f.write(INITPY_CONTENTS)
123+
124+
def get_init_paths(self, names):
125+
# Overwrite __init__.py in these directories.
126+
# (required as googleapis-common-protos has an empty __init__.py, which
127+
# blocks google.api.core from google-cloud-core)
128+
NAMESPACES = ["google/api"]
129+
130+
# Find package directories without __init__.py, or where the __init__.py
131+
# must be overwritten to create a working namespace. This is based on
132+
# Bazel's PythonUtils.getInitPyFiles().
133+
init_paths = set()
134+
for n in names:
135+
if os.path.splitext(n)[1] not in ['.so', '.py', '.pyc']:
136+
continue
137+
while os.path.sep in n:
138+
n = os.path.dirname(n)
139+
initpy = os.path.join(n, '__init__.py')
140+
initpyc = os.path.join(n, '__init__.pyc')
141+
if (initpy in names or initpyc in names) and n not in NAMESPACES:
142+
continue
143+
init_paths.add(initpy)
144+
145+
return init_paths
146+
107147
# _parse_metadata parses METADATA files according to https://www.python.org/dev/peps/pep-0314/
108148
def _parse_metadata(self, content):
109149
# TODO: handle fields other than just name
110150
name_pattern = re.compile('Name: (.*)')
111-
return { 'name': name_pattern.search(content).group(1) }
151+
return {'name': name_pattern.search(content).group(1)}
112152

113153

114154
parser = argparse.ArgumentParser(
115155
description='Unpack a WHL file as a py_library.')
116156

117-
parser.add_argument('--whl', action='store',
118-
help=('The .whl file we are expanding.'))
157+
parser.add_argument(
158+
'--whl', action='store', help=('The .whl file we are expanding.'))
159+
160+
parser.add_argument(
161+
'--requirements',
162+
action='store',
163+
help='The pip_import from which to draw dependencies.')
119164

120-
parser.add_argument('--requirements', action='store',
121-
help='The pip_import from which to draw dependencies.')
165+
parser.add_argument(
166+
'--directory',
167+
action='store',
168+
default='.',
169+
help='The directory into which to expand things.')
122170

123-
parser.add_argument('--directory', action='store', default='.',
124-
help='The directory into which to expand things.')
171+
parser.add_argument(
172+
'--extras',
173+
action='append',
174+
help='The set of extras for which to generate library targets.')
125175

126-
parser.add_argument('--extras', action='append',
127-
help='The set of extras for which to generate library targets.')
128176

129177
def main():
130178
args = parser.parse_args()
@@ -149,24 +197,22 @@ def main():
149197
deps = [{dependencies}],
150198
)
151199
{extras}""".format(
152-
requirements=args.requirements,
153-
dependencies=','.join([
154-
'requirement("%s")' % d
155-
for d in whl.dependencies()
156-
]),
157-
extras='\n\n'.join([
158-
"""py_library(
200+
requirements=args.requirements,
201+
dependencies=','.join(
202+
['requirement("%s")' % d for d in whl.dependencies()]),
203+
extras='\n\n'.join([
204+
"""py_library(
159205
name = "{extra}",
160206
deps = [
161207
":pkg",{deps}
162208
],
163209
)""".format(extra=extra,
164-
deps=','.join([
165-
'requirement("%s")' % dep
166-
for dep in whl.dependencies(extra)
167-
]))
168-
for extra in args.extras or []
169-
])))
210+
deps=','.join(
211+
['requirement("%s")' % dep
212+
for dep in whl.dependencies(extra)]))
213+
for extra in args.extras or []
214+
])))
215+
170216

171217
if __name__ == '__main__':
172218
main()

0 commit comments

Comments
 (0)