Skip to content

Commit c70267c

Browse files
committed
Fix broken Windows zipapp
Signed-off-by: Bernát Gábor <[email protected]>
1 parent 228b615 commit c70267c

File tree

6 files changed

+74
-63
lines changed

6 files changed

+74
-63
lines changed

docs/changelog/2783.bugfix.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Upgrade embedded wheels:
2+
3+
* setuptools to ``75.2.0`` from ``75.1.0``

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ lint.ignore = [
128128
"PLR0914", # Too many local variables
129129
"PLR0917", # Too many positional arguments
130130
"PLR6301", # Method could be a function, class method, or static method
131+
"PLW1510", # no need for check for subprocess
131132
"PTH", # no pathlib, <=39 has problems on Windows with absolute/resolve, can revisit once we no longer need 39
132133
"S104", # Possible binding to all interfaces
133134
"S404", # Using subprocess is alright

src/virtualenv/seed/wheels/embed/__init__.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,37 +13,37 @@
1313
},
1414
"3.8": {
1515
"pip": "pip-24.2-py3-none-any.whl",
16-
"setuptools": "setuptools-75.1.0-py3-none-any.whl",
16+
"setuptools": "setuptools-75.2.0-py3-none-any.whl",
1717
"wheel": "wheel-0.44.0-py3-none-any.whl",
1818
},
1919
"3.9": {
2020
"pip": "pip-24.2-py3-none-any.whl",
21-
"setuptools": "setuptools-75.1.0-py3-none-any.whl",
21+
"setuptools": "setuptools-75.2.0-py3-none-any.whl",
2222
"wheel": "wheel-0.44.0-py3-none-any.whl",
2323
},
2424
"3.10": {
2525
"pip": "pip-24.2-py3-none-any.whl",
26-
"setuptools": "setuptools-75.1.0-py3-none-any.whl",
26+
"setuptools": "setuptools-75.2.0-py3-none-any.whl",
2727
"wheel": "wheel-0.44.0-py3-none-any.whl",
2828
},
2929
"3.11": {
3030
"pip": "pip-24.2-py3-none-any.whl",
31-
"setuptools": "setuptools-75.1.0-py3-none-any.whl",
31+
"setuptools": "setuptools-75.2.0-py3-none-any.whl",
3232
"wheel": "wheel-0.44.0-py3-none-any.whl",
3333
},
3434
"3.12": {
3535
"pip": "pip-24.2-py3-none-any.whl",
36-
"setuptools": "setuptools-75.1.0-py3-none-any.whl",
36+
"setuptools": "setuptools-75.2.0-py3-none-any.whl",
3737
"wheel": "wheel-0.44.0-py3-none-any.whl",
3838
},
3939
"3.13": {
4040
"pip": "pip-24.2-py3-none-any.whl",
41-
"setuptools": "setuptools-75.1.0-py3-none-any.whl",
41+
"setuptools": "setuptools-75.2.0-py3-none-any.whl",
4242
"wheel": "wheel-0.44.0-py3-none-any.whl",
4343
},
4444
"3.14": {
4545
"pip": "pip-24.2-py3-none-any.whl",
46-
"setuptools": "setuptools-75.1.0-py3-none-any.whl",
46+
"setuptools": "setuptools-75.2.0-py3-none-any.whl",
4747
"wheel": "wheel-0.44.0-py3-none-any.whl",
4848
},
4949
}

tasks/__main__zipapp.py

Lines changed: 60 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,25 @@
44
import os
55
import sys
66
import zipfile
7+
from functools import cached_property
8+
from importlib.abc import SourceLoader
9+
from importlib.util import spec_from_file_location
710

811
ABS_HERE = os.path.abspath(os.path.dirname(__file__))
9-
NEW_IMPORT_SYSTEM = sys.version_info[0] >= 3 # noqa: PLR2004
1012

1113

1214
class VersionPlatformSelect:
1315
def __init__(self) -> None:
14-
self.archive = ABS_HERE
15-
self._zip_file = zipfile.ZipFile(ABS_HERE, "r")
16+
zipapp = ABS_HERE
17+
self.archive = zipapp
18+
self._zip_file = zipfile.ZipFile(zipapp)
1619
self.modules = self._load("modules.json")
1720
self.distributions = self._load("distributions.json")
1821
self.__cache = {}
1922

2023
def _load(self, of_file):
2124
version = ".".join(str(i) for i in sys.version_info[0:2])
22-
per_version = json.loads(self.get_data(of_file).decode("utf-8"))
25+
per_version = json.loads(self.get_data(of_file).decode())
2326
all_platforms = per_version[version] if version in per_version else per_version["3.9"]
2427
content = all_platforms.get("==any", {}) # start will all platforms
2528
not_us = f"!={sys.platform}"
@@ -65,25 +68,62 @@ def find_distributions(self, context):
6568
def __repr__(self) -> str:
6669
return f"{self.__class__.__name__}(path={ABS_HERE})"
6770

68-
def _register_distutils_finder(self):
71+
def _register_distutils_finder(self): # noqa: C901
6972
if "distlib" not in self.modules:
7073
return
7174

