Skip to main content

Support This Project

All projects made with passion 💙

Sponsor me

portapkg

PyPI License PyPI Downloads CI Last commit Ruff

Portable, offline-friendly Python package bundler and installer.

Bundle a package + all its dependencies on an online machine, then install on an air-gapped machine with nothing but Python and pip.

Quick start

Online machine — bundle a package

# Install portapkg
pip install portapkg

# Bundle a package for all 6 platforms + 5 Python versions
portapkg bundle instrumation

# Bundle for specific platforms only
portapkg bundle instrumation --platforms win_amd64,macosx_13_0_arm64

# Bundle for specific platforms and python versions (faster!)
portapkg bundle instrumation --platforms win_amd64 --python-versions 313

# Bundle a snapshot of the current environment (single platform, most reliable)
portapkg bundle instrumation --snapshot

# List all bundles
portapkg list
portapkg list --json    # machine-readable, for scripts / AI agents

# Show bundle details
portapkg info instrumation
portapkg info instrumation --json

# Update / re-fetch a bundle
portapkg update instrumation

# Verify a bundle covers a target platform/Python before shipping it
portapkg verify instrumation --platforms win_amd64 --python-versions 313

Output bundle structure:

bundles/
└── instrumation/
    ├── manifest.json
    └── wheels/
        ├── instrumation-0.3.0-py3-none-any.whl
        ├── pyserial-3.5-py2.py3-none-any.whl
        └── ...

Offline machine — install from USB

Copy the bundles/ folder and portapkg.py to a USB drive, then on the offline machine:

# List available bundles
python portapkg.py list

# Install a bundled package (works without internet)
python portapkg.py install instrumation

# Install to a custom path
python portapkg.py install instrumation --target ./myenv/Lib/site-packages

The portapkg.py file is fully self-contained — stdlib only, no dependencies.

How it works

  1. Dependency resolution: pip download <package> resolves the full transitive dependency tree using pip's own resolver. For multi-platform bundles, the resolver also scans each wheel's METADATA for platform-conditional deps (e.g. pefile; sys_platform == "win32") and recursively resolves any missing deps found.
  2. Multi-platform fetch: For each dependency, wheels are downloaded across multiple platforms × Python versions using pip download --platform --python-version --only-binary=:all:.
  3. Layered fallback strategy:
    • Layer 1: Exact binary wheel for the target platform/Python.
    • Layer 2: Platform-constrained source distribution.
    • Layer 3: Unconstrained source distribution — catches sdist-only packages like Eel.
    • Layer 4: Version bump — queries pip index versions for newer releases with binary wheel coverage (e.g. msgpack gaining cp313 wheels in a later patch).
  4. Offline install: pip install --no-index --find-links <wheels_dir> installs from local files only.

Development

Setup

# Clone the repo
git clone https://github.com/your-org/portapkg-py && cd portapkg-py

# Install in editable mode with dev dependencies
pip install -e ".[dev]"

Running tests

# Run all tests
pytest

# Run tests with coverage
pytest --cov=portapkg --cov-report=term-missing

# Run a specific test file
pytest tests/test_platform.py

# Run a specific test
pytest tests/test_platform.py::TestParseWheelFilename

# Run linter
pip install ruff
ruff check portapkg/ tests/ portapkg.py

Project structure

portapkg/
├── portapkg.py                ← standalone offline installer (stdlib only)
├── portapkg/
│   ├── cli.py                 ← entrypoint: bundle/list/info/update
│   ├── bundler/
│   │   ├── fetch.py           ← multi-platform wheel download
│   │   ├── resolver.py        ← dependency resolution (pip download)
│   │   └── manifest.py        ← manifest.json read/write
│   └── installer/
│       ├── install.py         ← offline install logic
│       └── platform.py        ← OS/arch/python detection
├── tests/                     ← pytest test suite
├── pyproject.toml             ← packaging & tool config
└── .github/workflows/         ← CI / release workflows

CI / CD

  • CI (.github/workflows/test.yml): runs on push/PR to main — tests across 3 OS × 5 Python versions, plus linting with ruff.
  • Release (.github/workflows/publish.yml): manual workflow_dispatch — specify a version tag, and it builds wheels + sdist and creates a GitHub Release with the artifacts attached.

Platform matrix

Platform Tag
Windows x86_64 win_amd64
Windows x86 win32
Linux x86_64 manylinux2014_x86_64
Linux ARM64 manylinux2014_aarch64
macOS Apple Silicon macosx_13_0_arm64
macOS Intel macosx_13_0_x86_64

Python versions: 3.9, 3.10, 3.11, 3.12, 3.13

Error handling

  • Missing binary wheel: warns and falls back through layered strategy (source dist → unconstrained sdist → version bump)
  • Platform-conditional deps: automatically resolved by scanning wheel METADATA for Requires-Dist lines with sys_platform / platform_system / implementation_name markers, evaluated with packaging.markers.
  • No compatible wheel on offline machine: clear human-readable error with suggested fix (--snapshot)
  • Missing pip: detected before any install attempt
  • Missing bundle: tells you which directory to copy

Configuration

PORTAPKG_BUNDLES_DIR

By default, bundles are stored in ./bundles/ relative to the current working directory. You can override this with the PORTAPKG_BUNDLES_DIR environment variable:

export PORTAPKG_BUNDLES_DIR=/path/to/bundles
portapkg bundle instrumation   # stores in /path/to/bundles/instrumation/

Both the CLI (portapkg) and the standalone script (portapkg.py) respect this environment variable.

Requirements

  • Online machine: Python 3.9+, pip (any version)
  • Offline machine: Python 3.9+, pip (any version)
  • No third-party packages are used by portapkg itself — stdlib only.

Metadata

Release files for portapkg 0.4.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for portapkg 0.4.0
File Size Uploaded
portapkg-0.4.0.tar.gz 25.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for portapkg 0.4.0
File Interpreter ABI Platform
portapkg-0.4.0-py3-none-any.whl Python 3 none any Details

Total release size: 43.6 kB

Release files / portapkg-0.4.0.tar.gz

Download URL portapkg-0.4.0.tar.gz
Size 25.4 kB
Tags Source
SHA-256 checksum
How to use checksums
a4941ddd8e8b3de57039854866caa6582becdd356436901d04e708b92ea54b7c
BLAKE2b-256 checksum
How to use checksums
755b7320daf40f70114178afc04cdd49d43f388b5a426732e508b1dd0115163c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 16, 2026.

Transparency log

Release files / portapkg-0.4.0-py3-none-any.whl

Download URL portapkg-0.4.0-py3-none-any.whl
Size 18.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
3a17a9490d5f0cbe11440e6954486d09cf9a3bb197bc6cec3efbe1a1693ded29
BLAKE2b-256 checksum
How to use checksums
60b370574b4552a0acc292dc45de2147c90fa87321080bd958a777f03c289668
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 16, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.4.0 This release

2 release files

0.3.3

2 release files

0.3.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page