PyApp

CI - Test CD - Publish Project - Version Project - Downloads License - Apache-2.0 OR MIT GitHub Sponsors


PyApp is a CLI wrapper for Python applications that bootstrap themselves at runtime. Each application is configured with environment variables at build time.

For a more streamlined workflow, consider using the built-in app build target of Hatch.

Table of Contents

Building

Before building your application, you must configure your project at the very least.

After you have done that, there are 2 ways to build your application.

Local repository

Clone this repository then enter the cloned directory and run:

cargo build --release

The executable will be located at target/release/pyapp.exe if on Windows or target/release/pyapp otherwise. If a particular target has been set (or if cross is used since it always sets one), then the release directory will be nested one level deeper under target/<TARGET>.

Installation

Select the directory in which to build the executable with the --root option and run:

cargo install pyapp --force --root <DIR>

The executable will be located at <DIR>/bin/pyapp.exe if on Windows or <DIR>/bin/pyapp otherwise.

Note: If you want to cross compile using cross, this method of building is currently unsupported.

Runtime behavior

Initialization

On the first run of the application:

  1. the distribution (if not embedded) will be downloaded and cached
  2. the distribution will be unpacked
  3. the project will be installed

All subsequent invocations will only check if the unpacked distribution directory exists and nothing else, to maximize CLI responsiveness.

Detection

A single environment variable called PYAPP is injected with the value of 1 (by default) when running applications and may be used to detect this mode of installation versus others.

pip

When installing or upgrading projects, pip uses isolation (by default) to provide consistent behavior on each user's machine.

Commands

Built applications have a single top-level command group named self (by default) and all other invocations will be forwarded to your actual execution logic.

Exposed

Restore

<EXE> self restore

This will wipe the unpacked distribution and start fresh.

Update

<EXE> self update

This will update the project to the latest available version in the currently used distribution.

Hidden

Metadata

<EXE> self metadata

This displays customized output based on a template.

Configuration

All configuration is done with environment variables.

Project

There are 2 ways to configure runtime installation, neither of which will occur when disabled.

Package index

The desired project name and version are configured with the PYAPP_PROJECT_NAME and PYAPP_PROJECT_VERSION options, respectively. The project name must adhere to PEP 508 and will be normalized during builds according to PEP 503.

Embedding

You may embed the project with the PYAPP_PROJECT_PATH option which should be a path to a wheel ending in .whl or a source distribution ending in .tar.gz.

Execution mode

The following options are mutually exclusive:

| Option | Description | | --- | --- | | PYAPP_EXEC_MODULE | This is the name of the module to execute via python -m <MODULE> | | PYAPP_EXEC_SPEC | This is an object reference to execute e.g. pkg.foo:cli | | PYAPP_EXEC_CODE | This is arbitrary code to run via python -c <CODE> (the spec option uses this internally) |

If none are set then the PYAPP_EXEC_MODULE option will default to the value of PYAPP_PROJECT_NAME with hyphens replaced by underscores.

Python distribution

Known

Setting the PYAPP_PYTHON_VERSION option will determine the distribution used at runtime based on the environment at build time. If unset then the default will be the latest stable minor version of CPython.

CPython

| ID | | --- | | 3.7 | | 3.8 | | 3.9 | | 3.10 | | 3.11 |

The source of distributions is the python-build-standalone project.

Some distributions have variants that may be configured with the PYAPP_DISTRIBUTION_VARIANT option:

| Platform | Options | | --- | --- | | Linux |

| | Windows | |

Custom

You may explicitly set the PYAPP_DISTRIBUTION_SOURCE option which overrides the known distribution settings. The source must be a URL that points to an archived version of the desired Python distribution.

Setting this manually may require you to define extra metadata about the distribution that is required for accurate runtime behavior.

Format

The following formats are supported for the PYAPP_DISTRIBUTION_FORMAT option, with the default chosen based on the ending of the source URL:

| Format | Extensions | Description | | --- | --- | --- | | tar\|gzip |

| A tar file with gzip compression | | tar\|zstd | | A tar file with Zstandard compression | | zip | | A ZIP file with DEFLATE compression |

Python location

You may set the relative path to the Python executable after unpacking the archive with the PYAPP_DISTRIBUTION_PYTHON_PATH option. The default is python.exe on Windows and bin/python3 on all other platforms.

Embedding

You may set the PYAPP_DISTRIBUTION_EMBED option to true or 1 to embed the distribution in the executable at build time to avoid fetching it at runtime. When distribution embedding is enabled, you can set the PYAPP_DISTRIBUTION_PATH option to use a local path rather than fetching the source.

pip

These options have no effect when the project installation is disabled.

Extra arguments

You may set the PYAPP_PIP_EXTRA_ARGS option to provide extra arguments to the pip install command at runtime when installing or updating the project e.g. --index-url URL --only-binary :all:.

Allowing configuration

You may set the PYAPP_PIP_ALLOW_CONFIG option to true or 1 to allow the use of environment variables and other configuration at runtime.

Skipping project installation

You may set the PYAPP_SKIP_INSTALL option to true or 1 to skip installing the project in the distribution. This allows for entirely predefined distributions and thus no network calls at runtime if used in conjunction with embedding.

Installation indicator

The environment variable that is used for detection may be set to the path of the executable at runtime if you set the PYAPP_PASS_LOCATION option to true or 1. This is useful if your application wishes to in some way manage itself.

Management command name

You may set the PYAPP_SELF_COMMAND option to override the default name (self) of the management command. This is useful if you wish to have complete control of the interface or to set it to a bogus value with the intention of not using it.

Metadata template

You may set a custom template used to output metadata with the PYAPP_METADATA_TEMPLATE option which supports the following placeholders:

| Placeholder | Description | | --- | --- | | {project} | The normalized project name | | {version} | The currently installed version of the project |

The default template is {project} v{version} if this option is unset.

This is useful for setting custom commands for the Starship prompt. The following example configuration assumes that the built executable has been renamed to foo:

````toml format = """ ... ${custom.foo}\ ... $line_break\ ... $character"""

[custom.foo] command = "foo self metadata" when = true

Windows

shell = ["cmd", "/C"]

Other

shell = ["sh", "--norc"]

````

Cross compilation

Configuration for cross is validated by CI to ensure all known environment variable options are passed through to the containers.

When embedding the project or the distribution using a local path, you must use the local repository way of building and ensure that the configured files to embed reside within the repository and the options refer to relative paths.

TODO

License

PyApp is distributed under the terms of any of the following licenses: