Skip to main content

Repackages apps to restrict installation into isolated env

Project description

srepkg (Solo Repackage)

srepkg is a Python package that wraps an isolation layer around other Python packages.

Description

When a package wrapped in an isolation layer by srepkg is installed in an active, pre-existing Python environment:

  • The original package plus its dependencies are installed in a new, automatically created virtual environment.
  • A dependency-free "access" package installed in the pre-existing environment contains a controller module capable of making calls to the Python interpreter in the newly created environment.
  • This package structure ensures that none of the original package's dependencies conflict with packages in the pre-existing environment but still exposes the original package’s CL to the pre-existing environment.

Use Cases

For Package Distributors

  • srepkg can be useful if you are sharing a Python command line application, and you want to be certain that users can install and run it without worrying about dependency conflicts.
  • Wrapping a CL package with srepkg prior to sharing the package with other users will ensure that wherever the package is installed, it does not introduce dependency conflicts into a user's existing Python environment — even if the user knows nothing about managing Python environments.

For Package Users

  • Any existing CL package obtained from Python Packaging Index (PyPI) or GitHub can be wrapped with srepkg prior to installation.
  • If you want the original package commands to be accessible from a single environment (that is distinct from the isolated environment where the original package is installed), then srepkg is likely a good option.
  • However, if you want the isolated package's command interface to be available globally and/or want a much more mature isolation tool, then pipx is likely a better choice.

Getting Started

Requirements

  • Python version 3.10 or higher
  • For compatibility with srepkg, and existing package must:
    • Be installable via pip
    • Have command line entry point(s) specified in either one the [project.scripts] section of a pyproject.toml (preferred), the [options.entry_points] section of a setup.cfg, or the entry_points arguments passed to setup() in a setupy.py file.
  • Optional: miniconda or conda if you want to exactly follow the examples below

Installing

[!CAUTION] It is recommended to install srepkg in a virtual environment created using a tool such as conda or Python's built-in venv module. In the example below, we use conda.

conda create -n srepkg_test python=3.10
pip install srepkg

Usage

usage: srepkg [-h] [-g [GIT_REF]] [-r [PYPI_VERSION]] [-n [SREPKG_NAME]]
              [-c [CONSTRUCTION_DIR]] [-d [DIST_OUT_DIR]] [-f [LOGFILE_DIR]]
              orig_pkg_ref

positional arguments:
  orig_pkg_ref          A reference to the original package to be repackaged. Can be a
                        local path to the directory where a package'spyproject.toml or
                        setup.py resides, a PyPI package name, or a Github repo url.

options:
  -h, --help            show this help message and exit
  -g [GIT_REF], --git_ref [GIT_REF]
                        A git branch name, tag name, or commit SHA that determines the
                        original package commit to use (if ORIG_PKG_REF is a git repo).
                        Defaults to: HEAD of the default branch for a remote Github repo,
                        and the currently checked out branch for a local repo.
  -r [PYPI_VERSION], --pypi_version [PYPI_VERSION]
                        Original package version to use (if ORIG_PKG_REF is a PyPI
                        package). Defaults to the latest PyPI package.
  -n [SREPKG_NAME], --srepkg_name [SREPKG_NAME]
                        Name to be used for repackaged package. Default is
                        <ORIGINAL_PACKAGE_NAME>srepkg
  -c [CONSTRUCTION_DIR], --construction_dir [CONSTRUCTION_DIR]
                        Directory where non-compressed repackage will be built and saved.
                        If not specified, srepkg is built in a temp directory that gets
                        deleted after wheel and or sdist archiveshave been created.
  -d [DIST_OUT_DIR], --dist_out_dir [DIST_OUT_DIR]
                        Directory where srepkg wheel and or sdist archives are saved.
                        Default is ./srepkg_dists.
  -f [LOGFILE_DIR], --logfile_dir [LOGFILE_DIR]
                        Directory where srepkg log file is saved. Default is to use
                        temporary directory that is automatically deleted at end of
                        execution.

Demos

Demo #1: Repackaging a local package that depends on old version of numpy

The following demo shows how we take an original package that has a dependency conflict what's already installed in an active Python environment, re-package with srepkg, install the re-packaged version, and access the original package's CLI from the active environment, without experiencing any dependency conflict.

Environment Setup

First, confirm we are using a conda environment dedicated to our tests. From the srepkg repo root, run:

$ conda create -n srepkg_oldmath_test python=3.10
$ conda activate srepkg_oldmath_test
$ pip install srepkg

Then, let's install a version of numpy that is relatively new (as of Feb. 2025).

$ pip install numpy==2.2.2

