Skip to content

Commit

Permalink
packages: Add tool to build an editable package impurely
Browse files Browse the repository at this point in the history
This is to be used with build-systems such as `meson-python` that builds native extensions.
It's purpose is the same as that of `python setup.py build_ext -i`, just using PEP-660.

Of course this is not a perfect analogy to using something like `meson-python` directly.
We just use the `.pth` machinery directly, while `meson-python` uses a more complex hook machinery:

- Automatic inference of Python

`meson-python` puts the editable build in `build/cp312`.
Users will have to manually override any automatically inferred editable root to point to the correct build directory.

- Automatic rebuilds

Thanks to it's hook machinery `meson-python` can rebuild packages as necessary on load.
This automatic rebuild behaviour will not work, and users will have to call `build-editable` manually.

These are just two examples of build-system specific behaviour that will not work.
  • Loading branch information
adisbladis committed Sep 29, 2024
1 parent 6873565 commit 57066da
Show file tree
Hide file tree
Showing 6 changed files with 128 additions and 0 deletions.
3 changes: 3 additions & 0 deletions doc/src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@
- [resolvers](./build/lib/resolvers.nix)
- [hooks](./build/hooks/default.nix)

- [Packages](./packages.md)
- [build-editable](./packages/build-editable/README.md)

# Contributing

- [Hacking](./HACKING.md)
1 change: 1 addition & 0 deletions packages/build-editable/.python-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
3.12
23 changes: 23 additions & 0 deletions packages/build-editable/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# build-editable

This package is intended to aid Nix-based Python development using [editable installs](https://pip.pypa.io/en/latest/topics/local-project-installs/#editable-installs).

This is to be used with build-systems such as `meson-python` that builds native extensions.
It's purpose is similar to that of `python setup.py build_ext -i`, just using PEP-660.

## Problems

Of course this is not a perfect analogy to using something like `meson-python` directly.
We just use the `.pth` machinery directly, while `meson-python` uses a more complex hook machinery:

- Automatic inference of Python

`meson-python` puts the editable build in `build/cp312`.
Users will have to manually override any editable root automatically inferred by Nix to point to the correct build directory.

- Automatic rebuilds

Thanks to it's hook machinery `meson-python` can rebuild packages as necessary on load.
This automatic rebuild behaviour will not work, and users will have to call `build-editable` manually.

These are just two examples of build-system specific behaviour that will not work out of the box.
17 changes: 17 additions & 0 deletions packages/build-editable/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[project]
name = "build-editable"
version = "0.1.0"
description = "Build editable package"
readme = "README.md"
requires-python = ">=3.11"
dependencies = [
"editables>=0.5",
"pyproject-hooks>=1.1.0",
]

[project.scripts]
build-editable = "build_editable:build-editable"

[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
49 changes: 49 additions & 0 deletions packages/build-editable/src/build_editable/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import argparse
import os
import os.path
import tempfile
from pathlib import Path

import pyproject_hooks
import tomllib

argparser = argparse.ArgumentParser(
description="Trigger in-place builds required for building editable packages with native extensions"
)
_ = argparser.add_argument(
"--wheel-dir",
help="Output wheel to directory instead of a temporary directory that gets immediately deleted",
type=str,
)


def main() -> None:
args = argparser.parse_args()

cwd = Path(os.getcwd())
if args.wheel_dir is not None:
out: str = str(args.wheel_dir)
else:
out_temp = tempfile.TemporaryDirectory()
out = out_temp.name

with open(cwd.joinpath("pyproject.toml"), "rb") as pyproject_file:
pyproject = tomllib.load(pyproject_file)

# Get build backend with fallback behaviour
# https://pip.pypa.io/en/stable/reference/build-system/pyproject-toml/#fallback-behaviour
try:
build_backend: str = pyproject["build-system"]["build-backend"]
except KeyError:
build_backend = "setuptools.build_meta:__legacy__"

# Call editable build hooks using pyproject-hooks
hook_caller = pyproject_hooks.BuildBackendHookCaller(
source_dir=cwd,
build_backend=build_backend,
)
hook_caller.build_editable(out)


if __name__ == "__main__":
main()
35 changes: 35 additions & 0 deletions packages/build-editable/uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 57066da

Please sign in to comment.