def write_dt_wrappers(self, node, el): cls_name = ft.strip_type(el.type).title() cls_mod_name = self.types[ft.strip_type(el.type)].mod_name dct = dict(el_name=el.name, mod_name=self.f90_mod_name, prefix=self.prefix, type_name=node.name, cls_name=cls_name, cls_mod_name=cls_mod_name, handle=isinstance(node, ft.Type) and 'self._handle' or '') if isinstance(node, ft.Type): dct['set_args'] = '%(handle)s, %(el_name)s' % dct else: dct['set_args'] = '%(el_name)s' % dct self.write('''@property def %(el_name)s(self):''' % dct) self.indent() self.write(self.format_doc_string(el)) self.write( '''%(el_name)s_handle = %(mod_name)s.%(prefix)s%(type_name)s__get__%(el_name)s(%(handle)s) if tuple(%(el_name)s_handle) in self._objs: %(el_name)s = self._objs[tuple(%(el_name)s_handle)] else: %(el_name)s = %(cls_mod_name)s.%(cls_name)s.from_handle(%(el_name)s_handle) self._objs[tuple(%(el_name)s_handle)] = %(el_name)s return %(el_name)s''' % dct) self.dedent() self.write() self.write('''@%(el_name)s.setter def %(el_name)s(self, %(el_name)s): %(el_name)s = %(el_name)s._handle %(mod_name)s.%(prefix)s%(type_name)s__set__%(el_name)s(%(set_args)s) ''' % dct) self.write()
def fix_subroutine_uses_clauses(tree, types): """Walk over all nodes in tree, updating subroutine uses clauses to include the parent module and all necessary modules from types Also rename any arguments that clash with module names. """ for mod, sub, arguments in ft.walk_procedures(tree): sub.uses = set() sub.mod_name = None if mod is not None: sub_name = sub.name if hasattr(sub, 'call_name'): sub_name = sub.call_name sub.uses.add((mod.name, (sub_name, ))) sub.mod_name = mod.name for arg in arguments: if arg.type.startswith('type') and ft.strip_type( arg.type) in types: sub.uses.add((types[ft.strip_type(arg.type)].mod_name, (ft.strip_type(arg.type), ))) for mod, sub, arguments in ft.walk_procedures(tree): for arg in arguments: for (mod_name, type_name) in sub.uses: if arg.name == mod_name: arg.name += '_' return tree
def fix_subroutine_uses_clauses(tree, types): """Walk over all nodes in tree, updating subroutine uses clauses to include the parent module and all necessary modules from types Also rename any arguments that clash with module names. """ for mod, sub, arguments in ft.walk_procedures(tree): sub.uses = set() sub.mod_name = None if mod is not None: sub_name = sub.name if hasattr(sub, 'call_name'): sub_name = sub.call_name sub.uses.add((mod.name, (sub_name,))) sub.mod_name = mod.name for arg in arguments: if arg.type.startswith('type') and ft.strip_type(arg.type) in types: sub.uses.add((types[ft.strip_type(arg.type)].mod_name, (ft.strip_type(arg.type),))) for mod, sub, arguments in ft.walk_procedures(tree): for arg in arguments: for (mod_name, type_name) in sub.uses: if arg.name == mod_name: arg.name += '_' return tree
def visit_Procedure(self, node): def py_arg_value(arg): if 'optional' in arg.attributes or arg.value is None: return '=None' else: return '' logging.info('PythonWrapperGenerator visiting routine %s' % node.name) if 'constructor' in node.attributes: self.write_constructor(node) elif 'destructor' in node.attributes: self.write_destructor(node) else: dct = dict(func_name=node.name, method_name=hasattr(node, 'method_name') and node.method_name or node.name, prefix=self.prefix, mod_name=self.f90_mod_name, py_arg_names=', '.join([arg.py_name+py_arg_value(arg) for arg in node.arguments]), f90_arg_names=', '.join(['%s=%s' % (arg.name, arg.py_value) for arg in node.arguments]), call='') if isinstance(node, ft.Function): dct['result'] = ', '.join([ret_val.name for ret_val in node.ret_val]) dct['call'] = '%(result)s = ' % dct if not self.make_package and node.mod_name is not None and node.type_name is None: # procedures outside of derived types become static methods self.write('@staticmethod') self.write("def %(method_name)s(%(py_arg_names)s):" % dct) self.indent() self.write(format_doc_string(node)) for arg in node.arguments: if 'optional' in arg.attributes and '._handle' in arg.py_value: dct['f90_arg_names'] = dct['f90_arg_names'].replace(arg.py_value, ('None if %(arg_py_name)s is None else %(arg_py_name)s._handle') % {'arg_py_name': arg.py_name}) call_line = '%(call)s%(mod_name)s.%(prefix)s%(func_name)s(%(f90_arg_names)s)' % dct self.write(call_line) if isinstance(node, ft.Function): # convert any derived type return values to Python objects for ret_val in node.ret_val: if ret_val.type.startswith('type'): cls_name = normalise_class_name(ft.strip_type(ret_val.type), self.class_names) cls_name = self.py_mod_name + '.' + cls_name cls_name = 'f90wrap.runtime.lookup_class("%s")' % cls_name cls_mod_name = self.types[ft.strip_type(ret_val.type)].mod_name cls_mod_name = self.py_mod_names.get(cls_mod_name, cls_mod_name) # if self.make_package: # if cls_mod_name != self.current_module: # self.imports.add((self.py_mod_name + '.' + cls_mod_name, cls_name)) # else: # cls_name = cls_mod_name + '.' + cls_name self.write('%s = %s.from_handle(%s)' % (ret_val.name, cls_name, ret_val.name)) self.write('return %(result)s' % dct) self.dedent() self.write()
def visit_Procedure(self, node): logging.info('PythonWrapperGenerator visiting routine %s' % node.name) if 'constructor' in node.attributes: self.write_constructor(node) elif 'destructor' in node.attributes: self.write_destructor(node) else: dct = dict( func_name=node.name, method_name=hasattr(node, 'method_name') and node.method_name or node.name, prefix=self.prefix, mod_name=self.f90_mod_name, py_arg_names=', '.join([ '%s%s' % (arg.py_name, ('optional' in arg.attributes or arg.value is None) and '=None' or '') for arg in node.arguments ]), f90_arg_names=', '.join([ '%s=%s' % (arg.name, arg.py_value) for arg in node.arguments ]), call='') if isinstance(node, ft.Function): dct['result'] = ', '.join( [ret_val.name for ret_val in node.ret_val]) dct['call'] = '%(result)s = ' % dct if not self.make_package and node.mod_name is not None and node.type_name is None: # procedures outside of derived types become static methods self.write('@staticmethod') self.write("def %(method_name)s(%(py_arg_names)s):" % dct) self.indent() self.write(format_doc_string(node)) call_line = '%(call)s%(mod_name)s.%(prefix)s%(func_name)s(%(f90_arg_names)s)' % dct self.write(call_line) if isinstance(node, ft.Function): # convert any derived type return values to Python objects for ret_val in node.ret_val: if ret_val.type.startswith('type'): cls_name = ft.strip_type(ret_val.type).title() cls_mod_name = self.types[ft.strip_type( ret_val.type)].mod_name if self.make_package: if cls_mod_name != self.current_module: self.imports.add( (self.py_mod_name + '.' + cls_mod_name, cls_name)) else: cls_name = cls_mod_name + '.' + cls_name self.write('%s = %s.from_handle(%s)' % (ret_val.name, cls_name, ret_val.name)) self.write('return %(result)s' % dct) self.dedent() self.write()
def write_dt_wrappers(self, node, el): cls_name = ft.strip_type(el.type).title() cls_mod_name = self.types[ft.strip_type(el.type)].mod_name dct = dict(el_name=el.name, el_name_get=el.name, el_name_set=el.name, mod_name=self.f90_mod_name, prefix=self.prefix, type_name=node.name, cls_name=cls_name, cls_mod_name=cls_mod_name + '.', self='self', selfdot='self.', selfcomma='self, ', handle=isinstance(node, ft.Type) and 'self._handle' or '') if isinstance(node, ft.Type): dct['set_args'] = '%(handle)s, %(el_name)s' % dct else: dct['set_args'] = '%(el_name)s' % dct if self.make_package: dct['cls_mod_name'] = '' if cls_mod_name != self.current_module: self.imports.add( (self.py_mod_name + '.' + cls_mod_name, cls_name)) if not isinstance(node, ft.Module) or not self.make_package: self.write('@property') else: dct['el_name_get'] = 'get_' + el.name dct['el_name_set'] = 'set_' + el.name dct['self'] = '' dct['selfdot'] = '' dct['selfcomma'] = '' self.write('def %(el_name_get)s(%(self)s):' % dct) self.indent() self.write(format_doc_string(el)) if isinstance(node, ft.Module) and self.make_package: self.write('global %(el_name)s' % dct) self.write( '''%(el_name)s_handle = %(mod_name)s.%(prefix)s%(type_name)s__get__%(el_name)s(%(handle)s) if tuple(%(el_name)s_handle) in %(selfdot)s_objs: %(el_name)s = %(selfdot)s_objs[tuple(%(el_name)s_handle)] else: %(el_name)s = %(cls_mod_name)s%(cls_name)s.from_handle(%(el_name)s_handle) %(selfdot)s_objs[tuple(%(el_name)s_handle)] = %(el_name)s return %(el_name)s''' % dct) self.dedent() self.write() if 'parameter' not in el.attributes: if not isinstance(node, ft.Module) or not self.make_package: self.write('@%(el_name_set)s.setter' % dct) self.write('''def %(el_name_set)s(%(selfcomma)s%(el_name)s): %(el_name)s = %(el_name)s._handle %(mod_name)s.%(prefix)s%(type_name)s__set__%(el_name)s(%(set_args)s) ''' % dct) self.write()
def write_dt_wrappers(self, node, el, properties): cls_name = ft.strip_type(el.type).title() cls_mod_name = self.types[ft.strip_type(el.type)].mod_name dct = dict(el_name=el.name, el_name_get=el.name, el_name_set=el.name, mod_name=self.f90_mod_name, prefix=self.prefix, type_name=node.name, cls_name=cls_name, cls_mod_name=cls_mod_name + '.', self='self', selfdot='self.', selfcomma='self, ', handle=isinstance(node, ft.Type) and 'self._handle' or '') if isinstance(node, ft.Type): dct['set_args'] = '%(handle)s, %(el_name)s' % dct else: dct['set_args'] = '%(el_name)s' % dct if self.make_package: dct['cls_mod_name'] = '' if cls_mod_name != self.current_module: self.imports.add((self.py_mod_name + '.' + cls_mod_name, cls_name)) if not isinstance(node, ft.Module) or not self.make_package: self.write('@property') properties.append(el) else: dct['el_name_get'] = 'get_' + el.name dct['el_name_set'] = 'set_' + el.name dct['self'] = '' dct['selfdot'] = '' dct['selfcomma'] = '' self.write('def %(el_name_get)s(%(self)s):' % dct) self.indent() self.write(format_doc_string(el)) if isinstance(node, ft.Module) and self.make_package: self.write('global %(el_name)s' % dct) self.write('''%(el_name)s_handle = %(mod_name)s.%(prefix)s%(type_name)s__get__%(el_name)s(%(handle)s) if tuple(%(el_name)s_handle) in %(selfdot)s_objs: %(el_name)s = %(selfdot)s_objs[tuple(%(el_name)s_handle)] else: %(el_name)s = %(cls_mod_name)s%(cls_name)s.from_handle(%(el_name)s_handle) %(selfdot)s_objs[tuple(%(el_name)s_handle)] = %(el_name)s return %(el_name)s''' % dct) self.dedent() self.write() if 'parameter' not in el.attributes: if not isinstance(node, ft.Module) or not self.make_package: self.write('@%(el_name_set)s.setter' % dct) self.write('''def %(el_name_set)s(%(selfcomma)s%(el_name)s): %(el_name)s = %(el_name)s._handle %(mod_name)s.%(prefix)s%(type_name)s__set__%(el_name)s(%(set_args)s) ''' % dct) self.write()
def fix_element_uses_clauses(tree, types): """ Add uses clauses to derived type elements in modules """ for mod in ft.walk_modules(tree): for el in mod.elements: el.uses = set() if el.type.startswith('type') and ft.strip_type(el.type) in types: el.uses.add((types[el.type].mod_name, (ft.strip_type(el.type),))) return tree
def fix_element_uses_clauses(tree, types): """ Add uses clauses to derived type elements in modules """ for mod in ft.walk_modules(tree): for el in mod.elements: el.uses = set() if el.type.startswith('type') and ft.strip_type(el.type) in types: el.uses.add( (types[el.type].mod_name, (ft.strip_type(el.type), ))) return tree
def write_dt_array_wrapper(self, node, el, dims): if el.type.startswith('type') and len( ArrayDimensionConverter.split_dimensions(dims)) != 1: return func_name = 'init_array_%s' % el.name node.dt_array_initialisers.append(func_name) cls_name = normalise_class_name(ft.strip_type(el.type), self.class_names) mod_name = self.types[ft.strip_type(el.type)].mod_name cls_mod_name = self.py_mod_names.get(mod_name, mod_name) dct = dict(el_name=el.name, func_name=func_name, mod_name=node.name, type_name=ft.strip_type(el.type).lower(), f90_mod_name=self.f90_mod_name, prefix=self.prefix, self='self', selfdot='self.', parent='self', doc=format_doc_string(el), cls_name=cls_name, cls_mod_name=cls_mod_name + '.') if isinstance(node, ft.Module): dct['parent'] = 'f90wrap.runtime.empty_type' if self.make_package: dct['selfdot'] = '' dct['self'] = '' if self.make_package: dct['cls_mod_name'] = '' if cls_mod_name != self.current_module: self.imports.add( (self.py_mod_name + '.' + cls_mod_name, cls_name)) self.write('def %(func_name)s(%(self)s):' % dct) self.indent() if isinstance(node, ft.Module) and self.make_package: self.write('global %(el_name)s' % dct) self.write( '''%(selfdot)s%(el_name)s = f90wrap.runtime.FortranDerivedTypeArray(%(parent)s, %(f90_mod_name)s.%(prefix)s%(mod_name)s__array_getitem__%(el_name)s, %(f90_mod_name)s.%(prefix)s%(mod_name)s__array_setitem__%(el_name)s, %(f90_mod_name)s.%(prefix)s%(mod_name)s__array_len__%(el_name)s, %(doc)s, %(cls_mod_name)s%(cls_name)s)''' % dct) self.write('return %(selfdot)s%(el_name)s' % dct) self.dedent() self.write()
def write_dt_array_wrapper(self, node, el, dims): if el.type.startswith('type') and len(ArrayDimensionConverter.split_dimensions(dims)) != 1: return func_name = 'init_array_%s' % el.name node.dt_array_initialisers.append(func_name) cls_name = normalise_class_name(ft.strip_type(el.type), self.class_names) mod_name = self.types[ft.strip_type(el.type)].mod_name cls_mod_name = self.py_mod_names.get(mod_name, mod_name) dct = dict(el_name=el.name, func_name=func_name, mod_name=node.name, type_name=ft.strip_type(el.type).lower(), f90_mod_name=self.f90_mod_name, prefix=self.prefix, self='self', selfdot='self.', parent='self', doc=format_doc_string(el), cls_name=cls_name, cls_mod_name=cls_mod_name + '.') if isinstance(node, ft.Module): dct['parent'] = 'f90wrap.runtime.empty_type' if self.make_package: dct['selfdot'] = '' dct['self'] = '' if self.make_package: dct['cls_mod_name'] = '' if cls_mod_name != self.current_module: self.imports.add((self.py_mod_name + '.' + cls_mod_name, cls_name)) self.write('def %(func_name)s(%(self)s):' % dct) self.indent() if isinstance(node, ft.Module) and self.make_package: self.write('global %(el_name)s' % dct) self.write('''%(selfdot)s%(el_name)s = f90wrap.runtime.FortranDerivedTypeArray(%(parent)s, %(f90_mod_name)s.%(prefix)s%(mod_name)s__array_getitem__%(el_name)s, %(f90_mod_name)s.%(prefix)s%(mod_name)s__array_setitem__%(el_name)s, %(f90_mod_name)s.%(prefix)s%(mod_name)s__array_len__%(el_name)s, %(doc)s, %(cls_mod_name)s%(cls_name)s)''' % dct) self.write('return %(selfdot)s%(el_name)s' % dct) self.dedent() self.write()
def write_type_lines(self, tname): """ Write a pointer type for a given type name Parameters ---------- tname : `str` Should be the name of a derived type in the wrapped code. """ tname = ft.strip_type(tname) self.write("""type %(typename)s_ptr_type type(%(typename)s), pointer :: p => NULL() end type %(typename)s_ptr_type""" % {'typename': tname})
def convert_derived_type_arguments(tree, init_lines, sizeof_fortran_t): for mod, sub, arguments in ft.walk_procedures(tree, include_ret_val=True): sub.types = set() sub.transfer_in = [] sub.transfer_out = [] sub.allocate = [] sub.deallocate = [] if 'constructor' in sub.attributes: sub.arguments[0].attributes = set_intent( sub.arguments[0].attributes, 'intent(out)') if 'destructor' in sub.attributes: logging.debug('deallocating arg "%s" in %s' % (sub.arguments[0].name, sub.name)) sub.deallocate.append(sub.arguments[0].name) for arg in arguments: if not hasattr(arg, 'type') or not arg.type.startswith('type'): continue # save original Fortran intent since we'll be overwriting it # with intent of the opaque pointer arg.attributes = arg.attributes + [ 'fortran_' + attr for attr in arg.attributes if attr.startswith('intent') ] typename = ft.strip_type(arg.type) arg.wrapper_type = 'integer' arg.wrapper_dim = sizeof_fortran_t sub.types.add(typename) if typename in init_lines: use, (exe, exe_optional) = init_lines[typename] if use is not None: sub.uses.add((use, [typename])) arg.init_lines = (exe_optional, exe) if 'intent(out)' in arg.attributes: arg.attributes = set_intent(arg.attributes, 'intent(out)') sub.transfer_out.append(arg.name) if 'pointer' not in arg.attributes: logging.debug('allocating arg "%s" in %s' % (arg.name, sub.name)) sub.allocate.append(arg.name) else: arg.attributes = set_intent(arg.attributes, 'intent(in)') sub.transfer_in.append(arg.name) return tree
def convert_derived_type_arguments(tree, init_lines, sizeof_fortran_t): for mod, sub, arguments in ft.walk_procedures(tree, include_ret_val=True): sub.types = set() sub.transfer_in = [] sub.transfer_out = [] sub.allocate = [] sub.deallocate = [] if 'constructor' in sub.attributes: sub.arguments[0].attributes = set_intent(sub.arguments[0].attributes, 'intent(out)') if 'destructor' in sub.attributes: logging.debug('deallocating arg "%s" in %s' % (sub.arguments[0].name, sub.name)) sub.deallocate.append(sub.arguments[0].name) for arg in arguments: if not hasattr(arg, 'type') or not arg.type.startswith('type'): continue # save original Fortran intent since we'll be overwriting it # with intent of the opaque pointer arg.attributes = arg.attributes + ['fortran_' + attr for attr in arg.attributes if attr.startswith('intent')] typename = ft.strip_type(arg.type) arg.wrapper_type = 'integer' arg.wrapper_dim = sizeof_fortran_t sub.types.add(typename) if typename in init_lines: use, (exe, exe_optional) = init_lines[typename] if use is not None: sub.uses.add((use, [typename])) arg.init_lines = (exe_optional, exe) if 'intent(out)' in arg.attributes: arg.attributes = set_intent(arg.attributes, 'intent(out)') sub.transfer_out.append(arg.name) if 'pointer' not in arg.attributes: logging.debug('allocating arg "%s" in %s' % (arg.name, sub.name)) sub.allocate.append(arg.name) else: arg.attributes = set_intent(arg.attributes, 'intent(in)') sub.transfer_in.append(arg.name) return tree
def visit_Interface(self, node): logging.info('PythonWrapperGenerator visiting interface %s' % node.name) # first output all the procedures within the interface self.generic_visit(node) cls_name = None if node.type_name is not None: cls_name = normalise_class_name(ft.strip_type(node.type_name), self.class_names) proc_names = [] for proc in node.procedures: proc_name = '' if not self.make_package: proc_name += normalise_class_name(proc.mod_name, self.class_names) + '.' elif cls_name is not None: proc_name += cls_name + '.' if hasattr(proc, 'method_name'): proc_name += proc.method_name else: proc_name += proc.name proc_names.append(proc_name) dct = dict(intf_name=node.method_name, proc_names='[' + ', '.join(proc_names) + ']') if not self.make_package: # procedures outside of derived types become static methods self.write('@staticmethod') self.write('def %(intf_name)s(*args, **kwargs):' % dct) self.indent() self.write(format_doc_string(node)) # try to call each in turn until no TypeError raised self.write('for proc in %(proc_names)s:' % dct) self.indent() self.write('try:') self.indent() self.write('return proc(*args, **kwargs)') self.dedent() self.write('except TypeError:') self.indent() self.write('continue') self.dedent() self.dedent() self.dedent() self.write()
def fix_subroutine_uses_clauses(tree, types): """Walk over all nodes in tree, updating subroutine uses clauses to include the parent module and all necessary modules from types""" for mod, sub, arguments in ft.walk_procedures(tree): sub.uses = set() sub.mod_name = None if mod is not None: sub.uses.add((mod.name, (sub.name,))) sub.mod_name = mod.name for arg in arguments: if arg.type.startswith('type') and arg.type in types: sub.uses.add((types[arg.type].mod_name, (ft.strip_type(arg.type),))) return tree
def fix_subroutine_uses_clauses(tree, types): """Walk over all nodes in tree, updating subroutine uses clauses to include the parent module and all necessary modules from types""" for mod, sub, arguments in ft.walk_procedures(tree): sub.uses = set() sub.mod_name = None if mod is not None: sub.uses.add((mod.name, (sub.name, ))) sub.mod_name = mod.name for arg in arguments: if arg.type.startswith('type') and arg.type in types: sub.uses.add( (types[arg.type].mod_name, (ft.strip_type(arg.type), ))) return tree
def visit_Interface(self, node): logging.info('PythonWrapperGenerator visiting interface %s' % node.name) # first output all the procedures within the interface self.generic_visit(node) cls_name = None if node.type_name is not None: cls_name = normalise_class_name(ft.strip_type(node.type_name), self.class_names) proc_names = [] for proc in node.procedures: proc_name = '' if not self.make_package: proc_name += proc.mod_name.title()+'.' elif cls_name is not None: proc_name += cls_name+'.' if hasattr(proc, 'method_name'): proc_name += proc.method_name else: proc_name += proc.name proc_names.append(proc_name) dct = dict(intf_name=node.method_name, proc_names='[' + ', '.join(proc_names) + ']') if not self.make_package: # procedures outside of derived types become static methods self.write('@staticmethod') self.write('def %(intf_name)s(*args, **kwargs):' % dct) self.indent() self.write(format_doc_string(node)) # try to call each in turn until no TypeError raised self.write('for proc in %(proc_names)s:' % dct) self.indent() self.write('try:') self.indent() self.write('return proc(*args, **kwargs)') self.dedent() self.write('except TypeError:') self.indent() self.write('continue') self.dedent() self.dedent() self.dedent() self.write()
def write_type_lines(self, tname, recursive=False): """ Write a pointer type for a given type name Parameters ---------- tname : `str` Should be the name of a derived type in the wrapped code. recursive : `boolean` Adjusts array pointer for recursive derived type array """ tname = ft.strip_type(tname) if not recursive: self.write("""type %(typename)s_ptr_type type(%(typename)s), pointer :: p => NULL() end type %(typename)s_ptr_type""" % {'typename': tname}) else: self.write("""type %(typename)s_rec_ptr_type type(%(typename)s), pointer :: p => NULL() end type %(typename)s_rec_ptr_type""" % {'typename': tname})
def _write_scalar_wrapper(self, t, el, sizeof_fortran_t, getset): """ Write get/set routines for scalar derived-types. Parameters ---------- t : `fortran.Type` node Derived-type node of the parse tree. el : `fortran.Element` node An element of a module which is derived-type array sizeof_fortan_t : `int` The size, in bytes, of a pointer to a fortran derived type ?? getset : `str` {``"get"``,``"set"``} String indicating whether to write a get routine, or a set routine. """ # getset and inout just change things simply from a get to a set routine. inout = "in" if getset == "get": inout = "out" if isinstance(t, ft.Type): this = 'this, ' elif isinstance(t, ft.Module): this = '' else: raise ValueError("Don't know how to write scalar wrappers for %s type %s" (t, type(t))) self.write('subroutine %s%s__%s__%s(%s%s)' % (self.prefix, t.name, getset, el.name, this, el.name)) self.indent() self.write_uses_lines(t) if isinstance(t, ft.Module): use_only = [] use_only.append('%s_%s => %s' % (t.name, el.name, el.name)) use_only = ', '.join(use_only) self.write('use %s, only: ' % t.name + use_only) self.write('implicit none') if isinstance(t, ft.Type): self.write_type_lines(t.name) if el.type.startswith('type'): self.write_type_lines(el.type) if isinstance(t, ft.Type): self.write('integer, intent(in) :: this(%d)' % sizeof_fortran_t) self.write('type(%s_ptr_type) :: this_ptr' % t.name) if el.type.startswith('type'): # For derived types elements, treat as opaque reference self.write('integer, intent(%s) :: %s(%d)' % (inout, el.name, sizeof_fortran_t)) self.write('type(%s_ptr_type) :: %s_ptr' % (ft.strip_type(el.type), el.name)) self.write() if isinstance(t, ft.Type): self.write('this_ptr = transfer(this, this_ptr)') if getset == "get": if isinstance(t, ft.Type): self.write('%s_ptr%%p => this_ptr%%p%%%s' % (el.name, el.name)) else: self.write('%s_ptr%%p => %s_%s' % (el.name, t.name, el.name)) self.write('%s = transfer(%s_ptr,%s)' % (el.name, el.name, el.name)) else: self.write('%s_ptr = transfer(%s,%s_ptr)' % (el.name, el.name, el.name)) if isinstance(t, ft.Type): self.write('this_ptr%%p%%%s = %s_ptr%%p' % (el.name, el.name)) else: self.write('%s_%s = %s_ptr%%p' % (t.name, el.name, el.name)) else: # Return/set by value if 'pointer' in el.attributes: el.attributes.remove('pointer') if el.attributes != []: self.write('%s, %s, intent(%s) :: %s' % (el.type, ','.join(el.attributes), inout, el.name)) else: self.write('%s, intent(%s) :: %s' % (el.type, inout, el.name)) self.write() if isinstance(t, ft.Type): self.write('this_ptr = transfer(this, this_ptr)') if getset == "get": if isinstance(t, ft.Type): self.write('%s = this_ptr%%p%%%s' % (el.name, el.name)) else: self.write('%s = %s_%s' % (el.name, t.name, el.name)) else: if isinstance(t, ft.Type): self.write('this_ptr%%p%%%s = %s' % (el.name, el.name)) else: self.write('%s_%s = %s' % (t.name, el.name, el.name)) self.dedent() self.write('end subroutine %s%s__%s__%s' % (self.prefix, t.name, getset, el.name)) self.write()
def write_dt_wrappers(self, node, el, properties): cls_name = normalise_class_name(ft.strip_type(el.type), self.class_names) mod_name = self.types[ft.strip_type(el.type)].mod_name cls_mod_name = self.py_mod_names.get(mod_name, mod_name) dct = dict(el_name=el.name, el_name_get=el.name, el_name_set=el.name, mod_name=self.f90_mod_name, prefix=self.prefix, type_name=node.name, cls_name=cls_name, cls_mod_name=cls_mod_name + '.', self='self', selfdot='self.', selfcomma='self, ', handle=isinstance(node, ft.Type) and 'self._handle' or '') if isinstance(node, ft.Type): dct['set_args'] = '%(handle)s, %(el_name)s' % dct else: dct['set_args'] = '%(el_name)s' % dct if self.make_package: dct['cls_mod_name'] = '' if cls_mod_name != self.current_module: self.imports.add( (self.py_mod_name + '.' + cls_mod_name, cls_name)) if not isinstance(node, ft.Module) or not self.make_package: self.write('@property') properties.append(el) else: dct['el_name_get'] = 'get_' + el.name dct['el_name_set'] = 'set_' + el.name dct['self'] = '' dct['selfdot'] = '' dct['selfcomma'] = '' # check for name clashes with pre-existing routines if hasattr(node, 'procedures'): procs = [proc.name for proc in node.procedures] if dct['el_name_get'] in procs: dct['el_name_get'] += '_' if dct['el_name_set'] in procs: dct['el_name_set'] += '_' self.write('def %(el_name_get)s(%(self)s):' % dct) self.indent() self.write(format_doc_string(el)) if isinstance(node, ft.Module) and self.make_package: self.write('global %(el_name)s' % dct) self.write( '''%(el_name)s_handle = %(mod_name)s.%(prefix)s%(type_name)s__get__%(el_name)s(%(handle)s) if tuple(%(el_name)s_handle) in %(selfdot)s_objs: %(el_name)s = %(selfdot)s_objs[tuple(%(el_name)s_handle)] else: %(el_name)s = %(cls_mod_name)s%(cls_name)s.from_handle(%(el_name)s_handle) %(selfdot)s_objs[tuple(%(el_name)s_handle)] = %(el_name)s return %(el_name)s''' % dct) self.dedent() self.write() if 'parameter' not in el.attributes: if not isinstance(node, ft.Module) or not self.make_package: self.write('@%(el_name_set)s.setter' % dct) self.write('''def %(el_name_set)s(%(selfcomma)s%(el_name)s): %(el_name)s = %(el_name)s._handle %(mod_name)s.%(prefix)s%(type_name)s__set__%(el_name)s(%(set_args)s) ''' % dct) self.write()
def _write_scalar_wrapper(self, t, el, sizeof_fortran_t, getset): """ Write get/set routines for scalar elements of derived-types and modules Parameters ---------- t : `fortran.Type` node or `fortran.Module` node Node of the parse tree which contains this derived-type as an element el : `fortran.Element` node An element of a module which is derived-type array sizeof_fortan_t : `int` The size, in bytes, of a pointer to a fortran derived type ?? getset : `str` {``"get"``,``"set"``} String indicating whether to write a get routine, or a set routine. """ logging.debug('writing %s wrapper for %s.%s' % (getset, t.name, el.name)) # getset and inout just change things simply from a get to a set routine. inout = "in" if getset == "get": inout = "out" if isinstance(t, ft.Type): this = 'this, ' elif isinstance(t, ft.Module): this = '' else: raise ValueError( "Don't know how to write scalar wrappers for %s type %s" ( t, type(t))) # Get appropriate use statements extra_uses = {} if isinstance(t, ft.Module): extra_uses[t.name] = ['%s_%s => %s' % (t.name, el.name, el.name)] elif isinstance(t, ft.Type): extra_uses[self.types[t.name].mod_name] = [t.name] if el.type.startswith('type'): mod = self.types[el.type].mod_name el_tname = ft.strip_type(el.type) if mod in extra_uses: extra_uses[mod].append(el_tname) else: extra_uses[mod] = [el_tname] # If the var that is get/set has the same name as something in uses, then append _ localvar = el.name if localvar in getattr(el, "uses", []) or localvar in extra_uses: localvar += "_" self.write('subroutine %s%s__%s__%s(%s%s)' % (self.prefix, t.name, getset, el.name, this, localvar)) self.indent() self.write_uses_lines(el, extra_uses) self.write('implicit none') if isinstance(t, ft.Type): self.write_type_lines(t.name) if el.type.startswith('type'): self.write_type_lines(el.type) if isinstance(t, ft.Type): self.write('integer, intent(in) :: this(%d)' % sizeof_fortran_t) self.write('type(%s_ptr_type) :: this_ptr' % t.name) # Return/set by value attributes = [ attr for attr in el.attributes if attr not in ['pointer', 'allocatable', 'public', 'parameter', 'save'] ] if el.type.startswith('type'): # For derived types elements, treat as opaque reference self.write('integer, intent(%s) :: %s(%d)' % (inout, localvar, sizeof_fortran_t)) self.write('type(%s_ptr_type) :: %s_ptr' % (ft.strip_type(el.type), el.name)) self.write() if isinstance(t, ft.Type): self.write('this_ptr = transfer(this, this_ptr)') if getset == "get": if isinstance(t, ft.Type): self.write('%s_ptr%%p => this_ptr%%p%%%s' % (el.name, el.name)) else: self.write('%s_ptr%%p => %s_%s' % (el.name, t.name, el.name)) self.write('%s = transfer(%s_ptr,%s)' % (localvar, el.name, localvar)) else: self.write('%s_ptr = transfer(%s,%s_ptr)' % (el.name, localvar, el.name)) if isinstance(t, ft.Type): self.write('this_ptr%%p%%%s = %s_ptr%%p' % (el.name, el.name)) else: self.write('%s_%s = %s_ptr%%p' % (t.name, el.name, el.name)) else: if attributes != []: self.write('%s, %s, intent(%s) :: %s' % (el.type, ','.join(attributes), inout, localvar)) else: self.write('%s, intent(%s) :: %s' % (el.type, inout, localvar)) self.write() if isinstance(t, ft.Type): self.write('this_ptr = transfer(this, this_ptr)') if getset == "get": if isinstance(t, ft.Type): self.write('%s = this_ptr%%p%%%s' % (localvar, el.name)) else: self.write('%s = %s_%s' % (localvar, t.name, el.name)) else: if isinstance(t, ft.Type): self.write('this_ptr%%p%%%s = %s' % (el.name, localvar)) else: self.write('%s_%s = %s' % (t.name, el.name, localvar)) self.dedent() self.write('end subroutine %s%s__%s__%s' % (self.prefix, t.name, getset, el.name)) self.write()
def _write_array_len(self, t, el, sizeof_fortran_t): """ Write a subroutine which returns the length of a derived-type array Parameters ---------- t : `fortran.Type` node or `fortran.Module` node Node of the parse tree which contains this derived-type as an element el : `fortran.Element` node An element of a module which is derived-type array sizeof_fortan_t : `int` The size, in bytes, of a pointer to a fortran derived type ?? """ if isinstance(t, ft.Type): this = 'this' else: this = 'dummy_this' self.write('subroutine %s%s__array_len__%s(%s, n)' % (self.prefix, t.name, el.name, this)) self.indent() self.write() extra_uses = {} if isinstance(t, ft.Module): extra_uses[t.name] = ['%s_%s => %s' % (t.name, el.name, el.name)] elif isinstance(t, ft.Type): extra_uses[self.types[t.name].mod_name] = [t.name] mod = self.types[el.type].mod_name el_tname = ft.strip_type(el.type) if mod in extra_uses: extra_uses[mod].append(el_tname) else: extra_uses[mod] = [el_tname] self.write_uses_lines(el, extra_uses) self.write('implicit none') self.write() if isinstance(t, ft.Type): self.write_type_lines(t.name) self.write_type_lines(el.type) self.write('integer, intent(out) :: n') self.write('integer, intent(in) :: %s(%d)' % (this, sizeof_fortran_t)) if isinstance(t, ft.Type): self.write('type(%s_ptr_type) :: this_ptr' % t.name) self.write() self.write('this_ptr = transfer(this, this_ptr)') array_name = 'this_ptr%%p%%%s' % el.name else: array_name = '%s_%s' % (t.name, el.name) if 'allocatable' in el.attributes: self.write('if (allocated(%s)) then' % array_name) self.indent() self.write('n = size(%s)' % array_name) if 'allocatable' in el.attributes: self.dedent() self.write('else') self.indent() self.write('n = 0') self.dedent() self.write('end if') self.dedent() self.write('end subroutine %s%s__array_len__%s' % (self.prefix, t.name, el.name)) self.write()
def _write_array_getset_item(self, t, el, sizeof_fortran_t, getset): """ Write a subroutine to get/set items in a derived-type array. Parameters ---------- t : `fortran.Type` node Derived-type node of the parse tree. el : `fortran.Element` node An element of a module which is derived-type array sizeof_fortan_t : `int` The size, in bytes, of a pointer to a fortran derived type ?? getset : `str` {``"get"``,``"set"``} String indicating whether to write a get routine, or a set routine. """ # getset and inout just change things simply from a get to a set routine. inout = "in" if getset == "get": inout = "out" if isinstance(t, ft.Type): this = 'this' else: this = 'dummy_this' self.write('subroutine %s%s__array_%sitem__%s(%s, i, %s)' % (self.prefix, t.name, getset, el.name, this, el.name)) self.indent() self.write() extra_uses = {} if isinstance(t, ft.Module): extra_uses[t.name] = ['%s_%s => %s' % (t.name, el.name, el.name)] elif isinstance(t, ft.Type): mod = self.types[t.name].mod_name extra_uses[mod] = [t.name] mod = self.types[el.type].mod_name el_tname = ft.strip_type(el.type) if mod in extra_uses: extra_uses[mod].append(el_tname) else: extra_uses[mod] = [el_tname] self.write_uses_lines(el, extra_uses) self.write('implicit none') self.write() if isinstance(t, ft.Type): self.write_type_lines(t.name) self.write_type_lines(el.type) self.write('integer, intent(in) :: %s(%d)' % (this, sizeof_fortran_t)) if isinstance(t, ft.Type): self.write('type(%s_ptr_type) :: this_ptr' % t.name) array_name = 'this_ptr%%p%%%s' % el.name else: array_name = '%s_%s' % (t.name, el.name) self.write('integer, intent(in) :: i') self.write('integer, intent(%s) :: %s(%d)' % (inout, el.name, sizeof_fortran_t)) self.write('type(%s_ptr_type) :: %s_ptr' % (ft.strip_type(el.type), el.name)) self.write() if isinstance(t, ft.Type): self.write('this_ptr = transfer(this, this_ptr)') if 'allocatable' in el.attributes: self.write('if (allocated(%s)) then' % array_name) self.indent() self.write('if (i < 1 .or. i > size(%s)) then' % array_name) self.indent() self.write('call %s("array index out of range")' % self.abort_func) self.dedent() self.write('else') self.indent() if getset == "get": self.write('%s_ptr%%p => %s(i)' % (el.name, array_name)) self.write('%s = transfer(%s_ptr,%s)' % (el.name, el.name, el.name)) else: self.write('%s_ptr = transfer(%s,%s_ptr)' % (el.name, el.name, el.name)) self.write('%s(i) = %s_ptr%%p' % (array_name, el.name)) self.dedent() self.write('endif') if 'allocatable' in el.attributes: self.dedent() self.write('else') self.indent() self.write('call %s("derived type array not allocated")' % self.abort_func) self.dedent() self.write('end if') self.dedent() self.write('end subroutine %s%s__array_%sitem__%s' % (self.prefix, t.name, getset, el.name)) self.write()
def _write_array_getset_item(self, t, el, sizeof_fortran_t, getset): """ Write a subroutine to get/set items in a derived-type array. Parameters ---------- t : `fortran.Type` node Derived-type node of the parse tree. el : `fortran.Element` node An element of a module which is derived-type array sizeof_fortan_t : `int` The size, in bytes, of a pointer to a fortran derived type ?? getset : `str` {``"get"``,``"set"``} String indicating whether to write a get routine, or a set routine. """ # getset and inout just change things simply from a get to a set routine. inout = "in" if getset == "get": inout = "out" if isinstance(t, ft.Type): this = self.prefix + 'this' else: this = 'dummy_this' safe_i = self.prefix + 'i' # YANN: i could be in the "uses" clauses # TODO: check if el.orig_name would be needed here instead of el.name self.write('subroutine %s%s__array_%sitem__%s(%s, %s, %s)' % (self.prefix, t.name, getset, el.name, this, safe_i, el.name + 'item')) self.indent() self.write() extra_uses = {} if isinstance(t, ft.Module): extra_uses[t.name] = ['%s_%s => %s' % (t.name, el.name, el.name)] elif isinstance(t, ft.Type): if 'super-type' in t.doc: # YANN: propagate parameter uses for use in t.uses: if use[0] in extra_uses and use[1][0] not in extra_uses[ use[0]]: extra_uses[use[0]].append(use[1][0]) else: extra_uses[use[0]] = [use[1][0]] else: extra_uses[t.mod_name] = [t.name] mod = self.types[el.type].mod_name el_tname = ft.strip_type(el.type) if mod in extra_uses: extra_uses[mod].append(el_tname) else: extra_uses[mod] = [el_tname] self.write_uses_lines(el, extra_uses) self.write('implicit none') self.write() if 'super-type' in t.doc: self.write_super_type_lines(t) if isinstance(t, ft.Type): self.write_type_lines(t.name) self.write_type_lines(el.type) self.write('integer, intent(in) :: %s(%d)' % (this, sizeof_fortran_t)) if isinstance(t, ft.Type): self.write('type(%s_ptr_type) :: this_ptr' % t.name) array_name = 'this_ptr%%p%%%s' % el.name else: array_name = '%s_%s' % (t.name, el.name) self.write('integer, intent(in) :: %s' % (safe_i)) self.write('integer, intent(%s) :: %s(%d)' % (inout, el.name + 'item', sizeof_fortran_t)) self.write('type(%s_ptr_type) :: %s_ptr' % (ft.strip_type(el.type), el.name)) self.write() if isinstance(t, ft.Type): self.write('this_ptr = transfer(%s, this_ptr)' % (this)) if 'allocatable' in el.attributes: self.write('if (allocated(%s)) then' % array_name) self.indent() self.write('if (%s < 1 .or. %s > size(%s)) then' % (safe_i, safe_i, array_name)) self.indent() self.write('call %s("array index out of range")' % self.abort_func) self.dedent() self.write('else') self.indent() if getset == "get": self.write('%s_ptr%%p => %s(%s)' % (el.name, array_name, safe_i)) self.write('%s = transfer(%s_ptr,%s)' % (el.name + 'item', el.name, el.name + 'item')) else: self.write('%s_ptr = transfer(%s,%s_ptr)' % (el.name, el.name + 'item', el.name)) self.write('%s(%s) = %s_ptr%%p' % (array_name, safe_i, el.name)) self.dedent() self.write('endif') if 'allocatable' in el.attributes: self.dedent() self.write('else') self.indent() self.write('call %s("derived type array not allocated")' % self.abort_func) self.dedent() self.write('end if') self.dedent() self.write('end subroutine %s%s__array_%sitem__%s' % (self.prefix, t.name, getset, el.name)) self.write()
def _write_array_len(self, t, el, sizeof_fortran_t): """ Write a subroutine which returns the length of a derived-type array Parameters ---------- t : `fortran.Type` node or `fortran.Module` node Node of the parse tree which contains this derived-type as an element el : `fortran.Element` node An element of a module which is derived-type array sizeof_fortan_t : `int` The size, in bytes, of a pointer to a fortran derived type ?? """ if isinstance(t, ft.Type): this = self.prefix + 'this' else: this = 'dummy_this' safe_n = self.prefix + 'n' # YANN: "n" could be in the "uses" self.write('subroutine %s%s__array_len__%s(%s, %s)' % (self.prefix, t.name, el.name, this, safe_n)) self.indent() self.write() extra_uses = {} if isinstance(t, ft.Module): extra_uses[t.name] = ['%s_%s => %s' % (t.name, el.name, el.name)] elif isinstance(t, ft.Type): if 'super-type' in t.doc: # YANN: propagate parameter uses for use in t.uses: if use[0] in extra_uses and use[1][0] not in extra_uses[ use[0]]: extra_uses[use[0]].append(use[1][0]) else: extra_uses[use[0]] = [use[1][0]] else: extra_uses[self.types[t.name].mod_name] = [t.name] mod = self.types[el.type].mod_name el_tname = ft.strip_type(el.type) if mod in extra_uses: extra_uses[mod].append(el_tname) else: extra_uses[mod] = [el_tname] self.write_uses_lines(el, extra_uses) self.write('implicit none') self.write() if 'super-type' in t.doc: self.write_super_type_lines(t) # Check if the type has recursive definition: same_type = (ft.strip_type(t.name) == ft.strip_type(el.type)) if isinstance(t, ft.Type): self.write_type_lines(t.name) self.write_type_lines(el.type, same_type) self.write('integer, intent(out) :: %s' % (safe_n)) self.write('integer, intent(in) :: %s(%d)' % (this, sizeof_fortran_t)) if isinstance(t, ft.Type): self.write('type(%s_ptr_type) :: this_ptr' % t.name) self.write() self.write('this_ptr = transfer(%s, this_ptr)' % (this)) array_name = 'this_ptr%%p%%%s' % el.name else: array_name = '%s_%s' % (t.name, el.name) if 'allocatable' in el.attributes: self.write('if (allocated(%s)) then' % array_name) self.indent() self.write('%s = size(%s)' % (safe_n, array_name)) if 'allocatable' in el.attributes: self.dedent() self.write('else') self.indent() self.write('%s = 0' % (safe_n)) self.dedent() self.write('end if') self.dedent() self.write('end subroutine %s%s__array_len__%s' % (self.prefix, t.name, el.name)) self.write()
def _write_scalar_wrapper(self, t, el, sizeof_fortran_t, getset): """ Write get/set routines for scalar elements of derived-types and modules Parameters ---------- t : `fortran.Type` node or `fortran.Module` node Node of the parse tree which contains this derived-type as an element el : `fortran.Element` node An element of a module which is derived-type array sizeof_fortan_t : `int` The size, in bytes, of a pointer to a fortran derived type ?? getset : `str` {``"get"``,``"set"``} String indicating whether to write a get routine, or a set routine. """ logging.debug('writing %s wrapper for %s.%s' % (getset, t.name, el.name)) # getset and inout just change things simply from a get to a set routine. inout = "in" if getset == "get": inout = "out" if isinstance(t, ft.Type): this = 'this, ' elif isinstance(t, ft.Module): this = '' else: raise ValueError("Don't know how to write scalar wrappers for %s type %s" (t, type(t))) # Get appropriate use statements extra_uses = {} if isinstance(t, ft.Module): extra_uses[t.name] = ['%s_%s => %s' % (t.name, el.name, el.name)] elif isinstance(t, ft.Type): extra_uses[self.types[t.name].mod_name] = [t.name] if el.type.startswith('type'): mod = self.types[el.type].mod_name el_tname = ft.strip_type(el.type) if mod in extra_uses: extra_uses[mod].append(el_tname) else: extra_uses[mod] = [el_tname] # If the var that is get/set has the same name as something in uses, then append _ localvar = el.name if localvar in getattr(el, "uses", []) or localvar in extra_uses: localvar += "_" self.write('subroutine %s%s__%s__%s(%s%s)' % (self.prefix, t.name, getset, el.name, this, localvar)) self.indent() self.write_uses_lines(el, extra_uses) self.write('implicit none') if isinstance(t, ft.Type): self.write_type_lines(t.name) if el.type.startswith('type'): self.write_type_lines(el.type) if isinstance(t, ft.Type): self.write('integer, intent(in) :: this(%d)' % sizeof_fortran_t) self.write('type(%s_ptr_type) :: this_ptr' % t.name) # Return/set by value attributes = [attr for attr in el.attributes if attr not in ['pointer', 'allocatable', 'public', 'parameter', 'save'] ] if el.type.startswith('type'): # For derived types elements, treat as opaque reference self.write('integer, intent(%s) :: %s(%d)' % (inout, localvar, sizeof_fortran_t)) self.write('type(%s_ptr_type) :: %s_ptr' % (ft.strip_type(el.type), el.name)) self.write() if isinstance(t, ft.Type): self.write('this_ptr = transfer(this, this_ptr)') if getset == "get": if isinstance(t, ft.Type): self.write('%s_ptr%%p => this_ptr%%p%%%s' % (el.name, el.name)) else: self.write('%s_ptr%%p => %s_%s' % (el.name, t.name, el.name)) self.write('%s = transfer(%s_ptr,%s)' % (localvar, el.name, localvar)) else: self.write('%s_ptr = transfer(%s,%s_ptr)' % (el.name, localvar, el.name)) if isinstance(t, ft.Type): self.write('this_ptr%%p%%%s = %s_ptr%%p' % (el.name, el.name)) else: self.write('%s_%s = %s_ptr%%p' % (t.name, el.name, el.name)) else: if attributes != []: self.write('%s, %s, intent(%s) :: %s' % (el.type, ','.join(attributes), inout, localvar)) else: self.write('%s, intent(%s) :: %s' % (el.type, inout, localvar)) self.write() if isinstance(t, ft.Type): self.write('this_ptr = transfer(this, this_ptr)') if getset == "get": if isinstance(t, ft.Type): self.write('%s = this_ptr%%p%%%s' % (localvar, el.name)) else: self.write('%s = %s_%s' % (localvar, t.name, el.name)) else: if isinstance(t, ft.Type): self.write('this_ptr%%p%%%s = %s' % (el.name, localvar)) else: self.write('%s_%s = %s' % (t.name, el.name, localvar)) self.dedent() self.write('end subroutine %s%s__%s__%s' % (self.prefix, t.name, getset, el.name)) self.write()
def visit_Procedure(self, node): logging.info('PythonWrapperGenerator visiting routine %s' % node.name) if 'classmethod' in node.attributes: self.write_classmethod(node) elif 'constructor' in node.attributes: self.write_constructor(node) elif 'destructor' in node.attributes: self.write_destructor(node) else: dct = dict( func_name=node.name, method_name=hasattr(node, 'method_name') and node.method_name or node.name, prefix=self.prefix, mod_name=self.f90_mod_name, py_arg_names=', '.join([ arg.py_name + py_arg_value(arg) for arg in node.arguments ]), f90_arg_names=', '.join([ '%s=%s' % (arg.name, arg.py_value) for arg in node.arguments ]), call='') if isinstance(node, ft.Function): dct['result'] = ', '.join( [ret_val.name for ret_val in node.ret_val]) dct['call'] = '%(result)s = ' % dct if not self.make_package and node.mod_name is not None and node.type_name is None: # procedures outside of derived types become static methods self.write('@staticmethod') self.write("def %(method_name)s(%(py_arg_names)s):" % dct) self.indent() self.write(format_doc_string(node)) for arg in node.arguments: if 'optional' in arg.attributes and '._handle' in arg.py_value: dct['f90_arg_names'] = dct['f90_arg_names'].replace( arg.py_value, ('None if %(arg_py_name)s is None else %(arg_py_name)s._handle' ) % {'arg_py_name': arg.py_name}) call_line = '%(call)s%(mod_name)s.%(prefix)s%(func_name)s(%(f90_arg_names)s)' % dct self.write(call_line) if isinstance(node, ft.Function): # convert any derived type return values to Python objects for ret_val in node.ret_val: if ret_val.type.startswith('type'): cls_name = normalise_class_name( ft.strip_type(ret_val.type), self.class_names) cls_name = self.py_mod_name + '.' + cls_name cls_name = 'f90wrap.runtime.lookup_class("%s")' % cls_name cls_mod_name = self.types[ft.strip_type( ret_val.type)].mod_name cls_mod_name = self.py_mod_names.get( cls_mod_name, cls_mod_name) # if self.make_package: # if cls_mod_name != self.current_module: # self.imports.add((self.py_mod_name + '.' + cls_mod_name, cls_name)) # else: # cls_name = cls_mod_name + '.' + cls_name self.write('%s = %s.from_handle(%s, alloc=True)' % (ret_val.name, cls_name, ret_val.name)) self.write('return %(result)s' % dct) self.dedent() self.write()