Build hook plugins¶
A build hook provides code that will be executed at various stages of the build process. See the documentation for build hook configuration.
Known third-party¶
- hatch-argparse-manpage - generate man pages for argparse-based CLIs
- hatch-autorun - used to inject code into an installation that will automatically run before the first import
- hatch-build-scripts - run arbitrary shell commands that create artifacts
- hatch-cython - build Cython extensions
- hatch-gettext - compiles multi-lingual messages with GNU
gettext
tools - hatch-jupyter-builder - used for packages in the Project Jupyter ecosystem
- hatch-mypyc - compiles code with Mypyc
- hatch-odoo - package Odoo add-ons into the appropriate namespace
- scikit-build-core - build extension modules with CMake
Overview¶
Build 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.
Build data¶
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 | Description |
---|---|---|
artifacts | 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.
Notes¶
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'
or
build_data['force_include']['/absolute/path/to/src/lib.so'] = 'src/lib.so'
BuildHookInterface
¶
Example usage:
from hatchling.builders.hooks.plugin.interface import BuildHookInterface
class SpecialBuildHook(BuildHookInterface):
PLUGIN_NAME = 'special'
...
from hatchling.plugin import hookimpl
from .plugin import SpecialBuildHook
@hookimpl
def hatch_register_build_hook():
return SpecialBuildHook
Source code in backend/src/hatchling/builders/hooks/plugin/interface.py
class BuildHookInterface(Generic[BuilderConfigBound]): # no cov
"""
Example usage:
```python tab="plugin.py"
from hatchling.builders.hooks.plugin.interface import BuildHookInterface
class SpecialBuildHook(BuildHookInterface):
PLUGIN_NAME = 'special'
...
```
```python tab="hooks.py"
from hatchling.plugin import hookimpl
from .plugin import SpecialBuildHook
@hookimpl
def hatch_register_build_hook():
return SpecialBuildHook
```
"""
PLUGIN_NAME = ''
"""The name used for selection."""
def __init__(
self,
root: str,
config: dict[str, Any],
build_config: BuilderConfigBound,
metadata: ProjectMetadata,
directory: str,
target_name: str,
app: Application | None = None,
) -> None:
self.__root = root
self.__config = config
self.__build_config = build_config
self.__metadata = metadata
self.__directory = directory
self.__target_name = target_name
self.__app = app
@property
def app(self) -> Application:
"""
An instance of [Application](../utilities.md#hatchling.bridge.app.Application).
"""
if self.__app is None:
from hatchling.bridge.app import Application
self.__app = cast(Application, Application().get_safe_application())
return self.__app
@property
def root(self) -> str:
"""
The root of the project tree.
"""
return self.__root
@property
def config(self) -> dict[str, Any]:
"""
The cumulative hook configuration.
```toml config-example
[tool.hatch.build.hooks.<PLUGIN_NAME>]
[tool.hatch.build.targets.<TARGET_NAME>.hooks.<PLUGIN_NAME>]
```
"""
return self.__config
@property
def metadata(self) -> ProjectMetadata:
# Undocumented for now
return self.__metadata
@property
def build_config(self) -> BuilderConfigBound:
"""
An instance of [BuilderConfig](../utilities.md#hatchling.builders.config.BuilderConfig).
"""
return self.__build_config
@property
def directory(self) -> str:
"""
The build directory.
"""
return self.__directory
@property
def target_name(self) -> str:
"""
The plugin name of the build target.
"""
return self.__target_name
def dependencies(self) -> list[str]: # noqa: PLR6301
"""
A list of extra [dependencies](../../config/dependency.md) that must be installed
prior to builds.
!!! warning
- For this to have any effect the hook dependency itself cannot be dynamic and
must always be defined in `build-system.requires`.
- As the hook must be imported to call this method, imports that require these
dependencies must be evaluated lazily.
"""
return []
def clean(self, versions: list[str]) -> None:
"""
This occurs before the build process if the `-c`/`--clean` flag was passed to
the [`build`](../../cli/reference.md#hatch-build) command, or when invoking
the [`clean`](../../cli/reference.md#hatch-clean) command.
"""
def initialize(self, version: str, build_data: dict[str, Any]) -> None:
"""
This occurs immediately before each build.
Any modifications to the build data will be seen by the build target.
"""
def finalize(self, version: str, build_data: dict[str, Any], artifact_path: str) -> None:
"""
This occurs immediately after each build and will not run if the `--hooks-only` flag
was passed to the [`build`](../../cli/reference.md#hatch-build) command.
The build data will reflect any modifications done by the target during the build.
"""
PLUGIN_NAME = ''
class-attribute
instance-attribute
¶
The name used for selection.
app: Application
property
¶
An instance of Application.
root: str
property
¶
The root of the project tree.
config: dict[str, Any]
property
¶
The cumulative hook configuration.
[tool.hatch.build.hooks.<PLUGIN_NAME>]
[tool.hatch.build.targets.<TARGET_NAME>.hooks.<PLUGIN_NAME>]
[build.hooks.<PLUGIN_NAME>]
[build.targets.<TARGET_NAME>.hooks.<PLUGIN_NAME>]
build_config: BuilderConfigBound
property
¶
An instance of BuilderConfig.
target_name: str
property
¶
The plugin name of the build target.
directory: str
property
¶
The build directory.
dependencies() -> list[str]
¶
A list of extra dependencies that must be installed prior to builds.
Warning
- For this to have any effect the hook dependency itself cannot be dynamic and must always be defined in
build-system.requires
. - As the hook must be imported to call this method, imports that require these dependencies must be evaluated lazily.
Source code in backend/src/hatchling/builders/hooks/plugin/interface.py
def dependencies(self) -> list[str]: # noqa: PLR6301
"""
A list of extra [dependencies](../../config/dependency.md) that must be installed
prior to builds.
!!! warning
- For this to have any effect the hook dependency itself cannot be dynamic and
must always be defined in `build-system.requires`.
- As the hook must be imported to call this method, imports that require these
dependencies must be evaluated lazily.
"""
return []
clean(versions: list[str]) -> None
¶
This occurs before the build process if the -c
/--clean
flag was passed to the build
command, or when invoking the clean
command.
Source code in backend/src/hatchling/builders/hooks/plugin/interface.py
def clean(self, versions: list[str]) -> None:
"""
This occurs before the build process if the `-c`/`--clean` flag was passed to
the [`build`](../../cli/reference.md#hatch-build) command, or when invoking
the [`clean`](../../cli/reference.md#hatch-clean) command.
"""
initialize(version: str, build_data: dict[str, Any]) -> None
¶
This occurs immediately before each build.
Any modifications to the build data will be seen by the build target.
Source code in backend/src/hatchling/builders/hooks/plugin/interface.py
def initialize(self, version: str, build_data: dict[str, Any]) -> None:
"""
This occurs immediately before each build.
Any modifications to the build data will be seen by the build target.
"""
finalize(version: str, build_data: dict[str, Any], artifact_path: str) -> None
¶
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 in backend/src/hatchling/builders/hooks/plugin/interface.py
def finalize(self, version: str, build_data: dict[str, Any], artifact_path: str) -> None:
"""
This occurs immediately after each build and will not run if the `--hooks-only` flag
was passed to the [`build`](../../cli/reference.md#hatch-build) command.
The build data will reflect any modifications done by the target during the build.
"""