def test_macro(): print (parse(stmts='#$ header macro _f(x) := f(x, x.shape)')) print (parse(stmts='#$ header macro _g(x) := g(x, x.shape[0], x.shape[1])')) print (parse(stmts='#$ header macro (a, b), _f(x) := f(x.shape, x, a, b)')) print (parse(stmts='#$ header macro _dswap(x, incx) := dswap(x.shape, x, incx)')) print (parse(stmts="#$ header macro _dswap(x, incx=1) := dswap(x.shape, x, incx)")) print (parse(stmts='#$ header macro _dswap(x, y, incx=1, incy=1) := dswap(x.shape, x, incx, y, incy)'))
def epyccel_old(func, inputs=None, verbose=False, modules=[], libs=[], libdirs=[], name=None, compiler=None, mpi=False, static=None, only=None, openmp=False): """Pyccelize a python function and wrap it using f2py. func: function, str a Python function or source code defining the function inputs: str, list, tuple, dict inputs can be the function header as a string, or a list/tuple of strings or the globals() dictionary verbose: bool talk more modules: list, tuple list of dependencies libs: list, tuple list of libraries libdirs: list, tuple list of paths for libraries name: str name of the function, if it is given as a string static: list/tuple a list of 'static' functions as strings only: list/tuple a list of what should be exposed by f2py as strings openmp: bool True if openmp is used. Note that in this case, one need to use nogil from cython Examples The following example shows how to use Pyccel within an IPython session >>> #$ header procedure static f_static(int [:]) results(int) >>> def f_static(x): >>> y = x[0] - 1 >>> return y >>> from test_epyccel import epyccel >>> f = epyccel(f_static, globals()) # appending IPython history >>> header = '#$ header procedure static f_static(int [:]) results(int)' >>> f = epyccel(f_static, header) # giving the header explicitly Now, **f** is a Fortran function that has been wrapped. It is compatible with numpy and you can call it >>> import numpy as np >>> x = np.array([3, 4, 5, 6], dtype=int) >>> y = f(x) You can also call it with a list instead of numpy arrays >>> f([3, 4, 5]) 2 """ if compiler is None: compiler = 'gfortran' is_module = False is_function = False if isinstance(func, ModuleType): is_module = True if callable(func): is_function = True assert (callable(func) or isinstance(func, str) or isinstance(func, ModuleType)) # ... if callable(func) or isinstance(func, ModuleType): name = func.__name__ elif name is None: # case of func as a string raise ValueError( 'function name must be provided, in the case of func string') # ... output_folder = name.rsplit('.', 1)[0] if '.' in name else '' # fortran module name modname = 'epyccel__' + name # ... if is_module: mod = func is_sharedlib = isinstance(getattr(mod, '__loader__', None), ExtensionFileLoader) if is_sharedlib: module_filename = inspect.getfile(mod) # clean cmd = 'rm -f {}'.format(module_filename) output = subprocess.check_output(cmd, shell=True) # then re-run again mod = importlib.import_module(name) # we must reload the module, otherwise it is still the .so one importlib.reload(mod) epyccel_old(mod, inputs=inputs, verbose=verbose, modules=modules, libs=libs, name=name, compiler=compiler, mpi=mpi, static=static, only=only, openmp=openmp) # ... # ... ignored_funcs = None if not static: if isinstance(func, ModuleType): mod = func funcs = [ i for i in dir(mod) if isinstance(getattr(mod, i), FunctionType) ] # remove pyccel.decorators ignored_funcs = [ i for i in funcs if getattr(mod, i).__module__ == 'pyccel.decorators' ] static = [i for i in funcs if not (i in ignored_funcs)] else: static = [name] # ... # ... headers = None if inputs: if isinstance(inputs, str): headers = inputs elif isinstance(inputs, (tuple, list)): # find all possible headers lines = [ str(i) for i in inputs if (isinstance(i, str) and i.lstrip().startswith('#$ header')) ] # TODO take the last occurence for f => use zip headers = "\n".join([str(i) for i in lines]) elif isinstance(inputs, dict): # case of globals() history from ipython if not 'In' in inputs.keys(): raise ValueError('Expecting `In` key in the inputs dictionary') inputs = inputs['In'] # TODO shall we reverse the list # find all possible headers lines = [ str(i) for i in inputs if i.lstrip().startswith('#$ header') ] # TODO take the last occurence for f => use zip headers = "\n".join([str(i) for i in lines]) # we parse all headers then convert them to static function d_headers = {} if headers: hdr = parse(stmts=headers) if isinstance(hdr, FunctionHeader): header = hdr.to_static() d_headers = {str(name): header} elif isinstance(hdr, (tuple, list)): hs = [h.to_static() for h in hdr] hs = [h for h in hs if hs.func == name] # TODO improve header = hs[0] raise NotImplementedError('TODO') else: raise NotImplementedError('TODO') # ... # ... if not static: raise NotImplementedError('TODO') # ... # ... get the function source code if callable(func): code = get_source_function(func) elif isinstance(func, ModuleType): lines = inspect.getsourcelines(func)[0] code = ''.join(lines) else: code = func # ... if verbose: print('------') print(code) print('------') extra_args = '' include_args = '' if libdirs: libdirs = ['-L{}'.format(i) for i in libdirs] extra_args += ' '.join(i for i in libdirs) try: # ... pyccel = Parser(code, headers=d_headers, static=static, output_folder=output_folder) ast = pyccel.parse() settings = {} ast = pyccel.annotate(**settings) codegen = Codegen(ast, modname) code = codegen.doprint() # ... # reset Errors singleton errors = Errors() errors.reset() except: # reset Errors singleton errors = Errors() errors.reset() raise PyccelError('Could not convert to Fortran') # Change module name to avoid name clashes: Python cannot import two modules with the same name if is_module: head, sep, tail = name.rpartition('.') name = sep.join([head, '__epyccel__' + tail]) else: name = '__epyccel__' + name # Find directory where Fortran extension module should be created if is_module: dirname = os.path.dirname(os.path.abspath(mod.__file__)) else: dirname = os.path.dirname( os.path.abspath(sys.modules[func.__module__].__file__)) # Move into working directory, create extension module, then move back to original directory origin = os.path.abspath(os.curdir) os.chdir(dirname) output, cmd = compile_fortran(code, name, extra_args=extra_args, libs=libs, compiler=compiler, mpi=mpi, openmp=openmp, includes=include_args, only=only) os.chdir(origin) if verbose: print(cmd) if verbose: print(code) # ... # ... try: if PY_VERSION == (3, 7): dirname = os.path.relpath(dirname).replace('/', '.') package = dirname + '.' + name package = importlib.import_module('..' + name, package=package) clean_extension_module(package, modname) else: os.chdir(dirname) package = importlib.import_module(name) clean_extension_module(package, modname) os.chdir(origin) except: raise ImportError('could not import {0}'.format(name)) # ... if is_module: return package else: return getattr(package, func.__name__.lower())
def test_function(): print (parse(stmts='#$ header function f(float [:], int [:]) results(int)'))
def test_variable(): print (parse(stmts='#$ header variable x :: int')) print (parse(stmts='#$ header variable x float [:, :]'))
def test_metavar(): print (parse(stmts="#$ header metavar module_name='mpi'"))
def test_method(): print (parse(stmts='#$ header method translate(Point, double, double)'))
def test_class(): print (parse(stmts='#$ header class Square(public)'))