How to do custom build.build and build_ext.build_ext classes in Python 3.12 (i.e., without the stdlib distutils)? #4062
-
I have this rather gigantic from distutils.command import build
from distutils.command.clean import clean
from distutils.dir_util import mkpath
import setuptools
from setuptools.command import build_ext
# ... many lines skipped over
class _M2CryptoBuild(build.build):
"""Enable swig_opts to inherit any include_dirs settings made elsewhere."""
user_options = build.build.user_options + \
[('openssl=', 'o', 'Prefix for openssl installation location')] + \
[('bundledlls', 'b', 'Bundle DLLs (win32 only)')]
def initialize_options(self):
"""Overload to enable custom openssl settings to be picked up."""
build.build.initialize_options(self)
self.openssl = None
self.bundledlls = None
class _M2CryptoBuildExt(build_ext.build_ext):
"""Enable swig_opts to inherit any include_dirs settings made elsewhere."""
user_options = build_ext.build_ext.user_options + \
[('openssl=', 'o', 'Prefix for openssl installation location')] + \
[('bundledlls', 'b', 'Bundle DLLs (win32 only)')]
def initialize_options(self):
"""Overload to enable custom openssl settings to be picked up."""
build_ext.build_ext.initialize_options(self)
self.openssl = None
self.bundledlls = None
def finalize_options(self):
# type: (None) -> None
"""Append custom openssl include file and library linking options."""
build_ext.build_ext.finalize_options(self)
self.openssl_default = None
# ... a lot of very complicated configuration to make build work
# on multiple platforms and with different architectures ...
def run(self):
"""
On Win32 platforms include the openssl dll's in the binary packages
"""
# ... more complicated stuff to make building on Win32 possible ...
build_ext.build_ext.run(self)
class Clean(clean):
def __init__(self, dist):
clean.__init__(self, dist)
def initialize_options(self):
clean.initialize_options(self)
self.all = True
def finalize_options(self):
clean.finalize_options(self)
def run(self):
clean.run(self)
garbage_list = [
os.path.join('src', 'M2Crypto', '*.so'),
os.path.join('src', 'M2Crypto', '*.pyd'),
os.path.join('src', 'M2Crypto', '*.dll')
]
for p in garbage_list:
for f in glob.glob(p):
if os.path.exists(f):
os.unlink(f) Now when I just try to import the same stuff from new locations: if sys.version_info[:2] < (3, 10):
from distutils.command import build
from distutils.command.clean import clean
from distutils.dir_util import mkpath
else:
from setuptools.command import build
from setuptools._distutils.command.clean import clean
from setuptools.command import build_ext I get dreaded
I was looking at #3743 and the solution there (“just import directly from the stdlib distutils”) is obviously not applicable any more for 3.12+. In the same time I cannot find anywhere any official (or non-official) documentation how to create custom classes with setuptools. Could anybody point me in the right direction please? |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 1 reply
-
Hi @mcepl, My understanding of how this works is the following:
Another note is that calling There is documentation on how to implement custom build sub-commands in https://setuptools.pypa.io/en/latest/userguide/extension.html and an example in #3762, but arbitrary commands to run in the CLI are no longer supported by setuptools. If you need custom runnable commands, maybe you can try tools like tox, nox, invoke, doit, etc... |
Beta Was this translation helpful? Give feedback.
Hi @mcepl,
My understanding of how this works is the following:
setuptools._distutils
is private for a reason and should not be imported.Indeed as discussed in #3743, importing directly from
setuptools._distutils
will actively break your code.This happens because
setuptools._distutils
is not implemented in such a way that it can be imported directly, but instead it needs to go through a customMetaPathFinder
implemented by setuptools.The statement in:
is not "completely" valid. Note that the solution presented in the other discussion was never "import directly…