Merging PR_218 openai_rev package with new streamlit chat app
This commit is contained in:
186
venv/lib/python3.9/site-packages/numpy/f2py/__init__.py
Normal file
186
venv/lib/python3.9/site-packages/numpy/f2py/__init__.py
Normal file
@@ -0,0 +1,186 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Fortran to Python Interface Generator.
|
||||
|
||||
"""
|
||||
__all__ = ['run_main', 'compile', 'get_include']
|
||||
|
||||
import sys
|
||||
import subprocess
|
||||
import os
|
||||
|
||||
from . import f2py2e
|
||||
from . import diagnose
|
||||
|
||||
run_main = f2py2e.run_main
|
||||
main = f2py2e.main
|
||||
|
||||
|
||||
def compile(source,
|
||||
modulename='untitled',
|
||||
extra_args='',
|
||||
verbose=True,
|
||||
source_fn=None,
|
||||
extension='.f',
|
||||
full_output=False
|
||||
):
|
||||
"""
|
||||
Build extension module from a Fortran 77 source string with f2py.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
source : str or bytes
|
||||
Fortran source of module / subroutine to compile
|
||||
|
||||
.. versionchanged:: 1.16.0
|
||||
Accept str as well as bytes
|
||||
|
||||
modulename : str, optional
|
||||
The name of the compiled python module
|
||||
extra_args : str or list, optional
|
||||
Additional parameters passed to f2py
|
||||
|
||||
.. versionchanged:: 1.16.0
|
||||
A list of args may also be provided.
|
||||
|
||||
verbose : bool, optional
|
||||
Print f2py output to screen
|
||||
source_fn : str, optional
|
||||
Name of the file where the fortran source is written.
|
||||
The default is to use a temporary file with the extension
|
||||
provided by the ``extension`` parameter
|
||||
extension : ``{'.f', '.f90'}``, optional
|
||||
Filename extension if `source_fn` is not provided.
|
||||
The extension tells which fortran standard is used.
|
||||
The default is ``.f``, which implies F77 standard.
|
||||
|
||||
.. versionadded:: 1.11.0
|
||||
|
||||
full_output : bool, optional
|
||||
If True, return a `subprocess.CompletedProcess` containing
|
||||
the stdout and stderr of the compile process, instead of just
|
||||
the status code.
|
||||
|
||||
.. versionadded:: 1.20.0
|
||||
|
||||
|
||||
Returns
|
||||
-------
|
||||
result : int or `subprocess.CompletedProcess`
|
||||
0 on success, or a `subprocess.CompletedProcess` if
|
||||
``full_output=True``
|
||||
|
||||
Examples
|
||||
--------
|
||||
.. literalinclude:: ../../source/f2py/code/results/compile_session.dat
|
||||
:language: python
|
||||
|
||||
"""
|
||||
import tempfile
|
||||
import shlex
|
||||
|
||||
if source_fn is None:
|
||||
f, fname = tempfile.mkstemp(suffix=extension)
|
||||
# f is a file descriptor so need to close it
|
||||
# carefully -- not with .close() directly
|
||||
os.close(f)
|
||||
else:
|
||||
fname = source_fn
|
||||
|
||||
if not isinstance(source, str):
|
||||
source = str(source, 'utf-8')
|
||||
try:
|
||||
with open(fname, 'w') as f:
|
||||
f.write(source)
|
||||
|
||||
args = ['-c', '-m', modulename, f.name]
|
||||
|
||||
if isinstance(extra_args, str):
|
||||
is_posix = (os.name == 'posix')
|
||||
extra_args = shlex.split(extra_args, posix=is_posix)
|
||||
|
||||
args.extend(extra_args)
|
||||
|
||||
c = [sys.executable,
|
||||
'-c',
|
||||
'import numpy.f2py as f2py2e;f2py2e.main()'] + args
|
||||
try:
|
||||
cp = subprocess.run(c, capture_output=True)
|
||||
except OSError:
|
||||
# preserve historic status code used by exec_command()
|
||||
cp = subprocess.CompletedProcess(c, 127, stdout=b'', stderr=b'')
|
||||
else:
|
||||
if verbose:
|
||||
print(cp.stdout.decode())
|
||||
finally:
|
||||
if source_fn is None:
|
||||
os.remove(fname)
|
||||
|
||||
if full_output:
|
||||
return cp
|
||||
else:
|
||||
return cp.returncode
|
||||
|
||||
|
||||
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)
|
||||
``_fblas-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"})
|
||||
43
venv/lib/python3.9/site-packages/numpy/f2py/__init__.pyi
Normal file
43
venv/lib/python3.9/site-packages/numpy/f2py/__init__.pyi
Normal file
@@ -0,0 +1,43 @@
|
||||
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]
|
||||
__path__: 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: ...
|
||||
5
venv/lib/python3.9/site-packages/numpy/f2py/__main__.py
Normal file
5
venv/lib/python3.9/site-packages/numpy/f2py/__main__.py
Normal 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()
|
||||
@@ -0,0 +1 @@
|
||||
from numpy.version import version
|
||||
890
venv/lib/python3.9/site-packages/numpy/f2py/auxfuncs.py
Normal file
890
venv/lib/python3.9/site-packages/numpy/f2py/auxfuncs.py
Normal file
@@ -0,0 +1,890 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
|
||||
Auxiliary functions for f2py2e.
|
||||
|
||||
Copyright 1999,2000 Pearu Peterson all rights reserved,
|
||||
Pearu Peterson <pearu@ioc.ee>
|
||||
Permission to use, modify, and distribute this software is given under the
|
||||
terms of the NumPy (BSD style) LICENSE.
|
||||
|
||||
|
||||
NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
|
||||
$Date: 2005/07/24 19:01:55 $
|
||||
Pearu Peterson
|
||||
|
||||
"""
|
||||
import pprint
|
||||
import sys
|
||||
import types
|
||||
from functools import reduce
|
||||
|
||||
from . import __version__
|
||||
from . import cfuncs
|
||||
|
||||
__all__ = [
|
||||
'applyrules', 'debugcapi', 'dictappend', 'errmess', 'gentitle',
|
||||
'getargs2', 'getcallprotoargument', 'getcallstatement',
|
||||
'getfortranname', 'getpymethoddef', 'getrestdoc', 'getusercode',
|
||||
'getusercode1', 'hasbody', 'hascallstatement', 'hascommon',
|
||||
'hasexternals', 'hasinitvalue', 'hasnote', 'hasresultnote',
|
||||
'isallocatable', 'isarray', 'isarrayofstrings',
|
||||
'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', 'isrequired',
|
||||
'isroutine', 'isscalar', 'issigned_long_longarray', 'isstring',
|
||||
'isstringarray', 'isstring_or_stringarray', 'isstringfunction',
|
||||
'issubroutine',
|
||||
'issubroutine_wrap', 'isthreadsafe', 'isunsigned', 'isunsigned_char',
|
||||
'isunsigned_chararray', 'isunsigned_long_long',
|
||||
'isunsigned_long_longarray', 'isunsigned_short',
|
||||
'isunsigned_shortarray', 'l_and', 'l_not', 'l_or', 'outmess',
|
||||
'replace', 'show', 'stripcomma', 'throw_error', 'isattr_value'
|
||||
]
|
||||
|
||||
|
||||
f2py_version = __version__.version
|
||||
|
||||
|
||||
errmess = sys.stderr.write
|
||||
show = pprint.pprint
|
||||
|
||||
options = {}
|
||||
debugoptions = []
|
||||
wrapfuncs = 1
|
||||
|
||||
|
||||
def outmess(t):
|
||||
if options.get('verbose', 1):
|
||||
sys.stdout.write(t)
|
||||
|
||||
|
||||
def debugcapi(var):
|
||||
return 'capi' in debugoptions
|
||||
|
||||
|
||||
def _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 isrequired(var):
|
||||
return not isoptional(var) and isintent_nothide(var)
|
||||
|
||||
|
||||
def isintent_in(var):
|
||||
if 'intent' not in var:
|
||||
return 1
|
||||
if 'hide' in var['intent']:
|
||||
return 0
|
||||
if 'inplace' in var['intent']:
|
||||
return 0
|
||||
if 'in' in var['intent']:
|
||||
return 1
|
||||
if 'out' in var['intent']:
|
||||
return 0
|
||||
if 'inout' in var['intent']:
|
||||
return 0
|
||||
if 'outin' in var['intent']:
|
||||
return 0
|
||||
return 1
|
||||
|
||||
|
||||
def isintent_inout(var):
|
||||
return ('intent' in var and ('inout' in var['intent'] or
|
||||
'outin' in var['intent']) and 'in' not in var['intent'] and
|
||||
'hide' not in var['intent'] and 'inplace' not in var['intent'])
|
||||
|
||||
|
||||
def isintent_out(var):
|
||||
return 'out' in var.get('intent', [])
|
||||
|
||||
|
||||
def isintent_hide(var):
|
||||
return ('intent' in var and ('hide' in var['intent'] or
|
||||
('out' in var['intent'] and 'in' not in var['intent'] and
|
||||
(not l_or(isintent_inout, isintent_inplace)(var)))))
|
||||
|
||||
|
||||
def isintent_nothide(var):
|
||||
return not isintent_hide(var)
|
||||
|
||||
|
||||
def isintent_c(var):
|
||||
return 'c' in var.get('intent', [])
|
||||
|
||||
|
||||
def isintent_cache(var):
|
||||
return 'cache' in var.get('intent', [])
|
||||
|
||||
|
||||
def isintent_copy(var):
|
||||
return 'copy' in var.get('intent', [])
|
||||
|
||||
|
||||
def isintent_overwrite(var):
|
||||
return 'overwrite' in var.get('intent', [])
|
||||
|
||||
|
||||
def isintent_callback(var):
|
||||
return 'callback' in var.get('intent', [])
|
||||
|
||||
|
||||
def isintent_inplace(var):
|
||||
return 'inplace' in var.get('intent', [])
|
||||
|
||||
|
||||
def isintent_aux(var):
|
||||
return 'aux' in var.get('intent', [])
|
||||
|
||||
|
||||
def isintent_aligned4(var):
|
||||
return 'aligned4' in var.get('intent', [])
|
||||
|
||||
|
||||
def isintent_aligned8(var):
|
||||
return 'aligned8' in var.get('intent', [])
|
||||
|
||||
|
||||
def isintent_aligned16(var):
|
||||
return 'aligned16' in var.get('intent', [])
|
||||
|
||||
|
||||
isintent_dict = {isintent_in: 'INTENT_IN', isintent_inout: 'INTENT_INOUT',
|
||||
isintent_out: 'INTENT_OUT', isintent_hide: 'INTENT_HIDE',
|
||||
isintent_cache: 'INTENT_CACHE',
|
||||
isintent_c: 'INTENT_C', isoptional: 'OPTIONAL',
|
||||
isintent_inplace: 'INTENT_INPLACE',
|
||||
isintent_aligned4: 'INTENT_ALIGNED4',
|
||||
isintent_aligned8: 'INTENT_ALIGNED8',
|
||||
isintent_aligned16: 'INTENT_ALIGNED16',
|
||||
}
|
||||
|
||||
|
||||
def isprivate(var):
|
||||
return 'attrspec' in var and 'private' in var['attrspec']
|
||||
|
||||
|
||||
def hasinitvalue(var):
|
||||
return '=' in var
|
||||
|
||||
|
||||
def hasinitvalueasstring(var):
|
||||
if not hasinitvalue(var):
|
||||
return 0
|
||||
return var['='][0] in ['"', "'"]
|
||||
|
||||
|
||||
def hasnote(var):
|
||||
return 'note' in var
|
||||
|
||||
|
||||
def hasresultnote(rout):
|
||||
if not isfunction(rout):
|
||||
return 0
|
||||
if 'result' in rout:
|
||||
a = rout['result']
|
||||
else:
|
||||
a = rout['name']
|
||||
if a in rout['vars']:
|
||||
return hasnote(rout['vars'][a])
|
||||
return 0
|
||||
|
||||
|
||||
def hascommon(rout):
|
||||
return 'common' in rout
|
||||
|
||||
|
||||
def containscommon(rout):
|
||||
if hascommon(rout):
|
||||
return 1
|
||||
if hasbody(rout):
|
||||
for b in rout['body']:
|
||||
if containscommon(b):
|
||||
return 1
|
||||
return 0
|
||||
|
||||
|
||||
def containsmodule(block):
|
||||
if ismodule(block):
|
||||
return 1
|
||||
if not hasbody(block):
|
||||
return 0
|
||||
for b in block['body']:
|
||||
if containsmodule(b):
|
||||
return 1
|
||||
return 0
|
||||
|
||||
|
||||
def hasbody(rout):
|
||||
return 'body' in rout
|
||||
|
||||
|
||||
def hascallstatement(rout):
|
||||
return getcallstatement(rout) is not None
|
||||
|
||||
|
||||
def istrue(var):
|
||||
return 1
|
||||
|
||||
|
||||
def isfalse(var):
|
||||
return 0
|
||||
|
||||
|
||||
class F2PYError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class throw_error:
|
||||
|
||||
def __init__(self, mess):
|
||||
self.mess = mess
|
||||
|
||||
def __call__(self, var):
|
||||
mess = '\n\n var = %s\n Message: %s\n' % (var, self.mess)
|
||||
raise F2PYError(mess)
|
||||
|
||||
|
||||
def l_and(*f):
|
||||
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
|
||||
880
venv/lib/python3.9/site-packages/numpy/f2py/capi_maps.py
Normal file
880
venv/lib/python3.9/site-packages/numpy/f2py/capi_maps.py
Normal file
@@ -0,0 +1,880 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
|
||||
Copyright 1999,2000 Pearu Peterson all rights reserved,
|
||||
Pearu Peterson <pearu@ioc.ee>
|
||||
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.
|
||||
$Date: 2005/05/06 10:57:33 $
|
||||
Pearu Peterson
|
||||
|
||||
"""
|
||||
from . import __version__
|
||||
f2py_version = __version__.version
|
||||
|
||||
import copy
|
||||
import re
|
||||
import os
|
||||
from .crackfortran import markoutercomma
|
||||
from . import cb_rules
|
||||
|
||||
# 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'
|
||||
]
|
||||
|
||||
|
||||
# Numarray and Numeric users should set this False
|
||||
using_newcore = True
|
||||
|
||||
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_DOUBLE', # forced casting
|
||||
'char': 'NPY_STRING',
|
||||
'unsigned_char': 'NPY_UBYTE',
|
||||
'signed_char': 'NPY_BYTE',
|
||||
'short': 'NPY_SHORT',
|
||||
'unsigned_short': 'NPY_USHORT',
|
||||
'int': 'NPY_INT',
|
||||
'unsigned': 'NPY_UINT',
|
||||
'long': 'NPY_LONG',
|
||||
'long_long': 'NPY_LONG', # forced casting
|
||||
'complex_float': 'NPY_CFLOAT',
|
||||
'complex_double': 'NPY_CDOUBLE',
|
||||
'complex_long_double': 'NPY_CDOUBLE', # forced casting
|
||||
'string': 'NPY_STRING',
|
||||
'character': 'NPY_CHAR'}
|
||||
|
||||
# These new maps aren't used anywhere yet, but should be by default
|
||||
# unless building numeric or numarray extensions.
|
||||
if using_newcore:
|
||||
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': 'd', # forced casting
|
||||
'char': '1',
|
||||
'signed_char': '1',
|
||||
'unsigned_char': 'b',
|
||||
'short': 's',
|
||||
'unsigned_short': 'w',
|
||||
'int': 'i',
|
||||
'unsigned': 'u',
|
||||
'long': 'l',
|
||||
'long_long': 'L',
|
||||
'complex_float': 'F',
|
||||
'complex_double': 'D',
|
||||
'complex_long_double': 'D', # forced casting
|
||||
'string': 'c',
|
||||
'character': 'c'
|
||||
}
|
||||
|
||||
if using_newcore:
|
||||
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 is NumPy agnostic, so no need to bother with using_newcore
|
||||
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'},
|
||||
}
|
||||
|
||||
f2cmap_default = copy.deepcopy(f2cmap_all)
|
||||
|
||||
f2cmap_mapped = []
|
||||
|
||||
def load_f2cmap_file(f2cmap_file):
|
||||
global f2cmap_all
|
||||
|
||||
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, 'r') as f:
|
||||
d = eval(f.read().lower(), {}, {})
|
||||
for k, d1 in d.items():
|
||||
for k1 in d1.keys():
|
||||
d1[k1.lower()] = d1[k1]
|
||||
d[k.lower()] = d[k]
|
||||
for k in d.keys():
|
||||
if k not in f2cmap_all:
|
||||
f2cmap_all[k] = {}
|
||||
for k1 in d[k].keys():
|
||||
if d[k][k1] in c2py_map:
|
||||
if k1 in f2cmap_all[k]:
|
||||
outmess(
|
||||
"\tWarning: redefinition of {'%s':{'%s':'%s'->'%s'}}\n" % (k, k1, f2cmap_all[k][k1], d[k][k1]))
|
||||
f2cmap_all[k][k1] = d[k][k1]
|
||||
outmess('\tMapping "%s(kind=%s)" to "%s"\n' %
|
||||
(k, k1, d[k][k1]))
|
||||
f2cmap_mapped.append(d[k][k1])
|
||||
else:
|
||||
errmess("\tIgnoring map {'%s':{'%s':'%s'}}: '%s' must be in %s\n" % (
|
||||
k, k1, d[k][k1], d[k][k1], list(c2py_map.keys())))
|
||||
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 '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
|
||||
649
venv/lib/python3.9/site-packages/numpy/f2py/cb_rules.py
Normal file
649
venv/lib/python3.9/site-packages/numpy/f2py/cb_rules.py
Normal file
@@ -0,0 +1,649 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
|
||||
Build call-back mechanism for f2py2e.
|
||||
|
||||
Copyright 2000 Pearu Peterson all rights reserved,
|
||||
Pearu Peterson <pearu@ioc.ee>
|
||||
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.
|
||||
$Date: 2005/07/20 11:27:58 $
|
||||
Pearu Peterson
|
||||
|
||||
"""
|
||||
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(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 #############
|
||||
1522
venv/lib/python3.9/site-packages/numpy/f2py/cfuncs.py
Normal file
1522
venv/lib/python3.9/site-packages/numpy/f2py/cfuncs.py
Normal file
File diff suppressed because it is too large
Load Diff
149
venv/lib/python3.9/site-packages/numpy/f2py/common_rules.py
Normal file
149
venv/lib/python3.9/site-packages/numpy/f2py/common_rules.py
Normal file
@@ -0,0 +1,149 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
|
||||
Build common block mechanism for f2py2e.
|
||||
|
||||
Copyright 2000 Pearu Peterson all rights reserved,
|
||||
Pearu Peterson <pearu@ioc.ee>
|
||||
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.
|
||||
$Date: 2005/05/06 10:57:33 $
|
||||
Pearu Peterson
|
||||
|
||||
"""
|
||||
from . import __version__
|
||||
f2py_version = __version__.version
|
||||
|
||||
from .auxfuncs import (
|
||||
hasbody, hascommon, hasnote, isintent_hide, outmess
|
||||
)
|
||||
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)
|
||||
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]
|
||||
3545
venv/lib/python3.9/site-packages/numpy/f2py/crackfortran.py
Normal file
3545
venv/lib/python3.9/site-packages/numpy/f2py/crackfortran.py
Normal file
File diff suppressed because it is too large
Load Diff
154
venv/lib/python3.9/site-packages/numpy/f2py/diagnose.py
Normal file
154
venv/lib/python3.9/site-packages/numpy/f2py/diagnose.py
Normal 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:
|
||||
print('Failed to import new numpy:', sys.exc_info()[1])
|
||||
has_newnumpy = 0
|
||||
|
||||
try:
|
||||
from numpy.f2py import f2py2e
|
||||
has_f2py2e = 1
|
||||
except ImportError:
|
||||
print('Failed to import f2py2e:', sys.exc_info()[1])
|
||||
has_f2py2e = 0
|
||||
|
||||
try:
|
||||
import numpy.distutils
|
||||
has_numpy_distutils = 2
|
||||
except ImportError:
|
||||
try:
|
||||
import numpy_distutils
|
||||
has_numpy_distutils = 1
|
||||
except ImportError:
|
||||
print('Failed to import numpy_distutils:', sys.exc_info()[1])
|
||||
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()
|
||||
704
venv/lib/python3.9/site-packages/numpy/f2py/f2py2e.py
Normal file
704
venv/lib/python3.9/site-packages/numpy/f2py/f2py2e.py
Normal file
@@ -0,0 +1,704 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
|
||||
f2py2e - Fortran to Python C/API generator. 2nd Edition.
|
||||
See __usage__ below.
|
||||
|
||||
Copyright 1999--2011 Pearu Peterson all rights reserved,
|
||||
Pearu Peterson <pearu@cens.ioc.ee>
|
||||
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.
|
||||
$Date: 2005/05/06 08:31:19 $
|
||||
Pearu Peterson
|
||||
|
||||
"""
|
||||
import sys
|
||||
import os
|
||||
import pprint
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
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
|
||||
|
||||
f2py_version = __version__.version
|
||||
numpy_version = __version__.version
|
||||
errmess = sys.stderr.write
|
||||
# outmess=sys.stdout.write
|
||||
show = pprint.pprint
|
||||
outmess = auxfuncs.outmess
|
||||
|
||||
__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:
|
||||
|
||||
--2d-numpy Use numpy.f2py tool with NumPy support. [DEFAULT]
|
||||
--2d-numeric Use f2py2e tool with Numeric support.
|
||||
--2d-numarray Use f2py2e tool with Numarray support.
|
||||
--g3-numpy Use 3rd generation f2py from the separate f2py package.
|
||||
[NOT AVAILABLE YET]
|
||||
|
||||
-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.
|
||||
|
||||
--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.
|
||||
|
||||
|
||||
numpy.distutils options (only effective with -c):
|
||||
|
||||
--fcompiler= Specify Fortran compiler type by vendor
|
||||
--compiler= Specify C compiler type (as defined by distutils)
|
||||
|
||||
--help-fcompiler List available Fortran compilers and exit
|
||||
--f77exec= Specify the path to F77 compiler
|
||||
--f90exec= Specify the path to F90 compiler
|
||||
--f77flags= Specify F77 compiler flags
|
||||
--f90flags= Specify F90 compiler flags
|
||||
--opt= Specify optimization flags
|
||||
--arch= Specify architecture specific optimization flags
|
||||
--noopt Compile without optimization
|
||||
--noarch Compile without arch-dependent optimization
|
||||
--debug Compile with debugging information
|
||||
|
||||
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.
|
||||
|
||||
-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
|
||||
-DUNDERSCORE_G77
|
||||
|
||||
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}
|
||||
Requires: Python 3.5 or higher.
|
||||
License: NumPy license (see LICENSE.txt in the NumPy source code)
|
||||
Copyright 1999 - 2011 Pearu Peterson all rights reserved.
|
||||
https://web.archive.org/web/20140822061353/http://cens.ioc.ee/projects/f2py2e"""
|
||||
|
||||
|
||||
def scaninputline(inputline):
|
||||
files, skipfuncs, onlyfuncs, debug = [], [], [], []
|
||||
f, f2, f3, f5, f6, f7, f8, f9, f10 = 1, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
verbose = 1
|
||||
emptygen = True
|
||||
dolc = -1
|
||||
dolatexdoc = 0
|
||||
dorestdoc = 0
|
||||
wrapfuncs = 1
|
||||
buildpath = '.'
|
||||
include_paths = []
|
||||
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[:15] in '--include_paths':
|
||||
outmess(
|
||||
'f2py option --include_paths is deprecated, use --include-paths instead.\n')
|
||||
f7 = 1
|
||||
elif l[:15] in '--include-paths':
|
||||
f7 = 1
|
||||
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 f7:
|
||||
f7 = 0
|
||||
include_paths.extend(l.split(os.pathsep))
|
||||
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.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"]
|
||||
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')
|
||||
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
|
||||
|
||||
|
||||
def run_compile():
|
||||
"""
|
||||
Do it all in one call!
|
||||
"""
|
||||
import tempfile
|
||||
|
||||
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)|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]
|
||||
_reg4 = re.compile(
|
||||
r'--((f(77|90)(flags|exec)|opt|arch)=|(debug|noopt|noarch|help-fcompiler))')
|
||||
fc_flags = [_m for _m in sys.argv[1:] if _reg4.match(_m)]
|
||||
sys.argv = [_m for _m in sys.argv if _m not in fc_flags]
|
||||
|
||||
del_list = []
|
||||
for s in flib_flags:
|
||||
v = '--fcompiler='
|
||||
if s[:len(v)] == v:
|
||||
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')
|
||||
|
||||
modulename = 'untitled'
|
||||
sources = sys.argv[1:]
|
||||
|
||||
for optname in ['--include_paths', '--include-paths', '--f2cmap']:
|
||||
if optname in sys.argv:
|
||||
i = sys.argv.index(optname)
|
||||
f2py_flags.extend(sys.argv[i:i + 2])
|
||||
del sys.argv[i + 1], sys.argv[i]
|
||||
sources = sys.argv[1:]
|
||||
|
||||
if '-m' in sys.argv:
|
||||
i = sys.argv.index('-m')
|
||||
modulename = sys.argv[i + 1]
|
||||
del sys.argv[i + 1], sys.argv[i]
|
||||
sources = sys.argv[1:]
|
||||
else:
|
||||
from numpy.distutils.command.build_src import get_f2py_modulename
|
||||
pyf_files, sources = filter_files('', '[.]pyf([.]src|)', sources)
|
||||
sources = pyf_files + sources
|
||||
for f in pyf_files:
|
||||
modulename = get_f2py_modulename(f)
|
||||
if modulename:
|
||||
break
|
||||
|
||||
extra_objects, sources = filter_files('', '[.](o|a|so|dylib)', sources)
|
||||
include_dirs, sources = filter_files('-I', '', sources, remove_prefix=1)
|
||||
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)
|
||||
|
||||
from numpy.distutils.system_info import get_info
|
||||
|
||||
num_info = {}
|
||||
if num_info:
|
||||
include_dirs.extend(num_info.get('include_dirs', []))
|
||||
|
||||
from numpy.distutils.core import setup, Extension
|
||||
ext_args = {'name': modulename, 'sources': sources,
|
||||
'include_dirs': include_dirs,
|
||||
'library_dirs': library_dirs,
|
||||
'libraries': libraries,
|
||||
'define_macros': define_macros,
|
||||
'undef_macros': undef_macros,
|
||||
'extra_objects': extra_objects,
|
||||
'f2py_options': f2py_flags,
|
||||
}
|
||||
|
||||
if sysinfo_flags:
|
||||
from numpy.distutils.misc_util import dict_append
|
||||
for n in sysinfo_flags:
|
||||
i = get_info(n)
|
||||
if not i:
|
||||
outmess('No %s resources found in system'
|
||||
' (try `f2py --help-link`)\n' % (repr(n)))
|
||||
dict_append(ext_args, **i)
|
||||
|
||||
ext = Extension(**ext_args)
|
||||
sys.argv = [sys.argv[0]] + setup_flags
|
||||
sys.argv.extend(['build',
|
||||
'--build-temp', build_dir,
|
||||
'--build-base', build_dir,
|
||||
'--build-platlib', '.',
|
||||
# disable CCompilerOpt
|
||||
'--disable-optimization'])
|
||||
if fc_flags:
|
||||
sys.argv.extend(['config_fc'] + fc_flags)
|
||||
if flib_flags:
|
||||
sys.argv.extend(['build_ext'] + flib_flags)
|
||||
|
||||
setup(ext_modules=[ext])
|
||||
|
||||
if remove_build_dir and os.path.exists(build_dir):
|
||||
import shutil
|
||||
outmess('Removing build directory %s\n' % (build_dir))
|
||||
shutil.rmtree(build_dir)
|
||||
|
||||
|
||||
def main():
|
||||
if '--help-link' in sys.argv[1:]:
|
||||
sys.argv.remove('--help-link')
|
||||
from numpy.distutils.system_info import show_all
|
||||
show_all()
|
||||
return
|
||||
|
||||
# Probably outdated options that were not working before 1.16
|
||||
if '--g3-numpy' in sys.argv[1:]:
|
||||
sys.stderr.write("G3 f2py support is not implemented, yet.\\n")
|
||||
sys.exit(1)
|
||||
elif '--2e-numeric' in sys.argv[1:]:
|
||||
sys.argv.remove('--2e-numeric')
|
||||
elif '--2e-numarray' in sys.argv[1:]:
|
||||
# Note that this errors becaust the -DNUMARRAY argument is
|
||||
# not recognized. Just here for back compatibility and the
|
||||
# error message.
|
||||
sys.argv.append("-DNUMARRAY")
|
||||
sys.argv.remove('--2e-numarray')
|
||||
elif '--2e-numpy' in sys.argv[1:]:
|
||||
sys.argv.remove('--2e-numpy')
|
||||
else:
|
||||
pass
|
||||
|
||||
if '-c' in sys.argv[1:]:
|
||||
run_compile()
|
||||
else:
|
||||
run_main(sys.argv[1:])
|
||||
264
venv/lib/python3.9/site-packages/numpy/f2py/f90mod_rules.py
Normal file
264
venv/lib/python3.9/site-packages/numpy/f2py/f90mod_rules.py
Normal file
@@ -0,0 +1,264 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
|
||||
Build F90 module support for f2py2e.
|
||||
|
||||
Copyright 2000 Pearu Peterson all rights reserved,
|
||||
Pearu Peterson <pearu@ioc.ee>
|
||||
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.
|
||||
$Date: 2005/02/03 19:30:23 $
|
||||
Pearu Peterson
|
||||
|
||||
"""
|
||||
__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)
|
||||
for m in findf90modules(pymod):
|
||||
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 (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 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*,int*,void(*)(char*,int*),int*)' % (n))
|
||||
sargsp.append('void (*)(int*,int*,void(*)(char*,int*),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]
|
||||
303
venv/lib/python3.9/site-packages/numpy/f2py/func2subr.py
Normal file
303
venv/lib/python3.9/site-packages/numpy/f2py/func2subr.py
Normal file
@@ -0,0 +1,303 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
|
||||
Rules for building C/API module with f2py2e.
|
||||
|
||||
Copyright 1999,2000 Pearu Peterson all rights reserved,
|
||||
Pearu Peterson <pearu@ioc.ee>
|
||||
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.
|
||||
$Date: 2004/11/26 11:13:06 $
|
||||
Pearu Peterson
|
||||
|
||||
"""
|
||||
import copy
|
||||
|
||||
from .auxfuncs import (
|
||||
getfortranname, isexternal, isfunction, isfunction_wrap, isintent_in,
|
||||
isintent_out, islogicalfunction, ismoduleroutine, isscalar,
|
||||
issubroutine, issubroutine_wrap, outmess, show
|
||||
)
|
||||
|
||||
|
||||
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 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
|
||||
|
||||
sargs = ', '.join(args)
|
||||
if f90mode:
|
||||
add('subroutine f2pywrap_%s_%s (%s)' %
|
||||
(rout['modulename'], name, sargs))
|
||||
if not signature:
|
||||
add('use %s, only : %s' % (rout['modulename'], fortranname))
|
||||
else:
|
||||
add('subroutine f2pywrap%s (%s)' % (name, sargs))
|
||||
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']
|
||||
|
||||
sargs = ', '.join(args)
|
||||
if f90mode:
|
||||
add('subroutine f2pywrap_%s_%s (%s)' %
|
||||
(rout['modulename'], name, sargs))
|
||||
if not signature:
|
||||
add('use %s, only : %s' % (rout['modulename'], fortranname))
|
||||
else:
|
||||
add('subroutine f2pywrap%s (%s)' % (name, sargs))
|
||||
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, ''
|
||||
1571
venv/lib/python3.9/site-packages/numpy/f2py/rules.py
Normal file
1571
venv/lib/python3.9/site-packages/numpy/f2py/rules.py
Normal file
File diff suppressed because it is too large
Load Diff
71
venv/lib/python3.9/site-packages/numpy/f2py/setup.py
Normal file
71
venv/lib/python3.9/site-packages/numpy/f2py/setup.py
Normal file
@@ -0,0 +1,71 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
setup.py for installing F2PY
|
||||
|
||||
Usage:
|
||||
pip install .
|
||||
|
||||
Copyright 2001-2005 Pearu Peterson all rights reserved,
|
||||
Pearu Peterson <pearu@cens.ioc.ee>
|
||||
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.
|
||||
$Revision: 1.32 $
|
||||
$Date: 2005/01/30 17:22:14 $
|
||||
Pearu Peterson
|
||||
|
||||
"""
|
||||
from numpy.distutils.core import setup
|
||||
from numpy.distutils.misc_util import Configuration
|
||||
|
||||
|
||||
from __version__ import version
|
||||
|
||||
|
||||
def configuration(parent_package='', top_path=None):
|
||||
config = Configuration('f2py', parent_package, top_path)
|
||||
config.add_subpackage('tests')
|
||||
config.add_data_dir('tests/src')
|
||||
config.add_data_files(
|
||||
'src/fortranobject.c',
|
||||
'src/fortranobject.h')
|
||||
config.add_data_files('*.pyi')
|
||||
return config
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
config = configuration(top_path='')
|
||||
config = config.todict()
|
||||
|
||||
config['classifiers'] = [
|
||||
'Development Status :: 5 - Production/Stable',
|
||||
'Intended Audience :: Developers',
|
||||
'Intended Audience :: Science/Research',
|
||||
'License :: OSI Approved :: NumPy License',
|
||||
'Natural Language :: English',
|
||||
'Operating System :: OS Independent',
|
||||
'Programming Language :: C',
|
||||
'Programming Language :: Fortran',
|
||||
'Programming Language :: Python',
|
||||
'Topic :: Scientific/Engineering',
|
||||
'Topic :: Software Development :: Code Generators',
|
||||
]
|
||||
setup(version=version,
|
||||
description="F2PY - Fortran to Python Interface Generator",
|
||||
author="Pearu Peterson",
|
||||
author_email="pearu@cens.ioc.ee",
|
||||
maintainer="Pearu Peterson",
|
||||
maintainer_email="pearu@cens.ioc.ee",
|
||||
license="BSD",
|
||||
platforms="Unix, Windows (mingw|cygwin), Mac OSX",
|
||||
long_description="""\
|
||||
The Fortran to Python Interface Generator, or F2PY for short, is a
|
||||
command line tool (f2py) for generating Python C/API modules for
|
||||
wrapping Fortran 77/90/95 subroutines, accessing common blocks from
|
||||
Python, and calling Python functions from Fortran (call-backs).
|
||||
Interfacing subroutines/data from Fortran 90/95 modules is supported.""",
|
||||
url="https://numpy.org/doc/stable/f2py/",
|
||||
keywords=['Fortran', 'f2py'],
|
||||
**config)
|
||||
1422
venv/lib/python3.9/site-packages/numpy/f2py/src/fortranobject.c
Normal file
1422
venv/lib/python3.9/site-packages/numpy/f2py/src/fortranobject.c
Normal file
File diff suppressed because it is too large
Load Diff
173
venv/lib/python3.9/site-packages/numpy/f2py/src/fortranobject.h
Normal file
173
venv/lib/python3.9/site-packages/numpy/f2py/src/fortranobject.h
Normal 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_DESCR(arr)->elsize >= 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_DESCR((capi_ ## var ## _as_array))->elsize)
|
||||
#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 */
|
||||
1510
venv/lib/python3.9/site-packages/numpy/f2py/symbolic.py
Normal file
1510
venv/lib/python3.9/site-packages/numpy/f2py/symbolic.py
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
@@ -0,0 +1,6 @@
|
||||
module test
|
||||
abstract interface
|
||||
subroutine foo()
|
||||
end subroutine
|
||||
end interface
|
||||
end module test
|
||||
@@ -0,0 +1,230 @@
|
||||
/*
|
||||
* 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),
|
||||
PyArray_DESCR(arr)->alignment,
|
||||
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", NPY_NTYPES);
|
||||
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
|
||||
|
||||
return m;
|
||||
}
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1 @@
|
||||
dict(real=dict(rk="double"))
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -0,0 +1,4 @@
|
||||
module precision
|
||||
integer, parameter :: rk = selected_real_kind(8)
|
||||
integer, parameter :: ik = selected_real_kind(4)
|
||||
end module
|
||||
@@ -0,0 +1,6 @@
|
||||
SUBROUTINE FOO()
|
||||
INTEGER BAR(2, 3)
|
||||
|
||||
COMMON /BLOCK/ BAR
|
||||
RETURN
|
||||
END
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -0,0 +1,3 @@
|
||||
SUBROUTINE HI
|
||||
PRINT*, "HELLO WORLD"
|
||||
END SUBROUTINE
|
||||
@@ -0,0 +1,3 @@
|
||||
function hi()
|
||||
print*, "Hello World"
|
||||
end function
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -0,0 +1,6 @@
|
||||
module foo
|
||||
type bar
|
||||
character(len = 4) :: text
|
||||
end type bar
|
||||
type(bar), parameter :: abar = bar('abar')
|
||||
end module foo
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -0,0 +1,4 @@
|
||||
subroutine foo(x)
|
||||
real(8), intent(in) :: x
|
||||
! Écrit à l'écran la valeur de x
|
||||
end subroutine
|
||||
@@ -0,0 +1 @@
|
||||
dict(real=dict(real32='float', real64='double'), integer=dict(int64='long_long'))
|
||||
@@ -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
|
||||
Cf2py intent(hide) :: n
|
||||
res = sum(x)
|
||||
end
|
||||
@@ -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
|
||||
@@ -0,0 +1,5 @@
|
||||
subroutine bar11(a)
|
||||
cf2py intent(out) a
|
||||
integer a
|
||||
a = 11
|
||||
end
|
||||
@@ -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
|
||||
@@ -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
|
||||
Binary file not shown.
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -0,0 +1,45 @@
|
||||
function t0(value)
|
||||
real value
|
||||
real t0
|
||||
t0 = value
|
||||
end
|
||||
function t4(value)
|
||||
real*4 value
|
||||
real*4 t4
|
||||
t4 = value
|
||||
end
|
||||
function t8(value)
|
||||
real*8 value
|
||||
real*8 t8
|
||||
t8 = value
|
||||
end
|
||||
function td(value)
|
||||
double precision value
|
||||
double precision td
|
||||
td = value
|
||||
end
|
||||
|
||||
subroutine s0(t0,value)
|
||||
real value
|
||||
real t0
|
||||
cf2py intent(out) t0
|
||||
t0 = value
|
||||
end
|
||||
subroutine s4(t4,value)
|
||||
real*4 value
|
||||
real*4 t4
|
||||
cf2py intent(out) t4
|
||||
t4 = value
|
||||
end
|
||||
subroutine s8(t8,value)
|
||||
real*8 value
|
||||
real*8 t8
|
||||
cf2py intent(out) t8
|
||||
t8 = value
|
||||
end
|
||||
subroutine sd(td,value)
|
||||
double precision value
|
||||
double precision td
|
||||
cf2py intent(out) td
|
||||
td = value
|
||||
end
|
||||
@@ -0,0 +1,48 @@
|
||||
module f90_return_real
|
||||
contains
|
||||
function t0(value)
|
||||
real :: value
|
||||
real :: t0
|
||||
t0 = value
|
||||
end function t0
|
||||
function t4(value)
|
||||
real(kind=4) :: value
|
||||
real(kind=4) :: t4
|
||||
t4 = value
|
||||
end function t4
|
||||
function t8(value)
|
||||
real(kind=8) :: value
|
||||
real(kind=8) :: t8
|
||||
t8 = value
|
||||
end function t8
|
||||
function td(value)
|
||||
double precision :: value
|
||||
double precision :: td
|
||||
td = value
|
||||
end function td
|
||||
|
||||
subroutine s0(t0,value)
|
||||
real :: value
|
||||
real :: t0
|
||||
!f2py intent(out) t0
|
||||
t0 = value
|
||||
end subroutine s0
|
||||
subroutine s4(t4,value)
|
||||
real(kind=4) :: value
|
||||
real(kind=4) :: t4
|
||||
!f2py intent(out) t4
|
||||
t4 = value
|
||||
end subroutine s4
|
||||
subroutine s8(t8,value)
|
||||
real(kind=8) :: value
|
||||
real(kind=8) :: t8
|
||||
!f2py intent(out) t8
|
||||
t8 = value
|
||||
end subroutine s8
|
||||
subroutine sd(td,value)
|
||||
double precision :: value
|
||||
double precision :: td
|
||||
!f2py intent(out) td
|
||||
td = value
|
||||
end subroutine sd
|
||||
end module f90_return_real
|
||||
@@ -0,0 +1,44 @@
|
||||
|
||||
subroutine foo(a, n, m, b)
|
||||
implicit none
|
||||
|
||||
real, intent(in) :: a(n, m)
|
||||
integer, intent(in) :: n, m
|
||||
real, intent(out) :: b(size(a, 1))
|
||||
|
||||
integer :: i
|
||||
|
||||
do i = 1, size(b)
|
||||
b(i) = sum(a(i,:))
|
||||
enddo
|
||||
end subroutine
|
||||
|
||||
subroutine trans(x,y)
|
||||
implicit none
|
||||
real, intent(in), dimension(:,:) :: x
|
||||
real, intent(out), dimension( size(x,2), size(x,1) ) :: y
|
||||
integer :: N, M, i, j
|
||||
N = size(x,1)
|
||||
M = size(x,2)
|
||||
DO i=1,N
|
||||
do j=1,M
|
||||
y(j,i) = x(i,j)
|
||||
END DO
|
||||
END DO
|
||||
end subroutine trans
|
||||
|
||||
subroutine flatten(x,y)
|
||||
implicit none
|
||||
real, intent(in), dimension(:,:) :: x
|
||||
real, intent(out), dimension( size(x) ) :: y
|
||||
integer :: N, M, i, j, k
|
||||
N = size(x,1)
|
||||
M = size(x,2)
|
||||
k = 1
|
||||
DO i=1,N
|
||||
do j=1,M
|
||||
y(k) = x(i,j)
|
||||
k = k + 1
|
||||
END DO
|
||||
END DO
|
||||
end subroutine flatten
|
||||
@@ -0,0 +1,29 @@
|
||||
MODULE char_test
|
||||
|
||||
CONTAINS
|
||||
|
||||
SUBROUTINE change_strings(strings, n_strs, out_strings)
|
||||
IMPLICIT NONE
|
||||
|
||||
! Inputs
|
||||
INTEGER, INTENT(IN) :: n_strs
|
||||
CHARACTER, INTENT(IN), DIMENSION(2,n_strs) :: strings
|
||||
CHARACTER, INTENT(OUT), DIMENSION(2,n_strs) :: out_strings
|
||||
|
||||
!f2py INTEGER, INTENT(IN) :: n_strs
|
||||
!f2py CHARACTER, INTENT(IN), DIMENSION(2,n_strs) :: strings
|
||||
!f2py CHARACTER, INTENT(OUT), DIMENSION(2,n_strs) :: strings
|
||||
|
||||
! Misc.
|
||||
INTEGER*4 :: j
|
||||
|
||||
|
||||
DO j=1, n_strs
|
||||
out_strings(1,j) = strings(1,j)
|
||||
out_strings(2,j) = 'A'
|
||||
END DO
|
||||
|
||||
END SUBROUTINE change_strings
|
||||
|
||||
END MODULE char_test
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
function sint(s) result(i)
|
||||
implicit none
|
||||
character(len=*) :: s
|
||||
integer :: j, i
|
||||
i = 0
|
||||
do j=len(s), 1, -1
|
||||
if (.not.((i.eq.0).and.(s(j:j).eq.' '))) then
|
||||
i = i + ichar(s(j:j)) * 10 ** (j - 1)
|
||||
endif
|
||||
end do
|
||||
return
|
||||
end function sint
|
||||
|
||||
function test_in_bytes4(a) result (i)
|
||||
implicit none
|
||||
integer :: sint
|
||||
character(len=4) :: a
|
||||
integer :: i
|
||||
i = sint(a)
|
||||
a(1:1) = 'A'
|
||||
return
|
||||
end function test_in_bytes4
|
||||
|
||||
function test_inout_bytes4(a) result (i)
|
||||
implicit none
|
||||
integer :: sint
|
||||
character(len=4), intent(inout) :: a
|
||||
integer :: i
|
||||
if (a(1:1).ne.' ') then
|
||||
a(1:1) = 'E'
|
||||
endif
|
||||
i = sint(a)
|
||||
return
|
||||
end function test_inout_bytes4
|
||||
@@ -0,0 +1,9 @@
|
||||
MODULE string_test
|
||||
|
||||
character(len=8) :: string
|
||||
character string77 * 8
|
||||
|
||||
character(len=12), dimension(5,7) :: strarr
|
||||
character strarr77(5,7) * 12
|
||||
|
||||
END MODULE string_test
|
||||
@@ -0,0 +1,12 @@
|
||||
C FILE: STRING.F
|
||||
SUBROUTINE FOO(A,B,C,D)
|
||||
CHARACTER*5 A, B
|
||||
CHARACTER*(*) C,D
|
||||
Cf2py intent(in) a,c
|
||||
Cf2py intent(inout) b,d
|
||||
A(1:1) = 'A'
|
||||
B(1:1) = 'B'
|
||||
C(1:1) = 'C'
|
||||
D(1:1) = 'D'
|
||||
END
|
||||
C END OF FILE STRING.F
|
||||
@@ -0,0 +1,9 @@
|
||||
module fortfuncs
|
||||
implicit none
|
||||
contains
|
||||
subroutine square(x,y)
|
||||
integer, intent(in), value :: x
|
||||
integer, intent(out) :: y
|
||||
y = x*x
|
||||
end subroutine square
|
||||
end module fortfuncs
|
||||
@@ -0,0 +1,25 @@
|
||||
from pathlib import Path
|
||||
import pytest
|
||||
import textwrap
|
||||
from . import util
|
||||
from numpy.f2py import crackfortran
|
||||
from numpy.testing import IS_WASM
|
||||
|
||||
|
||||
@pytest.mark.skipif(IS_WASM, reason="Cannot start subprocess")
|
||||
class TestAbstractInterface(util.F2PyTest):
|
||||
sources = [util.getpath("tests", "src", "abstract_interface", "foo.f90")]
|
||||
|
||||
skip = ["add1", "add2"]
|
||||
|
||||
def test_abstract_interface(self):
|
||||
assert self.module.ops_module.foo(3, 5) == (8, 13)
|
||||
|
||||
def test_parse_abstract_interface(self):
|
||||
# Test gh18403
|
||||
fpath = util.getpath("tests", "src", "abstract_interface",
|
||||
"gh18403_mod.f90")
|
||||
mod = crackfortran.crackfortran([str(fpath)])
|
||||
assert len(mod) == 1
|
||||
assert len(mod[0]["body"]) == 1
|
||||
assert mod[0]["body"][0]["block"] == "abstract interface"
|
||||
@@ -0,0 +1,686 @@
|
||||
import os
|
||||
import sys
|
||||
import copy
|
||||
import platform
|
||||
import pytest
|
||||
|
||||
import numpy as np
|
||||
|
||||
from numpy.testing import assert_, assert_equal
|
||||
from numpy.core.multiarray import typeinfo as _typeinfo
|
||||
from . import util
|
||||
|
||||
wrap = None
|
||||
|
||||
# Extend core typeinfo with CHARACTER to test dtype('c')
|
||||
_ti = _typeinfo['STRING']
|
||||
typeinfo = dict(
|
||||
CHARACTER=type(_ti)(('c', _ti.num, 8, _ti.alignment, _ti.type)),
|
||||
**_typeinfo)
|
||||
|
||||
|
||||
def setup_module():
|
||||
"""
|
||||
Build the required testing extension module
|
||||
|
||||
"""
|
||||
global wrap
|
||||
|
||||
# Check compiler availability first
|
||||
if not util.has_c_compiler():
|
||||
pytest.skip("No C compiler available")
|
||||
|
||||
if wrap is None:
|
||||
config_code = """
|
||||
config.add_extension('test_array_from_pyobj_ext',
|
||||
sources=['wrapmodule.c', 'fortranobject.c'],
|
||||
define_macros=[])
|
||||
"""
|
||||
d = os.path.dirname(__file__)
|
||||
src = [
|
||||
util.getpath("tests", "src", "array_from_pyobj", "wrapmodule.c"),
|
||||
util.getpath("src", "fortranobject.c"),
|
||||
util.getpath("src", "fortranobject.h"),
|
||||
]
|
||||
wrap = util.build_module_distutils(src, config_code,
|
||||
"test_array_from_pyobj_ext")
|
||||
|
||||
|
||||
def flags_info(arr):
|
||||
flags = wrap.array_attrs(arr)[6]
|
||||
return flags2names(flags)
|
||||
|
||||
|
||||
def flags2names(flags):
|
||||
info = []
|
||||
for flagname in [
|
||||
"CONTIGUOUS",
|
||||
"FORTRAN",
|
||||
"OWNDATA",
|
||||
"ENSURECOPY",
|
||||
"ENSUREARRAY",
|
||||
"ALIGNED",
|
||||
"NOTSWAPPED",
|
||||
"WRITEABLE",
|
||||
"WRITEBACKIFCOPY",
|
||||
"UPDATEIFCOPY",
|
||||
"BEHAVED",
|
||||
"BEHAVED_RO",
|
||||
"CARRAY",
|
||||
"FARRAY",
|
||||
]:
|
||||
if abs(flags) & getattr(wrap, flagname, 0):
|
||||
info.append(flagname)
|
||||
return info
|
||||
|
||||
|
||||
class Intent:
|
||||
def __init__(self, intent_list=[]):
|
||||
self.intent_list = intent_list[:]
|
||||
flags = 0
|
||||
for i in intent_list:
|
||||
if i == "optional":
|
||||
flags |= wrap.F2PY_OPTIONAL
|
||||
else:
|
||||
flags |= getattr(wrap, "F2PY_INTENT_" + i.upper())
|
||||
self.flags = flags
|
||||
|
||||
def __getattr__(self, name):
|
||||
name = name.lower()
|
||||
if name == "in_":
|
||||
name = "in"
|
||||
return self.__class__(self.intent_list + [name])
|
||||
|
||||
def __str__(self):
|
||||
return "intent(%s)" % (",".join(self.intent_list))
|
||||
|
||||
def __repr__(self):
|
||||
return "Intent(%r)" % (self.intent_list)
|
||||
|
||||
def is_intent(self, *names):
|
||||
for name in names:
|
||||
if name not in self.intent_list:
|
||||
return False
|
||||
return True
|
||||
|
||||
def is_intent_exact(self, *names):
|
||||
return len(self.intent_list) == len(names) and self.is_intent(*names)
|
||||
|
||||
|
||||
intent = Intent()
|
||||
|
||||
_type_names = [
|
||||
"BOOL",
|
||||
"BYTE",
|
||||
"UBYTE",
|
||||
"SHORT",
|
||||
"USHORT",
|
||||
"INT",
|
||||
"UINT",
|
||||
"LONG",
|
||||
"ULONG",
|
||||
"LONGLONG",
|
||||
"ULONGLONG",
|
||||
"FLOAT",
|
||||
"DOUBLE",
|
||||
"CFLOAT",
|
||||
"STRING1",
|
||||
"STRING5",
|
||||
"CHARACTER",
|
||||
]
|
||||
|
||||
_cast_dict = {"BOOL": ["BOOL"]}
|
||||
_cast_dict["BYTE"] = _cast_dict["BOOL"] + ["BYTE"]
|
||||
_cast_dict["UBYTE"] = _cast_dict["BOOL"] + ["UBYTE"]
|
||||
_cast_dict["BYTE"] = ["BYTE"]
|
||||
_cast_dict["UBYTE"] = ["UBYTE"]
|
||||
_cast_dict["SHORT"] = _cast_dict["BYTE"] + ["UBYTE", "SHORT"]
|
||||
_cast_dict["USHORT"] = _cast_dict["UBYTE"] + ["BYTE", "USHORT"]
|
||||
_cast_dict["INT"] = _cast_dict["SHORT"] + ["USHORT", "INT"]
|
||||
_cast_dict["UINT"] = _cast_dict["USHORT"] + ["SHORT", "UINT"]
|
||||
|
||||
_cast_dict["LONG"] = _cast_dict["INT"] + ["LONG"]
|
||||
_cast_dict["ULONG"] = _cast_dict["UINT"] + ["ULONG"]
|
||||
|
||||
_cast_dict["LONGLONG"] = _cast_dict["LONG"] + ["LONGLONG"]
|
||||
_cast_dict["ULONGLONG"] = _cast_dict["ULONG"] + ["ULONGLONG"]
|
||||
|
||||
_cast_dict["FLOAT"] = _cast_dict["SHORT"] + ["USHORT", "FLOAT"]
|
||||
_cast_dict["DOUBLE"] = _cast_dict["INT"] + ["UINT", "FLOAT", "DOUBLE"]
|
||||
|
||||
_cast_dict["CFLOAT"] = _cast_dict["FLOAT"] + ["CFLOAT"]
|
||||
|
||||
_cast_dict['STRING1'] = ['STRING1']
|
||||
_cast_dict['STRING5'] = ['STRING5']
|
||||
_cast_dict['CHARACTER'] = ['CHARACTER']
|
||||
|
||||
# 32 bit system malloc typically does not provide the alignment required by
|
||||
# 16 byte long double types this means the inout intent cannot be satisfied
|
||||
# and several tests fail as the alignment flag can be randomly true or fals
|
||||
# when numpy gains an aligned allocator the tests could be enabled again
|
||||
#
|
||||
# Furthermore, on macOS ARM64, LONGDOUBLE is an alias for DOUBLE.
|
||||
if ((np.intp().dtype.itemsize != 4 or np.clongdouble().dtype.alignment <= 8)
|
||||
and sys.platform != "win32"
|
||||
and (platform.system(), platform.processor()) != ("Darwin", "arm")):
|
||||
_type_names.extend(["LONGDOUBLE", "CDOUBLE", "CLONGDOUBLE"])
|
||||
_cast_dict["LONGDOUBLE"] = _cast_dict["LONG"] + [
|
||||
"ULONG",
|
||||
"FLOAT",
|
||||
"DOUBLE",
|
||||
"LONGDOUBLE",
|
||||
]
|
||||
_cast_dict["CLONGDOUBLE"] = _cast_dict["LONGDOUBLE"] + [
|
||||
"CFLOAT",
|
||||
"CDOUBLE",
|
||||
"CLONGDOUBLE",
|
||||
]
|
||||
_cast_dict["CDOUBLE"] = _cast_dict["DOUBLE"] + ["CFLOAT", "CDOUBLE"]
|
||||
|
||||
|
||||
class Type:
|
||||
_type_cache = {}
|
||||
|
||||
def __new__(cls, name):
|
||||
if isinstance(name, np.dtype):
|
||||
dtype0 = name
|
||||
name = None
|
||||
for n, i in typeinfo.items():
|
||||
if not isinstance(i, type) and dtype0.type is i.type:
|
||||
name = n
|
||||
break
|
||||
obj = cls._type_cache.get(name.upper(), None)
|
||||
if obj is not None:
|
||||
return obj
|
||||
obj = object.__new__(cls)
|
||||
obj._init(name)
|
||||
cls._type_cache[name.upper()] = obj
|
||||
return obj
|
||||
|
||||
def _init(self, name):
|
||||
self.NAME = name.upper()
|
||||
|
||||
if self.NAME == 'CHARACTER':
|
||||
info = typeinfo[self.NAME]
|
||||
self.type_num = getattr(wrap, 'NPY_STRING')
|
||||
self.elsize = 1
|
||||
self.dtype = np.dtype('c')
|
||||
elif self.NAME.startswith('STRING'):
|
||||
info = typeinfo[self.NAME[:6]]
|
||||
self.type_num = getattr(wrap, 'NPY_STRING')
|
||||
self.elsize = int(self.NAME[6:] or 0)
|
||||
self.dtype = np.dtype(f'S{self.elsize}')
|
||||
else:
|
||||
info = typeinfo[self.NAME]
|
||||
self.type_num = getattr(wrap, 'NPY_' + self.NAME)
|
||||
self.elsize = info.bits // 8
|
||||
self.dtype = np.dtype(info.type)
|
||||
|
||||
assert self.type_num == info.num
|
||||
self.type = info.type
|
||||
self.dtypechar = info.char
|
||||
|
||||
def __repr__(self):
|
||||
return (f"Type({self.NAME})|type_num={self.type_num},"
|
||||
f" dtype={self.dtype},"
|
||||
f" type={self.type}, elsize={self.elsize},"
|
||||
f" dtypechar={self.dtypechar}")
|
||||
|
||||
def cast_types(self):
|
||||
return [self.__class__(_m) for _m in _cast_dict[self.NAME]]
|
||||
|
||||
def all_types(self):
|
||||
return [self.__class__(_m) for _m in _type_names]
|
||||
|
||||
def smaller_types(self):
|
||||
bits = typeinfo[self.NAME].alignment
|
||||
types = []
|
||||
for name in _type_names:
|
||||
if typeinfo[name].alignment < bits:
|
||||
types.append(Type(name))
|
||||
return types
|
||||
|
||||
def equal_types(self):
|
||||
bits = typeinfo[self.NAME].alignment
|
||||
types = []
|
||||
for name in _type_names:
|
||||
if name == self.NAME:
|
||||
continue
|
||||
if typeinfo[name].alignment == bits:
|
||||
types.append(Type(name))
|
||||
return types
|
||||
|
||||
def larger_types(self):
|
||||
bits = typeinfo[self.NAME].alignment
|
||||
types = []
|
||||
for name in _type_names:
|
||||
if typeinfo[name].alignment > bits:
|
||||
types.append(Type(name))
|
||||
return types
|
||||
|
||||
|
||||
class Array:
|
||||
|
||||
def __repr__(self):
|
||||
return (f'Array({self.type}, {self.dims}, {self.intent},'
|
||||
f' {self.obj})|arr={self.arr}')
|
||||
|
||||
def __init__(self, typ, dims, intent, obj):
|
||||
self.type = typ
|
||||
self.dims = dims
|
||||
self.intent = intent
|
||||
self.obj_copy = copy.deepcopy(obj)
|
||||
self.obj = obj
|
||||
|
||||
# arr.dtypechar may be different from typ.dtypechar
|
||||
self.arr = wrap.call(typ.type_num,
|
||||
typ.elsize,
|
||||
dims, intent.flags, obj)
|
||||
|
||||
assert isinstance(self.arr, np.ndarray)
|
||||
|
||||
self.arr_attr = wrap.array_attrs(self.arr)
|
||||
|
||||
if len(dims) > 1:
|
||||
if self.intent.is_intent("c"):
|
||||
assert (intent.flags & wrap.F2PY_INTENT_C)
|
||||
assert not self.arr.flags["FORTRAN"]
|
||||
assert self.arr.flags["CONTIGUOUS"]
|
||||
assert (not self.arr_attr[6] & wrap.FORTRAN)
|
||||
else:
|
||||
assert (not intent.flags & wrap.F2PY_INTENT_C)
|
||||
assert self.arr.flags["FORTRAN"]
|
||||
assert not self.arr.flags["CONTIGUOUS"]
|
||||
assert (self.arr_attr[6] & wrap.FORTRAN)
|
||||
|
||||
if obj is None:
|
||||
self.pyarr = None
|
||||
self.pyarr_attr = None
|
||||
return
|
||||
|
||||
if intent.is_intent("cache"):
|
||||
assert isinstance(obj, np.ndarray), repr(type(obj))
|
||||
self.pyarr = np.array(obj).reshape(*dims).copy()
|
||||
else:
|
||||
self.pyarr = np.array(
|
||||
np.array(obj, dtype=typ.dtypechar).reshape(*dims),
|
||||
order=self.intent.is_intent("c") and "C" or "F",
|
||||
)
|
||||
assert self.pyarr.dtype == typ
|
||||
self.pyarr.setflags(write=self.arr.flags["WRITEABLE"])
|
||||
assert self.pyarr.flags["OWNDATA"], (obj, intent)
|
||||
self.pyarr_attr = wrap.array_attrs(self.pyarr)
|
||||
|
||||
if len(dims) > 1:
|
||||
if self.intent.is_intent("c"):
|
||||
assert not self.pyarr.flags["FORTRAN"]
|
||||
assert self.pyarr.flags["CONTIGUOUS"]
|
||||
assert (not self.pyarr_attr[6] & wrap.FORTRAN)
|
||||
else:
|
||||
assert self.pyarr.flags["FORTRAN"]
|
||||
assert not self.pyarr.flags["CONTIGUOUS"]
|
||||
assert (self.pyarr_attr[6] & wrap.FORTRAN)
|
||||
|
||||
assert self.arr_attr[1] == self.pyarr_attr[1] # nd
|
||||
assert self.arr_attr[2] == self.pyarr_attr[2] # dimensions
|
||||
if self.arr_attr[1] <= 1:
|
||||
assert self.arr_attr[3] == self.pyarr_attr[3], repr((
|
||||
self.arr_attr[3],
|
||||
self.pyarr_attr[3],
|
||||
self.arr.tobytes(),
|
||||
self.pyarr.tobytes(),
|
||||
)) # strides
|
||||
assert self.arr_attr[5][-2:] == self.pyarr_attr[5][-2:], repr((
|
||||
self.arr_attr[5], self.pyarr_attr[5]
|
||||
)) # descr
|
||||
assert self.arr_attr[6] == self.pyarr_attr[6], repr((
|
||||
self.arr_attr[6],
|
||||
self.pyarr_attr[6],
|
||||
flags2names(0 * self.arr_attr[6] - self.pyarr_attr[6]),
|
||||
flags2names(self.arr_attr[6]),
|
||||
intent,
|
||||
)) # flags
|
||||
|
||||
if intent.is_intent("cache"):
|
||||
assert self.arr_attr[5][3] >= self.type.elsize
|
||||
else:
|
||||
assert self.arr_attr[5][3] == self.type.elsize
|
||||
assert (self.arr_equal(self.pyarr, self.arr))
|
||||
|
||||
if isinstance(self.obj, np.ndarray):
|
||||
if typ.elsize == Type(obj.dtype).elsize:
|
||||
if not intent.is_intent("copy") and self.arr_attr[1] <= 1:
|
||||
assert self.has_shared_memory()
|
||||
|
||||
def arr_equal(self, arr1, arr2):
|
||||
if arr1.shape != arr2.shape:
|
||||
return False
|
||||
return (arr1 == arr2).all()
|
||||
|
||||
def __str__(self):
|
||||
return str(self.arr)
|
||||
|
||||
def has_shared_memory(self):
|
||||
"""Check that created array shares data with input array."""
|
||||
if self.obj is self.arr:
|
||||
return True
|
||||
if not isinstance(self.obj, np.ndarray):
|
||||
return False
|
||||
obj_attr = wrap.array_attrs(self.obj)
|
||||
return obj_attr[0] == self.arr_attr[0]
|
||||
|
||||
|
||||
class TestIntent:
|
||||
def test_in_out(self):
|
||||
assert str(intent.in_.out) == "intent(in,out)"
|
||||
assert intent.in_.c.is_intent("c")
|
||||
assert not intent.in_.c.is_intent_exact("c")
|
||||
assert intent.in_.c.is_intent_exact("c", "in")
|
||||
assert intent.in_.c.is_intent_exact("in", "c")
|
||||
assert not intent.in_.is_intent("c")
|
||||
|
||||
|
||||
class TestSharedMemory:
|
||||
|
||||
@pytest.fixture(autouse=True, scope="class", params=_type_names)
|
||||
def setup_type(self, request):
|
||||
request.cls.type = Type(request.param)
|
||||
request.cls.array = lambda self, dims, intent, obj: Array(
|
||||
Type(request.param), dims, intent, obj)
|
||||
|
||||
@property
|
||||
def num2seq(self):
|
||||
if self.type.NAME.startswith('STRING'):
|
||||
elsize = self.type.elsize
|
||||
return ['1' * elsize, '2' * elsize]
|
||||
return [1, 2]
|
||||
|
||||
@property
|
||||
def num23seq(self):
|
||||
if self.type.NAME.startswith('STRING'):
|
||||
elsize = self.type.elsize
|
||||
return [['1' * elsize, '2' * elsize, '3' * elsize],
|
||||
['4' * elsize, '5' * elsize, '6' * elsize]]
|
||||
return [[1, 2, 3], [4, 5, 6]]
|
||||
|
||||
def test_in_from_2seq(self):
|
||||
a = self.array([2], intent.in_, self.num2seq)
|
||||
assert not a.has_shared_memory()
|
||||
|
||||
def test_in_from_2casttype(self):
|
||||
for t in self.type.cast_types():
|
||||
obj = np.array(self.num2seq, dtype=t.dtype)
|
||||
a = self.array([len(self.num2seq)], intent.in_, obj)
|
||||
if t.elsize == self.type.elsize:
|
||||
assert a.has_shared_memory(), repr((self.type.dtype, t.dtype))
|
||||
else:
|
||||
assert not a.has_shared_memory()
|
||||
|
||||
@pytest.mark.parametrize("write", ["w", "ro"])
|
||||
@pytest.mark.parametrize("order", ["C", "F"])
|
||||
@pytest.mark.parametrize("inp", ["2seq", "23seq"])
|
||||
def test_in_nocopy(self, write, order, inp):
|
||||
"""Test if intent(in) array can be passed without copies"""
|
||||
seq = getattr(self, "num" + inp)
|
||||
obj = np.array(seq, dtype=self.type.dtype, order=order)
|
||||
obj.setflags(write=(write == 'w'))
|
||||
a = self.array(obj.shape,
|
||||
((order == 'C' and intent.in_.c) or intent.in_), obj)
|
||||
assert a.has_shared_memory()
|
||||
|
||||
def test_inout_2seq(self):
|
||||
obj = np.array(self.num2seq, dtype=self.type.dtype)
|
||||
a = self.array([len(self.num2seq)], intent.inout, obj)
|
||||
assert a.has_shared_memory()
|
||||
|
||||
try:
|
||||
a = self.array([2], intent.in_.inout, self.num2seq)
|
||||
except TypeError as msg:
|
||||
if not str(msg).startswith(
|
||||
"failed to initialize intent(inout|inplace|cache) array"):
|
||||
raise
|
||||
else:
|
||||
raise SystemError("intent(inout) should have failed on sequence")
|
||||
|
||||
def test_f_inout_23seq(self):
|
||||
obj = np.array(self.num23seq, dtype=self.type.dtype, order="F")
|
||||
shape = (len(self.num23seq), len(self.num23seq[0]))
|
||||
a = self.array(shape, intent.in_.inout, obj)
|
||||
assert a.has_shared_memory()
|
||||
|
||||
obj = np.array(self.num23seq, dtype=self.type.dtype, order="C")
|
||||
shape = (len(self.num23seq), len(self.num23seq[0]))
|
||||
try:
|
||||
a = self.array(shape, intent.in_.inout, obj)
|
||||
except ValueError as msg:
|
||||
if not str(msg).startswith(
|
||||
"failed to initialize intent(inout) array"):
|
||||
raise
|
||||
else:
|
||||
raise SystemError(
|
||||
"intent(inout) should have failed on improper array")
|
||||
|
||||
def test_c_inout_23seq(self):
|
||||
obj = np.array(self.num23seq, dtype=self.type.dtype)
|
||||
shape = (len(self.num23seq), len(self.num23seq[0]))
|
||||
a = self.array(shape, intent.in_.c.inout, obj)
|
||||
assert a.has_shared_memory()
|
||||
|
||||
def test_in_copy_from_2casttype(self):
|
||||
for t in self.type.cast_types():
|
||||
obj = np.array(self.num2seq, dtype=t.dtype)
|
||||
a = self.array([len(self.num2seq)], intent.in_.copy, obj)
|
||||
assert not a.has_shared_memory()
|
||||
|
||||
def test_c_in_from_23seq(self):
|
||||
a = self.array(
|
||||
[len(self.num23seq), len(self.num23seq[0])], intent.in_,
|
||||
self.num23seq)
|
||||
assert not a.has_shared_memory()
|
||||
|
||||
def test_in_from_23casttype(self):
|
||||
for t in self.type.cast_types():
|
||||
obj = np.array(self.num23seq, dtype=t.dtype)
|
||||
a = self.array(
|
||||
[len(self.num23seq), len(self.num23seq[0])], intent.in_, obj)
|
||||
assert not a.has_shared_memory()
|
||||
|
||||
def test_f_in_from_23casttype(self):
|
||||
for t in self.type.cast_types():
|
||||
obj = np.array(self.num23seq, dtype=t.dtype, order="F")
|
||||
a = self.array(
|
||||
[len(self.num23seq), len(self.num23seq[0])], intent.in_, obj)
|
||||
if t.elsize == self.type.elsize:
|
||||
assert a.has_shared_memory()
|
||||
else:
|
||||
assert not a.has_shared_memory()
|
||||
|
||||
def test_c_in_from_23casttype(self):
|
||||
for t in self.type.cast_types():
|
||||
obj = np.array(self.num23seq, dtype=t.dtype)
|
||||
a = self.array(
|
||||
[len(self.num23seq), len(self.num23seq[0])], intent.in_.c, obj)
|
||||
if t.elsize == self.type.elsize:
|
||||
assert a.has_shared_memory()
|
||||
else:
|
||||
assert not a.has_shared_memory()
|
||||
|
||||
def test_f_copy_in_from_23casttype(self):
|
||||
for t in self.type.cast_types():
|
||||
obj = np.array(self.num23seq, dtype=t.dtype, order="F")
|
||||
a = self.array(
|
||||
[len(self.num23seq), len(self.num23seq[0])], intent.in_.copy,
|
||||
obj)
|
||||
assert not a.has_shared_memory()
|
||||
|
||||
def test_c_copy_in_from_23casttype(self):
|
||||
for t in self.type.cast_types():
|
||||
obj = np.array(self.num23seq, dtype=t.dtype)
|
||||
a = self.array(
|
||||
[len(self.num23seq), len(self.num23seq[0])], intent.in_.c.copy,
|
||||
obj)
|
||||
assert not a.has_shared_memory()
|
||||
|
||||
def test_in_cache_from_2casttype(self):
|
||||
for t in self.type.all_types():
|
||||
if t.elsize != self.type.elsize:
|
||||
continue
|
||||
obj = np.array(self.num2seq, dtype=t.dtype)
|
||||
shape = (len(self.num2seq), )
|
||||
a = self.array(shape, intent.in_.c.cache, obj)
|
||||
assert a.has_shared_memory()
|
||||
|
||||
a = self.array(shape, intent.in_.cache, obj)
|
||||
assert a.has_shared_memory()
|
||||
|
||||
obj = np.array(self.num2seq, dtype=t.dtype, order="F")
|
||||
a = self.array(shape, intent.in_.c.cache, obj)
|
||||
assert a.has_shared_memory()
|
||||
|
||||
a = self.array(shape, intent.in_.cache, obj)
|
||||
assert a.has_shared_memory(), repr(t.dtype)
|
||||
|
||||
try:
|
||||
a = self.array(shape, intent.in_.cache, obj[::-1])
|
||||
except ValueError as msg:
|
||||
if not str(msg).startswith(
|
||||
"failed to initialize intent(cache) array"):
|
||||
raise
|
||||
else:
|
||||
raise SystemError(
|
||||
"intent(cache) should have failed on multisegmented array")
|
||||
|
||||
def test_in_cache_from_2casttype_failure(self):
|
||||
for t in self.type.all_types():
|
||||
if t.NAME == 'STRING':
|
||||
# string elsize is 0, so skipping the test
|
||||
continue
|
||||
if t.elsize >= self.type.elsize:
|
||||
continue
|
||||
obj = np.array(self.num2seq, dtype=t.dtype)
|
||||
shape = (len(self.num2seq), )
|
||||
try:
|
||||
self.array(shape, intent.in_.cache, obj) # Should succeed
|
||||
except ValueError as msg:
|
||||
if not str(msg).startswith(
|
||||
"failed to initialize intent(cache) array"):
|
||||
raise
|
||||
else:
|
||||
raise SystemError(
|
||||
"intent(cache) should have failed on smaller array")
|
||||
|
||||
def test_cache_hidden(self):
|
||||
shape = (2, )
|
||||
a = self.array(shape, intent.cache.hide, None)
|
||||
assert a.arr.shape == shape
|
||||
|
||||
shape = (2, 3)
|
||||
a = self.array(shape, intent.cache.hide, None)
|
||||
assert a.arr.shape == shape
|
||||
|
||||
shape = (-1, 3)
|
||||
try:
|
||||
a = self.array(shape, intent.cache.hide, None)
|
||||
except ValueError as msg:
|
||||
if not str(msg).startswith(
|
||||
"failed to create intent(cache|hide)|optional array"):
|
||||
raise
|
||||
else:
|
||||
raise SystemError(
|
||||
"intent(cache) should have failed on undefined dimensions")
|
||||
|
||||
def test_hidden(self):
|
||||
shape = (2, )
|
||||
a = self.array(shape, intent.hide, None)
|
||||
assert a.arr.shape == shape
|
||||
assert a.arr_equal(a.arr, np.zeros(shape, dtype=self.type.dtype))
|
||||
|
||||
shape = (2, 3)
|
||||
a = self.array(shape, intent.hide, None)
|
||||
assert a.arr.shape == shape
|
||||
assert a.arr_equal(a.arr, np.zeros(shape, dtype=self.type.dtype))
|
||||
assert a.arr.flags["FORTRAN"] and not a.arr.flags["CONTIGUOUS"]
|
||||
|
||||
shape = (2, 3)
|
||||
a = self.array(shape, intent.c.hide, None)
|
||||
assert a.arr.shape == shape
|
||||
assert a.arr_equal(a.arr, np.zeros(shape, dtype=self.type.dtype))
|
||||
assert not a.arr.flags["FORTRAN"] and a.arr.flags["CONTIGUOUS"]
|
||||
|
||||
shape = (-1, 3)
|
||||
try:
|
||||
a = self.array(shape, intent.hide, None)
|
||||
except ValueError as msg:
|
||||
if not str(msg).startswith(
|
||||
"failed to create intent(cache|hide)|optional array"):
|
||||
raise
|
||||
else:
|
||||
raise SystemError(
|
||||
"intent(hide) should have failed on undefined dimensions")
|
||||
|
||||
def test_optional_none(self):
|
||||
shape = (2, )
|
||||
a = self.array(shape, intent.optional, None)
|
||||
assert a.arr.shape == shape
|
||||
assert a.arr_equal(a.arr, np.zeros(shape, dtype=self.type.dtype))
|
||||
|
||||
shape = (2, 3)
|
||||
a = self.array(shape, intent.optional, None)
|
||||
assert a.arr.shape == shape
|
||||
assert a.arr_equal(a.arr, np.zeros(shape, dtype=self.type.dtype))
|
||||
assert a.arr.flags["FORTRAN"] and not a.arr.flags["CONTIGUOUS"]
|
||||
|
||||
shape = (2, 3)
|
||||
a = self.array(shape, intent.c.optional, None)
|
||||
assert a.arr.shape == shape
|
||||
assert a.arr_equal(a.arr, np.zeros(shape, dtype=self.type.dtype))
|
||||
assert not a.arr.flags["FORTRAN"] and a.arr.flags["CONTIGUOUS"]
|
||||
|
||||
def test_optional_from_2seq(self):
|
||||
obj = self.num2seq
|
||||
shape = (len(obj), )
|
||||
a = self.array(shape, intent.optional, obj)
|
||||
assert a.arr.shape == shape
|
||||
assert not a.has_shared_memory()
|
||||
|
||||
def test_optional_from_23seq(self):
|
||||
obj = self.num23seq
|
||||
shape = (len(obj), len(obj[0]))
|
||||
a = self.array(shape, intent.optional, obj)
|
||||
assert a.arr.shape == shape
|
||||
assert not a.has_shared_memory()
|
||||
|
||||
a = self.array(shape, intent.optional.c, obj)
|
||||
assert a.arr.shape == shape
|
||||
assert not a.has_shared_memory()
|
||||
|
||||
def test_inplace(self):
|
||||
obj = np.array(self.num23seq, dtype=self.type.dtype)
|
||||
assert not obj.flags["FORTRAN"] and obj.flags["CONTIGUOUS"]
|
||||
shape = obj.shape
|
||||
a = self.array(shape, intent.inplace, obj)
|
||||
assert obj[1][2] == a.arr[1][2], repr((obj, a.arr))
|
||||
a.arr[1][2] = 54
|
||||
assert obj[1][2] == a.arr[1][2] == np.array(54, dtype=self.type.dtype)
|
||||
assert a.arr is obj
|
||||
assert obj.flags["FORTRAN"] # obj attributes are changed inplace!
|
||||
assert not obj.flags["CONTIGUOUS"]
|
||||
|
||||
def test_inplace_from_casttype(self):
|
||||
for t in self.type.cast_types():
|
||||
if t is self.type:
|
||||
continue
|
||||
obj = np.array(self.num23seq, dtype=t.dtype)
|
||||
assert obj.dtype.type == t.type
|
||||
assert obj.dtype.type is not self.type.type
|
||||
assert not obj.flags["FORTRAN"] and obj.flags["CONTIGUOUS"]
|
||||
shape = obj.shape
|
||||
a = self.array(shape, intent.inplace, obj)
|
||||
assert obj[1][2] == a.arr[1][2], repr((obj, a.arr))
|
||||
a.arr[1][2] = 54
|
||||
assert obj[1][2] == a.arr[1][2] == np.array(54,
|
||||
dtype=self.type.dtype)
|
||||
assert a.arr is obj
|
||||
assert obj.flags["FORTRAN"] # obj attributes changed inplace!
|
||||
assert not obj.flags["CONTIGUOUS"]
|
||||
assert obj.dtype.type is self.type.type # obj changed inplace!
|
||||
@@ -0,0 +1,49 @@
|
||||
import os
|
||||
import pytest
|
||||
import tempfile
|
||||
|
||||
from . import util
|
||||
|
||||
|
||||
class TestAssumedShapeSumExample(util.F2PyTest):
|
||||
sources = [
|
||||
util.getpath("tests", "src", "assumed_shape", "foo_free.f90"),
|
||||
util.getpath("tests", "src", "assumed_shape", "foo_use.f90"),
|
||||
util.getpath("tests", "src", "assumed_shape", "precision.f90"),
|
||||
util.getpath("tests", "src", "assumed_shape", "foo_mod.f90"),
|
||||
util.getpath("tests", "src", "assumed_shape", ".f2py_f2cmap"),
|
||||
]
|
||||
|
||||
@pytest.mark.slow
|
||||
def test_all(self):
|
||||
r = self.module.fsum([1, 2])
|
||||
assert r == 3
|
||||
r = self.module.sum([1, 2])
|
||||
assert r == 3
|
||||
r = self.module.sum_with_use([1, 2])
|
||||
assert r == 3
|
||||
|
||||
r = self.module.mod.sum([1, 2])
|
||||
assert r == 3
|
||||
r = self.module.mod.fsum([1, 2])
|
||||
assert r == 3
|
||||
|
||||
|
||||
class TestF2cmapOption(TestAssumedShapeSumExample):
|
||||
def setup_method(self):
|
||||
# Use a custom file name for .f2py_f2cmap
|
||||
self.sources = list(self.sources)
|
||||
f2cmap_src = self.sources.pop(-1)
|
||||
|
||||
self.f2cmap_file = tempfile.NamedTemporaryFile(delete=False)
|
||||
with open(f2cmap_src, "rb") as f:
|
||||
self.f2cmap_file.write(f.read())
|
||||
self.f2cmap_file.close()
|
||||
|
||||
self.sources.append(self.f2cmap_file.name)
|
||||
self.options = ["--f2cmap", self.f2cmap_file.name]
|
||||
|
||||
super().setup_method()
|
||||
|
||||
def teardown_method(self):
|
||||
os.unlink(self.f2cmap_file.name)
|
||||
@@ -0,0 +1,17 @@
|
||||
import sys
|
||||
import pytest
|
||||
from . import util
|
||||
|
||||
from numpy.testing import IS_PYPY
|
||||
|
||||
|
||||
class TestBlockDocString(util.F2PyTest):
|
||||
sources = [util.getpath("tests", "src", "block_docstring", "foo.f")]
|
||||
|
||||
@pytest.mark.skipif(sys.platform == "win32",
|
||||
reason="Fails with MinGW64 Gfortran (Issue #9673)")
|
||||
@pytest.mark.xfail(IS_PYPY,
|
||||
reason="PyPy cannot modify tp_doc after PyType_Ready")
|
||||
def test_block_docstring(self):
|
||||
expected = "bar : 'i'-array(2,3)\n"
|
||||
assert self.module.block.__doc__ == expected
|
||||
@@ -0,0 +1,230 @@
|
||||
import math
|
||||
import textwrap
|
||||
import sys
|
||||
import pytest
|
||||
import threading
|
||||
import traceback
|
||||
import time
|
||||
|
||||
import numpy as np
|
||||
from numpy.testing import IS_PYPY
|
||||
from . import util
|
||||
|
||||
|
||||
class TestF77Callback(util.F2PyTest):
|
||||
sources = [util.getpath("tests", "src", "callback", "foo.f")]
|
||||
|
||||
@pytest.mark.parametrize("name", "t,t2".split(","))
|
||||
def test_all(self, name):
|
||||
self.check_function(name)
|
||||
|
||||
@pytest.mark.xfail(IS_PYPY,
|
||||
reason="PyPy cannot modify tp_doc after PyType_Ready")
|
||||
def test_docstring(self):
|
||||
expected = textwrap.dedent("""\
|
||||
a = t(fun,[fun_extra_args])
|
||||
|
||||
Wrapper for ``t``.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
fun : call-back function
|
||||
|
||||
Other Parameters
|
||||
----------------
|
||||
fun_extra_args : input tuple, optional
|
||||
Default: ()
|
||||
|
||||
Returns
|
||||
-------
|
||||
a : int
|
||||
|
||||
Notes
|
||||
-----
|
||||
Call-back functions::
|
||||
|
||||
def fun(): return a
|
||||
Return objects:
|
||||
a : int
|
||||
""")
|
||||
assert self.module.t.__doc__ == expected
|
||||
|
||||
def check_function(self, name):
|
||||
t = getattr(self.module, name)
|
||||
r = t(lambda: 4)
|
||||
assert r == 4
|
||||
r = t(lambda a: 5, fun_extra_args=(6, ))
|
||||
assert r == 5
|
||||
r = t(lambda a: a, fun_extra_args=(6, ))
|
||||
assert r == 6
|
||||
r = t(lambda a: 5 + a, fun_extra_args=(7, ))
|
||||
assert r == 12
|
||||
r = t(lambda a: math.degrees(a), fun_extra_args=(math.pi, ))
|
||||
assert r == 180
|
||||
r = t(math.degrees, fun_extra_args=(math.pi, ))
|
||||
assert r == 180
|
||||
|
||||
r = t(self.module.func, fun_extra_args=(6, ))
|
||||
assert r == 17
|
||||
r = t(self.module.func0)
|
||||
assert r == 11
|
||||
r = t(self.module.func0._cpointer)
|
||||
assert r == 11
|
||||
|
||||
class A:
|
||||
def __call__(self):
|
||||
return 7
|
||||
|
||||
def mth(self):
|
||||
return 9
|
||||
|
||||
a = A()
|
||||
r = t(a)
|
||||
assert r == 7
|
||||
r = t(a.mth)
|
||||
assert r == 9
|
||||
|
||||
@pytest.mark.skipif(sys.platform == 'win32',
|
||||
reason='Fails with MinGW64 Gfortran (Issue #9673)')
|
||||
def test_string_callback(self):
|
||||
def callback(code):
|
||||
if code == "r":
|
||||
return 0
|
||||
else:
|
||||
return 1
|
||||
|
||||
f = getattr(self.module, "string_callback")
|
||||
r = f(callback)
|
||||
assert r == 0
|
||||
|
||||
@pytest.mark.skipif(sys.platform == 'win32',
|
||||
reason='Fails with MinGW64 Gfortran (Issue #9673)')
|
||||
def test_string_callback_array(self):
|
||||
# See gh-10027
|
||||
cu1 = np.zeros((1, ), "S8")
|
||||
cu2 = np.zeros((1, 8), "c")
|
||||
cu3 = np.array([""], "S8")
|
||||
|
||||
def callback(cu, lencu):
|
||||
if cu.shape != (lencu,):
|
||||
return 1
|
||||
if cu.dtype != "S8":
|
||||
return 2
|
||||
if not np.all(cu == b""):
|
||||
return 3
|
||||
return 0
|
||||
|
||||
f = getattr(self.module, "string_callback_array")
|
||||
for cu in [cu1, cu2, cu3]:
|
||||
res = f(callback, cu, cu.size)
|
||||
assert res == 0
|
||||
|
||||
def test_threadsafety(self):
|
||||
# Segfaults if the callback handling is not threadsafe
|
||||
|
||||
errors = []
|
||||
|
||||
def cb():
|
||||
# Sleep here to make it more likely for another thread
|
||||
# to call their callback at the same time.
|
||||
time.sleep(1e-3)
|
||||
|
||||
# Check reentrancy
|
||||
r = self.module.t(lambda: 123)
|
||||
assert r == 123
|
||||
|
||||
return 42
|
||||
|
||||
def runner(name):
|
||||
try:
|
||||
for j in range(50):
|
||||
r = self.module.t(cb)
|
||||
assert r == 42
|
||||
self.check_function(name)
|
||||
except Exception:
|
||||
errors.append(traceback.format_exc())
|
||||
|
||||
threads = [
|
||||
threading.Thread(target=runner, args=(arg, ))
|
||||
for arg in ("t", "t2") for n in range(20)
|
||||
]
|
||||
|
||||
for t in threads:
|
||||
t.start()
|
||||
|
||||
for t in threads:
|
||||
t.join()
|
||||
|
||||
errors = "\n\n".join(errors)
|
||||
if errors:
|
||||
raise AssertionError(errors)
|
||||
|
||||
def test_hidden_callback(self):
|
||||
try:
|
||||
self.module.hidden_callback(2)
|
||||
except Exception as msg:
|
||||
assert str(msg).startswith("Callback global_f not defined")
|
||||
|
||||
try:
|
||||
self.module.hidden_callback2(2)
|
||||
except Exception as msg:
|
||||
assert str(msg).startswith("cb: Callback global_f not defined")
|
||||
|
||||
self.module.global_f = lambda x: x + 1
|
||||
r = self.module.hidden_callback(2)
|
||||
assert r == 3
|
||||
|
||||
self.module.global_f = lambda x: x + 2
|
||||
r = self.module.hidden_callback(2)
|
||||
assert r == 4
|
||||
|
||||
del self.module.global_f
|
||||
try:
|
||||
self.module.hidden_callback(2)
|
||||
except Exception as msg:
|
||||
assert str(msg).startswith("Callback global_f not defined")
|
||||
|
||||
self.module.global_f = lambda x=0: x + 3
|
||||
r = self.module.hidden_callback(2)
|
||||
assert r == 5
|
||||
|
||||
# reproducer of gh18341
|
||||
r = self.module.hidden_callback2(2)
|
||||
assert r == 3
|
||||
|
||||
|
||||
class TestF77CallbackPythonTLS(TestF77Callback):
|
||||
"""
|
||||
Callback tests using Python thread-local storage instead of
|
||||
compiler-provided
|
||||
"""
|
||||
|
||||
options = ["-DF2PY_USE_PYTHON_TLS"]
|
||||
|
||||
|
||||
class TestF90Callback(util.F2PyTest):
|
||||
sources = [util.getpath("tests", "src", "callback", "gh17797.f90")]
|
||||
|
||||
def test_gh17797(self):
|
||||
def incr(x):
|
||||
return x + 123
|
||||
|
||||
y = np.array([1, 2, 3], dtype=np.int64)
|
||||
r = self.module.gh17797(incr, y)
|
||||
assert r == 123 + 1 + 2 + 3
|
||||
|
||||
|
||||
class TestGH18335(util.F2PyTest):
|
||||
"""The reproduction of the reported issue requires specific input that
|
||||
extensions may break the issue conditions, so the reproducer is
|
||||
implemented as a separate test class. Do not extend this test with
|
||||
other tests!
|
||||
"""
|
||||
sources = [util.getpath("tests", "src", "callback", "gh18335.f90")]
|
||||
|
||||
def test_gh18335(self):
|
||||
def foo(x):
|
||||
x[0] += 1
|
||||
|
||||
r = self.module.gh18335(foo)
|
||||
assert r == 123 + 1
|
||||
@@ -0,0 +1,592 @@
|
||||
import pytest
|
||||
import textwrap
|
||||
from numpy.testing import assert_array_equal, assert_equal, assert_raises
|
||||
import numpy as np
|
||||
from numpy.f2py.tests import util
|
||||
|
||||
|
||||
class TestCharacterString(util.F2PyTest):
|
||||
# options = ['--debug-capi', '--build-dir', '/tmp/test-build-f2py']
|
||||
suffix = '.f90'
|
||||
fprefix = 'test_character_string'
|
||||
length_list = ['1', '3', 'star']
|
||||
|
||||
code = ''
|
||||
for length in length_list:
|
||||
fsuffix = length
|
||||
clength = dict(star='(*)').get(length, length)
|
||||
|
||||
code += textwrap.dedent(f"""
|
||||
|
||||
subroutine {fprefix}_input_{fsuffix}(c, o, n)
|
||||
character*{clength}, intent(in) :: c
|
||||
integer n
|
||||
!f2py integer, depend(c), intent(hide) :: n = slen(c)
|
||||
integer*1, dimension(n) :: o
|
||||
!f2py intent(out) o
|
||||
o = transfer(c, o)
|
||||
end subroutine {fprefix}_input_{fsuffix}
|
||||
|
||||
subroutine {fprefix}_output_{fsuffix}(c, o, n)
|
||||
character*{clength}, intent(out) :: c
|
||||
integer n
|
||||
integer*1, dimension(n), intent(in) :: o
|
||||
!f2py integer, depend(o), intent(hide) :: n = len(o)
|
||||
c = transfer(o, c)
|
||||
end subroutine {fprefix}_output_{fsuffix}
|
||||
|
||||
subroutine {fprefix}_array_input_{fsuffix}(c, o, m, n)
|
||||
integer m, i, n
|
||||
character*{clength}, intent(in), dimension(m) :: c
|
||||
!f2py integer, depend(c), intent(hide) :: m = len(c)
|
||||
!f2py integer, depend(c), intent(hide) :: n = f2py_itemsize(c)
|
||||
integer*1, dimension(m, n), intent(out) :: o
|
||||
do i=1,m
|
||||
o(i, :) = transfer(c(i), o(i, :))
|
||||
end do
|
||||
end subroutine {fprefix}_array_input_{fsuffix}
|
||||
|
||||
subroutine {fprefix}_array_output_{fsuffix}(c, o, m, n)
|
||||
character*{clength}, intent(out), dimension(m) :: c
|
||||
integer n
|
||||
integer*1, dimension(m, n), intent(in) :: o
|
||||
!f2py character(f2py_len=n) :: c
|
||||
!f2py integer, depend(o), intent(hide) :: m = len(o)
|
||||
!f2py integer, depend(o), intent(hide) :: n = shape(o, 1)
|
||||
do i=1,m
|
||||
c(i) = transfer(o(i, :), c(i))
|
||||
end do
|
||||
end subroutine {fprefix}_array_output_{fsuffix}
|
||||
|
||||
subroutine {fprefix}_2d_array_input_{fsuffix}(c, o, m1, m2, n)
|
||||
integer m1, m2, i, j, n
|
||||
character*{clength}, intent(in), dimension(m1, m2) :: c
|
||||
!f2py integer, depend(c), intent(hide) :: m1 = len(c)
|
||||
!f2py integer, depend(c), intent(hide) :: m2 = shape(c, 1)
|
||||
!f2py integer, depend(c), intent(hide) :: n = f2py_itemsize(c)
|
||||
integer*1, dimension(m1, m2, n), intent(out) :: o
|
||||
do i=1,m1
|
||||
do j=1,m2
|
||||
o(i, j, :) = transfer(c(i, j), o(i, j, :))
|
||||
end do
|
||||
end do
|
||||
end subroutine {fprefix}_2d_array_input_{fsuffix}
|
||||
""")
|
||||
|
||||
@pytest.mark.parametrize("length", length_list)
|
||||
def test_input(self, length):
|
||||
fsuffix = {'(*)': 'star'}.get(length, length)
|
||||
f = getattr(self.module, self.fprefix + '_input_' + fsuffix)
|
||||
|
||||
a = {'1': 'a', '3': 'abc', 'star': 'abcde' * 3}[length]
|
||||
|
||||
assert_array_equal(f(a), np.array(list(map(ord, a)), dtype='u1'))
|
||||
|
||||
@pytest.mark.parametrize("length", length_list[:-1])
|
||||
def test_output(self, length):
|
||||
fsuffix = length
|
||||
f = getattr(self.module, self.fprefix + '_output_' + fsuffix)
|
||||
|
||||
a = {'1': 'a', '3': 'abc'}[length]
|
||||
|
||||
assert_array_equal(f(np.array(list(map(ord, a)), dtype='u1')),
|
||||
a.encode())
|
||||
|
||||
@pytest.mark.parametrize("length", length_list)
|
||||
def test_array_input(self, length):
|
||||
fsuffix = length
|
||||
f = getattr(self.module, self.fprefix + '_array_input_' + fsuffix)
|
||||
|
||||
a = np.array([{'1': 'a', '3': 'abc', 'star': 'abcde' * 3}[length],
|
||||
{'1': 'A', '3': 'ABC', 'star': 'ABCDE' * 3}[length],
|
||||
], dtype='S')
|
||||
|
||||
expected = np.array([[c for c in s] for s in a], dtype='u1')
|
||||
assert_array_equal(f(a), expected)
|
||||
|
||||
@pytest.mark.parametrize("length", length_list)
|
||||
def test_array_output(self, length):
|
||||
fsuffix = length
|
||||
f = getattr(self.module, self.fprefix + '_array_output_' + fsuffix)
|
||||
|
||||
expected = np.array(
|
||||
[{'1': 'a', '3': 'abc', 'star': 'abcde' * 3}[length],
|
||||
{'1': 'A', '3': 'ABC', 'star': 'ABCDE' * 3}[length]], dtype='S')
|
||||
|
||||
a = np.array([[c for c in s] for s in expected], dtype='u1')
|
||||
assert_array_equal(f(a), expected)
|
||||
|
||||
@pytest.mark.parametrize("length", length_list)
|
||||
def test_2d_array_input(self, length):
|
||||
fsuffix = length
|
||||
f = getattr(self.module, self.fprefix + '_2d_array_input_' + fsuffix)
|
||||
|
||||
a = np.array([[{'1': 'a', '3': 'abc', 'star': 'abcde' * 3}[length],
|
||||
{'1': 'A', '3': 'ABC', 'star': 'ABCDE' * 3}[length]],
|
||||
[{'1': 'f', '3': 'fgh', 'star': 'fghij' * 3}[length],
|
||||
{'1': 'F', '3': 'FGH', 'star': 'FGHIJ' * 3}[length]]],
|
||||
dtype='S')
|
||||
expected = np.array([[[c for c in item] for item in row] for row in a],
|
||||
dtype='u1', order='F')
|
||||
assert_array_equal(f(a), expected)
|
||||
|
||||
|
||||
class TestCharacter(util.F2PyTest):
|
||||
# options = ['--debug-capi', '--build-dir', '/tmp/test-build-f2py']
|
||||
suffix = '.f90'
|
||||
fprefix = 'test_character'
|
||||
|
||||
code = textwrap.dedent(f"""
|
||||
subroutine {fprefix}_input(c, o)
|
||||
character, intent(in) :: c
|
||||
integer*1 o
|
||||
!f2py intent(out) o
|
||||
o = transfer(c, o)
|
||||
end subroutine {fprefix}_input
|
||||
|
||||
subroutine {fprefix}_output(c, o)
|
||||
character :: c
|
||||
integer*1, intent(in) :: o
|
||||
!f2py intent(out) c
|
||||
c = transfer(o, c)
|
||||
end subroutine {fprefix}_output
|
||||
|
||||
subroutine {fprefix}_input_output(c, o)
|
||||
character, intent(in) :: c
|
||||
character o
|
||||
!f2py intent(out) o
|
||||
o = c
|
||||
end subroutine {fprefix}_input_output
|
||||
|
||||
subroutine {fprefix}_inout(c, n)
|
||||
character :: c, n
|
||||
!f2py intent(in) n
|
||||
!f2py intent(inout) c
|
||||
c = n
|
||||
end subroutine {fprefix}_inout
|
||||
|
||||
function {fprefix}_return(o) result (c)
|
||||
character :: c
|
||||
character, intent(in) :: o
|
||||
c = transfer(o, c)
|
||||
end function {fprefix}_return
|
||||
|
||||
subroutine {fprefix}_array_input(c, o)
|
||||
character, intent(in) :: c(3)
|
||||
integer*1 o(3)
|
||||
!f2py intent(out) o
|
||||
integer i
|
||||
do i=1,3
|
||||
o(i) = transfer(c(i), o(i))
|
||||
end do
|
||||
end subroutine {fprefix}_array_input
|
||||
|
||||
subroutine {fprefix}_2d_array_input(c, o)
|
||||
character, intent(in) :: c(2, 3)
|
||||
integer*1 o(2, 3)
|
||||
!f2py intent(out) o
|
||||
integer i, j
|
||||
do i=1,2
|
||||
do j=1,3
|
||||
o(i, j) = transfer(c(i, j), o(i, j))
|
||||
end do
|
||||
end do
|
||||
end subroutine {fprefix}_2d_array_input
|
||||
|
||||
subroutine {fprefix}_array_output(c, o)
|
||||
character :: c(3)
|
||||
integer*1, intent(in) :: o(3)
|
||||
!f2py intent(out) c
|
||||
do i=1,3
|
||||
c(i) = transfer(o(i), c(i))
|
||||
end do
|
||||
end subroutine {fprefix}_array_output
|
||||
|
||||
subroutine {fprefix}_array_inout(c, n)
|
||||
character :: c(3), n(3)
|
||||
!f2py intent(in) n(3)
|
||||
!f2py intent(inout) c(3)
|
||||
do i=1,3
|
||||
c(i) = n(i)
|
||||
end do
|
||||
end subroutine {fprefix}_array_inout
|
||||
|
||||
subroutine {fprefix}_2d_array_inout(c, n)
|
||||
character :: c(2, 3), n(2, 3)
|
||||
!f2py intent(in) n(2, 3)
|
||||
!f2py intent(inout) c(2. 3)
|
||||
integer i, j
|
||||
do i=1,2
|
||||
do j=1,3
|
||||
c(i, j) = n(i, j)
|
||||
end do
|
||||
end do
|
||||
end subroutine {fprefix}_2d_array_inout
|
||||
|
||||
function {fprefix}_array_return(o) result (c)
|
||||
character, dimension(3) :: c
|
||||
character, intent(in) :: o(3)
|
||||
do i=1,3
|
||||
c(i) = o(i)
|
||||
end do
|
||||
end function {fprefix}_array_return
|
||||
|
||||
function {fprefix}_optional(o) result (c)
|
||||
character, intent(in) :: o
|
||||
!f2py character o = "a"
|
||||
character :: c
|
||||
c = o
|
||||
end function {fprefix}_optional
|
||||
""")
|
||||
|
||||
@pytest.mark.parametrize("dtype", ['c', 'S1'])
|
||||
def test_input(self, dtype):
|
||||
f = getattr(self.module, self.fprefix + '_input')
|
||||
|
||||
assert_equal(f(np.array('a', dtype=dtype)), ord('a'))
|
||||
assert_equal(f(np.array(b'a', dtype=dtype)), ord('a'))
|
||||
assert_equal(f(np.array(['a'], dtype=dtype)), ord('a'))
|
||||
assert_equal(f(np.array('abc', dtype=dtype)), ord('a'))
|
||||
assert_equal(f(np.array([['a']], dtype=dtype)), ord('a'))
|
||||
|
||||
def test_input_varia(self):
|
||||
f = getattr(self.module, self.fprefix + '_input')
|
||||
|
||||
assert_equal(f('a'), ord('a'))
|
||||
assert_equal(f(b'a'), ord(b'a'))
|
||||
assert_equal(f(''), 0)
|
||||
assert_equal(f(b''), 0)
|
||||
assert_equal(f(b'\0'), 0)
|
||||
assert_equal(f('ab'), ord('a'))
|
||||
assert_equal(f(b'ab'), ord('a'))
|
||||
assert_equal(f(['a']), ord('a'))
|
||||
|
||||
assert_equal(f(np.array(b'a')), ord('a'))
|
||||
assert_equal(f(np.array([b'a'])), ord('a'))
|
||||
a = np.array('a')
|
||||
assert_equal(f(a), ord('a'))
|
||||
a = np.array(['a'])
|
||||
assert_equal(f(a), ord('a'))
|
||||
|
||||
try:
|
||||
f([])
|
||||
except IndexError as msg:
|
||||
if not str(msg).endswith(' got 0-list'):
|
||||
raise
|
||||
else:
|
||||
raise SystemError(f'{f.__name__} should have failed on empty list')
|
||||
|
||||
try:
|
||||
f(97)
|
||||
except TypeError as msg:
|
||||
if not str(msg).endswith(' got int instance'):
|
||||
raise
|
||||
else:
|
||||
raise SystemError(f'{f.__name__} should have failed on int value')
|
||||
|
||||
@pytest.mark.parametrize("dtype", ['c', 'S1', 'U1'])
|
||||
def test_array_input(self, dtype):
|
||||
f = getattr(self.module, self.fprefix + '_array_input')
|
||||
|
||||
assert_array_equal(f(np.array(['a', 'b', 'c'], dtype=dtype)),
|
||||
np.array(list(map(ord, 'abc')), dtype='i1'))
|
||||
assert_array_equal(f(np.array([b'a', b'b', b'c'], dtype=dtype)),
|
||||
np.array(list(map(ord, 'abc')), dtype='i1'))
|
||||
|
||||
def test_array_input_varia(self):
|
||||
f = getattr(self.module, self.fprefix + '_array_input')
|
||||
assert_array_equal(f(['a', 'b', 'c']),
|
||||
np.array(list(map(ord, 'abc')), dtype='i1'))
|
||||
assert_array_equal(f([b'a', b'b', b'c']),
|
||||
np.array(list(map(ord, 'abc')), dtype='i1'))
|
||||
|
||||
try:
|
||||
f(['a', 'b', 'c', 'd'])
|
||||
except ValueError as msg:
|
||||
if not str(msg).endswith(
|
||||
'th dimension must be fixed to 3 but got 4'):
|
||||
raise
|
||||
else:
|
||||
raise SystemError(
|
||||
f'{f.__name__} should have failed on wrong input')
|
||||
|
||||
@pytest.mark.parametrize("dtype", ['c', 'S1', 'U1'])
|
||||
def test_2d_array_input(self, dtype):
|
||||
f = getattr(self.module, self.fprefix + '_2d_array_input')
|
||||
|
||||
a = np.array([['a', 'b', 'c'],
|
||||
['d', 'e', 'f']], dtype=dtype, order='F')
|
||||
expected = a.view(np.uint32 if dtype == 'U1' else np.uint8)
|
||||
assert_array_equal(f(a), expected)
|
||||
|
||||
def test_output(self):
|
||||
f = getattr(self.module, self.fprefix + '_output')
|
||||
|
||||
assert_equal(f(ord(b'a')), b'a')
|
||||
assert_equal(f(0), b'\0')
|
||||
|
||||
def test_array_output(self):
|
||||
f = getattr(self.module, self.fprefix + '_array_output')
|
||||
|
||||
assert_array_equal(f(list(map(ord, 'abc'))),
|
||||
np.array(list('abc'), dtype='S1'))
|
||||
|
||||
def test_input_output(self):
|
||||
f = getattr(self.module, self.fprefix + '_input_output')
|
||||
|
||||
assert_equal(f(b'a'), b'a')
|
||||
assert_equal(f('a'), b'a')
|
||||
assert_equal(f(''), b'\0')
|
||||
|
||||
@pytest.mark.parametrize("dtype", ['c', 'S1'])
|
||||
def test_inout(self, dtype):
|
||||
f = getattr(self.module, self.fprefix + '_inout')
|
||||
|
||||
a = np.array(list('abc'), dtype=dtype)
|
||||
f(a, 'A')
|
||||
assert_array_equal(a, np.array(list('Abc'), dtype=a.dtype))
|
||||
f(a[1:], 'B')
|
||||
assert_array_equal(a, np.array(list('ABc'), dtype=a.dtype))
|
||||
|
||||
a = np.array(['abc'], dtype=dtype)
|
||||
f(a, 'A')
|
||||
assert_array_equal(a, np.array(['Abc'], dtype=a.dtype))
|
||||
|
||||
def test_inout_varia(self):
|
||||
f = getattr(self.module, self.fprefix + '_inout')
|
||||
a = np.array('abc', dtype='S3')
|
||||
f(a, 'A')
|
||||
assert_array_equal(a, np.array('Abc', dtype=a.dtype))
|
||||
|
||||
a = np.array(['abc'], dtype='S3')
|
||||
f(a, 'A')
|
||||
assert_array_equal(a, np.array(['Abc'], dtype=a.dtype))
|
||||
|
||||
try:
|
||||
f('abc', 'A')
|
||||
except ValueError as msg:
|
||||
if not str(msg).endswith(' got 3-str'):
|
||||
raise
|
||||
else:
|
||||
raise SystemError(f'{f.__name__} should have failed on str value')
|
||||
|
||||
@pytest.mark.parametrize("dtype", ['c', 'S1'])
|
||||
def test_array_inout(self, dtype):
|
||||
f = getattr(self.module, self.fprefix + '_array_inout')
|
||||
n = np.array(['A', 'B', 'C'], dtype=dtype, order='F')
|
||||
|
||||
a = np.array(['a', 'b', 'c'], dtype=dtype, order='F')
|
||||
f(a, n)
|
||||
assert_array_equal(a, n)
|
||||
|
||||
a = np.array(['a', 'b', 'c', 'd'], dtype=dtype)
|
||||
f(a[1:], n)
|
||||
assert_array_equal(a, np.array(['a', 'A', 'B', 'C'], dtype=dtype))
|
||||
|
||||
a = np.array([['a', 'b', 'c']], dtype=dtype, order='F')
|
||||
f(a, n)
|
||||
assert_array_equal(a, np.array([['A', 'B', 'C']], dtype=dtype))
|
||||
|
||||
a = np.array(['a', 'b', 'c', 'd'], dtype=dtype, order='F')
|
||||
try:
|
||||
f(a, n)
|
||||
except ValueError as msg:
|
||||
if not str(msg).endswith(
|
||||
'th dimension must be fixed to 3 but got 4'):
|
||||
raise
|
||||
else:
|
||||
raise SystemError(
|
||||
f'{f.__name__} should have failed on wrong input')
|
||||
|
||||
@pytest.mark.parametrize("dtype", ['c', 'S1'])
|
||||
def test_2d_array_inout(self, dtype):
|
||||
f = getattr(self.module, self.fprefix + '_2d_array_inout')
|
||||
n = np.array([['A', 'B', 'C'],
|
||||
['D', 'E', 'F']],
|
||||
dtype=dtype, order='F')
|
||||
a = np.array([['a', 'b', 'c'],
|
||||
['d', 'e', 'f']],
|
||||
dtype=dtype, order='F')
|
||||
f(a, n)
|
||||
assert_array_equal(a, n)
|
||||
|
||||
def test_return(self):
|
||||
f = getattr(self.module, self.fprefix + '_return')
|
||||
|
||||
assert_equal(f('a'), b'a')
|
||||
|
||||
@pytest.mark.skip('fortran function returning array segfaults')
|
||||
def test_array_return(self):
|
||||
f = getattr(self.module, self.fprefix + '_array_return')
|
||||
|
||||
a = np.array(list('abc'), dtype='S1')
|
||||
assert_array_equal(f(a), a)
|
||||
|
||||
def test_optional(self):
|
||||
f = getattr(self.module, self.fprefix + '_optional')
|
||||
|
||||
assert_equal(f(), b"a")
|
||||
assert_equal(f(b'B'), b"B")
|
||||
|
||||
|
||||
class TestMiscCharacter(util.F2PyTest):
|
||||
# options = ['--debug-capi', '--build-dir', '/tmp/test-build-f2py']
|
||||
suffix = '.f90'
|
||||
fprefix = 'test_misc_character'
|
||||
|
||||
code = textwrap.dedent(f"""
|
||||
subroutine {fprefix}_gh18684(x, y, m)
|
||||
character(len=5), dimension(m), intent(in) :: x
|
||||
character*5, dimension(m), intent(out) :: y
|
||||
integer i, m
|
||||
!f2py integer, intent(hide), depend(x) :: m = f2py_len(x)
|
||||
do i=1,m
|
||||
y(i) = x(i)
|
||||
end do
|
||||
end subroutine {fprefix}_gh18684
|
||||
|
||||
subroutine {fprefix}_gh6308(x, i)
|
||||
integer i
|
||||
!f2py check(i>=0 && i<12) i
|
||||
character*5 name, x
|
||||
common name(12)
|
||||
name(i + 1) = x
|
||||
end subroutine {fprefix}_gh6308
|
||||
|
||||
subroutine {fprefix}_gh4519(x)
|
||||
character(len=*), intent(in) :: x(:)
|
||||
!f2py intent(out) x
|
||||
integer :: i
|
||||
do i=1, size(x)
|
||||
print*, "x(",i,")=", x(i)
|
||||
end do
|
||||
end subroutine {fprefix}_gh4519
|
||||
|
||||
pure function {fprefix}_gh3425(x) result (y)
|
||||
character(len=*), intent(in) :: x
|
||||
character(len=len(x)) :: y
|
||||
integer :: i
|
||||
do i = 1, len(x)
|
||||
j = iachar(x(i:i))
|
||||
if (j>=iachar("a") .and. j<=iachar("z") ) then
|
||||
y(i:i) = achar(j-32)
|
||||
else
|
||||
y(i:i) = x(i:i)
|
||||
endif
|
||||
end do
|
||||
end function {fprefix}_gh3425
|
||||
|
||||
subroutine {fprefix}_character_bc_new(x, y, z)
|
||||
character, intent(in) :: x
|
||||
character, intent(out) :: y
|
||||
!f2py character, depend(x) :: y = x
|
||||
!f2py character, dimension((x=='a'?1:2)), depend(x), intent(out) :: z
|
||||
character, dimension(*) :: z
|
||||
!f2py character, optional, check(x == 'a' || x == 'b') :: x = 'a'
|
||||
!f2py callstatement (*f2py_func)(&x, &y, z)
|
||||
!f2py callprotoargument character*, character*, character*
|
||||
if (y.eq.x) then
|
||||
y = x
|
||||
else
|
||||
y = 'e'
|
||||
endif
|
||||
z(1) = 'c'
|
||||
end subroutine {fprefix}_character_bc_new
|
||||
|
||||
subroutine {fprefix}_character_bc_old(x, y, z)
|
||||
character, intent(in) :: x
|
||||
character, intent(out) :: y
|
||||
!f2py character, depend(x) :: y = x[0]
|
||||
!f2py character, dimension((*x=='a'?1:2)), depend(x), intent(out) :: z
|
||||
character, dimension(*) :: z
|
||||
!f2py character, optional, check(*x == 'a' || x[0] == 'b') :: x = 'a'
|
||||
!f2py callstatement (*f2py_func)(x, y, z)
|
||||
!f2py callprotoargument char*, char*, char*
|
||||
if (y.eq.x) then
|
||||
y = x
|
||||
else
|
||||
y = 'e'
|
||||
endif
|
||||
z(1) = 'c'
|
||||
end subroutine {fprefix}_character_bc_old
|
||||
""")
|
||||
|
||||
def test_gh18684(self):
|
||||
# Test character(len=5) and character*5 usages
|
||||
f = getattr(self.module, self.fprefix + '_gh18684')
|
||||
x = np.array(["abcde", "fghij"], dtype='S5')
|
||||
y = f(x)
|
||||
|
||||
assert_array_equal(x, y)
|
||||
|
||||
def test_gh6308(self):
|
||||
# Test character string array in a common block
|
||||
f = getattr(self.module, self.fprefix + '_gh6308')
|
||||
|
||||
assert_equal(self.module._BLNK_.name.dtype, np.dtype('S5'))
|
||||
assert_equal(len(self.module._BLNK_.name), 12)
|
||||
f("abcde", 0)
|
||||
assert_equal(self.module._BLNK_.name[0], b"abcde")
|
||||
f("12345", 5)
|
||||
assert_equal(self.module._BLNK_.name[5], b"12345")
|
||||
|
||||
def test_gh4519(self):
|
||||
# Test array of assumed length strings
|
||||
f = getattr(self.module, self.fprefix + '_gh4519')
|
||||
|
||||
for x, expected in [
|
||||
('a', dict(shape=(), dtype=np.dtype('S1'))),
|
||||
('text', dict(shape=(), dtype=np.dtype('S4'))),
|
||||
(np.array(['1', '2', '3'], dtype='S1'),
|
||||
dict(shape=(3,), dtype=np.dtype('S1'))),
|
||||
(['1', '2', '34'],
|
||||
dict(shape=(3,), dtype=np.dtype('S2'))),
|
||||
(['', ''], dict(shape=(2,), dtype=np.dtype('S1')))]:
|
||||
r = f(x)
|
||||
for k, v in expected.items():
|
||||
assert_equal(getattr(r, k), v)
|
||||
|
||||
def test_gh3425(self):
|
||||
# Test returning a copy of assumed length string
|
||||
f = getattr(self.module, self.fprefix + '_gh3425')
|
||||
# f is equivalent to bytes.upper
|
||||
|
||||
assert_equal(f('abC'), b'ABC')
|
||||
assert_equal(f(''), b'')
|
||||
assert_equal(f('abC12d'), b'ABC12D')
|
||||
|
||||
@pytest.mark.parametrize("state", ['new', 'old'])
|
||||
def test_character_bc(self, state):
|
||||
f = getattr(self.module, self.fprefix + '_character_bc_' + state)
|
||||
|
||||
c, a = f()
|
||||
assert_equal(c, b'a')
|
||||
assert_equal(len(a), 1)
|
||||
|
||||
c, a = f(b'b')
|
||||
assert_equal(c, b'b')
|
||||
assert_equal(len(a), 2)
|
||||
|
||||
assert_raises(Exception, lambda: f(b'c'))
|
||||
|
||||
|
||||
class TestStringScalarArr(util.F2PyTest):
|
||||
sources = [util.getpath("tests", "src", "string", "scalar_string.f90")]
|
||||
|
||||
@pytest.mark.slow
|
||||
def test_char(self):
|
||||
for out in (self.module.string_test.string,
|
||||
self.module.string_test.string77):
|
||||
expected = ()
|
||||
assert out.shape == expected
|
||||
expected = '|S8'
|
||||
assert out.dtype == expected
|
||||
|
||||
@pytest.mark.slow
|
||||
def test_char_arr(self):
|
||||
for out in (self.module.string_test.strarr,
|
||||
self.module.string_test.strarr77):
|
||||
expected = (5,7)
|
||||
assert out.shape == expected
|
||||
expected = '|S12'
|
||||
assert out.dtype == expected
|
||||
@@ -0,0 +1,18 @@
|
||||
import os
|
||||
import sys
|
||||
import pytest
|
||||
|
||||
import numpy as np
|
||||
from . import util
|
||||
|
||||
|
||||
class TestCommonBlock(util.F2PyTest):
|
||||
sources = [util.getpath("tests", "src", "common", "block.f")]
|
||||
|
||||
@pytest.mark.skipif(sys.platform == "win32",
|
||||
reason="Fails with MinGW64 Gfortran (Issue #9673)")
|
||||
def test_common_block(self):
|
||||
self.module.initcb()
|
||||
assert self.module.block.long_bn == np.array(1.0, dtype=np.float64)
|
||||
assert self.module.block.string_bn == np.array("2", dtype="|S1")
|
||||
assert self.module.block.ok == np.array(3, dtype=np.int32)
|
||||
@@ -0,0 +1,117 @@
|
||||
"""See https://github.com/numpy/numpy/pull/11937.
|
||||
|
||||
"""
|
||||
import sys
|
||||
import os
|
||||
import uuid
|
||||
from importlib import import_module
|
||||
import pytest
|
||||
|
||||
import numpy.f2py
|
||||
|
||||
from . import util
|
||||
|
||||
|
||||
def setup_module():
|
||||
if not util.has_c_compiler():
|
||||
pytest.skip("Needs C compiler")
|
||||
if not util.has_f77_compiler():
|
||||
pytest.skip("Needs FORTRAN 77 compiler")
|
||||
|
||||
|
||||
# extra_args can be a list (since gh-11937) or string.
|
||||
# also test absence of extra_args
|
||||
@pytest.mark.parametrize("extra_args",
|
||||
[["--noopt", "--debug"], "--noopt --debug", ""])
|
||||
@pytest.mark.leaks_references(reason="Imported module seems never deleted.")
|
||||
def test_f2py_init_compile(extra_args):
|
||||
# flush through the f2py __init__ compile() function code path as a
|
||||
# crude test for input handling following migration from
|
||||
# exec_command() to subprocess.check_output() in gh-11937
|
||||
|
||||
# the Fortran 77 syntax requires 6 spaces before any commands, but
|
||||
# more space may be added/
|
||||
fsource = """
|
||||
integer function foo()
|
||||
foo = 10 + 5
|
||||
return
|
||||
end
|
||||
"""
|
||||
# use various helper functions in util.py to enable robust build /
|
||||
# compile and reimport cycle in test suite
|
||||
moddir = util.get_module_dir()
|
||||
modname = util.get_temp_module_name()
|
||||
|
||||
cwd = os.getcwd()
|
||||
target = os.path.join(moddir, str(uuid.uuid4()) + ".f")
|
||||
# try running compile() with and without a source_fn provided so
|
||||
# that the code path where a temporary file for writing Fortran
|
||||
# source is created is also explored
|
||||
for source_fn in [target, None]:
|
||||
# mimic the path changing behavior used by build_module() in
|
||||
# util.py, but don't actually use build_module() because it has
|
||||
# its own invocation of subprocess that circumvents the
|
||||
# f2py.compile code block under test
|
||||
with util.switchdir(moddir):
|
||||
ret_val = numpy.f2py.compile(fsource,
|
||||
modulename=modname,
|
||||
extra_args=extra_args,
|
||||
source_fn=source_fn)
|
||||
|
||||
# check for compile success return value
|
||||
assert ret_val == 0
|
||||
|
||||
# we are not currently able to import the Python-Fortran
|
||||
# interface module on Windows / Appveyor, even though we do get
|
||||
# successful compilation on that platform with Python 3.x
|
||||
if sys.platform != "win32":
|
||||
# check for sensible result of Fortran function; that means
|
||||
# we can import the module name in Python and retrieve the
|
||||
# result of the sum operation
|
||||
return_check = import_module(modname)
|
||||
calc_result = return_check.foo()
|
||||
assert calc_result == 15
|
||||
# Removal from sys.modules, is not as such necessary. Even with
|
||||
# removal, the module (dict) stays alive.
|
||||
del sys.modules[modname]
|
||||
|
||||
|
||||
def test_f2py_init_compile_failure():
|
||||
# verify an appropriate integer status value returned by
|
||||
# f2py.compile() when invalid Fortran is provided
|
||||
ret_val = numpy.f2py.compile(b"invalid")
|
||||
assert ret_val == 1
|
||||
|
||||
|
||||
def test_f2py_init_compile_bad_cmd():
|
||||
# verify that usage of invalid command in f2py.compile() returns
|
||||
# status value of 127 for historic consistency with exec_command()
|
||||
# error handling
|
||||
|
||||
# patch the sys Python exe path temporarily to induce an OSError
|
||||
# downstream NOTE: how bad of an idea is this patching?
|
||||
try:
|
||||
temp = sys.executable
|
||||
sys.executable = "does not exist"
|
||||
|
||||
# the OSError should take precedence over invalid Fortran
|
||||
ret_val = numpy.f2py.compile(b"invalid")
|
||||
assert ret_val == 127
|
||||
finally:
|
||||
sys.executable = temp
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"fsource",
|
||||
[
|
||||
"program test_f2py\nend program test_f2py",
|
||||
b"program test_f2py\nend program test_f2py",
|
||||
],
|
||||
)
|
||||
def test_compile_from_strings(tmpdir, fsource):
|
||||
# Make sure we can compile str and bytes gh-12796
|
||||
with util.switchdir(tmpdir):
|
||||
ret_val = numpy.f2py.compile(fsource,
|
||||
modulename="test_compile_from_strings",
|
||||
extension=".f90")
|
||||
assert ret_val == 0
|
||||
@@ -0,0 +1,278 @@
|
||||
import importlib
|
||||
import codecs
|
||||
import unicodedata
|
||||
import pytest
|
||||
import numpy as np
|
||||
from numpy.f2py.crackfortran import markinnerspaces
|
||||
from . import util
|
||||
from numpy.f2py import crackfortran
|
||||
import textwrap
|
||||
|
||||
|
||||
class TestNoSpace(util.F2PyTest):
|
||||
# issue gh-15035: add handling for endsubroutine, endfunction with no space
|
||||
# between "end" and the block name
|
||||
sources = [util.getpath("tests", "src", "crackfortran", "gh15035.f")]
|
||||
|
||||
def test_module(self):
|
||||
k = np.array([1, 2, 3], dtype=np.float64)
|
||||
w = np.array([1, 2, 3], dtype=np.float64)
|
||||
self.module.subb(k)
|
||||
assert np.allclose(k, w + 1)
|
||||
self.module.subc([w, k])
|
||||
assert np.allclose(k, w + 1)
|
||||
assert self.module.t0("23") == b"2"
|
||||
|
||||
|
||||
class TestPublicPrivate:
|
||||
def test_defaultPrivate(self):
|
||||
fpath = util.getpath("tests", "src", "crackfortran", "privatemod.f90")
|
||||
mod = crackfortran.crackfortran([str(fpath)])
|
||||
assert len(mod) == 1
|
||||
mod = mod[0]
|
||||
assert "private" in mod["vars"]["a"]["attrspec"]
|
||||
assert "public" not in mod["vars"]["a"]["attrspec"]
|
||||
assert "private" in mod["vars"]["b"]["attrspec"]
|
||||
assert "public" not in mod["vars"]["b"]["attrspec"]
|
||||
assert "private" not in mod["vars"]["seta"]["attrspec"]
|
||||
assert "public" in mod["vars"]["seta"]["attrspec"]
|
||||
|
||||
def test_defaultPublic(self, tmp_path):
|
||||
fpath = util.getpath("tests", "src", "crackfortran", "publicmod.f90")
|
||||
mod = crackfortran.crackfortran([str(fpath)])
|
||||
assert len(mod) == 1
|
||||
mod = mod[0]
|
||||
assert "private" in mod["vars"]["a"]["attrspec"]
|
||||
assert "public" not in mod["vars"]["a"]["attrspec"]
|
||||
assert "private" not in mod["vars"]["seta"]["attrspec"]
|
||||
assert "public" in mod["vars"]["seta"]["attrspec"]
|
||||
|
||||
def test_access_type(self, tmp_path):
|
||||
fpath = util.getpath("tests", "src", "crackfortran", "accesstype.f90")
|
||||
mod = crackfortran.crackfortran([str(fpath)])
|
||||
assert len(mod) == 1
|
||||
tt = mod[0]['vars']
|
||||
assert set(tt['a']['attrspec']) == {'private', 'bind(c)'}
|
||||
assert set(tt['b_']['attrspec']) == {'public', 'bind(c)'}
|
||||
assert set(tt['c']['attrspec']) == {'public'}
|
||||
|
||||
|
||||
class TestModuleProcedure():
|
||||
def test_moduleOperators(self, tmp_path):
|
||||
fpath = util.getpath("tests", "src", "crackfortran", "operators.f90")
|
||||
mod = crackfortran.crackfortran([str(fpath)])
|
||||
assert len(mod) == 1
|
||||
mod = mod[0]
|
||||
assert "body" in mod and len(mod["body"]) == 9
|
||||
assert mod["body"][1]["name"] == "operator(.item.)"
|
||||
assert "implementedby" in mod["body"][1]
|
||||
assert mod["body"][1]["implementedby"] == \
|
||||
["item_int", "item_real"]
|
||||
assert mod["body"][2]["name"] == "operator(==)"
|
||||
assert "implementedby" in mod["body"][2]
|
||||
assert mod["body"][2]["implementedby"] == ["items_are_equal"]
|
||||
assert mod["body"][3]["name"] == "assignment(=)"
|
||||
assert "implementedby" in mod["body"][3]
|
||||
assert mod["body"][3]["implementedby"] == \
|
||||
["get_int", "get_real"]
|
||||
|
||||
def test_notPublicPrivate(self, tmp_path):
|
||||
fpath = util.getpath("tests", "src", "crackfortran", "pubprivmod.f90")
|
||||
mod = crackfortran.crackfortran([str(fpath)])
|
||||
assert len(mod) == 1
|
||||
mod = mod[0]
|
||||
assert mod['vars']['a']['attrspec'] == ['private', ]
|
||||
assert mod['vars']['b']['attrspec'] == ['public', ]
|
||||
assert mod['vars']['seta']['attrspec'] == ['public', ]
|
||||
|
||||
|
||||
class TestExternal(util.F2PyTest):
|
||||
# issue gh-17859: add external attribute support
|
||||
sources = [util.getpath("tests", "src", "crackfortran", "gh17859.f")]
|
||||
|
||||
def test_external_as_statement(self):
|
||||
def incr(x):
|
||||
return x + 123
|
||||
|
||||
r = self.module.external_as_statement(incr)
|
||||
assert r == 123
|
||||
|
||||
def test_external_as_attribute(self):
|
||||
def incr(x):
|
||||
return x + 123
|
||||
|
||||
r = self.module.external_as_attribute(incr)
|
||||
assert r == 123
|
||||
|
||||
|
||||
class TestCrackFortran(util.F2PyTest):
|
||||
# gh-2848: commented lines between parameters in subroutine parameter lists
|
||||
sources = [util.getpath("tests", "src", "crackfortran", "gh2848.f90")]
|
||||
|
||||
def test_gh2848(self):
|
||||
r = self.module.gh2848(1, 2)
|
||||
assert r == (1, 2)
|
||||
|
||||
|
||||
class TestMarkinnerspaces:
|
||||
# gh-14118: markinnerspaces does not handle multiple quotations
|
||||
|
||||
def test_do_not_touch_normal_spaces(self):
|
||||
test_list = ["a ", " a", "a b c", "'abcdefghij'"]
|
||||
for i in test_list:
|
||||
assert markinnerspaces(i) == i
|
||||
|
||||
def test_one_relevant_space(self):
|
||||
assert markinnerspaces("a 'b c' \\' \\'") == "a 'b@_@c' \\' \\'"
|
||||
assert markinnerspaces(r'a "b c" \" \"') == r'a "b@_@c" \" \"'
|
||||
|
||||
def test_ignore_inner_quotes(self):
|
||||
assert markinnerspaces("a 'b c\" \" d' e") == "a 'b@_@c\"@_@\"@_@d' e"
|
||||
assert markinnerspaces("a \"b c' ' d\" e") == "a \"b@_@c'@_@'@_@d\" e"
|
||||
|
||||
def test_multiple_relevant_spaces(self):
|
||||
assert markinnerspaces("a 'b c' 'd e'") == "a 'b@_@c' 'd@_@e'"
|
||||
assert markinnerspaces(r'a "b c" "d e"') == r'a "b@_@c" "d@_@e"'
|
||||
|
||||
class TestDimSpec(util.F2PyTest):
|
||||
"""This test suite tests various expressions that are used as dimension
|
||||
specifications.
|
||||
|
||||
There exists two usage cases where analyzing dimensions
|
||||
specifications are important.
|
||||
|
||||
In the first case, the size of output arrays must be defined based
|
||||
on the inputs to a Fortran function. Because Fortran supports
|
||||
arbitrary bases for indexing, for instance, `arr(lower:upper)`,
|
||||
f2py has to evaluate an expression `upper - lower + 1` where
|
||||
`lower` and `upper` are arbitrary expressions of input parameters.
|
||||
The evaluation is performed in C, so f2py has to translate Fortran
|
||||
expressions to valid C expressions (an alternative approach is
|
||||
that a developer specifies the corresponding C expressions in a
|
||||
.pyf file).
|
||||
|
||||
In the second case, when user provides an input array with a given
|
||||
size but some hidden parameters used in dimensions specifications
|
||||
need to be determined based on the input array size. This is a
|
||||
harder problem because f2py has to solve the inverse problem: find
|
||||
a parameter `p` such that `upper(p) - lower(p) + 1` equals to the
|
||||
size of input array. In the case when this equation cannot be
|
||||
solved (e.g. because the input array size is wrong), raise an
|
||||
error before calling the Fortran function (that otherwise would
|
||||
likely crash Python process when the size of input arrays is
|
||||
wrong). f2py currently supports this case only when the equation
|
||||
is linear with respect to unknown parameter.
|
||||
|
||||
"""
|
||||
|
||||
suffix = ".f90"
|
||||
|
||||
code_template = textwrap.dedent("""
|
||||
function get_arr_size_{count}(a, n) result (length)
|
||||
integer, intent(in) :: n
|
||||
integer, dimension({dimspec}), intent(out) :: a
|
||||
integer length
|
||||
length = size(a)
|
||||
end function
|
||||
|
||||
subroutine get_inv_arr_size_{count}(a, n)
|
||||
integer :: n
|
||||
! the value of n is computed in f2py wrapper
|
||||
!f2py intent(out) n
|
||||
integer, dimension({dimspec}), intent(in) :: a
|
||||
if (a({first}).gt.0) then
|
||||
print*, "a=", a
|
||||
endif
|
||||
end subroutine
|
||||
""")
|
||||
|
||||
linear_dimspecs = [
|
||||
"n", "2*n", "2:n", "n/2", "5 - n/2", "3*n:20", "n*(n+1):n*(n+5)",
|
||||
"2*n, n"
|
||||
]
|
||||
nonlinear_dimspecs = ["2*n:3*n*n+2*n"]
|
||||
all_dimspecs = linear_dimspecs + nonlinear_dimspecs
|
||||
|
||||
code = ""
|
||||
for count, dimspec in enumerate(all_dimspecs):
|
||||
lst = [(d.split(":")[0] if ":" in d else "1") for d in dimspec.split(',')]
|
||||
code += code_template.format(
|
||||
count=count,
|
||||
dimspec=dimspec,
|
||||
first=", ".join(lst),
|
||||
)
|
||||
|
||||
@pytest.mark.parametrize("dimspec", all_dimspecs)
|
||||
def test_array_size(self, dimspec):
|
||||
|
||||
count = self.all_dimspecs.index(dimspec)
|
||||
get_arr_size = getattr(self.module, f"get_arr_size_{count}")
|
||||
|
||||
for n in [1, 2, 3, 4, 5]:
|
||||
sz, a = get_arr_size(n)
|
||||
assert a.size == sz
|
||||
|
||||
@pytest.mark.parametrize("dimspec", all_dimspecs)
|
||||
def test_inv_array_size(self, dimspec):
|
||||
|
||||
count = self.all_dimspecs.index(dimspec)
|
||||
get_arr_size = getattr(self.module, f"get_arr_size_{count}")
|
||||
get_inv_arr_size = getattr(self.module, f"get_inv_arr_size_{count}")
|
||||
|
||||
for n in [1, 2, 3, 4, 5]:
|
||||
sz, a = get_arr_size(n)
|
||||
if dimspec in self.nonlinear_dimspecs:
|
||||
# one must specify n as input, the call we'll ensure
|
||||
# that a and n are compatible:
|
||||
n1 = get_inv_arr_size(a, n)
|
||||
else:
|
||||
# in case of linear dependence, n can be determined
|
||||
# from the shape of a:
|
||||
n1 = get_inv_arr_size(a)
|
||||
# n1 may be different from n (for instance, when `a` size
|
||||
# is a function of some `n` fraction) but it must produce
|
||||
# the same sized array
|
||||
sz1, _ = get_arr_size(n1)
|
||||
assert sz == sz1, (n, n1, sz, sz1)
|
||||
|
||||
|
||||
class TestModuleDeclaration:
|
||||
def test_dependencies(self, tmp_path):
|
||||
fpath = util.getpath("tests", "src", "crackfortran", "foo_deps.f90")
|
||||
mod = crackfortran.crackfortran([str(fpath)])
|
||||
assert len(mod) == 1
|
||||
assert mod[0]["vars"]["abar"]["="] == "bar('abar')"
|
||||
|
||||
class TestEval(util.F2PyTest):
|
||||
def test_eval_scalar(self):
|
||||
eval_scalar = crackfortran._eval_scalar
|
||||
|
||||
assert eval_scalar('123', {}) == '123'
|
||||
assert eval_scalar('12 + 3', {}) == '15'
|
||||
assert eval_scalar('a + b', dict(a=1, b=2)) == '3'
|
||||
assert eval_scalar('"123"', {}) == "'123'"
|
||||
|
||||
|
||||
class TestFortranReader(util.F2PyTest):
|
||||
@pytest.mark.parametrize("encoding",
|
||||
['ascii', 'utf-8', 'utf-16', 'utf-32'])
|
||||
def test_input_encoding(self, tmp_path, encoding):
|
||||
# gh-635
|
||||
f_path = tmp_path / f"input_with_{encoding}_encoding.f90"
|
||||
with f_path.open('w', encoding=encoding) as ff:
|
||||
ff.write("""
|
||||
subroutine foo()
|
||||
end subroutine foo
|
||||
""")
|
||||
mod = crackfortran.crackfortran([str(f_path)])
|
||||
assert mod[0]['name'] == 'foo'
|
||||
|
||||
class TestUnicodeComment(util.F2PyTest):
|
||||
sources = [util.getpath("tests", "src", "crackfortran", "unicode_comment.f90")]
|
||||
|
||||
@pytest.mark.skipif(
|
||||
(importlib.util.find_spec("charset_normalizer") is None),
|
||||
reason="test requires charset_normalizer which is not installed",
|
||||
)
|
||||
def test_encoding_comment(self):
|
||||
self.module.foo(3)
|
||||
@@ -0,0 +1,55 @@
|
||||
import os
|
||||
import pytest
|
||||
import numpy as np
|
||||
from numpy.testing import assert_array_equal, assert_equal
|
||||
from . import util
|
||||
|
||||
|
||||
def get_docdir():
|
||||
# assuming that documentation tests are run from a source
|
||||
# directory
|
||||
return os.path.abspath(os.path.join(
|
||||
os.path.dirname(__file__),
|
||||
'..', '..', '..',
|
||||
'doc', 'source', 'f2py', 'code'))
|
||||
|
||||
|
||||
pytestmark = pytest.mark.skipif(
|
||||
not os.path.isdir(get_docdir()),
|
||||
reason=('Could not find f2py documentation sources'
|
||||
f' ({get_docdir()} does not exists)'))
|
||||
|
||||
|
||||
def _path(*a):
|
||||
return os.path.join(*((get_docdir(),) + a))
|
||||
|
||||
|
||||
class TestDocAdvanced(util.F2PyTest):
|
||||
# options = ['--debug-capi', '--build-dir', '/tmp/build-f2py']
|
||||
sources = [_path('asterisk1.f90'), _path('asterisk2.f90'),
|
||||
_path('ftype.f')]
|
||||
|
||||
def test_asterisk1(self):
|
||||
foo = getattr(self.module, 'foo1')
|
||||
assert_equal(foo(), b'123456789A12')
|
||||
|
||||
def test_asterisk2(self):
|
||||
foo = getattr(self.module, 'foo2')
|
||||
assert_equal(foo(2), b'12')
|
||||
assert_equal(foo(12), b'123456789A12')
|
||||
assert_equal(foo(24), b'123456789A123456789B')
|
||||
|
||||
def test_ftype(self):
|
||||
ftype = self.module
|
||||
ftype.foo()
|
||||
assert_equal(ftype.data.a, 0)
|
||||
ftype.data.a = 3
|
||||
ftype.data.x = [1, 2, 3]
|
||||
assert_equal(ftype.data.a, 3)
|
||||
assert_array_equal(ftype.data.x,
|
||||
np.array([1, 2, 3], dtype=np.float32))
|
||||
ftype.data.x[1] = 45
|
||||
assert_array_equal(ftype.data.x,
|
||||
np.array([1, 45, 3], dtype=np.float32))
|
||||
|
||||
# TODO: implement test methods for other example Fortran codes
|
||||
@@ -0,0 +1,15 @@
|
||||
from . import util
|
||||
import numpy as np
|
||||
|
||||
class TestF2Cmap(util.F2PyTest):
|
||||
sources = [
|
||||
util.getpath("tests", "src", "f2cmap", "isoFortranEnvMap.f90"),
|
||||
util.getpath("tests", "src", "f2cmap", ".f2py_f2cmap")
|
||||
]
|
||||
|
||||
# gh-15095
|
||||
def test_long_long_map(self):
|
||||
inp = np.ones(3)
|
||||
out = self.module.func1(inp)
|
||||
exp_out = 3
|
||||
assert out == exp_out
|
||||
769
venv/lib/python3.9/site-packages/numpy/f2py/tests/test_f2py2e.py
Normal file
769
venv/lib/python3.9/site-packages/numpy/f2py/tests/test_f2py2e.py
Normal file
@@ -0,0 +1,769 @@
|
||||
import textwrap, re, sys, subprocess, shlex
|
||||
from pathlib import Path
|
||||
from collections import namedtuple
|
||||
|
||||
import pytest
|
||||
|
||||
from . import util
|
||||
from numpy.f2py.f2py2e import main as f2pycli
|
||||
|
||||
#########################
|
||||
# CLI utils and classes #
|
||||
#########################
|
||||
|
||||
PPaths = namedtuple("PPaths", "finp, f90inp, pyf, wrap77, wrap90, cmodf")
|
||||
|
||||
|
||||
def get_io_paths(fname_inp, mname="untitled"):
|
||||
"""Takes in a temporary file for testing and returns the expected output and input paths
|
||||
|
||||
Here expected output is essentially one of any of the possible generated
|
||||
files.
|
||||
|
||||
..note::
|
||||
|
||||
Since this does not actually run f2py, none of these are guaranteed to
|
||||
exist, and module names are typically incorrect
|
||||
|
||||
Parameters
|
||||
----------
|
||||
fname_inp : str
|
||||
The input filename
|
||||
mname : str, optional
|
||||
The name of the module, untitled by default
|
||||
|
||||
Returns
|
||||
-------
|
||||
genp : NamedTuple PPaths
|
||||
The possible paths which are generated, not all of which exist
|
||||
"""
|
||||
bpath = Path(fname_inp)
|
||||
return PPaths(
|
||||
finp=bpath.with_suffix(".f"),
|
||||
f90inp=bpath.with_suffix(".f90"),
|
||||
pyf=bpath.with_suffix(".pyf"),
|
||||
wrap77=bpath.with_name(f"{mname}-f2pywrappers.f"),
|
||||
wrap90=bpath.with_name(f"{mname}-f2pywrappers2.f90"),
|
||||
cmodf=bpath.with_name(f"{mname}module.c"),
|
||||
)
|
||||
|
||||
|
||||
##############
|
||||
# CLI Fixtures and Tests #
|
||||
#############
|
||||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def hello_world_f90(tmpdir_factory):
|
||||
"""Generates a single f90 file for testing"""
|
||||
fdat = util.getpath("tests", "src", "cli", "hiworld.f90").read_text()
|
||||
fn = tmpdir_factory.getbasetemp() / "hello.f90"
|
||||
fn.write_text(fdat, encoding="ascii")
|
||||
return fn
|
||||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def hello_world_f77(tmpdir_factory):
|
||||
"""Generates a single f77 file for testing"""
|
||||
fdat = util.getpath("tests", "src", "cli", "hi77.f").read_text()
|
||||
fn = tmpdir_factory.getbasetemp() / "hello.f"
|
||||
fn.write_text(fdat, encoding="ascii")
|
||||
return fn
|
||||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def retreal_f77(tmpdir_factory):
|
||||
"""Generates a single f77 file for testing"""
|
||||
fdat = util.getpath("tests", "src", "return_real", "foo77.f").read_text()
|
||||
fn = tmpdir_factory.getbasetemp() / "foo.f"
|
||||
fn.write_text(fdat, encoding="ascii")
|
||||
return fn
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def f2cmap_f90(tmpdir_factory):
|
||||
"""Generates a single f90 file for testing"""
|
||||
fdat = util.getpath("tests", "src", "f2cmap", "isoFortranEnvMap.f90").read_text()
|
||||
f2cmap = util.getpath("tests", "src", "f2cmap", ".f2py_f2cmap").read_text()
|
||||
fn = tmpdir_factory.getbasetemp() / "f2cmap.f90"
|
||||
fmap = tmpdir_factory.getbasetemp() / "mapfile"
|
||||
fn.write_text(fdat, encoding="ascii")
|
||||
fmap.write_text(f2cmap, encoding="ascii")
|
||||
return fn
|
||||
|
||||
|
||||
def test_gen_pyf(capfd, hello_world_f90, monkeypatch):
|
||||
"""Ensures that a signature file is generated via the CLI
|
||||
CLI :: -h
|
||||
"""
|
||||
ipath = Path(hello_world_f90)
|
||||
opath = Path(hello_world_f90).stem + ".pyf"
|
||||
monkeypatch.setattr(sys, "argv", f'f2py -h {opath} {ipath}'.split())
|
||||
|
||||
with util.switchdir(ipath.parent):
|
||||
f2pycli() # Generate wrappers
|
||||
out, _ = capfd.readouterr()
|
||||
assert "Saving signatures to file" in out
|
||||
assert Path(f'{opath}').exists()
|
||||
|
||||
|
||||
def test_gen_pyf_stdout(capfd, hello_world_f90, monkeypatch):
|
||||
"""Ensures that a signature file can be dumped to stdout
|
||||
CLI :: -h
|
||||
"""
|
||||
ipath = Path(hello_world_f90)
|
||||
monkeypatch.setattr(sys, "argv", f'f2py -h stdout {ipath}'.split())
|
||||
with util.switchdir(ipath.parent):
|
||||
f2pycli()
|
||||
out, _ = capfd.readouterr()
|
||||
assert "Saving signatures to file" in out
|
||||
assert "function hi() ! in " in out
|
||||
|
||||
|
||||
def test_gen_pyf_no_overwrite(capfd, hello_world_f90, monkeypatch):
|
||||
"""Ensures that the CLI refuses to overwrite signature files
|
||||
CLI :: -h without --overwrite-signature
|
||||
"""
|
||||
ipath = Path(hello_world_f90)
|
||||
monkeypatch.setattr(sys, "argv", f'f2py -h faker.pyf {ipath}'.split())
|
||||
|
||||
with util.switchdir(ipath.parent):
|
||||
Path("faker.pyf").write_text("Fake news", encoding="ascii")
|
||||
with pytest.raises(SystemExit):
|
||||
f2pycli() # Refuse to overwrite
|
||||
_, err = capfd.readouterr()
|
||||
assert "Use --overwrite-signature to overwrite" in err
|
||||
|
||||
|
||||
@pytest.mark.xfail
|
||||
def test_f2py_skip(capfd, retreal_f77, monkeypatch):
|
||||
"""Tests that functions can be skipped
|
||||
CLI :: skip:
|
||||
"""
|
||||
foutl = get_io_paths(retreal_f77, mname="test")
|
||||
ipath = foutl.finp
|
||||
toskip = "t0 t4 t8 sd s8 s4"
|
||||
remaining = "td s0"
|
||||
monkeypatch.setattr(
|
||||
sys, "argv",
|
||||
f'f2py {ipath} -m test skip: {toskip}'.split())
|
||||
|
||||
with util.switchdir(ipath.parent):
|
||||
f2pycli()
|
||||
out, err = capfd.readouterr()
|
||||
for skey in toskip.split():
|
||||
assert (
|
||||
f'buildmodule: Could not found the body of interfaced routine "{skey}". Skipping.'
|
||||
in err)
|
||||
for rkey in remaining.split():
|
||||
assert f'Constructing wrapper function "{rkey}"' in out
|
||||
|
||||
|
||||
def test_f2py_only(capfd, retreal_f77, monkeypatch):
|
||||
"""Test that functions can be kept by only:
|
||||
CLI :: only:
|
||||
"""
|
||||
foutl = get_io_paths(retreal_f77, mname="test")
|
||||
ipath = foutl.finp
|
||||
toskip = "t0 t4 t8 sd s8 s4"
|
||||
tokeep = "td s0"
|
||||
monkeypatch.setattr(
|
||||
sys, "argv",
|
||||
f'f2py {ipath} -m test only: {tokeep}'.split())
|
||||
|
||||
with util.switchdir(ipath.parent):
|
||||
f2pycli()
|
||||
out, err = capfd.readouterr()
|
||||
for skey in toskip.split():
|
||||
assert (
|
||||
f'buildmodule: Could not find the body of interfaced routine "{skey}". Skipping.'
|
||||
in err)
|
||||
for rkey in tokeep.split():
|
||||
assert f'Constructing wrapper function "{rkey}"' in out
|
||||
|
||||
|
||||
def test_file_processing_switch(capfd, hello_world_f90, retreal_f77,
|
||||
monkeypatch):
|
||||
"""Tests that it is possible to return to file processing mode
|
||||
CLI :: :
|
||||
BUG: numpy-gh #20520
|
||||
"""
|
||||
foutl = get_io_paths(retreal_f77, mname="test")
|
||||
ipath = foutl.finp
|
||||
toskip = "t0 t4 t8 sd s8 s4"
|
||||
ipath2 = Path(hello_world_f90)
|
||||
tokeep = "td s0 hi" # hi is in ipath2
|
||||
mname = "blah"
|
||||
monkeypatch.setattr(
|
||||
sys,
|
||||
"argv",
|
||||
f'f2py {ipath} -m {mname} only: {tokeep} : {ipath2}'.split(
|
||||
),
|
||||
)
|
||||
|
||||
with util.switchdir(ipath.parent):
|
||||
f2pycli()
|
||||
out, err = capfd.readouterr()
|
||||
for skey in toskip.split():
|
||||
assert (
|
||||
f'buildmodule: Could not find the body of interfaced routine "{skey}". Skipping.'
|
||||
in err)
|
||||
for rkey in tokeep.split():
|
||||
assert f'Constructing wrapper function "{rkey}"' in out
|
||||
|
||||
|
||||
def test_mod_gen_f77(capfd, hello_world_f90, monkeypatch):
|
||||
"""Checks the generation of files based on a module name
|
||||
CLI :: -m
|
||||
"""
|
||||
MNAME = "hi"
|
||||
foutl = get_io_paths(hello_world_f90, mname=MNAME)
|
||||
ipath = foutl.f90inp
|
||||
monkeypatch.setattr(sys, "argv", f'f2py {ipath} -m {MNAME}'.split())
|
||||
with util.switchdir(ipath.parent):
|
||||
f2pycli()
|
||||
|
||||
# Always generate C module
|
||||
assert Path.exists(foutl.cmodf)
|
||||
# File contains a function, check for F77 wrappers
|
||||
assert Path.exists(foutl.wrap77)
|
||||
|
||||
|
||||
def test_lower_cmod(capfd, hello_world_f77, monkeypatch):
|
||||
"""Lowers cases by flag or when -h is present
|
||||
|
||||
CLI :: --[no-]lower
|
||||
"""
|
||||
foutl = get_io_paths(hello_world_f77, mname="test")
|
||||
ipath = foutl.finp
|
||||
capshi = re.compile(r"HI\(\)")
|
||||
capslo = re.compile(r"hi\(\)")
|
||||
# Case I: --lower is passed
|
||||
monkeypatch.setattr(sys, "argv", f'f2py {ipath} -m test --lower'.split())
|
||||
with util.switchdir(ipath.parent):
|
||||
f2pycli()
|
||||
out, _ = capfd.readouterr()
|
||||
assert capslo.search(out) is not None
|
||||
assert capshi.search(out) is None
|
||||
# Case II: --no-lower is passed
|
||||
monkeypatch.setattr(sys, "argv",
|
||||
f'f2py {ipath} -m test --no-lower'.split())
|
||||
with util.switchdir(ipath.parent):
|
||||
f2pycli()
|
||||
out, _ = capfd.readouterr()
|
||||
assert capslo.search(out) is None
|
||||
assert capshi.search(out) is not None
|
||||
|
||||
|
||||
def test_lower_sig(capfd, hello_world_f77, monkeypatch):
|
||||
"""Lowers cases in signature files by flag or when -h is present
|
||||
|
||||
CLI :: --[no-]lower -h
|
||||
"""
|
||||
foutl = get_io_paths(hello_world_f77, mname="test")
|
||||
ipath = foutl.finp
|
||||
# Signature files
|
||||
capshi = re.compile(r"Block: HI")
|
||||
capslo = re.compile(r"Block: hi")
|
||||
# Case I: --lower is implied by -h
|
||||
# TODO: Clean up to prevent passing --overwrite-signature
|
||||
monkeypatch.setattr(
|
||||
sys,
|
||||
"argv",
|
||||
f'f2py {ipath} -h {foutl.pyf} -m test --overwrite-signature'.split(),
|
||||
)
|
||||
|
||||
with util.switchdir(ipath.parent):
|
||||
f2pycli()
|
||||
out, _ = capfd.readouterr()
|
||||
assert capslo.search(out) is not None
|
||||
assert capshi.search(out) is None
|
||||
|
||||
# Case II: --no-lower overrides -h
|
||||
monkeypatch.setattr(
|
||||
sys,
|
||||
"argv",
|
||||
f'f2py {ipath} -h {foutl.pyf} -m test --overwrite-signature --no-lower'
|
||||
.split(),
|
||||
)
|
||||
|
||||
with util.switchdir(ipath.parent):
|
||||
f2pycli()
|
||||
out, _ = capfd.readouterr()
|
||||
assert capslo.search(out) is None
|
||||
assert capshi.search(out) is not None
|
||||
|
||||
|
||||
def test_build_dir(capfd, hello_world_f90, monkeypatch):
|
||||
"""Ensures that the build directory can be specified
|
||||
|
||||
CLI :: --build-dir
|
||||
"""
|
||||
ipath = Path(hello_world_f90)
|
||||
mname = "blah"
|
||||
odir = "tttmp"
|
||||
monkeypatch.setattr(sys, "argv",
|
||||
f'f2py -m {mname} {ipath} --build-dir {odir}'.split())
|
||||
|
||||
with util.switchdir(ipath.parent):
|
||||
f2pycli()
|
||||
out, _ = capfd.readouterr()
|
||||
assert f"Wrote C/API module \"{mname}\"" in out
|
||||
|
||||
|
||||
def test_overwrite(capfd, hello_world_f90, monkeypatch):
|
||||
"""Ensures that the build directory can be specified
|
||||
|
||||
CLI :: --overwrite-signature
|
||||
"""
|
||||
ipath = Path(hello_world_f90)
|
||||
monkeypatch.setattr(
|
||||
sys, "argv",
|
||||
f'f2py -h faker.pyf {ipath} --overwrite-signature'.split())
|
||||
|
||||
with util.switchdir(ipath.parent):
|
||||
Path("faker.pyf").write_text("Fake news", encoding="ascii")
|
||||
f2pycli()
|
||||
out, _ = capfd.readouterr()
|
||||
assert "Saving signatures to file" in out
|
||||
|
||||
|
||||
def test_latexdoc(capfd, hello_world_f90, monkeypatch):
|
||||
"""Ensures that TeX documentation is written out
|
||||
|
||||
CLI :: --latex-doc
|
||||
"""
|
||||
ipath = Path(hello_world_f90)
|
||||
mname = "blah"
|
||||
monkeypatch.setattr(sys, "argv",
|
||||
f'f2py -m {mname} {ipath} --latex-doc'.split())
|
||||
|
||||
with util.switchdir(ipath.parent):
|
||||
f2pycli()
|
||||
out, _ = capfd.readouterr()
|
||||
assert "Documentation is saved to file" in out
|
||||
with Path(f"{mname}module.tex").open() as otex:
|
||||
assert "\\documentclass" in otex.read()
|
||||
|
||||
|
||||
def test_nolatexdoc(capfd, hello_world_f90, monkeypatch):
|
||||
"""Ensures that TeX documentation is written out
|
||||
|
||||
CLI :: --no-latex-doc
|
||||
"""
|
||||
ipath = Path(hello_world_f90)
|
||||
mname = "blah"
|
||||
monkeypatch.setattr(sys, "argv",
|
||||
f'f2py -m {mname} {ipath} --no-latex-doc'.split())
|
||||
|
||||
with util.switchdir(ipath.parent):
|
||||
f2pycli()
|
||||
out, _ = capfd.readouterr()
|
||||
assert "Documentation is saved to file" not in out
|
||||
|
||||
|
||||
def test_shortlatex(capfd, hello_world_f90, monkeypatch):
|
||||
"""Ensures that truncated documentation is written out
|
||||
|
||||
TODO: Test to ensure this has no effect without --latex-doc
|
||||
CLI :: --latex-doc --short-latex
|
||||
"""
|
||||
ipath = Path(hello_world_f90)
|
||||
mname = "blah"
|
||||
monkeypatch.setattr(
|
||||
sys,
|
||||
"argv",
|
||||
f'f2py -m {mname} {ipath} --latex-doc --short-latex'.split(),
|
||||
)
|
||||
|
||||
with util.switchdir(ipath.parent):
|
||||
f2pycli()
|
||||
out, _ = capfd.readouterr()
|
||||
assert "Documentation is saved to file" in out
|
||||
with Path(f"./{mname}module.tex").open() as otex:
|
||||
assert "\\documentclass" not in otex.read()
|
||||
|
||||
|
||||
def test_restdoc(capfd, hello_world_f90, monkeypatch):
|
||||
"""Ensures that RsT documentation is written out
|
||||
|
||||
CLI :: --rest-doc
|
||||
"""
|
||||
ipath = Path(hello_world_f90)
|
||||
mname = "blah"
|
||||
monkeypatch.setattr(sys, "argv",
|
||||
f'f2py -m {mname} {ipath} --rest-doc'.split())
|
||||
|
||||
with util.switchdir(ipath.parent):
|
||||
f2pycli()
|
||||
out, _ = capfd.readouterr()
|
||||
assert "ReST Documentation is saved to file" in out
|
||||
with Path(f"./{mname}module.rest").open() as orst:
|
||||
assert r".. -*- rest -*-" in orst.read()
|
||||
|
||||
|
||||
def test_norestexdoc(capfd, hello_world_f90, monkeypatch):
|
||||
"""Ensures that TeX documentation is written out
|
||||
|
||||
CLI :: --no-rest-doc
|
||||
"""
|
||||
ipath = Path(hello_world_f90)
|
||||
mname = "blah"
|
||||
monkeypatch.setattr(sys, "argv",
|
||||
f'f2py -m {mname} {ipath} --no-rest-doc'.split())
|
||||
|
||||
with util.switchdir(ipath.parent):
|
||||
f2pycli()
|
||||
out, _ = capfd.readouterr()
|
||||
assert "ReST Documentation is saved to file" not in out
|
||||
|
||||
|
||||
def test_debugcapi(capfd, hello_world_f90, monkeypatch):
|
||||
"""Ensures that debugging wrappers are written
|
||||
|
||||
CLI :: --debug-capi
|
||||
"""
|
||||
ipath = Path(hello_world_f90)
|
||||
mname = "blah"
|
||||
monkeypatch.setattr(sys, "argv",
|
||||
f'f2py -m {mname} {ipath} --debug-capi'.split())
|
||||
|
||||
with util.switchdir(ipath.parent):
|
||||
f2pycli()
|
||||
with Path(f"./{mname}module.c").open() as ocmod:
|
||||
assert r"#define DEBUGCFUNCS" in ocmod.read()
|
||||
|
||||
|
||||
@pytest.mark.xfail(reason="Consistently fails on CI.")
|
||||
def test_debugcapi_bld(hello_world_f90, monkeypatch):
|
||||
"""Ensures that debugging wrappers work
|
||||
|
||||
CLI :: --debug-capi -c
|
||||
"""
|
||||
ipath = Path(hello_world_f90)
|
||||
mname = "blah"
|
||||
monkeypatch.setattr(sys, "argv",
|
||||
f'f2py -m {mname} {ipath} -c --debug-capi'.split())
|
||||
|
||||
with util.switchdir(ipath.parent):
|
||||
f2pycli()
|
||||
cmd_run = shlex.split("python3 -c \"import blah; blah.hi()\"")
|
||||
rout = subprocess.run(cmd_run, capture_output=True, encoding='UTF-8')
|
||||
eout = ' Hello World\n'
|
||||
eerr = textwrap.dedent("""\
|
||||
debug-capi:Python C/API function blah.hi()
|
||||
debug-capi:float hi=:output,hidden,scalar
|
||||
debug-capi:hi=0
|
||||
debug-capi:Fortran subroutine `f2pywraphi(&hi)'
|
||||
debug-capi:hi=0
|
||||
debug-capi:Building return value.
|
||||
debug-capi:Python C/API function blah.hi: successful.
|
||||
debug-capi:Freeing memory.
|
||||
""")
|
||||
assert rout.stdout == eout
|
||||
assert rout.stderr == eerr
|
||||
|
||||
|
||||
def test_wrapfunc_def(capfd, hello_world_f90, monkeypatch):
|
||||
"""Ensures that fortran subroutine wrappers for F77 are included by default
|
||||
|
||||
CLI :: --[no]-wrap-functions
|
||||
"""
|
||||
# Implied
|
||||
ipath = Path(hello_world_f90)
|
||||
mname = "blah"
|
||||
monkeypatch.setattr(sys, "argv", f'f2py -m {mname} {ipath}'.split())
|
||||
|
||||
with util.switchdir(ipath.parent):
|
||||
f2pycli()
|
||||
out, _ = capfd.readouterr()
|
||||
assert r"Fortran 77 wrappers are saved to" in out
|
||||
|
||||
# Explicit
|
||||
monkeypatch.setattr(sys, "argv",
|
||||
f'f2py -m {mname} {ipath} --wrap-functions'.split())
|
||||
|
||||
with util.switchdir(ipath.parent):
|
||||
f2pycli()
|
||||
out, _ = capfd.readouterr()
|
||||
assert r"Fortran 77 wrappers are saved to" in out
|
||||
|
||||
|
||||
def test_nowrapfunc(capfd, hello_world_f90, monkeypatch):
|
||||
"""Ensures that fortran subroutine wrappers for F77 can be disabled
|
||||
|
||||
CLI :: --no-wrap-functions
|
||||
"""
|
||||
ipath = Path(hello_world_f90)
|
||||
mname = "blah"
|
||||
monkeypatch.setattr(sys, "argv",
|
||||
f'f2py -m {mname} {ipath} --no-wrap-functions'.split())
|
||||
|
||||
with util.switchdir(ipath.parent):
|
||||
f2pycli()
|
||||
out, _ = capfd.readouterr()
|
||||
assert r"Fortran 77 wrappers are saved to" not in out
|
||||
|
||||
|
||||
def test_inclheader(capfd, hello_world_f90, monkeypatch):
|
||||
"""Add to the include directories
|
||||
|
||||
CLI :: -include
|
||||
TODO: Document this in the help string
|
||||
"""
|
||||
ipath = Path(hello_world_f90)
|
||||
mname = "blah"
|
||||
monkeypatch.setattr(
|
||||
sys,
|
||||
"argv",
|
||||
f'f2py -m {mname} {ipath} -include<stdbool.h> -include<stdio.h> '.
|
||||
split(),
|
||||
)
|
||||
|
||||
with util.switchdir(ipath.parent):
|
||||
f2pycli()
|
||||
with Path(f"./{mname}module.c").open() as ocmod:
|
||||
ocmr = ocmod.read()
|
||||
assert "#include <stdbool.h>" in ocmr
|
||||
assert "#include <stdio.h>" in ocmr
|
||||
|
||||
|
||||
def test_inclpath():
|
||||
"""Add to the include directories
|
||||
|
||||
CLI :: --include-paths
|
||||
"""
|
||||
# TODO: populate
|
||||
pass
|
||||
|
||||
|
||||
def test_hlink():
|
||||
"""Add to the include directories
|
||||
|
||||
CLI :: --help-link
|
||||
"""
|
||||
# TODO: populate
|
||||
pass
|
||||
|
||||
|
||||
def test_f2cmap(capfd, f2cmap_f90, monkeypatch):
|
||||
"""Check that Fortran-to-Python KIND specs can be passed
|
||||
|
||||
CLI :: --f2cmap
|
||||
"""
|
||||
ipath = Path(f2cmap_f90)
|
||||
monkeypatch.setattr(sys, "argv", f'f2py -m blah {ipath} --f2cmap mapfile'.split())
|
||||
|
||||
with util.switchdir(ipath.parent):
|
||||
f2pycli()
|
||||
out, _ = capfd.readouterr()
|
||||
assert "Reading f2cmap from 'mapfile' ..." in out
|
||||
assert "Mapping \"real(kind=real32)\" to \"float\"" in out
|
||||
assert "Mapping \"real(kind=real64)\" to \"double\"" in out
|
||||
assert "Mapping \"integer(kind=int64)\" to \"long_long\"" in out
|
||||
assert "Successfully applied user defined f2cmap changes" in out
|
||||
|
||||
|
||||
def test_quiet(capfd, hello_world_f90, monkeypatch):
|
||||
"""Reduce verbosity
|
||||
|
||||
CLI :: --quiet
|
||||
"""
|
||||
ipath = Path(hello_world_f90)
|
||||
monkeypatch.setattr(sys, "argv", f'f2py -m blah {ipath} --quiet'.split())
|
||||
|
||||
with util.switchdir(ipath.parent):
|
||||
f2pycli()
|
||||
out, _ = capfd.readouterr()
|
||||
assert len(out) == 0
|
||||
|
||||
|
||||
def test_verbose(capfd, hello_world_f90, monkeypatch):
|
||||
"""Increase verbosity
|
||||
|
||||
CLI :: --verbose
|
||||
"""
|
||||
ipath = Path(hello_world_f90)
|
||||
monkeypatch.setattr(sys, "argv", f'f2py -m blah {ipath} --verbose'.split())
|
||||
|
||||
with util.switchdir(ipath.parent):
|
||||
f2pycli()
|
||||
out, _ = capfd.readouterr()
|
||||
assert "analyzeline" in out
|
||||
|
||||
|
||||
def test_version(capfd, monkeypatch):
|
||||
"""Ensure version
|
||||
|
||||
CLI :: -v
|
||||
"""
|
||||
monkeypatch.setattr(sys, "argv", 'f2py -v'.split())
|
||||
# TODO: f2py2e should not call sys.exit() after printing the version
|
||||
with pytest.raises(SystemExit):
|
||||
f2pycli()
|
||||
out, _ = capfd.readouterr()
|
||||
import numpy as np
|
||||
assert np.__version__ == out.strip()
|
||||
|
||||
|
||||
@pytest.mark.xfail(reason="Consistently fails on CI.")
|
||||
def test_npdistop(hello_world_f90, monkeypatch):
|
||||
"""
|
||||
CLI :: -c
|
||||
"""
|
||||
ipath = Path(hello_world_f90)
|
||||
monkeypatch.setattr(sys, "argv", f'f2py -m blah {ipath} -c'.split())
|
||||
|
||||
with util.switchdir(ipath.parent):
|
||||
f2pycli()
|
||||
cmd_run = shlex.split("python -c \"import blah; blah.hi()\"")
|
||||
rout = subprocess.run(cmd_run, capture_output=True, encoding='UTF-8')
|
||||
eout = ' Hello World\n'
|
||||
assert rout.stdout == eout
|
||||
|
||||
|
||||
# Numpy distutils flags
|
||||
# TODO: These should be tested separately
|
||||
|
||||
|
||||
def test_npd_fcompiler():
|
||||
"""
|
||||
CLI :: -c --fcompiler
|
||||
"""
|
||||
# TODO: populate
|
||||
pass
|
||||
|
||||
|
||||
def test_npd_compiler():
|
||||
"""
|
||||
CLI :: -c --compiler
|
||||
"""
|
||||
# TODO: populate
|
||||
pass
|
||||
|
||||
|
||||
def test_npd_help_fcompiler():
|
||||
"""
|
||||
CLI :: -c --help-fcompiler
|
||||
"""
|
||||
# TODO: populate
|
||||
pass
|
||||
|
||||
|
||||
def test_npd_f77exec():
|
||||
"""
|
||||
CLI :: -c --f77exec
|
||||
"""
|
||||
# TODO: populate
|
||||
pass
|
||||
|
||||
|
||||
def test_npd_f90exec():
|
||||
"""
|
||||
CLI :: -c --f90exec
|
||||
"""
|
||||
# TODO: populate
|
||||
pass
|
||||
|
||||
|
||||
def test_npd_f77flags():
|
||||
"""
|
||||
CLI :: -c --f77flags
|
||||
"""
|
||||
# TODO: populate
|
||||
pass
|
||||
|
||||
|
||||
def test_npd_f90flags():
|
||||
"""
|
||||
CLI :: -c --f90flags
|
||||
"""
|
||||
# TODO: populate
|
||||
pass
|
||||
|
||||
|
||||
def test_npd_opt():
|
||||
"""
|
||||
CLI :: -c --opt
|
||||
"""
|
||||
# TODO: populate
|
||||
pass
|
||||
|
||||
|
||||
def test_npd_arch():
|
||||
"""
|
||||
CLI :: -c --arch
|
||||
"""
|
||||
# TODO: populate
|
||||
pass
|
||||
|
||||
|
||||
def test_npd_noopt():
|
||||
"""
|
||||
CLI :: -c --noopt
|
||||
"""
|
||||
# TODO: populate
|
||||
pass
|
||||
|
||||
|
||||
def test_npd_noarch():
|
||||
"""
|
||||
CLI :: -c --noarch
|
||||
"""
|
||||
# TODO: populate
|
||||
pass
|
||||
|
||||
|
||||
def test_npd_debug():
|
||||
"""
|
||||
CLI :: -c --debug
|
||||
"""
|
||||
# TODO: populate
|
||||
pass
|
||||
|
||||
|
||||
def test_npd_link_auto():
|
||||
"""
|
||||
CLI :: -c --link-<resource>
|
||||
"""
|
||||
# TODO: populate
|
||||
pass
|
||||
|
||||
|
||||
def test_npd_lib():
|
||||
"""
|
||||
CLI :: -c -L/path/to/lib/ -l<libname>
|
||||
"""
|
||||
# TODO: populate
|
||||
pass
|
||||
|
||||
|
||||
def test_npd_define():
|
||||
"""
|
||||
CLI :: -D<define>
|
||||
"""
|
||||
# TODO: populate
|
||||
pass
|
||||
|
||||
|
||||
def test_npd_undefine():
|
||||
"""
|
||||
CLI :: -U<name>
|
||||
"""
|
||||
# TODO: populate
|
||||
pass
|
||||
|
||||
|
||||
def test_npd_incl():
|
||||
"""
|
||||
CLI :: -I/path/to/include/
|
||||
"""
|
||||
# TODO: populate
|
||||
pass
|
||||
|
||||
|
||||
def test_npd_linker():
|
||||
"""
|
||||
CLI :: <filename>.o <filename>.so <filename>.a
|
||||
"""
|
||||
# TODO: populate
|
||||
pass
|
||||
@@ -0,0 +1,26 @@
|
||||
import os
|
||||
import pytest
|
||||
|
||||
from numpy.f2py.crackfortran import (
|
||||
_selected_int_kind_func as selected_int_kind,
|
||||
_selected_real_kind_func as selected_real_kind,
|
||||
)
|
||||
from . import util
|
||||
|
||||
|
||||
class TestKind(util.F2PyTest):
|
||||
sources = [util.getpath("tests", "src", "kind", "foo.f90")]
|
||||
|
||||
def test_all(self):
|
||||
selectedrealkind = self.module.selectedrealkind
|
||||
selectedintkind = self.module.selectedintkind
|
||||
|
||||
for i in range(40):
|
||||
assert selectedintkind(i) == selected_int_kind(
|
||||
i
|
||||
), f"selectedintkind({i}): expected {selected_int_kind(i)!r} but got {selectedintkind(i)!r}"
|
||||
|
||||
for i in range(20):
|
||||
assert selectedrealkind(i) == selected_real_kind(
|
||||
i
|
||||
), f"selectedrealkind({i}): expected {selected_real_kind(i)!r} but got {selectedrealkind(i)!r}"
|
||||
@@ -0,0 +1,33 @@
|
||||
import os
|
||||
import textwrap
|
||||
import pytest
|
||||
|
||||
from numpy.testing import IS_PYPY
|
||||
from . import util
|
||||
|
||||
|
||||
class TestMixed(util.F2PyTest):
|
||||
sources = [
|
||||
util.getpath("tests", "src", "mixed", "foo.f"),
|
||||
util.getpath("tests", "src", "mixed", "foo_fixed.f90"),
|
||||
util.getpath("tests", "src", "mixed", "foo_free.f90"),
|
||||
]
|
||||
|
||||
def test_all(self):
|
||||
assert self.module.bar11() == 11
|
||||
assert self.module.foo_fixed.bar12() == 12
|
||||
assert self.module.foo_free.bar13() == 13
|
||||
|
||||
@pytest.mark.xfail(IS_PYPY,
|
||||
reason="PyPy cannot modify tp_doc after PyType_Ready")
|
||||
def test_docstring(self):
|
||||
expected = textwrap.dedent("""\
|
||||
a = bar11()
|
||||
|
||||
Wrapper for ``bar11``.
|
||||
|
||||
Returns
|
||||
-------
|
||||
a : int
|
||||
""")
|
||||
assert self.module.bar11.__doc__ == expected
|
||||
@@ -0,0 +1,27 @@
|
||||
import os
|
||||
import sys
|
||||
import pytest
|
||||
import textwrap
|
||||
|
||||
from . import util
|
||||
from numpy.testing import IS_PYPY
|
||||
|
||||
|
||||
class TestModuleDocString(util.F2PyTest):
|
||||
sources = [
|
||||
util.getpath("tests", "src", "module_data",
|
||||
"module_data_docstring.f90")
|
||||
]
|
||||
|
||||
@pytest.mark.skipif(sys.platform == "win32",
|
||||
reason="Fails with MinGW64 Gfortran (Issue #9673)")
|
||||
@pytest.mark.xfail(IS_PYPY,
|
||||
reason="PyPy cannot modify tp_doc after PyType_Ready")
|
||||
def test_module_docstring(self):
|
||||
assert self.module.mod.__doc__ == textwrap.dedent("""\
|
||||
i : 'i'-scalar
|
||||
x : 'i'-array(4)
|
||||
a : 'f'-array(2,3)
|
||||
b : 'f'-array(-1,-1), not allocated\x00
|
||||
foo()\n
|
||||
Wrapper for ``foo``.\n\n""")
|
||||
@@ -0,0 +1,112 @@
|
||||
import os
|
||||
import pytest
|
||||
|
||||
import numpy as np
|
||||
|
||||
from . import util
|
||||
|
||||
|
||||
class TestParameters(util.F2PyTest):
|
||||
# Check that intent(in out) translates as intent(inout)
|
||||
sources = [
|
||||
util.getpath("tests", "src", "parameter", "constant_real.f90"),
|
||||
util.getpath("tests", "src", "parameter", "constant_integer.f90"),
|
||||
util.getpath("tests", "src", "parameter", "constant_both.f90"),
|
||||
util.getpath("tests", "src", "parameter", "constant_compound.f90"),
|
||||
util.getpath("tests", "src", "parameter", "constant_non_compound.f90"),
|
||||
]
|
||||
|
||||
@pytest.mark.slow
|
||||
def test_constant_real_single(self):
|
||||
# non-contiguous should raise error
|
||||
x = np.arange(6, dtype=np.float32)[::2]
|
||||
pytest.raises(ValueError, self.module.foo_single, x)
|
||||
|
||||
# check values with contiguous array
|
||||
x = np.arange(3, dtype=np.float32)
|
||||
self.module.foo_single(x)
|
||||
assert np.allclose(x, [0 + 1 + 2 * 3, 1, 2])
|
||||
|
||||
@pytest.mark.slow
|
||||
def test_constant_real_double(self):
|
||||
# non-contiguous should raise error
|
||||
x = np.arange(6, dtype=np.float64)[::2]
|
||||
pytest.raises(ValueError, self.module.foo_double, x)
|
||||
|
||||
# check values with contiguous array
|
||||
x = np.arange(3, dtype=np.float64)
|
||||
self.module.foo_double(x)
|
||||
assert np.allclose(x, [0 + 1 + 2 * 3, 1, 2])
|
||||
|
||||
@pytest.mark.slow
|
||||
def test_constant_compound_int(self):
|
||||
# non-contiguous should raise error
|
||||
x = np.arange(6, dtype=np.int32)[::2]
|
||||
pytest.raises(ValueError, self.module.foo_compound_int, x)
|
||||
|
||||
# check values with contiguous array
|
||||
x = np.arange(3, dtype=np.int32)
|
||||
self.module.foo_compound_int(x)
|
||||
assert np.allclose(x, [0 + 1 + 2 * 6, 1, 2])
|
||||
|
||||
@pytest.mark.slow
|
||||
def test_constant_non_compound_int(self):
|
||||
# check values
|
||||
x = np.arange(4, dtype=np.int32)
|
||||
self.module.foo_non_compound_int(x)
|
||||
assert np.allclose(x, [0 + 1 + 2 + 3 * 4, 1, 2, 3])
|
||||
|
||||
@pytest.mark.slow
|
||||
def test_constant_integer_int(self):
|
||||
# non-contiguous should raise error
|
||||
x = np.arange(6, dtype=np.int32)[::2]
|
||||
pytest.raises(ValueError, self.module.foo_int, x)
|
||||
|
||||
# check values with contiguous array
|
||||
x = np.arange(3, dtype=np.int32)
|
||||
self.module.foo_int(x)
|
||||
assert np.allclose(x, [0 + 1 + 2 * 3, 1, 2])
|
||||
|
||||
@pytest.mark.slow
|
||||
def test_constant_integer_long(self):
|
||||
# non-contiguous should raise error
|
||||
x = np.arange(6, dtype=np.int64)[::2]
|
||||
pytest.raises(ValueError, self.module.foo_long, x)
|
||||
|
||||
# check values with contiguous array
|
||||
x = np.arange(3, dtype=np.int64)
|
||||
self.module.foo_long(x)
|
||||
assert np.allclose(x, [0 + 1 + 2 * 3, 1, 2])
|
||||
|
||||
@pytest.mark.slow
|
||||
def test_constant_both(self):
|
||||
# non-contiguous should raise error
|
||||
x = np.arange(6, dtype=np.float64)[::2]
|
||||
pytest.raises(ValueError, self.module.foo, x)
|
||||
|
||||
# check values with contiguous array
|
||||
x = np.arange(3, dtype=np.float64)
|
||||
self.module.foo(x)
|
||||
assert np.allclose(x, [0 + 1 * 3 * 3 + 2 * 3 * 3, 1 * 3, 2 * 3])
|
||||
|
||||
@pytest.mark.slow
|
||||
def test_constant_no(self):
|
||||
# non-contiguous should raise error
|
||||
x = np.arange(6, dtype=np.float64)[::2]
|
||||
pytest.raises(ValueError, self.module.foo_no, x)
|
||||
|
||||
# check values with contiguous array
|
||||
x = np.arange(3, dtype=np.float64)
|
||||
self.module.foo_no(x)
|
||||
assert np.allclose(x, [0 + 1 * 3 * 3 + 2 * 3 * 3, 1 * 3, 2 * 3])
|
||||
|
||||
@pytest.mark.slow
|
||||
def test_constant_sum(self):
|
||||
# non-contiguous should raise error
|
||||
x = np.arange(6, dtype=np.float64)[::2]
|
||||
pytest.raises(ValueError, self.module.foo_sum, x)
|
||||
|
||||
# check values with contiguous array
|
||||
x = np.arange(3, dtype=np.float64)
|
||||
self.module.foo_sum(x)
|
||||
assert np.allclose(x, [0 + 1 * 3 * 3 + 2 * 3 * 3, 1 * 3, 2 * 3])
|
||||
@@ -0,0 +1,16 @@
|
||||
"""See https://github.com/numpy/numpy/pull/10676.
|
||||
|
||||
"""
|
||||
import sys
|
||||
import pytest
|
||||
|
||||
from . import util
|
||||
|
||||
|
||||
class TestQuotedCharacter(util.F2PyTest):
|
||||
sources = [util.getpath("tests", "src", "quoted_character", "foo.f")]
|
||||
|
||||
@pytest.mark.skipif(sys.platform == "win32",
|
||||
reason="Fails with MinGW64 Gfortran (Issue #9673)")
|
||||
def test_quoted_character(self):
|
||||
assert self.module.foo() == (b"'", b'"', b";", b"!", b"(", b")")
|
||||
@@ -0,0 +1,66 @@
|
||||
import os
|
||||
import pytest
|
||||
|
||||
import numpy as np
|
||||
|
||||
from . import util
|
||||
|
||||
|
||||
class TestIntentInOut(util.F2PyTest):
|
||||
# Check that intent(in out) translates as intent(inout)
|
||||
sources = [util.getpath("tests", "src", "regression", "inout.f90")]
|
||||
|
||||
@pytest.mark.slow
|
||||
def test_inout(self):
|
||||
# non-contiguous should raise error
|
||||
x = np.arange(6, dtype=np.float32)[::2]
|
||||
pytest.raises(ValueError, self.module.foo, x)
|
||||
|
||||
# check values with contiguous array
|
||||
x = np.arange(3, dtype=np.float32)
|
||||
self.module.foo(x)
|
||||
assert np.allclose(x, [3, 1, 2])
|
||||
|
||||
|
||||
class TestNegativeBounds(util.F2PyTest):
|
||||
# Check that negative bounds work correctly
|
||||
sources = [util.getpath("tests", "src", "negative_bounds", "issue_20853.f90")]
|
||||
|
||||
@pytest.mark.slow
|
||||
def test_negbound(self):
|
||||
xvec = np.arange(12)
|
||||
xlow = -6
|
||||
xhigh = 4
|
||||
# Calculate the upper bound,
|
||||
# Keeping the 1 index in mind
|
||||
def ubound(xl, xh):
|
||||
return xh - xl + 1
|
||||
rval = self.module.foo(is_=xlow, ie_=xhigh,
|
||||
arr=xvec[:ubound(xlow, xhigh)])
|
||||
expval = np.arange(11, dtype = np.float32)
|
||||
assert np.allclose(rval, expval)
|
||||
|
||||
|
||||
class TestNumpyVersionAttribute(util.F2PyTest):
|
||||
# Check that th attribute __f2py_numpy_version__ is present
|
||||
# in the compiled module and that has the value np.__version__.
|
||||
sources = [util.getpath("tests", "src", "regression", "inout.f90")]
|
||||
|
||||
@pytest.mark.slow
|
||||
def test_numpy_version_attribute(self):
|
||||
|
||||
# Check that self.module has an attribute named "__f2py_numpy_version__"
|
||||
assert hasattr(self.module, "__f2py_numpy_version__")
|
||||
|
||||
# Check that the attribute __f2py_numpy_version__ is a string
|
||||
assert isinstance(self.module.__f2py_numpy_version__, str)
|
||||
|
||||
# Check that __f2py_numpy_version__ has the value numpy.__version__
|
||||
assert np.__version__ == self.module.__f2py_numpy_version__
|
||||
|
||||
|
||||
def test_include_path():
|
||||
incdir = np.f2py.get_include()
|
||||
fnames_in_dir = os.listdir(incdir)
|
||||
for fname in ("fortranobject.c", "fortranobject.h"):
|
||||
assert fname in fnames_in_dir
|
||||
@@ -0,0 +1,45 @@
|
||||
import pytest
|
||||
|
||||
from numpy import array
|
||||
from . import util
|
||||
import platform
|
||||
|
||||
IS_S390X = platform.machine() == "s390x"
|
||||
|
||||
|
||||
class TestReturnCharacter(util.F2PyTest):
|
||||
def check_function(self, t, tname):
|
||||
if tname in ["t0", "t1", "s0", "s1"]:
|
||||
assert t("23") == b"2"
|
||||
r = t("ab")
|
||||
assert r == b"a"
|
||||
r = t(array("ab"))
|
||||
assert r == b"a"
|
||||
r = t(array(77, "u1"))
|
||||
assert r == b"M"
|
||||
elif tname in ["ts", "ss"]:
|
||||
assert t(23) == b"23"
|
||||
assert t("123456789abcdef") == b"123456789a"
|
||||
elif tname in ["t5", "s5"]:
|
||||
assert t(23) == b"23"
|
||||
assert t("ab") == b"ab"
|
||||
assert t("123456789abcdef") == b"12345"
|
||||
else:
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class TestFReturnCharacter(TestReturnCharacter):
|
||||
sources = [
|
||||
util.getpath("tests", "src", "return_character", "foo77.f"),
|
||||
util.getpath("tests", "src", "return_character", "foo90.f90"),
|
||||
]
|
||||
|
||||
@pytest.mark.xfail(IS_S390X, reason="callback returns ' '")
|
||||
@pytest.mark.parametrize("name", "t0,t1,t5,s0,s1,s5,ss".split(","))
|
||||
def test_all_f77(self, name):
|
||||
self.check_function(getattr(self.module, name), name)
|
||||
|
||||
@pytest.mark.xfail(IS_S390X, reason="callback returns ' '")
|
||||
@pytest.mark.parametrize("name", "t0,t1,t5,ts,s0,s1,s5,ss".split(","))
|
||||
def test_all_f90(self, name):
|
||||
self.check_function(getattr(self.module.f90_return_char, name), name)
|
||||
@@ -0,0 +1,65 @@
|
||||
import pytest
|
||||
|
||||
from numpy import array
|
||||
from . import util
|
||||
|
||||
|
||||
class TestReturnComplex(util.F2PyTest):
|
||||
def check_function(self, t, tname):
|
||||
if tname in ["t0", "t8", "s0", "s8"]:
|
||||
err = 1e-5
|
||||
else:
|
||||
err = 0.0
|
||||
assert abs(t(234j) - 234.0j) <= err
|
||||
assert abs(t(234.6) - 234.6) <= err
|
||||
assert abs(t(234) - 234.0) <= err
|
||||
assert abs(t(234.6 + 3j) - (234.6 + 3j)) <= err
|
||||
# assert abs(t('234')-234.)<=err
|
||||
# assert abs(t('234.6')-234.6)<=err
|
||||
assert abs(t(-234) + 234.0) <= err
|
||||
assert abs(t([234]) - 234.0) <= err
|
||||
assert abs(t((234, )) - 234.0) <= err
|
||||
assert abs(t(array(234)) - 234.0) <= err
|
||||
assert abs(t(array(23 + 4j, "F")) - (23 + 4j)) <= err
|
||||
assert abs(t(array([234])) - 234.0) <= err
|
||||
assert abs(t(array([[234]])) - 234.0) <= err
|
||||
assert abs(t(array([234]).astype("b")) + 22.0) <= err
|
||||
assert abs(t(array([234], "h")) - 234.0) <= err
|
||||
assert abs(t(array([234], "i")) - 234.0) <= err
|
||||
assert abs(t(array([234], "l")) - 234.0) <= err
|
||||
assert abs(t(array([234], "q")) - 234.0) <= err
|
||||
assert abs(t(array([234], "f")) - 234.0) <= err
|
||||
assert abs(t(array([234], "d")) - 234.0) <= err
|
||||
assert abs(t(array([234 + 3j], "F")) - (234 + 3j)) <= err
|
||||
assert abs(t(array([234], "D")) - 234.0) <= err
|
||||
|
||||
# pytest.raises(TypeError, t, array([234], 'a1'))
|
||||
pytest.raises(TypeError, t, "abc")
|
||||
|
||||
pytest.raises(IndexError, t, [])
|
||||
pytest.raises(IndexError, t, ())
|
||||
|
||||
pytest.raises(TypeError, t, t)
|
||||
pytest.raises(TypeError, t, {})
|
||||
|
||||
try:
|
||||
r = t(10**400)
|
||||
assert repr(r) in ["(inf+0j)", "(Infinity+0j)"]
|
||||
except OverflowError:
|
||||
pass
|
||||
|
||||
|
||||
class TestFReturnComplex(TestReturnComplex):
|
||||
sources = [
|
||||
util.getpath("tests", "src", "return_complex", "foo77.f"),
|
||||
util.getpath("tests", "src", "return_complex", "foo90.f90"),
|
||||
]
|
||||
|
||||
@pytest.mark.parametrize("name", "t0,t8,t16,td,s0,s8,s16,sd".split(","))
|
||||
def test_all_f77(self, name):
|
||||
self.check_function(getattr(self.module, name), name)
|
||||
|
||||
@pytest.mark.parametrize("name", "t0,t8,t16,td,s0,s8,s16,sd".split(","))
|
||||
def test_all_f90(self, name):
|
||||
self.check_function(getattr(self.module.f90_return_complex, name),
|
||||
name)
|
||||
@@ -0,0 +1,55 @@
|
||||
import pytest
|
||||
|
||||
from numpy import array
|
||||
from . import util
|
||||
|
||||
|
||||
class TestReturnInteger(util.F2PyTest):
|
||||
def check_function(self, t, tname):
|
||||
assert t(123) == 123
|
||||
assert t(123.6) == 123
|
||||
assert t("123") == 123
|
||||
assert t(-123) == -123
|
||||
assert t([123]) == 123
|
||||
assert t((123, )) == 123
|
||||
assert t(array(123)) == 123
|
||||
assert t(array([123])) == 123
|
||||
assert t(array([[123]])) == 123
|
||||
assert t(array([123], "b")) == 123
|
||||
assert t(array([123], "h")) == 123
|
||||
assert t(array([123], "i")) == 123
|
||||
assert t(array([123], "l")) == 123
|
||||
assert t(array([123], "B")) == 123
|
||||
assert t(array([123], "f")) == 123
|
||||
assert t(array([123], "d")) == 123
|
||||
|
||||
# pytest.raises(ValueError, t, array([123],'S3'))
|
||||
pytest.raises(ValueError, t, "abc")
|
||||
|
||||
pytest.raises(IndexError, t, [])
|
||||
pytest.raises(IndexError, t, ())
|
||||
|
||||
pytest.raises(Exception, t, t)
|
||||
pytest.raises(Exception, t, {})
|
||||
|
||||
if tname in ["t8", "s8"]:
|
||||
pytest.raises(OverflowError, t, 100000000000000000000000)
|
||||
pytest.raises(OverflowError, t, 10000000011111111111111.23)
|
||||
|
||||
|
||||
class TestFReturnInteger(TestReturnInteger):
|
||||
sources = [
|
||||
util.getpath("tests", "src", "return_integer", "foo77.f"),
|
||||
util.getpath("tests", "src", "return_integer", "foo90.f90"),
|
||||
]
|
||||
|
||||
@pytest.mark.parametrize("name",
|
||||
"t0,t1,t2,t4,t8,s0,s1,s2,s4,s8".split(","))
|
||||
def test_all_f77(self, name):
|
||||
self.check_function(getattr(self.module, name), name)
|
||||
|
||||
@pytest.mark.parametrize("name",
|
||||
"t0,t1,t2,t4,t8,s0,s1,s2,s4,s8".split(","))
|
||||
def test_all_f90(self, name):
|
||||
self.check_function(getattr(self.module.f90_return_integer, name),
|
||||
name)
|
||||
@@ -0,0 +1,64 @@
|
||||
import pytest
|
||||
|
||||
from numpy import array
|
||||
from . import util
|
||||
|
||||
|
||||
class TestReturnLogical(util.F2PyTest):
|
||||
def check_function(self, t):
|
||||
assert t(True) == 1
|
||||
assert t(False) == 0
|
||||
assert t(0) == 0
|
||||
assert t(None) == 0
|
||||
assert t(0.0) == 0
|
||||
assert t(0j) == 0
|
||||
assert t(1j) == 1
|
||||
assert t(234) == 1
|
||||
assert t(234.6) == 1
|
||||
assert t(234.6 + 3j) == 1
|
||||
assert t("234") == 1
|
||||
assert t("aaa") == 1
|
||||
assert t("") == 0
|
||||
assert t([]) == 0
|
||||
assert t(()) == 0
|
||||
assert t({}) == 0
|
||||
assert t(t) == 1
|
||||
assert t(-234) == 1
|
||||
assert t(10**100) == 1
|
||||
assert t([234]) == 1
|
||||
assert t((234, )) == 1
|
||||
assert t(array(234)) == 1
|
||||
assert t(array([234])) == 1
|
||||
assert t(array([[234]])) == 1
|
||||
assert t(array([127], "b")) == 1
|
||||
assert t(array([234], "h")) == 1
|
||||
assert t(array([234], "i")) == 1
|
||||
assert t(array([234], "l")) == 1
|
||||
assert t(array([234], "f")) == 1
|
||||
assert t(array([234], "d")) == 1
|
||||
assert t(array([234 + 3j], "F")) == 1
|
||||
assert t(array([234], "D")) == 1
|
||||
assert t(array(0)) == 0
|
||||
assert t(array([0])) == 0
|
||||
assert t(array([[0]])) == 0
|
||||
assert t(array([0j])) == 0
|
||||
assert t(array([1])) == 1
|
||||
pytest.raises(ValueError, t, array([0, 0]))
|
||||
|
||||
|
||||
class TestFReturnLogical(TestReturnLogical):
|
||||
sources = [
|
||||
util.getpath("tests", "src", "return_logical", "foo77.f"),
|
||||
util.getpath("tests", "src", "return_logical", "foo90.f90"),
|
||||
]
|
||||
|
||||
@pytest.mark.slow
|
||||
@pytest.mark.parametrize("name", "t0,t1,t2,t4,s0,s1,s2,s4".split(","))
|
||||
def test_all_f77(self, name):
|
||||
self.check_function(getattr(self.module, name))
|
||||
|
||||
@pytest.mark.slow
|
||||
@pytest.mark.parametrize("name",
|
||||
"t0,t1,t2,t4,t8,s0,s1,s2,s4,s8".split(","))
|
||||
def test_all_f90(self, name):
|
||||
self.check_function(getattr(self.module.f90_return_logical, name))
|
||||
@@ -0,0 +1,109 @@
|
||||
import platform
|
||||
import pytest
|
||||
import numpy as np
|
||||
|
||||
from numpy import array
|
||||
from . import util
|
||||
|
||||
|
||||
class TestReturnReal(util.F2PyTest):
|
||||
def check_function(self, t, tname):
|
||||
if tname in ["t0", "t4", "s0", "s4"]:
|
||||
err = 1e-5
|
||||
else:
|
||||
err = 0.0
|
||||
assert abs(t(234) - 234.0) <= err
|
||||
assert abs(t(234.6) - 234.6) <= err
|
||||
assert abs(t("234") - 234) <= err
|
||||
assert abs(t("234.6") - 234.6) <= err
|
||||
assert abs(t(-234) + 234) <= err
|
||||
assert abs(t([234]) - 234) <= err
|
||||
assert abs(t((234, )) - 234.0) <= err
|
||||
assert abs(t(array(234)) - 234.0) <= err
|
||||
assert abs(t(array([234])) - 234.0) <= err
|
||||
assert abs(t(array([[234]])) - 234.0) <= err
|
||||
assert abs(t(array([234]).astype("b")) + 22) <= err
|
||||
assert abs(t(array([234], "h")) - 234.0) <= err
|
||||
assert abs(t(array([234], "i")) - 234.0) <= err
|
||||
assert abs(t(array([234], "l")) - 234.0) <= err
|
||||
assert abs(t(array([234], "B")) - 234.0) <= err
|
||||
assert abs(t(array([234], "f")) - 234.0) <= err
|
||||
assert abs(t(array([234], "d")) - 234.0) <= err
|
||||
if tname in ["t0", "t4", "s0", "s4"]:
|
||||
assert t(1e200) == t(1e300) # inf
|
||||
|
||||
# pytest.raises(ValueError, t, array([234], 'S1'))
|
||||
pytest.raises(ValueError, t, "abc")
|
||||
|
||||
pytest.raises(IndexError, t, [])
|
||||
pytest.raises(IndexError, t, ())
|
||||
|
||||
pytest.raises(Exception, t, t)
|
||||
pytest.raises(Exception, t, {})
|
||||
|
||||
try:
|
||||
r = t(10**400)
|
||||
assert repr(r) in ["inf", "Infinity"]
|
||||
except OverflowError:
|
||||
pass
|
||||
|
||||
|
||||
@pytest.mark.skipif(
|
||||
platform.system() == "Darwin",
|
||||
reason="Prone to error when run with numpy/f2py/tests on mac os, "
|
||||
"but not when run in isolation",
|
||||
)
|
||||
@pytest.mark.skipif(
|
||||
np.dtype(np.intp).itemsize < 8,
|
||||
reason="32-bit builds are buggy"
|
||||
)
|
||||
class TestCReturnReal(TestReturnReal):
|
||||
suffix = ".pyf"
|
||||
module_name = "c_ext_return_real"
|
||||
code = """
|
||||
python module c_ext_return_real
|
||||
usercode \'\'\'
|
||||
float t4(float value) { return value; }
|
||||
void s4(float *t4, float value) { *t4 = value; }
|
||||
double t8(double value) { return value; }
|
||||
void s8(double *t8, double value) { *t8 = value; }
|
||||
\'\'\'
|
||||
interface
|
||||
function t4(value)
|
||||
real*4 intent(c) :: t4,value
|
||||
end
|
||||
function t8(value)
|
||||
real*8 intent(c) :: t8,value
|
||||
end
|
||||
subroutine s4(t4,value)
|
||||
intent(c) s4
|
||||
real*4 intent(out) :: t4
|
||||
real*4 intent(c) :: value
|
||||
end
|
||||
subroutine s8(t8,value)
|
||||
intent(c) s8
|
||||
real*8 intent(out) :: t8
|
||||
real*8 intent(c) :: value
|
||||
end
|
||||
end interface
|
||||
end python module c_ext_return_real
|
||||
"""
|
||||
|
||||
@pytest.mark.parametrize("name", "t4,t8,s4,s8".split(","))
|
||||
def test_all(self, name):
|
||||
self.check_function(getattr(self.module, name), name)
|
||||
|
||||
|
||||
class TestFReturnReal(TestReturnReal):
|
||||
sources = [
|
||||
util.getpath("tests", "src", "return_real", "foo77.f"),
|
||||
util.getpath("tests", "src", "return_real", "foo90.f90"),
|
||||
]
|
||||
|
||||
@pytest.mark.parametrize("name", "t0,t4,t8,td,s0,s4,s8,sd".split(","))
|
||||
def test_all_f77(self, name):
|
||||
self.check_function(getattr(self.module, name), name)
|
||||
|
||||
@pytest.mark.parametrize("name", "t0,t4,t8,td,s0,s4,s8,sd".split(","))
|
||||
def test_all_f90(self, name):
|
||||
self.check_function(getattr(self.module.f90_return_real, name), name)
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user