# Python

Like `pyenv`, `mise` can manage multiple versions of Python on the same system. Mise can also automatically create virtual environments for your projects and integrates with `uv`.

> The following are instructions for using the python mise core plugin. The core plugin will be used
> so long as no plugin is manually
> installed named "python" using `mise plugins install python [GIT_URL]`.

The code for this is inside of the mise repository
at [`./src/plugins/core/python.rs`](https://github.com/jdx/mise/blob/main/src/plugins/core/python.rs).

## Usage

The following installs the latest version of python-3.15.x and makes it the global
default:

```sh
mise use -g python@3.15
```

You can also use multiple versions of python at the same time:

```sh
$ mise use -g python@3.14 python@3.15
$ python -V
3.14.0
$ python3.15 -V
3.15.0
```

You can also install a specific python flavour. To get the latest version from a flavour just use the
flavour prefix.

```sh
mise use -g python@anaconda         # latest version of anaconda
```

See the [Python Cookbook](/mise-cookbook/python.html) for common tasks and examples.

## Tool Options

The following [tool-options](/dev-tools/#tool-options) are available for the `python` backend.
These options go in the `[tools]` section in `mise.toml`.

### `install_env`

Set environment variables for python-build, default package installation, and install-time
verification commands run by the core `python` backend:

```toml
[tools]
python = { version = "latest", install_env = { CONFIGURE_OPTS = "--enable-optimizations" } }
```

### `patch_sysconfig`

When installing precompiled Python binaries on Unix, mise patches the Python `sysconfig` data by
default so build-time paths from `python-build-standalone` point at the final mise install path. If
that patching causes an install problem for a specific Python build, disable it with
`patch_sysconfig = false`:

```toml
[tools]
python = { version = "3.14", patch_sysconfig = false }
```

Disabling this patch can leave stale build-time paths in the installed Python's `sysconfig` data, so
prefer the default unless you need this as an install workaround.

## `.python-version` support

`.python-version`/`.python-versions` files are supported by mise. See [idiomatic version files](/configuration.html#idiomatic-version-files).

## Automatic virtualenv activation

mise has two ways to manage Python virtualenvs:

| Mechanism             | Best for                     | Config location      |
| --------------------- | ---------------------------- | -------------------- |
| `python.uv_venv_auto` | uv projects (with `uv.lock`) | `[settings]` section |
| `_.python.venv`       | Projects not using uv        | `[env]` section      |

**`python.uv_venv_auto`** detects and sources the virtual environment managed by `uv` (`.venv` by default, or the path configured by `UV_PROJECT_ENVIRONMENT`). Use `"source"` to only activate existing venvs, or `"create|source"` to create if missing. mise locates the uv project by walking up for a `uv.lock` file, so a `uv.lock` must be present — without one the setting does nothing. See the [mise + uv Cookbook](/mise-cookbook/python.html#mise-uv) for full examples.

**`_.python.venv`** creates/activates a venv and adds it to PATH. It works with both `mise activate` and `mise exec`. Use this for projects that don't use uv.

::: warning
These are separate mechanisms with different code paths. Options like `uv_create_args` and `python_create_args` in `_.python.venv` are not used by `python.uv_venv_auto`.
:::

::: warning
The legacy `virtualenv` tool option (`python = { version = "3.15", virtualenv = ".venv" }` in `[tools]`) is deprecated and will be removed in a future release. Use `_.python.venv` (below) instead.
:::

### `_.python.venv` configuration

Use `_.python.venv` in the `[env]` section of `mise.toml`:

```toml
[tools]
python = "3.15" # [optional] will be used for the venv

[env]
_.python.venv = ".venv" # relative to this file's directory
_.python.venv = "/root/.venv" # can be absolute
_.python.venv = "{{env.HOME}}/.cache/venv/myproj" # can use templates
_.python.venv = { path = ".venv", create = true } # create the venv if it doesn't exist
_.python.venv = { path = ".venv", create = true, python = "3.15" } # use a specific python version
_.python.venv = {
  path = ".venv", create = true,
  python_create_args = ["--without-pip"], # pass args to python -m venv
}
_.python.venv = {
  path = ".venv", create = true,
  uv_create_args = ["--system-site-packages"], # pass args to uv venv
}
# Install seed packages (pip, setuptools, and wheel) into the virtual environment.
_.python.venv = { path = ".venv", create = true, uv_create_args = ['--seed'] }
```

The venv will need to be created manually with `python -m venv /path/to/venv` unless `create=true`.
See [env-directives](https://mise.jdx.dev/environments/#env-directives) for `_.python.venv`.

::: tip
Virtualenv activation requires `mise activate` or `mise exec`. When using [shims](/dev-tools/shims) alone, the venv's `bin/` directory is not added to PATH, so `which python` will point to the shim rather than the venv's interpreter.
:::

### `python.uv_venv_auto` setting

For uv-managed projects (those with a `uv.lock` file), you can use the `python.uv_venv_auto` setting to automatically source or create the virtual environment that uv manages. mise finds the project root by walking up for a `uv.lock`; the presence of that lockfile is how mise knows the project uses uv, so a `uv.lock` must be present. If no `uv.lock` is found the setting is a no-op — run `uv sync` (or `uv lock`) to generate one first. See the [mise + uv Cookbook](/mise-cookbook/python.html#mise-uv) for full examples.

```toml [mise.toml]
[settings]
python.uv_venv_auto = "source"        # activate existing .venv
# or
python.uv_venv_auto = "create|source" # create .venv if missing, then activate
```

mise respects uv's `UV_PROJECT_ENVIRONMENT` variable when choosing the environment path. A relative
path is resolved from the uv project root (the directory containing `uv.lock`), while an absolute
path is used as-is. When the variable is unset or empty, mise uses `.venv`.

```toml [mise.toml]
[env]
UV_PROJECT_ENVIRONMENT = "my.venv"

[settings]
python.uv_venv_auto = "create|source"
```

## mise & uv

If you have installed `uv` (for example, with `mise use -g uv@latest`), `mise` will use it to create virtual environments via `_.python.venv`. Otherwise, it will use the built-in `python -m venv` command.

Note that `uv` does not include `pip` by default (as `uv` provides `uv pip` instead). If you need the `pip` package, add the `uv_create_args = ['--seed']` option.

:::warning
The `true` value for `python.uv_venv_auto` is considered legacy and will be deprecated in a
future release (planned for mise 2026.7). Prefer `"source"` or `"create|source"` instead.
Note: the `python.uv_venv_auto` **setting** itself is not going away — only the `true` value is
being phased out.
:::

One difference between the legacy `true` value and the newer string values is that `true` also
exports `UV_PYTHON` (set to just the Python version number). This tells `uv` which Python version
to use, but does not guarantee that `uv` uses the specific interpreter managed by `mise` — `uv`
may fall back to a system or self-managed Python of the same version.

To strictly ensure `uv` uses `mise`'s managed Python interpreter, set `UV_PYTHON` to the actual
install path instead:

```toml
[tools]
python = "3.15"

[env]
UV_PYTHON = { value = "{{ tools.python.path }}", tools = true }
```

See the [mise + uv Cookbook](/mise-cookbook/python.html#mise-uv) for more examples.

## Default Python packages

::: warning Planned deprecation
Default package files are deprecated. They are still supported for now, but mise will start warning
in `2026.11.0` and support will be removed in `2027.11.0`.

For Python CLIs, install the tool directly with the [pipx backend](/dev-tools/backends/pipx.html):

```toml
[tools]
"pipx:black" = "latest"
```

For packages that really should be installed into every Python version, use a tool-level
`postinstall` hook:

```toml
[tools]
python = { version = "3.13", postinstall = "python -m pip install --upgrade ansible" }
```

:::

mise can automatically install a default set of Python packages with pip right after installing a
Python version. To use this legacy feature, provide a `$HOME/.default-python-packages` file that
lists one package per line, for example:

```text
ansible
pipenv
```

You can specify a non-default location of this file by setting a `MISE_PYTHON_DEFAULT_PACKAGES_FILE`
variable.

## Precompiled python binaries

By default, mise will
download [precompiled binaries](https://github.com/astral-sh/python-build-standalone)
for python instead of compiling them with python-build. This makes installing python much faster.

In addition to being faster, it also means you don't have to install all of the system dependencies
either.

That said, there are
some [quirks](https://github.com/astral-sh/python-build-standalone/blob/main/docs/quirks.rst)
with the precompiled binaries to be aware of.

If you'd like to disable these binaries, set `mise settings python.compile=1`.

These binaries may not work on older CPUs however you may opt into binaries which
are more compatible with older CPUs by setting `MISE_PYTHON_PRECOMPILED_ARCH` with
a different version. See <https://gregoryszorc.com/docs/python-build-standalone/main/running.html> for
more information
on this option. Set it to "x86_64" for the most compatible binaries.

## Windows

mise uses the same precompiled python-build-standalone binaries on Windows
(compiling with python-build is not supported there). Two of the upstream
[quirks](https://github.com/astral-sh/python-build-standalone/blob/main/docs/quirks.rst)
are smoothed over by mise:

- The archives only ship `python.exe`, so mise creates a `python3.exe` alias
  next to it.
- The archives ship no `pip.exe` (pip is only available as `python -m pip`),
  so mise creates `pip.cmd`/`pip3.cmd` wrappers in the install root that
  delegate to `python -m pip`. Because they delegate, they keep working even
  after pip upgrades itself.

The install's `Scripts` directory is included in `PATH`, so console scripts
from `pip install` (e.g. `black`) are runnable. If you rely on shims instead
of `mise activate`, run `mise reshim` after `pip install` to generate shims
for newly installed executables.

## python-build

Optionally, mise
uses [python-build](https://github.com/pyenv/pyenv/tree/master/plugins/python-build) (part of pyenv)
to compile python runtimes,
you need to ensure
its [dependencies](https://github.com/pyenv/pyenv/wiki#suggested-build-environment) are installed
before installing python with
python-build.

## Installing free-threaded python

Free-threaded python can be installed via python-build by running the following:

```bash
MISE_PYTHON_COMPILE=0 MISE_PYTHON_PRECOMPILED_FLAVOR=freethreaded+pgo-full mise install python
```

Or to compile with python-build:

```bash
MISE_PYTHON_COMPILE=1 PYTHON_BUILD_FREE_THREADING=1 mise install python
```

## Troubleshooting errors with Homebrew

If you normally use Homebrew and you see errors regarding OpenSSL,
your best bet might be using the following command to install Python:

```sh
CFLAGS="-I$(brew --prefix openssl)/include" \
LDFLAGS="-L$(brew --prefix openssl)/lib" \
mise install python@latest;
```

Homebrew installs its own OpenSSL version, which may collide with system-expected ones.
You could even add that to your
`.profile`,
`.bashrc`,
`.zshrc`...
to avoid setting them every time

Additionally, if you encounter issues with python-build,
you may benefit from unlinking pkg-config prior to install
([reason](https://github.com/pyenv/pyenv/issues/2823#issuecomment-1769081965)).

```sh
brew unlink pkg-config
mise install python@latest
brew link pkg-config
```

Thus the entire script would look like:

```sh
brew unlink pkg-config
CFLAGS="-I$(brew --prefix openssl)/include" \
  LDFLAGS="-L$(brew --prefix openssl)/lib" \
  mise install python@latest
brew link pkg-config
```

## Settings

`python-build` already has
a [handful of settings](https://github.com/pyenv/pyenv/tree/master/plugins/python-build), in
additional to that python in mise has a few extra configuration variables.

Set these with `mise settings set [VARIABLE]=[VALUE]` or by setting the environment variable.

<script setup>
import Settings from '/components/settings.vue';
</script>
<Settings child="python" :level="3" />