Later on, we will use the presence of this current numpy version to help illustrate the absence of dependency conflicts.

Repackage oldmathinto oldmathsrepkg

Next, we will re-package a simple local Python package oldmath with its source files located ./test/demos/oldmath/. oldmath depends on numpy 1.26.4.

$ srepkg test/demos/oldmath/

✅ Building original package wheel from source code
✅ Creating virtual env
	Virtual env created with the following pypa packages installed:
	• pip==25.0.1
	• setuptools==75.8.0
	• wheel==0.45.1
✅ Installing oldmath-0.1.0-py3-none-any.whl in virtual env
✅ Building srepkg wheel
	oldmathsrepkg wheel saved as: /home/duane/dproj/srepkg/srepkg_dists/oldmathsrepkg-0.1.0-py3-none-any.whl
✅ Building srepkg sdist
	oldmathsrepkg sdist saved as: /home/duane/dproj/srepkg/srepkg_dists/oldmathsrepkg-0.1.0.tar.gz

oldmathsrepkg can be installed using either of the following commands:
	• pip install /home/duane/dproj/srepkg/srepkg_dists/oldmathsrepkg-0.1.0-py3-none-any.whl
	• pip install /home/duane/dproj/srepkg/srepkg_dists/oldmathsrepkg-0.1.0.tar.gz
Upon installation, oldmathsrepkg will provide access to the following command line entry points: 
	• oldmath

The repackaged version of oldmath is called oldmathsrepkg, and it has been built into both wheel and sdist distributions.

[!NOTE] The -n option can be used to assign a custom name to the repackaged package and distributions.

Install and test oldmathsrepkg

Next, install oldmathsrepkg from the newly created wheel:

$ pip install ./srepkg_dists/oldmathsrepkg-0.1.0-py3-none-any.whl

Now, we can get some info about oldmath:

$ oldmath --help

usage: oldmath [-h] factor

Multiplies the numpy array [1 2 3] by a user-provided integer. Displays the resulting array as well as the version of numpy used.

positional arguments:
  factor      An integer that numpy array [1 2 3] will be multiplied by

options:
  -h, --help  show this help message and exit

Next, we run:

$ oldmath 2025

2025 * [1 2 3] = [2025 4050 6075]
numpy version used by this program = 1.26.4

Confirm absence of dependency conflicts

Double-check the version of numpy that's installed in our active Python environment:

$ pip freeze | grep numpy

numpy==2.2.2

Finally, confirm that we do not have any dependency conflicts:

$ pip check

No broken requirements found.

The key thing to note is that oldmath, which we can access from the active Python environment uses numpy 1.26.4, but we still have numpy 2.2.2 installed the active environment.

Distribute oldmathsrepkg with confidence that it will not break environments

We can now send the oldmathsrepkg wheel and/or sdist (saved under ./srepkg_dists) to colleagues, knowing that install it will not cause problems in their Python environment, even if they are using a current version of numpy and do not know much / anything about Python dependencies and environments.

Demo #2: Re-package a distribution obtained from PyPI

We can re-package the latest version of scrape available on the PyPI using the following:

$ srepkg scrape

✅ Retrieving scrape from Python Packaging Index
	Downloaded files:
	• scrape-0.11.3-py3-none-any.whl
✅ Creating virtual env
	Virtual env created with the following pypa packages installed:
	• pip==25.0.1
	• setuptools==75.8.0
	• wheel==0.45.1
✅ Installing scrape-0.11.3-py3-none-any.whl in virtual env
✅ Building srepkg wheel
	scrapesrepkg wheel saved as: /home/duane/dproj/srepkg/srepkg_dists/scrapesrepkg-0.11.3-py3-none-any.whl
✅ Building srepkg sdist
	scrapesrepkg sdist saved as: /home/duane/dproj/srepkg/srepkg_dists/scrapesrepkg-0.11.3.tar.gz

scrapesrepkg can be installed using either of the following commands:
	• pip install /home/duane/dproj/srepkg/srepkg_dists/scrapesrepkg-0.11.3-py3-none-any.whl
	• pip install /home/duane/dproj/srepkg/srepkg_dists/scrapesrepkg-0.11.3.tar.gz
Upon installation, scrapesrepkg will provide access to the following command line entry points: 
	• scrape

We can then install scrapesrepkg, and try using it on a file located under test/demos/:

$ pip install pip install srepkg_dists/scrapesrepkg-0.11.3-cp310-abi3-linux_x86_64.whl

Processing ./srepkg_dists/scrapesrepkg-0.11.3-py3-none-any.whl
Installing collected packages: scrapesrepkg
Successfully installed scrapesrepkg-0.11.3

