diff --git a/dev/search/search_index.json b/dev/search/search_index.json index 1a7e59cae..ee8e7f3df 100644 --- a/dev/search/search_index.json +++ b/dev/search/search_index.json @@ -1 +1 @@ -{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"],"fields":{"title":{"boost":1000.0},"text":{"boost":1.0},"tags":{"boost":1000000.0}}},"docs":[{"location":"","title":"Hatch","text":"CI/CD Docs Package Meta
Hatch is a modern, extensible Python project manager. See the Why Hatch? page for more information.
Build system
Reproducible builds by default with a rich ecosystem of plugins
Configure builds
Environments
Robust environment management with support for custom scripts and UV
Getting started
Python management
Choose between easy manual installations or automatic as part of environments
Try it
Testing
Test execution with known best practices
Run
Static analysis
Static analysis backed by Ruff with up-to-date, sane defaults
Learn
Script runner
Execute Python scripts with specific dependencies and Python versions
Execute
Publishing
Easily upload to PyPI or other indices
See how
Versioning
Streamlined workflow for bumping versions
Managing versions
Project generation
Create new projects from templates with known best practices
Project setup
Responsive CLI
Hatch is up to 3x faster than equivalent tools
CLI reference
Hatch is distributed under the terms of the MIT license.
"},{"location":"#navigation","title":"Navigation","text":"Documentation for specific MAJOR.MINOR
versions can be chosen by using the dropdown on the top of every page. The dev
version reflects changes that have not yet been released.
Also, desktop readers can use special keyboard shortcuts:
Keys ActionBuilds are configured using the tool.hatch.build
table. Every target is defined by a section within tool.hatch.build.targets
, for example:
[tool.hatch.build.targets.sdist]\nexclude = [\n \"/.github\",\n \"/docs\",\n]\n\n[tool.hatch.build.targets.wheel]\npackages = [\"src/foo\"]\n
[build.targets.sdist]\nexclude = [\n \"/.github\",\n \"/docs\",\n]\n\n[build.targets.wheel]\npackages = [\"src/foo\"]\n
"},{"location":"build/#building","title":"Building","text":"Invoking the build
command without any arguments will build the sdist and wheel targets:
$ hatch build\n[sdist]\ndist/hatch_demo-1rc0.tar.gz\n\n[wheel]\ndist/hatch_demo-1rc0-py3-none-any.whl\n
To only build specific targets, use the -t
/--target
option:
$ hatch build -t wheel\n[wheel]\ndist/hatch_demo-1rc0-py3-none-any.whl\n
If the target supports multiple versions, you can specify the exact versions to build by appending a colon followed by the desired versions separated by commas:
$ hatch -v build -t wheel:standard\n[wheel]\nBuilding `wheel` version `standard`\ndist/hatch_demo-1rc0-py3-none-any.whl\n
"},{"location":"build/#packaging-ecosystem","title":"Packaging ecosystem","text":"Hatch complies with modern Python packaging specs and therefore your projects can be used by other tools with Hatch serving as just the build backend.
So you could use tox as an alternative to Hatch's environment management, or cibuildwheel to distribute packages for every platform, and they both will transparently use Hatch without any extra modification.
"},{"location":"environment/","title":"Environments","text":"Environments are designed to allow for isolated workspaces for testing, building documentation, or anything else projects need.
Unless an environment is chosen explicitly, Hatch will use the default
environment.
Tip
For a more comprehensive walk-through, see the Basic usage tutorial.
"},{"location":"environment/#creation","title":"Creation","text":"You can create environments by using the env create
command. Let's enter the directory of the project we created in the setup phase:
$ hatch env create\nCreating environment: default\nInstalling project in development mode\nSyncing dependencies\n
Tip
You never need to manually create environments as spawning a shell or running commands within one will automatically trigger creation.
"},{"location":"environment/#entering-environments","title":"Entering environments","text":"You can spawn a shell within an environment by using the shell
command.
$ hatch shell\n(hatch-demo) $\n
Now confirm the project has been installed:
(hatch-demo) $ pip show hatch-demo\nName: hatch-demo\nVersion: 0.0.1\n...\n
Finally, see where your environment's Python is located:
(hatch-demo) $ python -c \"import sys;print(sys.executable)\"\n...\n
You can type exit
to leave the environment.
The run
command allows you to execute commands in an environment as if you had already entered it. For example, running the following command will output the same path as before:
hatch run python -c \"import sys;print(sys.executable)\"\n
Tip
Be sure to check out how to define scripts for your project.
"},{"location":"environment/#dependencies","title":"Dependencies","text":"Hatch ensures that environments are always compatible with the currently defined project dependencies (if installed and in dev mode) and environment dependencies.
To add cowsay
as a dependency, open pyproject.toml
and add it to the dependencies
array:
[project]\n...\ndependencies = [\n \"cowsay\"\n]\n
This dependency will be installed the next time you spawn a shell or run a command. For example:
$ hatch run cowsay -t \"Hello, world!\"\nSyncing dependencies\n _____________\n| Hello, world! |\n =============\n \\\n \\\n ^__^\n (oo)\\_______\n (__)\\ )\\/\\\n ||----w |\n || ||\n
Note
The Syncing dependencies
status will display temporarily when Hatch updates environments in response to any dependency changes that you make.
You can select which environment to enter or run commands in by using the -e
/--env
root option or by setting the HATCH_ENV
environment variable.
The run
command allows for more explicit selection by prepending <ENV_NAME>:
to commands. For example, if you had the following configuration:
[tool.hatch.envs.docs]\ndependencies = [\n \"mkdocs\"\n]\n[tool.hatch.envs.docs.scripts]\nbuild = \"mkdocs build --clean --strict\"\nserve = \"mkdocs serve --dev-addr localhost:8000\"\n
[envs.docs]\ndependencies = [\n \"mkdocs\"\n]\n[envs.docs.scripts]\nbuild = \"mkdocs build --clean --strict\"\nserve = \"mkdocs serve --dev-addr localhost:8000\"\n
you could then serve your documentation by running:
hatch run docs:serve\n
Tip
If you've already entered an environment, commands will target it by default.
"},{"location":"environment/#matrix","title":"Matrix","text":"Every environment can define its own set of matrices:
pyproject.toml hatch.toml[tool.hatch.envs.test]\ndependencies = [\n \"pytest\"\n]\n\n[[tool.hatch.envs.test.matrix]]\npython = [\"3.10\", \"3.11\"]\nversion = [\"42\", \"3.14\"]\n\n[[tool.hatch.envs.test.matrix]]\npython = [\"3.11\", \"3.12\"]\nversion = [\"9000\"]\nfeature = [\"foo\", \"bar\"]\n
[envs.test]\ndependencies = [\n \"pytest\"\n]\n\n[[envs.test.matrix]]\npython = [\"3.10\", \"3.11\"]\nversion = [\"42\", \"3.14\"]\n\n[[envs.test.matrix]]\npython = [\"3.11\", \"3.12\"]\nversion = [\"9000\"]\nfeature = [\"foo\", \"bar\"]\n
Using the env show
command would then display:
$ hatch env show --ascii\n Standalone\n+---------+---------+\n| Name | Type |\n+=========+=========+\n| default | virtual |\n+---------+---------+\n Matrices\n+------+---------+----------------------+--------------+\n| Name | Type | Envs | Dependencies |\n+======+=========+======================+==============+\n| test | virtual | test.py3.10-42 | pytest |\n| | | test.py3.10-3.14 | |\n| | | test.py3.11-42 | |\n| | | test.py3.11-3.14 | |\n| | | test.py3.11-9000-foo | |\n| | | test.py3.11-9000-bar | |\n| | | test.py3.12-9000-foo | |\n| | | test.py3.12-9000-bar | |\n+------+---------+----------------------+--------------+\n
"},{"location":"environment/#removal","title":"Removal","text":"You can remove a single environment or environment matrix by using the env remove
command or all of a project's environments by using the env prune
command.
- name: Install Hatch\n uses: pypa/hatch@install\n
Refer to the official action for more information.
"},{"location":"install/#installers","title":"Installers","text":"macOSWindows GUI installerCommand line installer.pkg
file: hatch-universal.pkgTo verify that the shell can find and run the hatch
command in your PATH
, use the following command.
$ hatch --version\n1.12.0\n
Download the file using the curl
command. The -o
option specifies the file name that the downloaded package is written to. In this example, the file is written to hatch-universal.pkg
in the current directory.
curl -Lo hatch-universal.pkg https://github.com/pypa/hatch/releases/latest/download/hatch-universal.pkg\n
Run the standard macOS installer
program, specifying the downloaded .pkg
file as the source. Use the -pkg
parameter to specify the name of the package to install, and the -target /
parameter for the drive in which to install the package. The files are installed to /usr/local/hatch
, and an entry is created at /etc/paths.d/hatch
that instructs shells to add the /usr/local/hatch
directory to. You must include sudo on the command to grant write permissions to those folders.
sudo installer -pkg ./hatch-universal.pkg -target /\n
Restart your terminal.
To verify that the shell can find and run the hatch
command in your PATH
, use the following command.
$ hatch --version\n1.12.0\n
.msi
files:To verify that the shell can find and run the hatch
command in your PATH
, use the following command.
$ hatch --version\n1.12.0\n
Download and run the installer using the standard Windows msiexec
program, specifying one of the .msi
files as the source. Use the /passive
and /i
parameters to request an unattended, normal installation.
msiexec /passive /i https://github.com/pypa/hatch/releases/latest/download/hatch-x64.msi\n
msiexec /passive /i https://github.com/pypa/hatch/releases/latest/download/hatch-x86.msi\n
Restart your terminal.
To verify that the shell can find and run the hatch
command in your PATH
, use the following command.
$ hatch --version\n1.12.0\n
After downloading the archive corresponding to your platform and architecture, extract the binary to a directory that is on your PATH and rename to hatch
.
Hatch is available on PyPI and can be installed with pip.
pip install hatch\n
Warning
This method modifies the Python environment in which you choose to install. Consider instead using pipx to avoid dependency conflicts.
"},{"location":"install/#pipx","title":"pipx","text":"pipx allows for the global installation of Python applications in isolated environments.
pipx install hatch\n
"},{"location":"install/#homebrew","title":"Homebrew","text":"See the formula for more details.
brew install hatch\n
"},{"location":"install/#conda","title":"Conda","text":"See the feedstock for more details.
conda install -c conda-forge hatch\n
or with mamba:
mamba install hatch\n
Warning
This method modifies the Conda environment in which you choose to install. Consider instead using pipx or condax to avoid dependency conflicts.
"},{"location":"install/#macports","title":"MacPorts","text":"See the port for more details.
sudo port install hatch\n
"},{"location":"install/#fedora","title":"Fedora","text":"The minimum supported version is 37, currently in development as Rawhide.
sudo dnf install hatch\n
"},{"location":"install/#void-linux","title":"Void Linux","text":"xbps-install hatch\n
"},{"location":"install/#build-system-availability","title":"Build system availability","text":"Hatchling is Hatch's build backend which you will never need to install manually. See its changelog for version information.
"},{"location":"intro/","title":"Introduction","text":""},{"location":"intro/#setup","title":"Setup","text":"Projects can be set up for use by Hatch using the new
command.
Let's say you want to create a project named Hatch Demo
. You would run:
hatch new \"Hatch Demo\"\n
This would create the following structure in your current working directory:
hatch-demo\n\u251c\u2500\u2500 src\n\u2502 \u2514\u2500\u2500 hatch_demo\n\u2502 \u251c\u2500\u2500 __about__.py\n\u2502 \u2514\u2500\u2500 __init__.py\n\u251c\u2500\u2500 tests\n\u2502 \u2514\u2500\u2500 __init__.py\n\u251c\u2500\u2500 LICENSE.txt\n\u251c\u2500\u2500 README.md\n\u2514\u2500\u2500 pyproject.toml\n
Tip
There are many ways to customize project generation.
"},{"location":"intro/#existing-project","title":"Existing project","text":"To initialize an existing project, enter the directory containing the project and run the following:
hatch new --init\n
If your project has a setup.py
file the command will automatically migrate setuptools
configuration for you. Otherwise, this will interactively guide you through the setup process.
Next you'll want to define more of your project's metadata located in the pyproject.toml
file. You can specify things like its license, the supported versions of Python, and URLs referring to various parts of your project, like documentation.
The last step of the setup process is to define any dependencies that you'd like your project to begin with.
"},{"location":"intro/#configuration","title":"Configuration","text":"All project-specific configuration recognized by Hatch can be defined in either the pyproject.toml
file, or a file named hatch.toml
where options are not contained within the tool.hatch
table:
[tool.hatch]\noption = \"...\"\n\n[tool.hatch.table1]\noption = \"...\"\n\n[tool.hatch.table2]\noption = \"...\"\n
option = \"...\"\n\n[table1]\noption = \"...\"\n\n[table2]\noption = \"...\"\n
Top level keys in the latter file take precedence when defined in both.
Tip
If you want to make your file more compact, you can use dotted keys, turning the above example into:
pyproject.toml hatch.toml[tool.hatch]\noption = \"...\"\ntable1.option = \"...\"\ntable2.option = \"...\"\n
option = \"...\"\ntable1.option = \"...\"\ntable2.option = \"...\"\n
"},{"location":"next-steps/","title":"Next steps","text":""},{"location":"next-steps/#learn-more","title":"Learn more","text":"At this point you should have a basic understanding of how to use Hatch.
Now you may want to check out advanced configuration for environments or builds, set up your preferred shell, or read more about Hatch's CLI.
After that, check out the Hatch Showcase project to see examples of what is possible.
Finally, if you see a need, feel free to write a plugin for extended functionality.
"},{"location":"next-steps/#community","title":"Community","text":"For any projects using Hatch, you may add its official badge somewhere prominent like the README.
MarkdownreStructuredText[![Hatch project](https://img.shields.io/badge/%F0%9F%A5%9A-Hatch-4051b5.svg)](https://github.com/pypa/hatch)\n
.. image:: https://img.shields.io/badge/%F0%9F%A5%9A-Hatch-4051b5.svg\n :alt: Hatch project\n :target: https://github.com/pypa/hatch\n
"},{"location":"publish/","title":"Publishing","text":"After your project is built, you can distribute it using the publish
command.
The -p
/--publisher
option controls which publisher to use, with the default being index.
By default, the dist
directory located at the root of your project will be used:
$ hatch publish\ndist/hatch_demo-1rc0-py3-none-any.whl ... success\ndist/hatch_demo-1rc0.tar.gz ... success\n\n[hatch-demo]\nhttps://pypi.org/project/hatch-demo/1rc0/\n
You can instead pass specific paths as arguments:
hatch publish /path/to/artifacts foo-1.tar.gz\n
Only files ending with .whl
or .tar.gz
will be published.
Please refer to the publisher plugin reference for configuration options.
There's a How-To on authentication and on options to select the target repository.
The publish
command is implemented as a built-in plugin, if you're planning your own plugin, read about the publisher plugin API.
When the version is not statically set, configuration is defined in the tool.hatch.version
table. The source
option determines the source to use for retrieving and updating the version. The regex source is used by default.
The regex
source requires an option path
that represents a relative path to a file containing the project's version:
[tool.hatch.version]\npath = \"src/hatch_demo/__about__.py\"\n
[version]\npath = \"src/hatch_demo/__about__.py\"\n
The default pattern looks for a variable named __version__
or VERSION
that is set to a string containing the version, optionally prefixed with the lowercase letter v
.
If this doesn't reflect how you store the version, you can define a different regular expression using the pattern
option:
[tool.hatch.version]\npath = \"pkg/__init__.py\"\npattern = \"BUILD = 'b(?P<version>[^']+)'\"\n
[version]\npath = \"pkg/__init__.py\"\npattern = \"BUILD = 'b(?P<version>[^']+)'\"\n
The pattern must have a named group called version
that represents the version.
Invoking the version
command without any arguments will display the current version of the project:
$ hatch version\n0.0.1\n
"},{"location":"version/#updating","title":"Updating","text":"You can update the version like so:
$ hatch version \"0.1.0\"\nOld: 0.0.1\nNew: 0.1.0\n
The scheme
option determines the scheme to use for parsing both the existing and new versions. The standard scheme is used by default, which is based on PEP 440.
Rather than setting the version explicitly, you can select the name of a segment used to increment the version:
$ hatch version minor\nOld: 0.1.0\nNew: 0.2.0\n
You can chain multiple segment updates with a comma. For example, if you wanted to release a preview of your project's first major version, you could do:
$ hatch version major,rc\nOld: 0.2.0\nNew: 1.0.0rc0\n
When you want to release the final version, you would do:
$ hatch version release\nOld: 1.0.0rc0\nNew: 1.0.0\n
"},{"location":"version/#supported-segments","title":"Supported segments","text":"Here are the supported segments and how they would influence an existing version of 1.0.0
:
release
1.0.0
major
2.0.0
minor
1.1.0
micro
patch
fix
1.0.1
a
alpha
1.0.0a0
b
beta
1.0.0b0
c
rc
pre
preview
1.0.0rc0
r
rev
post
1.0.0.post0
dev
1.0.0.dev0
"},{"location":"why/","title":"Why Hatch?","text":"The high level value proposition of Hatch is that if one adopts all functionality then many other tools become unnecessary since there is support for everything one might require. Further, if one chooses to use only specific features then there are still benefits compared to alternatives.
"},{"location":"why/#build-backend","title":"Build backend","text":"Hatchling, the build backend sister project, has many benefits compared to setuptools. Here we only compare setuptools as that is the one most people are familiar with.
.gitignore
file.MANIFEST.in
file. The custom syntax and directives must be learned and it is difficult knowing which options in the main files like setup.py
influence the behavior and under what conditions. For Hatchling, everything gets configured in a single file under dedicated sections for specific targets like [tool.hatch.build.targets.wheel]
.Why not?:
If building extension modules is required then it is recommended that you continue using setuptools, or even other backends that specialize in interfacing with compilers.
"},{"location":"why/#environment-management","title":"Environment management","text":"Here we compare to both tox
and nox
. At a high level, there are a few common advantages:
Philosophy: In the alternatives, environments are for the most part treated as executable units where a dependency set is associated with an action. If you are familiar with container ecosystems, this would be like defining a CMD
at the end of a Dockerfile but without the ability to change the action at runtime. This involves significant wasted disk space usually because one often requires slight modifications to the actions and therefore will define entirely different environments inherited from a base config just to perform different logic. Additionally, this can be confusing to users not just configuration-wise but also for execution of the different environments.
In Hatch, environments are treated as isolated areas where you can execute arbitrary commands at runtime. For example, you can define a single test environment with named scripts that runs unit vs non-unit tests, each command being potentially very long but named however you wish so you get to control the interface. Since environments are treated as places where work is performed, you can also spawn a shell into any which will execute a subprocess that automatically drops into your shell of choice. Your shell will be configured appropriately like python
on PATH being updated and the prompt being changed to reflect the chosen environment.
Configuration:
tox
only supports INI configuration and if one desires putting that in the standard pyproject.toml
file then it must be a multi-line string containing the INI config which would preclude syntax highlighting. Hatch allows for TOML-based config just like most other tools in the Python ecosystem.nox
config is defined in Python which often leads to increased verbosity and makes it challenging to onboard folks compared to a standardized format with known behaviors.tox
allows for extending most aspects of its functionality however the API is so low-level and attached to internals that creating plugins may be challenging. For example, here is a tox
plugin that was migrated to an equivalent Hatch environment collector plugin.nox
is configured with Python so for the local project you can do whatever you want, however there is no concept of third-party plugins per se. To achieve that, you must usually use a package that wraps nox
and use that package's imports instead (example).Why not?:
If you are using nox
and you wish to migrate, and for some reason you notify sessions, then migration wouldn't be a straight translation but rather you might have to redesign that conditional step.
Here we compare Python management to that of pyenv.
pyenv
does not support Windows so you must use an entirely different project that tries to emulate the functionality.pyenv
operates by adding shims which then act as wrappers around the actual underlying binaries. This has many unfortunate side effects:pyenv
on start, leading to inconsistencies when running processes that do not spawn a shell.pyenv
influencing the python
on PATH.Why not?:
Currently, Hatch does not allow for the installation of specific patch release versions but rather only uses minor release granularity that tracks the latest patch release. If specific patch releases are important to you then it is best to use an alternative installation mechanism.
"},{"location":"blog/","title":"Blog","text":""},{"location":"blog/2024/05/02/hatch-v1100/","title":"Hatch v1.10.0","text":"Hatch v1.10.0 brings a test command, support for UV, and a Python script runner.
"},{"location":"blog/2024/05/02/hatch-v1100/#test-command","title":"Test command","text":"The new test
command allows you to easily run tests for your project on multiple versions of Python. The default behavior follows best practices, using pytest with select plugins for test execution and coverage.py for code coverage measurement.
The command is designed to be both simple to use while also satisfying the needs of most projects. For example, the following shows Hatch running tests for Jinja in all environments in the default matrix:
Here is us testing Rich, with a bit of configuration:
See the tutorial for a detailed walk-through and the config reference for options.
"},{"location":"blog/2024/05/02/hatch-v1100/#uv","title":"UV","text":"The package installer UV, brought to you by the same folks behind Ruff, is now supported. In any environment, you can set the installer
option to uv
to use UV in place of virtualenv & pip for virtual environment creation and dependency management, respectively. This often results in a significant performance benefit.
For example, if you wanted to enable this functionality for the default environment, you could set the following:
pyproject.toml hatch.toml[tool.hatch.envs.default]\ninstaller = \"uv\"\n
[envs.default]\ninstaller = \"uv\"\n
Semi-internal environments like those used for testing and static analysis have this enabled by default.
See the how-to guide for more information about switching the installer.
"},{"location":"blog/2024/05/02/hatch-v1100/#python-script-runner","title":"Python script runner","text":"The run
command now supports executing Python scripts with inline metadata as standardized by PEP 723.
As an example, consider the following script:
script.py# /// script\n# requires-python = \">=3.11\"\n# dependencies = [\n# \"httpx\",\n# \"rich\",\n# ]\n# ///\n\nimport httpx\nfrom rich.pretty import pprint\n\nresp = httpx.get(\"https://peps.python.org/api/peps.json\")\ndata = resp.json()\npprint([(k, v[\"title\"]) for k, v in data.items()][:10])\n
If you run the script for the first time as follows:
hatch run script.py\n
Hatch will create a dedicated environment for that script using a version of Python greater than or equal to 3.11 with dependencies httpx
and rich
.
See the how-to guide for more information.
"},{"location":"blog/2024/05/02/hatch-v1100/#static-analysis","title":"Static analysis","text":"The environment used for static analysis is now completely configurable such that you can fully alter the underlying behavior of the fmt
command (see the how-to).
Additionally, Ruff has been updated to version 1.4.0 and the rules selected by default have been updated accordingly. Check out their blog post about how the new hand-written parser has made it twice as fast!
"},{"location":"blog/2024/05/02/hatch-v1100/#community-highlights","title":"Community highlights","text":""},{"location":"blog/2024/05/02/hatch-v1100/#visual-studio-code","title":"Visual Studio Code","text":"Visual Studio Code announced support for Hatch environments in their latest release. This means that you can now easily discover and select Hatch environments for your projects directly from the editor.
See the how-to guide for detailed instructions.
"},{"location":"blog/2024/05/02/hatch-v1100/#cmake-build-plugin","title":"CMake build plugin","text":"A new release of the extension module builder scikit-build-core has introduced a build plugin for Hatchling. This means that you can use Hatchling as your build backend while also shipping extension modules built with CMake.
To get started, add the dependency to your build requirements:
pyproject.toml[build-system]\nrequires = [\"hatchling>=1.24.2\", \"scikit-build-core~=0.9.3\"]\nbuild-backend = \"hatchling.build\"\n
Then explicitly enable the experimental
option (acknowledging that the plugin will move to a dedicated package in the future):
[tool.hatch.build.targets.wheel.hooks.scikit-build]\nexperimental = true\n
[build.targets.wheel.hooks.scikit-build]\nexperimental = true\n
At this point, you can create your CMakeLists.txt
file as usual and start building your extension modules with CMake! Check out the dedicated example project for a complete demonstration.
The efforts toward documentation improvements have increased substantially and the priorities have shifted. From now on expect to see far more tutorials and how-to guides rather than just reference material.
"},{"location":"blog/2024/05/02/hatch-v1100/#future","title":"Future","text":"Upcoming features include:
If you or your organization finds value in what Hatch provides, consider a sponsorship to assist with maintenance and more rapid development!
"},{"location":"blog/2022/10/08/hatch-v160/","title":"Hatch v1.6.0","text":"Hatch v1.6.0 brings improvements to build environments, better handling of dynamic metadata, and support for tools like Visual Studio Code.
"},{"location":"blog/2022/10/08/hatch-v160/#build-environments","title":"Build environments","text":"Originally, the environment interface method for providing builder sub-environments was intended to be used in conjunction with some cleanup logic in order to provide a fresh setup every time. However, this is unnecessary in practice because build dependencies rarely change.
Without caching, repeat build environment use is slow which affects the following scenarios:
build
commanddep hash
, if any fields are set dynamicallyNow a new environment interface method build_environment_exists
is used by Hatch to determine whether or not it has already been created, for implementations that have a caching mechanism.
The virtual
environment type now uses this method to cache build environments.
Dynamically defined metadata is now supported everywhere, thanks to the new caching of virtual
build environments.
A project metadata
command is introduced that displays the fully resolved metadata. The output format is JSON unless a field is specified as an argument.
For example, if you checkout a project that is built by Hatch, like FastAPI, and run:
hatch project metadata readme\n
only the readme
text will be displayed. If the content is in Markdown, then Rich will render it directly in your terminal:
The virtual
environment type now uses a flat layout for storage in the configured virtual
environment directory if the directory resides somewhere within the project root or if it is set to a .virtualenvs
directory within the user's home directory.
For example, if you define the following Hatch configuration:
config.toml[dirs.env]\nvirtual = \".hatch\"\n
and the following matrix:
pyproject.toml hatch.toml[[tool.hatch.envs.test.matrix]]\npython = [\"3.7\", \"3.8\", \"3.9\", \"3.10\", \"3.11\"]\n
[[envs.test.matrix]]\npython = [\"3.7\", \"3.8\", \"3.9\", \"3.10\", \"3.11\"]\n
then locating environments with the following command:
hatch env find test\n
will show that the general directory structure is:
.hatch\n\u251c\u2500\u2500 test.py3.7\n\u251c\u2500\u2500 test.py3.8\n\u251c\u2500\u2500 test.py3.9\n\u251c\u2500\u2500 test.py3.10\n\u2514\u2500\u2500 test.py3.11\n
This flat structure is required for detection of virtual environments by tools like Visual Studio Code and PyCharm.
Additionally, the virtual
environment type now supports a path
option to specify an explicit path that all inherited environments will share, such as the common .venv
.
The script used to migrate existing projects from setuptools
has been improved to handle more edge cases that were encountered in the wild and now no longer modifies the formatting of existing pyproject.toml
configuration.
Hatch now depends on Hatchling v1.11.0, which was also just released.
"},{"location":"blog/2022/10/08/hatch-v160/#environment-version-source","title":"Environment version source","text":"A new env
version source is available that allows for the project version to be defined by an environment variable.
The standard
version scheme now supports a validate-bump
option that when set to false
will forego the check when updating the version that the desired version is higher than the current version.
This use case comes from Project Jupyter:
A common pattern we use in Jupyter is to bump to a .dev0
minor version bump after making a release. If we have a bug fix that needs to go out in the interim, we'd rather not be forced to create a branch every time.
Hatch v1.8.0 brings Python distribution management, static analysis and formatting backed by Ruff, and binaries for every platform.
"},{"location":"blog/2023/12/11/hatch-v180/#installation-made-easy","title":"Installation made easy","text":"One thing that has been a perpetual problem for Hatch and other Python applications is that Python itself is a dependency. You, and more importantly your users, need to in some way get Python before your software can even be used. The recommended way to go about that is platform-dependent and even differs based on your target audience. I viewed this as a central UX problem for Hatch and so severe that I took a bit of a hiatus to solve it.
Luckily, I have to my satisfaction solved this problem in the form of PyApp. It is a runtime installer for Python projects written in Rust. Apps are distributed as standalone executables as users have come to expect and bootstrapping occurs upon the first invocation. Here is an example of what you would see the first time you run a binary from this release:
Now that we have binaries, creating installers for different platforms becomes trivial. Starting with this release not only are binaries available for every platform but also we have installers for Windows and macOS. The installer for macOS is signed using a certificate from the same account used to sign the official distributions from https://www.python.org, so users will not get any security pop-ups. Shout out to @ewdurbin for their extreme generosity in setting up multiple certificates in their free time!
These installers and binaries are now the recommended way to install and update Hatch. These binaries have built-in management so you can update to the latest version by running hatch self update
.
Windows signing
In future we will sign the installers for Windows but I did not have time to look into how that works. macOS signing took way longer than I anticipated
"},{"location":"blog/2023/12/11/hatch-v180/#python-management","title":"Python management","text":"For a long time I and other users have desired that Hatch gain the ability to manage Python distributions. In my mind this was always blocked on a better installation experience because there was sort of a chicken-or-egg problem where you want a Python manager but you first need Python. No longer is that the case!
The new python
command group allows for easy installation of various distributions to arbitrary locations which are then added to your PATH by default. Hatch supports CPython and PyPy distributions:
The virtual
environment type is now far more intelligent when resolving the parent distribution to use and guarantees that, when no specific version is requested, the resolved distribution will always be compatible with the project.
Additionally, when a requested version cannot be found on PATH it will automatically be downloaded and managed internally.
"},{"location":"blog/2023/12/11/hatch-v180/#static-analysis","title":"Static analysis","text":"There is a new fmt
command, backed entirely by Ruff, that checks and fixes your code for formatting and linting issues.
Starting with this release, Hatch maintains default settings that are guaranteed to be up-to-date and represent best practices for programming in modern Python. The idea is to provide defaults that are so broadly applicable that the majority of users will maintain little if any of their own overrides.
The default behavior is internal management of settings to provide an OOTB experience that works. It is recommended however that you persist the default config file in version control so that other tools like IDEs can utilize your full configuration.
Since Ruff is now provided as a built-in feature, new project templates no longer have such configuration and are much less verbose.
"},{"location":"blog/2023/12/11/hatch-v180/#build-improvements","title":"Build improvements","text":"Building projects that do not use Hatchling as a backend is now supported and such builds are managed with the standard build tool.
The bridge between Hatch and the Hatchling CLI has been removed. Previously, the builder would send serialized messages to Hatch that would contain the desired content and style for each line of output. This was done in an effort to allow builder and build hook plugins to output pretty messages without actually requiring a dependency like Rich. A problem that arises with this is that builders that invoke subprocesses will not display ANSI codes as one might expect and will lose out on the interactive experience of such invocations, like the built-in binary builder plugin calling cargo build
. So now everything is simpler at the expense of no colored output without manual logic, or adding a dependency if you're a third-party plugin.
Spawning a shell or running commands within environments always first checks that your project's dependencies are satisfied and if not synchronizes the environment with what is defined. Previously, this had the potential to be quite slow for projects that have many dependencies.
Now the set of dependency definitions is hashed and no check is performed if the hash is the same as before, significantly speeding up environment usage in most cases.
"},{"location":"blog/2023/12/11/hatch-v180/#hatchling","title":"Hatchling","text":"Hatch now depends on Hatchling v1.19.0, which was also just released.
"},{"location":"blog/2023/12/11/hatch-v180/#better-defaults","title":"Better defaults","text":"Hatchling is all about providing the best possible defaults, even at the expense of backward compatibility. In this release, there are two breaking changes that provide a much better user experience and were in fact requested by users.
force-include
option and the force_include_editable
wheel build data setting now raise errors if source paths do not exist.wheel
build target now raises an error when no file inclusion options have been defined and none of its heuristics to determine what to ship are satisfied.A new binary
build target is now stable that allows for the building of standalone binaries for projects. This is what Hatch itself uses for its binaries.
A new page has been introduced that discusses the value proposition of Hatch and Hatchling in comparison to alternatives. Currently, it only addresses a few features but in future this page will become more comprehensive.
"},{"location":"blog/2023/12/11/hatch-v180/#future","title":"Future","text":"Upcoming features include a test
command, commands to manage dependencies, and workspaces functionality similar to Cargo that will make managing monorepos far easier.
Next year there will be two large efforts that you should expect to see:
A significant amount of my free time (and some at work) will be devoted to introducing lock file functionality in Hatch and trying to get whatever that happens to be standardized.
I met with @brettcannon about his thoughts post-PEP 665 and about mousebender. I also met with the prefix.dev team about rip and was fortunate enough to be shown a demo before its official announcement.
At the moment, the two options I see are to either go all in and contribute to mousebender or rely on the Prefix folks and use rip. The latter has the benefit of potentially supporting Conda as a side effect with the downside of being quite new with the spec firmly out of our control. The former has the benefit of being able to easily gain institutional support from the Python packaging team and each of our employers with the downside being a significant amount of work needing to be done.
When @henryiii is able to get some free time away from teaching I plan to work with him once again and push very hard for the Python build ecosystem to adopt the extensionlib approach.
I am of the opinion that the Python community has not fully completed the expressed outcome of PEP 517 in that build backends are still (for the most part) reliant on setuptools for building non-Python code bases.
Basically, there are components that interact with compilers to produce extension modules and components that pack files into an archive which we call a build backend. These are two distinct pieces of functionality and my view is that there should be an API that allows backends to consume extension module builders to find out where things got created and where they should be shipped inside archives.
In this hypothetical future any build backend would be able to trigger the building of extension modules based on user configuration.
If you or your organization finds value in what Hatch provides, consider a sponsorship to assist with maintenance and more rapid development!
"},{"location":"blog/2023/12/18/hatch-v190/","title":"Hatch v1.9.0","text":"Hatch v1.9.0 brings improvements to static analysis and important bug fixes.
"},{"location":"blog/2023/12/18/hatch-v190/#static-analysis","title":"Static analysis","text":"The default version of Ruff has been increased to v0.1.8. This release brings formatting capabilities to docstrings and Hatch enables this by default with line length set to 80. This length was chosen as the default because it plays nicely with the rendering of the most popular themes for Python documentation, such as Material for MkDocs and Furo.
Additionally, it is now possible for projects to pin to specific versions of Ruff for upgrading at a later time:
pyproject.toml hatch.toml[tool.hatch.envs.hatch-static-analysis]\ndependencies = [\"ruff==X.Y.Z\"]\n
[envs.hatch-static-analysis]\ndependencies = [\"ruff==X.Y.Z\"]\n
"},{"location":"blog/2023/12/18/hatch-v190/#notable-fixes","title":"Notable fixes","text":"The amount of displayed output is controlled solely by the -v
/--verbose
(environment variable HATCH_VERBOSE
) and -q
/--quiet
(environment variable HATCH_QUIET
) root options.
The levels are documented here.
"},{"location":"cli/about/#project-awareness","title":"Project awareness","text":"No matter the mode, Hatch will always change to the project's root directory for entering or running commands in environments.
"},{"location":"cli/about/#tab-completion","title":"Tab completion","text":"Completion is achieved by saving a script and then executing it as a part of your shell's startup sequence.
Afterward, you'll need to start a new shell in order for the changes to take effect.
BashZ shellfishSave the script somewhere:
_HATCH_COMPLETE=bash_source hatch > ~/.hatch-complete.bash\n
Source the file in ~/.bashrc
(or ~/.bash_profile
if on macOS):
. ~/.hatch-complete.bash\n
Save the script somewhere:
_HATCH_COMPLETE=zsh_source hatch > ~/.hatch-complete.zsh\n
Source the file in ~/.zshrc
:
. ~/.hatch-complete.zsh\n
Save the script in ~/.config/fish/completions
:
_HATCH_COMPLETE=fish_source hatch > ~/.config/fish/completions/hatch.fish\n
"},{"location":"cli/reference/","title":"hatch","text":"Usage:
hatch [OPTIONS] COMMAND [ARGS]...\n
Options:
Name Type Description Default--env
, -e
text The name of the environment to use [env var: HATCH_ENV
] default
--project
, -p
text The name of the project to work on [env var: HATCH_PROJECT
] None --verbose
, -v
integer range (0
and above) Increase verbosity (can be used additively) [env var: HATCH_VERBOSE
] 0
--quiet
, -q
integer range (0
and above) Decrease verbosity (can be used additively) [env var: HATCH_QUIET
] 0
--color
/ --no-color
boolean Whether or not to display colored output (default is auto-detection) [env vars: FORCE_COLOR
/NO_COLOR
] None --interactive
/ --no-interactive
boolean Whether or not to allow features like prompts and progress bars (default is auto-detection) [env var: HATCH_INTERACTIVE
] None --data-dir
text The path to a custom directory used to persist data [env var: HATCH_DATA_DIR
] None --cache-dir
text The path to a custom directory used to cache data [env var: HATCH_CACHE_DIR
] None --config
text The path to a custom config file to use [env var: HATCH_CONFIG
] None --version
boolean Show the version and exit. False
--help
boolean Show this message and exit. False
"},{"location":"cli/reference/#hatch-build","title":"hatch build","text":"Build a project.
Usage:
hatch build [OPTIONS] [LOCATION]\n
Options:
Name Type Description Default--target
, -t
text The target to build, overriding project defaults. This may be selected multiple times e.g. -t sdist -t wheel
None --hooks-only
boolean Whether or not to only execute build hooks [env var: HATCH_BUILD_HOOKS_ONLY
] False
--no-hooks
boolean Whether or not to disable build hooks [env var: HATCH_BUILD_NO_HOOKS
] False
--ext
boolean Whether or not to only execute build hooks for distributing binary Python packages, such as compiling extensions. Equivalent to --hooks-only -t wheel
False
--clean
, -c
boolean Whether or not existing artifacts should first be removed [env var: HATCH_BUILD_CLEAN
] False
--clean-hooks-after
boolean Whether or not build hook artifacts should be removed after each build [env var: HATCH_BUILD_CLEAN_HOOKS_AFTER
] False
--help
boolean Show this message and exit. False
"},{"location":"cli/reference/#hatch-clean","title":"hatch clean","text":"Remove build artifacts.
Usage:
hatch clean [OPTIONS] [LOCATION]\n
Options:
Name Type Description Default--target
, -t
text The target with which to remove artifacts, overriding project defaults. This may be selected multiple times e.g. -t sdist -t wheel
None --hooks-only
boolean Whether or not to only remove artifacts from build hooks [env var: HATCH_BUILD_HOOKS_ONLY
] False
--no-hooks
boolean Whether or not to ignore artifacts from build hooks [env var: HATCH_BUILD_NO_HOOKS
] False
--ext
boolean Whether or not to only remove artifacts from build hooks for distributing binary Python packages, such as compiled extensions. Equivalent to --hooks-only -t wheel
False
--help
boolean Show this message and exit. False
"},{"location":"cli/reference/#hatch-config","title":"hatch config","text":"Manage the config file
Usage:
hatch config [OPTIONS] COMMAND [ARGS]...\n
Options:
Name Type Description Default--help
boolean Show this message and exit. False
"},{"location":"cli/reference/#hatch-config-explore","title":"hatch config explore","text":"Open the config location in your file manager.
Usage:
hatch config explore [OPTIONS]\n
Options:
Name Type Description Default--help
boolean Show this message and exit. False
"},{"location":"cli/reference/#hatch-config-find","title":"hatch config find","text":"Show the location of the config file.
Usage:
hatch config find [OPTIONS]\n
Options:
Name Type Description Default--help
boolean Show this message and exit. False
"},{"location":"cli/reference/#hatch-config-restore","title":"hatch config restore","text":"Restore the config file to default settings.
Usage:
hatch config restore [OPTIONS]\n
Options:
Name Type Description Default--help
boolean Show this message and exit. False
"},{"location":"cli/reference/#hatch-config-set","title":"hatch config set","text":"Assign values to config file entries. If the value is omitted, you will be prompted, with the input hidden if it is sensitive.
Usage:
hatch config set [OPTIONS] KEY [VALUE]\n
Options:
Name Type Description Default--help
boolean Show this message and exit. False
"},{"location":"cli/reference/#hatch-config-show","title":"hatch config show","text":"Show the contents of the config file.
Usage:
hatch config show [OPTIONS]\n
Options:
Name Type Description Default--all
, -a
boolean Do not scrub secret fields False
--help
boolean Show this message and exit. False
"},{"location":"cli/reference/#hatch-config-update","title":"hatch config update","text":"Update the config file with any new fields.
Usage:
hatch config update [OPTIONS]\n
Options:
Name Type Description Default--help
boolean Show this message and exit. False
"},{"location":"cli/reference/#hatch-dep","title":"hatch dep","text":"Manage environment dependencies
Usage:
hatch dep [OPTIONS] COMMAND [ARGS]...\n
Options:
Name Type Description Default--help
boolean Show this message and exit. False
"},{"location":"cli/reference/#hatch-dep-hash","title":"hatch dep hash","text":"Output a hash of the currently defined dependencies.
Usage:
hatch dep hash [OPTIONS]\n
Options:
Name Type Description Default--project-only
, -p
boolean Whether or not to exclude environment dependencies False
--env-only
, -e
boolean Whether or not to exclude project dependencies False
--help
boolean Show this message and exit. False
"},{"location":"cli/reference/#hatch-dep-show","title":"hatch dep show","text":"Display dependencies in various formats
Usage:
hatch dep show [OPTIONS] COMMAND [ARGS]...\n
Options:
Name Type Description Default--help
boolean Show this message and exit. False
"},{"location":"cli/reference/#hatch-dep-show-requirements","title":"hatch dep show requirements","text":"Enumerate dependencies as a list of requirements.
Usage:
hatch dep show requirements [OPTIONS]\n
Options:
Name Type Description Default--project-only
, -p
boolean Whether or not to exclude environment dependencies False
--env-only
, -e
boolean Whether or not to exclude project dependencies False
--feature
, -f
text Whether or not to only show the dependencies of the specified features None --all
boolean Whether or not to include the dependencies of all features False
--help
boolean Show this message and exit. False
"},{"location":"cli/reference/#hatch-dep-show-table","title":"hatch dep show table","text":"Enumerate dependencies in a tabular format.
Usage:
hatch dep show table [OPTIONS]\n
Options:
Name Type Description Default--project-only
, -p
boolean Whether or not to exclude environment dependencies False
--env-only
, -e
boolean Whether or not to exclude project dependencies False
--lines
, -l
boolean Whether or not to show lines between table rows False
--ascii
boolean Whether or not to only use ASCII characters False
--help
boolean Show this message and exit. False
"},{"location":"cli/reference/#hatch-env","title":"hatch env","text":"Manage project environments
Usage:
hatch env [OPTIONS] COMMAND [ARGS]...\n
Options:
Name Type Description Default--help
boolean Show this message and exit. False
"},{"location":"cli/reference/#hatch-env-create","title":"hatch env create","text":"Create environments.
Usage:
hatch env create [OPTIONS] [ENV_NAME]\n
Options:
Name Type Description Default--help
boolean Show this message and exit. False
"},{"location":"cli/reference/#hatch-env-find","title":"hatch env find","text":"Locate environments.
Usage:
hatch env find [OPTIONS] [ENV_NAME]\n
Options:
Name Type Description Default--help
boolean Show this message and exit. False
"},{"location":"cli/reference/#hatch-env-prune","title":"hatch env prune","text":"Remove all environments.
Usage:
hatch env prune [OPTIONS]\n
Options:
Name Type Description Default--help
boolean Show this message and exit. False
"},{"location":"cli/reference/#hatch-env-remove","title":"hatch env remove","text":"Remove environments.
Usage:
hatch env remove [OPTIONS] [ENV_NAME]\n
Options:
Name Type Description Default--help
boolean Show this message and exit. False
"},{"location":"cli/reference/#hatch-env-run","title":"hatch env run","text":"Run commands within project environments.
The -e
/--env
option overrides the equivalent root option and the HATCH_ENV
environment variable.
The -i
/--include
and -x
/--exclude
options may be used to include or exclude certain variables, optionally followed by specific comma-separated values, and may be selected multiple times. For example, if you have the following configuration:
[[tool.hatch.envs.test.matrix]]\npython = [\"3.9\", \"3.10\"]\nversion = [\"42\", \"3.14\", \"9000\"]\n
[[envs.test.matrix]]\npython = [\"3.9\", \"3.10\"]\nversion = [\"42\", \"3.14\", \"9000\"]\n
then running:
hatch env run -i py=3.10 -x version=9000 test:pytest\n
would execute pytest
in the environments test.py3.10-42
and test.py3.10-3.14
. Note that py
may be used as an alias for python
.
Note
The inclusion option is treated as an intersection while the exclusion option is treated as a union i.e. an environment must match all of the included variables to be selected while matching any of the excluded variables will prevent selection.
Usage:
hatch env run [OPTIONS] ARGS...\n
Options:
Name Type Description Default--env
, -e
text The environments to target None --include
, -i
text The matrix variables to include None --exclude
, -x
text The matrix variables to exclude None --filter
, -f
text The JSON data used to select environments None --force-continue
boolean Run every command and if there were any errors exit with the first code False
--ignore-compat
boolean Ignore incompatibility when selecting specific environments False
--help
boolean Show this message and exit. False
"},{"location":"cli/reference/#hatch-env-show","title":"hatch env show","text":"Show the available environments.
Usage:
hatch env show [OPTIONS] [ENVS]...\n
Options:
Name Type Description Default--ascii
boolean Whether or not to only use ASCII characters False
--json
boolean Whether or not to output in JSON format False
--internal
, -i
boolean Show internal environments False
--help
boolean Show this message and exit. False
"},{"location":"cli/reference/#hatch-fmt","title":"hatch fmt","text":"Format and lint source code.
Usage:
hatch fmt [OPTIONS] [ARGS]...\n
Options:
Name Type Description Default--check
boolean Only check for errors rather than fixing them False
--linter
, -l
boolean Only run the linter False
--formatter
, -f
boolean Only run the formatter False
--sync
boolean Sync the default config file with the current version of Hatch False
--help
boolean Show this message and exit. False
"},{"location":"cli/reference/#hatch-new","title":"hatch new","text":"Create or initialize a project.
Usage:
hatch new [OPTIONS] [NAME] [LOCATION]\n
Options:
Name Type Description Default--interactive
, -i
boolean Interactively choose details about the project False
--cli
boolean Give the project a command line interface False
--init
boolean Initialize an existing project False
--help
boolean Show this message and exit. False
"},{"location":"cli/reference/#hatch-project","title":"hatch project","text":"View project information
Usage:
hatch project [OPTIONS] COMMAND [ARGS]...\n
Options:
Name Type Description Default--help
boolean Show this message and exit. False
"},{"location":"cli/reference/#hatch-project-metadata","title":"hatch project metadata","text":"Display project metadata.
If you want to view the raw readme file without rendering, you can use a JSON parser like jq:
hatch project metadata | jq -r .readme\n
Usage:
hatch project metadata [OPTIONS] [FIELD]\n
Options:
Name Type Description Default--help
boolean Show this message and exit. False
"},{"location":"cli/reference/#hatch-publish","title":"hatch publish","text":"Publish build artifacts.
Usage:
hatch publish [OPTIONS] [ARTIFACTS]...\n
Options:
Name Type Description Default--repo
, -r
text The repository with which to publish artifacts [env var: HATCH_INDEX_REPO
] None --user
, -u
text The user with which to authenticate [env var: HATCH_INDEX_USER
] None --auth
, -a
text The credentials to use for authentication [env var: HATCH_INDEX_AUTH
] None --ca-cert
text The path to a CA bundle [env var: HATCH_INDEX_CA_CERT
] None --client-cert
text The path to a client certificate, optionally containing the private key [env var: HATCH_INDEX_CLIENT_CERT
] None --client-key
text The path to the client certificate's private key [env var: HATCH_INDEX_CLIENT_KEY
] None --no-prompt
, -n
boolean Disable prompts, such as for missing required fields False
--initialize-auth
boolean Save first-time authentication information even if nothing was published False
--publisher
, -p
text The publisher plugin to use (default is index
) [env var: HATCH_PUBLISHER
] index
--option
, -o
text Options to pass to the publisher plugin. This may be selected multiple times e.g. -o foo=bar -o baz=23
[env var: HATCH_PUBLISHER_OPTIONS
] None --yes
, -y
boolean Confirm without prompting when the plugin is disabled False
--help
boolean Show this message and exit. False
"},{"location":"cli/reference/#hatch-python","title":"hatch python","text":"Manage Python installations
Usage:
hatch python [OPTIONS] COMMAND [ARGS]...\n
Options:
Name Type Description Default--help
boolean Show this message and exit. False
"},{"location":"cli/reference/#hatch-python-find","title":"hatch python find","text":"Locate Python binaries.
Usage:
hatch python find [OPTIONS] NAME\n
Options:
Name Type Description Default-p
, --parent
boolean Show the parent directory of the Python binary False
--dir
, -d
text The directory in which distributions reside None --help
boolean Show this message and exit. False
"},{"location":"cli/reference/#hatch-python-install","title":"hatch python install","text":"Install Python distributions.
You may select all
to install all compatible distributions:
hatch python install all\n
You can set custom sources for distributions by setting the HATCH_PYTHON_SOURCE_<NAME>
environment variable where <NAME>
is the uppercased version of the distribution name with periods replaced by underscores e.g. HATCH_PYTHON_SOURCE_PYPY3_10
.
Usage:
hatch python install [OPTIONS] NAMES...\n
Options:
Name Type Description Default--private
boolean Do not add distributions to the user PATH False
--update
, -u
boolean Update existing installations False
--dir
, -d
text The directory in which to install distributions, overriding configuration None --help
boolean Show this message and exit. False
"},{"location":"cli/reference/#hatch-python-remove","title":"hatch python remove","text":"Remove Python distributions.
You may select all
to remove all installed distributions:
hatch python remove all\n
Usage:
hatch python remove [OPTIONS] NAMES...\n
Options:
Name Type Description Default--dir
, -d
text The directory in which distributions reside None --help
boolean Show this message and exit. False
"},{"location":"cli/reference/#hatch-python-show","title":"hatch python show","text":"Show the available Python distributions.
Usage:
hatch python show [OPTIONS]\n
Options:
Name Type Description Default--ascii
boolean Whether or not to only use ASCII characters False
--dir
, -d
text The directory in which distributions reside None --help
boolean Show this message and exit. False
"},{"location":"cli/reference/#hatch-python-update","title":"hatch python update","text":"Update Python distributions.
You may select all
to update all installed distributions:
hatch python update all\n
Usage:
hatch python update [OPTIONS] NAMES...\n
Options:
Name Type Description Default--dir
, -d
text The directory in which distributions reside None --help
boolean Show this message and exit. False
"},{"location":"cli/reference/#hatch-run","title":"hatch run","text":"Run commands within project environments. This is a convenience wrapper around the env run
command.
If the first argument contains a colon, then the preceding component will be interpreted as the name of the environment to target, overriding the -e
/--env
root option and the HATCH_ENV
environment variable.
If the environment provides matrices, then you may also provide leading arguments starting with a +
or -
to select or exclude certain variables, optionally followed by specific comma-separated values. For example, if you have the following configuration:
[[tool.hatch.envs.test.matrix]]\npython = [\"3.9\", \"3.10\"]\nversion = [\"42\", \"3.14\", \"9000\"]\n
[[envs.test.matrix]]\npython = [\"3.9\", \"3.10\"]\nversion = [\"42\", \"3.14\", \"9000\"]\n
then running:
hatch run +py=3.10 -version=9000 test:pytest\n
would execute pytest
in the environments test.py3.10-42
and test.py3.10-3.14
. Note that py
may be used as an alias for python
.
Note
Inclusions are treated as an intersection while exclusions are treated as a union i.e. an environment must match all of the included variables to be selected while matching any of the excluded variables will prevent selection.
Usage:
hatch run [OPTIONS] [ENV:]ARGS...\n
Options:
Name Type Description Default--help
boolean Show this message and exit. False
"},{"location":"cli/reference/#hatch-self","title":"hatch self","text":"Manage Hatch
Usage:
hatch self [OPTIONS] COMMAND [ARGS]...\n
Options:
Name Type Description Default--help
boolean Show this message and exit. False
"},{"location":"cli/reference/#hatch-self-report","title":"hatch self report","text":"Generate a pre-populated GitHub issue.
Usage:
hatch self report [OPTIONS]\n
Options:
Name Type Description Default--no-open
, -n
boolean Show the URL instead of opening it False
--help
boolean Show this message and exit. False
"},{"location":"cli/reference/#hatch-self-restore","title":"hatch self restore","text":"Restore the installation
Usage:
hatch self restore [OPTIONS] [ARGS]...\n
Options:
Name Type Description Default--help
boolean Show this message and exit. False
"},{"location":"cli/reference/#hatch-self-update","title":"hatch self update","text":"Install the latest version
Usage:
hatch self update [OPTIONS] [ARGS]...\n
Options:
Name Type Description Default--help
boolean Show this message and exit. False
"},{"location":"cli/reference/#hatch-shell","title":"hatch shell","text":"Enter a shell within a project's environment.
Usage:
hatch shell [OPTIONS] [ENV_NAME]\n
Options:
Name Type Description Default--name
text N/A None --path
text N/A None --help
boolean Show this message and exit. False
"},{"location":"cli/reference/#hatch-status","title":"hatch status","text":"Show information about the current environment.
Usage:
hatch status [OPTIONS]\n
Options:
Name Type Description Default--help
boolean Show this message and exit. False
"},{"location":"cli/reference/#hatch-test","title":"hatch test","text":"Run tests using the hatch-test
environment matrix.
If no filtering options are selected, then tests will be run in the first compatible environment found in the matrix with priority given to those matching the current interpreter.
The -i
/--include
and -x
/--exclude
options may be used to include or exclude certain variables, optionally followed by specific comma-separated values, and may be selected multiple times. For example, if you have the following configuration:
[[tool.hatch.envs.hatch-test.matrix]]\npython = [\"3.9\", \"3.10\"]\nversion = [\"42\", \"3.14\", \"9000\"]\n
[[envs.hatch-test.matrix]]\npython = [\"3.9\", \"3.10\"]\nversion = [\"42\", \"3.14\", \"9000\"]\n
then running:
hatch test -i py=3.10 -x version=9000\n
would run tests in the environments hatch-test.py3.10-42
and hatch-test.py3.10-3.14
.
The -py
/--python
option is a shortcut for specifying the inclusion -i py=...
.
Note
The inclusion option is treated as an intersection while the exclusion option is treated as a union i.e. an environment must match all of the included variables to be selected while matching any of the excluded variables will prevent selection.
Usage:
hatch test [OPTIONS] [ARGS]...\n
Options:
Name Type Description Default--randomize
, -r
boolean Randomize the order of test execution False
--parallel
, -p
boolean Parallelize test execution False
--retries
integer Number of times to retry failed tests None --retry-delay
float Seconds to wait between retries None --cover
, -c
boolean Measure code coverage False
--cover-quiet
boolean Disable coverage reporting after tests, implicitly enabling --cover False
--all
, -a
boolean Test all environments in the matrix False
--python
, -py
text The Python versions to test, equivalent to: -i py=... None --include
, -i
text The matrix variables to include None --exclude
, -x
text The matrix variables to exclude None --show
, -s
boolean Show information about environments in the matrix False
--help
boolean Show this message and exit. False
"},{"location":"cli/reference/#hatch-version","title":"hatch version","text":"View or set a project's version.
Usage:
hatch version [OPTIONS] [DESIRED_VERSION]\n
Options:
Name Type Description Default--help
boolean Show this message and exit. False
"},{"location":"community/contributing/","title":"Contributing","text":"The usual process to make a contribution is to:
Clone the hatch
repository, cd
into it, and create a new branch for your contribution:
cd hatch\ngit checkout -b add-my-contribution\n
"},{"location":"community/contributing/#run-the-tests","title":"Run the tests","text":"Run the test suite while developing:
hatch run dev\n
Run the test suite with coverage report:
hatch run cov\n
Run the extended test suite with coverage:
hatch run full\n
"},{"location":"community/contributing/#lint","title":"Lint","text":"Run automated formatting:
hatch run lint:fmt\n
Run full linting and type checking:
hatch run lint:all\n
"},{"location":"community/contributing/#docs","title":"Docs","text":"Start the documentation in development:
hatch run docs:serve\n
Build and validate the documentation website:
hatch run docs:build-check\n
"},{"location":"community/highlights/","title":"Community highlights","text":""},{"location":"community/highlights/#integration","title":"Integration","text":"The following is not intended to be a complete enumeration. Be sure to view the development version of this page for an up-to-date listing.
"},{"location":"community/users/#projects","title":"Projects","text":"aiogram | Apache Airflow | argon2-cffi | attrs | Black | coffea | Colorama | Django Anymail | Django Debug Toolbar | Django NYT | Django OTP | Django OTP Agents | Django OTP Twilio | Django OTP YubiKey | Django Places | Django Wiki | FastAPI | filelock | Fluentd | github3.py | Gradio | HTTPX | iCalendar for Humans | LinkChecker | Litestar | Material for MkDocs | MicroPython | MkDocs | openSUSE | Nox | Packit | pipx | platformdirs | Pydantic | Pygments | PyHamcrest | PyMdown Extensions | Python JSON Schema | Rye | SALib | Spack | Starlette | structlog | tox | Twisted | urllib3 | Uvicorn | virtualenv | Voil\u00e0 | XGBoost | Ypy | yt-dlp
"},{"location":"community/users/#industry","title":"Industry","text":"Build targets are defined as sections within tool.hatch.build.targets
:
[tool.hatch.build.targets.<TARGET_NAME>]\n
[build.targets.<TARGET_NAME>]\n
Tip
Although not recommended, you may define global configuration in the tool.hatch.build
table. Keys may then be overridden by target config.
To be compatible with the broader Python packaging ecosystem, you must define the build system as follows:
pyproject.toml[build-system]\nrequires = [\"hatchling\"]\nbuild-backend = \"hatchling.build\"\n
The version of hatchling
defined here will be used to build all targets.
Hatchling is a standards-compliant1 build backend and is a dependency of Hatch itself.
"},{"location":"config/build/#file-selection","title":"File selection","text":""},{"location":"config/build/#vcs","title":"VCS","text":"By default, Hatch will respect the first .gitignore
or .hgignore
file found in your project's root directory or parent directories. Set ignore-vcs
to true
to disable this behavior:
[tool.hatch.build.targets.sdist]\nignore-vcs = true\n
[build.targets.sdist]\nignore-vcs = true\n
Note
For .hgignore
files only glob syntax is supported.
You can set the include
and exclude
options to select exactly which files will be shipped in each build, with exclude
taking precedence. Every entry represents a Git-style glob pattern.
For example, the following configuration:
pyproject.toml hatch.toml[tool.hatch.build.targets.sdist]\ninclude = [\n \"pkg/*.py\",\n \"/tests\",\n]\nexclude = [\n \"*.json\",\n \"pkg/_compat.py\",\n]\n
[build.targets.sdist]\ninclude = [\n \"pkg/*.py\",\n \"/tests\",\n]\nexclude = [\n \"*.json\",\n \"pkg/_compat.py\",\n]\n
will exclude every file with a .json
extension, and will include everything under a tests
directory located at the root and every file with a .py
extension that is directly under a pkg
directory located at the root except for _compat.py
.
If you want to include files that are ignored by your VCS, such as those that might be created by build hooks, you can use the artifacts
option. This option is semantically equivalent to include
.
Note that artifacts are not affected by the exclude
option. Artifacts can be excluded by using more explicit paths or by using the !
negation operator. When using the !
operator, the negated pattern(s) must come after the more generic ones.
[tool.hatch.build.targets.wheel]\nartifacts = [\n \"*.so\",\n \"*.dll\",\n \"!/foo/*.so\",\n]\n
[build.targets.wheel]\nartifacts = [\n \"*.so\",\n \"*.dll\",\n \"!/foo/*.so\",\n]\n
"},{"location":"config/build/#explicit-selection","title":"Explicit selection","text":""},{"location":"config/build/#generic","title":"Generic","text":"You can use the only-include
option to prevent directory traversal starting at the project root and only select specific relative paths to directories or files. Using this option ignores any defined include
patterns.
[tool.hatch.build.targets.sdist]\nonly-include = [\"pkg\", \"tests/unit\"]\n
[build.targets.sdist]\nonly-include = [\"pkg\", \"tests/unit\"]\n
"},{"location":"config/build/#packages","title":"Packages","text":"The packages
option is semantically equivalent to only-include
(which takes precedence) except that the shipped path will be collapsed to only include the final component.
So for example, if you want to ship a package foo
that is stored in a directory src
you would do:
[tool.hatch.build.targets.wheel]\npackages = [\"src/foo\"]\n
[build.targets.wheel]\npackages = [\"src/foo\"]\n
"},{"location":"config/build/#forced-inclusion","title":"Forced inclusion","text":"The force-include
option allows you to select specific files or directories from anywhere on the file system that should be included and map them to the desired relative distribution path.
For example, if there was a directory alongside the project root named artifacts
containing a file named lib.so
and a file named lib.h
in your home directory, you could ship both files in a pkg
directory with the following configuration:
[tool.hatch.build.targets.wheel.force-include]\n\"../artifacts\" = \"pkg\"\n\"~/lib.h\" = \"pkg/lib.h\"\n
[build.targets.wheel.force-include]\n\"../artifacts\" = \"pkg\"\n\"~/lib.h\" = \"pkg/lib.h\"\n
Note
/
(a forward slash).Warning
Files included using this option will overwrite any file path that was already included by other file selection options.
"},{"location":"config/build/#default-file-selection","title":"Default file selection","text":"If no file selection options are provided, then what gets included is determined by each build target.
"},{"location":"config/build/#excluding-files-outside-packages","title":"Excluding files outside packages","text":"If you want to exclude non-artifact files that do not reside within a Python package, set only-packages
to true
:
[tool.hatch.build.targets.wheel]\nonly-packages = true\n
[build.targets.wheel]\nonly-packages = true\n
"},{"location":"config/build/#rewriting-paths","title":"Rewriting paths","text":"You can rewrite relative paths to directories with the sources
option. For example, the following configuration:
[tool.hatch.build.targets.wheel.sources]\n\"src/foo\" = \"bar\"\n
[build.targets.wheel.sources]\n\"src/foo\" = \"bar\"\n
would distribute the file src/foo/file.ext
as bar/file.ext
.
If you want to remove path prefixes entirely, rather than setting each to an empty string, you can define sources
as an array:
[tool.hatch.build.targets.wheel]\nsources = [\"src\"]\n
[build.targets.wheel]\nsources = [\"src\"]\n
If you want to add a prefix to paths, you can use an empty string. For example, the following configuration:
pyproject.toml hatch.toml[tool.hatch.build.targets.wheel.sources]\n\"\" = \"foo\"\n
[build.targets.wheel.sources]\n\"\" = \"foo\"\n
would distribute the file bar/file.ext
as foo/bar/file.ext
.
The packages option itself relies on sources. Defining packages = [\"src/foo\"]
for the wheel
target is equivalent to the following:
[tool.hatch.build.targets.wheel]\nonly-include = [\"src/foo\"]\nsources = [\"src\"]\n
[build.targets.wheel]\nonly-include = [\"src/foo\"]\nsources = [\"src\"]\n
"},{"location":"config/build/#performance","title":"Performance","text":"All encountered directories are traversed by default. To skip non-artifact directories that are excluded, set skip-excluded-dirs
to true
:
[tool.hatch.build]\nskip-excluded-dirs = true\n
[build]\nskip-excluded-dirs = true\n
Warning
This may result in not shipping desired files. For example, if you want to include the file a/b/c.txt
but your VCS ignores a/b
, the file c.txt
will not be seen because its parent directory will not be entered. In such cases you can use the force-include
option.
By default, build targets will build in a reproducible manner provided that they support that behavior. To disable this, set reproducible
to false
:
[tool.hatch.build]\nreproducible = false\n
[build]\nreproducible = false\n
When enabled, the SOURCE_DATE_EPOCH environment variable will be used for all build timestamps. If not set, then Hatch will use an unchanging default value.
"},{"location":"config/build/#output-directory","title":"Output directory","text":"When the output directory is not provided to the build
command, the dist
directory will be used by default. You can change the default to a different directory using a relative or absolute path like so:
[tool.hatch.build]\ndirectory = \"<PATH>\"\n
[build]\ndirectory = \"<PATH>\"\n
"},{"location":"config/build/#dev-mode","title":"Dev mode","text":"By default for dev mode environment installations or editable installs, the wheel
target will determine which directories should be added to Python's search path based on the selected files.
If you want to override this detection or perhaps instruct other build targets as well, you can use the dev-mode-dirs
option:
[tool.hatch.build]\ndev-mode-dirs = [\".\"]\n
[build]\ndev-mode-dirs = [\".\"]\n
If you don't want to add entire directories to Python's search path, you can enable a more targeted mechanism with the mutually exclusive dev-mode-exact
option:
[tool.hatch.build]\ndev-mode-exact = true\n
[build]\ndev-mode-exact = true\n
Warning
The dev-mode-exact
mechanism is not supported by static analysis tools & IDEs, therefore functionality such as autocompletion is unlikely to work.
A build target can be provided by any builder plugin. There are three built-in build targets: wheel, sdist, and custom.
"},{"location":"config/build/#target-dependencies","title":"Dependencies","text":"You can specify additional dependencies that will be installed in each build environment, such as for third party builders:
pyproject.toml hatch.toml[tool.hatch.build.targets.your-target-name]\ndependencies = [\n \"your-builder-plugin\"\n]\n
[build.targets.your-target-name]\ndependencies = [\n \"your-builder-plugin\"\n]\n
You can also declare dependence on the project's runtime dependencies with the require-runtime-dependencies
option:
[tool.hatch.build.targets.your-target-name]\nrequire-runtime-dependencies = true\n
[build.targets.your-target-name]\nrequire-runtime-dependencies = true\n
Additionally, you may declare dependence on specific runtime features of the project with the require-runtime-features
option:
[tool.hatch.build.targets.your-target-name]\nrequire-runtime-features = [\n \"feature1\",\n \"feature2\",\n]\n
[build.targets.your-target-name]\nrequire-runtime-features = [\n \"feature1\",\n \"feature2\",\n]\n
"},{"location":"config/build/#versions","title":"Versions","text":"If a build target supports multiple build strategies or if there are major changes over time, you can specify exactly which versions you want to build using the versions
option:
[tool.hatch.build.targets.<TARGET_NAME>]\nversions = [\n \"v1\",\n \"beta-feature\",\n]\n
[build.targets.<TARGET_NAME>]\nversions = [\n \"v1\",\n \"beta-feature\",\n]\n
See the wheel target for a real world example.
"},{"location":"config/build/#build-hooks","title":"Build hooks","text":"A build hook defines code that will be executed at various stages of the build process and can be provided by any build hook plugin. There is one built-in build hook: custom.
Build hooks can be applied either globally:
pyproject.toml hatch.toml[tool.hatch.build.hooks.<HOOK_NAME>]\n
[build.hooks.<HOOK_NAME>]\n
or to specific build targets:
pyproject.toml hatch.toml[tool.hatch.build.targets.<TARGET_NAME>.hooks.<HOOK_NAME>]\n
[build.targets.<TARGET_NAME>.hooks.<HOOK_NAME>]\n
"},{"location":"config/build/#hook-dependencies","title":"Dependencies","text":"You can specify additional dependencies that will be installed in each build environment, such as for third party build hooks:
pyproject.toml hatch.toml[tool.hatch.build.hooks.your-hook-name]\ndependencies = [\n \"your-build-hook-plugin\"\n]\n
[build.hooks.your-hook-name]\ndependencies = [\n \"your-build-hook-plugin\"\n]\n
You can also declare dependence on the project's runtime dependencies with the require-runtime-dependencies
option:
[tool.hatch.build.hooks.your-hook-name]\nrequire-runtime-dependencies = true\n
[build.hooks.your-hook-name]\nrequire-runtime-dependencies = true\n
Additionally, you may declare dependence on specific runtime features of the project with the require-runtime-features
option:
[tool.hatch.build.hooks.your-hook-name]\nrequire-runtime-features = [\n \"feature1\",\n \"feature2\",\n]\n
[build.hooks.your-hook-name]\nrequire-runtime-features = [\n \"feature1\",\n \"feature2\",\n]\n
"},{"location":"config/build/#order-of-execution","title":"Order of execution","text":"For each build target, build hooks execute in the order in which they are defined, starting with global hooks.
As an example, for the following configuration:
pyproject.toml hatch.toml[tool.hatch.build.targets.foo.hooks.hook2]\n\n[tool.hatch.build.hooks.hook3]\n[tool.hatch.build.hooks.hook1]\n
[build.targets.foo.hooks.hook2]\n\n[build.hooks.hook3]\n[build.hooks.hook1]\n
When target foo
is built, build hook hook3
will be executed first, followed by hook1
, and then finally hook2
.
If you want to disable a build hook by default and control its use by environment variables, you can do so by setting the enable-by-default
option to false
:
[tool.hatch.build.hooks.<HOOK_NAME>]\nenable-by-default = false\n
[build.hooks.<HOOK_NAME>]\nenable-by-default = false\n
"},{"location":"config/build/#environment-variables","title":"Environment variables","text":"Variable Default Description HATCH_BUILD_CLEAN
false
Whether or not existing artifacts should first be removed HATCH_BUILD_CLEAN_HOOKS_AFTER
false
Whether or not build hook artifacts should be removed after each build HATCH_BUILD_HOOKS_ONLY
false
Whether or not to only execute build hooks HATCH_BUILD_NO_HOOKS
false
Whether or not to disable all build hooks; this takes precedence over other options HATCH_BUILD_HOOKS_ENABLE
false
Whether or not to enable all build hooks HATCH_BUILD_HOOK_ENABLE_<HOOK_NAME>
false
Whether or not to enable the build hook named <HOOK_NAME>
HATCH_BUILD_LOCATION
dist
The location with which to build the targets; only used by the build
command Support for PEP 517 and PEP 660 guarantees interoperability with other build tools.\u00a0\u21a9
You can populate configuration with the values of certain supported fields using the syntax of Python's format strings. Each field interprets the modifier part after the colon differently, if at all.
"},{"location":"config/context/#global-fields","title":"Global fields","text":"Any configuration that declares support for context formatting will always support these fields.
"},{"location":"config/context/#paths","title":"Paths","text":"Field Descriptionroot
The root project directory home
The user's home directory All paths support the following modifiers:
Modifier Descriptionuri
The normalized absolute URI path prefixed by file:
real
The path with all symbolic links resolved parent
The parent of the preceding path Tip
The parent
modifier can be chained and may be combined with either the uri
or real
modifier, with the latter placed at the end. For example:
[tool.hatch.envs.test]\ndependencies = [\n \"example-project @ {root:parent:parent:uri}/example-project\",\n]\n
[envs.test]\ndependencies = [\n \"example-project @ {root:parent:parent:uri}/example-project\",\n]\n
"},{"location":"config/context/#system-separators","title":"System separators","text":"Field Description /
\\
on Windows, /
otherwise ;
;
on Windows, :
otherwise"},{"location":"config/context/#environment-variables","title":"Environment variables","text":"The env
field and its modifier allow you to select the value of an environment variable. If the environment variable is not set, you must specify a default value as an additional modifier e.g. {env:PATH:DEFAULT}
.
You can insert fields within others. For example, if you wanted a script that displays the value of the environment variable FOO
, with a fallback to the environment variable BAR
, with its own fallback to the user's home directory, you could do the following:
[tool.hatch.envs.test.scripts]\ndisplay = \"echo {env:FOO:{env:BAR:{home}}}\"\n
[envs.test.scripts]\ndisplay = \"echo {env:FOO:{env:BAR:{home}}}\"\n
"},{"location":"config/dependency/","title":"Dependency configuration","text":"Project dependencies are defined with PEP 508 strings using optional PEP 440 version specifiers.
"},{"location":"config/dependency/#version-specifiers","title":"Version specifiers","text":"A version specifier consists of a series of version clauses, separated by commas. For example:
pyproject.toml[project]\n...\ndependencies = [\n \"cryptography\",\n \"click>=7, <9, != 8.0.0\",\n \"python-dateutil==2.8.*\",\n \"numpy~=1.21.4\",\n]\n
The comma is equivalent to a logical AND
operator: a candidate version must match all given version clauses in order to match the specifier as a whole.
~=
Compatible release ==
Version matching !=
Version exclusion <=
, >=
Inclusive ordered comparison <
, >
Exclusive ordered comparison ===
Arbitrary equality"},{"location":"config/dependency/#version-matching","title":"Version matching","text":"A version matching clause includes the version matching operator ==
and a version identifier.
By default, the version matching operator is based on a strict equality comparison: the specified version must be exactly the same as the requested version.
Clause Allowed versions==1
1.0.0
==1.2
1.2.0
Prefix matching may be requested instead of strict comparison, by appending a trailing .*
to the version identifier in the version matching clause. This means that additional trailing segments will be ignored when determining whether or not a version identifier matches the clause.
==1.*
>=1.0.0, <2.0.0
==1.2.*
>=1.2.0, <1.3.0
"},{"location":"config/dependency/#compatible-release","title":"Compatible release","text":"A compatible release clause consists of the compatible release operator ~=
and a version identifier. It matches any candidate version that is expected to be compatible with the specified version.
For a given release identifier V.N
, the compatible release clause is approximately equivalent to the following pair of comparison clauses:
>= V.N, == V.*\n
This operator cannot be used with a single segment version number such as ~=1
.
~=1.2
>=1.2.0, <2.0.0
~=1.2.3
>=1.2.3, <1.3.0
"},{"location":"config/dependency/#version-exclusion","title":"Version exclusion","text":"A version exclusion clause includes the version exclusion operator !=
and a version identifier.
The allowed version identifiers and comparison semantics are the same as those of the Version matching operator, except that the sense of any match is inverted.
"},{"location":"config/dependency/#ordered-comparison","title":"Ordered comparison","text":"Inclusive comparisons allow for the version identifier part of clauses whereas exclusive comparisons do not. For example, >=1.2
allows for version 1.2.0
while >1.2
does not.
Unlike the inclusive ordered comparisons <=
and >=
, the exclusive ordered comparisons <
and >
specifically exclude pre-releases, post-releases, and local versions of the specified version.
Though heavily discouraged, arbitrary equality comparisons allow for simple string matching without any version semantics, for example ===foobar
.
Environment markers allow for dependencies to only be installed when certain conditions are met.
For example, if you need to install the latest version of cryptography
that is available for a given Python major version you could define the following:
cryptography==3.3.2; python_version < \"3\"\ncryptography>=35.0; python_version > \"3\"\n
Alternatively, if you only need it on Python 3 when running on Windows you could do:
cryptography; python_version ~= \"3.0\" and platform_system == \"Windows\"\n
The available environment markers are as follows.
Marker Python equivalent Examplesos_name
import os
os.name
sys_platform
import sys
sys.platform
platform_machine
import platform
platform.machine()
platform_python_implementation
import platform
platform.python_implementation()
platform_release
import platform
platform.release()
platform_system
import platform
platform.system()
platform_version
import platform
platform.version()
python_version
import platform
'.'.join(platform.python_version_tuple()[:2])
python_full_version
import platform
platform.python_version()
implementation_name
import sys
sys.implementation.name
implementation_version
See here You can select groups of optional dependencies to install using the extras syntax. For example, if a dependency named foo
defined the following:
[project.optional-dependencies]\ncrypto = [\n \"PyJWT\",\n \"cryptography\",\n]\nfastjson = [\n \"orjson\",\n]\ncli = [\n \"prompt-toolkit\",\n \"colorama; platform_system == 'Windows'\",\n]\n
You can select the cli
and crypto
features like so:
foo[cli,crypto]==1.*\n
Note that the features come immediately after the package name, before any version specifiers.
"},{"location":"config/dependency/#self-referential","title":"Self-referential","text":"Feature groups can self-referentially extend others. For example, for a project called awesome-project
, the dev
feature group in the following pyproject.toml
file would select everything in the crypto
feature group, plus black
:
[project]\nname = \"awesome-project\"\n\n[project.optional-dependencies]\ncrypto = [\n \"PyJWT\",\n \"cryptography\",\n]\ndev = [\n \"awesome-project[crypto]\",\n \"black\",\n]\n
"},{"location":"config/dependency/#direct-references","title":"Direct references","text":"Instead of using normal version specifiers and fetching packages from an index like PyPI, you can define exact sources using direct references with an explicit URI.
Direct references are usually not meant to be used for dependencies of a published project but rather are used for defining dependencies for an environment.
All direct reference types are prefixed by the package name like:
<NAME> @ <REFERENCE>\n
"},{"location":"config/dependency/#version-control-systems","title":"Version control systems","text":"Various version control systems (VCS) are supported as long as the associated executable is available along your PATH
.
VCS direct references are defined using one of the following formats:
<NAME> @ <SCHEME>://<PATH>\n<NAME> @ <SCHEME>://<PATH>@<REVISION>\n
You may also append a #subdirectory=<PATH>
component for specifying the relative path to the Python package when it is not located at the root e.g. #subdirectory=lib/foo
.
For more information, refer to this.
"},{"location":"config/dependency/#supported-vcs","title":"Supported VCS","text":"GitMercurialSubversionBazaar Executable Schemes Revisions Examplegit
git+file
git+https
git+ssh
git+http
git+git
git
proj @ git+https://github.com/org/proj.git@v1
Executable Schemes Revisions Example hg
hg+file
hg+https
hg+ssh
hg+http
hg+static-http
proj @ hg+file:///path/to/proj@v1
Executable Schemes Revisions Example svn
svn+https
svn+ssh
svn+http
svn+svn
svn
proj @ svn+file:///path/to/proj
Executable Schemes Revisions Example bzr
bzr+https
bzr+ssh
bzr+sftp
bzr+lp
bzr+http
bzr+ftp
proj @ bzr+lp:proj@v1
"},{"location":"config/dependency/#local","title":"Local","text":"You can install local packages with the file
scheme in the following format:
<NAME> @ file://<HOST>/<PATH>\n
The <HOST>
is only used on Windows systems, where it can refer to a network share. If omitted it is assumed to be localhost
and the third slash must still be present.
The <PATH>
can refer to a source archive, a wheel, or a directory containing a Python package.
proj @ file:///path/to/pkg.tar.gz
proj @ file:///c:/path/to/pkg.tar.gz
Wheel proj @ file:///path/to/pkg.whl
proj @ file:///c:/path/to/pkg.whl
Directory proj @ file:///path/to/pkg
proj @ file:///c:/path/to/pkg
Tip
You may also specify paths relative to your project's root directory on all platforms by using context formatting:
<NAME> @ {root:uri}/pkg_inside_project\n<NAME> @ {root:parent:uri}/pkg_alongside_project\n
"},{"location":"config/dependency/#remote","title":"Remote","text":"You can install source archives and wheels by simply referring to a URL:
black @ https://github.com/psf/black/archive/refs/tags/21.10b0.zip\npytorch @ https://download.pytorch.org/whl/cu102/torch-1.10.0%2Bcu102-cp39-cp39-linux_x86_64.whl\n
An expected hash value may be specified by appending a #<HASH_ALGORITHM>=<EXPECTED_HASH>
component:
requests @ https://github.com/psf/requests/archive/refs/tags/v2.26.0.zip#sha256=eb729a757f01c10546ebd179ae2aec852dd0d7f8ada2328ccf4558909d859985\n
If the hash differs from the expected hash, the installation will fail.
It is recommended that only hashes which are unconditionally provided by the latest version of the standard library's hashlib module be used for hashes. As of Python 3.10, that list consists of:
md5
sha1
sha224
sha256
sha384
sha512
blake2b
blake2s
The following is an example that uses features and environment markers:
pkg[feature1,feature2] @ <REFERENCE> ; python_version < \"3.7\"\n
Note that the space before the semicolon is required.
"},{"location":"config/hatch/","title":"Hatch configuration","text":"Configuration for Hatch itself is stored in a config.toml
file located by default in one of the following platform-specific directories.
~/Library/Application Support/hatch
Windows %USERPROFILE%\\AppData\\Local\\hatch
Unix $XDG_CONFIG_HOME/hatch
(the XDG_CONFIG_HOME environment variable default is ~/.config
) You can select a custom path to the file using the --config
root option or by setting the HATCH_CONFIG
environment variable.
The file can be managed by the config
command group.
The mode
key controls how Hatch selects the project to work on.
mode = \"local\"\n
By default, Hatch will look for a pyproject.toml
file in the current working directory and any parent directories. The directory storing the first found file will be considered the project root.
mode = \"project\"\nproject = \"proj1\"\n\n[projects]\nproj1 = \"/path/to/project1\"\nproj2 = {\"location\": \"/path/to/project2\"}\n\n[dirs]\nproject = [\"/path/to/monorepo1\", \"/path/to/monorepo2\"]\n
In this mode, Hatch will only work on the selected project
. The project is located using multiple heuristics:
projects
table then it must be a string, or an inline table with a location
key, that is the full path to the project.dirs.project
, then that will be used as the project root.An error will occur if the project cannot be found.
You can use the config set
command to change the project you are working on:
$ hatch config set project proj2\nNew setting:\nproject = \"proj2\"\n
The project can be selected on a per-command basis with the -p
/--project
(environment variable HATCH_PROJECT
) root option.
mode = \"aware\"\n
This is essentially the local
mode with a fallback to the project
mode.
You can control the shell used to enter environments with the shell
key.
If defined as a string, it must be the name of one of the supported shells and be available along your PATH
.
shell = \"fish\"\n
If the executable name of your shell differs from the supported name, you can define the shell
as a table with name
and path
keys.
[shell]\nname = \"bash\"\npath = \"/bin/ash\"\n
You can change the default arguments used to spawn most shells with the args
key. The default for such supported shells is usually [\"-i\"]
.
[shell]\nname = \"bash\"\nargs = [\"--login\"]\n
"},{"location":"config/hatch/#supported","title":"Supported","text":"Shell Name Arguments macOS Windows Unix Almquist shell ash
[\"-i\"]
Bash bash
[\"-i\"]
Command Prompt cmd
C shell csh
[\"-i\"]
fish fish
[\"-i\"]
Nushell nu
[]
PowerShell pwsh
, powershell
tcsh tcsh
[\"-i\"]
xonsh xonsh
[\"-i\"]
Z shell zsh
[\"-i\"]
"},{"location":"config/hatch/#default","title":"Default","text":"Hatch will attempt to use the current shell based on parent processes. If the shell cannot be determined, then on Windows systems Hatch will use the SHELL
environment variable, if present, followed by the COMSPEC
environment variable, defaulting to cmd
. On all other platforms only the SHELL
environment variable will be used, defaulting to bash
.
[dirs]\ndata = \"...\"\n
This is the directory that is used to persist data. By default it is set to one of the following platform-specific directories.
Platform Path macOS~/Library/Application Support/hatch
Windows %USERPROFILE%\\AppData\\Local\\hatch
Unix $XDG_DATA_HOME/hatch
(the XDG_DATA_HOME environment variable default is ~/.local/share
) You can select a custom path to the directory using the --data-dir
root option or by setting the HATCH_DATA_DIR
environment variable.
[dirs]\ncache = \"...\"\n
This is the directory that is used to cache data. By default it is set to one of the following platform-specific directories.
Platform Path macOS~/Library/Caches/hatch
Windows %USERPROFILE%\\AppData\\Local\\hatch\\Cache
Unix $XDG_CACHE_HOME/hatch
(the XDG_CACHE_HOME environment variable default is ~/.cache
) You can select a custom path to the directory using the --cache-dir
root option or by setting the HATCH_CACHE_DIR
environment variable.
[dirs.env]\n<ENV_TYPE> = \"...\"\n
This determines where to store environments, with every key being the type of environment and the value being the desired storage location.
For example, if you wanted to store virtual environments in a .virtualenvs
directory within your home directory, you could specify the following:
[dirs.env]\nvirtual = \"~/.virtualenvs\"\n
Any environment variables are also expanded.
If the path is not absolute, then it will be relative to the project root. So if you wanted to use a directory named .hatch
in each project directory, you could do:
[dirs.env]\nvirtual = \".hatch\"\n
Any type of environment that is not explicitly defined will default to <DATA_DIR>/env/<ENV_TYPE>
.
[dirs]\npython = \"...\"\n
This determines where to install specific versions of Python.
The following values have special meanings:
Value Pathisolated
(default) <DATA_DIR>/pythons
"},{"location":"config/hatch/#terminal","title":"Terminal","text":"You can configure how all output is displayed using the terminal.styles
table. These settings are also applied to all plugins.
[terminal.styles]\nerror = \"...\"\n...\n
Cross-platform terminal capabilities are provided by Rich.
"},{"location":"config/hatch/#output-levels","title":"Output levels","text":"The levels of output are as follows. Note that the verbosity indicates the minimum level at which the output is displayed.
Level Default Verbosity Descriptiondebug
bold
1 - 3 Messages that are not useful for most user experiences error
bold red
-2 Messages indicating some unrecoverable error info
bold
0 Messages conveying basic information success
bold cyan
0 Messages indicating some positive outcome waiting
bold magenta
0 Messages shown before potentially time consuming operations warning
bold yellow
-1 Messages conveying important information See the documentation and color reference for guidance on valid values.
"},{"location":"config/hatch/#spinner","title":"Spinner","text":"You can select the sequence used for waiting animations with the spinner
option.
[terminal.styles]\nspinner = \"...\"\n
"},{"location":"config/metadata/","title":"Configuring project metadata","text":"Project metadata is stored in a pyproject.toml
file located at the root of a project's tree and is based entirely on the standard.
The name of the project.
pyproject.toml[project]\nname = \"your-app\"\n
"},{"location":"config/metadata/#version","title":"Version (required)","text":"pyproject.toml DynamicStatic See the dedicated versioning section.
[project]\n...\ndynamic = [\"version\"]\n\n[tool.hatch.version]\npath = \"...\"\n
[project]\n...\nversion = \"0.0.1\"\n
"},{"location":"config/metadata/#description","title":"Description","text":"A brief summary of the project.
pyproject.toml[project]\n...\ndescription = '...'\n
"},{"location":"config/metadata/#readme","title":"Readme","text":"The full description of the project.
pyproject.toml SimpleComplexThe file extension must be .md
, .rst
, or .txt
.
[project]\n...\nreadme = \"README.md\"\n
The content-type
field must be set to text/markdown
, text/x-rst
, or text/plain
.
A charset
field may also be set to instruct which encoding to use for reading the file, defaulting to utf-8
.
[project]\n...\nreadme = {\"file\" = \"README.md\", \"content-type\" = \"text/markdown\"}\n
The content-type
field must be set to text/markdown
or text/x-rst
.
[project]\n...\nreadme = {\"text\" = \"...\", \"content-type\" = \"text/markdown\"}\n
Note
If this is defined as a file, then it will always be included in source distributions for consistent builds.
"},{"location":"config/metadata/#python-support","title":"Python support","text":"The Python version requirements of the project.
pyproject.toml[project]\n...\nrequires-python = \">=3.8\"\n
"},{"location":"config/metadata/#license","title":"License","text":"For more information, see PEP 639.
pyproject.toml SPDX expressionFiles[project]\n...\nlicense = \"Apache-2.0 OR MIT\"\n
PathsGlobs [project]\n...\nlicense-files = { paths = [\"LICENSE.txt\"] }\n
[project]\n...\nlicense-files = { globs = [\"LICENSES/*\"] }\n
"},{"location":"config/metadata/#ownership","title":"Ownership","text":"The people or organizations considered to be the authors
or maintainers
of the project. The exact meaning is open to interpretation; it may list the original or primary authors, current maintainers, or owners of the package. If the values are the same, prefer only the use of the authors
field.
[project]\n...\nauthors = [\n { name = \"...\", email = \"...\" },\n]\nmaintainers = [\n { name = \"...\", email = \"...\" },\n]\n
"},{"location":"config/metadata/#keywords","title":"Keywords","text":"The keywords used to assist in the discovery of the project.
pyproject.toml[project]\n...\nkeywords = [\n \"...\",\n]\n
"},{"location":"config/metadata/#classifiers","title":"Classifiers","text":"The trove classifiers that apply to the project.
pyproject.toml[project]\n...\nclassifiers = [\n \"...\",\n]\n
"},{"location":"config/metadata/#urls","title":"URLs","text":"A table of URLs where the key is the URL label and the value is the URL itself.
pyproject.toml[project.urls]\nDocumentation = \"...\"\n\"Source code\" = \"...\"\n
"},{"location":"config/metadata/#dependencies","title":"Dependencies","text":"See the dependency specification page for more information.
Entries support context formatting and disallow direct references by default.
"},{"location":"config/metadata/#required","title":"Required","text":"pyproject.toml[project]\n...\ndependencies = [\n \"...\",\n]\n
"},{"location":"config/metadata/#optional","title":"Optional","text":"pyproject.toml [project.optional-dependencies]\noption1 = [\n \"...\",\n]\noption2 = [\n \"...\",\n]\n
"},{"location":"config/metadata/#entry-points","title":"Entry points","text":"Entry points are a mechanism for the project to advertise components it provides to be discovered and used by other code.
"},{"location":"config/metadata/#cli","title":"CLI","text":"After installing projects that define CLI scripts, each key will be available along your PATH
as a command that will call its associated object.
[project.scripts]\ncli-name = \"pkg.subpkg:func\"\n
Using the above example, running cli-name
would essentially execute the following Python script:
import sys\n\nfrom pkg.subpkg import func\n\nsys.exit(func())\n
"},{"location":"config/metadata/#gui","title":"GUI","text":"GUI scripts are exactly the same as CLI scripts except on Windows, where they are handled specially so that they can be started without a console.
pyproject.toml[project.gui-scripts]\ngui-name = \"pkg.subpkg:func\"\n
"},{"location":"config/metadata/#plugins","title":"Plugins","text":"pyproject.toml [project.entry-points.plugin-namespace]\nplugin-name1 = \"pkg.subpkg1\"\nplugin-name2 = \"pkg.subpkg2:func\"\n
"},{"location":"config/metadata/#dynamic","title":"Dynamic","text":"If any metadata fields are set dynamically, like the version
may be, then they must be listed here.
[project]\n...\ndynamic = [\n \"...\",\n]\n
"},{"location":"config/metadata/#metadata-options","title":"Metadata options","text":""},{"location":"config/metadata/#allowing-direct-references","title":"Allowing direct references","text":"By default, dependencies are not allowed to define direct references. To disable this check, set allow-direct-references
to true
:
[tool.hatch.metadata]\nallow-direct-references = true\n
[metadata]\nallow-direct-references = true\n
"},{"location":"config/metadata/#allowing-ambiguous-features","title":"Allowing ambiguous features","text":"By default, names of optional dependencies are normalized to prevent ambiguity. To disable this normalization, set allow-ambiguous-features
to true
:
[tool.hatch.metadata]\nallow-ambiguous-features = true\n
[metadata]\nallow-ambiguous-features = true\n
Deprecated
This option temporarily exists to provide better interoperability with tools that do not yet support PEP 685 and will be removed in the first minor release after Jan 1, 2024.
"},{"location":"config/project-templates/","title":"Project templates","text":"You can control how new projects are created by the new command using Hatch's config file.
"},{"location":"config/project-templates/#author","title":"Author","text":"config.toml[template]\nname = \"...\"\nemail = \"...\"\n
"},{"location":"config/project-templates/#licenses","title":"Licenses","text":"config.toml [template.licenses]\nheaders = true\ndefault = [\n \"MIT\",\n]\n
The list of licenses should be composed of SPDX identifiers. If multiple licenses are specified, then they will be placed in a LICENSES directory.
"},{"location":"config/project-templates/#options","title":"Options","text":""},{"location":"config/project-templates/#tests","title":"Tests","text":"This adds a tests
directory with environments for testing and linting.
[template.plugins.default]\ntests = true\n
"},{"location":"config/project-templates/#ci","title":"CI","text":"This adds a GitHub Actions workflow that runs tests on all platforms using modern versions of Python.
config.toml[template.plugins.default]\nci = false\n
"},{"location":"config/project-templates/#src-layout","title":"src
layout","text":"See this blog post.
config.toml[template.plugins.default]\nsrc-layout = true\n
"},{"location":"config/project-templates/#feature-flags","title":"Feature flags","text":""},{"location":"config/project-templates/#command-line-interface","title":"Command line interface","text":"The --cli
flag adds a CLI backed by Click that can also be invoked with python -m <PKG_NAME>
.
All environments support the following extra context formatting fields:
Field Descriptionenv_name
The name of the environment env_type
The type of environment matrix
Its modifier selects the value of that matrix variable. If the environment is not part of a matrix or was not generated with the variable, you must specify a default value as an additional modifier e.g. {matrix:version:v1.0.0}
. verbosity
The integer verbosity value of Hatch. A flag
modifier is supported that will render the value as a CLI flag e.g. -2
becomes -qq
, 1
becomes -v
, and 0
becomes an empty string. An additional flag integer modifier may be used to adjust the verbosity level. For example, if you wanted to make a command quiet by default, you could use {verbosity:flag:-1}
within the command. args
For executed commands only, any extra command line arguments with an optional default modifier if none were provided"},{"location":"config/environment/advanced/#matrix","title":"Matrix","text":"Environments can define a series of matrices with the matrix
option:
[tool.hatch.envs.test]\ndependencies = [\n \"pytest\"\n]\n\n[[tool.hatch.envs.test.matrix]]\npython = [\"3.10\", \"3.11\"]\nversion = [\"42\", \"3.14\"]\n\n[[tool.hatch.envs.test.matrix]]\npython = [\"3.11\", \"3.12\"]\nversion = [\"9000\"]\nfeature = [\"foo\", \"bar\"]\n
[envs.test]\ndependencies = [\n \"pytest\"\n]\n\n[[envs.test.matrix]]\npython = [\"3.10\", \"3.11\"]\nversion = [\"42\", \"3.14\"]\n\n[[envs.test.matrix]]\npython = [\"3.11\", \"3.12\"]\nversion = [\"9000\"]\nfeature = [\"foo\", \"bar\"]\n
Doing so will result in the product of each variable combination being its own environment.
"},{"location":"config/environment/advanced/#naming","title":"Naming","text":"The name of the generated environments will be the variable values of each combination separated by hyphens, altogether prefixed by <ENV_NAME>.
. For example, the following configuration:
[[tool.hatch.envs.test.matrix]]\nversion = [\"42\"]\nfeature = [\"foo\", \"bar\"]\n
[[envs.test.matrix]]\nversion = [\"42\"]\nfeature = [\"foo\", \"bar\"]\n
would indicate the following unique environments:
test.42-foo\ntest.42-bar\n
The exceptions to this format are described below.
"},{"location":"config/environment/advanced/#python-variables","title":"Python variables","text":"If the variables py
or python
are specified, then they will rank first in the product result and will be prefixed by py
if the value is not. For example, the following configuration:
[[tool.hatch.envs.test.matrix]]\nversion = [\"42\"]\npython = [\"3.9\", \"pypy3\"]\n
[[envs.test.matrix]]\nversion = [\"42\"]\npython = [\"3.9\", \"pypy3\"]\n
would generate the following environments:
test.py3.9-42\ntest.pypy3-42\n
Note
The value of this variable sets the Python version.
"},{"location":"config/environment/advanced/#name-formatting","title":"Name formatting","text":"You can set the matrix-name-format
option to modify how each variable part is formatted which recognizes the placeholders {variable}
and {value}
. For example, the following configuration:
[tool.hatch.envs.test]\nmatrix-name-format = \"{variable}_{value}\"\n\n[[tool.hatch.envs.test.matrix]]\nversion = [\"42\"]\nfeature = [\"foo\", \"bar\"]\n
[envs.test]\nmatrix-name-format = \"{variable}_{value}\"\n\n[[envs.test.matrix]]\nversion = [\"42\"]\nfeature = [\"foo\", \"bar\"]\n
would produce the following environments:
test.version_42-feature_foo\ntest.version_42-feature_bar\n
By default this option is set to {value}
.
If the default
environment defines matrices, then the generated names will not be prefixed by the environment name. This can be useful for projects that only need a single series of matrices without any standalone environments.
Rather than selecting a single generated environment, you can select the root environment to target all of them. For example, if you have the following configuration:
pyproject.toml hatch.toml[tool.hatch.envs.test]\ndependencies = [\n \"coverage[toml]\",\n \"pytest\",\n \"pytest-cov\",\n]\n\n[tool.hatch.envs.test.scripts]\ncov = 'pytest --cov-report=term-missing --cov-config=pyproject.toml --cov=pkg --cov=tests'\n\n[[tool.hatch.envs.test.matrix]]\npython = [\"3.11\", \"3.12\"]\nversion = [\"42\", \"3.14\"]\n
[envs.test]\ndependencies = [\n \"coverage[toml]\",\n \"pytest\",\n \"pytest-cov\",\n]\n\n[envs.test.scripts]\ncov = 'pytest --cov-report=term-missing --cov-config=pyproject.toml --cov=pkg --cov=tests'\n\n[[envs.test.matrix]]\npython = [\"3.11\", \"3.12\"]\nversion = [\"42\", \"3.14\"]\n
you could then run your tests consecutively in all 4 environments with:
hatch run test:cov\n
"},{"location":"config/environment/advanced/#option-overrides","title":"Option overrides","text":"You can modify options based on the conditions of different sources like matrix variables with the overrides
table, using dotted key syntax for each declaration:
[tool.hatch.envs.<ENV_NAME>.overrides]\n<SOURCE>.<CONDITION>.<OPTION> = <VALUE>\n
[envs.<ENV_NAME>.overrides]\n<SOURCE>.<CONDITION>.<OPTION> = <VALUE>\n
The type of the selected option determines the types of values.
"},{"location":"config/environment/advanced/#platform-overrides","title":"Platform overrides","text":"Options can be modified based on the current platform using the platform
source.
[tool.hatch.envs.test.overrides]\nplatform.windows.scripts = [\n 'run=pytest -m \"not io_uring\"',\n]\n
[envs.test.overrides]\nplatform.windows.scripts = [\n 'run=pytest -m \"not io_uring\"',\n]\n
The following platforms are supported:
linux
windows
macos
Environment variables can modify options using the env
source.
[tool.hatch.envs.test.overrides]\nenv.GITHUB_ACTIONS.dev-mode = { value = false, if = [\"true\"] }\n
[envs.test.overrides]\nenv.GITHUB_ACTIONS.dev-mode = { value = false, if = [\"true\"] }\n
"},{"location":"config/environment/advanced/#matrix-variable-overrides","title":"Matrix variable overrides","text":"The matrix variables used to generate each environment can be used to modify options within using the matrix
source.
[tool.hatch.envs.test.overrides]\nmatrix.version.env-vars = \"PRODUCT_VERSION\"\nmatrix.auth.features = [\n { value = \"oauth\", if = [\"oauth2\"] },\n { value = \"kerberos\", if = [\"kerberos\"] },\n]\n\n[[tool.hatch.envs.test.matrix]]\npython = [\"3.11\", \"3.12\"]\nversion = [\"legacy\", \"latest\"]\nauth = [\"oauth2\", \"kerberos\", \"noauth\"]\n
[envs.test.overrides]\nmatrix.version.env-vars = \"PRODUCT_VERSION\"\nmatrix.auth.features = [\n { value = \"oauth\", if = [\"oauth2\"] },\n { value = \"kerberos\", if = [\"kerberos\"] },\n]\n\n[[envs.test.matrix]]\npython = [\"3.11\", \"3.12\"]\nversion = [\"legacy\", \"latest\"]\nauth = [\"oauth2\", \"kerberos\", \"noauth\"]\n
"},{"location":"config/environment/advanced/#name-overrides","title":"Name overrides","text":"When a matrix is defined, the name
source can be used for regular expression matching on the generated name, minus the prefix for non-default environments.
[tool.hatch.envs.test.overrides]\nname.\"^0\".env-vars = \"TESTING_UNSTABLE=true\"\n\n[[tool.hatch.envs.test.matrix]]\nversion = [\"0.1.0\", \"0.2.0\", \"1.0.0\"]\n
[envs.test.overrides]\nname.\"^0\".env-vars = \"TESTING_UNSTABLE=true\"\n\n[[envs.test.matrix]]\nversion = [\"0.1.0\", \"0.2.0\", \"1.0.0\"]\n
"},{"location":"config/environment/advanced/#types","title":"Types","text":"Literal types like strings for the Python version or booleans for skipping installation can be set using the value itself, an inline table, or an array. For example:
pyproject.toml hatch.toml[tool.hatch.envs.test.overrides]\nmatrix.foo.python = \"3.10\"\nmatrix.bar.skip-install = { value = true, if = [\"...\"] }\nenv.CI.dev-mode = [\n { value = false, if = [\"...\"] },\n true,\n]\n
[envs.test.overrides]\nmatrix.foo.python = \"3.10\"\nmatrix.bar.skip-install = { value = true, if = [\"...\"] }\nenv.CI.dev-mode = [\n { value = false, if = [\"...\"] },\n true,\n]\n
For arrays, the first allowed value will be used.
Array types like dependencies or commands can be appended to using an array of strings or inline tables. For example:
pyproject.toml hatch.toml[tool.hatch.envs.test.overrides]\nmatrix.foo.dependencies = [\n \"httpx\",\n { value = \"cryptography\" },\n]\n
[envs.test.overrides]\nmatrix.foo.dependencies = [\n \"httpx\",\n { value = \"cryptography\" },\n]\n
Mapping types like environment variables or scripts can have keys set using a string, or an array of strings or inline tables. For example:
pyproject.toml hatch.toml[tool.hatch.envs.test.overrides]\nmatrix.foo.env-vars = \"KEY=VALUE\"\nmatrix.bar.env-vars = [\n \"KEY1=VALUE1\",\n { key = \"KEY2\", value = \"VALUE2\" },\n]\n
[envs.test.overrides]\nmatrix.foo.env-vars = \"KEY=VALUE\"\nmatrix.bar.env-vars = [\n \"KEY1=VALUE1\",\n { key = \"KEY2\", value = \"VALUE2\" },\n]\n
If the value is missing (no =
for strings, no value
key for inline tables), then the value will be set to the value of the source condition.
Rather than supplementing the values within mapping types or array types, you can overwrite the option as a whole by prefixing the name with set-
:
[tool.hatch.envs.test.overrides]\nmatrix.foo.set-platforms = [\"macos\", \"linux\"]\n
[envs.test.overrides]\nmatrix.foo.set-platforms = [\"macos\", \"linux\"]\n
When overwriting entire options or keys within mappings, override sources are applied in the following order:
You may specify certain extra keys for any inline table that will determine whether or not to apply that entry. These modifiers may be combined with others and any negative evaluation will immediately cause the entry to be skipped.
"},{"location":"config/environment/advanced/#allowed-values","title":"Allowed values","text":"The if
key represents the allowed values for that condition. If the value of the condition is not listed, then that entry will not be applied:
[tool.hatch.envs.test.overrides]\nmatrix.version.python = { value = \"pypy\", if = [\"3.14\"] }\nmatrix.version.env-vars = [\n { key = \"KEY1\", value = \"VALUE1\", if = [\"42\"] },\n { key = \"KEY2\", value = \"VALUE2\", if = [\"3.14\"] },\n]\n\n[[tool.hatch.envs.test.matrix]]\nversion = [\"42\", \"3.14\"]\n
[envs.test.overrides]\nmatrix.version.python = { value = \"pypy\", if = [\"3.14\"] }\nmatrix.version.env-vars = [\n { key = \"KEY1\", value = \"VALUE1\", if = [\"42\"] },\n { key = \"KEY2\", value = \"VALUE2\", if = [\"3.14\"] },\n]\n\n[[envs.test.matrix]]\nversion = [\"42\", \"3.14\"]\n
"},{"location":"config/environment/advanced/#specific-platforms","title":"Specific platforms","text":"The platform
key represents the desired platforms. If the current platform is not listed, then that entry will not be applied:
[tool.hatch.envs.test.overrides]\nenv.EXPERIMENTAL.python = { value = \"pypy\", if = [\"1\"], platform = [\"macos\"] }\nmatrix.version.env-vars = [\n { key = \"KEY1\", value = \"VALUE1\", if = [\"42\"], platform = [\"linux\"] },\n { key = \"KEY2\", value = \"VALUE2\", if = [\"3.14\"] },\n]\n\n[[tool.hatch.envs.test.matrix]]\nversion = [\"42\", \"3.14\"]\n
[envs.test.overrides]\nenv.EXPERIMENTAL.python = { value = \"pypy\", if = [\"1\"], platform = [\"macos\"] }\nmatrix.version.env-vars = [\n { key = \"KEY1\", value = \"VALUE1\", if = [\"42\"], platform = [\"linux\"] },\n { key = \"KEY2\", value = \"VALUE2\", if = [\"3.14\"] },\n]\n\n[[envs.test.matrix]]\nversion = [\"42\", \"3.14\"]\n
"},{"location":"config/environment/advanced/#required-environment-variables","title":"Required environment variables","text":"The env
key represents the required environment variables. If any of the listed environment variables are not set or the defined value does not match, then that entry will not be applied:
[tool.hatch.envs.test.overrides]\nplatform.windows.python = { value = \"pypy\", env = [\"EXPERIMENTAL\"] }\nmatrix.version.env-vars = [\n { key = \"KEY1\", value = \"VALUE1\", if = [\"42\"], env = [\"FOO\", \"BAR=BAZ\"] },\n { key = \"KEY2\", value = \"VALUE2\", if = [\"3.14\"] },\n]\n\n[[tool.hatch.envs.test.matrix]]\nversion = [\"42\", \"3.14\"]\n
[envs.test.overrides]\nplatform.windows.python = { value = \"pypy\", env = [\"EXPERIMENTAL\"] }\nmatrix.version.env-vars = [\n { key = \"KEY1\", value = \"VALUE1\", if = [\"42\"], env = [\"FOO\", \"BAR=BAZ\"] },\n { key = \"KEY2\", value = \"VALUE2\", if = [\"3.14\"] },\n]\n\n[[envs.test.matrix]]\nversion = [\"42\", \"3.14\"]\n
"},{"location":"config/environment/overview/","title":"Environment configuration","text":"All environments are defined as sections within the tool.hatch.envs
table.
[tool.hatch.envs.<ENV_NAME>]\n
[envs.<ENV_NAME>]\n
The storage location for environments is completely configurable.
Unless an environment is explicitly selected on the command line, the default
environment will be used. The type of this environment defaults to virtual
.
Info
Environments prefixed by hatch-
are used for special purposes e.g. testing.
All environments inherit from the environment defined by its template
option, which defaults to default
.
So for the following configuration:
pyproject.toml hatch.toml[tool.hatch.envs.foo]\ntype = \"baz\"\nskip-install = true\n\n[tool.hatch.envs.bar]\ntemplate = \"foo\"\nskip-install = false\n
[envs.foo]\ntype = \"baz\"\nskip-install = true\n\n[envs.bar]\ntemplate = \"foo\"\nskip-install = false\n
the environment bar
will be of type baz
with skip-install
set to false
.
Note
Environments do not inherit matrices.
"},{"location":"config/environment/overview/#self-referential-environments","title":"Self-referential environments","text":"You can disable inheritance by setting template
to the environment's own name:
[tool.hatch.envs.foo]\ntemplate = \"foo\"\n
[envs.foo]\ntemplate = \"foo\"\n
"},{"location":"config/environment/overview/#detached-environments","title":"Detached environments","text":"A common use case is standalone environments that do not require inheritance nor the installation of the project, such as for linting or sometimes building documentation. Enabling the detached
option will make the environment self-referential and will skip project installation:
[tool.hatch.envs.lint]\ndetached = true\n
[envs.lint]\ndetached = true\n
"},{"location":"config/environment/overview/#dependencies","title":"Dependencies","text":"You can install dependencies in addition to the ones defined by your project's metadata. Entries support context formatting.
pyproject.toml hatch.toml[tool.hatch.envs.test]\ndependencies = [\n \"coverage[toml]\",\n \"pytest\",\n \"pytest-cov\",\n \"pytest-mock\",\n]\n
[envs.test]\ndependencies = [\n \"coverage[toml]\",\n \"pytest\",\n \"pytest-cov\",\n \"pytest-mock\",\n]\n
If you define environments with dependencies that only slightly differ from their inherited environments, you can use the extra-dependencies
option to avoid redeclaring the dependencies
option:
[tool.hatch.envs.default]\ndependencies = [\n \"foo\",\n \"bar\",\n]\n\n[tool.hatch.envs.experimental]\nextra-dependencies = [\n \"baz\",\n]\n
[envs.default]\ndependencies = [\n \"foo\",\n \"bar\",\n]\n\n[envs.experimental]\nextra-dependencies = [\n \"baz\",\n]\n
Tip
Hatch uses pip to install dependencies so any configuration it supports Hatch does as well. For example, if you wanted to only use a private repository you could set the PIP_INDEX_URL
environment variable.
If your project defines optional dependencies, you can select which groups to install using the features
option:
[tool.hatch.envs.nightly]\nfeatures = [\n \"server\",\n \"grpc\",\n]\n
[envs.nightly]\nfeatures = [\n \"server\",\n \"grpc\",\n]\n
Note
Features/optional dependencies are also known as extras
in other tools.
By default, environments will always reflect the current state of your project on disk, for example, by installing it in editable mode in a Python environment. Set dev-mode
to false
to disable this behavior and have your project installed only upon creation of a new environment. From then on, you need to manage your project installation manually.
[tool.hatch.envs.static]\ndev-mode = false\n
[envs.static]\ndev-mode = false\n
"},{"location":"config/environment/overview/#skip-install","title":"Skip install","text":"By default, environments will install your project during creation. To ignore this step, set skip-install
to true
:
[tool.hatch.envs.lint]\nskip-install = true\n
[envs.lint]\nskip-install = true\n
"},{"location":"config/environment/overview/#environment-variables","title":"Environment variables","text":""},{"location":"config/environment/overview/#defined","title":"Defined","text":"You can define environment variables with the env-vars
option:
[tool.hatch.envs.docs]\ndependencies = [\n \"mkdocs\"\n]\n[tool.hatch.envs.docs.env-vars]\nSOURCE_DATE_EPOCH = \"1580601600\"\n
[envs.docs]\ndependencies = [\n \"mkdocs\"\n]\n[envs.docs.env-vars]\nSOURCE_DATE_EPOCH = \"1580601600\"\n
Values support context formatting.
"},{"location":"config/environment/overview/#filters","title":"Filters","text":"By default, environments will have access to all environment variables. You can filter with wildcard patterns using the env-include
/env-exclude
options:
[tool.hatch.envs.<ENV_NAME>]\nenv-include = [\n \"FOO*\",\n]\nenv-exclude = [\n \"BAR\",\n]\n
[envs.<ENV_NAME>]\nenv-include = [\n \"FOO*\",\n]\nenv-exclude = [\n \"BAR\",\n]\n
Exclusion patterns take precedence but will never affect defined environment variables.
"},{"location":"config/environment/overview/#scripts","title":"Scripts","text":"You can define named scripts that may be executed or referenced at the beginning of other scripts. Context formatting is supported.
For example, in the following configuration:
pyproject.toml hatch.toml[tool.hatch.envs.test]\ndependencies = [\n \"coverage[toml]\",\n \"pytest\",\n \"pytest-cov\",\n \"pytest-mock\",\n]\n[tool.hatch.envs.test.scripts]\nrun-coverage = \"pytest --cov-config=pyproject.toml --cov=pkg --cov=tests\"\nrun = \"run-coverage --no-cov\"\n
[envs.test]\ndependencies = [\n \"coverage[toml]\",\n \"pytest\",\n \"pytest-cov\",\n \"pytest-mock\",\n]\n[envs.test.scripts]\nrun-coverage = \"pytest --cov-config=pyproject.toml --cov=pkg --cov=tests\"\nrun = \"run-coverage --no-cov\"\n
the run
script would be expanded to:
pytest --cov-config=pyproject.toml --cov=pkg --cov=tests --no-cov\n
Scripts can also be defined as an array of strings.
pyproject.toml hatch.toml[tool.hatch.envs.style]\ndetached = true\ndependencies = [\n \"flake8\",\n \"black\",\n \"isort\",\n]\n[tool.hatch.envs.style.scripts]\ncheck = [\n \"flake8 .\",\n \"black --check --diff .\",\n \"isort --check-only --diff .\",\n]\nfmt = [\n \"isort .\",\n \"black .\",\n \"check\",\n]\n
[envs.style]\ndetached = true\ndependencies = [\n \"flake8\",\n \"black\",\n \"isort\",\n]\n[envs.style.scripts]\ncheck = [\n \"flake8 .\",\n \"black --check --diff .\",\n \"isort --check-only --diff .\",\n]\nfmt = [\n \"isort .\",\n \"black .\",\n \"check\",\n]\n
Similar to make, you can ignore the exit code of commands that start with -
(a hyphen). For example, the script error
defined by the following configuration would halt after the second command with 3
as the exit code:
[tool.hatch.envs.test.scripts]\nerror = [\n \"- exit 1\",\n \"exit 3\",\n \"exit 0\",\n]\n
[envs.test.scripts]\nerror = [\n \"- exit 1\",\n \"exit 3\",\n \"exit 0\",\n]\n
"},{"location":"config/environment/overview/#extra-scripts","title":"Extra scripts","text":"Individual scripts inherit from parent environments just like options. To guarantee that individual scripts do not override those defined by parent environments, you can use the extra-scripts
option instead which is only capable of adding scripts that have not been defined.
All commands are able to use any defined scripts. Also like scripts, context formatting is supported and the exit code of commands that start with a hyphen will be ignored.
"},{"location":"config/environment/overview/#pre-install","title":"Pre-install","text":"You can run commands immediately before environments install your project.
pyproject.toml hatch.toml[tool.hatch.envs.<ENV_NAME>]\npre-install-commands = [\n \"...\",\n]\n
[envs.<ENV_NAME>]\npre-install-commands = [\n \"...\",\n]\n
"},{"location":"config/environment/overview/#post-install","title":"Post-install","text":"You can run commands immediately after environments install your project.
pyproject.toml hatch.toml[tool.hatch.envs.<ENV_NAME>]\npost-install-commands = [\n \"...\",\n]\n
[envs.<ENV_NAME>]\npost-install-commands = [\n \"...\",\n]\n
"},{"location":"config/environment/overview/#python-version","title":"Python version","text":"The python
option specifies which version of Python to use, or an absolute path to a Python interpreter:
[tool.hatch.envs.<ENV_NAME>]\npython = \"3.10\"\n
[envs.<ENV_NAME>]\npython = \"3.10\"\n
All environment types should respect this option.
"},{"location":"config/environment/overview/#supported-platforms","title":"Supported platforms","text":"The platforms
option indicates the operating systems with which the environment is compatible:
[tool.hatch.envs.<ENV_NAME>]\nplatforms = [\"linux\", \"windows\", \"macos\"]\n
[envs.<ENV_NAME>]\nplatforms = [\"linux\", \"windows\", \"macos\"]\n
The following platforms are supported:
linux
windows
macos
If unspecified, the environment is assumed to be compatible with all platforms.
"},{"location":"config/environment/overview/#description","title":"Description","text":"The description
option is purely informational and is displayed in the output of the env show
command:
[tool.hatch.envs.<ENV_NAME>]\ndescription = \"\"\"\nLorem ipsum ...\n\"\"\"\n
[envs.<ENV_NAME>]\ndescription = \"\"\"\nLorem ipsum ...\n\"\"\"\n
"},{"location":"config/environment/overview/#type","title":"Type","text":"An environment's type
determines which environment plugin will be used for management. The only built-in environment type is virtual
, which uses virtual Python environments.
You can fully alter the behavior of the environment used by the build
command.
Build environments will always have what is required by the build system, targets, and hooks.
You can define dependencies that your builds may require in the environment as well:
pyproject.toml hatch.toml[tool.hatch.envs.hatch-build]\ndependencies = [\n \"cython\",\n]\n
[envs.hatch-build]\ndependencies = [\n \"cython\",\n]\n
caution
It's recommended to only use the standard mechanisms to define build dependencies for better compatibility with other tools.
"},{"location":"config/internal/build/#environment-variables","title":"Environment variables","text":"You can define environment variables that will be set during builds:
pyproject.toml hatch.toml[tool.hatch.envs.hatch-build.env-vars]\nSOURCE_DATE_EPOCH = \"1580601600\"\n
[envs.hatch-build.env-vars]\nSOURCE_DATE_EPOCH = \"1580601600\"\n
"},{"location":"config/internal/build/#installer","title":"Installer","text":"By default, UV is enabled. You may disable that behavior as follows:
pyproject.toml hatch.toml[tool.hatch.envs.hatch-build]\ninstaller = \"pip\"\n
[envs.hatch-build]\ninstaller = \"pip\"\n
"},{"location":"config/internal/static-analysis/","title":"Static analysis configuration","text":"Static analysis performed by the fmt
command is (by default) backed entirely by Ruff.
Hatch provides default settings that user configuration can extend.
"},{"location":"config/internal/static-analysis/#extending-config","title":"Extending config","text":"When defining your configuration, be sure to use options that are prefixed by extend-
such as extend-select
, for example:
[tool.ruff.format]\npreview = true\nquote-style = \"single\"\n\n[tool.ruff.lint]\npreview = true\nextend-select = [\"C901\"]\n\n[tool.ruff.lint.extend-per-file-ignores]\n\"docs/.hooks/*\" = [\"INP001\", \"T201\"]\n\n[tool.ruff.lint.isort]\nknown-first-party = [\"foo\", \"bar\"]\n
[format]\npreview = true\nquote-style = \"single\"\n\n[lint]\npreview = true\nextend-select = [\"C901\"]\n\n[lint.extend-per-file-ignores]\n\"docs/.hooks/*\" = [\"INP001\", \"T201\"]\n\n[lint.isort]\nknown-first-party = [\"foo\", \"bar\"]\n
Note
When not persisting config, there is no need to explicitly extend the defaults as Hatch automatically handles that.
"},{"location":"config/internal/static-analysis/#persistent-config","title":"Persistent config","text":"If you want to store the default configuration in the project, set an explicit path like so:
pyproject.toml hatch.toml[tool.hatch.envs.hatch-static-analysis]\nconfig-path = \"ruff_defaults.toml\"\n
[envs.hatch-static-analysis]\nconfig-path = \"ruff_defaults.toml\"\n
Then instruct Ruff to consider your configuration as an extension of the default file:
pyproject.toml ruff.toml[tool.ruff]\nextend = \"ruff_defaults.toml\"\n
extend = \"ruff_defaults.toml\"\n
Anytime you wish to update the defaults (such as when upgrading Hatch), you must run the fmt
command once with the --sync
flag e.g.:
hatch fmt --check --sync\n
Tip
This is the recommended approach since it allows other tools like IDEs to use the default configuration.
"},{"location":"config/internal/static-analysis/#no-config","title":"No config","text":"If you don't want Hatch to use any of its default configuration and rely entirely on yours, set the path to anything and then simply don't extend
in your Ruff config:
[tool.hatch.envs.hatch-static-analysis]\nconfig-path = \"none\"\n
[envs.hatch-static-analysis]\nconfig-path = \"none\"\n
"},{"location":"config/internal/static-analysis/#customize-behavior","title":"Customize behavior","text":"You can fully alter the behavior of the environment used by the fmt
command. See the how-to for a detailed example.
Pin the particular version of Ruff by explicitly defining the environment dependencies:
pyproject.toml hatch.toml[tool.hatch.envs.hatch-static-analysis]\ndependencies = [\"ruff==X.Y.Z\"]\n
[envs.hatch-static-analysis]\ndependencies = [\"ruff==X.Y.Z\"]\n
"},{"location":"config/internal/static-analysis/#scripts","title":"Scripts","text":"If you want to change the default commands that are executed, you can override the scripts. The following four scripts must be defined:
pyproject.toml hatch.toml[tool.hatch.envs.hatch-static-analysis.scripts]\nformat-check = \"...\"\nformat-fix = \"...\"\nlint-check = \"...\"\nlint-fix = \"...\"\n
[envs.hatch-static-analysis.scripts]\nformat-check = \"...\"\nformat-fix = \"...\"\nlint-check = \"...\"\nlint-fix = \"...\"\n
The format-*
scripts correspond to the --formatter
/-f
flag while the lint-*
scripts correspond to the --linter
/-l
flag. The *-fix
scripts run by default while the *-check
scripts correspond to the --check
flag.
Reminder
If you choose to use different tools for static analysis, be sure to update the required dependencies.
"},{"location":"config/internal/static-analysis/#installer","title":"Installer","text":"By default, UV is enabled. You may disable that behavior as follows:
pyproject.toml hatch.toml[tool.hatch.envs.hatch-static-analysis]\ninstaller = \"pip\"\n
[envs.hatch-static-analysis]\ninstaller = \"pip\"\n
"},{"location":"config/internal/static-analysis/#default-settings","title":"Default settings","text":""},{"location":"config/internal/static-analysis/#non-rule-settings","title":"Non-rule settings","text":"**/scripts/*
: INP001, T201**/tests/**/*
: PLC1901, PLR2004, PLR6301, S, TID252The following rules are based on version 0.4.5 of Ruff. Rules with a P are only selected when preview mode is enabled.
There are 525 selected stable rules and 129 selected preview rules.
Selected rulesThere are 175 unselected rules.
Unselected rulesCheck out the testing overview tutorial for a more comprehensive walk-through.
"},{"location":"config/internal/testing/#settings","title":"Settings","text":"If an option has a corresponding test
command flag, the flag will always take precedence.
You can define default arguments for the test
command by setting the default-args
option, which must be an array of strings. The following is the default configuration:
[tool.hatch.envs.hatch-test]\ndefault-args = [\"tests\"]\n
[envs.hatch-test]\ndefault-args = [\"tests\"]\n
"},{"location":"config/internal/testing/#extra-arguments","title":"Extra arguments","text":"You can define extra internal arguments for test scripts by setting the extra-args
option, which must be an array of strings. For example, if you wanted to increase the verbosity of pytest
, you could set the following:
[tool.hatch.envs.hatch-test]\nextra-args = [\"-vv\"]\n
[envs.hatch-test]\nextra-args = [\"-vv\"]\n
"},{"location":"config/internal/testing/#randomize-test-order","title":"Randomize test order","text":"You can randomize the order of tests by enabling the randomize
option which corresponds to the --randomize
/-r
flag:
[tool.hatch.envs.hatch-test]\nrandomize = true\n
[envs.hatch-test]\nrandomize = true\n
"},{"location":"config/internal/testing/#parallelize-test-execution","title":"Parallelize test execution","text":"You can parallelize test execution by enabling the parallel
option which corresponds to the --parallel
/-p
flag:
[tool.hatch.envs.hatch-test]\nparallel = true\n
[envs.hatch-test]\nparallel = true\n
"},{"location":"config/internal/testing/#retry-failed-tests","title":"Retry failed tests","text":"You can retry failed tests by setting the retries
option which corresponds to the --retries
flag:
[tool.hatch.envs.hatch-test]\nretries = 2\n
[envs.hatch-test]\nretries = 2\n
You can also set the number of seconds to wait between retries by setting the retry-delay
option which corresponds to the --retry-delay
flag:
[tool.hatch.envs.hatch-test]\nretry-delay = 1\n
[envs.hatch-test]\nretry-delay = 1\n
"},{"location":"config/internal/testing/#customize-environment","title":"Customize environment","text":"You can fully alter the behavior of the environment used by the test
command.
You can define extra dependencies that your tests may require:
pyproject.toml hatch.toml[tool.hatch.envs.hatch-test]\nextra-dependencies = [\n \"pyfakefs\",\n \"pytest-asyncio\",\n \"pytest-benchmark\",\n \"pytest-memray\",\n \"pytest-playwright\",\n \"pytest-print\",\n]\n
[envs.hatch-test]\nextra-dependencies = [\n \"pyfakefs\",\n \"pytest-asyncio\",\n \"pytest-benchmark\",\n \"pytest-memray\",\n \"pytest-playwright\",\n \"pytest-print\",\n]\n
The following is the default configuration:
pyproject.toml hatch.toml[tool.hatch.envs.hatch-test]\ndependencies = [\n \"coverage-enable-subprocess==1.0\",\n \"coverage[toml]~=7.4\",\n \"pytest~=8.1\",\n \"pytest-mock~=3.12\",\n \"pytest-randomly~=3.15\",\n \"pytest-rerunfailures~=14.0\",\n \"pytest-xdist[psutil]~=3.5\",\n]\n
[envs.hatch-test]\ndependencies = [\n \"coverage-enable-subprocess==1.0\",\n \"coverage[toml]~=7.4\",\n \"pytest~=8.1\",\n \"pytest-mock~=3.12\",\n \"pytest-randomly~=3.15\",\n \"pytest-rerunfailures~=14.0\",\n \"pytest-xdist[psutil]~=3.5\",\n]\n
"},{"location":"config/internal/testing/#matrix","title":"Matrix","text":"You can override the default series of matrices:
pyproject.toml hatch.toml[[tool.hatch.envs.hatch-test.matrix]]\npython = [\"3.12\", \"3.11\", \"3.10\", \"3.9\", \"3.8\"]\n
[[envs.hatch-test.matrix]]\npython = [\"3.12\", \"3.11\", \"3.10\", \"3.9\", \"3.8\"]\n
"},{"location":"config/internal/testing/#scripts","title":"Scripts","text":"If you want to change the default commands that are executed, you can override the scripts. The following default scripts must be redefined:
pyproject.toml hatch.toml[tool.hatch.envs.hatch-test.scripts]\nrun = \"pytest{env:HATCH_TEST_ARGS:} {args}\"\nrun-cov = \"coverage run -m pytest{env:HATCH_TEST_ARGS:} {args}\"\ncov-combine = \"coverage combine\"\ncov-report = \"coverage report\"\n
[envs.hatch-test.scripts]\nrun = \"pytest{env:HATCH_TEST_ARGS:} {args}\"\nrun-cov = \"coverage run -m pytest{env:HATCH_TEST_ARGS:} {args}\"\ncov-combine = \"coverage combine\"\ncov-report = \"coverage report\"\n
The run
script is the default behavior while the run-cov
script is used instead when measuring code coverage. The cov-combine
script runs after all tests complete when measuring code coverage, as well as the cov-report
script when not using the --cover-quiet
flag.
Note
The HATCH_TEST_ARGS
environment variable is how the test
command's flags are translated and internally populated without affecting the user's arguments. This is also the way that extra arguments are passed.
By default, UV is enabled. You may disable that behavior as follows:
pyproject.toml hatch.toml[tool.hatch.envs.hatch-test]\ninstaller = \"pip\"\n
[envs.hatch-test]\ninstaller = \"pip\"\n
"},{"location":"history/hatch/","title":"Hatch history","text":"All notable changes to Hatch will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
"},{"location":"history/hatch/#unreleased","title":"Unreleased","text":"Changed:
build_environment
, build_environment_exists
, run_builder
, construct_build_command
Added:
version
and project metadata
commands now support projects that do not use Hatchling as the build backendhatch-build
project_root
, sep
, pathsep
, fs_context
Changed:
run
/env run
and test
commands now treat inclusion variable options as an intersection rather than a union to allow for specific targeting of environmentsAdded:
Fixed:
fmt
command no longer hides the commands that are being executedconfig show
commandAdded:
Fixed:
terminal.styles.spinner
configurationAdded:
Fixed:
Changed:
run
/env run
, fmt
and shell
commands now only change the current working directory to the project root if not already inside the projectshell
command now accepts a single argument to specify the environment to enter which overrides the standard choice mechanisms. The arguments determining shell options have been converted to flags.Added:
test
commandrun
command can now execute scripts that define inline metadata for dependencies and Python version constraintsvirtual
environment type now supports the ability to use UV in place of pip & virtualenvself report
command for submitting pre-populated bug reports to GitHubenvironment
interface for complete control over output during life cycle management: app_status_creation
, app_status_pre_installation
, app_status_post_installation
, app_status_project_installation
, app_status_dependency_state_check
, app_status_dependency_installation_check
, app_status_dependency_synchronization
~/.pypirc
file for the index
publisherHATCH_DEBUG
environment variable that when enabled will show local variables in the case of unhandled tracebacksenv show
command now outputs data about all internal environments when using the --json
flagFixed:
pyproject.toml
file but no project
table e.g. applicationsfmt
command when automatically installing plugin dependenciestypes
environment for new projectsE501
for the fmt
command by default since it conflicts with the formatterpackaging
dependency version as >=23.2
to avoid its URL validation which can conflict with context formattingREADME.md
file template for new projects to avoid Markdown linting issuesFixed:
Fixed:
Fixed:
Fixed:
Fixed:
dependency_hash
method of the environment
interface is called after sync_dependencies
for cases where the hash is only known at that point, such as for dependency lockersHATCH_PYTHON_VARIANT_*
environment variables for Python resolution for supported platforms and architecturesChanged:
hatch-
are now considered internal and used for special purposes such as configuration for static analysisAdded:
find
and check_compatibility
Fixed:
path
option for the virtual
environment typeFixed:
Changed:
get_build_process
method of the environment
interface has been removed; plugins should use the new run_builder
method insteadpyperclip
dependency and the --copy
flag of the config find
commandbuild
command all output from builders is now displayed as-is in real time without the stripping of ANSI codesAdded:
fmt
commandvirtual
environment type can now automatically download requested versions of Python that are not installeddependency_hash
method to the environment
interfacebuild
command now supports backends other than Hatchlingfeatures
for environments when skip-install
is enabled__token__
when prompting for a username for the publish
commandrun_builder
method to the environment
interfaceclick
to 8.0.6Fixed:
virtual
environment typeversion
command outside of a project rather than erroringproject metadata
command by only capturing stdout from the backendChanged:
src-layout
project template option is now enabled by defaultAdded:
tool.hatch.env.requires
configuration to automatically install dependencies for environment and environment collector pluginscustom
environment collectorisolated_data_directory
attribute to the environment interfaceindex
publisherFixed:
version
command when the version is static and build dependencies are unmetvirtual
environment type when storing within a relative pathsetup.py
if setup.cfg
is presentconfig set
commandFixed:
version
command when the version is dynamic and build dependencies are unmetFixed:
Fixed:
~
when it cannot be determinedChanged:
run_shell_command
environment interface method now accepts arbitrary subprocess.Popen
keyword arguments. This is not strictly breaking, but will be utilized in upcoming features.virtual
environments is now more nested. This is not breaking, but any local environments will be created anew.Added:
project
command group to view details about the project like PEP 621 metadatavirtual
environments will be flat if Hatch's configured virtual
environment directory resides somewhere within the project root or if it is set to a .virtualenvs
directory within the user's home directoryvirtual
environment type are now cached for improved performancebuild_environment_exists
method to the environment interface for implementations that cache the build environmentpath
option to the virtual
environment type--initialize-auth
flag to the index
publisher to allow for the saving of authentication information before publishingshell
commandsetuptools
migration script no longer modifies the formatting of existing pyproject.toml
configurationFixed:
dep hash
and all dep show
commands now respect dynamically defined project dependenciesenv show
, dep hash
, and all dep show
commands now honor context formattingrun
and env run
commands when there are multiple possible variablessetuptools
migration scriptextra-dependencies
in environment overridespackaging
explicitly rather than relying on it being a transitive dependency of HatchlingAdded:
index
publisher now recognizes repository-specific options--ignore-compat
flag to the env run
commandHATCH_PYTHON
environment variable to self
will now force the use of the Python executable Hatch is running on for virtual
environment creationFixed:
--force-continue
flag of the env run
commandsetuptools
migration scriptFixed:
version
command when metadata hooks are in useFixed:
Added:
virtual
environments now checks PATH before using the one Hatch is running onenv-vars
now support context formattingname
override for environments to allow for regular expression matchingindex
publisher now better supports non-PyPI indicesindex
publishershell
command is executedash
) shellshyperlink
as a dependency for better handling of package index URLsvirtualenv
to 20.16.2tomlkit
to 0.11.1Fixed:
extra-dependencies
for the env show
commandshell
commandsrc-layout
project template optionFixed:
-h
/--help
flag for the run
commandChanged:
pypi
to the more generic index
Added:
pyproject.toml
files, as is the case for apps and non-Python projectsenv show
command by default--force-continue
flag to the env run
commandpwsh
is now an alias for powershell
atomicwrites
dependencyuserpath
dependencyFixed:
utf-8
for all files generated for new projectssetuptools
migration scriptFixed:
data_files
in setuptools
migration scriptChanged:
enter_shell
environment plugin method now accepts an additional args
parameterAdded:
env_name
, env_type
, matrix
, verbosity
, and args
Fixed:
setuptools
migration scriptFixed:
Fixed:
setuptools
migration script for non-Windows systemsChanged:
run_shell_commands
method has been replaced by the singular run_shell_command
. A new command_context
method has been added to more easily satisfy complex use cases.finalize_command
environment plugin method has been removed in favor of the newly introduced context formatting functionality.Added:
make
, ignore the exit code of executed commands that start with -
(a hyphen)--init
flag of the new
command to automatically migrate setuptools
configurationThis is the first stable release of Hatch v1, a complete rewrite. Enjoy!
"},{"location":"history/hatchling/","title":"Hatchling history","text":"All notable changes to Hatchling will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
"},{"location":"history/hatchling/#unreleased","title":"Unreleased","text":""},{"location":"history/hatchling/#hatchling-v1.25.0","title":"1.25.0 - 2024-06-22","text":"Changed:
macos-max-compat
option for the wheel
target is now disabled by default and will be removed in a future releaseAdded:
wheel
and sdist
targets now have their permission bits normalizedFixed:
manylinux
/musllinux
tags for the wheel
target artifact name when enabling the infer_tag
build datawheel
target build data infer_tag
when enabled now respects the MACOSX_DEPLOYMENT_TARGET
environment variableFixed:
.venv
to the list of directories that cannot be traversedFixed:
shared-scripts
option/shared_scripts
build data of the wheel
targetAdded:
shared_data
and shared_scripts
build data for the wheel
targetAdded:
shared-scripts
option for the wheel
targetFixed:
packaging
dependency version as >=23.2
to avoid its URL validation which can conflict with context formattingFixed:
Fixed:
Fixed:
custom
build hook when using dynamic dependenciesFixed:
Fixed:
Deprecated:
app
build target has been renamed to binary
to reduce ambiguity with the name of an upcoming feature. The former name will still be usable for several minor releases.Added:
wheel
target now defaults to the PKG-INFO
metadata within source distributionsdependencies
method to the build hook interface so that hooks can themselves dynamically define dependenciesFixed:
editables
as a direct dependencysdist
build target now gracefully ignores UNIX socket files.DS_Store
on macOSFixed:
Added:
parent
context modifier for path fieldsAdded:
bypass-selection
option to the wheel
build target to allow for empty (metadata-only) wheelsFixed:
exclude
to count toward inclusion selection, thus bypassing the default inclusion selection heuristicsFixed:
wheel
build target cannot determine what to shipChanged:
wheel
build target if no file selection options are definedAdded:
sources
option to add a prefix to distribution pathsFixed:
standard
version schemewheel
build target for case insensitive file systems when the project metadata name does not match the directory name on diskapp
build target no longer has suppressed outputsources
option while build hooks overwrite included pathsChanged:
Added:
Fixed:
packages
or only-include
optionsAdded:
app
build target now embeds the project version in the name of binariesFixed:
app
build target option when using a local copy of PyApp when there is an explicit target triple setAdded:
app
build target option to build using a local copy of the PyApp repositoryAdded:
app
build targetFixed:
sdist
target when strict-naming
is disabled to match the file name in order to support the expectation of some frontendsAdded:
trove-classifiers
as a dependencyFixed:
Added:
Fixed:
macos-max-compat
option to the wheel
target that is enabled by default to support the latest version 22.0 of the packaging
libraryFixed:
Added:
extra_metadata
build data to the wheel
targetLicense-Expression
core metadata starting at version 2.1pyproject.toml
Fixed:
ARCHFLAGS
environment variable on macOS for the wheel
target when build hooks set the infer_tag
build data to true
support-legacy
option for the sdist
target when using a src-layout project structureversion
build hookFixed:
wheel
target when there is a single top-level moduleAdded:
env
version source to retrieve the version from an environment variablevalidate-bump
option to the standard
version schemeFixed:
RECORD
metadata file of the wheel
target to avoid warnings during installation by pip
if, for example, file names contain commasAdded:
__pypackages__
, .hg
, .hatch
, .tox
, .nox
Fixed:
project.optional-dependencies
that use direct referencesChanged:
Added:
prepare_metadata_for_build_wheel
and prepare_metadata_for_build_editable
for non-frontend tools that only need to inspect a project's metadatametadata
command to view PEP 621 project metadataLicense-File
for core metadata starting at version 2.1pathspec
to 0.10.1Fixed:
license
values LicenseRef-Public-Domain
and LicenseRef-Proprietary
Fixed:
wheel
build targets when both the project name and package directory name are not normalizedAdded:
get_known_classifiers
method to metadata hooksFixed:
version
command when metadata hooks are in useFixed:
relative_path
attribute of included files, that some build plugins may use, when selecting explicit pathsAdded:
require-runtime-features
option for builders and build hooksFixed:
wheel
target dev mode installations that define path rewrites with the sources
optionallow-direct-references
option in the relevant error messagesChanged:
sdist
and wheel
targets rather than what happens to be defined in configcode
version source now only supports files with known extensionsAdded:
code
version source now supports loading extension modulessearch-paths
option for the code
version sourceFixed:
sources
using an empty string value in the mappingstrict-naming
option now also applies to the metadata directory of wheel
targetsAdded:
strict-naming
option for sdist
and wheel
targetsFixed:
sdist
and wheel
target core metadata exactly as defined in pyproject.toml
without normalization to allow control of how PyPI displays themFixed:
sdist
targets when using the explicit selection optionsChanged:
packages
option uses the new only-include
option to provide targeted inclusion, since that is desired most of the time. You can retain the old behavior by using the include
and sources
options together.Added:
version
build hookonly-include
optioneditable
version of wheel
targets now respects the force-include
option by defaultforce-include
option now supports path rewriting with the sources
optionwheel
target shared-data
and extra-metadata
options now respect file selection optionswheel
target now auto-detects single module layouts__pycache__
rather than excluding individual files withinFixed:
wheel
targets if there are no entry points definedversion
in all casesforce-include
optionFixed:
code
version sourceRemoved:
args
context string formatting fieldAdded:
env
context string formatting fieldFixed:
uri
context string formatting modifier on WindowsAdded:
project.dependencies
and project.optional-dependencies
Added:
uri
and real
context string formatting modifiers for file system pathsChanged:
Added:
Fixed:
Added:
skip-excluded-dirs
build optionwheel
and sdist
build targetsforce_include_editable
build data for the wheel
build targetbuild_hooks
build data.hgignore
files when using glob syntaxFixed:
force_include
build dataThis is the initial public release of the Hatchling build system. Support for Python 2 will be dropped in version 1.
"},{"location":"how-to/config/dynamic-metadata/","title":"How to configure custom dynamic metadata","text":"If you have project metadata that is not appropriate for static entry into pyproject.toml
you will need to provide a custom metadata hook to apply such data during builds.
Alternatives
Dynamic metadata is a way to have a single source of truth that will be available at build time and at run time. Another way to achieve that is to enter the build data statically and then look up the same information dynamically in the program or package, using importlib.metadata.
If the version field is the only metadata of concern, Hatchling provides a few built-in ways such as the regex
version source and also third-party plugins. The approach here will also work, but is more complex.
Change the [project]
section of pyproject.toml
:
dynamic = [\"version\", \"license\", \"authors\", \"maintainers\"]
pyproject.toml
, delete those definitions. It is verboten to define a field statically and dynamically.Add a section to trigger loading of dynamic metadata plugins: [tool.hatch.metadata.hooks.custom]
. Use exactly that name, regardless of the name of the class you will use or its PLUGIN_NAME
. There doesn't need to be anything in the section.
If your plugin requires additional third-party packages to do its work, add them to the requires
array in the [build-system]
section of pyproject.toml
.
The dynamic lookup must happen in a custom plugin that you write. The default expectation is that it is in a hatch_build.py
file at the root of the project. Subclass MetadataHookInterface
and implement update()
; for example, here's plugin that reads metadata from a JSON file:
import json\nimport os\n\nfrom hatchling.metadata.plugin.interface import MetadataHookInterface\n\n\nclass JSONMetaDataHook(MetadataHookInterface):\n def update(self, metadata):\n src_file = os.path.join(self.root, \"gnumeric\", \".constants.json\")\n with open(src_file) as src:\n constants = json.load(src)\n metadata[\"version\"] = constants[\"__version__\"]\n metadata[\"license\"] = constants[\"__license__\"]\n metadata[\"authors\"] = [\n {\"name\": constants[\"__author__\"], \"email\": constants[\"__author_email__\"]},\n ]\n
update
method.metadata
refers to project metadata.list
for TOML arrays. Note that if a list is expected, it is required even if there is a single element.dict
for TOML tables e.g. authors
.If you want to store the hook in a different location, set the path
option:
[tool.hatch.metadata.hooks.custom]\npath = \"some/where.py\"\n
[metadata.hooks.custom]\npath = \"some/where.py\"\n
"},{"location":"how-to/environment/dependency-resolution/","title":"How to configure dependency resolution","text":"Most Hatch environment types, like the default virtual, simply use pip to install dependencies. Therefore, you can use the standard environment variables that influence pip
's behavior.
Here's an example of setting up the default environment to look at 2 private indices (using context formatting for authentication) before finally falling back to PyPI:
pyproject.toml hatch.toml[tool.hatch.envs.default.env-vars]\nPIP_INDEX_URL = \"https://token:{env:GITLAB_API_TOKEN}@gitlab.com/api/v4/groups/<group1_path>/-/packages/pypi/simple/\"\nPIP_EXTRA_INDEX_URL = \"https://token:{env:GITLAB_API_TOKEN}@gitlab.com/api/v4/groups/<group2_path>/-/packages/pypi/simple/ https://pypi.org/simple/\"\n
[envs.default.env-vars]\nPIP_INDEX_URL = \"https://token:{env:GITLAB_API_TOKEN}@gitlab.com/api/v4/groups/<group1_path>/-/packages/pypi/simple/\"\nPIP_EXTRA_INDEX_URL = \"https://token:{env:GITLAB_API_TOKEN}@gitlab.com/api/v4/groups/<group2_path>/-/packages/pypi/simple/ https://pypi.org/simple/\"\n
"},{"location":"how-to/environment/dependency-resolution/#uv","title":"UV","text":"If you're using UV, a different set of environment variables are available to configure its behavior. The previous example would look like this instead:
pyproject.toml hatch.toml[tool.hatch.envs.default.env-vars]\nUV_EXTRA_INDEX_URL = \"https://token:{env:GITLAB_API_TOKEN}@gitlab.com/api/v4/groups/<group1_path>/-/packages/pypi/simple/\"\nUV_INDEX_URL = \"https://token:{env:GITLAB_API_TOKEN}@gitlab.com/api/v4/groups/<group2_path>/-/packages/pypi/simple/ https://pypi.org/simple/\"\n
[envs.default.env-vars]\nUV_EXTRA_INDEX_URL = \"https://token:{env:GITLAB_API_TOKEN}@gitlab.com/api/v4/groups/<group1_path>/-/packages/pypi/simple/\"\nUV_INDEX_URL = \"https://token:{env:GITLAB_API_TOKEN}@gitlab.com/api/v4/groups/<group2_path>/-/packages/pypi/simple/ https://pypi.org/simple/\"\n
Tip
If you need precise control over the prioritization of package indices, then using UV is recommended because pip
has no index order guarantee.
The virtual environment type by default uses virtualenv for virtual environment creation and pip to install dependencies. You can speed up environment creation and dependency resolution by using UV instead of both of those tools.
caveat
UV is under active development and may not work for all dependencies.
To do so, set the installer
option to uv
. For example, if you wanted to enable this functionality for the default environment, you could set the following:
[tool.hatch.envs.default]\ninstaller = \"uv\"\n
[envs.default]\ninstaller = \"uv\"\n
Tip
All environments that enable UV will have the path to UV available as the HATCH_UV
environment variable.
The UV that is shared by all environments uses a specific version range that is known to work with Hatch. If you want to use a different version, you can override the dependencies for the internal hatch-uv
environment:
[tool.hatch.envs.hatch-uv]\ndependencies = [\n \"uv>9000\",\n]\n
[envs.hatch-uv]\ndependencies = [\n \"uv>9000\",\n]\n
"},{"location":"how-to/environment/select-installer/#externally-managed","title":"Externally managed","text":"If you want to manage UV yourself, you can expose it to Hatch by setting the HATCH_ENV_TYPE_VIRTUAL_UV_PATH
environment variable which should be the absolute path to a UV binary for Hatch to use instead. This implicitly enables UV.
If you have scripts or commands that call pip
, it may be useful to alias the uv pip
command to pip
so that you can use the same commands for both methods of configuration and retain your muscle memory. The following is an example of a matrix that conditionally enables UV and sets the alias:
[[tool.hatch.envs.example.matrix]]\ntool = [\"uv\", \"pip\"]\n\n[tool.hatch.envs.example.overrides]\nmatrix.tool.installer = { value = \"{matrix:tool}\" }\nmatrix.tool.scripts = [\n { key = \"pip\", value = \"{env:HATCH_UV} pip {args}\", if = [\"uv\"] },\n]\n
[[envs.example.matrix]]\ntool = [\"uv\", \"pip\"]\n\n[envs.example.overrides]\nmatrix.tool.installer = { value = \"{matrix:tool}\" }\nmatrix.tool.scripts = [\n { key = \"pip\", value = \"{env:HATCH_UV} pip {args}\", if = [\"uv\"] },\n]\n
Another common use case is to expose UV to all test environments. In this case, you often wouldn't want to modify the scripts
mapping directly but rather add an extra script:
[tool.hatch.envs.hatch-test.extra-scripts]\npip = \"{env:HATCH_UV} pip {args}\"\n
[envs.hatch-test.extra-scripts]\npip = \"{env:HATCH_UV} pip {args}\"\n
"},{"location":"how-to/integrate/vscode/","title":"How to use Hatch environments from Visual Studio Code","text":"Visual Studio Code announced support for Hatch environment discovery in vscode-python
's 2024.4 release.
For it to work, you should install Hatch globally. If you used the GUI installers on Windows or macOS, or your system package manager on e.g. Arch Linux or Fedora, this should be taken care of.
Setting up PATHIf you installed Hatch with pipx rather than system-wide, you might need to add $HOME/.local/bin
to your PATH environment variable for your graphical session, not just your terminal. Check like this:
$ pgrep bin/code # or some other graphical application\n1234\n$ cat /proc/1234/environ | tr '\\0' '\\n' | grep -E '^PATH='\nPATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\n
If the directory is not in there, you need to add it in your session startup script, in a way that depends on your desktop environment:
Make Hatch install the project and its dependencies to an environment using the env create
command.
Select an interpreter using the Python: Select Interpreter command:
You should now be able to use the environment. For example, if you have the python.terminal.activateEnvironment
setting set to true
and you open a new terminal, the environment should be activated. Alternatively, you could press the \"play\" button to run a file in the environment:
All reports regarding unexpected behavior should be generated with the self report
command:
$ hatch self report\n
By default, this will open a new tab in your default browser with pre-populated information about your environment.
If Hatch is not installed alongside a web browser, you may also pass the --no-open
/-n
command which will output the URL with correct parameters for copying elsewhere:
$ hatch self report -n\nhttps://github.com/pypa/hatch/issues/new?body=%23%23+Current+behavior%0A%3C%21--+A+clear+and+concise+description+of+the+behavior.+--%3E%0A%0A%23%23+Expected+behavior%0A%3C%21--+A+clear+and+concise+description+of+what+you+expected+to+happen.+--%3E%0A%0A%23%23+Additional+context%0A%3C%21--+Add+any+other+context+about+the+problem+here.+If+applicable%2C+add+screenshots+to+help+explain.+--%3E%0A%0A%23%23+Debug%0A%0A%23%23%23+Installation%0A%0A-+Source%3A+pip%0A-+Version%3A+1.9.2.dev5%0A-+Platform%3A+Windows%0A-+Python+version%3A%0A++++%60%60%60%0A++++3.11.1+%28tags%2Fv3.11.1%3Aa7a450f%2C+Dec++6+2022%2C+19%3A58%3A39%29+%5BMSC+v.1934+64+bit+%28AMD64%29%5D%0A++++%60%60%60%0A%0A%23%23%23+Configuration%0A%0A%60%60%60toml%0Amode+%3D+%22local%22%0Ashell+%3D+%22nu%22%0A%60%60%60%0A\n
"},{"location":"how-to/plugins/testing-builds/","title":"Testing build plugins","text":"For testing Hatchling plugins, you'll usually want to generate a project to execute builds as a real user would. For example, as a minimal pytest fixture:
from pathlib import Path\n\nimport pytest\n\n\n@pytest.fixture\ndef new_project(tmp_path):\n project_dir = tmp_path / 'my-app'\n project_dir.mkdir()\n\n project_file = project_dir / 'pyproject.toml'\n project_file.write_text(\n f\"\"\"\\\n[build-system]\nrequires = [\"hatchling\", \"hatch-plugin-name @ {Path.cwd().as_uri()}\"]\nbuild-backend = \"hatchling.build\"\n\n[project]\nname = \"my-app\"\nversion = \"0.1.0\"\n\"\"\",\n encoding='utf-8',\n )\n ...\n
The issue with this is that after the first test session, the project will be forever cached by pip based on the file path. Therefore, subsequent tests runs will never use updated code.
To invalidate the cache, copy your code to a new path for every test session:
import shutil\nfrom pathlib import Path\nfrom tempfile import TemporaryDirectory\n\nimport pytest\n\n\n@pytest.fixture(scope='session')\ndef plugin_dir():\n with TemporaryDirectory() as d:\n directory = Path(d, 'plugin')\n shutil.copytree(\n Path.cwd(), directory, ignore=shutil.ignore_patterns('.git')\n )\n\n yield directory.resolve()\n\n\n@pytest.fixture\ndef new_project(tmp_path, plugin_dir):\n project_dir = tmp_path / 'my-app'\n project_dir.mkdir()\n\n project_file = project_dir / 'pyproject.toml'\n project_file.write_text(\n f\"\"\"\\\n[build-system]\nrequires = [\"hatchling\", \"hatch-plugin-name @ {plugin_dir.as_uri()}\"]\nbuild-backend = \"hatchling.build\"\n\n[project]\nname = \"my-app\"\nversion = \"0.1.0\"\n\"\"\",\n encoding='utf-8',\n )\n ...\n
Note
This example chooses to ignore copying .git
for performance reasons. You may want to ignore more patterns, or copy only specific paths like this plugin does.
The username is derived from the following sources, in order of precedence:
--user
/ -u
cli option.HATCH_INDEX_USER
environment variable.repos
tables.~/.pypirc
file.As a fallback the value __token__
is applied.
The password is looked up in these:
~/.pypirc
file if the username was provided by it.--auth
/ -a
cli option.HATCH_INDEX_AUTH
environment variable.repos
tables.If interactively provided credentials were used, the username will be stored in Hatch's cache and the password stored in the available keyring backed credentials stores.
For automated releasing to PyPI, it is recommended to use \"Trusted Publishing\" with OIDC (e.g. PyPA's pypi-publish
GitHub Action) or per-project API tokens.
You can select the repository with which to upload using the -r
/--repo
option or by setting the HATCH_INDEX_REPO
environment variable.
Rather than specifying the full URL of a repository, you can use a named repository from a publish.index.repos
table defined in Hatch's config file:
[publish.index.repos.private]\nurl = \"...\"\n...\n
The following repository names are reserved by Hatch and cannot be overridden:
Name Repositorymain
https://upload.pypi.org/legacy/ test
https://test.pypi.org/legacy/ The main
repository is used by default.
The built-in Python management capabilities offer full support for using custom distributions.
"},{"location":"how-to/python/custom/#configuration","title":"Configuration","text":"Configuring custom Python distributions is done entirely through three environment variables that must all be defined, for each desired distribution. In the following sections, the placeholder <NAME>
is the uppercased version of the distribution name with periods replaced by underscores e.g. pypy3.10
would become PYPY3_10
.
The HATCH_PYTHON_CUSTOM_SOURCE_<NAME>
variable is the URL to the distribution's archive. The value must end with the archive's real file extension, which is used to determine the extraction method.
The following extensions are supported:
Extensions Description.tar.bz2
.bz2
.tar.gz
.tgz
.tar.zst
.tar.zstd
.zip
The HATCH_PYTHON_CUSTOM_PATH_<NAME>
variable is the path to the Python interpreter within the archive. This path is relative to the root of the archive and must be a Unix-style path, even on Windows.
The HATCH_PYTHON_CUSTOM_VERSION_<NAME>
variable is the version of the distribution. This value is used to determine whether updates are required and is displayed in the output of the python show
command.
The run
command supports executing Python scripts with inline metadata, such that a dedicated environment is automatically created with the required dependencies and with the correct version of Python.
A script metadata block is a comment block that starts with # /// script
and ends with # ///
. Every line between those two lines must be a comment line that starts with #
and contains a TOML document when the comment characters are removed.
The top-level fields are:
dependencies
: A list of strings that specifies the runtime dependencies of the script. Each entry must be a valid dependency specifier.requires-python
: A string that specifies the Python version(s) with which the script is compatible. The value of this field must be a valid version specifier.The following is an example of Python script with a valid metadata block:
script.py# /// script\n# requires-python = \">=3.11\"\n# dependencies = [\n# \"httpx\",\n# \"rich\",\n# ]\n# ///\n\nimport httpx\nfrom rich.pretty import pprint\n\nresp = httpx.get(\"https://peps.python.org/api/peps.json\")\ndata = resp.json()\npprint([(k, v[\"title\"]) for k, v in data.items()][:10])\n
Run it directly:
$ hatch run /path/to/script.py\nCreating environment: SyB4bPbL\nChecking dependencies\nSyncing dependencies\n[\n\u2502 ('1', 'PEP Purpose and Guidelines'),\n\u2502 ('2', 'Procedure for Adding New Modules'),\n\u2502 ('3', 'Guidelines for Handling Bug Reports'),\n\u2502 ('4', 'Deprecation of Standard Modules'),\n\u2502 ('5', 'Guidelines for Language Evolution'),\n\u2502 ('6', 'Bug Fix Releases'),\n\u2502 ('7', 'Style Guide for C Code'),\n\u2502 ('8', 'Style Guide for Python Code'),\n\u2502 ('9', 'Sample Plaintext PEP Template'),\n\u2502 ('10', 'Voting Guidelines')\n]\n
notes
You may use the [tool.hatch]
table directly to control the script's environment. For example, if you wanted to disable UV (which is enabled by default for scripts), you could add the following:
# /// script\n# ...\n# [tool.hatch]\n# installer = \"pip\"\n# ///\n
"},{"location":"how-to/static-analysis/behavior/","title":"Customize static analysis behavior","text":"You can fully alter the static analysis performed by the fmt
command by modifying the reserved environment named hatch-static-analysis
. For example, you could define the following if you wanted to replace the default behavior with a mix of Black, isort and basic flake8:
[tool.hatch.envs.hatch-static-analysis]\ndependencies = [\"black\", \"flake8\", \"isort\"]\n\n[tool.hatch.envs.hatch-static-analysis.scripts]\nformat-check = [\n \"black --check --diff {args:.}\",\n \"isort --check-only --diff {args:.}\",\n]\nformat-fix = [\n \"isort {args:.}\",\n \"black {args:.}\",\n]\nlint-check = \"flake8 {args:.}\"\nlint-fix = \"lint-check\"\n
[envs.hatch-static-analysis]\ndependencies = [\"black\", \"flake8\", \"isort\"]\n\n[envs.hatch-static-analysis.scripts]\nformat-check = [\n \"black --check --diff {args:.}\",\n \"isort --check-only --diff {args:.}\",\n]\nformat-fix = [\n \"isort {args:.}\",\n \"black {args:.}\",\n]\nlint-check = \"flake8 {args:.}\"\nlint-fix = \"lint-check\"\n
The format-*
scripts correspond to the --formatter
/-f
flag while the lint-*
scripts correspond to the --linter
/-l
flag. The *-fix
scripts run by default while the *-check
scripts correspond to the --check
flag. Based on this example, the following shows how the various scripts influence behavior:
hatch fmt
flake8 .
isort .
black .
hatch fmt src tests
flake8 src tests
isort src tests
black src tests
hatch fmt -f
isort .
black .
hatch fmt -l
flake8 .
hatch fmt --check
flake8 .
black --check --diff .
isort --check-only --diff .
hatch fmt --check -f
black --check --diff .
isort --check-only --diff .
hatch fmt --check -l
flake8 .
Q: What is the risk of lock-in?
A: Not much! Other than the plugin system, everything uses Python's established standards by default. Project metadata is based entirely on the standard, the build system is compatible with PEP 517/PEP 660, versioning uses the scheme specified by PEP 440, dependencies are defined with PEP 508 strings, and environments use virtualenv.
Q: Must one use all features?
A: No, all features are optional! You can use just the build system, publish wheels and source distributions that were built by other tools, only use the environment management, etc.
"},{"location":"meta/faq/#libraries-vs-applications","title":"Libraries vs applications","text":"Q: Are workflows for both libraries and applications supported?
A: Yes, mostly! Applications can utilize environment management just like libraries, and plugins can be used to build projects in arbitrary formats or publish artifacts to arbitrary destinations.
The only caveat is that currently there is no support for re-creating an environment given a set of dependencies in a reproducible manner. Although a standard lock file format may be far off since PEP 665 was rejected, resolving capabilities are coming to pip. When that is stabilized, Hatch will add locking functionality and dedicated documentation for managing applications.
"},{"location":"meta/faq/#tool-migration","title":"Tool migration","text":"Q: How to migrate to Hatch?
"},{"location":"meta/faq/#build-system","title":"Build system","text":"SetuptoolsHatch setup.py MANIFEST.inimport os\nfrom io import open\n\nfrom setuptools import find_packages, setup\n\nabout = {}\nwith open(os.path.join('src', 'foo', '__about__.py'), 'r', 'utf-8') as f:\n exec(f.read(), about)\n\nwith open('README.md', 'r', 'utf-8') as f:\n readme = f.read()\n\nsetup(\n # Metadata\n name='foo',\n version=about['__version__'],\n description='...',\n long_description=readme,\n long_description_content_type='text/markdown',\n author='...',\n author_email='...',\n project_urls={\n 'Documentation': '...',\n 'Source': '...',\n },\n classifiers=[\n '...',\n ],\n keywords=[\n '...',\n ],\n python_requires='>=3.8',\n install_requires=[\n '...',\n ],\n extras_require={\n 'feature': ['...'],\n },\n\n # Packaging\n packages=find_packages(where='src'),\n package_dir={'': 'src'},\n package_data={\n 'foo': ['py.typed'],\n },\n zip_safe=False,\n entry_points={\n 'console_scripts': [\n 'foo = foo.cli:main',\n ],\n },\n)\n
graft tests\n\nglobal-exclude *.py[cod] __pycache__\n
pyproject.toml [build-system]\nrequires = [\"hatchling\"]\nbuild-backend = \"hatchling.build\"\n\n[project]\nname = \"foo\"\ndescription = \"...\"\nreadme = \"README.md\"\nauthors = [\n { name = \"...\", email = \"...\" },\n]\nclassifiers = [\n \"...\",\n]\nkeywords = [\n \"...\",\n]\nrequires-python = \">=3.8\"\ndependencies = [\n \"...\",\n]\ndynamic = [\"version\"]\n\n[project.urls]\nDocumentation = \"...\"\nSource = \"...\"\n\n[project.optional-dependencies]\nfeature = [\"...\"]\n\n[project.scripts]\nfoo = \"foo.cli:main\"\n\n[tool.hatch.version]\npath = \"src/foo/__about__.py\"\n\n[tool.hatch.build.targets.sdist]\ninclude = [\n \"/src\",\n \"/tests\",\n]\n
"},{"location":"meta/faq/#environments","title":"Environments","text":"ToxHatch Invocation:
tox\n
tox.ini [tox]\nenvlist =\n py{38,39}-{42,3.14}\n py{39,310}-{9000}-{foo,bar}\n\n[testenv]\nusedevelop = true\ndeps =\n coverage[toml]\n pytest\n pytest-cov\n foo: cryptography\ncommands =\n pytest --cov-report=term-missing --cov-config=pyproject.toml --cov=pkg --cov=tests {posargs}\nsetenv =\n 3.14: PRODUCT_VERSION=3.14\n 42: PRODUCT_VERSION=42\n 9000: PRODUCT_VERSION=9000\n {foo,bar}: EXPERIMENTAL=true\n
Invocation:
hatch run test\n
pyproject.toml hatch.toml [tool.hatch.envs.default]\ndependencies = [\n \"coverage[toml]\",\n \"pytest\",\n \"pytest-cov\",\n]\n\n[tool.hatch.envs.default.scripts]\ntest = 'pytest --cov-report=term-missing --cov-config=pyproject.toml --cov=pkg --cov=tests'\n\n[tool.hatch.envs.default.overrides]\nmatrix.version.env-vars = \"PRODUCT_VERSION\"\nmatrix.feature.env-vars = \"EXPERIMENTAL=true\"\nmatrix.feature.dependencies = [\n { value = \"cryptography\", if = [\"foo\"] },\n]\n\n[[tool.hatch.envs.default.matrix]]\npython = [\"3.8\", \"3.9\"]\nversion = [\"42\", \"3.14\"]\n\n[[tool.hatch.envs.default.matrix]]\npython = [\"3.9\", \"3.10\"]\nversion = [\"9000\"]\nfeature = [\"foo\", \"bar\"]\n
[envs.default]\ndependencies = [\n \"coverage[toml]\",\n \"pytest\",\n \"pytest-cov\",\n]\n\n[envs.default.scripts]\ntest = 'pytest --cov-report=term-missing --cov-config=pyproject.toml --cov=pkg --cov=tests'\n\n[envs.default.overrides]\nmatrix.version.env-vars = \"PRODUCT_VERSION\"\nmatrix.feature.env-vars = \"EXPERIMENTAL=true\"\nmatrix.feature.dependencies = [\n { value = \"cryptography\", if = [\"foo\"] },\n]\n\n[[envs.default.matrix]]\npython = [\"3.8\", \"3.9\"]\nversion = [\"42\", \"3.14\"]\n\n[[envs.default.matrix]]\npython = [\"3.9\", \"3.10\"]\nversion = [\"9000\"]\nfeature = [\"foo\", \"bar\"]\n
"},{"location":"meta/faq/#fast-cli","title":"Fast CLI?","text":"The claim about being faster than other tools is based on timings that are always checked in CI.
Hatch achieves this by using lazy imports, lazily performing computation manually and with functools.cached_property, using hacks like not not ...
instead of bool(...)
, etc.
Hatch utilizes pluggy for its plugin functionality.
"},{"location":"plugins/about/#overview","title":"Overview","text":"All plugins provide registration hooks that return one or more classes that inherit from a particular type interface.
Each registration hook must be decorated by Hatch's hook marker. For example, if you wanted to create a new kind of environment you could do:
hooks.pyfrom hatchling.plugin import hookimpl\n\nfrom .plugin import SpecialEnvironment\n\n\n@hookimpl\ndef hatch_register_environment():\n return SpecialEnvironment\n
The hooks can return a single class or a list of classes.
Every class must define an attribute called PLUGIN_NAME
that users will select when they wish to use the plugin. So in the example above, the class might be defined like:
...\nclass SpecialEnvironment(...):\n PLUGIN_NAME = 'special'\n ...\n
"},{"location":"plugins/about/#project-configuration","title":"Project configuration","text":""},{"location":"plugins/about/#naming","title":"Naming","text":"It is recommended that plugin project names are prefixed with hatch-
. For example, if you wanted to make a plugin that provides some functionality for a product named foo
you might do:
[project]\nname = \"hatch-foo\"\n
"},{"location":"plugins/about/#discovery","title":"Discovery","text":"You'll need to define your project as a Python plugin for Hatch:
pyproject.toml[project.entry-points.hatch]\nfoo = \"pkg.hooks\"\n
The name of the plugin should be the project name (excluding any hatch-
prefix) and the path should represent the module that contains the registration hooks.
Add Framework :: Hatch
to your project's classifiers to make it easy to search for Hatch plugins:
[project]\nclassifiers = [\n ...\n \"Framework :: Hatch\",\n ...\n]\n
"},{"location":"plugins/about/#types","title":"Types","text":""},{"location":"plugins/about/#hatchling","title":"Hatchling","text":"These are all involved in building projects and therefore any defined dependencies are automatically installed in each build environment.
These must be installed in the same environment as Hatch itself.
hatchling.builders.utils.get_reproducible_timestamp() -> int
","text":"Returns an int
derived from the SOURCE_DATE_EPOCH
environment variable; see https://reproducible-builds.org/specs/source-date-epoch/.
The default value will always be: 1580601600
backend/src/hatchling/builders/utils.py
def get_reproducible_timestamp() -> int:\n \"\"\"\n Returns an `int` derived from the `SOURCE_DATE_EPOCH` environment variable; see\n https://reproducible-builds.org/specs/source-date-epoch/.\n\n The default value will always be: `1580601600`\n \"\"\"\n return int(os.environ.get('SOURCE_DATE_EPOCH', '1580601600'))\n
"},{"location":"plugins/utilities/#hatchling.builders.config.BuilderConfig","title":"BuilderConfig
","text":""},{"location":"plugins/utilities/#hatchling.builders.config.BuilderConfig.directory","title":"directory: str
property
","text":""},{"location":"plugins/utilities/#hatchling.builders.config.BuilderConfig.ignore_vcs","title":"ignore_vcs: bool
property
","text":""},{"location":"plugins/utilities/#hatchling.builders.config.BuilderConfig.reproducible","title":"reproducible: bool
property
","text":"Whether or not the target should be built in a reproducible manner, defaulting to true.
"},{"location":"plugins/utilities/#hatchling.builders.config.BuilderConfig.dev_mode_dirs","title":"dev_mode_dirs: list[str]
property
","text":"Directories which must be added to Python's search path in dev mode.
"},{"location":"plugins/utilities/#hatchling.builders.config.BuilderConfig.versions","title":"versions: list[str]
property
","text":""},{"location":"plugins/utilities/#hatchling.builders.config.BuilderConfig.dependencies","title":"dependencies: list[str]
property
","text":""},{"location":"plugins/utilities/#hatchling.builders.config.BuilderConfig.default_include","title":"default_include() -> list
","text":""},{"location":"plugins/utilities/#hatchling.builders.config.BuilderConfig.default_exclude","title":"default_exclude() -> list
","text":""},{"location":"plugins/utilities/#hatchling.builders.config.BuilderConfig.default_packages","title":"default_packages() -> list
","text":""},{"location":"plugins/utilities/#hatchling.builders.config.BuilderConfig.default_only_include","title":"default_only_include() -> list
","text":""},{"location":"plugins/utilities/#hatchling.bridge.app.Application","title":"Application
","text":"The way output is displayed can be configured by users.
Important
Never import this directly; Hatch judiciously decides if a type of plugin requires the capabilities herein and will grant access via an attribute.
"},{"location":"plugins/utilities/#hatchling.bridge.app.Application.verbosity","title":"verbosity: int
property
","text":"The verbosity level of the application, with 0 as the default.
"},{"location":"plugins/utilities/#hatchling.bridge.app.Application.abort","title":"abort(message: str = '', code: int = 1, **kwargs: Any) -> None
","text":"Terminate the program with the given return code.
"},{"location":"plugins/utilities/#hatchling.bridge.app.Application.display_debug","title":"display_debug(message: str = '', level: int = 1, **kwargs: Any) -> None
","text":"Meant to be used for messages that are not useful for most user experiences. The level
option must be between 1 and 3 (inclusive).
display_error(message: str = '', **kwargs: Any) -> None
","text":"Meant to be used for messages indicating some unrecoverable error.
"},{"location":"plugins/utilities/#hatchling.bridge.app.Application.display_info","title":"display_info(message: str = '', **kwargs: Any) -> None
","text":"Meant to be used for messages conveying basic information.
"},{"location":"plugins/utilities/#hatchling.bridge.app.Application.display_success","title":"display_success(message: str = '', **kwargs: Any) -> None
","text":"Meant to be used for messages indicating some positive outcome.
"},{"location":"plugins/utilities/#hatchling.bridge.app.Application.display_waiting","title":"display_waiting(message: str = '', **kwargs: Any) -> None
","text":"Meant to be used for messages shown before potentially time consuming operations.
"},{"location":"plugins/utilities/#hatchling.bridge.app.Application.display_warning","title":"display_warning(message: str = '', **kwargs: Any) -> None
","text":"Meant to be used for messages conveying important information.
"},{"location":"plugins/utilities/#hatch.utils.platform.Platform","title":"Platform
","text":""},{"location":"plugins/utilities/#hatch.utils.platform.Platform.default_shell","title":"default_shell: str
property
","text":"Returns the default shell of the system.
On Windows systems first try the SHELL
environment variable, if present, followed by the COMSPEC
environment variable, defaulting to cmd
. On all other platforms only the SHELL
environment variable will be used, defaulting to bash
.
modules: LazilyLoadedModules
property
","text":"Accessor for lazily loading modules that either take multiple milliseconds to import (like shutil
and subprocess
) or are not used on all platforms (like shlex
).
home: Path
property
","text":"The user's home directory as a path-like object.
"},{"location":"plugins/utilities/#hatch.utils.platform.Platform.name","title":"name: str
property
","text":"One of the following:
linux
windows
macos
display_name: str
property
","text":"One of the following:
Linux
Windows
macOS
windows: bool
property
","text":"Indicates whether Hatch is running on Windows.
"},{"location":"plugins/utilities/#hatch.utils.platform.Platform.macos","title":"macos: bool
property
","text":"Indicates whether Hatch is running on macOS.
"},{"location":"plugins/utilities/#hatch.utils.platform.Platform.linux","title":"linux: bool
property
","text":"Indicates whether Hatch is running on neither Windows nor macOS.
"},{"location":"plugins/utilities/#hatch.utils.platform.Platform.format_for_subprocess","title":"format_for_subprocess(command: str | list[str], *, shell: bool) -> str | list[str]
","text":"Format the given command in a cross-platform manner for immediate consumption by subprocess utilities.
"},{"location":"plugins/utilities/#hatch.utils.platform.Platform.run_command","title":"run_command(command: str | list[str], *, shell: bool = False, **kwargs: Any) -> CompletedProcess
","text":"Equivalent to the standard library's subprocess.run, with the command first being properly formatted.
"},{"location":"plugins/utilities/#hatch.utils.platform.Platform.check_command","title":"check_command(command: str | list[str], *, shell: bool = False, **kwargs: Any) -> CompletedProcess
","text":"Equivalent to run_command, but non-zero exit codes will gracefully end program execution.
"},{"location":"plugins/utilities/#hatch.utils.platform.Platform.check_command_output","title":"check_command_output(command: str | list[str], *, shell: bool = False, **kwargs: Any) -> str
","text":"Equivalent to the output from the process returned by capture_process, but non-zero exit codes will gracefully end program execution.
"},{"location":"plugins/utilities/#hatch.utils.platform.Platform.capture_process","title":"capture_process(command: str | list[str], *, shell: bool = False, **kwargs: Any) -> Popen
","text":"Equivalent to the standard library's subprocess.Popen, with all output captured by stdout
and the command first being properly formatted.
exit_with_command(command: list[str]) -> None
","text":"Run the given command and exit with its exit code. On non-Windows systems, this uses the standard library's os.execvp.
"},{"location":"plugins/utilities/#hatch.env.context.EnvironmentContextFormatter","title":"EnvironmentContextFormatter
","text":""},{"location":"plugins/utilities/#hatch.env.context.EnvironmentContextFormatter.formatters","title":"formatters()
","text":"This returns a mapping of supported field names to their respective formatting functions. Each function accepts 2 arguments:
value
that was passed to the format call, defaulting to None
data
, defaulting to an empty stringFileSystemContext
","text":"This class represents a synchronized path between the local file system and a potentially remote environment.
"},{"location":"plugins/utilities/#hatch.env.plugin.interface.FileSystemContext.env","title":"env: EnvironmentInterface
property
","text":"Returns the environment to which this context belongs.
"},{"location":"plugins/utilities/#hatch.env.plugin.interface.FileSystemContext.local_path","title":"local_path: Path
property
","text":"Returns the local path to which this context refers as a path-like object.
"},{"location":"plugins/utilities/#hatch.env.plugin.interface.FileSystemContext.env_path","title":"env_path: str
property
","text":"Returns the environment path to which this context refers as a string. The environment may not be on the local file system.
"},{"location":"plugins/utilities/#hatch.env.plugin.interface.FileSystemContext.sync_local","title":"sync_local()
","text":"Synchronizes the local path as the source with the environment path as the source.
"},{"location":"plugins/utilities/#hatch.env.plugin.interface.FileSystemContext.sync_env","title":"sync_env()
","text":"Synchronizes the environment path with the local path as the source.
"},{"location":"plugins/utilities/#hatch.env.plugin.interface.FileSystemContext.join","title":"join(relative_path: str) -> FileSystemContext
","text":"Returns a new instance of this class with the given relative path appended to the local and environment paths.
This method should not need overwriting.
"},{"location":"plugins/build-hook/custom/","title":"Custom build hook","text":"This is a custom class in a given Python file that inherits from the BuildHookInterface.
"},{"location":"plugins/build-hook/custom/#configuration","title":"Configuration","text":"The build hook plugin name is custom
.
[tool.hatch.build.hooks.custom]\n[tool.hatch.build.targets.<TARGET_NAME>.hooks.custom]\n
[build.hooks.custom]\n[build.targets.<TARGET_NAME>.hooks.custom]\n
"},{"location":"plugins/build-hook/custom/#options","title":"Options","text":"Option Default Description path
hatch_build.py
The path of the Python file"},{"location":"plugins/build-hook/custom/#example","title":"Example","text":"hatch_build.py from hatchling.builders.hooks.plugin.interface import BuildHookInterface\n\n\nclass CustomBuildHook(BuildHookInterface):\n ...\n
If multiple subclasses are found, you must define a function named get_build_hook
that returns the desired build hook.
Note
Any defined PLUGIN_NAME is ignored and will always be custom
.
A build hook provides code that will be executed at various stages of the build process. See the documentation for build hook configuration.
"},{"location":"plugins/build-hook/reference/#known-third-party","title":"Known third-party","text":"gettext
toolsBuild hooks run for every selected version of build targets.
The initialization stage occurs immediately before each build and the finalization stage occurs immediately after. Each stage has the opportunity to view or modify build data.
"},{"location":"plugins/build-hook/reference/#build-data","title":"Build data","text":"Build data is a simple mapping whose contents can influence the behavior of builds. Which fields exist and are recognized depends on each build target.
The following fields are always present and recognized by the build system itself:
Field Type Descriptionartifacts
list[str]
This is a list of extra artifact
patterns and should generally only be appended to force_include
dict[str, str]
This is a mapping of extra forced inclusion paths, with this mapping taking precedence in case of conflicts build_hooks
tuple[str, ...]
This is an immutable sequence of the names of the configured build hooks and matches the order in which they run Attention
While user-facing TOML options are hyphenated, build data fields should be named with underscores to allow plugins to use them as valid Python identifiers.
"},{"location":"plugins/build-hook/reference/#notes","title":"Notes","text":"In some cases it may be necessary to use force_include
rather than artifacts
. For example, say that you want to install a lib.so
directly at the root of site-packages
and a project defines a package src/foo
. If you create src/lib.so
, there will never be a match because the directory traversal starts at src/foo
rather than src
. In that case you must do either:
build_data['force_include']['src/lib.so'] = 'src/lib.so'\n
or
build_data['force_include']['/absolute/path/to/src/lib.so'] = 'src/lib.so'\n
"},{"location":"plugins/build-hook/reference/#hatchling.builders.hooks.plugin.interface.BuildHookInterface","title":"BuildHookInterface
","text":"Example usage:
plugin.py hooks.pyfrom hatchling.builders.hooks.plugin.interface import BuildHookInterface\n\n\nclass SpecialBuildHook(BuildHookInterface):\n PLUGIN_NAME = 'special'\n ...\n
from hatchling.plugin import hookimpl\n\nfrom .plugin import SpecialBuildHook\n\n\n@hookimpl\ndef hatch_register_build_hook():\n return SpecialBuildHook\n
Source code in backend/src/hatchling/builders/hooks/plugin/interface.py
class BuildHookInterface(Generic[BuilderConfigBound]): # no cov\n \"\"\"\n Example usage:\n\n ```python tab=\"plugin.py\"\n from hatchling.builders.hooks.plugin.interface import BuildHookInterface\n\n\n class SpecialBuildHook(BuildHookInterface):\n PLUGIN_NAME = 'special'\n ...\n ```\n\n ```python tab=\"hooks.py\"\n from hatchling.plugin import hookimpl\n\n from .plugin import SpecialBuildHook\n\n\n @hookimpl\n def hatch_register_build_hook():\n return SpecialBuildHook\n ```\n \"\"\"\n\n PLUGIN_NAME = ''\n \"\"\"The name used for selection.\"\"\"\n\n def __init__(\n self,\n root: str,\n config: dict[str, Any],\n build_config: BuilderConfigBound,\n metadata: ProjectMetadata,\n directory: str,\n target_name: str,\n app: Application | None = None,\n ) -> None:\n self.__root = root\n self.__config = config\n self.__build_config = build_config\n self.__metadata = metadata\n self.__directory = directory\n self.__target_name = target_name\n self.__app = app\n\n @property\n def app(self) -> Application:\n \"\"\"\n An instance of [Application](../utilities.md#hatchling.bridge.app.Application).\n \"\"\"\n if self.__app is None:\n from hatchling.bridge.app import Application\n\n self.__app = cast(Application, Application().get_safe_application())\n\n return self.__app\n\n @property\n def root(self) -> str:\n \"\"\"\n The root of the project tree.\n \"\"\"\n return self.__root\n\n @property\n def config(self) -> dict[str, Any]:\n \"\"\"\n The cumulative hook configuration.\n\n ```toml config-example\n [tool.hatch.build.hooks.<PLUGIN_NAME>]\n [tool.hatch.build.targets.<TARGET_NAME>.hooks.<PLUGIN_NAME>]\n ```\n \"\"\"\n return self.__config\n\n @property\n def metadata(self) -> ProjectMetadata:\n # Undocumented for now\n return self.__metadata\n\n @property\n def build_config(self) -> BuilderConfigBound:\n \"\"\"\n An instance of [BuilderConfig](../utilities.md#hatchling.builders.config.BuilderConfig).\n \"\"\"\n return self.__build_config\n\n @property\n def directory(self) -> str:\n \"\"\"\n The build directory.\n \"\"\"\n return self.__directory\n\n @property\n def target_name(self) -> str:\n \"\"\"\n The plugin name of the build target.\n \"\"\"\n return self.__target_name\n\n def dependencies(self) -> list[str]: # noqa: PLR6301\n \"\"\"\n A list of extra [dependencies](../../config/dependency.md) that must be installed\n prior to builds.\n\n !!! warning\n - For this to have any effect the hook dependency itself cannot be dynamic and\n must always be defined in `build-system.requires`.\n - As the hook must be imported to call this method, imports that require these\n dependencies must be evaluated lazily.\n \"\"\"\n return []\n\n def clean(self, versions: list[str]) -> None:\n \"\"\"\n This occurs before the build process if the `-c`/`--clean` flag was passed to\n the [`build`](../../cli/reference.md#hatch-build) command, or when invoking\n the [`clean`](../../cli/reference.md#hatch-clean) command.\n \"\"\"\n\n def initialize(self, version: str, build_data: dict[str, Any]) -> None:\n \"\"\"\n This occurs immediately before each build.\n\n Any modifications to the build data will be seen by the build target.\n \"\"\"\n\n def finalize(self, version: str, build_data: dict[str, Any], artifact_path: str) -> None:\n \"\"\"\n This occurs immediately after each build and will not run if the `--hooks-only` flag\n was passed to the [`build`](../../cli/reference.md#hatch-build) command.\n\n The build data will reflect any modifications done by the target during the build.\n \"\"\"\n
"},{"location":"plugins/build-hook/reference/#hatchling.builders.hooks.plugin.interface.BuildHookInterface.PLUGIN_NAME","title":"PLUGIN_NAME = ''
class-attribute
instance-attribute
","text":"The name used for selection.
"},{"location":"plugins/build-hook/reference/#hatchling.builders.hooks.plugin.interface.BuildHookInterface.app","title":"app: Application
property
","text":"An instance of Application.
"},{"location":"plugins/build-hook/reference/#hatchling.builders.hooks.plugin.interface.BuildHookInterface.root","title":"root: str
property
","text":"The root of the project tree.
"},{"location":"plugins/build-hook/reference/#hatchling.builders.hooks.plugin.interface.BuildHookInterface.config","title":"config: dict[str, Any]
property
","text":"The cumulative hook configuration.
pyproject.toml hatch.toml[tool.hatch.build.hooks.<PLUGIN_NAME>]\n[tool.hatch.build.targets.<TARGET_NAME>.hooks.<PLUGIN_NAME>]\n
[build.hooks.<PLUGIN_NAME>]\n[build.targets.<TARGET_NAME>.hooks.<PLUGIN_NAME>]\n
"},{"location":"plugins/build-hook/reference/#hatchling.builders.hooks.plugin.interface.BuildHookInterface.build_config","title":"build_config: BuilderConfigBound
property
","text":"An instance of BuilderConfig.
"},{"location":"plugins/build-hook/reference/#hatchling.builders.hooks.plugin.interface.BuildHookInterface.target_name","title":"target_name: str
property
","text":"The plugin name of the build target.
"},{"location":"plugins/build-hook/reference/#hatchling.builders.hooks.plugin.interface.BuildHookInterface.directory","title":"directory: str
property
","text":"The build directory.
"},{"location":"plugins/build-hook/reference/#hatchling.builders.hooks.plugin.interface.BuildHookInterface.dependencies","title":"dependencies() -> list[str]
","text":"A list of extra dependencies that must be installed prior to builds.
Warning
build-system.requires
.backend/src/hatchling/builders/hooks/plugin/interface.py
def dependencies(self) -> list[str]: # noqa: PLR6301\n \"\"\"\n A list of extra [dependencies](../../config/dependency.md) that must be installed\n prior to builds.\n\n !!! warning\n - For this to have any effect the hook dependency itself cannot be dynamic and\n must always be defined in `build-system.requires`.\n - As the hook must be imported to call this method, imports that require these\n dependencies must be evaluated lazily.\n \"\"\"\n return []\n
"},{"location":"plugins/build-hook/reference/#hatchling.builders.hooks.plugin.interface.BuildHookInterface.clean","title":"clean(versions: list[str]) -> None
","text":"This occurs before the build process if the -c
/--clean
flag was passed to the build
command, or when invoking the clean
command.
backend/src/hatchling/builders/hooks/plugin/interface.py
def clean(self, versions: list[str]) -> None:\n \"\"\"\n This occurs before the build process if the `-c`/`--clean` flag was passed to\n the [`build`](../../cli/reference.md#hatch-build) command, or when invoking\n the [`clean`](../../cli/reference.md#hatch-clean) command.\n \"\"\"\n
"},{"location":"plugins/build-hook/reference/#hatchling.builders.hooks.plugin.interface.BuildHookInterface.initialize","title":"initialize(version: str, build_data: dict[str, Any]) -> None
","text":"This occurs immediately before each build.
Any modifications to the build data will be seen by the build target.
Source code inbackend/src/hatchling/builders/hooks/plugin/interface.py
def initialize(self, version: str, build_data: dict[str, Any]) -> None:\n \"\"\"\n This occurs immediately before each build.\n\n Any modifications to the build data will be seen by the build target.\n \"\"\"\n
"},{"location":"plugins/build-hook/reference/#hatchling.builders.hooks.plugin.interface.BuildHookInterface.finalize","title":"finalize(version: str, build_data: dict[str, Any], artifact_path: str) -> None
","text":"This occurs immediately after each build and will not run if the --hooks-only
flag was passed to the build
command.
The build data will reflect any modifications done by the target during the build.
Source code inbackend/src/hatchling/builders/hooks/plugin/interface.py
def finalize(self, version: str, build_data: dict[str, Any], artifact_path: str) -> None:\n \"\"\"\n This occurs immediately after each build and will not run if the `--hooks-only` flag\n was passed to the [`build`](../../cli/reference.md#hatch-build) command.\n\n The build data will reflect any modifications done by the target during the build.\n \"\"\"\n
"},{"location":"plugins/build-hook/version/","title":"Version build hook","text":"This writes the project's version to a file.
"},{"location":"plugins/build-hook/version/#configuration","title":"Configuration","text":"The build hook plugin name is version
.
[tool.hatch.build.hooks.version]\n[tool.hatch.build.targets.<TARGET_NAME>.hooks.version]\n
[build.hooks.version]\n[build.targets.<TARGET_NAME>.hooks.version]\n
"},{"location":"plugins/build-hook/version/#options","title":"Options","text":"Option Description path
(required) A relative path to the desired file template
A string representing the entire contents of path
that will be formatted with a version
variable pattern
Rather than updating the entire file, a regular expression may be used that has a named group called version
that represents the version. If set to true
, a pattern will be used that looks for a variable named __version__
or VERSION
that is set to a string containing the version, optionally prefixed with the lowercase letter v
."},{"location":"plugins/builder/binary/","title":"Binary builder","text":"This uses PyApp to build an application that is able to bootstrap itself at runtime.
Note
This requires an installation of Rust.
"},{"location":"plugins/builder/binary/#configuration","title":"Configuration","text":"The builder plugin name is binary
.
[tool.hatch.build.targets.binary]\n
[build.targets.binary]\n
"},{"location":"plugins/builder/binary/#options","title":"Options","text":"Option Default Description scripts
all defined An array of defined script names to limit what gets built python-version
latest compatible Python minor version The Python version ID to use pyapp-version
The version of PyApp to use"},{"location":"plugins/builder/binary/#build-behavior","title":"Build behavior","text":"If any scripts are defined then each one will be built (limited by the scripts
option). Otherwise, a single executable will be built based on the project name assuming there is an equivalently named module with a __main__.py
file.
Every executable will be built inside an app
directory in the output directory.
If the CARGO
environment variable is set then that path will be used as the executable for performing builds.
If the CARGO_BUILD_TARGET
environment variable is set then its value will be appended to the file name stems.
If the PYAPP_REPO
environment variable is set then a local build will be performed inside that directory rather than installing from crates.io. Note that this is required if the CARGO
environment variable refers to cross.
This is a custom class in a given Python file that inherits from the BuilderInterface.
"},{"location":"plugins/builder/custom/#configuration","title":"Configuration","text":"The builder plugin name is custom
.
[tool.hatch.build.targets.custom]\n
[build.targets.custom]\n
"},{"location":"plugins/builder/custom/#options","title":"Options","text":"Option Default Description path
hatch_build.py
The path of the Python file"},{"location":"plugins/builder/custom/#example","title":"Example","text":"hatch_build.py from hatchling.builders.plugin.interface import BuilderInterface\n\n\nclass CustomBuilder(BuilderInterface):\n ...\n
If multiple subclasses are found, you must define a function named get_builder
that returns the desired builder.
Note
Any defined PLUGIN_NAME is ignored and will always be custom
.
See the documentation for build configuration.
"},{"location":"plugins/builder/reference/#known-third-party","title":"Known third-party","text":"BuilderInterface
","text":"Example usage:
plugin.py hooks.pyfrom hatchling.builders.plugin.interface import BuilderInterface\n\n\nclass SpecialBuilder(BuilderInterface):\n PLUGIN_NAME = 'special'\n ...\n
from hatchling.plugin import hookimpl\n\nfrom .plugin import SpecialBuilder\n\n\n@hookimpl\ndef hatch_register_builder():\n return SpecialBuilder\n
Source code in backend/src/hatchling/builders/plugin/interface.py
class BuilderInterface(ABC, Generic[BuilderConfigBound, PluginManagerBound]):\n \"\"\"\n Example usage:\n\n ```python tab=\"plugin.py\"\n from hatchling.builders.plugin.interface import BuilderInterface\n\n\n class SpecialBuilder(BuilderInterface):\n PLUGIN_NAME = 'special'\n ...\n ```\n\n ```python tab=\"hooks.py\"\n from hatchling.plugin import hookimpl\n\n from .plugin import SpecialBuilder\n\n\n @hookimpl\n def hatch_register_builder():\n return SpecialBuilder\n ```\n \"\"\"\n\n PLUGIN_NAME = ''\n \"\"\"The name used for selection.\"\"\"\n\n def __init__(\n self,\n root: str,\n plugin_manager: PluginManagerBound | None = None,\n config: dict[str, Any] | None = None,\n metadata: ProjectMetadata | None = None,\n app: Application | None = None,\n ) -> None:\n self.__root = root\n self.__plugin_manager = cast(PluginManagerBound, plugin_manager)\n self.__raw_config = config\n self.__metadata = metadata\n self.__app = app\n self.__config = cast(BuilderConfigBound, None)\n self.__project_config: dict[str, Any] | None = None\n self.__hatch_config: dict[str, Any] | None = None\n self.__build_config: dict[str, Any] | None = None\n self.__build_targets: list[str] | None = None\n self.__target_config: dict[str, Any] | None = None\n\n # Metadata\n self.__project_id: str | None = None\n\n def build(\n self,\n *,\n directory: str | None = None,\n versions: list[str] | None = None,\n hooks_only: bool | None = None,\n clean: bool | None = None,\n clean_hooks_after: bool | None = None,\n clean_only: bool | None = False,\n ) -> Generator[str, None, None]:\n # Fail early for invalid project metadata\n self.metadata.validate_fields()\n\n if directory is None:\n directory = (\n self.config.normalize_build_directory(os.environ[BuildEnvVars.LOCATION])\n if BuildEnvVars.LOCATION in os.environ\n else self.config.directory\n )\n\n if not os.path.isdir(directory):\n os.makedirs(directory)\n\n version_api = self.get_version_api()\n\n versions = versions or self.config.versions\n if versions:\n unknown_versions = set(versions) - set(version_api)\n if unknown_versions:\n message = (\n f'Unknown versions for target `{self.PLUGIN_NAME}`: {\", \".join(map(str, sorted(unknown_versions)))}'\n )\n raise ValueError(message)\n\n if hooks_only is None:\n hooks_only = env_var_enabled(BuildEnvVars.HOOKS_ONLY)\n\n configured_build_hooks = self.get_build_hooks(directory)\n build_hooks = list(configured_build_hooks.values())\n\n if clean_only:\n clean = True\n elif clean is None:\n clean = env_var_enabled(BuildEnvVars.CLEAN)\n if clean:\n if not hooks_only:\n self.clean(directory, versions)\n\n for build_hook in build_hooks:\n build_hook.clean(versions)\n\n if clean_only:\n return\n\n if clean_hooks_after is None:\n clean_hooks_after = env_var_enabled(BuildEnvVars.CLEAN_HOOKS_AFTER)\n\n for version in versions:\n self.app.display_debug(f'Building `{self.PLUGIN_NAME}` version `{version}`')\n\n build_data = self.get_default_build_data()\n self.set_build_data_defaults(build_data)\n\n # Allow inspection of configured build hooks and the order in which they run\n build_data['build_hooks'] = tuple(configured_build_hooks)\n\n # Execute all `initialize` build hooks\n for build_hook in build_hooks:\n build_hook.initialize(version, build_data)\n\n if hooks_only:\n self.app.display_debug(f'Only ran build hooks for `{self.PLUGIN_NAME}` version `{version}`')\n continue\n\n # Build the artifact\n with self.config.set_build_data(build_data):\n artifact = version_api[version](directory, **build_data)\n\n # Execute all `finalize` build hooks\n for build_hook in build_hooks:\n build_hook.finalize(version, build_data, artifact)\n\n if clean_hooks_after:\n for build_hook in build_hooks:\n build_hook.clean([version])\n\n yield artifact\n\n def recurse_included_files(self) -> Iterable[IncludedFile]:\n \"\"\"\n Returns a consistently generated series of file objects for every file that should be distributed. Each file\n object has three `str` attributes:\n\n - `path` - the absolute path\n - `relative_path` - the path relative to the project root; will be an empty string for external files\n - `distribution_path` - the path to be distributed as\n \"\"\"\n yield from self.recurse_selected_project_files()\n yield from self.recurse_forced_files(self.config.get_force_include())\n\n def recurse_selected_project_files(self) -> Iterable[IncludedFile]:\n if self.config.only_include:\n yield from self.recurse_explicit_files(self.config.only_include)\n else:\n yield from self.recurse_project_files()\n\n def recurse_project_files(self) -> Iterable[IncludedFile]:\n for root, dirs, files in safe_walk(self.root):\n relative_path = get_relative_path(root, self.root)\n\n dirs[:] = sorted(d for d in dirs if not self.config.directory_is_excluded(d, relative_path))\n\n files.sort()\n is_package = '__init__.py' in files\n for f in files:\n if f in EXCLUDED_FILES:\n continue\n\n relative_file_path = os.path.join(relative_path, f)\n distribution_path = self.config.get_distribution_path(relative_file_path)\n if self.config.path_is_reserved(distribution_path):\n continue\n\n if self.config.include_path(relative_file_path, is_package=is_package):\n yield IncludedFile(\n os.path.join(root, f), relative_file_path, self.config.get_distribution_path(relative_file_path)\n )\n\n def recurse_forced_files(self, inclusion_map: dict[str, str]) -> Iterable[IncludedFile]:\n for source, target_path in inclusion_map.items():\n external = not source.startswith(self.root)\n if os.path.isfile(source):\n yield IncludedFile(\n source,\n '' if external else os.path.relpath(source, self.root),\n self.config.get_distribution_path(target_path),\n )\n elif os.path.isdir(source):\n for root, dirs, files in safe_walk(source):\n relative_directory = get_relative_path(root, source)\n\n dirs[:] = sorted(d for d in dirs if d not in EXCLUDED_DIRECTORIES)\n\n files.sort()\n for f in files:\n if f in EXCLUDED_FILES:\n continue\n\n relative_file_path = os.path.join(target_path, relative_directory, f)\n distribution_path = self.config.get_distribution_path(relative_file_path)\n if not self.config.path_is_reserved(distribution_path):\n yield IncludedFile(\n os.path.join(root, f),\n '' if external else relative_file_path,\n distribution_path,\n )\n else:\n msg = f'Forced include not found: {source}'\n raise FileNotFoundError(msg)\n\n def recurse_explicit_files(self, inclusion_map: dict[str, str]) -> Iterable[IncludedFile]:\n for source, target_path in inclusion_map.items():\n external = not source.startswith(self.root)\n if os.path.isfile(source):\n distribution_path = self.config.get_distribution_path(target_path)\n if not self.config.path_is_reserved(distribution_path):\n yield IncludedFile(\n source,\n '' if external else os.path.relpath(source, self.root),\n self.config.get_distribution_path(target_path),\n )\n elif os.path.isdir(source):\n for root, dirs, files in safe_walk(source):\n relative_directory = get_relative_path(root, source)\n\n dirs[:] = sorted(d for d in dirs if d not in EXCLUDED_DIRECTORIES)\n\n files.sort()\n is_package = '__init__.py' in files\n for f in files:\n if f in EXCLUDED_FILES:\n continue\n\n relative_file_path = os.path.join(target_path, relative_directory, f)\n distribution_path = self.config.get_distribution_path(relative_file_path)\n if self.config.path_is_reserved(distribution_path):\n continue\n\n if self.config.include_path(relative_file_path, explicit=True, is_package=is_package):\n yield IncludedFile(\n os.path.join(root, f), '' if external else relative_file_path, distribution_path\n )\n\n @property\n def root(self) -> str:\n \"\"\"\n The root of the project tree.\n \"\"\"\n return self.__root\n\n @property\n def plugin_manager(self) -> PluginManagerBound:\n if self.__plugin_manager is None:\n from hatchling.plugin.manager import PluginManager\n\n self.__plugin_manager = PluginManager()\n\n return self.__plugin_manager\n\n @property\n def metadata(self) -> ProjectMetadata:\n if self.__metadata is None:\n from hatchling.metadata.core import ProjectMetadata\n\n self.__metadata = ProjectMetadata(self.root, self.plugin_manager, self.__raw_config)\n\n return self.__metadata\n\n @property\n def app(self) -> Application:\n \"\"\"\n An instance of [Application](../utilities.md#hatchling.bridge.app.Application).\n \"\"\"\n if self.__app is None:\n from hatchling.bridge.app import Application\n\n self.__app = cast(Application, Application().get_safe_application())\n\n return self.__app\n\n @property\n def raw_config(self) -> dict[str, Any]:\n if self.__raw_config is None:\n self.__raw_config = self.metadata.config\n\n return self.__raw_config\n\n @property\n def project_config(self) -> dict[str, Any]:\n if self.__project_config is None:\n self.__project_config = self.metadata.core.config\n\n return self.__project_config\n\n @property\n def hatch_config(self) -> dict[str, Any]:\n if self.__hatch_config is None:\n self.__hatch_config = self.metadata.hatch.config\n\n return self.__hatch_config\n\n @property\n def config(self) -> BuilderConfigBound:\n \"\"\"\n An instance of [BuilderConfig](../utilities.md#hatchling.builders.config.BuilderConfig).\n \"\"\"\n if self.__config is None:\n self.__config = self.get_config_class()(\n self, self.root, self.PLUGIN_NAME, self.build_config, self.target_config\n )\n\n return self.__config\n\n @property\n def build_config(self) -> dict[str, Any]:\n \"\"\"\n ```toml config-example\n [tool.hatch.build]\n ```\n \"\"\"\n if self.__build_config is None:\n self.__build_config = self.metadata.hatch.build_config\n\n return self.__build_config\n\n @property\n def target_config(self) -> dict[str, Any]:\n \"\"\"\n ```toml config-example\n [tool.hatch.build.targets.<PLUGIN_NAME>]\n ```\n \"\"\"\n if self.__target_config is None:\n target_config: dict[str, Any] = self.metadata.hatch.build_targets.get(self.PLUGIN_NAME, {})\n if not isinstance(target_config, dict):\n message = f'Field `tool.hatch.build.targets.{self.PLUGIN_NAME}` must be a table'\n raise TypeError(message)\n\n self.__target_config = target_config\n\n return self.__target_config\n\n @property\n def project_id(self) -> str:\n if self.__project_id is None:\n self.__project_id = f'{self.normalize_file_name_component(self.metadata.core.name)}-{self.metadata.version}'\n\n return self.__project_id\n\n def get_build_hooks(self, directory: str) -> dict[str, BuildHookInterface]:\n configured_build_hooks = {}\n for hook_name, config in self.config.hook_config.items():\n build_hook = self.plugin_manager.build_hook.get(hook_name)\n if build_hook is None:\n from hatchling.plugin.exceptions import UnknownPluginError\n\n message = f'Unknown build hook: {hook_name}'\n raise UnknownPluginError(message)\n\n configured_build_hooks[hook_name] = build_hook(\n self.root, config, self.config, self.metadata, directory, self.PLUGIN_NAME, self.app\n )\n\n return configured_build_hooks\n\n @abstractmethod\n def get_version_api(self) -> dict[str, Callable]:\n \"\"\"\n A mapping of `str` versions to a callable that is used for building.\n Each callable must have the following signature:\n\n ```python\n def ...(build_dir: str, build_data: dict) -> str:\n ```\n\n The return value must be the absolute path to the built artifact.\n \"\"\"\n\n def get_default_versions(self) -> list[str]:\n \"\"\"\n A list of versions to build when users do not specify any, defaulting to all versions.\n \"\"\"\n return list(self.get_version_api())\n\n def get_default_build_data(self) -> dict[str, Any]: # noqa: PLR6301\n \"\"\"\n A mapping that can be modified by [build hooks](../build-hook/reference.md) to influence the behavior of builds.\n \"\"\"\n return {}\n\n def set_build_data_defaults(self, build_data: dict[str, Any]) -> None: # noqa: PLR6301\n build_data.setdefault('artifacts', [])\n build_data.setdefault('force_include', {})\n\n def clean(self, directory: str, versions: list[str]) -> None:\n \"\"\"\n Called before builds if the `-c`/`--clean` flag was passed to the\n [`build`](../../cli/reference.md#hatch-build) command.\n \"\"\"\n\n @classmethod\n def get_config_class(cls) -> type[BuilderConfig]:\n \"\"\"\n Must return a subclass of [BuilderConfig](../utilities.md#hatchling.builders.config.BuilderConfig).\n \"\"\"\n return BuilderConfig\n\n @staticmethod\n def normalize_file_name_component(file_name: str) -> str:\n \"\"\"\n https://peps.python.org/pep-0427/#escaping-and-unicode\n \"\"\"\n return re.sub(r'[^\\w\\d.]+', '_', file_name, flags=re.UNICODE)\n
"},{"location":"plugins/builder/reference/#hatchling.builders.plugin.interface.BuilderInterface.PLUGIN_NAME","title":"PLUGIN_NAME = ''
class-attribute
instance-attribute
","text":"The name used for selection.
"},{"location":"plugins/builder/reference/#hatchling.builders.plugin.interface.BuilderInterface.app","title":"app: Application
property
","text":"An instance of Application.
"},{"location":"plugins/builder/reference/#hatchling.builders.plugin.interface.BuilderInterface.root","title":"root: str
property
","text":"The root of the project tree.
"},{"location":"plugins/builder/reference/#hatchling.builders.plugin.interface.BuilderInterface.build_config","title":"build_config: dict[str, Any]
property
","text":"pyproject.toml hatch.toml [tool.hatch.build]\n
[build]\n
"},{"location":"plugins/builder/reference/#hatchling.builders.plugin.interface.BuilderInterface.target_config","title":"target_config: dict[str, Any]
property
","text":"pyproject.toml hatch.toml [tool.hatch.build.targets.<PLUGIN_NAME>]\n
[build.targets.<PLUGIN_NAME>]\n
"},{"location":"plugins/builder/reference/#hatchling.builders.plugin.interface.BuilderInterface.config","title":"config: BuilderConfigBound
property
","text":"An instance of BuilderConfig.
"},{"location":"plugins/builder/reference/#hatchling.builders.plugin.interface.BuilderInterface.get_config_class","title":"get_config_class() -> type[BuilderConfig]
classmethod
","text":"Must return a subclass of BuilderConfig.
Source code inbackend/src/hatchling/builders/plugin/interface.py
@classmethod\ndef get_config_class(cls) -> type[BuilderConfig]:\n \"\"\"\n Must return a subclass of [BuilderConfig](../utilities.md#hatchling.builders.config.BuilderConfig).\n \"\"\"\n return BuilderConfig\n
"},{"location":"plugins/builder/reference/#hatchling.builders.plugin.interface.BuilderInterface.get_version_api","title":"get_version_api() -> dict[str, Callable]
abstractmethod
","text":"A mapping of str
versions to a callable that is used for building. Each callable must have the following signature:
def ...(build_dir: str, build_data: dict) -> str:\n
The return value must be the absolute path to the built artifact.
Source code inbackend/src/hatchling/builders/plugin/interface.py
@abstractmethod\ndef get_version_api(self) -> dict[str, Callable]:\n \"\"\"\n A mapping of `str` versions to a callable that is used for building.\n Each callable must have the following signature:\n\n ```python\n def ...(build_dir: str, build_data: dict) -> str:\n ```\n\n The return value must be the absolute path to the built artifact.\n \"\"\"\n
"},{"location":"plugins/builder/reference/#hatchling.builders.plugin.interface.BuilderInterface.get_default_versions","title":"get_default_versions() -> list[str]
","text":"A list of versions to build when users do not specify any, defaulting to all versions.
Source code inbackend/src/hatchling/builders/plugin/interface.py
def get_default_versions(self) -> list[str]:\n \"\"\"\n A list of versions to build when users do not specify any, defaulting to all versions.\n \"\"\"\n return list(self.get_version_api())\n
"},{"location":"plugins/builder/reference/#hatchling.builders.plugin.interface.BuilderInterface.clean","title":"clean(directory: str, versions: list[str]) -> None
","text":"Called before builds if the -c
/--clean
flag was passed to the build
command.
backend/src/hatchling/builders/plugin/interface.py
def clean(self, directory: str, versions: list[str]) -> None:\n \"\"\"\n Called before builds if the `-c`/`--clean` flag was passed to the\n [`build`](../../cli/reference.md#hatch-build) command.\n \"\"\"\n
"},{"location":"plugins/builder/reference/#hatchling.builders.plugin.interface.BuilderInterface.recurse_included_files","title":"recurse_included_files() -> Iterable[IncludedFile]
","text":"Returns a consistently generated series of file objects for every file that should be distributed. Each file object has three str
attributes:
path
- the absolute pathrelative_path
- the path relative to the project root; will be an empty string for external filesdistribution_path
- the path to be distributed asbackend/src/hatchling/builders/plugin/interface.py
def recurse_included_files(self) -> Iterable[IncludedFile]:\n \"\"\"\n Returns a consistently generated series of file objects for every file that should be distributed. Each file\n object has three `str` attributes:\n\n - `path` - the absolute path\n - `relative_path` - the path relative to the project root; will be an empty string for external files\n - `distribution_path` - the path to be distributed as\n \"\"\"\n yield from self.recurse_selected_project_files()\n yield from self.recurse_forced_files(self.config.get_force_include())\n
"},{"location":"plugins/builder/reference/#hatchling.builders.plugin.interface.BuilderInterface.get_default_build_data","title":"get_default_build_data() -> dict[str, Any]
","text":"A mapping that can be modified by build hooks to influence the behavior of builds.
Source code inbackend/src/hatchling/builders/plugin/interface.py
def get_default_build_data(self) -> dict[str, Any]: # noqa: PLR6301\n \"\"\"\n A mapping that can be modified by [build hooks](../build-hook/reference.md) to influence the behavior of builds.\n \"\"\"\n return {}\n
"},{"location":"plugins/builder/sdist/","title":"Source distribution builder","text":"A source distribution, or sdist
, is an archive of Python \"source code\". Although largely unspecified, by convention it should include everything that is required to build a wheel without making network requests.
The builder plugin name is sdist
.
[tool.hatch.build.targets.sdist]\n
[build.targets.sdist]\n
"},{"location":"plugins/builder/sdist/#options","title":"Options","text":"Option Default Description core-metadata-version
\"2.3\"
The version of core metadata to use strict-naming
true
Whether or not file names should contain the normalized version of the project name support-legacy
false
Whether or not to include a setup.py
file to support legacy installation mechanisms"},{"location":"plugins/builder/sdist/#versions","title":"Versions","text":"Version Description standard
(default) The latest conventional format"},{"location":"plugins/builder/sdist/#default-file-selection","title":"Default file selection","text":"When the user has not set any file selection options, all files that are not ignored by your VCS will be included.
Note
The following files are always included and cannot be excluded:
/pyproject.toml
/hatch.toml
/hatch_build.py
/.gitignore
or /.hgignore
readme
filelicense-files
Reproducible builds are supported.
"},{"location":"plugins/builder/sdist/#build-data","title":"Build data","text":"This is data that can be modified by build hooks.
Data Default Descriptiondependencies
Extra project dependencies"},{"location":"plugins/builder/wheel/","title":"Wheel builder","text":"A wheel is a binary distribution of a Python package that can be installed directly into an environment.
"},{"location":"plugins/builder/wheel/#configuration","title":"Configuration","text":"The builder plugin name is wheel
.
[tool.hatch.build.targets.wheel]\n
[build.targets.wheel]\n
"},{"location":"plugins/builder/wheel/#options","title":"Options","text":"Option Default Description core-metadata-version
\"2.3\"
The version of core metadata to use shared-data
A mapping similar to the forced inclusion option corresponding to the data
subdirectory within the standard data directory that will be installed globally in a given Python environment, usually under sys.prefix
shared-scripts
A mapping similar to the forced inclusion option corresponding to the scripts
subdirectory within the standard data directory that will be installed in a given Python environment, usually under Scripts
on Windows or bin
otherwise, and would normally be available on PATH extra-metadata
A mapping similar to the forced inclusion option corresponding to extra metadata that will be shipped in a directory named extra_metadata
strict-naming
true
Whether or not file names should contain the normalized version of the project name macos-max-compat
false
Whether or not on macOS, when build hooks have set the infer_tag
build data, the wheel name should signal broad support rather than specific versions for newer SDK versions.Note: This option will eventually be removed. bypass-selection
false
Whether or not to suppress the error when one has not defined any file selection options and all heuristics have failed to determine what to ship"},{"location":"plugins/builder/wheel/#versions","title":"Versions","text":"Version Description standard
(default) The latest standardized format editable
A wheel that only ships .pth
files or import hooks for real-time development"},{"location":"plugins/builder/wheel/#default-file-selection","title":"Default file selection","text":"When the user has not set any file selection options, the project name will be used to determine the package to ship in the following heuristic order:
<NAME>/__init__.py
src/<NAME>/__init__.py
<NAME>.py
<NAMESPACE>/<NAME>/__init__.py
If none of these heuristics are satisfied, an error will be raised.
"},{"location":"plugins/builder/wheel/#reproducibility","title":"Reproducibility","text":"Reproducible builds are supported.
"},{"location":"plugins/builder/wheel/#build-data","title":"Build data","text":"This is data that can be modified by build hooks.
Data Default Descriptiontag
The full tag part of the filename (e.g. py3-none-any
), defaulting to a cross-platform wheel with the supported major versions of Python based on project metadata infer_tag
False
When tag
is not set, this may be enabled to use the one most specific to the platform, Python interpreter, and ABI pure_python
True
Whether or not to write metadata indicating that the package does not contain any platform-specific files dependencies
Extra project dependencies shared_data
Additional shared-data
entries, which take precedence in case of conflicts shared_scripts
Additional shared-scripts
entries, which take precedence in case of conflicts extra_metadata
Additional extra-metadata
entries, which take precedence in case of conflicts force_include_editable
Similar to the force_include
option but specifically for the editable
version and takes precedence"},{"location":"plugins/environment/reference/","title":"Environment plugins","text":"See the documentation for environment configuration.
"},{"location":"plugins/environment/reference/#known-third-party","title":"Known third-party","text":"Any required environment types that are not built-in must be manually installed alongside Hatch or listed in the tool.hatch.env.requires
array for automatic management:
[tool.hatch.env]\nrequires = [\n \"...\",\n]\n
[env]\nrequires = [\n \"...\",\n]\n
"},{"location":"plugins/environment/reference/#life-cycle","title":"Life cycle","text":"Whenever an environment is used, the following logic is performed:
Source code insrc/hatch/project/core.py
def prepare_environment(self, environment: EnvironmentInterface):\n if not environment.exists():\n self.env_metadata.reset(environment)\n\n with environment.app_status_creation():\n environment.create()\n\n if not environment.skip_install:\n if environment.pre_install_commands:\n with environment.app_status_pre_installation():\n self.app.run_shell_commands(\n ExecutionContext(\n environment,\n shell_commands=environment.pre_install_commands,\n source='pre-install',\n show_code_on_error=True,\n )\n )\n\n with environment.app_status_project_installation():\n if environment.dev_mode:\n environment.install_project_dev_mode()\n else:\n environment.install_project()\n\n if environment.post_install_commands:\n with environment.app_status_post_installation():\n self.app.run_shell_commands(\n ExecutionContext(\n environment,\n shell_commands=environment.post_install_commands,\n source='post-install',\n show_code_on_error=True,\n )\n )\n\n with environment.app_status_dependency_state_check():\n new_dep_hash = environment.dependency_hash()\n\n current_dep_hash = self.env_metadata.dependency_hash(environment)\n if new_dep_hash != current_dep_hash:\n with environment.app_status_dependency_installation_check():\n dependencies_in_sync = environment.dependencies_in_sync()\n\n if not dependencies_in_sync:\n with environment.app_status_dependency_synchronization():\n environment.sync_dependencies()\n new_dep_hash = environment.dependency_hash()\n\n self.env_metadata.update_dependency_hash(environment, new_dep_hash)\n
"},{"location":"plugins/environment/reference/#build-environments","title":"Build environments","text":"All environment types should offer support for synchronized storage between the local file system and the environment. This functionality is used in the following scenarios:
build
commanddep hash
, if any project dependencies are set dynamicallyEnvironmentInterface
","text":"Example usage:
plugin.py hooks.py from hatch.env.plugin.interface import EnvironmentInterface\n\n\n class SpecialEnvironment(EnvironmentInterface):\n PLUGIN_NAME = 'special'\n ...\n
from hatchling.plugin import hookimpl\n\n from .plugin import SpecialEnvironment\n\n\n @hookimpl\n def hatch_register_environment():\n return SpecialEnvironment\n
Source code in src/hatch/env/plugin/interface.py
class EnvironmentInterface(ABC):\n \"\"\"\n Example usage:\n\n ```python tab=\"plugin.py\"\n from hatch.env.plugin.interface import EnvironmentInterface\n\n\n class SpecialEnvironment(EnvironmentInterface):\n PLUGIN_NAME = 'special'\n ...\n ```\n\n ```python tab=\"hooks.py\"\n from hatchling.plugin import hookimpl\n\n from .plugin import SpecialEnvironment\n\n\n @hookimpl\n def hatch_register_environment():\n return SpecialEnvironment\n ```\n \"\"\"\n\n PLUGIN_NAME = ''\n \"\"\"The name used for selection.\"\"\"\n\n def __init__(\n self,\n root,\n metadata,\n name,\n config,\n matrix_variables,\n data_directory,\n isolated_data_directory,\n platform,\n verbosity,\n app,\n ):\n self.__root = root\n self.__metadata = metadata\n self.__name = name\n self.__config = config\n self.__matrix_variables = matrix_variables\n self.__data_directory = data_directory\n self.__isolated_data_directory = isolated_data_directory\n self.__platform = platform\n self.__verbosity = verbosity\n self.__app = app\n\n @property\n def matrix_variables(self):\n return self.__matrix_variables\n\n @property\n def app(self):\n \"\"\"\n An instance of [Application](../utilities.md#hatchling.bridge.app.Application).\n \"\"\"\n return self.__app\n\n @cached_property\n def context(self):\n return self.get_context()\n\n @property\n def verbosity(self):\n return self.__verbosity\n\n @property\n def root(self):\n \"\"\"\n The root of the local project tree as a path-like object.\n \"\"\"\n return self.__root\n\n @property\n def metadata(self):\n return self.__metadata\n\n @property\n def name(self) -> str:\n \"\"\"\n The name of the environment.\n \"\"\"\n return self.__name\n\n @property\n def platform(self):\n \"\"\"\n An instance of [Platform](../utilities.md#hatch.utils.platform.Platform).\n \"\"\"\n return self.__platform\n\n @property\n def data_directory(self):\n \"\"\"\n The [directory](../../config/hatch.md#environments) this plugin should use for storage as a path-like object.\n If the user has not configured one then this will be the same as the\n [isolated data directory](reference.md#hatch.env.plugin.interface.EnvironmentInterface.isolated_data_directory).\n \"\"\"\n return self.__data_directory\n\n @property\n def isolated_data_directory(self):\n \"\"\"\n The default [directory](../../config/hatch.md#environments) reserved exclusively for this plugin as a path-like\n object.\n \"\"\"\n return self.__isolated_data_directory\n\n @property\n def config(self) -> dict:\n \"\"\"\n ```toml config-example\n [tool.hatch.envs.<ENV_NAME>]\n ```\n \"\"\"\n return self.__config\n\n @cached_property\n def project_root(self) -> str:\n \"\"\"\n The root of the project tree as a string. If the environment is not running locally,\n this should be the remote path to the project.\n \"\"\"\n return str(self.root)\n\n @cached_property\n def sep(self) -> str:\n \"\"\"\n The character used to separate directories in paths. By default, this is `\\\\` on Windows and `/` otherwise.\n \"\"\"\n return os.sep\n\n @cached_property\n def pathsep(self) -> str:\n \"\"\"\n The character used to separate paths. By default, this is `;` on Windows and `:` otherwise.\n \"\"\"\n return os.pathsep\n\n @cached_property\n def system_python(self):\n system_python = os.environ.get(AppEnvVars.PYTHON)\n if system_python == 'self':\n system_python = sys.executable\n\n system_python = (\n system_python\n or self.platform.modules.shutil.which('python')\n or self.platform.modules.shutil.which('python3')\n or sys.executable\n )\n if not isabs(system_python):\n system_python = self.platform.modules.shutil.which(system_python)\n\n return system_python\n\n @cached_property\n def env_vars(self) -> dict:\n \"\"\"\n ```toml config-example\n [tool.hatch.envs.<ENV_NAME>.env-vars]\n ```\n \"\"\"\n env_vars = self.config.get('env-vars', {})\n if not isinstance(env_vars, dict):\n message = f'Field `tool.hatch.envs.{self.name}.env-vars` must be a mapping'\n raise TypeError(message)\n\n for key, value in env_vars.items():\n if not isinstance(value, str):\n message = (\n f'Environment variable `{key}` of field `tool.hatch.envs.{self.name}.env-vars` must be a string'\n )\n raise TypeError(message)\n\n new_env_vars = {}\n with self.metadata.context.apply_context(self.context):\n for key, value in env_vars.items():\n new_env_vars[key] = self.metadata.context.format(value)\n\n new_env_vars[AppEnvVars.ENV_ACTIVE] = self.name\n return new_env_vars\n\n @cached_property\n def env_include(self) -> list[str]:\n \"\"\"\n ```toml config-example\n [tool.hatch.envs.<ENV_NAME>]\n env-include = [...]\n ```\n \"\"\"\n env_include = self.config.get('env-include', [])\n if not isinstance(env_include, list):\n message = f'Field `tool.hatch.envs.{self.name}.env-include` must be an array'\n raise TypeError(message)\n\n for i, pattern in enumerate(env_include, 1):\n if not isinstance(pattern, str):\n message = f'Pattern #{i} of field `tool.hatch.envs.{self.name}.env-include` must be a string'\n raise TypeError(message)\n\n return ['HATCH_BUILD_*', *env_include] if env_include else env_include\n\n @cached_property\n def env_exclude(self) -> list[str]:\n \"\"\"\n ```toml config-example\n [tool.hatch.envs.<ENV_NAME>]\n env-exclude = [...]\n ```\n \"\"\"\n env_exclude = self.config.get('env-exclude', [])\n if not isinstance(env_exclude, list):\n message = f'Field `tool.hatch.envs.{self.name}.env-exclude` must be an array'\n raise TypeError(message)\n\n for i, pattern in enumerate(env_exclude, 1):\n if not isinstance(pattern, str):\n message = f'Pattern #{i} of field `tool.hatch.envs.{self.name}.env-exclude` must be a string'\n raise TypeError(message)\n\n return env_exclude\n\n @cached_property\n def environment_dependencies_complex(self):\n from packaging.requirements import InvalidRequirement, Requirement\n\n dependencies_complex = []\n with self.apply_context():\n for option in ('dependencies', 'extra-dependencies'):\n dependencies = self.config.get(option, [])\n if not isinstance(dependencies, list):\n message = f'Field `tool.hatch.envs.{self.name}.{option}` must be an array'\n raise TypeError(message)\n\n for i, entry in enumerate(dependencies, 1):\n if not isinstance(entry, str):\n message = f'Dependency #{i} of field `tool.hatch.envs.{self.name}.{option}` must be a string'\n raise TypeError(message)\n\n try:\n dependencies_complex.append(Requirement(self.metadata.context.format(entry)))\n except InvalidRequirement as e:\n message = f'Dependency #{i} of field `tool.hatch.envs.{self.name}.{option}` is invalid: {e}'\n raise ValueError(message) from None\n\n return dependencies_complex\n\n @cached_property\n def environment_dependencies(self) -> list[str]:\n \"\"\"\n The list of all [environment dependencies](../../config/environment/overview.md#dependencies).\n \"\"\"\n return [str(dependency) for dependency in self.environment_dependencies_complex]\n\n @cached_property\n def dependencies_complex(self):\n all_dependencies_complex = list(self.environment_dependencies_complex)\n if self.builder:\n all_dependencies_complex.extend(self.metadata.build.requires_complex)\n return all_dependencies_complex\n\n # Ensure these are checked last to speed up initial environment creation since\n # they will already be installed along with the project\n if (not self.skip_install and self.dev_mode) or self.features:\n from hatch.utils.dep import get_complex_dependencies, get_complex_features\n\n dependencies, optional_dependencies = self.app.project.get_dependencies()\n dependencies_complex = get_complex_dependencies(dependencies)\n optional_dependencies_complex = get_complex_features(optional_dependencies)\n\n if not self.skip_install and self.dev_mode:\n all_dependencies_complex.extend(dependencies_complex.values())\n\n for feature in self.features:\n if feature not in optional_dependencies_complex:\n message = (\n f'Feature `{feature}` of field `tool.hatch.envs.{self.name}.features` is not '\n f'defined in the dynamic field `project.optional-dependencies`'\n )\n raise ValueError(message)\n\n all_dependencies_complex.extend(optional_dependencies_complex[feature].values())\n\n return all_dependencies_complex\n\n @cached_property\n def dependencies(self) -> list[str]:\n \"\"\"\n The list of all [project dependencies](../../config/metadata.md#dependencies) (if\n [installed](../../config/environment/overview.md#skip-install) and in\n [dev mode](../../config/environment/overview.md#dev-mode)), selected\n [optional dependencies](../../config/environment/overview.md#features), and\n [environment dependencies](../../config/environment/overview.md#dependencies).\n \"\"\"\n return [str(dependency) for dependency in self.dependencies_complex]\n\n @cached_property\n def platforms(self) -> list[str]:\n \"\"\"\n All names are stored as their lower-cased version.\n\n ```toml config-example\n [tool.hatch.envs.<ENV_NAME>]\n platforms = [...]\n ```\n \"\"\"\n platforms = self.config.get('platforms', [])\n if not isinstance(platforms, list):\n message = f'Field `tool.hatch.envs.{self.name}.platforms` must be an array'\n raise TypeError(message)\n\n for i, command in enumerate(platforms, 1):\n if not isinstance(command, str):\n message = f'Platform #{i} of field `tool.hatch.envs.{self.name}.platforms` must be a string'\n raise TypeError(message)\n\n return [platform.lower() for platform in platforms]\n\n @cached_property\n def skip_install(self) -> bool:\n \"\"\"\n ```toml config-example\n [tool.hatch.envs.<ENV_NAME>]\n skip-install = ...\n ```\n \"\"\"\n skip_install = self.config.get('skip-install', not self.metadata.has_project_file())\n if not isinstance(skip_install, bool):\n message = f'Field `tool.hatch.envs.{self.name}.skip-install` must be a boolean'\n raise TypeError(message)\n\n return skip_install\n\n @cached_property\n def dev_mode(self) -> bool:\n \"\"\"\n ```toml config-example\n [tool.hatch.envs.<ENV_NAME>]\n dev-mode = ...\n ```\n \"\"\"\n dev_mode = self.config.get('dev-mode', True)\n if not isinstance(dev_mode, bool):\n message = f'Field `tool.hatch.envs.{self.name}.dev-mode` must be a boolean'\n raise TypeError(message)\n\n return dev_mode\n\n @cached_property\n def builder(self) -> bool:\n \"\"\"\n ```toml config-example\n [tool.hatch.envs.<ENV_NAME>]\n builder = ...\n ```\n \"\"\"\n builder = self.config.get('builder', False)\n if not isinstance(builder, bool):\n message = f'Field `tool.hatch.envs.{self.name}.builder` must be a boolean'\n raise TypeError(message)\n\n return builder\n\n @cached_property\n def features(self):\n from hatchling.metadata.utils import normalize_project_name\n\n features = self.config.get('features', [])\n if not isinstance(features, list):\n message = f'Field `tool.hatch.envs.{self.name}.features` must be an array of strings'\n raise TypeError(message)\n\n all_features = set()\n for i, feature in enumerate(features, 1):\n if not isinstance(feature, str):\n message = f'Feature #{i} of field `tool.hatch.envs.{self.name}.features` must be a string'\n raise TypeError(message)\n\n if not feature:\n message = f'Feature #{i} of field `tool.hatch.envs.{self.name}.features` cannot be an empty string'\n raise ValueError(message)\n\n normalized_feature = (\n feature if self.metadata.hatch.metadata.allow_ambiguous_features else normalize_project_name(feature)\n )\n if (\n not self.metadata.hatch.metadata.hook_config\n and normalized_feature not in self.metadata.core.optional_dependencies\n ):\n message = (\n f'Feature `{normalized_feature}` of field `tool.hatch.envs.{self.name}.features` is not '\n f'defined in field `project.optional-dependencies`'\n )\n raise ValueError(message)\n\n all_features.add(normalized_feature)\n\n return sorted(all_features)\n\n @cached_property\n def description(self) -> str:\n \"\"\"\n ```toml config-example\n [tool.hatch.envs.<ENV_NAME>]\n description = ...\n ```\n \"\"\"\n description = self.config.get('description', '')\n if not isinstance(description, str):\n message = f'Field `tool.hatch.envs.{self.name}.description` must be a string'\n raise TypeError(message)\n\n return description\n\n @cached_property\n def scripts(self):\n config = {}\n\n # Extra scripts should come first to give less precedence\n for field in ('extra-scripts', 'scripts'):\n script_config = self.config.get(field, {})\n if not isinstance(script_config, dict):\n message = f'Field `tool.hatch.envs.{self.name}.{field}` must be a table'\n raise TypeError(message)\n\n for name, data in script_config.items():\n if ' ' in name:\n message = (\n f'Script name `{name}` in field `tool.hatch.envs.{self.name}.{field}` '\n f'must not contain spaces'\n )\n raise ValueError(message)\n\n commands = []\n\n if isinstance(data, str):\n commands.append(data)\n elif isinstance(data, list):\n for i, command in enumerate(data, 1):\n if not isinstance(command, str):\n message = (\n f'Command #{i} in field `tool.hatch.envs.{self.name}.{field}.{name}` '\n f'must be a string'\n )\n raise TypeError(message)\n\n commands.append(command)\n else:\n message = (\n f'Field `tool.hatch.envs.{self.name}.{field}.{name}` must be '\n f'a string or an array of strings'\n )\n raise TypeError(message)\n\n config[name] = commands\n\n seen = {}\n active = []\n for script_name, commands in config.items():\n commands[:] = expand_script_commands(self.name, script_name, commands, config, seen, active)\n\n return config\n\n @cached_property\n def pre_install_commands(self):\n pre_install_commands = self.config.get('pre-install-commands', [])\n if not isinstance(pre_install_commands, list):\n message = f'Field `tool.hatch.envs.{self.name}.pre-install-commands` must be an array'\n raise TypeError(message)\n\n for i, command in enumerate(pre_install_commands, 1):\n if not isinstance(command, str):\n message = f'Command #{i} of field `tool.hatch.envs.{self.name}.pre-install-commands` must be a string'\n raise TypeError(message)\n\n return list(pre_install_commands)\n\n @cached_property\n def post_install_commands(self):\n post_install_commands = self.config.get('post-install-commands', [])\n if not isinstance(post_install_commands, list):\n message = f'Field `tool.hatch.envs.{self.name}.post-install-commands` must be an array'\n raise TypeError(message)\n\n for i, command in enumerate(post_install_commands, 1):\n if not isinstance(command, str):\n message = f'Command #{i} of field `tool.hatch.envs.{self.name}.post-install-commands` must be a string'\n raise TypeError(message)\n\n return list(post_install_commands)\n\n def activate(self):\n \"\"\"\n A convenience method called when using the environment as a context manager:\n\n ```python\n with environment:\n ...\n ```\n \"\"\"\n\n def deactivate(self):\n \"\"\"\n A convenience method called after using the environment as a context manager:\n\n ```python\n with environment:\n ...\n ```\n \"\"\"\n\n @abstractmethod\n def find(self):\n \"\"\"\n :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n This should return information about how to locate the environment or represent its ID in\n some way. Additionally, this is expected to return something even if the environment is\n [incompatible](reference.md#hatch.env.plugin.interface.EnvironmentInterface.check_compatibility).\n \"\"\"\n\n @abstractmethod\n def create(self):\n \"\"\"\n :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n This should perform the necessary steps to set up the environment.\n \"\"\"\n\n @abstractmethod\n def remove(self):\n \"\"\"\n :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n This should perform the necessary steps to completely remove the environment from the system and will only\n be triggered manually by users with the [`env remove`](../../cli/reference.md#hatch-env-remove) or\n [`env prune`](../../cli/reference.md#hatch-env-prune) commands.\n \"\"\"\n\n @abstractmethod\n def exists(self) -> bool:\n \"\"\"\n :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n This should indicate whether or not the environment has already been created.\n \"\"\"\n\n @abstractmethod\n def install_project(self):\n \"\"\"\n :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n This should install the project in the environment.\n \"\"\"\n\n @abstractmethod\n def install_project_dev_mode(self):\n \"\"\"\n :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n This should install the project in the environment such that the environment\n always reflects the current state of the project.\n \"\"\"\n\n @abstractmethod\n def dependencies_in_sync(self) -> bool:\n \"\"\"\n :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n This should indicate whether or not the environment is compatible with the current\n [dependencies](reference.md#hatch.env.plugin.interface.EnvironmentInterface.dependencies).\n \"\"\"\n\n @abstractmethod\n def sync_dependencies(self):\n \"\"\"\n :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n This should install the\n [dependencies](reference.md#hatch.env.plugin.interface.EnvironmentInterface.dependencies)\n in the environment.\n \"\"\"\n\n def dependency_hash(self):\n \"\"\"\n This should return a hash of the environment's\n [dependencies](reference.md#hatch.env.plugin.interface.EnvironmentInterface.dependencies)\n and any other data that is handled by the\n [sync_dependencies](reference.md#hatch.env.plugin.interface.EnvironmentInterface.sync_dependencies)\n and\n [dependencies_in_sync](reference.md#hatch.env.plugin.interface.EnvironmentInterface.dependencies_in_sync)\n methods.\n \"\"\"\n from hatch.utils.dep import hash_dependencies\n\n return hash_dependencies(self.dependencies_complex)\n\n @contextmanager\n def app_status_creation(self):\n \"\"\"\n See the [life cycle of environments](reference.md#life-cycle).\n \"\"\"\n with self.app.status(f'Creating environment: {self.name}'):\n yield\n\n @contextmanager\n def app_status_pre_installation(self):\n \"\"\"\n See the [life cycle of environments](reference.md#life-cycle).\n \"\"\"\n with self.app.status('Running pre-installation commands'):\n yield\n\n @contextmanager\n def app_status_post_installation(self):\n \"\"\"\n See the [life cycle of environments](reference.md#life-cycle).\n \"\"\"\n with self.app.status('Running post-installation commands'):\n yield\n\n @contextmanager\n def app_status_project_installation(self):\n \"\"\"\n See the [life cycle of environments](reference.md#life-cycle).\n \"\"\"\n if self.dev_mode:\n with self.app.status('Installing project in development mode'):\n yield\n else:\n with self.app.status('Installing project'):\n yield\n\n @contextmanager\n def app_status_dependency_state_check(self):\n \"\"\"\n See the [life cycle of environments](reference.md#life-cycle).\n \"\"\"\n if not self.skip_install and (\n 'dependencies' in self.metadata.dynamic or 'optional-dependencies' in self.metadata.dynamic\n ):\n with self.app.status('Polling dependency state'):\n yield\n else:\n yield\n\n @contextmanager\n def app_status_dependency_installation_check(self):\n \"\"\"\n See the [life cycle of environments](reference.md#life-cycle).\n \"\"\"\n with self.app.status('Checking dependencies'):\n yield\n\n @contextmanager\n def app_status_dependency_synchronization(self):\n \"\"\"\n See the [life cycle of environments](reference.md#life-cycle).\n \"\"\"\n with self.app.status('Syncing dependencies'):\n yield\n\n @contextmanager\n def fs_context(self) -> Generator[FileSystemContext, None, None]:\n \"\"\"\n A context manager that must yield a subclass of\n [FileSystemContext](../utilities.md#hatch.env.plugin.interface.FileSystemContext).\n \"\"\"\n from hatch.utils.fs import temp_directory\n\n with temp_directory() as temp_dir:\n yield FileSystemContext(self, local_path=temp_dir, env_path=str(temp_dir))\n\n def enter_shell(\n self,\n name: str, # noqa: ARG002\n path: str,\n args: Iterable[str],\n ):\n \"\"\"\n Spawn a [shell](../../config/hatch.md#shell) within the environment.\n\n This should either use\n [command_context](reference.md#hatch.env.plugin.interface.EnvironmentInterface.command_context)\n directly or provide the same guarantee.\n \"\"\"\n with self.command_context():\n self.platform.exit_with_command([path, *args])\n\n def run_shell_command(self, command: str, **kwargs):\n \"\"\"\n This should return the standard library's\n [subprocess.CompletedProcess](https://docs.python.org/3/library/subprocess.html#subprocess.CompletedProcess)\n and will always be called when the\n [command_context](reference.md#hatch.env.plugin.interface.EnvironmentInterface.command_context)\n is active, with the expectation of providing the same guarantee.\n \"\"\"\n kwargs.setdefault('shell', True)\n return self.platform.run_command(command, **kwargs)\n\n @contextmanager\n def command_context(self):\n \"\"\"\n A context manager that when active should make executed shell commands reflect any\n [environment variables](reference.md#hatch.env.plugin.interface.EnvironmentInterface.get_env_vars)\n the user defined either currently or at the time of\n [creation](reference.md#hatch.env.plugin.interface.EnvironmentInterface.create).\n\n For an example, open the default implementation below:\n \"\"\"\n with self.get_env_vars():\n yield\n\n def resolve_commands(self, commands: list[str]):\n \"\"\"\n This expands each command into one or more commands based on any\n [scripts](../../config/environment/overview.md#scripts) that the user defined.\n \"\"\"\n for command in commands:\n yield from self.expand_command(command)\n\n def expand_command(self, command):\n possible_script, args, _ignore_exit_code = parse_script_command(command)\n\n # Indicate undefined\n if not args:\n args = None\n\n with self.apply_context():\n if possible_script in self.scripts:\n if args is not None:\n args = self.metadata.context.format(args)\n\n for cmd in self.scripts[possible_script]:\n yield self.metadata.context.format(cmd, args=args).strip()\n else:\n yield self.metadata.context.format(command, args=args).strip()\n\n def construct_pip_install_command(self, args: list[str]):\n \"\"\"\n A convenience method for constructing a [`pip install`](https://pip.pypa.io/en/stable/cli/pip_install/)\n command with the given verbosity. The default verbosity is set to one less than Hatch's verbosity.\n \"\"\"\n command = ['python', '-u', '-m', 'pip', 'install', '--disable-pip-version-check', '--no-python-version-warning']\n\n # Default to -1 verbosity\n add_verbosity_flag(command, self.verbosity, adjustment=-1)\n\n command.extend(args)\n return command\n\n def join_command_args(self, args: list[str]):\n \"\"\"\n This is used by the [`run`](../../cli/reference.md#hatch-run) command to construct the root command string\n from the received arguments.\n \"\"\"\n return self.platform.join_command_args(args)\n\n def apply_features(self, requirement: str):\n \"\"\"\n A convenience method that applies any user defined [features](../../config/environment/overview.md#features)\n to the given requirement.\n \"\"\"\n if self.features:\n features = ','.join(self.features)\n return f'{requirement}[{features}]'\n\n return requirement\n\n def check_compatibility(self):\n \"\"\"\n This raises an exception if the environment is not compatible with the user's setup. The default behavior\n checks for [platform compatibility](../../config/environment/overview.md#supported-platforms)\n and any method override should keep this check.\n\n This check is never performed if the environment has been\n [created](reference.md#hatch.env.plugin.interface.EnvironmentInterface.create).\n \"\"\"\n if self.platforms and self.platform.name not in self.platforms:\n message = 'unsupported platform'\n raise OSError(message)\n\n def get_env_vars(self) -> EnvVars:\n \"\"\"\n Returns a mapping of environment variables that should be available to the environment. The object can\n be used as a context manager to temporarily apply the environment variables to the current process.\n\n !!! note\n The environment variable `HATCH_ENV_ACTIVE` will always be set to the name of the environment.\n \"\"\"\n return EnvVars(self.env_vars, self.env_include, self.env_exclude)\n\n def get_env_var_option(self, option: str) -> str:\n \"\"\"\n Returns the value of the upper-cased environment variable `HATCH_ENV_TYPE_<PLUGIN_NAME>_<option>`.\n \"\"\"\n return get_env_var_option(plugin_name=self.PLUGIN_NAME, option=option)\n\n def get_context(self):\n \"\"\"\n Returns a subclass of\n [EnvironmentContextFormatter](../utilities.md#hatch.env.context.EnvironmentContextFormatter).\n \"\"\"\n from hatch.env.context import EnvironmentContextFormatter\n\n return EnvironmentContextFormatter(self)\n\n @staticmethod\n def get_option_types() -> dict:\n \"\"\"\n Returns a mapping of supported options to their respective types so that they can be used by\n [overrides](../../config/environment/advanced.md#option-overrides).\n \"\"\"\n return {}\n\n @contextmanager\n def apply_context(self):\n with self.get_env_vars(), self.metadata.context.apply_context(self.context):\n yield\n\n def __enter__(self):\n self.activate()\n return self\n\n def __exit__(self, exc_type, exc_value, traceback):\n self.deactivate()\n
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.PLUGIN_NAME","title":"PLUGIN_NAME = ''
class-attribute
instance-attribute
","text":"The name used for selection.
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.project_root","title":"project_root: str
cached
property
","text":"The root of the project tree as a string. If the environment is not running locally, this should be the remote path to the project.
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.sep","title":"sep: str
cached
property
","text":"The character used to separate directories in paths. By default, this is \\
on Windows and /
otherwise.
pathsep: str
cached
property
","text":"The character used to separate paths. By default, this is ;
on Windows and :
otherwise.
app
property
","text":"An instance of Application.
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.root","title":"root
property
","text":"The root of the local project tree as a path-like object.
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.name","title":"name: str
property
","text":"The name of the environment.
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.data_directory","title":"data_directory
property
","text":"The directory this plugin should use for storage as a path-like object. If the user has not configured one then this will be the same as the isolated data directory.
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.isolated_data_directory","title":"isolated_data_directory
property
","text":"The default directory reserved exclusively for this plugin as a path-like object.
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.config","title":"config: dict
property
","text":"pyproject.toml hatch.toml [tool.hatch.envs.<ENV_NAME>]\n
[envs.<ENV_NAME>]\n
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.platform","title":"platform
property
","text":"An instance of Platform.
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.environment_dependencies","title":"environment_dependencies: list[str]
cached
property
","text":"The list of all environment dependencies.
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.dependencies","title":"dependencies: list[str]
cached
property
","text":"The list of all project dependencies (if installed and in dev mode), selected optional dependencies, and environment dependencies.
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.env_vars","title":"env_vars: dict
cached
property
","text":"pyproject.toml hatch.toml [tool.hatch.envs.<ENV_NAME>.env-vars]\n
[envs.<ENV_NAME>.env-vars]\n
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.env_include","title":"env_include: list[str]
cached
property
","text":"pyproject.toml hatch.toml [tool.hatch.envs.<ENV_NAME>]\nenv-include = [...]\n
[envs.<ENV_NAME>]\nenv-include = [...]\n
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.env_exclude","title":"env_exclude: list[str]
cached
property
","text":"pyproject.toml hatch.toml [tool.hatch.envs.<ENV_NAME>]\nenv-exclude = [...]\n
[envs.<ENV_NAME>]\nenv-exclude = [...]\n
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.platforms","title":"platforms: list[str]
cached
property
","text":"All names are stored as their lower-cased version.
pyproject.toml hatch.toml[tool.hatch.envs.<ENV_NAME>]\nplatforms = [...]\n
[envs.<ENV_NAME>]\nplatforms = [...]\n
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.skip_install","title":"skip_install: bool
cached
property
","text":"pyproject.toml hatch.toml [tool.hatch.envs.<ENV_NAME>]\nskip-install = ...\n
[envs.<ENV_NAME>]\nskip-install = ...\n
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.dev_mode","title":"dev_mode: bool
cached
property
","text":"pyproject.toml hatch.toml [tool.hatch.envs.<ENV_NAME>]\ndev-mode = ...\n
[envs.<ENV_NAME>]\ndev-mode = ...\n
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.description","title":"description: str
cached
property
","text":"pyproject.toml hatch.toml [tool.hatch.envs.<ENV_NAME>]\ndescription = ...\n
[envs.<ENV_NAME>]\ndescription = ...\n
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.find","title":"find()
abstractmethod
","text":"REQUIRED
This should return information about how to locate the environment or represent its ID in some way. Additionally, this is expected to return something even if the environment is incompatible.
Source code insrc/hatch/env/plugin/interface.py
@abstractmethod\ndef find(self):\n \"\"\"\n :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n This should return information about how to locate the environment or represent its ID in\n some way. Additionally, this is expected to return something even if the environment is\n [incompatible](reference.md#hatch.env.plugin.interface.EnvironmentInterface.check_compatibility).\n \"\"\"\n
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.create","title":"create()
abstractmethod
","text":"REQUIRED
This should perform the necessary steps to set up the environment.
Source code insrc/hatch/env/plugin/interface.py
@abstractmethod\ndef create(self):\n \"\"\"\n :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n This should perform the necessary steps to set up the environment.\n \"\"\"\n
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.remove","title":"remove()
abstractmethod
","text":"REQUIRED
This should perform the necessary steps to completely remove the environment from the system and will only be triggered manually by users with the env remove
or env prune
commands.
src/hatch/env/plugin/interface.py
@abstractmethod\ndef remove(self):\n \"\"\"\n :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n This should perform the necessary steps to completely remove the environment from the system and will only\n be triggered manually by users with the [`env remove`](../../cli/reference.md#hatch-env-remove) or\n [`env prune`](../../cli/reference.md#hatch-env-prune) commands.\n \"\"\"\n
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.exists","title":"exists() -> bool
abstractmethod
","text":"REQUIRED
This should indicate whether or not the environment has already been created.
Source code insrc/hatch/env/plugin/interface.py
@abstractmethod\ndef exists(self) -> bool:\n \"\"\"\n :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n This should indicate whether or not the environment has already been created.\n \"\"\"\n
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.install_project","title":"install_project()
abstractmethod
","text":"REQUIRED
This should install the project in the environment.
Source code insrc/hatch/env/plugin/interface.py
@abstractmethod\ndef install_project(self):\n \"\"\"\n :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n This should install the project in the environment.\n \"\"\"\n
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.install_project_dev_mode","title":"install_project_dev_mode()
abstractmethod
","text":"REQUIRED
This should install the project in the environment such that the environment always reflects the current state of the project.
Source code insrc/hatch/env/plugin/interface.py
@abstractmethod\ndef install_project_dev_mode(self):\n \"\"\"\n :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n This should install the project in the environment such that the environment\n always reflects the current state of the project.\n \"\"\"\n
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.dependencies_in_sync","title":"dependencies_in_sync() -> bool
abstractmethod
","text":"REQUIRED
This should indicate whether or not the environment is compatible with the current dependencies.
Source code insrc/hatch/env/plugin/interface.py
@abstractmethod\ndef dependencies_in_sync(self) -> bool:\n \"\"\"\n :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n This should indicate whether or not the environment is compatible with the current\n [dependencies](reference.md#hatch.env.plugin.interface.EnvironmentInterface.dependencies).\n \"\"\"\n
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.sync_dependencies","title":"sync_dependencies()
abstractmethod
","text":"REQUIRED
This should install the dependencies in the environment.
Source code insrc/hatch/env/plugin/interface.py
@abstractmethod\ndef sync_dependencies(self):\n \"\"\"\n :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n This should install the\n [dependencies](reference.md#hatch.env.plugin.interface.EnvironmentInterface.dependencies)\n in the environment.\n \"\"\"\n
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.dependency_hash","title":"dependency_hash()
","text":"This should return a hash of the environment's dependencies and any other data that is handled by the sync_dependencies and dependencies_in_sync methods.
Source code insrc/hatch/env/plugin/interface.py
def dependency_hash(self):\n \"\"\"\n This should return a hash of the environment's\n [dependencies](reference.md#hatch.env.plugin.interface.EnvironmentInterface.dependencies)\n and any other data that is handled by the\n [sync_dependencies](reference.md#hatch.env.plugin.interface.EnvironmentInterface.sync_dependencies)\n and\n [dependencies_in_sync](reference.md#hatch.env.plugin.interface.EnvironmentInterface.dependencies_in_sync)\n methods.\n \"\"\"\n from hatch.utils.dep import hash_dependencies\n\n return hash_dependencies(self.dependencies_complex)\n
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.fs_context","title":"fs_context() -> Generator[FileSystemContext, None, None]
","text":"A context manager that must yield a subclass of FileSystemContext.
Source code insrc/hatch/env/plugin/interface.py
@contextmanager\ndef fs_context(self) -> Generator[FileSystemContext, None, None]:\n \"\"\"\n A context manager that must yield a subclass of\n [FileSystemContext](../utilities.md#hatch.env.plugin.interface.FileSystemContext).\n \"\"\"\n from hatch.utils.fs import temp_directory\n\n with temp_directory() as temp_dir:\n yield FileSystemContext(self, local_path=temp_dir, env_path=str(temp_dir))\n
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.activate","title":"activate()
","text":"A convenience method called when using the environment as a context manager:
with environment:\n ...\n
Source code in src/hatch/env/plugin/interface.py
def activate(self):\n \"\"\"\n A convenience method called when using the environment as a context manager:\n\n ```python\n with environment:\n ...\n ```\n \"\"\"\n
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.deactivate","title":"deactivate()
","text":"A convenience method called after using the environment as a context manager:
with environment:\n ...\n
Source code in src/hatch/env/plugin/interface.py
def deactivate(self):\n \"\"\"\n A convenience method called after using the environment as a context manager:\n\n ```python\n with environment:\n ...\n ```\n \"\"\"\n
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.app_status_creation","title":"app_status_creation()
","text":"See the life cycle of environments.
Source code insrc/hatch/env/plugin/interface.py
@contextmanager\ndef app_status_creation(self):\n \"\"\"\n See the [life cycle of environments](reference.md#life-cycle).\n \"\"\"\n with self.app.status(f'Creating environment: {self.name}'):\n yield\n
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.app_status_pre_installation","title":"app_status_pre_installation()
","text":"See the life cycle of environments.
Source code insrc/hatch/env/plugin/interface.py
@contextmanager\ndef app_status_pre_installation(self):\n \"\"\"\n See the [life cycle of environments](reference.md#life-cycle).\n \"\"\"\n with self.app.status('Running pre-installation commands'):\n yield\n
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.app_status_post_installation","title":"app_status_post_installation()
","text":"See the life cycle of environments.
Source code insrc/hatch/env/plugin/interface.py
@contextmanager\ndef app_status_post_installation(self):\n \"\"\"\n See the [life cycle of environments](reference.md#life-cycle).\n \"\"\"\n with self.app.status('Running post-installation commands'):\n yield\n
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.app_status_project_installation","title":"app_status_project_installation()
","text":"See the life cycle of environments.
Source code insrc/hatch/env/plugin/interface.py
@contextmanager\ndef app_status_project_installation(self):\n \"\"\"\n See the [life cycle of environments](reference.md#life-cycle).\n \"\"\"\n if self.dev_mode:\n with self.app.status('Installing project in development mode'):\n yield\n else:\n with self.app.status('Installing project'):\n yield\n
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.app_status_dependency_state_check","title":"app_status_dependency_state_check()
","text":"See the life cycle of environments.
Source code insrc/hatch/env/plugin/interface.py
@contextmanager\ndef app_status_dependency_state_check(self):\n \"\"\"\n See the [life cycle of environments](reference.md#life-cycle).\n \"\"\"\n if not self.skip_install and (\n 'dependencies' in self.metadata.dynamic or 'optional-dependencies' in self.metadata.dynamic\n ):\n with self.app.status('Polling dependency state'):\n yield\n else:\n yield\n
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.app_status_dependency_installation_check","title":"app_status_dependency_installation_check()
","text":"See the life cycle of environments.
Source code insrc/hatch/env/plugin/interface.py
@contextmanager\ndef app_status_dependency_installation_check(self):\n \"\"\"\n See the [life cycle of environments](reference.md#life-cycle).\n \"\"\"\n with self.app.status('Checking dependencies'):\n yield\n
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.app_status_dependency_synchronization","title":"app_status_dependency_synchronization()
","text":"See the life cycle of environments.
Source code insrc/hatch/env/plugin/interface.py
@contextmanager\ndef app_status_dependency_synchronization(self):\n \"\"\"\n See the [life cycle of environments](reference.md#life-cycle).\n \"\"\"\n with self.app.status('Syncing dependencies'):\n yield\n
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.command_context","title":"command_context()
","text":"A context manager that when active should make executed shell commands reflect any environment variables the user defined either currently or at the time of creation.
For an example, open the default implementation below:
Source code insrc/hatch/env/plugin/interface.py
@contextmanager\ndef command_context(self):\n \"\"\"\n A context manager that when active should make executed shell commands reflect any\n [environment variables](reference.md#hatch.env.plugin.interface.EnvironmentInterface.get_env_vars)\n the user defined either currently or at the time of\n [creation](reference.md#hatch.env.plugin.interface.EnvironmentInterface.create).\n\n For an example, open the default implementation below:\n \"\"\"\n with self.get_env_vars():\n yield\n
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.enter_shell","title":"enter_shell(name: str, path: str, args: Iterable[str])
","text":"Spawn a shell within the environment.
This should either use command_context directly or provide the same guarantee.
Source code insrc/hatch/env/plugin/interface.py
def enter_shell(\n self,\n name: str, # noqa: ARG002\n path: str,\n args: Iterable[str],\n):\n \"\"\"\n Spawn a [shell](../../config/hatch.md#shell) within the environment.\n\n This should either use\n [command_context](reference.md#hatch.env.plugin.interface.EnvironmentInterface.command_context)\n directly or provide the same guarantee.\n \"\"\"\n with self.command_context():\n self.platform.exit_with_command([path, *args])\n
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.run_shell_command","title":"run_shell_command(command: str, **kwargs)
","text":"This should return the standard library's subprocess.CompletedProcess and will always be called when the command_context is active, with the expectation of providing the same guarantee.
Source code insrc/hatch/env/plugin/interface.py
def run_shell_command(self, command: str, **kwargs):\n \"\"\"\n This should return the standard library's\n [subprocess.CompletedProcess](https://docs.python.org/3/library/subprocess.html#subprocess.CompletedProcess)\n and will always be called when the\n [command_context](reference.md#hatch.env.plugin.interface.EnvironmentInterface.command_context)\n is active, with the expectation of providing the same guarantee.\n \"\"\"\n kwargs.setdefault('shell', True)\n return self.platform.run_command(command, **kwargs)\n
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.resolve_commands","title":"resolve_commands(commands: list[str])
","text":"This expands each command into one or more commands based on any scripts that the user defined.
Source code insrc/hatch/env/plugin/interface.py
def resolve_commands(self, commands: list[str]):\n \"\"\"\n This expands each command into one or more commands based on any\n [scripts](../../config/environment/overview.md#scripts) that the user defined.\n \"\"\"\n for command in commands:\n yield from self.expand_command(command)\n
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.get_env_vars","title":"get_env_vars() -> EnvVars
","text":"Returns a mapping of environment variables that should be available to the environment. The object can be used as a context manager to temporarily apply the environment variables to the current process.
Note
The environment variable HATCH_ENV_ACTIVE
will always be set to the name of the environment.
src/hatch/env/plugin/interface.py
def get_env_vars(self) -> EnvVars:\n \"\"\"\n Returns a mapping of environment variables that should be available to the environment. The object can\n be used as a context manager to temporarily apply the environment variables to the current process.\n\n !!! note\n The environment variable `HATCH_ENV_ACTIVE` will always be set to the name of the environment.\n \"\"\"\n return EnvVars(self.env_vars, self.env_include, self.env_exclude)\n
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.apply_features","title":"apply_features(requirement: str)
","text":"A convenience method that applies any user defined features to the given requirement.
Source code insrc/hatch/env/plugin/interface.py
def apply_features(self, requirement: str):\n \"\"\"\n A convenience method that applies any user defined [features](../../config/environment/overview.md#features)\n to the given requirement.\n \"\"\"\n if self.features:\n features = ','.join(self.features)\n return f'{requirement}[{features}]'\n\n return requirement\n
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.construct_pip_install_command","title":"construct_pip_install_command(args: list[str])
","text":"A convenience method for constructing a pip install
command with the given verbosity. The default verbosity is set to one less than Hatch's verbosity.
src/hatch/env/plugin/interface.py
def construct_pip_install_command(self, args: list[str]):\n \"\"\"\n A convenience method for constructing a [`pip install`](https://pip.pypa.io/en/stable/cli/pip_install/)\n command with the given verbosity. The default verbosity is set to one less than Hatch's verbosity.\n \"\"\"\n command = ['python', '-u', '-m', 'pip', 'install', '--disable-pip-version-check', '--no-python-version-warning']\n\n # Default to -1 verbosity\n add_verbosity_flag(command, self.verbosity, adjustment=-1)\n\n command.extend(args)\n return command\n
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.join_command_args","title":"join_command_args(args: list[str])
","text":"This is used by the run
command to construct the root command string from the received arguments.
src/hatch/env/plugin/interface.py
def join_command_args(self, args: list[str]):\n \"\"\"\n This is used by the [`run`](../../cli/reference.md#hatch-run) command to construct the root command string\n from the received arguments.\n \"\"\"\n return self.platform.join_command_args(args)\n
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.check_compatibility","title":"check_compatibility()
","text":"This raises an exception if the environment is not compatible with the user's setup. The default behavior checks for platform compatibility and any method override should keep this check.
This check is never performed if the environment has been created.
Source code insrc/hatch/env/plugin/interface.py
def check_compatibility(self):\n \"\"\"\n This raises an exception if the environment is not compatible with the user's setup. The default behavior\n checks for [platform compatibility](../../config/environment/overview.md#supported-platforms)\n and any method override should keep this check.\n\n This check is never performed if the environment has been\n [created](reference.md#hatch.env.plugin.interface.EnvironmentInterface.create).\n \"\"\"\n if self.platforms and self.platform.name not in self.platforms:\n message = 'unsupported platform'\n raise OSError(message)\n
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.get_option_types","title":"get_option_types() -> dict
staticmethod
","text":"Returns a mapping of supported options to their respective types so that they can be used by overrides.
Source code insrc/hatch/env/plugin/interface.py
@staticmethod\ndef get_option_types() -> dict:\n \"\"\"\n Returns a mapping of supported options to their respective types so that they can be used by\n [overrides](../../config/environment/advanced.md#option-overrides).\n \"\"\"\n return {}\n
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.get_env_var_option","title":"get_env_var_option(option: str) -> str
","text":"Returns the value of the upper-cased environment variable HATCH_ENV_TYPE_<PLUGIN_NAME>_<option>
.
src/hatch/env/plugin/interface.py
def get_env_var_option(self, option: str) -> str:\n \"\"\"\n Returns the value of the upper-cased environment variable `HATCH_ENV_TYPE_<PLUGIN_NAME>_<option>`.\n \"\"\"\n return get_env_var_option(plugin_name=self.PLUGIN_NAME, option=option)\n
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.get_context","title":"get_context()
","text":"Returns a subclass of EnvironmentContextFormatter.
Source code insrc/hatch/env/plugin/interface.py
def get_context(self):\n \"\"\"\n Returns a subclass of\n [EnvironmentContextFormatter](../utilities.md#hatch.env.context.EnvironmentContextFormatter).\n \"\"\"\n from hatch.env.context import EnvironmentContextFormatter\n\n return EnvironmentContextFormatter(self)\n
"},{"location":"plugins/environment/virtual/","title":"Virtual environment","text":"This uses virtual environments backed by virtualenv or UV.
"},{"location":"plugins/environment/virtual/#configuration","title":"Configuration","text":"The environment plugin name is virtual
.
[tool.hatch.envs.<ENV_NAME>]\ntype = \"virtual\"\n
[envs.<ENV_NAME>]\ntype = \"virtual\"\n
"},{"location":"plugins/environment/virtual/#options","title":"Options","text":"Option Default Description python
The version of Python to find on your system and subsequently use to create the environment, defaulting to the HATCH_PYTHON
environment variable, followed by the normal resolution logic. Setting the HATCH_PYTHON
environment variable to self
will force the use of the Python executable Hatch is running on. For more information, see the documentation. python-sources
['external', 'internal']
This may be set to an array of strings that are either the literal internal
or external
. External considers only Python executables that are already on PATH
. Internal considers only internally managed Python distributions. path
An explicit path to the virtual environment. The path may be absolute or relative to the project root. Any environments that inherit this option will also use this path. The environment variable HATCH_ENV_TYPE_VIRTUAL_PATH
may be used, which will take precedence. system-packages
false
Whether or not to give the virtual environment access to the system site-packages
directory installer
pip
When set to uv
, UV will be used in place of virtualenv & pip for virtual environment creation and dependency management, respectively. If you intend to provide UV yourself, you may set the HATCH_ENV_TYPE_VIRTUAL_UV_PATH
environment variable which should be the absolute path to a UV binary. This environment variable implicitly sets the installer
option to uv
(if unset)."},{"location":"plugins/environment/virtual/#location","title":"Location","text":"The location of environments is determined in the following heuristic order:
path
optionvirtual
environment directory if the directory resides somewhere within the project root or if it is set to a .virtualenvs
directory within the user's home directoryvirtual
environment directory in a deeply nested structure in order to support multiple projectsAdditionally, when the path
option is not used, the name of the directory for the default
environment will be the normalized project name to provide a more meaningful default shell prompt.
Virtual environments necessarily require a parent installation of Python. The following rules determine how the parent is resolved.
The Python choice is determined by the python
option followed by the HATCH_PYTHON
environment variable. If the choice is via the environment variable, then resolution stops and that path is used unconditionally.
The resolvers will be based on the python-sources
option and all resolved interpreters will ensure compatibility with the project's defined Python support.
If a Python version has been chosen then each resolver will try to find an interpreter that satisfies that version.
If no version has been chosen, then each resolver will try to find a version that matches the version of Python that Hatch is currently running on. If not found then each resolver will try to find the highest compatible version.
Note
Some external Python paths are considered unstable and are ignored during resolution. For example, if Hatch is installed via Homebrew then sys.executable
will be ignored because the interpreter could change or be removed at any time.
Note
When resolution finds a match using an internally managed distribution and an update is available, the latest distribution will automatically be downloaded before environment creation.
"},{"location":"plugins/environment/virtual/#internal-distributions","title":"Internal distributions","text":"The following options are recognized for internal Python resolution.
Tip
You can set custom sources for distributions by setting the HATCH_PYTHON_SOURCE_<NAME>
environment variable where <NAME>
is the uppercased version of the distribution name with periods replaced by underscores e.g. HATCH_PYTHON_SOURCE_PYPY3_10
.
3.7
3.8
3.9
3.10
3.11
3.12
The source of distributions is the python-build-standalone project.
Some distributions have variants that may be configured with the HATCH_PYTHON_VARIANT_<PLATFORM>
environment variable where <PLATFORM>
is the uppercase version of one of the following:
v1
v2
v3
(default)v4
shared
(default)static
pypy2.7
pypy3.9
pypy3.10
The source of distributions is the PyPy project.
"},{"location":"plugins/environment/virtual/#troubleshooting","title":"Troubleshooting","text":""},{"location":"plugins/environment/virtual/#macos-sip","title":"macOS SIP","text":"If you need to set linker environment variables like those starting with DYLD_
or LD_
, any executable secured by System Integrity Protection that is invoked when running commands will not see those environment variable modifications as macOS strips those.
Hatch interprets such commands as shell commands but deliberately ignores such paths to protected shells. This workaround suffices for the majority of use cases but there are 2 situations in which it may not:
sh
, bash
, zsh
, nor fish
executables found along PATH.pip
and other installers will create such an entry point with a shebang pointing to /bin/sh
(which is protected) to avoid shebang limitations. Rather than changing the location, you could invoke the script as e.g. python -m pytest
(if the project supports that method of invocation by shipping a __main__.py
).The shebang length limit is usually 127 but 3 characters surround the executable path: #!<EXE_PATH>\\n
\u21a9
This is a custom class in a given Python file that inherits from the EnvironmentCollectorInterface.
"},{"location":"plugins/environment-collector/custom/#configuration","title":"Configuration","text":"The environment collector plugin name is custom
.
[tool.hatch.env.collectors.custom]\n
[env.collectors.custom]\n
"},{"location":"plugins/environment-collector/custom/#options","title":"Options","text":"Option Default Description path
hatch_plugins.py
The path of the Python file"},{"location":"plugins/environment-collector/custom/#example","title":"Example","text":"hatch_plugins.py from hatch.env.collectors.plugin.interface import EnvironmentCollectorInterface\n\n\n class CustomEnvironmentCollector(EnvironmentCollectorInterface):\n ...\n
If multiple subclasses are found, you must define a function named get_environment_collector
that returns the desired environment collector.
Note
Any defined PLUGIN_NAME is ignored and will always be custom
.
This adds the default
environment with type set to virtual and will always be applied.
The environment collector plugin name is default
.
[tool.hatch.env.collectors.default]\n
[env.collectors.default]\n
"},{"location":"plugins/environment-collector/default/#options","title":"Options","text":"There are no options available currently.
"},{"location":"plugins/environment-collector/reference/","title":"Environment collector plugins","text":"Environment collectors allow for dynamically modifying environments or adding environments beyond those defined in config. Users can override default values provided by each environment.
"},{"location":"plugins/environment-collector/reference/#known-third-party","title":"Known third-party","text":"Any required environment collectors that are not built-in must be manually installed alongside Hatch or listed in the tool.hatch.env.requires
array for automatic management:
[tool.hatch.env]\nrequires = [\n \"...\",\n]\n
[env]\nrequires = [\n \"...\",\n]\n
"},{"location":"plugins/environment-collector/reference/#hatch.env.collectors.plugin.interface.EnvironmentCollectorInterface","title":"EnvironmentCollectorInterface
","text":"Example usage:
plugin.py hooks.py from hatch.env.collectors.plugin.interface import EnvironmentCollectorInterface\n\n\n class SpecialEnvironmentCollector(EnvironmentCollectorInterface):\n PLUGIN_NAME = 'special'\n ...\n
from hatchling.plugin import hookimpl\n\n from .plugin import SpecialEnvironmentCollector\n\n\n @hookimpl\n def hatch_register_environment_collector():\n return SpecialEnvironmentCollector\n
Source code in src/hatch/env/collectors/plugin/interface.py
class EnvironmentCollectorInterface:\n \"\"\"\n Example usage:\n\n ```python tab=\"plugin.py\"\n from hatch.env.collectors.plugin.interface import EnvironmentCollectorInterface\n\n\n class SpecialEnvironmentCollector(EnvironmentCollectorInterface):\n PLUGIN_NAME = 'special'\n ...\n ```\n\n ```python tab=\"hooks.py\"\n from hatchling.plugin import hookimpl\n\n from .plugin import SpecialEnvironmentCollector\n\n\n @hookimpl\n def hatch_register_environment_collector():\n return SpecialEnvironmentCollector\n ```\n \"\"\"\n\n PLUGIN_NAME = ''\n \"\"\"The name used for selection.\"\"\"\n\n def __init__(self, root, config):\n self.__root = root\n self.__config = config\n\n @property\n def root(self):\n \"\"\"\n The root of the project tree as a path-like object.\n \"\"\"\n return self.__root\n\n @property\n def config(self) -> dict:\n \"\"\"\n ```toml config-example\n [tool.hatch.env.collectors.<PLUGIN_NAME>]\n ```\n \"\"\"\n return self.__config\n\n def get_initial_config(self) -> dict[str, dict]: # noqa: PLR6301\n \"\"\"\n Returns configuration for environments keyed by the environment or matrix name.\n \"\"\"\n return {}\n\n def finalize_config(self, config: dict[str, dict]):\n \"\"\"\n Finalizes configuration for environments keyed by the environment or matrix name. This will override\n any user-defined settings and any collectors that ran before this call.\n\n This is called before matrices are turned into concrete environments.\n \"\"\"\n\n def finalize_environments(self, config: dict[str, dict]):\n \"\"\"\n Finalizes configuration for environments keyed by the environment name. This will override\n any user-defined settings and any collectors that ran before this call.\n\n This is called after matrices are turned into concrete environments.\n \"\"\"\n
"},{"location":"plugins/environment-collector/reference/#hatch.env.collectors.plugin.interface.EnvironmentCollectorInterface.PLUGIN_NAME","title":"PLUGIN_NAME = ''
class-attribute
instance-attribute
","text":"The name used for selection.
"},{"location":"plugins/environment-collector/reference/#hatch.env.collectors.plugin.interface.EnvironmentCollectorInterface.root","title":"root
property
","text":"The root of the project tree as a path-like object.
"},{"location":"plugins/environment-collector/reference/#hatch.env.collectors.plugin.interface.EnvironmentCollectorInterface.config","title":"config: dict
property
","text":"pyproject.toml hatch.toml [tool.hatch.env.collectors.<PLUGIN_NAME>]\n
[env.collectors.<PLUGIN_NAME>]\n
"},{"location":"plugins/environment-collector/reference/#hatch.env.collectors.plugin.interface.EnvironmentCollectorInterface.get_initial_config","title":"get_initial_config() -> dict[str, dict]
","text":"Returns configuration for environments keyed by the environment or matrix name.
Source code insrc/hatch/env/collectors/plugin/interface.py
def get_initial_config(self) -> dict[str, dict]: # noqa: PLR6301\n \"\"\"\n Returns configuration for environments keyed by the environment or matrix name.\n \"\"\"\n return {}\n
"},{"location":"plugins/environment-collector/reference/#hatch.env.collectors.plugin.interface.EnvironmentCollectorInterface.finalize_config","title":"finalize_config(config: dict[str, dict])
","text":"Finalizes configuration for environments keyed by the environment or matrix name. This will override any user-defined settings and any collectors that ran before this call.
This is called before matrices are turned into concrete environments.
Source code insrc/hatch/env/collectors/plugin/interface.py
def finalize_config(self, config: dict[str, dict]):\n \"\"\"\n Finalizes configuration for environments keyed by the environment or matrix name. This will override\n any user-defined settings and any collectors that ran before this call.\n\n This is called before matrices are turned into concrete environments.\n \"\"\"\n
"},{"location":"plugins/environment-collector/reference/#hatch.env.collectors.plugin.interface.EnvironmentCollectorInterface.finalize_environments","title":"finalize_environments(config: dict[str, dict])
","text":"Finalizes configuration for environments keyed by the environment name. This will override any user-defined settings and any collectors that ran before this call.
This is called after matrices are turned into concrete environments.
Source code insrc/hatch/env/collectors/plugin/interface.py
def finalize_environments(self, config: dict[str, dict]):\n \"\"\"\n Finalizes configuration for environments keyed by the environment name. This will override\n any user-defined settings and any collectors that ran before this call.\n\n This is called after matrices are turned into concrete environments.\n \"\"\"\n
"},{"location":"plugins/metadata-hook/custom/","title":"Custom metadata hook","text":"This is a custom class in a given Python file that inherits from the MetadataHookInterface.
"},{"location":"plugins/metadata-hook/custom/#configuration","title":"Configuration","text":"The metadata hook plugin name is custom
.
[tool.hatch.metadata.hooks.custom]\n
[metadata.hooks.custom]\n
"},{"location":"plugins/metadata-hook/custom/#options","title":"Options","text":"Option Default Description path
hatch_build.py
The path of the Python file"},{"location":"plugins/metadata-hook/custom/#example","title":"Example","text":"hatch_build.py from hatchling.metadata.plugin.interface import MetadataHookInterface\n\n\nclass CustomMetadataHook(MetadataHookInterface):\n ...\n
If multiple subclasses are found, you must define a function named get_metadata_hook
that returns the desired build hook.
Note
Any defined PLUGIN_NAME is ignored and will always be custom
.
Metadata hooks allow for the modification of project metadata after it has been loaded.
"},{"location":"plugins/metadata-hook/reference/#known-third-party","title":"Known third-party","text":"package.json
filesrequirements.txt
filespip
and conda
dependency management using a single requirements.yaml
file for both MetadataHookInterface
","text":"Example usage:
plugin.py hooks.pyfrom hatchling.metadata.plugin.interface import MetadataHookInterface\n\n\nclass SpecialMetadataHook(MetadataHookInterface):\n PLUGIN_NAME = 'special'\n ...\n
from hatchling.plugin import hookimpl\n\nfrom .plugin import SpecialMetadataHook\n\n\n@hookimpl\ndef hatch_register_metadata_hook():\n return SpecialMetadataHook\n
Source code in backend/src/hatchling/metadata/plugin/interface.py
class MetadataHookInterface(ABC): # no cov\n \"\"\"\n Example usage:\n\n ```python tab=\"plugin.py\"\n from hatchling.metadata.plugin.interface import MetadataHookInterface\n\n\n class SpecialMetadataHook(MetadataHookInterface):\n PLUGIN_NAME = 'special'\n ...\n ```\n\n ```python tab=\"hooks.py\"\n from hatchling.plugin import hookimpl\n\n from .plugin import SpecialMetadataHook\n\n\n @hookimpl\n def hatch_register_metadata_hook():\n return SpecialMetadataHook\n ```\n \"\"\"\n\n PLUGIN_NAME = ''\n \"\"\"The name used for selection.\"\"\"\n\n def __init__(self, root: str, config: dict) -> None:\n self.__root = root\n self.__config = config\n\n @property\n def root(self) -> str:\n \"\"\"\n The root of the project tree.\n \"\"\"\n return self.__root\n\n @property\n def config(self) -> dict:\n \"\"\"\n The hook configuration.\n\n ```toml config-example\n [tool.hatch.metadata.hooks.<PLUGIN_NAME>]\n ```\n \"\"\"\n return self.__config\n\n @abstractmethod\n def update(self, metadata: dict) -> None:\n \"\"\"\n This updates the metadata mapping of the `project` table in-place.\n \"\"\"\n\n def get_known_classifiers(self) -> list[str]: # noqa: PLR6301\n \"\"\"\n This returns extra classifiers that should be considered valid in addition to the ones known to PyPI.\n \"\"\"\n return []\n
"},{"location":"plugins/metadata-hook/reference/#hatchling.metadata.plugin.interface.MetadataHookInterface.PLUGIN_NAME","title":"PLUGIN_NAME = ''
class-attribute
instance-attribute
","text":"The name used for selection.
"},{"location":"plugins/metadata-hook/reference/#hatchling.metadata.plugin.interface.MetadataHookInterface.root","title":"root: str
property
","text":"The root of the project tree.
"},{"location":"plugins/metadata-hook/reference/#hatchling.metadata.plugin.interface.MetadataHookInterface.config","title":"config: dict
property
","text":"The hook configuration.
pyproject.toml hatch.toml[tool.hatch.metadata.hooks.<PLUGIN_NAME>]\n
[metadata.hooks.<PLUGIN_NAME>]\n
"},{"location":"plugins/metadata-hook/reference/#hatchling.metadata.plugin.interface.MetadataHookInterface.update","title":"update(metadata: dict) -> None
abstractmethod
","text":"This updates the metadata mapping of the project
table in-place.
backend/src/hatchling/metadata/plugin/interface.py
@abstractmethod\ndef update(self, metadata: dict) -> None:\n \"\"\"\n This updates the metadata mapping of the `project` table in-place.\n \"\"\"\n
"},{"location":"plugins/metadata-hook/reference/#hatchling.metadata.plugin.interface.MetadataHookInterface.get_known_classifiers","title":"get_known_classifiers() -> list[str]
","text":"This returns extra classifiers that should be considered valid in addition to the ones known to PyPI.
Source code inbackend/src/hatchling/metadata/plugin/interface.py
def get_known_classifiers(self) -> list[str]: # noqa: PLR6301\n \"\"\"\n This returns extra classifiers that should be considered valid in addition to the ones known to PyPI.\n \"\"\"\n return []\n
"},{"location":"plugins/publisher/package-index/","title":"Index publisher","text":"See the documentation for publishing.
"},{"location":"plugins/publisher/package-index/#options","title":"Options","text":"Flag Config name Description-r
/--repo
repo
The repository with which to publish artifacts -u
/--user
user
The user with which to authenticate -a
/--auth
auth
The credentials to use for authentication --ca-cert
ca-cert
The path to a CA bundle --client-cert
client-cert
The path to a client certificate, optionally containing the private key --client-key
client-key
The path to the client certificate's private key repos
A table of named repositories to their respective options"},{"location":"plugins/publisher/package-index/#configuration","title":"Configuration","text":"The publisher plugin name is index
.
[publish.index]\n
"},{"location":"plugins/publisher/package-index/#repositories","title":"Repositories","text":"All top-level options can be overridden per repository using the repos
table with a required url
attribute for each repository. The following shows the default configuration:
[publish.index.repos.main]\nurl = \"https://upload.pypi.org/legacy/\"\n\n[publish.index.repos.test]\nurl = \"https://test.pypi.org/legacy/\"\n
The repo
and repos
options have no effect.
You can require a confirmation prompt or use of the -y
/--yes
flag by setting publishers' disable
option to true
in either Hatch's config file or project-specific configuration (which takes precedence):
[publish.index]\ndisable = true\n
[tool.hatch.publish.index]\ndisable = true\n
[publish.index]\ndisable = true\n
"},{"location":"plugins/publisher/reference/","title":"Publisher plugins","text":""},{"location":"plugins/publisher/reference/#known-third-party","title":"Known third-party","text":"PublisherInterface
","text":"Example usage:
plugin.py hooks.py from hatch.publish.plugin.interface import PublisherInterface\n\n\n class SpecialPublisher(PublisherInterface):\n PLUGIN_NAME = 'special'\n ...\n
from hatchling.plugin import hookimpl\n\n from .plugin import SpecialPublisher\n\n\n @hookimpl\n def hatch_register_publisher():\n return SpecialPublisher\n
Source code in src/hatch/publish/plugin/interface.py
class PublisherInterface(ABC):\n \"\"\"\n Example usage:\n\n ```python tab=\"plugin.py\"\n from hatch.publish.plugin.interface import PublisherInterface\n\n\n class SpecialPublisher(PublisherInterface):\n PLUGIN_NAME = 'special'\n ...\n ```\n\n ```python tab=\"hooks.py\"\n from hatchling.plugin import hookimpl\n\n from .plugin import SpecialPublisher\n\n\n @hookimpl\n def hatch_register_publisher():\n return SpecialPublisher\n ```\n \"\"\"\n\n PLUGIN_NAME = ''\n \"\"\"The name used for selection.\"\"\"\n\n def __init__(self, app, root, cache_dir, project_config, plugin_config):\n self.__app = app\n self.__root = root\n self.__cache_dir = cache_dir\n self.__project_config = project_config\n self.__plugin_config = plugin_config\n\n self.__disable = None\n\n @property\n def app(self):\n \"\"\"\n An instance of [Application](../utilities.md#hatchling.bridge.app.Application).\n \"\"\"\n return self.__app\n\n @property\n def root(self):\n \"\"\"\n The root of the project tree as a path-like object.\n \"\"\"\n return self.__root\n\n @property\n def cache_dir(self):\n \"\"\"\n The directory reserved exclusively for this plugin as a path-like object.\n \"\"\"\n return self.__cache_dir\n\n @property\n def project_config(self) -> dict:\n \"\"\"\n ```toml config-example\n [tool.hatch.publish.<PLUGIN_NAME>]\n ```\n \"\"\"\n return self.__project_config\n\n @property\n def plugin_config(self) -> dict:\n \"\"\"\n This is defined in Hatch's [config file](../../config/hatch.md).\n\n ```toml tab=\"config.toml\"\n [publish.<PLUGIN_NAME>]\n ```\n \"\"\"\n return self.__plugin_config\n\n @property\n def disable(self):\n \"\"\"\n Whether this plugin is disabled, thus requiring confirmation when publishing. Local\n [project configuration](reference.md#hatch.publish.plugin.interface.PublisherInterface.project_config)\n takes precedence over global\n [plugin configuration](reference.md#hatch.publish.plugin.interface.PublisherInterface.plugin_config).\n \"\"\"\n if self.__disable is None:\n if 'disable' in self.project_config:\n disable = self.project_config['disable']\n if not isinstance(disable, bool):\n message = f'Field `tool.hatch.publish.{self.PLUGIN_NAME}.disable` must be a boolean'\n raise TypeError(message)\n else:\n disable = self.plugin_config.get('disable', False)\n if not isinstance(disable, bool):\n message = f'Global plugin configuration `publish.{self.PLUGIN_NAME}.disable` must be a boolean'\n raise TypeError(message)\n\n self.__disable = disable\n\n return self.__disable\n\n @abstractmethod\n def publish(self, artifacts: list[str], options: dict):\n \"\"\"\n :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n This is called directly by the [`publish`](../../cli/reference.md#hatch-publish) command\n with the arguments and options it receives.\n \"\"\"\n
"},{"location":"plugins/publisher/reference/#hatch.publish.plugin.interface.PublisherInterface.PLUGIN_NAME","title":"PLUGIN_NAME = ''
class-attribute
instance-attribute
","text":"The name used for selection.
"},{"location":"plugins/publisher/reference/#hatch.publish.plugin.interface.PublisherInterface.app","title":"app
property
","text":"An instance of Application.
"},{"location":"plugins/publisher/reference/#hatch.publish.plugin.interface.PublisherInterface.root","title":"root
property
","text":"The root of the project tree as a path-like object.
"},{"location":"plugins/publisher/reference/#hatch.publish.plugin.interface.PublisherInterface.cache_dir","title":"cache_dir
property
","text":"The directory reserved exclusively for this plugin as a path-like object.
"},{"location":"plugins/publisher/reference/#hatch.publish.plugin.interface.PublisherInterface.project_config","title":"project_config: dict
property
","text":"pyproject.toml hatch.toml [tool.hatch.publish.<PLUGIN_NAME>]\n
[publish.<PLUGIN_NAME>]\n
"},{"location":"plugins/publisher/reference/#hatch.publish.plugin.interface.PublisherInterface.plugin_config","title":"plugin_config: dict
property
","text":"This is defined in Hatch's config file.
config.toml[publish.<PLUGIN_NAME>]\n
"},{"location":"plugins/publisher/reference/#hatch.publish.plugin.interface.PublisherInterface.disable","title":"disable
property
","text":"Whether this plugin is disabled, thus requiring confirmation when publishing. Local project configuration takes precedence over global plugin configuration.
"},{"location":"plugins/publisher/reference/#hatch.publish.plugin.interface.PublisherInterface.publish","title":"publish(artifacts: list[str], options: dict)
abstractmethod
","text":"REQUIRED
This is called directly by the publish
command with the arguments and options it receives.
src/hatch/publish/plugin/interface.py
@abstractmethod\ndef publish(self, artifacts: list[str], options: dict):\n \"\"\"\n :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n This is called directly by the [`publish`](../../cli/reference.md#hatch-publish) command\n with the arguments and options it receives.\n \"\"\"\n
"},{"location":"plugins/version-scheme/reference/","title":"Version scheme plugins","text":""},{"location":"plugins/version-scheme/reference/#known-third-party","title":"Known third-party","text":"VersionSchemeInterface
","text":"Example usage:
plugin.py hooks.pyfrom hatchling.version.scheme.plugin.interface import VersionSchemeInterface\n\n\nclass SpecialVersionScheme(VersionSchemeInterface):\n PLUGIN_NAME = 'special'\n ...\n
from hatchling.plugin import hookimpl\n\nfrom .plugin import SpecialVersionScheme\n\n\n@hookimpl\ndef hatch_register_version_scheme():\n return SpecialVersionScheme\n
Source code in backend/src/hatchling/version/scheme/plugin/interface.py
class VersionSchemeInterface(ABC): # no cov\n \"\"\"\n Example usage:\n\n ```python tab=\"plugin.py\"\n from hatchling.version.scheme.plugin.interface import VersionSchemeInterface\n\n\n class SpecialVersionScheme(VersionSchemeInterface):\n PLUGIN_NAME = 'special'\n ...\n ```\n\n ```python tab=\"hooks.py\"\n from hatchling.plugin import hookimpl\n\n from .plugin import SpecialVersionScheme\n\n\n @hookimpl\n def hatch_register_version_scheme():\n return SpecialVersionScheme\n ```\n \"\"\"\n\n PLUGIN_NAME = ''\n \"\"\"The name used for selection.\"\"\"\n\n def __init__(self, root: str, config: dict) -> None:\n self.__root = root\n self.__config = config\n\n @property\n def root(self) -> str:\n \"\"\"\n The root of the project tree as a string.\n \"\"\"\n return self.__root\n\n @property\n def config(self) -> dict:\n \"\"\"\n ```toml config-example\n [tool.hatch.version]\n ```\n \"\"\"\n return self.__config\n\n @abstractmethod\n def update(self, desired_version: str, original_version: str, version_data: dict) -> str:\n \"\"\"\n This should return a normalized form of the desired version and verify that it\n is higher than the original version.\n \"\"\"\n
"},{"location":"plugins/version-scheme/reference/#hatchling.version.scheme.plugin.interface.VersionSchemeInterface.PLUGIN_NAME","title":"PLUGIN_NAME = ''
class-attribute
instance-attribute
","text":"The name used for selection.
"},{"location":"plugins/version-scheme/reference/#hatchling.version.scheme.plugin.interface.VersionSchemeInterface.root","title":"root: str
property
","text":"The root of the project tree as a string.
"},{"location":"plugins/version-scheme/reference/#hatchling.version.scheme.plugin.interface.VersionSchemeInterface.config","title":"config: dict
property
","text":"pyproject.toml hatch.toml [tool.hatch.version]\n
[version]\n
"},{"location":"plugins/version-scheme/reference/#hatchling.version.scheme.plugin.interface.VersionSchemeInterface.update","title":"update(desired_version: str, original_version: str, version_data: dict) -> str
abstractmethod
","text":"This should return a normalized form of the desired version and verify that it is higher than the original version.
Source code inbackend/src/hatchling/version/scheme/plugin/interface.py
@abstractmethod\ndef update(self, desired_version: str, original_version: str, version_data: dict) -> str:\n \"\"\"\n This should return a normalized form of the desired version and verify that it\n is higher than the original version.\n \"\"\"\n
"},{"location":"plugins/version-scheme/standard/","title":"Standard version scheme","text":"See the documentation for versioning.
"},{"location":"plugins/version-scheme/standard/#configuration","title":"Configuration","text":"The version scheme plugin name is standard
.
[tool.hatch.version]\nscheme = \"standard\"\n
[version]\nscheme = \"standard\"\n
"},{"location":"plugins/version-scheme/standard/#options","title":"Options","text":"Option Description validate-bump
When setting a specific version, this determines whether to check that the new version is higher than the original. The default is true
."},{"location":"plugins/version-source/code/","title":"Code version source","text":""},{"location":"plugins/version-source/code/#updates","title":"Updates","text":"Setting the version is not supported.
"},{"location":"plugins/version-source/code/#configuration","title":"Configuration","text":"The version source plugin name is code
.
[tool.hatch.version]\nsource = \"code\"\n
[version]\nsource = \"code\"\n
"},{"location":"plugins/version-source/code/#options","title":"Options","text":"Option Description path
(required) A relative path to a Python file or extension module that will be loaded expression
A Python expression that when evaluated in the context of the loaded file returns the version. The default expression is simply __version__
. search-paths
A list of relative paths to directories that will be prepended to Python's search path"},{"location":"plugins/version-source/code/#missing-imports","title":"Missing imports","text":"If the chosen path imports another module in your project, then you'll need to use absolute imports coupled with the search-paths
option. For example, say you need to load the following file:
from ._version import get_version\n\n __version__ = get_version()\n
You should change it to:
src/pkg/__init__.py from pkg._version import get_version\n\n __version__ = get_version()\n
and the configuration would become:
pyproject.toml hatch.toml[tool.hatch.version]\nsource = \"code\"\npath = \"src/pkg/__init__.py\"\nsearch-paths = [\"src\"]\n
[version]\nsource = \"code\"\npath = \"src/pkg/__init__.py\"\nsearch-paths = [\"src\"]\n
"},{"location":"plugins/version-source/env/","title":"Environment version source","text":"Retrieves the version from an environment variable. This can be useful in build pipelines where the version is set by an external trigger.
"},{"location":"plugins/version-source/env/#updates","title":"Updates","text":"Setting the version is not supported.
"},{"location":"plugins/version-source/env/#configuration","title":"Configuration","text":"The version source plugin name is env
.
[tool.hatch.version]\nsource = \"env\"\n
[version]\nsource = \"env\"\n
"},{"location":"plugins/version-source/env/#options","title":"Options","text":"Option Description variable
(required) The name of the environment variable"},{"location":"plugins/version-source/reference/","title":"Version source plugins","text":""},{"location":"plugins/version-source/reference/#known-third-party","title":"Known third-party","text":"version
field of NodeJS package.json
filesVersionSourceInterface
","text":"Example usage:
plugin.py hooks.pyfrom hatchling.version.source.plugin.interface import VersionSourceInterface\n\n\nclass SpecialVersionSource(VersionSourceInterface):\n PLUGIN_NAME = 'special'\n ...\n
from hatchling.plugin import hookimpl\n\nfrom .plugin import SpecialVersionSource\n\n\n@hookimpl\ndef hatch_register_version_source():\n return SpecialVersionSource\n
Source code in backend/src/hatchling/version/source/plugin/interface.py
class VersionSourceInterface(ABC): # no cov\n \"\"\"\n Example usage:\n\n ```python tab=\"plugin.py\"\n from hatchling.version.source.plugin.interface import VersionSourceInterface\n\n\n class SpecialVersionSource(VersionSourceInterface):\n PLUGIN_NAME = 'special'\n ...\n ```\n\n ```python tab=\"hooks.py\"\n from hatchling.plugin import hookimpl\n\n from .plugin import SpecialVersionSource\n\n\n @hookimpl\n def hatch_register_version_source():\n return SpecialVersionSource\n ```\n \"\"\"\n\n PLUGIN_NAME = ''\n \"\"\"The name used for selection.\"\"\"\n\n def __init__(self, root: str, config: dict) -> None:\n self.__root = root\n self.__config = config\n\n @property\n def root(self) -> str:\n \"\"\"\n The root of the project tree as a string.\n \"\"\"\n return self.__root\n\n @property\n def config(self) -> dict:\n \"\"\"\n ```toml config-example\n [tool.hatch.version]\n ```\n \"\"\"\n return self.__config\n\n @abstractmethod\n def get_version_data(self) -> dict:\n \"\"\"\n This should return a mapping with a `version` key representing the current version of the project and will be\n displayed when invoking the [`version`](../../cli/reference.md#hatch-version) command without any arguments.\n\n The mapping can contain anything else and will be passed to\n [set_version](reference.md#hatchling.version.source.plugin.interface.VersionSourceInterface.set_version)\n when updating the version.\n \"\"\"\n\n def set_version(self, version: str, version_data: dict) -> None:\n \"\"\"\n This should update the version to the first argument with the data provided during retrieval.\n \"\"\"\n raise NotImplementedError\n
"},{"location":"plugins/version-source/reference/#hatchling.version.source.plugin.interface.VersionSourceInterface.PLUGIN_NAME","title":"PLUGIN_NAME = ''
class-attribute
instance-attribute
","text":"The name used for selection.
"},{"location":"plugins/version-source/reference/#hatchling.version.source.plugin.interface.VersionSourceInterface.root","title":"root: str
property
","text":"The root of the project tree as a string.
"},{"location":"plugins/version-source/reference/#hatchling.version.source.plugin.interface.VersionSourceInterface.config","title":"config: dict
property
","text":"pyproject.toml hatch.toml [tool.hatch.version]\n
[version]\n
"},{"location":"plugins/version-source/reference/#hatchling.version.source.plugin.interface.VersionSourceInterface.get_version_data","title":"get_version_data() -> dict
abstractmethod
","text":"This should return a mapping with a version
key representing the current version of the project and will be displayed when invoking the version
command without any arguments.
The mapping can contain anything else and will be passed to set_version when updating the version.
Source code inbackend/src/hatchling/version/source/plugin/interface.py
@abstractmethod\ndef get_version_data(self) -> dict:\n \"\"\"\n This should return a mapping with a `version` key representing the current version of the project and will be\n displayed when invoking the [`version`](../../cli/reference.md#hatch-version) command without any arguments.\n\n The mapping can contain anything else and will be passed to\n [set_version](reference.md#hatchling.version.source.plugin.interface.VersionSourceInterface.set_version)\n when updating the version.\n \"\"\"\n
"},{"location":"plugins/version-source/reference/#hatchling.version.source.plugin.interface.VersionSourceInterface.set_version","title":"set_version(version: str, version_data: dict) -> None
","text":"This should update the version to the first argument with the data provided during retrieval.
Source code inbackend/src/hatchling/version/source/plugin/interface.py
def set_version(self, version: str, version_data: dict) -> None:\n \"\"\"\n This should update the version to the first argument with the data provided during retrieval.\n \"\"\"\n raise NotImplementedError\n
"},{"location":"plugins/version-source/regex/","title":"Regex version source","text":"See the documentation for versioning.
"},{"location":"plugins/version-source/regex/#updates","title":"Updates","text":"Setting the version is supported.
"},{"location":"plugins/version-source/regex/#configuration","title":"Configuration","text":"The version source plugin name is regex
.
[tool.hatch.version]\nsource = \"regex\"\n
[version]\nsource = \"regex\"\n
"},{"location":"plugins/version-source/regex/#options","title":"Options","text":"Option Description path
(required) A relative path to a file containing the project's version pattern
A regular expression that has a named group called version
that represents the version. The default pattern looks for a variable named __version__
or VERSION
that is set to a string containing the version, optionally prefixed with the lowercase letter v
."},{"location":"tutorials/environment/basic-usage/","title":"Managing environments","text":"Hatch environments are isolated workspaces that can be used for project tasks including running tests, building documentation and running code formatters and linters.
"},{"location":"tutorials/environment/basic-usage/#the-default-environment","title":"The default environment","text":"When you start using Hatch, you can create the default
environment. To do this use the env create
command:
hatch env create\n
This will not only create will the default
environment for you to work in but will also install your project in dev mode in this default
environment.
Tip
You never need to manually create environments as spawning a shell or running commands within one will automatically trigger creation.
"},{"location":"tutorials/environment/basic-usage/#using-the-default-environment","title":"Using the default environment","text":"Hatch will always use the default
environment if an environment is not chosen explicitly when running a command.
For instance, the following shows how to get version information for the Python in use.
$ hatch run python -V\nPython 3.12.1\n
"},{"location":"tutorials/environment/basic-usage/#configure-the-default-environment","title":"Configure the default environment","text":"You can customize the tools that are installed into the default
environment by adding a table called tool.hatch.envs.default
to your pyproject.toml
file. Below is an example of adding the dependencies pydantic
and numpy
to the default
environment.
[tool.hatch.envs.default]\ndependencies = [\n \"pydantic\",\n \"numpy\",\n]\n
[envs.default]\ndependencies = [\n \"pydantic\",\n \"numpy\",\n]\n
You can declare versions for your dependencies as well within this configuration.
pyproject.toml hatch.toml[tool.hatch.envs.default]\ndependencies = [\n \"pydantic>=2.0\",\n \"numpy\",\n]\n
[envs.default]\ndependencies = [\n \"pydantic>=2.0\",\n \"numpy\",\n]\n
"},{"location":"tutorials/environment/basic-usage/#create-custom-environment","title":"Create custom environment","text":"You can create custom environments in Hatch by adding a section to your pyproject.toml
file [tool.hatch.envs.<ENV_NAME>]
. Below you define an environment called test
and you add the pytest
and pytest-cov
dependencies to that environment's configuration.
[tool.hatch.envs.test]\ndependencies = [\n \"pytest\",\n \"pytest-cov\"\n]\n
[envs.test]\ndependencies = [\n \"pytest\",\n \"pytest-cov\"\n]\n
The first time that you call the test environment, Hatch will:
Hatch offers a unique environment feature that allows you run a specific command within a specific environment rather than needing to activate the environment as you would using a tool such as Conda or venv.
For instance, if you define an environment called test
that contains the dependencies from the previous section, you can run the pytest
command from the test
environment using the syntax:
hatch run <ENV_NAME>:command\n
To access the test
environment and run pytest
, you can run:
$ hatch run test:pytest\n============================== test session starts ===============================\nplatform darwin -- Python 3.12.1, pytest-7.4.4, pluggy-1.3.0\nrootdir: /your/path/to/yourproject\ncollected 0 items\n
Note
test:pytest
represents the name of the environment to call (test
) and the command to run (pytest
).
Above you defined and created a new test environment in your pyproject.toml
file. You can now use the env show
command to see both the currently created environments and the dependencies in each environment.
$ hatch env show\n Standalone\n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Name \u2503 Type \u2503 Dependencies \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 default \u2502 virtual \u2502 \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 test \u2502 virtual \u2502 pytest \u2502\n\u2502 \u2502 \u2502 pytest-cov \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n
Note
The output may have more columns depending on your environment configuration.
"},{"location":"tutorials/environment/basic-usage/#locating-environments","title":"Locating environments","text":"To see where your current environment is located you can use the env find
command.
$ hatch env find test\n/your/path/Application Support/hatch/env/virtual/yourproject/twO2iQR3/test\n
Note
That path is what you would see on macOS but differs for each platform, and is configurable.
"},{"location":"tutorials/environment/basic-usage/#launching-a-shell-within-a-specific-environment","title":"Launching a shell within a specific environment","text":"If you wish to launch a shell for a specific environment that you have created, like the previous test
environment, you can use:
hatch -e test shell\n
Once the environment is active, you can run commands like you would in any Python environment.
Notice below that when running pip list
in the test environment, you can see:
pytest
and pytest-cov
as specified above in the pyproject.toml
file.$ pip list\nPackage Version Editable project location\n----------- ------- ----------------------------------------------------\ncoverage 7.4.1\niniconfig 2.0.0\npackaging 23.2\npip 23.3.1\npluggy 1.4.0\npytest 8.0.0\npytest-cov 4.1.0\nyourproject 0.1.0 /your/path/to/yourproject\n
"},{"location":"tutorials/environment/basic-usage/#conda-environments","title":"Conda environments","text":"If you prefer to use Conda environments with Hatch, you can check out the hatch-conda plugin.
"},{"location":"tutorials/python/manage/","title":"Managing Python distributions","text":"The python
command group provides a set of commands to manage Python distributions that may be used by other tools.
Note
When using environments, manual management is not necessary since by default Hatch will automatically download and manage Python distributions internally when a requested version cannot be found.
"},{"location":"tutorials/python/manage/#location","title":"Location","text":"There are two ways to control where Python distributions are installed. Both methods make it so that each installed distribution is placed in a subdirectory of the configured location named after the distribution.
-d
/--dir
option of every python
subcommand, which takes precedence over the default directory.To install a Python distribution, use the python install
command. For example:
hatch python install 3.12\n
This will:
3.12
Python distribution3.12
within the configured default directory for Python installationsNow its python
executable can be used by you or other tools.
Note
For PATH changes to take effect in the current shell, you will need to restart it.
"},{"location":"tutorials/python/manage/#multiple","title":"Multiple","text":"You can install multiple Python distributions at once by providing multiple distribution names. For example:
hatch python install 3.12 3.11 pypy3.10\n
If you would like to install all available Python distributions that are compatible with your system, use all
as the distribution name:
hatch python install all\n
Tip
The commands for updating and removing also support this functionality.
"},{"location":"tutorials/python/manage/#private","title":"Private","text":"By default, installing Python distributions will add them to the user PATH. To disable this behavior, use the --private
flag like so:
hatch python install 3.12 --private\n
This when combined with the directory option can be used to create private, isolated installations.
"},{"location":"tutorials/python/manage/#listing-distributions","title":"Listing distributions","text":"You can see all of the available and installed Python distributions by using the python show
command. For example, if you already installed the 3.12
distribution you may see something like this:
$ hatch python show\n Installed\n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Name \u2503 Version \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 3.12 \u2502 3.12.3 \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Available\n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Name \u2503 Version \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 3.7 \u2502 3.7.9 \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 3.8 \u2502 3.8.19 \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 3.9 \u2502 3.9.19 \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 3.10 \u2502 3.10.14 \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 3.11 \u2502 3.11.9 \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 pypy2.7 \u2502 7.3.15 \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 pypy3.9 \u2502 7.3.15 \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 pypy3.10 \u2502 7.3.15 \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n
"},{"location":"tutorials/python/manage/#finding-installations","title":"Finding installations","text":"The Python executable of an installed distribution can be found by using the python find
command. For example:
$ hatch python find 3.12\n/home/.local/share/hatch/pythons/3.12/python/bin/python3\n
You can instead output its parent directory by using the -p
/--parent
flag:
$ hatch python find 3.12 --parent\n/home/.local/share/hatch/pythons/3.12/python/bin\n
This is useful when other tools do not need to use the executable directly but require knowing the directory containing it.
"},{"location":"tutorials/python/manage/#updates","title":"Updates","text":"To update installed Python distributions, use the python update
command. For example:
hatch python update 3.12 3.11 pypy3.10\n
When there are no updates available for a distribution, a warning will be displayed:
$ hatch python update 3.12\nThe latest version is already installed: 3.12.3\n
"},{"location":"tutorials/python/manage/#removal","title":"Removal","text":"To remove installed Python distributions, use the python remove
command. For example:
hatch python remove 3.12 3.11 pypy3.10\n
"},{"location":"tutorials/testing/overview/","title":"Testing projects","text":"The test
command (by default) uses pytest with select plugins and coverage.py. View the testing configuration for more information.
The majority of projects can be fully tested this way without the need for custom environments.
"},{"location":"tutorials/testing/overview/#passing-arguments","title":"Passing arguments","text":"When you run the test
command without any arguments, tests
is passed as the default argument to pytest
(this assumes that you have a tests
directory). For example, the following command invocation:
hatch test\n
would be translated roughly to:
pytest tests\n
You can pass arguments to pytest
by appending them to the test
command. For example, the following command invocation:
hatch test -vv tests/test_foo.py::test_bar\n
would be translated roughly to:
pytest -vv tests/test_foo.py::test_bar\n
You can force the treatment of arguments as positional by using the --
separator, especially useful when built-in flags of the test
command conflict with those of pytest
, such as the --help
flag. For example, the following command invocation:
hatch test -r -- -r fE -- tests\n
would be translated roughly to:
pytest -r fE -- tests\n
Note
It's important to ensure that pytest
receives an argument instructing what to run/where to locate tests. It's default behavior is .
meaning that it will exhaustively search for tests in the current directory. This can not just be slow but also lead to unexpected behavior.
If no environment options are selected, the test
command will only run tests in the first defined environment that either already exists or is compatible. Additionally, the checking order will prioritize environments that define a version of Python that matches the interpreter that Hatch is running on.
For example, if you overrode the default matrix as follows:
pyproject.toml hatch.toml[[tool.hatch.envs.hatch-test.matrix]]\npython = [\"3.12\", \"3.11\"]\n\n[[tool.hatch.envs.hatch-test.matrix]]\npython = [\"3.11\"]\nfeature = [\"foo\", \"bar\"]\n
[[envs.hatch-test.matrix]]\npython = [\"3.12\", \"3.11\"]\n\n[[envs.hatch-test.matrix]]\npython = [\"3.11\"]\nfeature = [\"foo\", \"bar\"]\n
the expanded environments would normally be:
hatch-test.py3.12\nhatch-test.py3.11\nhatch-test.py3.11-foo\nhatch-test.py3.11-bar\n
If you install Hatch on Python 3.11, the checking order would be:
hatch-test.py3.11\nhatch-test.py3.11-foo\nhatch-test.py3.11-bar\nhatch-test.py3.12\n
Note
If you installed Hatch with an official installer or are using one of the standalone binaries, the version of Python that Hatch runs on is out of your control. If you are relying on the single environment resolution behavior, consider explicitly selecting environments based on the Python version instead.
"},{"location":"tutorials/testing/overview/#all-environments","title":"All environments","text":"You can run tests in all compatible environments by using the --all
flag. For example, say you defined the matrix and overrides as follows:
[[tool.hatch.envs.hatch-test.matrix]]\npython = [\"3.12\", \"3.11\"]\nfeature = [\"foo\", \"bar\"]\n\n[tool.hatch.envs.hatch-test.overrides]\nmatrix.feature.platforms = [\n { value = \"linux\", if = [\"foo\", \"bar\"] },\n { value = \"windows\", if = [\"foo\"] },\n { value = \"macos\", if = [\"bar\"] },\n]\n
[[envs.hatch-test.matrix]]\npython = [\"3.12\", \"3.11\"]\nfeature = [\"foo\", \"bar\"]\n\n[envs.hatch-test.overrides]\nmatrix.feature.platforms = [\n { value = \"linux\", if = [\"foo\", \"bar\"] },\n { value = \"windows\", if = [\"foo\"] },\n { value = \"macos\", if = [\"bar\"] },\n]\n
The following table shows the environments in which tests would be run:
Environment Linux Windows macOShatch-test.py3.12-foo
hatch-test.py3.12-bar
hatch-test.py3.11-foo
hatch-test.py3.11-bar
"},{"location":"tutorials/testing/overview/#specific-environments","title":"Specific environments","text":"You can select subsets of environments by using the --include
/-i
and --exclude
/-x
options. These options may be used to include or exclude certain matrix variables, optionally followed by specific comma-separated values, and may be selected multiple times.
For example, say you defined the matrix as follows:
pyproject.toml hatch.toml[[tool.hatch.envs.hatch-test.matrix]]\npython = [\"3.12\", \"3.11\"]\nfeature = [\"foo\", \"bar\", \"baz\"]\n
[[envs.hatch-test.matrix]]\npython = [\"3.12\", \"3.11\"]\nfeature = [\"foo\", \"bar\", \"baz\"]\n
If you wanted to run tests in all environments that have Python 3.12 and either the foo
or bar
feature, you could use the following command invocation:
hatch test -i python=3.12 -i feature=foo,bar\n
Alternatively, we could exclude the baz
feature to achieve the same result:
hatch test -i python=3.12 -x feature=baz\n
Tip
Since selecting the version of Python is a common use case, you can use the --python
/-py
option as a shorthand. For example, the previous commands could have been written as:
hatch test -py 3.12 -i feature=foo,bar\nhatch test -py 3.12 -x feature=baz\n
"},{"location":"tutorials/testing/overview/#measuring-code-coverage","title":"Measuring code coverage","text":"You can enable code coverage by using the --cover
flag. For example, the following command invocation:
hatch test --cover\n
would be translated roughly to:
coverage run -m pytest tests\n
After tests run in all of the selected environments, the coverage data is combined and a report is shown. The --cover-quiet
flag can be used to suppress the report and implicitly enables the --cover
flag:
hatch test --cover-quiet\n
Note
Coverage data files are generated at the root of the project. Be sure to exclude them from version control with the following glob-style pattern:
.coverage*\n
"},{"location":"tutorials/testing/overview/#retry-failed-tests","title":"Retry failed tests","text":"You can retry failed tests with the --retries
option:
hatch test --retries 2\n
If a test fails every time and the number of retries is set to 2
, the test will be run a total of three times.
You can also set the number of seconds to wait between retries with the --retry-delay
option:
hatch test --retries 2 --retry-delay 1\n
"},{"location":"tutorials/testing/overview/#parallelize-test-execution","title":"Parallelize test execution","text":"You can parallelize test execution with the --parallel
/-p
flag:
hatch test --parallel\n
This distributes tests within an environment across multiple workers. The number of workers corresponds to the number of logical rather than physical CPUs that are available.
"},{"location":"tutorials/testing/overview/#randomize-test-order","title":"Randomize test order","text":"You can randomize the order of tests with the --randomize
/-r
flag:
hatch test --randomize\n
"},{"location":"blog/archive/2024/","title":"2024","text":""},{"location":"blog/archive/2023/","title":"2023","text":""},{"location":"blog/archive/2022/","title":"2022","text":""},{"location":"blog/category/release/","title":"Release","text":""}]}
\ No newline at end of file
+{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"],"fields":{"title":{"boost":1000.0},"text":{"boost":1.0},"tags":{"boost":1000000.0}}},"docs":[{"location":"","title":"Hatch","text":"CI/CD Docs Package Meta Hatch is a modern, extensible Python project manager. See the Why Hatch? page for more information.
Build system
Reproducible builds by default with a rich ecosystem of plugins
Configure builds
Environments
Robust environment management with support for custom scripts and UV
Getting started
Python management
Choose between easy manual installations or automatic as part of environments
Try it
Testing
Test execution with known best practices
Run
Static analysis
Static analysis backed by Ruff with up-to-date, sane defaults
Learn
Script runner
Execute Python scripts with specific dependencies and Python versions
Execute
Publishing
Easily upload to PyPI or other indices
See how
Versioning
Streamlined workflow for bumping versions
Managing versions
Project generation
Create new projects from templates with known best practices
Project setup
Responsive CLI
Hatch is up to 3x faster than equivalent tools
CLI reference
Hatch is distributed under the terms of the MIT license.
"},{"location":"#navigation","title":"Navigation","text":"Documentation for specific MAJOR.MINOR
versions can be chosen by using the dropdown on the top of every page. The dev
version reflects changes that have not yet been released.
Also, desktop readers can use special keyboard shortcuts:
Keys ActionBuilds are configured using the tool.hatch.build
table. Every target is defined by a section within tool.hatch.build.targets
, for example:
[tool.hatch.build.targets.sdist]\nexclude = [\n \"/.github\",\n \"/docs\",\n]\n\n[tool.hatch.build.targets.wheel]\npackages = [\"src/foo\"]\n
[build.targets.sdist]\nexclude = [\n \"/.github\",\n \"/docs\",\n]\n\n[build.targets.wheel]\npackages = [\"src/foo\"]\n
"},{"location":"build/#building","title":"Building","text":"Invoking the build
command without any arguments will build the sdist and wheel targets:
$ hatch build\n[sdist]\ndist/hatch_demo-1rc0.tar.gz\n\n[wheel]\ndist/hatch_demo-1rc0-py3-none-any.whl\n
To only build specific targets, use the -t
/--target
option:
$ hatch build -t wheel\n[wheel]\ndist/hatch_demo-1rc0-py3-none-any.whl\n
If the target supports multiple versions, you can specify the exact versions to build by appending a colon followed by the desired versions separated by commas:
$ hatch -v build -t wheel:standard\n[wheel]\nBuilding `wheel` version `standard`\ndist/hatch_demo-1rc0-py3-none-any.whl\n
"},{"location":"build/#packaging-ecosystem","title":"Packaging ecosystem","text":"Hatch complies with modern Python packaging specs and therefore your projects can be used by other tools with Hatch serving as just the build backend.
So you could use tox as an alternative to Hatch's environment management, or cibuildwheel to distribute packages for every platform, and they both will transparently use Hatch without any extra modification.
"},{"location":"environment/","title":"Environments","text":"Environments are designed to allow for isolated workspaces for testing, building documentation, or anything else projects need.
Unless an environment is chosen explicitly, Hatch will use the default
environment.
Tip
For a more comprehensive walk-through, see the Basic usage tutorial.
"},{"location":"environment/#creation","title":"Creation","text":"You can create environments by using the env create
command. Let's enter the directory of the project we created in the setup phase:
$ hatch env create\nCreating environment: default\nInstalling project in development mode\nSyncing dependencies\n
Tip
You never need to manually create environments as spawning a shell or running commands within one will automatically trigger creation.
"},{"location":"environment/#entering-environments","title":"Entering environments","text":"You can spawn a shell within an environment by using the shell
command.
$ hatch shell\n(hatch-demo) $\n
Now confirm the project has been installed:
(hatch-demo) $ pip show hatch-demo\nName: hatch-demo\nVersion: 0.0.1\n...\n
Finally, see where your environment's Python is located:
(hatch-demo) $ python -c \"import sys;print(sys.executable)\"\n...\n
You can type exit
to leave the environment.
The run
command allows you to execute commands in an environment as if you had already entered it. For example, running the following command will output the same path as before:
hatch run python -c \"import sys;print(sys.executable)\"\n
Tip
Be sure to check out how to define scripts for your project.
"},{"location":"environment/#dependencies","title":"Dependencies","text":"Hatch ensures that environments are always compatible with the currently defined project dependencies (if installed and in dev mode) and environment dependencies.
To add cowsay
as a dependency, open pyproject.toml
and add it to the dependencies
array:
[project]\n...\ndependencies = [\n \"cowsay\"\n]\n
This dependency will be installed the next time you spawn a shell or run a command. For example:
$ hatch run cowsay -t \"Hello, world!\"\nSyncing dependencies\n _____________\n| Hello, world! |\n =============\n \\\n \\\n ^__^\n (oo)\\_______\n (__)\\ )\\/\\\n ||----w |\n || ||\n
Note
The Syncing dependencies
status will display temporarily when Hatch updates environments in response to any dependency changes that you make.
You can select which environment to enter or run commands in by using the -e
/--env
root option or by setting the HATCH_ENV
environment variable.
The run
command allows for more explicit selection by prepending <ENV_NAME>:
to commands. For example, if you had the following configuration:
[tool.hatch.envs.docs]\ndependencies = [\n \"mkdocs\"\n]\n[tool.hatch.envs.docs.scripts]\nbuild = \"mkdocs build --clean --strict\"\nserve = \"mkdocs serve --dev-addr localhost:8000\"\n
[envs.docs]\ndependencies = [\n \"mkdocs\"\n]\n[envs.docs.scripts]\nbuild = \"mkdocs build --clean --strict\"\nserve = \"mkdocs serve --dev-addr localhost:8000\"\n
you could then serve your documentation by running:
hatch run docs:serve\n
Tip
If you've already entered an environment, commands will target it by default.
"},{"location":"environment/#matrix","title":"Matrix","text":"Every environment can define its own set of matrices:
pyproject.toml hatch.toml[tool.hatch.envs.test]\ndependencies = [\n \"pytest\"\n]\n\n[[tool.hatch.envs.test.matrix]]\npython = [\"3.10\", \"3.11\"]\nversion = [\"42\", \"3.14\"]\n\n[[tool.hatch.envs.test.matrix]]\npython = [\"3.11\", \"3.12\"]\nversion = [\"9000\"]\nfeature = [\"foo\", \"bar\"]\n
[envs.test]\ndependencies = [\n \"pytest\"\n]\n\n[[envs.test.matrix]]\npython = [\"3.10\", \"3.11\"]\nversion = [\"42\", \"3.14\"]\n\n[[envs.test.matrix]]\npython = [\"3.11\", \"3.12\"]\nversion = [\"9000\"]\nfeature = [\"foo\", \"bar\"]\n
Using the env show
command would then display:
$ hatch env show --ascii\n Standalone\n+---------+---------+\n| Name | Type |\n+=========+=========+\n| default | virtual |\n+---------+---------+\n Matrices\n+------+---------+----------------------+--------------+\n| Name | Type | Envs | Dependencies |\n+======+=========+======================+==============+\n| test | virtual | test.py3.10-42 | pytest |\n| | | test.py3.10-3.14 | |\n| | | test.py3.11-42 | |\n| | | test.py3.11-3.14 | |\n| | | test.py3.11-9000-foo | |\n| | | test.py3.11-9000-bar | |\n| | | test.py3.12-9000-foo | |\n| | | test.py3.12-9000-bar | |\n+------+---------+----------------------+--------------+\n
"},{"location":"environment/#removal","title":"Removal","text":"You can remove a single environment or environment matrix by using the env remove
command or all of a project's environments by using the env prune
command.
- name: Install Hatch\n uses: pypa/hatch@install\n
Refer to the official action for more information.
"},{"location":"install/#installers","title":"Installers","text":"macOSWindows GUI installerCommand line installer.pkg
file: hatch-universal.pkgTo verify that the shell can find and run the hatch
command in your PATH
, use the following command.
$ hatch --version\n1.12.0\n
Download the file using the curl
command. The -o
option specifies the file name that the downloaded package is written to. In this example, the file is written to hatch-universal.pkg
in the current directory.
curl -Lo hatch-universal.pkg https://github.com/pypa/hatch/releases/latest/download/hatch-universal.pkg\n
Run the standard macOS installer
program, specifying the downloaded .pkg
file as the source. Use the -pkg
parameter to specify the name of the package to install, and the -target /
parameter for the drive in which to install the package. The files are installed to /usr/local/hatch
, and an entry is created at /etc/paths.d/hatch
that instructs shells to add the /usr/local/hatch
directory to. You must include sudo on the command to grant write permissions to those folders.
sudo installer -pkg ./hatch-universal.pkg -target /\n
Restart your terminal.
To verify that the shell can find and run the hatch
command in your PATH
, use the following command.
$ hatch --version\n1.12.0\n
.msi
files:To verify that the shell can find and run the hatch
command in your PATH
, use the following command.
$ hatch --version\n1.12.0\n
Download and run the installer using the standard Windows msiexec
program, specifying one of the .msi
files as the source. Use the /passive
and /i
parameters to request an unattended, normal installation.
msiexec /passive /i https://github.com/pypa/hatch/releases/latest/download/hatch-x64.msi\n
msiexec /passive /i https://github.com/pypa/hatch/releases/latest/download/hatch-x86.msi\n
Restart your terminal.
To verify that the shell can find and run the hatch
command in your PATH
, use the following command.
$ hatch --version\n1.12.0\n
After downloading the archive corresponding to your platform and architecture, extract the binary to a directory that is on your PATH and rename to hatch
.
Hatch is available on PyPI and can be installed with pip.
pip install hatch\n
Warning
This method modifies the Python environment in which you choose to install. Consider instead using pipx to avoid dependency conflicts.
"},{"location":"install/#pipx","title":"pipx","text":"pipx allows for the global installation of Python applications in isolated environments.
pipx install hatch\n
"},{"location":"install/#homebrew","title":"Homebrew","text":"See the formula for more details.
brew install hatch\n
"},{"location":"install/#conda","title":"Conda","text":"See the feedstock for more details.
conda install -c conda-forge hatch\n
or with mamba:
mamba install hatch\n
Warning
This method modifies the Conda environment in which you choose to install. Consider instead using pipx or condax to avoid dependency conflicts.
"},{"location":"install/#macports","title":"MacPorts","text":"See the port for more details.
sudo port install hatch\n
"},{"location":"install/#fedora","title":"Fedora","text":"The minimum supported version is 37, currently in development as Rawhide.
sudo dnf install hatch\n
"},{"location":"install/#void-linux","title":"Void Linux","text":"xbps-install hatch\n
"},{"location":"install/#build-system-availability","title":"Build system availability","text":"Hatchling is Hatch's build backend which you will never need to install manually. See its changelog for version information.
"},{"location":"intro/","title":"Introduction","text":""},{"location":"intro/#setup","title":"Setup","text":"Projects can be set up for use by Hatch using the new
command.
Let's say you want to create a project named Hatch Demo
. You would run:
hatch new \"Hatch Demo\"\n
This would create the following structure in your current working directory:
hatch-demo\n\u251c\u2500\u2500 src\n\u2502 \u2514\u2500\u2500 hatch_demo\n\u2502 \u251c\u2500\u2500 __about__.py\n\u2502 \u2514\u2500\u2500 __init__.py\n\u251c\u2500\u2500 tests\n\u2502 \u2514\u2500\u2500 __init__.py\n\u251c\u2500\u2500 LICENSE.txt\n\u251c\u2500\u2500 README.md\n\u2514\u2500\u2500 pyproject.toml\n
Tip
There are many ways to customize project generation.
"},{"location":"intro/#existing-project","title":"Existing project","text":"To initialize an existing project, enter the directory containing the project and run the following:
hatch new --init\n
If your project has a setup.py
file the command will automatically migrate setuptools
configuration for you. Otherwise, this will interactively guide you through the setup process.
Next you'll want to define more of your project's metadata located in the pyproject.toml
file. You can specify things like its license, the supported versions of Python, and URLs referring to various parts of your project, like documentation.
The last step of the setup process is to define any dependencies that you'd like your project to begin with.
"},{"location":"intro/#configuration","title":"Configuration","text":"All project-specific configuration recognized by Hatch can be defined in either the pyproject.toml
file, or a file named hatch.toml
where options are not contained within the tool.hatch
table:
[tool.hatch]\noption = \"...\"\n\n[tool.hatch.table1]\noption = \"...\"\n\n[tool.hatch.table2]\noption = \"...\"\n
option = \"...\"\n\n[table1]\noption = \"...\"\n\n[table2]\noption = \"...\"\n
Top level keys in the latter file take precedence when defined in both.
Tip
If you want to make your file more compact, you can use dotted keys, turning the above example into:
pyproject.toml hatch.toml[tool.hatch]\noption = \"...\"\ntable1.option = \"...\"\ntable2.option = \"...\"\n
option = \"...\"\ntable1.option = \"...\"\ntable2.option = \"...\"\n
"},{"location":"next-steps/","title":"Next steps","text":""},{"location":"next-steps/#learn-more","title":"Learn more","text":"At this point you should have a basic understanding of how to use Hatch.
Now you may want to check out advanced configuration for environments or builds, set up your preferred shell, or read more about Hatch's CLI.
After that, check out the Hatch Showcase project to see examples of what is possible.
Finally, if you see a need, feel free to write a plugin for extended functionality.
"},{"location":"next-steps/#community","title":"Community","text":"For any projects using Hatch, you may add its official badge somewhere prominent like the README.
MarkdownreStructuredText[![Hatch project](https://img.shields.io/badge/%F0%9F%A5%9A-Hatch-4051b5.svg)](https://github.com/pypa/hatch)\n
.. image:: https://img.shields.io/badge/%F0%9F%A5%9A-Hatch-4051b5.svg\n :alt: Hatch project\n :target: https://github.com/pypa/hatch\n
"},{"location":"publish/","title":"Publishing","text":"After your project is built, you can distribute it using the publish
command.
The -p
/--publisher
option controls which publisher to use, with the default being index.
By default, the dist
directory located at the root of your project will be used:
$ hatch publish\ndist/hatch_demo-1rc0-py3-none-any.whl ... success\ndist/hatch_demo-1rc0.tar.gz ... success\n\n[hatch-demo]\nhttps://pypi.org/project/hatch-demo/1rc0/\n
You can instead pass specific paths as arguments:
hatch publish /path/to/artifacts foo-1.tar.gz\n
Only files ending with .whl
or .tar.gz
will be published.
Please refer to the publisher plugin reference for configuration options.
There's a How-To on authentication and on options to select the target repository.
The publish
command is implemented as a built-in plugin, if you're planning your own plugin, read about the publisher plugin API.
When the version is not statically set, configuration is defined in the tool.hatch.version
table. The source
option determines the source to use for retrieving and updating the version. The regex source is used by default.
The regex
source requires an option path
that represents a relative path to a file containing the project's version:
[tool.hatch.version]\npath = \"src/hatch_demo/__about__.py\"\n
[version]\npath = \"src/hatch_demo/__about__.py\"\n
The default pattern looks for a variable named __version__
or VERSION
that is set to a string containing the version, optionally prefixed with the lowercase letter v
.
If this doesn't reflect how you store the version, you can define a different regular expression using the pattern
option:
[tool.hatch.version]\npath = \"pkg/__init__.py\"\npattern = \"BUILD = 'b(?P<version>[^']+)'\"\n
[version]\npath = \"pkg/__init__.py\"\npattern = \"BUILD = 'b(?P<version>[^']+)'\"\n
The pattern must have a named group called version
that represents the version.
Invoking the version
command without any arguments will display the current version of the project:
$ hatch version\n0.0.1\n
"},{"location":"version/#updating","title":"Updating","text":"You can update the version like so:
$ hatch version \"0.1.0\"\nOld: 0.0.1\nNew: 0.1.0\n
The scheme
option determines the scheme to use for parsing both the existing and new versions. The standard scheme is used by default, which is based on PEP 440.
Rather than setting the version explicitly, you can select the name of a segment used to increment the version:
$ hatch version minor\nOld: 0.1.0\nNew: 0.2.0\n
You can chain multiple segment updates with a comma. For example, if you wanted to release a preview of your project's first major version, you could do:
$ hatch version major,rc\nOld: 0.2.0\nNew: 1.0.0rc0\n
When you want to release the final version, you would do:
$ hatch version release\nOld: 1.0.0rc0\nNew: 1.0.0\n
"},{"location":"version/#supported-segments","title":"Supported segments","text":"Here are the supported segments and how they would influence an existing version of 1.0.0
:
release
1.0.0
major
2.0.0
minor
1.1.0
micro
patch
fix
1.0.1
a
alpha
1.0.0a0
b
beta
1.0.0b0
c
rc
pre
preview
1.0.0rc0
r
rev
post
1.0.0.post0
dev
1.0.0.dev0
"},{"location":"why/","title":"Why Hatch?","text":"The high level value proposition of Hatch is that if one adopts all functionality then many other tools become unnecessary since there is support for everything one might require. Further, if one chooses to use only specific features then there are still benefits compared to alternatives.
"},{"location":"why/#build-backend","title":"Build backend","text":"Hatchling, the build backend sister project, has many benefits compared to setuptools. Here we only compare setuptools as that is the one most people are familiar with.
.gitignore
file.MANIFEST.in
file. The custom syntax and directives must be learned and it is difficult knowing which options in the main files like setup.py
influence the behavior and under what conditions. For Hatchling, everything gets configured in a single file under dedicated sections for specific targets like [tool.hatch.build.targets.wheel]
.Why not?:
If building extension modules is required then it is recommended that you continue using setuptools, or even other backends that specialize in interfacing with compilers.
"},{"location":"why/#environment-management","title":"Environment management","text":"Here we compare to both tox
and nox
. At a high level, there are a few common advantages:
Philosophy: In the alternatives, environments are for the most part treated as executable units where a dependency set is associated with an action. If you are familiar with container ecosystems, this would be like defining a CMD
at the end of a Dockerfile but without the ability to change the action at runtime. This involves significant wasted disk space usually because one often requires slight modifications to the actions and therefore will define entirely different environments inherited from a base config just to perform different logic. Additionally, this can be confusing to users not just configuration-wise but also for execution of the different environments.
In Hatch, environments are treated as isolated areas where you can execute arbitrary commands at runtime. For example, you can define a single test environment with named scripts that runs unit vs non-unit tests, each command being potentially very long but named however you wish so you get to control the interface. Since environments are treated as places where work is performed, you can also spawn a shell into any which will execute a subprocess that automatically drops into your shell of choice. Your shell will be configured appropriately like python
on PATH being updated and the prompt being changed to reflect the chosen environment.
Configuration:
tox
only supports INI configuration and if one desires putting that in the standard pyproject.toml
file then it must be a multi-line string containing the INI config which would preclude syntax highlighting. Hatch allows for TOML-based config just like most other tools in the Python ecosystem.nox
config is defined in Python which often leads to increased verbosity and makes it challenging to onboard folks compared to a standardized format with known behaviors.tox
allows for extending most aspects of its functionality however the API is so low-level and attached to internals that creating plugins may be challenging. For example, here is a tox
plugin that was migrated to an equivalent Hatch environment collector plugin.nox
is configured with Python so for the local project you can do whatever you want, however there is no concept of third-party plugins per se. To achieve that, you must usually use a package that wraps nox
and use that package's imports instead (example).Why not?:
If you are using nox
and you wish to migrate, and for some reason you notify sessions, then migration wouldn't be a straight translation but rather you might have to redesign that conditional step.
Here we compare Python management to that of pyenv.
pyenv
does not support Windows so you must use an entirely different project that tries to emulate the functionality.pyenv
operates by adding shims which then act as wrappers around the actual underlying binaries. This has many unfortunate side effects:pyenv
on start, leading to inconsistencies when running processes that do not spawn a shell.pyenv
influencing the python
on PATH.Why not?:
Currently, Hatch does not allow for the installation of specific patch release versions but rather only uses minor release granularity that tracks the latest patch release. If specific patch releases are important to you then it is best to use an alternative installation mechanism.
"},{"location":"blog/","title":"Blog","text":""},{"location":"blog/2024/05/02/hatch-v1100/","title":"Hatch v1.10.0","text":"Hatch v1.10.0 brings a test command, support for UV, and a Python script runner.
"},{"location":"blog/2024/05/02/hatch-v1100/#test-command","title":"Test command","text":"The new test
command allows you to easily run tests for your project on multiple versions of Python. The default behavior follows best practices, using pytest with select plugins for test execution and coverage.py for code coverage measurement.
The command is designed to be both simple to use while also satisfying the needs of most projects. For example, the following shows Hatch running tests for Jinja in all environments in the default matrix:
Here is us testing Rich, with a bit of configuration:
See the tutorial for a detailed walk-through and the config reference for options.
"},{"location":"blog/2024/05/02/hatch-v1100/#uv","title":"UV","text":"The package installer UV, brought to you by the same folks behind Ruff, is now supported. In any environment, you can set the installer
option to uv
to use UV in place of virtualenv & pip for virtual environment creation and dependency management, respectively. This often results in a significant performance benefit.
For example, if you wanted to enable this functionality for the default environment, you could set the following:
pyproject.toml hatch.toml[tool.hatch.envs.default]\ninstaller = \"uv\"\n
[envs.default]\ninstaller = \"uv\"\n
Semi-internal environments like those used for testing and static analysis have this enabled by default.
See the how-to guide for more information about switching the installer.
"},{"location":"blog/2024/05/02/hatch-v1100/#python-script-runner","title":"Python script runner","text":"The run
command now supports executing Python scripts with inline metadata as standardized by PEP 723.
As an example, consider the following script:
script.py# /// script\n# requires-python = \">=3.11\"\n# dependencies = [\n# \"httpx\",\n# \"rich\",\n# ]\n# ///\n\nimport httpx\nfrom rich.pretty import pprint\n\nresp = httpx.get(\"https://peps.python.org/api/peps.json\")\ndata = resp.json()\npprint([(k, v[\"title\"]) for k, v in data.items()][:10])\n
If you run the script for the first time as follows:
hatch run script.py\n
Hatch will create a dedicated environment for that script using a version of Python greater than or equal to 3.11 with dependencies httpx
and rich
.
See the how-to guide for more information.
"},{"location":"blog/2024/05/02/hatch-v1100/#static-analysis","title":"Static analysis","text":"The environment used for static analysis is now completely configurable such that you can fully alter the underlying behavior of the fmt
command (see the how-to).
Additionally, Ruff has been updated to version 1.4.0 and the rules selected by default have been updated accordingly. Check out their blog post about how the new hand-written parser has made it twice as fast!
"},{"location":"blog/2024/05/02/hatch-v1100/#community-highlights","title":"Community highlights","text":""},{"location":"blog/2024/05/02/hatch-v1100/#visual-studio-code","title":"Visual Studio Code","text":"Visual Studio Code announced support for Hatch environments in their latest release. This means that you can now easily discover and select Hatch environments for your projects directly from the editor.
See the how-to guide for detailed instructions.
"},{"location":"blog/2024/05/02/hatch-v1100/#cmake-build-plugin","title":"CMake build plugin","text":"A new release of the extension module builder scikit-build-core has introduced a build plugin for Hatchling. This means that you can use Hatchling as your build backend while also shipping extension modules built with CMake.
To get started, add the dependency to your build requirements:
pyproject.toml[build-system]\nrequires = [\"hatchling>=1.24.2\", \"scikit-build-core~=0.9.3\"]\nbuild-backend = \"hatchling.build\"\n
Then explicitly enable the experimental
option (acknowledging that the plugin will move to a dedicated package in the future):
[tool.hatch.build.targets.wheel.hooks.scikit-build]\nexperimental = true\n
[build.targets.wheel.hooks.scikit-build]\nexperimental = true\n
At this point, you can create your CMakeLists.txt
file as usual and start building your extension modules with CMake! Check out the dedicated example project for a complete demonstration.
The efforts toward documentation improvements have increased substantially and the priorities have shifted. From now on expect to see far more tutorials and how-to guides rather than just reference material.
"},{"location":"blog/2024/05/02/hatch-v1100/#future","title":"Future","text":"Upcoming features include:
If you or your organization finds value in what Hatch provides, consider a sponsorship to assist with maintenance and more rapid development!
"},{"location":"blog/2022/10/08/hatch-v160/","title":"Hatch v1.6.0","text":"Hatch v1.6.0 brings improvements to build environments, better handling of dynamic metadata, and support for tools like Visual Studio Code.
"},{"location":"blog/2022/10/08/hatch-v160/#build-environments","title":"Build environments","text":"Originally, the environment interface method for providing builder sub-environments was intended to be used in conjunction with some cleanup logic in order to provide a fresh setup every time. However, this is unnecessary in practice because build dependencies rarely change.
Without caching, repeat build environment use is slow which affects the following scenarios:
build
commanddep hash
, if any fields are set dynamicallyNow a new environment interface method build_environment_exists
is used by Hatch to determine whether or not it has already been created, for implementations that have a caching mechanism.
The virtual
environment type now uses this method to cache build environments.
Dynamically defined metadata is now supported everywhere, thanks to the new caching of virtual
build environments.
A project metadata
command is introduced that displays the fully resolved metadata. The output format is JSON unless a field is specified as an argument.
For example, if you checkout a project that is built by Hatch, like FastAPI, and run:
hatch project metadata readme\n
only the readme
text will be displayed. If the content is in Markdown, then Rich will render it directly in your terminal:
The virtual
environment type now uses a flat layout for storage in the configured virtual
environment directory if the directory resides somewhere within the project root or if it is set to a .virtualenvs
directory within the user's home directory.
For example, if you define the following Hatch configuration:
config.toml[dirs.env]\nvirtual = \".hatch\"\n
and the following matrix:
pyproject.toml hatch.toml[[tool.hatch.envs.test.matrix]]\npython = [\"3.7\", \"3.8\", \"3.9\", \"3.10\", \"3.11\"]\n
[[envs.test.matrix]]\npython = [\"3.7\", \"3.8\", \"3.9\", \"3.10\", \"3.11\"]\n
then locating environments with the following command:
hatch env find test\n
will show that the general directory structure is:
.hatch\n\u251c\u2500\u2500 test.py3.7\n\u251c\u2500\u2500 test.py3.8\n\u251c\u2500\u2500 test.py3.9\n\u251c\u2500\u2500 test.py3.10\n\u2514\u2500\u2500 test.py3.11\n
This flat structure is required for detection of virtual environments by tools like Visual Studio Code and PyCharm.
Additionally, the virtual
environment type now supports a path
option to specify an explicit path that all inherited environments will share, such as the common .venv
.
The script used to migrate existing projects from setuptools
has been improved to handle more edge cases that were encountered in the wild and now no longer modifies the formatting of existing pyproject.toml
configuration.
Hatch now depends on Hatchling v1.11.0, which was also just released.
"},{"location":"blog/2022/10/08/hatch-v160/#environment-version-source","title":"Environment version source","text":"A new env
version source is available that allows for the project version to be defined by an environment variable.
The standard
version scheme now supports a validate-bump
option that when set to false
will forego the check when updating the version that the desired version is higher than the current version.
This use case comes from Project Jupyter:
A common pattern we use in Jupyter is to bump to a .dev0
minor version bump after making a release. If we have a bug fix that needs to go out in the interim, we'd rather not be forced to create a branch every time.
Hatch v1.8.0 brings Python distribution management, static analysis and formatting backed by Ruff, and binaries for every platform.
"},{"location":"blog/2023/12/11/hatch-v180/#installation-made-easy","title":"Installation made easy","text":"One thing that has been a perpetual problem for Hatch and other Python applications is that Python itself is a dependency. You, and more importantly your users, need to in some way get Python before your software can even be used. The recommended way to go about that is platform-dependent and even differs based on your target audience. I viewed this as a central UX problem for Hatch and so severe that I took a bit of a hiatus to solve it.
Luckily, I have to my satisfaction solved this problem in the form of PyApp. It is a runtime installer for Python projects written in Rust. Apps are distributed as standalone executables as users have come to expect and bootstrapping occurs upon the first invocation. Here is an example of what you would see the first time you run a binary from this release:
Now that we have binaries, creating installers for different platforms becomes trivial. Starting with this release not only are binaries available for every platform but also we have installers for Windows and macOS. The installer for macOS is signed using a certificate from the same account used to sign the official distributions from https://www.python.org, so users will not get any security pop-ups. Shout out to @ewdurbin for their extreme generosity in setting up multiple certificates in their free time!
These installers and binaries are now the recommended way to install and update Hatch. These binaries have built-in management so you can update to the latest version by running hatch self update
.
Windows signing
In future we will sign the installers for Windows but I did not have time to look into how that works. macOS signing took way longer than I anticipated
"},{"location":"blog/2023/12/11/hatch-v180/#python-management","title":"Python management","text":"For a long time I and other users have desired that Hatch gain the ability to manage Python distributions. In my mind this was always blocked on a better installation experience because there was sort of a chicken-or-egg problem where you want a Python manager but you first need Python. No longer is that the case!
The new python
command group allows for easy installation of various distributions to arbitrary locations which are then added to your PATH by default. Hatch supports CPython and PyPy distributions:
The virtual
environment type is now far more intelligent when resolving the parent distribution to use and guarantees that, when no specific version is requested, the resolved distribution will always be compatible with the project.
Additionally, when a requested version cannot be found on PATH it will automatically be downloaded and managed internally.
"},{"location":"blog/2023/12/11/hatch-v180/#static-analysis","title":"Static analysis","text":"There is a new fmt
command, backed entirely by Ruff, that checks and fixes your code for formatting and linting issues.
Starting with this release, Hatch maintains default settings that are guaranteed to be up-to-date and represent best practices for programming in modern Python. The idea is to provide defaults that are so broadly applicable that the majority of users will maintain little if any of their own overrides.
The default behavior is internal management of settings to provide an OOTB experience that works. It is recommended however that you persist the default config file in version control so that other tools like IDEs can utilize your full configuration.
Since Ruff is now provided as a built-in feature, new project templates no longer have such configuration and are much less verbose.
"},{"location":"blog/2023/12/11/hatch-v180/#build-improvements","title":"Build improvements","text":"Building projects that do not use Hatchling as a backend is now supported and such builds are managed with the standard build tool.
The bridge between Hatch and the Hatchling CLI has been removed. Previously, the builder would send serialized messages to Hatch that would contain the desired content and style for each line of output. This was done in an effort to allow builder and build hook plugins to output pretty messages without actually requiring a dependency like Rich. A problem that arises with this is that builders that invoke subprocesses will not display ANSI codes as one might expect and will lose out on the interactive experience of such invocations, like the built-in binary builder plugin calling cargo build
. So now everything is simpler at the expense of no colored output without manual logic, or adding a dependency if you're a third-party plugin.
Spawning a shell or running commands within environments always first checks that your project's dependencies are satisfied and if not synchronizes the environment with what is defined. Previously, this had the potential to be quite slow for projects that have many dependencies.
Now the set of dependency definitions is hashed and no check is performed if the hash is the same as before, significantly speeding up environment usage in most cases.
"},{"location":"blog/2023/12/11/hatch-v180/#hatchling","title":"Hatchling","text":"Hatch now depends on Hatchling v1.19.0, which was also just released.
"},{"location":"blog/2023/12/11/hatch-v180/#better-defaults","title":"Better defaults","text":"Hatchling is all about providing the best possible defaults, even at the expense of backward compatibility. In this release, there are two breaking changes that provide a much better user experience and were in fact requested by users.
force-include
option and the force_include_editable
wheel build data setting now raise errors if source paths do not exist.wheel
build target now raises an error when no file inclusion options have been defined and none of its heuristics to determine what to ship are satisfied.A new binary
build target is now stable that allows for the building of standalone binaries for projects. This is what Hatch itself uses for its binaries.
A new page has been introduced that discusses the value proposition of Hatch and Hatchling in comparison to alternatives. Currently, it only addresses a few features but in future this page will become more comprehensive.
"},{"location":"blog/2023/12/11/hatch-v180/#future","title":"Future","text":"Upcoming features include a test
command, commands to manage dependencies, and workspaces functionality similar to Cargo that will make managing monorepos far easier.
Next year there will be two large efforts that you should expect to see:
A significant amount of my free time (and some at work) will be devoted to introducing lock file functionality in Hatch and trying to get whatever that happens to be standardized.
I met with @brettcannon about his thoughts post-PEP 665 and about mousebender. I also met with the prefix.dev team about rip and was fortunate enough to be shown a demo before its official announcement.
At the moment, the two options I see are to either go all in and contribute to mousebender or rely on the Prefix folks and use rip. The latter has the benefit of potentially supporting Conda as a side effect with the downside of being quite new with the spec firmly out of our control. The former has the benefit of being able to easily gain institutional support from the Python packaging team and each of our employers with the downside being a significant amount of work needing to be done.
When @henryiii is able to get some free time away from teaching I plan to work with him once again and push very hard for the Python build ecosystem to adopt the extensionlib approach.
I am of the opinion that the Python community has not fully completed the expressed outcome of PEP 517 in that build backends are still (for the most part) reliant on setuptools for building non-Python code bases.
Basically, there are components that interact with compilers to produce extension modules and components that pack files into an archive which we call a build backend. These are two distinct pieces of functionality and my view is that there should be an API that allows backends to consume extension module builders to find out where things got created and where they should be shipped inside archives.
In this hypothetical future any build backend would be able to trigger the building of extension modules based on user configuration.
If you or your organization finds value in what Hatch provides, consider a sponsorship to assist with maintenance and more rapid development!
"},{"location":"blog/2023/12/18/hatch-v190/","title":"Hatch v1.9.0","text":"Hatch v1.9.0 brings improvements to static analysis and important bug fixes.
"},{"location":"blog/2023/12/18/hatch-v190/#static-analysis","title":"Static analysis","text":"The default version of Ruff has been increased to v0.1.8. This release brings formatting capabilities to docstrings and Hatch enables this by default with line length set to 80. This length was chosen as the default because it plays nicely with the rendering of the most popular themes for Python documentation, such as Material for MkDocs and Furo.
Additionally, it is now possible for projects to pin to specific versions of Ruff for upgrading at a later time:
pyproject.toml hatch.toml[tool.hatch.envs.hatch-static-analysis]\ndependencies = [\"ruff==X.Y.Z\"]\n
[envs.hatch-static-analysis]\ndependencies = [\"ruff==X.Y.Z\"]\n
"},{"location":"blog/2023/12/18/hatch-v190/#notable-fixes","title":"Notable fixes","text":"The amount of displayed output is controlled solely by the -v
/--verbose
(environment variable HATCH_VERBOSE
) and -q
/--quiet
(environment variable HATCH_QUIET
) root options.
The levels are documented here.
"},{"location":"cli/about/#project-awareness","title":"Project awareness","text":"No matter the mode, Hatch will always change to the project's root directory for entering or running commands in environments.
"},{"location":"cli/about/#tab-completion","title":"Tab completion","text":"Completion is achieved by saving a script and then executing it as a part of your shell's startup sequence.
Afterward, you'll need to start a new shell in order for the changes to take effect.
BashZ shellfishSave the script somewhere:
_HATCH_COMPLETE=bash_source hatch > ~/.hatch-complete.bash\n
Source the file in ~/.bashrc
(or ~/.bash_profile
if on macOS):
. ~/.hatch-complete.bash\n
Save the script somewhere:
_HATCH_COMPLETE=zsh_source hatch > ~/.hatch-complete.zsh\n
Source the file in ~/.zshrc
:
. ~/.hatch-complete.zsh\n
Save the script in ~/.config/fish/completions
:
_HATCH_COMPLETE=fish_source hatch > ~/.config/fish/completions/hatch.fish\n
"},{"location":"cli/reference/","title":"hatch","text":"Usage:
hatch [OPTIONS] COMMAND [ARGS]...\n
Options:
Name Type Description Default--env
, -e
text The name of the environment to use [env var: HATCH_ENV
] default
--project
, -p
text The name of the project to work on [env var: HATCH_PROJECT
] None --verbose
, -v
integer range (0
and above) Increase verbosity (can be used additively) [env var: HATCH_VERBOSE
] 0
--quiet
, -q
integer range (0
and above) Decrease verbosity (can be used additively) [env var: HATCH_QUIET
] 0
--color
/ --no-color
boolean Whether or not to display colored output (default is auto-detection) [env vars: FORCE_COLOR
/NO_COLOR
] None --interactive
/ --no-interactive
boolean Whether or not to allow features like prompts and progress bars (default is auto-detection) [env var: HATCH_INTERACTIVE
] None --data-dir
text The path to a custom directory used to persist data [env var: HATCH_DATA_DIR
] None --cache-dir
text The path to a custom directory used to cache data [env var: HATCH_CACHE_DIR
] None --config
text The path to a custom config file to use [env var: HATCH_CONFIG
] None --version
boolean Show the version and exit. False
--help
boolean Show this message and exit. False
"},{"location":"cli/reference/#hatch-build","title":"hatch build","text":"Build a project.
Usage:
hatch build [OPTIONS] [LOCATION]\n
Options:
Name Type Description Default--target
, -t
text The target to build, overriding project defaults. This may be selected multiple times e.g. -t sdist -t wheel
None --hooks-only
boolean Whether or not to only execute build hooks [env var: HATCH_BUILD_HOOKS_ONLY
] False
--no-hooks
boolean Whether or not to disable build hooks [env var: HATCH_BUILD_NO_HOOKS
] False
--ext
boolean Whether or not to only execute build hooks for distributing binary Python packages, such as compiling extensions. Equivalent to --hooks-only -t wheel
False
--clean
, -c
boolean Whether or not existing artifacts should first be removed [env var: HATCH_BUILD_CLEAN
] False
--clean-hooks-after
boolean Whether or not build hook artifacts should be removed after each build [env var: HATCH_BUILD_CLEAN_HOOKS_AFTER
] False
--help
boolean Show this message and exit. False
"},{"location":"cli/reference/#hatch-clean","title":"hatch clean","text":"Remove build artifacts.
Usage:
hatch clean [OPTIONS] [LOCATION]\n
Options:
Name Type Description Default--target
, -t
text The target with which to remove artifacts, overriding project defaults. This may be selected multiple times e.g. -t sdist -t wheel
None --hooks-only
boolean Whether or not to only remove artifacts from build hooks [env var: HATCH_BUILD_HOOKS_ONLY
] False
--no-hooks
boolean Whether or not to ignore artifacts from build hooks [env var: HATCH_BUILD_NO_HOOKS
] False
--ext
boolean Whether or not to only remove artifacts from build hooks for distributing binary Python packages, such as compiled extensions. Equivalent to --hooks-only -t wheel
False
--help
boolean Show this message and exit. False
"},{"location":"cli/reference/#hatch-config","title":"hatch config","text":"Manage the config file
Usage:
hatch config [OPTIONS] COMMAND [ARGS]...\n
Options:
Name Type Description Default--help
boolean Show this message and exit. False
"},{"location":"cli/reference/#hatch-config-explore","title":"hatch config explore","text":"Open the config location in your file manager.
Usage:
hatch config explore [OPTIONS]\n
Options:
Name Type Description Default--help
boolean Show this message and exit. False
"},{"location":"cli/reference/#hatch-config-find","title":"hatch config find","text":"Show the location of the config file.
Usage:
hatch config find [OPTIONS]\n
Options:
Name Type Description Default--help
boolean Show this message and exit. False
"},{"location":"cli/reference/#hatch-config-restore","title":"hatch config restore","text":"Restore the config file to default settings.
Usage:
hatch config restore [OPTIONS]\n
Options:
Name Type Description Default--help
boolean Show this message and exit. False
"},{"location":"cli/reference/#hatch-config-set","title":"hatch config set","text":"Assign values to config file entries. If the value is omitted, you will be prompted, with the input hidden if it is sensitive.
Usage:
hatch config set [OPTIONS] KEY [VALUE]\n
Options:
Name Type Description Default--help
boolean Show this message and exit. False
"},{"location":"cli/reference/#hatch-config-show","title":"hatch config show","text":"Show the contents of the config file.
Usage:
hatch config show [OPTIONS]\n
Options:
Name Type Description Default--all
, -a
boolean Do not scrub secret fields False
--help
boolean Show this message and exit. False
"},{"location":"cli/reference/#hatch-config-update","title":"hatch config update","text":"Update the config file with any new fields.
Usage:
hatch config update [OPTIONS]\n
Options:
Name Type Description Default--help
boolean Show this message and exit. False
"},{"location":"cli/reference/#hatch-dep","title":"hatch dep","text":"Manage environment dependencies
Usage:
hatch dep [OPTIONS] COMMAND [ARGS]...\n
Options:
Name Type Description Default--help
boolean Show this message and exit. False
"},{"location":"cli/reference/#hatch-dep-hash","title":"hatch dep hash","text":"Output a hash of the currently defined dependencies.
Usage:
hatch dep hash [OPTIONS]\n
Options:
Name Type Description Default--project-only
, -p
boolean Whether or not to exclude environment dependencies False
--env-only
, -e
boolean Whether or not to exclude project dependencies False
--help
boolean Show this message and exit. False
"},{"location":"cli/reference/#hatch-dep-show","title":"hatch dep show","text":"Display dependencies in various formats
Usage:
hatch dep show [OPTIONS] COMMAND [ARGS]...\n
Options:
Name Type Description Default--help
boolean Show this message and exit. False
"},{"location":"cli/reference/#hatch-dep-show-requirements","title":"hatch dep show requirements","text":"Enumerate dependencies as a list of requirements.
Usage:
hatch dep show requirements [OPTIONS]\n
Options:
Name Type Description Default--project-only
, -p
boolean Whether or not to exclude environment dependencies False
--env-only
, -e
boolean Whether or not to exclude project dependencies False
--feature
, -f
text Whether or not to only show the dependencies of the specified features None --all
boolean Whether or not to include the dependencies of all features False
--help
boolean Show this message and exit. False
"},{"location":"cli/reference/#hatch-dep-show-table","title":"hatch dep show table","text":"Enumerate dependencies in a tabular format.
Usage:
hatch dep show table [OPTIONS]\n
Options:
Name Type Description Default--project-only
, -p
boolean Whether or not to exclude environment dependencies False
--env-only
, -e
boolean Whether or not to exclude project dependencies False
--lines
, -l
boolean Whether or not to show lines between table rows False
--ascii
boolean Whether or not to only use ASCII characters False
--help
boolean Show this message and exit. False
"},{"location":"cli/reference/#hatch-env","title":"hatch env","text":"Manage project environments
Usage:
hatch env [OPTIONS] COMMAND [ARGS]...\n
Options:
Name Type Description Default--help
boolean Show this message and exit. False
"},{"location":"cli/reference/#hatch-env-create","title":"hatch env create","text":"Create environments.
Usage:
hatch env create [OPTIONS] [ENV_NAME]\n
Options:
Name Type Description Default--help
boolean Show this message and exit. False
"},{"location":"cli/reference/#hatch-env-find","title":"hatch env find","text":"Locate environments.
Usage:
hatch env find [OPTIONS] [ENV_NAME]\n
Options:
Name Type Description Default--help
boolean Show this message and exit. False
"},{"location":"cli/reference/#hatch-env-prune","title":"hatch env prune","text":"Remove all environments.
Usage:
hatch env prune [OPTIONS]\n
Options:
Name Type Description Default--help
boolean Show this message and exit. False
"},{"location":"cli/reference/#hatch-env-remove","title":"hatch env remove","text":"Remove environments.
Usage:
hatch env remove [OPTIONS] [ENV_NAME]\n
Options:
Name Type Description Default--help
boolean Show this message and exit. False
"},{"location":"cli/reference/#hatch-env-run","title":"hatch env run","text":"Run commands within project environments.
The -e
/--env
option overrides the equivalent root option and the HATCH_ENV
environment variable.
The -i
/--include
and -x
/--exclude
options may be used to include or exclude certain variables, optionally followed by specific comma-separated values, and may be selected multiple times. For example, if you have the following configuration:
[[tool.hatch.envs.test.matrix]]\npython = [\"3.9\", \"3.10\"]\nversion = [\"42\", \"3.14\", \"9000\"]\n
[[envs.test.matrix]]\npython = [\"3.9\", \"3.10\"]\nversion = [\"42\", \"3.14\", \"9000\"]\n
then running:
hatch env run -i py=3.10 -x version=9000 test:pytest\n
would execute pytest
in the environments test.py3.10-42
and test.py3.10-3.14
. Note that py
may be used as an alias for python
.
Note
The inclusion option is treated as an intersection while the exclusion option is treated as a union i.e. an environment must match all of the included variables to be selected while matching any of the excluded variables will prevent selection.
Usage:
hatch env run [OPTIONS] ARGS...\n
Options:
Name Type Description Default--env
, -e
text The environments to target None --include
, -i
text The matrix variables to include None --exclude
, -x
text The matrix variables to exclude None --filter
, -f
text The JSON data used to select environments None --force-continue
boolean Run every command and if there were any errors exit with the first code False
--ignore-compat
boolean Ignore incompatibility when selecting specific environments False
--help
boolean Show this message and exit. False
"},{"location":"cli/reference/#hatch-env-show","title":"hatch env show","text":"Show the available environments.
Usage:
hatch env show [OPTIONS] [ENVS]...\n
Options:
Name Type Description Default--ascii
boolean Whether or not to only use ASCII characters False
--json
boolean Whether or not to output in JSON format False
--internal
, -i
boolean Show internal environments False
--help
boolean Show this message and exit. False
"},{"location":"cli/reference/#hatch-fmt","title":"hatch fmt","text":"Format and lint source code.
Usage:
hatch fmt [OPTIONS] [ARGS]...\n
Options:
Name Type Description Default--check
boolean Only check for errors rather than fixing them False
--linter
, -l
boolean Only run the linter False
--formatter
, -f
boolean Only run the formatter False
--sync
boolean Sync the default config file with the current version of Hatch False
--help
boolean Show this message and exit. False
"},{"location":"cli/reference/#hatch-new","title":"hatch new","text":"Create or initialize a project.
Usage:
hatch new [OPTIONS] [NAME] [LOCATION]\n
Options:
Name Type Description Default--interactive
, -i
boolean Interactively choose details about the project False
--cli
boolean Give the project a command line interface False
--init
boolean Initialize an existing project False
--help
boolean Show this message and exit. False
"},{"location":"cli/reference/#hatch-project","title":"hatch project","text":"View project information
Usage:
hatch project [OPTIONS] COMMAND [ARGS]...\n
Options:
Name Type Description Default--help
boolean Show this message and exit. False
"},{"location":"cli/reference/#hatch-project-metadata","title":"hatch project metadata","text":"Display project metadata.
If you want to view the raw readme file without rendering, you can use a JSON parser like jq:
hatch project metadata | jq -r .readme\n
Usage:
hatch project metadata [OPTIONS] [FIELD]\n
Options:
Name Type Description Default--help
boolean Show this message and exit. False
"},{"location":"cli/reference/#hatch-publish","title":"hatch publish","text":"Publish build artifacts.
Usage:
hatch publish [OPTIONS] [ARTIFACTS]...\n
Options:
Name Type Description Default--repo
, -r
text The repository with which to publish artifacts [env var: HATCH_INDEX_REPO
] None --user
, -u
text The user with which to authenticate [env var: HATCH_INDEX_USER
] None --auth
, -a
text The credentials to use for authentication [env var: HATCH_INDEX_AUTH
] None --ca-cert
text The path to a CA bundle [env var: HATCH_INDEX_CA_CERT
] None --client-cert
text The path to a client certificate, optionally containing the private key [env var: HATCH_INDEX_CLIENT_CERT
] None --client-key
text The path to the client certificate's private key [env var: HATCH_INDEX_CLIENT_KEY
] None --no-prompt
, -n
boolean Disable prompts, such as for missing required fields False
--initialize-auth
boolean Save first-time authentication information even if nothing was published False
--publisher
, -p
text The publisher plugin to use (default is index
) [env var: HATCH_PUBLISHER
] index
--option
, -o
text Options to pass to the publisher plugin. This may be selected multiple times e.g. -o foo=bar -o baz=23
[env var: HATCH_PUBLISHER_OPTIONS
] None --yes
, -y
boolean Confirm without prompting when the plugin is disabled False
--help
boolean Show this message and exit. False
"},{"location":"cli/reference/#hatch-python","title":"hatch python","text":"Manage Python installations
Usage:
hatch python [OPTIONS] COMMAND [ARGS]...\n
Options:
Name Type Description Default--help
boolean Show this message and exit. False
"},{"location":"cli/reference/#hatch-python-find","title":"hatch python find","text":"Locate Python binaries.
Usage:
hatch python find [OPTIONS] NAME\n
Options:
Name Type Description Default-p
, --parent
boolean Show the parent directory of the Python binary False
--dir
, -d
text The directory in which distributions reside None --help
boolean Show this message and exit. False
"},{"location":"cli/reference/#hatch-python-install","title":"hatch python install","text":"Install Python distributions.
You may select all
to install all compatible distributions:
hatch python install all\n
You can set custom sources for distributions by setting the HATCH_PYTHON_SOURCE_<NAME>
environment variable where <NAME>
is the uppercased version of the distribution name with periods replaced by underscores e.g. HATCH_PYTHON_SOURCE_PYPY3_10
.
Usage:
hatch python install [OPTIONS] NAMES...\n
Options:
Name Type Description Default--private
boolean Do not add distributions to the user PATH False
--update
, -u
boolean Update existing installations False
--dir
, -d
text The directory in which to install distributions, overriding configuration None --help
boolean Show this message and exit. False
"},{"location":"cli/reference/#hatch-python-remove","title":"hatch python remove","text":"Remove Python distributions.
You may select all
to remove all installed distributions:
hatch python remove all\n
Usage:
hatch python remove [OPTIONS] NAMES...\n
Options:
Name Type Description Default--dir
, -d
text The directory in which distributions reside None --help
boolean Show this message and exit. False
"},{"location":"cli/reference/#hatch-python-show","title":"hatch python show","text":"Show the available Python distributions.
Usage:
hatch python show [OPTIONS]\n
Options:
Name Type Description Default--ascii
boolean Whether or not to only use ASCII characters False
--dir
, -d
text The directory in which distributions reside None --help
boolean Show this message and exit. False
"},{"location":"cli/reference/#hatch-python-update","title":"hatch python update","text":"Update Python distributions.
You may select all
to update all installed distributions:
hatch python update all\n
Usage:
hatch python update [OPTIONS] NAMES...\n
Options:
Name Type Description Default--dir
, -d
text The directory in which distributions reside None --help
boolean Show this message and exit. False
"},{"location":"cli/reference/#hatch-run","title":"hatch run","text":"Run commands within project environments. This is a convenience wrapper around the env run
command.
If the first argument contains a colon, then the preceding component will be interpreted as the name of the environment to target, overriding the -e
/--env
root option and the HATCH_ENV
environment variable.
If the environment provides matrices, then you may also provide leading arguments starting with a +
or -
to select or exclude certain variables, optionally followed by specific comma-separated values. For example, if you have the following configuration:
[[tool.hatch.envs.test.matrix]]\npython = [\"3.9\", \"3.10\"]\nversion = [\"42\", \"3.14\", \"9000\"]\n
[[envs.test.matrix]]\npython = [\"3.9\", \"3.10\"]\nversion = [\"42\", \"3.14\", \"9000\"]\n
then running:
hatch run +py=3.10 -version=9000 test:pytest\n
would execute pytest
in the environments test.py3.10-42
and test.py3.10-3.14
. Note that py
may be used as an alias for python
.
Note
Inclusions are treated as an intersection while exclusions are treated as a union i.e. an environment must match all of the included variables to be selected while matching any of the excluded variables will prevent selection.
Usage:
hatch run [OPTIONS] [ENV:]ARGS...\n
Options:
Name Type Description Default--help
boolean Show this message and exit. False
"},{"location":"cli/reference/#hatch-self","title":"hatch self","text":"Manage Hatch
Usage:
hatch self [OPTIONS] COMMAND [ARGS]...\n
Options:
Name Type Description Default--help
boolean Show this message and exit. False
"},{"location":"cli/reference/#hatch-self-report","title":"hatch self report","text":"Generate a pre-populated GitHub issue.
Usage:
hatch self report [OPTIONS]\n
Options:
Name Type Description Default--no-open
, -n
boolean Show the URL instead of opening it False
--help
boolean Show this message and exit. False
"},{"location":"cli/reference/#hatch-self-restore","title":"hatch self restore","text":"Restore the installation
Usage:
hatch self restore [OPTIONS] [ARGS]...\n
Options:
Name Type Description Default--help
boolean Show this message and exit. False
"},{"location":"cli/reference/#hatch-self-update","title":"hatch self update","text":"Install the latest version
Usage:
hatch self update [OPTIONS] [ARGS]...\n
Options:
Name Type Description Default--help
boolean Show this message and exit. False
"},{"location":"cli/reference/#hatch-shell","title":"hatch shell","text":"Enter a shell within a project's environment.
Usage:
hatch shell [OPTIONS] [ENV_NAME]\n
Options:
Name Type Description Default--name
text N/A None --path
text N/A None --help
boolean Show this message and exit. False
"},{"location":"cli/reference/#hatch-status","title":"hatch status","text":"Show information about the current environment.
Usage:
hatch status [OPTIONS]\n
Options:
Name Type Description Default--help
boolean Show this message and exit. False
"},{"location":"cli/reference/#hatch-test","title":"hatch test","text":"Run tests using the hatch-test
environment matrix.
If no filtering options are selected, then tests will be run in the first compatible environment found in the matrix with priority given to those matching the current interpreter.
The -i
/--include
and -x
/--exclude
options may be used to include or exclude certain variables, optionally followed by specific comma-separated values, and may be selected multiple times. For example, if you have the following configuration:
[[tool.hatch.envs.hatch-test.matrix]]\npython = [\"3.9\", \"3.10\"]\nversion = [\"42\", \"3.14\", \"9000\"]\n
[[envs.hatch-test.matrix]]\npython = [\"3.9\", \"3.10\"]\nversion = [\"42\", \"3.14\", \"9000\"]\n
then running:
hatch test -i py=3.10 -x version=9000\n
would run tests in the environments hatch-test.py3.10-42
and hatch-test.py3.10-3.14
.
The -py
/--python
option is a shortcut for specifying the inclusion -i py=...
.
Note
The inclusion option is treated as an intersection while the exclusion option is treated as a union i.e. an environment must match all of the included variables to be selected while matching any of the excluded variables will prevent selection.
Usage:
hatch test [OPTIONS] [ARGS]...\n
Options:
Name Type Description Default--randomize
, -r
boolean Randomize the order of test execution False
--parallel
, -p
boolean Parallelize test execution False
--retries
integer Number of times to retry failed tests None --retry-delay
float Seconds to wait between retries None --cover
, -c
boolean Measure code coverage False
--cover-quiet
boolean Disable coverage reporting after tests, implicitly enabling --cover False
--all
, -a
boolean Test all environments in the matrix False
--python
, -py
text The Python versions to test, equivalent to: -i py=... None --include
, -i
text The matrix variables to include None --exclude
, -x
text The matrix variables to exclude None --show
, -s
boolean Show information about environments in the matrix False
--help
boolean Show this message and exit. False
"},{"location":"cli/reference/#hatch-version","title":"hatch version","text":"View or set a project's version.
Usage:
hatch version [OPTIONS] [DESIRED_VERSION]\n
Options:
Name Type Description Default--help
boolean Show this message and exit. False
"},{"location":"community/contributing/","title":"Contributing","text":"The usual process to make a contribution is to:
Clone the hatch
repository, cd
into it, and create a new branch for your contribution:
cd hatch\ngit checkout -b add-my-contribution\n
"},{"location":"community/contributing/#run-the-tests","title":"Run the tests","text":"Run the test suite while developing:
hatch run dev\n
Run the test suite with coverage report:
hatch run cov\n
Run the extended test suite with coverage:
hatch run full\n
"},{"location":"community/contributing/#lint","title":"Lint","text":"Run automated formatting:
hatch run lint:fmt\n
Run full linting and type checking:
hatch run lint:all\n
"},{"location":"community/contributing/#docs","title":"Docs","text":"Start the documentation in development:
hatch run docs:serve\n
Build and validate the documentation website:
hatch run docs:build-check\n
"},{"location":"community/highlights/","title":"Community highlights","text":""},{"location":"community/highlights/#integration","title":"Integration","text":"The following is not intended to be a complete enumeration. Be sure to view the development version of this page for an up-to-date listing.
"},{"location":"community/users/#projects","title":"Projects","text":"aiogram | Apache Airflow | argon2-cffi | attrs | Black | coffea | Colorama | Django Anymail | Django Debug Toolbar | Django NYT | Django OTP | Django OTP Agents | Django OTP Twilio | Django OTP YubiKey | Django Places | Django Wiki | FastAPI | filelock | Fluentd | github3.py | Gradio | HTTPX | iCalendar for Humans | LinkChecker | Litestar | Material for MkDocs | MicroPython | MkDocs | openSUSE | Nox | Packit | pipx | platformdirs | Pydantic | Pygments | PyHamcrest | PyMdown Extensions | Python JSON Schema | Rye | SALib | Spack | Starlette | structlog | tox | Twisted | urllib3 | Uvicorn | virtualenv | Voil\u00e0 | XGBoost | Ypy | yt-dlp
"},{"location":"community/users/#industry","title":"Industry","text":"Build targets are defined as sections within tool.hatch.build.targets
:
[tool.hatch.build.targets.<TARGET_NAME>]\n
[build.targets.<TARGET_NAME>]\n
Tip
Although not recommended, you may define global configuration in the tool.hatch.build
table. Keys may then be overridden by target config.
To be compatible with the broader Python packaging ecosystem, you must define the build system as follows:
pyproject.toml[build-system]\nrequires = [\"hatchling\"]\nbuild-backend = \"hatchling.build\"\n
The version of hatchling
defined here will be used to build all targets.
Hatchling is a standards-compliant1 build backend and is a dependency of Hatch itself.
"},{"location":"config/build/#file-selection","title":"File selection","text":""},{"location":"config/build/#vcs","title":"VCS","text":"By default, Hatch will respect the first .gitignore
or .hgignore
file found in your project's root directory or parent directories. Set ignore-vcs
to true
to disable this behavior:
[tool.hatch.build.targets.sdist]\nignore-vcs = true\n
[build.targets.sdist]\nignore-vcs = true\n
Note
For .hgignore
files only glob syntax is supported.
You can set the include
and exclude
options to select exactly which files will be shipped in each build, with exclude
taking precedence. Every entry represents a Git-style glob pattern.
For example, the following configuration:
pyproject.toml hatch.toml[tool.hatch.build.targets.sdist]\ninclude = [\n \"pkg/*.py\",\n \"/tests\",\n]\nexclude = [\n \"*.json\",\n \"pkg/_compat.py\",\n]\n
[build.targets.sdist]\ninclude = [\n \"pkg/*.py\",\n \"/tests\",\n]\nexclude = [\n \"*.json\",\n \"pkg/_compat.py\",\n]\n
will exclude every file with a .json
extension, and will include everything under a tests
directory located at the root and every file with a .py
extension that is directly under a pkg
directory located at the root except for _compat.py
.
If you want to include files that are ignored by your VCS, such as those that might be created by build hooks, you can use the artifacts
option. This option is semantically equivalent to include
.
Note that artifacts are not affected by the exclude
option. Artifacts can be excluded by using more explicit paths or by using the !
negation operator. When using the !
operator, the negated pattern(s) must come after the more generic ones.
[tool.hatch.build.targets.wheel]\nartifacts = [\n \"*.so\",\n \"*.dll\",\n \"!/foo/*.so\",\n]\n
[build.targets.wheel]\nartifacts = [\n \"*.so\",\n \"*.dll\",\n \"!/foo/*.so\",\n]\n
"},{"location":"config/build/#explicit-selection","title":"Explicit selection","text":""},{"location":"config/build/#generic","title":"Generic","text":"You can use the only-include
option to prevent directory traversal starting at the project root and only select specific relative paths to directories or files. Using this option ignores any defined include
patterns.
[tool.hatch.build.targets.sdist]\nonly-include = [\"pkg\", \"tests/unit\"]\n
[build.targets.sdist]\nonly-include = [\"pkg\", \"tests/unit\"]\n
"},{"location":"config/build/#packages","title":"Packages","text":"The packages
option is semantically equivalent to only-include
(which takes precedence) except that the shipped path will be collapsed to only include the final component.
So for example, if you want to ship a package foo
that is stored in a directory src
you would do:
[tool.hatch.build.targets.wheel]\npackages = [\"src/foo\"]\n
[build.targets.wheel]\npackages = [\"src/foo\"]\n
"},{"location":"config/build/#forced-inclusion","title":"Forced inclusion","text":"The force-include
option allows you to select specific files or directories from anywhere on the file system that should be included and map them to the desired relative distribution path.
For example, if there was a directory alongside the project root named artifacts
containing a file named lib.so
and a file named lib.h
in your home directory, you could ship both files in a pkg
directory with the following configuration:
[tool.hatch.build.targets.wheel.force-include]\n\"../artifacts\" = \"pkg\"\n\"~/lib.h\" = \"pkg/lib.h\"\n
[build.targets.wheel.force-include]\n\"../artifacts\" = \"pkg\"\n\"~/lib.h\" = \"pkg/lib.h\"\n
Note
/
(a forward slash).Warning
Files included using this option will overwrite any file path that was already included by other file selection options.
"},{"location":"config/build/#default-file-selection","title":"Default file selection","text":"If no file selection options are provided, then what gets included is determined by each build target.
"},{"location":"config/build/#excluding-files-outside-packages","title":"Excluding files outside packages","text":"If you want to exclude non-artifact files that do not reside within a Python package, set only-packages
to true
:
[tool.hatch.build.targets.wheel]\nonly-packages = true\n
[build.targets.wheel]\nonly-packages = true\n
"},{"location":"config/build/#rewriting-paths","title":"Rewriting paths","text":"You can rewrite relative paths to directories with the sources
option. For example, the following configuration:
[tool.hatch.build.targets.wheel.sources]\n\"src/foo\" = \"bar\"\n
[build.targets.wheel.sources]\n\"src/foo\" = \"bar\"\n
would distribute the file src/foo/file.ext
as bar/file.ext
.
If you want to remove path prefixes entirely, rather than setting each to an empty string, you can define sources
as an array:
[tool.hatch.build.targets.wheel]\nsources = [\"src\"]\n
[build.targets.wheel]\nsources = [\"src\"]\n
If you want to add a prefix to paths, you can use an empty string. For example, the following configuration:
pyproject.toml hatch.toml[tool.hatch.build.targets.wheel.sources]\n\"\" = \"foo\"\n
[build.targets.wheel.sources]\n\"\" = \"foo\"\n
would distribute the file bar/file.ext
as foo/bar/file.ext
.
The packages option itself relies on sources. Defining packages = [\"src/foo\"]
for the wheel
target is equivalent to the following:
[tool.hatch.build.targets.wheel]\nonly-include = [\"src/foo\"]\nsources = [\"src\"]\n
[build.targets.wheel]\nonly-include = [\"src/foo\"]\nsources = [\"src\"]\n
"},{"location":"config/build/#performance","title":"Performance","text":"All encountered directories are traversed by default. To skip non-artifact directories that are excluded, set skip-excluded-dirs
to true
:
[tool.hatch.build]\nskip-excluded-dirs = true\n
[build]\nskip-excluded-dirs = true\n
Warning
This may result in not shipping desired files. For example, if you want to include the file a/b/c.txt
but your VCS ignores a/b
, the file c.txt
will not be seen because its parent directory will not be entered. In such cases you can use the force-include
option.
By default, build targets will build in a reproducible manner provided that they support that behavior. To disable this, set reproducible
to false
:
[tool.hatch.build]\nreproducible = false\n
[build]\nreproducible = false\n
When enabled, the SOURCE_DATE_EPOCH environment variable will be used for all build timestamps. If not set, then Hatch will use an unchanging default value.
"},{"location":"config/build/#output-directory","title":"Output directory","text":"When the output directory is not provided to the build
command, the dist
directory will be used by default. You can change the default to a different directory using a relative or absolute path like so:
[tool.hatch.build]\ndirectory = \"<PATH>\"\n
[build]\ndirectory = \"<PATH>\"\n
"},{"location":"config/build/#dev-mode","title":"Dev mode","text":"By default for dev mode environment installations or editable installs, the wheel
target will determine which directories should be added to Python's search path based on the selected files.
If you want to override this detection or perhaps instruct other build targets as well, you can use the dev-mode-dirs
option:
[tool.hatch.build]\ndev-mode-dirs = [\".\"]\n
[build]\ndev-mode-dirs = [\".\"]\n
If you don't want to add entire directories to Python's search path, you can enable a more targeted mechanism with the mutually exclusive dev-mode-exact
option:
[tool.hatch.build]\ndev-mode-exact = true\n
[build]\ndev-mode-exact = true\n
Warning
The dev-mode-exact
mechanism is not supported by static analysis tools & IDEs, therefore functionality such as autocompletion is unlikely to work.
A build target can be provided by any builder plugin. There are three built-in build targets: wheel, sdist, and custom.
"},{"location":"config/build/#target-dependencies","title":"Dependencies","text":"You can specify additional dependencies that will be installed in each build environment, such as for third party builders:
pyproject.toml hatch.toml[tool.hatch.build.targets.your-target-name]\ndependencies = [\n \"your-builder-plugin\"\n]\n
[build.targets.your-target-name]\ndependencies = [\n \"your-builder-plugin\"\n]\n
You can also declare dependence on the project's runtime dependencies with the require-runtime-dependencies
option:
[tool.hatch.build.targets.your-target-name]\nrequire-runtime-dependencies = true\n
[build.targets.your-target-name]\nrequire-runtime-dependencies = true\n
Additionally, you may declare dependence on specific runtime features of the project with the require-runtime-features
option:
[tool.hatch.build.targets.your-target-name]\nrequire-runtime-features = [\n \"feature1\",\n \"feature2\",\n]\n
[build.targets.your-target-name]\nrequire-runtime-features = [\n \"feature1\",\n \"feature2\",\n]\n
"},{"location":"config/build/#versions","title":"Versions","text":"If a build target supports multiple build strategies or if there are major changes over time, you can specify exactly which versions you want to build using the versions
option:
[tool.hatch.build.targets.<TARGET_NAME>]\nversions = [\n \"v1\",\n \"beta-feature\",\n]\n
[build.targets.<TARGET_NAME>]\nversions = [\n \"v1\",\n \"beta-feature\",\n]\n
See the wheel target for a real world example.
"},{"location":"config/build/#build-hooks","title":"Build hooks","text":"A build hook defines code that will be executed at various stages of the build process and can be provided by any build hook plugin. There is one built-in build hook: custom.
Build hooks can be applied either globally:
pyproject.toml hatch.toml[tool.hatch.build.hooks.<HOOK_NAME>]\n
[build.hooks.<HOOK_NAME>]\n
or to specific build targets:
pyproject.toml hatch.toml[tool.hatch.build.targets.<TARGET_NAME>.hooks.<HOOK_NAME>]\n
[build.targets.<TARGET_NAME>.hooks.<HOOK_NAME>]\n
"},{"location":"config/build/#hook-dependencies","title":"Dependencies","text":"You can specify additional dependencies that will be installed in each build environment, such as for third party build hooks:
pyproject.toml hatch.toml[tool.hatch.build.hooks.your-hook-name]\ndependencies = [\n \"your-build-hook-plugin\"\n]\n
[build.hooks.your-hook-name]\ndependencies = [\n \"your-build-hook-plugin\"\n]\n
You can also declare dependence on the project's runtime dependencies with the require-runtime-dependencies
option:
[tool.hatch.build.hooks.your-hook-name]\nrequire-runtime-dependencies = true\n
[build.hooks.your-hook-name]\nrequire-runtime-dependencies = true\n
Additionally, you may declare dependence on specific runtime features of the project with the require-runtime-features
option:
[tool.hatch.build.hooks.your-hook-name]\nrequire-runtime-features = [\n \"feature1\",\n \"feature2\",\n]\n
[build.hooks.your-hook-name]\nrequire-runtime-features = [\n \"feature1\",\n \"feature2\",\n]\n
"},{"location":"config/build/#order-of-execution","title":"Order of execution","text":"For each build target, build hooks execute in the order in which they are defined, starting with global hooks.
As an example, for the following configuration:
pyproject.toml hatch.toml[tool.hatch.build.targets.foo.hooks.hook2]\n\n[tool.hatch.build.hooks.hook3]\n[tool.hatch.build.hooks.hook1]\n
[build.targets.foo.hooks.hook2]\n\n[build.hooks.hook3]\n[build.hooks.hook1]\n
When target foo
is built, build hook hook3
will be executed first, followed by hook1
, and then finally hook2
.
If you want to disable a build hook by default and control its use by environment variables, you can do so by setting the enable-by-default
option to false
:
[tool.hatch.build.hooks.<HOOK_NAME>]\nenable-by-default = false\n
[build.hooks.<HOOK_NAME>]\nenable-by-default = false\n
"},{"location":"config/build/#environment-variables","title":"Environment variables","text":"Variable Default Description HATCH_BUILD_CLEAN
false
Whether or not existing artifacts should first be removed HATCH_BUILD_CLEAN_HOOKS_AFTER
false
Whether or not build hook artifacts should be removed after each build HATCH_BUILD_HOOKS_ONLY
false
Whether or not to only execute build hooks HATCH_BUILD_NO_HOOKS
false
Whether or not to disable all build hooks; this takes precedence over other options HATCH_BUILD_HOOKS_ENABLE
false
Whether or not to enable all build hooks HATCH_BUILD_HOOK_ENABLE_<HOOK_NAME>
false
Whether or not to enable the build hook named <HOOK_NAME>
HATCH_BUILD_LOCATION
dist
The location with which to build the targets; only used by the build
command Support for PEP 517 and PEP 660 guarantees interoperability with other build tools.\u00a0\u21a9
You can populate configuration with the values of certain supported fields using the syntax of Python's format strings. Each field interprets the modifier part after the colon differently, if at all.
"},{"location":"config/context/#global-fields","title":"Global fields","text":"Any configuration that declares support for context formatting will always support these fields.
"},{"location":"config/context/#paths","title":"Paths","text":"Field Descriptionroot
The root project directory home
The user's home directory All paths support the following modifiers:
Modifier Descriptionuri
The normalized absolute URI path prefixed by file:
real
The path with all symbolic links resolved parent
The parent of the preceding path Tip
The parent
modifier can be chained and may be combined with either the uri
or real
modifier, with the latter placed at the end. For example:
[tool.hatch.envs.test]\ndependencies = [\n \"example-project @ {root:parent:parent:uri}/example-project\",\n]\n
[envs.test]\ndependencies = [\n \"example-project @ {root:parent:parent:uri}/example-project\",\n]\n
"},{"location":"config/context/#system-separators","title":"System separators","text":"Field Description /
\\
on Windows, /
otherwise ;
;
on Windows, :
otherwise"},{"location":"config/context/#environment-variables","title":"Environment variables","text":"The env
field and its modifier allow you to select the value of an environment variable. If the environment variable is not set, you must specify a default value as an additional modifier e.g. {env:PATH:DEFAULT}
.
You can insert fields within others. For example, if you wanted a script that displays the value of the environment variable FOO
, with a fallback to the environment variable BAR
, with its own fallback to the user's home directory, you could do the following:
[tool.hatch.envs.test.scripts]\ndisplay = \"echo {env:FOO:{env:BAR:{home}}}\"\n
[envs.test.scripts]\ndisplay = \"echo {env:FOO:{env:BAR:{home}}}\"\n
"},{"location":"config/dependency/","title":"Dependency configuration","text":"Project dependencies are defined with PEP 508 strings using optional PEP 440 version specifiers.
"},{"location":"config/dependency/#version-specifiers","title":"Version specifiers","text":"A version specifier consists of a series of version clauses, separated by commas. For example:
pyproject.toml[project]\n...\ndependencies = [\n \"cryptography\",\n \"click>=7, <9, != 8.0.0\",\n \"python-dateutil==2.8.*\",\n \"numpy~=1.21.4\",\n]\n
The comma is equivalent to a logical AND
operator: a candidate version must match all given version clauses in order to match the specifier as a whole.
~=
Compatible release ==
Version matching !=
Version exclusion <=
, >=
Inclusive ordered comparison <
, >
Exclusive ordered comparison ===
Arbitrary equality"},{"location":"config/dependency/#version-matching","title":"Version matching","text":"A version matching clause includes the version matching operator ==
and a version identifier.
By default, the version matching operator is based on a strict equality comparison: the specified version must be exactly the same as the requested version.
Clause Allowed versions==1
1.0.0
==1.2
1.2.0
Prefix matching may be requested instead of strict comparison, by appending a trailing .*
to the version identifier in the version matching clause. This means that additional trailing segments will be ignored when determining whether or not a version identifier matches the clause.
==1.*
>=1.0.0, <2.0.0
==1.2.*
>=1.2.0, <1.3.0
"},{"location":"config/dependency/#compatible-release","title":"Compatible release","text":"A compatible release clause consists of the compatible release operator ~=
and a version identifier. It matches any candidate version that is expected to be compatible with the specified version.
For a given release identifier V.N
, the compatible release clause is approximately equivalent to the following pair of comparison clauses:
>= V.N, == V.*\n
This operator cannot be used with a single segment version number such as ~=1
.
~=1.2
>=1.2.0, <2.0.0
~=1.2.3
>=1.2.3, <1.3.0
"},{"location":"config/dependency/#version-exclusion","title":"Version exclusion","text":"A version exclusion clause includes the version exclusion operator !=
and a version identifier.
The allowed version identifiers and comparison semantics are the same as those of the Version matching operator, except that the sense of any match is inverted.
"},{"location":"config/dependency/#ordered-comparison","title":"Ordered comparison","text":"Inclusive comparisons allow for the version identifier part of clauses whereas exclusive comparisons do not. For example, >=1.2
allows for version 1.2.0
while >1.2
does not.
Unlike the inclusive ordered comparisons <=
and >=
, the exclusive ordered comparisons <
and >
specifically exclude pre-releases, post-releases, and local versions of the specified version.
Though heavily discouraged, arbitrary equality comparisons allow for simple string matching without any version semantics, for example ===foobar
.
Environment markers allow for dependencies to only be installed when certain conditions are met.
For example, if you need to install the latest version of cryptography
that is available for a given Python major version you could define the following:
cryptography==3.3.2; python_version < \"3\"\ncryptography>=35.0; python_version > \"3\"\n
Alternatively, if you only need it on Python 3 when running on Windows you could do:
cryptography; python_version ~= \"3.0\" and platform_system == \"Windows\"\n
The available environment markers are as follows.
Marker Python equivalent Examplesos_name
import os
os.name
sys_platform
import sys
sys.platform
platform_machine
import platform
platform.machine()
platform_python_implementation
import platform
platform.python_implementation()
platform_release
import platform
platform.release()
platform_system
import platform
platform.system()
platform_version
import platform
platform.version()
python_version
import platform
'.'.join(platform.python_version_tuple()[:2])
python_full_version
import platform
platform.python_version()
implementation_name
import sys
sys.implementation.name
implementation_version
See here You can select groups of optional dependencies to install using the extras syntax. For example, if a dependency named foo
defined the following:
[project.optional-dependencies]\ncrypto = [\n \"PyJWT\",\n \"cryptography\",\n]\nfastjson = [\n \"orjson\",\n]\ncli = [\n \"prompt-toolkit\",\n \"colorama; platform_system == 'Windows'\",\n]\n
You can select the cli
and crypto
features like so:
foo[cli,crypto]==1.*\n
Note that the features come immediately after the package name, before any version specifiers.
"},{"location":"config/dependency/#self-referential","title":"Self-referential","text":"Feature groups can self-referentially extend others. For example, for a project called awesome-project
, the dev
feature group in the following pyproject.toml
file would select everything in the crypto
feature group, plus black
:
[project]\nname = \"awesome-project\"\n\n[project.optional-dependencies]\ncrypto = [\n \"PyJWT\",\n \"cryptography\",\n]\ndev = [\n \"awesome-project[crypto]\",\n \"black\",\n]\n
"},{"location":"config/dependency/#direct-references","title":"Direct references","text":"Instead of using normal version specifiers and fetching packages from an index like PyPI, you can define exact sources using direct references with an explicit URI.
Direct references are usually not meant to be used for dependencies of a published project but rather are used for defining dependencies for an environment.
All direct reference types are prefixed by the package name like:
<NAME> @ <REFERENCE>\n
"},{"location":"config/dependency/#version-control-systems","title":"Version control systems","text":"Various version control systems (VCS) are supported as long as the associated executable is available along your PATH
.
VCS direct references are defined using one of the following formats:
<NAME> @ <SCHEME>://<PATH>\n<NAME> @ <SCHEME>://<PATH>@<REVISION>\n
You may also append a #subdirectory=<PATH>
component for specifying the relative path to the Python package when it is not located at the root e.g. #subdirectory=lib/foo
.
For more information, refer to this.
"},{"location":"config/dependency/#supported-vcs","title":"Supported VCS","text":"GitMercurialSubversionBazaar Executable Schemes Revisions Examplegit
git+file
git+https
git+ssh
git+http
git+git
git
proj @ git+https://github.com/org/proj.git@v1
Executable Schemes Revisions Example hg
hg+file
hg+https
hg+ssh
hg+http
hg+static-http
proj @ hg+file:///path/to/proj@v1
Executable Schemes Revisions Example svn
svn+https
svn+ssh
svn+http
svn+svn
svn
proj @ svn+file:///path/to/proj
Executable Schemes Revisions Example bzr
bzr+https
bzr+ssh
bzr+sftp
bzr+lp
bzr+http
bzr+ftp
proj @ bzr+lp:proj@v1
"},{"location":"config/dependency/#local","title":"Local","text":"You can install local packages with the file
scheme in the following format:
<NAME> @ file://<HOST>/<PATH>\n
The <HOST>
is only used on Windows systems, where it can refer to a network share. If omitted it is assumed to be localhost
and the third slash must still be present.
The <PATH>
can refer to a source archive, a wheel, or a directory containing a Python package.
proj @ file:///path/to/pkg.tar.gz
proj @ file:///c:/path/to/pkg.tar.gz
Wheel proj @ file:///path/to/pkg.whl
proj @ file:///c:/path/to/pkg.whl
Directory proj @ file:///path/to/pkg
proj @ file:///c:/path/to/pkg
Tip
You may also specify paths relative to your project's root directory on all platforms by using context formatting:
<NAME> @ {root:uri}/pkg_inside_project\n<NAME> @ {root:parent:uri}/pkg_alongside_project\n
"},{"location":"config/dependency/#remote","title":"Remote","text":"You can install source archives and wheels by simply referring to a URL:
black @ https://github.com/psf/black/archive/refs/tags/21.10b0.zip\npytorch @ https://download.pytorch.org/whl/cu102/torch-1.10.0%2Bcu102-cp39-cp39-linux_x86_64.whl\n
An expected hash value may be specified by appending a #<HASH_ALGORITHM>=<EXPECTED_HASH>
component:
requests @ https://github.com/psf/requests/archive/refs/tags/v2.26.0.zip#sha256=eb729a757f01c10546ebd179ae2aec852dd0d7f8ada2328ccf4558909d859985\n
If the hash differs from the expected hash, the installation will fail.
It is recommended that only hashes which are unconditionally provided by the latest version of the standard library's hashlib module be used for hashes. As of Python 3.10, that list consists of:
md5
sha1
sha224
sha256
sha384
sha512
blake2b
blake2s
The following is an example that uses features and environment markers:
pkg[feature1,feature2] @ <REFERENCE> ; python_version < \"3.7\"\n
Note that the space before the semicolon is required.
"},{"location":"config/hatch/","title":"Hatch configuration","text":"Configuration for Hatch itself is stored in a config.toml
file located by default in one of the following platform-specific directories.
~/Library/Application Support/hatch
Windows %USERPROFILE%\\AppData\\Local\\hatch
Unix $XDG_CONFIG_HOME/hatch
(the XDG_CONFIG_HOME environment variable default is ~/.config
) You can select a custom path to the file using the --config
root option or by setting the HATCH_CONFIG
environment variable.
The file can be managed by the config
command group.
The mode
key controls how Hatch selects the project to work on.
mode = \"local\"\n
By default, Hatch will look for a pyproject.toml
file in the current working directory and any parent directories. The directory storing the first found file will be considered the project root.
mode = \"project\"\nproject = \"proj1\"\n\n[projects]\nproj1 = \"/path/to/project1\"\nproj2 = {\"location\": \"/path/to/project2\"}\n\n[dirs]\nproject = [\"/path/to/monorepo1\", \"/path/to/monorepo2\"]\n
In this mode, Hatch will only work on the selected project
. The project is located using multiple heuristics:
projects
table then it must be a string, or an inline table with a location
key, that is the full path to the project.dirs.project
, then that will be used as the project root.An error will occur if the project cannot be found.
You can use the config set
command to change the project you are working on:
$ hatch config set project proj2\nNew setting:\nproject = \"proj2\"\n
The project can be selected on a per-command basis with the -p
/--project
(environment variable HATCH_PROJECT
) root option.
mode = \"aware\"\n
This is essentially the local
mode with a fallback to the project
mode.
You can control the shell used to enter environments with the shell
key.
If defined as a string, it must be the name of one of the supported shells and be available along your PATH
.
shell = \"fish\"\n
If the executable name of your shell differs from the supported name, you can define the shell
as a table with name
and path
keys.
[shell]\nname = \"bash\"\npath = \"/bin/ash\"\n
You can change the default arguments used to spawn most shells with the args
key. The default for such supported shells is usually [\"-i\"]
.
[shell]\nname = \"bash\"\nargs = [\"--login\"]\n
"},{"location":"config/hatch/#supported","title":"Supported","text":"Shell Name Arguments macOS Windows Unix Almquist shell ash
[\"-i\"]
Bash bash
[\"-i\"]
Command Prompt cmd
C shell csh
[\"-i\"]
fish fish
[\"-i\"]
Nushell nu
[]
PowerShell pwsh
, powershell
tcsh tcsh
[\"-i\"]
xonsh xonsh
[\"-i\"]
Z shell zsh
[\"-i\"]
"},{"location":"config/hatch/#default","title":"Default","text":"Hatch will attempt to use the current shell based on parent processes. If the shell cannot be determined, then on Windows systems Hatch will use the SHELL
environment variable, if present, followed by the COMSPEC
environment variable, defaulting to cmd
. On all other platforms only the SHELL
environment variable will be used, defaulting to bash
.
[dirs]\ndata = \"...\"\n
This is the directory that is used to persist data. By default it is set to one of the following platform-specific directories.
Platform Path macOS~/Library/Application Support/hatch
Windows %USERPROFILE%\\AppData\\Local\\hatch
Unix $XDG_DATA_HOME/hatch
(the XDG_DATA_HOME environment variable default is ~/.local/share
) You can select a custom path to the directory using the --data-dir
root option or by setting the HATCH_DATA_DIR
environment variable.
[dirs]\ncache = \"...\"\n
This is the directory that is used to cache data. By default it is set to one of the following platform-specific directories.
Platform Path macOS~/Library/Caches/hatch
Windows %USERPROFILE%\\AppData\\Local\\hatch\\Cache
Unix $XDG_CACHE_HOME/hatch
(the XDG_CACHE_HOME environment variable default is ~/.cache
) You can select a custom path to the directory using the --cache-dir
root option or by setting the HATCH_CACHE_DIR
environment variable.
[dirs.env]\n<ENV_TYPE> = \"...\"\n
This determines where to store environments, with every key being the type of environment and the value being the desired storage location.
For example, if you wanted to store virtual environments in a .virtualenvs
directory within your home directory, you could specify the following:
[dirs.env]\nvirtual = \"~/.virtualenvs\"\n
Any environment variables are also expanded.
If the path is not absolute, then it will be relative to the project root. So if you wanted to use a directory named .hatch
in each project directory, you could do:
[dirs.env]\nvirtual = \".hatch\"\n
Any type of environment that is not explicitly defined will default to <DATA_DIR>/env/<ENV_TYPE>
.
[dirs]\npython = \"...\"\n
This determines where to install specific versions of Python.
The following values have special meanings:
Value Pathisolated
(default) <DATA_DIR>/pythons
"},{"location":"config/hatch/#terminal","title":"Terminal","text":"You can configure how all output is displayed using the terminal.styles
table. These settings are also applied to all plugins.
[terminal.styles]\nerror = \"...\"\n...\n
Cross-platform terminal capabilities are provided by Rich.
"},{"location":"config/hatch/#output-levels","title":"Output levels","text":"The levels of output are as follows. Note that the verbosity indicates the minimum level at which the output is displayed.
Level Default Verbosity Descriptiondebug
bold
1 - 3 Messages that are not useful for most user experiences error
bold red
-2 Messages indicating some unrecoverable error info
bold
0 Messages conveying basic information success
bold cyan
0 Messages indicating some positive outcome waiting
bold magenta
0 Messages shown before potentially time consuming operations warning
bold yellow
-1 Messages conveying important information See the documentation and color reference for guidance on valid values.
"},{"location":"config/hatch/#spinner","title":"Spinner","text":"You can select the sequence used for waiting animations with the spinner
option.
[terminal.styles]\nspinner = \"...\"\n
"},{"location":"config/metadata/","title":"Configuring project metadata","text":"Project metadata is stored in a pyproject.toml
file located at the root of a project's tree and is based entirely on the standard.
The name of the project.
pyproject.toml[project]\nname = \"your-app\"\n
"},{"location":"config/metadata/#version","title":"Version (required)","text":"pyproject.toml DynamicStatic See the dedicated versioning section.
[project]\n...\ndynamic = [\"version\"]\n\n[tool.hatch.version]\npath = \"...\"\n
[project]\n...\nversion = \"0.0.1\"\n
"},{"location":"config/metadata/#description","title":"Description","text":"A brief summary of the project.
pyproject.toml[project]\n...\ndescription = '...'\n
"},{"location":"config/metadata/#readme","title":"Readme","text":"The full description of the project.
pyproject.toml SimpleComplexThe file extension must be .md
, .rst
, or .txt
.
[project]\n...\nreadme = \"README.md\"\n
The content-type
field must be set to text/markdown
, text/x-rst
, or text/plain
.
A charset
field may also be set to instruct which encoding to use for reading the file, defaulting to utf-8
.
[project]\n...\nreadme = {\"file\" = \"README.md\", \"content-type\" = \"text/markdown\"}\n
The content-type
field must be set to text/markdown
or text/x-rst
.
[project]\n...\nreadme = {\"text\" = \"...\", \"content-type\" = \"text/markdown\"}\n
Note
If this is defined as a file, then it will always be included in source distributions for consistent builds.
"},{"location":"config/metadata/#python-support","title":"Python support","text":"The Python version requirements of the project.
pyproject.toml[project]\n...\nrequires-python = \">=3.8\"\n
"},{"location":"config/metadata/#license","title":"License","text":"For more information, see PEP 639.
pyproject.toml SPDX expressionFiles[project]\n...\nlicense = \"Apache-2.0 OR MIT\"\n
PathsGlobs [project]\n...\nlicense-files = { paths = [\"LICENSE.txt\"] }\n
[project]\n...\nlicense-files = { globs = [\"LICENSES/*\"] }\n
"},{"location":"config/metadata/#ownership","title":"Ownership","text":"The people or organizations considered to be the authors
or maintainers
of the project. The exact meaning is open to interpretation; it may list the original or primary authors, current maintainers, or owners of the package. If the values are the same, prefer only the use of the authors
field.
[project]\n...\nauthors = [\n { name = \"...\", email = \"...\" },\n]\nmaintainers = [\n { name = \"...\", email = \"...\" },\n]\n
"},{"location":"config/metadata/#keywords","title":"Keywords","text":"The keywords used to assist in the discovery of the project.
pyproject.toml[project]\n...\nkeywords = [\n \"...\",\n]\n
"},{"location":"config/metadata/#classifiers","title":"Classifiers","text":"The trove classifiers that apply to the project.
pyproject.toml[project]\n...\nclassifiers = [\n \"...\",\n]\n
"},{"location":"config/metadata/#urls","title":"URLs","text":"A table of URLs where the key is the URL label and the value is the URL itself.
pyproject.toml[project.urls]\nDocumentation = \"...\"\n\"Source code\" = \"...\"\n
"},{"location":"config/metadata/#dependencies","title":"Dependencies","text":"See the dependency specification page for more information.
Entries support context formatting and disallow direct references by default.
"},{"location":"config/metadata/#required","title":"Required","text":"pyproject.toml[project]\n...\ndependencies = [\n \"...\",\n]\n
"},{"location":"config/metadata/#optional","title":"Optional","text":"pyproject.toml [project.optional-dependencies]\noption1 = [\n \"...\",\n]\noption2 = [\n \"...\",\n]\n
"},{"location":"config/metadata/#entry-points","title":"Entry points","text":"Entry points are a mechanism for the project to advertise components it provides to be discovered and used by other code.
"},{"location":"config/metadata/#cli","title":"CLI","text":"After installing projects that define CLI scripts, each key will be available along your PATH
as a command that will call its associated object.
[project.scripts]\ncli-name = \"pkg.subpkg:func\"\n
Using the above example, running cli-name
would essentially execute the following Python script:
import sys\n\nfrom pkg.subpkg import func\n\nsys.exit(func())\n
"},{"location":"config/metadata/#gui","title":"GUI","text":"GUI scripts are exactly the same as CLI scripts except on Windows, where they are handled specially so that they can be started without a console.
pyproject.toml[project.gui-scripts]\ngui-name = \"pkg.subpkg:func\"\n
"},{"location":"config/metadata/#plugins","title":"Plugins","text":"pyproject.toml [project.entry-points.plugin-namespace]\nplugin-name1 = \"pkg.subpkg1\"\nplugin-name2 = \"pkg.subpkg2:func\"\n
"},{"location":"config/metadata/#dynamic","title":"Dynamic","text":"If any metadata fields are set dynamically, like the version
may be, then they must be listed here.
[project]\n...\ndynamic = [\n \"...\",\n]\n
"},{"location":"config/metadata/#metadata-options","title":"Metadata options","text":""},{"location":"config/metadata/#allowing-direct-references","title":"Allowing direct references","text":"By default, dependencies are not allowed to define direct references. To disable this check, set allow-direct-references
to true
:
[tool.hatch.metadata]\nallow-direct-references = true\n
[metadata]\nallow-direct-references = true\n
"},{"location":"config/metadata/#allowing-ambiguous-features","title":"Allowing ambiguous features","text":"By default, names of optional dependencies are normalized to prevent ambiguity. To disable this normalization, set allow-ambiguous-features
to true
:
[tool.hatch.metadata]\nallow-ambiguous-features = true\n
[metadata]\nallow-ambiguous-features = true\n
Deprecated
This option temporarily exists to provide better interoperability with tools that do not yet support PEP 685 and will be removed in the first minor release after Jan 1, 2024.
"},{"location":"config/project-templates/","title":"Project templates","text":"You can control how new projects are created by the new command using Hatch's config file.
"},{"location":"config/project-templates/#author","title":"Author","text":"config.toml[template]\nname = \"...\"\nemail = \"...\"\n
"},{"location":"config/project-templates/#licenses","title":"Licenses","text":"config.toml [template.licenses]\nheaders = true\ndefault = [\n \"MIT\",\n]\n
The list of licenses should be composed of SPDX identifiers. If multiple licenses are specified, then they will be placed in a LICENSES directory.
"},{"location":"config/project-templates/#options","title":"Options","text":""},{"location":"config/project-templates/#tests","title":"Tests","text":"This adds a tests
directory with environments for testing and linting.
[template.plugins.default]\ntests = true\n
"},{"location":"config/project-templates/#ci","title":"CI","text":"This adds a GitHub Actions workflow that runs tests on all platforms using modern versions of Python.
config.toml[template.plugins.default]\nci = false\n
"},{"location":"config/project-templates/#src-layout","title":"src
layout","text":"See this blog post.
config.toml[template.plugins.default]\nsrc-layout = true\n
"},{"location":"config/project-templates/#feature-flags","title":"Feature flags","text":""},{"location":"config/project-templates/#command-line-interface","title":"Command line interface","text":"The --cli
flag adds a CLI backed by Click that can also be invoked with python -m <PKG_NAME>
.
All environments support the following extra context formatting fields:
Field Descriptionenv_name
The name of the environment env_type
The type of environment matrix
Its modifier selects the value of that matrix variable. If the environment is not part of a matrix or was not generated with the variable, you must specify a default value as an additional modifier e.g. {matrix:version:v1.0.0}
. verbosity
The integer verbosity value of Hatch. A flag
modifier is supported that will render the value as a CLI flag e.g. -2
becomes -qq
, 1
becomes -v
, and 0
becomes an empty string. An additional flag integer modifier may be used to adjust the verbosity level. For example, if you wanted to make a command quiet by default, you could use {verbosity:flag:-1}
within the command. args
For executed commands only, any extra command line arguments with an optional default modifier if none were provided"},{"location":"config/environment/advanced/#matrix","title":"Matrix","text":"Environments can define a series of matrices with the matrix
option:
[tool.hatch.envs.test]\ndependencies = [\n \"pytest\"\n]\n\n[[tool.hatch.envs.test.matrix]]\npython = [\"3.10\", \"3.11\"]\nversion = [\"42\", \"3.14\"]\n\n[[tool.hatch.envs.test.matrix]]\npython = [\"3.11\", \"3.12\"]\nversion = [\"9000\"]\nfeature = [\"foo\", \"bar\"]\n
[envs.test]\ndependencies = [\n \"pytest\"\n]\n\n[[envs.test.matrix]]\npython = [\"3.10\", \"3.11\"]\nversion = [\"42\", \"3.14\"]\n\n[[envs.test.matrix]]\npython = [\"3.11\", \"3.12\"]\nversion = [\"9000\"]\nfeature = [\"foo\", \"bar\"]\n
Doing so will result in the product of each variable combination being its own environment.
"},{"location":"config/environment/advanced/#naming","title":"Naming","text":"The name of the generated environments will be the variable values of each combination separated by hyphens, altogether prefixed by <ENV_NAME>.
. For example, the following configuration:
[[tool.hatch.envs.test.matrix]]\nversion = [\"42\"]\nfeature = [\"foo\", \"bar\"]\n
[[envs.test.matrix]]\nversion = [\"42\"]\nfeature = [\"foo\", \"bar\"]\n
would indicate the following unique environments:
test.42-foo\ntest.42-bar\n
The exceptions to this format are described below.
"},{"location":"config/environment/advanced/#python-variables","title":"Python variables","text":"If the variables py
or python
are specified, then they will rank first in the product result and will be prefixed by py
if the value is not. For example, the following configuration:
[[tool.hatch.envs.test.matrix]]\nversion = [\"42\"]\npython = [\"3.9\", \"pypy3\"]\n
[[envs.test.matrix]]\nversion = [\"42\"]\npython = [\"3.9\", \"pypy3\"]\n
would generate the following environments:
test.py3.9-42\ntest.pypy3-42\n
Note
The value of this variable sets the Python version.
"},{"location":"config/environment/advanced/#name-formatting","title":"Name formatting","text":"You can set the matrix-name-format
option to modify how each variable part is formatted which recognizes the placeholders {variable}
and {value}
. For example, the following configuration:
[tool.hatch.envs.test]\nmatrix-name-format = \"{variable}_{value}\"\n\n[[tool.hatch.envs.test.matrix]]\nversion = [\"42\"]\nfeature = [\"foo\", \"bar\"]\n
[envs.test]\nmatrix-name-format = \"{variable}_{value}\"\n\n[[envs.test.matrix]]\nversion = [\"42\"]\nfeature = [\"foo\", \"bar\"]\n
would produce the following environments:
test.version_42-feature_foo\ntest.version_42-feature_bar\n
By default this option is set to {value}
.
If the default
environment defines matrices, then the generated names will not be prefixed by the environment name. This can be useful for projects that only need a single series of matrices without any standalone environments.
Rather than selecting a single generated environment, you can select the root environment to target all of them. For example, if you have the following configuration:
pyproject.toml hatch.toml[tool.hatch.envs.test]\ndependencies = [\n \"coverage[toml]\",\n \"pytest\",\n \"pytest-cov\",\n]\n\n[tool.hatch.envs.test.scripts]\ncov = 'pytest --cov-report=term-missing --cov-config=pyproject.toml --cov=pkg --cov=tests'\n\n[[tool.hatch.envs.test.matrix]]\npython = [\"3.11\", \"3.12\"]\nversion = [\"42\", \"3.14\"]\n
[envs.test]\ndependencies = [\n \"coverage[toml]\",\n \"pytest\",\n \"pytest-cov\",\n]\n\n[envs.test.scripts]\ncov = 'pytest --cov-report=term-missing --cov-config=pyproject.toml --cov=pkg --cov=tests'\n\n[[envs.test.matrix]]\npython = [\"3.11\", \"3.12\"]\nversion = [\"42\", \"3.14\"]\n
you could then run your tests consecutively in all 4 environments with:
hatch run test:cov\n
"},{"location":"config/environment/advanced/#option-overrides","title":"Option overrides","text":"You can modify options based on the conditions of different sources like matrix variables with the overrides
table, using dotted key syntax for each declaration:
[tool.hatch.envs.<ENV_NAME>.overrides]\n<SOURCE>.<CONDITION>.<OPTION> = <VALUE>\n
[envs.<ENV_NAME>.overrides]\n<SOURCE>.<CONDITION>.<OPTION> = <VALUE>\n
The type of the selected option determines the types of values.
"},{"location":"config/environment/advanced/#platform-overrides","title":"Platform overrides","text":"Options can be modified based on the current platform using the platform
source.
[tool.hatch.envs.test.overrides]\nplatform.windows.scripts = [\n 'run=pytest -m \"not io_uring\"',\n]\n
[envs.test.overrides]\nplatform.windows.scripts = [\n 'run=pytest -m \"not io_uring\"',\n]\n
The following platforms are supported:
linux
windows
macos
Environment variables can modify options using the env
source.
[tool.hatch.envs.test.overrides]\nenv.GITHUB_ACTIONS.dev-mode = { value = false, if = [\"true\"] }\n
[envs.test.overrides]\nenv.GITHUB_ACTIONS.dev-mode = { value = false, if = [\"true\"] }\n
"},{"location":"config/environment/advanced/#matrix-variable-overrides","title":"Matrix variable overrides","text":"The matrix variables used to generate each environment can be used to modify options within using the matrix
source.
[tool.hatch.envs.test.overrides]\nmatrix.version.env-vars = \"PRODUCT_VERSION\"\nmatrix.auth.features = [\n { value = \"oauth\", if = [\"oauth2\"] },\n { value = \"kerberos\", if = [\"kerberos\"] },\n]\n\n[[tool.hatch.envs.test.matrix]]\npython = [\"3.11\", \"3.12\"]\nversion = [\"legacy\", \"latest\"]\nauth = [\"oauth2\", \"kerberos\", \"noauth\"]\n
[envs.test.overrides]\nmatrix.version.env-vars = \"PRODUCT_VERSION\"\nmatrix.auth.features = [\n { value = \"oauth\", if = [\"oauth2\"] },\n { value = \"kerberos\", if = [\"kerberos\"] },\n]\n\n[[envs.test.matrix]]\npython = [\"3.11\", \"3.12\"]\nversion = [\"legacy\", \"latest\"]\nauth = [\"oauth2\", \"kerberos\", \"noauth\"]\n
"},{"location":"config/environment/advanced/#name-overrides","title":"Name overrides","text":"When a matrix is defined, the name
source can be used for regular expression matching on the generated name, minus the prefix for non-default environments.
[tool.hatch.envs.test.overrides]\nname.\"^0\".env-vars = \"TESTING_UNSTABLE=true\"\n\n[[tool.hatch.envs.test.matrix]]\nversion = [\"0.1.0\", \"0.2.0\", \"1.0.0\"]\n
[envs.test.overrides]\nname.\"^0\".env-vars = \"TESTING_UNSTABLE=true\"\n\n[[envs.test.matrix]]\nversion = [\"0.1.0\", \"0.2.0\", \"1.0.0\"]\n
"},{"location":"config/environment/advanced/#types","title":"Types","text":"Literal types like strings for the Python version or booleans for skipping installation can be set using the value itself, an inline table, or an array. For example:
pyproject.toml hatch.toml[tool.hatch.envs.test.overrides]\nmatrix.foo.python = \"3.10\"\nmatrix.bar.skip-install = { value = true, if = [\"...\"] }\nenv.CI.dev-mode = [\n { value = false, if = [\"...\"] },\n true,\n]\n
[envs.test.overrides]\nmatrix.foo.python = \"3.10\"\nmatrix.bar.skip-install = { value = true, if = [\"...\"] }\nenv.CI.dev-mode = [\n { value = false, if = [\"...\"] },\n true,\n]\n
For arrays, the first allowed value will be used.
Array types like dependencies or commands can be appended to using an array of strings or inline tables. For example:
pyproject.toml hatch.toml[tool.hatch.envs.test.overrides]\nmatrix.foo.dependencies = [\n \"httpx\",\n { value = \"cryptography\" },\n]\n
[envs.test.overrides]\nmatrix.foo.dependencies = [\n \"httpx\",\n { value = \"cryptography\" },\n]\n
Mapping types like environment variables or scripts can have keys set using a string, or an array of strings or inline tables. For example:
pyproject.toml hatch.toml[tool.hatch.envs.test.overrides]\nmatrix.foo.env-vars = \"KEY=VALUE\"\nmatrix.bar.env-vars = [\n \"KEY1=VALUE1\",\n { key = \"KEY2\", value = \"VALUE2\" },\n]\n
[envs.test.overrides]\nmatrix.foo.env-vars = \"KEY=VALUE\"\nmatrix.bar.env-vars = [\n \"KEY1=VALUE1\",\n { key = \"KEY2\", value = \"VALUE2\" },\n]\n
If the value is missing (no =
for strings, no value
key for inline tables), then the value will be set to the value of the source condition.
Rather than supplementing the values within mapping types or array types, you can overwrite the option as a whole by prefixing the name with set-
:
[tool.hatch.envs.test.overrides]\nmatrix.foo.set-platforms = [\"macos\", \"linux\"]\n
[envs.test.overrides]\nmatrix.foo.set-platforms = [\"macos\", \"linux\"]\n
When overwriting entire options or keys within mappings, override sources are applied in the following order:
You may specify certain extra keys for any inline table that will determine whether or not to apply that entry. These modifiers may be combined with others and any negative evaluation will immediately cause the entry to be skipped.
"},{"location":"config/environment/advanced/#allowed-values","title":"Allowed values","text":"The if
key represents the allowed values for that condition. If the value of the condition is not listed, then that entry will not be applied:
[tool.hatch.envs.test.overrides]\nmatrix.version.python = { value = \"pypy\", if = [\"3.14\"] }\nmatrix.version.env-vars = [\n { key = \"KEY1\", value = \"VALUE1\", if = [\"42\"] },\n { key = \"KEY2\", value = \"VALUE2\", if = [\"3.14\"] },\n]\n\n[[tool.hatch.envs.test.matrix]]\nversion = [\"42\", \"3.14\"]\n
[envs.test.overrides]\nmatrix.version.python = { value = \"pypy\", if = [\"3.14\"] }\nmatrix.version.env-vars = [\n { key = \"KEY1\", value = \"VALUE1\", if = [\"42\"] },\n { key = \"KEY2\", value = \"VALUE2\", if = [\"3.14\"] },\n]\n\n[[envs.test.matrix]]\nversion = [\"42\", \"3.14\"]\n
"},{"location":"config/environment/advanced/#specific-platforms","title":"Specific platforms","text":"The platform
key represents the desired platforms. If the current platform is not listed, then that entry will not be applied:
[tool.hatch.envs.test.overrides]\nenv.EXPERIMENTAL.python = { value = \"pypy\", if = [\"1\"], platform = [\"macos\"] }\nmatrix.version.env-vars = [\n { key = \"KEY1\", value = \"VALUE1\", if = [\"42\"], platform = [\"linux\"] },\n { key = \"KEY2\", value = \"VALUE2\", if = [\"3.14\"] },\n]\n\n[[tool.hatch.envs.test.matrix]]\nversion = [\"42\", \"3.14\"]\n
[envs.test.overrides]\nenv.EXPERIMENTAL.python = { value = \"pypy\", if = [\"1\"], platform = [\"macos\"] }\nmatrix.version.env-vars = [\n { key = \"KEY1\", value = \"VALUE1\", if = [\"42\"], platform = [\"linux\"] },\n { key = \"KEY2\", value = \"VALUE2\", if = [\"3.14\"] },\n]\n\n[[envs.test.matrix]]\nversion = [\"42\", \"3.14\"]\n
"},{"location":"config/environment/advanced/#required-environment-variables","title":"Required environment variables","text":"The env
key represents the required environment variables. If any of the listed environment variables are not set or the defined value does not match, then that entry will not be applied:
[tool.hatch.envs.test.overrides]\nplatform.windows.python = { value = \"pypy\", env = [\"EXPERIMENTAL\"] }\nmatrix.version.env-vars = [\n { key = \"KEY1\", value = \"VALUE1\", if = [\"42\"], env = [\"FOO\", \"BAR=BAZ\"] },\n { key = \"KEY2\", value = \"VALUE2\", if = [\"3.14\"] },\n]\n\n[[tool.hatch.envs.test.matrix]]\nversion = [\"42\", \"3.14\"]\n
[envs.test.overrides]\nplatform.windows.python = { value = \"pypy\", env = [\"EXPERIMENTAL\"] }\nmatrix.version.env-vars = [\n { key = \"KEY1\", value = \"VALUE1\", if = [\"42\"], env = [\"FOO\", \"BAR=BAZ\"] },\n { key = \"KEY2\", value = \"VALUE2\", if = [\"3.14\"] },\n]\n\n[[envs.test.matrix]]\nversion = [\"42\", \"3.14\"]\n
"},{"location":"config/environment/overview/","title":"Environment configuration","text":"All environments are defined as sections within the tool.hatch.envs
table.
[tool.hatch.envs.<ENV_NAME>]\n
[envs.<ENV_NAME>]\n
The storage location for environments is completely configurable.
Unless an environment is explicitly selected on the command line, the default
environment will be used. The type of this environment defaults to virtual
.
Info
Environments prefixed by hatch-
are used for special purposes e.g. testing.
All environments inherit from the environment defined by its template
option, which defaults to default
.
So for the following configuration:
pyproject.toml hatch.toml[tool.hatch.envs.foo]\ntype = \"baz\"\nskip-install = true\n\n[tool.hatch.envs.bar]\ntemplate = \"foo\"\nskip-install = false\n
[envs.foo]\ntype = \"baz\"\nskip-install = true\n\n[envs.bar]\ntemplate = \"foo\"\nskip-install = false\n
the environment bar
will be of type baz
with skip-install
set to false
.
Note
Environments do not inherit matrices.
"},{"location":"config/environment/overview/#self-referential-environments","title":"Self-referential environments","text":"You can disable inheritance by setting template
to the environment's own name:
[tool.hatch.envs.foo]\ntemplate = \"foo\"\n
[envs.foo]\ntemplate = \"foo\"\n
"},{"location":"config/environment/overview/#detached-environments","title":"Detached environments","text":"A common use case is standalone environments that do not require inheritance nor the installation of the project, such as for linting or sometimes building documentation. Enabling the detached
option will make the environment self-referential and will skip project installation:
[tool.hatch.envs.lint]\ndetached = true\n
[envs.lint]\ndetached = true\n
"},{"location":"config/environment/overview/#dependencies","title":"Dependencies","text":"You can install dependencies in addition to the ones defined by your project's metadata. Entries support context formatting.
pyproject.toml hatch.toml[tool.hatch.envs.test]\ndependencies = [\n \"coverage[toml]\",\n \"pytest\",\n \"pytest-cov\",\n \"pytest-mock\",\n]\n
[envs.test]\ndependencies = [\n \"coverage[toml]\",\n \"pytest\",\n \"pytest-cov\",\n \"pytest-mock\",\n]\n
If you define environments with dependencies that only slightly differ from their inherited environments, you can use the extra-dependencies
option to avoid redeclaring the dependencies
option:
[tool.hatch.envs.default]\ndependencies = [\n \"foo\",\n \"bar\",\n]\n\n[tool.hatch.envs.experimental]\nextra-dependencies = [\n \"baz\",\n]\n
[envs.default]\ndependencies = [\n \"foo\",\n \"bar\",\n]\n\n[envs.experimental]\nextra-dependencies = [\n \"baz\",\n]\n
Tip
Hatch uses pip to install dependencies so any configuration it supports Hatch does as well. For example, if you wanted to only use a private repository you could set the PIP_INDEX_URL
environment variable.
If your project defines optional dependencies, you can select which groups to install using the features
option:
[tool.hatch.envs.nightly]\nfeatures = [\n \"server\",\n \"grpc\",\n]\n
[envs.nightly]\nfeatures = [\n \"server\",\n \"grpc\",\n]\n
Note
Features/optional dependencies are also known as extras
in other tools.
By default, environments will always reflect the current state of your project on disk, for example, by installing it in editable mode in a Python environment. Set dev-mode
to false
to disable this behavior and have your project installed only upon creation of a new environment. From then on, you need to manage your project installation manually.
[tool.hatch.envs.static]\ndev-mode = false\n
[envs.static]\ndev-mode = false\n
"},{"location":"config/environment/overview/#skip-install","title":"Skip install","text":"By default, environments will install your project during creation. To ignore this step, set skip-install
to true
:
[tool.hatch.envs.lint]\nskip-install = true\n
[envs.lint]\nskip-install = true\n
"},{"location":"config/environment/overview/#environment-variables","title":"Environment variables","text":""},{"location":"config/environment/overview/#defined","title":"Defined","text":"You can define environment variables with the env-vars
option:
[tool.hatch.envs.docs]\ndependencies = [\n \"mkdocs\"\n]\n[tool.hatch.envs.docs.env-vars]\nSOURCE_DATE_EPOCH = \"1580601600\"\n
[envs.docs]\ndependencies = [\n \"mkdocs\"\n]\n[envs.docs.env-vars]\nSOURCE_DATE_EPOCH = \"1580601600\"\n
Values support context formatting.
"},{"location":"config/environment/overview/#filters","title":"Filters","text":"By default, environments will have access to all environment variables. You can filter with wildcard patterns using the env-include
/env-exclude
options:
[tool.hatch.envs.<ENV_NAME>]\nenv-include = [\n \"FOO*\",\n]\nenv-exclude = [\n \"BAR\",\n]\n
[envs.<ENV_NAME>]\nenv-include = [\n \"FOO*\",\n]\nenv-exclude = [\n \"BAR\",\n]\n
Exclusion patterns take precedence but will never affect defined environment variables.
"},{"location":"config/environment/overview/#scripts","title":"Scripts","text":"You can define named scripts that may be executed or referenced at the beginning of other scripts. Context formatting is supported.
For example, in the following configuration:
pyproject.toml hatch.toml[tool.hatch.envs.test]\ndependencies = [\n \"coverage[toml]\",\n \"pytest\",\n \"pytest-cov\",\n \"pytest-mock\",\n]\n[tool.hatch.envs.test.scripts]\nrun-coverage = \"pytest --cov-config=pyproject.toml --cov=pkg --cov=tests\"\nrun = \"run-coverage --no-cov\"\n
[envs.test]\ndependencies = [\n \"coverage[toml]\",\n \"pytest\",\n \"pytest-cov\",\n \"pytest-mock\",\n]\n[envs.test.scripts]\nrun-coverage = \"pytest --cov-config=pyproject.toml --cov=pkg --cov=tests\"\nrun = \"run-coverage --no-cov\"\n
the run
script would be expanded to:
pytest --cov-config=pyproject.toml --cov=pkg --cov=tests --no-cov\n
Scripts can also be defined as an array of strings.
pyproject.toml hatch.toml[tool.hatch.envs.style]\ndetached = true\ndependencies = [\n \"flake8\",\n \"black\",\n \"isort\",\n]\n[tool.hatch.envs.style.scripts]\ncheck = [\n \"flake8 .\",\n \"black --check --diff .\",\n \"isort --check-only --diff .\",\n]\nfmt = [\n \"isort .\",\n \"black .\",\n \"check\",\n]\n
[envs.style]\ndetached = true\ndependencies = [\n \"flake8\",\n \"black\",\n \"isort\",\n]\n[envs.style.scripts]\ncheck = [\n \"flake8 .\",\n \"black --check --diff .\",\n \"isort --check-only --diff .\",\n]\nfmt = [\n \"isort .\",\n \"black .\",\n \"check\",\n]\n
Similar to make, you can ignore the exit code of commands that start with -
(a hyphen). For example, the script error
defined by the following configuration would halt after the second command with 3
as the exit code:
[tool.hatch.envs.test.scripts]\nerror = [\n \"- exit 1\",\n \"exit 3\",\n \"exit 0\",\n]\n
[envs.test.scripts]\nerror = [\n \"- exit 1\",\n \"exit 3\",\n \"exit 0\",\n]\n
"},{"location":"config/environment/overview/#extra-scripts","title":"Extra scripts","text":"Individual scripts inherit from parent environments just like options. To guarantee that individual scripts do not override those defined by parent environments, you can use the extra-scripts
option instead which is only capable of adding scripts that have not been defined.
All commands are able to use any defined scripts. Also like scripts, context formatting is supported and the exit code of commands that start with a hyphen will be ignored.
"},{"location":"config/environment/overview/#pre-install","title":"Pre-install","text":"You can run commands immediately before environments install your project.
pyproject.toml hatch.toml[tool.hatch.envs.<ENV_NAME>]\npre-install-commands = [\n \"...\",\n]\n
[envs.<ENV_NAME>]\npre-install-commands = [\n \"...\",\n]\n
"},{"location":"config/environment/overview/#post-install","title":"Post-install","text":"You can run commands immediately after environments install your project.
pyproject.toml hatch.toml[tool.hatch.envs.<ENV_NAME>]\npost-install-commands = [\n \"...\",\n]\n
[envs.<ENV_NAME>]\npost-install-commands = [\n \"...\",\n]\n
"},{"location":"config/environment/overview/#python-version","title":"Python version","text":"The python
option specifies which version of Python to use, or an absolute path to a Python interpreter:
[tool.hatch.envs.<ENV_NAME>]\npython = \"3.10\"\n
[envs.<ENV_NAME>]\npython = \"3.10\"\n
All environment types should respect this option.
"},{"location":"config/environment/overview/#supported-platforms","title":"Supported platforms","text":"The platforms
option indicates the operating systems with which the environment is compatible:
[tool.hatch.envs.<ENV_NAME>]\nplatforms = [\"linux\", \"windows\", \"macos\"]\n
[envs.<ENV_NAME>]\nplatforms = [\"linux\", \"windows\", \"macos\"]\n
The following platforms are supported:
linux
windows
macos
If unspecified, the environment is assumed to be compatible with all platforms.
"},{"location":"config/environment/overview/#description","title":"Description","text":"The description
option is purely informational and is displayed in the output of the env show
command:
[tool.hatch.envs.<ENV_NAME>]\ndescription = \"\"\"\nLorem ipsum ...\n\"\"\"\n
[envs.<ENV_NAME>]\ndescription = \"\"\"\nLorem ipsum ...\n\"\"\"\n
"},{"location":"config/environment/overview/#type","title":"Type","text":"An environment's type
determines which environment plugin will be used for management. The only built-in environment type is virtual
, which uses virtual Python environments.
You can fully alter the behavior of the environment used by the build
command.
Build environments will always have what is required by the build system, targets, and hooks.
You can define dependencies that your builds may require in the environment as well:
pyproject.toml hatch.toml[tool.hatch.envs.hatch-build]\ndependencies = [\n \"cython\",\n]\n
[envs.hatch-build]\ndependencies = [\n \"cython\",\n]\n
caution
It's recommended to only use the standard mechanisms to define build dependencies for better compatibility with other tools.
"},{"location":"config/internal/build/#environment-variables","title":"Environment variables","text":"You can define environment variables that will be set during builds:
pyproject.toml hatch.toml[tool.hatch.envs.hatch-build.env-vars]\nSOURCE_DATE_EPOCH = \"1580601600\"\n
[envs.hatch-build.env-vars]\nSOURCE_DATE_EPOCH = \"1580601600\"\n
"},{"location":"config/internal/build/#installer","title":"Installer","text":"By default, UV is enabled. You may disable that behavior as follows:
pyproject.toml hatch.toml[tool.hatch.envs.hatch-build]\ninstaller = \"pip\"\n
[envs.hatch-build]\ninstaller = \"pip\"\n
"},{"location":"config/internal/static-analysis/","title":"Static analysis configuration","text":"Static analysis performed by the fmt
command is (by default) backed entirely by Ruff.
Hatch provides default settings that user configuration can extend.
"},{"location":"config/internal/static-analysis/#extending-config","title":"Extending config","text":"When defining your configuration, be sure to use options that are prefixed by extend-
such as extend-select
, for example:
[tool.ruff.format]\npreview = true\nquote-style = \"single\"\n\n[tool.ruff.lint]\npreview = true\nextend-select = [\"C901\"]\n\n[tool.ruff.lint.extend-per-file-ignores]\n\"docs/.hooks/*\" = [\"INP001\", \"T201\"]\n\n[tool.ruff.lint.isort]\nknown-first-party = [\"foo\", \"bar\"]\n
[format]\npreview = true\nquote-style = \"single\"\n\n[lint]\npreview = true\nextend-select = [\"C901\"]\n\n[lint.extend-per-file-ignores]\n\"docs/.hooks/*\" = [\"INP001\", \"T201\"]\n\n[lint.isort]\nknown-first-party = [\"foo\", \"bar\"]\n
Note
When not persisting config, there is no need to explicitly extend the defaults as Hatch automatically handles that.
"},{"location":"config/internal/static-analysis/#persistent-config","title":"Persistent config","text":"If you want to store the default configuration in the project, set an explicit path like so:
pyproject.toml hatch.toml[tool.hatch.envs.hatch-static-analysis]\nconfig-path = \"ruff_defaults.toml\"\n
[envs.hatch-static-analysis]\nconfig-path = \"ruff_defaults.toml\"\n
Then instruct Ruff to consider your configuration as an extension of the default file:
pyproject.toml ruff.toml[tool.ruff]\nextend = \"ruff_defaults.toml\"\n
extend = \"ruff_defaults.toml\"\n
Anytime you wish to update the defaults (such as when upgrading Hatch), you must run the fmt
command once with the --sync
flag e.g.:
hatch fmt --check --sync\n
Tip
This is the recommended approach since it allows other tools like IDEs to use the default configuration.
"},{"location":"config/internal/static-analysis/#no-config","title":"No config","text":"If you don't want Hatch to use any of its default configuration and rely entirely on yours, set the path to anything and then simply don't extend
in your Ruff config:
[tool.hatch.envs.hatch-static-analysis]\nconfig-path = \"none\"\n
[envs.hatch-static-analysis]\nconfig-path = \"none\"\n
"},{"location":"config/internal/static-analysis/#customize-behavior","title":"Customize behavior","text":"You can fully alter the behavior of the environment used by the fmt
command. See the how-to for a detailed example.
Pin the particular version of Ruff by explicitly defining the environment dependencies:
pyproject.toml hatch.toml[tool.hatch.envs.hatch-static-analysis]\ndependencies = [\"ruff==X.Y.Z\"]\n
[envs.hatch-static-analysis]\ndependencies = [\"ruff==X.Y.Z\"]\n
"},{"location":"config/internal/static-analysis/#scripts","title":"Scripts","text":"If you want to change the default commands that are executed, you can override the scripts. The following four scripts must be defined:
pyproject.toml hatch.toml[tool.hatch.envs.hatch-static-analysis.scripts]\nformat-check = \"...\"\nformat-fix = \"...\"\nlint-check = \"...\"\nlint-fix = \"...\"\n
[envs.hatch-static-analysis.scripts]\nformat-check = \"...\"\nformat-fix = \"...\"\nlint-check = \"...\"\nlint-fix = \"...\"\n
The format-*
scripts correspond to the --formatter
/-f
flag while the lint-*
scripts correspond to the --linter
/-l
flag. The *-fix
scripts run by default while the *-check
scripts correspond to the --check
flag.
Reminder
If you choose to use different tools for static analysis, be sure to update the required dependencies.
"},{"location":"config/internal/static-analysis/#installer","title":"Installer","text":"By default, UV is enabled. You may disable that behavior as follows:
pyproject.toml hatch.toml[tool.hatch.envs.hatch-static-analysis]\ninstaller = \"pip\"\n
[envs.hatch-static-analysis]\ninstaller = \"pip\"\n
"},{"location":"config/internal/static-analysis/#default-settings","title":"Default settings","text":""},{"location":"config/internal/static-analysis/#non-rule-settings","title":"Non-rule settings","text":"**/scripts/*
: INP001, T201**/tests/**/*
: PLC1901, PLR2004, PLR6301, S, TID252The following rules are based on version 0.4.5 of Ruff. Rules with a P are only selected when preview mode is enabled.
There are 525 selected stable rules and 129 selected preview rules.
Selected rulesThere are 175 unselected rules.
Unselected rulesCheck out the testing overview tutorial for a more comprehensive walk-through.
"},{"location":"config/internal/testing/#settings","title":"Settings","text":"If an option has a corresponding test
command flag, the flag will always take precedence.
You can define default arguments for the test
command by setting the default-args
option, which must be an array of strings. The following is the default configuration:
[tool.hatch.envs.hatch-test]\ndefault-args = [\"tests\"]\n
[envs.hatch-test]\ndefault-args = [\"tests\"]\n
"},{"location":"config/internal/testing/#extra-arguments","title":"Extra arguments","text":"You can define extra internal arguments for test scripts by setting the extra-args
option, which must be an array of strings. For example, if you wanted to increase the verbosity of pytest
, you could set the following:
[tool.hatch.envs.hatch-test]\nextra-args = [\"-vv\"]\n
[envs.hatch-test]\nextra-args = [\"-vv\"]\n
"},{"location":"config/internal/testing/#randomize-test-order","title":"Randomize test order","text":"You can randomize the order of tests by enabling the randomize
option which corresponds to the --randomize
/-r
flag:
[tool.hatch.envs.hatch-test]\nrandomize = true\n
[envs.hatch-test]\nrandomize = true\n
"},{"location":"config/internal/testing/#parallelize-test-execution","title":"Parallelize test execution","text":"You can parallelize test execution by enabling the parallel
option which corresponds to the --parallel
/-p
flag:
[tool.hatch.envs.hatch-test]\nparallel = true\n
[envs.hatch-test]\nparallel = true\n
"},{"location":"config/internal/testing/#retry-failed-tests","title":"Retry failed tests","text":"You can retry failed tests by setting the retries
option which corresponds to the --retries
flag:
[tool.hatch.envs.hatch-test]\nretries = 2\n
[envs.hatch-test]\nretries = 2\n
You can also set the number of seconds to wait between retries by setting the retry-delay
option which corresponds to the --retry-delay
flag:
[tool.hatch.envs.hatch-test]\nretry-delay = 1\n
[envs.hatch-test]\nretry-delay = 1\n
"},{"location":"config/internal/testing/#customize-environment","title":"Customize environment","text":"You can fully alter the behavior of the environment used by the test
command.
You can define extra dependencies that your tests may require:
pyproject.toml hatch.toml[tool.hatch.envs.hatch-test]\nextra-dependencies = [\n \"pyfakefs\",\n \"pytest-asyncio\",\n \"pytest-benchmark\",\n \"pytest-memray\",\n \"pytest-playwright\",\n \"pytest-print\",\n]\n
[envs.hatch-test]\nextra-dependencies = [\n \"pyfakefs\",\n \"pytest-asyncio\",\n \"pytest-benchmark\",\n \"pytest-memray\",\n \"pytest-playwright\",\n \"pytest-print\",\n]\n
The following is the default configuration:
pyproject.toml hatch.toml[tool.hatch.envs.hatch-test]\ndependencies = [\n \"coverage-enable-subprocess==1.0\",\n \"coverage[toml]~=7.4\",\n \"pytest~=8.1\",\n \"pytest-mock~=3.12\",\n \"pytest-randomly~=3.15\",\n \"pytest-rerunfailures~=14.0\",\n \"pytest-xdist[psutil]~=3.5\",\n]\n
[envs.hatch-test]\ndependencies = [\n \"coverage-enable-subprocess==1.0\",\n \"coverage[toml]~=7.4\",\n \"pytest~=8.1\",\n \"pytest-mock~=3.12\",\n \"pytest-randomly~=3.15\",\n \"pytest-rerunfailures~=14.0\",\n \"pytest-xdist[psutil]~=3.5\",\n]\n
"},{"location":"config/internal/testing/#matrix","title":"Matrix","text":"You can override the default series of matrices:
pyproject.toml hatch.toml[[tool.hatch.envs.hatch-test.matrix]]\npython = [\"3.12\", \"3.11\", \"3.10\", \"3.9\", \"3.8\"]\n
[[envs.hatch-test.matrix]]\npython = [\"3.12\", \"3.11\", \"3.10\", \"3.9\", \"3.8\"]\n
"},{"location":"config/internal/testing/#scripts","title":"Scripts","text":"If you want to change the default commands that are executed, you can override the scripts. The following default scripts must be redefined:
pyproject.toml hatch.toml[tool.hatch.envs.hatch-test.scripts]\nrun = \"pytest{env:HATCH_TEST_ARGS:} {args}\"\nrun-cov = \"coverage run -m pytest{env:HATCH_TEST_ARGS:} {args}\"\ncov-combine = \"coverage combine\"\ncov-report = \"coverage report\"\n
[envs.hatch-test.scripts]\nrun = \"pytest{env:HATCH_TEST_ARGS:} {args}\"\nrun-cov = \"coverage run -m pytest{env:HATCH_TEST_ARGS:} {args}\"\ncov-combine = \"coverage combine\"\ncov-report = \"coverage report\"\n
The run
script is the default behavior while the run-cov
script is used instead when measuring code coverage. The cov-combine
script runs after all tests complete when measuring code coverage, as well as the cov-report
script when not using the --cover-quiet
flag.
Note
The HATCH_TEST_ARGS
environment variable is how the test
command's flags are translated and internally populated without affecting the user's arguments. This is also the way that extra arguments are passed.
By default, UV is enabled. You may disable that behavior as follows:
pyproject.toml hatch.toml[tool.hatch.envs.hatch-test]\ninstaller = \"pip\"\n
[envs.hatch-test]\ninstaller = \"pip\"\n
"},{"location":"history/hatch/","title":"Hatch history","text":"All notable changes to Hatch will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
"},{"location":"history/hatch/#unreleased","title":"Unreleased","text":"Changed:
build_environment
, build_environment_exists
, run_builder
, construct_build_command
Added:
version
and project metadata
commands now support projects that do not use Hatchling as the build backendhatch-build
project_root
, sep
, pathsep
, fs_context
Changed:
run
/env run
and test
commands now treat inclusion variable options as an intersection rather than a union to allow for specific targeting of environmentsAdded:
Fixed:
fmt
command no longer hides the commands that are being executedconfig show
commandAdded:
Fixed:
terminal.styles.spinner
configurationAdded:
Fixed:
Changed:
run
/env run
, fmt
and shell
commands now only change the current working directory to the project root if not already inside the projectshell
command now accepts a single argument to specify the environment to enter which overrides the standard choice mechanisms. The arguments determining shell options have been converted to flags.Added:
test
commandrun
command can now execute scripts that define inline metadata for dependencies and Python version constraintsvirtual
environment type now supports the ability to use UV in place of pip & virtualenvself report
command for submitting pre-populated bug reports to GitHubenvironment
interface for complete control over output during life cycle management: app_status_creation
, app_status_pre_installation
, app_status_post_installation
, app_status_project_installation
, app_status_dependency_state_check
, app_status_dependency_installation_check
, app_status_dependency_synchronization
~/.pypirc
file for the index
publisherHATCH_DEBUG
environment variable that when enabled will show local variables in the case of unhandled tracebacksenv show
command now outputs data about all internal environments when using the --json
flagFixed:
pyproject.toml
file but no project
table e.g. applicationsfmt
command when automatically installing plugin dependenciestypes
environment for new projectsE501
for the fmt
command by default since it conflicts with the formatterpackaging
dependency version as >=23.2
to avoid its URL validation which can conflict with context formattingREADME.md
file template for new projects to avoid Markdown linting issuesFixed:
Fixed:
Fixed:
Fixed:
Fixed:
dependency_hash
method of the environment
interface is called after sync_dependencies
for cases where the hash is only known at that point, such as for dependency lockersHATCH_PYTHON_VARIANT_*
environment variables for Python resolution for supported platforms and architecturesChanged:
hatch-
are now considered internal and used for special purposes such as configuration for static analysisAdded:
find
and check_compatibility
Fixed:
path
option for the virtual
environment typeFixed:
Changed:
get_build_process
method of the environment
interface has been removed; plugins should use the new run_builder
method insteadpyperclip
dependency and the --copy
flag of the config find
commandbuild
command all output from builders is now displayed as-is in real time without the stripping of ANSI codesAdded:
fmt
commandvirtual
environment type can now automatically download requested versions of Python that are not installeddependency_hash
method to the environment
interfacebuild
command now supports backends other than Hatchlingfeatures
for environments when skip-install
is enabled__token__
when prompting for a username for the publish
commandrun_builder
method to the environment
interfaceclick
to 8.0.6Fixed:
virtual
environment typeversion
command outside of a project rather than erroringproject metadata
command by only capturing stdout from the backendChanged:
src-layout
project template option is now enabled by defaultAdded:
tool.hatch.env.requires
configuration to automatically install dependencies for environment and environment collector pluginscustom
environment collectorisolated_data_directory
attribute to the environment interfaceindex
publisherFixed:
version
command when the version is static and build dependencies are unmetvirtual
environment type when storing within a relative pathsetup.py
if setup.cfg
is presentconfig set
commandFixed:
version
command when the version is dynamic and build dependencies are unmetFixed:
Fixed:
~
when it cannot be determinedChanged:
run_shell_command
environment interface method now accepts arbitrary subprocess.Popen
keyword arguments. This is not strictly breaking, but will be utilized in upcoming features.virtual
environments is now more nested. This is not breaking, but any local environments will be created anew.Added:
project
command group to view details about the project like PEP 621 metadatavirtual
environments will be flat if Hatch's configured virtual
environment directory resides somewhere within the project root or if it is set to a .virtualenvs
directory within the user's home directoryvirtual
environment type are now cached for improved performancebuild_environment_exists
method to the environment interface for implementations that cache the build environmentpath
option to the virtual
environment type--initialize-auth
flag to the index
publisher to allow for the saving of authentication information before publishingshell
commandsetuptools
migration script no longer modifies the formatting of existing pyproject.toml
configurationFixed:
dep hash
and all dep show
commands now respect dynamically defined project dependenciesenv show
, dep hash
, and all dep show
commands now honor context formattingrun
and env run
commands when there are multiple possible variablessetuptools
migration scriptextra-dependencies
in environment overridespackaging
explicitly rather than relying on it being a transitive dependency of HatchlingAdded:
index
publisher now recognizes repository-specific options--ignore-compat
flag to the env run
commandHATCH_PYTHON
environment variable to self
will now force the use of the Python executable Hatch is running on for virtual
environment creationFixed:
--force-continue
flag of the env run
commandsetuptools
migration scriptFixed:
version
command when metadata hooks are in useFixed:
Added:
virtual
environments now checks PATH before using the one Hatch is running onenv-vars
now support context formattingname
override for environments to allow for regular expression matchingindex
publisher now better supports non-PyPI indicesindex
publishershell
command is executedash
) shellshyperlink
as a dependency for better handling of package index URLsvirtualenv
to 20.16.2tomlkit
to 0.11.1Fixed:
extra-dependencies
for the env show
commandshell
commandsrc-layout
project template optionFixed:
-h
/--help
flag for the run
commandChanged:
pypi
to the more generic index
Added:
pyproject.toml
files, as is the case for apps and non-Python projectsenv show
command by default--force-continue
flag to the env run
commandpwsh
is now an alias for powershell
atomicwrites
dependencyuserpath
dependencyFixed:
utf-8
for all files generated for new projectssetuptools
migration scriptFixed:
data_files
in setuptools
migration scriptChanged:
enter_shell
environment plugin method now accepts an additional args
parameterAdded:
env_name
, env_type
, matrix
, verbosity
, and args
Fixed:
setuptools
migration scriptFixed:
Fixed:
setuptools
migration script for non-Windows systemsChanged:
run_shell_commands
method has been replaced by the singular run_shell_command
. A new command_context
method has been added to more easily satisfy complex use cases.finalize_command
environment plugin method has been removed in favor of the newly introduced context formatting functionality.Added:
make
, ignore the exit code of executed commands that start with -
(a hyphen)--init
flag of the new
command to automatically migrate setuptools
configurationThis is the first stable release of Hatch v1, a complete rewrite. Enjoy!
"},{"location":"history/hatchling/","title":"Hatchling history","text":"All notable changes to Hatchling will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
"},{"location":"history/hatchling/#unreleased","title":"Unreleased","text":""},{"location":"history/hatchling/#hatchling-v1.25.0","title":"1.25.0 - 2024-06-22","text":"Changed:
macos-max-compat
option for the wheel
target is now disabled by default and will be removed in a future releaseAdded:
wheel
and sdist
targets now have their permission bits normalizedFixed:
manylinux
/musllinux
tags for the wheel
target artifact name when enabling the infer_tag
build datawheel
target build data infer_tag
when enabled now respects the MACOSX_DEPLOYMENT_TARGET
environment variableFixed:
.venv
to the list of directories that cannot be traversedFixed:
shared-scripts
option/shared_scripts
build data of the wheel
targetAdded:
shared_data
and shared_scripts
build data for the wheel
targetAdded:
shared-scripts
option for the wheel
targetFixed:
packaging
dependency version as >=23.2
to avoid its URL validation which can conflict with context formattingFixed:
Fixed:
Fixed:
custom
build hook when using dynamic dependenciesFixed:
Fixed:
Deprecated:
app
build target has been renamed to binary
to reduce ambiguity with the name of an upcoming feature. The former name will still be usable for several minor releases.Added:
wheel
target now defaults to the PKG-INFO
metadata within source distributionsdependencies
method to the build hook interface so that hooks can themselves dynamically define dependenciesFixed:
editables
as a direct dependencysdist
build target now gracefully ignores UNIX socket files.DS_Store
on macOSFixed:
Added:
parent
context modifier for path fieldsAdded:
bypass-selection
option to the wheel
build target to allow for empty (metadata-only) wheelsFixed:
exclude
to count toward inclusion selection, thus bypassing the default inclusion selection heuristicsFixed:
wheel
build target cannot determine what to shipChanged:
wheel
build target if no file selection options are definedAdded:
sources
option to add a prefix to distribution pathsFixed:
standard
version schemewheel
build target for case insensitive file systems when the project metadata name does not match the directory name on diskapp
build target no longer has suppressed outputsources
option while build hooks overwrite included pathsChanged:
Added:
Fixed:
packages
or only-include
optionsAdded:
app
build target now embeds the project version in the name of binariesFixed:
app
build target option when using a local copy of PyApp when there is an explicit target triple setAdded:
app
build target option to build using a local copy of the PyApp repositoryAdded:
app
build targetFixed:
sdist
target when strict-naming
is disabled to match the file name in order to support the expectation of some frontendsAdded:
trove-classifiers
as a dependencyFixed:
Added:
Fixed:
macos-max-compat
option to the wheel
target that is enabled by default to support the latest version 22.0 of the packaging
libraryFixed:
Added:
extra_metadata
build data to the wheel
targetLicense-Expression
core metadata starting at version 2.1pyproject.toml
Fixed:
ARCHFLAGS
environment variable on macOS for the wheel
target when build hooks set the infer_tag
build data to true
support-legacy
option for the sdist
target when using a src-layout project structureversion
build hookFixed:
wheel
target when there is a single top-level moduleAdded:
env
version source to retrieve the version from an environment variablevalidate-bump
option to the standard
version schemeFixed:
RECORD
metadata file of the wheel
target to avoid warnings during installation by pip
if, for example, file names contain commasAdded:
__pypackages__
, .hg
, .hatch
, .tox
, .nox
Fixed:
project.optional-dependencies
that use direct referencesChanged:
Added:
prepare_metadata_for_build_wheel
and prepare_metadata_for_build_editable
for non-frontend tools that only need to inspect a project's metadatametadata
command to view PEP 621 project metadataLicense-File
for core metadata starting at version 2.1pathspec
to 0.10.1Fixed:
license
values LicenseRef-Public-Domain
and LicenseRef-Proprietary
Fixed:
wheel
build targets when both the project name and package directory name are not normalizedAdded:
get_known_classifiers
method to metadata hooksFixed:
version
command when metadata hooks are in useFixed:
relative_path
attribute of included files, that some build plugins may use, when selecting explicit pathsAdded:
require-runtime-features
option for builders and build hooksFixed:
wheel
target dev mode installations that define path rewrites with the sources
optionallow-direct-references
option in the relevant error messagesChanged:
sdist
and wheel
targets rather than what happens to be defined in configcode
version source now only supports files with known extensionsAdded:
code
version source now supports loading extension modulessearch-paths
option for the code
version sourceFixed:
sources
using an empty string value in the mappingstrict-naming
option now also applies to the metadata directory of wheel
targetsAdded:
strict-naming
option for sdist
and wheel
targetsFixed:
sdist
and wheel
target core metadata exactly as defined in pyproject.toml
without normalization to allow control of how PyPI displays themFixed:
sdist
targets when using the explicit selection optionsChanged:
packages
option uses the new only-include
option to provide targeted inclusion, since that is desired most of the time. You can retain the old behavior by using the include
and sources
options together.Added:
version
build hookonly-include
optioneditable
version of wheel
targets now respects the force-include
option by defaultforce-include
option now supports path rewriting with the sources
optionwheel
target shared-data
and extra-metadata
options now respect file selection optionswheel
target now auto-detects single module layouts__pycache__
rather than excluding individual files withinFixed:
wheel
targets if there are no entry points definedversion
in all casesforce-include
optionFixed:
code
version sourceRemoved:
args
context string formatting fieldAdded:
env
context string formatting fieldFixed:
uri
context string formatting modifier on WindowsAdded:
project.dependencies
and project.optional-dependencies
Added:
uri
and real
context string formatting modifiers for file system pathsChanged:
Added:
Fixed:
Added:
skip-excluded-dirs
build optionwheel
and sdist
build targetsforce_include_editable
build data for the wheel
build targetbuild_hooks
build data.hgignore
files when using glob syntaxFixed:
force_include
build dataThis is the initial public release of the Hatchling build system. Support for Python 2 will be dropped in version 1.
"},{"location":"how-to/config/dynamic-metadata/","title":"How to configure custom dynamic metadata","text":"If you have project metadata that is not appropriate for static entry into pyproject.toml
you will need to provide a custom metadata hook to apply such data during builds.
Alternatives
Dynamic metadata is a way to have a single source of truth that will be available at build time and at run time. Another way to achieve that is to enter the build data statically and then look up the same information dynamically in the program or package, using importlib.metadata.
If the version field is the only metadata of concern, Hatchling provides a few built-in ways such as the regex
version source and also third-party plugins. The approach here will also work, but is more complex.
Change the [project]
section of pyproject.toml
:
dynamic = [\"version\", \"license\", \"authors\", \"maintainers\"]
pyproject.toml
, delete those definitions. It is verboten to define a field statically and dynamically.Add a section to trigger loading of dynamic metadata plugins: [tool.hatch.metadata.hooks.custom]
. Use exactly that name, regardless of the name of the class you will use or its PLUGIN_NAME
. There doesn't need to be anything in the section.
If your plugin requires additional third-party packages to do its work, add them to the requires
array in the [build-system]
section of pyproject.toml
.
The dynamic lookup must happen in a custom plugin that you write. The default expectation is that it is in a hatch_build.py
file at the root of the project. Subclass MetadataHookInterface
and implement update()
; for example, here's plugin that reads metadata from a JSON file:
import json\nimport os\n\nfrom hatchling.metadata.plugin.interface import MetadataHookInterface\n\n\nclass JSONMetaDataHook(MetadataHookInterface):\n def update(self, metadata):\n src_file = os.path.join(self.root, \"gnumeric\", \".constants.json\")\n with open(src_file) as src:\n constants = json.load(src)\n metadata[\"version\"] = constants[\"__version__\"]\n metadata[\"license\"] = constants[\"__license__\"]\n metadata[\"authors\"] = [\n {\"name\": constants[\"__author__\"], \"email\": constants[\"__author_email__\"]},\n ]\n
update
method.metadata
refers to project metadata.list
for TOML arrays. Note that if a list is expected, it is required even if there is a single element.dict
for TOML tables e.g. authors
.If you want to store the hook in a different location, set the path
option:
[tool.hatch.metadata.hooks.custom]\npath = \"some/where.py\"\n
[metadata.hooks.custom]\npath = \"some/where.py\"\n
"},{"location":"how-to/environment/dependency-resolution/","title":"How to configure dependency resolution","text":"Most Hatch environment types, like the default virtual, simply use pip to install dependencies. Therefore, you can use the standard environment variables that influence pip
's behavior.
Here's an example of setting up the default environment to look at 2 private indices (using context formatting for authentication) before finally falling back to PyPI:
pyproject.toml hatch.toml[tool.hatch.envs.default.env-vars]\nPIP_INDEX_URL = \"https://token:{env:GITLAB_API_TOKEN}@gitlab.com/api/v4/groups/<group1_path>/-/packages/pypi/simple/\"\nPIP_EXTRA_INDEX_URL = \"https://token:{env:GITLAB_API_TOKEN}@gitlab.com/api/v4/groups/<group2_path>/-/packages/pypi/simple/ https://pypi.org/simple/\"\n
[envs.default.env-vars]\nPIP_INDEX_URL = \"https://token:{env:GITLAB_API_TOKEN}@gitlab.com/api/v4/groups/<group1_path>/-/packages/pypi/simple/\"\nPIP_EXTRA_INDEX_URL = \"https://token:{env:GITLAB_API_TOKEN}@gitlab.com/api/v4/groups/<group2_path>/-/packages/pypi/simple/ https://pypi.org/simple/\"\n
"},{"location":"how-to/environment/dependency-resolution/#uv","title":"UV","text":"If you're using UV, a different set of environment variables are available to configure its behavior. The previous example would look like this instead:
pyproject.toml hatch.toml[tool.hatch.envs.default.env-vars]\nUV_EXTRA_INDEX_URL = \"https://token:{env:GITLAB_API_TOKEN}@gitlab.com/api/v4/groups/<group1_path>/-/packages/pypi/simple/\"\nUV_INDEX_URL = \"https://token:{env:GITLAB_API_TOKEN}@gitlab.com/api/v4/groups/<group2_path>/-/packages/pypi/simple/ https://pypi.org/simple/\"\n
[envs.default.env-vars]\nUV_EXTRA_INDEX_URL = \"https://token:{env:GITLAB_API_TOKEN}@gitlab.com/api/v4/groups/<group1_path>/-/packages/pypi/simple/\"\nUV_INDEX_URL = \"https://token:{env:GITLAB_API_TOKEN}@gitlab.com/api/v4/groups/<group2_path>/-/packages/pypi/simple/ https://pypi.org/simple/\"\n
Tip
If you need precise control over the prioritization of package indices, then using UV is recommended because pip
has no index order guarantee.
The virtual environment type by default uses virtualenv for virtual environment creation and pip to install dependencies. You can speed up environment creation and dependency resolution by using UV instead of both of those tools.
caveat
UV is under active development and may not work for all dependencies.
To do so, set the installer
option to uv
. For example, if you wanted to enable this functionality for the default environment, you could set the following:
[tool.hatch.envs.default]\ninstaller = \"uv\"\n
[envs.default]\ninstaller = \"uv\"\n
Tip
All environments that enable UV will have the path to UV available as the HATCH_UV
environment variable.
The UV that is shared by all environments uses a specific version range that is known to work with Hatch. If you want to use a different version, you can override the dependencies for the internal hatch-uv
environment:
[tool.hatch.envs.hatch-uv]\ndependencies = [\n \"uv>9000\",\n]\n
[envs.hatch-uv]\ndependencies = [\n \"uv>9000\",\n]\n
"},{"location":"how-to/environment/select-installer/#externally-managed","title":"Externally managed","text":"If you want to manage UV yourself, you can expose it to Hatch by setting the HATCH_ENV_TYPE_VIRTUAL_UV_PATH
environment variable which should be the absolute path to a UV binary for Hatch to use instead. This implicitly enables UV.
If you have scripts or commands that call pip
, it may be useful to alias the uv pip
command to pip
so that you can use the same commands for both methods of configuration and retain your muscle memory. The following is an example of a matrix that conditionally enables UV and sets the alias:
[[tool.hatch.envs.example.matrix]]\ntool = [\"uv\", \"pip\"]\n\n[tool.hatch.envs.example.overrides]\nmatrix.tool.installer = { value = \"{matrix:tool}\" }\nmatrix.tool.scripts = [\n { key = \"pip\", value = \"{env:HATCH_UV} pip {args}\", if = [\"uv\"] },\n]\n
[[envs.example.matrix]]\ntool = [\"uv\", \"pip\"]\n\n[envs.example.overrides]\nmatrix.tool.installer = { value = \"{matrix:tool}\" }\nmatrix.tool.scripts = [\n { key = \"pip\", value = \"{env:HATCH_UV} pip {args}\", if = [\"uv\"] },\n]\n
Another common use case is to expose UV to all test environments. In this case, you often wouldn't want to modify the scripts
mapping directly but rather add an extra script:
[tool.hatch.envs.hatch-test.extra-scripts]\npip = \"{env:HATCH_UV} pip {args}\"\n
[envs.hatch-test.extra-scripts]\npip = \"{env:HATCH_UV} pip {args}\"\n
"},{"location":"how-to/integrate/vscode/","title":"How to use Hatch environments from Visual Studio Code","text":"Visual Studio Code announced support for Hatch environment discovery in vscode-python
's 2024.4 release.
For it to work, you should install Hatch globally. If you used the GUI installers on Windows or macOS, or your system package manager on e.g. Arch Linux or Fedora, this should be taken care of.
Setting up PATHIf you installed Hatch with pipx rather than system-wide, you might need to add $HOME/.local/bin
to your PATH environment variable for your graphical session, not just your terminal. Check like this:
$ pgrep bin/code # or some other graphical application\n1234\n$ cat /proc/1234/environ | tr '\\0' '\\n' | grep -E '^PATH='\nPATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\n
If the directory is not in there, you need to add it in your session startup script, in a way that depends on your desktop environment:
Make Hatch install the project and its dependencies to an environment using the env create
command.
Select an interpreter using the Python: Select Interpreter command:
You should now be able to use the environment. For example, if you have the python.terminal.activateEnvironment
setting set to true
and you open a new terminal, the environment should be activated. Alternatively, you could press the \"play\" button to run a file in the environment:
All reports regarding unexpected behavior should be generated with the self report
command:
$ hatch self report\n
By default, this will open a new tab in your default browser with pre-populated information about your environment.
If Hatch is not installed alongside a web browser, you may also pass the --no-open
/-n
command which will output the URL with correct parameters for copying elsewhere:
$ hatch self report -n\nhttps://github.com/pypa/hatch/issues/new?body=%23%23+Current+behavior%0A%3C%21--+A+clear+and+concise+description+of+the+behavior.+--%3E%0A%0A%23%23+Expected+behavior%0A%3C%21--+A+clear+and+concise+description+of+what+you+expected+to+happen.+--%3E%0A%0A%23%23+Additional+context%0A%3C%21--+Add+any+other+context+about+the+problem+here.+If+applicable%2C+add+screenshots+to+help+explain.+--%3E%0A%0A%23%23+Debug%0A%0A%23%23%23+Installation%0A%0A-+Source%3A+pip%0A-+Version%3A+1.9.2.dev5%0A-+Platform%3A+Windows%0A-+Python+version%3A%0A++++%60%60%60%0A++++3.11.1+%28tags%2Fv3.11.1%3Aa7a450f%2C+Dec++6+2022%2C+19%3A58%3A39%29+%5BMSC+v.1934+64+bit+%28AMD64%29%5D%0A++++%60%60%60%0A%0A%23%23%23+Configuration%0A%0A%60%60%60toml%0Amode+%3D+%22local%22%0Ashell+%3D+%22nu%22%0A%60%60%60%0A\n
"},{"location":"how-to/plugins/testing-builds/","title":"Testing build plugins","text":"For testing Hatchling plugins, you'll usually want to generate a project to execute builds as a real user would. For example, as a minimal pytest fixture:
from pathlib import Path\n\nimport pytest\n\n\n@pytest.fixture\ndef new_project(tmp_path):\n project_dir = tmp_path / 'my-app'\n project_dir.mkdir()\n\n project_file = project_dir / 'pyproject.toml'\n project_file.write_text(\n f\"\"\"\\\n[build-system]\nrequires = [\"hatchling\", \"hatch-plugin-name @ {Path.cwd().as_uri()}\"]\nbuild-backend = \"hatchling.build\"\n\n[project]\nname = \"my-app\"\nversion = \"0.1.0\"\n\"\"\",\n encoding='utf-8',\n )\n ...\n
The issue with this is that after the first test session, the project will be forever cached by pip based on the file path. Therefore, subsequent tests runs will never use updated code.
To invalidate the cache, copy your code to a new path for every test session:
import shutil\nfrom pathlib import Path\nfrom tempfile import TemporaryDirectory\n\nimport pytest\n\n\n@pytest.fixture(scope='session')\ndef plugin_dir():\n with TemporaryDirectory() as d:\n directory = Path(d, 'plugin')\n shutil.copytree(\n Path.cwd(), directory, ignore=shutil.ignore_patterns('.git')\n )\n\n yield directory.resolve()\n\n\n@pytest.fixture\ndef new_project(tmp_path, plugin_dir):\n project_dir = tmp_path / 'my-app'\n project_dir.mkdir()\n\n project_file = project_dir / 'pyproject.toml'\n project_file.write_text(\n f\"\"\"\\\n[build-system]\nrequires = [\"hatchling\", \"hatch-plugin-name @ {plugin_dir.as_uri()}\"]\nbuild-backend = \"hatchling.build\"\n\n[project]\nname = \"my-app\"\nversion = \"0.1.0\"\n\"\"\",\n encoding='utf-8',\n )\n ...\n
Note
This example chooses to ignore copying .git
for performance reasons. You may want to ignore more patterns, or copy only specific paths like this plugin does.
The username is derived from the following sources, in order of precedence:
--user
/ -u
cli option.HATCH_INDEX_USER
environment variable.repos
tables.~/.pypirc
file.As a fallback the value __token__
is applied.
The password is looked up in these:
~/.pypirc
file if the username was provided by it.--auth
/ -a
cli option.HATCH_INDEX_AUTH
environment variable.repos
tables.If interactively provided credentials were used, the username will be stored in Hatch's cache and the password stored in the available keyring backed credentials stores.
For automated releasing to PyPI, it is recommended to use \"Trusted Publishing\" with OIDC (e.g. PyPA's pypi-publish
GitHub Action) or per-project API tokens.
You can select the repository with which to upload using the -r
/--repo
option or by setting the HATCH_INDEX_REPO
environment variable.
Rather than specifying the full URL of a repository, you can use a named repository from a publish.index.repos
table defined in Hatch's config file:
[publish.index.repos.private]\nurl = \"...\"\n...\n
The following repository names are reserved by Hatch and cannot be overridden:
Name Repositorymain
https://upload.pypi.org/legacy/ test
https://test.pypi.org/legacy/ The main
repository is used by default.
The built-in Python management capabilities offer full support for using custom distributions.
"},{"location":"how-to/python/custom/#configuration","title":"Configuration","text":"Configuring custom Python distributions is done entirely through three environment variables that must all be defined, for each desired distribution. In the following sections, the placeholder <NAME>
is the uppercased version of the distribution name with periods replaced by underscores e.g. pypy3.10
would become PYPY3_10
.
The HATCH_PYTHON_CUSTOM_SOURCE_<NAME>
variable is the URL to the distribution's archive. The value must end with the archive's real file extension, which is used to determine the extraction method.
The following extensions are supported:
Extensions Description.tar.bz2
.bz2
.tar.gz
.tgz
.tar.zst
.tar.zstd
.zip
The HATCH_PYTHON_CUSTOM_PATH_<NAME>
variable is the path to the Python interpreter within the archive. This path is relative to the root of the archive and must be a Unix-style path, even on Windows.
The HATCH_PYTHON_CUSTOM_VERSION_<NAME>
variable is the version of the distribution. This value is used to determine whether updates are required and is displayed in the output of the python show
command.
The run
command supports executing Python scripts with inline metadata, such that a dedicated environment is automatically created with the required dependencies and with the correct version of Python.
A script metadata block is a comment block that starts with # /// script
and ends with # ///
. Every line between those two lines must be a comment line that starts with #
and contains a TOML document when the comment characters are removed.
The top-level fields are:
dependencies
: A list of strings that specifies the runtime dependencies of the script. Each entry must be a valid dependency specifier.requires-python
: A string that specifies the Python version(s) with which the script is compatible. The value of this field must be a valid version specifier.The following is an example of Python script with a valid metadata block:
script.py# /// script\n# requires-python = \">=3.11\"\n# dependencies = [\n# \"httpx\",\n# \"rich\",\n# ]\n# ///\n\nimport httpx\nfrom rich.pretty import pprint\n\nresp = httpx.get(\"https://peps.python.org/api/peps.json\")\ndata = resp.json()\npprint([(k, v[\"title\"]) for k, v in data.items()][:10])\n
Run it directly:
$ hatch run /path/to/script.py\nCreating environment: SyB4bPbL\nChecking dependencies\nSyncing dependencies\n[\n\u2502 ('1', 'PEP Purpose and Guidelines'),\n\u2502 ('2', 'Procedure for Adding New Modules'),\n\u2502 ('3', 'Guidelines for Handling Bug Reports'),\n\u2502 ('4', 'Deprecation of Standard Modules'),\n\u2502 ('5', 'Guidelines for Language Evolution'),\n\u2502 ('6', 'Bug Fix Releases'),\n\u2502 ('7', 'Style Guide for C Code'),\n\u2502 ('8', 'Style Guide for Python Code'),\n\u2502 ('9', 'Sample Plaintext PEP Template'),\n\u2502 ('10', 'Voting Guidelines')\n]\n
notes
You may use the [tool.hatch]
table directly to control the script's environment. For example, if you wanted to disable UV (which is enabled by default for scripts), you could add the following:
# /// script\n# ...\n# [tool.hatch]\n# installer = \"pip\"\n# ///\n
"},{"location":"how-to/static-analysis/behavior/","title":"Customize static analysis behavior","text":"You can fully alter the static analysis performed by the fmt
command by modifying the reserved environment named hatch-static-analysis
. For example, you could define the following if you wanted to replace the default behavior with a mix of Black, isort and basic flake8:
[tool.hatch.envs.hatch-static-analysis]\ndependencies = [\"black\", \"flake8\", \"isort\"]\n\n[tool.hatch.envs.hatch-static-analysis.scripts]\nformat-check = [\n \"black --check --diff {args:.}\",\n \"isort --check-only --diff {args:.}\",\n]\nformat-fix = [\n \"isort {args:.}\",\n \"black {args:.}\",\n]\nlint-check = \"flake8 {args:.}\"\nlint-fix = \"lint-check\"\n
[envs.hatch-static-analysis]\ndependencies = [\"black\", \"flake8\", \"isort\"]\n\n[envs.hatch-static-analysis.scripts]\nformat-check = [\n \"black --check --diff {args:.}\",\n \"isort --check-only --diff {args:.}\",\n]\nformat-fix = [\n \"isort {args:.}\",\n \"black {args:.}\",\n]\nlint-check = \"flake8 {args:.}\"\nlint-fix = \"lint-check\"\n
The format-*
scripts correspond to the --formatter
/-f
flag while the lint-*
scripts correspond to the --linter
/-l
flag. The *-fix
scripts run by default while the *-check
scripts correspond to the --check
flag. Based on this example, the following shows how the various scripts influence behavior:
hatch fmt
flake8 .
isort .
black .
hatch fmt src tests
flake8 src tests
isort src tests
black src tests
hatch fmt -f
isort .
black .
hatch fmt -l
flake8 .
hatch fmt --check
flake8 .
black --check --diff .
isort --check-only --diff .
hatch fmt --check -f
black --check --diff .
isort --check-only --diff .
hatch fmt --check -l
flake8 .
Q: What is the risk of lock-in?
A: Not much! Other than the plugin system, everything uses Python's established standards by default. Project metadata is based entirely on the standard, the build system is compatible with PEP 517/PEP 660, versioning uses the scheme specified by PEP 440, dependencies are defined with PEP 508 strings, and environments use virtualenv.
Q: Must one use all features?
A: No, all features are optional! You can use just the build system, publish wheels and source distributions that were built by other tools, only use the environment management, etc.
"},{"location":"meta/faq/#libraries-vs-applications","title":"Libraries vs applications","text":"Q: Are workflows for both libraries and applications supported?
A: Yes, mostly! Applications can utilize environment management just like libraries, and plugins can be used to build projects in arbitrary formats or publish artifacts to arbitrary destinations.
The only caveat is that currently there is no support for re-creating an environment given a set of dependencies in a reproducible manner. Although a standard lock file format may be far off since PEP 665 was rejected, resolving capabilities are coming to pip. When that is stabilized, Hatch will add locking functionality and dedicated documentation for managing applications.
"},{"location":"meta/faq/#tool-migration","title":"Tool migration","text":"Q: How to migrate to Hatch?
"},{"location":"meta/faq/#build-system","title":"Build system","text":"SetuptoolsHatch setup.py MANIFEST.inimport os\nfrom io import open\n\nfrom setuptools import find_packages, setup\n\nabout = {}\nwith open(os.path.join('src', 'foo', '__about__.py'), 'r', 'utf-8') as f:\n exec(f.read(), about)\n\nwith open('README.md', 'r', 'utf-8') as f:\n readme = f.read()\n\nsetup(\n # Metadata\n name='foo',\n version=about['__version__'],\n description='...',\n long_description=readme,\n long_description_content_type='text/markdown',\n author='...',\n author_email='...',\n project_urls={\n 'Documentation': '...',\n 'Source': '...',\n },\n classifiers=[\n '...',\n ],\n keywords=[\n '...',\n ],\n python_requires='>=3.8',\n install_requires=[\n '...',\n ],\n extras_require={\n 'feature': ['...'],\n },\n\n # Packaging\n packages=find_packages(where='src'),\n package_dir={'': 'src'},\n package_data={\n 'foo': ['py.typed'],\n },\n zip_safe=False,\n entry_points={\n 'console_scripts': [\n 'foo = foo.cli:main',\n ],\n },\n)\n
graft tests\n\nglobal-exclude *.py[cod] __pycache__\n
pyproject.toml [build-system]\nrequires = [\"hatchling\"]\nbuild-backend = \"hatchling.build\"\n\n[project]\nname = \"foo\"\ndescription = \"...\"\nreadme = \"README.md\"\nauthors = [\n { name = \"...\", email = \"...\" },\n]\nclassifiers = [\n \"...\",\n]\nkeywords = [\n \"...\",\n]\nrequires-python = \">=3.8\"\ndependencies = [\n \"...\",\n]\ndynamic = [\"version\"]\n\n[project.urls]\nDocumentation = \"...\"\nSource = \"...\"\n\n[project.optional-dependencies]\nfeature = [\"...\"]\n\n[project.scripts]\nfoo = \"foo.cli:main\"\n\n[tool.hatch.version]\npath = \"src/foo/__about__.py\"\n\n[tool.hatch.build.targets.sdist]\ninclude = [\n \"/src\",\n \"/tests\",\n]\n
"},{"location":"meta/faq/#environments","title":"Environments","text":"ToxHatch Invocation:
tox\n
tox.ini [tox]\nenvlist =\n py{38,39}-{42,3.14}\n py{39,310}-{9000}-{foo,bar}\n\n[testenv]\nusedevelop = true\ndeps =\n coverage[toml]\n pytest\n pytest-cov\n foo: cryptography\ncommands =\n pytest --cov-report=term-missing --cov-config=pyproject.toml --cov=pkg --cov=tests {posargs}\nsetenv =\n 3.14: PRODUCT_VERSION=3.14\n 42: PRODUCT_VERSION=42\n 9000: PRODUCT_VERSION=9000\n {foo,bar}: EXPERIMENTAL=true\n
Invocation:
hatch run test\n
pyproject.toml hatch.toml [tool.hatch.envs.default]\ndependencies = [\n \"coverage[toml]\",\n \"pytest\",\n \"pytest-cov\",\n]\n\n[tool.hatch.envs.default.scripts]\ntest = 'pytest --cov-report=term-missing --cov-config=pyproject.toml --cov=pkg --cov=tests'\n\n[tool.hatch.envs.default.overrides]\nmatrix.version.env-vars = \"PRODUCT_VERSION\"\nmatrix.feature.env-vars = \"EXPERIMENTAL=true\"\nmatrix.feature.dependencies = [\n { value = \"cryptography\", if = [\"foo\"] },\n]\n\n[[tool.hatch.envs.default.matrix]]\npython = [\"3.8\", \"3.9\"]\nversion = [\"42\", \"3.14\"]\n\n[[tool.hatch.envs.default.matrix]]\npython = [\"3.9\", \"3.10\"]\nversion = [\"9000\"]\nfeature = [\"foo\", \"bar\"]\n
[envs.default]\ndependencies = [\n \"coverage[toml]\",\n \"pytest\",\n \"pytest-cov\",\n]\n\n[envs.default.scripts]\ntest = 'pytest --cov-report=term-missing --cov-config=pyproject.toml --cov=pkg --cov=tests'\n\n[envs.default.overrides]\nmatrix.version.env-vars = \"PRODUCT_VERSION\"\nmatrix.feature.env-vars = \"EXPERIMENTAL=true\"\nmatrix.feature.dependencies = [\n { value = \"cryptography\", if = [\"foo\"] },\n]\n\n[[envs.default.matrix]]\npython = [\"3.8\", \"3.9\"]\nversion = [\"42\", \"3.14\"]\n\n[[envs.default.matrix]]\npython = [\"3.9\", \"3.10\"]\nversion = [\"9000\"]\nfeature = [\"foo\", \"bar\"]\n
"},{"location":"meta/faq/#fast-cli","title":"Fast CLI?","text":"The claim about being faster than other tools is based on timings that are always checked in CI.
Hatch achieves this by using lazy imports, lazily performing computation manually and with functools.cached_property, using hacks like not not ...
instead of bool(...)
, etc.
Hatch utilizes pluggy for its plugin functionality.
"},{"location":"plugins/about/#overview","title":"Overview","text":"All plugins provide registration hooks that return one or more classes that inherit from a particular type interface.
Each registration hook must be decorated by Hatch's hook marker. For example, if you wanted to create a new kind of environment you could do:
hooks.pyfrom hatchling.plugin import hookimpl\n\nfrom .plugin import SpecialEnvironment\n\n\n@hookimpl\ndef hatch_register_environment():\n return SpecialEnvironment\n
The hooks can return a single class or a list of classes.
Every class must define an attribute called PLUGIN_NAME
that users will select when they wish to use the plugin. So in the example above, the class might be defined like:
...\nclass SpecialEnvironment(...):\n PLUGIN_NAME = 'special'\n ...\n
"},{"location":"plugins/about/#project-configuration","title":"Project configuration","text":""},{"location":"plugins/about/#naming","title":"Naming","text":"It is recommended that plugin project names are prefixed with hatch-
. For example, if you wanted to make a plugin that provides some functionality for a product named foo
you might do:
[project]\nname = \"hatch-foo\"\n
"},{"location":"plugins/about/#discovery","title":"Discovery","text":"You'll need to define your project as a Python plugin for Hatch:
pyproject.toml[project.entry-points.hatch]\nfoo = \"pkg.hooks\"\n
The name of the plugin should be the project name (excluding any hatch-
prefix) and the path should represent the module that contains the registration hooks.
Add Framework :: Hatch
to your project's classifiers to make it easy to search for Hatch plugins:
[project]\nclassifiers = [\n ...\n \"Framework :: Hatch\",\n ...\n]\n
"},{"location":"plugins/about/#types","title":"Types","text":""},{"location":"plugins/about/#hatchling","title":"Hatchling","text":"These are all involved in building projects and therefore any defined dependencies are automatically installed in each build environment.
These must be installed in the same environment as Hatch itself.
hatchling.builders.utils.get_reproducible_timestamp() -> int
","text":"Returns an int
derived from the SOURCE_DATE_EPOCH
environment variable; see https://reproducible-builds.org/specs/source-date-epoch/.
The default value will always be: 1580601600
backend/src/hatchling/builders/utils.py
def get_reproducible_timestamp() -> int:\n \"\"\"\n Returns an `int` derived from the `SOURCE_DATE_EPOCH` environment variable; see\n https://reproducible-builds.org/specs/source-date-epoch/.\n\n The default value will always be: `1580601600`\n \"\"\"\n return int(os.environ.get('SOURCE_DATE_EPOCH', '1580601600'))\n
"},{"location":"plugins/utilities/#hatchling.builders.config.BuilderConfig","title":"BuilderConfig
","text":""},{"location":"plugins/utilities/#hatchling.builders.config.BuilderConfig.directory","title":"directory: str
property
","text":""},{"location":"plugins/utilities/#hatchling.builders.config.BuilderConfig.ignore_vcs","title":"ignore_vcs: bool
property
","text":""},{"location":"plugins/utilities/#hatchling.builders.config.BuilderConfig.reproducible","title":"reproducible: bool
property
","text":"Whether or not the target should be built in a reproducible manner, defaulting to true.
"},{"location":"plugins/utilities/#hatchling.builders.config.BuilderConfig.dev_mode_dirs","title":"dev_mode_dirs: list[str]
property
","text":"Directories which must be added to Python's search path in dev mode.
"},{"location":"plugins/utilities/#hatchling.builders.config.BuilderConfig.versions","title":"versions: list[str]
property
","text":""},{"location":"plugins/utilities/#hatchling.builders.config.BuilderConfig.dependencies","title":"dependencies: list[str]
property
","text":""},{"location":"plugins/utilities/#hatchling.builders.config.BuilderConfig.default_include","title":"default_include() -> list
","text":""},{"location":"plugins/utilities/#hatchling.builders.config.BuilderConfig.default_exclude","title":"default_exclude() -> list
","text":""},{"location":"plugins/utilities/#hatchling.builders.config.BuilderConfig.default_packages","title":"default_packages() -> list
","text":""},{"location":"plugins/utilities/#hatchling.builders.config.BuilderConfig.default_only_include","title":"default_only_include() -> list
","text":""},{"location":"plugins/utilities/#hatchling.bridge.app.Application","title":"Application
","text":"The way output is displayed can be configured by users.
Important
Never import this directly; Hatch judiciously decides if a type of plugin requires the capabilities herein and will grant access via an attribute.
"},{"location":"plugins/utilities/#hatchling.bridge.app.Application.verbosity","title":"verbosity: int
property
","text":"The verbosity level of the application, with 0 as the default.
"},{"location":"plugins/utilities/#hatchling.bridge.app.Application.abort","title":"abort(message: str = '', code: int = 1, **kwargs: Any) -> None
","text":"Terminate the program with the given return code.
"},{"location":"plugins/utilities/#hatchling.bridge.app.Application.display_debug","title":"display_debug(message: str = '', level: int = 1, **kwargs: Any) -> None
","text":"Meant to be used for messages that are not useful for most user experiences. The level
option must be between 1 and 3 (inclusive).
display_error(message: str = '', **kwargs: Any) -> None
","text":"Meant to be used for messages indicating some unrecoverable error.
"},{"location":"plugins/utilities/#hatchling.bridge.app.Application.display_info","title":"display_info(message: str = '', **kwargs: Any) -> None
","text":"Meant to be used for messages conveying basic information.
"},{"location":"plugins/utilities/#hatchling.bridge.app.Application.display_success","title":"display_success(message: str = '', **kwargs: Any) -> None
","text":"Meant to be used for messages indicating some positive outcome.
"},{"location":"plugins/utilities/#hatchling.bridge.app.Application.display_waiting","title":"display_waiting(message: str = '', **kwargs: Any) -> None
","text":"Meant to be used for messages shown before potentially time consuming operations.
"},{"location":"plugins/utilities/#hatchling.bridge.app.Application.display_warning","title":"display_warning(message: str = '', **kwargs: Any) -> None
","text":"Meant to be used for messages conveying important information.
"},{"location":"plugins/utilities/#hatch.utils.platform.Platform","title":"Platform
","text":""},{"location":"plugins/utilities/#hatch.utils.platform.Platform.default_shell","title":"default_shell: str
property
","text":"Returns the default shell of the system.
On Windows systems first try the SHELL
environment variable, if present, followed by the COMSPEC
environment variable, defaulting to cmd
. On all other platforms only the SHELL
environment variable will be used, defaulting to bash
.
modules: LazilyLoadedModules
property
","text":"Accessor for lazily loading modules that either take multiple milliseconds to import (like shutil
and subprocess
) or are not used on all platforms (like shlex
).
home: Path
property
","text":"The user's home directory as a path-like object.
"},{"location":"plugins/utilities/#hatch.utils.platform.Platform.name","title":"name: str
property
","text":"One of the following:
linux
windows
macos
display_name: str
property
","text":"One of the following:
Linux
Windows
macOS
windows: bool
property
","text":"Indicates whether Hatch is running on Windows.
"},{"location":"plugins/utilities/#hatch.utils.platform.Platform.macos","title":"macos: bool
property
","text":"Indicates whether Hatch is running on macOS.
"},{"location":"plugins/utilities/#hatch.utils.platform.Platform.linux","title":"linux: bool
property
","text":"Indicates whether Hatch is running on neither Windows nor macOS.
"},{"location":"plugins/utilities/#hatch.utils.platform.Platform.format_for_subprocess","title":"format_for_subprocess(command: str | list[str], *, shell: bool) -> str | list[str]
","text":"Format the given command in a cross-platform manner for immediate consumption by subprocess utilities.
"},{"location":"plugins/utilities/#hatch.utils.platform.Platform.run_command","title":"run_command(command: str | list[str], *, shell: bool = False, **kwargs: Any) -> CompletedProcess
","text":"Equivalent to the standard library's subprocess.run, with the command first being properly formatted.
"},{"location":"plugins/utilities/#hatch.utils.platform.Platform.check_command","title":"check_command(command: str | list[str], *, shell: bool = False, **kwargs: Any) -> CompletedProcess
","text":"Equivalent to run_command, but non-zero exit codes will gracefully end program execution.
"},{"location":"plugins/utilities/#hatch.utils.platform.Platform.check_command_output","title":"check_command_output(command: str | list[str], *, shell: bool = False, **kwargs: Any) -> str
","text":"Equivalent to the output from the process returned by capture_process, but non-zero exit codes will gracefully end program execution.
"},{"location":"plugins/utilities/#hatch.utils.platform.Platform.capture_process","title":"capture_process(command: str | list[str], *, shell: bool = False, **kwargs: Any) -> Popen
","text":"Equivalent to the standard library's subprocess.Popen, with all output captured by stdout
and the command first being properly formatted.
exit_with_command(command: list[str]) -> None
","text":"Run the given command and exit with its exit code. On non-Windows systems, this uses the standard library's os.execvp.
"},{"location":"plugins/utilities/#hatch.env.context.EnvironmentContextFormatter","title":"EnvironmentContextFormatter
","text":""},{"location":"plugins/utilities/#hatch.env.context.EnvironmentContextFormatter.formatters","title":"formatters()
","text":"This returns a mapping of supported field names to their respective formatting functions. Each function accepts 2 arguments:
value
that was passed to the format call, defaulting to None
data
, defaulting to an empty stringFileSystemContext
","text":"This class represents a synchronized path between the local file system and a potentially remote environment.
"},{"location":"plugins/utilities/#hatch.env.plugin.interface.FileSystemContext.env","title":"env: EnvironmentInterface
property
","text":"Returns the environment to which this context belongs.
"},{"location":"plugins/utilities/#hatch.env.plugin.interface.FileSystemContext.local_path","title":"local_path: Path
property
","text":"Returns the local path to which this context refers as a path-like object.
"},{"location":"plugins/utilities/#hatch.env.plugin.interface.FileSystemContext.env_path","title":"env_path: str
property
","text":"Returns the environment path to which this context refers as a string. The environment may not be on the local file system.
"},{"location":"plugins/utilities/#hatch.env.plugin.interface.FileSystemContext.sync_local","title":"sync_local()
","text":"Synchronizes the local path as the source with the environment path as the source.
"},{"location":"plugins/utilities/#hatch.env.plugin.interface.FileSystemContext.sync_env","title":"sync_env()
","text":"Synchronizes the environment path with the local path as the source.
"},{"location":"plugins/utilities/#hatch.env.plugin.interface.FileSystemContext.join","title":"join(relative_path: str) -> FileSystemContext
","text":"Returns a new instance of this class with the given relative path appended to the local and environment paths.
This method should not need overwriting.
"},{"location":"plugins/build-hook/custom/","title":"Custom build hook","text":"This is a custom class in a given Python file that inherits from the BuildHookInterface.
"},{"location":"plugins/build-hook/custom/#configuration","title":"Configuration","text":"The build hook plugin name is custom
.
[tool.hatch.build.hooks.custom]\n[tool.hatch.build.targets.<TARGET_NAME>.hooks.custom]\n
[build.hooks.custom]\n[build.targets.<TARGET_NAME>.hooks.custom]\n
"},{"location":"plugins/build-hook/custom/#options","title":"Options","text":"Option Default Description path
hatch_build.py
The path of the Python file"},{"location":"plugins/build-hook/custom/#example","title":"Example","text":"hatch_build.py from hatchling.builders.hooks.plugin.interface import BuildHookInterface\n\n\nclass CustomBuildHook(BuildHookInterface):\n ...\n
If multiple subclasses are found, you must define a function named get_build_hook
that returns the desired build hook.
Note
Any defined PLUGIN_NAME is ignored and will always be custom
.
A build hook provides code that will be executed at various stages of the build process. See the documentation for build hook configuration.
"},{"location":"plugins/build-hook/reference/#known-third-party","title":"Known third-party","text":"gettext
toolsBuild hooks run for every selected version of build targets.
The initialization stage occurs immediately before each build and the finalization stage occurs immediately after. Each stage has the opportunity to view or modify build data.
"},{"location":"plugins/build-hook/reference/#build-data","title":"Build data","text":"Build data is a simple mapping whose contents can influence the behavior of builds. Which fields exist and are recognized depends on each build target.
The following fields are always present and recognized by the build system itself:
Field Type Descriptionartifacts
list[str]
This is a list of extra artifact
patterns and should generally only be appended to force_include
dict[str, str]
This is a mapping of extra forced inclusion paths, with this mapping taking precedence in case of conflicts build_hooks
tuple[str, ...]
This is an immutable sequence of the names of the configured build hooks and matches the order in which they run Attention
While user-facing TOML options are hyphenated, build data fields should be named with underscores to allow plugins to use them as valid Python identifiers.
"},{"location":"plugins/build-hook/reference/#notes","title":"Notes","text":"In some cases it may be necessary to use force_include
rather than artifacts
. For example, say that you want to install a lib.so
directly at the root of site-packages
and a project defines a package src/foo
. If you create src/lib.so
, there will never be a match because the directory traversal starts at src/foo
rather than src
. In that case you must do either:
build_data['force_include']['src/lib.so'] = 'src/lib.so'\n
or
build_data['force_include']['/absolute/path/to/src/lib.so'] = 'src/lib.so'\n
"},{"location":"plugins/build-hook/reference/#hatchling.builders.hooks.plugin.interface.BuildHookInterface","title":"BuildHookInterface
","text":"Example usage:
plugin.py hooks.pyfrom hatchling.builders.hooks.plugin.interface import BuildHookInterface\n\n\nclass SpecialBuildHook(BuildHookInterface):\n PLUGIN_NAME = 'special'\n ...\n
from hatchling.plugin import hookimpl\n\nfrom .plugin import SpecialBuildHook\n\n\n@hookimpl\ndef hatch_register_build_hook():\n return SpecialBuildHook\n
Source code in backend/src/hatchling/builders/hooks/plugin/interface.py
class BuildHookInterface(Generic[BuilderConfigBound]): # no cov\n \"\"\"\n Example usage:\n\n ```python tab=\"plugin.py\"\n from hatchling.builders.hooks.plugin.interface import BuildHookInterface\n\n\n class SpecialBuildHook(BuildHookInterface):\n PLUGIN_NAME = 'special'\n ...\n ```\n\n ```python tab=\"hooks.py\"\n from hatchling.plugin import hookimpl\n\n from .plugin import SpecialBuildHook\n\n\n @hookimpl\n def hatch_register_build_hook():\n return SpecialBuildHook\n ```\n \"\"\"\n\n PLUGIN_NAME = ''\n \"\"\"The name used for selection.\"\"\"\n\n def __init__(\n self,\n root: str,\n config: dict[str, Any],\n build_config: BuilderConfigBound,\n metadata: ProjectMetadata,\n directory: str,\n target_name: str,\n app: Application | None = None,\n ) -> None:\n self.__root = root\n self.__config = config\n self.__build_config = build_config\n self.__metadata = metadata\n self.__directory = directory\n self.__target_name = target_name\n self.__app = app\n\n @property\n def app(self) -> Application:\n \"\"\"\n An instance of [Application](../utilities.md#hatchling.bridge.app.Application).\n \"\"\"\n if self.__app is None:\n from hatchling.bridge.app import Application\n\n self.__app = cast(Application, Application().get_safe_application())\n\n return self.__app\n\n @property\n def root(self) -> str:\n \"\"\"\n The root of the project tree.\n \"\"\"\n return self.__root\n\n @property\n def config(self) -> dict[str, Any]:\n \"\"\"\n The cumulative hook configuration.\n\n ```toml config-example\n [tool.hatch.build.hooks.<PLUGIN_NAME>]\n [tool.hatch.build.targets.<TARGET_NAME>.hooks.<PLUGIN_NAME>]\n ```\n \"\"\"\n return self.__config\n\n @property\n def metadata(self) -> ProjectMetadata:\n # Undocumented for now\n return self.__metadata\n\n @property\n def build_config(self) -> BuilderConfigBound:\n \"\"\"\n An instance of [BuilderConfig](../utilities.md#hatchling.builders.config.BuilderConfig).\n \"\"\"\n return self.__build_config\n\n @property\n def directory(self) -> str:\n \"\"\"\n The build directory.\n \"\"\"\n return self.__directory\n\n @property\n def target_name(self) -> str:\n \"\"\"\n The plugin name of the build target.\n \"\"\"\n return self.__target_name\n\n def dependencies(self) -> list[str]: # noqa: PLR6301\n \"\"\"\n A list of extra [dependencies](../../config/dependency.md) that must be installed\n prior to builds.\n\n !!! warning\n - For this to have any effect the hook dependency itself cannot be dynamic and\n must always be defined in `build-system.requires`.\n - As the hook must be imported to call this method, imports that require these\n dependencies must be evaluated lazily.\n \"\"\"\n return []\n\n def clean(self, versions: list[str]) -> None:\n \"\"\"\n This occurs before the build process if the `-c`/`--clean` flag was passed to\n the [`build`](../../cli/reference.md#hatch-build) command, or when invoking\n the [`clean`](../../cli/reference.md#hatch-clean) command.\n \"\"\"\n\n def initialize(self, version: str, build_data: dict[str, Any]) -> None:\n \"\"\"\n This occurs immediately before each build.\n\n Any modifications to the build data will be seen by the build target.\n \"\"\"\n\n def finalize(self, version: str, build_data: dict[str, Any], artifact_path: str) -> None:\n \"\"\"\n This occurs immediately after each build and will not run if the `--hooks-only` flag\n was passed to the [`build`](../../cli/reference.md#hatch-build) command.\n\n The build data will reflect any modifications done by the target during the build.\n \"\"\"\n
"},{"location":"plugins/build-hook/reference/#hatchling.builders.hooks.plugin.interface.BuildHookInterface.PLUGIN_NAME","title":"PLUGIN_NAME = ''
class-attribute
instance-attribute
","text":"The name used for selection.
"},{"location":"plugins/build-hook/reference/#hatchling.builders.hooks.plugin.interface.BuildHookInterface.app","title":"app: Application
property
","text":"An instance of Application.
"},{"location":"plugins/build-hook/reference/#hatchling.builders.hooks.plugin.interface.BuildHookInterface.root","title":"root: str
property
","text":"The root of the project tree.
"},{"location":"plugins/build-hook/reference/#hatchling.builders.hooks.plugin.interface.BuildHookInterface.config","title":"config: dict[str, Any]
property
","text":"The cumulative hook configuration.
pyproject.toml hatch.toml[tool.hatch.build.hooks.<PLUGIN_NAME>]\n[tool.hatch.build.targets.<TARGET_NAME>.hooks.<PLUGIN_NAME>]\n
[build.hooks.<PLUGIN_NAME>]\n[build.targets.<TARGET_NAME>.hooks.<PLUGIN_NAME>]\n
"},{"location":"plugins/build-hook/reference/#hatchling.builders.hooks.plugin.interface.BuildHookInterface.build_config","title":"build_config: BuilderConfigBound
property
","text":"An instance of BuilderConfig.
"},{"location":"plugins/build-hook/reference/#hatchling.builders.hooks.plugin.interface.BuildHookInterface.target_name","title":"target_name: str
property
","text":"The plugin name of the build target.
"},{"location":"plugins/build-hook/reference/#hatchling.builders.hooks.plugin.interface.BuildHookInterface.directory","title":"directory: str
property
","text":"The build directory.
"},{"location":"plugins/build-hook/reference/#hatchling.builders.hooks.plugin.interface.BuildHookInterface.dependencies","title":"dependencies() -> list[str]
","text":"A list of extra dependencies that must be installed prior to builds.
Warning
build-system.requires
.backend/src/hatchling/builders/hooks/plugin/interface.py
def dependencies(self) -> list[str]: # noqa: PLR6301\n \"\"\"\n A list of extra [dependencies](../../config/dependency.md) that must be installed\n prior to builds.\n\n !!! warning\n - For this to have any effect the hook dependency itself cannot be dynamic and\n must always be defined in `build-system.requires`.\n - As the hook must be imported to call this method, imports that require these\n dependencies must be evaluated lazily.\n \"\"\"\n return []\n
"},{"location":"plugins/build-hook/reference/#hatchling.builders.hooks.plugin.interface.BuildHookInterface.clean","title":"clean(versions: list[str]) -> None
","text":"This occurs before the build process if the -c
/--clean
flag was passed to the build
command, or when invoking the clean
command.
backend/src/hatchling/builders/hooks/plugin/interface.py
def clean(self, versions: list[str]) -> None:\n \"\"\"\n This occurs before the build process if the `-c`/`--clean` flag was passed to\n the [`build`](../../cli/reference.md#hatch-build) command, or when invoking\n the [`clean`](../../cli/reference.md#hatch-clean) command.\n \"\"\"\n
"},{"location":"plugins/build-hook/reference/#hatchling.builders.hooks.plugin.interface.BuildHookInterface.initialize","title":"initialize(version: str, build_data: dict[str, Any]) -> None
","text":"This occurs immediately before each build.
Any modifications to the build data will be seen by the build target.
Source code inbackend/src/hatchling/builders/hooks/plugin/interface.py
def initialize(self, version: str, build_data: dict[str, Any]) -> None:\n \"\"\"\n This occurs immediately before each build.\n\n Any modifications to the build data will be seen by the build target.\n \"\"\"\n
"},{"location":"plugins/build-hook/reference/#hatchling.builders.hooks.plugin.interface.BuildHookInterface.finalize","title":"finalize(version: str, build_data: dict[str, Any], artifact_path: str) -> None
","text":"This occurs immediately after each build and will not run if the --hooks-only
flag was passed to the build
command.
The build data will reflect any modifications done by the target during the build.
Source code inbackend/src/hatchling/builders/hooks/plugin/interface.py
def finalize(self, version: str, build_data: dict[str, Any], artifact_path: str) -> None:\n \"\"\"\n This occurs immediately after each build and will not run if the `--hooks-only` flag\n was passed to the [`build`](../../cli/reference.md#hatch-build) command.\n\n The build data will reflect any modifications done by the target during the build.\n \"\"\"\n
"},{"location":"plugins/build-hook/version/","title":"Version build hook","text":"This writes the project's version to a file.
"},{"location":"plugins/build-hook/version/#configuration","title":"Configuration","text":"The build hook plugin name is version
.
[tool.hatch.build.hooks.version]\n[tool.hatch.build.targets.<TARGET_NAME>.hooks.version]\n
[build.hooks.version]\n[build.targets.<TARGET_NAME>.hooks.version]\n
"},{"location":"plugins/build-hook/version/#options","title":"Options","text":"Option Description path
(required) A relative path to the desired file template
A string representing the entire contents of path
that will be formatted with a version
variable pattern
Rather than updating the entire file, a regular expression may be used that has a named group called version
that represents the version. If set to true
, a pattern will be used that looks for a variable named __version__
or VERSION
that is set to a string containing the version, optionally prefixed with the lowercase letter v
."},{"location":"plugins/builder/binary/","title":"Binary builder","text":"This uses PyApp to build an application that is able to bootstrap itself at runtime.
Note
This requires an installation of Rust.
"},{"location":"plugins/builder/binary/#configuration","title":"Configuration","text":"The builder plugin name is binary
.
[tool.hatch.build.targets.binary]\n
[build.targets.binary]\n
"},{"location":"plugins/builder/binary/#options","title":"Options","text":"Option Default Description scripts
all defined An array of defined script names to limit what gets built python-version
latest compatible Python minor version The Python version ID to use pyapp-version
The version of PyApp to use"},{"location":"plugins/builder/binary/#build-behavior","title":"Build behavior","text":"If any scripts are defined then each one will be built (limited by the scripts
option). Otherwise, a single executable will be built based on the project name assuming there is an equivalently named module with a __main__.py
file.
Every executable will be built inside an app
directory in the output directory.
If the CARGO
environment variable is set then that path will be used as the executable for performing builds.
If the CARGO_BUILD_TARGET
environment variable is set then its value will be appended to the file name stems.
If the PYAPP_REPO
environment variable is set then a local build will be performed inside that directory rather than installing from crates.io. Note that this is required if the CARGO
environment variable refers to cross.
This is a custom class in a given Python file that inherits from the BuilderInterface.
"},{"location":"plugins/builder/custom/#configuration","title":"Configuration","text":"The builder plugin name is custom
.
[tool.hatch.build.targets.custom]\n
[build.targets.custom]\n
"},{"location":"plugins/builder/custom/#options","title":"Options","text":"Option Default Description path
hatch_build.py
The path of the Python file"},{"location":"plugins/builder/custom/#example","title":"Example","text":"hatch_build.py from hatchling.builders.plugin.interface import BuilderInterface\n\n\nclass CustomBuilder(BuilderInterface):\n ...\n
If multiple subclasses are found, you must define a function named get_builder
that returns the desired builder.
Note
Any defined PLUGIN_NAME is ignored and will always be custom
.
See the documentation for build configuration.
"},{"location":"plugins/builder/reference/#known-third-party","title":"Known third-party","text":"BuilderInterface
","text":"Example usage:
plugin.py hooks.pyfrom hatchling.builders.plugin.interface import BuilderInterface\n\n\nclass SpecialBuilder(BuilderInterface):\n PLUGIN_NAME = 'special'\n ...\n
from hatchling.plugin import hookimpl\n\nfrom .plugin import SpecialBuilder\n\n\n@hookimpl\ndef hatch_register_builder():\n return SpecialBuilder\n
Source code in backend/src/hatchling/builders/plugin/interface.py
class BuilderInterface(ABC, Generic[BuilderConfigBound, PluginManagerBound]):\n \"\"\"\n Example usage:\n\n ```python tab=\"plugin.py\"\n from hatchling.builders.plugin.interface import BuilderInterface\n\n\n class SpecialBuilder(BuilderInterface):\n PLUGIN_NAME = 'special'\n ...\n ```\n\n ```python tab=\"hooks.py\"\n from hatchling.plugin import hookimpl\n\n from .plugin import SpecialBuilder\n\n\n @hookimpl\n def hatch_register_builder():\n return SpecialBuilder\n ```\n \"\"\"\n\n PLUGIN_NAME = ''\n \"\"\"The name used for selection.\"\"\"\n\n def __init__(\n self,\n root: str,\n plugin_manager: PluginManagerBound | None = None,\n config: dict[str, Any] | None = None,\n metadata: ProjectMetadata | None = None,\n app: Application | None = None,\n ) -> None:\n self.__root = root\n self.__plugin_manager = cast(PluginManagerBound, plugin_manager)\n self.__raw_config = config\n self.__metadata = metadata\n self.__app = app\n self.__config = cast(BuilderConfigBound, None)\n self.__project_config: dict[str, Any] | None = None\n self.__hatch_config: dict[str, Any] | None = None\n self.__build_config: dict[str, Any] | None = None\n self.__build_targets: list[str] | None = None\n self.__target_config: dict[str, Any] | None = None\n\n # Metadata\n self.__project_id: str | None = None\n\n def build(\n self,\n *,\n directory: str | None = None,\n versions: list[str] | None = None,\n hooks_only: bool | None = None,\n clean: bool | None = None,\n clean_hooks_after: bool | None = None,\n clean_only: bool | None = False,\n ) -> Generator[str, None, None]:\n # Fail early for invalid project metadata\n self.metadata.validate_fields()\n\n if directory is None:\n directory = (\n self.config.normalize_build_directory(os.environ[BuildEnvVars.LOCATION])\n if BuildEnvVars.LOCATION in os.environ\n else self.config.directory\n )\n\n if not os.path.isdir(directory):\n os.makedirs(directory)\n\n version_api = self.get_version_api()\n\n versions = versions or self.config.versions\n if versions:\n unknown_versions = set(versions) - set(version_api)\n if unknown_versions:\n message = (\n f'Unknown versions for target `{self.PLUGIN_NAME}`: {\", \".join(map(str, sorted(unknown_versions)))}'\n )\n raise ValueError(message)\n\n if hooks_only is None:\n hooks_only = env_var_enabled(BuildEnvVars.HOOKS_ONLY)\n\n configured_build_hooks = self.get_build_hooks(directory)\n build_hooks = list(configured_build_hooks.values())\n\n if clean_only:\n clean = True\n elif clean is None:\n clean = env_var_enabled(BuildEnvVars.CLEAN)\n if clean:\n if not hooks_only:\n self.clean(directory, versions)\n\n for build_hook in build_hooks:\n build_hook.clean(versions)\n\n if clean_only:\n return\n\n if clean_hooks_after is None:\n clean_hooks_after = env_var_enabled(BuildEnvVars.CLEAN_HOOKS_AFTER)\n\n for version in versions:\n self.app.display_debug(f'Building `{self.PLUGIN_NAME}` version `{version}`')\n\n build_data = self.get_default_build_data()\n self.set_build_data_defaults(build_data)\n\n # Allow inspection of configured build hooks and the order in which they run\n build_data['build_hooks'] = tuple(configured_build_hooks)\n\n # Execute all `initialize` build hooks\n for build_hook in build_hooks:\n build_hook.initialize(version, build_data)\n\n if hooks_only:\n self.app.display_debug(f'Only ran build hooks for `{self.PLUGIN_NAME}` version `{version}`')\n continue\n\n # Build the artifact\n with self.config.set_build_data(build_data):\n artifact = version_api[version](directory, **build_data)\n\n # Execute all `finalize` build hooks\n for build_hook in build_hooks:\n build_hook.finalize(version, build_data, artifact)\n\n if clean_hooks_after:\n for build_hook in build_hooks:\n build_hook.clean([version])\n\n yield artifact\n\n def recurse_included_files(self) -> Iterable[IncludedFile]:\n \"\"\"\n Returns a consistently generated series of file objects for every file that should be distributed. Each file\n object has three `str` attributes:\n\n - `path` - the absolute path\n - `relative_path` - the path relative to the project root; will be an empty string for external files\n - `distribution_path` - the path to be distributed as\n \"\"\"\n yield from self.recurse_selected_project_files()\n yield from self.recurse_forced_files(self.config.get_force_include())\n\n def recurse_selected_project_files(self) -> Iterable[IncludedFile]:\n if self.config.only_include:\n yield from self.recurse_explicit_files(self.config.only_include)\n else:\n yield from self.recurse_project_files()\n\n def recurse_project_files(self) -> Iterable[IncludedFile]:\n for root, dirs, files in safe_walk(self.root):\n relative_path = get_relative_path(root, self.root)\n\n dirs[:] = sorted(d for d in dirs if not self.config.directory_is_excluded(d, relative_path))\n\n files.sort()\n is_package = '__init__.py' in files\n for f in files:\n if f in EXCLUDED_FILES:\n continue\n\n relative_file_path = os.path.join(relative_path, f)\n distribution_path = self.config.get_distribution_path(relative_file_path)\n if self.config.path_is_reserved(distribution_path):\n continue\n\n if self.config.include_path(relative_file_path, is_package=is_package):\n yield IncludedFile(\n os.path.join(root, f), relative_file_path, self.config.get_distribution_path(relative_file_path)\n )\n\n def recurse_forced_files(self, inclusion_map: dict[str, str]) -> Iterable[IncludedFile]:\n for source, target_path in inclusion_map.items():\n external = not source.startswith(self.root)\n if os.path.isfile(source):\n yield IncludedFile(\n source,\n '' if external else os.path.relpath(source, self.root),\n self.config.get_distribution_path(target_path),\n )\n elif os.path.isdir(source):\n for root, dirs, files in safe_walk(source):\n relative_directory = get_relative_path(root, source)\n\n dirs[:] = sorted(d for d in dirs if d not in EXCLUDED_DIRECTORIES)\n\n files.sort()\n for f in files:\n if f in EXCLUDED_FILES:\n continue\n\n relative_file_path = os.path.join(target_path, relative_directory, f)\n distribution_path = self.config.get_distribution_path(relative_file_path)\n if not self.config.path_is_reserved(distribution_path):\n yield IncludedFile(\n os.path.join(root, f),\n '' if external else relative_file_path,\n distribution_path,\n )\n else:\n msg = f'Forced include not found: {source}'\n raise FileNotFoundError(msg)\n\n def recurse_explicit_files(self, inclusion_map: dict[str, str]) -> Iterable[IncludedFile]:\n for source, target_path in inclusion_map.items():\n external = not source.startswith(self.root)\n if os.path.isfile(source):\n distribution_path = self.config.get_distribution_path(target_path)\n if not self.config.path_is_reserved(distribution_path):\n yield IncludedFile(\n source,\n '' if external else os.path.relpath(source, self.root),\n self.config.get_distribution_path(target_path),\n )\n elif os.path.isdir(source):\n for root, dirs, files in safe_walk(source):\n relative_directory = get_relative_path(root, source)\n\n dirs[:] = sorted(d for d in dirs if d not in EXCLUDED_DIRECTORIES)\n\n files.sort()\n is_package = '__init__.py' in files\n for f in files:\n if f in EXCLUDED_FILES:\n continue\n\n relative_file_path = os.path.join(target_path, relative_directory, f)\n distribution_path = self.config.get_distribution_path(relative_file_path)\n if self.config.path_is_reserved(distribution_path):\n continue\n\n if self.config.include_path(relative_file_path, explicit=True, is_package=is_package):\n yield IncludedFile(\n os.path.join(root, f), '' if external else relative_file_path, distribution_path\n )\n\n @property\n def root(self) -> str:\n \"\"\"\n The root of the project tree.\n \"\"\"\n return self.__root\n\n @property\n def plugin_manager(self) -> PluginManagerBound:\n if self.__plugin_manager is None:\n from hatchling.plugin.manager import PluginManager\n\n self.__plugin_manager = PluginManager()\n\n return self.__plugin_manager\n\n @property\n def metadata(self) -> ProjectMetadata:\n if self.__metadata is None:\n from hatchling.metadata.core import ProjectMetadata\n\n self.__metadata = ProjectMetadata(self.root, self.plugin_manager, self.__raw_config)\n\n return self.__metadata\n\n @property\n def app(self) -> Application:\n \"\"\"\n An instance of [Application](../utilities.md#hatchling.bridge.app.Application).\n \"\"\"\n if self.__app is None:\n from hatchling.bridge.app import Application\n\n self.__app = cast(Application, Application().get_safe_application())\n\n return self.__app\n\n @property\n def raw_config(self) -> dict[str, Any]:\n if self.__raw_config is None:\n self.__raw_config = self.metadata.config\n\n return self.__raw_config\n\n @property\n def project_config(self) -> dict[str, Any]:\n if self.__project_config is None:\n self.__project_config = self.metadata.core.config\n\n return self.__project_config\n\n @property\n def hatch_config(self) -> dict[str, Any]:\n if self.__hatch_config is None:\n self.__hatch_config = self.metadata.hatch.config\n\n return self.__hatch_config\n\n @property\n def config(self) -> BuilderConfigBound:\n \"\"\"\n An instance of [BuilderConfig](../utilities.md#hatchling.builders.config.BuilderConfig).\n \"\"\"\n if self.__config is None:\n self.__config = self.get_config_class()(\n self, self.root, self.PLUGIN_NAME, self.build_config, self.target_config\n )\n\n return self.__config\n\n @property\n def build_config(self) -> dict[str, Any]:\n \"\"\"\n ```toml config-example\n [tool.hatch.build]\n ```\n \"\"\"\n if self.__build_config is None:\n self.__build_config = self.metadata.hatch.build_config\n\n return self.__build_config\n\n @property\n def target_config(self) -> dict[str, Any]:\n \"\"\"\n ```toml config-example\n [tool.hatch.build.targets.<PLUGIN_NAME>]\n ```\n \"\"\"\n if self.__target_config is None:\n target_config: dict[str, Any] = self.metadata.hatch.build_targets.get(self.PLUGIN_NAME, {})\n if not isinstance(target_config, dict):\n message = f'Field `tool.hatch.build.targets.{self.PLUGIN_NAME}` must be a table'\n raise TypeError(message)\n\n self.__target_config = target_config\n\n return self.__target_config\n\n @property\n def project_id(self) -> str:\n if self.__project_id is None:\n self.__project_id = f'{self.normalize_file_name_component(self.metadata.core.name)}-{self.metadata.version}'\n\n return self.__project_id\n\n def get_build_hooks(self, directory: str) -> dict[str, BuildHookInterface]:\n configured_build_hooks = {}\n for hook_name, config in self.config.hook_config.items():\n build_hook = self.plugin_manager.build_hook.get(hook_name)\n if build_hook is None:\n from hatchling.plugin.exceptions import UnknownPluginError\n\n message = f'Unknown build hook: {hook_name}'\n raise UnknownPluginError(message)\n\n configured_build_hooks[hook_name] = build_hook(\n self.root, config, self.config, self.metadata, directory, self.PLUGIN_NAME, self.app\n )\n\n return configured_build_hooks\n\n @abstractmethod\n def get_version_api(self) -> dict[str, Callable]:\n \"\"\"\n A mapping of `str` versions to a callable that is used for building.\n Each callable must have the following signature:\n\n ```python\n def ...(build_dir: str, build_data: dict) -> str:\n ```\n\n The return value must be the absolute path to the built artifact.\n \"\"\"\n\n def get_default_versions(self) -> list[str]:\n \"\"\"\n A list of versions to build when users do not specify any, defaulting to all versions.\n \"\"\"\n return list(self.get_version_api())\n\n def get_default_build_data(self) -> dict[str, Any]: # noqa: PLR6301\n \"\"\"\n A mapping that can be modified by [build hooks](../build-hook/reference.md) to influence the behavior of builds.\n \"\"\"\n return {}\n\n def set_build_data_defaults(self, build_data: dict[str, Any]) -> None: # noqa: PLR6301\n build_data.setdefault('artifacts', [])\n build_data.setdefault('force_include', {})\n\n def clean(self, directory: str, versions: list[str]) -> None:\n \"\"\"\n Called before builds if the `-c`/`--clean` flag was passed to the\n [`build`](../../cli/reference.md#hatch-build) command.\n \"\"\"\n\n @classmethod\n def get_config_class(cls) -> type[BuilderConfig]:\n \"\"\"\n Must return a subclass of [BuilderConfig](../utilities.md#hatchling.builders.config.BuilderConfig).\n \"\"\"\n return BuilderConfig\n\n @staticmethod\n def normalize_file_name_component(file_name: str) -> str:\n \"\"\"\n https://peps.python.org/pep-0427/#escaping-and-unicode\n \"\"\"\n return re.sub(r'[^\\w\\d.]+', '_', file_name, flags=re.UNICODE)\n
"},{"location":"plugins/builder/reference/#hatchling.builders.plugin.interface.BuilderInterface.PLUGIN_NAME","title":"PLUGIN_NAME = ''
class-attribute
instance-attribute
","text":"The name used for selection.
"},{"location":"plugins/builder/reference/#hatchling.builders.plugin.interface.BuilderInterface.app","title":"app: Application
property
","text":"An instance of Application.
"},{"location":"plugins/builder/reference/#hatchling.builders.plugin.interface.BuilderInterface.root","title":"root: str
property
","text":"The root of the project tree.
"},{"location":"plugins/builder/reference/#hatchling.builders.plugin.interface.BuilderInterface.build_config","title":"build_config: dict[str, Any]
property
","text":"pyproject.toml hatch.toml [tool.hatch.build]\n
[build]\n
"},{"location":"plugins/builder/reference/#hatchling.builders.plugin.interface.BuilderInterface.target_config","title":"target_config: dict[str, Any]
property
","text":"pyproject.toml hatch.toml [tool.hatch.build.targets.<PLUGIN_NAME>]\n
[build.targets.<PLUGIN_NAME>]\n
"},{"location":"plugins/builder/reference/#hatchling.builders.plugin.interface.BuilderInterface.config","title":"config: BuilderConfigBound
property
","text":"An instance of BuilderConfig.
"},{"location":"plugins/builder/reference/#hatchling.builders.plugin.interface.BuilderInterface.get_config_class","title":"get_config_class() -> type[BuilderConfig]
classmethod
","text":"Must return a subclass of BuilderConfig.
Source code inbackend/src/hatchling/builders/plugin/interface.py
@classmethod\ndef get_config_class(cls) -> type[BuilderConfig]:\n \"\"\"\n Must return a subclass of [BuilderConfig](../utilities.md#hatchling.builders.config.BuilderConfig).\n \"\"\"\n return BuilderConfig\n
"},{"location":"plugins/builder/reference/#hatchling.builders.plugin.interface.BuilderInterface.get_version_api","title":"get_version_api() -> dict[str, Callable]
abstractmethod
","text":"A mapping of str
versions to a callable that is used for building. Each callable must have the following signature:
def ...(build_dir: str, build_data: dict) -> str:\n
The return value must be the absolute path to the built artifact.
Source code inbackend/src/hatchling/builders/plugin/interface.py
@abstractmethod\ndef get_version_api(self) -> dict[str, Callable]:\n \"\"\"\n A mapping of `str` versions to a callable that is used for building.\n Each callable must have the following signature:\n\n ```python\n def ...(build_dir: str, build_data: dict) -> str:\n ```\n\n The return value must be the absolute path to the built artifact.\n \"\"\"\n
"},{"location":"plugins/builder/reference/#hatchling.builders.plugin.interface.BuilderInterface.get_default_versions","title":"get_default_versions() -> list[str]
","text":"A list of versions to build when users do not specify any, defaulting to all versions.
Source code inbackend/src/hatchling/builders/plugin/interface.py
def get_default_versions(self) -> list[str]:\n \"\"\"\n A list of versions to build when users do not specify any, defaulting to all versions.\n \"\"\"\n return list(self.get_version_api())\n
"},{"location":"plugins/builder/reference/#hatchling.builders.plugin.interface.BuilderInterface.clean","title":"clean(directory: str, versions: list[str]) -> None
","text":"Called before builds if the -c
/--clean
flag was passed to the build
command.
backend/src/hatchling/builders/plugin/interface.py
def clean(self, directory: str, versions: list[str]) -> None:\n \"\"\"\n Called before builds if the `-c`/`--clean` flag was passed to the\n [`build`](../../cli/reference.md#hatch-build) command.\n \"\"\"\n
"},{"location":"plugins/builder/reference/#hatchling.builders.plugin.interface.BuilderInterface.recurse_included_files","title":"recurse_included_files() -> Iterable[IncludedFile]
","text":"Returns a consistently generated series of file objects for every file that should be distributed. Each file object has three str
attributes:
path
- the absolute pathrelative_path
- the path relative to the project root; will be an empty string for external filesdistribution_path
- the path to be distributed asbackend/src/hatchling/builders/plugin/interface.py
def recurse_included_files(self) -> Iterable[IncludedFile]:\n \"\"\"\n Returns a consistently generated series of file objects for every file that should be distributed. Each file\n object has three `str` attributes:\n\n - `path` - the absolute path\n - `relative_path` - the path relative to the project root; will be an empty string for external files\n - `distribution_path` - the path to be distributed as\n \"\"\"\n yield from self.recurse_selected_project_files()\n yield from self.recurse_forced_files(self.config.get_force_include())\n
"},{"location":"plugins/builder/reference/#hatchling.builders.plugin.interface.BuilderInterface.get_default_build_data","title":"get_default_build_data() -> dict[str, Any]
","text":"A mapping that can be modified by build hooks to influence the behavior of builds.
Source code inbackend/src/hatchling/builders/plugin/interface.py
def get_default_build_data(self) -> dict[str, Any]: # noqa: PLR6301\n \"\"\"\n A mapping that can be modified by [build hooks](../build-hook/reference.md) to influence the behavior of builds.\n \"\"\"\n return {}\n
"},{"location":"plugins/builder/sdist/","title":"Source distribution builder","text":"A source distribution, or sdist
, is an archive of Python \"source code\". Although largely unspecified, by convention it should include everything that is required to build a wheel without making network requests.
The builder plugin name is sdist
.
[tool.hatch.build.targets.sdist]\n
[build.targets.sdist]\n
"},{"location":"plugins/builder/sdist/#options","title":"Options","text":"Option Default Description core-metadata-version
\"2.3\"
The version of core metadata to use strict-naming
true
Whether or not file names should contain the normalized version of the project name support-legacy
false
Whether or not to include a setup.py
file to support legacy installation mechanisms"},{"location":"plugins/builder/sdist/#versions","title":"Versions","text":"Version Description standard
(default) The latest conventional format"},{"location":"plugins/builder/sdist/#default-file-selection","title":"Default file selection","text":"When the user has not set any file selection options, all files that are not ignored by your VCS will be included.
Note
The following files are always included and cannot be excluded:
/pyproject.toml
/hatch.toml
/hatch_build.py
/.gitignore
or /.hgignore
readme
filelicense-files
Reproducible builds are supported.
"},{"location":"plugins/builder/sdist/#build-data","title":"Build data","text":"This is data that can be modified by build hooks.
Data Default Descriptiondependencies
Extra project dependencies"},{"location":"plugins/builder/wheel/","title":"Wheel builder","text":"A wheel is a binary distribution of a Python package that can be installed directly into an environment.
"},{"location":"plugins/builder/wheel/#configuration","title":"Configuration","text":"The builder plugin name is wheel
.
[tool.hatch.build.targets.wheel]\n
[build.targets.wheel]\n
"},{"location":"plugins/builder/wheel/#options","title":"Options","text":"Option Default Description core-metadata-version
\"2.3\"
The version of core metadata to use shared-data
A mapping similar to the forced inclusion option corresponding to the data
subdirectory within the standard data directory that will be installed globally in a given Python environment, usually under sys.prefix
shared-scripts
A mapping similar to the forced inclusion option corresponding to the scripts
subdirectory within the standard data directory that will be installed in a given Python environment, usually under Scripts
on Windows or bin
otherwise, and would normally be available on PATH extra-metadata
A mapping similar to the forced inclusion option corresponding to extra metadata that will be shipped in a directory named extra_metadata
strict-naming
true
Whether or not file names should contain the normalized version of the project name macos-max-compat
false
Whether or not on macOS, when build hooks have set the infer_tag
build data, the wheel name should signal broad support rather than specific versions for newer SDK versions.Note: This option will eventually be removed. bypass-selection
false
Whether or not to suppress the error when one has not defined any file selection options and all heuristics have failed to determine what to ship"},{"location":"plugins/builder/wheel/#versions","title":"Versions","text":"Version Description standard
(default) The latest standardized format editable
A wheel that only ships .pth
files or import hooks for real-time development"},{"location":"plugins/builder/wheel/#default-file-selection","title":"Default file selection","text":"When the user has not set any file selection options, the project name will be used to determine the package to ship in the following heuristic order:
<NAME>/__init__.py
src/<NAME>/__init__.py
<NAME>.py
<NAMESPACE>/<NAME>/__init__.py
If none of these heuristics are satisfied, an error will be raised.
"},{"location":"plugins/builder/wheel/#reproducibility","title":"Reproducibility","text":"Reproducible builds are supported.
"},{"location":"plugins/builder/wheel/#build-data","title":"Build data","text":"This is data that can be modified by build hooks.
Data Default Descriptiontag
The full tag part of the filename (e.g. py3-none-any
), defaulting to a cross-platform wheel with the supported major versions of Python based on project metadata infer_tag
False
When tag
is not set, this may be enabled to use the one most specific to the platform, Python interpreter, and ABI pure_python
True
Whether or not to write metadata indicating that the package does not contain any platform-specific files dependencies
Extra project dependencies shared_data
Additional shared-data
entries, which take precedence in case of conflicts shared_scripts
Additional shared-scripts
entries, which take precedence in case of conflicts extra_metadata
Additional extra-metadata
entries, which take precedence in case of conflicts force_include_editable
Similar to the force_include
option but specifically for the editable
version and takes precedence"},{"location":"plugins/environment/reference/","title":"Environment plugins","text":"See the documentation for environment configuration.
"},{"location":"plugins/environment/reference/#known-third-party","title":"Known third-party","text":"Any required environment types that are not built-in must be manually installed alongside Hatch or listed in the tool.hatch.env.requires
array for automatic management:
[tool.hatch.env]\nrequires = [\n \"...\",\n]\n
[env]\nrequires = [\n \"...\",\n]\n
"},{"location":"plugins/environment/reference/#life-cycle","title":"Life cycle","text":"Whenever an environment is used, the following logic is performed:
Source code insrc/hatch/project/core.py
def prepare_environment(self, environment: EnvironmentInterface):\n if not environment.exists():\n self.env_metadata.reset(environment)\n\n with environment.app_status_creation():\n environment.create()\n\n if not environment.skip_install:\n if environment.pre_install_commands:\n with environment.app_status_pre_installation():\n self.app.run_shell_commands(\n ExecutionContext(\n environment,\n shell_commands=environment.pre_install_commands,\n source='pre-install',\n show_code_on_error=True,\n )\n )\n\n with environment.app_status_project_installation():\n if environment.dev_mode:\n environment.install_project_dev_mode()\n else:\n environment.install_project()\n\n if environment.post_install_commands:\n with environment.app_status_post_installation():\n self.app.run_shell_commands(\n ExecutionContext(\n environment,\n shell_commands=environment.post_install_commands,\n source='post-install',\n show_code_on_error=True,\n )\n )\n\n with environment.app_status_dependency_state_check():\n new_dep_hash = environment.dependency_hash()\n\n current_dep_hash = self.env_metadata.dependency_hash(environment)\n if new_dep_hash != current_dep_hash:\n with environment.app_status_dependency_installation_check():\n dependencies_in_sync = environment.dependencies_in_sync()\n\n if not dependencies_in_sync:\n with environment.app_status_dependency_synchronization():\n environment.sync_dependencies()\n new_dep_hash = environment.dependency_hash()\n\n self.env_metadata.update_dependency_hash(environment, new_dep_hash)\n
"},{"location":"plugins/environment/reference/#build-environments","title":"Build environments","text":"All environment types should offer support for synchronized storage between the local file system and the environment. This functionality is used in the following scenarios:
build
commanddep hash
, if any project dependencies are set dynamicallyEnvironmentInterface
","text":"Example usage:
plugin.py hooks.py from hatch.env.plugin.interface import EnvironmentInterface\n\n\n class SpecialEnvironment(EnvironmentInterface):\n PLUGIN_NAME = 'special'\n ...\n
from hatchling.plugin import hookimpl\n\n from .plugin import SpecialEnvironment\n\n\n @hookimpl\n def hatch_register_environment():\n return SpecialEnvironment\n
Source code in src/hatch/env/plugin/interface.py
class EnvironmentInterface(ABC):\n \"\"\"\n Example usage:\n\n ```python tab=\"plugin.py\"\n from hatch.env.plugin.interface import EnvironmentInterface\n\n\n class SpecialEnvironment(EnvironmentInterface):\n PLUGIN_NAME = 'special'\n ...\n ```\n\n ```python tab=\"hooks.py\"\n from hatchling.plugin import hookimpl\n\n from .plugin import SpecialEnvironment\n\n\n @hookimpl\n def hatch_register_environment():\n return SpecialEnvironment\n ```\n \"\"\"\n\n PLUGIN_NAME = ''\n \"\"\"The name used for selection.\"\"\"\n\n def __init__(\n self,\n root,\n metadata,\n name,\n config,\n matrix_variables,\n data_directory,\n isolated_data_directory,\n platform,\n verbosity,\n app,\n ):\n self.__root = root\n self.__metadata = metadata\n self.__name = name\n self.__config = config\n self.__matrix_variables = matrix_variables\n self.__data_directory = data_directory\n self.__isolated_data_directory = isolated_data_directory\n self.__platform = platform\n self.__verbosity = verbosity\n self.__app = app\n\n @property\n def matrix_variables(self):\n return self.__matrix_variables\n\n @property\n def app(self):\n \"\"\"\n An instance of [Application](../utilities.md#hatchling.bridge.app.Application).\n \"\"\"\n return self.__app\n\n @cached_property\n def context(self):\n return self.get_context()\n\n @property\n def verbosity(self):\n return self.__verbosity\n\n @property\n def root(self):\n \"\"\"\n The root of the local project tree as a path-like object.\n \"\"\"\n return self.__root\n\n @property\n def metadata(self):\n return self.__metadata\n\n @property\n def name(self) -> str:\n \"\"\"\n The name of the environment.\n \"\"\"\n return self.__name\n\n @property\n def platform(self):\n \"\"\"\n An instance of [Platform](../utilities.md#hatch.utils.platform.Platform).\n \"\"\"\n return self.__platform\n\n @property\n def data_directory(self):\n \"\"\"\n The [directory](../../config/hatch.md#environments) this plugin should use for storage as a path-like object.\n If the user has not configured one then this will be the same as the\n [isolated data directory](reference.md#hatch.env.plugin.interface.EnvironmentInterface.isolated_data_directory).\n \"\"\"\n return self.__data_directory\n\n @property\n def isolated_data_directory(self):\n \"\"\"\n The default [directory](../../config/hatch.md#environments) reserved exclusively for this plugin as a path-like\n object.\n \"\"\"\n return self.__isolated_data_directory\n\n @property\n def config(self) -> dict:\n \"\"\"\n ```toml config-example\n [tool.hatch.envs.<ENV_NAME>]\n ```\n \"\"\"\n return self.__config\n\n @cached_property\n def project_root(self) -> str:\n \"\"\"\n The root of the project tree as a string. If the environment is not running locally,\n this should be the remote path to the project.\n \"\"\"\n return str(self.root)\n\n @cached_property\n def sep(self) -> str:\n \"\"\"\n The character used to separate directories in paths. By default, this is `\\\\` on Windows and `/` otherwise.\n \"\"\"\n return os.sep\n\n @cached_property\n def pathsep(self) -> str:\n \"\"\"\n The character used to separate paths. By default, this is `;` on Windows and `:` otherwise.\n \"\"\"\n return os.pathsep\n\n @cached_property\n def system_python(self):\n system_python = os.environ.get(AppEnvVars.PYTHON)\n if system_python == 'self':\n system_python = sys.executable\n\n system_python = (\n system_python\n or self.platform.modules.shutil.which('python')\n or self.platform.modules.shutil.which('python3')\n or sys.executable\n )\n if not isabs(system_python):\n system_python = self.platform.modules.shutil.which(system_python)\n\n return system_python\n\n @cached_property\n def env_vars(self) -> dict:\n \"\"\"\n ```toml config-example\n [tool.hatch.envs.<ENV_NAME>.env-vars]\n ```\n \"\"\"\n env_vars = self.config.get('env-vars', {})\n if not isinstance(env_vars, dict):\n message = f'Field `tool.hatch.envs.{self.name}.env-vars` must be a mapping'\n raise TypeError(message)\n\n for key, value in env_vars.items():\n if not isinstance(value, str):\n message = (\n f'Environment variable `{key}` of field `tool.hatch.envs.{self.name}.env-vars` must be a string'\n )\n raise TypeError(message)\n\n new_env_vars = {}\n with self.metadata.context.apply_context(self.context):\n for key, value in env_vars.items():\n new_env_vars[key] = self.metadata.context.format(value)\n\n new_env_vars[AppEnvVars.ENV_ACTIVE] = self.name\n return new_env_vars\n\n @cached_property\n def env_include(self) -> list[str]:\n \"\"\"\n ```toml config-example\n [tool.hatch.envs.<ENV_NAME>]\n env-include = [...]\n ```\n \"\"\"\n env_include = self.config.get('env-include', [])\n if not isinstance(env_include, list):\n message = f'Field `tool.hatch.envs.{self.name}.env-include` must be an array'\n raise TypeError(message)\n\n for i, pattern in enumerate(env_include, 1):\n if not isinstance(pattern, str):\n message = f'Pattern #{i} of field `tool.hatch.envs.{self.name}.env-include` must be a string'\n raise TypeError(message)\n\n return ['HATCH_BUILD_*', *env_include] if env_include else env_include\n\n @cached_property\n def env_exclude(self) -> list[str]:\n \"\"\"\n ```toml config-example\n [tool.hatch.envs.<ENV_NAME>]\n env-exclude = [...]\n ```\n \"\"\"\n env_exclude = self.config.get('env-exclude', [])\n if not isinstance(env_exclude, list):\n message = f'Field `tool.hatch.envs.{self.name}.env-exclude` must be an array'\n raise TypeError(message)\n\n for i, pattern in enumerate(env_exclude, 1):\n if not isinstance(pattern, str):\n message = f'Pattern #{i} of field `tool.hatch.envs.{self.name}.env-exclude` must be a string'\n raise TypeError(message)\n\n return env_exclude\n\n @cached_property\n def environment_dependencies_complex(self):\n from packaging.requirements import InvalidRequirement, Requirement\n\n dependencies_complex = []\n with self.apply_context():\n for option in ('dependencies', 'extra-dependencies'):\n dependencies = self.config.get(option, [])\n if not isinstance(dependencies, list):\n message = f'Field `tool.hatch.envs.{self.name}.{option}` must be an array'\n raise TypeError(message)\n\n for i, entry in enumerate(dependencies, 1):\n if not isinstance(entry, str):\n message = f'Dependency #{i} of field `tool.hatch.envs.{self.name}.{option}` must be a string'\n raise TypeError(message)\n\n try:\n dependencies_complex.append(Requirement(self.metadata.context.format(entry)))\n except InvalidRequirement as e:\n message = f'Dependency #{i} of field `tool.hatch.envs.{self.name}.{option}` is invalid: {e}'\n raise ValueError(message) from None\n\n return dependencies_complex\n\n @cached_property\n def environment_dependencies(self) -> list[str]:\n \"\"\"\n The list of all [environment dependencies](../../config/environment/overview.md#dependencies).\n \"\"\"\n return [str(dependency) for dependency in self.environment_dependencies_complex]\n\n @cached_property\n def dependencies_complex(self):\n all_dependencies_complex = list(self.environment_dependencies_complex)\n if self.builder:\n all_dependencies_complex.extend(self.metadata.build.requires_complex)\n return all_dependencies_complex\n\n # Ensure these are checked last to speed up initial environment creation since\n # they will already be installed along with the project\n if (not self.skip_install and self.dev_mode) or self.features:\n from hatch.utils.dep import get_complex_dependencies, get_complex_features\n\n dependencies, optional_dependencies = self.app.project.get_dependencies()\n dependencies_complex = get_complex_dependencies(dependencies)\n optional_dependencies_complex = get_complex_features(optional_dependencies)\n\n if not self.skip_install and self.dev_mode:\n all_dependencies_complex.extend(dependencies_complex.values())\n\n for feature in self.features:\n if feature not in optional_dependencies_complex:\n message = (\n f'Feature `{feature}` of field `tool.hatch.envs.{self.name}.features` is not '\n f'defined in the dynamic field `project.optional-dependencies`'\n )\n raise ValueError(message)\n\n all_dependencies_complex.extend(optional_dependencies_complex[feature].values())\n\n return all_dependencies_complex\n\n @cached_property\n def dependencies(self) -> list[str]:\n \"\"\"\n The list of all [project dependencies](../../config/metadata.md#dependencies) (if\n [installed](../../config/environment/overview.md#skip-install) and in\n [dev mode](../../config/environment/overview.md#dev-mode)), selected\n [optional dependencies](../../config/environment/overview.md#features), and\n [environment dependencies](../../config/environment/overview.md#dependencies).\n \"\"\"\n return [str(dependency) for dependency in self.dependencies_complex]\n\n @cached_property\n def platforms(self) -> list[str]:\n \"\"\"\n All names are stored as their lower-cased version.\n\n ```toml config-example\n [tool.hatch.envs.<ENV_NAME>]\n platforms = [...]\n ```\n \"\"\"\n platforms = self.config.get('platforms', [])\n if not isinstance(platforms, list):\n message = f'Field `tool.hatch.envs.{self.name}.platforms` must be an array'\n raise TypeError(message)\n\n for i, command in enumerate(platforms, 1):\n if not isinstance(command, str):\n message = f'Platform #{i} of field `tool.hatch.envs.{self.name}.platforms` must be a string'\n raise TypeError(message)\n\n return [platform.lower() for platform in platforms]\n\n @cached_property\n def skip_install(self) -> bool:\n \"\"\"\n ```toml config-example\n [tool.hatch.envs.<ENV_NAME>]\n skip-install = ...\n ```\n \"\"\"\n skip_install = self.config.get('skip-install', not self.metadata.has_project_file())\n if not isinstance(skip_install, bool):\n message = f'Field `tool.hatch.envs.{self.name}.skip-install` must be a boolean'\n raise TypeError(message)\n\n return skip_install\n\n @cached_property\n def dev_mode(self) -> bool:\n \"\"\"\n ```toml config-example\n [tool.hatch.envs.<ENV_NAME>]\n dev-mode = ...\n ```\n \"\"\"\n dev_mode = self.config.get('dev-mode', True)\n if not isinstance(dev_mode, bool):\n message = f'Field `tool.hatch.envs.{self.name}.dev-mode` must be a boolean'\n raise TypeError(message)\n\n return dev_mode\n\n @cached_property\n def builder(self) -> bool:\n \"\"\"\n ```toml config-example\n [tool.hatch.envs.<ENV_NAME>]\n builder = ...\n ```\n \"\"\"\n builder = self.config.get('builder', False)\n if not isinstance(builder, bool):\n message = f'Field `tool.hatch.envs.{self.name}.builder` must be a boolean'\n raise TypeError(message)\n\n return builder\n\n @cached_property\n def features(self):\n from hatchling.metadata.utils import normalize_project_name\n\n features = self.config.get('features', [])\n if not isinstance(features, list):\n message = f'Field `tool.hatch.envs.{self.name}.features` must be an array of strings'\n raise TypeError(message)\n\n all_features = set()\n for i, feature in enumerate(features, 1):\n if not isinstance(feature, str):\n message = f'Feature #{i} of field `tool.hatch.envs.{self.name}.features` must be a string'\n raise TypeError(message)\n\n if not feature:\n message = f'Feature #{i} of field `tool.hatch.envs.{self.name}.features` cannot be an empty string'\n raise ValueError(message)\n\n normalized_feature = (\n feature if self.metadata.hatch.metadata.allow_ambiguous_features else normalize_project_name(feature)\n )\n if (\n not self.metadata.hatch.metadata.hook_config\n and normalized_feature not in self.metadata.core.optional_dependencies\n ):\n message = (\n f'Feature `{normalized_feature}` of field `tool.hatch.envs.{self.name}.features` is not '\n f'defined in field `project.optional-dependencies`'\n )\n raise ValueError(message)\n\n all_features.add(normalized_feature)\n\n return sorted(all_features)\n\n @cached_property\n def description(self) -> str:\n \"\"\"\n ```toml config-example\n [tool.hatch.envs.<ENV_NAME>]\n description = ...\n ```\n \"\"\"\n description = self.config.get('description', '')\n if not isinstance(description, str):\n message = f'Field `tool.hatch.envs.{self.name}.description` must be a string'\n raise TypeError(message)\n\n return description\n\n @cached_property\n def scripts(self):\n config = {}\n\n # Extra scripts should come first to give less precedence\n for field in ('extra-scripts', 'scripts'):\n script_config = self.config.get(field, {})\n if not isinstance(script_config, dict):\n message = f'Field `tool.hatch.envs.{self.name}.{field}` must be a table'\n raise TypeError(message)\n\n for name, data in script_config.items():\n if ' ' in name:\n message = (\n f'Script name `{name}` in field `tool.hatch.envs.{self.name}.{field}` '\n f'must not contain spaces'\n )\n raise ValueError(message)\n\n commands = []\n\n if isinstance(data, str):\n commands.append(data)\n elif isinstance(data, list):\n for i, command in enumerate(data, 1):\n if not isinstance(command, str):\n message = (\n f'Command #{i} in field `tool.hatch.envs.{self.name}.{field}.{name}` '\n f'must be a string'\n )\n raise TypeError(message)\n\n commands.append(command)\n else:\n message = (\n f'Field `tool.hatch.envs.{self.name}.{field}.{name}` must be '\n f'a string or an array of strings'\n )\n raise TypeError(message)\n\n config[name] = commands\n\n seen = {}\n active = []\n for script_name, commands in config.items():\n commands[:] = expand_script_commands(self.name, script_name, commands, config, seen, active)\n\n return config\n\n @cached_property\n def pre_install_commands(self):\n pre_install_commands = self.config.get('pre-install-commands', [])\n if not isinstance(pre_install_commands, list):\n message = f'Field `tool.hatch.envs.{self.name}.pre-install-commands` must be an array'\n raise TypeError(message)\n\n for i, command in enumerate(pre_install_commands, 1):\n if not isinstance(command, str):\n message = f'Command #{i} of field `tool.hatch.envs.{self.name}.pre-install-commands` must be a string'\n raise TypeError(message)\n\n return list(pre_install_commands)\n\n @cached_property\n def post_install_commands(self):\n post_install_commands = self.config.get('post-install-commands', [])\n if not isinstance(post_install_commands, list):\n message = f'Field `tool.hatch.envs.{self.name}.post-install-commands` must be an array'\n raise TypeError(message)\n\n for i, command in enumerate(post_install_commands, 1):\n if not isinstance(command, str):\n message = f'Command #{i} of field `tool.hatch.envs.{self.name}.post-install-commands` must be a string'\n raise TypeError(message)\n\n return list(post_install_commands)\n\n def activate(self):\n \"\"\"\n A convenience method called when using the environment as a context manager:\n\n ```python\n with environment:\n ...\n ```\n \"\"\"\n\n def deactivate(self):\n \"\"\"\n A convenience method called after using the environment as a context manager:\n\n ```python\n with environment:\n ...\n ```\n \"\"\"\n\n @abstractmethod\n def find(self):\n \"\"\"\n :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n This should return information about how to locate the environment or represent its ID in\n some way. Additionally, this is expected to return something even if the environment is\n [incompatible](reference.md#hatch.env.plugin.interface.EnvironmentInterface.check_compatibility).\n \"\"\"\n\n @abstractmethod\n def create(self):\n \"\"\"\n :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n This should perform the necessary steps to set up the environment.\n \"\"\"\n\n @abstractmethod\n def remove(self):\n \"\"\"\n :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n This should perform the necessary steps to completely remove the environment from the system and will only\n be triggered manually by users with the [`env remove`](../../cli/reference.md#hatch-env-remove) or\n [`env prune`](../../cli/reference.md#hatch-env-prune) commands.\n \"\"\"\n\n @abstractmethod\n def exists(self) -> bool:\n \"\"\"\n :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n This should indicate whether or not the environment has already been created.\n \"\"\"\n\n @abstractmethod\n def install_project(self):\n \"\"\"\n :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n This should install the project in the environment.\n \"\"\"\n\n @abstractmethod\n def install_project_dev_mode(self):\n \"\"\"\n :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n This should install the project in the environment such that the environment\n always reflects the current state of the project.\n \"\"\"\n\n @abstractmethod\n def dependencies_in_sync(self) -> bool:\n \"\"\"\n :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n This should indicate whether or not the environment is compatible with the current\n [dependencies](reference.md#hatch.env.plugin.interface.EnvironmentInterface.dependencies).\n \"\"\"\n\n @abstractmethod\n def sync_dependencies(self):\n \"\"\"\n :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n This should install the\n [dependencies](reference.md#hatch.env.plugin.interface.EnvironmentInterface.dependencies)\n in the environment.\n \"\"\"\n\n def dependency_hash(self):\n \"\"\"\n This should return a hash of the environment's\n [dependencies](reference.md#hatch.env.plugin.interface.EnvironmentInterface.dependencies)\n and any other data that is handled by the\n [sync_dependencies](reference.md#hatch.env.plugin.interface.EnvironmentInterface.sync_dependencies)\n and\n [dependencies_in_sync](reference.md#hatch.env.plugin.interface.EnvironmentInterface.dependencies_in_sync)\n methods.\n \"\"\"\n from hatch.utils.dep import hash_dependencies\n\n return hash_dependencies(self.dependencies_complex)\n\n @contextmanager\n def app_status_creation(self):\n \"\"\"\n See the [life cycle of environments](reference.md#life-cycle).\n \"\"\"\n with self.app.status(f'Creating environment: {self.name}'):\n yield\n\n @contextmanager\n def app_status_pre_installation(self):\n \"\"\"\n See the [life cycle of environments](reference.md#life-cycle).\n \"\"\"\n with self.app.status('Running pre-installation commands'):\n yield\n\n @contextmanager\n def app_status_post_installation(self):\n \"\"\"\n See the [life cycle of environments](reference.md#life-cycle).\n \"\"\"\n with self.app.status('Running post-installation commands'):\n yield\n\n @contextmanager\n def app_status_project_installation(self):\n \"\"\"\n See the [life cycle of environments](reference.md#life-cycle).\n \"\"\"\n if self.dev_mode:\n with self.app.status('Installing project in development mode'):\n yield\n else:\n with self.app.status('Installing project'):\n yield\n\n @contextmanager\n def app_status_dependency_state_check(self):\n \"\"\"\n See the [life cycle of environments](reference.md#life-cycle).\n \"\"\"\n if not self.skip_install and (\n 'dependencies' in self.metadata.dynamic or 'optional-dependencies' in self.metadata.dynamic\n ):\n with self.app.status('Polling dependency state'):\n yield\n else:\n yield\n\n @contextmanager\n def app_status_dependency_installation_check(self):\n \"\"\"\n See the [life cycle of environments](reference.md#life-cycle).\n \"\"\"\n with self.app.status('Checking dependencies'):\n yield\n\n @contextmanager\n def app_status_dependency_synchronization(self):\n \"\"\"\n See the [life cycle of environments](reference.md#life-cycle).\n \"\"\"\n with self.app.status('Syncing dependencies'):\n yield\n\n @contextmanager\n def fs_context(self) -> Generator[FileSystemContext, None, None]:\n \"\"\"\n A context manager that must yield a subclass of\n [FileSystemContext](../utilities.md#hatch.env.plugin.interface.FileSystemContext).\n \"\"\"\n from hatch.utils.fs import temp_directory\n\n with temp_directory() as temp_dir:\n yield FileSystemContext(self, local_path=temp_dir, env_path=str(temp_dir))\n\n def enter_shell(\n self,\n name: str, # noqa: ARG002\n path: str,\n args: Iterable[str],\n ):\n \"\"\"\n Spawn a [shell](../../config/hatch.md#shell) within the environment.\n\n This should either use\n [command_context](reference.md#hatch.env.plugin.interface.EnvironmentInterface.command_context)\n directly or provide the same guarantee.\n \"\"\"\n with self.command_context():\n self.platform.exit_with_command([path, *args])\n\n def run_shell_command(self, command: str, **kwargs):\n \"\"\"\n This should return the standard library's\n [subprocess.CompletedProcess](https://docs.python.org/3/library/subprocess.html#subprocess.CompletedProcess)\n and will always be called when the\n [command_context](reference.md#hatch.env.plugin.interface.EnvironmentInterface.command_context)\n is active, with the expectation of providing the same guarantee.\n \"\"\"\n kwargs.setdefault('shell', True)\n return self.platform.run_command(command, **kwargs)\n\n @contextmanager\n def command_context(self):\n \"\"\"\n A context manager that when active should make executed shell commands reflect any\n [environment variables](reference.md#hatch.env.plugin.interface.EnvironmentInterface.get_env_vars)\n the user defined either currently or at the time of\n [creation](reference.md#hatch.env.plugin.interface.EnvironmentInterface.create).\n\n For an example, open the default implementation below:\n \"\"\"\n with self.get_env_vars():\n yield\n\n def resolve_commands(self, commands: list[str]):\n \"\"\"\n This expands each command into one or more commands based on any\n [scripts](../../config/environment/overview.md#scripts) that the user defined.\n \"\"\"\n for command in commands:\n yield from self.expand_command(command)\n\n def expand_command(self, command):\n possible_script, args, _ignore_exit_code = parse_script_command(command)\n\n # Indicate undefined\n if not args:\n args = None\n\n with self.apply_context():\n if possible_script in self.scripts:\n if args is not None:\n args = self.metadata.context.format(args)\n\n for cmd in self.scripts[possible_script]:\n yield self.metadata.context.format(cmd, args=args).strip()\n else:\n yield self.metadata.context.format(command, args=args).strip()\n\n def construct_pip_install_command(self, args: list[str]):\n \"\"\"\n A convenience method for constructing a [`pip install`](https://pip.pypa.io/en/stable/cli/pip_install/)\n command with the given verbosity. The default verbosity is set to one less than Hatch's verbosity.\n \"\"\"\n command = ['python', '-u', '-m', 'pip', 'install', '--disable-pip-version-check', '--no-python-version-warning']\n\n # Default to -1 verbosity\n add_verbosity_flag(command, self.verbosity, adjustment=-1)\n\n command.extend(args)\n return command\n\n def join_command_args(self, args: list[str]):\n \"\"\"\n This is used by the [`run`](../../cli/reference.md#hatch-run) command to construct the root command string\n from the received arguments.\n \"\"\"\n return self.platform.join_command_args(args)\n\n def apply_features(self, requirement: str):\n \"\"\"\n A convenience method that applies any user defined [features](../../config/environment/overview.md#features)\n to the given requirement.\n \"\"\"\n if self.features:\n features = ','.join(self.features)\n return f'{requirement}[{features}]'\n\n return requirement\n\n def check_compatibility(self):\n \"\"\"\n This raises an exception if the environment is not compatible with the user's setup. The default behavior\n checks for [platform compatibility](../../config/environment/overview.md#supported-platforms)\n and any method override should keep this check.\n\n This check is never performed if the environment has been\n [created](reference.md#hatch.env.plugin.interface.EnvironmentInterface.create).\n \"\"\"\n if self.platforms and self.platform.name not in self.platforms:\n message = 'unsupported platform'\n raise OSError(message)\n\n def get_env_vars(self) -> EnvVars:\n \"\"\"\n Returns a mapping of environment variables that should be available to the environment. The object can\n be used as a context manager to temporarily apply the environment variables to the current process.\n\n !!! note\n The environment variable `HATCH_ENV_ACTIVE` will always be set to the name of the environment.\n \"\"\"\n return EnvVars(self.env_vars, self.env_include, self.env_exclude)\n\n def get_env_var_option(self, option: str) -> str:\n \"\"\"\n Returns the value of the upper-cased environment variable `HATCH_ENV_TYPE_<PLUGIN_NAME>_<option>`.\n \"\"\"\n return get_env_var_option(plugin_name=self.PLUGIN_NAME, option=option)\n\n def get_context(self):\n \"\"\"\n Returns a subclass of\n [EnvironmentContextFormatter](../utilities.md#hatch.env.context.EnvironmentContextFormatter).\n \"\"\"\n from hatch.env.context import EnvironmentContextFormatter\n\n return EnvironmentContextFormatter(self)\n\n @staticmethod\n def get_option_types() -> dict:\n \"\"\"\n Returns a mapping of supported options to their respective types so that they can be used by\n [overrides](../../config/environment/advanced.md#option-overrides).\n \"\"\"\n return {}\n\n @contextmanager\n def apply_context(self):\n with self.get_env_vars(), self.metadata.context.apply_context(self.context):\n yield\n\n def __enter__(self):\n self.activate()\n return self\n\n def __exit__(self, exc_type, exc_value, traceback):\n self.deactivate()\n
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.PLUGIN_NAME","title":"PLUGIN_NAME = ''
class-attribute
instance-attribute
","text":"The name used for selection.
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.project_root","title":"project_root: str
cached
property
","text":"The root of the project tree as a string. If the environment is not running locally, this should be the remote path to the project.
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.sep","title":"sep: str
cached
property
","text":"The character used to separate directories in paths. By default, this is \\
on Windows and /
otherwise.
pathsep: str
cached
property
","text":"The character used to separate paths. By default, this is ;
on Windows and :
otherwise.
app
property
","text":"An instance of Application.
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.root","title":"root
property
","text":"The root of the local project tree as a path-like object.
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.name","title":"name: str
property
","text":"The name of the environment.
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.data_directory","title":"data_directory
property
","text":"The directory this plugin should use for storage as a path-like object. If the user has not configured one then this will be the same as the isolated data directory.
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.isolated_data_directory","title":"isolated_data_directory
property
","text":"The default directory reserved exclusively for this plugin as a path-like object.
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.config","title":"config: dict
property
","text":"pyproject.toml hatch.toml [tool.hatch.envs.<ENV_NAME>]\n
[envs.<ENV_NAME>]\n
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.platform","title":"platform
property
","text":"An instance of Platform.
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.environment_dependencies","title":"environment_dependencies: list[str]
cached
property
","text":"The list of all environment dependencies.
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.dependencies","title":"dependencies: list[str]
cached
property
","text":"The list of all project dependencies (if installed and in dev mode), selected optional dependencies, and environment dependencies.
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.env_vars","title":"env_vars: dict
cached
property
","text":"pyproject.toml hatch.toml [tool.hatch.envs.<ENV_NAME>.env-vars]\n
[envs.<ENV_NAME>.env-vars]\n
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.env_include","title":"env_include: list[str]
cached
property
","text":"pyproject.toml hatch.toml [tool.hatch.envs.<ENV_NAME>]\nenv-include = [...]\n
[envs.<ENV_NAME>]\nenv-include = [...]\n
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.env_exclude","title":"env_exclude: list[str]
cached
property
","text":"pyproject.toml hatch.toml [tool.hatch.envs.<ENV_NAME>]\nenv-exclude = [...]\n
[envs.<ENV_NAME>]\nenv-exclude = [...]\n
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.platforms","title":"platforms: list[str]
cached
property
","text":"All names are stored as their lower-cased version.
pyproject.toml hatch.toml[tool.hatch.envs.<ENV_NAME>]\nplatforms = [...]\n
[envs.<ENV_NAME>]\nplatforms = [...]\n
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.skip_install","title":"skip_install: bool
cached
property
","text":"pyproject.toml hatch.toml [tool.hatch.envs.<ENV_NAME>]\nskip-install = ...\n
[envs.<ENV_NAME>]\nskip-install = ...\n
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.dev_mode","title":"dev_mode: bool
cached
property
","text":"pyproject.toml hatch.toml [tool.hatch.envs.<ENV_NAME>]\ndev-mode = ...\n
[envs.<ENV_NAME>]\ndev-mode = ...\n
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.description","title":"description: str
cached
property
","text":"pyproject.toml hatch.toml [tool.hatch.envs.<ENV_NAME>]\ndescription = ...\n
[envs.<ENV_NAME>]\ndescription = ...\n
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.find","title":"find()
abstractmethod
","text":"REQUIRED
This should return information about how to locate the environment or represent its ID in some way. Additionally, this is expected to return something even if the environment is incompatible.
Source code insrc/hatch/env/plugin/interface.py
@abstractmethod\ndef find(self):\n \"\"\"\n :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n This should return information about how to locate the environment or represent its ID in\n some way. Additionally, this is expected to return something even if the environment is\n [incompatible](reference.md#hatch.env.plugin.interface.EnvironmentInterface.check_compatibility).\n \"\"\"\n
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.create","title":"create()
abstractmethod
","text":"REQUIRED
This should perform the necessary steps to set up the environment.
Source code insrc/hatch/env/plugin/interface.py
@abstractmethod\ndef create(self):\n \"\"\"\n :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n This should perform the necessary steps to set up the environment.\n \"\"\"\n
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.remove","title":"remove()
abstractmethod
","text":"REQUIRED
This should perform the necessary steps to completely remove the environment from the system and will only be triggered manually by users with the env remove
or env prune
commands.
src/hatch/env/plugin/interface.py
@abstractmethod\ndef remove(self):\n \"\"\"\n :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n This should perform the necessary steps to completely remove the environment from the system and will only\n be triggered manually by users with the [`env remove`](../../cli/reference.md#hatch-env-remove) or\n [`env prune`](../../cli/reference.md#hatch-env-prune) commands.\n \"\"\"\n
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.exists","title":"exists() -> bool
abstractmethod
","text":"REQUIRED
This should indicate whether or not the environment has already been created.
Source code insrc/hatch/env/plugin/interface.py
@abstractmethod\ndef exists(self) -> bool:\n \"\"\"\n :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n This should indicate whether or not the environment has already been created.\n \"\"\"\n
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.install_project","title":"install_project()
abstractmethod
","text":"REQUIRED
This should install the project in the environment.
Source code insrc/hatch/env/plugin/interface.py
@abstractmethod\ndef install_project(self):\n \"\"\"\n :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n This should install the project in the environment.\n \"\"\"\n
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.install_project_dev_mode","title":"install_project_dev_mode()
abstractmethod
","text":"REQUIRED
This should install the project in the environment such that the environment always reflects the current state of the project.
Source code insrc/hatch/env/plugin/interface.py
@abstractmethod\ndef install_project_dev_mode(self):\n \"\"\"\n :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n This should install the project in the environment such that the environment\n always reflects the current state of the project.\n \"\"\"\n
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.dependencies_in_sync","title":"dependencies_in_sync() -> bool
abstractmethod
","text":"REQUIRED
This should indicate whether or not the environment is compatible with the current dependencies.
Source code insrc/hatch/env/plugin/interface.py
@abstractmethod\ndef dependencies_in_sync(self) -> bool:\n \"\"\"\n :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n This should indicate whether or not the environment is compatible with the current\n [dependencies](reference.md#hatch.env.plugin.interface.EnvironmentInterface.dependencies).\n \"\"\"\n
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.sync_dependencies","title":"sync_dependencies()
abstractmethod
","text":"REQUIRED
This should install the dependencies in the environment.
Source code insrc/hatch/env/plugin/interface.py
@abstractmethod\ndef sync_dependencies(self):\n \"\"\"\n :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n This should install the\n [dependencies](reference.md#hatch.env.plugin.interface.EnvironmentInterface.dependencies)\n in the environment.\n \"\"\"\n
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.dependency_hash","title":"dependency_hash()
","text":"This should return a hash of the environment's dependencies and any other data that is handled by the sync_dependencies and dependencies_in_sync methods.
Source code insrc/hatch/env/plugin/interface.py
def dependency_hash(self):\n \"\"\"\n This should return a hash of the environment's\n [dependencies](reference.md#hatch.env.plugin.interface.EnvironmentInterface.dependencies)\n and any other data that is handled by the\n [sync_dependencies](reference.md#hatch.env.plugin.interface.EnvironmentInterface.sync_dependencies)\n and\n [dependencies_in_sync](reference.md#hatch.env.plugin.interface.EnvironmentInterface.dependencies_in_sync)\n methods.\n \"\"\"\n from hatch.utils.dep import hash_dependencies\n\n return hash_dependencies(self.dependencies_complex)\n
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.fs_context","title":"fs_context() -> Generator[FileSystemContext, None, None]
","text":"A context manager that must yield a subclass of FileSystemContext.
Source code insrc/hatch/env/plugin/interface.py
@contextmanager\ndef fs_context(self) -> Generator[FileSystemContext, None, None]:\n \"\"\"\n A context manager that must yield a subclass of\n [FileSystemContext](../utilities.md#hatch.env.plugin.interface.FileSystemContext).\n \"\"\"\n from hatch.utils.fs import temp_directory\n\n with temp_directory() as temp_dir:\n yield FileSystemContext(self, local_path=temp_dir, env_path=str(temp_dir))\n
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.activate","title":"activate()
","text":"A convenience method called when using the environment as a context manager:
with environment:\n ...\n
Source code in src/hatch/env/plugin/interface.py
def activate(self):\n \"\"\"\n A convenience method called when using the environment as a context manager:\n\n ```python\n with environment:\n ...\n ```\n \"\"\"\n
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.deactivate","title":"deactivate()
","text":"A convenience method called after using the environment as a context manager:
with environment:\n ...\n
Source code in src/hatch/env/plugin/interface.py
def deactivate(self):\n \"\"\"\n A convenience method called after using the environment as a context manager:\n\n ```python\n with environment:\n ...\n ```\n \"\"\"\n
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.app_status_creation","title":"app_status_creation()
","text":"See the life cycle of environments.
Source code insrc/hatch/env/plugin/interface.py
@contextmanager\ndef app_status_creation(self):\n \"\"\"\n See the [life cycle of environments](reference.md#life-cycle).\n \"\"\"\n with self.app.status(f'Creating environment: {self.name}'):\n yield\n
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.app_status_pre_installation","title":"app_status_pre_installation()
","text":"See the life cycle of environments.
Source code insrc/hatch/env/plugin/interface.py
@contextmanager\ndef app_status_pre_installation(self):\n \"\"\"\n See the [life cycle of environments](reference.md#life-cycle).\n \"\"\"\n with self.app.status('Running pre-installation commands'):\n yield\n
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.app_status_post_installation","title":"app_status_post_installation()
","text":"See the life cycle of environments.
Source code insrc/hatch/env/plugin/interface.py
@contextmanager\ndef app_status_post_installation(self):\n \"\"\"\n See the [life cycle of environments](reference.md#life-cycle).\n \"\"\"\n with self.app.status('Running post-installation commands'):\n yield\n
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.app_status_project_installation","title":"app_status_project_installation()
","text":"See the life cycle of environments.
Source code insrc/hatch/env/plugin/interface.py
@contextmanager\ndef app_status_project_installation(self):\n \"\"\"\n See the [life cycle of environments](reference.md#life-cycle).\n \"\"\"\n if self.dev_mode:\n with self.app.status('Installing project in development mode'):\n yield\n else:\n with self.app.status('Installing project'):\n yield\n
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.app_status_dependency_state_check","title":"app_status_dependency_state_check()
","text":"See the life cycle of environments.
Source code insrc/hatch/env/plugin/interface.py
@contextmanager\ndef app_status_dependency_state_check(self):\n \"\"\"\n See the [life cycle of environments](reference.md#life-cycle).\n \"\"\"\n if not self.skip_install and (\n 'dependencies' in self.metadata.dynamic or 'optional-dependencies' in self.metadata.dynamic\n ):\n with self.app.status('Polling dependency state'):\n yield\n else:\n yield\n
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.app_status_dependency_installation_check","title":"app_status_dependency_installation_check()
","text":"See the life cycle of environments.
Source code insrc/hatch/env/plugin/interface.py
@contextmanager\ndef app_status_dependency_installation_check(self):\n \"\"\"\n See the [life cycle of environments](reference.md#life-cycle).\n \"\"\"\n with self.app.status('Checking dependencies'):\n yield\n
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.app_status_dependency_synchronization","title":"app_status_dependency_synchronization()
","text":"See the life cycle of environments.
Source code insrc/hatch/env/plugin/interface.py
@contextmanager\ndef app_status_dependency_synchronization(self):\n \"\"\"\n See the [life cycle of environments](reference.md#life-cycle).\n \"\"\"\n with self.app.status('Syncing dependencies'):\n yield\n
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.command_context","title":"command_context()
","text":"A context manager that when active should make executed shell commands reflect any environment variables the user defined either currently or at the time of creation.
For an example, open the default implementation below:
Source code insrc/hatch/env/plugin/interface.py
@contextmanager\ndef command_context(self):\n \"\"\"\n A context manager that when active should make executed shell commands reflect any\n [environment variables](reference.md#hatch.env.plugin.interface.EnvironmentInterface.get_env_vars)\n the user defined either currently or at the time of\n [creation](reference.md#hatch.env.plugin.interface.EnvironmentInterface.create).\n\n For an example, open the default implementation below:\n \"\"\"\n with self.get_env_vars():\n yield\n
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.enter_shell","title":"enter_shell(name: str, path: str, args: Iterable[str])
","text":"Spawn a shell within the environment.
This should either use command_context directly or provide the same guarantee.
Source code insrc/hatch/env/plugin/interface.py
def enter_shell(\n self,\n name: str, # noqa: ARG002\n path: str,\n args: Iterable[str],\n):\n \"\"\"\n Spawn a [shell](../../config/hatch.md#shell) within the environment.\n\n This should either use\n [command_context](reference.md#hatch.env.plugin.interface.EnvironmentInterface.command_context)\n directly or provide the same guarantee.\n \"\"\"\n with self.command_context():\n self.platform.exit_with_command([path, *args])\n
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.run_shell_command","title":"run_shell_command(command: str, **kwargs)
","text":"This should return the standard library's subprocess.CompletedProcess and will always be called when the command_context is active, with the expectation of providing the same guarantee.
Source code insrc/hatch/env/plugin/interface.py
def run_shell_command(self, command: str, **kwargs):\n \"\"\"\n This should return the standard library's\n [subprocess.CompletedProcess](https://docs.python.org/3/library/subprocess.html#subprocess.CompletedProcess)\n and will always be called when the\n [command_context](reference.md#hatch.env.plugin.interface.EnvironmentInterface.command_context)\n is active, with the expectation of providing the same guarantee.\n \"\"\"\n kwargs.setdefault('shell', True)\n return self.platform.run_command(command, **kwargs)\n
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.resolve_commands","title":"resolve_commands(commands: list[str])
","text":"This expands each command into one or more commands based on any scripts that the user defined.
Source code insrc/hatch/env/plugin/interface.py
def resolve_commands(self, commands: list[str]):\n \"\"\"\n This expands each command into one or more commands based on any\n [scripts](../../config/environment/overview.md#scripts) that the user defined.\n \"\"\"\n for command in commands:\n yield from self.expand_command(command)\n
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.get_env_vars","title":"get_env_vars() -> EnvVars
","text":"Returns a mapping of environment variables that should be available to the environment. The object can be used as a context manager to temporarily apply the environment variables to the current process.
Note
The environment variable HATCH_ENV_ACTIVE
will always be set to the name of the environment.
src/hatch/env/plugin/interface.py
def get_env_vars(self) -> EnvVars:\n \"\"\"\n Returns a mapping of environment variables that should be available to the environment. The object can\n be used as a context manager to temporarily apply the environment variables to the current process.\n\n !!! note\n The environment variable `HATCH_ENV_ACTIVE` will always be set to the name of the environment.\n \"\"\"\n return EnvVars(self.env_vars, self.env_include, self.env_exclude)\n
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.apply_features","title":"apply_features(requirement: str)
","text":"A convenience method that applies any user defined features to the given requirement.
Source code insrc/hatch/env/plugin/interface.py
def apply_features(self, requirement: str):\n \"\"\"\n A convenience method that applies any user defined [features](../../config/environment/overview.md#features)\n to the given requirement.\n \"\"\"\n if self.features:\n features = ','.join(self.features)\n return f'{requirement}[{features}]'\n\n return requirement\n
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.construct_pip_install_command","title":"construct_pip_install_command(args: list[str])
","text":"A convenience method for constructing a pip install
command with the given verbosity. The default verbosity is set to one less than Hatch's verbosity.
src/hatch/env/plugin/interface.py
def construct_pip_install_command(self, args: list[str]):\n \"\"\"\n A convenience method for constructing a [`pip install`](https://pip.pypa.io/en/stable/cli/pip_install/)\n command with the given verbosity. The default verbosity is set to one less than Hatch's verbosity.\n \"\"\"\n command = ['python', '-u', '-m', 'pip', 'install', '--disable-pip-version-check', '--no-python-version-warning']\n\n # Default to -1 verbosity\n add_verbosity_flag(command, self.verbosity, adjustment=-1)\n\n command.extend(args)\n return command\n
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.join_command_args","title":"join_command_args(args: list[str])
","text":"This is used by the run
command to construct the root command string from the received arguments.
src/hatch/env/plugin/interface.py
def join_command_args(self, args: list[str]):\n \"\"\"\n This is used by the [`run`](../../cli/reference.md#hatch-run) command to construct the root command string\n from the received arguments.\n \"\"\"\n return self.platform.join_command_args(args)\n
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.check_compatibility","title":"check_compatibility()
","text":"This raises an exception if the environment is not compatible with the user's setup. The default behavior checks for platform compatibility and any method override should keep this check.
This check is never performed if the environment has been created.
Source code insrc/hatch/env/plugin/interface.py
def check_compatibility(self):\n \"\"\"\n This raises an exception if the environment is not compatible with the user's setup. The default behavior\n checks for [platform compatibility](../../config/environment/overview.md#supported-platforms)\n and any method override should keep this check.\n\n This check is never performed if the environment has been\n [created](reference.md#hatch.env.plugin.interface.EnvironmentInterface.create).\n \"\"\"\n if self.platforms and self.platform.name not in self.platforms:\n message = 'unsupported platform'\n raise OSError(message)\n
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.get_option_types","title":"get_option_types() -> dict
staticmethod
","text":"Returns a mapping of supported options to their respective types so that they can be used by overrides.
Source code insrc/hatch/env/plugin/interface.py
@staticmethod\ndef get_option_types() -> dict:\n \"\"\"\n Returns a mapping of supported options to their respective types so that they can be used by\n [overrides](../../config/environment/advanced.md#option-overrides).\n \"\"\"\n return {}\n
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.get_env_var_option","title":"get_env_var_option(option: str) -> str
","text":"Returns the value of the upper-cased environment variable HATCH_ENV_TYPE_<PLUGIN_NAME>_<option>
.
src/hatch/env/plugin/interface.py
def get_env_var_option(self, option: str) -> str:\n \"\"\"\n Returns the value of the upper-cased environment variable `HATCH_ENV_TYPE_<PLUGIN_NAME>_<option>`.\n \"\"\"\n return get_env_var_option(plugin_name=self.PLUGIN_NAME, option=option)\n
"},{"location":"plugins/environment/reference/#hatch.env.plugin.interface.EnvironmentInterface.get_context","title":"get_context()
","text":"Returns a subclass of EnvironmentContextFormatter.
Source code insrc/hatch/env/plugin/interface.py
def get_context(self):\n \"\"\"\n Returns a subclass of\n [EnvironmentContextFormatter](../utilities.md#hatch.env.context.EnvironmentContextFormatter).\n \"\"\"\n from hatch.env.context import EnvironmentContextFormatter\n\n return EnvironmentContextFormatter(self)\n
"},{"location":"plugins/environment/virtual/","title":"Virtual environment","text":"This uses virtual environments backed by virtualenv or UV.
"},{"location":"plugins/environment/virtual/#configuration","title":"Configuration","text":"The environment plugin name is virtual
.
[tool.hatch.envs.<ENV_NAME>]\ntype = \"virtual\"\n
[envs.<ENV_NAME>]\ntype = \"virtual\"\n
"},{"location":"plugins/environment/virtual/#options","title":"Options","text":"Option Default Description python
The version of Python to find on your system and subsequently use to create the environment, defaulting to the HATCH_PYTHON
environment variable, followed by the normal resolution logic. Setting the HATCH_PYTHON
environment variable to self
will force the use of the Python executable Hatch is running on. For more information, see the documentation. python-sources
['external', 'internal']
This may be set to an array of strings that are either the literal internal
or external
. External considers only Python executables that are already on PATH
. Internal considers only internally managed Python distributions. path
An explicit path to the virtual environment. The path may be absolute or relative to the project root. Any environments that inherit this option will also use this path. The environment variable HATCH_ENV_TYPE_VIRTUAL_PATH
may be used, which will take precedence. system-packages
false
Whether or not to give the virtual environment access to the system site-packages
directory installer
pip
When set to uv
, UV will be used in place of virtualenv & pip for virtual environment creation and dependency management, respectively. If you intend to provide UV yourself, you may set the HATCH_ENV_TYPE_VIRTUAL_UV_PATH
environment variable which should be the absolute path to a UV binary. This environment variable implicitly sets the installer
option to uv
(if unset)."},{"location":"plugins/environment/virtual/#location","title":"Location","text":"The location of environments is determined in the following heuristic order:
path
optionvirtual
environment directory if the directory resides somewhere within the project root or if it is set to a .virtualenvs
directory within the user's home directoryvirtual
environment directory in a deeply nested structure in order to support multiple projectsAdditionally, when the path
option is not used, the name of the directory for the default
environment will be the normalized project name to provide a more meaningful default shell prompt.
Virtual environments necessarily require a parent installation of Python. The following rules determine how the parent is resolved.
The Python choice is determined by the python
option followed by the HATCH_PYTHON
environment variable. If the choice is via the environment variable, then resolution stops and that path is used unconditionally.
The resolvers will be based on the python-sources
option and all resolved interpreters will ensure compatibility with the project's defined Python support.
If a Python version has been chosen then each resolver will try to find an interpreter that satisfies that version.
If no version has been chosen, then each resolver will try to find a version that matches the version of Python that Hatch is currently running on. If not found then each resolver will try to find the highest compatible version.
Note
Some external Python paths are considered unstable and are ignored during resolution. For example, if Hatch is installed via Homebrew then sys.executable
will be ignored because the interpreter could change or be removed at any time.
Note
When resolution finds a match using an internally managed distribution and an update is available, the latest distribution will automatically be downloaded before environment creation.
"},{"location":"plugins/environment/virtual/#internal-distributions","title":"Internal distributions","text":"The following options are recognized for internal Python resolution.
Tip
You can set custom sources for distributions by setting the HATCH_PYTHON_SOURCE_<NAME>
environment variable where <NAME>
is the uppercased version of the distribution name with periods replaced by underscores e.g. HATCH_PYTHON_SOURCE_PYPY3_10
.
3.7
3.8
3.9
3.10
3.11
3.12
The source of distributions is the python-build-standalone project.
Some distributions have variants that may be configured with the HATCH_PYTHON_VARIANT_<PLATFORM>
environment variable where <PLATFORM>
is the uppercase version of one of the following:
v1
v2
v3
(default)v4
shared
(default)static
pypy2.7
pypy3.9
pypy3.10
The source of distributions is the PyPy project.
"},{"location":"plugins/environment/virtual/#troubleshooting","title":"Troubleshooting","text":""},{"location":"plugins/environment/virtual/#macos-sip","title":"macOS SIP","text":"If you need to set linker environment variables like those starting with DYLD_
or LD_
, any executable secured by System Integrity Protection that is invoked when running commands will not see those environment variable modifications as macOS strips those.
Hatch interprets such commands as shell commands but deliberately ignores such paths to protected shells. This workaround suffices for the majority of use cases but there are 2 situations in which it may not:
sh
, bash
, zsh
, nor fish
executables found along PATH.pip
and other installers will create such an entry point with a shebang pointing to /bin/sh
(which is protected) to avoid shebang limitations. Rather than changing the location, you could invoke the script as e.g. python -m pytest
(if the project supports that method of invocation by shipping a __main__.py
).The shebang length limit is usually 127 but 3 characters surround the executable path: #!<EXE_PATH>\\n
\u21a9
This is a custom class in a given Python file that inherits from the EnvironmentCollectorInterface.
"},{"location":"plugins/environment-collector/custom/#configuration","title":"Configuration","text":"The environment collector plugin name is custom
.
[tool.hatch.env.collectors.custom]\n
[env.collectors.custom]\n
"},{"location":"plugins/environment-collector/custom/#options","title":"Options","text":"Option Default Description path
hatch_plugins.py
The path of the Python file"},{"location":"plugins/environment-collector/custom/#example","title":"Example","text":"hatch_plugins.py from hatch.env.collectors.plugin.interface import EnvironmentCollectorInterface\n\n\n class CustomEnvironmentCollector(EnvironmentCollectorInterface):\n ...\n
If multiple subclasses are found, you must define a function named get_environment_collector
that returns the desired environment collector.
Note
Any defined PLUGIN_NAME is ignored and will always be custom
.
This adds the default
environment with type set to virtual and will always be applied.
The environment collector plugin name is default
.
[tool.hatch.env.collectors.default]\n
[env.collectors.default]\n
"},{"location":"plugins/environment-collector/default/#options","title":"Options","text":"There are no options available currently.
"},{"location":"plugins/environment-collector/reference/","title":"Environment collector plugins","text":"Environment collectors allow for dynamically modifying environments or adding environments beyond those defined in config. Users can override default values provided by each environment.
"},{"location":"plugins/environment-collector/reference/#known-third-party","title":"Known third-party","text":"Any required environment collectors that are not built-in must be manually installed alongside Hatch or listed in the tool.hatch.env.requires
array for automatic management:
[tool.hatch.env]\nrequires = [\n \"...\",\n]\n
[env]\nrequires = [\n \"...\",\n]\n
"},{"location":"plugins/environment-collector/reference/#hatch.env.collectors.plugin.interface.EnvironmentCollectorInterface","title":"EnvironmentCollectorInterface
","text":"Example usage:
plugin.py hooks.py from hatch.env.collectors.plugin.interface import EnvironmentCollectorInterface\n\n\n class SpecialEnvironmentCollector(EnvironmentCollectorInterface):\n PLUGIN_NAME = 'special'\n ...\n
from hatchling.plugin import hookimpl\n\n from .plugin import SpecialEnvironmentCollector\n\n\n @hookimpl\n def hatch_register_environment_collector():\n return SpecialEnvironmentCollector\n
Source code in src/hatch/env/collectors/plugin/interface.py
class EnvironmentCollectorInterface:\n \"\"\"\n Example usage:\n\n ```python tab=\"plugin.py\"\n from hatch.env.collectors.plugin.interface import EnvironmentCollectorInterface\n\n\n class SpecialEnvironmentCollector(EnvironmentCollectorInterface):\n PLUGIN_NAME = 'special'\n ...\n ```\n\n ```python tab=\"hooks.py\"\n from hatchling.plugin import hookimpl\n\n from .plugin import SpecialEnvironmentCollector\n\n\n @hookimpl\n def hatch_register_environment_collector():\n return SpecialEnvironmentCollector\n ```\n \"\"\"\n\n PLUGIN_NAME = ''\n \"\"\"The name used for selection.\"\"\"\n\n def __init__(self, root, config):\n self.__root = root\n self.__config = config\n\n @property\n def root(self):\n \"\"\"\n The root of the project tree as a path-like object.\n \"\"\"\n return self.__root\n\n @property\n def config(self) -> dict:\n \"\"\"\n ```toml config-example\n [tool.hatch.env.collectors.<PLUGIN_NAME>]\n ```\n \"\"\"\n return self.__config\n\n def get_initial_config(self) -> dict[str, dict]: # noqa: PLR6301\n \"\"\"\n Returns configuration for environments keyed by the environment or matrix name.\n \"\"\"\n return {}\n\n def finalize_config(self, config: dict[str, dict]):\n \"\"\"\n Finalizes configuration for environments keyed by the environment or matrix name. This will override\n any user-defined settings and any collectors that ran before this call.\n\n This is called before matrices are turned into concrete environments.\n \"\"\"\n\n def finalize_environments(self, config: dict[str, dict]):\n \"\"\"\n Finalizes configuration for environments keyed by the environment name. This will override\n any user-defined settings and any collectors that ran before this call.\n\n This is called after matrices are turned into concrete environments.\n \"\"\"\n
"},{"location":"plugins/environment-collector/reference/#hatch.env.collectors.plugin.interface.EnvironmentCollectorInterface.PLUGIN_NAME","title":"PLUGIN_NAME = ''
class-attribute
instance-attribute
","text":"The name used for selection.
"},{"location":"plugins/environment-collector/reference/#hatch.env.collectors.plugin.interface.EnvironmentCollectorInterface.root","title":"root
property
","text":"The root of the project tree as a path-like object.
"},{"location":"plugins/environment-collector/reference/#hatch.env.collectors.plugin.interface.EnvironmentCollectorInterface.config","title":"config: dict
property
","text":"pyproject.toml hatch.toml [tool.hatch.env.collectors.<PLUGIN_NAME>]\n
[env.collectors.<PLUGIN_NAME>]\n
"},{"location":"plugins/environment-collector/reference/#hatch.env.collectors.plugin.interface.EnvironmentCollectorInterface.get_initial_config","title":"get_initial_config() -> dict[str, dict]
","text":"Returns configuration for environments keyed by the environment or matrix name.
Source code insrc/hatch/env/collectors/plugin/interface.py
def get_initial_config(self) -> dict[str, dict]: # noqa: PLR6301\n \"\"\"\n Returns configuration for environments keyed by the environment or matrix name.\n \"\"\"\n return {}\n
"},{"location":"plugins/environment-collector/reference/#hatch.env.collectors.plugin.interface.EnvironmentCollectorInterface.finalize_config","title":"finalize_config(config: dict[str, dict])
","text":"Finalizes configuration for environments keyed by the environment or matrix name. This will override any user-defined settings and any collectors that ran before this call.
This is called before matrices are turned into concrete environments.
Source code insrc/hatch/env/collectors/plugin/interface.py
def finalize_config(self, config: dict[str, dict]):\n \"\"\"\n Finalizes configuration for environments keyed by the environment or matrix name. This will override\n any user-defined settings and any collectors that ran before this call.\n\n This is called before matrices are turned into concrete environments.\n \"\"\"\n
"},{"location":"plugins/environment-collector/reference/#hatch.env.collectors.plugin.interface.EnvironmentCollectorInterface.finalize_environments","title":"finalize_environments(config: dict[str, dict])
","text":"Finalizes configuration for environments keyed by the environment name. This will override any user-defined settings and any collectors that ran before this call.
This is called after matrices are turned into concrete environments.
Source code insrc/hatch/env/collectors/plugin/interface.py
def finalize_environments(self, config: dict[str, dict]):\n \"\"\"\n Finalizes configuration for environments keyed by the environment name. This will override\n any user-defined settings and any collectors that ran before this call.\n\n This is called after matrices are turned into concrete environments.\n \"\"\"\n
"},{"location":"plugins/metadata-hook/custom/","title":"Custom metadata hook","text":"This is a custom class in a given Python file that inherits from the MetadataHookInterface.
"},{"location":"plugins/metadata-hook/custom/#configuration","title":"Configuration","text":"The metadata hook plugin name is custom
.
[tool.hatch.metadata.hooks.custom]\n
[metadata.hooks.custom]\n
"},{"location":"plugins/metadata-hook/custom/#options","title":"Options","text":"Option Default Description path
hatch_build.py
The path of the Python file"},{"location":"plugins/metadata-hook/custom/#example","title":"Example","text":"hatch_build.py from hatchling.metadata.plugin.interface import MetadataHookInterface\n\n\nclass CustomMetadataHook(MetadataHookInterface):\n ...\n
If multiple subclasses are found, you must define a function named get_metadata_hook
that returns the desired build hook.
Note
Any defined PLUGIN_NAME is ignored and will always be custom
.
Metadata hooks allow for the modification of project metadata after it has been loaded.
"},{"location":"plugins/metadata-hook/reference/#known-third-party","title":"Known third-party","text":"package.json
filesrequirements.txt
filespip
and conda
dependency management using a single requirements.yaml
file for both MetadataHookInterface
","text":"Example usage:
plugin.py hooks.pyfrom hatchling.metadata.plugin.interface import MetadataHookInterface\n\n\nclass SpecialMetadataHook(MetadataHookInterface):\n PLUGIN_NAME = 'special'\n ...\n
from hatchling.plugin import hookimpl\n\nfrom .plugin import SpecialMetadataHook\n\n\n@hookimpl\ndef hatch_register_metadata_hook():\n return SpecialMetadataHook\n
Source code in backend/src/hatchling/metadata/plugin/interface.py
class MetadataHookInterface(ABC): # no cov\n \"\"\"\n Example usage:\n\n ```python tab=\"plugin.py\"\n from hatchling.metadata.plugin.interface import MetadataHookInterface\n\n\n class SpecialMetadataHook(MetadataHookInterface):\n PLUGIN_NAME = 'special'\n ...\n ```\n\n ```python tab=\"hooks.py\"\n from hatchling.plugin import hookimpl\n\n from .plugin import SpecialMetadataHook\n\n\n @hookimpl\n def hatch_register_metadata_hook():\n return SpecialMetadataHook\n ```\n \"\"\"\n\n PLUGIN_NAME = ''\n \"\"\"The name used for selection.\"\"\"\n\n def __init__(self, root: str, config: dict) -> None:\n self.__root = root\n self.__config = config\n\n @property\n def root(self) -> str:\n \"\"\"\n The root of the project tree.\n \"\"\"\n return self.__root\n\n @property\n def config(self) -> dict:\n \"\"\"\n The hook configuration.\n\n ```toml config-example\n [tool.hatch.metadata.hooks.<PLUGIN_NAME>]\n ```\n \"\"\"\n return self.__config\n\n @abstractmethod\n def update(self, metadata: dict) -> None:\n \"\"\"\n This updates the metadata mapping of the `project` table in-place.\n \"\"\"\n\n def get_known_classifiers(self) -> list[str]: # noqa: PLR6301\n \"\"\"\n This returns extra classifiers that should be considered valid in addition to the ones known to PyPI.\n \"\"\"\n return []\n
"},{"location":"plugins/metadata-hook/reference/#hatchling.metadata.plugin.interface.MetadataHookInterface.PLUGIN_NAME","title":"PLUGIN_NAME = ''
class-attribute
instance-attribute
","text":"The name used for selection.
"},{"location":"plugins/metadata-hook/reference/#hatchling.metadata.plugin.interface.MetadataHookInterface.root","title":"root: str
property
","text":"The root of the project tree.
"},{"location":"plugins/metadata-hook/reference/#hatchling.metadata.plugin.interface.MetadataHookInterface.config","title":"config: dict
property
","text":"The hook configuration.
pyproject.toml hatch.toml[tool.hatch.metadata.hooks.<PLUGIN_NAME>]\n
[metadata.hooks.<PLUGIN_NAME>]\n
"},{"location":"plugins/metadata-hook/reference/#hatchling.metadata.plugin.interface.MetadataHookInterface.update","title":"update(metadata: dict) -> None
abstractmethod
","text":"This updates the metadata mapping of the project
table in-place.
backend/src/hatchling/metadata/plugin/interface.py
@abstractmethod\ndef update(self, metadata: dict) -> None:\n \"\"\"\n This updates the metadata mapping of the `project` table in-place.\n \"\"\"\n
"},{"location":"plugins/metadata-hook/reference/#hatchling.metadata.plugin.interface.MetadataHookInterface.get_known_classifiers","title":"get_known_classifiers() -> list[str]
","text":"This returns extra classifiers that should be considered valid in addition to the ones known to PyPI.
Source code inbackend/src/hatchling/metadata/plugin/interface.py
def get_known_classifiers(self) -> list[str]: # noqa: PLR6301\n \"\"\"\n This returns extra classifiers that should be considered valid in addition to the ones known to PyPI.\n \"\"\"\n return []\n
"},{"location":"plugins/publisher/package-index/","title":"Index publisher","text":"See the documentation for publishing.
"},{"location":"plugins/publisher/package-index/#options","title":"Options","text":"Flag Config name Description-r
/--repo
repo
The repository with which to publish artifacts -u
/--user
user
The user with which to authenticate -a
/--auth
auth
The credentials to use for authentication --ca-cert
ca-cert
The path to a CA bundle --client-cert
client-cert
The path to a client certificate, optionally containing the private key --client-key
client-key
The path to the client certificate's private key repos
A table of named repositories to their respective options"},{"location":"plugins/publisher/package-index/#configuration","title":"Configuration","text":"The publisher plugin name is index
.
[publish.index]\n
"},{"location":"plugins/publisher/package-index/#repositories","title":"Repositories","text":"All top-level options can be overridden per repository using the repos
table with a required url
attribute for each repository. The following shows the default configuration:
[publish.index.repos.main]\nurl = \"https://upload.pypi.org/legacy/\"\n\n[publish.index.repos.test]\nurl = \"https://test.pypi.org/legacy/\"\n
The repo
and repos
options have no effect.
You can require a confirmation prompt or use of the -y
/--yes
flag by setting publishers' disable
option to true
in either Hatch's config file or project-specific configuration (which takes precedence):
[publish.index]\ndisable = true\n
[tool.hatch.publish.index]\ndisable = true\n
[publish.index]\ndisable = true\n
"},{"location":"plugins/publisher/reference/","title":"Publisher plugins","text":""},{"location":"plugins/publisher/reference/#known-third-party","title":"Known third-party","text":"PublisherInterface
","text":"Example usage:
plugin.py hooks.py from hatch.publish.plugin.interface import PublisherInterface\n\n\n class SpecialPublisher(PublisherInterface):\n PLUGIN_NAME = 'special'\n ...\n
from hatchling.plugin import hookimpl\n\n from .plugin import SpecialPublisher\n\n\n @hookimpl\n def hatch_register_publisher():\n return SpecialPublisher\n
Source code in src/hatch/publish/plugin/interface.py
class PublisherInterface(ABC):\n \"\"\"\n Example usage:\n\n ```python tab=\"plugin.py\"\n from hatch.publish.plugin.interface import PublisherInterface\n\n\n class SpecialPublisher(PublisherInterface):\n PLUGIN_NAME = 'special'\n ...\n ```\n\n ```python tab=\"hooks.py\"\n from hatchling.plugin import hookimpl\n\n from .plugin import SpecialPublisher\n\n\n @hookimpl\n def hatch_register_publisher():\n return SpecialPublisher\n ```\n \"\"\"\n\n PLUGIN_NAME = ''\n \"\"\"The name used for selection.\"\"\"\n\n def __init__(self, app, root, cache_dir, project_config, plugin_config):\n self.__app = app\n self.__root = root\n self.__cache_dir = cache_dir\n self.__project_config = project_config\n self.__plugin_config = plugin_config\n\n self.__disable = None\n\n @property\n def app(self):\n \"\"\"\n An instance of [Application](../utilities.md#hatchling.bridge.app.Application).\n \"\"\"\n return self.__app\n\n @property\n def root(self):\n \"\"\"\n The root of the project tree as a path-like object.\n \"\"\"\n return self.__root\n\n @property\n def cache_dir(self):\n \"\"\"\n The directory reserved exclusively for this plugin as a path-like object.\n \"\"\"\n return self.__cache_dir\n\n @property\n def project_config(self) -> dict:\n \"\"\"\n ```toml config-example\n [tool.hatch.publish.<PLUGIN_NAME>]\n ```\n \"\"\"\n return self.__project_config\n\n @property\n def plugin_config(self) -> dict:\n \"\"\"\n This is defined in Hatch's [config file](../../config/hatch.md).\n\n ```toml tab=\"config.toml\"\n [publish.<PLUGIN_NAME>]\n ```\n \"\"\"\n return self.__plugin_config\n\n @property\n def disable(self):\n \"\"\"\n Whether this plugin is disabled, thus requiring confirmation when publishing. Local\n [project configuration](reference.md#hatch.publish.plugin.interface.PublisherInterface.project_config)\n takes precedence over global\n [plugin configuration](reference.md#hatch.publish.plugin.interface.PublisherInterface.plugin_config).\n \"\"\"\n if self.__disable is None:\n if 'disable' in self.project_config:\n disable = self.project_config['disable']\n if not isinstance(disable, bool):\n message = f'Field `tool.hatch.publish.{self.PLUGIN_NAME}.disable` must be a boolean'\n raise TypeError(message)\n else:\n disable = self.plugin_config.get('disable', False)\n if not isinstance(disable, bool):\n message = f'Global plugin configuration `publish.{self.PLUGIN_NAME}.disable` must be a boolean'\n raise TypeError(message)\n\n self.__disable = disable\n\n return self.__disable\n\n @abstractmethod\n def publish(self, artifacts: list[str], options: dict):\n \"\"\"\n :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n This is called directly by the [`publish`](../../cli/reference.md#hatch-publish) command\n with the arguments and options it receives.\n \"\"\"\n
"},{"location":"plugins/publisher/reference/#hatch.publish.plugin.interface.PublisherInterface.PLUGIN_NAME","title":"PLUGIN_NAME = ''
class-attribute
instance-attribute
","text":"The name used for selection.
"},{"location":"plugins/publisher/reference/#hatch.publish.plugin.interface.PublisherInterface.app","title":"app
property
","text":"An instance of Application.
"},{"location":"plugins/publisher/reference/#hatch.publish.plugin.interface.PublisherInterface.root","title":"root
property
","text":"The root of the project tree as a path-like object.
"},{"location":"plugins/publisher/reference/#hatch.publish.plugin.interface.PublisherInterface.cache_dir","title":"cache_dir
property
","text":"The directory reserved exclusively for this plugin as a path-like object.
"},{"location":"plugins/publisher/reference/#hatch.publish.plugin.interface.PublisherInterface.project_config","title":"project_config: dict
property
","text":"pyproject.toml hatch.toml [tool.hatch.publish.<PLUGIN_NAME>]\n
[publish.<PLUGIN_NAME>]\n
"},{"location":"plugins/publisher/reference/#hatch.publish.plugin.interface.PublisherInterface.plugin_config","title":"plugin_config: dict
property
","text":"This is defined in Hatch's config file.
config.toml[publish.<PLUGIN_NAME>]\n
"},{"location":"plugins/publisher/reference/#hatch.publish.plugin.interface.PublisherInterface.disable","title":"disable
property
","text":"Whether this plugin is disabled, thus requiring confirmation when publishing. Local project configuration takes precedence over global plugin configuration.
"},{"location":"plugins/publisher/reference/#hatch.publish.plugin.interface.PublisherInterface.publish","title":"publish(artifacts: list[str], options: dict)
abstractmethod
","text":"REQUIRED
This is called directly by the publish
command with the arguments and options it receives.
src/hatch/publish/plugin/interface.py
@abstractmethod\ndef publish(self, artifacts: list[str], options: dict):\n \"\"\"\n :material-align-horizontal-left: **REQUIRED** :material-align-horizontal-right:\n\n This is called directly by the [`publish`](../../cli/reference.md#hatch-publish) command\n with the arguments and options it receives.\n \"\"\"\n
"},{"location":"plugins/version-scheme/reference/","title":"Version scheme plugins","text":""},{"location":"plugins/version-scheme/reference/#known-third-party","title":"Known third-party","text":"VersionSchemeInterface
","text":"Example usage:
plugin.py hooks.pyfrom hatchling.version.scheme.plugin.interface import VersionSchemeInterface\n\n\nclass SpecialVersionScheme(VersionSchemeInterface):\n PLUGIN_NAME = 'special'\n ...\n
from hatchling.plugin import hookimpl\n\nfrom .plugin import SpecialVersionScheme\n\n\n@hookimpl\ndef hatch_register_version_scheme():\n return SpecialVersionScheme\n
Source code in backend/src/hatchling/version/scheme/plugin/interface.py
class VersionSchemeInterface(ABC): # no cov\n \"\"\"\n Example usage:\n\n ```python tab=\"plugin.py\"\n from hatchling.version.scheme.plugin.interface import VersionSchemeInterface\n\n\n class SpecialVersionScheme(VersionSchemeInterface):\n PLUGIN_NAME = 'special'\n ...\n ```\n\n ```python tab=\"hooks.py\"\n from hatchling.plugin import hookimpl\n\n from .plugin import SpecialVersionScheme\n\n\n @hookimpl\n def hatch_register_version_scheme():\n return SpecialVersionScheme\n ```\n \"\"\"\n\n PLUGIN_NAME = ''\n \"\"\"The name used for selection.\"\"\"\n\n def __init__(self, root: str, config: dict) -> None:\n self.__root = root\n self.__config = config\n\n @property\n def root(self) -> str:\n \"\"\"\n The root of the project tree as a string.\n \"\"\"\n return self.__root\n\n @property\n def config(self) -> dict:\n \"\"\"\n ```toml config-example\n [tool.hatch.version]\n ```\n \"\"\"\n return self.__config\n\n @abstractmethod\n def update(self, desired_version: str, original_version: str, version_data: dict) -> str:\n \"\"\"\n This should return a normalized form of the desired version and verify that it\n is higher than the original version.\n \"\"\"\n
"},{"location":"plugins/version-scheme/reference/#hatchling.version.scheme.plugin.interface.VersionSchemeInterface.PLUGIN_NAME","title":"PLUGIN_NAME = ''
class-attribute
instance-attribute
","text":"The name used for selection.
"},{"location":"plugins/version-scheme/reference/#hatchling.version.scheme.plugin.interface.VersionSchemeInterface.root","title":"root: str
property
","text":"The root of the project tree as a string.
"},{"location":"plugins/version-scheme/reference/#hatchling.version.scheme.plugin.interface.VersionSchemeInterface.config","title":"config: dict
property
","text":"pyproject.toml hatch.toml [tool.hatch.version]\n
[version]\n
"},{"location":"plugins/version-scheme/reference/#hatchling.version.scheme.plugin.interface.VersionSchemeInterface.update","title":"update(desired_version: str, original_version: str, version_data: dict) -> str
abstractmethod
","text":"This should return a normalized form of the desired version and verify that it is higher than the original version.
Source code inbackend/src/hatchling/version/scheme/plugin/interface.py
@abstractmethod\ndef update(self, desired_version: str, original_version: str, version_data: dict) -> str:\n \"\"\"\n This should return a normalized form of the desired version and verify that it\n is higher than the original version.\n \"\"\"\n
"},{"location":"plugins/version-scheme/standard/","title":"Standard version scheme","text":"See the documentation for versioning.
"},{"location":"plugins/version-scheme/standard/#configuration","title":"Configuration","text":"The version scheme plugin name is standard
.
[tool.hatch.version]\nscheme = \"standard\"\n
[version]\nscheme = \"standard\"\n
"},{"location":"plugins/version-scheme/standard/#options","title":"Options","text":"Option Description validate-bump
When setting a specific version, this determines whether to check that the new version is higher than the original. The default is true
."},{"location":"plugins/version-source/code/","title":"Code version source","text":""},{"location":"plugins/version-source/code/#updates","title":"Updates","text":"Setting the version is not supported.
"},{"location":"plugins/version-source/code/#configuration","title":"Configuration","text":"The version source plugin name is code
.
[tool.hatch.version]\nsource = \"code\"\n
[version]\nsource = \"code\"\n
"},{"location":"plugins/version-source/code/#options","title":"Options","text":"Option Description path
(required) A relative path to a Python file or extension module that will be loaded expression
A Python expression that when evaluated in the context of the loaded file returns the version. The default expression is simply __version__
. search-paths
A list of relative paths to directories that will be prepended to Python's search path"},{"location":"plugins/version-source/code/#missing-imports","title":"Missing imports","text":"If the chosen path imports another module in your project, then you'll need to use absolute imports coupled with the search-paths
option. For example, say you need to load the following file:
from ._version import get_version\n\n __version__ = get_version()\n
You should change it to:
src/pkg/__init__.py from pkg._version import get_version\n\n __version__ = get_version()\n
and the configuration would become:
pyproject.toml hatch.toml[tool.hatch.version]\nsource = \"code\"\npath = \"src/pkg/__init__.py\"\nsearch-paths = [\"src\"]\n
[version]\nsource = \"code\"\npath = \"src/pkg/__init__.py\"\nsearch-paths = [\"src\"]\n
"},{"location":"plugins/version-source/env/","title":"Environment version source","text":"Retrieves the version from an environment variable. This can be useful in build pipelines where the version is set by an external trigger.
"},{"location":"plugins/version-source/env/#updates","title":"Updates","text":"Setting the version is not supported.
"},{"location":"plugins/version-source/env/#configuration","title":"Configuration","text":"The version source plugin name is env
.
[tool.hatch.version]\nsource = \"env\"\n
[version]\nsource = \"env\"\n
"},{"location":"plugins/version-source/env/#options","title":"Options","text":"Option Description variable
(required) The name of the environment variable"},{"location":"plugins/version-source/reference/","title":"Version source plugins","text":""},{"location":"plugins/version-source/reference/#known-third-party","title":"Known third-party","text":"version
field of NodeJS package.json
filesVersionSourceInterface
","text":"Example usage:
plugin.py hooks.pyfrom hatchling.version.source.plugin.interface import VersionSourceInterface\n\n\nclass SpecialVersionSource(VersionSourceInterface):\n PLUGIN_NAME = 'special'\n ...\n
from hatchling.plugin import hookimpl\n\nfrom .plugin import SpecialVersionSource\n\n\n@hookimpl\ndef hatch_register_version_source():\n return SpecialVersionSource\n
Source code in backend/src/hatchling/version/source/plugin/interface.py
class VersionSourceInterface(ABC): # no cov\n \"\"\"\n Example usage:\n\n ```python tab=\"plugin.py\"\n from hatchling.version.source.plugin.interface import VersionSourceInterface\n\n\n class SpecialVersionSource(VersionSourceInterface):\n PLUGIN_NAME = 'special'\n ...\n ```\n\n ```python tab=\"hooks.py\"\n from hatchling.plugin import hookimpl\n\n from .plugin import SpecialVersionSource\n\n\n @hookimpl\n def hatch_register_version_source():\n return SpecialVersionSource\n ```\n \"\"\"\n\n PLUGIN_NAME = ''\n \"\"\"The name used for selection.\"\"\"\n\n def __init__(self, root: str, config: dict) -> None:\n self.__root = root\n self.__config = config\n\n @property\n def root(self) -> str:\n \"\"\"\n The root of the project tree as a string.\n \"\"\"\n return self.__root\n\n @property\n def config(self) -> dict:\n \"\"\"\n ```toml config-example\n [tool.hatch.version]\n ```\n \"\"\"\n return self.__config\n\n @abstractmethod\n def get_version_data(self) -> dict:\n \"\"\"\n This should return a mapping with a `version` key representing the current version of the project and will be\n displayed when invoking the [`version`](../../cli/reference.md#hatch-version) command without any arguments.\n\n The mapping can contain anything else and will be passed to\n [set_version](reference.md#hatchling.version.source.plugin.interface.VersionSourceInterface.set_version)\n when updating the version.\n \"\"\"\n\n def set_version(self, version: str, version_data: dict) -> None:\n \"\"\"\n This should update the version to the first argument with the data provided during retrieval.\n \"\"\"\n raise NotImplementedError\n
"},{"location":"plugins/version-source/reference/#hatchling.version.source.plugin.interface.VersionSourceInterface.PLUGIN_NAME","title":"PLUGIN_NAME = ''
class-attribute
instance-attribute
","text":"The name used for selection.
"},{"location":"plugins/version-source/reference/#hatchling.version.source.plugin.interface.VersionSourceInterface.root","title":"root: str
property
","text":"The root of the project tree as a string.
"},{"location":"plugins/version-source/reference/#hatchling.version.source.plugin.interface.VersionSourceInterface.config","title":"config: dict
property
","text":"pyproject.toml hatch.toml [tool.hatch.version]\n
[version]\n
"},{"location":"plugins/version-source/reference/#hatchling.version.source.plugin.interface.VersionSourceInterface.get_version_data","title":"get_version_data() -> dict
abstractmethod
","text":"This should return a mapping with a version
key representing the current version of the project and will be displayed when invoking the version
command without any arguments.
The mapping can contain anything else and will be passed to set_version when updating the version.
Source code inbackend/src/hatchling/version/source/plugin/interface.py
@abstractmethod\ndef get_version_data(self) -> dict:\n \"\"\"\n This should return a mapping with a `version` key representing the current version of the project and will be\n displayed when invoking the [`version`](../../cli/reference.md#hatch-version) command without any arguments.\n\n The mapping can contain anything else and will be passed to\n [set_version](reference.md#hatchling.version.source.plugin.interface.VersionSourceInterface.set_version)\n when updating the version.\n \"\"\"\n
"},{"location":"plugins/version-source/reference/#hatchling.version.source.plugin.interface.VersionSourceInterface.set_version","title":"set_version(version: str, version_data: dict) -> None
","text":"This should update the version to the first argument with the data provided during retrieval.
Source code inbackend/src/hatchling/version/source/plugin/interface.py
def set_version(self, version: str, version_data: dict) -> None:\n \"\"\"\n This should update the version to the first argument with the data provided during retrieval.\n \"\"\"\n raise NotImplementedError\n
"},{"location":"plugins/version-source/regex/","title":"Regex version source","text":"See the documentation for versioning.
"},{"location":"plugins/version-source/regex/#updates","title":"Updates","text":"Setting the version is supported.
"},{"location":"plugins/version-source/regex/#configuration","title":"Configuration","text":"The version source plugin name is regex
.
[tool.hatch.version]\nsource = \"regex\"\n
[version]\nsource = \"regex\"\n
"},{"location":"plugins/version-source/regex/#options","title":"Options","text":"Option Description path
(required) A relative path to a file containing the project's version pattern
A regular expression that has a named group called version
that represents the version. The default pattern looks for a variable named __version__
or VERSION
that is set to a string containing the version, optionally prefixed with the lowercase letter v
."},{"location":"tutorials/environment/basic-usage/","title":"Managing environments","text":"Hatch environments are isolated workspaces that can be used for project tasks including running tests, building documentation and running code formatters and linters.
"},{"location":"tutorials/environment/basic-usage/#the-default-environment","title":"The default environment","text":"When you start using Hatch, you can create the default
environment. To do this use the env create
command:
hatch env create\n
This will not only create will the default
environment for you to work in but will also install your project in dev mode in this default
environment.
Tip
You never need to manually create environments as spawning a shell or running commands within one will automatically trigger creation.
"},{"location":"tutorials/environment/basic-usage/#using-the-default-environment","title":"Using the default environment","text":"Hatch will always use the default
environment if an environment is not chosen explicitly when running a command.
For instance, the following shows how to get version information for the Python in use.
$ hatch run python -V\nPython 3.12.1\n
"},{"location":"tutorials/environment/basic-usage/#configure-the-default-environment","title":"Configure the default environment","text":"You can customize the tools that are installed into the default
environment by adding a table called tool.hatch.envs.default
to your pyproject.toml
file. Below is an example of adding the dependencies pydantic
and numpy
to the default
environment.
[tool.hatch.envs.default]\ndependencies = [\n \"pydantic\",\n \"numpy\",\n]\n
[envs.default]\ndependencies = [\n \"pydantic\",\n \"numpy\",\n]\n
You can declare versions for your dependencies as well within this configuration.
pyproject.toml hatch.toml[tool.hatch.envs.default]\ndependencies = [\n \"pydantic>=2.0\",\n \"numpy\",\n]\n
[envs.default]\ndependencies = [\n \"pydantic>=2.0\",\n \"numpy\",\n]\n
"},{"location":"tutorials/environment/basic-usage/#create-custom-environment","title":"Create custom environment","text":"You can create custom environments in Hatch by adding a section to your pyproject.toml
file [tool.hatch.envs.<ENV_NAME>]
. Below you define an environment called test
and you add the pytest
and pytest-cov
dependencies to that environment's configuration.
[tool.hatch.envs.test]\ndependencies = [\n \"pytest\",\n \"pytest-cov\"\n]\n
[envs.test]\ndependencies = [\n \"pytest\",\n \"pytest-cov\"\n]\n
The first time that you call the test environment, Hatch will:
Hatch offers a unique environment feature that allows you run a specific command within a specific environment rather than needing to activate the environment as you would using a tool such as Conda or venv.
For instance, if you define an environment called test
that contains the dependencies from the previous section, you can run the pytest
command from the test
environment using the syntax:
hatch run <ENV_NAME>:command\n
To access the test
environment and run pytest
, you can run:
$ hatch run test:pytest\n============================== test session starts ===============================\nplatform darwin -- Python 3.12.1, pytest-7.4.4, pluggy-1.3.0\nrootdir: /your/path/to/yourproject\ncollected 0 items\n
Note
test:pytest
represents the name of the environment to call (test
) and the command to run (pytest
).
Above you defined and created a new test environment in your pyproject.toml
file. You can now use the env show
command to see both the currently created environments and the dependencies in each environment.
$ hatch env show\n Standalone\n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Name \u2503 Type \u2503 Dependencies \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 default \u2502 virtual \u2502 \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 test \u2502 virtual \u2502 pytest \u2502\n\u2502 \u2502 \u2502 pytest-cov \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n
Note
The output may have more columns depending on your environment configuration.
"},{"location":"tutorials/environment/basic-usage/#locating-environments","title":"Locating environments","text":"To see where your current environment is located you can use the env find
command.
$ hatch env find test\n/your/path/Application Support/hatch/env/virtual/yourproject/twO2iQR3/test\n
Note
That path is what you would see on macOS but differs for each platform, and is configurable.
"},{"location":"tutorials/environment/basic-usage/#launching-a-shell-within-a-specific-environment","title":"Launching a shell within a specific environment","text":"If you wish to launch a shell for a specific environment that you have created, like the previous test
environment, you can use:
hatch -e test shell\n
Once the environment is active, you can run commands like you would in any Python environment.
Notice below that when running pip list
in the test environment, you can see:
pytest
and pytest-cov
as specified above in the pyproject.toml
file.$ pip list\nPackage Version Editable project location\n----------- ------- ----------------------------------------------------\ncoverage 7.4.1\niniconfig 2.0.0\npackaging 23.2\npip 23.3.1\npluggy 1.4.0\npytest 8.0.0\npytest-cov 4.1.0\nyourproject 0.1.0 /your/path/to/yourproject\n
"},{"location":"tutorials/environment/basic-usage/#conda-environments","title":"Conda environments","text":"If you prefer to use Conda environments with Hatch, you can check out the hatch-conda plugin.
"},{"location":"tutorials/python/manage/","title":"Managing Python distributions","text":"The python
command group provides a set of commands to manage Python distributions that may be used by other tools.
Note
When using environments, manual management is not necessary since by default Hatch will automatically download and manage Python distributions internally when a requested version cannot be found.
"},{"location":"tutorials/python/manage/#location","title":"Location","text":"There are two ways to control where Python distributions are installed. Both methods make it so that each installed distribution is placed in a subdirectory of the configured location named after the distribution.
-d
/--dir
option of every python
subcommand, which takes precedence over the default directory.To install a Python distribution, use the python install
command. For example:
hatch python install 3.12\n
This will:
3.12
Python distribution3.12
within the configured default directory for Python installationsNow its python
executable can be used by you or other tools.
Note
For PATH changes to take effect in the current shell, you will need to restart it.
"},{"location":"tutorials/python/manage/#multiple","title":"Multiple","text":"You can install multiple Python distributions at once by providing multiple distribution names. For example:
hatch python install 3.12 3.11 pypy3.10\n
If you would like to install all available Python distributions that are compatible with your system, use all
as the distribution name:
hatch python install all\n
Tip
The commands for updating and removing also support this functionality.
"},{"location":"tutorials/python/manage/#private","title":"Private","text":"By default, installing Python distributions will add them to the user PATH. To disable this behavior, use the --private
flag like so:
hatch python install 3.12 --private\n
This when combined with the directory option can be used to create private, isolated installations.
"},{"location":"tutorials/python/manage/#listing-distributions","title":"Listing distributions","text":"You can see all of the available and installed Python distributions by using the python show
command. For example, if you already installed the 3.12
distribution you may see something like this:
$ hatch python show\n Installed\n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Name \u2503 Version \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 3.12 \u2502 3.12.3 \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n Available\n\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503 Name \u2503 Version \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 3.7 \u2502 3.7.9 \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 3.8 \u2502 3.8.19 \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 3.9 \u2502 3.9.19 \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 3.10 \u2502 3.10.14 \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 3.11 \u2502 3.11.9 \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 pypy2.7 \u2502 7.3.15 \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 pypy3.9 \u2502 7.3.15 \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 pypy3.10 \u2502 7.3.15 \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n
"},{"location":"tutorials/python/manage/#finding-installations","title":"Finding installations","text":"The Python executable of an installed distribution can be found by using the python find
command. For example:
$ hatch python find 3.12\n/home/.local/share/hatch/pythons/3.12/python/bin/python3\n
You can instead output its parent directory by using the -p
/--parent
flag:
$ hatch python find 3.12 --parent\n/home/.local/share/hatch/pythons/3.12/python/bin\n
This is useful when other tools do not need to use the executable directly but require knowing the directory containing it.
"},{"location":"tutorials/python/manage/#updates","title":"Updates","text":"To update installed Python distributions, use the python update
command. For example:
hatch python update 3.12 3.11 pypy3.10\n
When there are no updates available for a distribution, a warning will be displayed:
$ hatch python update 3.12\nThe latest version is already installed: 3.12.3\n
"},{"location":"tutorials/python/manage/#removal","title":"Removal","text":"To remove installed Python distributions, use the python remove
command. For example:
hatch python remove 3.12 3.11 pypy3.10\n
"},{"location":"tutorials/testing/overview/","title":"Testing projects","text":"The test
command (by default) uses pytest with select plugins and coverage.py. View the testing configuration for more information.
The majority of projects can be fully tested this way without the need for custom environments.
"},{"location":"tutorials/testing/overview/#passing-arguments","title":"Passing arguments","text":"When you run the test
command without any arguments, tests
is passed as the default argument to pytest
(this assumes that you have a tests
directory). For example, the following command invocation:
hatch test\n
would be translated roughly to:
pytest tests\n
You can pass arguments to pytest
by appending them to the test
command. For example, the following command invocation:
hatch test -vv tests/test_foo.py::test_bar\n
would be translated roughly to:
pytest -vv tests/test_foo.py::test_bar\n
You can force the treatment of arguments as positional by using the --
separator, especially useful when built-in flags of the test
command conflict with those of pytest
, such as the --help
flag. For example, the following command invocation:
hatch test -r -- -r fE -- tests\n
would be translated roughly to:
pytest -r fE -- tests\n
Note
It's important to ensure that pytest
receives an argument instructing what to run/where to locate tests. It's default behavior is .
meaning that it will exhaustively search for tests in the current directory. This can not just be slow but also lead to unexpected behavior.
If no environment options are selected, the test
command will only run tests in the first defined environment that either already exists or is compatible. Additionally, the checking order will prioritize environments that define a version of Python that matches the interpreter that Hatch is running on.
For example, if you overrode the default matrix as follows:
pyproject.toml hatch.toml[[tool.hatch.envs.hatch-test.matrix]]\npython = [\"3.12\", \"3.11\"]\n\n[[tool.hatch.envs.hatch-test.matrix]]\npython = [\"3.11\"]\nfeature = [\"foo\", \"bar\"]\n
[[envs.hatch-test.matrix]]\npython = [\"3.12\", \"3.11\"]\n\n[[envs.hatch-test.matrix]]\npython = [\"3.11\"]\nfeature = [\"foo\", \"bar\"]\n
the expanded environments would normally be:
hatch-test.py3.12\nhatch-test.py3.11\nhatch-test.py3.11-foo\nhatch-test.py3.11-bar\n
If you install Hatch on Python 3.11, the checking order would be:
hatch-test.py3.11\nhatch-test.py3.11-foo\nhatch-test.py3.11-bar\nhatch-test.py3.12\n
Note
If you installed Hatch with an official installer or are using one of the standalone binaries, the version of Python that Hatch runs on is out of your control. If you are relying on the single environment resolution behavior, consider explicitly selecting environments based on the Python version instead.
"},{"location":"tutorials/testing/overview/#all-environments","title":"All environments","text":"You can run tests in all compatible environments by using the --all
flag. For example, say you defined the matrix and overrides as follows:
[[tool.hatch.envs.hatch-test.matrix]]\npython = [\"3.12\", \"3.11\"]\nfeature = [\"foo\", \"bar\"]\n\n[tool.hatch.envs.hatch-test.overrides]\nmatrix.feature.platforms = [\n { value = \"linux\", if = [\"foo\", \"bar\"] },\n { value = \"windows\", if = [\"foo\"] },\n { value = \"macos\", if = [\"bar\"] },\n]\n
[[envs.hatch-test.matrix]]\npython = [\"3.12\", \"3.11\"]\nfeature = [\"foo\", \"bar\"]\n\n[envs.hatch-test.overrides]\nmatrix.feature.platforms = [\n { value = \"linux\", if = [\"foo\", \"bar\"] },\n { value = \"windows\", if = [\"foo\"] },\n { value = \"macos\", if = [\"bar\"] },\n]\n
The following table shows the environments in which tests would be run:
Environment Linux Windows macOShatch-test.py3.12-foo
hatch-test.py3.12-bar
hatch-test.py3.11-foo
hatch-test.py3.11-bar
"},{"location":"tutorials/testing/overview/#specific-environments","title":"Specific environments","text":"You can select subsets of environments by using the --include
/-i
and --exclude
/-x
options. These options may be used to include or exclude certain matrix variables, optionally followed by specific comma-separated values, and may be selected multiple times.
For example, say you defined the matrix as follows:
pyproject.toml hatch.toml[[tool.hatch.envs.hatch-test.matrix]]\npython = [\"3.12\", \"3.11\"]\nfeature = [\"foo\", \"bar\", \"baz\"]\n
[[envs.hatch-test.matrix]]\npython = [\"3.12\", \"3.11\"]\nfeature = [\"foo\", \"bar\", \"baz\"]\n
If you wanted to run tests in all environments that have Python 3.12 and either the foo
or bar
feature, you could use the following command invocation:
hatch test -i python=3.12 -i feature=foo,bar\n
Alternatively, we could exclude the baz
feature to achieve the same result:
hatch test -i python=3.12 -x feature=baz\n
Tip
Since selecting the version of Python is a common use case, you can use the --python
/-py
option as a shorthand. For example, the previous commands could have been written as:
hatch test -py 3.12 -i feature=foo,bar\nhatch test -py 3.12 -x feature=baz\n
"},{"location":"tutorials/testing/overview/#measuring-code-coverage","title":"Measuring code coverage","text":"You can enable code coverage by using the --cover
flag. For example, the following command invocation:
hatch test --cover\n
would be translated roughly to:
coverage run -m pytest tests\n
After tests run in all of the selected environments, the coverage data is combined and a report is shown. The --cover-quiet
flag can be used to suppress the report and implicitly enables the --cover
flag:
hatch test --cover-quiet\n
Note
Coverage data files are generated at the root of the project. Be sure to exclude them from version control with the following glob-style pattern:
.coverage*\n
"},{"location":"tutorials/testing/overview/#retry-failed-tests","title":"Retry failed tests","text":"You can retry failed tests with the --retries
option:
hatch test --retries 2\n
If a test fails every time and the number of retries is set to 2
, the test will be run a total of three times.
You can also set the number of seconds to wait between retries with the --retry-delay
option:
hatch test --retries 2 --retry-delay 1\n
"},{"location":"tutorials/testing/overview/#parallelize-test-execution","title":"Parallelize test execution","text":"You can parallelize test execution with the --parallel
/-p
flag:
hatch test --parallel\n
This distributes tests within an environment across multiple workers. The number of workers corresponds to the number of logical rather than physical CPUs that are available.
"},{"location":"tutorials/testing/overview/#randomize-test-order","title":"Randomize test order","text":"You can randomize the order of tests with the --randomize
/-r
flag:
hatch test --randomize\n
"},{"location":"blog/archive/2024/","title":"2024","text":""},{"location":"blog/archive/2023/","title":"2023","text":""},{"location":"blog/archive/2022/","title":"2022","text":""},{"location":"blog/category/release/","title":"Release","text":""}]}
\ No newline at end of file
diff --git a/dev/tutorials/environment/basic-usage/index.html b/dev/tutorials/environment/basic-usage/index.html
index fe36dc8bf..20e3f7517 100644
--- a/dev/tutorials/environment/basic-usage/index.html
+++ b/dev/tutorials/environment/basic-usage/index.html
@@ -59,7 +59,7 @@
Note
The output may have more columns depending on your environment configuration.
To see where your current environment is located you can use the env find
command.
$ hatch env find test
/your/path/Application Support/hatch/env/virtual/yourproject/twO2iQR3/test
Note
That path is what you would see on macOS but differs for each platform, and is configurable.
If you wish to launch a shell for a specific environment that you have created, like the previous test
environment, you can use:
hatch -e test shell
-
Once the environment is active, you can run commands like you would in any Python environment.
Notice below that when running pip list
in the test environment, you can see:
pytest
and pytest-cov
as specified above in the pyproject.toml
file.$ pip list
+
Once the environment is active, you can run commands like you would in any Python environment.
Notice below that when running pip list
in the test environment, you can see:
pytest
and pytest-cov
as specified above in the pyproject.toml
file.$ pip list
Package Version Editable project location
----------- ------- ----------------------------------------------------
coverage 7.4.1
@@ -70,6 +70,6 @@
pytest 8.0.0
pytest-cov 4.1.0
yourproject 0.1.0 /your/path/to/yourproject
-
If you prefer to use Conda environments with Hatch, you can check out the hatch-conda plugin.