75+
class Resource:
76+
def __init__(self, path: str, name: str, loader: SourceLoader) -> None:
77+
self.path = os.path.join(path, name)
78+
self.name = name
79+
self.loader = loader
80+
81+
@property
82+
def bytes(self) -> bytes:
83+
return self.loader.get_data(self.name)
84+
85+
@property
86+
def is_container(self) -> bool:
87+
return len(self.resources) > 1
88+
89+
@cached_property
90+
def resources(self) -> list[str]:
91+
return [
92+
i.filename
93+
for i in (
94+
(j for j in zip_file.filelist if j.filename.startswith(f"{self.name}/"))
95+
if self.name
96+
else zip_file.filelist
97+
)
98+
]
99+
72100
class DistlibFinder:
73101
def __init__(self, path, loader) -> None:
74102
self.path = path
75103
self.loader = loader
76104

77105
def find(self, name):
78-
class Resource:
79-
def __init__(self, content) -> None:
80-
self.bytes = content
81-
82-
full_path = os.path.join(self.path, name)
83-
return Resource(self.loader.get_data(full_path))
106+
return Resource(self.path, name, self.loader)
107+
108+
def iterator(self, resource_name):
109+
resource = self.find(resource_name)
110+
if resource is not None:
111+
todo = [resource]
112+
while todo:
113+
resource = todo.pop(0)
114+
yield resource
115+
if resource.is_container:
116+
resource_name = resource.name
117+
for name in resource.resources:
118+
child = self.find(f"{resource_name}/{name}" if resource_name else name)
119+
if child.is_container:
120+
todo.append(child)
121+
else:
122+
yield child
84123

85124
from distlib.resources import register_finder # noqa: PLC0415
86125

126+
zip_file = self._zip_file
87127
register_finder(self, lambda module: DistlibFinder(os.path.dirname(module.__file__), self))
88128

89129

@@ -113,41 +153,15 @@ def locate_file(self, path):
113153
return _VER_DISTRIBUTION_CLASS
114154

115155

116-
if NEW_IMPORT_SYSTEM:
117-
from importlib.abc import SourceLoader
118-
from importlib.util import spec_from_file_location
119-
120-
class VersionedFindLoad(VersionPlatformSelect, SourceLoader):
121-
def find_spec(self, fullname, path, target=None): # noqa: ARG002
122-
zip_path = self.find_mod(fullname)
123-
if zip_path is not None:
124-
return spec_from_file_location(name=fullname, loader=self)
125-
return None
126-
127-
def module_repr(self, module):
128-
raise NotImplementedError
129-
130-
else:
131-
from imp import new_module
132-
133-
class VersionedFindLoad(VersionPlatformSelect):
134-
def find_module(self, fullname, path=None): # noqa: ARG002
135-
return self if self.find_mod(fullname) else None
136-
137-
def load_module(self, fullname):
138-
filename = self.get_filename(fullname)
139-
code = self.get_data(filename)
140-
mod = sys.modules.setdefault(fullname, new_module(fullname))
141-
mod.__file__ = filename
142-
mod.__loader__ = self
143-
is_package = filename.endswith("__init__.py")
144-
if is_package:
145-
mod.__path__ = [os.path.dirname(filename)]
146-
mod.__package__ = fullname
147-
else:
148-
mod.__package__ = fullname.rpartition(".")[0]
149-
exec(code, mod.__dict__) # noqa: S102
150-
return mod
156+
class VersionedFindLoad(VersionPlatformSelect, SourceLoader):
157+
def find_spec(self, fullname, path, target=None): # noqa: ARG002
158+
zip_path = self.find_mod(fullname)
159+
if zip_path is not None:
160+
return spec_from_file_location(name=fullname, loader=self)
161+
return None
162+
163+
def module_repr(self, module):
164+
raise NotImplementedError
151165

152166

153167
def run():

tasks/upgrade_wheels.py

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,8 @@ def run(): # noqa: C901
6666

6767
added = collect_package_versions(new_packages)
6868
removed = collect_package_versions(remove_packages)
69-
7069
outcome = (1 if STRICT else 0) if (added or removed) else 0
70+
print(f"Outcome {outcome} added {added} removed {removed}") # noqa: T201
7171
lines = ["Upgrade embedded wheels:", ""]
7272
for key, versions in added.items():
7373
text = f"* {key} to {fmt_version(versions)}"
@@ -119,15 +119,8 @@ def get_embed_wheel(distribution, for_py_version):
119119
)
120120
dest_target = DEST / "__init__.py"
121121
dest_target.write_text(msg, encoding="utf-8")
122-
123-
subprocess.run(
124-
[sys.executable, "-m", "ruff", "check", str(dest_target), "--fix", "--unsafe-fixes"],
125-
check=False,
126-
)
127-
subprocess.run(
128-
[sys.executable, "-m", "ruff", "format", str(dest_target), "--preview"],
129-
check=False,
130-
)
122+
subprocess.run([sys.executable, "-m", "ruff", "format", str(dest_target), "--preview"])
123+
subprocess.run([sys.executable, "-m", "ruff", "check", str(dest_target), "--fix", "--unsafe-fixes"])
131124

132125
raise SystemExit(outcome)
133126

0 commit comments

Comments
 (0)