@@ -214,7 +214,7 @@ def make_extension(name, files, *args, **kwargs):
214214 Any additional arguments are passed to the
215215 `distutils.core.Extension` constructor.
216216 """
217- ext = Extension (name , files , * args , ** kwargs )
217+ ext = DelayedExtension (name , files , * args , ** kwargs )
218218 for dir in get_base_dirs ():
219219 include_dir = os .path .join (dir , 'include' )
220220 if os .path .exists (include_dir ):
@@ -390,6 +390,14 @@ def get_install_requires(self):
390390 """
391391 return []
392392
393+ def get_setup_requires (self ):
394+ """
395+ Get a list of Python packages that we require at build time.
396+ pip/easy_install will attempt to download and install this
397+ package if it is not installed.
398+ """
399+ return []
400+
393401 def _check_for_pkg_config (self , package , include_file , min_version = None ,
394402 version = None ):
395403 """
@@ -647,42 +655,113 @@ def get_install_requires(self):
647655 return ['nose' ]
648656
649657
658+ class DelayedExtension (Extension , object ):
659+ """
660+ A distutils Extension subclass where some of its members
661+ may have delayed computation until reaching the build phase.
662+
663+ This is so we can, for example, get the Numpy include dirs
664+ after pip has installed Numpy for us if it wasn't already
665+ on the system.
666+ """
667+ def __init__ (self , * args , ** kwargs ):
668+ super (DelayedExtension , self ).__init__ (* args , ** kwargs )
669+ self ._finalized = False
670+ self ._hooks = {}
671+
672+ def add_hook (self , member , func ):
673+ """
674+ Add a hook to dynamically compute a member.
675+
676+ Parameters
677+ ----------
678+ member : string
679+ The name of the member
680+
681+ func : callable
682+ The function to call to get dynamically-computed values
683+ for the member.
684+ """
685+ self ._hooks [member ] = func
686+
687+ def finalize (self ):
688+ self ._finalized = True
689+
690+ class DelayedMember (property ):
691+ def __init__ (self , name ):
692+ self ._name = name
693+
694+ def __get__ (self , obj , objtype = None ):
695+ result = getattr (obj , '_' + self ._name , [])
696+
697+ if obj ._finalized :
698+ if self ._name in obj ._hooks :
699+ result = obj ._hooks [self ._name ]() + result
700+
701+ return result
702+
703+ def __set__ (self , obj , value ):
704+ setattr (obj , '_' + self ._name , value )
705+
706+ include_dirs = DelayedMember ('include_dirs' )
707+
708+
650709class Numpy (SetupPackage ):
651710 name = "numpy"
652711
712+ @staticmethod
713+ def include_dirs_hook ():
714+ if sys .version_info [0 ] >= 3 :
715+ import builtins
716+ if hasattr (builtins , '__NUMPY_SETUP__' ):
717+ del builtins .__NUMPY_SETUP__
718+ import imp
719+ import numpy
720+ imp .reload (numpy )
721+ else :
722+ import __builtin__
723+ if hasattr (__builtin__ , '__NUMPY_SETUP__' ):
724+ del __builtin__ .__NUMPY_SETUP__
725+ import numpy
726+ reload (numpy )
727+
728+ ext = Extension ('test' , [])
729+ ext .include_dirs .append (numpy .get_include ())
730+ if not has_include_file (
731+ ext .include_dirs , os .path .join ("numpy" , "arrayobject.h" )):
732+ warnings .warn (
733+ "The C headers for numpy could not be found. "
734+ "You may need to install the development package" )
735+
736+ return [numpy .get_include ()]
737+
653738 def check (self ):
654739 min_version = extract_versions ()['__version__numpy__' ]
655740 try :
656741 import numpy
657742 except ImportError :
658- raise SystemExit (
659- "Requires numpy %s or later to build. (Numpy not found)" %
660- min_version )
743+ return 'not found. pip may install it below.'
661744
662745 if not is_min_version (numpy .__version__ , min_version ):
663746 raise SystemExit (
664747 "Requires numpy %s or later to build. (Found %s)" %
665748 (min_version , numpy .__version__ ))
666749
667- ext = make_extension ('test' , [])
668- ext .include_dirs .append (numpy .get_include ())
669- if not has_include_file (
670- ext .include_dirs , os .path .join ("numpy" , "arrayobject.h" )):
671- raise CheckFailed (
672- "The C headers for numpy could not be found. You"
673- "may need to install the development package." )
674-
675750 return 'version %s' % numpy .__version__
676751
677752 def add_flags (self , ext ):
678- import numpy
679-
680753 # Ensure that PY_ARRAY_UNIQUE_SYMBOL is uniquely defined for
681754 # each extension
682755 array_api_name = 'MPL_' + ext .name .replace ('.' , '_' ) + '_ARRAY_API'
683756
684- ext .include_dirs .append (numpy .get_include ())
685757 ext .define_macros .append (('PY_ARRAY_UNIQUE_SYMBOL' , array_api_name ))
758+ ext .add_hook ('include_dirs' , self .include_dirs_hook )
759+
760+ def get_setup_requires (self ):
761+ return ['numpy>=1.5' ]
762+
763+ def get_install_requires (self ):
764+ return ['numpy>=1.5' ]
686765
687766
688767class CXX (SetupPackage ):
0 commit comments