Skip to content

Commit 047aaa9

Browse files
committed
Temporary patch to make packages with namespaces such as google work
Copied from hutchk@10d8f0f This is a hack and should be superseded with whatever real solution people come up with for bazelbuild#14
1 parent d60c037 commit 047aaa9

File tree

1 file changed

+41
-0
lines changed

1 file changed

+41
-0
lines changed

rules_python/whl.py

+41
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,18 @@
2121
import zipfile
2222

2323

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

2638
def __init__(self, path):
@@ -103,8 +115,37 @@ def extras(self):
103115

104116
def expand(self, directory):
105117
with zipfile.ZipFile(self.path(), 'r') as whl:
118+
names = set(whl.namelist())
106119
whl.extractall(directory)
107120

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

0 commit comments

Comments
 (0)