Skip to content

Commit 4496323

Browse files
committed
Fix up imports
1 parent 9e2a80b commit 4496323

File tree

4 files changed

+110
-26
lines changed

4 files changed

+110
-26
lines changed

relenv/build/darwin.py

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,14 @@
66
"""
77
from __future__ import annotations
88

9+
import glob
910
import io
11+
import os
12+
import pathlib
13+
import shutil
14+
import tarfile
15+
import time
16+
import urllib.request
1017
from typing import IO, MutableMapping
1118

1219
from ..common import DARWIN, MACOS_DEVELOPMENT_TARGET, arches
@@ -18,6 +25,7 @@
1825
finalize,
1926
get_dependency_version,
2027
runcmd,
28+
update_sbom_checksums,
2129
)
2230

2331
ARCHES = arches[DARWIN]
@@ -53,12 +61,6 @@ def update_expat(dirs: Dirs, env: MutableMapping[str, str]) -> None:
5361
Python ships with an older bundled expat. This function updates it
5462
to the latest version for security and bug fixes.
5563
"""
56-
import pathlib
57-
import shutil
58-
import glob
59-
import urllib.request
60-
import tarfile
61-
6264
# Get version from JSON
6365
expat_info = get_dependency_version("expat", "darwin")
6466
if not expat_info:
@@ -97,16 +99,11 @@ def update_expat(dirs: Dirs, env: MutableMapping[str, str]) -> None:
9799

98100
# Touch all updated files to ensure make rebuilds them
99101
# (The tarball may contain files with newer timestamps)
100-
import time
101-
import os
102-
103102
now = time.time()
104103
for target_file in updated_files:
105104
os.utime(target_file, (now, now))
106105

107106
# Update SBOM with correct checksums for updated expat files
108-
from relenv.build.common import update_sbom_checksums
109-
110107
files_to_update = {}
111108
for target_file in updated_files:
112109
# SBOM uses relative paths from Python source root

relenv/build/linux.py

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,15 @@
66
"""
77
from __future__ import annotations
88

9+
import glob
910
import io
1011
import os
1112
import pathlib
1213
import shutil
14+
import tarfile
1315
import tempfile
16+
import time
17+
import urllib.request
1418
from typing import IO, MutableMapping
1519

1620
from .common import (
@@ -22,6 +26,7 @@
2226
finalize,
2327
get_dependency_version,
2428
runcmd,
29+
update_sbom_checksums,
2530
)
2631
from ..common import LINUX, Version, arches
2732

@@ -368,13 +373,6 @@ def update_expat(dirs: Dirs, env: EnvMapping) -> None:
368373
Python ships with an older bundled expat. This function updates it
369374
to the latest version for security and bug fixes.
370375
"""
371-
from .common import get_dependency_version
372-
import urllib.request
373-
import tarfile
374-
import glob
375-
import pathlib
376-
import shutil
377-
378376
# Get version from JSON
379377
expat_info = get_dependency_version("expat", "linux")
380378
if not expat_info:
@@ -413,15 +411,11 @@ def update_expat(dirs: Dirs, env: EnvMapping) -> None:
413411

414412
# Touch all updated files to ensure make rebuilds them
415413
# (The tarball may contain files with newer timestamps)
416-
import time
417-
418414
now = time.time()
419415
for target_file in updated_files:
420416
os.utime(target_file, (now, now))
421417

422418
# Update SBOM with correct checksums for updated expat files
423-
from relenv.build.common import update_sbom_checksums
424-
425419
files_to_update = {}
426420
for target_file in updated_files:
427421
# SBOM uses relative paths from Python source root

relenv/build/windows.py

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import shutil
1515
import sys
1616
import tarfile
17+
import time
1718
from typing import IO, MutableMapping, Union
1819

1920
from .common import (
@@ -28,6 +29,7 @@
2829
patch_file,
2930
runcmd,
3031
update_ensurepip,
32+
update_sbom_checksums,
3133
)
3234
from ..common import WIN32, arches
3335

