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