Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit aeb03c6

Browse filesBrowse files
committed
Simplify extension setup.
setupext currently has a complex machinery to define extension modules. Essentially, the problem is that numpy may not be installed at the time the extensions are declared, so we can't call np.get_include() to get the include paths. So we use a DelayedExtension class and a hook mechanism to inject the numpy include path later, once it becomes available. Instead, we can just declare a dummy extension (so that setuptools doesn't elide the call to build_ext), then swap in the correct extensions in build_ext.finalize_options(): at that point, numpy will have been installed and we don't need any crazy machinery.
1 parent d1060a8 commit aeb03c6
Copy full SHA for aeb03c6

File tree

Expand file treeCollapse file tree

2 files changed

+15
-81
lines changed
Filter options
Expand file treeCollapse file tree

2 files changed

+15
-81
lines changed

‎setup.py

Copy file name to clipboardExpand all lines: setup.py
+12-10Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
# to ensure that we error out properly for people with outdated setuptools
88
# and/or pip.
99
import sys
10-
from setuptools import setup
10+
from setuptools import setup, Extension
1111
from setuptools.command.test import test as TestCommand
1212
from setuptools.command.build_ext import build_ext as BuildExtCommand
1313

@@ -94,6 +94,12 @@ def __init__(self, dist):
9494

9595

9696
class BuildExtraLibraries(BuildExtCommand):
97+
def finalize_options(self):
98+
self.distribution.ext_modules[:] = [
99+
*filter(None, (package.get_extension()
100+
for package in good_packages))]
101+
super().finalize_options()
102+
97103
def build_extensions(self):
98104
# Remove the -Wstrict-prototypes option, it's not valid for C++. Fixed
99105
# in Py3.7 as bpo-5755.
@@ -119,7 +125,9 @@ def build_extensions(self):
119125
packages = []
120126
namespace_packages = []
121127
py_modules = []
122-
ext_modules = []
128+
# Dummy extension to trigger build_ext, which will swap it out with real
129+
# extensions that can depend on numpy for the build.
130+
ext_modules = [Extension('', [])]
123131
package_data = {}
124132
package_dir = {'': 'lib'}
125133
install_requires = []
@@ -178,9 +186,8 @@ def build_extensions(self):
178186
packages.extend(package.get_packages())
179187
namespace_packages.extend(package.get_namespace_packages())
180188
py_modules.extend(package.get_py_modules())
181-
ext = package.get_extension()
182-
if ext is not None:
183-
ext_modules.append(ext)
189+
# Extension modules only get added in build_ext, as numpy will have
190+
# been installed (as setup_requires) at that point.
184191
data = package.get_package_data()
185192
for key, val in data.items():
186193
package_data.setdefault(key, [])
@@ -200,11 +207,6 @@ def build_extensions(self):
200207
with open('lib/matplotlib/mpl-data/matplotlibrc', 'w') as fd:
201208
fd.write(''.join(template_lines))
202209

203-
# Finalize the extension modules so they can get the Numpy include
204-
# dirs
205-
for mod in ext_modules:
206-
mod.finalize()
207-
208210
# Finally, pass this all along to distutils to do the heavy lifting.
209211
setup(
210212
name="matplotlib",

‎setupext.py

Copy file name to clipboardExpand all lines: setupext.py
+3-71Lines changed: 3 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ def make_extension(name, files, *args, **kwargs):
203203
Any additional arguments are passed to the
204204
`distutils.core.Extension` constructor.
205205
"""
206-
ext = DelayedExtension(name, files, *args, **kwargs)
206+
ext = Extension(name, files, *args, **kwargs)
207207
for dir in get_base_dirs():
208208
include_dir = os.path.join(dir, 'include')
209209
if os.path.exists(include_dir):
@@ -213,7 +213,6 @@ def make_extension(name, files, *args, **kwargs):
213213
if os.path.exists(lib_dir):
214214
ext.library_dirs.append(lib_dir)
215215
ext.include_dirs.append('.')
216-
217216
return ext
218217

219218

@@ -702,79 +701,12 @@ def get_package_data(self):
702701
}
703702

704703

705-
class DelayedExtension(Extension, object):
706-
"""
707-
A distutils Extension subclass where some of its members
708-
may have delayed computation until reaching the build phase.
709-
710-
This is so we can, for example, get the Numpy include dirs
711-
after pip has installed Numpy for us if it wasn't already
712-
on the system.
713-
"""
714-
def __init__(self, *args, **kwargs):
715-
super().__init__(*args, **kwargs)
716-
self._finalized = False
717-
self._hooks = {}
718-
719-
def add_hook(self, member, func):
720-
"""
721-
Add a hook to dynamically compute a member.
722-
723-
Parameters
724-
----------
725-
member : string
726-
The name of the member
727-
728-
func : callable
729-
The function to call to get dynamically-computed values
730-
for the member.
731-
"""
732-
self._hooks[member] = func
733-
734-
def finalize(self):
735-
self._finalized = True
736-
737-
class DelayedMember(property):
738-
def __init__(self, name):
739-
self._name = name
740-
741-
def __get__(self, obj, objtype=None):
742-
result = getattr(obj, '_' + self._name, [])
743-
744-
if obj._finalized:
745-
if self._name in obj._hooks:
746-
result = obj._hooks[self._name]() + result
747-
748-
return result
749-
750-
def __set__(self, obj, value):
751-
setattr(obj, '_' + self._name, value)
752-
753-
include_dirs = DelayedMember('include_dirs')
754-
755-
756704
class Numpy(SetupPackage):
757705
name = "numpy"
758706

759-
@staticmethod
760-
def include_dirs_hook():
761-
if hasattr(builtins, '__NUMPY_SETUP__'):
762-
del builtins.__NUMPY_SETUP__
763-
import numpy
764-
importlib.reload(numpy)
765-
766-
ext = Extension('test', [])
767-
ext.include_dirs.append(numpy.get_include())
768-
if not has_include_file(
769-
ext.include_dirs, os.path.join("numpy", "arrayobject.h")):
770-
_log.warning(
771-
"The C headers for numpy could not be found. "
772-
"You may need to install the development package")
773-
774-
return [numpy.get_include()]
775-
776707
def add_flags(self, ext):
777-
ext.add_hook('include_dirs', self.include_dirs_hook)
708+
import numpy as np
709+
ext.include_dirs.append(np.get_include())
778710
ext.define_macros.extend([
779711
# Ensure that PY_ARRAY_UNIQUE_SYMBOL is uniquely defined for each
780712
# extension.

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.