Hi all,
Does pip install -e . – editable installation with pip for a project available locally with pyproject.toml – not run setup.py? Because I have a project I am developing, with a pyproject.toml that installs with some custom steps expressed with setup.py which works with pip install . and python -m build (as per PyPa, IIRC), but the custom steps seem to be entirely omitted when installing in “editable” mode.
The pyproject.toml, edited for brevity:
[build-system]
requires = [ "setuptools", "setuptools-scm", "wheel" ]
build-backend = "setuptools.build_meta"
[project]
name = "foobar"
dynamic = [ "version" ]
requires-python = ">=3.11"
[tool.setuptools_scm]
The reason I have a setup.py is because there’s an additional step it expresses before the wheel is built – I run make to pre-process some Python code. Shouldn’t really matter how, but I need said additional step, and setup.py ended up being the way I could enable running the step:
import setuptools.command.build
from setuptools import Command, setup
import os
import os.path
import subprocess
class MakeCommand(Command):
"""Class of `setuptools`/`distutils` commands which invoke a `make` program.
GNU Make (http://www.gnu.org/software/make) is currently assumed for providing `make`. The program is invoked in a manner where it changes the working directory to the build directory advertised for the command (utilizing `self.set_undefined_options` as hinted at by [the documentation](http://setuptools.pypa.io/en/latest/userguide/extension.html) which defers to `help(setuptools.command.build.SubCommand)`).
The command is expected to produce build artefacts which will be added to the wheel.
"""
build_lib: str | None
def finalize_options(self) -> None:
self.set_undefined_options('build_py', ('build_lib', 'build_lib'))
def initialize_options(self) -> None:
self.build_lib = None
def run(self, *args, **kwargs) -> None:
os.makedirs(self.build_lib, exist_ok=True)
subprocess.check_call(('make', '-C', self.build_lib, '-f', os.path.realpath('Makefile')))
class BuildCommand(setuptools.command.build.build):
sub_commands = [ ('build_make', None) ] + setuptools.command.build.build.sub_commands # Makes the `build_make` command a sub-command of the `build` command, which has the effect of the former being invoked when the latter is invoked (which is invoked in turn when the wheel must be built, through the `bdist_wheel` command)
setup(cmdclass={ 'build': BuildCommand, 'build_make': MakeCommand })
I am not against abandoning setup.py – I am not sure if my particular set-up (in the broad(er) sense of the term) is “deprecated”. It was only an accident I noticed while doing local development that pip install -e . doesn’t end up invoking make as expressed with setup.py, which is essential for the project. Everything works exactly as intended with pip install ., in comparison. I am not sure I am doing this all correctly anymore – I want to declare what can be declared with pyproject.toml while make is run when building the wheel – my sdist should be the original (before make artifacts) source code.