Hey! These docs are for version 2.10, which is no longer officially supported. Click here for the latest version, 2.15!

PyOxidizer allows you to distribute your code as a single binary file, similar to [Pex files](🔗). Unlike Pex, these binaries include a Python interpreter, often greatly simplifying distribution.

See our blog post on [Packaging Python with the Pants PyOxidizer Plugin](🔗) for more discussion of the benefits of PyOxidizer.

## Step 1: Activate the backend

Add this to your `pants.toml`:

This adds the new `pyoxidizer_binary` target, which you can confirm by running `./pants help pyoxidizer_binary`.

This backend is experimental

We are still discovering the best ways to provide PyOxidizer support, such as how to make our [default template more useful](🔗). This backend does not follow the normal [deprecation policy](🔗), although we will do our best to minimize breaking changes.

We would [love your feedback](🔗) on this backend!

## Step 2: Define a `python_distribution` target

The `pyoxidizer_binary` target works by pointing to a `python_distribution` target with the code you want included. Pants then passes the distribution to PyOxidizer to install it as a binary.

So, to get started, create a `python_distribution` target per [Building distributions](🔗).

The `python_distribution` must produce at least one wheel (`.whl`) file. If you are using Pants's default of `generate_setup=True`, make sure you also use Pants's default of `wheel=True`. Pants will eagerly error when building your `pyoxidizer_binary` if you use a `python_distribution` that does not produce wheels.

## Step 3: Define a `pyoxidizer_binary` target

Now, create a `pyoxidizer_binary` target and set the `dependencies` field to the [address](🔗) of the `python_distribution` you created previously.

Usually, you will want to set the `entry_point` field, which sets the behavior for what happens when you run the binary.

If the `entry_point` field is not specified, running the binary will launch a Python interpreter with all the relevant code and dependencies loaded.

You can instead set `entry_point` to the Python module to execute (e.g. `myproject.myapp`). If specified, running the binary will launch the application similar to if it had been run as `python -m myproject.myapp`, for example.

## Step 4: Run `package`

Finally, run `./pants package` on your `pyoxidizer_binary` target to create a directory including your binary.

For example:

By default, Pants will write the package using this scheme: `dist/{path.to.tgt_dir}/{tgt_name}/{platform}/{debug,release}/install/{tgt_name}`. You can change the first part of this path by setting the `output_path` field, although you risk name collisions with other `pyoxidizer_binary` targets in your project. See [pyoxidizer_binary](🔗) for more info.

`debug` vs `release` builds

By default, PyOxidizer will build with Rust's "debug" mode, which results in much faster compile times but means that your binary will be slower to run. Instead, you can instruct PyOxidizer to build in [release mode](🔗) by adding this to `pants.toml`:

Or by using the command line flag `./pants --pyoxidizer-args='--release' package path/to:tgt`.

`run` support is upcoming

This will allow you to use `./pants run` to directly start your binary, without having to run from `dist/`. See https://github.com/pantsbuild/pants/pull/14646.

## Advanced use cases

Missing functionality? Let us know!

We would like to keep improving Pants's PyOxidizer support. We encourage you to let us know what features are missing through [Slack or GitHub](🔗)!

`[python-repos]` not yet supported for custom indexes

Currently, PyOxidizer can only resolve dependencies from PyPI and your first-party code. If you need support for custom indexes, please let us know by commenting on https://github.com/pantsbuild/pants/issues/14619.

(We'd be happy to help mentor someone through this change, although please still comment either way!)

### `python_distribution`s that implicitly depend on each other

As explained at [Building distributions](🔗), Pants automatically detects when one `python_distribution` depends on another, and it will add that dependency to the `install_requires` for the distribution.

When this happens, PyOxidizer would naively try installing that first-party dependency from PyPI, which will likely fail. Instead, include all relevant `python_distribution` targets in the `dependencies` field of the `pyoxidizer_binary` target.

### `template` field

If the default PyOxidizer configuration that Pants generates is too limiting, a custom template can be used instead. Pants will expect a file with the extension `.bzlt` in a path relative to the `BUILD` file.

The custom `.bzlt` may use four parameters from within the Pants build process inside the template (these parameters must be prefixed by `$` or surrounded with `${ }` in the template).

  • `RUN_MODULE` - The re-formatted `entry_point` passed to this target (or None).

  • `NAME` - This target's name.

  • `WHEELS` - All python distributions passed to this target (or `[]`).

  • `UNCLASSIFIED_RESOURCE_INSTALLATION` - This will populate a snippet of code to correctly inject the target's `filesystem_resources`.

For example, in a custom PyOxidizer configuration template, to use the `pyoxidizer_binary` target's `name` field:

You almost certainly will want to include this line, which is how the `dependencies` field gets consumed:

### `filesystem_resources` field

As explained in [PyOxidizer's documentation](🔗), you may sometimes need to force certain dependencies to be installed to the filesystem. You can do that with the `filesystem_resources` field: