Reputation: 148965
In order to be able to translate GNU gettext po files into mo ones at build time in setuptools, I have created a subclass of setuptools.command.build_py
that compiles them (through a copy of pymsgfmt) before calling its base class:
from setuptools.command.build_py import build_py as _build_py
class build_py(_build_py):
parent = _build_py
def run(self):
self.compile_po_files() # internal implementation
self.parent.run(self)
def get_outputs(self): # overriden to produce a correct list of installed files
build_mo = self.get_finalized_command("build_mo")
return _build_py.get_outputs(self) + self.outputs
Then I have only to declare it in the cmdclass
parameter of setup
:
setup(
...
cmdclass = {"build_py", mypgk.build_py},
)
So far, so good, when my module is installed and imported in the setup.py
script, the build phase of setuptools correctly process my po files.
The goal would be to allow a simple installation of a source distribution with pip. Things look nice, because pip takes care of any dependency provided they are declared in a install_requires
, or setup_requires
parameter. And this is where the chicken and egg problem lies: the dependancy are installed when setup.py
is runned, but it cannot run without mypkg
being first installed.
I have tried to use the magic entry_points
to declare the build_py
override in mypkg
setup.py
script:
...
entry_points = {
"distutils.commands": [
"build_py = mypkg:build_py",
],
}
but it has no effects, while I can declare a working new build_mo
command that way:
entry_points = {
"distutils.commands": [
"build_mo = mypkg:build_py",
],
}
Long story short, python setup.py build_mo
calls my override, while python setup.py build_py
calls setuptools version.
Why does my attempt of overriding the build_py
command with an entry_points
declaration not work, and how could I do it?
Upvotes: 5
Views: 2234
Reputation: 148965
I was close to the solution. After some more research in setuptools
docs and sources, I finally realized that it already used the entry_points
machinery to override distutils
commands by its own ones.
That means that when you try to override a setuptools
command, in fact you propose a second override for the same command. Because of the way setuptools
processes it, only the first override found is used, and from my tests, setuptools
one is that first.
I can now say that because of that, only commands from distutils
that are not overriden in setuptools
can be processed that way. The good news is that build
is not overriden and that in normal use, build_py
is always called from build
.
As the build
command is not overriden by setuptools
, it is easy to replace it with an entry_point
. Then the custom build
command class can update the cmdclass
directory to declare the custom build_py
class because the base build
loads it. The code can be:
from distutils.command.build import build as _build
class build(_build):
parent = _build
def run(self):
self.distribution.cmdclass["build_py"] = build_py
self.parent.run(self)
In my test, it is enough to make setuptools
use the custom build_py
class with a simple
setup(
...
setup_requires = ["mypkg"],
)
Upvotes: 4