$ scrape test/demos/scrape/explorers_club.html -pt

Failed to enable cache: No module named 'requests_cache'
DISCOVER THE GRAND EXPLORERS' CLUB!
The Grand Explorers' Club is a prestigious society dedicated to adventurers and thrill-seekers. More than 250,000 members participate in daring expeditions and exploration missions across the globe.

If we wanted to re-package a specific version (e.g.0.11.0) from PyPI we could do this:

$ srepkg scrape -r 0.11.0

Demo #3: Re-package a distribution obtained from Github

We can also re-package using a GitHub repo as the original source:

srepkg https://github.com/huntrar/scrape      
✅ Cloning https://github.com/huntrar/scrape into temporary directory
✅ Building original package wheel from source code
✅ Creating virtual env
	Virtual env created with the following pypa packages installed:
	• pip==25.0.1
	• setuptools==75.8.0
	• wheel==0.45.1
✅ Installing scrape-0.11.3-py3-none-any.whl in virtual env
✅ Building srepkg wheel
	scrapesrepkg wheel saved as: /home/duane/dproj/srepkg/srepkg_dists/scrapesrepkg-0.11.3-py3-none-any.whl
✅ Building srepkg sdist
	scrapesrepkg sdist saved as: /home/duane/dproj/srepkg/srepkg_dists/scrapesrepkg-0.11.3.tar.gz

scrapesrepkg can be installed using either of the following commands:
	• pip install /home/duane/dproj/srepkg/srepkg_dists/scrapesrepkg-0.11.3-py3-none-any.whl
	• pip install /home/duane/dproj/srepkg/srepkg_dists/scrapesrepkg-0.11.3.tar.gz
Upon installation, scrapesrepkg will provide access to the following command line entry points: 
	• scrape

If we want to re-package a specific commit from the scrape GitHub repo, we can do this:

$ srepkg https://github.com/huntrar/scrape -g 1dfd98bb0a308ef2a45b1e5dd136c38b17c27bc7

If we want to re-package a specific release or tag, we would do this:

$ srepkg https://github.com/huntrar/scrape -g 0.11.2 

Comparing with a similar tool: pipx

srepkg is in many ways similar to the widely used tool pipx which also allows users to install a Python package in an isolated environment and then access its command line tool(s) from another environment. Key differences between srepkg and pipx include:

  • The actions that ensure isolation via pipx are taken by the user at the time of package installation. With srepkg, source code is wrapped in an isolating layer prior to installation, and the re-packaged application is automatically placed in its own environment during installation.
  • The CLI of a package that has been re-packaged by srepkg accessible from an environment containing its access package. pipx allows global access to isolated command line applications.
  • pipx is more mature and feature-rich than srepkg. If you have control of the package installation process, pipx will likely be more useful than srepkg. However, if you are distributing but not installing a Python CLI app and want to be certain the app is always installed into an isolated environment regardless what happens at install time, consider using srepkg.

Testing

To run the project tests, we can clone a copy of the repo locally, and install in editable mode with:

$ git clone https://github.com/duanegoodner/srepkg
$ cd srepkg
$ pip install -e '.[test]'

Then run the test suite and generate a coverage report:

$ coverage run -m pytest
$ coverage report -m

Contributing

Issues, Pull Requests and/or Discussions are welcome and appreciated!

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

srepkg-0.1.1.tar.gz (74.6 kB view details)

Uploaded Source

Built Distribution

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

srepkg-0.1.1-py3-none-any.whl (91.7 kB view details)

Uploaded Python 3

File details

Details for the file srepkg-0.1.1.tar.gz.

File metadata

  • Download URL: srepkg-0.1.1.tar.gz
  • Upload date:
  • Size: 74.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.11.11

File hashes

Hashes for srepkg-0.1.1.tar.gz
Algorithm Hash digest
SHA256 d7ecf394a1c6a70388ea241277700798b1cd6b57b9448b29b2a00f2b5d7effd7
MD5 8643b0b7ac0f680d5db95aeaf7931f9f
BLAKE2b-256 27e3059aa6f6479855dba68d23a899261093f7c07bbcdb0f7304cf7bc2ba2391

See more details on using hashes here.

File details

Details for the file srepkg-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: srepkg-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 91.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.11.11

File hashes

Hashes for srepkg-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 567ebf3320bd4cdd5677cc31047df0d855a40212f04eb61ba61fa120f40a2db0
MD5 d0895298384a00d0f5d3226a85fc5f94
BLAKE2b-256 0aa8a78fd7ebafb8fe00e93d4c0cd92f17fed985e216e41fc6622ee61eb09840

See more details on using hashes here.

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