Updated script that can be controled by Nodejs web app

This commit is contained in:
mac OS
2024-11-25 12:24:18 +07:00
parent c440eda1f4
commit 8b0ab2bd3a
8662 changed files with 1803808 additions and 34 deletions

View File

@ -0,0 +1,88 @@
#!/usr/bin/env python3
"""Fortran to Python Interface Generator.
Copyright 1999 -- 2011 Pearu Peterson all rights reserved.
Copyright 2011 -- present NumPy Developers.
Permission to use, modify, and distribute this software is given under the terms
of the NumPy License.
NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
"""
__all__ = ['run_main', 'get_include']
import sys
import subprocess
import os
import warnings
from numpy.exceptions import VisibleDeprecationWarning
from . import f2py2e
from . import diagnose
run_main = f2py2e.run_main
main = f2py2e.main
def get_include():
"""
Return the directory that contains the ``fortranobject.c`` and ``.h`` files.
.. note::
This function is not needed when building an extension with
`numpy.distutils` directly from ``.f`` and/or ``.pyf`` files
in one go.
Python extension modules built with f2py-generated code need to use
``fortranobject.c`` as a source file, and include the ``fortranobject.h``
header. This function can be used to obtain the directory containing
both of these files.
Returns
-------
include_path : str
Absolute path to the directory containing ``fortranobject.c`` and
``fortranobject.h``.
Notes
-----
.. versionadded:: 1.21.1
Unless the build system you are using has specific support for f2py,
building a Python extension using a ``.pyf`` signature file is a two-step
process. For a module ``mymod``:
* Step 1: run ``python -m numpy.f2py mymod.pyf --quiet``. This
generates ``mymodmodule.c`` and (if needed)
``mymod-f2pywrappers.f`` files next to ``mymod.pyf``.
* Step 2: build your Python extension module. This requires the
following source files:
* ``mymodmodule.c``
* ``mymod-f2pywrappers.f`` (if it was generated in Step 1)
* ``fortranobject.c``
See Also
--------
numpy.get_include : function that returns the numpy include directory
"""
return os.path.join(os.path.dirname(__file__), 'src')
def __getattr__(attr):
# Avoid importing things that aren't needed for building
# which might import the main numpy module
if attr == "test":
from numpy._pytesttester import PytestTester
test = PytestTester(__name__)
return test
else:
raise AttributeError("module {!r} has no attribute "
"{!r}".format(__name__, attr))
def __dir__():
return list(globals().keys() | {"test"})

View File

@ -0,0 +1,42 @@
import os
import subprocess
from collections.abc import Iterable
from typing import Literal as L, Any, overload, TypedDict
from numpy._pytesttester import PytestTester
class _F2PyDictBase(TypedDict):
csrc: list[str]
h: list[str]
class _F2PyDict(_F2PyDictBase, total=False):
fsrc: list[str]
ltx: list[str]
__all__: list[str]
test: PytestTester
def run_main(comline_list: Iterable[str]) -> dict[str, _F2PyDict]: ...
@overload
def compile( # type: ignore[misc]
source: str | bytes,
modulename: str = ...,
extra_args: str | list[str] = ...,
verbose: bool = ...,
source_fn: None | str | bytes | os.PathLike[Any] = ...,
extension: L[".f", ".f90"] = ...,
full_output: L[False] = ...,
) -> int: ...
@overload
def compile(
source: str | bytes,
modulename: str = ...,
extra_args: str | list[str] = ...,
verbose: bool = ...,
source_fn: None | str | bytes | os.PathLike[Any] = ...,
extension: L[".f", ".f90"] = ...,
full_output: L[True] = ...,
) -> subprocess.CompletedProcess[bytes]: ...
def get_include() -> str: ...

View File

@ -0,0 +1,5 @@
# See:
# https://web.archive.org/web/20140822061353/http://cens.ioc.ee/projects/f2py2e
from numpy.f2py.f2py2e import main
main()

View File

@ -0,0 +1 @@
from numpy.version import version

View File

@ -0,0 +1,9 @@
def f2py_build_generator(name):
if name == "meson":
from ._meson import MesonBackend
return MesonBackend
elif name == "distutils":
from ._distutils import DistutilsBackend
return DistutilsBackend
else:
raise ValueError(f"Unknown backend: {name}")

View File

@ -0,0 +1,46 @@
from __future__ import annotations
from abc import ABC, abstractmethod
class Backend(ABC):
def __init__(
self,
modulename,
sources,
extra_objects,
build_dir,
include_dirs,
library_dirs,
libraries,
define_macros,
undef_macros,
f2py_flags,
sysinfo_flags,
fc_flags,
flib_flags,
setup_flags,
remove_build_dir,
extra_dat,
):
self.modulename = modulename
self.sources = sources
self.extra_objects = extra_objects
self.build_dir = build_dir
self.include_dirs = include_dirs
self.library_dirs = library_dirs
self.libraries = libraries
self.define_macros = define_macros
self.undef_macros = undef_macros
self.f2py_flags = f2py_flags
self.sysinfo_flags = sysinfo_flags
self.fc_flags = fc_flags
self.flib_flags = flib_flags
self.setup_flags = setup_flags
self.remove_build_dir = remove_build_dir
self.extra_dat = extra_dat
@abstractmethod
def compile(self) -> None:
"""Compile the wrapper."""
pass

View File

@ -0,0 +1,75 @@
from ._backend import Backend
from numpy.distutils.core import setup, Extension
from numpy.distutils.system_info import get_info
from numpy.distutils.misc_util import dict_append
from numpy.exceptions import VisibleDeprecationWarning
import os
import sys
import shutil
import warnings
class DistutilsBackend(Backend):
def __init__(sef, *args, **kwargs):
warnings.warn(
"\ndistutils has been deprecated since NumPy 1.26.x\n"
"Use the Meson backend instead, or generate wrappers"
" without -c and use a custom build script",
VisibleDeprecationWarning,
stacklevel=2,
)
super().__init__(*args, **kwargs)
def compile(self):
num_info = {}
if num_info:
self.include_dirs.extend(num_info.get("include_dirs", []))
ext_args = {
"name": self.modulename,
"sources": self.sources,
"include_dirs": self.include_dirs,
"library_dirs": self.library_dirs,
"libraries": self.libraries,
"define_macros": self.define_macros,
"undef_macros": self.undef_macros,
"extra_objects": self.extra_objects,
"f2py_options": self.f2py_flags,
}
if self.sysinfo_flags:
for n in self.sysinfo_flags:
i = get_info(n)
if not i:
print(
f"No {repr(n)} resources found"
"in system (try `f2py --help-link`)"
)
dict_append(ext_args, **i)
ext = Extension(**ext_args)
sys.argv = [sys.argv[0]] + self.setup_flags
sys.argv.extend(
[
"build",
"--build-temp",
self.build_dir,
"--build-base",
self.build_dir,
"--build-platlib",
".",
"--disable-optimization",
]
)
if self.fc_flags:
sys.argv.extend(["config_fc"] + self.fc_flags)
if self.flib_flags:
sys.argv.extend(["build_ext"] + self.flib_flags)
setup(ext_modules=[ext])
if self.remove_build_dir and os.path.exists(self.build_dir):
print(f"Removing build directory {self.build_dir}")
shutil.rmtree(self.build_dir)

View File

@ -0,0 +1,234 @@
from __future__ import annotations
import os
import errno
import shutil
import subprocess
import sys
import re
from pathlib import Path
from ._backend import Backend
from string import Template
from itertools import chain
import warnings
class MesonTemplate:
"""Template meson build file generation class."""
def __init__(
self,
modulename: str,
sources: list[Path],
deps: list[str],
libraries: list[str],
library_dirs: list[Path],
include_dirs: list[Path],
object_files: list[Path],
linker_args: list[str],
fortran_args: list[str],
build_type: str,
python_exe: str,
):
self.modulename = modulename
self.build_template_path = (
Path(__file__).parent.absolute() / "meson.build.template"
)
self.sources = sources
self.deps = deps
self.libraries = libraries
self.library_dirs = library_dirs
if include_dirs is not None:
self.include_dirs = include_dirs
else:
self.include_dirs = []
self.substitutions = {}
self.objects = object_files
# Convert args to '' wrapped variant for meson
self.fortran_args = [
f"'{x}'" if not (x.startswith("'") and x.endswith("'")) else x
for x in fortran_args
]
self.pipeline = [
self.initialize_template,
self.sources_substitution,
self.deps_substitution,
self.include_substitution,
self.libraries_substitution,
self.fortran_args_substitution,
]
self.build_type = build_type
self.python_exe = python_exe
self.indent = " " * 21
def meson_build_template(self) -> str:
if not self.build_template_path.is_file():
raise FileNotFoundError(
errno.ENOENT,
"Meson build template"
f" {self.build_template_path.absolute()}"
" does not exist.",
)
return self.build_template_path.read_text()
def initialize_template(self) -> None:
self.substitutions["modulename"] = self.modulename
self.substitutions["buildtype"] = self.build_type
self.substitutions["python"] = self.python_exe
def sources_substitution(self) -> None:
self.substitutions["source_list"] = ",\n".join(
[f"{self.indent}'''{source}'''," for source in self.sources]
)
def deps_substitution(self) -> None:
self.substitutions["dep_list"] = f",\n{self.indent}".join(
[f"{self.indent}dependency('{dep}')," for dep in self.deps]
)
def libraries_substitution(self) -> None:
self.substitutions["lib_dir_declarations"] = "\n".join(
[
f"lib_dir_{i} = declare_dependency(link_args : ['''-L{lib_dir}'''])"
for i, lib_dir in enumerate(self.library_dirs)
]
)
self.substitutions["lib_declarations"] = "\n".join(
[
f"{lib.replace('.','_')} = declare_dependency(link_args : ['-l{lib}'])"
for lib in self.libraries
]
)
self.substitutions["lib_list"] = f"\n{self.indent}".join(
[f"{self.indent}{lib.replace('.','_')}," for lib in self.libraries]
)
self.substitutions["lib_dir_list"] = f"\n{self.indent}".join(
[f"{self.indent}lib_dir_{i}," for i in range(len(self.library_dirs))]
)
def include_substitution(self) -> None:
self.substitutions["inc_list"] = f",\n{self.indent}".join(
[f"{self.indent}'''{inc}'''," for inc in self.include_dirs]
)
def fortran_args_substitution(self) -> None:
if self.fortran_args:
self.substitutions["fortran_args"] = (
f"{self.indent}fortran_args: [{', '.join([arg for arg in self.fortran_args])}],"
)
else:
self.substitutions["fortran_args"] = ""
def generate_meson_build(self):
for node in self.pipeline:
node()
template = Template(self.meson_build_template())
meson_build = template.substitute(self.substitutions)
meson_build = re.sub(r",,", ",", meson_build)
return meson_build
class MesonBackend(Backend):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.dependencies = self.extra_dat.get("dependencies", [])
self.meson_build_dir = "bbdir"
self.build_type = (
"debug" if any("debug" in flag for flag in self.fc_flags) else "release"
)
self.fc_flags = _get_flags(self.fc_flags)
def _move_exec_to_root(self, build_dir: Path):
walk_dir = Path(build_dir) / self.meson_build_dir
path_objects = chain(
walk_dir.glob(f"{self.modulename}*.so"),
walk_dir.glob(f"{self.modulename}*.pyd"),
)
# Same behavior as distutils
# https://github.com/numpy/numpy/issues/24874#issuecomment-1835632293
for path_object in path_objects:
dest_path = Path.cwd() / path_object.name
if dest_path.exists():
dest_path.unlink()
shutil.copy2(path_object, dest_path)
os.remove(path_object)
def write_meson_build(self, build_dir: Path) -> None:
"""Writes the meson build file at specified location"""
meson_template = MesonTemplate(
self.modulename,
self.sources,
self.dependencies,
self.libraries,
self.library_dirs,
self.include_dirs,
self.extra_objects,
self.flib_flags,
self.fc_flags,
self.build_type,
sys.executable,
)
src = meson_template.generate_meson_build()
Path(build_dir).mkdir(parents=True, exist_ok=True)
meson_build_file = Path(build_dir) / "meson.build"
meson_build_file.write_text(src)
return meson_build_file
def _run_subprocess_command(self, command, cwd):
subprocess.run(command, cwd=cwd, check=True)
def run_meson(self, build_dir: Path):
setup_command = ["meson", "setup", self.meson_build_dir]
self._run_subprocess_command(setup_command, build_dir)
compile_command = ["meson", "compile", "-C", self.meson_build_dir]
self._run_subprocess_command(compile_command, build_dir)
def compile(self) -> None:
self.sources = _prepare_sources(self.modulename, self.sources, self.build_dir)
self.write_meson_build(self.build_dir)
self.run_meson(self.build_dir)
self._move_exec_to_root(self.build_dir)
def _prepare_sources(mname, sources, bdir):
extended_sources = sources.copy()
Path(bdir).mkdir(parents=True, exist_ok=True)
# Copy sources
for source in sources:
if Path(source).exists() and Path(source).is_file():
shutil.copy(source, bdir)
generated_sources = [
Path(f"{mname}module.c"),
Path(f"{mname}-f2pywrappers2.f90"),
Path(f"{mname}-f2pywrappers.f"),
]
bdir = Path(bdir)
for generated_source in generated_sources:
if generated_source.exists():
shutil.copy(generated_source, bdir / generated_source.name)
extended_sources.append(generated_source.name)
generated_source.unlink()
extended_sources = [
Path(source).name
for source in extended_sources
if not Path(source).suffix == ".pyf"
]
return extended_sources
def _get_flags(fc_flags):
flag_values = []
flag_pattern = re.compile(r"--f(77|90)flags=(.*)")
for flag in fc_flags:
match_result = flag_pattern.match(flag)
if match_result:
values = match_result.group(2).strip().split()
values = [val.strip("'\"") for val in values]
flag_values.extend(values)
# Hacky way to preserve order of flags
unique_flags = list(dict.fromkeys(flag_values))
return unique_flags

View File

@ -0,0 +1,55 @@
project('${modulename}',
['c', 'fortran'],
version : '0.1',
meson_version: '>= 1.1.0',
default_options : [
'warning_level=1',
'buildtype=${buildtype}'
])
fc = meson.get_compiler('fortran')
py = import('python').find_installation('''${python}''', pure: false)
py_dep = py.dependency()
incdir_numpy = run_command(py,
['-c', 'import os; os.chdir(".."); import numpy; print(numpy.get_include())'],
check : true
).stdout().strip()
incdir_f2py = run_command(py,
['-c', 'import os; os.chdir(".."); import numpy.f2py; print(numpy.f2py.get_include())'],
check : true
).stdout().strip()
inc_np = include_directories(incdir_numpy)
np_dep = declare_dependency(include_directories: inc_np)
incdir_f2py = incdir_numpy / '..' / '..' / 'f2py' / 'src'
inc_f2py = include_directories(incdir_f2py)
fortranobject_c = incdir_f2py / 'fortranobject.c'
inc_np = include_directories(incdir_numpy, incdir_f2py)
# gh-25000
quadmath_dep = fc.find_library('quadmath', required: false)
${lib_declarations}
${lib_dir_declarations}
py.extension_module('${modulename}',
[
${source_list},
fortranobject_c
],
include_directories: [
inc_np,
${inc_list}
],
dependencies : [
py_dep,
quadmath_dep,
${dep_list}
${lib_list}
${lib_dir_list}
],
${fortran_args}
install : true)

View File

@ -0,0 +1,62 @@
"""
ISO_C_BINDING maps for f2py2e.
Only required declarations/macros/functions will be used.
Copyright 1999 -- 2011 Pearu Peterson all rights reserved.
Copyright 2011 -- present NumPy Developers.
Permission to use, modify, and distribute this software is given under the
terms of the NumPy License.
NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
"""
# These map to keys in c2py_map, via forced casting for now, see gh-25229
iso_c_binding_map = {
'integer': {
'c_int': 'int',
'c_short': 'short', # 'short' <=> 'int' for now
'c_long': 'long', # 'long' <=> 'int' for now
'c_long_long': 'long_long',
'c_signed_char': 'signed_char',
'c_size_t': 'unsigned', # size_t <=> 'unsigned' for now
'c_int8_t': 'signed_char', # int8_t <=> 'signed_char' for now
'c_int16_t': 'short', # int16_t <=> 'short' for now
'c_int32_t': 'int', # int32_t <=> 'int' for now
'c_int64_t': 'long_long',
'c_int_least8_t': 'signed_char', # int_least8_t <=> 'signed_char' for now
'c_int_least16_t': 'short', # int_least16_t <=> 'short' for now
'c_int_least32_t': 'int', # int_least32_t <=> 'int' for now
'c_int_least64_t': 'long_long',
'c_int_fast8_t': 'signed_char', # int_fast8_t <=> 'signed_char' for now
'c_int_fast16_t': 'short', # int_fast16_t <=> 'short' for now
'c_int_fast32_t': 'int', # int_fast32_t <=> 'int' for now
'c_int_fast64_t': 'long_long',
'c_intmax_t': 'long_long', # intmax_t <=> 'long_long' for now
'c_intptr_t': 'long', # intptr_t <=> 'long' for now
'c_ptrdiff_t': 'long', # ptrdiff_t <=> 'long' for now
},
'real': {
'c_float': 'float',
'c_double': 'double',
'c_long_double': 'long_double'
},
'complex': {
'c_float_complex': 'complex_float',
'c_double_complex': 'complex_double',
'c_long_double_complex': 'complex_long_double'
},
'logical': {
'c_bool': 'unsigned_char' # _Bool <=> 'unsigned_char' for now
},
'character': {
'c_char': 'char'
}
}
# TODO: See gh-25229
isoc_c2pycode_map = {}
iso_c2py_map = {}
isoc_kindmap = {}
for fortran_type, c_type_dict in iso_c_binding_map.items():
for c_type in c_type_dict.keys():
isoc_kindmap[c_type] = fortran_type

View File

@ -0,0 +1,239 @@
import re
# START OF CODE VENDORED FROM `numpy.distutils.from_template`
#############################################################
"""
process_file(filename)
takes templated file .xxx.src and produces .xxx file where .xxx
is .pyf .f90 or .f using the following template rules:
'<..>' denotes a template.
All function and subroutine blocks in a source file with names that
contain '<..>' will be replicated according to the rules in '<..>'.
The number of comma-separated words in '<..>' will determine the number of
replicates.
'<..>' may have two different forms, named and short. For example,
named:
<p=d,s,z,c> where anywhere inside a block '<p>' will be replaced with
'd', 's', 'z', and 'c' for each replicate of the block.
<_c> is already defined: <_c=s,d,c,z>
<_t> is already defined: <_t=real,double precision,complex,double complex>
short:
<s,d,c,z>, a short form of the named, useful when no <p> appears inside
a block.
In general, '<..>' contains a comma separated list of arbitrary
expressions. If these expression must contain a comma|leftarrow|rightarrow,
then prepend the comma|leftarrow|rightarrow with a backslash.
If an expression matches '\\<index>' then it will be replaced
by <index>-th expression.
Note that all '<..>' forms in a block must have the same number of
comma-separated entries.
Predefined named template rules:
<prefix=s,d,c,z>
<ftype=real,double precision,complex,double complex>
<ftypereal=real,double precision,\\0,\\1>
<ctype=float,double,complex_float,complex_double>
<ctypereal=float,double,\\0,\\1>
"""
routine_start_re = re.compile(r'(\n|\A)(( (\$|\*))|)\s*(subroutine|function)\b', re.I)
routine_end_re = re.compile(r'\n\s*end\s*(subroutine|function)\b.*(\n|\Z)', re.I)
function_start_re = re.compile(r'\n (\$|\*)\s*function\b', re.I)
def parse_structure(astr):
""" Return a list of tuples for each function or subroutine each
tuple is the start and end of a subroutine or function to be
expanded.
"""
spanlist = []
ind = 0
while True:
m = routine_start_re.search(astr, ind)
if m is None:
break
start = m.start()
if function_start_re.match(astr, start, m.end()):
while True:
i = astr.rfind('\n', ind, start)
if i==-1:
break
start = i
if astr[i:i+7]!='\n $':
break
start += 1
m = routine_end_re.search(astr, m.end())
ind = end = m and m.end()-1 or len(astr)
spanlist.append((start, end))
return spanlist
template_re = re.compile(r"<\s*(\w[\w\d]*)\s*>")
named_re = re.compile(r"<\s*(\w[\w\d]*)\s*=\s*(.*?)\s*>")
list_re = re.compile(r"<\s*((.*?))\s*>")
def find_repl_patterns(astr):
reps = named_re.findall(astr)
names = {}
for rep in reps:
name = rep[0].strip() or unique_key(names)
repl = rep[1].replace(r'\,', '@comma@')
thelist = conv(repl)
names[name] = thelist
return names
def find_and_remove_repl_patterns(astr):
names = find_repl_patterns(astr)
astr = re.subn(named_re, '', astr)[0]
return astr, names
item_re = re.compile(r"\A\\(?P<index>\d+)\Z")
def conv(astr):
b = astr.split(',')
l = [x.strip() for x in b]
for i in range(len(l)):
m = item_re.match(l[i])
if m:
j = int(m.group('index'))
l[i] = l[j]
return ','.join(l)
def unique_key(adict):
""" Obtain a unique key given a dictionary."""
allkeys = list(adict.keys())
done = False
n = 1
while not done:
newkey = '__l%s' % (n)
if newkey in allkeys:
n += 1
else:
done = True
return newkey
template_name_re = re.compile(r'\A\s*(\w[\w\d]*)\s*\Z')
def expand_sub(substr, names):
substr = substr.replace(r'\>', '@rightarrow@')
substr = substr.replace(r'\<', '@leftarrow@')
lnames = find_repl_patterns(substr)
substr = named_re.sub(r"<\1>", substr) # get rid of definition templates
def listrepl(mobj):
thelist = conv(mobj.group(1).replace(r'\,', '@comma@'))
if template_name_re.match(thelist):
return "<%s>" % (thelist)
name = None
for key in lnames.keys(): # see if list is already in dictionary
if lnames[key] == thelist:
name = key
if name is None: # this list is not in the dictionary yet
name = unique_key(lnames)
lnames[name] = thelist
return "<%s>" % name
substr = list_re.sub(listrepl, substr) # convert all lists to named templates
# newnames are constructed as needed
numsubs = None
base_rule = None
rules = {}
for r in template_re.findall(substr):
if r not in rules:
thelist = lnames.get(r, names.get(r, None))
if thelist is None:
raise ValueError('No replicates found for <%s>' % (r))
if r not in names and not thelist.startswith('_'):
names[r] = thelist
rule = [i.replace('@comma@', ',') for i in thelist.split(',')]
num = len(rule)
if numsubs is None:
numsubs = num
rules[r] = rule
base_rule = r
elif num == numsubs:
rules[r] = rule
else:
print("Mismatch in number of replacements (base <{}={}>) "
"for <{}={}>. Ignoring.".format(base_rule, ','.join(rules[base_rule]), r, thelist))
if not rules:
return substr
def namerepl(mobj):
name = mobj.group(1)
return rules.get(name, (k+1)*[name])[k]
newstr = ''
for k in range(numsubs):
newstr += template_re.sub(namerepl, substr) + '\n\n'
newstr = newstr.replace('@rightarrow@', '>')
newstr = newstr.replace('@leftarrow@', '<')
return newstr
def process_str(allstr):
newstr = allstr
writestr = ''
struct = parse_structure(newstr)
oldend = 0
names = {}
names.update(_special_names)
for sub in struct:
cleanedstr, defs = find_and_remove_repl_patterns(newstr[oldend:sub[0]])
writestr += cleanedstr
names.update(defs)
writestr += expand_sub(newstr[sub[0]:sub[1]], names)
oldend = sub[1]
writestr += newstr[oldend:]
return writestr
include_src_re = re.compile(r"(\n|\A)\s*include\s*['\"](?P<name>[\w\d./\\]+\.src)['\"]", re.I)
def resolve_includes(source):
d = os.path.dirname(source)
with open(source) as fid:
lines = []
for line in fid:
m = include_src_re.match(line)
if m:
fn = m.group('name')
if not os.path.isabs(fn):
fn = os.path.join(d, fn)
if os.path.isfile(fn):
lines.extend(resolve_includes(fn))
else:
lines.append(line)
else:
lines.append(line)
return lines
def process_file(source):
lines = resolve_includes(source)
return process_str(''.join(lines))
_special_names = find_repl_patterns('''
<_c=s,d,c,z>
<_t=real,double precision,complex,double complex>
<prefix=s,d,c,z>
<ftype=real,double precision,complex,double complex>
<ctype=float,double,complex_float,complex_double>
<ftypereal=real,double precision,\\0,\\1>
<ctypereal=float,double,\\0,\\1>
''')
# END OF CODE VENDORED FROM `numpy.distutils.from_template`
###########################################################

