Skip to content

Commit b9ed0e3

Browse files
author
Jonathon Belotti
authored
Merge pull request #6 from dillon-giacoppo/jonathon/support-purelib-platlib
2 parents 571c268 + f0e29e2 commit b9ed0e3

File tree

7 files changed

+94
-10
lines changed

7 files changed

+94
-10
lines changed

src/BUILD

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,12 @@ py_test(
99
name = "test",
1010
srcs = glob(["tests/*.py"]),
1111
main = "tests/__main__.py",
12-
deps = [":src"],
12+
deps = [
13+
":src",
14+
"//third_party/python:pkginfo",
15+
],
16+
size="small",
17+
imports = [
18+
"../third_party/python/",
19+
]
1320
)

src/extract_wheels.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77

88
from . import namespace_pkgs
9+
from . import purelib
910
from .wheel import Wheel
1011

1112
BUILD_TEMPLATE = """\
@@ -78,6 +79,8 @@ def extract_wheel(whl, directory, extras):
7879

7980
whl.unzip(directory)
8081

82+
# Note: Order of operations matters here
83+
purelib.spread_purelib_into_root(directory)
8184
_setup_namespace_pkg_compatibility(directory)
8285

8386
with open(os.path.join(directory, "BUILD"), "w") as f:

src/namespace_pkgs.py

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import os
2-
import glob
32
import sys
43

4+
from . import wheel
55
from typing import Set
66

77

@@ -21,13 +21,7 @@ def pkg_resources_style_namespace_packages(extracted_whl_directory) -> Set[str]:
2121
"""
2222
namespace_pkg_dirs = set()
2323

24-
dist_info_dirs = glob.glob(os.path.join(extracted_whl_directory, "*.dist-info"))
25-
if not dist_info_dirs:
26-
raise ValueError(f"No *.dist-info directory found. {extracted_whl_directory} is not a valid Wheel.")
27-
elif len(dist_info_dirs) > 1:
28-
raise ValueError(f"Found more than 1 *.dist-info directory. {extracted_whl_directory} is not a valid Wheel.")
29-
else:
30-
dist_info = dist_info_dirs[0]
24+
dist_info = wheel.get_dist_info(extracted_whl_directory)
3125
namespace_packages_record_file = os.path.join(dist_info, "namespace_packages.txt")
3226
if os.path.exists(namespace_packages_record_file):
3327
with open(namespace_packages_record_file) as nspkg:

src/purelib.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import os
2+
import pathlib
3+
import shutil
4+
5+
from . import wheel
6+
7+
8+
def spread_purelib_into_root(extracted_whl_directory: str) -> None:
9+
dist_info = wheel.get_dist_info(extracted_whl_directory)
10+
wheel_metadata_file_path = pathlib.Path(dist_info, "WHEEL")
11+
wheel_metadata_dict = wheel.parse_WHEEL_file(str(wheel_metadata_file_path))
12+
13+
if "Root-Is-Purelib" not in wheel_metadata_dict:
14+
raise ValueError(f"Invalid WHEEL file '{wheel_metadata_file_path}'. Expected key 'Root-Is-Purelib'.")
15+
root_is_purelib = wheel_metadata_dict["Root-Is-Purelib"]
16+
17+
if root_is_purelib.lower() == "true":
18+
# The Python package code is in the root of the Wheel, so no need to 'spread' anything.
19+
return
20+
21+
dot_data_dir = wheel.get_dot_data_directory(extracted_whl_directory)
22+
23+
# 'Root-Is-Purelib: false' is no guarantee a .date directory exists with
24+
# package code in it. eg. the 'markupsafe' package.
25+
if dot_data_dir:
26+
for child in pathlib.Path(dot_data_dir).iterdir():
27+
# TODO(Jonathon): Should all other potential folders get ignored? eg. 'platlib'
28+
if str(child).endswith("purelib"):
29+
for grandchild in child.iterdir():
30+
shutil.move(
31+
src=str(grandchild),
32+
dst=extracted_whl_directory,
33+
)

src/tests/test_namespace_pkgs.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import os
21
import pathlib
32
import unittest
43
import tempfile

src/wheel.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
1+
import os
12
import pkginfo
23
import zipfile
34
import pkg_resources
5+
import glob
6+
7+
from typing import Dict, Optional
48

59

610
class Wheel(object):
@@ -37,3 +41,42 @@ def dependencies(self, extras_requested=None):
3741
def unzip(self, directory):
3842
with zipfile.ZipFile(self.path(), "r") as whl:
3943
whl.extractall(directory)
44+
45+
46+
def get_dist_info(extracted_whl_directory) -> str:
47+
dist_info_dirs = glob.glob(os.path.join(extracted_whl_directory, "*.dist-info"))
48+
if not dist_info_dirs:
49+
raise ValueError(f"No *.dist-info directory found. {extracted_whl_directory} is not a valid Wheel.")
50+
elif len(dist_info_dirs) > 1:
51+
raise ValueError(f"Found more than 1 *.dist-info directory. {extracted_whl_directory} is not a valid Wheel.")
52+
else:
53+
dist_info = dist_info_dirs[0]
54+
return dist_info
55+
56+
57+
def get_dot_data_directory(extracted_whl_directory) -> Optional[str]:
58+
# See: https://www.python.org/dev/peps/pep-0491/#the-data-directory
59+
dot_data_dirs = glob.glob(os.path.join(extracted_whl_directory, "*.data"))
60+
if not dot_data_dirs:
61+
return None
62+
elif len(dot_data_dirs) > 1:
63+
raise ValueError(f"Found more than 1 *.data directory. {extracted_whl_directory} is not a valid Wheel.")
64+
else:
65+
dot_data_dir = dot_data_dirs[0]
66+
return dot_data_dir
67+
68+
69+
def parse_WHEEL_file(whl_file_path: str) -> Dict[str, str]:
70+
contents = {}
71+
with open(whl_file_path, "r") as f:
72+
for line in f:
73+
cleaned = line.strip()
74+
if not cleaned:
75+
continue
76+
try:
77+
key, value = cleaned.split(":", maxsplit=1)
78+
contents[key] = value.strip()
79+
except ValueError:
80+
raise RuntimeError(f"Encounted invalid line in WHEEL file: '{cleaned}'")
81+
return contents
82+

third_party/python/BUILD

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)