import os import sys import re __all__ = ['WrapperBase','WrapperCPPMacro','WrapperCCode'] class WrapperBase: def __init__(self): self.srcdir = os.path.join(os.path.dirname(__file__),'src') return def warning(self, message): print >> sys.stderr, message def info(self, message): print >> sys.stderr, message def get_resource_content(self, name, ext): if name.startswith('pyobj_to_'): try: return self.generate_pyobj_to_ctype_c(name[9:]) except NotImplementedError: pass elif name.startswith('pyobj_from_'): try: return self.generate_pyobj_from_ctype_c(name[11:]) except NotImplementedError: pass generator_mth_name = 'generate_' + name + ext.replace('.','_') generator_mth = getattr(self, generator_mth_name, lambda : None) body = generator_mth() if body is not None: return body fn = os.path.join(self.srcdir,name+ext) if os.path.isfile(fn): f = open(fn,'r') body = f.read() f.close() return body self.warning('No such file: %r' % (fn)) return def get_dependencies(self, code): l = [] for uses in re.findall(r'(?<=depends:)([,\w\s.]+)', code, re.I): for use in uses.split(','): use = use.strip() if not use: continue l.append(use) return l def resolve_dependencies(self, parent, body): assert isinstance(body, str),type(body) for d in self.get_dependencies(body): if d.endswith('.cpp'): WrapperCPPMacro(parent, d[:-4]) elif d.endswith('.c'): WrapperCCode(parent, d[:-2]) else: self.warning('Unknown dependence: %r.' % (d)) return def apply_attributes(self, template): """ Apply instance attributes to template string. Replace rules for attributes: _list - will be joined with newline _clist - _list will be joined with comma _elist - _list will be joined ..+.. - attributes will be added [..] - will be evaluated """ replace_names = set(re.findall(r'[ ]*%\(.*?\)s', template)) d = {} for name in replace_names: tab = ' ' * (len(name)-len(name.lstrip())) name = name.lstrip()[2:-2] names = name.split('+') joinsymbol = '\n' attrs = None for n in names: realname = n.strip() if n.endswith('_clist'): joinsymbol = ', ' realname = realname[:-6] + '_list' elif n.endswith('_elist'): joinsymbol = '' realname = realname[:-6] + '_list' realname_lower = realname.lower() parent = getattr(self,'parent',None) if hasattr(self, realname): attr = getattr(self, realname) elif hasattr(self, realname_lower): attr = getattr(self, realname_lower).upper() elif hasattr(parent, realname): attr = getattr(parent, realname) elif hasattr(parent, realname_lower): attr = getattr(parent, realname_lower).upper() elif realname.startswith('['): attr = eval(realname) else: self.warning('Undefined %r attribute: %r' % (self.__class__.__name__, realname)) continue if attrs is None: attrs = attr else: attrs += attr if isinstance(attrs, list): attrs = joinsymbol.join(attrs) d[name] = str(attrs).replace('\n','\n'+tab) return template % d def apply_templates(self, child): for n in self.list_names: l = getattr(self,n + '_list') c = child.apply_attributes(getattr(child, n+'_template','')) if c: l.append(c) return class WrapperCPPMacro(WrapperBase): """ CPP macros """ def __init__(self, parent, name): WrapperBase.__init__(self) defined = parent.defined_cpp_code if name in defined: return defined.append(name) body = self.get_resource_content(name,'.cpp') if body is None: self.warning('Failed to get CPP macro %r content.' % (name)) return self.resolve_dependencies(parent, body) parent.header_list.append(body) return class WrapperCCode(WrapperBase): """ C code """ def __init__(self, parent, name): WrapperBase.__init__(self) defined = parent.defined_c_code if name in defined: return defined.append(name) body = self.get_resource_content(name,'.c') if body is None: self.warning('Failed to get C code %r content.' % (name)) return if isinstance(body, dict): for k,v in body.items(): self.resolve_dependencies(parent, v) for k,v in body.items(): l = getattr(parent,k+'_list') l.append(v) else: self.resolve_dependencies(parent, body) parent.c_code_list.append(body) return def generate_pyobj_to_ctype_c(self, ctype): from generate_pyobj_tofrom_funcs import pyobj_to_npy_scalar, pyobj_to_f2py_string if ctype.startswith('npy_'): return pyobj_to_npy_scalar(ctype) elif ctype.startswith('f2py_string'): return pyobj_to_f2py_string(ctype) raise NotImplementedError,`ctype` def generate_pyobj_from_ctype_c(self, ctype): from generate_pyobj_tofrom_funcs import pyobj_from_npy_scalar if ctype.startswith('npy_'): return pyobj_from_npy_scalar(ctype) raise NotImplementedError,`ctype`