relenv 0.22.1__py3-none-any.whl → 0.22.3__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.
Files changed (50) hide show
  1. relenv/__init__.py +1 -1
  2. relenv/__main__.py +1 -1
  3. relenv/_resources/xz/crc32_table.c +22 -0
  4. relenv/_resources/xz/crc64_table.c +33 -0
  5. relenv/_resources/xz/readme.md +13 -4
  6. relenv/build/__init__.py +21 -25
  7. relenv/build/common/__init__.py +1 -1
  8. relenv/build/common/_sysconfigdata_template.py +1 -1
  9. relenv/build/common/builder.py +1 -1
  10. relenv/build/common/builders.py +1 -1
  11. relenv/build/common/download.py +1 -1
  12. relenv/build/common/install.py +6 -2
  13. relenv/build/common/ui.py +1 -1
  14. relenv/build/darwin.py +1 -1
  15. relenv/build/linux.py +1 -1
  16. relenv/build/windows.py +9 -1
  17. relenv/buildenv.py +1 -1
  18. relenv/check.py +1 -1
  19. relenv/common.py +2 -4
  20. relenv/create.py +19 -27
  21. relenv/fetch.py +7 -5
  22. relenv/manifest.py +1 -1
  23. relenv/python-versions.json +43 -0
  24. relenv/pyversions.py +49 -1
  25. relenv/relocate.py +118 -4
  26. relenv/runtime.py +29 -20
  27. relenv/toolchain.py +1 -1
  28. {relenv-0.22.1.dist-info → relenv-0.22.3.dist-info}/METADATA +1 -1
  29. relenv-0.22.3.dist-info/RECORD +51 -0
  30. {relenv-0.22.1.dist-info → relenv-0.22.3.dist-info}/WHEEL +1 -1
  31. tests/__init__.py +1 -1
  32. tests/_pytest_typing.py +1 -1
  33. tests/conftest.py +1 -1
  34. tests/test_build.py +3 -7
  35. tests/test_common.py +2 -2
  36. tests/test_create.py +1 -1
  37. tests/test_downloads.py +1 -1
  38. tests/test_fips_photon.py +1 -1
  39. tests/test_module_imports.py +1 -1
  40. tests/test_pyversions_runtime.py +78 -1
  41. tests/test_relocate.py +86 -1
  42. tests/test_relocate_module.py +1 -1
  43. tests/test_relocate_tools.py +152 -0
  44. tests/test_runtime.py +73 -1
  45. tests/test_verify_build.py +10 -5
  46. relenv-0.22.1.dist-info/RECORD +0 -48
  47. {relenv-0.22.1.dist-info → relenv-0.22.3.dist-info}/entry_points.txt +0 -0
  48. {relenv-0.22.1.dist-info → relenv-0.22.3.dist-info}/licenses/LICENSE.md +0 -0
  49. {relenv-0.22.1.dist-info → relenv-0.22.3.dist-info}/licenses/NOTICE +0 -0
  50. {relenv-0.22.1.dist-info → relenv-0.22.3.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,152 @@
1
+ # Copyright 2022-2026 Broadcom.
2
+ # SPDX-License-Identifier: Apache-2.0
3
+
4
+ import pathlib
5
+ from typing import Iterator
6
+ from unittest.mock import patch
7
+
8
+ import pytest
9
+
10
+ from relenv import relocate
11
+
12
+
13
+ @pytest.fixture(autouse=True) # type: ignore[misc]
14
+ def reset_globals() -> Iterator[None]:
15
+ """Reset global caches in relocate module before and after each test."""
16
+ relocate._READELF_BINARY = None
17
+ relocate._PATCHELF_BINARY = None
18
+ yield
19
+ relocate._READELF_BINARY = None
20
+ relocate._PATCHELF_BINARY = None
21
+
22
+
23
+ def test_get_readelf_binary_toolchain_exists(tmp_path: pathlib.Path) -> None:
24
+ """Test that toolchain readelf is used when available."""
25
+ toolchain_root = tmp_path / "toolchain"
26
+ toolchain_root.mkdir()
27
+ triplet = "x86_64-linux-gnu"
28
+
29
+ # Create the fake toolchain binary
30
+ bin_dir = toolchain_root / "bin"
31
+ bin_dir.mkdir(parents=True)
32
+ toolchain_readelf = bin_dir / f"{triplet}-readelf"
33
+ toolchain_readelf.touch()
34
+
35
+ with patch("relenv.relocate.sys.platform", "linux"):
36
+ # We need to mock relenv.common.get_toolchain and get_triplet
37
+ # Since they are imported inside the function, we can patch the module if it's already imported
38
+ # or use patch.dict(sys.modules)
39
+
40
+ # Ensure relenv.common is imported so we can patch it
41
+ import relenv.common # noqa: F401
42
+
43
+ with patch("relenv.common.get_toolchain", return_value=toolchain_root):
44
+ with patch("relenv.common.get_triplet", return_value=triplet):
45
+ readelf = relocate._get_readelf_binary()
46
+
47
+ assert readelf == str(toolchain_readelf)
48
+ assert relocate._READELF_BINARY == str(toolchain_readelf)
49
+
50
+
51
+ def test_get_readelf_binary_toolchain_missing(tmp_path: pathlib.Path) -> None:
52
+ """Test that system readelf is used when toolchain binary is missing."""
53
+ toolchain_root = tmp_path / "toolchain"
54
+ toolchain_root.mkdir()
55
+ triplet = "x86_64-linux-gnu"
56
+
57
+ # Do NOT create the binary
58
+
59
+ with patch("relenv.relocate.sys.platform", "linux"):
60
+ # Ensure relenv.common is imported so we can patch it
61
+ import relenv.common # noqa: F401
62
+
63
+ with patch("relenv.common.get_toolchain", return_value=toolchain_root):
64
+ with patch("relenv.common.get_triplet", return_value=triplet):
65
+ readelf = relocate._get_readelf_binary()
66
+
67
+ assert readelf == "readelf"
68
+ assert relocate._READELF_BINARY == "readelf"
69
+
70
+
71
+ def test_get_readelf_binary_no_toolchain() -> None:
72
+ """Test that system readelf is used when get_toolchain returns None."""
73
+ with patch("relenv.relocate.sys.platform", "linux"):
74
+ # Ensure relenv.common is imported so we can patch it
75
+ import relenv.common # noqa: F401
76
+
77
+ with patch("relenv.common.get_toolchain", return_value=None):
78
+ readelf = relocate._get_readelf_binary()
79
+
80
+ assert readelf == "readelf"
81
+ assert relocate._READELF_BINARY == "readelf"
82
+
83
+
84
+ def test_get_readelf_binary_not_linux() -> None:
85
+ """Test that system readelf is used on non-Linux platforms."""
86
+ with patch("relenv.relocate.sys.platform", "darwin"):
87
+ readelf = relocate._get_readelf_binary()
88
+
89
+ assert readelf == "readelf"
90
+ assert relocate._READELF_BINARY == "readelf"
91
+
92
+
93
+ def test_get_patchelf_binary_toolchain_exists(tmp_path: pathlib.Path) -> None:
94
+ """Test that toolchain patchelf is used when available."""
95
+ toolchain_root = tmp_path / "toolchain"
96
+ toolchain_root.mkdir()
97
+
98
+ # Create the fake toolchain binary
99
+ bin_dir = toolchain_root / "bin"
100
+ bin_dir.mkdir(parents=True)
101
+ toolchain_patchelf = bin_dir / "patchelf"
102
+ toolchain_patchelf.touch()
103
+
104
+ with patch("relenv.relocate.sys.platform", "linux"):
105
+ # Ensure relenv.common is imported so we can patch it
106
+ import relenv.common # noqa: F401
107
+
108
+ with patch("relenv.common.get_toolchain", return_value=toolchain_root):
109
+ patchelf = relocate._get_patchelf_binary()
110
+
111
+ assert patchelf == str(toolchain_patchelf)
112
+ assert relocate._PATCHELF_BINARY == str(toolchain_patchelf)
113
+
114
+
115
+ def test_get_patchelf_binary_toolchain_missing(tmp_path: pathlib.Path) -> None:
116
+ """Test that system patchelf is used when toolchain binary is missing."""
117
+ toolchain_root = tmp_path / "toolchain"
118
+ toolchain_root.mkdir()
119
+
120
+ # Do NOT create the binary
121
+
122
+ with patch("relenv.relocate.sys.platform", "linux"):
123
+ # Ensure relenv.common is imported so we can patch it
124
+ import relenv.common # noqa: F401
125
+
126
+ with patch("relenv.common.get_toolchain", return_value=toolchain_root):
127
+ patchelf = relocate._get_patchelf_binary()
128
+
129
+ assert patchelf == "patchelf"
130
+ assert relocate._PATCHELF_BINARY == "patchelf"
131
+
132
+
133
+ def test_get_patchelf_binary_no_toolchain() -> None:
134
+ """Test that system patchelf is used when get_toolchain returns None."""
135
+ with patch("relenv.relocate.sys.platform", "linux"):
136
+ # Ensure relenv.common is imported so we can patch it
137
+ import relenv.common # noqa: F401
138
+
139
+ with patch("relenv.common.get_toolchain", return_value=None):
140
+ patchelf = relocate._get_patchelf_binary()
141
+
142
+ assert patchelf == "patchelf"
143
+ assert relocate._PATCHELF_BINARY == "patchelf"
144
+
145
+
146
+ def test_get_patchelf_binary_not_linux() -> None:
147
+ """Test that system patchelf is used on non-Linux platforms."""
148
+ with patch("relenv.relocate.sys.platform", "darwin"):
149
+ patchelf = relocate._get_patchelf_binary()
150
+
151
+ assert patchelf == "patchelf"
152
+ assert relocate._PATCHELF_BINARY == "patchelf"
tests/test_runtime.py CHANGED
@@ -1,4 +1,4 @@
1
- # Copyright 2022-2025 Broadcom.
1
+ # Copyright 2022-2026 Broadcom.
2
2
  # SPDX-License-Identifier: Apache-2.0
3
3
  #
4
4
  from __future__ import annotations
@@ -374,6 +374,7 @@ def test_finalize_options_wrapper_appends_include(
374
374
  def test_install_wheel_wrapper_processes_record(
375
375
  tmp_path: pathlib.Path, monkeypatch: pytest.MonkeyPatch
376
376
  ) -> None:
377
+ monkeypatch.setenv("RELENV_BUILDENV", "1")
377
378
  plat_dir = tmp_path / "plat"
378
379
  info_dir = plat_dir / "demo.dist-info"
379
380
  info_dir.mkdir(parents=True)
@@ -440,6 +441,7 @@ def test_install_wheel_wrapper_processes_record(
440
441
  def test_install_wheel_wrapper_missing_file(
441
442
  tmp_path: pathlib.Path, monkeypatch: pytest.MonkeyPatch
442
443
  ) -> None:
444
+ monkeypatch.setenv("RELENV_BUILDENV", "1")
443
445
  plat_dir = tmp_path / "plat"
444
446
  info_dir = plat_dir / "demo.dist-info"
445
447
  info_dir.mkdir(parents=True)
@@ -477,6 +479,7 @@ def test_install_wheel_wrapper_missing_file(
477
479
  def test_install_wheel_wrapper_macho_with_otool(
478
480
  tmp_path: pathlib.Path, monkeypatch: pytest.MonkeyPatch
479
481
  ) -> None:
482
+ monkeypatch.setenv("RELENV_BUILDENV", "1")
480
483
  plat_dir = tmp_path / "plat"
481
484
  info_dir = plat_dir / "demo.dist-info"
482
485
  info_dir.mkdir(parents=True)
@@ -520,6 +523,7 @@ def test_install_wheel_wrapper_macho_with_otool(
520
523
  def test_install_wheel_wrapper_macho_without_otool(
521
524
  tmp_path: pathlib.Path, monkeypatch: pytest.MonkeyPatch
522
525
  ) -> None:
526
+ monkeypatch.setenv("RELENV_BUILDENV", "1")
523
527
  plat_dir = tmp_path / "plat"
524
528
  info_dir = plat_dir / "demo.dist-info"
525
529
  info_dir.mkdir(parents=True)
@@ -565,6 +569,74 @@ def test_install_wheel_wrapper_macho_without_otool(
565
569
  assert any("otool command is not available" in msg for msg in messages)
566
570
 
567
571
 
572
+ def test_install_wheel_wrapper_skips_without_buildenv(
573
+ tmp_path: pathlib.Path, monkeypatch: pytest.MonkeyPatch
574
+ ) -> None:
575
+ monkeypatch.delenv("RELENV_BUILDENV", raising=False)
576
+ plat_dir = tmp_path / "plat"
577
+ info_dir = plat_dir / "demo.dist-info"
578
+ info_dir.mkdir(parents=True)
579
+ record = info_dir / "RECORD"
580
+ record.write_text("libdemo.so,,\n")
581
+ binary = plat_dir / "libdemo.so"
582
+ binary.touch()
583
+
584
+ # If relocation runs, this mock will raise an error or capture calls
585
+ handled: list[tuple[pathlib.Path, pathlib.Path]] = []
586
+ monkeypatch.setattr(
587
+ relenv.runtime,
588
+ "relocate",
589
+ lambda: SimpleNamespace(
590
+ is_elf=lambda path: path.name.endswith(".so"),
591
+ is_macho=lambda path: False,
592
+ handle_elf=lambda file, lib_dir, fix, root: handled.append((file, lib_dir)),
593
+ handle_macho=lambda *args, **kwargs: None,
594
+ ),
595
+ )
596
+
597
+ wheel_utils = ModuleType("pip._internal.utils.wheel")
598
+ wheel_utils.parse_wheel = lambda _zf, _name: ("demo.dist-info", {})
599
+ monkeypatch.setitem(sys.modules, wheel_utils.__name__, wheel_utils)
600
+
601
+ class DummyZip:
602
+ def __init__(self, path: pathlib.Path) -> None:
603
+ self.path = path
604
+
605
+ def __enter__(self) -> DummyZip:
606
+ return self
607
+
608
+ def __exit__(self, *exc: object) -> bool:
609
+ return False
610
+
611
+ monkeypatch.setattr("zipfile.ZipFile", DummyZip)
612
+
613
+ install_module = ModuleType("pip._internal.operations.install.wheel")
614
+
615
+ def original_install(*_args: object, **_kwargs: object) -> str:
616
+ return "original"
617
+
618
+ install_module.install_wheel = original_install # type: ignore[attr-defined]
619
+ monkeypatch.setitem(sys.modules, install_module.__name__, install_module)
620
+
621
+ wrapped_module = relenv.runtime.wrap_pip_install_wheel(install_module.__name__)
622
+
623
+ scheme = SimpleNamespace(
624
+ platlib=str(plat_dir),
625
+ )
626
+ wrapped_module.install_wheel(
627
+ "demo",
628
+ tmp_path / "wheel.whl",
629
+ scheme,
630
+ "desc",
631
+ None,
632
+ None,
633
+ None,
634
+ None,
635
+ )
636
+
637
+ assert not handled
638
+
639
+
568
640
  def test_install_legacy_wrapper_prefix(
569
641
  monkeypatch: pytest.MonkeyPatch, tmp_path: pathlib.Path
570
642
  ) -> None:
@@ -1,4 +1,4 @@
1
- # Copyright 2022-2025 Broadcom.
1
+ # Copyright 2022-2026 Broadcom.
2
2
  # SPDX-License-Identifier: Apache-2.0
3
3
  # mypy: ignore-errors
4
4
  """
@@ -180,13 +180,15 @@ def test_imports(pyexec):
180
180
 
181
181
 
182
182
  def test_pip_install_salt_git(pipexec, build, build_dir, pyexec, build_version):
183
- if (
184
- sys.platform == "win32"
185
- and "3.11" in build_version
183
+ if sys.platform == "win32" and (
184
+ "3.10" in build_version
185
+ or "3.11" in build_version
186
186
  or "3.12" in build_version
187
187
  or "3.13" in build_version
188
188
  ):
189
- pytest.xfail("Salt does not work with 3.11 or 3.12 on windows yet")
189
+ pytest.xfail(
190
+ "Salt git install fails on Windows (setup.py tries to install missing man pages)"
191
+ )
190
192
  if sys.platform == "darwin" and "3.12" in build_version:
191
193
  pytest.xfail("Salt does not work with 3.12 on macos yet")
192
194
  if sys.platform == "darwin" and "3.13" in build_version:
@@ -517,6 +519,9 @@ def test_pip_install_pyzmq(
517
519
  env["RELENV_BUILDENV"] = "yes"
518
520
  env["USE_STATIC_REQUIREMENTS"] = "1"
519
521
 
522
+ if pyzmq_version == "26.2.0":
523
+ env["CMAKE_ARGS"] = "-DCMAKE_POLICY_VERSION_MINIMUM=3.5"
524
+
520
525
  if sys.platform == "linux":
521
526
  fake_bsd_root = tmp_path / "fake_libbsd"
522
527
  (fake_bsd_root / "bsd").mkdir(parents=True, exist_ok=True)
@@ -1,48 +0,0 @@
1
- relenv/__init__.py,sha256=JGbn7yb2-o9LBupMRzj1RYcvMWC6eB8yJv76NHCM0-w,325
2
- relenv/__main__.py,sha256=6N3x5KYX02c2xLWvvtmmLjpcG5Oi2yt9DvP0UW4srM8,1538
3
- relenv/buildenv.py,sha256=MioqMak_bjA5lhKUU8NDyJOFvjv7MoGY2S7PJld-vyA,4120
4
- relenv/check.py,sha256=KnYu60lKud9bwAyUKEzSn5MNBHpA6e3D_pGe_Toml70,1133
5
- relenv/common.py,sha256=Fu8buI3przHoSuOFyAeHQSw2DxcwLu1YlJG0pAWSlUQ,35854
6
- relenv/create.py,sha256=8Pxqc5rrOER8iWiOMFwA6b0oG7il6fICyjhGh4h2uw0,8383
7
- relenv/fetch.py,sha256=6kIla7zOV43r-1NAXzOg4TFGH6z0vPOcF99SkneGSPA,2567
8
- relenv/manifest.py,sha256=W2QTjPsDHlm4OLUpL1bwIGvlNpJijhh1LDYidqCm538,1057
9
- relenv/python-versions.json,sha256=axX8aDQhLwdQn55WRYc5JbQd9_qV9yw6Syue-7ieWh8,14571
10
- relenv/pyversions.py,sha256=8SnFqHdtb0Lrp4JH7Ri6h-YHJngroh8SOL1chHn3GjY,41276
11
- relenv/relocate.py,sha256=Xfmr1lTMu7DwB8SdMIYQFFfC5La5je8Z33G4md557ew,13182
12
- relenv/runtime.py,sha256=YLKuJmpQSmTr9r4FQ82J7VGFFXjo4LT0k8bHo1RyHRY,40035
13
- relenv/toolchain.py,sha256=wRRtgDfkOsvY6N1wQQWf7cc7SRXaFBsO_gxIK8mfjOM,929
14
- relenv/_resources/xz/config.h,sha256=2IofvMqyAa8xBaQb6QGStiUugMmjyUCq_Of5drh7fro,4117
15
- relenv/_resources/xz/readme.md,sha256=aOs7hz9RhTnTwHUt6gbO-2Sl0xLKIJp8-w6Du4VIFgY,258
16
- relenv/_scripts/install_vc_build.ps1,sha256=ir1bcz7rNOuFw4E5_AqBidiKS0SpPViXW7zaanRPCoM,7629
17
- relenv/build/__init__.py,sha256=Wfs38kXJTKJodtWLAvAUeEOrVnu0ss-krzv2ICM7XnI,6341
18
- relenv/build/darwin.py,sha256=OvsTmpKq87WILxkmjP0aDdUv8lh3DadJ5MwRqPyXXK0,7131
19
- relenv/build/linux.py,sha256=S5v4jp4_nCYN3H5h_fel-VbjQcuY_XfZqBeFWdS6qjo,26156
20
- relenv/build/windows.py,sha256=b1hxd8NmmbvblB8W7-qu_b1_TdMQBNl3Vee-C-edUHc,16102
21
- relenv/build/common/__init__.py,sha256=YzSyjBpW6StrbiQ4Q0CCT4Iaj-wok2ZtuaHW4cCheDE,1004
22
- relenv/build/common/_sysconfigdata_template.py,sha256=six70jAkN_4eBP4aKrJhABu9hXMxudUE6ccNQbQT-J8,1955
23
- relenv/build/common/builder.py,sha256=RaRlWMeShYRcTvT47ry135cpeqhEJ_lMwHZeMtZCuGM,31000
24
- relenv/build/common/builders.py,sha256=sEwJu9HApcPwp2nSrDHvX42Jc8W3dqRqo4Kt9D2mNdo,4772
25
- relenv/build/common/download.py,sha256=jHuIrc5jhDGoa4lWGMYdrO6FsYxJvmiuTVhjDzs7ogc,10479
26
- relenv/build/common/install.py,sha256=1s8cl2GV8yauGAIyAqsOvAWZEorWPPI_hrHkk3Oy9_4,19201
27
- relenv/build/common/ui.py,sha256=j14BE0uFqa5u8XoSBfphSW38XSwboi4StMJ81gLgkkQ,14192
28
- relenv-0.22.1.dist-info/licenses/LICENSE.md,sha256=T0SRk3vJM1YcAJjDz9vsX9gsCRatAVSBS7LeU0tklRM,9919
29
- relenv-0.22.1.dist-info/licenses/NOTICE,sha256=Ns0AybPHBsgJKJJfjE6YnGgWEQQ9F7lQ6QNlYLlQT3E,548
30
- tests/__init__.py,sha256=PFmZ0Etkh3YyYMcTEuVClZE9LTIC_7LYZQ-U6TpFO-g,70
31
- tests/_pytest_typing.py,sha256=aTeDhNtOJCKhwkZ-BP560Zi4Jkac_Ylv1RimBpNGtMA,1204
32
- tests/conftest.py,sha256=inPHwb4duz33BzIxfPoH3z3PK_dbMCbtytUZU785NPk,2628
33
- tests/test_build.py,sha256=48-4ZWdDk8oCHiWcGhhWoPwyqOhZNrSfXrEsXZuhfmw,14992
34
- tests/test_common.py,sha256=rf1WcIDf_StEoF2iWk7YxHySrd2VZlpUwHxoWrJnkMI,18008
35
- tests/test_create.py,sha256=rjJ7mvInJXqn0r3a5D_q6zzftR4pkzI7M-ipkR5qD9U,6849
36
- tests/test_downloads.py,sha256=OJViW_atWbQiAUhHImIp4dU7U4hNoJQVDEFD-0hSHx8,3528
37
- tests/test_fips_photon.py,sha256=LD6a3jUmMmNrERoDPYgW63ts1Dy48aMr4eZpzkGcixE,1397
38
- tests/test_module_imports.py,sha256=RhwPeUvdKLvuFcZSxCt2WCu81SKTjykaunrrN1sORpw,1354
39
- tests/test_pyversions_runtime.py,sha256=utmG3CLP061AIbAqRE0n6mVqsQ2DCZDc54LUz3SOQts,5980
40
- tests/test_relocate.py,sha256=TAYARIL5VRCEPwz1HL1BJpvUSS6RQkk4D0DqGag7rv4,9694
41
- tests/test_relocate_module.py,sha256=G_KQqR5d7y7WCru_c2fPZKplhtzKgAJX9QONEQmzUAI,7802
42
- tests/test_runtime.py,sha256=MvXMNnM2g0Oz9Ftr2mtCmA7zew_lrA6vIoiWnfW3OuI,71990
43
- tests/test_verify_build.py,sha256=G4HsBbtHCYgBGX1KFKbm3_cskJZcQT6m4hBfZOeltig,67750
44
- relenv-0.22.1.dist-info/METADATA,sha256=7UbXO1pdPL30mjiBbjhWmV0LStAc_58FAKdKOelw_Jw,1360
45
- relenv-0.22.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
46
- relenv-0.22.1.dist-info/entry_points.txt,sha256=dO66nWPPWl8ALWWnZFlHKAo6mfPFuQid7purYWL2ddc,48
47
- relenv-0.22.1.dist-info/top_level.txt,sha256=P4Ro6JLZE53ZdsQ76o2OzBcpb0MaVJmbfr0HAn9WF8M,13
48
- relenv-0.22.1.dist-info/RECORD,,