Hatch

repository·master·Indexed 11 days ago

https://github.com/pypa/hatch

A modern, extensible Python project manager providing a unified workflow for building, managing environments, testing, and publishing Python projects. It includes Hatchling, a PEP 517 and PEP 660 compliant build backend for creating sdist and wheel artifacts.

Tokens
75.6K
Snippets
315
Records
427
Agent score
93%

What's inside Hatch

  1. Overview of Hatch features

    master

    Hatch is a modern, extensible Python project manager designed to handle the full lifecycle of a Python project. Its core capabilities include:

    • Build system: Provides reproducible builds using a plugin ecosystem.
    • Environments: Robust management of project environments, supporting custom scripts and uv integration.
    • Python management: Allows for manual Python installations or automatic management within environments.
    • Testing: Executes tests following industry best practices.
    • Static analysis: Integrated static analysis powered by Ruff with sane defaults.
    • Script runner: Executes Python scripts within specific environments (defined by dependencies and Python versions).
    • Publishing: Streamlined workflow for uploading packages to PyPI or other indices.
    • Versioning: Automated workflows for bumping project versions.
    • Project generation: Creates new projects from templates.
    • CLI: A high-performance command-line interface designed for speed.
  2. Configure workspace environments

    master

    Workspace environments allow you to manage multiple related packages within a single environment, which is ideal for monorepos or interdependent package structures. When you define workspace members, Hatch automatically installs them as editable packages within that environment.

    To define members, use the workspace.members option within an environment configuration in your pyproject.toml.

    [tool.hatch.envs.default]
    workspace.members = [
      "packages/core",
      "packages/utils",
      "packages/cli"
    ]
  3. Understand Wheel builder default file selection heuristics

    master

    If you do not define any file selection options, Hatch uses the project name to find the package to ship. It follows this heuristic order:

    1. <NAME>/__init__.py
    2. src/<NAME>/__init__.py
    3. <NAME>.py
    4. <NAMESPACE>/<NAME>/__init__.py

    If none of these patterns match, Hatch will raise an error.

  4. Use environment sources to redirect dependencies

    master

    The sources table allows you to redirect dependencies to alternative origins (like local paths, Git repos, or private indices) during installation without changing your project's published metadata. This is ideal for development workflows where you want to use a local checkout of a dependency instead of the version from PyPI.

    Sources match dependencies by name (using PEP 503 normalization) and apply to both project.dependencies and environment-specific dependencies.

    Note: Sources only affect installs performed by Hatch when managing an environment. They do not affect the metadata of wheels produced by hatch build.

    [project]
    dependencies = ["foo"]
    
    [tool.hatch.envs.default.sources]
    foo = "./packages/foo"
  5. How Python resolution works for virtual environments

    master

    Virtual environments require a parent Python installation. Hatch resolves this using these rules:

    1. Selection: The python option is checked, then the HATCH_PYTHON environment variable. If HATCH_PYTHON is set, resolution stops and that path is used.
    2. Resolvers: Based on the python-sources option, resolvers find an interpreter compatible with the project's defined Python support.
    3. Version Matching: If a version is specified, resolvers find a matching interpreter. If no version is specified, resolvers try to match the Python version Hatch is running on, or the highest compatible version.

    Note: Some external paths (like Homebrew-installed Python) are considered unstable and may be ignored during resolution to prevent errors if the interpreter changes or is removed.

  6. Use environment overrides for conditional configuration

    master

    The overrides table allows you to modify environment options based on specific conditions. Use dotted key syntax: [tool.hatch.envs.<ENV_NAME>.overrides]<SOURCE>.<CONDITION>.<OPTION> = <VALUE>.

    Supported Sources:

    • platform: Based on linux, windows, or macos.
    • env: Based on the presence or value of environment variables.
    • matrix: Based on matrix variable values.
    • name: Based on regular expression matching of the generated environment name.

    Override Application Order:

    1. platform
    2. env
    3. matrix
    4. name

    Overwriting vs. Supplementing:

    • To supplement (append to arrays or add to mappings), use the standard syntax.
    • To overwrite an entire option (e.g., replacing all platforms instead of adding one), prefix the name with set- (e.g., matrix.foo.set-platforms = ["macos"]).

    Conditional Modifiers (Inline Tables): You can use inline tables to apply overrides only if certain conditions are met:

    • if: An array of allowed values for a condition.
    • platform: An array of required platforms.
    • env: An array of required environment variables (e.g., env = ["FOO", "BAR=BAZ"]).
    [tool.hatch.envs.test.overrides]
    platform.windows.scripts = [
      'run=pytest -m "not io_uring"',
    ]
  7. Configure Pyrefly type checking in Hatch

    master

    Hatch uses Pyrefly for type checking via the hatch check types command. By default, Hatch auto-generates a pyrefly.toml file that detects source directories, sets search paths, uses the legacy preset, and ignores uninstalled platform-conditional dependencies.

    To use your own configuration instead of the auto-generated one, provide either:

    1. A pyrefly.toml file in the project root.
    2. A [tool.pyrefly] section in your pyproject.toml.
  8. Compare Hatchling to setuptools for build backends

    master

    Hatchling is the build backend for Hatch and offers several advantages over setuptools for standard Python projects:

    • Better Defaults: Hatchling uses your version control system (e.g., .gitignore) to determine file inclusion/exclusion for source distributions. For wheels, it uses specific heuristics based on the project name rather than attempting to include every directory that looks like a package.
    • Simplified Configuration: All build configuration is handled in a single file using Git-style glob patterns. Unlike setuptools, which may require a separate MANIFEST.in file and complex shell-style globs, Hatchling uses dedicated sections like [tool.hatch.build.targets.wheel].
    • Improved Editable Installs: Hatchling's default editable installation behavior supports proper static analysis by IDEs (like Visual Studio Code) without additional configuration.
    • Reproducibility: Hatchling builds reproducible wheels and source distributions by default.
    • Extensibility: Hatchling uses a plugin system with discrete, well-defined types, making it easier to extend than the low-level setuptools API.

    When to avoid Hatchling: If your project requires building C/C++ extension modules, continue using setuptools or a backend specialized in compiler interfacing.

  9. Use version matching and compatible release operators

    master

    Version Matching (==)

    By default, == performs strict equality. You can use prefix matching by appending .* to the version identifier.

    • ==1.2 matches exactly 1.2.0.
    • ==1.2.* matches >=1.2.0, <1.3.0.

    Compatible Release (~=)

    Matches any version expected to be compatible with the specified version. For a version V.N, ~=V.N is approximately equivalent to >= V.N, == V.*.

    • ~=1.2 matches >=1.2.0, <2.0.0.
    • ~=1.2.3 matches >=1.2.3, <1.3.0.

    Note: ~= cannot be used with a single segment version like ~=1.

    # Example of different matching styles
    dependencies = [
      "pkg==1.2.3",    # Strict
      "pkg==1.2.*",   # Prefix matching
      "pkg~=1.2.3",   # Compatible release
    ]
  10. Configure Hatch project selection modes

    master

    The mode key in config.toml determines how Hatch identifies the project to work on. There are three modes:

    1. local (Default): Hatch looks for a pyproject.toml file in the current working directory and any parent directories. The first one found defines the project root.
    2. project: Hatch works only on a specific project defined in the configuration. Projects can be defined in the [projects] table via a path string or an inline table with a location key. Alternatively, you can list base directories in [dirs].project, and Hatch will treat any matching subdirectory as a project root.
    3. aware: A hybrid mode that attempts local mode first and falls back to project mode if no local project is found.

    You can override the project selection for a single command using the -p/--project flag or the HATCH_PROJECT environment variable.

    # Example Project Mode configuration
    mode = "project"
    project = "proj1"
    
    [projects]
    proj1 = "/path/to/project1"
    proj2 = { location = "/path/to/project2" }
    
    [dirs]
    project = ["/path/to/monorepo1", "/path/to/monorepo2"]
  11. Select optional dependencies using features (extras)

    master

    You can group optional dependencies under [project.optional-dependencies] and select them using the [feature] syntax. Features must be placed immediately after the package name and before any version specifiers.

    Self-referential features: A feature group can extend another group within the same project by referencing the project name.

    Example pyproject.toml:

    [project]
    name = "awesome-project"
    
    [project.optional-dependencies]
    crypto = [
      "PyJWT",
      "cryptography",
    ]
    dev = [
      "awesome-project[crypto]",
      "black",
    ]

    To install the dev group, you would request awesome-project[dev].

    # Selecting multiple features
    foo[cli,crypto]==1.*