From 3c063d34f2adaac3a541a2f5b4e11cf63cb68370 Mon Sep 17 00:00:00 2001 From: adisbladis Date: Sun, 29 Sep 2024 03:48:20 +0000 Subject: [PATCH 1/4] build: Add editables package --- build/pkgs/editables/default.nix | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 build/pkgs/editables/default.nix diff --git a/build/pkgs/editables/default.nix b/build/pkgs/editables/default.nix new file mode 100644 index 0000000..206ab9c --- /dev/null +++ b/build/pkgs/editables/default.nix @@ -0,0 +1,22 @@ +{ + stdenv, + python3Packages, + pyprojectHook, + resolveBuildSystem, +}: +stdenv.mkDerivation { + inherit (python3Packages.editables) + pname + version + src + meta + ; + + nativeBuildInputs = + [ + pyprojectHook + ] + ++ resolveBuildSystem { + flit-core = [ ]; + }; +} From 68735655960efca8a381b7550998110132235bf1 Mon Sep 17 00:00:00 2001 From: adisbladis Date: Sun, 29 Sep 2024 03:48:40 +0000 Subject: [PATCH 2/4] flake: Use our builders to make venv --- flake.nix | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index 49a0fac..07bf333 100644 --- a/flake.nix +++ b/flake.nix @@ -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 From bad9fd0ffab67782419888b5d860a4f219017663 Mon Sep 17 00:00:00 2001 From: adisbladis Date: Sun, 29 Sep 2024 03:49:19 +0000 Subject: [PATCH 3/4] packages: Add tool to build an editable package impurely 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. --- doc/src/SUMMARY.md | 3 ++ packages/build-editable/.python-version | 1 + packages/build-editable/README.md | 23 +++++++++ packages/build-editable/pyproject.toml | 17 +++++++ .../src/build_editable/__init__.py | 49 +++++++++++++++++++ 5 files changed, 93 insertions(+) create mode 100644 packages/build-editable/.python-version create mode 100644 packages/build-editable/README.md create mode 100644 packages/build-editable/pyproject.toml create mode 100644 packages/build-editable/src/build_editable/__init__.py diff --git a/doc/src/SUMMARY.md b/doc/src/SUMMARY.md index 31117ed..2c881d9 100644 --- a/doc/src/SUMMARY.md +++ b/doc/src/SUMMARY.md @@ -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) diff --git a/packages/build-editable/.python-version b/packages/build-editable/.python-version new file mode 100644 index 0000000..e4fba21 --- /dev/null +++ b/packages/build-editable/.python-version @@ -0,0 +1 @@ +3.12 diff --git a/packages/build-editable/README.md b/packages/build-editable/README.md new file mode 100644 index 0000000..9e85a87 --- /dev/null +++ b/packages/build-editable/README.md @@ -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. diff --git a/packages/build-editable/pyproject.toml b/packages/build-editable/pyproject.toml new file mode 100644 index 0000000..38a7ce9 --- /dev/null +++ b/packages/build-editable/pyproject.toml @@ -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" diff --git a/packages/build-editable/src/build_editable/__init__.py b/packages/build-editable/src/build_editable/__init__.py new file mode 100644 index 0000000..a02c90e --- /dev/null +++ b/packages/build-editable/src/build_editable/__init__.py @@ -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() From fa6a83680d8a50992be32dfd427c7fee24187fe6 Mon Sep 17 00:00:00 2001 From: adisbladis Date: Sun, 29 Sep 2024 04:15:03 +0000 Subject: [PATCH 4/4] make-venv: Reorganise imports --- build/hooks/make-venv.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/build/hooks/make-venv.py b/build/hooks/make-venv.py index 93490ce..b1d70ab 100644 --- a/build/hooks/make-venv.py +++ b/build/hooks/make-venv.py @@ -1,4 +1,5 @@ #!/usr/bin/env python3 +import filecmp import os import os.path import shutil @@ -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)))