I test reportlab with multiple pythons. Rather than having to install into different virtualenvs I prefer to build my C-extensions in the repository using pythonxx setup.py build_ext and place the repository source folder onto the python path (using eg a link). However, this means I must load the extensions from somewhere other than their natural place. The BuiltExtensionFinder can be used for this.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 | '''
BuiltExtensionFinder(
{'buildpath0': dotted_module_name0,
....
'buildpath1': dotted_module_name1,
}
)
creates a built c-extension module finder. This allows for a single code repository
to have all of its extensions built using python setup.py build_ext with different
python versions and have these extensions loadable without installation into the
different python areas.
#eg:
import sys
from builtextensionfinder import BuiltExtensionFinder
sys.meta_path.append(
BuiltExtensionFinder(
{r'c:\code\hg-repos\reportlab\build':(
'reportlab.graphics._renderPM',
'reportlab.lib._rl_accel',
),
r'c:\code\hg-repos\pyRXP\build': 'pyRXPU',
}
)
)
'''
__all__=('BuiltExtensionFinder',)
import sys, os
from distutils.util import get_platform
if sys.version_info[:2]<(3,4):
import imp
class BuiltExtensionFinder(object):
libname = 'lib.%s-%d.%d' % (get_platform(),sys.version_info[0],sys.version_info[1])
EXTENSION_SUFFIXES = tuple(x[0] for x in imp.get_suffixes() if x[2]==imp.C_EXTENSION)
def __init__(self,build_roots={}):
self.overrides = {}
for k, V in build_roots.items():
if not isinstance(V,(list,tuple)):
V = (V,)
for v in V:
self.overrides[v] = os.path.join(k,self.libname,*v.split('.'))
self.module = None
def find_module(self, name, path=None):
if name in self.overrides:
fnroot = self.overrides[name]
alt_paths = [os.path.dirname(fnroot)]
modname = name.split('.')[-1]
for sfx in self.EXTENSION_SUFFIXES:
fn = fnroot + sfx
if os.path.isfile(fn):
try:
fpd = imp.find_module(modname,alt_paths)
if fpd:
try:
try:
m = imp.load_module(name,fpd[0],fpd[1],fpd[2])
if m:
m.__loader__ = self
self.module = m
return self
except:
pass
finally:
if fpd[0]: fpd[0].close()
except:
continue
def load_module(self, name):
if not self.module:
raise ImportError("Unable to load module %s" % name)
sys.modules[name] = m = self.module
self.module = None
return m
else:
from importlib.abc import MetaPathFinder
from importlib.machinery import ExtensionFileLoader, ModuleSpec
class BuiltExtensionFinder(MetaPathFinder):
libname = 'lib.%s-%d.%d' % (get_platform(),sys.version_info[0],sys.version_info[1])
from importlib.machinery import EXTENSION_SUFFIXES
def __init__(self,build_roots={}):
self.overrides = {}
for k, V in build_roots.items():
if not isinstance(V,(list,tuple)):
V = (V,)
for v in V:
self.overrides[v] = os.path.join(k,self.libname,*v.split('.'))
def find_spec(self,name,path,target=None):
if name in self.overrides:
fnroot=self.overrides[name]
for sfx in self.EXTENSION_SUFFIXES:
fn = fnroot + sfx
if os.path.isfile(fn):
spec = ModuleSpec(
name=name,
loader=ExtensionFileLoader(name,fn),
origin=fn,
is_package=False,
)
return spec
|