portable-python 1.9.8__tar.gz → 1.10.0__tar.gz

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 (38) hide show
  1. {portable_python-1.9.8 → portable_python-1.10.0}/DEVELOP.md +8 -15
  2. {portable_python-1.9.8/src/portable_python.egg-info → portable_python-1.10.0}/PKG-INFO +4 -4
  3. {portable_python-1.9.8 → portable_python-1.10.0}/pyproject.toml +1 -1
  4. {portable_python-1.9.8 → portable_python-1.10.0}/setup.py +1 -2
  5. {portable_python-1.9.8 → portable_python-1.10.0}/src/portable_python/__init__.py +44 -2
  6. {portable_python-1.9.8 → portable_python-1.10.0}/src/portable_python/external/__init__.py +1 -1
  7. {portable_python-1.9.8 → portable_python-1.10.0}/src/portable_python/external/xcpython.py +7 -7
  8. {portable_python-1.9.8 → portable_python-1.10.0}/src/portable_python/versions.py +1 -1
  9. {portable_python-1.9.8 → portable_python-1.10.0/src/portable_python.egg-info}/PKG-INFO +4 -4
  10. {portable_python-1.9.8 → portable_python-1.10.0}/tests/test_failed.py +1 -1
  11. {portable_python-1.9.8 → portable_python-1.10.0}/tests/test_list.py +5 -5
  12. {portable_python-1.9.8 → portable_python-1.10.0}/tests/test_setup.py +7 -0
  13. {portable_python-1.9.8 → portable_python-1.10.0}/LICENSE +0 -0
  14. {portable_python-1.9.8 → portable_python-1.10.0}/MANIFEST.in +0 -0
  15. {portable_python-1.9.8 → portable_python-1.10.0}/README.rst +0 -0
  16. {portable_python-1.9.8 → portable_python-1.10.0}/SECURITY.md +0 -0
  17. {portable_python-1.9.8 → portable_python-1.10.0}/requirements.txt +0 -0
  18. {portable_python-1.9.8 → portable_python-1.10.0}/setup.cfg +0 -0
  19. {portable_python-1.9.8 → portable_python-1.10.0}/src/portable_python/__main__.py +0 -0
  20. {portable_python-1.9.8 → portable_python-1.10.0}/src/portable_python/cli.py +0 -0
  21. {portable_python-1.9.8 → portable_python-1.10.0}/src/portable_python/config.py +0 -0
  22. {portable_python-1.9.8 → portable_python-1.10.0}/src/portable_python/cpython.py +0 -0
  23. {portable_python-1.9.8 → portable_python-1.10.0}/src/portable_python/external/_inspect.py +0 -0
  24. {portable_python-1.9.8 → portable_python-1.10.0}/src/portable_python/external/xtkinter.py +0 -0
  25. {portable_python-1.9.8 → portable_python-1.10.0}/src/portable_python/inspector.py +0 -0
  26. {portable_python-1.9.8 → portable_python-1.10.0}/src/portable_python/tracking.py +0 -0
  27. {portable_python-1.9.8 → portable_python-1.10.0}/src/portable_python.egg-info/SOURCES.txt +0 -0
  28. {portable_python-1.9.8 → portable_python-1.10.0}/src/portable_python.egg-info/dependency_links.txt +0 -0
  29. {portable_python-1.9.8 → portable_python-1.10.0}/src/portable_python.egg-info/entry_points.txt +0 -0
  30. {portable_python-1.9.8 → portable_python-1.10.0}/src/portable_python.egg-info/requires.txt +0 -0
  31. {portable_python-1.9.8 → portable_python-1.10.0}/src/portable_python.egg-info/top_level.txt +0 -0
  32. {portable_python-1.9.8 → portable_python-1.10.0}/tests/test_build.py +0 -0
  33. {portable_python-1.9.8 → portable_python-1.10.0}/tests/test_cleanup.py +0 -0
  34. {portable_python-1.9.8 → portable_python-1.10.0}/tests/test_inspector.py +0 -0
  35. {portable_python-1.9.8 → portable_python-1.10.0}/tests/test_invoker.py +0 -0
  36. {portable_python-1.9.8 → portable_python-1.10.0}/tests/test_prefix.py +0 -0
  37. {portable_python-1.9.8 → portable_python-1.10.0}/tests/test_recompress.py +0 -0
  38. {portable_python-1.9.8 → portable_python-1.10.0}/tests/test_report.py +0 -0
