Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add companion package for editable packages with native extensions #160

Draft
wants to merge 4 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions build/hooks/make-venv.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#!/usr/bin/env python3
import filecmp
import os
import os.path
import shutil
Expand All @@ -7,8 +8,6 @@
import typing
from pathlib import Path
from venv import EnvBuilder
import filecmp


EXECUTABLE = os.path.basename(sys.executable)
PYTHON_VERSION = ".".join((str(sys.version_info.major), str(sys.version_info.minor)))
Expand Down
22 changes: 22 additions & 0 deletions build/pkgs/editables/default.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
stdenv,
python3Packages,
pyprojectHook,
resolveBuildSystem,
}:
stdenv.mkDerivation {
inherit (python3Packages.editables)
pname
version
src
meta
;

nativeBuildInputs =
[
pyprojectHook
]
++ resolveBuildSystem {
flit-core = [ ];
};
}
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)
17 changes: 16 additions & 1 deletion flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -89,16 +89,31 @@
system:
let
pkgs = nixpkgs.legacyPackages.${system};

pythonSet = pkgs.callPackage self.build.packages {
python = pkgs.python3;
};

venv = pythonSet.mkVirtualEnv "root-venv" {
pyproject-hooks = [ ];
hatchling = [ ];
editables = [ ];
};

mkShell' =
{ nix-unit }:
pkgs.mkShell {
packages = [
nix-unit
inputs.mdbook-nixdoc.packages.${system}.default
(pkgs.python3.withPackages (_ps: [ ]))
venv
pkgs.hivemind
pkgs.reflex
] ++ self.packages.${system}.doc.nativeBuildInputs;

shellHook = ''
source ${venv}/bin/activate
'';
};

in
Expand Down
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()