View File

@ -0,0 +1,996 @@
"""
Auxiliary functions for f2py2e.
Copyright 1999 -- 2011 Pearu Peterson all rights reserved.
Copyright 2011 -- present NumPy Developers.
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.
"""
import pprint
import sys
import re
import types
from functools import reduce
from copy import deepcopy
from . import __version__
from . import cfuncs
from .cfuncs import errmess
__all__ = [
'applyrules', 'debugcapi', 'dictappend', 'errmess', 'gentitle',
'getargs2', 'getcallprotoargument', 'getcallstatement',
'getfortranname', 'getpymethoddef', 'getrestdoc', 'getusercode',
'getusercode1', 'getdimension', 'hasbody', 'hascallstatement', 'hascommon',
'hasexternals', 'hasinitvalue', 'hasnote', 'hasresultnote',
'isallocatable', 'isarray', 'isarrayofstrings',
'ischaracter', 'ischaracterarray', 'ischaracter_or_characterarray',
'iscomplex',
'iscomplexarray', 'iscomplexfunction', 'iscomplexfunction_warn',
'isdouble', 'isdummyroutine', 'isexternal', 'isfunction',
'isfunction_wrap', 'isint1', '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', 'isvariable',
'isrequired', 'isroutine', 'isscalar', 'issigned_long_longarray',
'isstring', 'isstringarray', 'isstring_or_stringarray', 'isstringfunction',
'issubroutine', 'get_f2py_modulename', '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', 'isattr_value', 'getuseblocks',
'process_f2cmap_dict'
]
f2py_version = __version__.version
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 _ischaracter(var):
return 'typespec' in var and var['typespec'] == 'character' and \
not isexternal(var)
def _isstring(var):
return 'typespec' in var and var['typespec'] == 'character' and \
not isexternal(var)
def ischaracter_or_characterarray(var):
return _ischaracter(var) and 'charselector' not in var
def ischaracter(var):
return ischaracter_or_characterarray(var) and not isarray(var)
def ischaracterarray(var):
return ischaracter_or_characterarray(var) and isarray(var)
def isstring_or_stringarray(var):
return _ischaracter(var) and 'charselector' in var
def isstring(var):
return isstring_or_stringarray(var) and not isarray(var)
def isstringarray(var):
return isstring_or_stringarray(var) and isarray(var)
def isarrayofstrings(var): # obsolete?
# 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 isint1(var):
return var.get('typespec') == 'integer' \
and get_kind(var) == '1' and not isarray(var)
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 isattr_value(var):
return 'value' in var.get('attrspec', [])
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.
When using GNU gcc/g77 compilers, codes should work
correctly for callbacks with:
f2py -c -DF2PY_CB_RETURNCOMPLEX
**************************************************************\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 getdimension(var):
dimpattern = r"\((.*?)\)"
if 'attrspec' in var.keys():
if any('dimension' in s for s in var['attrspec']):
return [re.findall(dimpattern, v) for v in var['attrspec']][0]
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 isvariable(var):
# heuristic to find public/private declarations of filtered subroutines
if len(var) == 1 and 'attrspec' in var and \
var['attrspec'][0] in ('public', 'private'):
is_var = False
else:
is_var = True
return is_var
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):
l1, l2 = 'lambda v', []
for i in range(len(f)):
l1 = '%s,f%d=f[%d]' % (l1, i, i)
l2.append('f%d(v)' % (i))
return eval('%s:%s' % (l1, ' and '.join(l2)))
def l_or(*f):
l1, l2 = 'lambda v', []
for i in range(len(f)):
l1 = '%s,f%d=f[%d]' % (l1, i, i)
l2.append('f%d(v)' % (i))
return eval('%s:%s' % (l1, ' 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:
if not isattr_value(var):
ctype = ctype + '*'
if (isstring(var)
or isarrayofstrings(var) # obsolete?
or isstringarray(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):
ln = (80 - len(name) - 6) // 2
return '/*%s %s %s*/' % (ln * '*', name, ln * '*')
def flatlist(lst):
if isinstance(lst, list):
return reduce(lambda x, y, f=flatlist: x + f(y), lst, [])
return [lst]
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
_f2py_module_name_match = re.compile(r'\s*python\s*module\s*(?P<name>[\w_]+)',
re.I).match
_f2py_user_module_name_match = re.compile(r'\s*python\s*module\s*(?P<name>[\w_]*?'
r'__user__[\w_]*)', re.I).match
def get_f2py_modulename(source):
name = None
with open(source) as f:
for line in f:
m = _f2py_module_name_match(line)
if m:
if _f2py_user_module_name_match(line): # skip *__user__* names
continue
name = m.group('name')
break
return name
def getuseblocks(pymod):
all_uses = []
for inner in pymod['body']:
for modblock in inner['body']:
if modblock.get('use'):
all_uses.extend([x for x in modblock.get("use").keys() if "__" not in x])
return all_uses
def process_f2cmap_dict(f2cmap_all, new_map, c2py_map, verbose = False):
"""
Update the Fortran-to-C type mapping dictionary with new mappings and
return a list of successfully mapped C types.
This function integrates a new mapping dictionary into an existing
Fortran-to-C type mapping dictionary. It ensures that all keys are in
lowercase and validates new entries against a given C-to-Python mapping
dictionary. Redefinitions and invalid entries are reported with a warning.
Parameters
----------
f2cmap_all : dict
The existing Fortran-to-C type mapping dictionary that will be updated.
It should be a dictionary of dictionaries where the main keys represent
Fortran types and the nested dictionaries map Fortran type specifiers
to corresponding C types.
new_map : dict
A dictionary containing new type mappings to be added to `f2cmap_all`.
The structure should be similar to `f2cmap_all`, with keys representing
Fortran types and values being dictionaries of type specifiers and their
C type equivalents.
c2py_map : dict
A dictionary used for validating the C types in `new_map`. It maps C
types to corresponding Python types and is used to ensure that the C
types specified in `new_map` are valid.
verbose : boolean
A flag used to provide information about the types mapped
Returns
-------
tuple of (dict, list)
The updated Fortran-to-C type mapping dictionary and a list of
successfully mapped C types.
"""
f2cmap_mapped = []
new_map_lower = {}
for k, d1 in new_map.items():
d1_lower = {k1.lower(): v1 for k1, v1 in d1.items()}
new_map_lower[k.lower()] = d1_lower
for k, d1 in new_map_lower.items():
if k not in f2cmap_all:
f2cmap_all[k] = {}
for k1, v1 in d1.items():
if v1 in c2py_map:
if k1 in f2cmap_all[k]:
outmess(
"\tWarning: redefinition of {'%s':{'%s':'%s'->'%s'}}\n"
% (k, k1, f2cmap_all[k][k1], v1)
)
f2cmap_all[k][k1] = v1
if verbose:
outmess('\tMapping "%s(kind=%s)" to "%s"\n' % (k, k1, v1))
f2cmap_mapped.append(v1)
else:
if verbose:
errmess(
"\tIgnoring map {'%s':{'%s':'%s'}}: '%s' must be in %s\n"
% (k, k1, v1, v1, list(c2py_map.keys()))
)
return f2cmap_all, f2cmap_mapped

View File

@ -0,0 +1,821 @@
"""
Copyright 1999 -- 2011 Pearu Peterson all rights reserved.
Copyright 2011 -- present NumPy Developers.
Permission to use, modify, and distribute this software is given under the
terms of the NumPy License.
NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
"""
from . import __version__
f2py_version = __version__.version
import copy
import re
import os
from .crackfortran import markoutercomma
from . import cb_rules
from ._isocbind import iso_c_binding_map, isoc_c2pycode_map, iso_c2py_map
# The environment provided by auxfuncs.py is needed for some calls to eval.
# As the needed functions cannot be determined by static inspection of the
# code, it is safest to use import * pending a major refactoring of f2py.
from .auxfuncs import *
__all__ = [
'getctype', 'getstrlength', 'getarrdims', 'getpydocsign',
'getarrdocsign', 'getinit', 'sign2map', 'routsign2map', 'modsign2map',
'cb_sign2map', 'cb_routsign2map', 'common_sign2map', 'process_f2cmap_dict'
]
depargs = []
lcb_map = {}
lcb2_map = {}
# forced casting: mainly caused by the fact that Python or Numeric
# C/APIs do not support the corresponding C types.
c2py_map = {'double': 'float',
'float': 'float', # forced casting
'long_double': 'float', # forced casting
'char': 'int', # forced casting
'signed_char': 'int', # forced casting
'unsigned_char': 'int', # forced casting
'short': 'int', # forced casting
'unsigned_short': 'int', # forced casting
'int': 'int', # forced casting
'long': 'int',
'long_long': 'long',
'unsigned': 'int', # forced casting
'complex_float': 'complex', # forced casting
'complex_double': 'complex',
'complex_long_double': 'complex', # forced casting
'string': 'string',
'character': 'bytes',
}
c2capi_map = {'double': 'NPY_DOUBLE',
'float': 'NPY_FLOAT',
'long_double': 'NPY_LONGDOUBLE',
'char': 'NPY_BYTE',
'unsigned_char': 'NPY_UBYTE',
'signed_char': 'NPY_BYTE',
'short': 'NPY_SHORT',
'unsigned_short': 'NPY_USHORT',
'int': 'NPY_INT',
'unsigned': 'NPY_UINT',
'long': 'NPY_LONG',
'unsigned_long': 'NPY_ULONG',
'long_long': 'NPY_LONGLONG',
'unsigned_long_long': 'NPY_ULONGLONG',
'complex_float': 'NPY_CFLOAT',
'complex_double': 'NPY_CDOUBLE',
'complex_long_double': 'NPY_CDOUBLE',
'string': 'NPY_STRING',
'character': 'NPY_STRING'}
c2pycode_map = {'double': 'd',
'float': 'f',
'long_double': 'g',
'char': 'b',
'unsigned_char': 'B',
'signed_char': 'b',
'short': 'h',
'unsigned_short': 'H',
'int': 'i',
'unsigned': 'I',
'long': 'l',
'unsigned_long': 'L',
'long_long': 'q',
'unsigned_long_long': 'Q',
'complex_float': 'F',
'complex_double': 'D',
'complex_long_double': 'G',
'string': 'S',
'character': 'c'}
# https://docs.python.org/3/c-api/arg.html#building-values
c2buildvalue_map = {'double': 'd',
'float': 'f',
'char': 'b',
'signed_char': 'b',
'short': 'h',
'int': 'i',
'long': 'l',
'long_long': 'L',
'complex_float': 'N',
'complex_double': 'N',
'complex_long_double': 'N',
'string': 'y',
'character': 'c'}
f2cmap_all = {'real': {'': 'float', '4': 'float', '8': 'double',
'12': 'long_double', '16': 'long_double'},
'integer': {'': 'int', '1': 'signed_char', '2': 'short',
'4': 'int', '8': 'long_long',
'-1': 'unsigned_char', '-2': 'unsigned_short',
'-4': 'unsigned', '-8': 'unsigned_long_long'},
'complex': {'': 'complex_float', '8': 'complex_float',
'16': 'complex_double', '24': 'complex_long_double',
'32': 'complex_long_double'},
'complexkind': {'': 'complex_float', '4': 'complex_float',
'8': 'complex_double', '12': 'complex_long_double',
'16': 'complex_long_double'},
'logical': {'': 'int', '1': 'char', '2': 'short', '4': 'int',
'8': 'long_long'},
'double complex': {'': 'complex_double'},
'double precision': {'': 'double'},
'byte': {'': 'char'},
}
# Add ISO_C handling
c2pycode_map.update(isoc_c2pycode_map)
c2py_map.update(iso_c2py_map)
f2cmap_all, _ = process_f2cmap_dict(f2cmap_all, iso_c_binding_map, c2py_map)
# End ISO_C handling
f2cmap_default = copy.deepcopy(f2cmap_all)
f2cmap_mapped = []
def load_f2cmap_file(f2cmap_file):
global f2cmap_all, f2cmap_mapped
f2cmap_all = copy.deepcopy(f2cmap_default)
if f2cmap_file is None:
# Default value
f2cmap_file = '.f2py_f2cmap'
if not os.path.isfile(f2cmap_file):
return
# User defined additions to f2cmap_all.
# f2cmap_file must contain a dictionary of dictionaries, only. For
# example, {'real':{'low':'float'}} means that Fortran 'real(low)' is
# interpreted as C 'float'. This feature is useful for F90/95 users if
# they use PARAMETERS in type specifications.
try:
outmess('Reading f2cmap from {!r} ...\n'.format(f2cmap_file))
with open(f2cmap_file) as f:
d = eval(f.read().lower(), {}, {})
f2cmap_all, f2cmap_mapped = process_f2cmap_dict(f2cmap_all, d, c2py_map, True)
outmess('Successfully applied user defined f2cmap changes\n')
except Exception as msg:
errmess('Failed to apply user defined f2cmap changes: %s. Skipping.\n' % (msg))
cformat_map = {'double': '%g',
'float': '%g',
'long_double': '%Lg',
'char': '%d',
'signed_char': '%d',
'unsigned_char': '%hhu',
'short': '%hd',
'unsigned_short': '%hu',
'int': '%d',
'unsigned': '%u',
'long': '%ld',
'unsigned_long': '%lu',
'long_long': '%ld',
'complex_float': '(%g,%g)',
'complex_double': '(%g,%g)',
'complex_long_double': '(%Lg,%Lg)',
'string': '\\"%s\\"',
'character': "'%c'",
}
# Auxiliary functions
def getctype(var):
"""
Determines C type
"""
ctype = 'void'
if isfunction(var):
if 'result' in var:
a = var['result']
else:
a = var['name']
if a in var['vars']:
return getctype(var['vars'][a])
else:
errmess('getctype: function %s has no return value?!\n' % a)
elif issubroutine(var):
return ctype
elif ischaracter_or_characterarray(var):
return 'character'
elif isstring_or_stringarray(var):
return 'string'
elif 'typespec' in var and var['typespec'].lower() in f2cmap_all:
typespec = var['typespec'].lower()
f2cmap = f2cmap_all[typespec]
ctype = f2cmap[''] # default type
if 'kindselector' in var:
if '*' in var['kindselector']:
try:
ctype = f2cmap[var['kindselector']['*']]
except KeyError:
errmess('getctype: "%s %s %s" not supported.\n' %
(var['typespec'], '*', var['kindselector']['*']))
elif 'kind' in var['kindselector']:
if typespec + 'kind' in f2cmap_all:
f2cmap = f2cmap_all[typespec + 'kind']
try:
ctype = f2cmap[var['kindselector']['kind']]
except KeyError:
if typespec in f2cmap_all:
f2cmap = f2cmap_all[typespec]
try:
ctype = f2cmap[str(var['kindselector']['kind'])]
except KeyError:
errmess('getctype: "%s(kind=%s)" is mapped to C "%s" (to override define dict(%s = dict(%s="<C typespec>")) in %s/.f2py_f2cmap file).\n'
% (typespec, var['kindselector']['kind'], ctype,
typespec, var['kindselector']['kind'], os.getcwd()))
else:
if not isexternal(var):
errmess('getctype: No C-type found in "%s", assuming void.\n' % var)
return ctype
def f2cexpr(expr):
"""Rewrite Fortran expression as f2py supported C expression.
Due to the lack of a proper expression parser in f2py, this
function uses a heuristic approach that assumes that Fortran
arithmetic expressions are valid C arithmetic expressions when
mapping Fortran function calls to the corresponding C function/CPP
macros calls.
"""
# TODO: support Fortran `len` function with optional kind parameter
expr = re.sub(r'\blen\b', 'f2py_slen', expr)
return expr
def getstrlength(var):
if isstringfunction(var):
if 'result' in var:
a = var['result']
else:
a = var['name']
if a in var['vars']:
return getstrlength(var['vars'][a])
else:
errmess('getstrlength: function %s has no return value?!\n' % a)
if not isstring(var):
errmess(
'getstrlength: expected a signature of a string but got: %s\n' % (repr(var)))
len = '1'
if 'charselector' in var:
a = var['charselector']
if '*' in a:
len = a['*']
elif 'len' in a:
len = f2cexpr(a['len'])
if re.match(r'\(\s*(\*|:)\s*\)', len) or re.match(r'(\*|:)', len):
if isintent_hide(var):
errmess('getstrlength:intent(hide): expected a string with defined length but got: %s\n' % (
repr(var)))
len = '-1'
return len
def getarrdims(a, var, verbose=0):
ret = {}
if isstring(var) and not isarray(var):
ret['size'] = getstrlength(var)
ret['rank'] = '0'
ret['dims'] = ''
elif isscalar(var):
ret['size'] = '1'
ret['rank'] = '0'
ret['dims'] = ''
elif isarray(var):
dim = copy.copy(var['dimension'])
ret['size'] = '*'.join(dim)
try:
ret['size'] = repr(eval(ret['size']))
except Exception:
pass
ret['dims'] = ','.join(dim)
ret['rank'] = repr(len(dim))
ret['rank*[-1]'] = repr(len(dim) * [-1])[1:-1]
for i in range(len(dim)): # solve dim for dependencies
v = []
if dim[i] in depargs:
v = [dim[i]]
else:
for va in depargs:
if re.match(r'.*?\b%s\b.*' % va, dim[i]):
v.append(va)
for va in v:
if depargs.index(va) > depargs.index(a):
dim[i] = '*'
break
ret['setdims'], i = '', -1
for d in dim:
i = i + 1
if d not in ['*', ':', '(*)', '(:)']:
ret['setdims'] = '%s#varname#_Dims[%d]=%s,' % (
ret['setdims'], i, d)
if ret['setdims']:
ret['setdims'] = ret['setdims'][:-1]
ret['cbsetdims'], i = '', -1
for d in var['dimension']:
i = i + 1
if d not in ['*', ':', '(*)', '(:)']:
ret['cbsetdims'] = '%s#varname#_Dims[%d]=%s,' % (
ret['cbsetdims'], i, d)
elif isintent_in(var):
outmess('getarrdims:warning: assumed shape array, using 0 instead of %r\n'
% (d))
ret['cbsetdims'] = '%s#varname#_Dims[%d]=%s,' % (
ret['cbsetdims'], i, 0)
elif verbose:
errmess(
'getarrdims: If in call-back function: array argument %s must have bounded dimensions: got %s\n' % (repr(a), repr(d)))
if ret['cbsetdims']:
ret['cbsetdims'] = ret['cbsetdims'][:-1]
# if not isintent_c(var):
# var['dimension'].reverse()
return ret
def getpydocsign(a, var):
global lcb_map
if isfunction(var):
if 'result' in var:
af = var['result']
else:
af = var['name']
if af in var['vars']:
return getpydocsign(af, var['vars'][af])
else:
errmess('getctype: function %s has no return value?!\n' % af)
return '', ''
sig, sigout = a, a
opt = ''
if isintent_in(var):
opt = 'input'
elif isintent_inout(var):
opt = 'in/output'
out_a = a
if isintent_out(var):
for k in var['intent']:
if k[:4] == 'out=':
out_a = k[4:]
break
init = ''
ctype = getctype(var)
if hasinitvalue(var):
init, showinit = getinit(a, var)
init = ', optional\\n Default: %s' % showinit
if isscalar(var):
if isintent_inout(var):
sig = '%s : %s rank-0 array(%s,\'%s\')%s' % (a, opt, c2py_map[ctype],
c2pycode_map[ctype], init)
else:
sig = '%s : %s %s%s' % (a, opt, c2py_map[ctype], init)
sigout = '%s : %s' % (out_a, c2py_map[ctype])
elif isstring(var):
if isintent_inout(var):
sig = '%s : %s rank-0 array(string(len=%s),\'c\')%s' % (
a, opt, getstrlength(var), init)
else:
sig = '%s : %s string(len=%s)%s' % (
a, opt, getstrlength(var), init)
sigout = '%s : string(len=%s)' % (out_a, getstrlength(var))
elif isarray(var):
dim = var['dimension']
rank = repr(len(dim))
sig = '%s : %s rank-%s array(\'%s\') with bounds (%s)%s' % (a, opt, rank,
c2pycode_map[
ctype],
','.join(dim), init)
if a == out_a:
sigout = '%s : rank-%s array(\'%s\') with bounds (%s)'\
% (a, rank, c2pycode_map[ctype], ','.join(dim))
else:
sigout = '%s : rank-%s array(\'%s\') with bounds (%s) and %s storage'\
% (out_a, rank, c2pycode_map[ctype], ','.join(dim), a)
elif isexternal(var):
ua = ''
if a in lcb_map and lcb_map[a] in lcb2_map and 'argname' in lcb2_map[lcb_map[a]]:
ua = lcb2_map[lcb_map[a]]['argname']
if not ua == a:
ua = ' => %s' % ua
else:
ua = ''
sig = '%s : call-back function%s' % (a, ua)
sigout = sig
else:
errmess(
'getpydocsign: Could not resolve docsignature for "%s".\n' % a)
return sig, sigout
def getarrdocsign(a, var):
ctype = getctype(var)
if isstring(var) and (not isarray(var)):
sig = '%s : rank-0 array(string(len=%s),\'c\')' % (a,
getstrlength(var))
elif isscalar(var):
sig = '%s : rank-0 array(%s,\'%s\')' % (a, c2py_map[ctype],
c2pycode_map[ctype],)
elif isarray(var):
dim = var['dimension']
rank = repr(len(dim))
sig = '%s : rank-%s array(\'%s\') with bounds (%s)' % (a, rank,
c2pycode_map[
ctype],
','.join(dim))
return sig
def getinit(a, var):
if isstring(var):
init, showinit = '""', "''"
else:
init, showinit = '', ''
if hasinitvalue(var):
init = var['=']
showinit = init
if iscomplex(var) or iscomplexarray(var):
ret = {}
try:
v = var["="]
if ',' in v:
ret['init.r'], ret['init.i'] = markoutercomma(
v[1:-1]).split('@,@')
else:
v = eval(v, {}, {})
ret['init.r'], ret['init.i'] = str(v.real), str(v.imag)
except Exception:
raise ValueError(
'getinit: expected complex number `(r,i)\' but got `%s\' as initial value of %r.' % (init, a))
if isarray(var):
init = '(capi_c.r=%s,capi_c.i=%s,capi_c)' % (
ret['init.r'], ret['init.i'])
elif isstring(var):
if not init:
init, showinit = '""', "''"
if init[0] == "'":
init = '"%s"' % (init[1:-1].replace('"', '\\"'))
if init[0] == '"':
showinit = "'%s'" % (init[1:-1])
return init, showinit
def get_elsize(var):
if isstring(var) or isstringarray(var):
elsize = getstrlength(var)
# override with user-specified length when available:
elsize = var['charselector'].get('f2py_len', elsize)
return elsize
if ischaracter(var) or ischaracterarray(var):
return '1'
# for numerical types, PyArray_New* functions ignore specified
# elsize, so we just return 1 and let elsize be determined at
# runtime, see fortranobject.c
return '1'
def sign2map(a, var):
"""
varname,ctype,atype
init,init.r,init.i,pytype
vardebuginfo,vardebugshowvalue,varshowvalue
varrformat
intent
"""
out_a = a
if isintent_out(var):
for k in var['intent']:
if k[:4] == 'out=':
out_a = k[4:]
break
ret = {'varname': a, 'outvarname': out_a, 'ctype': getctype(var)}
intent_flags = []
for f, s in isintent_dict.items():
if f(var):
intent_flags.append('F2PY_%s' % s)
if intent_flags:
# TODO: Evaluate intent_flags here.
ret['intent'] = '|'.join(intent_flags)
else:
ret['intent'] = 'F2PY_INTENT_IN'
if isarray(var):
ret['varrformat'] = 'N'
elif ret['ctype'] in c2buildvalue_map:
ret['varrformat'] = c2buildvalue_map[ret['ctype']]
else:
ret['varrformat'] = 'O'
ret['init'], ret['showinit'] = getinit(a, var)
if hasinitvalue(var) and iscomplex(var) and not isarray(var):
ret['init.r'], ret['init.i'] = markoutercomma(
ret['init'][1:-1]).split('@,@')
if isexternal(var):
ret['cbnamekey'] = a
if a in lcb_map:
ret['cbname'] = lcb_map[a]
ret['maxnofargs'] = lcb2_map[lcb_map[a]]['maxnofargs']
ret['nofoptargs'] = lcb2_map[lcb_map[a]]['nofoptargs']
ret['cbdocstr'] = lcb2_map[lcb_map[a]]['docstr']
ret['cblatexdocstr'] = lcb2_map[lcb_map[a]]['latexdocstr']
else:
ret['cbname'] = a
errmess('sign2map: Confused: external %s is not in lcb_map%s.\n' % (
a, list(lcb_map.keys())))
if isstring(var):
ret['length'] = getstrlength(var)
if isarray(var):
ret = dictappend(ret, getarrdims(a, var))
dim = copy.copy(var['dimension'])
if ret['ctype'] in c2capi_map:
ret['atype'] = c2capi_map[ret['ctype']]
ret['elsize'] = get_elsize(var)
# Debug info
if debugcapi(var):
il = [isintent_in, 'input', isintent_out, 'output',
isintent_inout, 'inoutput', isrequired, 'required',
isoptional, 'optional', isintent_hide, 'hidden',
iscomplex, 'complex scalar',
l_and(isscalar, l_not(iscomplex)), 'scalar',
isstring, 'string', isarray, 'array',
iscomplexarray, 'complex array', isstringarray, 'string array',
iscomplexfunction, 'complex function',
l_and(isfunction, l_not(iscomplexfunction)), 'function',
isexternal, 'callback',
isintent_callback, 'callback',
isintent_aux, 'auxiliary',
]
rl = []
for i in range(0, len(il), 2):
if il[i](var):
rl.append(il[i + 1])
if isstring(var):
rl.append('slen(%s)=%s' % (a, ret['length']))
if isarray(var):
ddim = ','.join(
map(lambda x, y: '%s|%s' % (x, y), var['dimension'], dim))
rl.append('dims(%s)' % ddim)
if isexternal(var):
ret['vardebuginfo'] = 'debug-capi:%s=>%s:%s' % (
a, ret['cbname'], ','.join(rl))
else:
ret['vardebuginfo'] = 'debug-capi:%s %s=%s:%s' % (
ret['ctype'], a, ret['showinit'], ','.join(rl))
if isscalar(var):
if ret['ctype'] in cformat_map:
ret['vardebugshowvalue'] = 'debug-capi:%s=%s' % (
a, cformat_map[ret['ctype']])
if isstring(var):
ret['vardebugshowvalue'] = 'debug-capi:slen(%s)=%%d %s=\\"%%s\\"' % (
a, a)
if isexternal(var):
ret['vardebugshowvalue'] = 'debug-capi:%s=%%p' % (a)
if ret['ctype'] in cformat_map:
ret['varshowvalue'] = '#name#:%s=%s' % (a, cformat_map[ret['ctype']])
ret['showvalueformat'] = '%s' % (cformat_map[ret['ctype']])
if isstring(var):
ret['varshowvalue'] = '#name#:slen(%s)=%%d %s=\\"%%s\\"' % (a, a)
ret['pydocsign'], ret['pydocsignout'] = getpydocsign(a, var)
if hasnote(var):
ret['note'] = var['note']
return ret
def routsign2map(rout):
"""
name,NAME,begintitle,endtitle
rname,ctype,rformat
routdebugshowvalue
"""
global lcb_map
name = rout['name']
fname = getfortranname(rout)
ret = {'name': name,
'texname': name.replace('_', '\\_'),
'name_lower': name.lower(),
'NAME': name.upper(),
'begintitle': gentitle(name),
'endtitle': gentitle('end of %s' % name),
'fortranname': fname,
'FORTRANNAME': fname.upper(),
'callstatement': getcallstatement(rout) or '',
'usercode': getusercode(rout) or '',
'usercode1': getusercode1(rout) or '',
}
if '_' in fname:
ret['F_FUNC'] = 'F_FUNC_US'
else:
ret['F_FUNC'] = 'F_FUNC'
if '_' in name:
ret['F_WRAPPEDFUNC'] = 'F_WRAPPEDFUNC_US'
else:
ret['F_WRAPPEDFUNC'] = 'F_WRAPPEDFUNC'
lcb_map = {}
if 'use' in rout:
for u in rout['use'].keys():
if u in cb_rules.cb_map:
for un in cb_rules.cb_map[u]:
ln = un[0]
if 'map' in rout['use'][u]:
for k in rout['use'][u]['map'].keys():
if rout['use'][u]['map'][k] == un[0]:
ln = k
break
lcb_map[ln] = un[1]
elif 'externals' in rout and rout['externals']:
errmess('routsign2map: Confused: function %s has externals %s but no "use" statement.\n' % (
ret['name'], repr(rout['externals'])))
ret['callprotoargument'] = getcallprotoargument(rout, lcb_map) or ''
if isfunction(rout):
if 'result' in rout:
a = rout['result']
else:
a = rout['name']
ret['rname'] = a
ret['pydocsign'], ret['pydocsignout'] = getpydocsign(a, rout)
ret['ctype'] = getctype(rout['vars'][a])
if hasresultnote(rout):
ret['resultnote'] = rout['vars'][a]['note']
rout['vars'][a]['note'] = ['See elsewhere.']
if ret['ctype'] in c2buildvalue_map:
ret['rformat'] = c2buildvalue_map[ret['ctype']]
else:
ret['rformat'] = 'O'
errmess('routsign2map: no c2buildvalue key for type %s\n' %
(repr(ret['ctype'])))
if debugcapi(rout):
if ret['ctype'] in cformat_map:
ret['routdebugshowvalue'] = 'debug-capi:%s=%s' % (
a, cformat_map[ret['ctype']])
if isstringfunction(rout):
ret['routdebugshowvalue'] = 'debug-capi:slen(%s)=%%d %s=\\"%%s\\"' % (
a, a)
if isstringfunction(rout):
ret['rlength'] = getstrlength(rout['vars'][a])
if ret['rlength'] == '-1':
errmess('routsign2map: expected explicit specification of the length of the string returned by the fortran function %s; taking 10.\n' % (
repr(rout['name'])))
ret['rlength'] = '10'
if hasnote(rout):
ret['note'] = rout['note']
rout['note'] = ['See elsewhere.']
return ret
def modsign2map(m):
"""
modulename
"""
if ismodule(m):
ret = {'f90modulename': m['name'],
'F90MODULENAME': m['name'].upper(),
'texf90modulename': m['name'].replace('_', '\\_')}
else:
ret = {'modulename': m['name'],
'MODULENAME': m['name'].upper(),
'texmodulename': m['name'].replace('_', '\\_')}
ret['restdoc'] = getrestdoc(m) or []
if hasnote(m):
ret['note'] = m['note']
ret['usercode'] = getusercode(m) or ''
ret['usercode1'] = getusercode1(m) or ''
if m['body']:
ret['interface_usercode'] = getusercode(m['body'][0]) or ''
else:
ret['interface_usercode'] = ''
ret['pymethoddef'] = getpymethoddef(m) or ''
if 'gil_used' in m:
ret['gil_used'] = m['gil_used']
if 'coutput' in m:
ret['coutput'] = m['coutput']
if 'f2py_wrapper_output' in m:
ret['f2py_wrapper_output'] = m['f2py_wrapper_output']
return ret
def cb_sign2map(a, var, index=None):
ret = {'varname': a}
ret['varname_i'] = ret['varname']
ret['ctype'] = getctype(var)
if ret['ctype'] in c2capi_map:
ret['atype'] = c2capi_map[ret['ctype']]
ret['elsize'] = get_elsize(var)
if ret['ctype'] in cformat_map:
ret['showvalueformat'] = '%s' % (cformat_map[ret['ctype']])
if isarray(var):
ret = dictappend(ret, getarrdims(a, var))
ret['pydocsign'], ret['pydocsignout'] = getpydocsign(a, var)
if hasnote(var):
ret['note'] = var['note']
var['note'] = ['See elsewhere.']
return ret
def cb_routsign2map(rout, um):
"""
name,begintitle,endtitle,argname
ctype,rctype,maxnofargs,nofoptargs,returncptr
"""
ret = {'name': 'cb_%s_in_%s' % (rout['name'], um),
'returncptr': ''}
if isintent_callback(rout):
if '_' in rout['name']:
F_FUNC = 'F_FUNC_US'
else:
F_FUNC = 'F_FUNC'
ret['callbackname'] = '%s(%s,%s)' \
% (F_FUNC,
rout['name'].lower(),
rout['name'].upper(),
)
ret['static'] = 'extern'
else:
ret['callbackname'] = ret['name']
ret['static'] = 'static'
ret['argname'] = rout['name']
ret['begintitle'] = gentitle(ret['name'])
ret['endtitle'] = gentitle('end of %s' % ret['name'])
ret['ctype'] = getctype(rout)
ret['rctype'] = 'void'
if ret['ctype'] == 'string':
ret['rctype'] = 'void'
else:
ret['rctype'] = ret['ctype']
if ret['rctype'] != 'void':
if iscomplexfunction(rout):
ret['returncptr'] = """
#ifdef F2PY_CB_RETURNCOMPLEX
return_value=
#endif
"""
else:
ret['returncptr'] = 'return_value='
if ret['ctype'] in cformat_map:
ret['showvalueformat'] = '%s' % (cformat_map[ret['ctype']])
if isstringfunction(rout):
ret['strlength'] = getstrlength(rout)
if isfunction(rout):
if 'result' in rout:
a = rout['result']
else:
a = rout['name']
if hasnote(rout['vars'][a]):
ret['note'] = rout['vars'][a]['note']
rout['vars'][a]['note'] = ['See elsewhere.']
ret['rname'] = a
ret['pydocsign'], ret['pydocsignout'] = getpydocsign(a, rout)
if iscomplexfunction(rout):
ret['rctype'] = """
#ifdef F2PY_CB_RETURNCOMPLEX
#ctype#
#else
void
#endif
"""
else:
if hasnote(rout):
ret['note'] = rout['note']
rout['note'] = ['See elsewhere.']
nofargs = 0
nofoptargs = 0
if 'args' in rout and 'vars' in rout:
for a in rout['args']:
var = rout['vars'][a]
if l_or(isintent_in, isintent_inout)(var):
nofargs = nofargs + 1
if isoptional(var):
nofoptargs = nofoptargs + 1
ret['maxnofargs'] = repr(nofargs)
ret['nofoptargs'] = repr(nofoptargs)
if hasnote(rout) and isfunction(rout) and 'result' in rout:
ret['routnote'] = rout['note']
rout['note'] = ['See elsewhere.']
return ret
def common_sign2map(a, var): # obsolute
ret = {'varname': a, 'ctype': getctype(var)}
if isstringarray(var):
ret['ctype'] = 'char'
if ret['ctype'] in c2capi_map:
ret['atype'] = c2capi_map[ret['ctype']]
ret['elsize'] = get_elsize(var)
if ret['ctype'] in cformat_map:
ret['showvalueformat'] = '%s' % (cformat_map[ret['ctype']])
if isarray(var):
ret = dictappend(ret, getarrdims(a, var))
elif isstring(var):
ret['size'] = getstrlength(var)
ret['rank'] = '1'
ret['pydocsign'], ret['pydocsignout'] = getpydocsign(a, var)
if hasnote(var):
ret['note'] = var['note']
var['note'] = ['See elsewhere.']
# for strings this returns 0-rank but actually is 1-rank
ret['arrdocstr'] = getarrdocsign(a, var)
return ret

View File

@ -0,0 +1,644 @@
"""
Build call-back mechanism for f2py2e.
Copyright 1999 -- 2011 Pearu Peterson all rights reserved.
Copyright 2011 -- present NumPy Developers.
Permission to use, modify, and distribute this software is given under the
terms of the NumPy License.
NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
"""
from . import __version__
from .auxfuncs import (
applyrules, debugcapi, dictappend, errmess, getargs, hasnote, isarray,
iscomplex, iscomplexarray, iscomplexfunction, isfunction, isintent_c,
isintent_hide, isintent_in, isintent_inout, isintent_nothide,
isintent_out, isoptional, isrequired, isscalar, isstring,
isstringfunction, issubroutine, l_and, l_not, l_or, outmess, replace,
stripcomma, throw_error
)
from . import cfuncs
f2py_version = __version__.version
################## Rules for callback function ##############
cb_routine_rules = {
'cbtypedefs': 'typedef #rctype#(*#name#_typedef)(#optargs_td##args_td##strarglens_td##noargs#);',
'body': """
#begintitle#
typedef struct {
PyObject *capi;
PyTupleObject *args_capi;
int nofargs;
jmp_buf jmpbuf;
} #name#_t;
#if defined(F2PY_THREAD_LOCAL_DECL) && !defined(F2PY_USE_PYTHON_TLS)
static F2PY_THREAD_LOCAL_DECL #name#_t *_active_#name# = NULL;
static #name#_t *swap_active_#name#(#name#_t *ptr) {
#name#_t *prev = _active_#name#;
_active_#name# = ptr;
return prev;
}
static #name#_t *get_active_#name#(void) {
return _active_#name#;
}
#else
static #name#_t *swap_active_#name#(#name#_t *ptr) {
char *key = "__f2py_cb_#name#";
return (#name#_t *)F2PySwapThreadLocalCallbackPtr(key, ptr);
}
static #name#_t *get_active_#name#(void) {
char *key = "__f2py_cb_#name#";
return (#name#_t *)F2PyGetThreadLocalCallbackPtr(key);
}
#endif
/*typedef #rctype#(*#name#_typedef)(#optargs_td##args_td##strarglens_td##noargs#);*/
#static# #rctype# #callbackname# (#optargs##args##strarglens##noargs#) {
#name#_t cb_local = { NULL, NULL, 0 };
#name#_t *cb = NULL;
PyTupleObject *capi_arglist = NULL;
PyObject *capi_return = NULL;
PyObject *capi_tmp = NULL;
PyObject *capi_arglist_list = NULL;
int capi_j,capi_i = 0;
int capi_longjmp_ok = 1;
#decl#
#ifdef F2PY_REPORT_ATEXIT
f2py_cb_start_clock();
#endif
cb = get_active_#name#();
if (cb == NULL) {
capi_longjmp_ok = 0;
cb = &cb_local;
}
capi_arglist = cb->args_capi;
CFUNCSMESS(\"cb:Call-back function #name# (maxnofargs=#maxnofargs#(-#nofoptargs#))\\n\");
CFUNCSMESSPY(\"cb:#name#_capi=\",cb->capi);
if (cb->capi==NULL) {
capi_longjmp_ok = 0;
cb->capi = PyObject_GetAttrString(#modulename#_module,\"#argname#\");
CFUNCSMESSPY(\"cb:#name#_capi=\",cb->capi);
}
if (cb->capi==NULL) {
PyErr_SetString(#modulename#_error,\"cb: Callback #argname# not defined (as an argument or module #modulename# attribute).\\n\");
goto capi_fail;
}
if (F2PyCapsule_Check(cb->capi)) {
#name#_typedef #name#_cptr;
#name#_cptr = F2PyCapsule_AsVoidPtr(cb->capi);
#returncptr#(*#name#_cptr)(#optargs_nm##args_nm##strarglens_nm#);
#return#
}
if (capi_arglist==NULL) {
capi_longjmp_ok = 0;
capi_tmp = PyObject_GetAttrString(#modulename#_module,\"#argname#_extra_args\");
if (capi_tmp) {
capi_arglist = (PyTupleObject *)PySequence_Tuple(capi_tmp);
Py_DECREF(capi_tmp);
if (capi_arglist==NULL) {
PyErr_SetString(#modulename#_error,\"Failed to convert #modulename#.#argname#_extra_args to tuple.\\n\");
goto capi_fail;
}
} else {
PyErr_Clear();
capi_arglist = (PyTupleObject *)Py_BuildValue(\"()\");
}
}
if (capi_arglist == NULL) {
PyErr_SetString(#modulename#_error,\"Callback #argname# argument list is not set.\\n\");
goto capi_fail;
}
#setdims#
#ifdef PYPY_VERSION
#define CAPI_ARGLIST_SETITEM(idx, value) PyList_SetItem((PyObject *)capi_arglist_list, idx, value)
capi_arglist_list = PySequence_List((PyObject *)capi_arglist);
if (capi_arglist_list == NULL) goto capi_fail;
#else
#define CAPI_ARGLIST_SETITEM(idx, value) PyTuple_SetItem((PyObject *)capi_arglist, idx, value)
#endif
#pyobjfrom#
#undef CAPI_ARGLIST_SETITEM
#ifdef PYPY_VERSION
CFUNCSMESSPY(\"cb:capi_arglist=\",capi_arglist_list);
#else
CFUNCSMESSPY(\"cb:capi_arglist=\",capi_arglist);
#endif
CFUNCSMESS(\"cb:Call-back calling Python function #argname#.\\n\");
#ifdef F2PY_REPORT_ATEXIT
f2py_cb_start_call_clock();
#endif
#ifdef PYPY_VERSION
capi_return = PyObject_CallObject(cb->capi,(PyObject *)capi_arglist_list);
Py_DECREF(capi_arglist_list);
capi_arglist_list = NULL;
#else
capi_return = PyObject_CallObject(cb->capi,(PyObject *)capi_arglist);
#endif
#ifdef F2PY_REPORT_ATEXIT
f2py_cb_stop_call_clock();
#endif
CFUNCSMESSPY(\"cb:capi_return=\",capi_return);
if (capi_return == NULL) {
fprintf(stderr,\"capi_return is NULL\\n\");
goto capi_fail;
}
if (capi_return == Py_None) {
Py_DECREF(capi_return);
capi_return = Py_BuildValue(\"()\");
}
else if (!PyTuple_Check(capi_return)) {
capi_return = Py_BuildValue(\"(N)\",capi_return);
}
capi_j = PyTuple_Size(capi_return);
capi_i = 0;
#frompyobj#
CFUNCSMESS(\"cb:#name#:successful\\n\");
Py_DECREF(capi_return);
#ifdef F2PY_REPORT_ATEXIT
f2py_cb_stop_clock();
#endif
goto capi_return_pt;
capi_fail:
fprintf(stderr,\"Call-back #name# failed.\\n\");
Py_XDECREF(capi_return);
Py_XDECREF(capi_arglist_list);
if (capi_longjmp_ok) {
longjmp(cb->jmpbuf,-1);
}
capi_return_pt:
;
#return#
}
#endtitle#
""",
'need': ['setjmp.h', 'CFUNCSMESS', 'F2PY_THREAD_LOCAL_DECL'],
'maxnofargs': '#maxnofargs#',
'nofoptargs': '#nofoptargs#',
'docstr': """\
def #argname#(#docsignature#): return #docreturn#\\n\\
#docstrsigns#""",
'latexdocstr': """
{{}\\verb@def #argname#(#latexdocsignature#): return #docreturn#@{}}
#routnote#
#latexdocstrsigns#""",
'docstrshort': 'def #argname#(#docsignature#): return #docreturn#'
}
cb_rout_rules = [
{ # Init
'separatorsfor': {'decl': '\n',
'args': ',', 'optargs': '', 'pyobjfrom': '\n', 'freemem': '\n',
'args_td': ',', 'optargs_td': '',
'args_nm': ',', 'optargs_nm': '',
'frompyobj': '\n', 'setdims': '\n',
'docstrsigns': '\\n"\n"',
'latexdocstrsigns': '\n',
'latexdocstrreq': '\n', 'latexdocstropt': '\n',
'latexdocstrout': '\n', 'latexdocstrcbs': '\n',
},
'decl': '/*decl*/', 'pyobjfrom': '/*pyobjfrom*/', 'frompyobj': '/*frompyobj*/',
'args': [], 'optargs': '', 'return': '', 'strarglens': '', 'freemem': '/*freemem*/',
'args_td': [], 'optargs_td': '', 'strarglens_td': '',
'args_nm': [], 'optargs_nm': '', 'strarglens_nm': '',
'noargs': '',
'setdims': '/*setdims*/',
'docstrsigns': '', 'latexdocstrsigns': '',
'docstrreq': ' Required arguments:',
'docstropt': ' Optional arguments:',
'docstrout': ' Return objects:',
'docstrcbs': ' Call-back functions:',
'docreturn': '', 'docsign': '', 'docsignopt': '',
'latexdocstrreq': '\\noindent Required arguments:',
'latexdocstropt': '\\noindent Optional arguments:',
'latexdocstrout': '\\noindent Return objects:',
'latexdocstrcbs': '\\noindent Call-back functions:',
'routnote': {hasnote: '--- #note#', l_not(hasnote): ''},
}, { # Function
'decl': ' #ctype# return_value = 0;',
'frompyobj': [
{debugcapi: ' CFUNCSMESS("cb:Getting return_value->");'},
'''\
if (capi_j>capi_i) {
GETSCALARFROMPYTUPLE(capi_return,capi_i++,&return_value,#ctype#,
"#ctype#_from_pyobj failed in converting return_value of"
" call-back function #name# to C #ctype#\\n");
} else {
fprintf(stderr,"Warning: call-back function #name# did not provide"
" return value (index=%d, type=#ctype#)\\n",capi_i);
}''',
{debugcapi:
' fprintf(stderr,"#showvalueformat#.\\n",return_value);'}
],
'need': ['#ctype#_from_pyobj', {debugcapi: 'CFUNCSMESS'}, 'GETSCALARFROMPYTUPLE'],
'return': ' return return_value;',
'_check': l_and(isfunction, l_not(isstringfunction), l_not(iscomplexfunction))
},
{ # String function
'pyobjfrom': {debugcapi: ' fprintf(stderr,"debug-capi:cb:#name#:%d:\\n",return_value_len);'},
'args': '#ctype# return_value,int return_value_len',
'args_nm': 'return_value,&return_value_len',
'args_td': '#ctype# ,int',
'frompyobj': [
{debugcapi: ' CFUNCSMESS("cb:Getting return_value->\\"");'},
"""\
if (capi_j>capi_i) {
GETSTRFROMPYTUPLE(capi_return,capi_i++,return_value,return_value_len);
} else {
fprintf(stderr,"Warning: call-back function #name# did not provide"
" return value (index=%d, type=#ctype#)\\n",capi_i);
}""",
{debugcapi:
' fprintf(stderr,"#showvalueformat#\\".\\n",return_value);'}
],
'need': ['#ctype#_from_pyobj', {debugcapi: 'CFUNCSMESS'},
'string.h', 'GETSTRFROMPYTUPLE'],
'return': 'return;',
'_check': isstringfunction
},
{ # Complex function
'optargs': """
#ifndef F2PY_CB_RETURNCOMPLEX
#ctype# *return_value
#endif
""",
'optargs_nm': """
#ifndef F2PY_CB_RETURNCOMPLEX
return_value
#endif
""",
'optargs_td': """
#ifndef F2PY_CB_RETURNCOMPLEX
#ctype# *
#endif
""",
'decl': """
#ifdef F2PY_CB_RETURNCOMPLEX
#ctype# return_value = {0, 0};
#endif
""",
'frompyobj': [
{debugcapi: ' CFUNCSMESS("cb:Getting return_value->");'},
"""\
if (capi_j>capi_i) {
#ifdef F2PY_CB_RETURNCOMPLEX
GETSCALARFROMPYTUPLE(capi_return,capi_i++,&return_value,#ctype#,
\"#ctype#_from_pyobj failed in converting return_value of call-back\"
\" function #name# to C #ctype#\\n\");
#else
GETSCALARFROMPYTUPLE(capi_return,capi_i++,return_value,#ctype#,
\"#ctype#_from_pyobj failed in converting return_value of call-back\"
\" function #name# to C #ctype#\\n\");
#endif
} else {
fprintf(stderr,
\"Warning: call-back function #name# did not provide\"
\" return value (index=%d, type=#ctype#)\\n\",capi_i);
}""",
{debugcapi: """\
#ifdef F2PY_CB_RETURNCOMPLEX
fprintf(stderr,\"#showvalueformat#.\\n\",(return_value).r,(return_value).i);
#else
fprintf(stderr,\"#showvalueformat#.\\n\",(*return_value).r,(*return_value).i);
#endif
"""}
],
'return': """
#ifdef F2PY_CB_RETURNCOMPLEX
return return_value;
#else
return;
#endif
""",
'need': ['#ctype#_from_pyobj', {debugcapi: 'CFUNCSMESS'},
'string.h', 'GETSCALARFROMPYTUPLE', '#ctype#'],
'_check': iscomplexfunction
},
{'docstrout': ' #pydocsignout#',
'latexdocstrout': ['\\item[]{{}\\verb@#pydocsignout#@{}}',
{hasnote: '--- #note#'}],
'docreturn': '#rname#,',
'_check': isfunction},
{'_check': issubroutine, 'return': 'return;'}
]
cb_arg_rules = [
{ # Doc
'docstropt': {l_and(isoptional, isintent_nothide): ' #pydocsign#'},
'docstrreq': {l_and(isrequired, isintent_nothide): ' #pydocsign#'},
'docstrout': {isintent_out: ' #pydocsignout#'},
'latexdocstropt': {l_and(isoptional, isintent_nothide): ['\\item[]{{}\\verb@#pydocsign#@{}}',
{hasnote: '--- #note#'}]},
'latexdocstrreq': {l_and(isrequired, isintent_nothide): ['\\item[]{{}\\verb@#pydocsign#@{}}',
{hasnote: '--- #note#'}]},
'latexdocstrout': {isintent_out: ['\\item[]{{}\\verb@#pydocsignout#@{}}',
{l_and(hasnote, isintent_hide): '--- #note#',
l_and(hasnote, isintent_nothide): '--- See above.'}]},
'docsign': {l_and(isrequired, isintent_nothide): '#varname#,'},
'docsignopt': {l_and(isoptional, isintent_nothide): '#varname#,'},
'depend': ''
},
{
'args': {
l_and(isscalar, isintent_c): '#ctype# #varname_i#',
l_and(isscalar, l_not(isintent_c)): '#ctype# *#varname_i#_cb_capi',
isarray: '#ctype# *#varname_i#',
isstring: '#ctype# #varname_i#'
},
'args_nm': {
l_and(isscalar, isintent_c): '#varname_i#',
l_and(isscalar, l_not(isintent_c)): '#varname_i#_cb_capi',
isarray: '#varname_i#',
isstring: '#varname_i#'
},
'args_td': {
l_and(isscalar, isintent_c): '#ctype#',
l_and(isscalar, l_not(isintent_c)): '#ctype# *',
isarray: '#ctype# *',
isstring: '#ctype#'
},
'need': {l_or(isscalar, isarray, isstring): '#ctype#'},
# untested with multiple args
'strarglens': {isstring: ',int #varname_i#_cb_len'},
'strarglens_td': {isstring: ',int'}, # untested with multiple args
# untested with multiple args
'strarglens_nm': {isstring: ',#varname_i#_cb_len'},
},
{ # Scalars
'decl': {l_not(isintent_c): ' #ctype# #varname_i#=(*#varname_i#_cb_capi);'},
'error': {l_and(isintent_c, isintent_out,
throw_error('intent(c,out) is forbidden for callback scalar arguments')):
''},
'frompyobj': [{debugcapi: ' CFUNCSMESS("cb:Getting #varname#->");'},
{isintent_out:
' if (capi_j>capi_i)\n GETSCALARFROMPYTUPLE(capi_return,capi_i++,#varname_i#_cb_capi,#ctype#,"#ctype#_from_pyobj failed in converting argument #varname# of call-back function #name# to C #ctype#\\n");'},
{l_and(debugcapi, l_and(l_not(iscomplex), isintent_c)):
' fprintf(stderr,"#showvalueformat#.\\n",#varname_i#);'},
{l_and(debugcapi, l_and(l_not(iscomplex), l_not( isintent_c))):
' fprintf(stderr,"#showvalueformat#.\\n",*#varname_i#_cb_capi);'},
{l_and(debugcapi, l_and(iscomplex, isintent_c)):
' fprintf(stderr,"#showvalueformat#.\\n",(#varname_i#).r,(#varname_i#).i);'},
{l_and(debugcapi, l_and(iscomplex, l_not( isintent_c))):
' fprintf(stderr,"#showvalueformat#.\\n",(*#varname_i#_cb_capi).r,(*#varname_i#_cb_capi).i);'},
],
'need': [{isintent_out: ['#ctype#_from_pyobj', 'GETSCALARFROMPYTUPLE']},
{debugcapi: 'CFUNCSMESS'}],
'_check': isscalar
}, {
'pyobjfrom': [{isintent_in: """\
if (cb->nofargs>capi_i)
if (CAPI_ARGLIST_SETITEM(capi_i++,pyobj_from_#ctype#1(#varname_i#)))
goto capi_fail;"""},
{isintent_inout: """\
if (cb->nofargs>capi_i)
if (CAPI_ARGLIST_SETITEM(capi_i++,pyarr_from_p_#ctype#1(#varname_i#_cb_capi)))
goto capi_fail;"""}],
'need': [{isintent_in: 'pyobj_from_#ctype#1'},
{isintent_inout: 'pyarr_from_p_#ctype#1'},
{iscomplex: '#ctype#'}],
'_check': l_and(isscalar, isintent_nothide),
'_optional': ''
}, { # String
'frompyobj': [{debugcapi: ' CFUNCSMESS("cb:Getting #varname#->\\"");'},
""" if (capi_j>capi_i)
GETSTRFROMPYTUPLE(capi_return,capi_i++,#varname_i#,#varname_i#_cb_len);""",
{debugcapi:
' fprintf(stderr,"#showvalueformat#\\":%d:.\\n",#varname_i#,#varname_i#_cb_len);'},
],
'need': ['#ctype#', 'GETSTRFROMPYTUPLE',
{debugcapi: 'CFUNCSMESS'}, 'string.h'],
'_check': l_and(isstring, isintent_out)
}, {
'pyobjfrom': [
{debugcapi:
(' fprintf(stderr,"debug-capi:cb:#varname#=#showvalueformat#:'
'%d:\\n",#varname_i#,#varname_i#_cb_len);')},
{isintent_in: """\
if (cb->nofargs>capi_i)
if (CAPI_ARGLIST_SETITEM(capi_i++,pyobj_from_#ctype#1size(#varname_i#,#varname_i#_cb_len)))
goto capi_fail;"""},
{isintent_inout: """\
if (cb->nofargs>capi_i) {
int #varname_i#_cb_dims[] = {#varname_i#_cb_len};
if (CAPI_ARGLIST_SETITEM(capi_i++,pyarr_from_p_#ctype#1(#varname_i#,#varname_i#_cb_dims)))
goto capi_fail;
}"""}],
'need': [{isintent_in: 'pyobj_from_#ctype#1size'},
{isintent_inout: 'pyarr_from_p_#ctype#1'}],
'_check': l_and(isstring, isintent_nothide),
'_optional': ''
},
# Array ...
{
'decl': ' npy_intp #varname_i#_Dims[#rank#] = {#rank*[-1]#};',
'setdims': ' #cbsetdims#;',
'_check': isarray,
'_depend': ''
},
{
'pyobjfrom': [{debugcapi: ' fprintf(stderr,"debug-capi:cb:#varname#\\n");'},
{isintent_c: """\
if (cb->nofargs>capi_i) {
/* tmp_arr will be inserted to capi_arglist_list that will be
destroyed when leaving callback function wrapper together
with tmp_arr. */
PyArrayObject *tmp_arr = (PyArrayObject *)PyArray_New(&PyArray_Type,
#rank#,#varname_i#_Dims,#atype#,NULL,(char*)#varname_i#,#elsize#,
NPY_ARRAY_CARRAY,NULL);
""",
l_not(isintent_c): """\
if (cb->nofargs>capi_i) {
/* tmp_arr will be inserted to capi_arglist_list that will be
destroyed when leaving callback function wrapper together
with tmp_arr. */
PyArrayObject *tmp_arr = (PyArrayObject *)PyArray_New(&PyArray_Type,
#rank#,#varname_i#_Dims,#atype#,NULL,(char*)#varname_i#,#elsize#,
NPY_ARRAY_FARRAY,NULL);
""",
},
"""
if (tmp_arr==NULL)
goto capi_fail;
if (CAPI_ARGLIST_SETITEM(capi_i++,(PyObject *)tmp_arr))
goto capi_fail;
}"""],
'_check': l_and(isarray, isintent_nothide, l_or(isintent_in, isintent_inout)),
'_optional': '',
}, {
'frompyobj': [{debugcapi: ' CFUNCSMESS("cb:Getting #varname#->");'},
""" if (capi_j>capi_i) {
PyArrayObject *rv_cb_arr = NULL;
if ((capi_tmp = PyTuple_GetItem(capi_return,capi_i++))==NULL) goto capi_fail;
rv_cb_arr = array_from_pyobj(#atype#,#varname_i#_Dims,#rank#,F2PY_INTENT_IN""",
{isintent_c: '|F2PY_INTENT_C'},
""",capi_tmp);
if (rv_cb_arr == NULL) {
fprintf(stderr,\"rv_cb_arr is NULL\\n\");
goto capi_fail;
}
MEMCOPY(#varname_i#,PyArray_DATA(rv_cb_arr),PyArray_NBYTES(rv_cb_arr));
if (capi_tmp != (PyObject *)rv_cb_arr) {
Py_DECREF(rv_cb_arr);
}
}""",
{debugcapi: ' fprintf(stderr,"<-.\\n");'},
],
'need': ['MEMCOPY', {iscomplexarray: '#ctype#'}],
'_check': l_and(isarray, isintent_out)
}, {
'docreturn': '#varname#,',
'_check': isintent_out
}
]
################## Build call-back module #############
cb_map = {}
def buildcallbacks(m):
cb_map[m['name']] = []
for bi in m['body']:
if bi['block'] == 'interface':
for b in bi['body']:
if b:
buildcallback(b, m['name'])
else:
errmess('warning: empty body for %s\n' % (m['name']))
def buildcallback(rout, um):
from . import capi_maps
outmess(' Constructing call-back function "cb_%s_in_%s"\n' %
(rout['name'], um))
args, depargs = getargs(rout)
capi_maps.depargs = depargs
var = rout['vars']
vrd = capi_maps.cb_routsign2map(rout, um)
rd = dictappend({}, vrd)
cb_map[um].append([rout['name'], rd['name']])
for r in cb_rout_rules:
if ('_check' in r and r['_check'](rout)) or ('_check' not in r):
ar = applyrules(r, vrd, rout)
rd = dictappend(rd, ar)
savevrd = {}
for i, a in enumerate(args):
vrd = capi_maps.cb_sign2map(a, var[a], index=i)
savevrd[a] = vrd
for r in cb_arg_rules:
if '_depend' in r:
continue
if '_optional' in r and isoptional(var[a]):
continue
if ('_check' in r and r['_check'](var[a])) or ('_check' not in r):
ar = applyrules(r, vrd, var[a])
rd = dictappend(rd, ar)
if '_break' in r:
break
for a in args:
vrd = savevrd[a]
for r in cb_arg_rules:
if '_depend' in r:
continue
if ('_optional' not in r) or ('_optional' in r and isrequired(var[a])):
continue
if ('_check' in r and r['_check'](var[a])) or ('_check' not in r):
ar = applyrules(r, vrd, var[a])
rd = dictappend(rd, ar)
if '_break' in r:
break
for a in depargs:
vrd = savevrd[a]
for r in cb_arg_rules:
if '_depend' not in r:
continue
if '_optional' in r:
continue
if ('_check' in r and r['_check'](var[a])) or ('_check' not in r):
ar = applyrules(r, vrd, var[a])
rd = dictappend(rd, ar)
if '_break' in r:
break
if 'args' in rd and 'optargs' in rd:
if isinstance(rd['optargs'], list):
rd['optargs'] = rd['optargs'] + ["""
#ifndef F2PY_CB_RETURNCOMPLEX
,
#endif
"""]
rd['optargs_nm'] = rd['optargs_nm'] + ["""
#ifndef F2PY_CB_RETURNCOMPLEX
,
#endif
"""]
rd['optargs_td'] = rd['optargs_td'] + ["""
#ifndef F2PY_CB_RETURNCOMPLEX
,
#endif
"""]
if isinstance(rd['docreturn'], list):
rd['docreturn'] = stripcomma(
replace('#docreturn#', {'docreturn': rd['docreturn']}))
optargs = stripcomma(replace('#docsignopt#',
{'docsignopt': rd['docsignopt']}
))
if optargs == '':
rd['docsignature'] = stripcomma(
replace('#docsign#', {'docsign': rd['docsign']}))
else:
rd['docsignature'] = replace('#docsign#[#docsignopt#]',
{'docsign': rd['docsign'],
'docsignopt': optargs,
})
rd['latexdocsignature'] = rd['docsignature'].replace('_', '\\_')
rd['latexdocsignature'] = rd['latexdocsignature'].replace(',', ', ')
rd['docstrsigns'] = []
rd['latexdocstrsigns'] = []
for k in ['docstrreq', 'docstropt', 'docstrout', 'docstrcbs']:
if k in rd and isinstance(rd[k], list):
rd['docstrsigns'] = rd['docstrsigns'] + rd[k]
k = 'latex' + k
if k in rd and isinstance(rd[k], list):
rd['latexdocstrsigns'] = rd['latexdocstrsigns'] + rd[k][0:1] +\
['\\begin{description}'] + rd[k][1:] +\
['\\end{description}']
if 'args' not in rd:
rd['args'] = ''
rd['args_td'] = ''
rd['args_nm'] = ''
if not (rd.get('args') or rd.get('optargs') or rd.get('strarglens')):
rd['noargs'] = 'void'
ar = applyrules(cb_routine_rules, rd)
cfuncs.callbacks[rd['name']] = ar['body']
if isinstance(ar['need'], str):
ar['need'] = [ar['need']]
if 'need' in rd:
for t in cfuncs.typedefs.keys():
if t in rd['need']:
ar['need'].append(t)
cfuncs.typedefs_generated[rd['name'] + '_typedef'] = ar['cbtypedefs']
ar['need'].append(rd['name'] + '_typedef')
cfuncs.needs[rd['name']] = ar['need']
capi_maps.lcb2_map[rd['name']] = {'maxnofargs': ar['maxnofargs'],
'nofoptargs': ar['nofoptargs'],
'docstr': ar['docstr'],
'latexdocstr': ar['latexdocstr'],
'argname': rd['argname']
}
outmess(' %s\n' % (ar['docstrshort']))
return
################## Build call-back function #############

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,146 @@
"""
Build common block mechanism for f2py2e.
Copyright 1999 -- 2011 Pearu Peterson all rights reserved.
Copyright 2011 -- present NumPy Developers.
Permission to use, modify, and distribute this software is given under the
terms of the NumPy License
NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
"""
from . import __version__
f2py_version = __version__.version
from .auxfuncs import (
hasbody, hascommon, hasnote, isintent_hide, outmess, getuseblocks
)
from . import capi_maps
from . import func2subr
from .crackfortran import rmbadname
def findcommonblocks(block, top=1):
ret = []
if hascommon(block):
for key, value in block['common'].items():
vars_ = {v: block['vars'][v] for v in value}
ret.append((key, value, vars_))
elif hasbody(block):
for b in block['body']:
ret = ret + findcommonblocks(b, 0)
if top:
tret = []
names = []
for t in ret:
if t[0] not in names:
names.append(t[0])
tret.append(t)
return tret
return ret
def buildhooks(m):
ret = {'commonhooks': [], 'initcommonhooks': [],
'docs': ['"COMMON blocks:\\n"']}
fwrap = ['']
def fadd(line, s=fwrap):
s[0] = '%s\n %s' % (s[0], line)
chooks = ['']
def cadd(line, s=chooks):
s[0] = '%s\n%s' % (s[0], line)
ihooks = ['']
def iadd(line, s=ihooks):
s[0] = '%s\n%s' % (s[0], line)
doc = ['']
def dadd(line, s=doc):
s[0] = '%s\n%s' % (s[0], line)
for (name, vnames, vars) in findcommonblocks(m):
lower_name = name.lower()
hnames, inames = [], []
for n in vnames:
if isintent_hide(vars[n]):
hnames.append(n)
else:
inames.append(n)
if hnames:
outmess('\t\tConstructing COMMON block support for "%s"...\n\t\t %s\n\t\t Hidden: %s\n' % (
name, ','.join(inames), ','.join(hnames)))
else:
outmess('\t\tConstructing COMMON block support for "%s"...\n\t\t %s\n' % (
name, ','.join(inames)))
fadd('subroutine f2pyinit%s(setupfunc)' % name)
for usename in getuseblocks(m):
fadd(f'use {usename}')
fadd('external setupfunc')
for n in vnames:
fadd(func2subr.var2fixfortran(vars, n))
if name == '_BLNK_':
fadd('common %s' % (','.join(vnames)))
else:
fadd('common /%s/ %s' % (name, ','.join(vnames)))
fadd('call setupfunc(%s)' % (','.join(inames)))
fadd('end\n')
cadd('static FortranDataDef f2py_%s_def[] = {' % (name))
idims = []
for n in inames:
ct = capi_maps.getctype(vars[n])
elsize = capi_maps.get_elsize(vars[n])
at = capi_maps.c2capi_map[ct]
dm = capi_maps.getarrdims(n, vars[n])
if dm['dims']:
idims.append('(%s)' % (dm['dims']))
else:
idims.append('')
dms = dm['dims'].strip()
if not dms:
dms = '-1'
cadd('\t{\"%s\",%s,{{%s}},%s, %s},'
% (n, dm['rank'], dms, at, elsize))
cadd('\t{NULL}\n};')
inames1 = rmbadname(inames)
inames1_tps = ','.join(['char *' + s for s in inames1])
cadd('static void f2py_setup_%s(%s) {' % (name, inames1_tps))
cadd('\tint i_f2py=0;')
for n in inames1:
cadd('\tf2py_%s_def[i_f2py++].data = %s;' % (name, n))
cadd('}')
if '_' in lower_name:
F_FUNC = 'F_FUNC_US'
else:
F_FUNC = 'F_FUNC'
cadd('extern void %s(f2pyinit%s,F2PYINIT%s)(void(*)(%s));'
% (F_FUNC, lower_name, name.upper(),
','.join(['char*'] * len(inames1))))
cadd('static void f2py_init_%s(void) {' % name)
cadd('\t%s(f2pyinit%s,F2PYINIT%s)(f2py_setup_%s);'
% (F_FUNC, lower_name, name.upper(), name))
cadd('}\n')
iadd('\ttmp = PyFortranObject_New(f2py_%s_def,f2py_init_%s);' % (name, name))
iadd('\tif (tmp == NULL) return NULL;')
iadd('\tif (F2PyDict_SetItemString(d, \"%s\", tmp) == -1) return NULL;'
% name)
iadd('\tPy_DECREF(tmp);')
tname = name.replace('_', '\\_')
dadd('\\subsection{Common block \\texttt{%s}}\n' % (tname))
dadd('\\begin{description}')
for n in inames:
dadd('\\item[]{{}\\verb@%s@{}}' %
(capi_maps.getarrdocsign(n, vars[n])))
if hasnote(vars[n]):
note = vars[n]['note']
if isinstance(note, list):
note = '\n'.join(note)
dadd('--- %s' % (note))
dadd('\\end{description}')
ret['docs'].append(
'"\t/%s/ %s\\n"' % (name, ','.join(map(lambda v, d: v + d, inames, idims))))
ret['commonhooks'] = chooks
ret['initcommonhooks'] = ihooks
ret['latexdoc'] = doc[0]
if len(ret['docs']) <= 1:
ret['docs'] = ''
return ret, fwrap[0]

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,154 @@
#!/usr/bin/env python3
import os
import sys
import tempfile
def run_command(cmd):
print('Running %r:' % (cmd))
os.system(cmd)
print('------')
def run():
_path = os.getcwd()
os.chdir(tempfile.gettempdir())
print('------')
print('os.name=%r' % (os.name))
print('------')
print('sys.platform=%r' % (sys.platform))
print('------')
print('sys.version:')
print(sys.version)
print('------')
print('sys.prefix:')
print(sys.prefix)
print('------')
print('sys.path=%r' % (':'.join(sys.path)))
print('------')
try:
import numpy
has_newnumpy = 1
except ImportError as e:
print('Failed to import new numpy:', e)
has_newnumpy = 0
try:
from numpy.f2py import f2py2e
has_f2py2e = 1
except ImportError as e:
print('Failed to import f2py2e:', e)
has_f2py2e = 0
try:
import numpy.distutils
has_numpy_distutils = 2
except ImportError:
try:
import numpy_distutils
has_numpy_distutils = 1
except ImportError as e:
print('Failed to import numpy_distutils:', e)
has_numpy_distutils = 0
if has_newnumpy:
try:
print('Found new numpy version %r in %s' %
(numpy.__version__, numpy.__file__))
except Exception as msg:
print('error:', msg)
print('------')
if has_f2py2e:
try:
print('Found f2py2e version %r in %s' %
(f2py2e.__version__.version, f2py2e.__file__))
except Exception as msg:
print('error:', msg)
print('------')
if has_numpy_distutils:
try:
if has_numpy_distutils == 2:
print('Found numpy.distutils version %r in %r' % (
numpy.distutils.__version__,
numpy.distutils.__file__))
else:
print('Found numpy_distutils version %r in %r' % (
numpy_distutils.numpy_distutils_version.numpy_distutils_version,
numpy_distutils.__file__))
print('------')
except Exception as msg:
print('error:', msg)
print('------')
try:
if has_numpy_distutils == 1:
print(
'Importing numpy_distutils.command.build_flib ...', end=' ')
import numpy_distutils.command.build_flib as build_flib
print('ok')
print('------')
try:
print(
'Checking availability of supported Fortran compilers:')
for compiler_class in build_flib.all_compilers:
compiler_class(verbose=1).is_available()
print('------')
except Exception as msg:
print('error:', msg)
print('------')
except Exception as msg:
print(
'error:', msg, '(ignore it, build_flib is obsolute for numpy.distutils 0.2.2 and up)')
print('------')
try:
if has_numpy_distutils == 2:
print('Importing numpy.distutils.fcompiler ...', end=' ')
import numpy.distutils.fcompiler as fcompiler
else:
print('Importing numpy_distutils.fcompiler ...', end=' ')
import numpy_distutils.fcompiler as fcompiler
print('ok')
print('------')
try:
print('Checking availability of supported Fortran compilers:')
fcompiler.show_fcompilers()
print('------')
except Exception as msg:
print('error:', msg)
print('------')
except Exception as msg:
print('error:', msg)
print('------')
try:
if has_numpy_distutils == 2:
print('Importing numpy.distutils.cpuinfo ...', end=' ')
from numpy.distutils.cpuinfo import cpuinfo
print('ok')
print('------')
else:
try:
print(
'Importing numpy_distutils.command.cpuinfo ...', end=' ')
from numpy_distutils.command.cpuinfo import cpuinfo
print('ok')
print('------')
except Exception as msg:
print('error:', msg, '(ignore it)')
print('Importing numpy_distutils.cpuinfo ...', end=' ')
from numpy_distutils.cpuinfo import cpuinfo
print('ok')
print('------')
cpu = cpuinfo()
print('CPU information:', end=' ')
for name in dir(cpuinfo):
if name[0] == '_' and name[1] != '_' and getattr(cpu, name[1:])():
print(name[1:], end=' ')
print('------')
except Exception as msg:
print('error:', msg)
print('------')
os.chdir(_path)
if __name__ == "__main__":
run()

View File

@ -0,0 +1,787 @@
#!/usr/bin/env python3
"""
f2py2e - Fortran to Python C/API generator. 2nd Edition.
See __usage__ below.
Copyright 1999 -- 2011 Pearu Peterson all rights reserved.
Copyright 2011 -- present NumPy Developers.
Permission to use, modify, and distribute this software is given under the
terms of the NumPy License.
NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
"""
import sys
import os
import pprint
import re
from pathlib import Path
from itertools import dropwhile
import argparse
import copy
from . import crackfortran
from . import rules
from . import cb_rules
from . import auxfuncs
from . import cfuncs
from . import f90mod_rules
from . import __version__
from . import capi_maps
from .cfuncs import errmess
from numpy.f2py._backends import f2py_build_generator
f2py_version = __version__.version
numpy_version = __version__.version
# outmess=sys.stdout.write
show = pprint.pprint
outmess = auxfuncs.outmess
MESON_ONLY_VER = (sys.version_info >= (3, 12))
__usage__ =\
f"""Usage:
1) To construct extension module sources:
f2py [<options>] <fortran files> [[[only:]||[skip:]] \\
<fortran functions> ] \\
[: <fortran files> ...]
2) To compile fortran files and build extension modules:
f2py -c [<options>, <build_flib options>, <extra options>] <fortran files>
3) To generate signature files:
f2py -h <filename.pyf> ...< same options as in (1) >
Description: This program generates a Python C/API file (<modulename>module.c)
that contains wrappers for given fortran functions so that they
can be called from Python. With the -c option the corresponding
extension modules are built.
Options:
-h <filename> Write signatures of the fortran routines to file <filename>
and exit. You can then edit <filename> and use it instead
of <fortran files>. If <filename>==stdout then the
signatures are printed to stdout.
<fortran functions> Names of fortran routines for which Python C/API
functions will be generated. Default is all that are found
in <fortran files>.
<fortran files> Paths to fortran/signature files that will be scanned for
<fortran functions> in order to determine their signatures.
skip: Ignore fortran functions that follow until `:'.
only: Use only fortran functions that follow until `:'.
: Get back to <fortran files> mode.
-m <modulename> Name of the module; f2py generates a Python/C API
file <modulename>module.c or extension module <modulename>.
Default is 'untitled'.
'-include<header>' Writes additional headers in the C wrapper, can be passed
multiple times, generates #include <header> each time.
--[no-]lower Do [not] lower the cases in <fortran files>. By default,
--lower is assumed with -h key, and --no-lower without -h key.
--build-dir <dirname> All f2py generated files are created in <dirname>.
Default is tempfile.mkdtemp().
--overwrite-signature Overwrite existing signature file.
--[no-]latex-doc Create (or not) <modulename>module.tex.
Default is --no-latex-doc.
--short-latex Create 'incomplete' LaTeX document (without commands
\\documentclass, \\tableofcontents, and \\begin{{document}},
\\end{{document}}).
--[no-]rest-doc Create (or not) <modulename>module.rst.
Default is --no-rest-doc.
--debug-capi Create C/API code that reports the state of the wrappers
during runtime. Useful for debugging.
--[no-]wrap-functions Create Fortran subroutine wrappers to Fortran 77
functions. --wrap-functions is default because it ensures
maximum portability/compiler independence.
--[no-]freethreading-compatible Create a module that declares it does or
doesn't require the GIL. The default is
--freethreading-compatible for backward
compatibility. Inspect the Fortran code you are wrapping for
thread safety issues before passing
--no-freethreading-compatible, as f2py does not analyze
fortran code for thread safety issues.
--include-paths <path1>:<path2>:... Search include files from the given
directories.
--help-link [..] List system resources found by system_info.py. See also
--link-<resource> switch below. [..] is optional list
of resources names. E.g. try 'f2py --help-link lapack_opt'.
--f2cmap <filename> Load Fortran-to-Python KIND specification from the given
file. Default: .f2py_f2cmap in current directory.
--quiet Run quietly.
--verbose Run with extra verbosity.
--skip-empty-wrappers Only generate wrapper files when needed.
-v Print f2py version ID and exit.
build backend options (only effective with -c)
[NO_MESON] is used to indicate an option not meant to be used
with the meson backend or above Python 3.12:
--fcompiler= Specify Fortran compiler type by vendor [NO_MESON]
--compiler= Specify distutils C compiler type [NO_MESON]
--help-fcompiler List available Fortran compilers and exit [NO_MESON]
--f77exec= Specify the path to F77 compiler [NO_MESON]
--f90exec= Specify the path to F90 compiler [NO_MESON]
--f77flags= Specify F77 compiler flags
--f90flags= Specify F90 compiler flags
--opt= Specify optimization flags [NO_MESON]
--arch= Specify architecture specific optimization flags [NO_MESON]
--noopt Compile without optimization [NO_MESON]
--noarch Compile without arch-dependent optimization [NO_MESON]
--debug Compile with debugging information
--dep <dependency>
Specify a meson dependency for the module. This may
be passed multiple times for multiple dependencies.
Dependencies are stored in a list for further processing.
Example: --dep lapack --dep scalapack
This will identify "lapack" and "scalapack" as dependencies
and remove them from argv, leaving a dependencies list
containing ["lapack", "scalapack"].
--backend <backend_type>
Specify the build backend for the compilation process.
The supported backends are 'meson' and 'distutils'.
If not specified, defaults to 'distutils'. On
Python 3.12 or higher, the default is 'meson'.
Extra options (only effective with -c):
--link-<resource> Link extension module with <resource> as defined
by numpy.distutils/system_info.py. E.g. to link
with optimized LAPACK libraries (vecLib on MacOSX,
ATLAS elsewhere), use --link-lapack_opt.
See also --help-link switch. [NO_MESON]
-L/path/to/lib/ -l<libname>
-D<define> -U<name>
-I/path/to/include/
<filename>.o <filename>.so <filename>.a
Using the following macros may be required with non-gcc Fortran
compilers:
-DPREPEND_FORTRAN -DNO_APPEND_FORTRAN -DUPPERCASE_FORTRAN
When using -DF2PY_REPORT_ATEXIT, a performance report of F2PY
interface is printed out at exit (platforms: Linux).
When using -DF2PY_REPORT_ON_ARRAY_COPY=<int>, a message is
sent to stderr whenever F2PY interface makes a copy of an
array. Integer <int> sets the threshold for array sizes when
a message should be shown.
Version: {f2py_version}
numpy Version: {numpy_version}
License: NumPy license (see LICENSE.txt in the NumPy source code)
Copyright 1999 -- 2011 Pearu Peterson all rights reserved.
Copyright 2011 -- present NumPy Developers.
https://numpy.org/doc/stable/f2py/index.html\n"""
def scaninputline(inputline):
files, skipfuncs, onlyfuncs, debug = [], [], [], []
f, f2, f3, f5, f6, f8, f9, f10 = 1, 0, 0, 0, 0, 0, 0, 0
verbose = 1
emptygen = True
dolc = -1
dolatexdoc = 0
dorestdoc = 0
wrapfuncs = 1
buildpath = '.'
include_paths, freethreading_compatible, inputline = get_newer_options(inputline)
signsfile, modulename = None, None
options = {'buildpath': buildpath,
'coutput': None,
'f2py_wrapper_output': None}
for l in inputline:
if l == '':
pass
elif l == 'only:':
f = 0
elif l == 'skip:':
f = -1
elif l == ':':
f = 1
elif l[:8] == '--debug-':
debug.append(l[8:])
elif l == '--lower':
dolc = 1
elif l == '--build-dir':
f6 = 1
elif l == '--no-lower':
dolc = 0
elif l == '--quiet':
verbose = 0
elif l == '--verbose':
verbose += 1
elif l == '--latex-doc':
dolatexdoc = 1
elif l == '--no-latex-doc':
dolatexdoc = 0
elif l == '--rest-doc':
dorestdoc = 1
elif l == '--no-rest-doc':
dorestdoc = 0
elif l == '--wrap-functions':
wrapfuncs = 1
elif l == '--no-wrap-functions':
wrapfuncs = 0
elif l == '--short-latex':
options['shortlatex'] = 1
elif l == '--coutput':
f8 = 1
elif l == '--f2py-wrapper-output':
f9 = 1
elif l == '--f2cmap':
f10 = 1
elif l == '--overwrite-signature':
options['h-overwrite'] = 1
elif l == '-h':
f2 = 1
elif l == '-m':
f3 = 1
elif l[:2] == '-v':
print(f2py_version)
sys.exit()
elif l == '--show-compilers':
f5 = 1
elif l[:8] == '-include':
cfuncs.outneeds['userincludes'].append(l[9:-1])
cfuncs.userincludes[l[9:-1]] = '#include ' + l[8:]
elif l == '--skip-empty-wrappers':
emptygen = False
elif l[0] == '-':
errmess('Unknown option %s\n' % repr(l))
sys.exit()
elif f2:
f2 = 0
signsfile = l
elif f3:
f3 = 0
modulename = l
elif f6:
f6 = 0
buildpath = l
elif f8:
f8 = 0
options["coutput"] = l
elif f9:
f9 = 0
options["f2py_wrapper_output"] = l
elif f10:
f10 = 0
options["f2cmap_file"] = l
elif f == 1:
try:
with open(l):
pass
files.append(l)
except OSError as detail:
errmess(f'OSError: {detail!s}. Skipping file "{l!s}".\n')
elif f == -1:
skipfuncs.append(l)
elif f == 0:
onlyfuncs.append(l)
if not f5 and not files and not modulename:
print(__usage__)
sys.exit()
if not os.path.isdir(buildpath):
if not verbose:
outmess('Creating build directory %s\n' % (buildpath))
os.mkdir(buildpath)
if signsfile:
signsfile = os.path.join(buildpath, signsfile)
if signsfile and os.path.isfile(signsfile) and 'h-overwrite' not in options:
errmess(
'Signature file "%s" exists!!! Use --overwrite-signature to overwrite.\n' % (signsfile))
sys.exit()
options['emptygen'] = emptygen
options['debug'] = debug
options['verbose'] = verbose
if dolc == -1 and not signsfile:
options['do-lower'] = 0
else:
options['do-lower'] = dolc
if modulename:
options['module'] = modulename
if signsfile:
options['signsfile'] = signsfile
if onlyfuncs:
options['onlyfuncs'] = onlyfuncs
if skipfuncs:
options['skipfuncs'] = skipfuncs
options['dolatexdoc'] = dolatexdoc
options['dorestdoc'] = dorestdoc
options['wrapfuncs'] = wrapfuncs
options['buildpath'] = buildpath
options['include_paths'] = include_paths
options['requires_gil'] = not freethreading_compatible
options.setdefault('f2cmap_file', None)
return files, options
def callcrackfortran(files, options):
rules.options = options
crackfortran.debug = options['debug']
crackfortran.verbose = options['verbose']
if 'module' in options:
crackfortran.f77modulename = options['module']
if 'skipfuncs' in options:
crackfortran.skipfuncs = options['skipfuncs']
if 'onlyfuncs' in options:
crackfortran.onlyfuncs = options['onlyfuncs']
crackfortran.include_paths[:] = options['include_paths']
crackfortran.dolowercase = options['do-lower']
postlist = crackfortran.crackfortran(files)
if 'signsfile' in options:
outmess('Saving signatures to file "%s"\n' % (options['signsfile']))
pyf = crackfortran.crack2fortran(postlist)
if options['signsfile'][-6:] == 'stdout':
sys.stdout.write(pyf)
else:
with open(options['signsfile'], 'w') as f:
f.write(pyf)
if options["coutput"] is None:
for mod in postlist:
mod["coutput"] = "%smodule.c" % mod["name"]
else:
for mod in postlist:
mod["coutput"] = options["coutput"]
if options["f2py_wrapper_output"] is None:
for mod in postlist:
mod["f2py_wrapper_output"] = "%s-f2pywrappers.f" % mod["name"]
else:
for mod in postlist:
mod["f2py_wrapper_output"] = options["f2py_wrapper_output"]
for mod in postlist:
if options["requires_gil"]:
mod['gil_used'] = 'Py_MOD_GIL_USED'
else:
mod['gil_used'] = 'Py_MOD_GIL_NOT_USED'
return postlist
def buildmodules(lst):
cfuncs.buildcfuncs()
outmess('Building modules...\n')
modules, mnames, isusedby = [], [], {}
for item in lst:
if '__user__' in item['name']:
cb_rules.buildcallbacks(item)
else:
if 'use' in item:
for u in item['use'].keys():
if u not in isusedby:
isusedby[u] = []
isusedby[u].append(item['name'])
modules.append(item)
mnames.append(item['name'])
ret = {}
for module, name in zip(modules, mnames):
if name in isusedby:
outmess('\tSkipping module "%s" which is used by %s.\n' % (
name, ','.join('"%s"' % s for s in isusedby[name])))
else:
um = []
if 'use' in module:
for u in module['use'].keys():
if u in isusedby and u in mnames:
um.append(modules[mnames.index(u)])
else:
outmess(
f'\tModule "{name}" uses nonexisting "{u}" '
'which will be ignored.\n')
ret[name] = {}
dict_append(ret[name], rules.buildmodule(module, um))
return ret
def dict_append(d_out, d_in):
for (k, v) in d_in.items():
if k not in d_out:
d_out[k] = []
if isinstance(v, list):
d_out[k] = d_out[k] + v
else:
d_out[k].append(v)
def run_main(comline_list):
"""
Equivalent to running::
f2py <args>
where ``<args>=string.join(<list>,' ')``, but in Python. Unless
``-h`` is used, this function returns a dictionary containing
information on generated modules and their dependencies on source
files.
You cannot build extension modules with this function, that is,
using ``-c`` is not allowed. Use the ``compile`` command instead.
Examples
--------
The command ``f2py -m scalar scalar.f`` can be executed from Python as
follows.
.. literalinclude:: ../../source/f2py/code/results/run_main_session.dat
:language: python
"""
crackfortran.reset_global_f2py_vars()
f2pydir = os.path.dirname(os.path.abspath(cfuncs.__file__))
fobjhsrc = os.path.join(f2pydir, 'src', 'fortranobject.h')
fobjcsrc = os.path.join(f2pydir, 'src', 'fortranobject.c')
# gh-22819 -- begin
parser = make_f2py_compile_parser()
args, comline_list = parser.parse_known_args(comline_list)
pyf_files, _ = filter_files("", "[.]pyf([.]src|)", comline_list)
# Checks that no existing modulename is defined in a pyf file
# TODO: Remove all this when scaninputline is replaced
if args.module_name:
if "-h" in comline_list:
modname = (
args.module_name
) # Directly use from args when -h is present
else:
modname = validate_modulename(
pyf_files, args.module_name
) # Validate modname when -h is not present
comline_list += ['-m', modname] # needed for the rest of scaninputline
# gh-22819 -- end
files, options = scaninputline(comline_list)
auxfuncs.options = options
capi_maps.load_f2cmap_file(options['f2cmap_file'])
postlist = callcrackfortran(files, options)
isusedby = {}
for plist in postlist:
if 'use' in plist:
for u in plist['use'].keys():
if u not in isusedby:
isusedby[u] = []
isusedby[u].append(plist['name'])
for plist in postlist:
if plist['block'] == 'python module' and '__user__' in plist['name']:
if plist['name'] in isusedby:
# if not quiet:
outmess(
f'Skipping Makefile build for module "{plist["name"]}" '
'which is used by {}\n'.format(
','.join(f'"{s}"' for s in isusedby[plist['name']])))
if 'signsfile' in options:
if options['verbose'] > 1:
outmess(
'Stopping. Edit the signature file and then run f2py on the signature file: ')
outmess('%s %s\n' %
(os.path.basename(sys.argv[0]), options['signsfile']))
return
for plist in postlist:
if plist['block'] != 'python module':
if 'python module' not in options:
errmess(
'Tip: If your original code is Fortran source then you must use -m option.\n')
raise TypeError('All blocks must be python module blocks but got %s' % (
repr(plist['block'])))
auxfuncs.debugoptions = options['debug']
f90mod_rules.options = options
auxfuncs.wrapfuncs = options['wrapfuncs']
ret = buildmodules(postlist)
for mn in ret.keys():
dict_append(ret[mn], {'csrc': fobjcsrc, 'h': fobjhsrc})
return ret
def filter_files(prefix, suffix, files, remove_prefix=None):
"""
Filter files by prefix and suffix.
"""
filtered, rest = [], []
match = re.compile(prefix + r'.*' + suffix + r'\Z').match
if remove_prefix:
ind = len(prefix)
else:
ind = 0
for file in [x.strip() for x in files]:
if match(file):
filtered.append(file[ind:])
else:
rest.append(file)
return filtered, rest
def get_prefix(module):
p = os.path.dirname(os.path.dirname(module.__file__))
return p
class CombineIncludePaths(argparse.Action):
def __call__(self, parser, namespace, values, option_string=None):
include_paths_set = set(getattr(namespace, 'include_paths', []) or [])
if option_string == "--include_paths":
outmess("Use --include-paths or -I instead of --include_paths which will be removed")
if option_string == "--include-paths" or option_string == "--include_paths":
include_paths_set.update(values.split(':'))
else:
include_paths_set.add(values)
setattr(namespace, 'include_paths', list(include_paths_set))
def f2py_parser():
parser = argparse.ArgumentParser(add_help=False)
parser.add_argument("-I", dest="include_paths", action=CombineIncludePaths)
parser.add_argument("--include-paths", dest="include_paths", action=CombineIncludePaths)
parser.add_argument("--include_paths", dest="include_paths", action=CombineIncludePaths)
parser.add_argument("--freethreading-compatible", dest="ftcompat", action=argparse.BooleanOptionalAction)
return parser
def get_newer_options(iline):
iline = (' '.join(iline)).split()
parser = f2py_parser()
args, remain = parser.parse_known_args(iline)
ipaths = args.include_paths
if args.include_paths is None:
ipaths = []
return ipaths, args.ftcompat, remain
def make_f2py_compile_parser():
parser = argparse.ArgumentParser(add_help=False)
parser.add_argument("--dep", action="append", dest="dependencies")
parser.add_argument("--backend", choices=['meson', 'distutils'], default='distutils')
parser.add_argument("-m", dest="module_name")
return parser
def preparse_sysargv():
# To keep backwards bug compatibility, newer flags are handled by argparse,
# and `sys.argv` is passed to the rest of `f2py` as is.
parser = make_f2py_compile_parser()
args, remaining_argv = parser.parse_known_args()
sys.argv = [sys.argv[0]] + remaining_argv
backend_key = args.backend
if MESON_ONLY_VER and backend_key == 'distutils':
outmess("Cannot use distutils backend with Python>=3.12,"
" using meson backend instead.\n")
backend_key = "meson"
return {
"dependencies": args.dependencies or [],
"backend": backend_key,
"modulename": args.module_name,
}
def run_compile():
"""
Do it all in one call!
"""
import tempfile
# Collect dependency flags, preprocess sys.argv
argy = preparse_sysargv()
modulename = argy["modulename"]
if modulename is None:
modulename = 'untitled'
dependencies = argy["dependencies"]
backend_key = argy["backend"]
build_backend = f2py_build_generator(backend_key)
i = sys.argv.index('-c')
del sys.argv[i]
remove_build_dir = 0
try:
i = sys.argv.index('--build-dir')
except ValueError:
i = None
if i is not None:
build_dir = sys.argv[i + 1]
del sys.argv[i + 1]
del sys.argv[i]
else:
remove_build_dir = 1
build_dir = tempfile.mkdtemp()
_reg1 = re.compile(r'--link-')
sysinfo_flags = [_m for _m in sys.argv[1:] if _reg1.match(_m)]
sys.argv = [_m for _m in sys.argv if _m not in sysinfo_flags]
if sysinfo_flags:
sysinfo_flags = [f[7:] for f in sysinfo_flags]
_reg2 = re.compile(
r'--((no-|)(wrap-functions|lower|freethreading-compatible)|debug-capi|quiet|skip-empty-wrappers)|-include')
f2py_flags = [_m for _m in sys.argv[1:] if _reg2.match(_m)]
sys.argv = [_m for _m in sys.argv if _m not in f2py_flags]
f2py_flags2 = []
fl = 0
for a in sys.argv[1:]:
if a in ['only:', 'skip:']:
fl = 1
elif a == ':':
fl = 0
if fl or a == ':':
f2py_flags2.append(a)
if f2py_flags2 and f2py_flags2[-1] != ':':
f2py_flags2.append(':')
f2py_flags.extend(f2py_flags2)
sys.argv = [_m for _m in sys.argv if _m not in f2py_flags2]
_reg3 = re.compile(
r'--((f(90)?compiler(-exec|)|compiler)=|help-compiler)')
flib_flags = [_m for _m in sys.argv[1:] if _reg3.match(_m)]
sys.argv = [_m for _m in sys.argv if _m not in flib_flags]
# TODO: Once distutils is dropped completely, i.e. min_ver >= 3.12, unify into --fflags
reg_f77_f90_flags = re.compile(r'--f(77|90)flags=')
reg_distutils_flags = re.compile(r'--((f(77|90)exec|opt|arch)=|(debug|noopt|noarch|help-fcompiler))')
fc_flags = [_m for _m in sys.argv[1:] if reg_f77_f90_flags.match(_m)]
distutils_flags = [_m for _m in sys.argv[1:] if reg_distutils_flags.match(_m)]
if not (MESON_ONLY_VER or backend_key == 'meson'):
fc_flags.extend(distutils_flags)
sys.argv = [_m for _m in sys.argv if _m not in (fc_flags + distutils_flags)]
del_list = []
for s in flib_flags:
v = '--fcompiler='
if s[:len(v)] == v:
if MESON_ONLY_VER or backend_key == 'meson':
outmess(
"--fcompiler cannot be used with meson,"
"set compiler with the FC environment variable\n"
)
else:
from numpy.distutils import fcompiler
fcompiler.load_all_fcompiler_classes()
allowed_keys = list(fcompiler.fcompiler_class.keys())
nv = ov = s[len(v):].lower()
if ov not in allowed_keys:
vmap = {} # XXX
try:
nv = vmap[ov]
except KeyError:
if ov not in vmap.values():
print('Unknown vendor: "%s"' % (s[len(v):]))
nv = ov
i = flib_flags.index(s)
flib_flags[i] = '--fcompiler=' + nv
continue
for s in del_list:
i = flib_flags.index(s)
del flib_flags[i]
assert len(flib_flags) <= 2, repr(flib_flags)
_reg5 = re.compile(r'--(verbose)')
setup_flags = [_m for _m in sys.argv[1:] if _reg5.match(_m)]
sys.argv = [_m for _m in sys.argv if _m not in setup_flags]
if '--quiet' in f2py_flags:
setup_flags.append('--quiet')
# Ugly filter to remove everything but sources
sources = sys.argv[1:]
f2cmapopt = '--f2cmap'
if f2cmapopt in sys.argv:
i = sys.argv.index(f2cmapopt)
f2py_flags.extend(sys.argv[i:i + 2])
del sys.argv[i + 1], sys.argv[i]
sources = sys.argv[1:]
pyf_files, _sources = filter_files("", "[.]pyf([.]src|)", sources)
sources = pyf_files + _sources
modulename = validate_modulename(pyf_files, modulename)
extra_objects, sources = filter_files('', '[.](o|a|so|dylib)', sources)
library_dirs, sources = filter_files('-L', '', sources, remove_prefix=1)
libraries, sources = filter_files('-l', '', sources, remove_prefix=1)
undef_macros, sources = filter_files('-U', '', sources, remove_prefix=1)
define_macros, sources = filter_files('-D', '', sources, remove_prefix=1)
for i in range(len(define_macros)):
name_value = define_macros[i].split('=', 1)
if len(name_value) == 1:
name_value.append(None)
if len(name_value) == 2:
define_macros[i] = tuple(name_value)
else:
print('Invalid use of -D:', name_value)
# Construct wrappers / signatures / things
if backend_key == 'meson':
if not pyf_files:
outmess('Using meson backend\nWill pass --lower to f2py\nSee https://numpy.org/doc/stable/f2py/buildtools/meson.html\n')
f2py_flags.append('--lower')
run_main(f" {' '.join(f2py_flags)} -m {modulename} {' '.join(sources)}".split())
else:
run_main(f" {' '.join(f2py_flags)} {' '.join(pyf_files)}".split())
# Order matters here, includes are needed for run_main above
include_dirs, _, sources = get_newer_options(sources)
# Now use the builder
builder = build_backend(
modulename,
sources,
extra_objects,
build_dir,
include_dirs,
library_dirs,
libraries,
define_macros,
undef_macros,
f2py_flags,
sysinfo_flags,
fc_flags,
flib_flags,
setup_flags,
remove_build_dir,
{"dependencies": dependencies},
)
builder.compile()
def validate_modulename(pyf_files, modulename='untitled'):
if len(pyf_files) > 1:
raise ValueError("Only one .pyf file per call")
if pyf_files:
pyff = pyf_files[0]
pyf_modname = auxfuncs.get_f2py_modulename(pyff)
if modulename != pyf_modname:
outmess(
f"Ignoring -m {modulename}.\n"
f"{pyff} defines {pyf_modname} to be the modulename.\n"
)
modulename = pyf_modname
return modulename
def main():
if '--help-link' in sys.argv[1:]:
sys.argv.remove('--help-link')
if MESON_ONLY_VER:
outmess("Use --dep for meson builds\n")
else:
from numpy.distutils.system_info import show_all
show_all()
return
if '-c' in sys.argv[1:]:
run_compile()
else:
run_main(sys.argv[1:])

View File

@ -0,0 +1,272 @@
"""
Build F90 module support for f2py2e.
Copyright 1999 -- 2011 Pearu Peterson all rights reserved.
Copyright 2011 -- present NumPy Developers.
Permission to use, modify, and distribute this software is given under the
terms of the NumPy License.
NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
"""
__version__ = "$Revision: 1.27 $"[10:-1]
f2py_version = 'See `f2py -v`'
import numpy as np
from . import capi_maps
from . import func2subr
from .crackfortran import undo_rmbadname, undo_rmbadname1
# The environment provided by auxfuncs.py is needed for some calls to eval.
# As the needed functions cannot be determined by static inspection of the
# code, it is safest to use import * pending a major refactoring of f2py.
from .auxfuncs import *
options = {}
def findf90modules(m):
if ismodule(m):
return [m]
if not hasbody(m):
return []
ret = []
for b in m['body']:
if ismodule(b):
ret.append(b)
else:
ret = ret + findf90modules(b)
return ret
fgetdims1 = """\
external f2pysetdata
logical ns
integer r,i
integer(%d) s(*)
ns = .FALSE.
if (allocated(d)) then
do i=1,r
if ((size(d,i).ne.s(i)).and.(s(i).ge.0)) then
ns = .TRUE.
end if
end do
if (ns) then
deallocate(d)
end if
end if
if ((.not.allocated(d)).and.(s(1).ge.1)) then""" % np.intp().itemsize
fgetdims2 = """\
end if
if (allocated(d)) then
do i=1,r
s(i) = size(d,i)
end do
end if
flag = 1
call f2pysetdata(d,allocated(d))"""
fgetdims2_sa = """\
end if
if (allocated(d)) then
do i=1,r
s(i) = size(d,i)
end do
!s(r) must be equal to len(d(1))
end if
flag = 2
call f2pysetdata(d,allocated(d))"""
def buildhooks(pymod):
from . import rules
ret = {'f90modhooks': [], 'initf90modhooks': [], 'body': [],
'need': ['F_FUNC', 'arrayobject.h'],
'separatorsfor': {'includes0': '\n', 'includes': '\n'},
'docs': ['"Fortran 90/95 modules:\\n"'],
'latexdoc': []}
fhooks = ['']
def fadd(line, s=fhooks):
s[0] = '%s\n %s' % (s[0], line)
doc = ['']
def dadd(line, s=doc):
s[0] = '%s\n%s' % (s[0], line)
usenames = getuseblocks(pymod)
for m in findf90modules(pymod):
contains_functions_or_subroutines = any(
item for item in m["body"] if item["block"] in ["function", "subroutine"]
)
sargs, fargs, efargs, modobjs, notvars, onlyvars = [], [], [], [], [
m['name']], []
sargsp = []
ifargs = []
mfargs = []
if hasbody(m):
for b in m['body']:
notvars.append(b['name'])
for n in m['vars'].keys():
var = m['vars'][n]
if (n not in notvars and isvariable(var)) and (not l_or(isintent_hide, isprivate)(var)):
onlyvars.append(n)
mfargs.append(n)
outmess('\t\tConstructing F90 module support for "%s"...\n' %
(m['name']))
if len(onlyvars) == 0 and len(notvars) == 1 and m['name'] in notvars:
outmess(f"\t\t\tSkipping {m['name']} since there are no public vars/func in this module...\n")
continue
if m['name'] in usenames and not contains_functions_or_subroutines:
outmess(f"\t\t\tSkipping {m['name']} since it is in 'use'...\n")
continue
if onlyvars:
outmess('\t\t Variables: %s\n' % (' '.join(onlyvars)))
chooks = ['']
def cadd(line, s=chooks):
s[0] = '%s\n%s' % (s[0], line)
ihooks = ['']
def iadd(line, s=ihooks):
s[0] = '%s\n%s' % (s[0], line)
vrd = capi_maps.modsign2map(m)
cadd('static FortranDataDef f2py_%s_def[] = {' % (m['name']))
dadd('\\subsection{Fortran 90/95 module \\texttt{%s}}\n' % (m['name']))
if hasnote(m):
note = m['note']
if isinstance(note, list):
note = '\n'.join(note)
dadd(note)
if onlyvars:
dadd('\\begin{description}')
for n in onlyvars:
var = m['vars'][n]
modobjs.append(n)
ct = capi_maps.getctype(var)
at = capi_maps.c2capi_map[ct]
dm = capi_maps.getarrdims(n, var)
dms = dm['dims'].replace('*', '-1').strip()
dms = dms.replace(':', '-1').strip()
if not dms:
dms = '-1'
use_fgetdims2 = fgetdims2
cadd('\t{"%s",%s,{{%s}},%s, %s},' %
(undo_rmbadname1(n), dm['rank'], dms, at,
capi_maps.get_elsize(var)))
dadd('\\item[]{{}\\verb@%s@{}}' %
(capi_maps.getarrdocsign(n, var)))
if hasnote(var):
note = var['note']
if isinstance(note, list):
note = '\n'.join(note)
dadd('--- %s' % (note))
if isallocatable(var):
fargs.append('f2py_%s_getdims_%s' % (m['name'], n))
efargs.append(fargs[-1])
sargs.append(
'void (*%s)(int*,npy_intp*,void(*)(char*,npy_intp*),int*)' % (n))
sargsp.append('void (*)(int*,npy_intp*,void(*)(char*,npy_intp*),int*)')
iadd('\tf2py_%s_def[i_f2py++].func = %s;' % (m['name'], n))
fadd('subroutine %s(r,s,f2pysetdata,flag)' % (fargs[-1]))
fadd('use %s, only: d => %s\n' %
(m['name'], undo_rmbadname1(n)))
fadd('integer flag\n')
fhooks[0] = fhooks[0] + fgetdims1
dms = range(1, int(dm['rank']) + 1)
fadd(' allocate(d(%s))\n' %
(','.join(['s(%s)' % i for i in dms])))
fhooks[0] = fhooks[0] + use_fgetdims2
fadd('end subroutine %s' % (fargs[-1]))
else:
fargs.append(n)
sargs.append('char *%s' % (n))
sargsp.append('char*')
iadd('\tf2py_%s_def[i_f2py++].data = %s;' % (m['name'], n))
if onlyvars:
dadd('\\end{description}')
if hasbody(m):
for b in m['body']:
if not isroutine(b):
outmess("f90mod_rules.buildhooks:"
f" skipping {b['block']} {b['name']}\n")
continue
modobjs.append('%s()' % (b['name']))
b['modulename'] = m['name']
api, wrap = rules.buildapi(b)
if isfunction(b):
fhooks[0] = fhooks[0] + wrap
fargs.append('f2pywrap_%s_%s' % (m['name'], b['name']))
ifargs.append(func2subr.createfuncwrapper(b, signature=1))
else:
if wrap:
fhooks[0] = fhooks[0] + wrap
fargs.append('f2pywrap_%s_%s' % (m['name'], b['name']))
ifargs.append(
func2subr.createsubrwrapper(b, signature=1))
else:
fargs.append(b['name'])
mfargs.append(fargs[-1])
api['externroutines'] = []
ar = applyrules(api, vrd)
ar['docs'] = []
ar['docshort'] = []
ret = dictappend(ret, ar)
cadd(('\t{"%s",-1,{{-1}},0,0,NULL,(void *)'
'f2py_rout_#modulename#_%s_%s,'
'doc_f2py_rout_#modulename#_%s_%s},')
% (b['name'], m['name'], b['name'], m['name'], b['name']))
sargs.append('char *%s' % (b['name']))
sargsp.append('char *')
iadd('\tf2py_%s_def[i_f2py++].data = %s;' %
(m['name'], b['name']))
cadd('\t{NULL}\n};\n')
iadd('}')
ihooks[0] = 'static void f2py_setup_%s(%s) {\n\tint i_f2py=0;%s' % (
m['name'], ','.join(sargs), ihooks[0])
if '_' in m['name']:
F_FUNC = 'F_FUNC_US'
else:
F_FUNC = 'F_FUNC'
iadd('extern void %s(f2pyinit%s,F2PYINIT%s)(void (*)(%s));'
% (F_FUNC, m['name'], m['name'].upper(), ','.join(sargsp)))
iadd('static void f2py_init_%s(void) {' % (m['name']))
iadd('\t%s(f2pyinit%s,F2PYINIT%s)(f2py_setup_%s);'
% (F_FUNC, m['name'], m['name'].upper(), m['name']))
iadd('}\n')
ret['f90modhooks'] = ret['f90modhooks'] + chooks + ihooks
ret['initf90modhooks'] = ['\tPyDict_SetItemString(d, "%s", PyFortranObject_New(f2py_%s_def,f2py_init_%s));' % (
m['name'], m['name'], m['name'])] + ret['initf90modhooks']
fadd('')
fadd('subroutine f2pyinit%s(f2pysetupfunc)' % (m['name']))
if mfargs:
for a in undo_rmbadname(mfargs):
fadd('use %s, only : %s' % (m['name'], a))
if ifargs:
fadd(' '.join(['interface'] + ifargs))
fadd('end interface')
fadd('external f2pysetupfunc')
if efargs:
for a in undo_rmbadname(efargs):
fadd('external %s' % (a))
fadd('call f2pysetupfunc(%s)' % (','.join(undo_rmbadname(fargs))))
fadd('end subroutine f2pyinit%s\n' % (m['name']))
dadd('\n'.join(ret['latexdoc']).replace(
r'\subsection{', r'\subsubsection{'))
ret['latexdoc'] = []
ret['docs'].append('"\t%s --- %s"' % (m['name'],
','.join(undo_rmbadname(modobjs))))
ret['routine_defs'] = ''
ret['doc'] = []
ret['docshort'] = []
ret['latexdoc'] = doc[0]
if len(ret['docs']) <= 1:
ret['docs'] = ''
return ret, fhooks[0]

View File

@ -0,0 +1,323 @@
"""
Rules for building C/API module with f2py2e.
Copyright 1999 -- 2011 Pearu Peterson all rights reserved.
Copyright 2011 -- present NumPy Developers.
Permission to use, modify, and distribute this software is given under the
terms of the NumPy License.
NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
"""
import copy
from .auxfuncs import (
getfortranname, isexternal, isfunction, isfunction_wrap, isintent_in,
isintent_out, islogicalfunction, ismoduleroutine, isscalar,
issubroutine, issubroutine_wrap, outmess, show
)
from ._isocbind import isoc_kindmap
def var2fixfortran(vars, a, fa=None, f90mode=None):
if fa is None:
fa = a
if a not in vars:
show(vars)
outmess('var2fixfortran: No definition for argument "%s".\n' % a)
return ''
if 'typespec' not in vars[a]:
show(vars[a])
outmess('var2fixfortran: No typespec for argument "%s".\n' % a)
return ''
vardef = vars[a]['typespec']
if vardef == 'type' and 'typename' in vars[a]:
vardef = '%s(%s)' % (vardef, vars[a]['typename'])
selector = {}
lk = ''
if 'kindselector' in vars[a]:
selector = vars[a]['kindselector']
lk = 'kind'
elif 'charselector' in vars[a]:
selector = vars[a]['charselector']
lk = 'len'
if '*' in selector:
if f90mode:
if selector['*'] in ['*', ':', '(*)']:
vardef = '%s(len=*)' % (vardef)
else:
vardef = '%s(%s=%s)' % (vardef, lk, selector['*'])
else:
if selector['*'] in ['*', ':']:
vardef = '%s*(%s)' % (vardef, selector['*'])
else:
vardef = '%s*%s' % (vardef, selector['*'])
else:
if 'len' in selector:
vardef = '%s(len=%s' % (vardef, selector['len'])
if 'kind' in selector:
vardef = '%s,kind=%s)' % (vardef, selector['kind'])
else:
vardef = '%s)' % (vardef)
elif 'kind' in selector:
vardef = '%s(kind=%s)' % (vardef, selector['kind'])
vardef = '%s %s' % (vardef, fa)
if 'dimension' in vars[a]:
vardef = '%s(%s)' % (vardef, ','.join(vars[a]['dimension']))
return vardef
def useiso_c_binding(rout):
useisoc = False
for key, value in rout['vars'].items():
kind_value = value.get('kindselector', {}).get('kind')
if kind_value in isoc_kindmap:
return True
return useisoc
def createfuncwrapper(rout, signature=0):
assert isfunction(rout)
extra_args = []
vars = rout['vars']
for a in rout['args']:
v = rout['vars'][a]
for i, d in enumerate(v.get('dimension', [])):
if d == ':':
dn = 'f2py_%s_d%s' % (a, i)
dv = dict(typespec='integer', intent=['hide'])
dv['='] = 'shape(%s, %s)' % (a, i)
extra_args.append(dn)
vars[dn] = dv
v['dimension'][i] = dn
rout['args'].extend(extra_args)
need_interface = bool(extra_args)
ret = ['']
def add(line, ret=ret):
ret[0] = '%s\n %s' % (ret[0], line)
name = rout['name']
fortranname = getfortranname(rout)
f90mode = ismoduleroutine(rout)
newname = '%sf2pywrap' % (name)
if newname not in vars:
vars[newname] = vars[name]
args = [newname] + rout['args'][1:]
else:
args = [newname] + rout['args']
l_tmpl = var2fixfortran(vars, name, '@@@NAME@@@', f90mode)
if l_tmpl[:13] == 'character*(*)':
if f90mode:
l_tmpl = 'character(len=10)' + l_tmpl[13:]
else:
l_tmpl = 'character*10' + l_tmpl[13:]
charselect = vars[name]['charselector']
if charselect.get('*', '') == '(*)':
charselect['*'] = '10'
l1 = l_tmpl.replace('@@@NAME@@@', newname)
rl = None
useisoc = useiso_c_binding(rout)
sargs = ', '.join(args)
if f90mode:
# gh-23598 fix warning
# Essentially, this gets called again with modules where the name of the
# function is added to the arguments, which is not required, and removed
sargs = sargs.replace(f"{name}, ", '')
args = [arg for arg in args if arg != name]
rout['args'] = args
add('subroutine f2pywrap_%s_%s (%s)' %
(rout['modulename'], name, sargs))
if not signature:
add('use %s, only : %s' % (rout['modulename'], fortranname))
if useisoc:
add('use iso_c_binding')
else:
add('subroutine f2pywrap%s (%s)' % (name, sargs))
if useisoc:
add('use iso_c_binding')
if not need_interface:
add('external %s' % (fortranname))
rl = l_tmpl.replace('@@@NAME@@@', '') + ' ' + fortranname
if need_interface:
for line in rout['saved_interface'].split('\n'):
if line.lstrip().startswith('use ') and '__user__' not in line:
add(line)
args = args[1:]
dumped_args = []
for a in args:
if isexternal(vars[a]):
add('external %s' % (a))
dumped_args.append(a)
for a in args:
if a in dumped_args:
continue
if isscalar(vars[a]):
add(var2fixfortran(vars, a, f90mode=f90mode))
dumped_args.append(a)
for a in args:
if a in dumped_args:
continue
if isintent_in(vars[a]):
add(var2fixfortran(vars, a, f90mode=f90mode))
dumped_args.append(a)
for a in args:
if a in dumped_args:
continue
add(var2fixfortran(vars, a, f90mode=f90mode))
add(l1)
if rl is not None:
add(rl)
if need_interface:
if f90mode:
# f90 module already defines needed interface
pass
else:
add('interface')
add(rout['saved_interface'].lstrip())
add('end interface')
sargs = ', '.join([a for a in args if a not in extra_args])
if not signature:
if islogicalfunction(rout):
add('%s = .not.(.not.%s(%s))' % (newname, fortranname, sargs))
else:
add('%s = %s(%s)' % (newname, fortranname, sargs))
if f90mode:
add('end subroutine f2pywrap_%s_%s' % (rout['modulename'], name))
else:
add('end')
return ret[0]
def createsubrwrapper(rout, signature=0):
assert issubroutine(rout)
extra_args = []
vars = rout['vars']
for a in rout['args']:
v = rout['vars'][a]
for i, d in enumerate(v.get('dimension', [])):
if d == ':':
dn = 'f2py_%s_d%s' % (a, i)
dv = dict(typespec='integer', intent=['hide'])
dv['='] = 'shape(%s, %s)' % (a, i)
extra_args.append(dn)
vars[dn] = dv
v['dimension'][i] = dn
rout['args'].extend(extra_args)
need_interface = bool(extra_args)
ret = ['']
def add(line, ret=ret):
ret[0] = '%s\n %s' % (ret[0], line)
name = rout['name']
fortranname = getfortranname(rout)
f90mode = ismoduleroutine(rout)
args = rout['args']
useisoc = useiso_c_binding(rout)
sargs = ', '.join(args)
if f90mode:
add('subroutine f2pywrap_%s_%s (%s)' %
(rout['modulename'], name, sargs))
if useisoc:
add('use iso_c_binding')
if not signature:
add('use %s, only : %s' % (rout['modulename'], fortranname))
else:
add('subroutine f2pywrap%s (%s)' % (name, sargs))
if useisoc:
add('use iso_c_binding')
if not need_interface:
add('external %s' % (fortranname))
if need_interface:
for line in rout['saved_interface'].split('\n'):
if line.lstrip().startswith('use ') and '__user__' not in line:
add(line)
dumped_args = []
for a in args:
if isexternal(vars[a]):
add('external %s' % (a))
dumped_args.append(a)
for a in args:
if a in dumped_args:
continue
if isscalar(vars[a]):
add(var2fixfortran(vars, a, f90mode=f90mode))
dumped_args.append(a)
for a in args:
if a in dumped_args:
continue
add(var2fixfortran(vars, a, f90mode=f90mode))
if need_interface:
if f90mode:
# f90 module already defines needed interface
pass
else:
add('interface')
for line in rout['saved_interface'].split('\n'):
if line.lstrip().startswith('use ') and '__user__' in line:
continue
add(line)
add('end interface')
sargs = ', '.join([a for a in args if a not in extra_args])
if not signature:
add('call %s(%s)' % (fortranname, sargs))
if f90mode:
add('end subroutine f2pywrap_%s_%s' % (rout['modulename'], name))
else:
add('end')
return ret[0]
def assubr(rout):
if isfunction_wrap(rout):
fortranname = getfortranname(rout)
name = rout['name']
outmess('\t\tCreating wrapper for Fortran function "%s"("%s")...\n' % (
name, fortranname))
rout = copy.copy(rout)
fname = name
rname = fname
if 'result' in rout:
rname = rout['result']
rout['vars'][fname] = rout['vars'][rname]
fvar = rout['vars'][fname]
if not isintent_out(fvar):
if 'intent' not in fvar:
fvar['intent'] = []
fvar['intent'].append('out')
flag = 1
for i in fvar['intent']:
if i.startswith('out='):
flag = 0
break
if flag:
fvar['intent'].append('out=%s' % (rname))
rout['args'][:] = [fname] + rout['args']
return rout, createfuncwrapper(rout)
if issubroutine_wrap(rout):
fortranname = getfortranname(rout)
name = rout['name']
outmess('\t\tCreating wrapper for Fortran subroutine "%s"("%s")...\n'
% (name, fortranname))
rout = copy.copy(rout)
return rout, createsubrwrapper(rout)
return rout, ''

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,3 @@
[bdist_rpm]
doc_files = docs/
tests/

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,173 @@
#ifndef Py_FORTRANOBJECT_H
#define Py_FORTRANOBJECT_H
#ifdef __cplusplus
extern "C" {
#endif
#include <Python.h>
#ifndef NPY_NO_DEPRECATED_API
#define NPY_NO_DEPRECATED_API NPY_API_VERSION
#endif
#ifdef FORTRANOBJECT_C
#define NO_IMPORT_ARRAY
#endif
#define PY_ARRAY_UNIQUE_SYMBOL _npy_f2py_ARRAY_API
#include "numpy/arrayobject.h"
#include "numpy/npy_3kcompat.h"
#ifdef F2PY_REPORT_ATEXIT
#include <sys/timeb.h>
// clang-format off
extern void f2py_start_clock(void);
extern void f2py_stop_clock(void);
extern void f2py_start_call_clock(void);
extern void f2py_stop_call_clock(void);
extern void f2py_cb_start_clock(void);
extern void f2py_cb_stop_clock(void);
extern void f2py_cb_start_call_clock(void);
extern void f2py_cb_stop_call_clock(void);
extern void f2py_report_on_exit(int, void *);
// clang-format on
#endif
#ifdef DMALLOC
#include "dmalloc.h"
#endif
/* Fortran object interface */
/*
123456789-123456789-123456789-123456789-123456789-123456789-123456789-12
PyFortranObject represents various Fortran objects:
Fortran (module) routines, COMMON blocks, module data.
Author: Pearu Peterson <pearu@cens.ioc.ee>
*/
#define F2PY_MAX_DIMS 40
#define F2PY_MESSAGE_BUFFER_SIZE 300 // Increase on "stack smashing detected"
typedef void (*f2py_set_data_func)(char *, npy_intp *);
typedef void (*f2py_void_func)(void);
typedef void (*f2py_init_func)(int *, npy_intp *, f2py_set_data_func, int *);
/*typedef void* (*f2py_c_func)(void*,...);*/
typedef void *(*f2pycfunc)(void);
typedef struct {
char *name; /* attribute (array||routine) name */
int rank; /* array rank, 0 for scalar, max is F2PY_MAX_DIMS,
|| rank=-1 for Fortran routine */
struct {
npy_intp d[F2PY_MAX_DIMS];
} dims; /* dimensions of the array, || not used */
int type; /* PyArray_<type> || not used */
int elsize; /* Element size || not used */
char *data; /* pointer to array || Fortran routine */
f2py_init_func func; /* initialization function for
allocatable arrays:
func(&rank,dims,set_ptr_func,name,len(name))
|| C/API wrapper for Fortran routine */
char *doc; /* documentation string; only recommended
for routines. */
} FortranDataDef;
typedef struct {
PyObject_HEAD
int len; /* Number of attributes */
FortranDataDef *defs; /* An array of FortranDataDef's */
PyObject *dict; /* Fortran object attribute dictionary */
} PyFortranObject;
#define PyFortran_Check(op) (Py_TYPE(op) == &PyFortran_Type)
#define PyFortran_Check1(op) (0 == strcmp(Py_TYPE(op)->tp_name, "fortran"))
extern PyTypeObject PyFortran_Type;
extern int
F2PyDict_SetItemString(PyObject *dict, char *name, PyObject *obj);
extern PyObject *
PyFortranObject_New(FortranDataDef *defs, f2py_void_func init);
extern PyObject *
PyFortranObject_NewAsAttr(FortranDataDef *defs);
PyObject *
F2PyCapsule_FromVoidPtr(void *ptr, void (*dtor)(PyObject *));
void *
F2PyCapsule_AsVoidPtr(PyObject *obj);
int
F2PyCapsule_Check(PyObject *ptr);
extern void *
F2PySwapThreadLocalCallbackPtr(char *key, void *ptr);
extern void *
F2PyGetThreadLocalCallbackPtr(char *key);
#define ISCONTIGUOUS(m) (PyArray_FLAGS(m) & NPY_ARRAY_C_CONTIGUOUS)
#define F2PY_INTENT_IN 1
#define F2PY_INTENT_INOUT 2
#define F2PY_INTENT_OUT 4
#define F2PY_INTENT_HIDE 8
#define F2PY_INTENT_CACHE 16
#define F2PY_INTENT_COPY 32
#define F2PY_INTENT_C 64
#define F2PY_OPTIONAL 128
#define F2PY_INTENT_INPLACE 256
#define F2PY_INTENT_ALIGNED4 512
#define F2PY_INTENT_ALIGNED8 1024
#define F2PY_INTENT_ALIGNED16 2048
#define ARRAY_ISALIGNED(ARR, SIZE) ((size_t)(PyArray_DATA(ARR)) % (SIZE) == 0)
#define F2PY_ALIGN4(intent) (intent & F2PY_INTENT_ALIGNED4)
#define F2PY_ALIGN8(intent) (intent & F2PY_INTENT_ALIGNED8)
#define F2PY_ALIGN16(intent) (intent & F2PY_INTENT_ALIGNED16)
#define F2PY_GET_ALIGNMENT(intent) \
(F2PY_ALIGN4(intent) \
? 4 \
: (F2PY_ALIGN8(intent) ? 8 : (F2PY_ALIGN16(intent) ? 16 : 1)))
#define F2PY_CHECK_ALIGNMENT(arr, intent) \
ARRAY_ISALIGNED(arr, F2PY_GET_ALIGNMENT(intent))
#define F2PY_ARRAY_IS_CHARACTER_COMPATIBLE(arr) ((PyArray_DESCR(arr)->type_num == NPY_STRING && PyArray_ITEMSIZE(arr) >= 1) \
|| PyArray_DESCR(arr)->type_num == NPY_UINT8)
#define F2PY_IS_UNICODE_ARRAY(arr) (PyArray_DESCR(arr)->type_num == NPY_UNICODE)
extern PyArrayObject *
ndarray_from_pyobj(const int type_num, const int elsize_, npy_intp *dims,
const int rank, const int intent, PyObject *obj,
const char *errmess);
extern PyArrayObject *
array_from_pyobj(const int type_num, npy_intp *dims, const int rank,
const int intent, PyObject *obj);
extern int
copy_ND_array(const PyArrayObject *in, PyArrayObject *out);
#ifdef DEBUG_COPY_ND_ARRAY
extern void
dump_attrs(const PyArrayObject *arr);
#endif
extern int f2py_describe(PyObject *obj, char *buf);
/* Utility CPP macros and functions that can be used in signature file
expressions. See signature-file.rst for documentation.
*/
#define f2py_itemsize(var) (PyArray_ITEMSIZE(capi_ ## var ## _as_array))
#define f2py_size(var, ...) f2py_size_impl((PyArrayObject *)(capi_ ## var ## _as_array), ## __VA_ARGS__, -1)
#define f2py_rank(var) var ## _Rank
#define f2py_shape(var,dim) var ## _Dims[dim]
#define f2py_len(var) f2py_shape(var,0)
#define f2py_fshape(var,dim) f2py_shape(var,rank(var)-dim-1)
#define f2py_flen(var) f2py_fshape(var,0)
#define f2py_slen(var) capi_ ## var ## _len
extern npy_intp f2py_size_impl(PyArrayObject* var, ...);
#ifdef __cplusplus
}
#endif
#endif /* !Py_FORTRANOBJECT_H */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,15 @@
from numpy.testing import IS_WASM, IS_EDITABLE
import pytest
if IS_WASM:
pytest.skip(
"WASM/Pyodide does not use or support Fortran",
allow_module_level=True
)
if IS_EDITABLE:
pytest.skip(
"Editable install doesn't support tests with a compile step",
allow_module_level=True
)

View File

@ -0,0 +1,34 @@
module ops_module
abstract interface
subroutine op(x, y, z)
integer, intent(in) :: x, y
integer, intent(out) :: z
end subroutine
end interface
contains
subroutine foo(x, y, r1, r2)
integer, intent(in) :: x, y
integer, intent(out) :: r1, r2
procedure (op) add1, add2
procedure (op), pointer::p
p=>add1
call p(x, y, r1)
p=>add2
call p(x, y, r2)
end subroutine
end module
subroutine add1(x, y, z)
integer, intent(in) :: x, y
integer, intent(out) :: z
z = x + y
end subroutine
subroutine add2(x, y, z)
integer, intent(in) :: x, y
integer, intent(out) :: z
z = x + 2 * y
end subroutine

View File

@ -0,0 +1,6 @@
module test
abstract interface
subroutine foo()
end subroutine
end interface
end module test

View File

@ -0,0 +1,235 @@
/*
* This file was auto-generated with f2py (version:2_1330) and hand edited by
* Pearu for testing purposes. Do not edit this file unless you know what you
* are doing!!!
*/
#ifdef __cplusplus
extern "C" {
#endif
/*********************** See f2py2e/cfuncs.py: includes ***********************/
#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include "fortranobject.h"
#include <math.h>
static PyObject *wrap_error;
static PyObject *wrap_module;
/************************************ call ************************************/
static char doc_f2py_rout_wrap_call[] = "\
Function signature:\n\
arr = call(type_num,dims,intent,obj)\n\
Required arguments:\n"
" type_num : input int\n"
" dims : input int-sequence\n"
" intent : input int\n"
" obj : input python object\n"
"Return objects:\n"
" arr : array";
static PyObject *f2py_rout_wrap_call(PyObject *capi_self,
PyObject *capi_args) {
PyObject * volatile capi_buildvalue = NULL;
int type_num = 0;
int elsize = 0;
npy_intp *dims = NULL;
PyObject *dims_capi = Py_None;
int rank = 0;
int intent = 0;
PyArrayObject *capi_arr_tmp = NULL;
PyObject *arr_capi = Py_None;
int i;
if (!PyArg_ParseTuple(capi_args,"iiOiO|:wrap.call",\
&type_num,&elsize,&dims_capi,&intent,&arr_capi))
return NULL;
rank = PySequence_Length(dims_capi);
dims = malloc(rank*sizeof(npy_intp));
for (i=0;i<rank;++i) {
PyObject *tmp;
tmp = PySequence_GetItem(dims_capi, i);
if (tmp == NULL) {
goto fail;
}
dims[i] = (npy_intp)PyLong_AsLong(tmp);
Py_DECREF(tmp);
if (dims[i] == -1 && PyErr_Occurred()) {
goto fail;
}
}
capi_arr_tmp = ndarray_from_pyobj(type_num,elsize,dims,rank,intent|F2PY_INTENT_OUT,arr_capi,"wrap.call failed");
if (capi_arr_tmp == NULL) {
free(dims);
return NULL;
}
capi_buildvalue = Py_BuildValue("N",capi_arr_tmp);
free(dims);
return capi_buildvalue;
fail:
free(dims);
return NULL;
}
static char doc_f2py_rout_wrap_attrs[] = "\
Function signature:\n\
arr = array_attrs(arr)\n\
Required arguments:\n"
" arr : input array object\n"
"Return objects:\n"
" data : data address in hex\n"
" nd : int\n"
" dimensions : tuple\n"
" strides : tuple\n"
" base : python object\n"
" (kind,type,type_num,elsize,alignment) : 4-tuple\n"
" flags : int\n"
" itemsize : int\n"
;
static PyObject *f2py_rout_wrap_attrs(PyObject *capi_self,
PyObject *capi_args) {
PyObject *arr_capi = Py_None;
PyArrayObject *arr = NULL;
PyObject *dimensions = NULL;
PyObject *strides = NULL;
char s[100];
int i;
memset(s,0,100);
if (!PyArg_ParseTuple(capi_args,"O!|:wrap.attrs",
&PyArray_Type,&arr_capi))
return NULL;
arr = (PyArrayObject *)arr_capi;
sprintf(s,"%p",PyArray_DATA(arr));
dimensions = PyTuple_New(PyArray_NDIM(arr));
strides = PyTuple_New(PyArray_NDIM(arr));
for (i=0;i<PyArray_NDIM(arr);++i) {
PyTuple_SetItem(dimensions,i,PyLong_FromLong(PyArray_DIM(arr,i)));
PyTuple_SetItem(strides,i,PyLong_FromLong(PyArray_STRIDE(arr,i)));
}
return Py_BuildValue("siNNO(cciii)ii",s,PyArray_NDIM(arr),
dimensions,strides,
(PyArray_BASE(arr)==NULL?Py_None:PyArray_BASE(arr)),
PyArray_DESCR(arr)->kind,
PyArray_DESCR(arr)->type,
PyArray_TYPE(arr),
PyArray_ITEMSIZE(arr),
PyDataType_ALIGNMENT(PyArray_DESCR(arr)),
PyArray_FLAGS(arr),
PyArray_ITEMSIZE(arr));
}
static PyMethodDef f2py_module_methods[] = {
{"call",f2py_rout_wrap_call,METH_VARARGS,doc_f2py_rout_wrap_call},
{"array_attrs",f2py_rout_wrap_attrs,METH_VARARGS,doc_f2py_rout_wrap_attrs},
{NULL,NULL}
};
static struct PyModuleDef moduledef = {
PyModuleDef_HEAD_INIT,
"test_array_from_pyobj_ext",
NULL,
-1,
f2py_module_methods,
NULL,
NULL,
NULL,
NULL
};
PyMODINIT_FUNC PyInit_test_array_from_pyobj_ext(void) {
PyObject *m,*d, *s;
m = wrap_module = PyModule_Create(&moduledef);
Py_SET_TYPE(&PyFortran_Type, &PyType_Type);
import_array();
if (PyErr_Occurred())
Py_FatalError("can't initialize module wrap (failed to import numpy)");
d = PyModule_GetDict(m);
s = PyUnicode_FromString("This module 'wrap' is auto-generated with f2py (version:2_1330).\nFunctions:\n"
" arr = call(type_num,dims,intent,obj)\n"
".");
PyDict_SetItemString(d, "__doc__", s);
wrap_error = PyErr_NewException ("wrap.error", NULL, NULL);
Py_DECREF(s);
#define ADDCONST(NAME, CONST) \
s = PyLong_FromLong(CONST); \
PyDict_SetItemString(d, NAME, s); \
Py_DECREF(s)
ADDCONST("F2PY_INTENT_IN", F2PY_INTENT_IN);
ADDCONST("F2PY_INTENT_INOUT", F2PY_INTENT_INOUT);
ADDCONST("F2PY_INTENT_OUT", F2PY_INTENT_OUT);
ADDCONST("F2PY_INTENT_HIDE", F2PY_INTENT_HIDE);
ADDCONST("F2PY_INTENT_CACHE", F2PY_INTENT_CACHE);
ADDCONST("F2PY_INTENT_COPY", F2PY_INTENT_COPY);
ADDCONST("F2PY_INTENT_C", F2PY_INTENT_C);
ADDCONST("F2PY_OPTIONAL", F2PY_OPTIONAL);
ADDCONST("F2PY_INTENT_INPLACE", F2PY_INTENT_INPLACE);
ADDCONST("NPY_BOOL", NPY_BOOL);
ADDCONST("NPY_BYTE", NPY_BYTE);
ADDCONST("NPY_UBYTE", NPY_UBYTE);
ADDCONST("NPY_SHORT", NPY_SHORT);
ADDCONST("NPY_USHORT", NPY_USHORT);
ADDCONST("NPY_INT", NPY_INT);
ADDCONST("NPY_UINT", NPY_UINT);
ADDCONST("NPY_INTP", NPY_INTP);
ADDCONST("NPY_UINTP", NPY_UINTP);
ADDCONST("NPY_LONG", NPY_LONG);
ADDCONST("NPY_ULONG", NPY_ULONG);
ADDCONST("NPY_LONGLONG", NPY_LONGLONG);
ADDCONST("NPY_ULONGLONG", NPY_ULONGLONG);
ADDCONST("NPY_FLOAT", NPY_FLOAT);
ADDCONST("NPY_DOUBLE", NPY_DOUBLE);
ADDCONST("NPY_LONGDOUBLE", NPY_LONGDOUBLE);
ADDCONST("NPY_CFLOAT", NPY_CFLOAT);
ADDCONST("NPY_CDOUBLE", NPY_CDOUBLE);
ADDCONST("NPY_CLONGDOUBLE", NPY_CLONGDOUBLE);
ADDCONST("NPY_OBJECT", NPY_OBJECT);
ADDCONST("NPY_STRING", NPY_STRING);
ADDCONST("NPY_UNICODE", NPY_UNICODE);
ADDCONST("NPY_VOID", NPY_VOID);
ADDCONST("NPY_NTYPES_LEGACY", NPY_NTYPES_LEGACY);
ADDCONST("NPY_NOTYPE", NPY_NOTYPE);
ADDCONST("NPY_USERDEF", NPY_USERDEF);
ADDCONST("CONTIGUOUS", NPY_ARRAY_C_CONTIGUOUS);
ADDCONST("FORTRAN", NPY_ARRAY_F_CONTIGUOUS);
ADDCONST("OWNDATA", NPY_ARRAY_OWNDATA);
ADDCONST("FORCECAST", NPY_ARRAY_FORCECAST);
ADDCONST("ENSURECOPY", NPY_ARRAY_ENSURECOPY);
ADDCONST("ENSUREARRAY", NPY_ARRAY_ENSUREARRAY);
ADDCONST("ALIGNED", NPY_ARRAY_ALIGNED);
ADDCONST("WRITEABLE", NPY_ARRAY_WRITEABLE);
ADDCONST("WRITEBACKIFCOPY", NPY_ARRAY_WRITEBACKIFCOPY);
ADDCONST("BEHAVED", NPY_ARRAY_BEHAVED);
ADDCONST("BEHAVED_NS", NPY_ARRAY_BEHAVED_NS);
ADDCONST("CARRAY", NPY_ARRAY_CARRAY);
ADDCONST("FARRAY", NPY_ARRAY_FARRAY);
ADDCONST("CARRAY_RO", NPY_ARRAY_CARRAY_RO);
ADDCONST("FARRAY_RO", NPY_ARRAY_FARRAY_RO);
ADDCONST("DEFAULT", NPY_ARRAY_DEFAULT);
ADDCONST("UPDATE_ALL", NPY_ARRAY_UPDATE_ALL);
#undef ADDCONST
if (PyErr_Occurred())
Py_FatalError("can't initialize module wrap");
#ifdef F2PY_REPORT_ATEXIT
on_exit(f2py_report_on_exit,(void*)"array_from_pyobj.wrap.call");
#endif
#if Py_GIL_DISABLED
// signal whether this module supports running with the GIL disabled
PyUnstable_Module_SetGIL(m, Py_MOD_GIL_NOT_USED);
#endif
return m;
}
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1 @@
dict(real=dict(rk="double"))

View File

@ -0,0 +1,34 @@
subroutine sum(x, res)
implicit none
real, intent(in) :: x(:)
real, intent(out) :: res
integer :: i
!print *, "sum: size(x) = ", size(x)
res = 0.0
do i = 1, size(x)
res = res + x(i)
enddo
end subroutine sum
function fsum(x) result (res)
implicit none
real, intent(in) :: x(:)
real :: res
integer :: i
!print *, "fsum: size(x) = ", size(x)
res = 0.0
do i = 1, size(x)
res = res + x(i)
enddo
end function fsum

View File

@ -0,0 +1,41 @@
module mod
contains
subroutine sum(x, res)
implicit none
real, intent(in) :: x(:)
real, intent(out) :: res
integer :: i
!print *, "sum: size(x) = ", size(x)
res = 0.0
do i = 1, size(x)
res = res + x(i)
enddo
end subroutine sum
function fsum(x) result (res)
implicit none
real, intent(in) :: x(:)
real :: res
integer :: i
!print *, "fsum: size(x) = ", size(x)
res = 0.0
do i = 1, size(x)
res = res + x(i)
enddo
end function fsum
end module mod

View File

@ -0,0 +1,19 @@
subroutine sum_with_use(x, res)
use precision
implicit none
real(kind=rk), intent(in) :: x(:)
real(kind=rk), intent(out) :: res
integer :: i
!print *, "size(x) = ", size(x)
res = 0.0
do i = 1, size(x)
res = res + x(i)
enddo
end subroutine

View File

@ -0,0 +1,4 @@
module precision
integer, parameter :: rk = selected_real_kind(8)
integer, parameter :: ik = selected_real_kind(4)
end module

View File

@ -0,0 +1,6 @@
SUBROUTINE FOO()
INTEGER BAR(2, 3)
COMMON /BLOCK/ BAR
RETURN
END

View File

@ -0,0 +1,62 @@
subroutine t(fun,a)
integer a
cf2py intent(out) a
external fun
call fun(a)
end
subroutine func(a)
cf2py intent(in,out) a
integer a
a = a + 11
end
subroutine func0(a)
cf2py intent(out) a
integer a
a = 11
end
subroutine t2(a)
cf2py intent(callback) fun
integer a
cf2py intent(out) a
external fun
call fun(a)
end
subroutine string_callback(callback, a)
external callback
double precision callback
double precision a
character*1 r
cf2py intent(out) a
r = 'r'
a = callback(r)
end
subroutine string_callback_array(callback, cu, lencu, a)
external callback
integer callback
integer lencu
character*8 cu(lencu)
integer a
cf2py intent(out) a
a = callback(cu, lencu)
end
subroutine hidden_callback(a, r)
external global_f
cf2py intent(callback, hide) global_f
integer a, r, global_f
cf2py intent(out) r
r = global_f(a)
end
subroutine hidden_callback2(a, r)
external global_f
integer a, r, global_f
cf2py intent(out) r
r = global_f(a)
end

View File

@ -0,0 +1,7 @@
function gh17797(f, y) result(r)
external f
integer(8) :: r, f
integer(8), dimension(:) :: y
r = f(0)
r = r + sum(y)
end function gh17797

View File

@ -0,0 +1,17 @@
! When gh18335_workaround is defined as an extension,
! the issue cannot be reproduced.
!subroutine gh18335_workaround(f, y)
! implicit none
! external f
! integer(kind=1) :: y(1)
! call f(y)
!end subroutine gh18335_workaround
function gh18335(f) result (r)
implicit none
external f
integer(kind=1) :: y(1), r
y(1) = 123
call f(y)
r = y(1)
end function gh18335

View File

@ -0,0 +1,10 @@
SUBROUTINE FOO(FUN,R)
EXTERNAL FUN
INTEGER I
REAL*8 R, FUN
Cf2py intent(out) r
R = 0D0
DO I=-5,5
R = R + FUN(I)
ENDDO
END

View File

@ -0,0 +1,18 @@
python module __user__routines
interface
function fun(i) result (r)
integer :: i
real*8 :: r
end function fun
end interface
end python module __user__routines
python module callback2
interface
subroutine foo(f,r)
use __user__routines, f=>fun
external f
real*8 intent(out) :: r
end subroutine foo
end interface
end python module callback2

View File

@ -0,0 +1,6 @@
python module test_22819
interface
subroutine hello()
end subroutine hello
end interface
end python module test_22819

View File

@ -0,0 +1,3 @@
SUBROUTINE HI
PRINT*, "HELLO WORLD"
END SUBROUTINE

View File

@ -0,0 +1,3 @@
function hi()
print*, "Hello World"
end function

View File

@ -0,0 +1,11 @@
SUBROUTINE INITCB
DOUBLE PRECISION LONG
CHARACTER STRING
INTEGER OK
COMMON /BLOCK/ LONG, STRING, OK
LONG = 1.0
STRING = '2'
OK = 3
RETURN
END

View File

@ -0,0 +1,10 @@
module typedefmod
use iso_fortran_env, only: real32
end module typedefmod
module data
use typedefmod, only: real32
implicit none
real(kind=real32) :: x
common/test/x
end module data

View File

@ -0,0 +1,13 @@
module foo
public
type, private, bind(c) :: a
integer :: i
end type a
type, bind(c) :: b_
integer :: j
end type b_
public :: b_
type :: c
integer :: k
end type c
end module foo

View File

@ -0,0 +1,8 @@
BLOCK DATA PARAM_INI
COMMON /MYCOM/ MYDATA
DATA MYDATA /0/
END
SUBROUTINE SUB1
COMMON /MYCOM/ MYDATA
MYDATA = MYDATA + 1
END

View File

@ -0,0 +1,5 @@
BLOCK DATA MYBLK
IMPLICIT DOUBLE PRECISION (A-H,O-Z)
COMMON /MYCOM/ IVAR1, IVAR2, IVAR3, IVAR4, EVAR5
DATA IVAR1, IVAR2, IVAR3, IVAR4, EVAR5 /2*3,2*2,0.0D0/
END

View File

@ -0,0 +1,20 @@
! gh-23276
module cmplxdat
implicit none
integer :: i, j
real :: x, y
real, dimension(2) :: z
real(kind=8) :: pi
complex(kind=8), target :: medium_ref_index
complex(kind=8), target :: ref_index_one, ref_index_two
complex(kind=8), dimension(2) :: my_array
real(kind=8), dimension(3) :: my_real_array = (/1.0d0, 2.0d0, 3.0d0/)
data i, j / 2, 3 /
data x, y / 1.5, 2.0 /
data z / 3.5, 7.0 /
data medium_ref_index / (1.d0, 0.d0) /
data ref_index_one, ref_index_two / (13.0d0, 21.0d0), (-30.0d0, 43.0d0) /
data my_array / (1.0d0, 2.0d0), (-3.0d0, 4.0d0) /
data pi / 3.1415926535897932384626433832795028841971693993751058209749445923078164062d0 /
end module cmplxdat

View File

@ -0,0 +1,8 @@
BLOCK DATA PARAM_INI
COMMON /MYCOM/ MYTAB
INTEGER MYTAB(3)
DATA MYTAB/
* 0, ! 1 and more commenty stuff
* 4, ! 2
* 0 /
END

View File

@ -0,0 +1,6 @@
module foo
type bar
character(len = 4) :: text
end type bar
type(bar), parameter :: abar = bar('abar')
end module foo

View File

@ -0,0 +1,16 @@
subroutine subb(k)
real(8), intent(inout) :: k(:)
k=k+1
endsubroutine
subroutine subc(w,k)
real(8), intent(in) :: w(:)
real(8), intent(out) :: k(size(w))
k=w+1
endsubroutine
function t0(value)
character value
character t0
t0 = value
endfunction

View File

@ -0,0 +1,12 @@
integer(8) function external_as_statement(fcn)
implicit none
external fcn
integer(8) :: fcn
external_as_statement = fcn(0)
end
integer(8) function external_as_attribute(fcn)
implicit none
integer(8), external :: fcn
external_as_attribute = fcn(0)
end

View File

@ -0,0 +1,7 @@
python module iri16py ! in
interface ! in :iri16py
block data ! in :iri16py:iridreg_modified.for
COMMON /fircom/ eden,tabhe,tabla,tabmo,tabza,tabfl
end block data
end interface
end python module iri16py

View File

@ -0,0 +1,5 @@
SUBROUTINE EXAMPLE( )
IF( .TRUE. ) THEN
CALL DO_SOMETHING()
END IF ! ** .TRUE. **
END

View File

@ -0,0 +1,4 @@
integer function intproduct(a, b) result(res)
integer, intent(in) :: a, b
res = a*b
end function

View File

@ -0,0 +1,11 @@
module test_bug
implicit none
private
public :: intproduct
contains
integer function intproduct(a, b) result(res)
integer, intent(in) :: a, b
res = a*b
end function
end module

View File

@ -0,0 +1,20 @@
module gh23879
implicit none
private
public :: foo
contains
subroutine foo(a, b)
integer, intent(in) :: a
integer, intent(out) :: b
b = a
call bar(b)
end subroutine
subroutine bar(x)
integer, intent(inout) :: x
x = 2*x
end subroutine
end module gh23879

View File

@ -0,0 +1,13 @@
subroutine gh2848( &
! first 2 parameters
par1, par2,&
! last 2 parameters
par3, par4)
integer, intent(in) :: par1, par2
integer, intent(out) :: par3, par4
par3 = par1
par4 = par2
end subroutine gh2848

View File

@ -0,0 +1,49 @@
module foo
type bar
character(len = 32) :: item
end type bar
interface operator(.item.)
module procedure item_int, item_real
end interface operator(.item.)
interface operator(==)
module procedure items_are_equal
end interface operator(==)
interface assignment(=)
module procedure get_int, get_real
end interface assignment(=)
contains
function item_int(val) result(elem)
integer, intent(in) :: val
type(bar) :: elem
write(elem%item, "(I32)") val
end function item_int
function item_real(val) result(elem)
real, intent(in) :: val
type(bar) :: elem
write(elem%item, "(1PE32.12)") val
end function item_real
function items_are_equal(val1, val2) result(equal)
type(bar), intent(in) :: val1, val2
logical :: equal
equal = (val1%item == val2%item)
end function items_are_equal
subroutine get_real(rval, item)
real, intent(out) :: rval
type(bar), intent(in) :: item
read(item%item, *) rval
end subroutine get_real
subroutine get_int(rval, item)
integer, intent(out) :: rval
type(bar), intent(in) :: item
read(item%item, *) rval
end subroutine get_int
end module foo

View File

@ -0,0 +1,11 @@
module foo
private
integer :: a
public :: setA
integer :: b
contains
subroutine setA(v)
integer, intent(in) :: v
a = v
end subroutine setA
end module foo

View File

@ -0,0 +1,10 @@
module foo
public
integer, private :: a
public :: setA
contains
subroutine setA(v)
integer, intent(in) :: v
a = v
end subroutine setA
end module foo

View File

@ -0,0 +1,10 @@
module foo
public
integer, private :: a
integer :: b
contains
subroutine setA(v)
integer, intent(in) :: v
a = v
end subroutine setA
end module foo

View File

@ -0,0 +1,4 @@
subroutine foo(x)
real(8), intent(in) :: x
! Écrit à l'écran la valeur de x
end subroutine

View File

@ -0,0 +1 @@
dict(real=dict(real32='float', real64='double'), integer=dict(int64='long_long'))

View File

@ -0,0 +1,9 @@
subroutine func1(n, x, res)
use, intrinsic :: iso_fortran_env, only: int64, real64
implicit none
integer(int64), intent(in) :: n
real(real64), intent(in) :: x(n)
real(real64), intent(out) :: res
!f2py intent(hide) :: n
res = sum(x)
end

View File

@ -0,0 +1,34 @@
module coddity
use iso_c_binding, only: c_double, c_int, c_int64_t
implicit none
contains
subroutine c_add(a, b, c) bind(c, name="c_add")
real(c_double), intent(in) :: a, b
real(c_double), intent(out) :: c
c = a + b
end subroutine c_add
! gh-9693
function wat(x, y) result(z) bind(c)
integer(c_int), intent(in) :: x, y
integer(c_int) :: z
z = x + 7
end function wat
! gh-25207
subroutine c_add_int64(a, b, c) bind(c)
integer(c_int64_t), intent(in) :: a, b
integer(c_int64_t), intent(out) :: c
c = a + b
end subroutine c_add_int64
! gh-25207
subroutine add_arr(A, B, C)
integer(c_int64_t), intent(in) :: A(3)
integer(c_int64_t), intent(in) :: B(3)
integer(c_int64_t), intent(out) :: C(3)
integer :: j
do j = 1, 3
C(j) = A(j)+B(j)
end do
end subroutine
end module coddity

View File

@ -0,0 +1,20 @@
subroutine selectedrealkind(p, r, res)
implicit none
integer, intent(in) :: p, r
!f2py integer :: r=0
integer, intent(out) :: res
res = selected_real_kind(p, r)
end subroutine
subroutine selectedintkind(p, res)
implicit none
integer, intent(in) :: p
integer, intent(out) :: res
res = selected_int_kind(p)
end subroutine

View File

@ -0,0 +1,5 @@
subroutine bar11(a)
cf2py intent(out) a
integer a
a = 11
end

View File

@ -0,0 +1,8 @@
module foo_fixed
contains
subroutine bar12(a)
!f2py intent(out) a
integer a
a = 12
end subroutine bar12
end module foo_fixed

View File

@ -0,0 +1,8 @@
module foo_free
contains
subroutine bar13(a)
!f2py intent(out) a
integer a
a = 13
end subroutine bar13
end module foo_free

View File

@ -0,0 +1,8 @@
module data
real(8) :: shift
contains
subroutine set_shift(in_shift)
real(8), intent(in) :: in_shift
shift = in_shift
end subroutine set_shift
end module data

View File

@ -0,0 +1,6 @@
subroutine shift_a(dim_a, a)
use data, only: shift
integer, intent(in) :: dim_a
real(8), intent(inout), dimension(dim_a) :: a
a = a + shift
end subroutine shift_a

View File

@ -0,0 +1,21 @@
module mod2
implicit none
private mod2_func1
contains
subroutine mod2_func1()
print*, "mod2_func1"
end subroutine mod2_func1
end module mod2
module mod1
implicit none
private :: mod1_func1
contains
subroutine mod1_func1()
print*, "mod1_func1"
end subroutine mod1_func1
end module mod1

View File

@ -0,0 +1,21 @@
module mod2
implicit none
PUBLIC :: mod2_func1
contains
subroutine mod2_func1()
print*, "mod2_func1"
end subroutine mod2_func1
end module mod2
module mod1
implicit none
PUBLIC :: mod1_func1
contains
subroutine mod1_func1()
print*, "mod1_func1"
end subroutine mod1_func1
end module mod1

View File

@ -0,0 +1,12 @@
module mod
integer :: i
integer :: x(4)
real, dimension(2,3) :: a
real, allocatable, dimension(:,:) :: b
contains
subroutine foo
integer :: k
k = 1
a(1,2) = a(1,2)+3
end subroutine foo
end module mod

View File

@ -0,0 +1,20 @@
module mathops
implicit none
contains
function add(a, b) result(c)
integer, intent(in) :: a, b
integer :: c
c = a + b
end function add
end module mathops
module useops
use mathops, only: add
implicit none
contains
function sum_and_double(a, b) result(d)
integer, intent(in) :: a, b
integer :: d
d = 2 * add(a, b)
end function sum_and_double
end module useops

View File

@ -0,0 +1,7 @@
subroutine foo(is_, ie_, arr, tout)
implicit none
integer :: is_,ie_
real, intent(in) :: arr(is_:ie_)
real, intent(out) :: tout(is_:ie_)
tout = arr
end

View File

@ -0,0 +1,45 @@
! Check that parameter arrays are correctly intercepted.
subroutine foo_array(x, y, z)
implicit none
integer, parameter :: dp = selected_real_kind(15)
integer, parameter :: pa = 2
integer, parameter :: intparamarray(2) = (/ 3, 5 /)
integer, dimension(pa), parameter :: pb = (/ 2, 10 /)
integer, parameter, dimension(intparamarray(1)) :: pc = (/ 2, 10, 20 /)
real(dp), parameter :: doubleparamarray(3) = (/ 3.14_dp, 4._dp, 6.44_dp /)
real(dp), intent(inout) :: x(intparamarray(1))
real(dp), intent(inout) :: y(intparamarray(2))
real(dp), intent(out) :: z
x = x/pb(2)
y = y*pc(2)
z = doubleparamarray(1)*doubleparamarray(2) + doubleparamarray(3)
return
end subroutine
subroutine foo_array_any_index(x, y)
implicit none
integer, parameter :: dp = selected_real_kind(15)
integer, parameter, dimension(-1:1) :: myparamarray = (/ 6, 3, 1 /)
integer, parameter, dimension(2) :: nested = (/ 2, 0 /)
integer, parameter :: dim = 2
real(dp), intent(in) :: x(myparamarray(-1))
real(dp), intent(out) :: y(nested(1), myparamarray(nested(dim)))
y = reshape(x, (/nested(1), myparamarray(nested(2))/))
return
end subroutine
subroutine foo_array_delims(x)
implicit none
integer, parameter :: dp = selected_real_kind(15)
integer, parameter, dimension(2) :: myparamarray = (/ (6), 1 /)
integer, parameter, dimension(3) :: test = (/2, 1, (3)/)
real(dp), intent(out) :: x
x = myparamarray(1)+test(3)
return
end subroutine

View File

@ -0,0 +1,57 @@
! Check that parameters are correct intercepted.
! Constants with comma separations are commonly
! used, for instance Pi = 3._dp
subroutine foo(x)
implicit none
integer, parameter :: sp = selected_real_kind(6)
integer, parameter :: dp = selected_real_kind(15)
integer, parameter :: ii = selected_int_kind(9)
integer, parameter :: il = selected_int_kind(18)
real(dp), intent(inout) :: x
dimension x(3)
real(sp), parameter :: three_s = 3._sp
real(dp), parameter :: three_d = 3._dp
integer(ii), parameter :: three_i = 3_ii
integer(il), parameter :: three_l = 3_il
x(1) = x(1) + x(2) * three_s * three_i + x(3) * three_d * three_l
x(2) = x(2) * three_s
x(3) = x(3) * three_l
return
end subroutine
subroutine foo_no(x)
implicit none
integer, parameter :: sp = selected_real_kind(6)
integer, parameter :: dp = selected_real_kind(15)
integer, parameter :: ii = selected_int_kind(9)
integer, parameter :: il = selected_int_kind(18)
real(dp), intent(inout) :: x
dimension x(3)
real(sp), parameter :: three_s = 3.
real(dp), parameter :: three_d = 3.
integer(ii), parameter :: three_i = 3
integer(il), parameter :: three_l = 3
x(1) = x(1) + x(2) * three_s * three_i + x(3) * three_d * three_l
x(2) = x(2) * three_s
x(3) = x(3) * three_l
return
end subroutine
subroutine foo_sum(x)
implicit none
integer, parameter :: sp = selected_real_kind(6)
integer, parameter :: dp = selected_real_kind(15)
integer, parameter :: ii = selected_int_kind(9)
integer, parameter :: il = selected_int_kind(18)
real(dp), intent(inout) :: x
dimension x(3)
real(sp), parameter :: three_s = 2._sp + 1._sp
real(dp), parameter :: three_d = 1._dp + 2._dp
integer(ii), parameter :: three_i = 2_ii + 1_ii
integer(il), parameter :: three_l = 1_il + 2_il
x(1) = x(1) + x(2) * three_s * three_i + x(3) * three_d * three_l
x(2) = x(2) * three_s
x(3) = x(3) * three_l
return
end subroutine

View File

@ -0,0 +1,15 @@
! Check that parameters are correct intercepted.
! Constants with comma separations are commonly
! used, for instance Pi = 3._dp
subroutine foo_compound_int(x)
implicit none
integer, parameter :: ii = selected_int_kind(9)
integer(ii), intent(inout) :: x
dimension x(3)
integer(ii), parameter :: three = 3_ii
integer(ii), parameter :: two = 2_ii
integer(ii), parameter :: six = three * 1_ii * two
x(1) = x(1) + x(2) + x(3) * six
return
end subroutine

View File

@ -0,0 +1,22 @@
! Check that parameters are correct intercepted.
! Constants with comma separations are commonly
! used, for instance Pi = 3._dp
subroutine foo_int(x)
implicit none
integer, parameter :: ii = selected_int_kind(9)
integer(ii), intent(inout) :: x
dimension x(3)
integer(ii), parameter :: three = 3_ii
x(1) = x(1) + x(2) + x(3) * three
return
end subroutine
subroutine foo_long(x)
implicit none
integer, parameter :: ii = selected_int_kind(18)
integer(ii), intent(inout) :: x
dimension x(3)
integer(ii), parameter :: three = 3_ii
x(1) = x(1) + x(2) + x(3) * three
return
end subroutine

View File

@ -0,0 +1,23 @@
! Check that parameters are correct intercepted.
! Specifically that types of constants without
! compound kind specs are correctly inferred
! adapted Gibbs iteration code from pymc
! for this test case
subroutine foo_non_compound_int(x)
implicit none
integer, parameter :: ii = selected_int_kind(9)
integer(ii) maxiterates
parameter (maxiterates=2)
integer(ii) maxseries
parameter (maxseries=2)
integer(ii) wasize
parameter (wasize=maxiterates*maxseries)
integer(ii), intent(inout) :: x
dimension x(wasize)
x(1) = x(1) + x(2) + x(3) + x(4) * wasize
return
end subroutine

View File

@ -0,0 +1,23 @@
! Check that parameters are correct intercepted.
! Constants with comma separations are commonly
! used, for instance Pi = 3._dp
subroutine foo_single(x)
implicit none
integer, parameter :: rp = selected_real_kind(6)
real(rp), intent(inout) :: x
dimension x(3)
real(rp), parameter :: three = 3._rp
x(1) = x(1) + x(2) + x(3) * three
return
end subroutine
subroutine foo_double(x)
implicit none
integer, parameter :: rp = selected_real_kind(15)
real(rp), intent(inout) :: x
dimension x(3)
real(rp), parameter :: three = 3._rp
x(1) = x(1) + x(2) + x(3) * three
return
end subroutine

View File

@ -0,0 +1,14 @@
SUBROUTINE FOO(OUT1, OUT2, OUT3, OUT4, OUT5, OUT6)
CHARACTER SINGLE, DOUBLE, SEMICOL, EXCLA, OPENPAR, CLOSEPAR
PARAMETER (SINGLE="'", DOUBLE='"', SEMICOL=';', EXCLA="!",
1 OPENPAR="(", CLOSEPAR=")")
CHARACTER OUT1, OUT2, OUT3, OUT4, OUT5, OUT6
Cf2py intent(out) OUT1, OUT2, OUT3, OUT4, OUT5, OUT6
OUT1 = SINGLE
OUT2 = DOUBLE
OUT3 = SEMICOL
OUT4 = EXCLA
OUT5 = OPENPAR
OUT6 = CLOSEPAR
RETURN
END

View File

@ -0,0 +1 @@
real(8) b, n, m

View File

@ -0,0 +1,26 @@
SUBROUTINE TESTSUB(
& INPUT1, INPUT2, !Input
& OUTPUT1, OUTPUT2) !Output
IMPLICIT NONE
INTEGER, INTENT(IN) :: INPUT1, INPUT2
INTEGER, INTENT(OUT) :: OUTPUT1, OUTPUT2
OUTPUT1 = INPUT1 + INPUT2
OUTPUT2 = INPUT1 * INPUT2
RETURN
END SUBROUTINE TESTSUB
SUBROUTINE TESTSUB2(OUTPUT)
IMPLICIT NONE
INTEGER, PARAMETER :: N = 10 ! Array dimension
REAL, INTENT(OUT) :: OUTPUT(N)
INTEGER :: I
DO I = 1, N
OUTPUT(I) = I * 2.0
END DO
RETURN
END

View File

@ -0,0 +1,5 @@
C This is an invalid file, but it does compile with -ffixed-form
subroutine mwe(
& x)
real x
end subroutine mwe

View File

@ -0,0 +1,9 @@
SUBROUTINE TESTSUB(INPUT1, & ! Hello
! commenty
INPUT2, OUTPUT1, OUTPUT2) ! more comments
INTEGER, INTENT(IN) :: INPUT1, INPUT2
INTEGER, INTENT(OUT) :: OUTPUT1, OUTPUT2
OUTPUT1 = INPUT1 + &
INPUT2
OUTPUT2 = INPUT1 * INPUT2
END SUBROUTINE TESTSUB

View File

@ -0,0 +1,5 @@
function add(n,m) result(b)
implicit none
include 'AB.inc'
b = n + m
end function add

View File

@ -0,0 +1,9 @@
! Check that intent(in out) translates as intent(inout).
! The separation seems to be a common usage.
subroutine foo(x)
implicit none
real(4), intent(in out) :: x
dimension x(3)
x(1) = x(1) + x(2) + x(3)
return
end

View File

@ -0,0 +1,45 @@
function t0(value)
character value
character t0
t0 = value
end
function t1(value)
character*1 value
character*1 t1
t1 = value
end
function t5(value)
character*5 value
character*5 t5
t5 = value
end
function ts(value)
character*(*) value
character*(*) ts
ts = value
end
subroutine s0(t0,value)
character value
character t0
cf2py intent(out) t0
t0 = value
end
subroutine s1(t1,value)
character*1 value
character*1 t1
cf2py intent(out) t1
t1 = value
end
subroutine s5(t5,value)
character*5 value
character*5 t5
cf2py intent(out) t5
t5 = value
end
subroutine ss(ts,value)
character*(*) value
character*10 ts
cf2py intent(out) ts
ts = value
end

View File

@ -0,0 +1,48 @@
module f90_return_char
contains
function t0(value)
character :: value
character :: t0
t0 = value
end function t0
function t1(value)
character(len=1) :: value
character(len=1) :: t1
t1 = value
end function t1
function t5(value)
character(len=5) :: value
character(len=5) :: t5
t5 = value
end function t5
function ts(value)
character(len=*) :: value
character(len=10) :: ts
ts = value
end function ts
subroutine s0(t0,value)
character :: value
character :: t0
!f2py intent(out) t0
t0 = value
end subroutine s0
subroutine s1(t1,value)
character(len=1) :: value
character(len=1) :: t1
!f2py intent(out) t1
t1 = value
end subroutine s1
subroutine s5(t5,value)
character(len=5) :: value
character(len=5) :: t5
!f2py intent(out) t5
t5 = value
end subroutine s5
subroutine ss(ts,value)
character(len=*) :: value
character(len=10) :: ts
!f2py intent(out) ts
ts = value
end subroutine ss
end module f90_return_char

View File

@ -0,0 +1,45 @@
function t0(value)
complex value
complex t0
t0 = value
end
function t8(value)
complex*8 value
complex*8 t8
t8 = value
end
function t16(value)
complex*16 value
complex*16 t16
t16 = value
end
function td(value)
double complex value
double complex td
td = value
end
subroutine s0(t0,value)
complex value
complex t0
cf2py intent(out) t0
t0 = value
end
subroutine s8(t8,value)
complex*8 value
complex*8 t8
cf2py intent(out) t8
t8 = value
end
subroutine s16(t16,value)
complex*16 value
complex*16 t16
cf2py intent(out) t16
t16 = value
end
subroutine sd(td,value)
double complex value
double complex td
cf2py intent(out) td
td = value
end

View File

@ -0,0 +1,48 @@
module f90_return_complex
contains
function t0(value)
complex :: value
complex :: t0
t0 = value
end function t0
function t8(value)
complex(kind=4) :: value
complex(kind=4) :: t8
t8 = value
end function t8
function t16(value)
complex(kind=8) :: value
complex(kind=8) :: t16
t16 = value
end function t16
function td(value)
double complex :: value
double complex :: td
td = value
end function td
subroutine s0(t0,value)
complex :: value
complex :: t0
!f2py intent(out) t0
t0 = value
end subroutine s0
subroutine s8(t8,value)
complex(kind=4) :: value
complex(kind=4) :: t8
!f2py intent(out) t8
t8 = value
end subroutine s8
subroutine s16(t16,value)
complex(kind=8) :: value
complex(kind=8) :: t16
!f2py intent(out) t16
t16 = value
end subroutine s16
subroutine sd(td,value)
double complex :: value
double complex :: td
!f2py intent(out) td
td = value
end subroutine sd
end module f90_return_complex

View File

@ -0,0 +1,56 @@
function t0(value)
integer value
integer t0
t0 = value
end
function t1(value)
integer*1 value
integer*1 t1
t1 = value
end
function t2(value)
integer*2 value
integer*2 t2
t2 = value
end
function t4(value)
integer*4 value
integer*4 t4
t4 = value
end
function t8(value)
integer*8 value
integer*8 t8
t8 = value
end
subroutine s0(t0,value)
integer value
integer t0
cf2py intent(out) t0
t0 = value
end
subroutine s1(t1,value)
integer*1 value
integer*1 t1
cf2py intent(out) t1
t1 = value
end
subroutine s2(t2,value)
integer*2 value
integer*2 t2
cf2py intent(out) t2
t2 = value
end
subroutine s4(t4,value)
integer*4 value
integer*4 t4
cf2py intent(out) t4
t4 = value
end
subroutine s8(t8,value)
integer*8 value
integer*8 t8
cf2py intent(out) t8
t8 = value
end

View File

@ -0,0 +1,59 @@
module f90_return_integer
contains
function t0(value)
integer :: value
integer :: t0
t0 = value
end function t0
function t1(value)
integer(kind=1) :: value
integer(kind=1) :: t1
t1 = value
end function t1
function t2(value)
integer(kind=2) :: value
integer(kind=2) :: t2
t2 = value
end function t2
function t4(value)
integer(kind=4) :: value
integer(kind=4) :: t4
t4 = value
end function t4
function t8(value)
integer(kind=8) :: value
integer(kind=8) :: t8
t8 = value
end function t8
subroutine s0(t0,value)
integer :: value
integer :: t0
!f2py intent(out) t0
t0 = value
end subroutine s0
subroutine s1(t1,value)
integer(kind=1) :: value
integer(kind=1) :: t1
!f2py intent(out) t1
t1 = value
end subroutine s1
subroutine s2(t2,value)
integer(kind=2) :: value
integer(kind=2) :: t2
!f2py intent(out) t2
t2 = value
end subroutine s2
subroutine s4(t4,value)
integer(kind=4) :: value
integer(kind=4) :: t4
!f2py intent(out) t4
t4 = value
end subroutine s4
subroutine s8(t8,value)
integer(kind=8) :: value
integer(kind=8) :: t8
!f2py intent(out) t8
t8 = value
end subroutine s8
end module f90_return_integer

View File

@ -0,0 +1,56 @@
function t0(value)
logical value
logical t0
t0 = value
end
function t1(value)
logical*1 value
logical*1 t1
t1 = value
end
function t2(value)
logical*2 value
logical*2 t2
t2 = value
end
function t4(value)
logical*4 value
logical*4 t4
t4 = value
end
c function t8(value)
c logical*8 value
c logical*8 t8
c t8 = value
c end
subroutine s0(t0,value)
logical value
logical t0
cf2py intent(out) t0
t0 = value
end
subroutine s1(t1,value)
logical*1 value
logical*1 t1
cf2py intent(out) t1
t1 = value
end
subroutine s2(t2,value)
logical*2 value
logical*2 t2
cf2py intent(out) t2
t2 = value
end
subroutine s4(t4,value)
logical*4 value
logical*4 t4
cf2py intent(out) t4
t4 = value
end
c subroutine s8(t8,value)
c logical*8 value
c logical*8 t8
cf2py intent(out) t8
c t8 = value
c end

View File

@ -0,0 +1,59 @@
module f90_return_logical
contains
function t0(value)
logical :: value
logical :: t0
t0 = value
end function t0
function t1(value)
logical(kind=1) :: value
logical(kind=1) :: t1
t1 = value
end function t1
function t2(value)
logical(kind=2) :: value
logical(kind=2) :: t2
t2 = value
end function t2
function t4(value)
logical(kind=4) :: value
logical(kind=4) :: t4
t4 = value
end function t4
function t8(value)
logical(kind=8) :: value
logical(kind=8) :: t8
t8 = value
end function t8
subroutine s0(t0,value)
logical :: value
logical :: t0
!f2py intent(out) t0
t0 = value
end subroutine s0
subroutine s1(t1,value)
logical(kind=1) :: value
logical(kind=1) :: t1
!f2py intent(out) t1
t1 = value
end subroutine s1
subroutine s2(t2,value)
logical(kind=2) :: value
logical(kind=2) :: t2
!f2py intent(out) t2
t2 = value
end subroutine s2
subroutine s4(t4,value)
logical(kind=4) :: value
logical(kind=4) :: t4
!f2py intent(out) t4
t4 = value
end subroutine s4
subroutine s8(t8,value)
logical(kind=8) :: value
logical(kind=8) :: t8
!f2py intent(out) t8
t8 = value
end subroutine s8
end module f90_return_logical

Some files were not shown because too many files have changed in this diff Show More