py2docfx 0.1.11.dev1824276__py3-none-any.whl → 0.1.11.dev1827111__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- py2docfx/convert_prepare/environment.py +1 -1
- py2docfx/venv/0/Lib/site-packages/setuptools/_distutils/_collections.py +0 -145
- py2docfx/venv/0/Lib/site-packages/setuptools/_distutils/bcppcompiler.py +1 -2
- py2docfx/venv/0/Lib/site-packages/setuptools/_distutils/ccompiler.py +7 -11
- py2docfx/venv/0/Lib/site-packages/setuptools/_distutils/command/bdist.py +4 -3
- py2docfx/venv/0/Lib/site-packages/setuptools/_distutils/command/build_ext.py +1 -4
- py2docfx/venv/0/Lib/site-packages/setuptools/_distutils/command/check.py +3 -4
- py2docfx/venv/0/Lib/site-packages/setuptools/_distutils/command/install_data.py +39 -29
- py2docfx/venv/0/Lib/site-packages/setuptools/_distutils/command/install_lib.py +1 -3
- py2docfx/venv/0/Lib/site-packages/setuptools/_distutils/command/sdist.py +4 -4
- py2docfx/venv/0/Lib/site-packages/setuptools/_distutils/compat/py38.py +1 -0
- py2docfx/venv/0/Lib/site-packages/setuptools/_distutils/cygwinccompiler.py +21 -42
- py2docfx/venv/0/Lib/site-packages/setuptools/_distutils/dist.py +3 -12
- py2docfx/venv/0/Lib/site-packages/setuptools/_distutils/extension.py +9 -4
- py2docfx/venv/0/Lib/site-packages/setuptools/_distutils/msvc9compiler.py +1 -3
- py2docfx/venv/0/Lib/site-packages/setuptools/_distutils/msvccompiler.py +1 -3
- py2docfx/venv/0/Lib/site-packages/setuptools/_distutils/spawn.py +0 -1
- py2docfx/venv/0/Lib/site-packages/setuptools/_distutils/sysconfig.py +44 -25
- py2docfx/venv/0/Lib/site-packages/setuptools/_distutils/tests/test_archive_util.py +1 -1
- py2docfx/venv/0/Lib/site-packages/setuptools/_distutils/tests/test_build.py +1 -2
- py2docfx/venv/0/Lib/site-packages/setuptools/_distutils/tests/test_build_ext.py +1 -1
- py2docfx/venv/0/Lib/site-packages/setuptools/_distutils/tests/test_cygwinccompiler.py +0 -42
- py2docfx/venv/0/Lib/site-packages/setuptools/_distutils/tests/test_dist.py +1 -1
- py2docfx/venv/0/Lib/site-packages/setuptools/_distutils/tests/test_extension.py +4 -1
- py2docfx/venv/0/Lib/site-packages/setuptools/_distutils/tests/test_install_data.py +17 -9
- py2docfx/venv/0/Lib/site-packages/setuptools/_distutils/tests/test_mingwccompiler.py +5 -4
- py2docfx/venv/0/Lib/site-packages/setuptools/_distutils/tests/test_spawn.py +1 -1
- py2docfx/venv/0/Lib/site-packages/setuptools/_distutils/tests/test_sysconfig.py +6 -3
- py2docfx/venv/0/Lib/site-packages/setuptools/_distutils/tests/test_unixccompiler.py +35 -1
- py2docfx/venv/0/Lib/site-packages/setuptools/_distutils/tests/test_util.py +4 -24
- py2docfx/venv/0/Lib/site-packages/setuptools/_distutils/unixccompiler.py +19 -20
- py2docfx/venv/0/Lib/site-packages/setuptools/_distutils/util.py +20 -26
- py2docfx/venv/0/Lib/site-packages/wheel/__init__.py +3 -0
- py2docfx/venv/0/Lib/site-packages/wheel/__main__.py +23 -0
- py2docfx/venv/0/Lib/site-packages/wheel/_bdist_wheel.py +604 -0
- py2docfx/venv/0/Lib/site-packages/wheel/_setuptools_logging.py +26 -0
- py2docfx/venv/0/Lib/site-packages/wheel/bdist_wheel.py +11 -0
- py2docfx/venv/0/Lib/site-packages/wheel/cli/__init__.py +155 -0
- py2docfx/venv/0/Lib/site-packages/wheel/cli/convert.py +273 -0
- py2docfx/venv/0/Lib/site-packages/wheel/cli/pack.py +85 -0
- py2docfx/venv/0/Lib/site-packages/wheel/cli/tags.py +139 -0
- py2docfx/venv/0/Lib/site-packages/wheel/cli/unpack.py +30 -0
- py2docfx/venv/0/Lib/site-packages/wheel/macosx_libfile.py +482 -0
- py2docfx/venv/0/Lib/site-packages/wheel/metadata.py +183 -0
- py2docfx/venv/0/Lib/site-packages/wheel/util.py +26 -0
- py2docfx/venv/0/Lib/site-packages/wheel/vendored/__init__.py +0 -0
- py2docfx/venv/0/Lib/site-packages/wheel/vendored/packaging/__init__.py +0 -0
- py2docfx/venv/0/Lib/site-packages/wheel/vendored/packaging/_elffile.py +108 -0
- py2docfx/venv/0/Lib/site-packages/wheel/vendored/packaging/_manylinux.py +260 -0
- py2docfx/venv/0/Lib/site-packages/wheel/vendored/packaging/_musllinux.py +83 -0
- py2docfx/venv/0/Lib/site-packages/wheel/vendored/packaging/_parser.py +356 -0
- py2docfx/venv/0/Lib/site-packages/wheel/vendored/packaging/_structures.py +61 -0
- py2docfx/venv/0/Lib/site-packages/wheel/vendored/packaging/_tokenizer.py +192 -0
- py2docfx/venv/0/Lib/site-packages/wheel/vendored/packaging/markers.py +253 -0
- py2docfx/venv/0/Lib/site-packages/wheel/vendored/packaging/requirements.py +90 -0
- py2docfx/venv/0/Lib/site-packages/wheel/vendored/packaging/specifiers.py +1011 -0
- py2docfx/venv/0/Lib/site-packages/wheel/vendored/packaging/tags.py +571 -0
- py2docfx/venv/0/Lib/site-packages/wheel/vendored/packaging/utils.py +172 -0
- py2docfx/venv/0/Lib/site-packages/wheel/vendored/packaging/version.py +561 -0
- py2docfx/venv/0/Lib/site-packages/wheel/wheelfile.py +227 -0
- py2docfx/venv/template/Lib/site-packages/setuptools/_distutils/_collections.py +0 -145
- py2docfx/venv/template/Lib/site-packages/setuptools/_distutils/bcppcompiler.py +1 -2
- py2docfx/venv/template/Lib/site-packages/setuptools/_distutils/ccompiler.py +7 -11
- py2docfx/venv/template/Lib/site-packages/setuptools/_distutils/command/bdist.py +4 -3
- py2docfx/venv/template/Lib/site-packages/setuptools/_distutils/command/build_ext.py +1 -4
- py2docfx/venv/template/Lib/site-packages/setuptools/_distutils/command/check.py +3 -4
- py2docfx/venv/template/Lib/site-packages/setuptools/_distutils/command/install_data.py +39 -29
- py2docfx/venv/template/Lib/site-packages/setuptools/_distutils/command/install_lib.py +1 -3
- py2docfx/venv/template/Lib/site-packages/setuptools/_distutils/command/sdist.py +4 -4
- py2docfx/venv/template/Lib/site-packages/setuptools/_distutils/compat/py38.py +1 -0
- py2docfx/venv/template/Lib/site-packages/setuptools/_distutils/cygwinccompiler.py +21 -42
- py2docfx/venv/template/Lib/site-packages/setuptools/_distutils/dist.py +3 -12
- py2docfx/venv/template/Lib/site-packages/setuptools/_distutils/extension.py +9 -4
- py2docfx/venv/template/Lib/site-packages/setuptools/_distutils/msvc9compiler.py +1 -3
- py2docfx/venv/template/Lib/site-packages/setuptools/_distutils/msvccompiler.py +1 -3
- py2docfx/venv/template/Lib/site-packages/setuptools/_distutils/spawn.py +0 -1
- py2docfx/venv/template/Lib/site-packages/setuptools/_distutils/sysconfig.py +44 -25
- py2docfx/venv/template/Lib/site-packages/setuptools/_distutils/tests/test_archive_util.py +1 -1
- py2docfx/venv/template/Lib/site-packages/setuptools/_distutils/tests/test_build.py +1 -2
- py2docfx/venv/template/Lib/site-packages/setuptools/_distutils/tests/test_build_ext.py +1 -1
- py2docfx/venv/template/Lib/site-packages/setuptools/_distutils/tests/test_cygwinccompiler.py +0 -42
- py2docfx/venv/template/Lib/site-packages/setuptools/_distutils/tests/test_dist.py +1 -1
- py2docfx/venv/template/Lib/site-packages/setuptools/_distutils/tests/test_extension.py +4 -1
- py2docfx/venv/template/Lib/site-packages/setuptools/_distutils/tests/test_install_data.py +17 -9
- py2docfx/venv/template/Lib/site-packages/setuptools/_distutils/tests/test_mingwccompiler.py +5 -4
- py2docfx/venv/template/Lib/site-packages/setuptools/_distutils/tests/test_spawn.py +1 -1
- py2docfx/venv/template/Lib/site-packages/setuptools/_distutils/tests/test_sysconfig.py +6 -3
- py2docfx/venv/template/Lib/site-packages/setuptools/_distutils/tests/test_unixccompiler.py +35 -1
- py2docfx/venv/template/Lib/site-packages/setuptools/_distutils/tests/test_util.py +4 -24
- py2docfx/venv/template/Lib/site-packages/setuptools/_distutils/unixccompiler.py +19 -20
- py2docfx/venv/template/Lib/site-packages/setuptools/_distutils/util.py +20 -26
- py2docfx/venv/template/Lib/site-packages/wheel/__init__.py +3 -0
- py2docfx/venv/template/Lib/site-packages/wheel/__main__.py +23 -0
- py2docfx/venv/template/Lib/site-packages/wheel/_bdist_wheel.py +604 -0
- py2docfx/venv/template/Lib/site-packages/wheel/_setuptools_logging.py +26 -0
- py2docfx/venv/template/Lib/site-packages/wheel/bdist_wheel.py +11 -0
- py2docfx/venv/template/Lib/site-packages/wheel/cli/__init__.py +155 -0
- py2docfx/venv/template/Lib/site-packages/wheel/cli/convert.py +273 -0
- py2docfx/venv/template/Lib/site-packages/wheel/cli/pack.py +85 -0
- py2docfx/venv/template/Lib/site-packages/wheel/cli/tags.py +139 -0
- py2docfx/venv/template/Lib/site-packages/wheel/cli/unpack.py +30 -0
- py2docfx/venv/template/Lib/site-packages/wheel/macosx_libfile.py +482 -0
- py2docfx/venv/template/Lib/site-packages/wheel/metadata.py +183 -0
- py2docfx/venv/template/Lib/site-packages/wheel/util.py +26 -0
- py2docfx/venv/template/Lib/site-packages/wheel/vendored/__init__.py +0 -0
- py2docfx/venv/template/Lib/site-packages/wheel/vendored/packaging/__init__.py +0 -0
- py2docfx/venv/template/Lib/site-packages/wheel/vendored/packaging/_elffile.py +108 -0
- py2docfx/venv/template/Lib/site-packages/wheel/vendored/packaging/_manylinux.py +260 -0
- py2docfx/venv/template/Lib/site-packages/wheel/vendored/packaging/_musllinux.py +83 -0
- py2docfx/venv/template/Lib/site-packages/wheel/vendored/packaging/_parser.py +356 -0
- py2docfx/venv/template/Lib/site-packages/wheel/vendored/packaging/_structures.py +61 -0
- py2docfx/venv/template/Lib/site-packages/wheel/vendored/packaging/_tokenizer.py +192 -0
- py2docfx/venv/template/Lib/site-packages/wheel/vendored/packaging/markers.py +253 -0
- py2docfx/venv/template/Lib/site-packages/wheel/vendored/packaging/requirements.py +90 -0
- py2docfx/venv/template/Lib/site-packages/wheel/vendored/packaging/specifiers.py +1011 -0
- py2docfx/venv/template/Lib/site-packages/wheel/vendored/packaging/tags.py +571 -0
- py2docfx/venv/template/Lib/site-packages/wheel/vendored/packaging/utils.py +172 -0
- py2docfx/venv/template/Lib/site-packages/wheel/vendored/packaging/version.py +561 -0
- py2docfx/venv/template/Lib/site-packages/wheel/wheelfile.py +227 -0
- {py2docfx-0.1.11.dev1824276.dist-info → py2docfx-0.1.11.dev1827111.dist-info}/METADATA +1 -1
- {py2docfx-0.1.11.dev1824276.dist-info → py2docfx-0.1.11.dev1827111.dist-info}/RECORD +123 -67
- {py2docfx-0.1.11.dev1824276.dist-info → py2docfx-0.1.11.dev1827111.dist-info}/WHEEL +0 -0
- {py2docfx-0.1.11.dev1824276.dist-info → py2docfx-0.1.11.dev1827111.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,227 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
import csv
|
4
|
+
import hashlib
|
5
|
+
import os.path
|
6
|
+
import re
|
7
|
+
import stat
|
8
|
+
import time
|
9
|
+
from io import StringIO, TextIOWrapper
|
10
|
+
from typing import IO, TYPE_CHECKING, Literal
|
11
|
+
from zipfile import ZIP_DEFLATED, ZipFile, ZipInfo
|
12
|
+
|
13
|
+
from wheel.cli import WheelError
|
14
|
+
from wheel.util import log, urlsafe_b64decode, urlsafe_b64encode
|
15
|
+
|
16
|
+
if TYPE_CHECKING:
|
17
|
+
from typing import Protocol, Sized, Union
|
18
|
+
|
19
|
+
from typing_extensions import Buffer
|
20
|
+
|
21
|
+
StrPath = Union[str, os.PathLike[str]]
|
22
|
+
|
23
|
+
class SizedBuffer(Sized, Buffer, Protocol): ...
|
24
|
+
|
25
|
+
|
26
|
+
# Non-greedy matching of an optional build number may be too clever (more
|
27
|
+
# invalid wheel filenames will match). Separate regex for .dist-info?
|
28
|
+
WHEEL_INFO_RE = re.compile(
|
29
|
+
r"""^(?P<namever>(?P<name>[^\s-]+?)-(?P<ver>[^\s-]+?))(-(?P<build>\d[^\s-]*))?
|
30
|
+
-(?P<pyver>[^\s-]+?)-(?P<abi>[^\s-]+?)-(?P<plat>\S+)\.whl$""",
|
31
|
+
re.VERBOSE,
|
32
|
+
)
|
33
|
+
MINIMUM_TIMESTAMP = 315532800 # 1980-01-01 00:00:00 UTC
|
34
|
+
|
35
|
+
|
36
|
+
def get_zipinfo_datetime(timestamp: float | None = None):
|
37
|
+
# Some applications need reproducible .whl files, but they can't do this without
|
38
|
+
# forcing the timestamp of the individual ZipInfo objects. See issue #143.
|
39
|
+
timestamp = int(os.environ.get("SOURCE_DATE_EPOCH", timestamp or time.time()))
|
40
|
+
timestamp = max(timestamp, MINIMUM_TIMESTAMP)
|
41
|
+
return time.gmtime(timestamp)[0:6]
|
42
|
+
|
43
|
+
|
44
|
+
class WheelFile(ZipFile):
|
45
|
+
"""A ZipFile derivative class that also reads SHA-256 hashes from
|
46
|
+
.dist-info/RECORD and checks any read files against those.
|
47
|
+
"""
|
48
|
+
|
49
|
+
_default_algorithm = hashlib.sha256
|
50
|
+
|
51
|
+
def __init__(
|
52
|
+
self,
|
53
|
+
file: StrPath,
|
54
|
+
mode: Literal["r", "w", "x", "a"] = "r",
|
55
|
+
compression: int = ZIP_DEFLATED,
|
56
|
+
):
|
57
|
+
basename = os.path.basename(file)
|
58
|
+
self.parsed_filename = WHEEL_INFO_RE.match(basename)
|
59
|
+
if not basename.endswith(".whl") or self.parsed_filename is None:
|
60
|
+
raise WheelError(f"Bad wheel filename {basename!r}")
|
61
|
+
|
62
|
+
ZipFile.__init__(self, file, mode, compression=compression, allowZip64=True)
|
63
|
+
|
64
|
+
self.dist_info_path = "{}.dist-info".format(
|
65
|
+
self.parsed_filename.group("namever")
|
66
|
+
)
|
67
|
+
self.record_path = self.dist_info_path + "/RECORD"
|
68
|
+
self._file_hashes: dict[str, tuple[None, None] | tuple[int, bytes]] = {}
|
69
|
+
self._file_sizes = {}
|
70
|
+
if mode == "r":
|
71
|
+
# Ignore RECORD and any embedded wheel signatures
|
72
|
+
self._file_hashes[self.record_path] = None, None
|
73
|
+
self._file_hashes[self.record_path + ".jws"] = None, None
|
74
|
+
self._file_hashes[self.record_path + ".p7s"] = None, None
|
75
|
+
|
76
|
+
# Fill in the expected hashes by reading them from RECORD
|
77
|
+
try:
|
78
|
+
record = self.open(self.record_path)
|
79
|
+
except KeyError:
|
80
|
+
raise WheelError(f"Missing {self.record_path} file") from None
|
81
|
+
|
82
|
+
with record:
|
83
|
+
for line in csv.reader(
|
84
|
+
TextIOWrapper(record, newline="", encoding="utf-8")
|
85
|
+
):
|
86
|
+
path, hash_sum, size = line
|
87
|
+
if not hash_sum:
|
88
|
+
continue
|
89
|
+
|
90
|
+
algorithm, hash_sum = hash_sum.split("=")
|
91
|
+
try:
|
92
|
+
hashlib.new(algorithm)
|
93
|
+
except ValueError:
|
94
|
+
raise WheelError(
|
95
|
+
f"Unsupported hash algorithm: {algorithm}"
|
96
|
+
) from None
|
97
|
+
|
98
|
+
if algorithm.lower() in {"md5", "sha1"}:
|
99
|
+
raise WheelError(
|
100
|
+
f"Weak hash algorithm ({algorithm}) is not permitted by "
|
101
|
+
f"PEP 427"
|
102
|
+
)
|
103
|
+
|
104
|
+
self._file_hashes[path] = (
|
105
|
+
algorithm,
|
106
|
+
urlsafe_b64decode(hash_sum.encode("ascii")),
|
107
|
+
)
|
108
|
+
|
109
|
+
def open(
|
110
|
+
self,
|
111
|
+
name_or_info: str | ZipInfo,
|
112
|
+
mode: Literal["r", "w"] = "r",
|
113
|
+
pwd: bytes | None = None,
|
114
|
+
) -> IO[bytes]:
|
115
|
+
def _update_crc(newdata: bytes) -> None:
|
116
|
+
eof = ef._eof
|
117
|
+
update_crc_orig(newdata)
|
118
|
+
running_hash.update(newdata)
|
119
|
+
if eof and running_hash.digest() != expected_hash:
|
120
|
+
raise WheelError(f"Hash mismatch for file '{ef_name}'")
|
121
|
+
|
122
|
+
ef_name = (
|
123
|
+
name_or_info.filename if isinstance(name_or_info, ZipInfo) else name_or_info
|
124
|
+
)
|
125
|
+
if (
|
126
|
+
mode == "r"
|
127
|
+
and not ef_name.endswith("/")
|
128
|
+
and ef_name not in self._file_hashes
|
129
|
+
):
|
130
|
+
raise WheelError(f"No hash found for file '{ef_name}'")
|
131
|
+
|
132
|
+
ef = ZipFile.open(self, name_or_info, mode, pwd)
|
133
|
+
if mode == "r" and not ef_name.endswith("/"):
|
134
|
+
algorithm, expected_hash = self._file_hashes[ef_name]
|
135
|
+
if expected_hash is not None:
|
136
|
+
# Monkey patch the _update_crc method to also check for the hash from
|
137
|
+
# RECORD
|
138
|
+
running_hash = hashlib.new(algorithm)
|
139
|
+
update_crc_orig, ef._update_crc = ef._update_crc, _update_crc
|
140
|
+
|
141
|
+
return ef
|
142
|
+
|
143
|
+
def write_files(self, base_dir: str):
|
144
|
+
log.info(f"creating '{self.filename}' and adding '{base_dir}' to it")
|
145
|
+
deferred: list[tuple[str, str]] = []
|
146
|
+
for root, dirnames, filenames in os.walk(base_dir):
|
147
|
+
# Sort the directory names so that `os.walk` will walk them in a
|
148
|
+
# defined order on the next iteration.
|
149
|
+
dirnames.sort()
|
150
|
+
for name in sorted(filenames):
|
151
|
+
path = os.path.normpath(os.path.join(root, name))
|
152
|
+
if os.path.isfile(path):
|
153
|
+
arcname = os.path.relpath(path, base_dir).replace(os.path.sep, "/")
|
154
|
+
if arcname == self.record_path:
|
155
|
+
pass
|
156
|
+
elif root.endswith(".dist-info"):
|
157
|
+
deferred.append((path, arcname))
|
158
|
+
else:
|
159
|
+
self.write(path, arcname)
|
160
|
+
|
161
|
+
deferred.sort()
|
162
|
+
for path, arcname in deferred:
|
163
|
+
self.write(path, arcname)
|
164
|
+
|
165
|
+
def write(
|
166
|
+
self,
|
167
|
+
filename: str,
|
168
|
+
arcname: str | None = None,
|
169
|
+
compress_type: int | None = None,
|
170
|
+
) -> None:
|
171
|
+
with open(filename, "rb") as f:
|
172
|
+
st = os.fstat(f.fileno())
|
173
|
+
data = f.read()
|
174
|
+
|
175
|
+
zinfo = ZipInfo(
|
176
|
+
arcname or filename, date_time=get_zipinfo_datetime(st.st_mtime)
|
177
|
+
)
|
178
|
+
zinfo.external_attr = (stat.S_IMODE(st.st_mode) | stat.S_IFMT(st.st_mode)) << 16
|
179
|
+
zinfo.compress_type = compress_type or self.compression
|
180
|
+
self.writestr(zinfo, data, compress_type)
|
181
|
+
|
182
|
+
def writestr(
|
183
|
+
self,
|
184
|
+
zinfo_or_arcname: str | ZipInfo,
|
185
|
+
data: SizedBuffer | str,
|
186
|
+
compress_type: int | None = None,
|
187
|
+
):
|
188
|
+
if isinstance(zinfo_or_arcname, str):
|
189
|
+
zinfo_or_arcname = ZipInfo(
|
190
|
+
zinfo_or_arcname, date_time=get_zipinfo_datetime()
|
191
|
+
)
|
192
|
+
zinfo_or_arcname.compress_type = self.compression
|
193
|
+
zinfo_or_arcname.external_attr = (0o664 | stat.S_IFREG) << 16
|
194
|
+
|
195
|
+
if isinstance(data, str):
|
196
|
+
data = data.encode("utf-8")
|
197
|
+
|
198
|
+
ZipFile.writestr(self, zinfo_or_arcname, data, compress_type)
|
199
|
+
fname = (
|
200
|
+
zinfo_or_arcname.filename
|
201
|
+
if isinstance(zinfo_or_arcname, ZipInfo)
|
202
|
+
else zinfo_or_arcname
|
203
|
+
)
|
204
|
+
log.info(f"adding '{fname}'")
|
205
|
+
if fname != self.record_path:
|
206
|
+
hash_ = self._default_algorithm(data)
|
207
|
+
self._file_hashes[fname] = (
|
208
|
+
hash_.name,
|
209
|
+
urlsafe_b64encode(hash_.digest()).decode("ascii"),
|
210
|
+
)
|
211
|
+
self._file_sizes[fname] = len(data)
|
212
|
+
|
213
|
+
def close(self):
|
214
|
+
# Write RECORD
|
215
|
+
if self.fp is not None and self.mode == "w" and self._file_hashes:
|
216
|
+
data = StringIO()
|
217
|
+
writer = csv.writer(data, delimiter=",", quotechar='"', lineterminator="\n")
|
218
|
+
writer.writerows(
|
219
|
+
(
|
220
|
+
(fname, algorithm + "=" + hash_, self._file_sizes[fname])
|
221
|
+
for fname, (algorithm, hash_) in self._file_hashes.items()
|
222
|
+
)
|
223
|
+
)
|
224
|
+
writer.writerow((format(self.record_path), "", ""))
|
225
|
+
self.writestr(self.record_path, data.getvalue())
|
226
|
+
|
227
|
+
ZipFile.close(self)
|
@@ -1,11 +1,7 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
3
|
import collections
|
4
|
-
import functools
|
5
4
|
import itertools
|
6
|
-
import operator
|
7
|
-
from collections.abc import Mapping
|
8
|
-
from typing import Any
|
9
5
|
|
10
6
|
|
11
7
|
# from jaraco.collections 3.5.1
|
@@ -60,144 +56,3 @@ class DictStack(list, collections.abc.Mapping):
|
|
60
56
|
|
61
57
|
def __len__(self):
|
62
58
|
return len(list(iter(self)))
|
63
|
-
|
64
|
-
|
65
|
-
# from jaraco.collections 5.0.1
|
66
|
-
class RangeMap(dict):
|
67
|
-
"""
|
68
|
-
A dictionary-like object that uses the keys as bounds for a range.
|
69
|
-
Inclusion of the value for that range is determined by the
|
70
|
-
key_match_comparator, which defaults to less-than-or-equal.
|
71
|
-
A value is returned for a key if it is the first key that matches in
|
72
|
-
the sorted list of keys.
|
73
|
-
|
74
|
-
One may supply keyword parameters to be passed to the sort function used
|
75
|
-
to sort keys (i.e. key, reverse) as sort_params.
|
76
|
-
|
77
|
-
Create a map that maps 1-3 -> 'a', 4-6 -> 'b'
|
78
|
-
|
79
|
-
>>> r = RangeMap({3: 'a', 6: 'b'}) # boy, that was easy
|
80
|
-
>>> r[1], r[2], r[3], r[4], r[5], r[6]
|
81
|
-
('a', 'a', 'a', 'b', 'b', 'b')
|
82
|
-
|
83
|
-
Even float values should work so long as the comparison operator
|
84
|
-
supports it.
|
85
|
-
|
86
|
-
>>> r[4.5]
|
87
|
-
'b'
|
88
|
-
|
89
|
-
Notice that the way rangemap is defined, it must be open-ended
|
90
|
-
on one side.
|
91
|
-
|
92
|
-
>>> r[0]
|
93
|
-
'a'
|
94
|
-
>>> r[-1]
|
95
|
-
'a'
|
96
|
-
|
97
|
-
One can close the open-end of the RangeMap by using undefined_value
|
98
|
-
|
99
|
-
>>> r = RangeMap({0: RangeMap.undefined_value, 3: 'a', 6: 'b'})
|
100
|
-
>>> r[0]
|
101
|
-
Traceback (most recent call last):
|
102
|
-
...
|
103
|
-
KeyError: 0
|
104
|
-
|
105
|
-
One can get the first or last elements in the range by using RangeMap.Item
|
106
|
-
|
107
|
-
>>> last_item = RangeMap.Item(-1)
|
108
|
-
>>> r[last_item]
|
109
|
-
'b'
|
110
|
-
|
111
|
-
.last_item is a shortcut for Item(-1)
|
112
|
-
|
113
|
-
>>> r[RangeMap.last_item]
|
114
|
-
'b'
|
115
|
-
|
116
|
-
Sometimes it's useful to find the bounds for a RangeMap
|
117
|
-
|
118
|
-
>>> r.bounds()
|
119
|
-
(0, 6)
|
120
|
-
|
121
|
-
RangeMap supports .get(key, default)
|
122
|
-
|
123
|
-
>>> r.get(0, 'not found')
|
124
|
-
'not found'
|
125
|
-
|
126
|
-
>>> r.get(7, 'not found')
|
127
|
-
'not found'
|
128
|
-
|
129
|
-
One often wishes to define the ranges by their left-most values,
|
130
|
-
which requires use of sort params and a key_match_comparator.
|
131
|
-
|
132
|
-
>>> r = RangeMap({1: 'a', 4: 'b'},
|
133
|
-
... sort_params=dict(reverse=True),
|
134
|
-
... key_match_comparator=operator.ge)
|
135
|
-
>>> r[1], r[2], r[3], r[4], r[5], r[6]
|
136
|
-
('a', 'a', 'a', 'b', 'b', 'b')
|
137
|
-
|
138
|
-
That wasn't nearly as easy as before, so an alternate constructor
|
139
|
-
is provided:
|
140
|
-
|
141
|
-
>>> r = RangeMap.left({1: 'a', 4: 'b', 7: RangeMap.undefined_value})
|
142
|
-
>>> r[1], r[2], r[3], r[4], r[5], r[6]
|
143
|
-
('a', 'a', 'a', 'b', 'b', 'b')
|
144
|
-
|
145
|
-
"""
|
146
|
-
|
147
|
-
def __init__(
|
148
|
-
self,
|
149
|
-
source,
|
150
|
-
sort_params: Mapping[str, Any] = {},
|
151
|
-
key_match_comparator=operator.le,
|
152
|
-
):
|
153
|
-
dict.__init__(self, source)
|
154
|
-
self.sort_params = sort_params
|
155
|
-
self.match = key_match_comparator
|
156
|
-
|
157
|
-
@classmethod
|
158
|
-
def left(cls, source):
|
159
|
-
return cls(
|
160
|
-
source, sort_params=dict(reverse=True), key_match_comparator=operator.ge
|
161
|
-
)
|
162
|
-
|
163
|
-
def __getitem__(self, item):
|
164
|
-
sorted_keys = sorted(self.keys(), **self.sort_params)
|
165
|
-
if isinstance(item, RangeMap.Item):
|
166
|
-
result = self.__getitem__(sorted_keys[item])
|
167
|
-
else:
|
168
|
-
key = self._find_first_match_(sorted_keys, item)
|
169
|
-
result = dict.__getitem__(self, key)
|
170
|
-
if result is RangeMap.undefined_value:
|
171
|
-
raise KeyError(key)
|
172
|
-
return result
|
173
|
-
|
174
|
-
def get(self, key, default=None):
|
175
|
-
"""
|
176
|
-
Return the value for key if key is in the dictionary, else default.
|
177
|
-
If default is not given, it defaults to None, so that this method
|
178
|
-
never raises a KeyError.
|
179
|
-
"""
|
180
|
-
try:
|
181
|
-
return self[key]
|
182
|
-
except KeyError:
|
183
|
-
return default
|
184
|
-
|
185
|
-
def _find_first_match_(self, keys, item):
|
186
|
-
is_match = functools.partial(self.match, item)
|
187
|
-
matches = list(filter(is_match, keys))
|
188
|
-
if matches:
|
189
|
-
return matches[0]
|
190
|
-
raise KeyError(item)
|
191
|
-
|
192
|
-
def bounds(self):
|
193
|
-
sorted_keys = sorted(self.keys(), **self.sort_params)
|
194
|
-
return (sorted_keys[RangeMap.first_item], sorted_keys[RangeMap.last_item])
|
195
|
-
|
196
|
-
# some special values for the RangeMap
|
197
|
-
undefined_value = type('RangeValueUndefined', (), {})()
|
198
|
-
|
199
|
-
class Item(int):
|
200
|
-
"RangeMap Item"
|
201
|
-
|
202
|
-
first_item = Item(0)
|
203
|
-
last_item = Item(-1)
|
@@ -236,8 +236,7 @@ class BCPPCompiler(CCompiler):
|
|
236
236
|
temp_dir = os.path.dirname(objects[0]) # preserve tree structure
|
237
237
|
def_file = os.path.join(temp_dir, f'{modname}.def')
|
238
238
|
contents = ['EXPORTS']
|
239
|
-
for sym in export_symbols
|
240
|
-
contents.append(f' {sym}=_{sym}')
|
239
|
+
contents.extend(f' {sym}=_{sym}' for sym in export_symbols)
|
241
240
|
self.execute(write_file, (def_file, contents), f"writing {def_file}")
|
242
241
|
|
243
242
|
# Borland C++ has problems with '/' in paths
|
@@ -22,7 +22,7 @@ from .errors import (
|
|
22
22
|
)
|
23
23
|
from .file_util import move_file
|
24
24
|
from .spawn import spawn
|
25
|
-
from .util import execute,
|
25
|
+
from .util import execute, is_mingw, split_quoted
|
26
26
|
|
27
27
|
|
28
28
|
class CCompiler:
|
@@ -1124,10 +1124,10 @@ def show_compilers():
|
|
1124
1124
|
# commands that use it.
|
1125
1125
|
from distutils.fancy_getopt import FancyGetopt
|
1126
1126
|
|
1127
|
-
compilers =
|
1128
|
-
|
1129
|
-
|
1130
|
-
|
1127
|
+
compilers = sorted(
|
1128
|
+
("compiler=" + compiler, None, compiler_class[compiler][2])
|
1129
|
+
for compiler in compiler_class.keys()
|
1130
|
+
)
|
1131
1131
|
pretty_printer = FancyGetopt(compilers)
|
1132
1132
|
pretty_printer.print_help("List of available compilers:")
|
1133
1133
|
|
@@ -1218,8 +1218,7 @@ def gen_preprocess_options(macros, include_dirs):
|
|
1218
1218
|
# shell at all costs when we spawn the command!
|
1219
1219
|
pp_opts.append("-D{}={}".format(*macro))
|
1220
1220
|
|
1221
|
-
for dir in include_dirs
|
1222
|
-
pp_opts.append(f"-I{dir}")
|
1221
|
+
pp_opts.extend(f"-I{dir}" for dir in include_dirs)
|
1223
1222
|
return pp_opts
|
1224
1223
|
|
1225
1224
|
|
@@ -1230,10 +1229,7 @@ def gen_lib_options(compiler, library_dirs, runtime_library_dirs, libraries):
|
|
1230
1229
|
directories. Returns a list of command-line options suitable for use
|
1231
1230
|
with some compiler (depending on the two format strings passed in).
|
1232
1231
|
"""
|
1233
|
-
lib_opts = []
|
1234
|
-
|
1235
|
-
for dir in library_dirs:
|
1236
|
-
lib_opts.append(compiler.library_dir_option(dir))
|
1232
|
+
lib_opts = [compiler.library_dir_option(dir) for dir in library_dirs]
|
1237
1233
|
|
1238
1234
|
for dir in runtime_library_dirs:
|
1239
1235
|
lib_opts.extend(always_iterable(compiler.runtime_library_dir_option(dir)))
|
@@ -15,9 +15,10 @@ def show_formats():
|
|
15
15
|
"""Print list of available formats (arguments to "--format" option)."""
|
16
16
|
from ..fancy_getopt import FancyGetopt
|
17
17
|
|
18
|
-
formats = [
|
19
|
-
|
20
|
-
|
18
|
+
formats = [
|
19
|
+
("formats=" + format, None, bdist.format_commands[format][1])
|
20
|
+
for format in bdist.format_commands
|
21
|
+
]
|
21
22
|
pretty_printer = FancyGetopt(formats)
|
22
23
|
pretty_printer.print_help("List of available distribution formats:")
|
23
24
|
|
@@ -465,10 +465,7 @@ class build_ext(Command):
|
|
465
465
|
# And build the list of output (built) filenames. Note that this
|
466
466
|
# ignores the 'inplace' flag, and assumes everything goes in the
|
467
467
|
# "build" tree.
|
468
|
-
|
469
|
-
for ext in self.extensions:
|
470
|
-
outputs.append(self.get_ext_fullpath(ext.name))
|
471
|
-
return outputs
|
468
|
+
return [self.get_ext_fullpath(ext.name) for ext in self.extensions]
|
472
469
|
|
473
470
|
def build_extensions(self):
|
474
471
|
# First, sanity-check the 'extensions' list
|
@@ -100,10 +100,9 @@ class check(Command):
|
|
100
100
|
"""
|
101
101
|
metadata = self.distribution.metadata
|
102
102
|
|
103
|
-
missing = [
|
104
|
-
|
105
|
-
|
106
|
-
missing.append(attr)
|
103
|
+
missing = [
|
104
|
+
attr for attr in ('name', 'version') if not getattr(metadata, attr, None)
|
105
|
+
]
|
107
106
|
|
108
107
|
if missing:
|
109
108
|
self.warn("missing required meta-data: {}".format(', '.join(missing)))
|
@@ -5,7 +5,11 @@ platform-independent data files."""
|
|
5
5
|
|
6
6
|
# contributed by Bastian Kleineidam
|
7
7
|
|
8
|
+
from __future__ import annotations
|
9
|
+
|
10
|
+
import functools
|
8
11
|
import os
|
12
|
+
from typing import Iterable
|
9
13
|
|
10
14
|
from ..core import Command
|
11
15
|
from ..util import change_root, convert_path
|
@@ -46,36 +50,42 @@ class install_data(Command):
|
|
46
50
|
def run(self):
|
47
51
|
self.mkpath(self.install_dir)
|
48
52
|
for f in self.data_files:
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
53
|
+
self._copy(f)
|
54
|
+
|
55
|
+
@functools.singledispatchmethod
|
56
|
+
def _copy(self, f: tuple[str | os.PathLike, Iterable[str | os.PathLike]]):
|
57
|
+
# it's a tuple with path to install to and a list of files
|
58
|
+
dir = convert_path(f[0])
|
59
|
+
if not os.path.isabs(dir):
|
60
|
+
dir = os.path.join(self.install_dir, dir)
|
61
|
+
elif self.root:
|
62
|
+
dir = change_root(self.root, dir)
|
63
|
+
self.mkpath(dir)
|
64
|
+
|
65
|
+
if f[1] == []:
|
66
|
+
# If there are no files listed, the user must be
|
67
|
+
# trying to create an empty directory, so add the
|
68
|
+
# directory to the list of output files.
|
69
|
+
self.outfiles.append(dir)
|
70
|
+
else:
|
71
|
+
# Copy files, adding them to the list of output files.
|
72
|
+
for data in f[1]:
|
73
|
+
data = convert_path(data)
|
74
|
+
(out, _) = self.copy_file(data, dir)
|
58
75
|
self.outfiles.append(out)
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
self.outfiles.append(dir)
|
73
|
-
else:
|
74
|
-
# Copy files, adding them to the list of output files.
|
75
|
-
for data in f[1]:
|
76
|
-
data = convert_path(data)
|
77
|
-
(out, _) = self.copy_file(data, dir)
|
78
|
-
self.outfiles.append(out)
|
76
|
+
|
77
|
+
@_copy.register(str)
|
78
|
+
@_copy.register(os.PathLike)
|
79
|
+
def _(self, f: str | os.PathLike):
|
80
|
+
# it's a simple file, so copy it
|
81
|
+
f = convert_path(f)
|
82
|
+
if self.warn_dir:
|
83
|
+
self.warn(
|
84
|
+
"setup script did not provide a directory for "
|
85
|
+
f"'{f}' -- installing right in '{self.install_dir}'"
|
86
|
+
)
|
87
|
+
(out, _) = self.copy_file(f, self.install_dir)
|
88
|
+
self.outfiles.append(out)
|
79
89
|
|
80
90
|
def get_inputs(self):
|
81
91
|
return self.data_files or []
|
@@ -161,9 +161,7 @@ class install_lib(Command):
|
|
161
161
|
build_dir = getattr(build_cmd, cmd_option)
|
162
162
|
|
163
163
|
prefix_len = len(build_dir) + len(os.sep)
|
164
|
-
outputs = []
|
165
|
-
for file in build_files:
|
166
|
-
outputs.append(os.path.join(output_dir, file[prefix_len:]))
|
164
|
+
outputs = [os.path.join(output_dir, file[prefix_len:]) for file in build_files]
|
167
165
|
|
168
166
|
return outputs
|
169
167
|
|
@@ -24,10 +24,10 @@ def show_formats():
|
|
24
24
|
from ..archive_util import ARCHIVE_FORMATS
|
25
25
|
from ..fancy_getopt import FancyGetopt
|
26
26
|
|
27
|
-
formats =
|
28
|
-
|
29
|
-
|
30
|
-
|
27
|
+
formats = sorted(
|
28
|
+
("formats=" + format, None, ARCHIVE_FORMATS[format][2])
|
29
|
+
for format in ARCHIVE_FORMATS.keys()
|
30
|
+
)
|
31
31
|
FancyGetopt(formats).print_help("List of available source distribution formats:")
|
32
32
|
|
33
33
|
|