1import re 2import functools 3import distutils.core 4import distutils.errors 5import distutils.extension 6 7from setuptools.extern.six.moves import map 8 9from .monkey import get_unpatched 10 11 12def _have_cython(): 13 """ 14 Return True if Cython can be imported. 15 """ 16 cython_impl = 'Cython.Distutils.build_ext' 17 try: 18 # from (cython_impl) import build_ext 19 __import__(cython_impl, fromlist=['build_ext']).build_ext 20 return True 21 except Exception: 22 pass 23 return False 24 25 26# for compatibility 27have_pyrex = _have_cython 28 29_Extension = get_unpatched(distutils.core.Extension) 30 31 32class Extension(_Extension): 33 """Extension that uses '.c' files in place of '.pyx' files""" 34 35 def __init__(self, name, sources, *args, **kw): 36 # The *args is needed for compatibility as calls may use positional 37 # arguments. py_limited_api may be set only via keyword. 38 self.py_limited_api = kw.pop("py_limited_api", False) 39 _Extension.__init__(self, name, sources, *args, **kw) 40 41 def _convert_pyx_sources_to_lang(self): 42 """ 43 Replace sources with .pyx extensions to sources with the target 44 language extension. This mechanism allows language authors to supply 45 pre-converted sources but to prefer the .pyx sources. 46 """ 47 if _have_cython(): 48 # the build has Cython, so allow it to compile the .pyx files 49 return 50 lang = self.language or '' 51 target_ext = '.cpp' if lang.lower() == 'c++' else '.c' 52 sub = functools.partial(re.sub, '.pyx$', target_ext) 53 self.sources = list(map(sub, self.sources)) 54 55 56class Library(Extension): 57 """Just like a regular Extension, but built as a library instead""" 58