Skip to content

Commit 458ffae

Browse files
committed
Fix up imports
1 parent 2a49ca0 commit 458ffae

File tree

4 files changed

+112
-26
lines changed

4 files changed

+112
-26
lines changed

relenv/build/darwin.py

Lines changed: 9 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, runcmd
@@ -17,6 +24,8 @@
1724
builds,
1825
finalize,
1926
get_dependency_version,
27+
runcmd,
28+
update_sbom_checksums,
2029
)
2130

2231
ARCHES = arches[DARWIN]
@@ -52,12 +61,6 @@ def update_expat(dirs: Dirs, env: MutableMapping[str, str]) -> None:
5261
Python ships with an older bundled expat. This function updates it
5362
to the latest version for security and bug fixes.
5463
"""
55-
import pathlib
56-
import shutil
57-
import glob
58-
import urllib.request
59-
import tarfile
60-
6164
# Get version from JSON
6265
expat_info = get_dependency_version("expat", "darwin")
6366
if not expat_info:
@@ -96,16 +99,11 @@ def update_expat(dirs: Dirs, env: MutableMapping[str, str]) -> None:
9699

97100
# Touch all updated files to ensure make rebuilds them
98101
# (The tarball may contain files with newer timestamps)
99-
import time
100-
import os
101-
102102
now = time.time()
103103
for target_file in updated_files:
104104
os.utime(target_file, (now, now))
105105

106106
# Update SBOM with correct checksums for updated expat files
107-
from relenv.build.common import update_sbom_checksums
108-
109107
files_to_update = {}
110108
for target_file in updated_files:
111109
# SBOM uses relative paths from Python source root

relenv/build/linux.py

Lines changed: 6 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 (
@@ -21,6 +25,8 @@
2125
builds,
2226
finalize,
2327
get_dependency_version,
28+
runcmd,
29+
update_sbom_checksums,
2430
)
2531
from ..common import LINUX, Version, arches, runcmd
2632

@@ -367,13 +373,6 @@ def update_expat(dirs: Dirs, env: EnvMapping) -> None:
367373
Python ships with an older bundled expat. This function updates it
368374
to the latest version for security and bug fixes.
369375
"""
370-
from .common import get_dependency_version
371-
import urllib.request
372-
import tarfile
373-
import glob
374-
import pathlib
375-
import shutil
376-
377376
# Get version from JSON
378377
expat_info = get_dependency_version("expat", "linux")
379378
if not expat_info:
@@ -412,15 +411,11 @@ def update_expat(dirs: Dirs, env: EnvMapping) -> None:
412411

413412
# Touch all updated files to ensure make rebuilds them
414413
# (The tarball may contain files with newer timestamps)
415-
import time
416-
417414
now = time.time()
418415
for target_file in updated_files:
419416
os.utime(target_file, (now, now))
420417

421418
# Update SBOM with correct checksums for updated expat files
422-
from relenv.build.common import update_sbom_checksums
423-
424419
files_to_update = {}
425420
for target_file in updated_files:
426421
# 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 (
@@ -24,6 +25,7 @@
2425
install_runtime,
2526
patch_file,
2627
update_ensurepip,
28+
update_sbom_checksums,
2729
)
2830
from ..common import (
2931
WIN32,
@@ -149,6 +151,25 @@ def update_sqlite(dirs: Dirs, env: EnvMapping) -> None:
149151
def update_xz(dirs: Dirs, env: EnvMapping) -> None:
150152
"""
151153
Update the XZ library.
154+
155+
COMPATIBILITY NOTE: We use config.h from XZ 5.4.7 for all XZ versions.
156+
Starting with XZ 5.5.0, the project removed Visual Studio .vcxproj files
157+
and switched to CMake. Python's build system (PCbuild/liblzma.vcxproj)
158+
still expects MSBuild-compatible builds, so we maintain a compatibility
159+
shim at relenv/_resources/xz/config.h.
160+
161+
When updating XZ versions, verify compatibility by checking:
162+
1. Build completes without compiler errors
163+
2. test_xz_lzma_functionality passes
164+
3. No new HAVE_* defines required in src/liblzma source files
165+
4. No removed HAVE_* defines that config.h references
166+
167+
If compatibility breaks, you have two options:
168+
- Use CMake to generate new config.h for Windows (see discussion at
169+
https://discuss.python.org/t/building-python-from-source-on-windows-using-a-custom-version-of-xz/74717)
170+
- Update relenv/_resources/xz/config.h manually from newer XZ source
171+
172+
See also: relenv/_resources/xz/readme.md
152173
"""
153174
# Try to get version from JSON
154175
# Note: Windows may use a different XZ version than Linux/Darwin due to MSBuild compatibility
@@ -241,16 +262,12 @@ def update_expat(dirs: Dirs, env: EnvMapping) -> None:
241262

242263
# Touch all updated files to ensure MSBuild rebuilds them
243264
# (The original files may have newer timestamps)
244-
import time
245-
246265
now = time.time()
247266
for target_file in updated_files:
248267
os.utime(target_file, (now, now))
249268

250269
# Update SBOM with correct checksums for updated expat files
251270
# Map SBOM file names to actual file paths
252-
from relenv.build.common import update_sbom_checksums
253-
254271
files_to_update = {}
255272
for target_file in updated_files:
256273
# 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)