> ## Documentation Index
> Fetch the complete documentation index at: https://aspect.build/llms.txt
> Use this file to discover all available pages before exploring further.

# Python with Bazel

> Build, test, and containerize Python projects with Bazel using aspect_rules_py, rules_python, uv lockfiles, and hermetic python-build-standalone interpreters.

export const gatedAccess = (user, group) => {
  const loggedIn = !!(user && user.loggedIn);
  const groups = user && user.tenantMetadata && user.tenantMetadata.docsGroups || [];
  if (loggedIn && (!group || groups.indexOf(group) >= 0)) {
    return "entitled";
  }
  return loggedIn ? "signed-in" : "anonymous";
};

export const GatedLink = ({access, href, group, children}) => {
  const note = group ? "Aspect Enterprise customers" : "free Aspect account";
  const muted = {
    fontSize: "0.85em",
    opacity: 0.7,
    whiteSpace: "nowrap"
  };
  if (access === "entitled") {
    return <a href={href}>{children}</a>;
  }
  if (access !== "signed-in") {
    return <span>
        <a href={"/login?redirect=" + encodeURIComponent(href)}>{children}</a>
        <span style={muted}> (sign in: {note})</span>
      </span>;
  }
  return <span>
      {children}
      <span style={muted}> ({note})</span>
    </span>;
};

