portable-python 2.0.0__tar.gz → 2.0.1__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.
- portable_python-2.0.1/.claude/settings.json +10 -0
- portable_python-2.0.1/.dockerignore +15 -0
- portable_python-2.0.1/.github/workflows/release.yml +26 -0
- portable_python-2.0.1/.github/workflows/tests.yml +59 -0
- portable_python-2.0.1/.gitignore +28 -0
- portable_python-2.0.1/CLAUDE.md +25 -0
- portable_python-2.0.1/Dockerfile +18 -0
- portable_python-2.0.1/MANIFEST.in +2 -0
- {portable_python-2.0.0/src/portable_python.egg-info → portable_python-2.0.1}/PKG-INFO +68 -26
- {portable_python-2.0.0 → portable_python-2.0.1}/README.rst +60 -2
- portable_python-2.0.1/docs/architecture/build-setup.md +29 -0
- portable_python-2.0.1/docs/architecture/config.md +30 -0
- portable_python-2.0.1/docs/architecture/cpython.md +24 -0
- portable_python-2.0.1/docs/architecture/index.md +30 -0
- portable_python-2.0.1/docs/architecture/module-builder.md +26 -0
- portable_python-2.0.1/docs/architecture/ppg.md +21 -0
- portable_python-2.0.1/docs/architecture/python-builder.md +25 -0
- portable_python-2.0.1/docs/architecture/python-inspector.md +27 -0
- portable_python-2.0.1/docs/changelog.md +13 -0
- portable_python-2.0.1/docs/cli/build-report.md +24 -0
- portable_python-2.0.1/docs/cli/build.md +30 -0
- portable_python-2.0.1/docs/cli/diagnostics.md +17 -0
- portable_python-2.0.1/docs/cli/index.md +19 -0
- portable_python-2.0.1/docs/cli/inspect.md +29 -0
- portable_python-2.0.1/docs/cli/lib-auto-correct.md +24 -0
- portable_python-2.0.1/docs/cli/list.md +24 -0
- portable_python-2.0.1/docs/cli/recompress.md +23 -0
- portable_python-2.0.1/docs/concepts/build-layout.md +49 -0
- portable_python-2.0.1/docs/concepts/folder-masking.md +26 -0
- portable_python-2.0.1/docs/concepts/index.md +10 -0
- portable_python-2.0.1/docs/concepts/portability.md +35 -0
- portable_python-2.0.1/docs/concepts/ppp-marker.md +24 -0
- portable_python-2.0.1/docs/concepts/static-linking.md +31 -0
- portable_python-2.0.1/docs/concepts/telltale-detection.md +49 -0
- portable_python-2.0.1/docs/configuration/index.md +7 -0
- portable_python-2.0.1/docs/configuration/portable-python-yml.md +82 -0
- portable_python-2.0.1/docs/guides/add-a-config-option.md +20 -0
- portable_python-2.0.1/docs/guides/add-an-external-module.md +59 -0
- portable_python-2.0.1/docs/guides/build-a-portable-python.md +61 -0
- portable_python-2.0.1/docs/guides/bump-components.md +66 -0
- portable_python-2.0.1/docs/guides/bump-python-support.md +18 -0
- portable_python-2.0.1/docs/guides/ci-cd.md +31 -0
- portable_python-2.0.1/docs/guides/fix-a-portability-issue.md +18 -0
- portable_python-2.0.1/docs/guides/index.md +12 -0
- portable_python-2.0.1/docs/guides/local-development.md +75 -0
- portable_python-2.0.1/docs/index.md +32 -0
- portable_python-2.0.1/docs/log.md +25 -0
- portable_python-2.0.1/docs/modules/external-modules.md +54 -0
- portable_python-2.0.1/docs/modules/index.md +7 -0
- portable_python-2.0.1/docs/overview.md +62 -0
- portable_python-2.0.1/docs/release.md +52 -0
- portable_python-2.0.1/lock-deps.sh +5 -0
- portable_python-2.0.1/portable-python.yml +67 -0
- {portable_python-2.0.0 → portable_python-2.0.1}/pyproject.toml +75 -1
- portable_python-2.0.1/requirements.txt +48 -0
- portable_python-2.0.1/retired/README.md +9 -0
- portable_python-2.0.1/retired/toolchain.py +52 -0
- portable_python-2.0.1/scripts/bashrc.sh +4 -0
- portable_python-2.0.1/scripts/check_okf.py +124 -0
- portable_python-2.0.1/scripts/portable-python.sh +21 -0
- {portable_python-2.0.0 → portable_python-2.0.1}/src/portable_python/external/__init__.py +1 -0
- {portable_python-2.0.0 → portable_python-2.0.1}/src/portable_python/external/xcpython.py +25 -8
- {portable_python-2.0.0 → portable_python-2.0.1}/src/portable_python/external/xtkinter.py +6 -1
- {portable_python-2.0.0 → portable_python-2.0.1/src/portable_python.egg-info}/PKG-INFO +68 -26
- portable_python-2.0.1/src/portable_python.egg-info/SOURCES.txt +97 -0
- portable_python-2.0.1/src/portable_python.egg-info/requires.txt +5 -0
- portable_python-2.0.1/src/portable_python.egg-info/scm_file_list.json +93 -0
- portable_python-2.0.1/src/portable_python.egg-info/scm_version.json +8 -0
- portable_python-2.0.1/tests/__init__.py +0 -0
- portable_python-2.0.1/tests/conftest.py +18 -0
- portable_python-2.0.1/tests/sample-config1.yml +50 -0
- portable_python-2.0.1/tests/sample-config2.yml +7 -0
- portable_python-2.0.1/tests/sample-incomplete.yml +2 -0
- {portable_python-2.0.0 → portable_python-2.0.1}/tests/test_failed.py +1 -1
- {portable_python-2.0.0 → portable_python-2.0.1}/tests/test_inspector.py +2 -2
- portable_python-2.0.1/tox.ini +31 -0
- portable_python-2.0.0/DEVELOP.md +0 -68
- portable_python-2.0.0/MANIFEST.in +0 -5
- portable_python-2.0.0/requirements.txt +0 -5
- portable_python-2.0.0/setup.py +0 -41
- portable_python-2.0.0/src/portable_python.egg-info/SOURCES.txt +0 -36
- portable_python-2.0.0/src/portable_python.egg-info/requires.txt +0 -5
- {portable_python-2.0.0 → portable_python-2.0.1}/LICENSE +0 -0
- {portable_python-2.0.0 → portable_python-2.0.1}/SECURITY.md +0 -0
- {portable_python-2.0.0 → portable_python-2.0.1}/setup.cfg +0 -0
- {portable_python-2.0.0 → portable_python-2.0.1}/src/portable_python/__init__.py +0 -0
- {portable_python-2.0.0 → portable_python-2.0.1}/src/portable_python/__main__.py +0 -0
- {portable_python-2.0.0 → portable_python-2.0.1}/src/portable_python/cli.py +0 -0
- {portable_python-2.0.0 → portable_python-2.0.1}/src/portable_python/config.py +0 -0
- {portable_python-2.0.0 → portable_python-2.0.1}/src/portable_python/cpython.py +0 -0
- {portable_python-2.0.0 → portable_python-2.0.1}/src/portable_python/external/_inspect.py +0 -0
- {portable_python-2.0.0 → portable_python-2.0.1}/src/portable_python/inspector.py +0 -0
- {portable_python-2.0.0 → portable_python-2.0.1}/src/portable_python/tracking.py +0 -0
- {portable_python-2.0.0 → portable_python-2.0.1}/src/portable_python/versions.py +0 -0
- {portable_python-2.0.0 → portable_python-2.0.1}/src/portable_python.egg-info/dependency_links.txt +0 -0
- {portable_python-2.0.0 → portable_python-2.0.1}/src/portable_python.egg-info/entry_points.txt +0 -0
- {portable_python-2.0.0 → portable_python-2.0.1}/src/portable_python.egg-info/top_level.txt +0 -0
- {portable_python-2.0.0 → portable_python-2.0.1}/tests/test_build.py +0 -0
- {portable_python-2.0.0 → portable_python-2.0.1}/tests/test_cleanup.py +0 -0
- {portable_python-2.0.0 → portable_python-2.0.1}/tests/test_invoker.py +0 -0
- {portable_python-2.0.0 → portable_python-2.0.1}/tests/test_list.py +0 -0
- {portable_python-2.0.0 → portable_python-2.0.1}/tests/test_prefix.py +0 -0
- {portable_python-2.0.0 → portable_python-2.0.1}/tests/test_recompress.py +0 -0
- {portable_python-2.0.0 → portable_python-2.0.1}/tests/test_report.py +0 -0
- {portable_python-2.0.0 → portable_python-2.0.1}/tests/test_setup.py +0 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- 'v[0-9]*'
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
publish:
|
|
10
|
+
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
environment: release
|
|
13
|
+
permissions:
|
|
14
|
+
id-token: write # mandatory for trusted publishing
|
|
15
|
+
|
|
16
|
+
steps:
|
|
17
|
+
- uses: actions/checkout@v6
|
|
18
|
+
- uses: actions/setup-python@v6
|
|
19
|
+
with:
|
|
20
|
+
python-version: "3.14"
|
|
21
|
+
|
|
22
|
+
- uses: astral-sh/setup-uv@v7
|
|
23
|
+
- run: uvx --with tox-uv tox -e py,style
|
|
24
|
+
- run: uv build
|
|
25
|
+
- name: Publish to PyPI
|
|
26
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
name: Tests
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [ main ]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [ main ]
|
|
8
|
+
|
|
9
|
+
concurrency:
|
|
10
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
11
|
+
cancel-in-progress: true
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
test:
|
|
15
|
+
name: Test py${{ matrix.python-version }}
|
|
16
|
+
runs-on: ubuntu-latest
|
|
17
|
+
|
|
18
|
+
strategy:
|
|
19
|
+
fail-fast: false
|
|
20
|
+
matrix:
|
|
21
|
+
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
|
|
22
|
+
|
|
23
|
+
steps:
|
|
24
|
+
- uses: actions/checkout@v6
|
|
25
|
+
- uses: actions/setup-python@v6
|
|
26
|
+
with:
|
|
27
|
+
python-version: ${{ matrix.python-version }}
|
|
28
|
+
|
|
29
|
+
- uses: astral-sh/setup-uv@v7
|
|
30
|
+
- run: uvx --with tox-uv tox -e py
|
|
31
|
+
|
|
32
|
+
- uses: coverallsapp/github-action@v2
|
|
33
|
+
with:
|
|
34
|
+
file: .tox/test-reports/coverage.xml
|
|
35
|
+
flag-name: python-${{ matrix.python-version }}
|
|
36
|
+
parallel: true
|
|
37
|
+
|
|
38
|
+
coveralls-finish:
|
|
39
|
+
name: Finish Coveralls
|
|
40
|
+
needs: [test]
|
|
41
|
+
runs-on: ubuntu-latest
|
|
42
|
+
steps:
|
|
43
|
+
- name: Finish parallel build
|
|
44
|
+
uses: coverallsapp/github-action@v2
|
|
45
|
+
with:
|
|
46
|
+
parallel-finished: true
|
|
47
|
+
|
|
48
|
+
linters:
|
|
49
|
+
|
|
50
|
+
runs-on: ubuntu-latest
|
|
51
|
+
|
|
52
|
+
steps:
|
|
53
|
+
- uses: actions/checkout@v6
|
|
54
|
+
- uses: actions/setup-python@v6
|
|
55
|
+
with:
|
|
56
|
+
python-version: "3.14"
|
|
57
|
+
|
|
58
|
+
- uses: astral-sh/setup-uv@v7
|
|
59
|
+
- run: uvx --with tox-uv tox -e style
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Various
|
|
2
|
+
*~
|
|
3
|
+
\#*#
|
|
4
|
+
.\#*
|
|
5
|
+
.*cache
|
|
6
|
+
.DS_Store*
|
|
7
|
+
*.swp
|
|
8
|
+
.*version
|
|
9
|
+
.idea/
|
|
10
|
+
.vscode/
|
|
11
|
+
ehthumbs.db
|
|
12
|
+
Icon?
|
|
13
|
+
Thumbs.db
|
|
14
|
+
.new*
|
|
15
|
+
|
|
16
|
+
# Build artifacts
|
|
17
|
+
_Dockerfile*
|
|
18
|
+
__pycache__/
|
|
19
|
+
*.egg*
|
|
20
|
+
.tox/
|
|
21
|
+
.venv*/
|
|
22
|
+
build/
|
|
23
|
+
dist/
|
|
24
|
+
root/
|
|
25
|
+
venv*/
|
|
26
|
+
|
|
27
|
+
pp*.yml
|
|
28
|
+
uv.lock
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
Guidance for Claude Code working in this repository.
|
|
4
|
+
|
|
5
|
+
`portable-python` is a CLI and Python library that compiles portable (statically-linked, relocatable) CPython binaries from source — see [`docs/overview.md`](docs/overview.md) for the full picture.
|
|
6
|
+
|
|
7
|
+
## Documentation lives in `docs/`
|
|
8
|
+
|
|
9
|
+
The authoritative, self-contained documentation is the OKF knowledge bundle under **`docs/`** — start at [`docs/index.md`](docs/index.md). **Don't duplicate it in this file — link to it.** When you change behavior, update the matching `docs/` entry and add a line to [`docs/log.md`](docs/log.md).
|
|
10
|
+
|
|
11
|
+
| Looking for… | Go to |
|
|
12
|
+
|--------------|-------|
|
|
13
|
+
| What it does, guiding principles, end-to-end build flow | [`docs/overview.md`](docs/overview.md) |
|
|
14
|
+
| Core classes & how they collaborate | [`docs/architecture/`](docs/architecture/index.md) |
|
|
15
|
+
| Concepts: portability, static linking, telltale detection, folder masking, ppp-marker, build layout | [`docs/concepts/`](docs/concepts/index.md) |
|
|
16
|
+
| CLI commands & options | [`docs/cli/`](docs/cli/index.md) |
|
|
17
|
+
| External modules (the statically-linked C libraries) | [`docs/modules/`](docs/modules/index.md) |
|
|
18
|
+
| Configuration (`portable-python.yml`) | [`docs/configuration/`](docs/configuration/index.md) |
|
|
19
|
+
| Dev setup, tests, code style, debugging, Docker, CI/CD, and common tasks | [`docs/guides/`](docs/guides/index.md) |
|
|
20
|
+
|
|
21
|
+
## Working in this repo
|
|
22
|
+
|
|
23
|
+
- Check **runez** before reimplementing file / system / CLI / logging / version helpers — see [`docs/guides/local-development.md`](docs/guides/local-development.md).
|
|
24
|
+
- The docs use the OKF format; keep the bundle conformant (`scripts/check_okf.py docs`) when you edit it.
|
|
25
|
+
- As changes land, keep a top section in [`docs/changelog.md`](docs/changelog.md) for the upcoming release — `## Unreleased`, or the next version directly once it's known. Maintain it as PRs come in; it's double-checked at release. Don't fuss over marking released-vs-unreleased (small audience, `git tag` says what's out).
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
FROM ubuntu:22.04
|
|
2
|
+
|
|
3
|
+
ARG DEBIAN_FRONTEND=noninteractive
|
|
4
|
+
ENV TZ=Etc/UTC
|
|
5
|
+
|
|
6
|
+
RUN apt-get update && apt-get install -y git htop build-essential \
|
|
7
|
+
gdb lcov patchelf python3-pip python3-venv tcl \
|
|
8
|
+
libexpat1-dev libffi-dev zlib1g-dev libgdbm-dev libgdbm-compat-dev \
|
|
9
|
+
libssl-dev libsqlite3-dev uuid-dev \
|
|
10
|
+
liblzma-dev libbz2-dev libzstd-dev libmpdec-dev
|
|
11
|
+
|
|
12
|
+
RUN /usr/bin/python3 -mpip install -U pip setuptools
|
|
13
|
+
|
|
14
|
+
COPY ./scripts/portable-python.sh /usr/local/bin/portable-python
|
|
15
|
+
COPY ./scripts/bashrc.sh /root/.bashrc
|
|
16
|
+
WORKDIR /src
|
|
17
|
+
|
|
18
|
+
CMD ["/bin/bash"]
|
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: portable-python
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.1
|
|
4
4
|
Summary: Portable python binaries
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
Author-email: zoran@simicweb.com
|
|
8
|
-
License: MIT
|
|
9
|
-
Project-URL: Documentation, https://github.com/codrsquad/portable-python/wiki
|
|
10
|
-
Project-URL: Release notes, https://github.com/codrsquad/portable-python/wiki/Release-notes
|
|
5
|
+
Author-email: Zoran Simic <zoran@simicweb.com>
|
|
6
|
+
License-Expression: MIT
|
|
11
7
|
Project-URL: Source, https://github.com/codrsquad/portable-python
|
|
12
8
|
Keywords: python,portable,binary
|
|
13
9
|
Classifier: Development Status :: 5 - Production/Stable
|
|
@@ -31,24 +27,12 @@ Classifier: Topic :: Utilities
|
|
|
31
27
|
Requires-Python: >=3.10
|
|
32
28
|
Description-Content-Type: text/x-rst
|
|
33
29
|
License-File: LICENSE
|
|
34
|
-
Requires-Dist: click
|
|
35
|
-
Requires-Dist: pyyaml
|
|
36
|
-
Requires-Dist: requests<3
|
|
37
|
-
Requires-Dist: runez
|
|
38
|
-
Requires-Dist: urllib3
|
|
39
|
-
Dynamic: author
|
|
40
|
-
Dynamic: author-email
|
|
41
|
-
Dynamic: classifier
|
|
42
|
-
Dynamic: description
|
|
43
|
-
Dynamic: description-content-type
|
|
44
|
-
Dynamic: home-page
|
|
45
|
-
Dynamic: keywords
|
|
46
|
-
Dynamic: license
|
|
30
|
+
Requires-Dist: click<9
|
|
31
|
+
Requires-Dist: pyyaml<7
|
|
32
|
+
Requires-Dist: requests<3
|
|
33
|
+
Requires-Dist: runez<6
|
|
34
|
+
Requires-Dist: urllib3<3
|
|
47
35
|
Dynamic: license-file
|
|
48
|
-
Dynamic: project-url
|
|
49
|
-
Dynamic: requires-dist
|
|
50
|
-
Dynamic: requires-python
|
|
51
|
-
Dynamic: summary
|
|
52
36
|
|
|
53
37
|
Portable python binaries
|
|
54
38
|
========================
|
|
@@ -61,8 +45,8 @@ Portable python binaries
|
|
|
61
45
|
:target: https://github.com/codrsquad/portable-python/actions
|
|
62
46
|
:alt: Tested with Github Actions
|
|
63
47
|
|
|
64
|
-
.. image:: https://
|
|
65
|
-
:target: https://
|
|
48
|
+
.. image:: https://coveralls.io/repos/github/codrsquad/portable-python/badge.svg?branch=main
|
|
49
|
+
:target: https://coveralls.io/github/codrsquad/portable-python?branch=main
|
|
66
50
|
:alt: Test coverage
|
|
67
51
|
|
|
68
52
|
.. image:: https://img.shields.io/pypi/pyversions/portable-python.svg
|
|
@@ -180,6 +164,64 @@ Note that you can use ``--dryrun`` mode to inspect what would be done without do
|
|
|
180
164
|
Would tar build/3.9.7 -> dist/cpython-3.9.7-macos-x86_64.tar.gz
|
|
181
165
|
|
|
182
166
|
|
|
167
|
+
CLI reference
|
|
168
|
+
-------------
|
|
169
|
+
|
|
170
|
+
Main entry point::
|
|
171
|
+
|
|
172
|
+
portable-python [OPTIONS] COMMAND [ARGS]
|
|
173
|
+
|
|
174
|
+
**Global options**:
|
|
175
|
+
|
|
176
|
+
- ``--config PATH``: Config file (default: ``portable-python.yml``)
|
|
177
|
+
- ``--quiet``: Turn off DEBUG logging
|
|
178
|
+
- ``--dryrun`` / ``-n``: Show what would be done
|
|
179
|
+
- ``--target PLATFORM``: Override detected platform (for testing)
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
**build** ``<PYTHON_SPEC>`` - Build a portable Python binary::
|
|
183
|
+
|
|
184
|
+
portable-python build 3.13.2 -m openssl,zlib
|
|
185
|
+
|
|
186
|
+
- ``--modules, -m CSV``: External modules to include
|
|
187
|
+
- ``--prefix, -p PATH``: Use ``--prefix`` (non-portable)
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
**build-report** ``[PYTHON_SPEC]`` - Show module status and what will be compiled:
|
|
191
|
+
|
|
192
|
+
- ``--modules, -m CSV``: Specific modules to check
|
|
193
|
+
- Validates that modules can be built
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
**inspect** ``<PATH>`` - Check if a Python installation is portable::
|
|
197
|
+
|
|
198
|
+
portable-python inspect /usr/bin/python3
|
|
199
|
+
|
|
200
|
+
- ``--modules, -m MODULES``: Which modules to inspect
|
|
201
|
+
- ``--verbose, -v``: Show full ``.so`` report
|
|
202
|
+
- ``--prefix, -p``: Built with ``--prefix`` (not portable)
|
|
203
|
+
- ``--skip-so, -s``: Don't check all ``.so`` files
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
**list** ``[FAMILY]`` - List available versions (default: cpython)::
|
|
207
|
+
|
|
208
|
+
portable-python list cpython
|
|
209
|
+
|
|
210
|
+
- ``--json``: Output as JSON
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
**diagnostics** - Show system diagnostics
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
**recompress** ``<PATH> <EXT>`` - Re-compress existing binary tarball (for comparing compression sizes)
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
**lib-auto-correct** ``<PATH>`` - Auto-correct exes/libs to use relative paths:
|
|
220
|
+
|
|
221
|
+
- ``--commit``: Actually perform changes (dryrun by default)
|
|
222
|
+
- ``--prefix, -p PATH``: Expected ``--prefix`` from build
|
|
223
|
+
|
|
224
|
+
|
|
183
225
|
Library
|
|
184
226
|
-------
|
|
185
227
|
|
|
@@ -9,8 +9,8 @@ Portable python binaries
|
|
|
9
9
|
:target: https://github.com/codrsquad/portable-python/actions
|
|
10
10
|
:alt: Tested with Github Actions
|
|
11
11
|
|
|
12
|
-
.. image:: https://
|
|
13
|
-
:target: https://
|
|
12
|
+
.. image:: https://coveralls.io/repos/github/codrsquad/portable-python/badge.svg?branch=main
|
|
13
|
+
:target: https://coveralls.io/github/codrsquad/portable-python?branch=main
|
|
14
14
|
:alt: Test coverage
|
|
15
15
|
|
|
16
16
|
.. image:: https://img.shields.io/pypi/pyversions/portable-python.svg
|
|
@@ -128,6 +128,64 @@ Note that you can use ``--dryrun`` mode to inspect what would be done without do
|
|
|
128
128
|
Would tar build/3.9.7 -> dist/cpython-3.9.7-macos-x86_64.tar.gz
|
|
129
129
|
|
|
130
130
|
|
|
131
|
+
CLI reference
|
|
132
|
+
-------------
|
|
133
|
+
|
|
134
|
+
Main entry point::
|
|
135
|
+
|
|
136
|
+
portable-python [OPTIONS] COMMAND [ARGS]
|
|
137
|
+
|
|
138
|
+
**Global options**:
|
|
139
|
+
|
|
140
|
+
- ``--config PATH``: Config file (default: ``portable-python.yml``)
|
|
141
|
+
- ``--quiet``: Turn off DEBUG logging
|
|
142
|
+
- ``--dryrun`` / ``-n``: Show what would be done
|
|
143
|
+
- ``--target PLATFORM``: Override detected platform (for testing)
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
**build** ``<PYTHON_SPEC>`` - Build a portable Python binary::
|
|
147
|
+
|
|
148
|
+
portable-python build 3.13.2 -m openssl,zlib
|
|
149
|
+
|
|
150
|
+
- ``--modules, -m CSV``: External modules to include
|
|
151
|
+
- ``--prefix, -p PATH``: Use ``--prefix`` (non-portable)
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
**build-report** ``[PYTHON_SPEC]`` - Show module status and what will be compiled:
|
|
155
|
+
|
|
156
|
+
- ``--modules, -m CSV``: Specific modules to check
|
|
157
|
+
- Validates that modules can be built
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
**inspect** ``<PATH>`` - Check if a Python installation is portable::
|
|
161
|
+
|
|
162
|
+
portable-python inspect /usr/bin/python3
|
|
163
|
+
|
|
164
|
+
- ``--modules, -m MODULES``: Which modules to inspect
|
|
165
|
+
- ``--verbose, -v``: Show full ``.so`` report
|
|
166
|
+
- ``--prefix, -p``: Built with ``--prefix`` (not portable)
|
|
167
|
+
- ``--skip-so, -s``: Don't check all ``.so`` files
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
**list** ``[FAMILY]`` - List available versions (default: cpython)::
|
|
171
|
+
|
|
172
|
+
portable-python list cpython
|
|
173
|
+
|
|
174
|
+
- ``--json``: Output as JSON
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
**diagnostics** - Show system diagnostics
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
**recompress** ``<PATH> <EXT>`` - Re-compress existing binary tarball (for comparing compression sizes)
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
**lib-auto-correct** ``<PATH>`` - Auto-correct exes/libs to use relative paths:
|
|
184
|
+
|
|
185
|
+
- ``--commit``: Actually perform changes (dryrun by default)
|
|
186
|
+
- ``--prefix, -p PATH``: Expected ``--prefix`` from build
|
|
187
|
+
|
|
188
|
+
|
|
131
189
|
Library
|
|
132
190
|
-------
|
|
133
191
|
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: Class
|
|
3
|
+
title: BuildSetup
|
|
4
|
+
description: Orchestrates a build end to end — resolves the spec, builds external modules then CPython, validates, and compresses the result.
|
|
5
|
+
tags: [class, build, coordinator]
|
|
6
|
+
timestamp: 2026-06-23T00:00:00Z
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# BuildSetup
|
|
10
|
+
|
|
11
|
+
The build orchestrator (`__init__.py`). The [`build`](/cli/build.md) command — and library users — construct one from a python spec and call `compile()`:
|
|
12
|
+
|
|
13
|
+
```python
|
|
14
|
+
from portable_python import BuildSetup
|
|
15
|
+
|
|
16
|
+
BuildSetup("cpython:3.13.2").compile()
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Mental model
|
|
20
|
+
|
|
21
|
+
A conductor: it compiles nothing itself, it sequences the pieces. `compile()` is the spine — it cleans the [build folders](/concepts/build-layout.md), enters a [`BuildContext`](/concepts/folder-masking.md) (macOS isolation), builds the [external modules](/modules/index.md) into `build/deps/`, then builds CPython through its [`PythonBuilder`](/architecture/python-builder.md) (a [`Cpython`](/architecture/cpython.md)), and finally compresses the install into `dist/`. **External libraries first, CPython last.**
|
|
22
|
+
|
|
23
|
+
It owns the [`Folders`](/architecture/config.md) (resolved paths) and the python builder; shared config, target platform, and version family come from [`PPG`](/architecture/ppg.md).
|
|
24
|
+
|
|
25
|
+
## Worth knowing
|
|
26
|
+
|
|
27
|
+
- **Start reading at `compile()`** — it calls everything else in order.
|
|
28
|
+
- A `--prefix` makes the build **non-portable**; without it the result is relocatable (see [ppp-marker](/concepts/ppp-marker.md) and [portability](/concepts/portability.md)).
|
|
29
|
+
- It requires a full `X.Y.Z` spec — a bare `3.13` is rejected; `"latest"` (or empty) resolves to the newest known version.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: Class
|
|
3
|
+
title: Config & Folders
|
|
4
|
+
description: Config loads and merges YAML configuration with platform-specific overrides; Folders resolves the templated build/dist/sources paths.
|
|
5
|
+
tags: [class, configuration, folders, yaml]
|
|
6
|
+
timestamp: 2026-06-23T00:00:00Z
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Config & Folders
|
|
10
|
+
|
|
11
|
+
`Config` (`config.py`) loads, merges, and queries the YAML [configuration](/configuration/portable-python-yml.md). `Folders` (`versions.py`) turns its templated path settings into concrete filesystem paths. Both are reached through [`PPG`](/architecture/ppg.md).
|
|
12
|
+
|
|
13
|
+
## Merge & precedence
|
|
14
|
+
|
|
15
|
+
The mental model is layering. A built-in `DEFAULT_CONFIG` provides sane defaults; user files (default `portable-python.yml`, plus any `include:`d files) layer on top. Within a file, **platform-specific** sections override generic ones, and the most specific match for the [target platform](/architecture/ppg.md) wins:
|
|
16
|
+
|
|
17
|
+
```yaml
|
|
18
|
+
ext: gz # generic default
|
|
19
|
+
windows:
|
|
20
|
+
ext: zip # used only when targeting windows
|
|
21
|
+
macos:
|
|
22
|
+
env:
|
|
23
|
+
MACOSX_DEPLOYMENT_TARGET: 13
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
A lookup returns that most-specific value (with the option to ignore platform overrides).
|
|
27
|
+
|
|
28
|
+
## Folders
|
|
29
|
+
|
|
30
|
+
`Folders` resolves the templated `folders:` settings (placeholders like `{build}`, `{version}`, `{abi_suffix}`) into the concrete `build/`, `deps/`, `dist/`, … paths every component uses — including the [ppp-marker](/concepts/ppp-marker.md) install prefix. See [build layout](/concepts/build-layout.md) for the resulting tree.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: Class
|
|
3
|
+
title: Cpython
|
|
4
|
+
description: The concrete PythonBuilder that compiles CPython — configure/make/install, optimization flags, and the finalize step that makes the install relocatable.
|
|
5
|
+
tags: [class, cpython, build, finalize]
|
|
6
|
+
timestamp: 2026-06-23T00:00:00Z
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Cpython
|
|
10
|
+
|
|
11
|
+
The concrete [`PythonBuilder`](/architecture/python-builder.md) that compiles CPython (`cpython.py`); `CPythonFamily.get_builder()` returns it (see [`PPG`](/architecture/ppg.md)). Most of its work is two things: configuring the build, and finalizing the install so it's relocatable.
|
|
12
|
+
|
|
13
|
+
## Configure
|
|
14
|
+
|
|
15
|
+
CPython is configured purely through flags — never source patches (the [no-patches principle](/overview.md)). Defaults come from `cpython-configure` in [config](/configuration/portable-python-yml.md) (optimizations, LTO, ensurepip), plus computed flags that point the build at the statically-compiled [deps](/concepts/static-linking.md).
|
|
16
|
+
|
|
17
|
+
## Finalize — making it relocatable
|
|
18
|
+
|
|
19
|
+
After `make install`, a portable build's interpreter still thinks it lives at the placeholder [`/ppp-marker/{version}`](/concepts/ppp-marker.md). Finalizing turns it into a [portable](/concepts/portability.md) install:
|
|
20
|
+
|
|
21
|
+
- **Trim** — remove tests / idle / 2to3 before byte-compiling, then prune seldom-used pycaches after (driven by the `cpython-clean-*` config).
|
|
22
|
+
- **Byte-compile** the standard library.
|
|
23
|
+
- **Relativize** — rewrite `bin/` shebangs and the absolute paths baked into `sysconfig` so everything resolves relative to the install's own location.
|
|
24
|
+
- **Verify** — sanity-check that `venv` works in the finished build.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Architecture
|
|
2
|
+
|
|
3
|
+
The core classes and how they collaborate during a build.
|
|
4
|
+
## Global state & configuration
|
|
5
|
+
|
|
6
|
+
* [PPG](/architecture/ppg.md) - Global singleton holding config, target platform, and version families.
|
|
7
|
+
* [Config](/architecture/config.md) - Loads and merges YAML configuration; the `Folders` helper resolves build paths.
|
|
8
|
+
|
|
9
|
+
## Build coordination
|
|
10
|
+
|
|
11
|
+
* [BuildSetup](/architecture/build-setup.md) - Drives the overall compilation: resolve spec, select modules, build, validate, compress.
|
|
12
|
+
* [ModuleBuilder](/architecture/module-builder.md) - Abstract base for anything that gets compiled (external C libs and Python itself).
|
|
13
|
+
* [PythonBuilder](/architecture/python-builder.md) - `ModuleBuilder` specialization for python implementations.
|
|
14
|
+
* [Cpython](/architecture/cpython.md) - Concrete builder: CPython's configure/make/install, optimization, and finalization.
|
|
15
|
+
|
|
16
|
+
## Validation
|
|
17
|
+
|
|
18
|
+
* [PythonInspector](/architecture/python-inspector.md) - Validates the portability of a built (or any) python by checking shared-library dependencies and paths.
|
|
19
|
+
|
|
20
|
+
## Collaboration at a glance
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
PPG (config, target, families)
|
|
24
|
+
└─ BuildSetup(python_spec)
|
|
25
|
+
├─ Folders (resolved build/dist/... paths)
|
|
26
|
+
├─ BuildContext (macOS folder masking, isolation)
|
|
27
|
+
└─ python_builder : Cpython (a PythonBuilder, a ModuleBuilder)
|
|
28
|
+
└─ modules : ModuleCollection
|
|
29
|
+
└─ candidates/selected : ModuleBuilder (Openssl, Zlib, ...)
|
|
30
|
+
```
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: Class
|
|
3
|
+
title: ModuleBuilder
|
|
4
|
+
description: Abstract base for everything that gets compiled — external C libraries and CPython itself — providing the common download/configure/make/install flow and environment injection.
|
|
5
|
+
tags: [class, abstract, build, module]
|
|
6
|
+
timestamp: 2026-06-23T00:00:00Z
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# ModuleBuilder
|
|
10
|
+
|
|
11
|
+
The abstract base for everything the tool compiles (`__init__.py`). Both the [external C modules](/modules/index.md) and [`PythonBuilder`](/architecture/python-builder.md) (hence [`Cpython`](/architecture/cpython.md)) extend it, so every component is built the same way and lands in the same [build layout](/concepts/build-layout.md).
|
|
12
|
+
|
|
13
|
+
## Mental model
|
|
14
|
+
|
|
15
|
+
A subclass is mostly **declarative**: it sets a few `m_*` class attributes (name, [telltale](/concepts/telltale-detection.md) marker, Debian package, include subfolder) and provides a source `url` + `version`. The base class runs the rest of the flow — download → unpack → patch → configure → make → install — into the shared `build/deps/` prefix. Platform differences are isolated to `_do_linux_compile()` / `_do_macos_compile()`, dispatched on [`PPG.target`](/architecture/ppg.md).
|
|
16
|
+
|
|
17
|
+
Two mechanisms recur everywhere and are worth understanding:
|
|
18
|
+
|
|
19
|
+
- **Environment injection** (`xenv_*` methods) — each contributes one variable (CPATH, LDFLAGS, PATH, …) pointing the compiler at `build/deps/`. This is how a statically-built dependency gets found by the next build; see [static linking](/concepts/static-linking.md).
|
|
20
|
+
- **Per-module config overrides** — `cfg_*` helpers read `{module}-version`, `{module}-url`, `{module}-configure`, … from [configuration](/configuration/portable-python-yml.md), so any default can be overridden without code changes.
|
|
21
|
+
|
|
22
|
+
`linker_outcome()` decides, per module and platform, whether it will be linked `static` / `shared`, is `absent`, or would `fail` — the verdict surfaced by [`build-report`](/cli/build-report.md).
|
|
23
|
+
|
|
24
|
+
## Adding one
|
|
25
|
+
|
|
26
|
+
Subclass `ModuleBuilder`, set the `m_*` attributes, implement `url` / `version` and `_do_linux_compile()` — see the [guide](/guides/add-an-external-module.md).
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: Class
|
|
3
|
+
title: PPG
|
|
4
|
+
description: Global singleton holding shared configuration, the target platform, and the registry of supported python version families.
|
|
5
|
+
tags: [class, global-state, singleton, versions]
|
|
6
|
+
timestamp: 2026-06-23T00:00:00Z
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# PPG
|
|
10
|
+
|
|
11
|
+
`PPG` ("**P**ortable **P**ython **G**lobals") is the global state holder (`versions.py`) — the one place the rest of the code reaches for three process-wide facts: the merged [configuration](/architecture/config.md), the target platform (OS/arch), and the registry of python version families. The CLI's `main` initializes it once; everything else reads from it.
|
|
12
|
+
|
|
13
|
+
Like [`ppp-marker`](/concepts/ppp-marker.md), the name is a deliberately uncommon, greppable token — searching for `PPG` surfaces only its own usages, with no collisions in upstream CPython or third-party source.
|
|
14
|
+
|
|
15
|
+
## Why a singleton
|
|
16
|
+
|
|
17
|
+
The build depends on global facts — which config is active, what platform we target, which python versions exist — so centralizing them avoids threading that state through every constructor and gives the CLI one initialization point. Shared helpers hang off it too: resolving a python on `PATH`, building [`Folders`](/architecture/config.md) for a version, and expanding [telltale](/concepts/telltale-detection.md) markers against the target's system includes.
|
|
18
|
+
|
|
19
|
+
## Version families
|
|
20
|
+
|
|
21
|
+
A `VersionFamily` (e.g. `CPythonFamily`) lists the available versions and hands back the right builder ([`Cpython`](/architecture/cpython.md) for cpython). Versions are fetched lazily and cached — from `python.org/ftp`, or GitHub tags when configured — which is why [`list`](/cli/list.md) hits the network on first use. A family also pins the minimum supported version (non-EOL only).
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: Class
|
|
3
|
+
title: PythonBuilder
|
|
4
|
+
description: A ModuleBuilder specialization for python implementations — adds module selection, the python install layout, and helpers to run the freshly built interpreter.
|
|
5
|
+
tags: [class, abstract, python, build]
|
|
6
|
+
timestamp: 2026-06-23T00:00:00Z
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# PythonBuilder
|
|
10
|
+
|
|
11
|
+
The abstract [`ModuleBuilder`](/architecture/module-builder.md) specialization for building a python interpreter (`__init__.py`); the concrete implementation is [`Cpython`](/architecture/cpython.md).
|
|
12
|
+
|
|
13
|
+
## What it adds over ModuleBuilder
|
|
14
|
+
|
|
15
|
+
Beyond the base compile flow, a `PythonBuilder` owns the **module selection** (which [external modules](/modules/index.md) to build) and can **run the freshly-built interpreter** — used during finalize and validation.
|
|
16
|
+
|
|
17
|
+
## ModuleCollection
|
|
18
|
+
|
|
19
|
+
A `PythonBuilder` owns a `ModuleCollection` that resolves which external modules actually get built — a distinction worth keeping straight:
|
|
20
|
+
|
|
21
|
+
- **candidates** — every module this builder *could* compile.
|
|
22
|
+
- **selected** — the ones chosen for *this* build (config + `--modules` + auto-selection). This is what's actually compiled, not all candidates.
|
|
23
|
+
- **auto-selected** — modules force-included because the build can't succeed without them (each module's `auto_select_reason()`).
|
|
24
|
+
|
|
25
|
+
It's what [`build-report`](/cli/build-report.md) renders.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: Class
|
|
3
|
+
title: PythonInspector
|
|
4
|
+
description: Validates the portability of a python installation by parsing the dynamic-library dependencies of every executable and .so, and reporting any non-portable references.
|
|
5
|
+
tags: [class, inspection, validation, portability]
|
|
6
|
+
timestamp: 2026-06-23T00:00:00Z
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# PythonInspector
|
|
10
|
+
|
|
11
|
+
`PythonInspector` (`inspector.py`) answers the question the whole project exists for: *is this python [portable](/concepts/portability.md), and if not, why not?* It powers the [`inspect`](/cli/inspect.md) command and the portability gate at the end of [`BuildSetup.compile()`](/architecture/build-setup.md).
|
|
12
|
+
|
|
13
|
+
## How it works
|
|
14
|
+
|
|
15
|
+
It walks every executable and `.so` in an installation, lists each one's dynamic-library dependencies (parsing `ldd` on Linux / `otool` on macOS), and classifies every reference:
|
|
16
|
+
|
|
17
|
+
- **system / standard** library → fine;
|
|
18
|
+
- **relative / self** reference → fine (what a relocatable build should have);
|
|
19
|
+
- **absolute, non-system** reference → a portability problem.
|
|
20
|
+
|
|
21
|
+
For a portable build, any problem fails the inspection (the report exposes a single "first problem" verdict that callers check).
|
|
22
|
+
|
|
23
|
+
## Relativization
|
|
24
|
+
|
|
25
|
+
The fix lives in `LibAutoCorrect`, which rewrites the absolute library paths (rpaths) baked into binaries so they resolve relative to the install — `patchelf` on Linux (an `$ORIGIN`-relative rpath), `install_name_tool` on macOS (`@rpath` / `@loader_path`). It runs **during** finalize (so the result passes the portable check) and is exposed standalone as [`lib-auto-correct`](/cli/lib-auto-correct.md).
|
|
26
|
+
|
|
27
|
+
The same step also supports **non-portable** builds: with `--prefix` or `--enable-shared`, it additionally keeps the real prefix's `lib/` in the rpath, so a build pinned to a fixed location still finds its libraries. (CPython is built with a deliberately long rpath — unlike `chrpath`, `patchelf` can set a fresh rpath of any length, leaving room to rewrite it.)
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: Changelog
|
|
3
|
+
title: Changelog
|
|
4
|
+
description: High-level release highlights for portable-python, newest first.
|
|
5
|
+
tags: [changelog, releases]
|
|
6
|
+
timestamp: 2026-06-23T00:00:00Z
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## v2.0.1
|
|
10
|
+
|
|
11
|
+
- Bumped the bundled components (OpenSSL, SQLite, Tcl/Tk, …) to current versions.
|
|
12
|
+
- Refreshed dependencies and modernized CI (now on uv / tox-uv, with updated GitHub Actions).
|
|
13
|
+
- Added an OKF documentation bundle under `docs/` (the old top-level docs folded into it).
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: CLI Command
|
|
3
|
+
title: build-report
|
|
4
|
+
description: Show the status of buildable modules — which will be auto-compiled, which are present on the system, and which would fail — without building anything.
|
|
5
|
+
tags: [cli, build, report, command]
|
|
6
|
+
timestamp: 2026-06-23T00:00:00Z
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# build-report
|
|
10
|
+
|
|
11
|
+
Show which [modules](/modules/index.md) would be compiled for a spec, and whether the selection can actually build on this host — **without** building. The fastest way to catch a "broken" module before committing to a full compile.
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
portable-python build-report [OPTIONS] [PYTHON_SPEC]
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
For each candidate module it shows the [telltale](/concepts/telltale-detection.md) status and the linker outcome — `static` (will be compiled), `shared` (system copy used), `absent`, or `failed` (can't build here, e.g. a `-`-sigil Debian dev package is present). `PYTHON_SPEC` defaults to the latest known version.
|
|
18
|
+
|
|
19
|
+
# Examples
|
|
20
|
+
|
|
21
|
+
```shell
|
|
22
|
+
portable-python build-report 3.13.2
|
|
23
|
+
portable-python build-report 3.13.2 -m openssl,sqlite
|
|
24
|
+
```
|