Chris@87: #!/usr/bin/env python Chris@87: """ Chris@87: Chris@87: Auxiliary functions for f2py2e. Chris@87: Chris@87: Copyright 1999,2000 Pearu Peterson all rights reserved, Chris@87: Pearu Peterson Chris@87: Permission to use, modify, and distribute this software is given under the Chris@87: terms of the NumPy (BSD style) LICENSE. Chris@87: Chris@87: Chris@87: NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. Chris@87: $Date: 2005/07/24 19:01:55 $ Chris@87: Pearu Peterson Chris@87: Chris@87: """ Chris@87: from __future__ import division, absolute_import, print_function Chris@87: Chris@87: import pprint Chris@87: import sys Chris@87: import types Chris@87: from functools import reduce Chris@87: Chris@87: from . import __version__ Chris@87: from . import cfuncs Chris@87: Chris@87: f2py_version = __version__.version Chris@87: Chris@87: Chris@87: errmess=sys.stderr.write Chris@87: #outmess=sys.stdout.write Chris@87: show=pprint.pprint Chris@87: Chris@87: options={} Chris@87: debugoptions=[] Chris@87: wrapfuncs = 1 Chris@87: Chris@87: Chris@87: def outmess(t): Chris@87: if options.get('verbose', 1): Chris@87: sys.stdout.write(t) Chris@87: Chris@87: def debugcapi(var): Chris@87: return 'capi' in debugoptions Chris@87: Chris@87: def _isstring(var): Chris@87: return 'typespec' in var and var['typespec']=='character' and (not isexternal(var)) Chris@87: Chris@87: def isstring(var): Chris@87: return _isstring(var) and not isarray(var) Chris@87: Chris@87: def ischaracter(var): Chris@87: return isstring(var) and 'charselector' not in var Chris@87: Chris@87: def isstringarray(var): Chris@87: return isarray(var) and _isstring(var) Chris@87: Chris@87: def isarrayofstrings(var): Chris@87: # leaving out '*' for now so that Chris@87: # `character*(*) a(m)` and `character a(m,*)` Chris@87: # are treated differently. Luckily `character**` is illegal. Chris@87: return isstringarray(var) and var['dimension'][-1]=='(*)' Chris@87: Chris@87: def isarray(var): Chris@87: return 'dimension' in var and (not isexternal(var)) Chris@87: Chris@87: def isscalar(var): Chris@87: return not (isarray(var) or isstring(var) or isexternal(var)) Chris@87: Chris@87: def iscomplex(var): Chris@87: return isscalar(var) and var.get('typespec') in ['complex', 'double complex'] Chris@87: Chris@87: def islogical(var): Chris@87: return isscalar(var) and var.get('typespec')=='logical' Chris@87: Chris@87: def isinteger(var): Chris@87: return isscalar(var) and var.get('typespec')=='integer' Chris@87: Chris@87: def isreal(var): Chris@87: return isscalar(var) and var.get('typespec')=='real' Chris@87: Chris@87: def get_kind(var): Chris@87: try: Chris@87: return var['kindselector']['*'] Chris@87: except KeyError: Chris@87: try: Chris@87: return var['kindselector']['kind'] Chris@87: except KeyError: Chris@87: pass Chris@87: Chris@87: def islong_long(var): Chris@87: if not isscalar(var): Chris@87: return 0 Chris@87: if var.get('typespec') not in ['integer', 'logical']: Chris@87: return 0 Chris@87: return get_kind(var)=='8' Chris@87: Chris@87: def isunsigned_char(var): Chris@87: if not isscalar(var): Chris@87: return 0 Chris@87: if var.get('typespec') != 'integer': Chris@87: return 0 Chris@87: return get_kind(var)=='-1' Chris@87: Chris@87: def isunsigned_short(var): Chris@87: if not isscalar(var): Chris@87: return 0 Chris@87: if var.get('typespec') != 'integer': Chris@87: return 0 Chris@87: return get_kind(var)=='-2' Chris@87: Chris@87: def isunsigned(var): Chris@87: if not isscalar(var): Chris@87: return 0 Chris@87: if var.get('typespec') != 'integer': Chris@87: return 0 Chris@87: return get_kind(var)=='-4' Chris@87: Chris@87: def isunsigned_long_long(var): Chris@87: if not isscalar(var): Chris@87: return 0 Chris@87: if var.get('typespec') != 'integer': Chris@87: return 0 Chris@87: return get_kind(var)=='-8' Chris@87: Chris@87: def isdouble(var): Chris@87: if not isscalar(var): Chris@87: return 0 Chris@87: if not var.get('typespec')=='real': Chris@87: return 0 Chris@87: return get_kind(var)=='8' Chris@87: Chris@87: def islong_double(var): Chris@87: if not isscalar(var): Chris@87: return 0 Chris@87: if not var.get('typespec')=='real': Chris@87: return 0 Chris@87: return get_kind(var)=='16' Chris@87: Chris@87: def islong_complex(var): Chris@87: if not iscomplex(var): Chris@87: return 0 Chris@87: return get_kind(var)=='32' Chris@87: Chris@87: def iscomplexarray(var): Chris@87: return isarray(var) and var.get('typespec') in ['complex', 'double complex'] Chris@87: Chris@87: def isint1array(var): Chris@87: return isarray(var) and var.get('typespec')=='integer' \ Chris@87: and get_kind(var)=='1' Chris@87: Chris@87: def isunsigned_chararray(var): Chris@87: return isarray(var) and var.get('typespec') in ['integer', 'logical']\ Chris@87: and get_kind(var)=='-1' Chris@87: Chris@87: def isunsigned_shortarray(var): Chris@87: return isarray(var) and var.get('typespec') in ['integer', 'logical']\ Chris@87: and get_kind(var)=='-2' Chris@87: Chris@87: def isunsignedarray(var): Chris@87: return isarray(var) and var.get('typespec') in ['integer', 'logical']\ Chris@87: and get_kind(var)=='-4' Chris@87: Chris@87: def isunsigned_long_longarray(var): Chris@87: return isarray(var) and var.get('typespec') in ['integer', 'logical']\ Chris@87: and get_kind(var)=='-8' Chris@87: Chris@87: def issigned_chararray(var): Chris@87: return isarray(var) and var.get('typespec') in ['integer', 'logical']\ Chris@87: and get_kind(var)=='1' Chris@87: Chris@87: def issigned_shortarray(var): Chris@87: return isarray(var) and var.get('typespec') in ['integer', 'logical']\ Chris@87: and get_kind(var)=='2' Chris@87: Chris@87: def issigned_array(var): Chris@87: return isarray(var) and var.get('typespec') in ['integer', 'logical']\ Chris@87: and get_kind(var)=='4' Chris@87: Chris@87: def issigned_long_longarray(var): Chris@87: return isarray(var) and var.get('typespec') in ['integer', 'logical']\ Chris@87: and get_kind(var)=='8' Chris@87: Chris@87: def isallocatable(var): Chris@87: return 'attrspec' in var and 'allocatable' in var['attrspec'] Chris@87: Chris@87: def ismutable(var): Chris@87: return not (not 'dimension' in var or isstring(var)) Chris@87: Chris@87: def ismoduleroutine(rout): Chris@87: return 'modulename' in rout Chris@87: Chris@87: def ismodule(rout): Chris@87: return ('block' in rout and 'module'==rout['block']) Chris@87: Chris@87: def isfunction(rout): Chris@87: return ('block' in rout and 'function'==rout['block']) Chris@87: Chris@87: #def isfunction_wrap(rout): Chris@87: # return wrapfuncs and (iscomplexfunction(rout) or isstringfunction(rout)) and (not isexternal(rout)) Chris@87: Chris@87: def isfunction_wrap(rout): Chris@87: if isintent_c(rout): Chris@87: return 0 Chris@87: return wrapfuncs and isfunction(rout) and (not isexternal(rout)) Chris@87: Chris@87: def issubroutine(rout): Chris@87: return ('block' in rout and 'subroutine'==rout['block']) Chris@87: Chris@87: def issubroutine_wrap(rout): Chris@87: if isintent_c(rout): Chris@87: return 0 Chris@87: return issubroutine(rout) and hasassumedshape(rout) Chris@87: Chris@87: def hasassumedshape(rout): Chris@87: if rout.get('hasassumedshape'): Chris@87: return True Chris@87: for a in rout['args']: Chris@87: for d in rout['vars'].get(a, {}).get('dimension', []): Chris@87: if d==':': Chris@87: rout['hasassumedshape'] = True Chris@87: return True Chris@87: return False Chris@87: Chris@87: def isroutine(rout): Chris@87: return isfunction(rout) or issubroutine(rout) Chris@87: Chris@87: def islogicalfunction(rout): Chris@87: if not isfunction(rout): Chris@87: return 0 Chris@87: if 'result' in rout: Chris@87: a=rout['result'] Chris@87: else: Chris@87: a=rout['name'] Chris@87: if a in rout['vars']: Chris@87: return islogical(rout['vars'][a]) Chris@87: return 0 Chris@87: Chris@87: def islong_longfunction(rout): Chris@87: if not isfunction(rout): Chris@87: return 0 Chris@87: if 'result' in rout: Chris@87: a=rout['result'] Chris@87: else: Chris@87: a=rout['name'] Chris@87: if a in rout['vars']: Chris@87: return islong_long(rout['vars'][a]) Chris@87: return 0 Chris@87: Chris@87: def islong_doublefunction(rout): Chris@87: if not isfunction(rout): Chris@87: return 0 Chris@87: if 'result' in rout: Chris@87: a=rout['result'] Chris@87: else: Chris@87: a=rout['name'] Chris@87: if a in rout['vars']: Chris@87: return islong_double(rout['vars'][a]) Chris@87: return 0 Chris@87: Chris@87: def iscomplexfunction(rout): Chris@87: if not isfunction(rout): Chris@87: return 0 Chris@87: if 'result' in rout: Chris@87: a=rout['result'] Chris@87: else: Chris@87: a=rout['name'] Chris@87: if a in rout['vars']: Chris@87: return iscomplex(rout['vars'][a]) Chris@87: return 0 Chris@87: Chris@87: def iscomplexfunction_warn(rout): Chris@87: if iscomplexfunction(rout): Chris@87: outmess("""\ Chris@87: ************************************************************** Chris@87: Warning: code with a function returning complex value Chris@87: may not work correctly with your Fortran compiler. Chris@87: Run the following test before using it in your applications: Chris@87: $(f2py install dir)/test-site/{b/runme_scalar,e/runme} Chris@87: When using GNU gcc/g77 compilers, codes should work correctly. Chris@87: **************************************************************\n""") Chris@87: return 1 Chris@87: return 0 Chris@87: Chris@87: def isstringfunction(rout): Chris@87: if not isfunction(rout): Chris@87: return 0 Chris@87: if 'result' in rout: Chris@87: a=rout['result'] Chris@87: else: Chris@87: a=rout['name'] Chris@87: if a in rout['vars']: Chris@87: return isstring(rout['vars'][a]) Chris@87: return 0 Chris@87: Chris@87: def hasexternals(rout): Chris@87: return 'externals' in rout and rout['externals'] Chris@87: Chris@87: def isthreadsafe(rout): Chris@87: return 'f2pyenhancements' in rout and 'threadsafe' in rout['f2pyenhancements'] Chris@87: Chris@87: def hasvariables(rout): Chris@87: return 'vars' in rout and rout['vars'] Chris@87: Chris@87: def isoptional(var): Chris@87: return ('attrspec' in var and 'optional' in var['attrspec'] and 'required' not in var['attrspec']) and isintent_nothide(var) Chris@87: Chris@87: def isexternal(var): Chris@87: return ('attrspec' in var and 'external' in var['attrspec']) Chris@87: Chris@87: def isrequired(var): Chris@87: return not isoptional(var) and isintent_nothide(var) Chris@87: Chris@87: def isintent_in(var): Chris@87: if 'intent' not in var: Chris@87: return 1 Chris@87: if 'hide' in var['intent']: Chris@87: return 0 Chris@87: if 'inplace' in var['intent']: Chris@87: return 0 Chris@87: if 'in' in var['intent']: Chris@87: return 1 Chris@87: if 'out' in var['intent']: Chris@87: return 0 Chris@87: if 'inout' in var['intent']: Chris@87: return 0 Chris@87: if 'outin' in var['intent']: Chris@87: return 0 Chris@87: return 1 Chris@87: Chris@87: def isintent_inout(var): Chris@87: return 'intent' in var and ('inout' in var['intent'] or 'outin' in var['intent']) and 'in' not in var['intent'] and 'hide' not in var['intent'] and 'inplace' not in var['intent'] Chris@87: Chris@87: def isintent_out(var): Chris@87: return 'out' in var.get('intent', []) Chris@87: Chris@87: def isintent_hide(var): Chris@87: return ('intent' in var and ('hide' in var['intent'] or ('out' in var['intent'] and 'in' not in var['intent'] and (not l_or(isintent_inout, isintent_inplace)(var))))) Chris@87: Chris@87: def isintent_nothide(var): Chris@87: return not isintent_hide(var) Chris@87: Chris@87: def isintent_c(var): Chris@87: return 'c' in var.get('intent', []) Chris@87: Chris@87: # def isintent_f(var): Chris@87: # return not isintent_c(var) Chris@87: Chris@87: def isintent_cache(var): Chris@87: return 'cache' in var.get('intent', []) Chris@87: Chris@87: def isintent_copy(var): Chris@87: return 'copy' in var.get('intent', []) Chris@87: Chris@87: def isintent_overwrite(var): Chris@87: return 'overwrite' in var.get('intent', []) Chris@87: Chris@87: def isintent_callback(var): Chris@87: return 'callback' in var.get('intent', []) Chris@87: Chris@87: def isintent_inplace(var): Chris@87: return 'inplace' in var.get('intent', []) Chris@87: Chris@87: def isintent_aux(var): Chris@87: return 'aux' in var.get('intent', []) Chris@87: Chris@87: def isintent_aligned4(var): Chris@87: return 'aligned4' in var.get('intent', []) Chris@87: def isintent_aligned8(var): Chris@87: return 'aligned8' in var.get('intent', []) Chris@87: def isintent_aligned16(var): Chris@87: return 'aligned16' in var.get('intent', []) Chris@87: Chris@87: isintent_dict = {isintent_in: 'INTENT_IN', isintent_inout: 'INTENT_INOUT', Chris@87: isintent_out: 'INTENT_OUT', isintent_hide: 'INTENT_HIDE', Chris@87: isintent_cache: 'INTENT_CACHE', Chris@87: isintent_c: 'INTENT_C', isoptional: 'OPTIONAL', Chris@87: isintent_inplace: 'INTENT_INPLACE', Chris@87: isintent_aligned4: 'INTENT_ALIGNED4', Chris@87: isintent_aligned8: 'INTENT_ALIGNED8', Chris@87: isintent_aligned16: 'INTENT_ALIGNED16', Chris@87: } Chris@87: Chris@87: def isprivate(var): Chris@87: return 'attrspec' in var and 'private' in var['attrspec'] Chris@87: Chris@87: def hasinitvalue(var): Chris@87: return '=' in var Chris@87: Chris@87: def hasinitvalueasstring(var): Chris@87: if not hasinitvalue(var): Chris@87: return 0 Chris@87: return var['='][0] in ['"', "'"] Chris@87: Chris@87: def hasnote(var): Chris@87: return 'note' in var Chris@87: Chris@87: def hasresultnote(rout): Chris@87: if not isfunction(rout): Chris@87: return 0 Chris@87: if 'result' in rout: Chris@87: a=rout['result'] Chris@87: else: Chris@87: a=rout['name'] Chris@87: if a in rout['vars']: Chris@87: return hasnote(rout['vars'][a]) Chris@87: return 0 Chris@87: Chris@87: def hascommon(rout): Chris@87: return 'common' in rout Chris@87: Chris@87: def containscommon(rout): Chris@87: if hascommon(rout): Chris@87: return 1 Chris@87: if hasbody(rout): Chris@87: for b in rout['body']: Chris@87: if containscommon(b): Chris@87: return 1 Chris@87: return 0 Chris@87: Chris@87: def containsmodule(block): Chris@87: if ismodule(block): Chris@87: return 1 Chris@87: if not hasbody(block): Chris@87: return 0 Chris@87: for b in block['body']: Chris@87: if containsmodule(b): Chris@87: return 1 Chris@87: return 0 Chris@87: Chris@87: def hasbody(rout): Chris@87: return 'body' in rout Chris@87: Chris@87: def hascallstatement(rout): Chris@87: return getcallstatement(rout) is not None Chris@87: Chris@87: def istrue(var): Chris@87: return 1 Chris@87: Chris@87: def isfalse(var): Chris@87: return 0 Chris@87: Chris@87: class F2PYError(Exception): Chris@87: pass Chris@87: Chris@87: class throw_error: Chris@87: def __init__(self, mess): Chris@87: self.mess = mess Chris@87: def __call__(self, var): Chris@87: mess = '\n\n var = %s\n Message: %s\n' % (var, self.mess) Chris@87: raise F2PYError(mess) Chris@87: Chris@87: def l_and(*f): Chris@87: l, l2='lambda v', [] Chris@87: for i in range(len(f)): Chris@87: l='%s,f%d=f[%d]'%(l, i, i) Chris@87: l2.append('f%d(v)'%(i)) Chris@87: return eval('%s:%s'%(l, ' and '.join(l2))) Chris@87: Chris@87: def l_or(*f): Chris@87: l, l2='lambda v', [] Chris@87: for i in range(len(f)): Chris@87: l='%s,f%d=f[%d]'%(l, i, i) Chris@87: l2.append('f%d(v)'%(i)) Chris@87: return eval('%s:%s'%(l, ' or '.join(l2))) Chris@87: Chris@87: def l_not(f): Chris@87: return eval('lambda v,f=f:not f(v)') Chris@87: Chris@87: def isdummyroutine(rout): Chris@87: try: Chris@87: return rout['f2pyenhancements']['fortranname']=='' Chris@87: except KeyError: Chris@87: return 0 Chris@87: Chris@87: def getfortranname(rout): Chris@87: try: Chris@87: name = rout['f2pyenhancements']['fortranname'] Chris@87: if name=='': Chris@87: raise KeyError Chris@87: if not name: Chris@87: errmess('Failed to use fortranname from %s\n'%(rout['f2pyenhancements'])) Chris@87: raise KeyError Chris@87: except KeyError: Chris@87: name = rout['name'] Chris@87: return name Chris@87: Chris@87: def getmultilineblock(rout,blockname,comment=1,counter=0): Chris@87: try: Chris@87: r = rout['f2pyenhancements'].get(blockname) Chris@87: except KeyError: Chris@87: return Chris@87: if not r: return Chris@87: if counter > 0 and isinstance(r, str): Chris@87: return Chris@87: if isinstance(r, list): Chris@87: if counter>=len(r): return Chris@87: r = r[counter] Chris@87: if r[:3]=="'''": Chris@87: if comment: Chris@87: r = '\t/* start ' + blockname + ' multiline ('+repr(counter)+') */\n' + r[3:] Chris@87: else: Chris@87: r = r[3:] Chris@87: if r[-3:]=="'''": Chris@87: if comment: Chris@87: r = r[:-3] + '\n\t/* end multiline ('+repr(counter)+')*/' Chris@87: else: Chris@87: r = r[:-3] Chris@87: else: Chris@87: errmess("%s multiline block should end with `'''`: %s\n" \ Chris@87: % (blockname, repr(r))) Chris@87: return r Chris@87: Chris@87: def getcallstatement(rout): Chris@87: return getmultilineblock(rout, 'callstatement') Chris@87: Chris@87: def getcallprotoargument(rout,cb_map={}): Chris@87: r = getmultilineblock(rout, 'callprotoargument', comment=0) Chris@87: if r: return r Chris@87: if hascallstatement(rout): Chris@87: outmess('warning: callstatement is defined without callprotoargument\n') Chris@87: return Chris@87: from .capi_maps import getctype Chris@87: arg_types, arg_types2 = [], [] Chris@87: if l_and(isstringfunction, l_not(isfunction_wrap))(rout): Chris@87: arg_types.extend(['char*', 'size_t']) Chris@87: for n in rout['args']: Chris@87: var = rout['vars'][n] Chris@87: if isintent_callback(var): Chris@87: continue Chris@87: if n in cb_map: Chris@87: ctype = cb_map[n]+'_typedef' Chris@87: else: Chris@87: ctype = getctype(var) Chris@87: if l_and(isintent_c, l_or(isscalar, iscomplex))(var): Chris@87: pass Chris@87: elif isstring(var): Chris@87: pass Chris@87: #ctype = 'void*' Chris@87: else: Chris@87: ctype = ctype+'*' Chris@87: if isstring(var) or isarrayofstrings(var): Chris@87: arg_types2.append('size_t') Chris@87: arg_types.append(ctype) Chris@87: Chris@87: proto_args = ','.join(arg_types+arg_types2) Chris@87: if not proto_args: Chris@87: proto_args = 'void' Chris@87: #print proto_args Chris@87: return proto_args Chris@87: Chris@87: def getusercode(rout): Chris@87: return getmultilineblock(rout, 'usercode') Chris@87: Chris@87: def getusercode1(rout): Chris@87: return getmultilineblock(rout, 'usercode', counter=1) Chris@87: Chris@87: def getpymethoddef(rout): Chris@87: return getmultilineblock(rout, 'pymethoddef') Chris@87: Chris@87: def getargs(rout): Chris@87: sortargs, args=[], [] Chris@87: if 'args' in rout: Chris@87: args=rout['args'] Chris@87: if 'sortvars' in rout: Chris@87: for a in rout['sortvars']: Chris@87: if a in args: sortargs.append(a) Chris@87: for a in args: Chris@87: if a not in sortargs: Chris@87: sortargs.append(a) Chris@87: else: sortargs=rout['args'] Chris@87: return args, sortargs Chris@87: Chris@87: def getargs2(rout): Chris@87: sortargs, args=[], rout.get('args', []) Chris@87: auxvars = [a for a in rout['vars'].keys() if isintent_aux(rout['vars'][a])\ Chris@87: and a not in args] Chris@87: args = auxvars + args Chris@87: if 'sortvars' in rout: Chris@87: for a in rout['sortvars']: Chris@87: if a in args: sortargs.append(a) Chris@87: for a in args: Chris@87: if a not in sortargs: Chris@87: sortargs.append(a) Chris@87: else: sortargs=auxvars + rout['args'] Chris@87: return args, sortargs Chris@87: Chris@87: def getrestdoc(rout): Chris@87: if 'f2pymultilines' not in rout: Chris@87: return None Chris@87: k = None Chris@87: if rout['block']=='python module': Chris@87: k = rout['block'], rout['name'] Chris@87: return rout['f2pymultilines'].get(k, None) Chris@87: Chris@87: def gentitle(name): Chris@87: l=(80-len(name)-6)//2 Chris@87: return '/*%s %s %s*/'%(l*'*', name, l*'*') Chris@87: Chris@87: def flatlist(l): Chris@87: if isinstance(l, list): Chris@87: return reduce(lambda x,y,f=flatlist:x+f(y), l, []) Chris@87: return [l] Chris@87: Chris@87: def stripcomma(s): Chris@87: if s and s[-1]==',': return s[:-1] Chris@87: return s Chris@87: Chris@87: def replace(str,d,defaultsep=''): Chris@87: if isinstance(d, list): Chris@87: return [replace(str, _m, defaultsep) for _m in d] Chris@87: if isinstance(str, list): Chris@87: return [replace(_m, d, defaultsep) for _m in str] Chris@87: for k in 2*list(d.keys()): Chris@87: if k=='separatorsfor': Chris@87: continue Chris@87: if 'separatorsfor' in d and k in d['separatorsfor']: Chris@87: sep=d['separatorsfor'][k] Chris@87: else: Chris@87: sep=defaultsep Chris@87: if isinstance(d[k], list): Chris@87: str=str.replace('#%s#'%(k), sep.join(flatlist(d[k]))) Chris@87: else: Chris@87: str=str.replace('#%s#'%(k), d[k]) Chris@87: return str Chris@87: Chris@87: def dictappend(rd, ar): Chris@87: if isinstance(ar, list): Chris@87: for a in ar: Chris@87: rd=dictappend(rd, a) Chris@87: return rd Chris@87: for k in ar.keys(): Chris@87: if k[0]=='_': Chris@87: continue Chris@87: if k in rd: Chris@87: if isinstance(rd[k], str): Chris@87: rd[k]=[rd[k]] Chris@87: if isinstance(rd[k], list): Chris@87: if isinstance(ar[k], list): Chris@87: rd[k]=rd[k]+ar[k] Chris@87: else: Chris@87: rd[k].append(ar[k]) Chris@87: elif isinstance(rd[k], dict): Chris@87: if isinstance(ar[k], dict): Chris@87: if k=='separatorsfor': Chris@87: for k1 in ar[k].keys(): Chris@87: if k1 not in rd[k]: Chris@87: rd[k][k1]=ar[k][k1] Chris@87: else: Chris@87: rd[k]=dictappend(rd[k], ar[k]) Chris@87: else: Chris@87: rd[k]=ar[k] Chris@87: return rd Chris@87: Chris@87: def applyrules(rules,d,var={}): Chris@87: ret={} Chris@87: if isinstance(rules, list): Chris@87: for r in rules: Chris@87: rr=applyrules(r, d, var) Chris@87: ret=dictappend(ret, rr) Chris@87: if '_break' in rr: Chris@87: break Chris@87: return ret Chris@87: if '_check' in rules and (not rules['_check'](var)): Chris@87: return ret Chris@87: if 'need' in rules: Chris@87: res = applyrules({'needs':rules['need']}, d, var) Chris@87: if 'needs' in res: Chris@87: cfuncs.append_needs(res['needs']) Chris@87: Chris@87: for k in rules.keys(): Chris@87: if k=='separatorsfor': Chris@87: ret[k]=rules[k]; continue Chris@87: if isinstance(rules[k], str): Chris@87: ret[k]=replace(rules[k], d) Chris@87: elif isinstance(rules[k], list): Chris@87: ret[k]=[] Chris@87: for i in rules[k]: Chris@87: ar=applyrules({k:i}, d, var) Chris@87: if k in ar: Chris@87: ret[k].append(ar[k]) Chris@87: elif k[0]=='_': Chris@87: continue Chris@87: elif isinstance(rules[k], dict): Chris@87: ret[k]=[] Chris@87: for k1 in rules[k].keys(): Chris@87: if isinstance(k1, types.FunctionType) and k1(var): Chris@87: if isinstance(rules[k][k1], list): Chris@87: for i in rules[k][k1]: Chris@87: if isinstance(i, dict): Chris@87: res=applyrules({'supertext':i}, d, var) Chris@87: if 'supertext' in res: Chris@87: i=res['supertext'] Chris@87: else: i='' Chris@87: ret[k].append(replace(i, d)) Chris@87: else: Chris@87: i=rules[k][k1] Chris@87: if isinstance(i, dict): Chris@87: res=applyrules({'supertext':i}, d) Chris@87: if 'supertext' in res: Chris@87: i=res['supertext'] Chris@87: else: i='' Chris@87: ret[k].append(replace(i, d)) Chris@87: else: Chris@87: errmess('applyrules: ignoring rule %s.\n'%repr(rules[k])) Chris@87: if isinstance(ret[k], list): Chris@87: if len(ret[k])==1: Chris@87: ret[k]=ret[k][0] Chris@87: if ret[k]==[]: Chris@87: del ret[k] Chris@87: return ret