Metadata-Version: 2.5
Name: hatch-uv-lock
Version: 0.1
Summary: Hatchling build hook that embeds uv.lock and pyproject.toml into wheels
Project-URL: Homepage, https://gitlab.com/Kound/hatch-uv-lock
Project-URL: Documentation, https://gitlab.com/Kound/hatch-uv-lock/-/blob/main/README.md
Project-URL: Changelog, https://gitlab.com/Kound/hatch-uv-lock/-/blob/main/CHANGELOG.md
Project-URL: Issues, https://gitlab.com/Kound/hatch-uv-lock/-/issues
Project-URL: Source Code, https://gitlab.com/Kound/hatch-uv-lock
Author-email: Carli* Freudenberg <kound@posteo.de>
License-Expression: MIT
License-File: LICENSE
Classifier: Development Status :: 4 - Beta
Classifier: Framework :: Hatch
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Natural Language :: English
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Programming Language :: Python :: 3.15
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Programming Language :: Python :: Implementation :: PyPy
Classifier: Topic :: Software Development :: Build Tools
Classifier: Typing :: Typed
Requires-Python: >=3.12
Requires-Dist: hatchling>=1.28
Description-Content-Type: text/markdown

# hatch-uv-lock

[![pipeline](https://gitlab.com/Kound/hatch-uv-lock/badges/main/pipeline.svg)](https://gitlab.com/Kound/hatch-uv-lock/-/pipelines?ref=main)
[![coverage](https://gitlab.com/Kound/hatch-uv-lock/badges/main/coverage.svg)](https://gitlab.com/Kound/hatch-uv-lock/-/pipelines?ref=main)
[![PyPI](https://img.shields.io/pypi/v/hatch-uv-lock)](https://pypi.org/project/hatch-uv-lock/)
[![Python versions](https://img.shields.io/pypi/pyversions/hatch-uv-lock)](https://pypi.org/project/hatch-uv-lock/)
[![License](https://img.shields.io/pypi/l/hatch-uv-lock)](https://gitlab.com/Kound/hatch-uv-lock/-/blob/main/LICENSE)
[![Typed](https://img.shields.io/badge/typing-typed-blue)](https://peps.python.org/pep-0561/)
[![Checked with mypy](https://www.mypy-lang.org/static/mypy_badge.svg)](https://mypy-lang.org/)
[![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
[![uv](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/uv/main/assets/badge/v0.json)](https://github.com/astral-sh/uv)
[![prek](https://raw.githubusercontent.com/j178/prek/master/docs/assets/badge.svg)](https://github.com/j178/prek)

Hatchling build hook that embeds the project's `uv.lock` and `pyproject.toml` into its wheels.
A tool like [`uvrev tool run`](https://gitlab.com/Kound/uvrev) can then rebuild the exact locked environment from the wheel alone, with `uv sync --locked --no-install-project`.

## Usage

```toml
[project]
name = "my-project"

[build-system]
requires = ["hatchling>=1.28", "hatch-uv-lock"]
build-backend = "hatchling.build"

[tool.hatch.build.hooks.uv-lock]
```

The hook is active whenever hatchling loads it, so the (empty) `[tool.hatch.build.hooks.uv-lock]` table is all it takes.
There is no other switch.
To use it for wheels only, use `[tool.hatch.build.targets.wheel.hooks.uv-lock]` instead (the sdist then does not force-include `uv.lock`).

hatchling's [generic build hook options](https://hatch.pypa.io/latest/config/build/#build-hooks) work as usual.
For example, `enable-by-default = false` turns the hook off unless `HATCH_BUILD_HOOKS_ENABLE=true` is set.

## Using it from an existing build hook

```python
from pathlib import Path

from hatch_uv_lock import add_lock_files


class MyBuildHook(BuildHookInterface):
    def initialize(self, version, build_data):
        add_lock_files(
            root=Path(self.root),
            target_name=self.target_name,
            version=version,
            dynamic=self.metadata.dynamic,
            build_data=build_data,
        )
```

`self.metadata.dynamic` is the original `project.dynamic` list (hatchling keeps a copy before metadata hooks change it).

## What ends up where

| Target | Files |
|---|---|
| wheel | `<name>-<version>.dist-info/extra_metadata/uv.lock` and `.../extra_metadata/pyproject.toml`, byte-identical to the originals |
| sdist | `uv.lock` (force-included), so a wheel built from the sdist gets it too |
| editable wheel | nothing |
| any other target | the build fails |

Reading the files from an installed distribution:

```python
from importlib.metadata import distribution

lock = distribution("my-project").read_text("extra_metadata/uv.lock")
```

## Checks

The lock file itself is not checked.
The only check: `project.dynamic` must not contain `dependencies` or `optional-dependencies`.
For these, `uv sync --locked` must call the build backend, which fails without the source tree.
All other dynamic fields work, including `version` (hatch-vcs and similar) and `requires-python`.

## Development

```bash
uv sync
uv run prek run --all-files
```

This runs `ruff format`, `ruff check`, `mypy --strict`, the doctests and the tests under coverage (100 % required).
The tests in `tests/test_integration.py` build real projects with `uv build` and need network access to the package index (marker `network`).
Skip them with `uv run pytest -m "not network"`.

Background: [pre-PEP on discuss.python.org](https://discuss.python.org/t/pre-pep-add-ability-to-install-a-package-with-reproducible-dependencies/99497/).