@@ -1,16 +1,11 @@
1
- # How to create a dev venv
1
+ # Local development
2
2
 
3
- If you have tox, you can run: `tox -re venv`, that will get you a `.venv/`
4
- ready to go.
5
-
6
- If you don't have tox, you can run this (any python 3.6+ will do):
3
+ Create a dev venv:
7
4
 
8
5
  ```shell
9
- rm -rf .venv
10
- /usr/bin/python3 -mvenv .venv
11
- .venv/bin/pip install -U pip
12
- .venv/bin/pip install -r requirements.txt -r tests/requirements.txt
13
- .venv/bin/pip install -e .
6
+ uv venv
7
+ uv pip install -r requirements.txt -r tests/requirements.txt
8
+ uv pip install -e .
14
9
  ```
15
10
 
16
11
  You can then run `portable-python` from that venv:
@@ -24,10 +19,8 @@ You can then run `portable-python` from that venv:
24
19
  # Run the tests
25
20
 
26
21
  If you have tox, just run: `tox` to run all the tests. You can also run:
27
- - `tox -e py39` to run with just one python version
22
+ - `tox -e py313` to run with just one python version
28
23
  - `tox -e style` to check PEP8 formatting
29
- - `tox -r` if you changed any `requirements.txt` (`-r` is short for `--recreate`)
30
- - `tox -re py39` to recreate and run `py39` only
31
24
  - etc
32
25
 
33
26
  If you don't have tox, you can run the tests with: `.venv/bin/pytest tests/`
@@ -49,7 +42,7 @@ You can easily run `portable-python` in a debugger.
49
42
  In PyCharm for example, you would simply browse to `.venv/bin/portable-python`
50
43
  then right-click and select "Debug portable-python".
51
44
  You can then edit the build/run configuration in PyCharm, add some "Parameters" to it,
52
- like for example `build-report 3.10.5`, and then set breakpoints wherever you like.
45
+ like for example `build-report 3.13.2`, and then set breakpoints wherever you like.
53
46
 
54
47
  There is a `--dryrun` mode that can come in very handy for rapid iterations.
55
48
 
@@ -71,5 +64,5 @@ docker run -it -v./:/src/ portable-python-jammy /bin/bash
71
64
  Now inside docker, you run a build:
72
65
 
73
66
  ```shell
74
- portable-python build 3.11.4
67
+ portable-python build 3.13.2
75
68
  ```
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: portable-python
3
- Version: 1.9.8
3
+ Version: 1.10.0
4
4
  Summary: Portable python binaries
5
5
  Home-page: https://github.com/codrsquad/portable-python
6
6
  Author: Zoran Simic
@@ -18,7 +18,6 @@ Classifier: Operating System :: POSIX
18
18
  Classifier: Operating System :: Unix
19
19
  Classifier: Programming Language :: Python
20
20
  Classifier: Programming Language :: Python :: 3
21
- Classifier: Programming Language :: Python :: 3.8
22
21
  Classifier: Programming Language :: Python :: 3.9
23
22
  Classifier: Programming Language :: Python :: 3.10
24
23
  Classifier: Programming Language :: Python :: 3.11
@@ -29,7 +28,7 @@ Classifier: Topic :: Software Development :: Build Tools
29
28
  Classifier: Topic :: System :: Installation/Setup
30
29
  Classifier: Topic :: System :: Software Distribution