`aspect_rules_py` provides `py_library`, `py_binary`, and `py_test` rules that
behave like standard Python tooling, as an alternative to the community
[rules\_python](https://github.com/bazel-contrib/rules_python) ruleset. It
resolves PyPI dependencies from a [uv](https://github.com/astral-sh/uv)
lockfile and provisions its own hermetic interpreters, so `rules_python` is
optional.

<Tip>
  Stuck?

  * Check for [known issues](https://github.com/aspect-build/rules_py/issues)
  * Ask in <code>#python</code> on [Bazel Slack](https://slack.bazel.build)
  * Sign up for [commercial support](/services), provided by Aspect as a shared Slack channel.
</Tip>

## Create a new project

<Steps>
  <Step title="Install the Aspect CLI">
    ```bash theme={null}
    brew install aspect-build/aspect/aspect
    ```

    For other installation methods, see [Aspect CLI](/docs/cli).
  </Step>

  <Step title="Scaffold a new project">
    ```bash theme={null}
    aspect init my-app --preset py && cd my-app
    ```

    A working Bazel + Python setup with `uv` for dependency management and `ruff` and `ty` for linting. See [`aspect init`](/docs/cli/tasks/init) for the full flag reference (presets, `--template`, `--license`).

    Prefer GitHub's "Use this template" button? Start from [aspect-starters/py](https://github.com/aspect-starters/py) instead, or `git clone https://github.com/aspect-starters/py my-app`.
  </Step>

  <Step title="Set up your dev environment">
    ```bash theme={null}
    direnv allow
    ```

    Follow the prompts to run `bazel run //tools:bazel_env`, which installs project tools to your PATH. [direnv](https://direnv.net) is optional but recommended; without it you have to install tools yourself.
  </Step>

  <Step title="Add a dependency">
    Add the package to `pyproject.toml` under `[project] dependencies`, then regenerate `uv.lock`:

    ```bash theme={null}
    ./tools/repin
    ```

    Depend on it as `@pypi//requests` in a `BUILD` file.
  </Step>

  <Step title="Build and run">
    ```bash theme={null}
    bazel run //hello/py:hello    # run the sample binary
    bazel test //...              # run all tests
    ```

    The starter's Python `BUILD` files are written by hand; see `hello/py/BUILD.bazel` for the pattern.
  </Step>
</Steps>

## Explore Bazel with Python

<Columns cols={2}>
  <Card title="Starter template" icon="clone" href="https://github.com/aspect-starters/py">
    Clone the starter repository for a working Bazel + Python setup.

    Open it in a GitHub Codespace to try it without a local install.
  </Card>

  <Card title="Bazel 102: Python training" icon="graduation-cap" href="/learning/bazel-102">
    A hands-on course for building, testing, and shipping Python with Bazel.

    Covers dependency pinning, virtualenvs, pytest, linting, and container images.
  </Card>
</Columns>

## Key features

* **Idiomatic Python behavior.** Uses the standard `site-packages` folder
  layout instead of manipulating `$PYTHONPATH`, so your code behaves the
  same way under Bazel as it does in a normal Python environment.
* **Real virtualenvs.** Each build runs in a virtualenv, which means IDE
  support (autocomplete, jump-to-definition) works in PyCharm, VS Code, and
  others without extra configuration.
* **Hermetic.** The launcher uses Bash rather than Python, so there's
  no dependency on a system Python interpreter. Interpreters come from
  [python-build-standalone](/docs/bazel/python/python-interpreter).
* **Cross-platform.** Build Linux container images from a Mac, build across
  architectures, and target custom platforms. Wheels are selected for the
  target platform, not the host.
* **uv instead of pip.** `aspect_rules_py` reads `uv.lock` directly. One
  lockfile replaces per-platform `requirements.txt` files, and all downloads
  go through the Bazel downloader, so private mirrors work.

## Ecosystem

<Columns cols={2}>
  <Card title="Manage dependencies with uv" icon="lock" href="/docs/bazel/python/uv">
    One lockfile for all platforms. Fast, reproducible installs and cross-platform container builds.
  </Card>

  <Card title="Migrating from rules_python" icon="arrow-right-arrow-left" href="/docs/bazel/python/migrating">
    Already using rules\_python? Migration is mostly a drop-in replacement.
  </Card>
</Columns>

<Columns cols={1}>
  <Card title="Video: Python at Monorepo World" icon="video" href="https://www.youtube.com/watch?v=en3ep4rw0oA">
    Alex Eagle's talk, with a demo of rules\_py.
  </Card>
</Columns>

## Package management with PyPI

Declare direct dependencies in `pyproject.toml` and pin them with `uv lock` into a `uv.lock` file.
The `uv` module extension in `aspect_rules_py` reads `uv.lock` directly and exposes each package as `@pypi//<package>`:

```python theme={null}
# MODULE.bazel
bazel_dep(name = "aspect_rules_py", version = "1.12.1")

uv = use_extension("@aspect_rules_py//uv/unstable:extension.bzl", "uv")
uv.declare_hub(hub_name = "pypi")
uv.project(
    hub_name = "pypi",
    pyproject = "//:pyproject.toml",
    lock = "//:uv.lock",
)
use_repo(uv, "pypi")
```

There's no `requirements.txt`, `pip_compile`, or `pip.parse` step. See [Manage dependencies with uv](/docs/bazel/python/uv) for the full setup, including the `.bazelrc` venv flag.

<Tip>
  After changing dependencies, repin before building. In the starter template, <code>./tools/repin</code> runs <code>bazel run @uv -- lock</code> and updates <code>MODULE.bazel.lock</code>.
</Tip>

## Python programs

Use `py_library`, `py_binary`, and `py_test` for code organization, executables, and tests. Write the `BUILD` files by hand, or generate them with the [aspect-gazelle](https://github.com/aspect-build/aspect-gazelle) Python extension, which needs a `gazelle_python.yaml` manifest generated from your lockfile (see [Gazelle integration](https://github.com/aspect-build/rules_py/blob/main/docs/uv.md#gazelle-integration)).
Bazel runs these targets with a hermetic Python toolchain instead of relying on a system interpreter.

**API reference:**
[Python rules](/docs/bazel/python/aspect_rules_py/py_defs) |
[toolchains](/docs/bazel/python/aspect_rules_py/py_toolchains) |
[repositories](/docs/bazel/python/aspect_rules_py/py_repositories)

## Developer workflow

For day-to-day development, Bazel-generated virtualenv targets improve editor integration and local debugging while staying aligned with Bazel's dependency graph.

* <GatedLink access={gatedAccess(user)} href="/learning/bazel-102/virtualenvs">Editor features: virtualenvs</GatedLink>
* <GatedLink access={gatedAccess(user)} href="/learning/bazel-102/test-and-debug">Testing and debugging</GatedLink>
* <GatedLink access={gatedAccess(user)} href="/learning/bazel-102/watch-mode">Watch mode</GatedLink>

## Monorepo dependencies

In a live-at-HEAD monorepo, local libraries and services depend on each other directly through `deps`, without publishing intermediate package versions.
Keep one `@pypi` hub for the whole repository. When teams need different versions of the same package, register each dependency set as a `[dependency-group]` in `pyproject.toml` and select it per target or per build with the venv flag. See [Virtual dependencies](/docs/bazel/python/virtual_deps).

**Course:**
<GatedLink access={gatedAccess(user)} href="/learning/bazel-102/monorepo-deps">Monorepo dependencies</GatedLink>

## Code generation and tools

Python console scripts can be exposed as Bazel tools and invoked from build actions.
Use `py_console_script_binary` and `run_binary` to model code generation with explicit inputs and outputs.

**Course:**
<GatedLink access={gatedAccess(user)} href="/learning/bazel-102/console-scripts">Integrate Python console scripts as tools</GatedLink>

## Shipping artifacts

Bazel can package Python applications into OCI images and load them locally for quick verification.
For release pipelines, stamping can embed build metadata in otherwise deterministic outputs.

**Course:**
<GatedLink access={gatedAccess(user)} href="/learning/bazel-102/ship-artifacts">Shipping artifacts</GatedLink>

## Cross-builds

Cross-build scenarios require careful handling of host, exec, and target platforms, especially when dependencies include non-pure Python wheels or source builds.

**Course:**
<GatedLink access={gatedAccess(user)} href="/learning/bazel-102/crossbuilds">Cross-builds</GatedLink>

## Formatting and linting

The starter uses two commands:

1. Format tracked files:
   ```bash theme={null}
   aspect format
   ```
2. Run lint checks (and apply safe fixes when offered):
   ```bash theme={null}
   aspect lint //...
   ```

Configure tool behavior in `pyproject.toml` and keep linting in CI so style and correctness checks stay consistent across the team.

**API reference:**

* [ruff](/docs/bazel/python/aspect_rules_lint/lint_ruff) - Ruff linter integration. [Homepage](https://docs.astral.sh/ruff/).
* [ty](/docs/bazel/python/aspect_rules_lint/lint_ty) - Ty type-checking integration. [Homepage](https://docs.astral.sh/ty/).
* [flake8](/docs/bazel/python/aspect_rules_lint/lint_flake8) - Flake8 linter integration. [Homepage](https://flake8.pycqa.org/).
* [pylint](/docs/bazel/python/aspect_rules_lint/lint_pylint) - Pylint linter integration. [Homepage](https://pylint.pycqa.org/).

### Additional APIs

* [Unstable APIs](/docs/bazel/python/aspect_rules_py/py_unstable_defs): interfaces that may change between releases.

## Community

**[Join the Aspect Community Slack](https://slack.aspect.build)**, Aspect's free community support. Ask in `#help` for general support. Join the discussion and see what others are building with the [Aspect CLI](/docs/cli/overview) and [Aspect Extension Language (AXL)](/docs/cli/axl) in the `#cli` and `#axl` channels.

For Bazel and the Bazel rulesets, [Bazel Slack](https://slack.bazel.build) is the best place for support and discussion. Ask about Aspect's [rules\_js](/docs/bazel/javascript) in `#javascript` and [rules\_py](/docs/bazel/python) in `#python`.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.