@@ -145,6 +147,25 @@ def update_sqlite(dirs: Dirs, env: EnvMapping) -> None:
145147
def update_xz(dirs: Dirs, env: EnvMapping) -> None:
146148
"""
147149
Update the XZ library.
150+
151+
COMPATIBILITY NOTE: We use config.h from XZ 5.4.7 for all XZ versions.
152+
Starting with XZ 5.5.0, the project removed Visual Studio .vcxproj files
153+
and switched to CMake. Python's build system (PCbuild/liblzma.vcxproj)
154+
still expects MSBuild-compatible builds, so we maintain a compatibility
155+
shim at relenv/_resources/xz/config.h.
156+
157+
When updating XZ versions, verify compatibility by checking:
158+
1. Build completes without compiler errors
159+
2. test_xz_lzma_functionality passes
160+
3. No new HAVE_* defines required in src/liblzma source files
161+
4. No removed HAVE_* defines that config.h references
162+
163+
If compatibility breaks, you have two options:
164+
- Use CMake to generate new config.h for Windows (see discussion at
165+
https://discuss.python.org/t/building-python-from-source-on-windows-using-a-custom-version-of-xz/74717)
166+
- Update relenv/_resources/xz/config.h manually from newer XZ source
167+
168+
See also: relenv/_resources/xz/readme.md
148169
"""
149170
# Try to get version from JSON
150171
# Note: Windows may use a different XZ version than Linux/Darwin due to MSBuild compatibility
@@ -237,16 +258,12 @@ def update_expat(dirs: Dirs, env: EnvMapping) -> None:
237258

238259
# Touch all updated files to ensure MSBuild rebuilds them
239260
# (The original files may have newer timestamps)
240-
import time
241-
242261
now = time.time()
243262
for target_file in updated_files:
244263
os.utime(target_file, (now, now))
245264

246265
# Update SBOM with correct checksums for updated expat files
247266
# Map SBOM file names to actual file paths
248-
from relenv.build.common import update_sbom_checksums
249-
250267
files_to_update = {}
251268
for target_file in updated_files:
252269
# SBOM uses relative paths from Python source root

tests/test_verify_build.py

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2249,3 +2249,79 @@ def test_openssl_version(pyexec):
22492249
f"OpenSSL version mismatch on {platform}: expected {expected_version}, "
22502250
f"found {actual_version} (from {actual_version_str})"
22512251
)
2252+
2253+
2254+
def test_xz_lzma_functionality(pyexec):
2255+
"""
2256+
Verify that the lzma module works correctly.
2257+
2258+
This is especially important for Windows builds which use a config.h
2259+
compatibility shim from XZ 5.4.7 to support newer XZ versions that
2260+
removed MSBuild support.
2261+
2262+
If this test fails, it indicates that the config.h in
2263+
relenv/_resources/xz/config.h is no longer compatible with the
2264+
current XZ version being used.
2265+
2266+
Works on all platforms: Linux, Darwin (macOS), and Windows.
2267+
"""
2268+
# Test that lzma module loads and basic compression works
2269+
test_code = """
2270+
import lzma
2271+
import sys
2272+
2273+
# Test basic compression/decompression
2274+
test_data = b"Hello, World! " * 100
2275+
compressed = lzma.compress(test_data)
2276+
decompressed = lzma.decompress(compressed)
2277+
2278+
if test_data != decompressed:
2279+
print("ERROR: Decompressed data does not match original", file=sys.stderr)
2280+
sys.exit(1)
2281+
2282+
# Verify compression actually happened
2283+
if len(compressed) >= len(test_data):
2284+
print("ERROR: Compression did not reduce size", file=sys.stderr)
2285+
sys.exit(2)
2286+
2287+
# Test different formats (skip FORMAT_RAW as it requires explicit filters)
2288+
for fmt in [lzma.FORMAT_XZ, lzma.FORMAT_ALONE]:
2289+
try:
2290+
data = lzma.compress(test_data, format=fmt)
2291+
result = lzma.decompress(data)
2292+
if result != test_data:
2293+
print(f"ERROR: Format {fmt} failed round-trip", file=sys.stderr)
2294+
sys.exit(3)
2295+
except Exception as e:
2296+
print(f"ERROR: Format {fmt} raised exception: {e}", file=sys.stderr)
2297+
sys.exit(4)
2298+
2299+
# Test streaming compression/decompression
2300+
import io
2301+
output = io.BytesIO()
2302+
with lzma.LZMAFile(output, "w") as f:
2303+
f.write(test_data)
2304+
2305+
compressed_stream = output.getvalue()
2306+
input_stream = io.BytesIO(compressed_stream)
2307+
with lzma.LZMAFile(input_stream, "r") as f:
2308+
decompressed_stream = f.read()
2309+
2310+
if decompressed_stream != test_data:
2311+
print("ERROR: Streaming compression/decompression failed", file=sys.stderr)
2312+
sys.exit(5)
2313+
2314+
print("OK")
2315+
"""
2316+
2317+
proc = subprocess.run(
2318+
[str(pyexec), "-c", test_code],
2319+
capture_output=True,
2320+
check=False,
2321+
)
2322+
2323+
assert proc.returncode == 0, (
2324+
f"LZMA functionality test failed (exit code {proc.returncode}): "
2325+
f"{proc.stderr.decode()}"
2326+
)
2327+
assert proc.stdout.decode().strip() == "OK"

0 commit comments

Comments
 (0)