31
30
  Classifier: Topic :: Utilities
32
- Requires-Python: >=3.8
31
+ Requires-Python: >=3.9
33
32
  Description-Content-Type: text/x-rst
34
33
  License-File: LICENSE
35
34
  Requires-Dist: click~=8.0
@@ -45,6 +44,7 @@ Dynamic: description-content-type
45
44
  Dynamic: home-page
46
45
  Dynamic: keywords
47
46
  Dynamic: license
47
+ Dynamic: license-file
48
48
  Dynamic: project-url
49
49
  Dynamic: requires-dist
50
50
  Dynamic: requires-python
@@ -63,7 +63,7 @@ ignore = [
63
63
  order-by-type = false
64
64
 
65
65
  [tool.ruff.lint.mccabe]
66
- max-complexity = 14
66
+ max-complexity = 18
67
67
 
68
68
  [tool.ruff.lint.pydocstyle]
69
69
  convention = "numpy"
@@ -7,7 +7,7 @@ setup(
7
7
  author="Zoran Simic zoran@simicweb.com",
8
8
  keywords="python, portable, binary",
9
9
  url="https://github.com/codrsquad/portable-python",
10
- python_requires=">=3.8",
10
+ python_requires=">=3.9",
11
11
  entry_points={
12
12
  "console_scripts": [
13
13
  "portable-python = portable_python.__main__:main",
@@ -22,7 +22,6 @@ setup(
22
22
  "Operating System :: Unix",
23
23
  "Programming Language :: Python",
24
24
  "Programming Language :: Python :: 3",
25
- "Programming Language :: Python :: 3.8",
26
25
  "Programming Language :: Python :: 3.9",
27
26
  "Programming Language :: Python :: 3.10",
28
27
  "Programming Language :: Python :: 3.11",
@@ -492,10 +492,23 @@ class ModuleBuilder:
492
492
  def cfg_version(self, default):
493
493
  return PPG.config.get_value("%s-version" % self.m_name) or default
494
494
 
495
+ def cfg_http_headers(self):
496
+ if config_http_headers := PPG.config.get_value("%s-http-headers" % self.m_name):
497
+ expanded_http_headers = {}
498
+ for header_dict in config_http_headers:
499
+ for key, value in header_dict.items():
500
+ expanded_http_headers[os.path.expandvars(key)] = os.path.expandvars(value)
501
+
502
+ return expanded_http_headers
503
+
495
504
  def cfg_url(self, version):
496
505
  if config_url := PPG.config.get_value("%s-url" % self.m_name):
497
506
  url_template = Template(config_url)
498
- return url_template.substitute(version=version)
507
+ url_subbed = url_template.substitute(version=version)
508
+ return os.path.expandvars(url_subbed)
509
+
510
+ def cfg_src_suffix(self):
511
+ return PPG.config.get_value("%s-src-suffix" % self.m_name)
499
512
 
500
513
  def cfg_configure(self, deps_lib_dir, deps_lib64_dir):
501
514
  if configure := PPG.config.get_value("%s-configure" % self.m_name):
@@ -510,6 +523,16 @@ class ModuleBuilder:
510
523
  """Url of source tarball, if any"""
511
524
  return ""
512
525
 
526
+ @property
527
+ def headers(self):
528
+ """Headers for connecting to source url, if any"""
529
+ return self.cfg_http_headers()
530
+
531
+ @property
532
+ def src_suffix(self):
533
+ """Suffix of src archive for when URL doesn't end in the file extension"""
534
+ return self.cfg_src_suffix()
535
+
513
536
  @property
514
537
  def version(self):
515
538
  """Version to use"""
@@ -632,8 +655,16 @@ class ModuleBuilder:
632
655
  self._finalize()
633
656
  return
634
657
 
658
+ # Some URL's may not end in file extension, such as with redirects.
659
+ # Github releases asset endpoint is this way .../releases/assets/48151
660
+
635
661
  # Split on '#' for urls that include a checksum, such as #sha256=... fragment
636
662
  basename = runez.basename(self.url, extension_marker="#")
663
+ if not basename.endswith((".zip", ".tar.gz")):
664
+ suffix = self.src_suffix or ".tar.gz"
665
+ suffix = ".%s" % (suffix.strip(".")) # Ensure it starts with a dot (in case config forgot leading dot)
666
+ basename = f"{self.m_name}-{self.version}{suffix}"
667
+
637
668
  path = self.setup.folders.sources / basename
638
669
  if not path.exists():
639
670
  proxies = {}
@@ -643,11 +674,22 @@ class ModuleBuilder:
643
674
  https_proxy = os.environ.get("HTTPS_PROXY") or os.environ.get("https_proxy")
644
675
  if https_proxy:
645
676
  proxies["https"] = https_proxy
646
- RestClient().download(self.url, path, proxies=proxies)
677
+
678
+ RestClient().download(self.url, path, proxies=proxies, headers=self.headers)
647
679
 
648
680
  runez.decompress(path, self.m_src_build, simplify=True)
649
681
 
650
682
  env_vars = self._get_env_vars()
683
+ if not PPG.config.get_value("allow-homebrew"):
684
+ # Remove any mention of /opt/homebrew from PATH (reduce chances of dynamic links to homebrew)
685
+ path_env_var = env_vars.get("PATH")
686
+ if path_env_var:
687
+ _paths = os.environ.get("PATH", "").split(":")
688
+ _revised = [p for p in _paths if not p.startswith("/opt/homebrew")]
689
+ if _revised != _paths:
690
+ LOG.info("Removed /opt/homebrew mentions from PATH")
691
+ env_vars["PATH"] = runez.joined(_revised, delimiter=":")
692
+
651
693
  prev_env_vars = {}
652
694
  for var_name, value in env_vars.items():
653
695
  LOG.info("env %s=%s", var_name, runez.short(value, size=2048))
@@ -6,7 +6,7 @@ class GettextTiny(ModuleBuilder):
6
6
 
7
7
  @property
8
8
  def url(self):
9
- return f"https://github.com/sabotage-linux/gettext-tiny/archive/refs/tags/v{self.version}.tar.gz"
9
+ return self.cfg_url(self.version) or f"https://github.com/sabotage-linux/gettext-tiny/archive/refs/tags/v{self.version}.tar.gz"
10
10
 
11
11
  @property
12
12
  def version(self):
@@ -80,11 +80,11 @@ class Gdbm(ModuleBuilder):
80
80
 
81
81
  @property
82
82
  def url(self):
83
- return self.cfg_url(self.version) or f"https://ftp.gnu.org/gnu/gdbm/gdbm-{self.version}.tar.gz"
83
+ return self.cfg_url(self.version) or f"https://ftpmirror.gnu.org/gnu/gdbm/gdbm-{self.version}.tar.gz"
84
84
 
85
85
  @property
86
86
  def version(self):
87
- return self.cfg_version("1.24")
87
+ return self.cfg_version("1.26")
88
88
 
89
89
  def c_configure_args(self):
90
90
  if config_args := self.cfg_configure(self.deps_lib_dir, self.deps_lib64_dir):
@@ -129,7 +129,7 @@ class LibFFI(ModuleBuilder):
129
129
 
130
130
  @property
131
131
  def version(self):
132
- return self.cfg_version("3.4.6")
132
+ return self.cfg_version("3.4.8")
133
133
 
134
134
  def c_configure_args(self):
135
135
  if config_args := self.cfg_configure(self.deps_lib_dir, self.deps_lib64_dir):
@@ -176,7 +176,7 @@ class Openssl(ModuleBuilder):
176
176
  def version(self):
177
177
  # See https://endoflife.date/openssl
178
178
  # This default here picks the most conservative longest supported version
179
- return self.cfg_version("3.0.15")
179
+ return self.cfg_version("3.0.17")
180
180
 
181
181
  def c_configure_args(self):
182
182
  if config_args := self.cfg_configure(self.deps_lib_dir, self.deps_lib64_dir):
@@ -258,7 +258,7 @@ class Readline(ModuleBuilder):
258
258
 
259
259
  @property
260
260
  def url(self):
261
- return self.cfg_url(self.version) or f"https://ftp.gnu.org/gnu/readline/readline-{self.version}.tar.gz"
261
+ return self.cfg_url(self.version) or f"http://ftpmirror.gnu.org/gnu/readline/readline-{self.version}.tar.gz"
262
262
 
263
263
  @property
264
264
  def version(self):
@@ -306,7 +306,7 @@ class Sqlite(ModuleBuilder):
306
306
 
307
307
  @property
308
308
  def version(self):
309
- return self.cfg_version("3.47.0")
309
+ return self.cfg_version("3.50.4")
310
310
 
311
311
  def c_configure_args(self):
312
312
  if config_args := self.cfg_configure(self.deps_lib_dir, self.deps_lib64_dir):
@@ -373,7 +373,7 @@ class Xz(ModuleBuilder):
373
373
 
374
374
  @property
375
375
  def version(self):
376
- return self.cfg_version("5.6.3")
376
+ return self.cfg_version("5.8.1")
377
377
 
378
378
  def c_configure_args(self):
379
379
  if config_args := self.cfg_configure(self.deps_lib_dir, self.deps_lib64_dir):
@@ -74,7 +74,7 @@ class VersionFamily:
74
74
  class CPythonFamily(VersionFamily):
75
75
  """Implementation for cpython"""
76
76
 
77
- min_version = "3.7" # Earliest non-EOL known to compile well
77
+ min_version = "3.9" # Earliest non-EOL known to compile well
78
78
 
79
79
  @runez.cached_property
80
80
  def client(self):
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: portable-python
3
- Version: 1.9.8
3
+ Version: 1.10.0
4
4
  Summary: Portable python binaries
5
5
  Home-page: https://github.com/codrsquad/portable-python
6
6
  Author: Zoran Simic
@@ -18,7 +18,6 @@ Classifier: Operating System :: POSIX
18
18
  Classifier: Operating System :: Unix
19
19
  Classifier: Programming Language :: Python
20
20
  Classifier: Programming Language :: Python :: 3
21
- Classifier: Programming Language :: Python :: 3.8
22
21
  Classifier: Programming Language :: Python :: 3.9
23
22
  Classifier: Programming Language :: Python :: 3.10
24
23
  Classifier: Programming Language :: Python :: 3.11
@@ -29,7 +28,7 @@ Classifier: Topic :: Software Development :: Build Tools
29
28
  Classifier: Topic :: System :: Installation/Setup
30
29
  Classifier: Topic :: System :: Software Distribution
31
30
  Classifier: Topic :: Utilities
32
- Requires-Python: >=3.8
31
+ Requires-Python: >=3.9
33
32
  Description-Content-Type: text/x-rst
34
33
  License-File: LICENSE
35
34
  Requires-Dist: click~=8.0
@@ -45,6 +44,7 @@ Dynamic: description-content-type
45
44
  Dynamic: home-page
46
45
  Dynamic: keywords
47
46
  Dynamic: license
47
+ Dynamic: license-file
48
48
  Dynamic: project-url
49
49
  Dynamic: requires-dist
50
50
  Dynamic: requires-python
@@ -7,7 +7,7 @@ def test_build_bogus_platform(cli):
7
7
  def test_failed_build(cli):
8
8
  cli.run("-tmacos-arm64", "build", "3.12.0")
9
9
  assert cli.failed
10
- assert "Error while compiling xz:5.6.3: ForbiddenHttpError" in cli.logged
10
+ assert "Error while compiling xz:5.8.1: ForbiddenHttpError" in cli.logged
11
11
  assert "Overall compilation failed:" in cli.logged
12
12
 
13
13
 
@@ -7,7 +7,7 @@ REST_CLIENT = RestClient()
7
7
  GH_CPYTHON_SAMPLE = """
8
8
  [
9
9
  {"ref": "refs/tags/v3.9.7"},
10
- {"ref": "refs/tags/v3.8.12"},
10
+ {"ref": "refs/tags/v3.13.3"},
11
11
  {"ref": "refs/tags/v3.5.10"}
12
12
  ]
13
13
  """
@@ -15,7 +15,7 @@ GH_CPYTHON_SAMPLE = """
15
15
  PYTHON_ORG_SAMPLE = """
16
16
  <a href="3.9.5/">3.9.5/</a>
17
17
  <a href="3.9.6/">3.9.6/</a>
18
- <a href="3.8.11/">3.9.11/</a>
18
+ <a href="3.13.2/">3.13.2/</a>
19
19
  <a href="3.5.10/">3.5.10/</a>
20
20
  """
21
21
 
@@ -34,12 +34,12 @@ def test_list(cli, monkeypatch):
34
34
  assert setup.python_spec.version == PPG.cpython.latest
35
35
 
36
36
  cp = CPythonFamily()
37
- assert str(cp.latest) == "3.9.6"
37
+ assert str(cp.latest) == "3.13.2"
38
38
 
39
39
  monkeypatch.setattr(PPG.cpython, "_versions", None)
40
40
  cli.run("list")
41
41
  assert cli.succeeded
42
- assert cli.logged.stdout.contents().strip() == "cpython:\n 3.9: 3.9.6\n 3.8: 3.8.11"
42
+ assert cli.logged.stdout.contents().strip() == "cpython:\n 3.13: 3.13.2\n 3.9: 3.9.6"
43
43
 
44
44
  cli.run("list", "--json")
45
45
  assert cli.succeeded
@@ -52,4 +52,4 @@ def test_list(cli, monkeypatch):
52
52
  monkeypatch.setattr(PPG.cpython, "_versions", None)
53
53
  cli.run("-c", cli.tests_path("sample-config1.yml"), "list")
54
54
  assert cli.succeeded
55
- assert cli.logged.stdout.contents().strip() == "cpython:\n 3.9: 3.9.7\n 3.8: 3.8.12"
55
+ assert cli.logged.stdout.contents().strip() == "cpython:\n 3.13: 3.13.3\n 3.9: 3.9.7"
@@ -9,8 +9,15 @@ def test_config(cli):
9
9
  with pytest.raises(runez.system.AbortException):
10
10
  PPG.config.parsed_yaml("a: b\ninvalid line", "testing")
11
11
 
12
+ # Exercise custom url in config
13
+ cli.run("-ntmacos-arm64", "-c", cli.tests_path("sample-config1.yml"), "build", "3.9.7", "-mbzip2")
14
+ assert cli.succeeded
15
+ assert "Would download https://my-enterprise/.../assets/bzip2/123#sha256=123...def\n" in cli.logged
16
+ assert "Would untar build/sources/bzip2-1.2.3.tar.gz -> build/components/bzip2\n" in cli.logged
17
+
12
18
  cli.run("-ntmacos-arm64", "-c", cli.tests_path("sample-config1.yml"), "build", "3.9.7", "-mnone")
13
19
  assert cli.succeeded
20
+
14
21
  assert " -mpip install --no-cache-dir --upgrade my-additional-package" in cli.logged
15
22
  assert "env MACOSX_DEPLOYMENT_TARGET=12" in cli.logged # Comes from more specific macos-arm64.yml
16
23
  assert " -> dist/cpython-3.9.7-macos-arm64.tar.xz" in cli.logged # Comes from macos.yml (not defined in macos-arm64.yml)