Skip to main content

Portable, offline-friendly Python package bundler and installer

Project description

portapkg

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 a snapshot of the current environment (single platform, most reliable)
portapkg bundle instrumation --snapshot

# List all bundles
portapkg list

# Show bundle details
portapkg info instrumation

# Update / re-fetch a bundle
portapkg update instrumation

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.
  2. Multi-platform fetch: For each dependency, wheels are downloaded across 6 platforms × 5 Python versions using pip download --platform --python-version --only-binary=:all:.
  3. Fallback: If no binary wheel exists for a platform, the tool falls back to a source distribution and warns the user.
  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 to source dist
  • 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

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.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

portapkg-0.1.0.tar.gz (16.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

portapkg-0.1.0-py3-none-any.whl (11.2 kB view details)

Uploaded Python 3

File details

Details for the file portapkg-0.1.0.tar.gz.

File metadata

  • Download URL: portapkg-0.1.0.tar.gz
  • Upload date:
  • Size: 16.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for portapkg-0.1.0.tar.gz
Algorithm Hash digest
SHA256 b3f107ce6d6fe25685c289cb1b344fedae1de827d8eb73aafad546d4a60b9588
MD5 94ae0bf5b695c1c844dde1c90dcbcc99
BLAKE2b-256 6257a824f1ed40afde577e77303aa5c5e76f2e084f4b088099f1cb1d3b6a3429

See more details on using hashes here.

Provenance

The following attestation bundles were made for portapkg-0.1.0.tar.gz:

Publisher: publish.yml on abduznik/portapkg-py

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file portapkg-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: portapkg-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 11.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for portapkg-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 8d5f2dca54dcaec5c89cb585c12ded0b88ad5f0fd50911b60c7c6620715c07c3
MD5 7b3ea1fa997d11391ac742bc8afb9b54
BLAKE2b-256 46a4d31ec0d73e6bed5944866810029be34616fe2f4ddb581ac4a714a606d427

See more details on using hashes here.

Provenance

The following attestation bundles were made for portapkg-0.1.0-py3-none-any.whl:

Publisher: publish.yml on abduznik/portapkg-py

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page