Add files using upload-large-folder tool
Browse filesThis view is limited to 50 files because it contains too many changes.
See raw diff
- .gitattributes +3 -0
- .venv/lib/python3.11/site-packages/numpy/f2py/__init__.py +194 -0
- .venv/lib/python3.11/site-packages/numpy/f2py/__pycache__/__main__.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/numpy/f2py/__pycache__/__version__.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/numpy/f2py/__pycache__/_src_pyf.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/numpy/f2py/__pycache__/cb_rules.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/numpy/f2py/__pycache__/cfuncs.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/numpy/f2py/__pycache__/common_rules.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/numpy/f2py/__pycache__/diagnose.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/numpy/f2py/__pycache__/f2py2e.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/numpy/f2py/__pycache__/f90mod_rules.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/numpy/f2py/__pycache__/func2subr.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/numpy/f2py/_backends/__init__.py +9 -0
- .venv/lib/python3.11/site-packages/numpy/f2py/_backends/__pycache__/__init__.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/numpy/f2py/_backends/__pycache__/_backend.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/numpy/f2py/_backends/__pycache__/_distutils.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/numpy/f2py/_backends/__pycache__/_meson.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/numpy/f2py/_backends/_backend.py +46 -0
- .venv/lib/python3.11/site-packages/numpy/f2py/_backends/_distutils.py +75 -0
- .venv/lib/python3.11/site-packages/numpy/f2py/_backends/_meson.py +205 -0
- .venv/lib/python3.11/site-packages/numpy/f2py/_backends/meson.build.template +54 -0
- .venv/lib/python3.11/site-packages/numpy/f2py/_isocbind.py +62 -0
- .venv/lib/python3.11/site-packages/numpy/f2py/_src_pyf.py +239 -0
- .venv/lib/python3.11/site-packages/numpy/f2py/capi_maps.py +819 -0
- .venv/lib/python3.11/site-packages/numpy/f2py/common_rules.py +146 -0
- .venv/lib/python3.11/site-packages/numpy/f2py/crackfortran.py +0 -0
- .venv/lib/python3.11/site-packages/numpy/f2py/diagnose.py +154 -0
- .venv/lib/python3.11/site-packages/numpy/f2py/f2py2e.py +768 -0
- .venv/lib/python3.11/site-packages/numpy/f2py/func2subr.py +323 -0
- .venv/lib/python3.11/site-packages/numpy/f2py/rules.py +1568 -0
- .venv/lib/python3.11/site-packages/numpy/f2py/setup.py +74 -0
- .venv/lib/python3.11/site-packages/numpy/f2py/tests/__init__.py +0 -0
- .venv/lib/python3.11/site-packages/numpy/f2py/tests/__pycache__/test_abstract_interface.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/numpy/f2py/tests/__pycache__/test_common.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/numpy/f2py/tests/__pycache__/test_data.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/numpy/f2py/tests/__pycache__/test_f2cmap.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/numpy/f2py/tests/__pycache__/test_regression.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/numpy/f2py/tests/__pycache__/test_semicolon_split.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/numpy/f2py/tests/test_abstract_interface.py +25 -0
- .venv/lib/python3.11/site-packages/numpy/f2py/tests/test_array_from_pyobj.py +686 -0
- .venv/lib/python3.11/site-packages/numpy/f2py/tests/test_assumed_shape.py +49 -0
- .venv/lib/python3.11/site-packages/numpy/f2py/tests/test_block_docstring.py +17 -0
- .venv/lib/python3.11/site-packages/numpy/f2py/tests/test_callback.py +243 -0
- .venv/lib/python3.11/site-packages/numpy/f2py/tests/test_character.py +636 -0
- .venv/lib/python3.11/site-packages/numpy/f2py/tests/test_common.py +27 -0
- .venv/lib/python3.11/site-packages/numpy/f2py/tests/test_compile_function.py +117 -0
- .venv/lib/python3.11/site-packages/numpy/f2py/tests/test_crackfortran.py +350 -0
- .venv/lib/python3.11/site-packages/numpy/f2py/tests/test_data.py +70 -0
- .venv/lib/python3.11/site-packages/numpy/f2py/tests/test_docs.py +55 -0
- .venv/lib/python3.11/site-packages/numpy/f2py/tests/test_f2cmap.py +15 -0
.gitattributes
CHANGED
@@ -388,3 +388,6 @@ tuning-competition-baseline/.venv/lib/python3.11/site-packages/nvidia/cudnn/lib/
|
|
388 |
.venv/lib/python3.11/site-packages/numpy/testing/_private/__pycache__/utils.cpython-311.pyc filter=lfs diff=lfs merge=lfs -text
|
389 |
.venv/lib/python3.11/site-packages/numpy/ma/__pycache__/core.cpython-311.pyc filter=lfs diff=lfs merge=lfs -text
|
390 |
.venv/lib/python3.11/site-packages/numpy/testing/tests/__pycache__/test_utils.cpython-311.pyc filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
388 |
.venv/lib/python3.11/site-packages/numpy/testing/_private/__pycache__/utils.cpython-311.pyc filter=lfs diff=lfs merge=lfs -text
|
389 |
.venv/lib/python3.11/site-packages/numpy/ma/__pycache__/core.cpython-311.pyc filter=lfs diff=lfs merge=lfs -text
|
390 |
.venv/lib/python3.11/site-packages/numpy/testing/tests/__pycache__/test_utils.cpython-311.pyc filter=lfs diff=lfs merge=lfs -text
|
391 |
+
.venv/lib/python3.11/site-packages/numpy/lib/__pycache__/function_base.cpython-311.pyc filter=lfs diff=lfs merge=lfs -text
|
392 |
+
.venv/lib/python3.11/site-packages/numpy/lib/__pycache__/npyio.cpython-311.pyc filter=lfs diff=lfs merge=lfs -text
|
393 |
+
.venv/lib/python3.11/site-packages/numpy/lib/tests/__pycache__/test_function_base.cpython-311.pyc filter=lfs diff=lfs merge=lfs -text
|
.venv/lib/python3.11/site-packages/numpy/f2py/__init__.py
ADDED
@@ -0,0 +1,194 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#!/usr/bin/env python3
|
2 |
+
"""Fortran to Python Interface Generator.
|
3 |
+
|
4 |
+
Copyright 1999 -- 2011 Pearu Peterson all rights reserved.
|
5 |
+
Copyright 2011 -- present NumPy Developers.
|
6 |
+
Permission to use, modify, and distribute this software is given under the terms
|
7 |
+
of the NumPy License.
|
8 |
+
|
9 |
+
NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
|
10 |
+
"""
|
11 |
+
__all__ = ['run_main', 'compile', 'get_include']
|
12 |
+
|
13 |
+
import sys
|
14 |
+
import subprocess
|
15 |
+
import os
|
16 |
+
import warnings
|
17 |
+
|
18 |
+
from numpy.exceptions import VisibleDeprecationWarning
|
19 |
+
from . import f2py2e
|
20 |
+
from . import diagnose
|
21 |
+
|
22 |
+
run_main = f2py2e.run_main
|
23 |
+
main = f2py2e.main
|
24 |
+
|
25 |
+
|
26 |
+
def compile(source,
|
27 |
+
modulename='untitled',
|
28 |
+
extra_args='',
|
29 |
+
verbose=True,
|
30 |
+
source_fn=None,
|
31 |
+
extension='.f',
|
32 |
+
full_output=False
|
33 |
+
):
|
34 |
+
"""
|
35 |
+
Build extension module from a Fortran 77 source string with f2py.
|
36 |
+
|
37 |
+
Parameters
|
38 |
+
----------
|
39 |
+
source : str or bytes
|
40 |
+
Fortran source of module / subroutine to compile
|
41 |
+
|
42 |
+
.. versionchanged:: 1.16.0
|
43 |
+
Accept str as well as bytes
|
44 |
+
|
45 |
+
modulename : str, optional
|
46 |
+
The name of the compiled python module
|
47 |
+
extra_args : str or list, optional
|
48 |
+
Additional parameters passed to f2py
|
49 |
+
|
50 |
+
.. versionchanged:: 1.16.0
|
51 |
+
A list of args may also be provided.
|
52 |
+
|
53 |
+
verbose : bool, optional
|
54 |
+
Print f2py output to screen
|
55 |
+
source_fn : str, optional
|
56 |
+
Name of the file where the fortran source is written.
|
57 |
+
The default is to use a temporary file with the extension
|
58 |
+
provided by the ``extension`` parameter
|
59 |
+
extension : ``{'.f', '.f90'}``, optional
|
60 |
+
Filename extension if `source_fn` is not provided.
|
61 |
+
The extension tells which fortran standard is used.
|
62 |
+
The default is ``.f``, which implies F77 standard.
|
63 |
+
|
64 |
+
.. versionadded:: 1.11.0
|
65 |
+
|
66 |
+
full_output : bool, optional
|
67 |
+
If True, return a `subprocess.CompletedProcess` containing
|
68 |
+
the stdout and stderr of the compile process, instead of just
|
69 |
+
the status code.
|
70 |
+
|
71 |
+
.. versionadded:: 1.20.0
|
72 |
+
|
73 |
+
|
74 |
+
Returns
|
75 |
+
-------
|
76 |
+
result : int or `subprocess.CompletedProcess`
|
77 |
+
0 on success, or a `subprocess.CompletedProcess` if
|
78 |
+
``full_output=True``
|
79 |
+
|
80 |
+
Examples
|
81 |
+
--------
|
82 |
+
.. literalinclude:: ../../source/f2py/code/results/compile_session.dat
|
83 |
+
:language: python
|
84 |
+
|
85 |
+
"""
|
86 |
+
import tempfile
|
87 |
+
import shlex
|
88 |
+
|
89 |
+
if source_fn is None:
|
90 |
+
f, fname = tempfile.mkstemp(suffix=extension)
|
91 |
+
# f is a file descriptor so need to close it
|
92 |
+
# carefully -- not with .close() directly
|
93 |
+
os.close(f)
|
94 |
+
else:
|
95 |
+
fname = source_fn
|
96 |
+
|
97 |
+
if not isinstance(source, str):
|
98 |
+
source = str(source, 'utf-8')
|
99 |
+
try:
|
100 |
+
with open(fname, 'w') as f:
|
101 |
+
f.write(source)
|
102 |
+
|
103 |
+
args = ['-c', '-m', modulename, f.name]
|
104 |
+
|
105 |
+
if isinstance(extra_args, str):
|
106 |
+
is_posix = (os.name == 'posix')
|
107 |
+
extra_args = shlex.split(extra_args, posix=is_posix)
|
108 |
+
|
109 |
+
args.extend(extra_args)
|
110 |
+
|
111 |
+
c = [sys.executable,
|
112 |
+
'-c',
|
113 |
+
'import numpy.f2py as f2py2e;f2py2e.main()'] + args
|
114 |
+
try:
|
115 |
+
cp = subprocess.run(c, capture_output=True)
|
116 |
+
except OSError:
|
117 |
+
# preserve historic status code used by exec_command()
|
118 |
+
cp = subprocess.CompletedProcess(c, 127, stdout=b'', stderr=b'')
|
119 |
+
else:
|
120 |
+
if verbose:
|
121 |
+
print(cp.stdout.decode())
|
122 |
+
finally:
|
123 |
+
if source_fn is None:
|
124 |
+
os.remove(fname)
|
125 |
+
|
126 |
+
if full_output:
|
127 |
+
return cp
|
128 |
+
else:
|
129 |
+
return cp.returncode
|
130 |
+
|
131 |
+
|
132 |
+
def get_include():
|
133 |
+
"""
|
134 |
+
Return the directory that contains the ``fortranobject.c`` and ``.h`` files.
|
135 |
+
|
136 |
+
.. note::
|
137 |
+
|
138 |
+
This function is not needed when building an extension with
|
139 |
+
`numpy.distutils` directly from ``.f`` and/or ``.pyf`` files
|
140 |
+
in one go.
|
141 |
+
|
142 |
+
Python extension modules built with f2py-generated code need to use
|
143 |
+
``fortranobject.c`` as a source file, and include the ``fortranobject.h``
|
144 |
+
header. This function can be used to obtain the directory containing
|
145 |
+
both of these files.
|
146 |
+
|
147 |
+
Returns
|
148 |
+
-------
|
149 |
+
include_path : str
|
150 |
+
Absolute path to the directory containing ``fortranobject.c`` and
|
151 |
+
``fortranobject.h``.
|
152 |
+
|
153 |
+
Notes
|
154 |
+
-----
|
155 |
+
.. versionadded:: 1.21.1
|
156 |
+
|
157 |
+
Unless the build system you are using has specific support for f2py,
|
158 |
+
building a Python extension using a ``.pyf`` signature file is a two-step
|
159 |
+
process. For a module ``mymod``:
|
160 |
+
|
161 |
+
* Step 1: run ``python -m numpy.f2py mymod.pyf --quiet``. This
|
162 |
+
generates ``_mymodmodule.c`` and (if needed)
|
163 |
+
``_fblas-f2pywrappers.f`` files next to ``mymod.pyf``.
|
164 |
+
* Step 2: build your Python extension module. This requires the
|
165 |
+
following source files:
|
166 |
+
|
167 |
+
* ``_mymodmodule.c``
|
168 |
+
* ``_mymod-f2pywrappers.f`` (if it was generated in Step 1)
|
169 |
+
* ``fortranobject.c``
|
170 |
+
|
171 |
+
See Also
|
172 |
+
--------
|
173 |
+
numpy.get_include : function that returns the numpy include directory
|
174 |
+
|
175 |
+
"""
|
176 |
+
return os.path.join(os.path.dirname(__file__), 'src')
|
177 |
+
|
178 |
+
|
179 |
+
def __getattr__(attr):
|
180 |
+
|
181 |
+
# Avoid importing things that aren't needed for building
|
182 |
+
# which might import the main numpy module
|
183 |
+
if attr == "test":
|
184 |
+
from numpy._pytesttester import PytestTester
|
185 |
+
test = PytestTester(__name__)
|
186 |
+
return test
|
187 |
+
|
188 |
+
else:
|
189 |
+
raise AttributeError("module {!r} has no attribute "
|
190 |
+
"{!r}".format(__name__, attr))
|
191 |
+
|
192 |
+
|
193 |
+
def __dir__():
|
194 |
+
return list(globals().keys() | {"test"})
|
.venv/lib/python3.11/site-packages/numpy/f2py/__pycache__/__main__.cpython-311.pyc
ADDED
Binary file (274 Bytes). View file
|
|
.venv/lib/python3.11/site-packages/numpy/f2py/__pycache__/__version__.cpython-311.pyc
ADDED
Binary file (245 Bytes). View file
|
|
.venv/lib/python3.11/site-packages/numpy/f2py/__pycache__/_src_pyf.cpython-311.pyc
ADDED
Binary file (10.3 kB). View file
|
|
.venv/lib/python3.11/site-packages/numpy/f2py/__pycache__/cb_rules.cpython-311.pyc
ADDED
Binary file (24.4 kB). View file
|
|
.venv/lib/python3.11/site-packages/numpy/f2py/__pycache__/cfuncs.cpython-311.pyc
ADDED
Binary file (49.9 kB). View file
|
|
.venv/lib/python3.11/site-packages/numpy/f2py/__pycache__/common_rules.cpython-311.pyc
ADDED
Binary file (9.08 kB). View file
|
|
.venv/lib/python3.11/site-packages/numpy/f2py/__pycache__/diagnose.cpython-311.pyc
ADDED
Binary file (8.29 kB). View file
|
|
.venv/lib/python3.11/site-packages/numpy/f2py/__pycache__/f2py2e.cpython-311.pyc
ADDED
Binary file (38.3 kB). View file
|
|
.venv/lib/python3.11/site-packages/numpy/f2py/__pycache__/f90mod_rules.cpython-311.pyc
ADDED
Binary file (14.2 kB). View file
|
|
.venv/lib/python3.11/site-packages/numpy/f2py/__pycache__/func2subr.cpython-311.pyc
ADDED
Binary file (14.5 kB). View file
|
|
.venv/lib/python3.11/site-packages/numpy/f2py/_backends/__init__.py
ADDED
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
def f2py_build_generator(name):
|
2 |
+
if name == "meson":
|
3 |
+
from ._meson import MesonBackend
|
4 |
+
return MesonBackend
|
5 |
+
elif name == "distutils":
|
6 |
+
from ._distutils import DistutilsBackend
|
7 |
+
return DistutilsBackend
|
8 |
+
else:
|
9 |
+
raise ValueError(f"Unknown backend: {name}")
|
.venv/lib/python3.11/site-packages/numpy/f2py/_backends/__pycache__/__init__.cpython-311.pyc
ADDED
Binary file (626 Bytes). View file
|
|
.venv/lib/python3.11/site-packages/numpy/f2py/_backends/__pycache__/_backend.cpython-311.pyc
ADDED
Binary file (1.56 kB). View file
|
|
.venv/lib/python3.11/site-packages/numpy/f2py/_backends/__pycache__/_distutils.cpython-311.pyc
ADDED
Binary file (3.74 kB). View file
|
|
.venv/lib/python3.11/site-packages/numpy/f2py/_backends/__pycache__/_meson.cpython-311.pyc
ADDED
Binary file (13.1 kB). View file
|
|
.venv/lib/python3.11/site-packages/numpy/f2py/_backends/_backend.py
ADDED
@@ -0,0 +1,46 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from __future__ import annotations
|
2 |
+
|
3 |
+
from abc import ABC, abstractmethod
|
4 |
+
|
5 |
+
|
6 |
+
class Backend(ABC):
|
7 |
+
def __init__(
|
8 |
+
self,
|
9 |
+
modulename,
|
10 |
+
sources,
|
11 |
+
extra_objects,
|
12 |
+
build_dir,
|
13 |
+
include_dirs,
|
14 |
+
library_dirs,
|
15 |
+
libraries,
|
16 |
+
define_macros,
|
17 |
+
undef_macros,
|
18 |
+
f2py_flags,
|
19 |
+
sysinfo_flags,
|
20 |
+
fc_flags,
|
21 |
+
flib_flags,
|
22 |
+
setup_flags,
|
23 |
+
remove_build_dir,
|
24 |
+
extra_dat,
|
25 |
+
):
|
26 |
+
self.modulename = modulename
|
27 |
+
self.sources = sources
|
28 |
+
self.extra_objects = extra_objects
|
29 |
+
self.build_dir = build_dir
|
30 |
+
self.include_dirs = include_dirs
|
31 |
+
self.library_dirs = library_dirs
|
32 |
+
self.libraries = libraries
|
33 |
+
self.define_macros = define_macros
|
34 |
+
self.undef_macros = undef_macros
|
35 |
+
self.f2py_flags = f2py_flags
|
36 |
+
self.sysinfo_flags = sysinfo_flags
|
37 |
+
self.fc_flags = fc_flags
|
38 |
+
self.flib_flags = flib_flags
|
39 |
+
self.setup_flags = setup_flags
|
40 |
+
self.remove_build_dir = remove_build_dir
|
41 |
+
self.extra_dat = extra_dat
|
42 |
+
|
43 |
+
@abstractmethod
|
44 |
+
def compile(self) -> None:
|
45 |
+
"""Compile the wrapper."""
|
46 |
+
pass
|
.venv/lib/python3.11/site-packages/numpy/f2py/_backends/_distutils.py
ADDED
@@ -0,0 +1,75 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from ._backend import Backend
|
2 |
+
|
3 |
+
from numpy.distutils.core import setup, Extension
|
4 |
+
from numpy.distutils.system_info import get_info
|
5 |
+
from numpy.distutils.misc_util import dict_append
|
6 |
+
from numpy.exceptions import VisibleDeprecationWarning
|
7 |
+
import os
|
8 |
+
import sys
|
9 |
+
import shutil
|
10 |
+
import warnings
|
11 |
+
|
12 |
+
|
13 |
+
class DistutilsBackend(Backend):
|
14 |
+
def __init__(sef, *args, **kwargs):
|
15 |
+
warnings.warn(
|
16 |
+
"distutils has been deprecated since NumPy 1.26.x"
|
17 |
+
"Use the Meson backend instead, or generate wrappers"
|
18 |
+
"without -c and use a custom build script",
|
19 |
+
VisibleDeprecationWarning,
|
20 |
+
stacklevel=2,
|
21 |
+
)
|
22 |
+
super().__init__(*args, **kwargs)
|
23 |
+
|
24 |
+
def compile(self):
|
25 |
+
num_info = {}
|
26 |
+
if num_info:
|
27 |
+
self.include_dirs.extend(num_info.get("include_dirs", []))
|
28 |
+
ext_args = {
|
29 |
+
"name": self.modulename,
|
30 |
+
"sources": self.sources,
|
31 |
+
"include_dirs": self.include_dirs,
|
32 |
+
"library_dirs": self.library_dirs,
|
33 |
+
"libraries": self.libraries,
|
34 |
+
"define_macros": self.define_macros,
|
35 |
+
"undef_macros": self.undef_macros,
|
36 |
+
"extra_objects": self.extra_objects,
|
37 |
+
"f2py_options": self.f2py_flags,
|
38 |
+
}
|
39 |
+
|
40 |
+
if self.sysinfo_flags:
|
41 |
+
for n in self.sysinfo_flags:
|
42 |
+
i = get_info(n)
|
43 |
+
if not i:
|
44 |
+
print(
|
45 |
+
f"No {repr(n)} resources found"
|
46 |
+
"in system (try `f2py --help-link`)"
|
47 |
+
)
|
48 |
+
dict_append(ext_args, **i)
|
49 |
+
|
50 |
+
ext = Extension(**ext_args)
|
51 |
+
|
52 |
+
sys.argv = [sys.argv[0]] + self.setup_flags
|
53 |
+
sys.argv.extend(
|
54 |
+
[
|
55 |
+
"build",
|
56 |
+
"--build-temp",
|
57 |
+
self.build_dir,
|
58 |
+
"--build-base",
|
59 |
+
self.build_dir,
|
60 |
+
"--build-platlib",
|
61 |
+
".",
|
62 |
+
"--disable-optimization",
|
63 |
+
]
|
64 |
+
)
|
65 |
+
|
66 |
+
if self.fc_flags:
|
67 |
+
sys.argv.extend(["config_fc"] + self.fc_flags)
|
68 |
+
if self.flib_flags:
|
69 |
+
sys.argv.extend(["build_ext"] + self.flib_flags)
|
70 |
+
|
71 |
+
setup(ext_modules=[ext])
|
72 |
+
|
73 |
+
if self.remove_build_dir and os.path.exists(self.build_dir):
|
74 |
+
print(f"Removing build directory {self.build_dir}")
|
75 |
+
shutil.rmtree(self.build_dir)
|
.venv/lib/python3.11/site-packages/numpy/f2py/_backends/_meson.py
ADDED
@@ -0,0 +1,205 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from __future__ import annotations
|
2 |
+
|
3 |
+
import os
|
4 |
+
import errno
|
5 |
+
import shutil
|
6 |
+
import subprocess
|
7 |
+
import sys
|
8 |
+
from pathlib import Path
|
9 |
+
|
10 |
+
from ._backend import Backend
|
11 |
+
from string import Template
|
12 |
+
from itertools import chain
|
13 |
+
|
14 |
+
import warnings
|
15 |
+
|
16 |
+
|
17 |
+
class MesonTemplate:
|
18 |
+
"""Template meson build file generation class."""
|
19 |
+
|
20 |
+
def __init__(
|
21 |
+
self,
|
22 |
+
modulename: str,
|
23 |
+
sources: list[Path],
|
24 |
+
deps: list[str],
|
25 |
+
libraries: list[str],
|
26 |
+
library_dirs: list[Path],
|
27 |
+
include_dirs: list[Path],
|
28 |
+
object_files: list[Path],
|
29 |
+
linker_args: list[str],
|
30 |
+
c_args: list[str],
|
31 |
+
build_type: str,
|
32 |
+
python_exe: str,
|
33 |
+
):
|
34 |
+
self.modulename = modulename
|
35 |
+
self.build_template_path = (
|
36 |
+
Path(__file__).parent.absolute() / "meson.build.template"
|
37 |
+
)
|
38 |
+
self.sources = sources
|
39 |
+
self.deps = deps
|
40 |
+
self.libraries = libraries
|
41 |
+
self.library_dirs = library_dirs
|
42 |
+
if include_dirs is not None:
|
43 |
+
self.include_dirs = include_dirs
|
44 |
+
else:
|
45 |
+
self.include_dirs = []
|
46 |
+
self.substitutions = {}
|
47 |
+
self.objects = object_files
|
48 |
+
self.pipeline = [
|
49 |
+
self.initialize_template,
|
50 |
+
self.sources_substitution,
|
51 |
+
self.deps_substitution,
|
52 |
+
self.include_substitution,
|
53 |
+
self.libraries_substitution,
|
54 |
+
]
|
55 |
+
self.build_type = build_type
|
56 |
+
self.python_exe = python_exe
|
57 |
+
|
58 |
+
def meson_build_template(self) -> str:
|
59 |
+
if not self.build_template_path.is_file():
|
60 |
+
raise FileNotFoundError(
|
61 |
+
errno.ENOENT,
|
62 |
+
"Meson build template"
|
63 |
+
f" {self.build_template_path.absolute()}"
|
64 |
+
" does not exist.",
|
65 |
+
)
|
66 |
+
return self.build_template_path.read_text()
|
67 |
+
|
68 |
+
def initialize_template(self) -> None:
|
69 |
+
self.substitutions["modulename"] = self.modulename
|
70 |
+
self.substitutions["buildtype"] = self.build_type
|
71 |
+
self.substitutions["python"] = self.python_exe
|
72 |
+
|
73 |
+
def sources_substitution(self) -> None:
|
74 |
+
indent = " " * 21
|
75 |
+
self.substitutions["source_list"] = f",\n{indent}".join(
|
76 |
+
[f"{indent}'{source}'" for source in self.sources]
|
77 |
+
)
|
78 |
+
|
79 |
+
def deps_substitution(self) -> None:
|
80 |
+
indent = " " * 21
|
81 |
+
self.substitutions["dep_list"] = f",\n{indent}".join(
|
82 |
+
[f"{indent}dependency('{dep}')" for dep in self.deps]
|
83 |
+
)
|
84 |
+
|
85 |
+
def libraries_substitution(self) -> None:
|
86 |
+
self.substitutions["lib_dir_declarations"] = "\n".join(
|
87 |
+
[
|
88 |
+
f"lib_dir_{i} = declare_dependency(link_args : ['-L{lib_dir}'])"
|
89 |
+
for i, lib_dir in enumerate(self.library_dirs)
|
90 |
+
]
|
91 |
+
)
|
92 |
+
|
93 |
+
self.substitutions["lib_declarations"] = "\n".join(
|
94 |
+
[
|
95 |
+
f"{lib} = declare_dependency(link_args : ['-l{lib}'])"
|
96 |
+
for lib in self.libraries
|
97 |
+
]
|
98 |
+
)
|
99 |
+
|
100 |
+
indent = " " * 21
|
101 |
+
self.substitutions["lib_list"] = f"\n{indent}".join(
|
102 |
+
[f"{indent}{lib}," for lib in self.libraries]
|
103 |
+
)
|
104 |
+
self.substitutions["lib_dir_list"] = f"\n{indent}".join(
|
105 |
+
[f"{indent}lib_dir_{i}," for i in range(len(self.library_dirs))]
|
106 |
+
)
|
107 |
+
|
108 |
+
def include_substitution(self) -> None:
|
109 |
+
indent = " " * 21
|
110 |
+
self.substitutions["inc_list"] = f",\n{indent}".join(
|
111 |
+
[f"{indent}'{inc}'" for inc in self.include_dirs]
|
112 |
+
)
|
113 |
+
|
114 |
+
def generate_meson_build(self):
|
115 |
+
for node in self.pipeline:
|
116 |
+
node()
|
117 |
+
template = Template(self.meson_build_template())
|
118 |
+
return template.substitute(self.substitutions)
|
119 |
+
|
120 |
+
|
121 |
+
class MesonBackend(Backend):
|
122 |
+
def __init__(self, *args, **kwargs):
|
123 |
+
super().__init__(*args, **kwargs)
|
124 |
+
self.dependencies = self.extra_dat.get("dependencies", [])
|
125 |
+
self.meson_build_dir = "bbdir"
|
126 |
+
self.build_type = (
|
127 |
+
"debug" if any("debug" in flag for flag in self.fc_flags) else "release"
|
128 |
+
)
|
129 |
+
|
130 |
+
def _move_exec_to_root(self, build_dir: Path):
|
131 |
+
walk_dir = Path(build_dir) / self.meson_build_dir
|
132 |
+
path_objects = chain(
|
133 |
+
walk_dir.glob(f"{self.modulename}*.so"),
|
134 |
+
walk_dir.glob(f"{self.modulename}*.pyd"),
|
135 |
+
)
|
136 |
+
# Same behavior as distutils
|
137 |
+
# https://github.com/numpy/numpy/issues/24874#issuecomment-1835632293
|
138 |
+
for path_object in path_objects:
|
139 |
+
dest_path = Path.cwd() / path_object.name
|
140 |
+
if dest_path.exists():
|
141 |
+
dest_path.unlink()
|
142 |
+
shutil.copy2(path_object, dest_path)
|
143 |
+
os.remove(path_object)
|
144 |
+
|
145 |
+
def write_meson_build(self, build_dir: Path) -> None:
|
146 |
+
"""Writes the meson build file at specified location"""
|
147 |
+
meson_template = MesonTemplate(
|
148 |
+
self.modulename,
|
149 |
+
self.sources,
|
150 |
+
self.dependencies,
|
151 |
+
self.libraries,
|
152 |
+
self.library_dirs,
|
153 |
+
self.include_dirs,
|
154 |
+
self.extra_objects,
|
155 |
+
self.flib_flags,
|
156 |
+
self.fc_flags,
|
157 |
+
self.build_type,
|
158 |
+
sys.executable,
|
159 |
+
)
|
160 |
+
src = meson_template.generate_meson_build()
|
161 |
+
Path(build_dir).mkdir(parents=True, exist_ok=True)
|
162 |
+
meson_build_file = Path(build_dir) / "meson.build"
|
163 |
+
meson_build_file.write_text(src)
|
164 |
+
return meson_build_file
|
165 |
+
|
166 |
+
def _run_subprocess_command(self, command, cwd):
|
167 |
+
subprocess.run(command, cwd=cwd, check=True)
|
168 |
+
|
169 |
+
def run_meson(self, build_dir: Path):
|
170 |
+
setup_command = ["meson", "setup", self.meson_build_dir]
|
171 |
+
self._run_subprocess_command(setup_command, build_dir)
|
172 |
+
compile_command = ["meson", "compile", "-C", self.meson_build_dir]
|
173 |
+
self._run_subprocess_command(compile_command, build_dir)
|
174 |
+
|
175 |
+
def compile(self) -> None:
|
176 |
+
self.sources = _prepare_sources(self.modulename, self.sources, self.build_dir)
|
177 |
+
self.write_meson_build(self.build_dir)
|
178 |
+
self.run_meson(self.build_dir)
|
179 |
+
self._move_exec_to_root(self.build_dir)
|
180 |
+
|
181 |
+
|
182 |
+
def _prepare_sources(mname, sources, bdir):
|
183 |
+
extended_sources = sources.copy()
|
184 |
+
Path(bdir).mkdir(parents=True, exist_ok=True)
|
185 |
+
# Copy sources
|
186 |
+
for source in sources:
|
187 |
+
if Path(source).exists() and Path(source).is_file():
|
188 |
+
shutil.copy(source, bdir)
|
189 |
+
generated_sources = [
|
190 |
+
Path(f"{mname}module.c"),
|
191 |
+
Path(f"{mname}-f2pywrappers2.f90"),
|
192 |
+
Path(f"{mname}-f2pywrappers.f"),
|
193 |
+
]
|
194 |
+
bdir = Path(bdir)
|
195 |
+
for generated_source in generated_sources:
|
196 |
+
if generated_source.exists():
|
197 |
+
shutil.copy(generated_source, bdir / generated_source.name)
|
198 |
+
extended_sources.append(generated_source.name)
|
199 |
+
generated_source.unlink()
|
200 |
+
extended_sources = [
|
201 |
+
Path(source).name
|
202 |
+
for source in extended_sources
|
203 |
+
if not Path(source).suffix == ".pyf"
|
204 |
+
]
|
205 |
+
return extended_sources
|
.venv/lib/python3.11/site-packages/numpy/f2py/_backends/meson.build.template
ADDED
@@ -0,0 +1,54 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
project('${modulename}',
|
2 |
+
['c', 'fortran'],
|
3 |
+
version : '0.1',
|
4 |
+
meson_version: '>= 1.1.0',
|
5 |
+
default_options : [
|
6 |
+
'warning_level=1',
|
7 |
+
'buildtype=${buildtype}'
|
8 |
+
])
|
9 |
+
fc = meson.get_compiler('fortran')
|
10 |
+
|
11 |
+
py = import('python').find_installation('${python}', pure: false)
|
12 |
+
py_dep = py.dependency()
|
13 |
+
|
14 |
+
incdir_numpy = run_command(py,
|
15 |
+
['-c', 'import os; os.chdir(".."); import numpy; print(numpy.get_include())'],
|
16 |
+
check : true
|
17 |
+
).stdout().strip()
|
18 |
+
|
19 |
+
incdir_f2py = run_command(py,
|
20 |
+
['-c', 'import os; os.chdir(".."); import numpy.f2py; print(numpy.f2py.get_include())'],
|
21 |
+
check : true
|
22 |
+
).stdout().strip()
|
23 |
+
|
24 |
+
inc_np = include_directories(incdir_numpy)
|
25 |
+
np_dep = declare_dependency(include_directories: inc_np)
|
26 |
+
|
27 |
+
incdir_f2py = incdir_numpy / '..' / '..' / 'f2py' / 'src'
|
28 |
+
inc_f2py = include_directories(incdir_f2py)
|
29 |
+
fortranobject_c = incdir_f2py / 'fortranobject.c'
|
30 |
+
|
31 |
+
inc_np = include_directories(incdir_numpy, incdir_f2py)
|
32 |
+
# gh-25000
|
33 |
+
quadmath_dep = fc.find_library('quadmath', required: false)
|
34 |
+
|
35 |
+
${lib_declarations}
|
36 |
+
${lib_dir_declarations}
|
37 |
+
|
38 |
+
py.extension_module('${modulename}',
|
39 |
+
[
|
40 |
+
${source_list},
|
41 |
+
fortranobject_c
|
42 |
+
],
|
43 |
+
include_directories: [
|
44 |
+
inc_np,
|
45 |
+
${inc_list}
|
46 |
+
],
|
47 |
+
dependencies : [
|
48 |
+
py_dep,
|
49 |
+
quadmath_dep,
|
50 |
+
${dep_list}
|
51 |
+
${lib_list}
|
52 |
+
${lib_dir_list}
|
53 |
+
],
|
54 |
+
install : true)
|
.venv/lib/python3.11/site-packages/numpy/f2py/_isocbind.py
ADDED
@@ -0,0 +1,62 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""
|
2 |
+
ISO_C_BINDING maps for f2py2e.
|
3 |
+
Only required declarations/macros/functions will be used.
|
4 |
+
|
5 |
+
Copyright 1999 -- 2011 Pearu Peterson all rights reserved.
|
6 |
+
Copyright 2011 -- present NumPy Developers.
|
7 |
+
Permission to use, modify, and distribute this software is given under the
|
8 |
+
terms of the NumPy License.
|
9 |
+
|
10 |
+
NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
|
11 |
+
"""
|
12 |
+
# These map to keys in c2py_map, via forced casting for now, see gh-25229
|
13 |
+
iso_c_binding_map = {
|
14 |
+
'integer': {
|
15 |
+
'c_int': 'int',
|
16 |
+
'c_short': 'short', # 'short' <=> 'int' for now
|
17 |
+
'c_long': 'long', # 'long' <=> 'int' for now
|
18 |
+
'c_long_long': 'long_long',
|
19 |
+
'c_signed_char': 'signed_char',
|
20 |
+
'c_size_t': 'unsigned', # size_t <=> 'unsigned' for now
|
21 |
+
'c_int8_t': 'signed_char', # int8_t <=> 'signed_char' for now
|
22 |
+
'c_int16_t': 'short', # int16_t <=> 'short' for now
|
23 |
+
'c_int32_t': 'int', # int32_t <=> 'int' for now
|
24 |
+
'c_int64_t': 'long_long',
|
25 |
+
'c_int_least8_t': 'signed_char', # int_least8_t <=> 'signed_char' for now
|
26 |
+
'c_int_least16_t': 'short', # int_least16_t <=> 'short' for now
|
27 |
+
'c_int_least32_t': 'int', # int_least32_t <=> 'int' for now
|
28 |
+
'c_int_least64_t': 'long_long',
|
29 |
+
'c_int_fast8_t': 'signed_char', # int_fast8_t <=> 'signed_char' for now
|
30 |
+
'c_int_fast16_t': 'short', # int_fast16_t <=> 'short' for now
|
31 |
+
'c_int_fast32_t': 'int', # int_fast32_t <=> 'int' for now
|
32 |
+
'c_int_fast64_t': 'long_long',
|
33 |
+
'c_intmax_t': 'long_long', # intmax_t <=> 'long_long' for now
|
34 |
+
'c_intptr_t': 'long', # intptr_t <=> 'long' for now
|
35 |
+
'c_ptrdiff_t': 'long', # ptrdiff_t <=> 'long' for now
|
36 |
+
},
|
37 |
+
'real': {
|
38 |
+
'c_float': 'float',
|
39 |
+
'c_double': 'double',
|
40 |
+
'c_long_double': 'long_double'
|
41 |
+
},
|
42 |
+
'complex': {
|
43 |
+
'c_float_complex': 'complex_float',
|
44 |
+
'c_double_complex': 'complex_double',
|
45 |
+
'c_long_double_complex': 'complex_long_double'
|
46 |
+
},
|
47 |
+
'logical': {
|
48 |
+
'c_bool': 'unsigned_char' # _Bool <=> 'unsigned_char' for now
|
49 |
+
},
|
50 |
+
'character': {
|
51 |
+
'c_char': 'char'
|
52 |
+
}
|
53 |
+
}
|
54 |
+
|
55 |
+
# TODO: See gh-25229
|
56 |
+
isoc_c2pycode_map = {}
|
57 |
+
iso_c2py_map = {}
|
58 |
+
|
59 |
+
isoc_kindmap = {}
|
60 |
+
for fortran_type, c_type_dict in iso_c_binding_map.items():
|
61 |
+
for c_type in c_type_dict.keys():
|
62 |
+
isoc_kindmap[c_type] = fortran_type
|
.venv/lib/python3.11/site-packages/numpy/f2py/_src_pyf.py
ADDED
@@ -0,0 +1,239 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import re
|
2 |
+
|
3 |
+
# START OF CODE VENDORED FROM `numpy.distutils.from_template`
|
4 |
+
#############################################################
|
5 |
+
"""
|
6 |
+
process_file(filename)
|
7 |
+
|
8 |
+
takes templated file .xxx.src and produces .xxx file where .xxx
|
9 |
+
is .pyf .f90 or .f using the following template rules:
|
10 |
+
|
11 |
+
'<..>' denotes a template.
|
12 |
+
|
13 |
+
All function and subroutine blocks in a source file with names that
|
14 |
+
contain '<..>' will be replicated according to the rules in '<..>'.
|
15 |
+
|
16 |
+
The number of comma-separated words in '<..>' will determine the number of
|
17 |
+
replicates.
|
18 |
+
|
19 |
+
'<..>' may have two different forms, named and short. For example,
|
20 |
+
|
21 |
+
named:
|
22 |
+
<p=d,s,z,c> where anywhere inside a block '<p>' will be replaced with
|
23 |
+
'd', 's', 'z', and 'c' for each replicate of the block.
|
24 |
+
|
25 |
+
<_c> is already defined: <_c=s,d,c,z>
|
26 |
+
<_t> is already defined: <_t=real,double precision,complex,double complex>
|
27 |
+
|
28 |
+
short:
|
29 |
+
<s,d,c,z>, a short form of the named, useful when no <p> appears inside
|
30 |
+
a block.
|
31 |
+
|
32 |
+
In general, '<..>' contains a comma separated list of arbitrary
|
33 |
+
expressions. If these expression must contain a comma|leftarrow|rightarrow,
|
34 |
+
then prepend the comma|leftarrow|rightarrow with a backslash.
|
35 |
+
|
36 |
+
If an expression matches '\\<index>' then it will be replaced
|
37 |
+
by <index>-th expression.
|
38 |
+
|
39 |
+
Note that all '<..>' forms in a block must have the same number of
|
40 |
+
comma-separated entries.
|
41 |
+
|
42 |
+
Predefined named template rules:
|
43 |
+
<prefix=s,d,c,z>
|
44 |
+
<ftype=real,double precision,complex,double complex>
|
45 |
+
<ftypereal=real,double precision,\\0,\\1>
|
46 |
+
<ctype=float,double,complex_float,complex_double>
|
47 |
+
<ctypereal=float,double,\\0,\\1>
|
48 |
+
"""
|
49 |
+
|
50 |
+
routine_start_re = re.compile(r'(\n|\A)(( (\$|\*))|)\s*(subroutine|function)\b', re.I)
|
51 |
+
routine_end_re = re.compile(r'\n\s*end\s*(subroutine|function)\b.*(\n|\Z)', re.I)
|
52 |
+
function_start_re = re.compile(r'\n (\$|\*)\s*function\b', re.I)
|
53 |
+
|
54 |
+
def parse_structure(astr):
|
55 |
+
""" Return a list of tuples for each function or subroutine each
|
56 |
+
tuple is the start and end of a subroutine or function to be
|
57 |
+
expanded.
|
58 |
+
"""
|
59 |
+
|
60 |
+
spanlist = []
|
61 |
+
ind = 0
|
62 |
+
while True:
|
63 |
+
m = routine_start_re.search(astr, ind)
|
64 |
+
if m is None:
|
65 |
+
break
|
66 |
+
start = m.start()
|
67 |
+
if function_start_re.match(astr, start, m.end()):
|
68 |
+
while True:
|
69 |
+
i = astr.rfind('\n', ind, start)
|
70 |
+
if i==-1:
|
71 |
+
break
|
72 |
+
start = i
|
73 |
+
if astr[i:i+7]!='\n $':
|
74 |
+
break
|
75 |
+
start += 1
|
76 |
+
m = routine_end_re.search(astr, m.end())
|
77 |
+
ind = end = m and m.end()-1 or len(astr)
|
78 |
+
spanlist.append((start, end))
|
79 |
+
return spanlist
|
80 |
+
|
81 |
+
template_re = re.compile(r"<\s*(\w[\w\d]*)\s*>")
|
82 |
+
named_re = re.compile(r"<\s*(\w[\w\d]*)\s*=\s*(.*?)\s*>")
|
83 |
+
list_re = re.compile(r"<\s*((.*?))\s*>")
|
84 |
+
|
85 |
+
def find_repl_patterns(astr):
|
86 |
+
reps = named_re.findall(astr)
|
87 |
+
names = {}
|
88 |
+
for rep in reps:
|
89 |
+
name = rep[0].strip() or unique_key(names)
|
90 |
+
repl = rep[1].replace(r'\,', '@comma@')
|
91 |
+
thelist = conv(repl)
|
92 |
+
names[name] = thelist
|
93 |
+
return names
|
94 |
+
|
95 |
+
def find_and_remove_repl_patterns(astr):
|
96 |
+
names = find_repl_patterns(astr)
|
97 |
+
astr = re.subn(named_re, '', astr)[0]
|
98 |
+
return astr, names
|
99 |
+
|
100 |
+
item_re = re.compile(r"\A\\(?P<index>\d+)\Z")
|
101 |
+
def conv(astr):
|
102 |
+
b = astr.split(',')
|
103 |
+
l = [x.strip() for x in b]
|
104 |
+
for i in range(len(l)):
|
105 |
+
m = item_re.match(l[i])
|
106 |
+
if m:
|
107 |
+
j = int(m.group('index'))
|
108 |
+
l[i] = l[j]
|
109 |
+
return ','.join(l)
|
110 |
+
|
111 |
+
def unique_key(adict):
|
112 |
+
""" Obtain a unique key given a dictionary."""
|
113 |
+
allkeys = list(adict.keys())
|
114 |
+
done = False
|
115 |
+
n = 1
|
116 |
+
while not done:
|
117 |
+
newkey = '__l%s' % (n)
|
118 |
+
if newkey in allkeys:
|
119 |
+
n += 1
|
120 |
+
else:
|
121 |
+
done = True
|
122 |
+
return newkey
|
123 |
+
|
124 |
+
|
125 |
+
template_name_re = re.compile(r'\A\s*(\w[\w\d]*)\s*\Z')
|
126 |
+
def expand_sub(substr, names):
|
127 |
+
substr = substr.replace(r'\>', '@rightarrow@')
|
128 |
+
substr = substr.replace(r'\<', '@leftarrow@')
|
129 |
+
lnames = find_repl_patterns(substr)
|
130 |
+
substr = named_re.sub(r"<\1>", substr) # get rid of definition templates
|
131 |
+
|
132 |
+
def listrepl(mobj):
|
133 |
+
thelist = conv(mobj.group(1).replace(r'\,', '@comma@'))
|
134 |
+
if template_name_re.match(thelist):
|
135 |
+
return "<%s>" % (thelist)
|
136 |
+
name = None
|
137 |
+
for key in lnames.keys(): # see if list is already in dictionary
|
138 |
+
if lnames[key] == thelist:
|
139 |
+
name = key
|
140 |
+
if name is None: # this list is not in the dictionary yet
|
141 |
+
name = unique_key(lnames)
|
142 |
+
lnames[name] = thelist
|
143 |
+
return "<%s>" % name
|
144 |
+
|
145 |
+
substr = list_re.sub(listrepl, substr) # convert all lists to named templates
|
146 |
+
# newnames are constructed as needed
|
147 |
+
|
148 |
+
numsubs = None
|
149 |
+
base_rule = None
|
150 |
+
rules = {}
|
151 |
+
for r in template_re.findall(substr):
|
152 |
+
if r not in rules:
|
153 |
+
thelist = lnames.get(r, names.get(r, None))
|
154 |
+
if thelist is None:
|
155 |
+
raise ValueError('No replicates found for <%s>' % (r))
|
156 |
+
if r not in names and not thelist.startswith('_'):
|
157 |
+
names[r] = thelist
|
158 |
+
rule = [i.replace('@comma@', ',') for i in thelist.split(',')]
|
159 |
+
num = len(rule)
|
160 |
+
|
161 |
+
if numsubs is None:
|
162 |
+
numsubs = num
|
163 |
+
rules[r] = rule
|
164 |
+
base_rule = r
|
165 |
+
elif num == numsubs:
|
166 |
+
rules[r] = rule
|
167 |
+
else:
|
168 |
+
print("Mismatch in number of replacements (base <{}={}>) "
|
169 |
+
"for <{}={}>. Ignoring.".format(base_rule, ','.join(rules[base_rule]), r, thelist))
|
170 |
+
if not rules:
|
171 |
+
return substr
|
172 |
+
|
173 |
+
def namerepl(mobj):
|
174 |
+
name = mobj.group(1)
|
175 |
+
return rules.get(name, (k+1)*[name])[k]
|
176 |
+
|
177 |
+
newstr = ''
|
178 |
+
for k in range(numsubs):
|
179 |
+
newstr += template_re.sub(namerepl, substr) + '\n\n'
|
180 |
+
|
181 |
+
newstr = newstr.replace('@rightarrow@', '>')
|
182 |
+
newstr = newstr.replace('@leftarrow@', '<')
|
183 |
+
return newstr
|
184 |
+
|
185 |
+
def process_str(allstr):
|
186 |
+
newstr = allstr
|
187 |
+
writestr = ''
|
188 |
+
|
189 |
+
struct = parse_structure(newstr)
|
190 |
+
|
191 |
+
oldend = 0
|
192 |
+
names = {}
|
193 |
+
names.update(_special_names)
|
194 |
+
for sub in struct:
|
195 |
+
cleanedstr, defs = find_and_remove_repl_patterns(newstr[oldend:sub[0]])
|
196 |
+
writestr += cleanedstr
|
197 |
+
names.update(defs)
|
198 |
+
writestr += expand_sub(newstr[sub[0]:sub[1]], names)
|
199 |
+
oldend = sub[1]
|
200 |
+
writestr += newstr[oldend:]
|
201 |
+
|
202 |
+
return writestr
|
203 |
+
|
204 |
+
include_src_re = re.compile(r"(\n|\A)\s*include\s*['\"](?P<name>[\w\d./\\]+\.src)['\"]", re.I)
|
205 |
+
|
206 |
+
def resolve_includes(source):
|
207 |
+
d = os.path.dirname(source)
|
208 |
+
with open(source) as fid:
|
209 |
+
lines = []
|
210 |
+
for line in fid:
|
211 |
+
m = include_src_re.match(line)
|
212 |
+
if m:
|
213 |
+
fn = m.group('name')
|
214 |
+
if not os.path.isabs(fn):
|
215 |
+
fn = os.path.join(d, fn)
|
216 |
+
if os.path.isfile(fn):
|
217 |
+
lines.extend(resolve_includes(fn))
|
218 |
+
else:
|
219 |
+
lines.append(line)
|
220 |
+
else:
|
221 |
+
lines.append(line)
|
222 |
+
return lines
|
223 |
+
|
224 |
+
def process_file(source):
|
225 |
+
lines = resolve_includes(source)
|
226 |
+
return process_str(''.join(lines))
|
227 |
+
|
228 |
+
_special_names = find_repl_patterns('''
|
229 |
+
<_c=s,d,c,z>
|
230 |
+
<_t=real,double precision,complex,double complex>
|
231 |
+
<prefix=s,d,c,z>
|
232 |
+
<ftype=real,double precision,complex,double complex>
|
233 |
+
<ctype=float,double,complex_float,complex_double>
|
234 |
+
<ftypereal=real,double precision,\\0,\\1>
|
235 |
+
<ctypereal=float,double,\\0,\\1>
|
236 |
+
''')
|
237 |
+
|
238 |
+
# END OF CODE VENDORED FROM `numpy.distutils.from_template`
|
239 |
+
###########################################################
|
.venv/lib/python3.11/site-packages/numpy/f2py/capi_maps.py
ADDED
@@ -0,0 +1,819 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""
|
2 |
+
Copyright 1999 -- 2011 Pearu Peterson all rights reserved.
|
3 |
+
Copyright 2011 -- present NumPy Developers.
|
4 |
+
Permission to use, modify, and distribute this software is given under the
|
5 |
+
terms of the NumPy License.
|
6 |
+
|
7 |
+
NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
|
8 |
+
"""
|
9 |
+
from . import __version__
|
10 |
+
f2py_version = __version__.version
|
11 |
+
|
12 |
+
import copy
|
13 |
+
import re
|
14 |
+
import os
|
15 |
+
from .crackfortran import markoutercomma
|
16 |
+
from . import cb_rules
|
17 |
+
from ._isocbind import iso_c_binding_map, isoc_c2pycode_map, iso_c2py_map
|
18 |
+
|
19 |
+
# The environment provided by auxfuncs.py is needed for some calls to eval.
|
20 |
+
# As the needed functions cannot be determined by static inspection of the
|
21 |
+
# code, it is safest to use import * pending a major refactoring of f2py.
|
22 |
+
from .auxfuncs import *
|
23 |
+
|
24 |
+
__all__ = [
|
25 |
+
'getctype', 'getstrlength', 'getarrdims', 'getpydocsign',
|
26 |
+
'getarrdocsign', 'getinit', 'sign2map', 'routsign2map', 'modsign2map',
|
27 |
+
'cb_sign2map', 'cb_routsign2map', 'common_sign2map', 'process_f2cmap_dict'
|
28 |
+
]
|
29 |
+
|
30 |
+
|
31 |
+
depargs = []
|
32 |
+
lcb_map = {}
|
33 |
+
lcb2_map = {}
|
34 |
+
# forced casting: mainly caused by the fact that Python or Numeric
|
35 |
+
# C/APIs do not support the corresponding C types.
|
36 |
+
c2py_map = {'double': 'float',
|
37 |
+
'float': 'float', # forced casting
|
38 |
+
'long_double': 'float', # forced casting
|
39 |
+
'char': 'int', # forced casting
|
40 |
+
'signed_char': 'int', # forced casting
|
41 |
+
'unsigned_char': 'int', # forced casting
|
42 |
+
'short': 'int', # forced casting
|
43 |
+
'unsigned_short': 'int', # forced casting
|
44 |
+
'int': 'int', # forced casting
|
45 |
+
'long': 'int',
|
46 |
+
'long_long': 'long',
|
47 |
+
'unsigned': 'int', # forced casting
|
48 |
+
'complex_float': 'complex', # forced casting
|
49 |
+
'complex_double': 'complex',
|
50 |
+
'complex_long_double': 'complex', # forced casting
|
51 |
+
'string': 'string',
|
52 |
+
'character': 'bytes',
|
53 |
+
}
|
54 |
+
|
55 |
+
c2capi_map = {'double': 'NPY_DOUBLE',
|
56 |
+
'float': 'NPY_FLOAT',
|
57 |
+
'long_double': 'NPY_LONGDOUBLE',
|
58 |
+
'char': 'NPY_BYTE',
|
59 |
+
'unsigned_char': 'NPY_UBYTE',
|
60 |
+
'signed_char': 'NPY_BYTE',
|
61 |
+
'short': 'NPY_SHORT',
|
62 |
+
'unsigned_short': 'NPY_USHORT',
|
63 |
+
'int': 'NPY_INT',
|
64 |
+
'unsigned': 'NPY_UINT',
|
65 |
+
'long': 'NPY_LONG',
|
66 |
+
'unsigned_long': 'NPY_ULONG',
|
67 |
+
'long_long': 'NPY_LONGLONG',
|
68 |
+
'unsigned_long_long': 'NPY_ULONGLONG',
|
69 |
+
'complex_float': 'NPY_CFLOAT',
|
70 |
+
'complex_double': 'NPY_CDOUBLE',
|
71 |
+
'complex_long_double': 'NPY_CDOUBLE',
|
72 |
+
'string': 'NPY_STRING',
|
73 |
+
'character': 'NPY_STRING'}
|
74 |
+
|
75 |
+
c2pycode_map = {'double': 'd',
|
76 |
+
'float': 'f',
|
77 |
+
'long_double': 'g',
|
78 |
+
'char': 'b',
|
79 |
+
'unsigned_char': 'B',
|
80 |
+
'signed_char': 'b',
|
81 |
+
'short': 'h',
|
82 |
+
'unsigned_short': 'H',
|
83 |
+
'int': 'i',
|
84 |
+
'unsigned': 'I',
|
85 |
+
'long': 'l',
|
86 |
+
'unsigned_long': 'L',
|
87 |
+
'long_long': 'q',
|
88 |
+
'unsigned_long_long': 'Q',
|
89 |
+
'complex_float': 'F',
|
90 |
+
'complex_double': 'D',
|
91 |
+
'complex_long_double': 'G',
|
92 |
+
'string': 'S',
|
93 |
+
'character': 'c'}
|
94 |
+
|
95 |
+
# https://docs.python.org/3/c-api/arg.html#building-values
|
96 |
+
c2buildvalue_map = {'double': 'd',
|
97 |
+
'float': 'f',
|
98 |
+
'char': 'b',
|
99 |
+
'signed_char': 'b',
|
100 |
+
'short': 'h',
|
101 |
+
'int': 'i',
|
102 |
+
'long': 'l',
|
103 |
+
'long_long': 'L',
|
104 |
+
'complex_float': 'N',
|
105 |
+
'complex_double': 'N',
|
106 |
+
'complex_long_double': 'N',
|
107 |
+
'string': 'y',
|
108 |
+
'character': 'c'}
|
109 |
+
|
110 |
+
f2cmap_all = {'real': {'': 'float', '4': 'float', '8': 'double',
|
111 |
+
'12': 'long_double', '16': 'long_double'},
|
112 |
+
'integer': {'': 'int', '1': 'signed_char', '2': 'short',
|
113 |
+
'4': 'int', '8': 'long_long',
|
114 |
+
'-1': 'unsigned_char', '-2': 'unsigned_short',
|
115 |
+
'-4': 'unsigned', '-8': 'unsigned_long_long'},
|
116 |
+
'complex': {'': 'complex_float', '8': 'complex_float',
|
117 |
+
'16': 'complex_double', '24': 'complex_long_double',
|
118 |
+
'32': 'complex_long_double'},
|
119 |
+
'complexkind': {'': 'complex_float', '4': 'complex_float',
|
120 |
+
'8': 'complex_double', '12': 'complex_long_double',
|
121 |
+
'16': 'complex_long_double'},
|
122 |
+
'logical': {'': 'int', '1': 'char', '2': 'short', '4': 'int',
|
123 |
+
'8': 'long_long'},
|
124 |
+
'double complex': {'': 'complex_double'},
|
125 |
+
'double precision': {'': 'double'},
|
126 |
+
'byte': {'': 'char'},
|
127 |
+
}
|
128 |
+
|
129 |
+
# Add ISO_C handling
|
130 |
+
c2pycode_map.update(isoc_c2pycode_map)
|
131 |
+
c2py_map.update(iso_c2py_map)
|
132 |
+
f2cmap_all, _ = process_f2cmap_dict(f2cmap_all, iso_c_binding_map, c2py_map)
|
133 |
+
# End ISO_C handling
|
134 |
+
f2cmap_default = copy.deepcopy(f2cmap_all)
|
135 |
+
|
136 |
+
f2cmap_mapped = []
|
137 |
+
|
138 |
+
def load_f2cmap_file(f2cmap_file):
|
139 |
+
global f2cmap_all, f2cmap_mapped
|
140 |
+
|
141 |
+
f2cmap_all = copy.deepcopy(f2cmap_default)
|
142 |
+
|
143 |
+
if f2cmap_file is None:
|
144 |
+
# Default value
|
145 |
+
f2cmap_file = '.f2py_f2cmap'
|
146 |
+
if not os.path.isfile(f2cmap_file):
|
147 |
+
return
|
148 |
+
|
149 |
+
# User defined additions to f2cmap_all.
|
150 |
+
# f2cmap_file must contain a dictionary of dictionaries, only. For
|
151 |
+
# example, {'real':{'low':'float'}} means that Fortran 'real(low)' is
|
152 |
+
# interpreted as C 'float'. This feature is useful for F90/95 users if
|
153 |
+
# they use PARAMETERS in type specifications.
|
154 |
+
try:
|
155 |
+
outmess('Reading f2cmap from {!r} ...\n'.format(f2cmap_file))
|
156 |
+
with open(f2cmap_file) as f:
|
157 |
+
d = eval(f.read().lower(), {}, {})
|
158 |
+
f2cmap_all, f2cmap_mapped = process_f2cmap_dict(f2cmap_all, d, c2py_map, True)
|
159 |
+
outmess('Successfully applied user defined f2cmap changes\n')
|
160 |
+
except Exception as msg:
|
161 |
+
errmess('Failed to apply user defined f2cmap changes: %s. Skipping.\n' % (msg))
|
162 |
+
|
163 |
+
|
164 |
+
cformat_map = {'double': '%g',
|
165 |
+
'float': '%g',
|
166 |
+
'long_double': '%Lg',
|
167 |
+
'char': '%d',
|
168 |
+
'signed_char': '%d',
|
169 |
+
'unsigned_char': '%hhu',
|
170 |
+
'short': '%hd',
|
171 |
+
'unsigned_short': '%hu',
|
172 |
+
'int': '%d',
|
173 |
+
'unsigned': '%u',
|
174 |
+
'long': '%ld',
|
175 |
+
'unsigned_long': '%lu',
|
176 |
+
'long_long': '%ld',
|
177 |
+
'complex_float': '(%g,%g)',
|
178 |
+
'complex_double': '(%g,%g)',
|
179 |
+
'complex_long_double': '(%Lg,%Lg)',
|
180 |
+
'string': '\\"%s\\"',
|
181 |
+
'character': "'%c'",
|
182 |
+
}
|
183 |
+
|
184 |
+
# Auxiliary functions
|
185 |
+
|
186 |
+
|
187 |
+
def getctype(var):
|
188 |
+
"""
|
189 |
+
Determines C type
|
190 |
+
"""
|
191 |
+
ctype = 'void'
|
192 |
+
if isfunction(var):
|
193 |
+
if 'result' in var:
|
194 |
+
a = var['result']
|
195 |
+
else:
|
196 |
+
a = var['name']
|
197 |
+
if a in var['vars']:
|
198 |
+
return getctype(var['vars'][a])
|
199 |
+
else:
|
200 |
+
errmess('getctype: function %s has no return value?!\n' % a)
|
201 |
+
elif issubroutine(var):
|
202 |
+
return ctype
|
203 |
+
elif ischaracter_or_characterarray(var):
|
204 |
+
return 'character'
|
205 |
+
elif isstring_or_stringarray(var):
|
206 |
+
return 'string'
|
207 |
+
elif 'typespec' in var and var['typespec'].lower() in f2cmap_all:
|
208 |
+
typespec = var['typespec'].lower()
|
209 |
+
f2cmap = f2cmap_all[typespec]
|
210 |
+
ctype = f2cmap[''] # default type
|
211 |
+
if 'kindselector' in var:
|
212 |
+
if '*' in var['kindselector']:
|
213 |
+
try:
|
214 |
+
ctype = f2cmap[var['kindselector']['*']]
|
215 |
+
except KeyError:
|
216 |
+
errmess('getctype: "%s %s %s" not supported.\n' %
|
217 |
+
(var['typespec'], '*', var['kindselector']['*']))
|
218 |
+
elif 'kind' in var['kindselector']:
|
219 |
+
if typespec + 'kind' in f2cmap_all:
|
220 |
+
f2cmap = f2cmap_all[typespec + 'kind']
|
221 |
+
try:
|
222 |
+
ctype = f2cmap[var['kindselector']['kind']]
|
223 |
+
except KeyError:
|
224 |
+
if typespec in f2cmap_all:
|
225 |
+
f2cmap = f2cmap_all[typespec]
|
226 |
+
try:
|
227 |
+
ctype = f2cmap[str(var['kindselector']['kind'])]
|
228 |
+
except KeyError:
|
229 |
+
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'
|
230 |
+
% (typespec, var['kindselector']['kind'], ctype,
|
231 |
+
typespec, var['kindselector']['kind'], os.getcwd()))
|
232 |
+
else:
|
233 |
+
if not isexternal(var):
|
234 |
+
errmess('getctype: No C-type found in "%s", assuming void.\n' % var)
|
235 |
+
return ctype
|
236 |
+
|
237 |
+
|
238 |
+
def f2cexpr(expr):
|
239 |
+
"""Rewrite Fortran expression as f2py supported C expression.
|
240 |
+
|
241 |
+
Due to the lack of a proper expression parser in f2py, this
|
242 |
+
function uses a heuristic approach that assumes that Fortran
|
243 |
+
arithmetic expressions are valid C arithmetic expressions when
|
244 |
+
mapping Fortran function calls to the corresponding C function/CPP
|
245 |
+
macros calls.
|
246 |
+
|
247 |
+
"""
|
248 |
+
# TODO: support Fortran `len` function with optional kind parameter
|
249 |
+
expr = re.sub(r'\blen\b', 'f2py_slen', expr)
|
250 |
+
return expr
|
251 |
+
|
252 |
+
|
253 |
+
def getstrlength(var):
|
254 |
+
if isstringfunction(var):
|
255 |
+
if 'result' in var:
|
256 |
+
a = var['result']
|
257 |
+
else:
|
258 |
+
a = var['name']
|
259 |
+
if a in var['vars']:
|
260 |
+
return getstrlength(var['vars'][a])
|
261 |
+
else:
|
262 |
+
errmess('getstrlength: function %s has no return value?!\n' % a)
|
263 |
+
if not isstring(var):
|
264 |
+
errmess(
|
265 |
+
'getstrlength: expected a signature of a string but got: %s\n' % (repr(var)))
|
266 |
+
len = '1'
|
267 |
+
if 'charselector' in var:
|
268 |
+
a = var['charselector']
|
269 |
+
if '*' in a:
|
270 |
+
len = a['*']
|
271 |
+
elif 'len' in a:
|
272 |
+
len = f2cexpr(a['len'])
|
273 |
+
if re.match(r'\(\s*(\*|:)\s*\)', len) or re.match(r'(\*|:)', len):
|
274 |
+
if isintent_hide(var):
|
275 |
+
errmess('getstrlength:intent(hide): expected a string with defined length but got: %s\n' % (
|
276 |
+
repr(var)))
|
277 |
+
len = '-1'
|
278 |
+
return len
|
279 |
+
|
280 |
+
|
281 |
+
def getarrdims(a, var, verbose=0):
|
282 |
+
ret = {}
|
283 |
+
if isstring(var) and not isarray(var):
|
284 |
+
ret['size'] = getstrlength(var)
|
285 |
+
ret['rank'] = '0'
|
286 |
+
ret['dims'] = ''
|
287 |
+
elif isscalar(var):
|
288 |
+
ret['size'] = '1'
|
289 |
+
ret['rank'] = '0'
|
290 |
+
ret['dims'] = ''
|
291 |
+
elif isarray(var):
|
292 |
+
dim = copy.copy(var['dimension'])
|
293 |
+
ret['size'] = '*'.join(dim)
|
294 |
+
try:
|
295 |
+
ret['size'] = repr(eval(ret['size']))
|
296 |
+
except Exception:
|
297 |
+
pass
|
298 |
+
ret['dims'] = ','.join(dim)
|
299 |
+
ret['rank'] = repr(len(dim))
|
300 |
+
ret['rank*[-1]'] = repr(len(dim) * [-1])[1:-1]
|
301 |
+
for i in range(len(dim)): # solve dim for dependencies
|
302 |
+
v = []
|
303 |
+
if dim[i] in depargs:
|
304 |
+
v = [dim[i]]
|
305 |
+
else:
|
306 |
+
for va in depargs:
|
307 |
+
if re.match(r'.*?\b%s\b.*' % va, dim[i]):
|
308 |
+
v.append(va)
|
309 |
+
for va in v:
|
310 |
+
if depargs.index(va) > depargs.index(a):
|
311 |
+
dim[i] = '*'
|
312 |
+
break
|
313 |
+
ret['setdims'], i = '', -1
|
314 |
+
for d in dim:
|
315 |
+
i = i + 1
|
316 |
+
if d not in ['*', ':', '(*)', '(:)']:
|
317 |
+
ret['setdims'] = '%s#varname#_Dims[%d]=%s,' % (
|
318 |
+
ret['setdims'], i, d)
|
319 |
+
if ret['setdims']:
|
320 |
+
ret['setdims'] = ret['setdims'][:-1]
|
321 |
+
ret['cbsetdims'], i = '', -1
|
322 |
+
for d in var['dimension']:
|
323 |
+
i = i + 1
|
324 |
+
if d not in ['*', ':', '(*)', '(:)']:
|
325 |
+
ret['cbsetdims'] = '%s#varname#_Dims[%d]=%s,' % (
|
326 |
+
ret['cbsetdims'], i, d)
|
327 |
+
elif isintent_in(var):
|
328 |
+
outmess('getarrdims:warning: assumed shape array, using 0 instead of %r\n'
|
329 |
+
% (d))
|
330 |
+
ret['cbsetdims'] = '%s#varname#_Dims[%d]=%s,' % (
|
331 |
+
ret['cbsetdims'], i, 0)
|
332 |
+
elif verbose:
|
333 |
+
errmess(
|
334 |
+
'getarrdims: If in call-back function: array argument %s must have bounded dimensions: got %s\n' % (repr(a), repr(d)))
|
335 |
+
if ret['cbsetdims']:
|
336 |
+
ret['cbsetdims'] = ret['cbsetdims'][:-1]
|
337 |
+
# if not isintent_c(var):
|
338 |
+
# var['dimension'].reverse()
|
339 |
+
return ret
|
340 |
+
|
341 |
+
|
342 |
+
def getpydocsign(a, var):
|
343 |
+
global lcb_map
|
344 |
+
if isfunction(var):
|
345 |
+
if 'result' in var:
|
346 |
+
af = var['result']
|
347 |
+
else:
|
348 |
+
af = var['name']
|
349 |
+
if af in var['vars']:
|
350 |
+
return getpydocsign(af, var['vars'][af])
|
351 |
+
else:
|
352 |
+
errmess('getctype: function %s has no return value?!\n' % af)
|
353 |
+
return '', ''
|
354 |
+
sig, sigout = a, a
|
355 |
+
opt = ''
|
356 |
+
if isintent_in(var):
|
357 |
+
opt = 'input'
|
358 |
+
elif isintent_inout(var):
|
359 |
+
opt = 'in/output'
|
360 |
+
out_a = a
|
361 |
+
if isintent_out(var):
|
362 |
+
for k in var['intent']:
|
363 |
+
if k[:4] == 'out=':
|
364 |
+
out_a = k[4:]
|
365 |
+
break
|
366 |
+
init = ''
|
367 |
+
ctype = getctype(var)
|
368 |
+
|
369 |
+
if hasinitvalue(var):
|
370 |
+
init, showinit = getinit(a, var)
|
371 |
+
init = ', optional\\n Default: %s' % showinit
|
372 |
+
if isscalar(var):
|
373 |
+
if isintent_inout(var):
|
374 |
+
sig = '%s : %s rank-0 array(%s,\'%s\')%s' % (a, opt, c2py_map[ctype],
|
375 |
+
c2pycode_map[ctype], init)
|
376 |
+
else:
|
377 |
+
sig = '%s : %s %s%s' % (a, opt, c2py_map[ctype], init)
|
378 |
+
sigout = '%s : %s' % (out_a, c2py_map[ctype])
|
379 |
+
elif isstring(var):
|
380 |
+
if isintent_inout(var):
|
381 |
+
sig = '%s : %s rank-0 array(string(len=%s),\'c\')%s' % (
|
382 |
+
a, opt, getstrlength(var), init)
|
383 |
+
else:
|
384 |
+
sig = '%s : %s string(len=%s)%s' % (
|
385 |
+
a, opt, getstrlength(var), init)
|
386 |
+
sigout = '%s : string(len=%s)' % (out_a, getstrlength(var))
|
387 |
+
elif isarray(var):
|
388 |
+
dim = var['dimension']
|
389 |
+
rank = repr(len(dim))
|
390 |
+
sig = '%s : %s rank-%s array(\'%s\') with bounds (%s)%s' % (a, opt, rank,
|
391 |
+
c2pycode_map[
|
392 |
+
ctype],
|
393 |
+
','.join(dim), init)
|
394 |
+
if a == out_a:
|
395 |
+
sigout = '%s : rank-%s array(\'%s\') with bounds (%s)'\
|
396 |
+
% (a, rank, c2pycode_map[ctype], ','.join(dim))
|
397 |
+
else:
|
398 |
+
sigout = '%s : rank-%s array(\'%s\') with bounds (%s) and %s storage'\
|
399 |
+
% (out_a, rank, c2pycode_map[ctype], ','.join(dim), a)
|
400 |
+
elif isexternal(var):
|
401 |
+
ua = ''
|
402 |
+
if a in lcb_map and lcb_map[a] in lcb2_map and 'argname' in lcb2_map[lcb_map[a]]:
|
403 |
+
ua = lcb2_map[lcb_map[a]]['argname']
|
404 |
+
if not ua == a:
|
405 |
+
ua = ' => %s' % ua
|
406 |
+
else:
|
407 |
+
ua = ''
|
408 |
+
sig = '%s : call-back function%s' % (a, ua)
|
409 |
+
sigout = sig
|
410 |
+
else:
|
411 |
+
errmess(
|
412 |
+
'getpydocsign: Could not resolve docsignature for "%s".\n' % a)
|
413 |
+
return sig, sigout
|
414 |
+
|
415 |
+
|
416 |
+
def getarrdocsign(a, var):
|
417 |
+
ctype = getctype(var)
|
418 |
+
if isstring(var) and (not isarray(var)):
|
419 |
+
sig = '%s : rank-0 array(string(len=%s),\'c\')' % (a,
|
420 |
+
getstrlength(var))
|
421 |
+
elif isscalar(var):
|
422 |
+
sig = '%s : rank-0 array(%s,\'%s\')' % (a, c2py_map[ctype],
|
423 |
+
c2pycode_map[ctype],)
|
424 |
+
elif isarray(var):
|
425 |
+
dim = var['dimension']
|
426 |
+
rank = repr(len(dim))
|
427 |
+
sig = '%s : rank-%s array(\'%s\') with bounds (%s)' % (a, rank,
|
428 |
+
c2pycode_map[
|
429 |
+
ctype],
|
430 |
+
','.join(dim))
|
431 |
+
return sig
|
432 |
+
|
433 |
+
|
434 |
+
def getinit(a, var):
|
435 |
+
if isstring(var):
|
436 |
+
init, showinit = '""', "''"
|
437 |
+
else:
|
438 |
+
init, showinit = '', ''
|
439 |
+
if hasinitvalue(var):
|
440 |
+
init = var['=']
|
441 |
+
showinit = init
|
442 |
+
if iscomplex(var) or iscomplexarray(var):
|
443 |
+
ret = {}
|
444 |
+
|
445 |
+
try:
|
446 |
+
v = var["="]
|
447 |
+
if ',' in v:
|
448 |
+
ret['init.r'], ret['init.i'] = markoutercomma(
|
449 |
+
v[1:-1]).split('@,@')
|
450 |
+
else:
|
451 |
+
v = eval(v, {}, {})
|
452 |
+
ret['init.r'], ret['init.i'] = str(v.real), str(v.imag)
|
453 |
+
except Exception:
|
454 |
+
raise ValueError(
|
455 |
+
'getinit: expected complex number `(r,i)\' but got `%s\' as initial value of %r.' % (init, a))
|
456 |
+
if isarray(var):
|
457 |
+
init = '(capi_c.r=%s,capi_c.i=%s,capi_c)' % (
|
458 |
+
ret['init.r'], ret['init.i'])
|
459 |
+
elif isstring(var):
|
460 |
+
if not init:
|
461 |
+
init, showinit = '""', "''"
|
462 |
+
if init[0] == "'":
|
463 |
+
init = '"%s"' % (init[1:-1].replace('"', '\\"'))
|
464 |
+
if init[0] == '"':
|
465 |
+
showinit = "'%s'" % (init[1:-1])
|
466 |
+
return init, showinit
|
467 |
+
|
468 |
+
|
469 |
+
def get_elsize(var):
|
470 |
+
if isstring(var) or isstringarray(var):
|
471 |
+
elsize = getstrlength(var)
|
472 |
+
# override with user-specified length when available:
|
473 |
+
elsize = var['charselector'].get('f2py_len', elsize)
|
474 |
+
return elsize
|
475 |
+
if ischaracter(var) or ischaracterarray(var):
|
476 |
+
return '1'
|
477 |
+
# for numerical types, PyArray_New* functions ignore specified
|
478 |
+
# elsize, so we just return 1 and let elsize be determined at
|
479 |
+
# runtime, see fortranobject.c
|
480 |
+
return '1'
|
481 |
+
|
482 |
+
|
483 |
+
def sign2map(a, var):
|
484 |
+
"""
|
485 |
+
varname,ctype,atype
|
486 |
+
init,init.r,init.i,pytype
|
487 |
+
vardebuginfo,vardebugshowvalue,varshowvalue
|
488 |
+
varrformat
|
489 |
+
|
490 |
+
intent
|
491 |
+
"""
|
492 |
+
out_a = a
|
493 |
+
if isintent_out(var):
|
494 |
+
for k in var['intent']:
|
495 |
+
if k[:4] == 'out=':
|
496 |
+
out_a = k[4:]
|
497 |
+
break
|
498 |
+
ret = {'varname': a, 'outvarname': out_a, 'ctype': getctype(var)}
|
499 |
+
intent_flags = []
|
500 |
+
for f, s in isintent_dict.items():
|
501 |
+
if f(var):
|
502 |
+
intent_flags.append('F2PY_%s' % s)
|
503 |
+
if intent_flags:
|
504 |
+
# TODO: Evaluate intent_flags here.
|
505 |
+
ret['intent'] = '|'.join(intent_flags)
|
506 |
+
else:
|
507 |
+
ret['intent'] = 'F2PY_INTENT_IN'
|
508 |
+
if isarray(var):
|
509 |
+
ret['varrformat'] = 'N'
|
510 |
+
elif ret['ctype'] in c2buildvalue_map:
|
511 |
+
ret['varrformat'] = c2buildvalue_map[ret['ctype']]
|
512 |
+
else:
|
513 |
+
ret['varrformat'] = 'O'
|
514 |
+
ret['init'], ret['showinit'] = getinit(a, var)
|
515 |
+
if hasinitvalue(var) and iscomplex(var) and not isarray(var):
|
516 |
+
ret['init.r'], ret['init.i'] = markoutercomma(
|
517 |
+
ret['init'][1:-1]).split('@,@')
|
518 |
+
if isexternal(var):
|
519 |
+
ret['cbnamekey'] = a
|
520 |
+
if a in lcb_map:
|
521 |
+
ret['cbname'] = lcb_map[a]
|
522 |
+
ret['maxnofargs'] = lcb2_map[lcb_map[a]]['maxnofargs']
|
523 |
+
ret['nofoptargs'] = lcb2_map[lcb_map[a]]['nofoptargs']
|
524 |
+
ret['cbdocstr'] = lcb2_map[lcb_map[a]]['docstr']
|
525 |
+
ret['cblatexdocstr'] = lcb2_map[lcb_map[a]]['latexdocstr']
|
526 |
+
else:
|
527 |
+
ret['cbname'] = a
|
528 |
+
errmess('sign2map: Confused: external %s is not in lcb_map%s.\n' % (
|
529 |
+
a, list(lcb_map.keys())))
|
530 |
+
if isstring(var):
|
531 |
+
ret['length'] = getstrlength(var)
|
532 |
+
if isarray(var):
|
533 |
+
ret = dictappend(ret, getarrdims(a, var))
|
534 |
+
dim = copy.copy(var['dimension'])
|
535 |
+
if ret['ctype'] in c2capi_map:
|
536 |
+
ret['atype'] = c2capi_map[ret['ctype']]
|
537 |
+
ret['elsize'] = get_elsize(var)
|
538 |
+
# Debug info
|
539 |
+
if debugcapi(var):
|
540 |
+
il = [isintent_in, 'input', isintent_out, 'output',
|
541 |
+
isintent_inout, 'inoutput', isrequired, 'required',
|
542 |
+
isoptional, 'optional', isintent_hide, 'hidden',
|
543 |
+
iscomplex, 'complex scalar',
|
544 |
+
l_and(isscalar, l_not(iscomplex)), 'scalar',
|
545 |
+
isstring, 'string', isarray, 'array',
|
546 |
+
iscomplexarray, 'complex array', isstringarray, 'string array',
|
547 |
+
iscomplexfunction, 'complex function',
|
548 |
+
l_and(isfunction, l_not(iscomplexfunction)), 'function',
|
549 |
+
isexternal, 'callback',
|
550 |
+
isintent_callback, 'callback',
|
551 |
+
isintent_aux, 'auxiliary',
|
552 |
+
]
|
553 |
+
rl = []
|
554 |
+
for i in range(0, len(il), 2):
|
555 |
+
if il[i](var):
|
556 |
+
rl.append(il[i + 1])
|
557 |
+
if isstring(var):
|
558 |
+
rl.append('slen(%s)=%s' % (a, ret['length']))
|
559 |
+
if isarray(var):
|
560 |
+
ddim = ','.join(
|
561 |
+
map(lambda x, y: '%s|%s' % (x, y), var['dimension'], dim))
|
562 |
+
rl.append('dims(%s)' % ddim)
|
563 |
+
if isexternal(var):
|
564 |
+
ret['vardebuginfo'] = 'debug-capi:%s=>%s:%s' % (
|
565 |
+
a, ret['cbname'], ','.join(rl))
|
566 |
+
else:
|
567 |
+
ret['vardebuginfo'] = 'debug-capi:%s %s=%s:%s' % (
|
568 |
+
ret['ctype'], a, ret['showinit'], ','.join(rl))
|
569 |
+
if isscalar(var):
|
570 |
+
if ret['ctype'] in cformat_map:
|
571 |
+
ret['vardebugshowvalue'] = 'debug-capi:%s=%s' % (
|
572 |
+
a, cformat_map[ret['ctype']])
|
573 |
+
if isstring(var):
|
574 |
+
ret['vardebugshowvalue'] = 'debug-capi:slen(%s)=%%d %s=\\"%%s\\"' % (
|
575 |
+
a, a)
|
576 |
+
if isexternal(var):
|
577 |
+
ret['vardebugshowvalue'] = 'debug-capi:%s=%%p' % (a)
|
578 |
+
if ret['ctype'] in cformat_map:
|
579 |
+
ret['varshowvalue'] = '#name#:%s=%s' % (a, cformat_map[ret['ctype']])
|
580 |
+
ret['showvalueformat'] = '%s' % (cformat_map[ret['ctype']])
|
581 |
+
if isstring(var):
|
582 |
+
ret['varshowvalue'] = '#name#:slen(%s)=%%d %s=\\"%%s\\"' % (a, a)
|
583 |
+
ret['pydocsign'], ret['pydocsignout'] = getpydocsign(a, var)
|
584 |
+
if hasnote(var):
|
585 |
+
ret['note'] = var['note']
|
586 |
+
return ret
|
587 |
+
|
588 |
+
|
589 |
+
def routsign2map(rout):
|
590 |
+
"""
|
591 |
+
name,NAME,begintitle,endtitle
|
592 |
+
rname,ctype,rformat
|
593 |
+
routdebugshowvalue
|
594 |
+
"""
|
595 |
+
global lcb_map
|
596 |
+
name = rout['name']
|
597 |
+
fname = getfortranname(rout)
|
598 |
+
ret = {'name': name,
|
599 |
+
'texname': name.replace('_', '\\_'),
|
600 |
+
'name_lower': name.lower(),
|
601 |
+
'NAME': name.upper(),
|
602 |
+
'begintitle': gentitle(name),
|
603 |
+
'endtitle': gentitle('end of %s' % name),
|
604 |
+
'fortranname': fname,
|
605 |
+
'FORTRANNAME': fname.upper(),
|
606 |
+
'callstatement': getcallstatement(rout) or '',
|
607 |
+
'usercode': getusercode(rout) or '',
|
608 |
+
'usercode1': getusercode1(rout) or '',
|
609 |
+
}
|
610 |
+
if '_' in fname:
|
611 |
+
ret['F_FUNC'] = 'F_FUNC_US'
|
612 |
+
else:
|
613 |
+
ret['F_FUNC'] = 'F_FUNC'
|
614 |
+
if '_' in name:
|
615 |
+
ret['F_WRAPPEDFUNC'] = 'F_WRAPPEDFUNC_US'
|
616 |
+
else:
|
617 |
+
ret['F_WRAPPEDFUNC'] = 'F_WRAPPEDFUNC'
|
618 |
+
lcb_map = {}
|
619 |
+
if 'use' in rout:
|
620 |
+
for u in rout['use'].keys():
|
621 |
+
if u in cb_rules.cb_map:
|
622 |
+
for un in cb_rules.cb_map[u]:
|
623 |
+
ln = un[0]
|
624 |
+
if 'map' in rout['use'][u]:
|
625 |
+
for k in rout['use'][u]['map'].keys():
|
626 |
+
if rout['use'][u]['map'][k] == un[0]:
|
627 |
+
ln = k
|
628 |
+
break
|
629 |
+
lcb_map[ln] = un[1]
|
630 |
+
elif 'externals' in rout and rout['externals']:
|
631 |
+
errmess('routsign2map: Confused: function %s has externals %s but no "use" statement.\n' % (
|
632 |
+
ret['name'], repr(rout['externals'])))
|
633 |
+
ret['callprotoargument'] = getcallprotoargument(rout, lcb_map) or ''
|
634 |
+
if isfunction(rout):
|
635 |
+
if 'result' in rout:
|
636 |
+
a = rout['result']
|
637 |
+
else:
|
638 |
+
a = rout['name']
|
639 |
+
ret['rname'] = a
|
640 |
+
ret['pydocsign'], ret['pydocsignout'] = getpydocsign(a, rout)
|
641 |
+
ret['ctype'] = getctype(rout['vars'][a])
|
642 |
+
if hasresultnote(rout):
|
643 |
+
ret['resultnote'] = rout['vars'][a]['note']
|
644 |
+
rout['vars'][a]['note'] = ['See elsewhere.']
|
645 |
+
if ret['ctype'] in c2buildvalue_map:
|
646 |
+
ret['rformat'] = c2buildvalue_map[ret['ctype']]
|
647 |
+
else:
|
648 |
+
ret['rformat'] = 'O'
|
649 |
+
errmess('routsign2map: no c2buildvalue key for type %s\n' %
|
650 |
+
(repr(ret['ctype'])))
|
651 |
+
if debugcapi(rout):
|
652 |
+
if ret['ctype'] in cformat_map:
|
653 |
+
ret['routdebugshowvalue'] = 'debug-capi:%s=%s' % (
|
654 |
+
a, cformat_map[ret['ctype']])
|
655 |
+
if isstringfunction(rout):
|
656 |
+
ret['routdebugshowvalue'] = 'debug-capi:slen(%s)=%%d %s=\\"%%s\\"' % (
|
657 |
+
a, a)
|
658 |
+
if isstringfunction(rout):
|
659 |
+
ret['rlength'] = getstrlength(rout['vars'][a])
|
660 |
+
if ret['rlength'] == '-1':
|
661 |
+
errmess('routsign2map: expected explicit specification of the length of the string returned by the fortran function %s; taking 10.\n' % (
|
662 |
+
repr(rout['name'])))
|
663 |
+
ret['rlength'] = '10'
|
664 |
+
if hasnote(rout):
|
665 |
+
ret['note'] = rout['note']
|
666 |
+
rout['note'] = ['See elsewhere.']
|
667 |
+
return ret
|
668 |
+
|
669 |
+
|
670 |
+
def modsign2map(m):
|
671 |
+
"""
|
672 |
+
modulename
|
673 |
+
"""
|
674 |
+
if ismodule(m):
|
675 |
+
ret = {'f90modulename': m['name'],
|
676 |
+
'F90MODULENAME': m['name'].upper(),
|
677 |
+
'texf90modulename': m['name'].replace('_', '\\_')}
|
678 |
+
else:
|
679 |
+
ret = {'modulename': m['name'],
|
680 |
+
'MODULENAME': m['name'].upper(),
|
681 |
+
'texmodulename': m['name'].replace('_', '\\_')}
|
682 |
+
ret['restdoc'] = getrestdoc(m) or []
|
683 |
+
if hasnote(m):
|
684 |
+
ret['note'] = m['note']
|
685 |
+
ret['usercode'] = getusercode(m) or ''
|
686 |
+
ret['usercode1'] = getusercode1(m) or ''
|
687 |
+
if m['body']:
|
688 |
+
ret['interface_usercode'] = getusercode(m['body'][0]) or ''
|
689 |
+
else:
|
690 |
+
ret['interface_usercode'] = ''
|
691 |
+
ret['pymethoddef'] = getpymethoddef(m) or ''
|
692 |
+
if 'coutput' in m:
|
693 |
+
ret['coutput'] = m['coutput']
|
694 |
+
if 'f2py_wrapper_output' in m:
|
695 |
+
ret['f2py_wrapper_output'] = m['f2py_wrapper_output']
|
696 |
+
return ret
|
697 |
+
|
698 |
+
|
699 |
+
def cb_sign2map(a, var, index=None):
|
700 |
+
ret = {'varname': a}
|
701 |
+
ret['varname_i'] = ret['varname']
|
702 |
+
ret['ctype'] = getctype(var)
|
703 |
+
if ret['ctype'] in c2capi_map:
|
704 |
+
ret['atype'] = c2capi_map[ret['ctype']]
|
705 |
+
ret['elsize'] = get_elsize(var)
|
706 |
+
if ret['ctype'] in cformat_map:
|
707 |
+
ret['showvalueformat'] = '%s' % (cformat_map[ret['ctype']])
|
708 |
+
if isarray(var):
|
709 |
+
ret = dictappend(ret, getarrdims(a, var))
|
710 |
+
ret['pydocsign'], ret['pydocsignout'] = getpydocsign(a, var)
|
711 |
+
if hasnote(var):
|
712 |
+
ret['note'] = var['note']
|
713 |
+
var['note'] = ['See elsewhere.']
|
714 |
+
return ret
|
715 |
+
|
716 |
+
|
717 |
+
def cb_routsign2map(rout, um):
|
718 |
+
"""
|
719 |
+
name,begintitle,endtitle,argname
|
720 |
+
ctype,rctype,maxnofargs,nofoptargs,returncptr
|
721 |
+
"""
|
722 |
+
ret = {'name': 'cb_%s_in_%s' % (rout['name'], um),
|
723 |
+
'returncptr': ''}
|
724 |
+
if isintent_callback(rout):
|
725 |
+
if '_' in rout['name']:
|
726 |
+
F_FUNC = 'F_FUNC_US'
|
727 |
+
else:
|
728 |
+
F_FUNC = 'F_FUNC'
|
729 |
+
ret['callbackname'] = '%s(%s,%s)' \
|
730 |
+
% (F_FUNC,
|
731 |
+
rout['name'].lower(),
|
732 |
+
rout['name'].upper(),
|
733 |
+
)
|
734 |
+
ret['static'] = 'extern'
|
735 |
+
else:
|
736 |
+
ret['callbackname'] = ret['name']
|
737 |
+
ret['static'] = 'static'
|
738 |
+
ret['argname'] = rout['name']
|
739 |
+
ret['begintitle'] = gentitle(ret['name'])
|
740 |
+
ret['endtitle'] = gentitle('end of %s' % ret['name'])
|
741 |
+
ret['ctype'] = getctype(rout)
|
742 |
+
ret['rctype'] = 'void'
|
743 |
+
if ret['ctype'] == 'string':
|
744 |
+
ret['rctype'] = 'void'
|
745 |
+
else:
|
746 |
+
ret['rctype'] = ret['ctype']
|
747 |
+
if ret['rctype'] != 'void':
|
748 |
+
if iscomplexfunction(rout):
|
749 |
+
ret['returncptr'] = """
|
750 |
+
#ifdef F2PY_CB_RETURNCOMPLEX
|
751 |
+
return_value=
|
752 |
+
#endif
|
753 |
+
"""
|
754 |
+
else:
|
755 |
+
ret['returncptr'] = 'return_value='
|
756 |
+
if ret['ctype'] in cformat_map:
|
757 |
+
ret['showvalueformat'] = '%s' % (cformat_map[ret['ctype']])
|
758 |
+
if isstringfunction(rout):
|
759 |
+
ret['strlength'] = getstrlength(rout)
|
760 |
+
if isfunction(rout):
|
761 |
+
if 'result' in rout:
|
762 |
+
a = rout['result']
|
763 |
+
else:
|
764 |
+
a = rout['name']
|
765 |
+
if hasnote(rout['vars'][a]):
|
766 |
+
ret['note'] = rout['vars'][a]['note']
|
767 |
+
rout['vars'][a]['note'] = ['See elsewhere.']
|
768 |
+
ret['rname'] = a
|
769 |
+
ret['pydocsign'], ret['pydocsignout'] = getpydocsign(a, rout)
|
770 |
+
if iscomplexfunction(rout):
|
771 |
+
ret['rctype'] = """
|
772 |
+
#ifdef F2PY_CB_RETURNCOMPLEX
|
773 |
+
#ctype#
|
774 |
+
#else
|
775 |
+
void
|
776 |
+
#endif
|
777 |
+
"""
|
778 |
+
else:
|
779 |
+
if hasnote(rout):
|
780 |
+
ret['note'] = rout['note']
|
781 |
+
rout['note'] = ['See elsewhere.']
|
782 |
+
nofargs = 0
|
783 |
+
nofoptargs = 0
|
784 |
+
if 'args' in rout and 'vars' in rout:
|
785 |
+
for a in rout['args']:
|
786 |
+
var = rout['vars'][a]
|
787 |
+
if l_or(isintent_in, isintent_inout)(var):
|
788 |
+
nofargs = nofargs + 1
|
789 |
+
if isoptional(var):
|
790 |
+
nofoptargs = nofoptargs + 1
|
791 |
+
ret['maxnofargs'] = repr(nofargs)
|
792 |
+
ret['nofoptargs'] = repr(nofoptargs)
|
793 |
+
if hasnote(rout) and isfunction(rout) and 'result' in rout:
|
794 |
+
ret['routnote'] = rout['note']
|
795 |
+
rout['note'] = ['See elsewhere.']
|
796 |
+
return ret
|
797 |
+
|
798 |
+
|
799 |
+
def common_sign2map(a, var): # obsolute
|
800 |
+
ret = {'varname': a, 'ctype': getctype(var)}
|
801 |
+
if isstringarray(var):
|
802 |
+
ret['ctype'] = 'char'
|
803 |
+
if ret['ctype'] in c2capi_map:
|
804 |
+
ret['atype'] = c2capi_map[ret['ctype']]
|
805 |
+
ret['elsize'] = get_elsize(var)
|
806 |
+
if ret['ctype'] in cformat_map:
|
807 |
+
ret['showvalueformat'] = '%s' % (cformat_map[ret['ctype']])
|
808 |
+
if isarray(var):
|
809 |
+
ret = dictappend(ret, getarrdims(a, var))
|
810 |
+
elif isstring(var):
|
811 |
+
ret['size'] = getstrlength(var)
|
812 |
+
ret['rank'] = '1'
|
813 |
+
ret['pydocsign'], ret['pydocsignout'] = getpydocsign(a, var)
|
814 |
+
if hasnote(var):
|
815 |
+
ret['note'] = var['note']
|
816 |
+
var['note'] = ['See elsewhere.']
|
817 |
+
# for strings this returns 0-rank but actually is 1-rank
|
818 |
+
ret['arrdocstr'] = getarrdocsign(a, var)
|
819 |
+
return ret
|
.venv/lib/python3.11/site-packages/numpy/f2py/common_rules.py
ADDED
@@ -0,0 +1,146 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""
|
2 |
+
Build common block mechanism for f2py2e.
|
3 |
+
|
4 |
+
Copyright 1999 -- 2011 Pearu Peterson all rights reserved.
|
5 |
+
Copyright 2011 -- present NumPy Developers.
|
6 |
+
Permission to use, modify, and distribute this software is given under the
|
7 |
+
terms of the NumPy License
|
8 |
+
|
9 |
+
NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
|
10 |
+
"""
|
11 |
+
from . import __version__
|
12 |
+
f2py_version = __version__.version
|
13 |
+
|
14 |
+
from .auxfuncs import (
|
15 |
+
hasbody, hascommon, hasnote, isintent_hide, outmess, getuseblocks
|
16 |
+
)
|
17 |
+
from . import capi_maps
|
18 |
+
from . import func2subr
|
19 |
+
from .crackfortran import rmbadname
|
20 |
+
|
21 |
+
|
22 |
+
def findcommonblocks(block, top=1):
|
23 |
+
ret = []
|
24 |
+
if hascommon(block):
|
25 |
+
for key, value in block['common'].items():
|
26 |
+
vars_ = {v: block['vars'][v] for v in value}
|
27 |
+
ret.append((key, value, vars_))
|
28 |
+
elif hasbody(block):
|
29 |
+
for b in block['body']:
|
30 |
+
ret = ret + findcommonblocks(b, 0)
|
31 |
+
if top:
|
32 |
+
tret = []
|
33 |
+
names = []
|
34 |
+
for t in ret:
|
35 |
+
if t[0] not in names:
|
36 |
+
names.append(t[0])
|
37 |
+
tret.append(t)
|
38 |
+
return tret
|
39 |
+
return ret
|
40 |
+
|
41 |
+
|
42 |
+
def buildhooks(m):
|
43 |
+
ret = {'commonhooks': [], 'initcommonhooks': [],
|
44 |
+
'docs': ['"COMMON blocks:\\n"']}
|
45 |
+
fwrap = ['']
|
46 |
+
|
47 |
+
def fadd(line, s=fwrap):
|
48 |
+
s[0] = '%s\n %s' % (s[0], line)
|
49 |
+
chooks = ['']
|
50 |
+
|
51 |
+
def cadd(line, s=chooks):
|
52 |
+
s[0] = '%s\n%s' % (s[0], line)
|
53 |
+
ihooks = ['']
|
54 |
+
|
55 |
+
def iadd(line, s=ihooks):
|
56 |
+
s[0] = '%s\n%s' % (s[0], line)
|
57 |
+
doc = ['']
|
58 |
+
|
59 |
+
def dadd(line, s=doc):
|
60 |
+
s[0] = '%s\n%s' % (s[0], line)
|
61 |
+
for (name, vnames, vars) in findcommonblocks(m):
|
62 |
+
lower_name = name.lower()
|
63 |
+
hnames, inames = [], []
|
64 |
+
for n in vnames:
|
65 |
+
if isintent_hide(vars[n]):
|
66 |
+
hnames.append(n)
|
67 |
+
else:
|
68 |
+
inames.append(n)
|
69 |
+
if hnames:
|
70 |
+
outmess('\t\tConstructing COMMON block support for "%s"...\n\t\t %s\n\t\t Hidden: %s\n' % (
|
71 |
+
name, ','.join(inames), ','.join(hnames)))
|
72 |
+
else:
|
73 |
+
outmess('\t\tConstructing COMMON block support for "%s"...\n\t\t %s\n' % (
|
74 |
+
name, ','.join(inames)))
|
75 |
+
fadd('subroutine f2pyinit%s(setupfunc)' % name)
|
76 |
+
for usename in getuseblocks(m):
|
77 |
+
fadd(f'use {usename}')
|
78 |
+
fadd('external setupfunc')
|
79 |
+
for n in vnames:
|
80 |
+
fadd(func2subr.var2fixfortran(vars, n))
|
81 |
+
if name == '_BLNK_':
|
82 |
+
fadd('common %s' % (','.join(vnames)))
|
83 |
+
else:
|
84 |
+
fadd('common /%s/ %s' % (name, ','.join(vnames)))
|
85 |
+
fadd('call setupfunc(%s)' % (','.join(inames)))
|
86 |
+
fadd('end\n')
|
87 |
+
cadd('static FortranDataDef f2py_%s_def[] = {' % (name))
|
88 |
+
idims = []
|
89 |
+
for n in inames:
|
90 |
+
ct = capi_maps.getctype(vars[n])
|
91 |
+
elsize = capi_maps.get_elsize(vars[n])
|
92 |
+
at = capi_maps.c2capi_map[ct]
|
93 |
+
dm = capi_maps.getarrdims(n, vars[n])
|
94 |
+
if dm['dims']:
|
95 |
+
idims.append('(%s)' % (dm['dims']))
|
96 |
+
else:
|
97 |
+
idims.append('')
|
98 |
+
dms = dm['dims'].strip()
|
99 |
+
if not dms:
|
100 |
+
dms = '-1'
|
101 |
+
cadd('\t{\"%s\",%s,{{%s}},%s, %s},'
|
102 |
+
% (n, dm['rank'], dms, at, elsize))
|
103 |
+
cadd('\t{NULL}\n};')
|
104 |
+
inames1 = rmbadname(inames)
|
105 |
+
inames1_tps = ','.join(['char *' + s for s in inames1])
|
106 |
+
cadd('static void f2py_setup_%s(%s) {' % (name, inames1_tps))
|
107 |
+
cadd('\tint i_f2py=0;')
|
108 |
+
for n in inames1:
|
109 |
+
cadd('\tf2py_%s_def[i_f2py++].data = %s;' % (name, n))
|
110 |
+
cadd('}')
|
111 |
+
if '_' in lower_name:
|
112 |
+
F_FUNC = 'F_FUNC_US'
|
113 |
+
else:
|
114 |
+
F_FUNC = 'F_FUNC'
|
115 |
+
cadd('extern void %s(f2pyinit%s,F2PYINIT%s)(void(*)(%s));'
|
116 |
+
% (F_FUNC, lower_name, name.upper(),
|
117 |
+
','.join(['char*'] * len(inames1))))
|
118 |
+
cadd('static void f2py_init_%s(void) {' % name)
|
119 |
+
cadd('\t%s(f2pyinit%s,F2PYINIT%s)(f2py_setup_%s);'
|
120 |
+
% (F_FUNC, lower_name, name.upper(), name))
|
121 |
+
cadd('}\n')
|
122 |
+
iadd('\ttmp = PyFortranObject_New(f2py_%s_def,f2py_init_%s);' % (name, name))
|
123 |
+
iadd('\tif (tmp == NULL) return NULL;')
|
124 |
+
iadd('\tif (F2PyDict_SetItemString(d, \"%s\", tmp) == -1) return NULL;'
|
125 |
+
% name)
|
126 |
+
iadd('\tPy_DECREF(tmp);')
|
127 |
+
tname = name.replace('_', '\\_')
|
128 |
+
dadd('\\subsection{Common block \\texttt{%s}}\n' % (tname))
|
129 |
+
dadd('\\begin{description}')
|
130 |
+
for n in inames:
|
131 |
+
dadd('\\item[]{{}\\verb@%s@{}}' %
|
132 |
+
(capi_maps.getarrdocsign(n, vars[n])))
|
133 |
+
if hasnote(vars[n]):
|
134 |
+
note = vars[n]['note']
|
135 |
+
if isinstance(note, list):
|
136 |
+
note = '\n'.join(note)
|
137 |
+
dadd('--- %s' % (note))
|
138 |
+
dadd('\\end{description}')
|
139 |
+
ret['docs'].append(
|
140 |
+
'"\t/%s/ %s\\n"' % (name, ','.join(map(lambda v, d: v + d, inames, idims))))
|
141 |
+
ret['commonhooks'] = chooks
|
142 |
+
ret['initcommonhooks'] = ihooks
|
143 |
+
ret['latexdoc'] = doc[0]
|
144 |
+
if len(ret['docs']) <= 1:
|
145 |
+
ret['docs'] = ''
|
146 |
+
return ret, fwrap[0]
|
.venv/lib/python3.11/site-packages/numpy/f2py/crackfortran.py
ADDED
The diff for this file is too large to render.
See raw diff
|
|
.venv/lib/python3.11/site-packages/numpy/f2py/diagnose.py
ADDED
@@ -0,0 +1,154 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#!/usr/bin/env python3
|
2 |
+
import os
|
3 |
+
import sys
|
4 |
+
import tempfile
|
5 |
+
|
6 |
+
|
7 |
+
def run_command(cmd):
|
8 |
+
print('Running %r:' % (cmd))
|
9 |
+
os.system(cmd)
|
10 |
+
print('------')
|
11 |
+
|
12 |
+
|
13 |
+
def run():
|
14 |
+
_path = os.getcwd()
|
15 |
+
os.chdir(tempfile.gettempdir())
|
16 |
+
print('------')
|
17 |
+
print('os.name=%r' % (os.name))
|
18 |
+
print('------')
|
19 |
+
print('sys.platform=%r' % (sys.platform))
|
20 |
+
print('------')
|
21 |
+
print('sys.version:')
|
22 |
+
print(sys.version)
|
23 |
+
print('------')
|
24 |
+
print('sys.prefix:')
|
25 |
+
print(sys.prefix)
|
26 |
+
print('------')
|
27 |
+
print('sys.path=%r' % (':'.join(sys.path)))
|
28 |
+
print('------')
|
29 |
+
|
30 |
+
try:
|
31 |
+
import numpy
|
32 |
+
has_newnumpy = 1
|
33 |
+
except ImportError as e:
|
34 |
+
print('Failed to import new numpy:', e)
|
35 |
+
has_newnumpy = 0
|
36 |
+
|
37 |
+
try:
|
38 |
+
from numpy.f2py import f2py2e
|
39 |
+
has_f2py2e = 1
|
40 |
+
except ImportError as e:
|
41 |
+
print('Failed to import f2py2e:', e)
|
42 |
+
has_f2py2e = 0
|
43 |
+
|
44 |
+
try:
|
45 |
+
import numpy.distutils
|
46 |
+
has_numpy_distutils = 2
|
47 |
+
except ImportError:
|
48 |
+
try:
|
49 |
+
import numpy_distutils
|
50 |
+
has_numpy_distutils = 1
|
51 |
+
except ImportError as e:
|
52 |
+
print('Failed to import numpy_distutils:', e)
|
53 |
+
has_numpy_distutils = 0
|
54 |
+
|
55 |
+
if has_newnumpy:
|
56 |
+
try:
|
57 |
+
print('Found new numpy version %r in %s' %
|
58 |
+
(numpy.__version__, numpy.__file__))
|
59 |
+
except Exception as msg:
|
60 |
+
print('error:', msg)
|
61 |
+
print('------')
|
62 |
+
|
63 |
+
if has_f2py2e:
|
64 |
+
try:
|
65 |
+
print('Found f2py2e version %r in %s' %
|
66 |
+
(f2py2e.__version__.version, f2py2e.__file__))
|
67 |
+
except Exception as msg:
|
68 |
+
print('error:', msg)
|
69 |
+
print('------')
|
70 |
+
|
71 |
+
if has_numpy_distutils:
|
72 |
+
try:
|
73 |
+
if has_numpy_distutils == 2:
|
74 |
+
print('Found numpy.distutils version %r in %r' % (
|
75 |
+
numpy.distutils.__version__,
|
76 |
+
numpy.distutils.__file__))
|
77 |
+
else:
|
78 |
+
print('Found numpy_distutils version %r in %r' % (
|
79 |
+
numpy_distutils.numpy_distutils_version.numpy_distutils_version,
|
80 |
+
numpy_distutils.__file__))
|
81 |
+
print('------')
|
82 |
+
except Exception as msg:
|
83 |
+
print('error:', msg)
|
84 |
+
print('------')
|
85 |
+
try:
|
86 |
+
if has_numpy_distutils == 1:
|
87 |
+
print(
|
88 |
+
'Importing numpy_distutils.command.build_flib ...', end=' ')
|
89 |
+
import numpy_distutils.command.build_flib as build_flib
|
90 |
+
print('ok')
|
91 |
+
print('------')
|
92 |
+
try:
|
93 |
+
print(
|
94 |
+
'Checking availability of supported Fortran compilers:')
|
95 |
+
for compiler_class in build_flib.all_compilers:
|
96 |
+
compiler_class(verbose=1).is_available()
|
97 |
+
print('------')
|
98 |
+
except Exception as msg:
|
99 |
+
print('error:', msg)
|
100 |
+
print('------')
|
101 |
+
except Exception as msg:
|
102 |
+
print(
|
103 |
+
'error:', msg, '(ignore it, build_flib is obsolute for numpy.distutils 0.2.2 and up)')
|
104 |
+
print('------')
|
105 |
+
try:
|
106 |
+
if has_numpy_distutils == 2:
|
107 |
+
print('Importing numpy.distutils.fcompiler ...', end=' ')
|
108 |
+
import numpy.distutils.fcompiler as fcompiler
|
109 |
+
else:
|
110 |
+
print('Importing numpy_distutils.fcompiler ...', end=' ')
|
111 |
+
import numpy_distutils.fcompiler as fcompiler
|
112 |
+
print('ok')
|
113 |
+
print('------')
|
114 |
+
try:
|
115 |
+
print('Checking availability of supported Fortran compilers:')
|
116 |
+
fcompiler.show_fcompilers()
|
117 |
+
print('------')
|
118 |
+
except Exception as msg:
|
119 |
+
print('error:', msg)
|
120 |
+
print('------')
|
121 |
+
except Exception as msg:
|
122 |
+
print('error:', msg)
|
123 |
+
print('------')
|
124 |
+
try:
|
125 |
+
if has_numpy_distutils == 2:
|
126 |
+
print('Importing numpy.distutils.cpuinfo ...', end=' ')
|
127 |
+
from numpy.distutils.cpuinfo import cpuinfo
|
128 |
+
print('ok')
|
129 |
+
print('------')
|
130 |
+
else:
|
131 |
+
try:
|
132 |
+
print(
|
133 |
+
'Importing numpy_distutils.command.cpuinfo ...', end=' ')
|
134 |
+
from numpy_distutils.command.cpuinfo import cpuinfo
|
135 |
+
print('ok')
|
136 |
+
print('------')
|
137 |
+
except Exception as msg:
|
138 |
+
print('error:', msg, '(ignore it)')
|
139 |
+
print('Importing numpy_distutils.cpuinfo ...', end=' ')
|
140 |
+
from numpy_distutils.cpuinfo import cpuinfo
|
141 |
+
print('ok')
|
142 |
+
print('------')
|
143 |
+
cpu = cpuinfo()
|
144 |
+
print('CPU information:', end=' ')
|
145 |
+
for name in dir(cpuinfo):
|
146 |
+
if name[0] == '_' and name[1] != '_' and getattr(cpu, name[1:])():
|
147 |
+
print(name[1:], end=' ')
|
148 |
+
print('------')
|
149 |
+
except Exception as msg:
|
150 |
+
print('error:', msg)
|
151 |
+
print('------')
|
152 |
+
os.chdir(_path)
|
153 |
+
if __name__ == "__main__":
|
154 |
+
run()
|
.venv/lib/python3.11/site-packages/numpy/f2py/f2py2e.py
ADDED
@@ -0,0 +1,768 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#!/usr/bin/env python3
|
2 |
+
"""
|
3 |
+
|
4 |
+
f2py2e - Fortran to Python C/API generator. 2nd Edition.
|
5 |
+
See __usage__ below.
|
6 |
+
|
7 |
+
Copyright 1999 -- 2011 Pearu Peterson all rights reserved.
|
8 |
+
Copyright 2011 -- present NumPy Developers.
|
9 |
+
Permission to use, modify, and distribute this software is given under the
|
10 |
+
terms of the NumPy License.
|
11 |
+
|
12 |
+
NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
|
13 |
+
"""
|
14 |
+
import sys
|
15 |
+
import os
|
16 |
+
import pprint
|
17 |
+
import re
|
18 |
+
from pathlib import Path
|
19 |
+
from itertools import dropwhile
|
20 |
+
import argparse
|
21 |
+
import copy
|
22 |
+
|
23 |
+
from . import crackfortran
|
24 |
+
from . import rules
|
25 |
+
from . import cb_rules
|
26 |
+
from . import auxfuncs
|
27 |
+
from . import cfuncs
|
28 |
+
from . import f90mod_rules
|
29 |
+
from . import __version__
|
30 |
+
from . import capi_maps
|
31 |
+
from numpy.f2py._backends import f2py_build_generator
|
32 |
+
|
33 |
+
f2py_version = __version__.version
|
34 |
+
numpy_version = __version__.version
|
35 |
+
errmess = sys.stderr.write
|
36 |
+
# outmess=sys.stdout.write
|
37 |
+
show = pprint.pprint
|
38 |
+
outmess = auxfuncs.outmess
|
39 |
+
MESON_ONLY_VER = (sys.version_info >= (3, 12))
|
40 |
+
|
41 |
+
__usage__ =\
|
42 |
+
f"""Usage:
|
43 |
+
|
44 |
+
1) To construct extension module sources:
|
45 |
+
|
46 |
+
f2py [<options>] <fortran files> [[[only:]||[skip:]] \\
|
47 |
+
<fortran functions> ] \\
|
48 |
+
[: <fortran files> ...]
|
49 |
+
|
50 |
+
2) To compile fortran files and build extension modules:
|
51 |
+
|
52 |
+
f2py -c [<options>, <build_flib options>, <extra options>] <fortran files>
|
53 |
+
|
54 |
+
3) To generate signature files:
|
55 |
+
|
56 |
+
f2py -h <filename.pyf> ...< same options as in (1) >
|
57 |
+
|
58 |
+
Description: This program generates a Python C/API file (<modulename>module.c)
|
59 |
+
that contains wrappers for given fortran functions so that they
|
60 |
+
can be called from Python. With the -c option the corresponding
|
61 |
+
extension modules are built.
|
62 |
+
|
63 |
+
Options:
|
64 |
+
|
65 |
+
-h <filename> Write signatures of the fortran routines to file <filename>
|
66 |
+
and exit. You can then edit <filename> and use it instead
|
67 |
+
of <fortran files>. If <filename>==stdout then the
|
68 |
+
signatures are printed to stdout.
|
69 |
+
<fortran functions> Names of fortran routines for which Python C/API
|
70 |
+
functions will be generated. Default is all that are found
|
71 |
+
in <fortran files>.
|
72 |
+
<fortran files> Paths to fortran/signature files that will be scanned for
|
73 |
+
<fortran functions> in order to determine their signatures.
|
74 |
+
skip: Ignore fortran functions that follow until `:'.
|
75 |
+
only: Use only fortran functions that follow until `:'.
|
76 |
+
: Get back to <fortran files> mode.
|
77 |
+
|
78 |
+
-m <modulename> Name of the module; f2py generates a Python/C API
|
79 |
+
file <modulename>module.c or extension module <modulename>.
|
80 |
+
Default is 'untitled'.
|
81 |
+
|
82 |
+
'-include<header>' Writes additional headers in the C wrapper, can be passed
|
83 |
+
multiple times, generates #include <header> each time.
|
84 |
+
|
85 |
+
--[no-]lower Do [not] lower the cases in <fortran files>. By default,
|
86 |
+
--lower is assumed with -h key, and --no-lower without -h key.
|
87 |
+
|
88 |
+
--build-dir <dirname> All f2py generated files are created in <dirname>.
|
89 |
+
Default is tempfile.mkdtemp().
|
90 |
+
|
91 |
+
--overwrite-signature Overwrite existing signature file.
|
92 |
+
|
93 |
+
--[no-]latex-doc Create (or not) <modulename>module.tex.
|
94 |
+
Default is --no-latex-doc.
|
95 |
+
--short-latex Create 'incomplete' LaTeX document (without commands
|
96 |
+
\\documentclass, \\tableofcontents, and \\begin{{document}},
|
97 |
+
\\end{{document}}).
|
98 |
+
|
99 |
+
--[no-]rest-doc Create (or not) <modulename>module.rst.
|
100 |
+
Default is --no-rest-doc.
|
101 |
+
|
102 |
+
--debug-capi Create C/API code that reports the state of the wrappers
|
103 |
+
during runtime. Useful for debugging.
|
104 |
+
|
105 |
+
--[no-]wrap-functions Create Fortran subroutine wrappers to Fortran 77
|
106 |
+
functions. --wrap-functions is default because it ensures
|
107 |
+
maximum portability/compiler independence.
|
108 |
+
|
109 |
+
--include-paths <path1>:<path2>:... Search include files from the given
|
110 |
+
directories.
|
111 |
+
|
112 |
+
--help-link [..] List system resources found by system_info.py. See also
|
113 |
+
--link-<resource> switch below. [..] is optional list
|
114 |
+
of resources names. E.g. try 'f2py --help-link lapack_opt'.
|
115 |
+
|
116 |
+
--f2cmap <filename> Load Fortran-to-Python KIND specification from the given
|
117 |
+
file. Default: .f2py_f2cmap in current directory.
|
118 |
+
|
119 |
+
--quiet Run quietly.
|
120 |
+
--verbose Run with extra verbosity.
|
121 |
+
--skip-empty-wrappers Only generate wrapper files when needed.
|
122 |
+
-v Print f2py version ID and exit.
|
123 |
+
|
124 |
+
|
125 |
+
build backend options (only effective with -c)
|
126 |
+
[NO_MESON] is used to indicate an option not meant to be used
|
127 |
+
with the meson backend or above Python 3.12:
|
128 |
+
|
129 |
+
--fcompiler= Specify Fortran compiler type by vendor [NO_MESON]
|
130 |
+
--compiler= Specify distutils C compiler type [NO_MESON]
|
131 |
+
|
132 |
+
--help-fcompiler List available Fortran compilers and exit [NO_MESON]
|
133 |
+
--f77exec= Specify the path to F77 compiler [NO_MESON]
|
134 |
+
--f90exec= Specify the path to F90 compiler [NO_MESON]
|
135 |
+
--f77flags= Specify F77 compiler flags
|
136 |
+
--f90flags= Specify F90 compiler flags
|
137 |
+
--opt= Specify optimization flags [NO_MESON]
|
138 |
+
--arch= Specify architecture specific optimization flags [NO_MESON]
|
139 |
+
--noopt Compile without optimization [NO_MESON]
|
140 |
+
--noarch Compile without arch-dependent optimization [NO_MESON]
|
141 |
+
--debug Compile with debugging information
|
142 |
+
|
143 |
+
--dep <dependency>
|
144 |
+
Specify a meson dependency for the module. This may
|
145 |
+
be passed multiple times for multiple dependencies.
|
146 |
+
Dependencies are stored in a list for further processing.
|
147 |
+
|
148 |
+
Example: --dep lapack --dep scalapack
|
149 |
+
This will identify "lapack" and "scalapack" as dependencies
|
150 |
+
and remove them from argv, leaving a dependencies list
|
151 |
+
containing ["lapack", "scalapack"].
|
152 |
+
|
153 |
+
--backend <backend_type>
|
154 |
+
Specify the build backend for the compilation process.
|
155 |
+
The supported backends are 'meson' and 'distutils'.
|
156 |
+
If not specified, defaults to 'distutils'. On
|
157 |
+
Python 3.12 or higher, the default is 'meson'.
|
158 |
+
|
159 |
+
Extra options (only effective with -c):
|
160 |
+
|
161 |
+
--link-<resource> Link extension module with <resource> as defined
|
162 |
+
by numpy.distutils/system_info.py. E.g. to link
|
163 |
+
with optimized LAPACK libraries (vecLib on MacOSX,
|
164 |
+
ATLAS elsewhere), use --link-lapack_opt.
|
165 |
+
See also --help-link switch. [NO_MESON]
|
166 |
+
|
167 |
+
-L/path/to/lib/ -l<libname>
|
168 |
+
-D<define> -U<name>
|
169 |
+
-I/path/to/include/
|
170 |
+
<filename>.o <filename>.so <filename>.a
|
171 |
+
|
172 |
+
Using the following macros may be required with non-gcc Fortran
|
173 |
+
compilers:
|
174 |
+
-DPREPEND_FORTRAN -DNO_APPEND_FORTRAN -DUPPERCASE_FORTRAN
|
175 |
+
-DUNDERSCORE_G77
|
176 |
+
|
177 |
+
When using -DF2PY_REPORT_ATEXIT, a performance report of F2PY
|
178 |
+
interface is printed out at exit (platforms: Linux).
|
179 |
+
|
180 |
+
When using -DF2PY_REPORT_ON_ARRAY_COPY=<int>, a message is
|
181 |
+
sent to stderr whenever F2PY interface makes a copy of an
|
182 |
+
array. Integer <int> sets the threshold for array sizes when
|
183 |
+
a message should be shown.
|
184 |
+
|
185 |
+
Version: {f2py_version}
|
186 |
+
numpy Version: {numpy_version}
|
187 |
+
License: NumPy license (see LICENSE.txt in the NumPy source code)
|
188 |
+
Copyright 1999 -- 2011 Pearu Peterson all rights reserved.
|
189 |
+
Copyright 2011 -- present NumPy Developers.
|
190 |
+
https://numpy.org/doc/stable/f2py/index.html\n"""
|
191 |
+
|
192 |
+
|
193 |
+
def scaninputline(inputline):
|
194 |
+
files, skipfuncs, onlyfuncs, debug = [], [], [], []
|
195 |
+
f, f2, f3, f5, f6, f8, f9, f10 = 1, 0, 0, 0, 0, 0, 0, 0
|
196 |
+
verbose = 1
|
197 |
+
emptygen = True
|
198 |
+
dolc = -1
|
199 |
+
dolatexdoc = 0
|
200 |
+
dorestdoc = 0
|
201 |
+
wrapfuncs = 1
|
202 |
+
buildpath = '.'
|
203 |
+
include_paths, inputline = get_includes(inputline)
|
204 |
+
signsfile, modulename = None, None
|
205 |
+
options = {'buildpath': buildpath,
|
206 |
+
'coutput': None,
|
207 |
+
'f2py_wrapper_output': None}
|
208 |
+
for l in inputline:
|
209 |
+
if l == '':
|
210 |
+
pass
|
211 |
+
elif l == 'only:':
|
212 |
+
f = 0
|
213 |
+
elif l == 'skip:':
|
214 |
+
f = -1
|
215 |
+
elif l == ':':
|
216 |
+
f = 1
|
217 |
+
elif l[:8] == '--debug-':
|
218 |
+
debug.append(l[8:])
|
219 |
+
elif l == '--lower':
|
220 |
+
dolc = 1
|
221 |
+
elif l == '--build-dir':
|
222 |
+
f6 = 1
|
223 |
+
elif l == '--no-lower':
|
224 |
+
dolc = 0
|
225 |
+
elif l == '--quiet':
|
226 |
+
verbose = 0
|
227 |
+
elif l == '--verbose':
|
228 |
+
verbose += 1
|
229 |
+
elif l == '--latex-doc':
|
230 |
+
dolatexdoc = 1
|
231 |
+
elif l == '--no-latex-doc':
|
232 |
+
dolatexdoc = 0
|
233 |
+
elif l == '--rest-doc':
|
234 |
+
dorestdoc = 1
|
235 |
+
elif l == '--no-rest-doc':
|
236 |
+
dorestdoc = 0
|
237 |
+
elif l == '--wrap-functions':
|
238 |
+
wrapfuncs = 1
|
239 |
+
elif l == '--no-wrap-functions':
|
240 |
+
wrapfuncs = 0
|
241 |
+
elif l == '--short-latex':
|
242 |
+
options['shortlatex'] = 1
|
243 |
+
elif l == '--coutput':
|
244 |
+
f8 = 1
|
245 |
+
elif l == '--f2py-wrapper-output':
|
246 |
+
f9 = 1
|
247 |
+
elif l == '--f2cmap':
|
248 |
+
f10 = 1
|
249 |
+
elif l == '--overwrite-signature':
|
250 |
+
options['h-overwrite'] = 1
|
251 |
+
elif l == '-h':
|
252 |
+
f2 = 1
|
253 |
+
elif l == '-m':
|
254 |
+
f3 = 1
|
255 |
+
elif l[:2] == '-v':
|
256 |
+
print(f2py_version)
|
257 |
+
sys.exit()
|
258 |
+
elif l == '--show-compilers':
|
259 |
+
f5 = 1
|
260 |
+
elif l[:8] == '-include':
|
261 |
+
cfuncs.outneeds['userincludes'].append(l[9:-1])
|
262 |
+
cfuncs.userincludes[l[9:-1]] = '#include ' + l[8:]
|
263 |
+
elif l == '--skip-empty-wrappers':
|
264 |
+
emptygen = False
|
265 |
+
elif l[0] == '-':
|
266 |
+
errmess('Unknown option %s\n' % repr(l))
|
267 |
+
sys.exit()
|
268 |
+
elif f2:
|
269 |
+
f2 = 0
|
270 |
+
signsfile = l
|
271 |
+
elif f3:
|
272 |
+
f3 = 0
|
273 |
+
modulename = l
|
274 |
+
elif f6:
|
275 |
+
f6 = 0
|
276 |
+
buildpath = l
|
277 |
+
elif f8:
|
278 |
+
f8 = 0
|
279 |
+
options["coutput"] = l
|
280 |
+
elif f9:
|
281 |
+
f9 = 0
|
282 |
+
options["f2py_wrapper_output"] = l
|
283 |
+
elif f10:
|
284 |
+
f10 = 0
|
285 |
+
options["f2cmap_file"] = l
|
286 |
+
elif f == 1:
|
287 |
+
try:
|
288 |
+
with open(l):
|
289 |
+
pass
|
290 |
+
files.append(l)
|
291 |
+
except OSError as detail:
|
292 |
+
errmess(f'OSError: {detail!s}. Skipping file "{l!s}".\n')
|
293 |
+
elif f == -1:
|
294 |
+
skipfuncs.append(l)
|
295 |
+
elif f == 0:
|
296 |
+
onlyfuncs.append(l)
|
297 |
+
if not f5 and not files and not modulename:
|
298 |
+
print(__usage__)
|
299 |
+
sys.exit()
|
300 |
+
if not os.path.isdir(buildpath):
|
301 |
+
if not verbose:
|
302 |
+
outmess('Creating build directory %s\n' % (buildpath))
|
303 |
+
os.mkdir(buildpath)
|
304 |
+
if signsfile:
|
305 |
+
signsfile = os.path.join(buildpath, signsfile)
|
306 |
+
if signsfile and os.path.isfile(signsfile) and 'h-overwrite' not in options:
|
307 |
+
errmess(
|
308 |
+
'Signature file "%s" exists!!! Use --overwrite-signature to overwrite.\n' % (signsfile))
|
309 |
+
sys.exit()
|
310 |
+
|
311 |
+
options['emptygen'] = emptygen
|
312 |
+
options['debug'] = debug
|
313 |
+
options['verbose'] = verbose
|
314 |
+
if dolc == -1 and not signsfile:
|
315 |
+
options['do-lower'] = 0
|
316 |
+
else:
|
317 |
+
options['do-lower'] = dolc
|
318 |
+
if modulename:
|
319 |
+
options['module'] = modulename
|
320 |
+
if signsfile:
|
321 |
+
options['signsfile'] = signsfile
|
322 |
+
if onlyfuncs:
|
323 |
+
options['onlyfuncs'] = onlyfuncs
|
324 |
+
if skipfuncs:
|
325 |
+
options['skipfuncs'] = skipfuncs
|
326 |
+
options['dolatexdoc'] = dolatexdoc
|
327 |
+
options['dorestdoc'] = dorestdoc
|
328 |
+
options['wrapfuncs'] = wrapfuncs
|
329 |
+
options['buildpath'] = buildpath
|
330 |
+
options['include_paths'] = include_paths
|
331 |
+
options.setdefault('f2cmap_file', None)
|
332 |
+
return files, options
|
333 |
+
|
334 |
+
|
335 |
+
def callcrackfortran(files, options):
|
336 |
+
rules.options = options
|
337 |
+
crackfortran.debug = options['debug']
|
338 |
+
crackfortran.verbose = options['verbose']
|
339 |
+
if 'module' in options:
|
340 |
+
crackfortran.f77modulename = options['module']
|
341 |
+
if 'skipfuncs' in options:
|
342 |
+
crackfortran.skipfuncs = options['skipfuncs']
|
343 |
+
if 'onlyfuncs' in options:
|
344 |
+
crackfortran.onlyfuncs = options['onlyfuncs']
|
345 |
+
crackfortran.include_paths[:] = options['include_paths']
|
346 |
+
crackfortran.dolowercase = options['do-lower']
|
347 |
+
postlist = crackfortran.crackfortran(files)
|
348 |
+
if 'signsfile' in options:
|
349 |
+
outmess('Saving signatures to file "%s"\n' % (options['signsfile']))
|
350 |
+
pyf = crackfortran.crack2fortran(postlist)
|
351 |
+
if options['signsfile'][-6:] == 'stdout':
|
352 |
+
sys.stdout.write(pyf)
|
353 |
+
else:
|
354 |
+
with open(options['signsfile'], 'w') as f:
|
355 |
+
f.write(pyf)
|
356 |
+
if options["coutput"] is None:
|
357 |
+
for mod in postlist:
|
358 |
+
mod["coutput"] = "%smodule.c" % mod["name"]
|
359 |
+
else:
|
360 |
+
for mod in postlist:
|
361 |
+
mod["coutput"] = options["coutput"]
|
362 |
+
if options["f2py_wrapper_output"] is None:
|
363 |
+
for mod in postlist:
|
364 |
+
mod["f2py_wrapper_output"] = "%s-f2pywrappers.f" % mod["name"]
|
365 |
+
else:
|
366 |
+
for mod in postlist:
|
367 |
+
mod["f2py_wrapper_output"] = options["f2py_wrapper_output"]
|
368 |
+
return postlist
|
369 |
+
|
370 |
+
|
371 |
+
def buildmodules(lst):
|
372 |
+
cfuncs.buildcfuncs()
|
373 |
+
outmess('Building modules...\n')
|
374 |
+
modules, mnames, isusedby = [], [], {}
|
375 |
+
for item in lst:
|
376 |
+
if '__user__' in item['name']:
|
377 |
+
cb_rules.buildcallbacks(item)
|
378 |
+
else:
|
379 |
+
if 'use' in item:
|
380 |
+
for u in item['use'].keys():
|
381 |
+
if u not in isusedby:
|
382 |
+
isusedby[u] = []
|
383 |
+
isusedby[u].append(item['name'])
|
384 |
+
modules.append(item)
|
385 |
+
mnames.append(item['name'])
|
386 |
+
ret = {}
|
387 |
+
for module, name in zip(modules, mnames):
|
388 |
+
if name in isusedby:
|
389 |
+
outmess('\tSkipping module "%s" which is used by %s.\n' % (
|
390 |
+
name, ','.join('"%s"' % s for s in isusedby[name])))
|
391 |
+
else:
|
392 |
+
um = []
|
393 |
+
if 'use' in module:
|
394 |
+
for u in module['use'].keys():
|
395 |
+
if u in isusedby and u in mnames:
|
396 |
+
um.append(modules[mnames.index(u)])
|
397 |
+
else:
|
398 |
+
outmess(
|
399 |
+
f'\tModule "{name}" uses nonexisting "{u}" '
|
400 |
+
'which will be ignored.\n')
|
401 |
+
ret[name] = {}
|
402 |
+
dict_append(ret[name], rules.buildmodule(module, um))
|
403 |
+
return ret
|
404 |
+
|
405 |
+
|
406 |
+
def dict_append(d_out, d_in):
|
407 |
+
for (k, v) in d_in.items():
|
408 |
+
if k not in d_out:
|
409 |
+
d_out[k] = []
|
410 |
+
if isinstance(v, list):
|
411 |
+
d_out[k] = d_out[k] + v
|
412 |
+
else:
|
413 |
+
d_out[k].append(v)
|
414 |
+
|
415 |
+
|
416 |
+
def run_main(comline_list):
|
417 |
+
"""
|
418 |
+
Equivalent to running::
|
419 |
+
|
420 |
+
f2py <args>
|
421 |
+
|
422 |
+
where ``<args>=string.join(<list>,' ')``, but in Python. Unless
|
423 |
+
``-h`` is used, this function returns a dictionary containing
|
424 |
+
information on generated modules and their dependencies on source
|
425 |
+
files.
|
426 |
+
|
427 |
+
You cannot build extension modules with this function, that is,
|
428 |
+
using ``-c`` is not allowed. Use the ``compile`` command instead.
|
429 |
+
|
430 |
+
Examples
|
431 |
+
--------
|
432 |
+
The command ``f2py -m scalar scalar.f`` can be executed from Python as
|
433 |
+
follows.
|
434 |
+
|
435 |
+
.. literalinclude:: ../../source/f2py/code/results/run_main_session.dat
|
436 |
+
:language: python
|
437 |
+
|
438 |
+
"""
|
439 |
+
crackfortran.reset_global_f2py_vars()
|
440 |
+
f2pydir = os.path.dirname(os.path.abspath(cfuncs.__file__))
|
441 |
+
fobjhsrc = os.path.join(f2pydir, 'src', 'fortranobject.h')
|
442 |
+
fobjcsrc = os.path.join(f2pydir, 'src', 'fortranobject.c')
|
443 |
+
# gh-22819 -- begin
|
444 |
+
parser = make_f2py_compile_parser()
|
445 |
+
args, comline_list = parser.parse_known_args(comline_list)
|
446 |
+
pyf_files, _ = filter_files("", "[.]pyf([.]src|)", comline_list)
|
447 |
+
# Checks that no existing modulename is defined in a pyf file
|
448 |
+
# TODO: Remove all this when scaninputline is replaced
|
449 |
+
if args.module_name:
|
450 |
+
if "-h" in comline_list:
|
451 |
+
modname = (
|
452 |
+
args.module_name
|
453 |
+
) # Directly use from args when -h is present
|
454 |
+
else:
|
455 |
+
modname = validate_modulename(
|
456 |
+
pyf_files, args.module_name
|
457 |
+
) # Validate modname when -h is not present
|
458 |
+
comline_list += ['-m', modname] # needed for the rest of scaninputline
|
459 |
+
# gh-22819 -- end
|
460 |
+
files, options = scaninputline(comline_list)
|
461 |
+
auxfuncs.options = options
|
462 |
+
capi_maps.load_f2cmap_file(options['f2cmap_file'])
|
463 |
+
postlist = callcrackfortran(files, options)
|
464 |
+
isusedby = {}
|
465 |
+
for plist in postlist:
|
466 |
+
if 'use' in plist:
|
467 |
+
for u in plist['use'].keys():
|
468 |
+
if u not in isusedby:
|
469 |
+
isusedby[u] = []
|
470 |
+
isusedby[u].append(plist['name'])
|
471 |
+
for plist in postlist:
|
472 |
+
if plist['block'] == 'python module' and '__user__' in plist['name']:
|
473 |
+
if plist['name'] in isusedby:
|
474 |
+
# if not quiet:
|
475 |
+
outmess(
|
476 |
+
f'Skipping Makefile build for module "{plist["name"]}" '
|
477 |
+
'which is used by {}\n'.format(
|
478 |
+
','.join(f'"{s}"' for s in isusedby[plist['name']])))
|
479 |
+
if 'signsfile' in options:
|
480 |
+
if options['verbose'] > 1:
|
481 |
+
outmess(
|
482 |
+
'Stopping. Edit the signature file and then run f2py on the signature file: ')
|
483 |
+
outmess('%s %s\n' %
|
484 |
+
(os.path.basename(sys.argv[0]), options['signsfile']))
|
485 |
+
return
|
486 |
+
for plist in postlist:
|
487 |
+
if plist['block'] != 'python module':
|
488 |
+
if 'python module' not in options:
|
489 |
+
errmess(
|
490 |
+
'Tip: If your original code is Fortran source then you must use -m option.\n')
|
491 |
+
raise TypeError('All blocks must be python module blocks but got %s' % (
|
492 |
+
repr(plist['block'])))
|
493 |
+
auxfuncs.debugoptions = options['debug']
|
494 |
+
f90mod_rules.options = options
|
495 |
+
auxfuncs.wrapfuncs = options['wrapfuncs']
|
496 |
+
|
497 |
+
ret = buildmodules(postlist)
|
498 |
+
|
499 |
+
for mn in ret.keys():
|
500 |
+
dict_append(ret[mn], {'csrc': fobjcsrc, 'h': fobjhsrc})
|
501 |
+
return ret
|
502 |
+
|
503 |
+
|
504 |
+
def filter_files(prefix, suffix, files, remove_prefix=None):
|
505 |
+
"""
|
506 |
+
Filter files by prefix and suffix.
|
507 |
+
"""
|
508 |
+
filtered, rest = [], []
|
509 |
+
match = re.compile(prefix + r'.*' + suffix + r'\Z').match
|
510 |
+
if remove_prefix:
|
511 |
+
ind = len(prefix)
|
512 |
+
else:
|
513 |
+
ind = 0
|
514 |
+
for file in [x.strip() for x in files]:
|
515 |
+
if match(file):
|
516 |
+
filtered.append(file[ind:])
|
517 |
+
else:
|
518 |
+
rest.append(file)
|
519 |
+
return filtered, rest
|
520 |
+
|
521 |
+
|
522 |
+
def get_prefix(module):
|
523 |
+
p = os.path.dirname(os.path.dirname(module.__file__))
|
524 |
+
return p
|
525 |
+
|
526 |
+
|
527 |
+
class CombineIncludePaths(argparse.Action):
|
528 |
+
def __call__(self, parser, namespace, values, option_string=None):
|
529 |
+
include_paths_set = set(getattr(namespace, 'include_paths', []) or [])
|
530 |
+
if option_string == "--include_paths":
|
531 |
+
outmess("Use --include-paths or -I instead of --include_paths which will be removed")
|
532 |
+
if option_string == "--include-paths" or option_string == "--include_paths":
|
533 |
+
include_paths_set.update(values.split(':'))
|
534 |
+
else:
|
535 |
+
include_paths_set.add(values)
|
536 |
+
setattr(namespace, 'include_paths', list(include_paths_set))
|
537 |
+
|
538 |
+
def include_parser():
|
539 |
+
parser = argparse.ArgumentParser(add_help=False)
|
540 |
+
parser.add_argument("-I", dest="include_paths", action=CombineIncludePaths)
|
541 |
+
parser.add_argument("--include-paths", dest="include_paths", action=CombineIncludePaths)
|
542 |
+
parser.add_argument("--include_paths", dest="include_paths", action=CombineIncludePaths)
|
543 |
+
return parser
|
544 |
+
|
545 |
+
def get_includes(iline):
|
546 |
+
iline = (' '.join(iline)).split()
|
547 |
+
parser = include_parser()
|
548 |
+
args, remain = parser.parse_known_args(iline)
|
549 |
+
ipaths = args.include_paths
|
550 |
+
if args.include_paths is None:
|
551 |
+
ipaths = []
|
552 |
+
return ipaths, remain
|
553 |
+
|
554 |
+
def make_f2py_compile_parser():
|
555 |
+
parser = argparse.ArgumentParser(add_help=False)
|
556 |
+
parser.add_argument("--dep", action="append", dest="dependencies")
|
557 |
+
parser.add_argument("--backend", choices=['meson', 'distutils'], default='distutils')
|
558 |
+
parser.add_argument("-m", dest="module_name")
|
559 |
+
return parser
|
560 |
+
|
561 |
+
def preparse_sysargv():
|
562 |
+
# To keep backwards bug compatibility, newer flags are handled by argparse,
|
563 |
+
# and `sys.argv` is passed to the rest of `f2py` as is.
|
564 |
+
parser = make_f2py_compile_parser()
|
565 |
+
|
566 |
+
args, remaining_argv = parser.parse_known_args()
|
567 |
+
sys.argv = [sys.argv[0]] + remaining_argv
|
568 |
+
|
569 |
+
backend_key = args.backend
|
570 |
+
if MESON_ONLY_VER and backend_key == 'distutils':
|
571 |
+
outmess("Cannot use distutils backend with Python>=3.12,"
|
572 |
+
" using meson backend instead.\n")
|
573 |
+
backend_key = "meson"
|
574 |
+
|
575 |
+
return {
|
576 |
+
"dependencies": args.dependencies or [],
|
577 |
+
"backend": backend_key,
|
578 |
+
"modulename": args.module_name,
|
579 |
+
}
|
580 |
+
|
581 |
+
def run_compile():
|
582 |
+
"""
|
583 |
+
Do it all in one call!
|
584 |
+
"""
|
585 |
+
import tempfile
|
586 |
+
|
587 |
+
# Collect dependency flags, preprocess sys.argv
|
588 |
+
argy = preparse_sysargv()
|
589 |
+
modulename = argy["modulename"]
|
590 |
+
if modulename is None:
|
591 |
+
modulename = 'untitled'
|
592 |
+
dependencies = argy["dependencies"]
|
593 |
+
backend_key = argy["backend"]
|
594 |
+
build_backend = f2py_build_generator(backend_key)
|
595 |
+
|
596 |
+
i = sys.argv.index('-c')
|
597 |
+
del sys.argv[i]
|
598 |
+
|
599 |
+
remove_build_dir = 0
|
600 |
+
try:
|
601 |
+
i = sys.argv.index('--build-dir')
|
602 |
+
except ValueError:
|
603 |
+
i = None
|
604 |
+
if i is not None:
|
605 |
+
build_dir = sys.argv[i + 1]
|
606 |
+
del sys.argv[i + 1]
|
607 |
+
del sys.argv[i]
|
608 |
+
else:
|
609 |
+
remove_build_dir = 1
|
610 |
+
build_dir = tempfile.mkdtemp()
|
611 |
+
|
612 |
+
_reg1 = re.compile(r'--link-')
|
613 |
+
sysinfo_flags = [_m for _m in sys.argv[1:] if _reg1.match(_m)]
|
614 |
+
sys.argv = [_m for _m in sys.argv if _m not in sysinfo_flags]
|
615 |
+
if sysinfo_flags:
|
616 |
+
sysinfo_flags = [f[7:] for f in sysinfo_flags]
|
617 |
+
|
618 |
+
_reg2 = re.compile(
|
619 |
+
r'--((no-|)(wrap-functions|lower)|debug-capi|quiet|skip-empty-wrappers)|-include')
|
620 |
+
f2py_flags = [_m for _m in sys.argv[1:] if _reg2.match(_m)]
|
621 |
+
sys.argv = [_m for _m in sys.argv if _m not in f2py_flags]
|
622 |
+
f2py_flags2 = []
|
623 |
+
fl = 0
|
624 |
+
for a in sys.argv[1:]:
|
625 |
+
if a in ['only:', 'skip:']:
|
626 |
+
fl = 1
|
627 |
+
elif a == ':':
|
628 |
+
fl = 0
|
629 |
+
if fl or a == ':':
|
630 |
+
f2py_flags2.append(a)
|
631 |
+
if f2py_flags2 and f2py_flags2[-1] != ':':
|
632 |
+
f2py_flags2.append(':')
|
633 |
+
f2py_flags.extend(f2py_flags2)
|
634 |
+
sys.argv = [_m for _m in sys.argv if _m not in f2py_flags2]
|
635 |
+
_reg3 = re.compile(
|
636 |
+
r'--((f(90)?compiler(-exec|)|compiler)=|help-compiler)')
|
637 |
+
flib_flags = [_m for _m in sys.argv[1:] if _reg3.match(_m)]
|
638 |
+
sys.argv = [_m for _m in sys.argv if _m not in flib_flags]
|
639 |
+
_reg4 = re.compile(
|
640 |
+
r'--((f(77|90)(flags|exec)|opt|arch)=|(debug|noopt|noarch|help-fcompiler))')
|
641 |
+
fc_flags = [_m for _m in sys.argv[1:] if _reg4.match(_m)]
|
642 |
+
sys.argv = [_m for _m in sys.argv if _m not in fc_flags]
|
643 |
+
|
644 |
+
del_list = []
|
645 |
+
for s in flib_flags:
|
646 |
+
v = '--fcompiler='
|
647 |
+
if s[:len(v)] == v:
|
648 |
+
if MESON_ONLY_VER or backend_key == 'meson':
|
649 |
+
outmess(
|
650 |
+
"--fcompiler cannot be used with meson,"
|
651 |
+
"set compiler with the FC environment variable\n"
|
652 |
+
)
|
653 |
+
else:
|
654 |
+
from numpy.distutils import fcompiler
|
655 |
+
fcompiler.load_all_fcompiler_classes()
|
656 |
+
allowed_keys = list(fcompiler.fcompiler_class.keys())
|
657 |
+
nv = ov = s[len(v):].lower()
|
658 |
+
if ov not in allowed_keys:
|
659 |
+
vmap = {} # XXX
|
660 |
+
try:
|
661 |
+
nv = vmap[ov]
|
662 |
+
except KeyError:
|
663 |
+
if ov not in vmap.values():
|
664 |
+
print('Unknown vendor: "%s"' % (s[len(v):]))
|
665 |
+
nv = ov
|
666 |
+
i = flib_flags.index(s)
|
667 |
+
flib_flags[i] = '--fcompiler=' + nv
|
668 |
+
continue
|
669 |
+
for s in del_list:
|
670 |
+
i = flib_flags.index(s)
|
671 |
+
del flib_flags[i]
|
672 |
+
assert len(flib_flags) <= 2, repr(flib_flags)
|
673 |
+
|
674 |
+
_reg5 = re.compile(r'--(verbose)')
|
675 |
+
setup_flags = [_m for _m in sys.argv[1:] if _reg5.match(_m)]
|
676 |
+
sys.argv = [_m for _m in sys.argv if _m not in setup_flags]
|
677 |
+
|
678 |
+
if '--quiet' in f2py_flags:
|
679 |
+
setup_flags.append('--quiet')
|
680 |
+
|
681 |
+
# Ugly filter to remove everything but sources
|
682 |
+
sources = sys.argv[1:]
|
683 |
+
f2cmapopt = '--f2cmap'
|
684 |
+
if f2cmapopt in sys.argv:
|
685 |
+
i = sys.argv.index(f2cmapopt)
|
686 |
+
f2py_flags.extend(sys.argv[i:i + 2])
|
687 |
+
del sys.argv[i + 1], sys.argv[i]
|
688 |
+
sources = sys.argv[1:]
|
689 |
+
|
690 |
+
pyf_files, _sources = filter_files("", "[.]pyf([.]src|)", sources)
|
691 |
+
sources = pyf_files + _sources
|
692 |
+
modulename = validate_modulename(pyf_files, modulename)
|
693 |
+
extra_objects, sources = filter_files('', '[.](o|a|so|dylib)', sources)
|
694 |
+
library_dirs, sources = filter_files('-L', '', sources, remove_prefix=1)
|
695 |
+
libraries, sources = filter_files('-l', '', sources, remove_prefix=1)
|
696 |
+
undef_macros, sources = filter_files('-U', '', sources, remove_prefix=1)
|
697 |
+
define_macros, sources = filter_files('-D', '', sources, remove_prefix=1)
|
698 |
+
for i in range(len(define_macros)):
|
699 |
+
name_value = define_macros[i].split('=', 1)
|
700 |
+
if len(name_value) == 1:
|
701 |
+
name_value.append(None)
|
702 |
+
if len(name_value) == 2:
|
703 |
+
define_macros[i] = tuple(name_value)
|
704 |
+
else:
|
705 |
+
print('Invalid use of -D:', name_value)
|
706 |
+
|
707 |
+
# Construct wrappers / signatures / things
|
708 |
+
if backend_key == 'meson':
|
709 |
+
if not pyf_files:
|
710 |
+
outmess('Using meson backend\nWill pass --lower to f2py\nSee https://numpy.org/doc/stable/f2py/buildtools/meson.html\n')
|
711 |
+
f2py_flags.append('--lower')
|
712 |
+
run_main(f" {' '.join(f2py_flags)} -m {modulename} {' '.join(sources)}".split())
|
713 |
+
else:
|
714 |
+
run_main(f" {' '.join(f2py_flags)} {' '.join(pyf_files)}".split())
|
715 |
+
|
716 |
+
# Order matters here, includes are needed for run_main above
|
717 |
+
include_dirs, sources = get_includes(sources)
|
718 |
+
# Now use the builder
|
719 |
+
builder = build_backend(
|
720 |
+
modulename,
|
721 |
+
sources,
|
722 |
+
extra_objects,
|
723 |
+
build_dir,
|
724 |
+
include_dirs,
|
725 |
+
library_dirs,
|
726 |
+
libraries,
|
727 |
+
define_macros,
|
728 |
+
undef_macros,
|
729 |
+
f2py_flags,
|
730 |
+
sysinfo_flags,
|
731 |
+
fc_flags,
|
732 |
+
flib_flags,
|
733 |
+
setup_flags,
|
734 |
+
remove_build_dir,
|
735 |
+
{"dependencies": dependencies},
|
736 |
+
)
|
737 |
+
|
738 |
+
builder.compile()
|
739 |
+
|
740 |
+
|
741 |
+
def validate_modulename(pyf_files, modulename='untitled'):
|
742 |
+
if len(pyf_files) > 1:
|
743 |
+
raise ValueError("Only one .pyf file per call")
|
744 |
+
if pyf_files:
|
745 |
+
pyff = pyf_files[0]
|
746 |
+
pyf_modname = auxfuncs.get_f2py_modulename(pyff)
|
747 |
+
if modulename != pyf_modname:
|
748 |
+
outmess(
|
749 |
+
f"Ignoring -m {modulename}.\n"
|
750 |
+
f"{pyff} defines {pyf_modname} to be the modulename.\n"
|
751 |
+
)
|
752 |
+
modulename = pyf_modname
|
753 |
+
return modulename
|
754 |
+
|
755 |
+
def main():
|
756 |
+
if '--help-link' in sys.argv[1:]:
|
757 |
+
sys.argv.remove('--help-link')
|
758 |
+
if MESON_ONLY_VER:
|
759 |
+
outmess("Use --dep for meson builds\n")
|
760 |
+
else:
|
761 |
+
from numpy.distutils.system_info import show_all
|
762 |
+
show_all()
|
763 |
+
return
|
764 |
+
|
765 |
+
if '-c' in sys.argv[1:]:
|
766 |
+
run_compile()
|
767 |
+
else:
|
768 |
+
run_main(sys.argv[1:])
|
.venv/lib/python3.11/site-packages/numpy/f2py/func2subr.py
ADDED
@@ -0,0 +1,323 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""
|
2 |
+
|
3 |
+
Rules for building C/API module with f2py2e.
|
4 |
+
|
5 |
+
Copyright 1999 -- 2011 Pearu Peterson all rights reserved.
|
6 |
+
Copyright 2011 -- present NumPy Developers.
|
7 |
+
Permission to use, modify, and distribute this software is given under the
|
8 |
+
terms of the NumPy License.
|
9 |
+
|
10 |
+
NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
|
11 |
+
"""
|
12 |
+
import copy
|
13 |
+
|
14 |
+
from .auxfuncs import (
|
15 |
+
getfortranname, isexternal, isfunction, isfunction_wrap, isintent_in,
|
16 |
+
isintent_out, islogicalfunction, ismoduleroutine, isscalar,
|
17 |
+
issubroutine, issubroutine_wrap, outmess, show
|
18 |
+
)
|
19 |
+
|
20 |
+
from ._isocbind import isoc_kindmap
|
21 |
+
|
22 |
+
def var2fixfortran(vars, a, fa=None, f90mode=None):
|
23 |
+
if fa is None:
|
24 |
+
fa = a
|
25 |
+
if a not in vars:
|
26 |
+
show(vars)
|
27 |
+
outmess('var2fixfortran: No definition for argument "%s".\n' % a)
|
28 |
+
return ''
|
29 |
+
if 'typespec' not in vars[a]:
|
30 |
+
show(vars[a])
|
31 |
+
outmess('var2fixfortran: No typespec for argument "%s".\n' % a)
|
32 |
+
return ''
|
33 |
+
vardef = vars[a]['typespec']
|
34 |
+
if vardef == 'type' and 'typename' in vars[a]:
|
35 |
+
vardef = '%s(%s)' % (vardef, vars[a]['typename'])
|
36 |
+
selector = {}
|
37 |
+
lk = ''
|
38 |
+
if 'kindselector' in vars[a]:
|
39 |
+
selector = vars[a]['kindselector']
|
40 |
+
lk = 'kind'
|
41 |
+
elif 'charselector' in vars[a]:
|
42 |
+
selector = vars[a]['charselector']
|
43 |
+
lk = 'len'
|
44 |
+
if '*' in selector:
|
45 |
+
if f90mode:
|
46 |
+
if selector['*'] in ['*', ':', '(*)']:
|
47 |
+
vardef = '%s(len=*)' % (vardef)
|
48 |
+
else:
|
49 |
+
vardef = '%s(%s=%s)' % (vardef, lk, selector['*'])
|
50 |
+
else:
|
51 |
+
if selector['*'] in ['*', ':']:
|
52 |
+
vardef = '%s*(%s)' % (vardef, selector['*'])
|
53 |
+
else:
|
54 |
+
vardef = '%s*%s' % (vardef, selector['*'])
|
55 |
+
else:
|
56 |
+
if 'len' in selector:
|
57 |
+
vardef = '%s(len=%s' % (vardef, selector['len'])
|
58 |
+
if 'kind' in selector:
|
59 |
+
vardef = '%s,kind=%s)' % (vardef, selector['kind'])
|
60 |
+
else:
|
61 |
+
vardef = '%s)' % (vardef)
|
62 |
+
elif 'kind' in selector:
|
63 |
+
vardef = '%s(kind=%s)' % (vardef, selector['kind'])
|
64 |
+
|
65 |
+
vardef = '%s %s' % (vardef, fa)
|
66 |
+
if 'dimension' in vars[a]:
|
67 |
+
vardef = '%s(%s)' % (vardef, ','.join(vars[a]['dimension']))
|
68 |
+
return vardef
|
69 |
+
|
70 |
+
def useiso_c_binding(rout):
|
71 |
+
useisoc = False
|
72 |
+
for key, value in rout['vars'].items():
|
73 |
+
kind_value = value.get('kindselector', {}).get('kind')
|
74 |
+
if kind_value in isoc_kindmap:
|
75 |
+
return True
|
76 |
+
return useisoc
|
77 |
+
|
78 |
+
def createfuncwrapper(rout, signature=0):
|
79 |
+
assert isfunction(rout)
|
80 |
+
|
81 |
+
extra_args = []
|
82 |
+
vars = rout['vars']
|
83 |
+
for a in rout['args']:
|
84 |
+
v = rout['vars'][a]
|
85 |
+
for i, d in enumerate(v.get('dimension', [])):
|
86 |
+
if d == ':':
|
87 |
+
dn = 'f2py_%s_d%s' % (a, i)
|
88 |
+
dv = dict(typespec='integer', intent=['hide'])
|
89 |
+
dv['='] = 'shape(%s, %s)' % (a, i)
|
90 |
+
extra_args.append(dn)
|
91 |
+
vars[dn] = dv
|
92 |
+
v['dimension'][i] = dn
|
93 |
+
rout['args'].extend(extra_args)
|
94 |
+
need_interface = bool(extra_args)
|
95 |
+
|
96 |
+
ret = ['']
|
97 |
+
|
98 |
+
def add(line, ret=ret):
|
99 |
+
ret[0] = '%s\n %s' % (ret[0], line)
|
100 |
+
name = rout['name']
|
101 |
+
fortranname = getfortranname(rout)
|
102 |
+
f90mode = ismoduleroutine(rout)
|
103 |
+
newname = '%sf2pywrap' % (name)
|
104 |
+
|
105 |
+
if newname not in vars:
|
106 |
+
vars[newname] = vars[name]
|
107 |
+
args = [newname] + rout['args'][1:]
|
108 |
+
else:
|
109 |
+
args = [newname] + rout['args']
|
110 |
+
|
111 |
+
l_tmpl = var2fixfortran(vars, name, '@@@NAME@@@', f90mode)
|
112 |
+
if l_tmpl[:13] == 'character*(*)':
|
113 |
+
if f90mode:
|
114 |
+
l_tmpl = 'character(len=10)' + l_tmpl[13:]
|
115 |
+
else:
|
116 |
+
l_tmpl = 'character*10' + l_tmpl[13:]
|
117 |
+
charselect = vars[name]['charselector']
|
118 |
+
if charselect.get('*', '') == '(*)':
|
119 |
+
charselect['*'] = '10'
|
120 |
+
|
121 |
+
l1 = l_tmpl.replace('@@@NAME@@@', newname)
|
122 |
+
rl = None
|
123 |
+
|
124 |
+
useisoc = useiso_c_binding(rout)
|
125 |
+
sargs = ', '.join(args)
|
126 |
+
if f90mode:
|
127 |
+
# gh-23598 fix warning
|
128 |
+
# Essentially, this gets called again with modules where the name of the
|
129 |
+
# function is added to the arguments, which is not required, and removed
|
130 |
+
sargs = sargs.replace(f"{name}, ", '')
|
131 |
+
args = [arg for arg in args if arg != name]
|
132 |
+
rout['args'] = args
|
133 |
+
add('subroutine f2pywrap_%s_%s (%s)' %
|
134 |
+
(rout['modulename'], name, sargs))
|
135 |
+
if not signature:
|
136 |
+
add('use %s, only : %s' % (rout['modulename'], fortranname))
|
137 |
+
if useisoc:
|
138 |
+
add('use iso_c_binding')
|
139 |
+
else:
|
140 |
+
add('subroutine f2pywrap%s (%s)' % (name, sargs))
|
141 |
+
if useisoc:
|
142 |
+
add('use iso_c_binding')
|
143 |
+
if not need_interface:
|
144 |
+
add('external %s' % (fortranname))
|
145 |
+
rl = l_tmpl.replace('@@@NAME@@@', '') + ' ' + fortranname
|
146 |
+
|
147 |
+
if need_interface:
|
148 |
+
for line in rout['saved_interface'].split('\n'):
|
149 |
+
if line.lstrip().startswith('use ') and '__user__' not in line:
|
150 |
+
add(line)
|
151 |
+
|
152 |
+
args = args[1:]
|
153 |
+
dumped_args = []
|
154 |
+
for a in args:
|
155 |
+
if isexternal(vars[a]):
|
156 |
+
add('external %s' % (a))
|
157 |
+
dumped_args.append(a)
|
158 |
+
for a in args:
|
159 |
+
if a in dumped_args:
|
160 |
+
continue
|
161 |
+
if isscalar(vars[a]):
|
162 |
+
add(var2fixfortran(vars, a, f90mode=f90mode))
|
163 |
+
dumped_args.append(a)
|
164 |
+
for a in args:
|
165 |
+
if a in dumped_args:
|
166 |
+
continue
|
167 |
+
if isintent_in(vars[a]):
|
168 |
+
add(var2fixfortran(vars, a, f90mode=f90mode))
|
169 |
+
dumped_args.append(a)
|
170 |
+
for a in args:
|
171 |
+
if a in dumped_args:
|
172 |
+
continue
|
173 |
+
add(var2fixfortran(vars, a, f90mode=f90mode))
|
174 |
+
|
175 |
+
add(l1)
|
176 |
+
if rl is not None:
|
177 |
+
add(rl)
|
178 |
+
|
179 |
+
if need_interface:
|
180 |
+
if f90mode:
|
181 |
+
# f90 module already defines needed interface
|
182 |
+
pass
|
183 |
+
else:
|
184 |
+
add('interface')
|
185 |
+
add(rout['saved_interface'].lstrip())
|
186 |
+
add('end interface')
|
187 |
+
|
188 |
+
sargs = ', '.join([a for a in args if a not in extra_args])
|
189 |
+
|
190 |
+
if not signature:
|
191 |
+
if islogicalfunction(rout):
|
192 |
+
add('%s = .not.(.not.%s(%s))' % (newname, fortranname, sargs))
|
193 |
+
else:
|
194 |
+
add('%s = %s(%s)' % (newname, fortranname, sargs))
|
195 |
+
if f90mode:
|
196 |
+
add('end subroutine f2pywrap_%s_%s' % (rout['modulename'], name))
|
197 |
+
else:
|
198 |
+
add('end')
|
199 |
+
return ret[0]
|
200 |
+
|
201 |
+
|
202 |
+
def createsubrwrapper(rout, signature=0):
|
203 |
+
assert issubroutine(rout)
|
204 |
+
|
205 |
+
extra_args = []
|
206 |
+
vars = rout['vars']
|
207 |
+
for a in rout['args']:
|
208 |
+
v = rout['vars'][a]
|
209 |
+
for i, d in enumerate(v.get('dimension', [])):
|
210 |
+
if d == ':':
|
211 |
+
dn = 'f2py_%s_d%s' % (a, i)
|
212 |
+
dv = dict(typespec='integer', intent=['hide'])
|
213 |
+
dv['='] = 'shape(%s, %s)' % (a, i)
|
214 |
+
extra_args.append(dn)
|
215 |
+
vars[dn] = dv
|
216 |
+
v['dimension'][i] = dn
|
217 |
+
rout['args'].extend(extra_args)
|
218 |
+
need_interface = bool(extra_args)
|
219 |
+
|
220 |
+
ret = ['']
|
221 |
+
|
222 |
+
def add(line, ret=ret):
|
223 |
+
ret[0] = '%s\n %s' % (ret[0], line)
|
224 |
+
name = rout['name']
|
225 |
+
fortranname = getfortranname(rout)
|
226 |
+
f90mode = ismoduleroutine(rout)
|
227 |
+
|
228 |
+
args = rout['args']
|
229 |
+
|
230 |
+
useisoc = useiso_c_binding(rout)
|
231 |
+
sargs = ', '.join(args)
|
232 |
+
if f90mode:
|
233 |
+
add('subroutine f2pywrap_%s_%s (%s)' %
|
234 |
+
(rout['modulename'], name, sargs))
|
235 |
+
if useisoc:
|
236 |
+
add('use iso_c_binding')
|
237 |
+
if not signature:
|
238 |
+
add('use %s, only : %s' % (rout['modulename'], fortranname))
|
239 |
+
else:
|
240 |
+
add('subroutine f2pywrap%s (%s)' % (name, sargs))
|
241 |
+
if useisoc:
|
242 |
+
add('use iso_c_binding')
|
243 |
+
if not need_interface:
|
244 |
+
add('external %s' % (fortranname))
|
245 |
+
|
246 |
+
if need_interface:
|
247 |
+
for line in rout['saved_interface'].split('\n'):
|
248 |
+
if line.lstrip().startswith('use ') and '__user__' not in line:
|
249 |
+
add(line)
|
250 |
+
|
251 |
+
dumped_args = []
|
252 |
+
for a in args:
|
253 |
+
if isexternal(vars[a]):
|
254 |
+
add('external %s' % (a))
|
255 |
+
dumped_args.append(a)
|
256 |
+
for a in args:
|
257 |
+
if a in dumped_args:
|
258 |
+
continue
|
259 |
+
if isscalar(vars[a]):
|
260 |
+
add(var2fixfortran(vars, a, f90mode=f90mode))
|
261 |
+
dumped_args.append(a)
|
262 |
+
for a in args:
|
263 |
+
if a in dumped_args:
|
264 |
+
continue
|
265 |
+
add(var2fixfortran(vars, a, f90mode=f90mode))
|
266 |
+
|
267 |
+
if need_interface:
|
268 |
+
if f90mode:
|
269 |
+
# f90 module already defines needed interface
|
270 |
+
pass
|
271 |
+
else:
|
272 |
+
add('interface')
|
273 |
+
for line in rout['saved_interface'].split('\n'):
|
274 |
+
if line.lstrip().startswith('use ') and '__user__' in line:
|
275 |
+
continue
|
276 |
+
add(line)
|
277 |
+
add('end interface')
|
278 |
+
|
279 |
+
sargs = ', '.join([a for a in args if a not in extra_args])
|
280 |
+
|
281 |
+
if not signature:
|
282 |
+
add('call %s(%s)' % (fortranname, sargs))
|
283 |
+
if f90mode:
|
284 |
+
add('end subroutine f2pywrap_%s_%s' % (rout['modulename'], name))
|
285 |
+
else:
|
286 |
+
add('end')
|
287 |
+
return ret[0]
|
288 |
+
|
289 |
+
|
290 |
+
def assubr(rout):
|
291 |
+
if isfunction_wrap(rout):
|
292 |
+
fortranname = getfortranname(rout)
|
293 |
+
name = rout['name']
|
294 |
+
outmess('\t\tCreating wrapper for Fortran function "%s"("%s")...\n' % (
|
295 |
+
name, fortranname))
|
296 |
+
rout = copy.copy(rout)
|
297 |
+
fname = name
|
298 |
+
rname = fname
|
299 |
+
if 'result' in rout:
|
300 |
+
rname = rout['result']
|
301 |
+
rout['vars'][fname] = rout['vars'][rname]
|
302 |
+
fvar = rout['vars'][fname]
|
303 |
+
if not isintent_out(fvar):
|
304 |
+
if 'intent' not in fvar:
|
305 |
+
fvar['intent'] = []
|
306 |
+
fvar['intent'].append('out')
|
307 |
+
flag = 1
|
308 |
+
for i in fvar['intent']:
|
309 |
+
if i.startswith('out='):
|
310 |
+
flag = 0
|
311 |
+
break
|
312 |
+
if flag:
|
313 |
+
fvar['intent'].append('out=%s' % (rname))
|
314 |
+
rout['args'][:] = [fname] + rout['args']
|
315 |
+
return rout, createfuncwrapper(rout)
|
316 |
+
if issubroutine_wrap(rout):
|
317 |
+
fortranname = getfortranname(rout)
|
318 |
+
name = rout['name']
|
319 |
+
outmess('\t\tCreating wrapper for Fortran subroutine "%s"("%s")...\n'
|
320 |
+
% (name, fortranname))
|
321 |
+
rout = copy.copy(rout)
|
322 |
+
return rout, createsubrwrapper(rout)
|
323 |
+
return rout, ''
|
.venv/lib/python3.11/site-packages/numpy/f2py/rules.py
ADDED
@@ -0,0 +1,1568 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#!/usr/bin/env python3
|
2 |
+
"""
|
3 |
+
|
4 |
+
Rules for building C/API module with f2py2e.
|
5 |
+
|
6 |
+
Here is a skeleton of a new wrapper function (13Dec2001):
|
7 |
+
|
8 |
+
wrapper_function(args)
|
9 |
+
declarations
|
10 |
+
get_python_arguments, say, `a' and `b'
|
11 |
+
|
12 |
+
get_a_from_python
|
13 |
+
if (successful) {
|
14 |
+
|
15 |
+
get_b_from_python
|
16 |
+
if (successful) {
|
17 |
+
|
18 |
+
callfortran
|
19 |
+
if (successful) {
|
20 |
+
|
21 |
+
put_a_to_python
|
22 |
+
if (successful) {
|
23 |
+
|
24 |
+
put_b_to_python
|
25 |
+
if (successful) {
|
26 |
+
|
27 |
+
buildvalue = ...
|
28 |
+
|
29 |
+
}
|
30 |
+
|
31 |
+
}
|
32 |
+
|
33 |
+
}
|
34 |
+
|
35 |
+
}
|
36 |
+
cleanup_b
|
37 |
+
|
38 |
+
}
|
39 |
+
cleanup_a
|
40 |
+
|
41 |
+
return buildvalue
|
42 |
+
|
43 |
+
Copyright 1999 -- 2011 Pearu Peterson all rights reserved.
|
44 |
+
Copyright 2011 -- present NumPy Developers.
|
45 |
+
Permission to use, modify, and distribute this software is given under the
|
46 |
+
terms of the NumPy License.
|
47 |
+
|
48 |
+
NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
|
49 |
+
"""
|
50 |
+
import os, sys
|
51 |
+
import time
|
52 |
+
import copy
|
53 |
+
from pathlib import Path
|
54 |
+
|
55 |
+
# __version__.version is now the same as the NumPy version
|
56 |
+
from . import __version__
|
57 |
+
|
58 |
+
from .auxfuncs import (
|
59 |
+
applyrules, debugcapi, dictappend, errmess, gentitle, getargs2,
|
60 |
+
hascallstatement, hasexternals, hasinitvalue, hasnote,
|
61 |
+
hasresultnote, isarray, isarrayofstrings, ischaracter,
|
62 |
+
ischaracterarray, ischaracter_or_characterarray, iscomplex,
|
63 |
+
iscomplexarray, iscomplexfunction, iscomplexfunction_warn,
|
64 |
+
isdummyroutine, isexternal, isfunction, isfunction_wrap, isint1,
|
65 |
+
isint1array, isintent_aux, isintent_c, isintent_callback,
|
66 |
+
isintent_copy, isintent_hide, isintent_inout, isintent_nothide,
|
67 |
+
isintent_out, isintent_overwrite, islogical, islong_complex,
|
68 |
+
islong_double, islong_doublefunction, islong_long,
|
69 |
+
islong_longfunction, ismoduleroutine, isoptional, isrequired,
|
70 |
+
isscalar, issigned_long_longarray, isstring, isstringarray,
|
71 |
+
isstringfunction, issubroutine, isattr_value,
|
72 |
+
issubroutine_wrap, isthreadsafe, isunsigned, isunsigned_char,
|
73 |
+
isunsigned_chararray, isunsigned_long_long,
|
74 |
+
isunsigned_long_longarray, isunsigned_short, isunsigned_shortarray,
|
75 |
+
l_and, l_not, l_or, outmess, replace, stripcomma, requiresf90wrapper
|
76 |
+
)
|
77 |
+
|
78 |
+
from . import capi_maps
|
79 |
+
from . import cfuncs
|
80 |
+
from . import common_rules
|
81 |
+
from . import use_rules
|
82 |
+
from . import f90mod_rules
|
83 |
+
from . import func2subr
|
84 |
+
|
85 |
+
f2py_version = __version__.version
|
86 |
+
numpy_version = __version__.version
|
87 |
+
|
88 |
+
options = {}
|
89 |
+
sepdict = {}
|
90 |
+
# for k in ['need_cfuncs']: sepdict[k]=','
|
91 |
+
for k in ['decl',
|
92 |
+
'frompyobj',
|
93 |
+
'cleanupfrompyobj',
|
94 |
+
'topyarr', 'method',
|
95 |
+
'pyobjfrom', 'closepyobjfrom',
|
96 |
+
'freemem',
|
97 |
+
'userincludes',
|
98 |
+
'includes0', 'includes', 'typedefs', 'typedefs_generated',
|
99 |
+
'cppmacros', 'cfuncs', 'callbacks',
|
100 |
+
'latexdoc',
|
101 |
+
'restdoc',
|
102 |
+
'routine_defs', 'externroutines',
|
103 |
+
'initf2pywraphooks',
|
104 |
+
'commonhooks', 'initcommonhooks',
|
105 |
+
'f90modhooks', 'initf90modhooks']:
|
106 |
+
sepdict[k] = '\n'
|
107 |
+
|
108 |
+
#################### Rules for C/API module #################
|
109 |
+
|
110 |
+
generationtime = int(os.environ.get('SOURCE_DATE_EPOCH', time.time()))
|
111 |
+
module_rules = {
|
112 |
+
'modulebody': """\
|
113 |
+
/* File: #modulename#module.c
|
114 |
+
* This file is auto-generated with f2py (version:#f2py_version#).
|
115 |
+
* f2py is a Fortran to Python Interface Generator (FPIG), Second Edition,
|
116 |
+
* written by Pearu Peterson <[email protected]>.
|
117 |
+
* Generation date: """ + time.asctime(time.gmtime(generationtime)) + """
|
118 |
+
* Do not edit this file directly unless you know what you are doing!!!
|
119 |
+
*/
|
120 |
+
|
121 |
+
#ifdef __cplusplus
|
122 |
+
extern \"C\" {
|
123 |
+
#endif
|
124 |
+
|
125 |
+
#ifndef PY_SSIZE_T_CLEAN
|
126 |
+
#define PY_SSIZE_T_CLEAN
|
127 |
+
#endif /* PY_SSIZE_T_CLEAN */
|
128 |
+
|
129 |
+
/* Unconditionally included */
|
130 |
+
#include <Python.h>
|
131 |
+
#include <numpy/npy_os.h>
|
132 |
+
|
133 |
+
""" + gentitle("See f2py2e/cfuncs.py: includes") + """
|
134 |
+
#includes#
|
135 |
+
#includes0#
|
136 |
+
|
137 |
+
""" + gentitle("See f2py2e/rules.py: mod_rules['modulebody']") + """
|
138 |
+
static PyObject *#modulename#_error;
|
139 |
+
static PyObject *#modulename#_module;
|
140 |
+
|
141 |
+
""" + gentitle("See f2py2e/cfuncs.py: typedefs") + """
|
142 |
+
#typedefs#
|
143 |
+
|
144 |
+
""" + gentitle("See f2py2e/cfuncs.py: typedefs_generated") + """
|
145 |
+
#typedefs_generated#
|
146 |
+
|
147 |
+
""" + gentitle("See f2py2e/cfuncs.py: cppmacros") + """
|
148 |
+
#cppmacros#
|
149 |
+
|
150 |
+
""" + gentitle("See f2py2e/cfuncs.py: cfuncs") + """
|
151 |
+
#cfuncs#
|
152 |
+
|
153 |
+
""" + gentitle("See f2py2e/cfuncs.py: userincludes") + """
|
154 |
+
#userincludes#
|
155 |
+
|
156 |
+
""" + gentitle("See f2py2e/capi_rules.py: usercode") + """
|
157 |
+
#usercode#
|
158 |
+
|
159 |
+
/* See f2py2e/rules.py */
|
160 |
+
#externroutines#
|
161 |
+
|
162 |
+
""" + gentitle("See f2py2e/capi_rules.py: usercode1") + """
|
163 |
+
#usercode1#
|
164 |
+
|
165 |
+
""" + gentitle("See f2py2e/cb_rules.py: buildcallback") + """
|
166 |
+
#callbacks#
|
167 |
+
|
168 |
+
""" + gentitle("See f2py2e/rules.py: buildapi") + """
|
169 |
+
#body#
|
170 |
+
|
171 |
+
""" + gentitle("See f2py2e/f90mod_rules.py: buildhooks") + """
|
172 |
+
#f90modhooks#
|
173 |
+
|
174 |
+
""" + gentitle("See f2py2e/rules.py: module_rules['modulebody']") + """
|
175 |
+
|
176 |
+
""" + gentitle("See f2py2e/common_rules.py: buildhooks") + """
|
177 |
+
#commonhooks#
|
178 |
+
|
179 |
+
""" + gentitle("See f2py2e/rules.py") + """
|
180 |
+
|
181 |
+
static FortranDataDef f2py_routine_defs[] = {
|
182 |
+
#routine_defs#
|
183 |
+
{NULL}
|
184 |
+
};
|
185 |
+
|
186 |
+
static PyMethodDef f2py_module_methods[] = {
|
187 |
+
#pymethoddef#
|
188 |
+
{NULL,NULL}
|
189 |
+
};
|
190 |
+
|
191 |
+
static struct PyModuleDef moduledef = {
|
192 |
+
PyModuleDef_HEAD_INIT,
|
193 |
+
"#modulename#",
|
194 |
+
NULL,
|
195 |
+
-1,
|
196 |
+
f2py_module_methods,
|
197 |
+
NULL,
|
198 |
+
NULL,
|
199 |
+
NULL,
|
200 |
+
NULL
|
201 |
+
};
|
202 |
+
|
203 |
+
PyMODINIT_FUNC PyInit_#modulename#(void) {
|
204 |
+
int i;
|
205 |
+
PyObject *m,*d, *s, *tmp;
|
206 |
+
m = #modulename#_module = PyModule_Create(&moduledef);
|
207 |
+
Py_SET_TYPE(&PyFortran_Type, &PyType_Type);
|
208 |
+
import_array();
|
209 |
+
if (PyErr_Occurred())
|
210 |
+
{PyErr_SetString(PyExc_ImportError, \"can't initialize module #modulename# (failed to import numpy)\"); return m;}
|
211 |
+
d = PyModule_GetDict(m);
|
212 |
+
s = PyUnicode_FromString(\"#f2py_version#\");
|
213 |
+
PyDict_SetItemString(d, \"__version__\", s);
|
214 |
+
Py_DECREF(s);
|
215 |
+
s = PyUnicode_FromString(
|
216 |
+
\"This module '#modulename#' is auto-generated with f2py (version:#f2py_version#).\\nFunctions:\\n\"\n#docs#\".\");
|
217 |
+
PyDict_SetItemString(d, \"__doc__\", s);
|
218 |
+
Py_DECREF(s);
|
219 |
+
s = PyUnicode_FromString(\"""" + numpy_version + """\");
|
220 |
+
PyDict_SetItemString(d, \"__f2py_numpy_version__\", s);
|
221 |
+
Py_DECREF(s);
|
222 |
+
#modulename#_error = PyErr_NewException (\"#modulename#.error\", NULL, NULL);
|
223 |
+
/*
|
224 |
+
* Store the error object inside the dict, so that it could get deallocated.
|
225 |
+
* (in practice, this is a module, so it likely will not and cannot.)
|
226 |
+
*/
|
227 |
+
PyDict_SetItemString(d, \"_#modulename#_error\", #modulename#_error);
|
228 |
+
Py_DECREF(#modulename#_error);
|
229 |
+
for(i=0;f2py_routine_defs[i].name!=NULL;i++) {
|
230 |
+
tmp = PyFortranObject_NewAsAttr(&f2py_routine_defs[i]);
|
231 |
+
PyDict_SetItemString(d, f2py_routine_defs[i].name, tmp);
|
232 |
+
Py_DECREF(tmp);
|
233 |
+
}
|
234 |
+
#initf2pywraphooks#
|
235 |
+
#initf90modhooks#
|
236 |
+
#initcommonhooks#
|
237 |
+
#interface_usercode#
|
238 |
+
|
239 |
+
#ifdef F2PY_REPORT_ATEXIT
|
240 |
+
if (! PyErr_Occurred())
|
241 |
+
on_exit(f2py_report_on_exit,(void*)\"#modulename#\");
|
242 |
+
#endif
|
243 |
+
return m;
|
244 |
+
}
|
245 |
+
#ifdef __cplusplus
|
246 |
+
}
|
247 |
+
#endif
|
248 |
+
""",
|
249 |
+
'separatorsfor': {'latexdoc': '\n\n',
|
250 |
+
'restdoc': '\n\n'},
|
251 |
+
'latexdoc': ['\\section{Module \\texttt{#texmodulename#}}\n',
|
252 |
+
'#modnote#\n',
|
253 |
+
'#latexdoc#'],
|
254 |
+
'restdoc': ['Module #modulename#\n' + '=' * 80,
|
255 |
+
'\n#restdoc#']
|
256 |
+
}
|
257 |
+
|
258 |
+
defmod_rules = [
|
259 |
+
{'body': '/*eof body*/',
|
260 |
+
'method': '/*eof method*/',
|
261 |
+
'externroutines': '/*eof externroutines*/',
|
262 |
+
'routine_defs': '/*eof routine_defs*/',
|
263 |
+
'initf90modhooks': '/*eof initf90modhooks*/',
|
264 |
+
'initf2pywraphooks': '/*eof initf2pywraphooks*/',
|
265 |
+
'initcommonhooks': '/*eof initcommonhooks*/',
|
266 |
+
'latexdoc': '',
|
267 |
+
'restdoc': '',
|
268 |
+
'modnote': {hasnote: '#note#', l_not(hasnote): ''},
|
269 |
+
}
|
270 |
+
]
|
271 |
+
|
272 |
+
routine_rules = {
|
273 |
+
'separatorsfor': sepdict,
|
274 |
+
'body': """
|
275 |
+
#begintitle#
|
276 |
+
static char doc_#apiname#[] = \"\\\n#docreturn##name#(#docsignatureshort#)\\n\\nWrapper for ``#name#``.\\\n\\n#docstrsigns#\";
|
277 |
+
/* #declfortranroutine# */
|
278 |
+
static PyObject *#apiname#(const PyObject *capi_self,
|
279 |
+
PyObject *capi_args,
|
280 |
+
PyObject *capi_keywds,
|
281 |
+
#functype# (*f2py_func)(#callprotoargument#)) {
|
282 |
+
PyObject * volatile capi_buildvalue = NULL;
|
283 |
+
volatile int f2py_success = 1;
|
284 |
+
#decl#
|
285 |
+
static char *capi_kwlist[] = {#kwlist##kwlistopt##kwlistxa#NULL};
|
286 |
+
#usercode#
|
287 |
+
#routdebugenter#
|
288 |
+
#ifdef F2PY_REPORT_ATEXIT
|
289 |
+
f2py_start_clock();
|
290 |
+
#endif
|
291 |
+
if (!PyArg_ParseTupleAndKeywords(capi_args,capi_keywds,\\
|
292 |
+
\"#argformat#|#keyformat##xaformat#:#pyname#\",\\
|
293 |
+
capi_kwlist#args_capi##keys_capi##keys_xa#))\n return NULL;
|
294 |
+
#frompyobj#
|
295 |
+
/*end of frompyobj*/
|
296 |
+
#ifdef F2PY_REPORT_ATEXIT
|
297 |
+
f2py_start_call_clock();
|
298 |
+
#endif
|
299 |
+
#callfortranroutine#
|
300 |
+
if (PyErr_Occurred())
|
301 |
+
f2py_success = 0;
|
302 |
+
#ifdef F2PY_REPORT_ATEXIT
|
303 |
+
f2py_stop_call_clock();
|
304 |
+
#endif
|
305 |
+
/*end of callfortranroutine*/
|
306 |
+
if (f2py_success) {
|
307 |
+
#pyobjfrom#
|
308 |
+
/*end of pyobjfrom*/
|
309 |
+
CFUNCSMESS(\"Building return value.\\n\");
|
310 |
+
capi_buildvalue = Py_BuildValue(\"#returnformat#\"#return#);
|
311 |
+
/*closepyobjfrom*/
|
312 |
+
#closepyobjfrom#
|
313 |
+
} /*if (f2py_success) after callfortranroutine*/
|
314 |
+
/*cleanupfrompyobj*/
|
315 |
+
#cleanupfrompyobj#
|
316 |
+
if (capi_buildvalue == NULL) {
|
317 |
+
#routdebugfailure#
|
318 |
+
} else {
|
319 |
+
#routdebugleave#
|
320 |
+
}
|
321 |
+
CFUNCSMESS(\"Freeing memory.\\n\");
|
322 |
+
#freemem#
|
323 |
+
#ifdef F2PY_REPORT_ATEXIT
|
324 |
+
f2py_stop_clock();
|
325 |
+
#endif
|
326 |
+
return capi_buildvalue;
|
327 |
+
}
|
328 |
+
#endtitle#
|
329 |
+
""",
|
330 |
+
'routine_defs': '#routine_def#',
|
331 |
+
'initf2pywraphooks': '#initf2pywraphook#',
|
332 |
+
'externroutines': '#declfortranroutine#',
|
333 |
+
'doc': '#docreturn##name#(#docsignature#)',
|
334 |
+
'docshort': '#docreturn##name#(#docsignatureshort#)',
|
335 |
+
'docs': '" #docreturn##name#(#docsignature#)\\n"\n',
|
336 |
+
'need': ['arrayobject.h', 'CFUNCSMESS', 'MINMAX'],
|
337 |
+
'cppmacros': {debugcapi: '#define DEBUGCFUNCS'},
|
338 |
+
'latexdoc': ['\\subsection{Wrapper function \\texttt{#texname#}}\n',
|
339 |
+
"""
|
340 |
+
\\noindent{{}\\verb@#docreturn##name#@{}}\\texttt{(#latexdocsignatureshort#)}
|
341 |
+
#routnote#
|
342 |
+
|
343 |
+
#latexdocstrsigns#
|
344 |
+
"""],
|
345 |
+
'restdoc': ['Wrapped function ``#name#``\n' + '-' * 80,
|
346 |
+
|
347 |
+
]
|
348 |
+
}
|
349 |
+
|
350 |
+
################## Rules for C/API function ##############
|
351 |
+
|
352 |
+
rout_rules = [
|
353 |
+
{ # Init
|
354 |
+
'separatorsfor': {'callfortranroutine': '\n', 'routdebugenter': '\n', 'decl': '\n',
|
355 |
+
'routdebugleave': '\n', 'routdebugfailure': '\n',
|
356 |
+
'setjmpbuf': ' || ',
|
357 |
+
'docstrreq': '\n', 'docstropt': '\n', 'docstrout': '\n',
|
358 |
+
'docstrcbs': '\n', 'docstrsigns': '\\n"\n"',
|
359 |
+
'latexdocstrsigns': '\n',
|
360 |
+
'latexdocstrreq': '\n', 'latexdocstropt': '\n',
|
361 |
+
'latexdocstrout': '\n', 'latexdocstrcbs': '\n',
|
362 |
+
},
|
363 |
+
'kwlist': '', 'kwlistopt': '', 'callfortran': '', 'callfortranappend': '',
|
364 |
+
'docsign': '', 'docsignopt': '', 'decl': '/*decl*/',
|
365 |
+
'freemem': '/*freemem*/',
|
366 |
+
'docsignshort': '', 'docsignoptshort': '',
|
367 |
+
'docstrsigns': '', 'latexdocstrsigns': '',
|
368 |
+
'docstrreq': '\\nParameters\\n----------',
|
369 |
+
'docstropt': '\\nOther Parameters\\n----------------',
|
370 |
+
'docstrout': '\\nReturns\\n-------',
|
371 |
+
'docstrcbs': '\\nNotes\\n-----\\nCall-back functions::\\n',
|
372 |
+
'latexdocstrreq': '\\noindent Required arguments:',
|
373 |
+
'latexdocstropt': '\\noindent Optional arguments:',
|
374 |
+
'latexdocstrout': '\\noindent Return objects:',
|
375 |
+
'latexdocstrcbs': '\\noindent Call-back functions:',
|
376 |
+
'args_capi': '', 'keys_capi': '', 'functype': '',
|
377 |
+
'frompyobj': '/*frompyobj*/',
|
378 |
+
# this list will be reversed
|
379 |
+
'cleanupfrompyobj': ['/*end of cleanupfrompyobj*/'],
|
380 |
+
'pyobjfrom': '/*pyobjfrom*/',
|
381 |
+
# this list will be reversed
|
382 |
+
'closepyobjfrom': ['/*end of closepyobjfrom*/'],
|
383 |
+
'topyarr': '/*topyarr*/', 'routdebugleave': '/*routdebugleave*/',
|
384 |
+
'routdebugenter': '/*routdebugenter*/',
|
385 |
+
'routdebugfailure': '/*routdebugfailure*/',
|
386 |
+
'callfortranroutine': '/*callfortranroutine*/',
|
387 |
+
'argformat': '', 'keyformat': '', 'need_cfuncs': '',
|
388 |
+
'docreturn': '', 'return': '', 'returnformat': '', 'rformat': '',
|
389 |
+
'kwlistxa': '', 'keys_xa': '', 'xaformat': '', 'docsignxa': '', 'docsignxashort': '',
|
390 |
+
'initf2pywraphook': '',
|
391 |
+
'routnote': {hasnote: '--- #note#', l_not(hasnote): ''},
|
392 |
+
}, {
|
393 |
+
'apiname': 'f2py_rout_#modulename#_#name#',
|
394 |
+
'pyname': '#modulename#.#name#',
|
395 |
+
'decl': '',
|
396 |
+
'_check': l_not(ismoduleroutine)
|
397 |
+
}, {
|
398 |
+
'apiname': 'f2py_rout_#modulename#_#f90modulename#_#name#',
|
399 |
+
'pyname': '#modulename#.#f90modulename#.#name#',
|
400 |
+
'decl': '',
|
401 |
+
'_check': ismoduleroutine
|
402 |
+
}, { # Subroutine
|
403 |
+
'functype': 'void',
|
404 |
+
'declfortranroutine': {l_and(l_not(l_or(ismoduleroutine, isintent_c)), l_not(isdummyroutine)): 'extern void #F_FUNC#(#fortranname#,#FORTRANNAME#)(#callprotoargument#);',
|
405 |
+
l_and(l_not(ismoduleroutine), isintent_c, l_not(isdummyroutine)): 'extern void #fortranname#(#callprotoargument#);',
|
406 |
+
ismoduleroutine: '',
|
407 |
+
isdummyroutine: ''
|
408 |
+
},
|
409 |
+
'routine_def': {
|
410 |
+
l_not(l_or(ismoduleroutine, isintent_c, isdummyroutine)):
|
411 |
+
' {\"#name#\",-1,{{-1}},0,0,(char *)'
|
412 |
+
' #F_FUNC#(#fortranname#,#FORTRANNAME#),'
|
413 |
+
' (f2py_init_func)#apiname#,doc_#apiname#},',
|
414 |
+
l_and(l_not(ismoduleroutine), isintent_c, l_not(isdummyroutine)):
|
415 |
+
' {\"#name#\",-1,{{-1}},0,0,(char *)#fortranname#,'
|
416 |
+
' (f2py_init_func)#apiname#,doc_#apiname#},',
|
417 |
+
l_and(l_not(ismoduleroutine), isdummyroutine):
|
418 |
+
' {\"#name#\",-1,{{-1}},0,0,NULL,'
|
419 |
+
' (f2py_init_func)#apiname#,doc_#apiname#},',
|
420 |
+
},
|
421 |
+
'need': {l_and(l_not(l_or(ismoduleroutine, isintent_c)), l_not(isdummyroutine)): 'F_FUNC'},
|
422 |
+
'callfortranroutine': [
|
423 |
+
{debugcapi: [
|
424 |
+
""" fprintf(stderr,\"debug-capi:Fortran subroutine `#fortranname#(#callfortran#)\'\\n\");"""]},
|
425 |
+
{hasexternals: """\
|
426 |
+
if (#setjmpbuf#) {
|
427 |
+
f2py_success = 0;
|
428 |
+
} else {"""},
|
429 |
+
{isthreadsafe: ' Py_BEGIN_ALLOW_THREADS'},
|
430 |
+
{hascallstatement: ''' #callstatement#;
|
431 |
+
/*(*f2py_func)(#callfortran#);*/'''},
|
432 |
+
{l_not(l_or(hascallstatement, isdummyroutine))
|
433 |
+
: ' (*f2py_func)(#callfortran#);'},
|
434 |
+
{isthreadsafe: ' Py_END_ALLOW_THREADS'},
|
435 |
+
{hasexternals: """ }"""}
|
436 |
+
],
|
437 |
+
'_check': l_and(issubroutine, l_not(issubroutine_wrap)),
|
438 |
+
}, { # Wrapped function
|
439 |
+
'functype': 'void',
|
440 |
+
'declfortranroutine': {l_not(l_or(ismoduleroutine, isdummyroutine)): 'extern void #F_WRAPPEDFUNC#(#name_lower#,#NAME#)(#callprotoargument#);',
|
441 |
+
isdummyroutine: '',
|
442 |
+
},
|
443 |
+
|
444 |
+
'routine_def': {
|
445 |
+
l_not(l_or(ismoduleroutine, isdummyroutine)):
|
446 |
+
' {\"#name#\",-1,{{-1}},0,0,(char *)'
|
447 |
+
' #F_WRAPPEDFUNC#(#name_lower#,#NAME#),'
|
448 |
+
' (f2py_init_func)#apiname#,doc_#apiname#},',
|
449 |
+
isdummyroutine:
|
450 |
+
' {\"#name#\",-1,{{-1}},0,0,NULL,'
|
451 |
+
' (f2py_init_func)#apiname#,doc_#apiname#},',
|
452 |
+
},
|
453 |
+
'initf2pywraphook': {l_not(l_or(ismoduleroutine, isdummyroutine)): '''
|
454 |
+
{
|
455 |
+
extern #ctype# #F_FUNC#(#name_lower#,#NAME#)(void);
|
456 |
+
PyObject* o = PyDict_GetItemString(d,"#name#");
|
457 |
+
tmp = F2PyCapsule_FromVoidPtr((void*)#F_FUNC#(#name_lower#,#NAME#),NULL);
|
458 |
+
PyObject_SetAttrString(o,"_cpointer", tmp);
|
459 |
+
Py_DECREF(tmp);
|
460 |
+
s = PyUnicode_FromString("#name#");
|
461 |
+
PyObject_SetAttrString(o,"__name__", s);
|
462 |
+
Py_DECREF(s);
|
463 |
+
}
|
464 |
+
'''},
|
465 |
+
'need': {l_not(l_or(ismoduleroutine, isdummyroutine)): ['F_WRAPPEDFUNC', 'F_FUNC']},
|
466 |
+
'callfortranroutine': [
|
467 |
+
{debugcapi: [
|
468 |
+
""" fprintf(stderr,\"debug-capi:Fortran subroutine `f2pywrap#name_lower#(#callfortran#)\'\\n\");"""]},
|
469 |
+
{hasexternals: """\
|
470 |
+
if (#setjmpbuf#) {
|
471 |
+
f2py_success = 0;
|
472 |
+
} else {"""},
|
473 |
+
{isthreadsafe: ' Py_BEGIN_ALLOW_THREADS'},
|
474 |
+
{l_not(l_or(hascallstatement, isdummyroutine))
|
475 |
+
: ' (*f2py_func)(#callfortran#);'},
|
476 |
+
{hascallstatement:
|
477 |
+
' #callstatement#;\n /*(*f2py_func)(#callfortran#);*/'},
|
478 |
+
{isthreadsafe: ' Py_END_ALLOW_THREADS'},
|
479 |
+
{hasexternals: ' }'}
|
480 |
+
],
|
481 |
+
'_check': isfunction_wrap,
|
482 |
+
}, { # Wrapped subroutine
|
483 |
+
'functype': 'void',
|
484 |
+
'declfortranroutine': {l_not(l_or(ismoduleroutine, isdummyroutine)): 'extern void #F_WRAPPEDFUNC#(#name_lower#,#NAME#)(#callprotoargument#);',
|
485 |
+
isdummyroutine: '',
|
486 |
+
},
|
487 |
+
|
488 |
+
'routine_def': {
|
489 |
+
l_not(l_or(ismoduleroutine, isdummyroutine)):
|
490 |
+
' {\"#name#\",-1,{{-1}},0,0,(char *)'
|
491 |
+
' #F_WRAPPEDFUNC#(#name_lower#,#NAME#),'
|
492 |
+
' (f2py_init_func)#apiname#,doc_#apiname#},',
|
493 |
+
isdummyroutine:
|
494 |
+
' {\"#name#\",-1,{{-1}},0,0,NULL,'
|
495 |
+
' (f2py_init_func)#apiname#,doc_#apiname#},',
|
496 |
+
},
|
497 |
+
'initf2pywraphook': {l_not(l_or(ismoduleroutine, isdummyroutine)): '''
|
498 |
+
{
|
499 |
+
extern void #F_FUNC#(#name_lower#,#NAME#)(void);
|
500 |
+
PyObject* o = PyDict_GetItemString(d,"#name#");
|
501 |
+
tmp = F2PyCapsule_FromVoidPtr((void*)#F_FUNC#(#name_lower#,#NAME#),NULL);
|
502 |
+
PyObject_SetAttrString(o,"_cpointer", tmp);
|
503 |
+
Py_DECREF(tmp);
|
504 |
+
s = PyUnicode_FromString("#name#");
|
505 |
+
PyObject_SetAttrString(o,"__name__", s);
|
506 |
+
Py_DECREF(s);
|
507 |
+
}
|
508 |
+
'''},
|
509 |
+
'need': {l_not(l_or(ismoduleroutine, isdummyroutine)): ['F_WRAPPEDFUNC', 'F_FUNC']},
|
510 |
+
'callfortranroutine': [
|
511 |
+
{debugcapi: [
|
512 |
+
""" fprintf(stderr,\"debug-capi:Fortran subroutine `f2pywrap#name_lower#(#callfortran#)\'\\n\");"""]},
|
513 |
+
{hasexternals: """\
|
514 |
+
if (#setjmpbuf#) {
|
515 |
+
f2py_success = 0;
|
516 |
+
} else {"""},
|
517 |
+
{isthreadsafe: ' Py_BEGIN_ALLOW_THREADS'},
|
518 |
+
{l_not(l_or(hascallstatement, isdummyroutine))
|
519 |
+
: ' (*f2py_func)(#callfortran#);'},
|
520 |
+
{hascallstatement:
|
521 |
+
' #callstatement#;\n /*(*f2py_func)(#callfortran#);*/'},
|
522 |
+
{isthreadsafe: ' Py_END_ALLOW_THREADS'},
|
523 |
+
{hasexternals: ' }'}
|
524 |
+
],
|
525 |
+
'_check': issubroutine_wrap,
|
526 |
+
}, { # Function
|
527 |
+
'functype': '#ctype#',
|
528 |
+
'docreturn': {l_not(isintent_hide): '#rname#,'},
|
529 |
+
'docstrout': '#pydocsignout#',
|
530 |
+
'latexdocstrout': ['\\item[]{{}\\verb@#pydocsignout#@{}}',
|
531 |
+
{hasresultnote: '--- #resultnote#'}],
|
532 |
+
'callfortranroutine': [{l_and(debugcapi, isstringfunction): """\
|
533 |
+
#ifdef USESCOMPAQFORTRAN
|
534 |
+
fprintf(stderr,\"debug-capi:Fortran function #ctype# #fortranname#(#callcompaqfortran#)\\n\");
|
535 |
+
#else
|
536 |
+
fprintf(stderr,\"debug-capi:Fortran function #ctype# #fortranname#(#callfortran#)\\n\");
|
537 |
+
#endif
|
538 |
+
"""},
|
539 |
+
{l_and(debugcapi, l_not(isstringfunction)): """\
|
540 |
+
fprintf(stderr,\"debug-capi:Fortran function #ctype# #fortranname#(#callfortran#)\\n\");
|
541 |
+
"""}
|
542 |
+
],
|
543 |
+
'_check': l_and(isfunction, l_not(isfunction_wrap))
|
544 |
+
}, { # Scalar function
|
545 |
+
'declfortranroutine': {l_and(l_not(l_or(ismoduleroutine, isintent_c)), l_not(isdummyroutine)): 'extern #ctype# #F_FUNC#(#fortranname#,#FORTRANNAME#)(#callprotoargument#);',
|
546 |
+
l_and(l_not(ismoduleroutine), isintent_c, l_not(isdummyroutine)): 'extern #ctype# #fortranname#(#callprotoargument#);',
|
547 |
+
isdummyroutine: ''
|
548 |
+
},
|
549 |
+
'routine_def': {
|
550 |
+
l_and(l_not(l_or(ismoduleroutine, isintent_c)),
|
551 |
+
l_not(isdummyroutine)):
|
552 |
+
(' {\"#name#\",-1,{{-1}},0,0,(char *)'
|
553 |
+
' #F_FUNC#(#fortranname#,#FORTRANNAME#),'
|
554 |
+
' (f2py_init_func)#apiname#,doc_#apiname#},'),
|
555 |
+
l_and(l_not(ismoduleroutine), isintent_c, l_not(isdummyroutine)):
|
556 |
+
(' {\"#name#\",-1,{{-1}},0,0,(char *)#fortranname#,'
|
557 |
+
' (f2py_init_func)#apiname#,doc_#apiname#},'),
|
558 |
+
isdummyroutine:
|
559 |
+
' {\"#name#\",-1,{{-1}},0,0,NULL,'
|
560 |
+
'(f2py_init_func)#apiname#,doc_#apiname#},',
|
561 |
+
},
|
562 |
+
'decl': [{iscomplexfunction_warn: ' #ctype# #name#_return_value={0,0};',
|
563 |
+
l_not(iscomplexfunction): ' #ctype# #name#_return_value=0;'},
|
564 |
+
{iscomplexfunction:
|
565 |
+
' PyObject *#name#_return_value_capi = Py_None;'}
|
566 |
+
],
|
567 |
+
'callfortranroutine': [
|
568 |
+
{hasexternals: """\
|
569 |
+
if (#setjmpbuf#) {
|
570 |
+
f2py_success = 0;
|
571 |
+
} else {"""},
|
572 |
+
{isthreadsafe: ' Py_BEGIN_ALLOW_THREADS'},
|
573 |
+
{hascallstatement: ''' #callstatement#;
|
574 |
+
/* #name#_return_value = (*f2py_func)(#callfortran#);*/
|
575 |
+
'''},
|
576 |
+
{l_not(l_or(hascallstatement, isdummyroutine))
|
577 |
+
: ' #name#_return_value = (*f2py_func)(#callfortran#);'},
|
578 |
+
{isthreadsafe: ' Py_END_ALLOW_THREADS'},
|
579 |
+
{hasexternals: ' }'},
|
580 |
+
{l_and(debugcapi, iscomplexfunction)
|
581 |
+
: ' fprintf(stderr,"#routdebugshowvalue#\\n",#name#_return_value.r,#name#_return_value.i);'},
|
582 |
+
{l_and(debugcapi, l_not(iscomplexfunction)): ' fprintf(stderr,"#routdebugshowvalue#\\n",#name#_return_value);'}],
|
583 |
+
'pyobjfrom': {iscomplexfunction: ' #name#_return_value_capi = pyobj_from_#ctype#1(#name#_return_value);'},
|
584 |
+
'need': [{l_not(isdummyroutine): 'F_FUNC'},
|
585 |
+
{iscomplexfunction: 'pyobj_from_#ctype#1'},
|
586 |
+
{islong_longfunction: 'long_long'},
|
587 |
+
{islong_doublefunction: 'long_double'}],
|
588 |
+
'returnformat': {l_not(isintent_hide): '#rformat#'},
|
589 |
+
'return': {iscomplexfunction: ',#name#_return_value_capi',
|
590 |
+
l_not(l_or(iscomplexfunction, isintent_hide)): ',#name#_return_value'},
|
591 |
+
'_check': l_and(isfunction, l_not(isstringfunction), l_not(isfunction_wrap))
|
592 |
+
}, { # String function # in use for --no-wrap
|
593 |
+
'declfortranroutine': 'extern void #F_FUNC#(#fortranname#,#FORTRANNAME#)(#callprotoargument#);',
|
594 |
+
'routine_def': {l_not(l_or(ismoduleroutine, isintent_c)):
|
595 |
+
' {\"#name#\",-1,{{-1}},0,0,(char *)#F_FUNC#(#fortranname#,#FORTRANNAME#),(f2py_init_func)#apiname#,doc_#apiname#},',
|
596 |
+
l_and(l_not(ismoduleroutine), isintent_c):
|
597 |
+
' {\"#name#\",-1,{{-1}},0,0,(char *)#fortranname#,(f2py_init_func)#apiname#,doc_#apiname#},'
|
598 |
+
},
|
599 |
+
'decl': [' #ctype# #name#_return_value = NULL;',
|
600 |
+
' int #name#_return_value_len = 0;'],
|
601 |
+
'callfortran':'#name#_return_value,#name#_return_value_len,',
|
602 |
+
'callfortranroutine':[' #name#_return_value_len = #rlength#;',
|
603 |
+
' if ((#name#_return_value = (string)malloc('
|
604 |
+
+ '#name#_return_value_len+1) == NULL) {',
|
605 |
+
' PyErr_SetString(PyExc_MemoryError, \"out of memory\");',
|
606 |
+
' f2py_success = 0;',
|
607 |
+
' } else {',
|
608 |
+
" (#name#_return_value)[#name#_return_value_len] = '\\0';",
|
609 |
+
' }',
|
610 |
+
' if (f2py_success) {',
|
611 |
+
{hasexternals: """\
|
612 |
+
if (#setjmpbuf#) {
|
613 |
+
f2py_success = 0;
|
614 |
+
} else {"""},
|
615 |
+
{isthreadsafe: ' Py_BEGIN_ALLOW_THREADS'},
|
616 |
+
"""\
|
617 |
+
#ifdef USESCOMPAQFORTRAN
|
618 |
+
(*f2py_func)(#callcompaqfortran#);
|
619 |
+
#else
|
620 |
+
(*f2py_func)(#callfortran#);
|
621 |
+
#endif
|
622 |
+
""",
|
623 |
+
{isthreadsafe: ' Py_END_ALLOW_THREADS'},
|
624 |
+
{hasexternals: ' }'},
|
625 |
+
{debugcapi:
|
626 |
+
' fprintf(stderr,"#routdebugshowvalue#\\n",#name#_return_value_len,#name#_return_value);'},
|
627 |
+
' } /* if (f2py_success) after (string)malloc */',
|
628 |
+
],
|
629 |
+
'returnformat': '#rformat#',
|
630 |
+
'return': ',#name#_return_value',
|
631 |
+
'freemem': ' STRINGFREE(#name#_return_value);',
|
632 |
+
'need': ['F_FUNC', '#ctype#', 'STRINGFREE'],
|
633 |
+
'_check':l_and(isstringfunction, l_not(isfunction_wrap)) # ???obsolete
|
634 |
+
},
|
635 |
+
{ # Debugging
|
636 |
+
'routdebugenter': ' fprintf(stderr,"debug-capi:Python C/API function #modulename#.#name#(#docsignature#)\\n");',
|
637 |
+
'routdebugleave': ' fprintf(stderr,"debug-capi:Python C/API function #modulename#.#name#: successful.\\n");',
|
638 |
+
'routdebugfailure': ' fprintf(stderr,"debug-capi:Python C/API function #modulename#.#name#: failure.\\n");',
|
639 |
+
'_check': debugcapi
|
640 |
+
}
|
641 |
+
]
|
642 |
+
|
643 |
+
################ Rules for arguments ##################
|
644 |
+
|
645 |
+
typedef_need_dict = {islong_long: 'long_long',
|
646 |
+
islong_double: 'long_double',
|
647 |
+
islong_complex: 'complex_long_double',
|
648 |
+
isunsigned_char: 'unsigned_char',
|
649 |
+
isunsigned_short: 'unsigned_short',
|
650 |
+
isunsigned: 'unsigned',
|
651 |
+
isunsigned_long_long: 'unsigned_long_long',
|
652 |
+
isunsigned_chararray: 'unsigned_char',
|
653 |
+
isunsigned_shortarray: 'unsigned_short',
|
654 |
+
isunsigned_long_longarray: 'unsigned_long_long',
|
655 |
+
issigned_long_longarray: 'long_long',
|
656 |
+
isint1: 'signed_char',
|
657 |
+
ischaracter_or_characterarray: 'character',
|
658 |
+
}
|
659 |
+
|
660 |
+
aux_rules = [
|
661 |
+
{
|
662 |
+
'separatorsfor': sepdict
|
663 |
+
},
|
664 |
+
{ # Common
|
665 |
+
'frompyobj': [' /* Processing auxiliary variable #varname# */',
|
666 |
+
{debugcapi: ' fprintf(stderr,"#vardebuginfo#\\n");'}, ],
|
667 |
+
'cleanupfrompyobj': ' /* End of cleaning variable #varname# */',
|
668 |
+
'need': typedef_need_dict,
|
669 |
+
},
|
670 |
+
# Scalars (not complex)
|
671 |
+
{ # Common
|
672 |
+
'decl': ' #ctype# #varname# = 0;',
|
673 |
+
'need': {hasinitvalue: 'math.h'},
|
674 |
+
'frompyobj': {hasinitvalue: ' #varname# = #init#;'},
|
675 |
+
'_check': l_and(isscalar, l_not(iscomplex)),
|
676 |
+
},
|
677 |
+
{
|
678 |
+
'return': ',#varname#',
|
679 |
+
'docstrout': '#pydocsignout#',
|
680 |
+
'docreturn': '#outvarname#,',
|
681 |
+
'returnformat': '#varrformat#',
|
682 |
+
'_check': l_and(isscalar, l_not(iscomplex), isintent_out),
|
683 |
+
},
|
684 |
+
# Complex scalars
|
685 |
+
{ # Common
|
686 |
+
'decl': ' #ctype# #varname#;',
|
687 |
+
'frompyobj': {hasinitvalue: ' #varname#.r = #init.r#, #varname#.i = #init.i#;'},
|
688 |
+
'_check': iscomplex
|
689 |
+
},
|
690 |
+
# String
|
691 |
+
{ # Common
|
692 |
+
'decl': [' #ctype# #varname# = NULL;',
|
693 |
+
' int slen(#varname#);',
|
694 |
+
],
|
695 |
+
'need':['len..'],
|
696 |
+
'_check':isstring
|
697 |
+
},
|
698 |
+
# Array
|
699 |
+
{ # Common
|
700 |
+
'decl': [' #ctype# *#varname# = NULL;',
|
701 |
+
' npy_intp #varname#_Dims[#rank#] = {#rank*[-1]#};',
|
702 |
+
' const int #varname#_Rank = #rank#;',
|
703 |
+
],
|
704 |
+
'need':['len..', {hasinitvalue: 'forcomb'}, {hasinitvalue: 'CFUNCSMESS'}],
|
705 |
+
'_check': isarray
|
706 |
+
},
|
707 |
+
# Scalararray
|
708 |
+
{ # Common
|
709 |
+
'_check': l_and(isarray, l_not(iscomplexarray))
|
710 |
+
}, { # Not hidden
|
711 |
+
'_check': l_and(isarray, l_not(iscomplexarray), isintent_nothide)
|
712 |
+
},
|
713 |
+
# Integer*1 array
|
714 |
+
{'need': '#ctype#',
|
715 |
+
'_check': isint1array,
|
716 |
+
'_depend': ''
|
717 |
+
},
|
718 |
+
# Integer*-1 array
|
719 |
+
{'need': '#ctype#',
|
720 |
+
'_check': l_or(isunsigned_chararray, isunsigned_char),
|
721 |
+
'_depend': ''
|
722 |
+
},
|
723 |
+
# Integer*-2 array
|
724 |
+
{'need': '#ctype#',
|
725 |
+
'_check': isunsigned_shortarray,
|
726 |
+
'_depend': ''
|
727 |
+
},
|
728 |
+
# Integer*-8 array
|
729 |
+
{'need': '#ctype#',
|
730 |
+
'_check': isunsigned_long_longarray,
|
731 |
+
'_depend': ''
|
732 |
+
},
|
733 |
+
# Complexarray
|
734 |
+
{'need': '#ctype#',
|
735 |
+
'_check': iscomplexarray,
|
736 |
+
'_depend': ''
|
737 |
+
},
|
738 |
+
# Stringarray
|
739 |
+
{
|
740 |
+
'callfortranappend': {isarrayofstrings: 'flen(#varname#),'},
|
741 |
+
'need': 'string',
|
742 |
+
'_check': isstringarray
|
743 |
+
}
|
744 |
+
]
|
745 |
+
|
746 |
+
arg_rules = [
|
747 |
+
{
|
748 |
+
'separatorsfor': sepdict
|
749 |
+
},
|
750 |
+
{ # Common
|
751 |
+
'frompyobj': [' /* Processing variable #varname# */',
|
752 |
+
{debugcapi: ' fprintf(stderr,"#vardebuginfo#\\n");'}, ],
|
753 |
+
'cleanupfrompyobj': ' /* End of cleaning variable #varname# */',
|
754 |
+
'_depend': '',
|
755 |
+
'need': typedef_need_dict,
|
756 |
+
},
|
757 |
+
# Doc signatures
|
758 |
+
{
|
759 |
+
'docstropt': {l_and(isoptional, isintent_nothide): '#pydocsign#'},
|
760 |
+
'docstrreq': {l_and(isrequired, isintent_nothide): '#pydocsign#'},
|
761 |
+
'docstrout': {isintent_out: '#pydocsignout#'},
|
762 |
+
'latexdocstropt': {l_and(isoptional, isintent_nothide): ['\\item[]{{}\\verb@#pydocsign#@{}}',
|
763 |
+
{hasnote: '--- #note#'}]},
|
764 |
+
'latexdocstrreq': {l_and(isrequired, isintent_nothide): ['\\item[]{{}\\verb@#pydocsign#@{}}',
|
765 |
+
{hasnote: '--- #note#'}]},
|
766 |
+
'latexdocstrout': {isintent_out: ['\\item[]{{}\\verb@#pydocsignout#@{}}',
|
767 |
+
{l_and(hasnote, isintent_hide): '--- #note#',
|
768 |
+
l_and(hasnote, isintent_nothide): '--- See above.'}]},
|
769 |
+
'depend': ''
|
770 |
+
},
|
771 |
+
# Required/Optional arguments
|
772 |
+
{
|
773 |
+
'kwlist': '"#varname#",',
|
774 |
+
'docsign': '#varname#,',
|
775 |
+
'_check': l_and(isintent_nothide, l_not(isoptional))
|
776 |
+
},
|
777 |
+
{
|
778 |
+
'kwlistopt': '"#varname#",',
|
779 |
+
'docsignopt': '#varname#=#showinit#,',
|
780 |
+
'docsignoptshort': '#varname#,',
|
781 |
+
'_check': l_and(isintent_nothide, isoptional)
|
782 |
+
},
|
783 |
+
# Docstring/BuildValue
|
784 |
+
{
|
785 |
+
'docreturn': '#outvarname#,',
|
786 |
+
'returnformat': '#varrformat#',
|
787 |
+
'_check': isintent_out
|
788 |
+
},
|
789 |
+
# Externals (call-back functions)
|
790 |
+
{ # Common
|
791 |
+
'docsignxa': {isintent_nothide: '#varname#_extra_args=(),'},
|
792 |
+
'docsignxashort': {isintent_nothide: '#varname#_extra_args,'},
|
793 |
+
'docstropt': {isintent_nothide: '#varname#_extra_args : input tuple, optional\\n Default: ()'},
|
794 |
+
'docstrcbs': '#cbdocstr#',
|
795 |
+
'latexdocstrcbs': '\\item[] #cblatexdocstr#',
|
796 |
+
'latexdocstropt': {isintent_nothide: '\\item[]{{}\\verb@#varname#_extra_args := () input tuple@{}} --- Extra arguments for call-back function {{}\\verb@#varname#@{}}.'},
|
797 |
+
'decl': [' #cbname#_t #varname#_cb = { Py_None, NULL, 0 };',
|
798 |
+
' #cbname#_t *#varname#_cb_ptr = &#varname#_cb;',
|
799 |
+
' PyTupleObject *#varname#_xa_capi = NULL;',
|
800 |
+
{l_not(isintent_callback):
|
801 |
+
' #cbname#_typedef #varname#_cptr;'}
|
802 |
+
],
|
803 |
+
'kwlistxa': {isintent_nothide: '"#varname#_extra_args",'},
|
804 |
+
'argformat': {isrequired: 'O'},
|
805 |
+
'keyformat': {isoptional: 'O'},
|
806 |
+
'xaformat': {isintent_nothide: 'O!'},
|
807 |
+
'args_capi': {isrequired: ',&#varname#_cb.capi'},
|
808 |
+
'keys_capi': {isoptional: ',&#varname#_cb.capi'},
|
809 |
+
'keys_xa': ',&PyTuple_Type,&#varname#_xa_capi',
|
810 |
+
'setjmpbuf': '(setjmp(#varname#_cb.jmpbuf))',
|
811 |
+
'callfortran': {l_not(isintent_callback): '#varname#_cptr,'},
|
812 |
+
'need': ['#cbname#', 'setjmp.h'],
|
813 |
+
'_check':isexternal
|
814 |
+
},
|
815 |
+
{
|
816 |
+
'frompyobj': [{l_not(isintent_callback): """\
|
817 |
+
if(F2PyCapsule_Check(#varname#_cb.capi)) {
|
818 |
+
#varname#_cptr = F2PyCapsule_AsVoidPtr(#varname#_cb.capi);
|
819 |
+
} else {
|
820 |
+
#varname#_cptr = #cbname#;
|
821 |
+
}
|
822 |
+
"""}, {isintent_callback: """\
|
823 |
+
if (#varname#_cb.capi==Py_None) {
|
824 |
+
#varname#_cb.capi = PyObject_GetAttrString(#modulename#_module,\"#varname#\");
|
825 |
+
if (#varname#_cb.capi) {
|
826 |
+
if (#varname#_xa_capi==NULL) {
|
827 |
+
if (PyObject_HasAttrString(#modulename#_module,\"#varname#_extra_args\")) {
|
828 |
+
PyObject* capi_tmp = PyObject_GetAttrString(#modulename#_module,\"#varname#_extra_args\");
|
829 |
+
if (capi_tmp) {
|
830 |
+
#varname#_xa_capi = (PyTupleObject *)PySequence_Tuple(capi_tmp);
|
831 |
+
Py_DECREF(capi_tmp);
|
832 |
+
}
|
833 |
+
else {
|
834 |
+
#varname#_xa_capi = (PyTupleObject *)Py_BuildValue(\"()\");
|
835 |
+
}
|
836 |
+
if (#varname#_xa_capi==NULL) {
|
837 |
+
PyErr_SetString(#modulename#_error,\"Failed to convert #modulename#.#varname#_extra_args to tuple.\\n\");
|
838 |
+
return NULL;
|
839 |
+
}
|
840 |
+
}
|
841 |
+
}
|
842 |
+
}
|
843 |
+
if (#varname#_cb.capi==NULL) {
|
844 |
+
PyErr_SetString(#modulename#_error,\"Callback #varname# not defined (as an argument or module #modulename# attribute).\\n\");
|
845 |
+
return NULL;
|
846 |
+
}
|
847 |
+
}
|
848 |
+
"""},
|
849 |
+
"""\
|
850 |
+
if (create_cb_arglist(#varname#_cb.capi,#varname#_xa_capi,#maxnofargs#,#nofoptargs#,&#varname#_cb.nofargs,&#varname#_cb.args_capi,\"failed in processing argument list for call-back #varname#.\")) {
|
851 |
+
""",
|
852 |
+
{debugcapi: ["""\
|
853 |
+
fprintf(stderr,\"debug-capi:Assuming %d arguments; at most #maxnofargs#(-#nofoptargs#) is expected.\\n\",#varname#_cb.nofargs);
|
854 |
+
CFUNCSMESSPY(\"for #varname#=\",#varname#_cb.capi);""",
|
855 |
+
{l_not(isintent_callback): """ fprintf(stderr,\"#vardebugshowvalue# (call-back in C).\\n\",#cbname#);"""}]},
|
856 |
+
"""\
|
857 |
+
CFUNCSMESS(\"Saving callback variables for `#varname#`.\\n\");
|
858 |
+
#varname#_cb_ptr = swap_active_#cbname#(#varname#_cb_ptr);""",
|
859 |
+
],
|
860 |
+
'cleanupfrompyobj':
|
861 |
+
"""\
|
862 |
+
CFUNCSMESS(\"Restoring callback variables for `#varname#`.\\n\");
|
863 |
+
#varname#_cb_ptr = swap_active_#cbname#(#varname#_cb_ptr);
|
864 |
+
Py_DECREF(#varname#_cb.args_capi);
|
865 |
+
}""",
|
866 |
+
'need': ['SWAP', 'create_cb_arglist'],
|
867 |
+
'_check':isexternal,
|
868 |
+
'_depend':''
|
869 |
+
},
|
870 |
+
# Scalars (not complex)
|
871 |
+
{ # Common
|
872 |
+
'decl': ' #ctype# #varname# = 0;',
|
873 |
+
'pyobjfrom': {debugcapi: ' fprintf(stderr,"#vardebugshowvalue#\\n",#varname#);'},
|
874 |
+
'callfortran': {l_or(isintent_c, isattr_value): '#varname#,', l_not(l_or(isintent_c, isattr_value)): '&#varname#,'},
|
875 |
+
'return': {isintent_out: ',#varname#'},
|
876 |
+
'_check': l_and(isscalar, l_not(iscomplex))
|
877 |
+
}, {
|
878 |
+
'need': {hasinitvalue: 'math.h'},
|
879 |
+
'_check': l_and(isscalar, l_not(iscomplex)),
|
880 |
+
}, { # Not hidden
|
881 |
+
'decl': ' PyObject *#varname#_capi = Py_None;',
|
882 |
+
'argformat': {isrequired: 'O'},
|
883 |
+
'keyformat': {isoptional: 'O'},
|
884 |
+
'args_capi': {isrequired: ',&#varname#_capi'},
|
885 |
+
'keys_capi': {isoptional: ',&#varname#_capi'},
|
886 |
+
'pyobjfrom': {isintent_inout: """\
|
887 |
+
f2py_success = try_pyarr_from_#ctype#(#varname#_capi,&#varname#);
|
888 |
+
if (f2py_success) {"""},
|
889 |
+
'closepyobjfrom': {isintent_inout: " } /*if (f2py_success) of #varname# pyobjfrom*/"},
|
890 |
+
'need': {isintent_inout: 'try_pyarr_from_#ctype#'},
|
891 |
+
'_check': l_and(isscalar, l_not(iscomplex), l_not(isstring),
|
892 |
+
isintent_nothide)
|
893 |
+
}, {
|
894 |
+
'frompyobj': [
|
895 |
+
# hasinitvalue...
|
896 |
+
# if pyobj is None:
|
897 |
+
# varname = init
|
898 |
+
# else
|
899 |
+
# from_pyobj(varname)
|
900 |
+
#
|
901 |
+
# isoptional and noinitvalue...
|
902 |
+
# if pyobj is not None:
|
903 |
+
# from_pyobj(varname)
|
904 |
+
# else:
|
905 |
+
# varname is uninitialized
|
906 |
+
#
|
907 |
+
# ...
|
908 |
+
# from_pyobj(varname)
|
909 |
+
#
|
910 |
+
{hasinitvalue: ' if (#varname#_capi == Py_None) #varname# = #init#; else',
|
911 |
+
'_depend': ''},
|
912 |
+
{l_and(isoptional, l_not(hasinitvalue)): ' if (#varname#_capi != Py_None)',
|
913 |
+
'_depend': ''},
|
914 |
+
{l_not(islogical): '''\
|
915 |
+
f2py_success = #ctype#_from_pyobj(&#varname#,#varname#_capi,"#pyname#() #nth# (#varname#) can\'t be converted to #ctype#");
|
916 |
+
if (f2py_success) {'''},
|
917 |
+
{islogical: '''\
|
918 |
+
#varname# = (#ctype#)PyObject_IsTrue(#varname#_capi);
|
919 |
+
f2py_success = 1;
|
920 |
+
if (f2py_success) {'''},
|
921 |
+
],
|
922 |
+
'cleanupfrompyobj': ' } /*if (f2py_success) of #varname#*/',
|
923 |
+
'need': {l_not(islogical): '#ctype#_from_pyobj'},
|
924 |
+
'_check': l_and(isscalar, l_not(iscomplex), isintent_nothide),
|
925 |
+
'_depend': ''
|
926 |
+
}, { # Hidden
|
927 |
+
'frompyobj': {hasinitvalue: ' #varname# = #init#;'},
|
928 |
+
'need': typedef_need_dict,
|
929 |
+
'_check': l_and(isscalar, l_not(iscomplex), isintent_hide),
|
930 |
+
'_depend': ''
|
931 |
+
}, { # Common
|
932 |
+
'frompyobj': {debugcapi: ' fprintf(stderr,"#vardebugshowvalue#\\n",#varname#);'},
|
933 |
+
'_check': l_and(isscalar, l_not(iscomplex)),
|
934 |
+
'_depend': ''
|
935 |
+
},
|
936 |
+
# Complex scalars
|
937 |
+
{ # Common
|
938 |
+
'decl': ' #ctype# #varname#;',
|
939 |
+
'callfortran': {isintent_c: '#varname#,', l_not(isintent_c): '&#varname#,'},
|
940 |
+
'pyobjfrom': {debugcapi: ' fprintf(stderr,"#vardebugshowvalue#\\n",#varname#.r,#varname#.i);'},
|
941 |
+
'return': {isintent_out: ',#varname#_capi'},
|
942 |
+
'_check': iscomplex
|
943 |
+
}, { # Not hidden
|
944 |
+
'decl': ' PyObject *#varname#_capi = Py_None;',
|
945 |
+
'argformat': {isrequired: 'O'},
|
946 |
+
'keyformat': {isoptional: 'O'},
|
947 |
+
'args_capi': {isrequired: ',&#varname#_capi'},
|
948 |
+
'keys_capi': {isoptional: ',&#varname#_capi'},
|
949 |
+
'need': {isintent_inout: 'try_pyarr_from_#ctype#'},
|
950 |
+
'pyobjfrom': {isintent_inout: """\
|
951 |
+
f2py_success = try_pyarr_from_#ctype#(#varname#_capi,&#varname#);
|
952 |
+
if (f2py_success) {"""},
|
953 |
+
'closepyobjfrom': {isintent_inout: " } /*if (f2py_success) of #varname# pyobjfrom*/"},
|
954 |
+
'_check': l_and(iscomplex, isintent_nothide)
|
955 |
+
}, {
|
956 |
+
'frompyobj': [{hasinitvalue: ' if (#varname#_capi==Py_None) {#varname#.r = #init.r#, #varname#.i = #init.i#;} else'},
|
957 |
+
{l_and(isoptional, l_not(hasinitvalue))
|
958 |
+
: ' if (#varname#_capi != Py_None)'},
|
959 |
+
' f2py_success = #ctype#_from_pyobj(&#varname#,#varname#_capi,"#pyname#() #nth# (#varname#) can\'t be converted to #ctype#");'
|
960 |
+
'\n if (f2py_success) {'],
|
961 |
+
'cleanupfrompyobj': ' } /*if (f2py_success) of #varname# frompyobj*/',
|
962 |
+
'need': ['#ctype#_from_pyobj'],
|
963 |
+
'_check': l_and(iscomplex, isintent_nothide),
|
964 |
+
'_depend': ''
|
965 |
+
}, { # Hidden
|
966 |
+
'decl': {isintent_out: ' PyObject *#varname#_capi = Py_None;'},
|
967 |
+
'_check': l_and(iscomplex, isintent_hide)
|
968 |
+
}, {
|
969 |
+
'frompyobj': {hasinitvalue: ' #varname#.r = #init.r#, #varname#.i = #init.i#;'},
|
970 |
+
'_check': l_and(iscomplex, isintent_hide),
|
971 |
+
'_depend': ''
|
972 |
+
}, { # Common
|
973 |
+
'pyobjfrom': {isintent_out: ' #varname#_capi = pyobj_from_#ctype#1(#varname#);'},
|
974 |
+
'need': ['pyobj_from_#ctype#1'],
|
975 |
+
'_check': iscomplex
|
976 |
+
}, {
|
977 |
+
'frompyobj': {debugcapi: ' fprintf(stderr,"#vardebugshowvalue#\\n",#varname#.r,#varname#.i);'},
|
978 |
+
'_check': iscomplex,
|
979 |
+
'_depend': ''
|
980 |
+
},
|
981 |
+
# String
|
982 |
+
{ # Common
|
983 |
+
'decl': [' #ctype# #varname# = NULL;',
|
984 |
+
' int slen(#varname#);',
|
985 |
+
' PyObject *#varname#_capi = Py_None;'],
|
986 |
+
'callfortran':'#varname#,',
|
987 |
+
'callfortranappend':'slen(#varname#),',
|
988 |
+
'pyobjfrom':[
|
989 |
+
{debugcapi:
|
990 |
+
' fprintf(stderr,'
|
991 |
+
'"#vardebugshowvalue#\\n",slen(#varname#),#varname#);'},
|
992 |
+
# The trailing null value for Fortran is blank.
|
993 |
+
{l_and(isintent_out, l_not(isintent_c)):
|
994 |
+
" STRINGPADN(#varname#, slen(#varname#), ' ', '\\0');"},
|
995 |
+
],
|
996 |
+
'return': {isintent_out: ',#varname#'},
|
997 |
+
'need': ['len..',
|
998 |
+
{l_and(isintent_out, l_not(isintent_c)): 'STRINGPADN'}],
|
999 |
+
'_check': isstring
|
1000 |
+
}, { # Common
|
1001 |
+
'frompyobj': [
|
1002 |
+
"""\
|
1003 |
+
slen(#varname#) = #elsize#;
|
1004 |
+
f2py_success = #ctype#_from_pyobj(&#varname#,&slen(#varname#),#init#,"""
|
1005 |
+
"""#varname#_capi,\"#ctype#_from_pyobj failed in converting #nth#"""
|
1006 |
+
"""`#varname#\' of #pyname# to C #ctype#\");
|
1007 |
+
if (f2py_success) {""",
|
1008 |
+
# The trailing null value for Fortran is blank.
|
1009 |
+
{l_not(isintent_c):
|
1010 |
+
" STRINGPADN(#varname#, slen(#varname#), '\\0', ' ');"},
|
1011 |
+
],
|
1012 |
+
'cleanupfrompyobj': """\
|
1013 |
+
STRINGFREE(#varname#);
|
1014 |
+
} /*if (f2py_success) of #varname#*/""",
|
1015 |
+
'need': ['#ctype#_from_pyobj', 'len..', 'STRINGFREE',
|
1016 |
+
{l_not(isintent_c): 'STRINGPADN'}],
|
1017 |
+
'_check':isstring,
|
1018 |
+
'_depend':''
|
1019 |
+
}, { # Not hidden
|
1020 |
+
'argformat': {isrequired: 'O'},
|
1021 |
+
'keyformat': {isoptional: 'O'},
|
1022 |
+
'args_capi': {isrequired: ',&#varname#_capi'},
|
1023 |
+
'keys_capi': {isoptional: ',&#varname#_capi'},
|
1024 |
+
'pyobjfrom': [
|
1025 |
+
{l_and(isintent_inout, l_not(isintent_c)):
|
1026 |
+
" STRINGPADN(#varname#, slen(#varname#), ' ', '\\0');"},
|
1027 |
+
{isintent_inout: '''\
|
1028 |
+
f2py_success = try_pyarr_from_#ctype#(#varname#_capi, #varname#,
|
1029 |
+
slen(#varname#));
|
1030 |
+
if (f2py_success) {'''}],
|
1031 |
+
'closepyobjfrom': {isintent_inout: ' } /*if (f2py_success) of #varname# pyobjfrom*/'},
|
1032 |
+
'need': {isintent_inout: 'try_pyarr_from_#ctype#',
|
1033 |
+
l_and(isintent_inout, l_not(isintent_c)): 'STRINGPADN'},
|
1034 |
+
'_check': l_and(isstring, isintent_nothide)
|
1035 |
+
}, { # Hidden
|
1036 |
+
'_check': l_and(isstring, isintent_hide)
|
1037 |
+
}, {
|
1038 |
+
'frompyobj': {debugcapi: ' fprintf(stderr,"#vardebugshowvalue#\\n",slen(#varname#),#varname#);'},
|
1039 |
+
'_check': isstring,
|
1040 |
+
'_depend': ''
|
1041 |
+
},
|
1042 |
+
# Array
|
1043 |
+
{ # Common
|
1044 |
+
'decl': [' #ctype# *#varname# = NULL;',
|
1045 |
+
' npy_intp #varname#_Dims[#rank#] = {#rank*[-1]#};',
|
1046 |
+
' const int #varname#_Rank = #rank#;',
|
1047 |
+
' PyArrayObject *capi_#varname#_as_array = NULL;',
|
1048 |
+
' int capi_#varname#_intent = 0;',
|
1049 |
+
{isstringarray: ' int slen(#varname#) = 0;'},
|
1050 |
+
],
|
1051 |
+
'callfortran':'#varname#,',
|
1052 |
+
'callfortranappend': {isstringarray: 'slen(#varname#),'},
|
1053 |
+
'return': {isintent_out: ',capi_#varname#_as_array'},
|
1054 |
+
'need': 'len..',
|
1055 |
+
'_check': isarray
|
1056 |
+
}, { # intent(overwrite) array
|
1057 |
+
'decl': ' int capi_overwrite_#varname# = 1;',
|
1058 |
+
'kwlistxa': '"overwrite_#varname#",',
|
1059 |
+
'xaformat': 'i',
|
1060 |
+
'keys_xa': ',&capi_overwrite_#varname#',
|
1061 |
+
'docsignxa': 'overwrite_#varname#=1,',
|
1062 |
+
'docsignxashort': 'overwrite_#varname#,',
|
1063 |
+
'docstropt': 'overwrite_#varname# : input int, optional\\n Default: 1',
|
1064 |
+
'_check': l_and(isarray, isintent_overwrite),
|
1065 |
+
}, {
|
1066 |
+
'frompyobj': ' capi_#varname#_intent |= (capi_overwrite_#varname#?0:F2PY_INTENT_COPY);',
|
1067 |
+
'_check': l_and(isarray, isintent_overwrite),
|
1068 |
+
'_depend': '',
|
1069 |
+
},
|
1070 |
+
{ # intent(copy) array
|
1071 |
+
'decl': ' int capi_overwrite_#varname# = 0;',
|
1072 |
+
'kwlistxa': '"overwrite_#varname#",',
|
1073 |
+
'xaformat': 'i',
|
1074 |
+
'keys_xa': ',&capi_overwrite_#varname#',
|
1075 |
+
'docsignxa': 'overwrite_#varname#=0,',
|
1076 |
+
'docsignxashort': 'overwrite_#varname#,',
|
1077 |
+
'docstropt': 'overwrite_#varname# : input int, optional\\n Default: 0',
|
1078 |
+
'_check': l_and(isarray, isintent_copy),
|
1079 |
+
}, {
|
1080 |
+
'frompyobj': ' capi_#varname#_intent |= (capi_overwrite_#varname#?0:F2PY_INTENT_COPY);',
|
1081 |
+
'_check': l_and(isarray, isintent_copy),
|
1082 |
+
'_depend': '',
|
1083 |
+
}, {
|
1084 |
+
'need': [{hasinitvalue: 'forcomb'}, {hasinitvalue: 'CFUNCSMESS'}],
|
1085 |
+
'_check': isarray,
|
1086 |
+
'_depend': ''
|
1087 |
+
}, { # Not hidden
|
1088 |
+
'decl': ' PyObject *#varname#_capi = Py_None;',
|
1089 |
+
'argformat': {isrequired: 'O'},
|
1090 |
+
'keyformat': {isoptional: 'O'},
|
1091 |
+
'args_capi': {isrequired: ',&#varname#_capi'},
|
1092 |
+
'keys_capi': {isoptional: ',&#varname#_capi'},
|
1093 |
+
'_check': l_and(isarray, isintent_nothide)
|
1094 |
+
}, {
|
1095 |
+
'frompyobj': [
|
1096 |
+
' #setdims#;',
|
1097 |
+
' capi_#varname#_intent |= #intent#;',
|
1098 |
+
(' const char * capi_errmess = "#modulename#.#pyname#:'
|
1099 |
+
' failed to create array from the #nth# `#varname#`";'),
|
1100 |
+
{isintent_hide:
|
1101 |
+
' capi_#varname#_as_array = ndarray_from_pyobj('
|
1102 |
+
' #atype#,#elsize#,#varname#_Dims,#varname#_Rank,'
|
1103 |
+
' capi_#varname#_intent,Py_None,capi_errmess);'},
|
1104 |
+
{isintent_nothide:
|
1105 |
+
' capi_#varname#_as_array = ndarray_from_pyobj('
|
1106 |
+
' #atype#,#elsize#,#varname#_Dims,#varname#_Rank,'
|
1107 |
+
' capi_#varname#_intent,#varname#_capi,capi_errmess);'},
|
1108 |
+
"""\
|
1109 |
+
if (capi_#varname#_as_array == NULL) {
|
1110 |
+
PyObject* capi_err = PyErr_Occurred();
|
1111 |
+
if (capi_err == NULL) {
|
1112 |
+
capi_err = #modulename#_error;
|
1113 |
+
PyErr_SetString(capi_err, capi_errmess);
|
1114 |
+
}
|
1115 |
+
} else {
|
1116 |
+
#varname# = (#ctype# *)(PyArray_DATA(capi_#varname#_as_array));
|
1117 |
+
""",
|
1118 |
+
{isstringarray:
|
1119 |
+
' slen(#varname#) = f2py_itemsize(#varname#);'},
|
1120 |
+
{hasinitvalue: [
|
1121 |
+
{isintent_nothide:
|
1122 |
+
' if (#varname#_capi == Py_None) {'},
|
1123 |
+
{isintent_hide: ' {'},
|
1124 |
+
{iscomplexarray: ' #ctype# capi_c;'},
|
1125 |
+
"""\
|
1126 |
+
int *_i,capi_i=0;
|
1127 |
+
CFUNCSMESS(\"#name#: Initializing #varname#=#init#\\n\");
|
1128 |
+
if (initforcomb(PyArray_DIMS(capi_#varname#_as_array),
|
1129 |
+
PyArray_NDIM(capi_#varname#_as_array),1)) {
|
1130 |
+
while ((_i = nextforcomb()))
|
1131 |
+
#varname#[capi_i++] = #init#; /* fortran way */
|
1132 |
+
} else {
|
1133 |
+
PyObject *exc, *val, *tb;
|
1134 |
+
PyErr_Fetch(&exc, &val, &tb);
|
1135 |
+
PyErr_SetString(exc ? exc : #modulename#_error,
|
1136 |
+
\"Initialization of #nth# #varname# failed (initforcomb).\");
|
1137 |
+
npy_PyErr_ChainExceptionsCause(exc, val, tb);
|
1138 |
+
f2py_success = 0;
|
1139 |
+
}
|
1140 |
+
}
|
1141 |
+
if (f2py_success) {"""]},
|
1142 |
+
],
|
1143 |
+
'cleanupfrompyobj': [ # note that this list will be reversed
|
1144 |
+
' } '
|
1145 |
+
'/* if (capi_#varname#_as_array == NULL) ... else of #varname# */',
|
1146 |
+
{l_not(l_or(isintent_out, isintent_hide)): """\
|
1147 |
+
if((PyObject *)capi_#varname#_as_array!=#varname#_capi) {
|
1148 |
+
Py_XDECREF(capi_#varname#_as_array); }"""},
|
1149 |
+
{l_and(isintent_hide, l_not(isintent_out))
|
1150 |
+
: """ Py_XDECREF(capi_#varname#_as_array);"""},
|
1151 |
+
{hasinitvalue: ' } /*if (f2py_success) of #varname# init*/'},
|
1152 |
+
],
|
1153 |
+
'_check': isarray,
|
1154 |
+
'_depend': ''
|
1155 |
+
},
|
1156 |
+
# Scalararray
|
1157 |
+
{ # Common
|
1158 |
+
'_check': l_and(isarray, l_not(iscomplexarray))
|
1159 |
+
}, { # Not hidden
|
1160 |
+
'_check': l_and(isarray, l_not(iscomplexarray), isintent_nothide)
|
1161 |
+
},
|
1162 |
+
# Integer*1 array
|
1163 |
+
{'need': '#ctype#',
|
1164 |
+
'_check': isint1array,
|
1165 |
+
'_depend': ''
|
1166 |
+
},
|
1167 |
+
# Integer*-1 array
|
1168 |
+
{'need': '#ctype#',
|
1169 |
+
'_check': isunsigned_chararray,
|
1170 |
+
'_depend': ''
|
1171 |
+
},
|
1172 |
+
# Integer*-2 array
|
1173 |
+
{'need': '#ctype#',
|
1174 |
+
'_check': isunsigned_shortarray,
|
1175 |
+
'_depend': ''
|
1176 |
+
},
|
1177 |
+
# Integer*-8 array
|
1178 |
+
{'need': '#ctype#',
|
1179 |
+
'_check': isunsigned_long_longarray,
|
1180 |
+
'_depend': ''
|
1181 |
+
},
|
1182 |
+
# Complexarray
|
1183 |
+
{'need': '#ctype#',
|
1184 |
+
'_check': iscomplexarray,
|
1185 |
+
'_depend': ''
|
1186 |
+
},
|
1187 |
+
# Character
|
1188 |
+
{
|
1189 |
+
'need': 'string',
|
1190 |
+
'_check': ischaracter,
|
1191 |
+
},
|
1192 |
+
# Character array
|
1193 |
+
{
|
1194 |
+
'need': 'string',
|
1195 |
+
'_check': ischaracterarray,
|
1196 |
+
},
|
1197 |
+
# Stringarray
|
1198 |
+
{
|
1199 |
+
'callfortranappend': {isarrayofstrings: 'flen(#varname#),'},
|
1200 |
+
'need': 'string',
|
1201 |
+
'_check': isstringarray
|
1202 |
+
}
|
1203 |
+
]
|
1204 |
+
|
1205 |
+
################# Rules for checking ###############
|
1206 |
+
|
1207 |
+
check_rules = [
|
1208 |
+
{
|
1209 |
+
'frompyobj': {debugcapi: ' fprintf(stderr,\"debug-capi:Checking `#check#\'\\n\");'},
|
1210 |
+
'need': 'len..'
|
1211 |
+
}, {
|
1212 |
+
'frompyobj': ' CHECKSCALAR(#check#,\"#check#\",\"#nth# #varname#\",\"#varshowvalue#\",#varname#) {',
|
1213 |
+
'cleanupfrompyobj': ' } /*CHECKSCALAR(#check#)*/',
|
1214 |
+
'need': 'CHECKSCALAR',
|
1215 |
+
'_check': l_and(isscalar, l_not(iscomplex)),
|
1216 |
+
'_break': ''
|
1217 |
+
}, {
|
1218 |
+
'frompyobj': ' CHECKSTRING(#check#,\"#check#\",\"#nth# #varname#\",\"#varshowvalue#\",#varname#) {',
|
1219 |
+
'cleanupfrompyobj': ' } /*CHECKSTRING(#check#)*/',
|
1220 |
+
'need': 'CHECKSTRING',
|
1221 |
+
'_check': isstring,
|
1222 |
+
'_break': ''
|
1223 |
+
}, {
|
1224 |
+
'need': 'CHECKARRAY',
|
1225 |
+
'frompyobj': ' CHECKARRAY(#check#,\"#check#\",\"#nth# #varname#\") {',
|
1226 |
+
'cleanupfrompyobj': ' } /*CHECKARRAY(#check#)*/',
|
1227 |
+
'_check': isarray,
|
1228 |
+
'_break': ''
|
1229 |
+
}, {
|
1230 |
+
'need': 'CHECKGENERIC',
|
1231 |
+
'frompyobj': ' CHECKGENERIC(#check#,\"#check#\",\"#nth# #varname#\") {',
|
1232 |
+
'cleanupfrompyobj': ' } /*CHECKGENERIC(#check#)*/',
|
1233 |
+
}
|
1234 |
+
]
|
1235 |
+
|
1236 |
+
########## Applying the rules. No need to modify what follows #############
|
1237 |
+
|
1238 |
+
#################### Build C/API module #######################
|
1239 |
+
|
1240 |
+
|
1241 |
+
def buildmodule(m, um):
|
1242 |
+
"""
|
1243 |
+
Return
|
1244 |
+
"""
|
1245 |
+
outmess(' Building module "%s"...\n' % (m['name']))
|
1246 |
+
ret = {}
|
1247 |
+
mod_rules = defmod_rules[:]
|
1248 |
+
vrd = capi_maps.modsign2map(m)
|
1249 |
+
rd = dictappend({'f2py_version': f2py_version}, vrd)
|
1250 |
+
funcwrappers = []
|
1251 |
+
funcwrappers2 = [] # F90 codes
|
1252 |
+
for n in m['interfaced']:
|
1253 |
+
nb = None
|
1254 |
+
for bi in m['body']:
|
1255 |
+
if bi['block'] not in ['interface', 'abstract interface']:
|
1256 |
+
errmess('buildmodule: Expected interface block. Skipping.\n')
|
1257 |
+
continue
|
1258 |
+
for b in bi['body']:
|
1259 |
+
if b['name'] == n:
|
1260 |
+
nb = b
|
1261 |
+
break
|
1262 |
+
|
1263 |
+
if not nb:
|
1264 |
+
print(
|
1265 |
+
'buildmodule: Could not find the body of interfaced routine "%s". Skipping.\n' % (n), file=sys.stderr)
|
1266 |
+
continue
|
1267 |
+
nb_list = [nb]
|
1268 |
+
if 'entry' in nb:
|
1269 |
+
for k, a in nb['entry'].items():
|
1270 |
+
nb1 = copy.deepcopy(nb)
|
1271 |
+
del nb1['entry']
|
1272 |
+
nb1['name'] = k
|
1273 |
+
nb1['args'] = a
|
1274 |
+
nb_list.append(nb1)
|
1275 |
+
for nb in nb_list:
|
1276 |
+
# requiresf90wrapper must be called before buildapi as it
|
1277 |
+
# rewrites assumed shape arrays as automatic arrays.
|
1278 |
+
isf90 = requiresf90wrapper(nb)
|
1279 |
+
# options is in scope here
|
1280 |
+
if options['emptygen']:
|
1281 |
+
b_path = options['buildpath']
|
1282 |
+
m_name = vrd['modulename']
|
1283 |
+
outmess(' Generating possibly empty wrappers"\n')
|
1284 |
+
Path(f"{b_path}/{vrd['coutput']}").touch()
|
1285 |
+
if isf90:
|
1286 |
+
# f77 + f90 wrappers
|
1287 |
+
outmess(f' Maybe empty "{m_name}-f2pywrappers2.f90"\n')
|
1288 |
+
Path(f'{b_path}/{m_name}-f2pywrappers2.f90').touch()
|
1289 |
+
outmess(f' Maybe empty "{m_name}-f2pywrappers.f"\n')
|
1290 |
+
Path(f'{b_path}/{m_name}-f2pywrappers.f').touch()
|
1291 |
+
else:
|
1292 |
+
# only f77 wrappers
|
1293 |
+
outmess(f' Maybe empty "{m_name}-f2pywrappers.f"\n')
|
1294 |
+
Path(f'{b_path}/{m_name}-f2pywrappers.f').touch()
|
1295 |
+
api, wrap = buildapi(nb)
|
1296 |
+
if wrap:
|
1297 |
+
if isf90:
|
1298 |
+
funcwrappers2.append(wrap)
|
1299 |
+
else:
|
1300 |
+
funcwrappers.append(wrap)
|
1301 |
+
ar = applyrules(api, vrd)
|
1302 |
+
rd = dictappend(rd, ar)
|
1303 |
+
|
1304 |
+
# Construct COMMON block support
|
1305 |
+
cr, wrap = common_rules.buildhooks(m)
|
1306 |
+
if wrap:
|
1307 |
+
funcwrappers.append(wrap)
|
1308 |
+
ar = applyrules(cr, vrd)
|
1309 |
+
rd = dictappend(rd, ar)
|
1310 |
+
|
1311 |
+
# Construct F90 module support
|
1312 |
+
mr, wrap = f90mod_rules.buildhooks(m)
|
1313 |
+
if wrap:
|
1314 |
+
funcwrappers2.append(wrap)
|
1315 |
+
ar = applyrules(mr, vrd)
|
1316 |
+
rd = dictappend(rd, ar)
|
1317 |
+
|
1318 |
+
for u in um:
|
1319 |
+
ar = use_rules.buildusevars(u, m['use'][u['name']])
|
1320 |
+
rd = dictappend(rd, ar)
|
1321 |
+
|
1322 |
+
needs = cfuncs.get_needs()
|
1323 |
+
# Add mapped definitions
|
1324 |
+
needs['typedefs'] += [cvar for cvar in capi_maps.f2cmap_mapped #
|
1325 |
+
if cvar in typedef_need_dict.values()]
|
1326 |
+
code = {}
|
1327 |
+
for n in needs.keys():
|
1328 |
+
code[n] = []
|
1329 |
+
for k in needs[n]:
|
1330 |
+
c = ''
|
1331 |
+
if k in cfuncs.includes0:
|
1332 |
+
c = cfuncs.includes0[k]
|
1333 |
+
elif k in cfuncs.includes:
|
1334 |
+
c = cfuncs.includes[k]
|
1335 |
+
elif k in cfuncs.userincludes:
|
1336 |
+
c = cfuncs.userincludes[k]
|
1337 |
+
elif k in cfuncs.typedefs:
|
1338 |
+
c = cfuncs.typedefs[k]
|
1339 |
+
elif k in cfuncs.typedefs_generated:
|
1340 |
+
c = cfuncs.typedefs_generated[k]
|
1341 |
+
elif k in cfuncs.cppmacros:
|
1342 |
+
c = cfuncs.cppmacros[k]
|
1343 |
+
elif k in cfuncs.cfuncs:
|
1344 |
+
c = cfuncs.cfuncs[k]
|
1345 |
+
elif k in cfuncs.callbacks:
|
1346 |
+
c = cfuncs.callbacks[k]
|
1347 |
+
elif k in cfuncs.f90modhooks:
|
1348 |
+
c = cfuncs.f90modhooks[k]
|
1349 |
+
elif k in cfuncs.commonhooks:
|
1350 |
+
c = cfuncs.commonhooks[k]
|
1351 |
+
else:
|
1352 |
+
errmess('buildmodule: unknown need %s.\n' % (repr(k)))
|
1353 |
+
continue
|
1354 |
+
code[n].append(c)
|
1355 |
+
mod_rules.append(code)
|
1356 |
+
for r in mod_rules:
|
1357 |
+
if ('_check' in r and r['_check'](m)) or ('_check' not in r):
|
1358 |
+
ar = applyrules(r, vrd, m)
|
1359 |
+
rd = dictappend(rd, ar)
|
1360 |
+
ar = applyrules(module_rules, rd)
|
1361 |
+
|
1362 |
+
fn = os.path.join(options['buildpath'], vrd['coutput'])
|
1363 |
+
ret['csrc'] = fn
|
1364 |
+
with open(fn, 'w') as f:
|
1365 |
+
f.write(ar['modulebody'].replace('\t', 2 * ' '))
|
1366 |
+
outmess(' Wrote C/API module "%s" to file "%s"\n' % (m['name'], fn))
|
1367 |
+
|
1368 |
+
if options['dorestdoc']:
|
1369 |
+
fn = os.path.join(
|
1370 |
+
options['buildpath'], vrd['modulename'] + 'module.rest')
|
1371 |
+
with open(fn, 'w') as f:
|
1372 |
+
f.write('.. -*- rest -*-\n')
|
1373 |
+
f.write('\n'.join(ar['restdoc']))
|
1374 |
+
outmess(' ReST Documentation is saved to file "%s/%smodule.rest"\n' %
|
1375 |
+
(options['buildpath'], vrd['modulename']))
|
1376 |
+
if options['dolatexdoc']:
|
1377 |
+
fn = os.path.join(
|
1378 |
+
options['buildpath'], vrd['modulename'] + 'module.tex')
|
1379 |
+
ret['ltx'] = fn
|
1380 |
+
with open(fn, 'w') as f:
|
1381 |
+
f.write(
|
1382 |
+
'%% This file is auto-generated with f2py (version:%s)\n' % (f2py_version))
|
1383 |
+
if 'shortlatex' not in options:
|
1384 |
+
f.write(
|
1385 |
+
'\\documentclass{article}\n\\usepackage{a4wide}\n\\begin{document}\n\\tableofcontents\n\n')
|
1386 |
+
f.write('\n'.join(ar['latexdoc']))
|
1387 |
+
if 'shortlatex' not in options:
|
1388 |
+
f.write('\\end{document}')
|
1389 |
+
outmess(' Documentation is saved to file "%s/%smodule.tex"\n' %
|
1390 |
+
(options['buildpath'], vrd['modulename']))
|
1391 |
+
if funcwrappers:
|
1392 |
+
wn = os.path.join(options['buildpath'], vrd['f2py_wrapper_output'])
|
1393 |
+
ret['fsrc'] = wn
|
1394 |
+
with open(wn, 'w') as f:
|
1395 |
+
f.write('C -*- fortran -*-\n')
|
1396 |
+
f.write(
|
1397 |
+
'C This file is autogenerated with f2py (version:%s)\n' % (f2py_version))
|
1398 |
+
f.write(
|
1399 |
+
'C It contains Fortran 77 wrappers to fortran functions.\n')
|
1400 |
+
lines = []
|
1401 |
+
for l in ('\n\n'.join(funcwrappers) + '\n').split('\n'):
|
1402 |
+
if 0 <= l.find('!') < 66:
|
1403 |
+
# don't split comment lines
|
1404 |
+
lines.append(l + '\n')
|
1405 |
+
elif l and l[0] == ' ':
|
1406 |
+
while len(l) >= 66:
|
1407 |
+
lines.append(l[:66] + '\n &')
|
1408 |
+
l = l[66:]
|
1409 |
+
lines.append(l + '\n')
|
1410 |
+
else:
|
1411 |
+
lines.append(l + '\n')
|
1412 |
+
lines = ''.join(lines).replace('\n &\n', '\n')
|
1413 |
+
f.write(lines)
|
1414 |
+
outmess(' Fortran 77 wrappers are saved to "%s"\n' % (wn))
|
1415 |
+
if funcwrappers2:
|
1416 |
+
wn = os.path.join(
|
1417 |
+
options['buildpath'], '%s-f2pywrappers2.f90' % (vrd['modulename']))
|
1418 |
+
ret['fsrc'] = wn
|
1419 |
+
with open(wn, 'w') as f:
|
1420 |
+
f.write('! -*- f90 -*-\n')
|
1421 |
+
f.write(
|
1422 |
+
'! This file is autogenerated with f2py (version:%s)\n' % (f2py_version))
|
1423 |
+
f.write(
|
1424 |
+
'! It contains Fortran 90 wrappers to fortran functions.\n')
|
1425 |
+
lines = []
|
1426 |
+
for l in ('\n\n'.join(funcwrappers2) + '\n').split('\n'):
|
1427 |
+
if 0 <= l.find('!') < 72:
|
1428 |
+
# don't split comment lines
|
1429 |
+
lines.append(l + '\n')
|
1430 |
+
elif len(l) > 72 and l[0] == ' ':
|
1431 |
+
lines.append(l[:72] + '&\n &')
|
1432 |
+
l = l[72:]
|
1433 |
+
while len(l) > 66:
|
1434 |
+
lines.append(l[:66] + '&\n &')
|
1435 |
+
l = l[66:]
|
1436 |
+
lines.append(l + '\n')
|
1437 |
+
else:
|
1438 |
+
lines.append(l + '\n')
|
1439 |
+
lines = ''.join(lines).replace('\n &\n', '\n')
|
1440 |
+
f.write(lines)
|
1441 |
+
outmess(' Fortran 90 wrappers are saved to "%s"\n' % (wn))
|
1442 |
+
return ret
|
1443 |
+
|
1444 |
+
################## Build C/API function #############
|
1445 |
+
|
1446 |
+
stnd = {1: 'st', 2: 'nd', 3: 'rd', 4: 'th', 5: 'th',
|
1447 |
+
6: 'th', 7: 'th', 8: 'th', 9: 'th', 0: 'th'}
|
1448 |
+
|
1449 |
+
|
1450 |
+
def buildapi(rout):
|
1451 |
+
rout, wrap = func2subr.assubr(rout)
|
1452 |
+
args, depargs = getargs2(rout)
|
1453 |
+
capi_maps.depargs = depargs
|
1454 |
+
var = rout['vars']
|
1455 |
+
|
1456 |
+
if ismoduleroutine(rout):
|
1457 |
+
outmess(' Constructing wrapper function "%s.%s"...\n' %
|
1458 |
+
(rout['modulename'], rout['name']))
|
1459 |
+
else:
|
1460 |
+
outmess(' Constructing wrapper function "%s"...\n' % (rout['name']))
|
1461 |
+
# Routine
|
1462 |
+
vrd = capi_maps.routsign2map(rout)
|
1463 |
+
rd = dictappend({}, vrd)
|
1464 |
+
for r in rout_rules:
|
1465 |
+
if ('_check' in r and r['_check'](rout)) or ('_check' not in r):
|
1466 |
+
ar = applyrules(r, vrd, rout)
|
1467 |
+
rd = dictappend(rd, ar)
|
1468 |
+
|
1469 |
+
# Args
|
1470 |
+
nth, nthk = 0, 0
|
1471 |
+
savevrd = {}
|
1472 |
+
for a in args:
|
1473 |
+
vrd = capi_maps.sign2map(a, var[a])
|
1474 |
+
if isintent_aux(var[a]):
|
1475 |
+
_rules = aux_rules
|
1476 |
+
else:
|
1477 |
+
_rules = arg_rules
|
1478 |
+
if not isintent_hide(var[a]):
|
1479 |
+
if not isoptional(var[a]):
|
1480 |
+
nth = nth + 1
|
1481 |
+
vrd['nth'] = repr(nth) + stnd[nth % 10] + ' argument'
|
1482 |
+
else:
|
1483 |
+
nthk = nthk + 1
|
1484 |
+
vrd['nth'] = repr(nthk) + stnd[nthk % 10] + ' keyword'
|
1485 |
+
else:
|
1486 |
+
vrd['nth'] = 'hidden'
|
1487 |
+
savevrd[a] = vrd
|
1488 |
+
for r in _rules:
|
1489 |
+
if '_depend' in r:
|
1490 |
+
continue
|
1491 |
+
if ('_check' in r and r['_check'](var[a])) or ('_check' not in r):
|
1492 |
+
ar = applyrules(r, vrd, var[a])
|
1493 |
+
rd = dictappend(rd, ar)
|
1494 |
+
if '_break' in r:
|
1495 |
+
break
|
1496 |
+
for a in depargs:
|
1497 |
+
if isintent_aux(var[a]):
|
1498 |
+
_rules = aux_rules
|
1499 |
+
else:
|
1500 |
+
_rules = arg_rules
|
1501 |
+
vrd = savevrd[a]
|
1502 |
+
for r in _rules:
|
1503 |
+
if '_depend' not in r:
|
1504 |
+
continue
|
1505 |
+
if ('_check' in r and r['_check'](var[a])) or ('_check' not in r):
|
1506 |
+
ar = applyrules(r, vrd, var[a])
|
1507 |
+
rd = dictappend(rd, ar)
|
1508 |
+
if '_break' in r:
|
1509 |
+
break
|
1510 |
+
if 'check' in var[a]:
|
1511 |
+
for c in var[a]['check']:
|
1512 |
+
vrd['check'] = c
|
1513 |
+
ar = applyrules(check_rules, vrd, var[a])
|
1514 |
+
rd = dictappend(rd, ar)
|
1515 |
+
if isinstance(rd['cleanupfrompyobj'], list):
|
1516 |
+
rd['cleanupfrompyobj'].reverse()
|
1517 |
+
if isinstance(rd['closepyobjfrom'], list):
|
1518 |
+
rd['closepyobjfrom'].reverse()
|
1519 |
+
rd['docsignature'] = stripcomma(replace('#docsign##docsignopt##docsignxa#',
|
1520 |
+
{'docsign': rd['docsign'],
|
1521 |
+
'docsignopt': rd['docsignopt'],
|
1522 |
+
'docsignxa': rd['docsignxa']}))
|
1523 |
+
optargs = stripcomma(replace('#docsignopt##docsignxa#',
|
1524 |
+
{'docsignxa': rd['docsignxashort'],
|
1525 |
+
'docsignopt': rd['docsignoptshort']}
|
1526 |
+
))
|
1527 |
+
if optargs == '':
|
1528 |
+
rd['docsignatureshort'] = stripcomma(
|
1529 |
+
replace('#docsign#', {'docsign': rd['docsign']}))
|
1530 |
+
else:
|
1531 |
+
rd['docsignatureshort'] = replace('#docsign#[#docsignopt#]',
|
1532 |
+
{'docsign': rd['docsign'],
|
1533 |
+
'docsignopt': optargs,
|
1534 |
+
})
|
1535 |
+
rd['latexdocsignatureshort'] = rd['docsignatureshort'].replace('_', '\\_')
|
1536 |
+
rd['latexdocsignatureshort'] = rd[
|
1537 |
+
'latexdocsignatureshort'].replace(',', ', ')
|
1538 |
+
cfs = stripcomma(replace('#callfortran##callfortranappend#', {
|
1539 |
+
'callfortran': rd['callfortran'], 'callfortranappend': rd['callfortranappend']}))
|
1540 |
+
if len(rd['callfortranappend']) > 1:
|
1541 |
+
rd['callcompaqfortran'] = stripcomma(replace('#callfortran# 0,#callfortranappend#', {
|
1542 |
+
'callfortran': rd['callfortran'], 'callfortranappend': rd['callfortranappend']}))
|
1543 |
+
else:
|
1544 |
+
rd['callcompaqfortran'] = cfs
|
1545 |
+
rd['callfortran'] = cfs
|
1546 |
+
if isinstance(rd['docreturn'], list):
|
1547 |
+
rd['docreturn'] = stripcomma(
|
1548 |
+
replace('#docreturn#', {'docreturn': rd['docreturn']})) + ' = '
|
1549 |
+
rd['docstrsigns'] = []
|
1550 |
+
rd['latexdocstrsigns'] = []
|
1551 |
+
for k in ['docstrreq', 'docstropt', 'docstrout', 'docstrcbs']:
|
1552 |
+
if k in rd and isinstance(rd[k], list):
|
1553 |
+
rd['docstrsigns'] = rd['docstrsigns'] + rd[k]
|
1554 |
+
k = 'latex' + k
|
1555 |
+
if k in rd and isinstance(rd[k], list):
|
1556 |
+
rd['latexdocstrsigns'] = rd['latexdocstrsigns'] + rd[k][0:1] +\
|
1557 |
+
['\\begin{description}'] + rd[k][1:] +\
|
1558 |
+
['\\end{description}']
|
1559 |
+
|
1560 |
+
ar = applyrules(routine_rules, rd)
|
1561 |
+
if ismoduleroutine(rout):
|
1562 |
+
outmess(' %s\n' % (ar['docshort']))
|
1563 |
+
else:
|
1564 |
+
outmess(' %s\n' % (ar['docshort']))
|
1565 |
+
return ar, wrap
|
1566 |
+
|
1567 |
+
|
1568 |
+
#################### EOF rules.py #######################
|
.venv/lib/python3.11/site-packages/numpy/f2py/setup.py
ADDED
@@ -0,0 +1,74 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#!/usr/bin/env python3
|
2 |
+
"""
|
3 |
+
setup.py for installing F2PY
|
4 |
+
|
5 |
+
Usage:
|
6 |
+
pip install .
|
7 |
+
|
8 |
+
Copyright 2001-2005 Pearu Peterson all rights reserved,
|
9 |
+
Pearu Peterson <[email protected]>
|
10 |
+
Permission to use, modify, and distribute this software is given under the
|
11 |
+
terms of the NumPy License.
|
12 |
+
|
13 |
+
NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
|
14 |
+
$Revision: 1.32 $
|
15 |
+
$Date: 2005/01/30 17:22:14 $
|
16 |
+
Pearu Peterson
|
17 |
+
|
18 |
+
"""
|
19 |
+
from numpy.distutils.core import setup
|
20 |
+
from numpy.distutils.misc_util import Configuration
|
21 |
+
|
22 |
+
|
23 |
+
from __version__ import version
|
24 |
+
|
25 |
+
|
26 |
+
def configuration(parent_package='', top_path=None):
|
27 |
+
config = Configuration('f2py', parent_package, top_path)
|
28 |
+
config.add_subpackage('tests')
|
29 |
+
config.add_subpackage('_backends')
|
30 |
+
config.add_data_dir('tests/src')
|
31 |
+
config.add_data_files(
|
32 |
+
'src/fortranobject.c',
|
33 |
+
'src/fortranobject.h',
|
34 |
+
'_backends/meson.build.template',
|
35 |
+
)
|
36 |
+
config.add_data_files('*.pyi')
|
37 |
+
return config
|
38 |
+
|
39 |
+
|
40 |
+
if __name__ == "__main__":
|
41 |
+
|
42 |
+
config = configuration(top_path='')
|
43 |
+
config = config.todict()
|
44 |
+
|
45 |
+
config['classifiers'] = [
|
46 |
+
'Development Status :: 5 - Production/Stable',
|
47 |
+
'Intended Audience :: Developers',
|
48 |
+
'Intended Audience :: Science/Research',
|
49 |
+
'License :: OSI Approved :: NumPy License',
|
50 |
+
'Natural Language :: English',
|
51 |
+
'Operating System :: OS Independent',
|
52 |
+
'Programming Language :: C',
|
53 |
+
'Programming Language :: Fortran',
|
54 |
+
'Programming Language :: Python',
|
55 |
+
'Topic :: Scientific/Engineering',
|
56 |
+
'Topic :: Software Development :: Code Generators',
|
57 |
+
]
|
58 |
+
setup(version=version,
|
59 |
+
description="F2PY - Fortran to Python Interface Generator",
|
60 |
+
author="Pearu Peterson",
|
61 |
+
author_email="[email protected]",
|
62 |
+
maintainer="Pearu Peterson",
|
63 |
+
maintainer_email="[email protected]",
|
64 |
+
license="BSD",
|
65 |
+
platforms="Unix, Windows (mingw|cygwin), Mac OSX",
|
66 |
+
long_description="""\
|
67 |
+
The Fortran to Python Interface Generator, or F2PY for short, is a
|
68 |
+
command line tool (f2py) for generating Python C/API modules for
|
69 |
+
wrapping Fortran 77/90/95 subroutines, accessing common blocks from
|
70 |
+
Python, and calling Python functions from Fortran (call-backs).
|
71 |
+
Interfacing subroutines/data from Fortran 90/95 modules is supported.""",
|
72 |
+
url="https://numpy.org/doc/stable/f2py/",
|
73 |
+
keywords=['Fortran', 'f2py'],
|
74 |
+
**config)
|
.venv/lib/python3.11/site-packages/numpy/f2py/tests/__init__.py
ADDED
File without changes
|
.venv/lib/python3.11/site-packages/numpy/f2py/tests/__pycache__/test_abstract_interface.cpython-311.pyc
ADDED
Binary file (2.15 kB). View file
|
|
.venv/lib/python3.11/site-packages/numpy/f2py/tests/__pycache__/test_common.cpython-311.pyc
ADDED
Binary file (2.49 kB). View file
|
|
.venv/lib/python3.11/site-packages/numpy/f2py/tests/__pycache__/test_data.cpython-311.pyc
ADDED
Binary file (6.6 kB). View file
|
|
.venv/lib/python3.11/site-packages/numpy/f2py/tests/__pycache__/test_f2cmap.cpython-311.pyc
ADDED
Binary file (1.1 kB). View file
|
|
.venv/lib/python3.11/site-packages/numpy/f2py/tests/__pycache__/test_regression.cpython-311.pyc
ADDED
Binary file (4.99 kB). View file
|
|
.venv/lib/python3.11/site-packages/numpy/f2py/tests/__pycache__/test_semicolon_split.cpython-311.pyc
ADDED
Binary file (3.04 kB). View file
|
|
.venv/lib/python3.11/site-packages/numpy/f2py/tests/test_abstract_interface.py
ADDED
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from pathlib import Path
|
2 |
+
import pytest
|
3 |
+
import textwrap
|
4 |
+
from . import util
|
5 |
+
from numpy.f2py import crackfortran
|
6 |
+
from numpy.testing import IS_WASM
|
7 |
+
|
8 |
+
|
9 |
+
@pytest.mark.skipif(IS_WASM, reason="Cannot start subprocess")
|
10 |
+
class TestAbstractInterface(util.F2PyTest):
|
11 |
+
sources = [util.getpath("tests", "src", "abstract_interface", "foo.f90")]
|
12 |
+
|
13 |
+
skip = ["add1", "add2"]
|
14 |
+
|
15 |
+
def test_abstract_interface(self):
|
16 |
+
assert self.module.ops_module.foo(3, 5) == (8, 13)
|
17 |
+
|
18 |
+
def test_parse_abstract_interface(self):
|
19 |
+
# Test gh18403
|
20 |
+
fpath = util.getpath("tests", "src", "abstract_interface",
|
21 |
+
"gh18403_mod.f90")
|
22 |
+
mod = crackfortran.crackfortran([str(fpath)])
|
23 |
+
assert len(mod) == 1
|
24 |
+
assert len(mod[0]["body"]) == 1
|
25 |
+
assert mod[0]["body"][0]["block"] == "abstract interface"
|
.venv/lib/python3.11/site-packages/numpy/f2py/tests/test_array_from_pyobj.py
ADDED
@@ -0,0 +1,686 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
import sys
|
3 |
+
import copy
|
4 |
+
import platform
|
5 |
+
import pytest
|
6 |
+
|
7 |
+
import numpy as np
|
8 |
+
|
9 |
+
from numpy.testing import assert_, assert_equal
|
10 |
+
from numpy.core.multiarray import typeinfo as _typeinfo
|
11 |
+
from . import util
|
12 |
+
|
13 |
+
wrap = None
|
14 |
+
|
15 |
+
# Extend core typeinfo with CHARACTER to test dtype('c')
|
16 |
+
_ti = _typeinfo['STRING']
|
17 |
+
typeinfo = dict(
|
18 |
+
CHARACTER=type(_ti)(('c', _ti.num, 8, _ti.alignment, _ti.type)),
|
19 |
+
**_typeinfo)
|
20 |
+
|
21 |
+
|
22 |
+
def setup_module():
|
23 |
+
"""
|
24 |
+
Build the required testing extension module
|
25 |
+
|
26 |
+
"""
|
27 |
+
global wrap
|
28 |
+
|
29 |
+
# Check compiler availability first
|
30 |
+
if not util.has_c_compiler():
|
31 |
+
pytest.skip("No C compiler available")
|
32 |
+
|
33 |
+
if wrap is None:
|
34 |
+
config_code = """
|
35 |
+
config.add_extension('test_array_from_pyobj_ext',
|
36 |
+
sources=['wrapmodule.c', 'fortranobject.c'],
|
37 |
+
define_macros=[])
|
38 |
+
"""
|
39 |
+
d = os.path.dirname(__file__)
|
40 |
+
src = [
|
41 |
+
util.getpath("tests", "src", "array_from_pyobj", "wrapmodule.c"),
|
42 |
+
util.getpath("src", "fortranobject.c"),
|
43 |
+
util.getpath("src", "fortranobject.h"),
|
44 |
+
]
|
45 |
+
wrap = util.build_module_distutils(src, config_code,
|
46 |
+
"test_array_from_pyobj_ext")
|
47 |
+
|
48 |
+
|
49 |
+
def flags_info(arr):
|
50 |
+
flags = wrap.array_attrs(arr)[6]
|
51 |
+
return flags2names(flags)
|
52 |
+
|
53 |
+
|
54 |
+
def flags2names(flags):
|
55 |
+
info = []
|
56 |
+
for flagname in [
|
57 |
+
"CONTIGUOUS",
|
58 |
+
"FORTRAN",
|
59 |
+
"OWNDATA",
|
60 |
+
"ENSURECOPY",
|
61 |
+
"ENSUREARRAY",
|
62 |
+
"ALIGNED",
|
63 |
+
"NOTSWAPPED",
|
64 |
+
"WRITEABLE",
|
65 |
+
"WRITEBACKIFCOPY",
|
66 |
+
"UPDATEIFCOPY",
|
67 |
+
"BEHAVED",
|
68 |
+
"BEHAVED_RO",
|
69 |
+
"CARRAY",
|
70 |
+
"FARRAY",
|
71 |
+
]:
|
72 |
+
if abs(flags) & getattr(wrap, flagname, 0):
|
73 |
+
info.append(flagname)
|
74 |
+
return info
|
75 |
+
|
76 |
+
|
77 |
+
class Intent:
|
78 |
+
def __init__(self, intent_list=[]):
|
79 |
+
self.intent_list = intent_list[:]
|
80 |
+
flags = 0
|
81 |
+
for i in intent_list:
|
82 |
+
if i == "optional":
|
83 |
+
flags |= wrap.F2PY_OPTIONAL
|
84 |
+
else:
|
85 |
+
flags |= getattr(wrap, "F2PY_INTENT_" + i.upper())
|
86 |
+
self.flags = flags
|
87 |
+
|
88 |
+
def __getattr__(self, name):
|
89 |
+
name = name.lower()
|
90 |
+
if name == "in_":
|
91 |
+
name = "in"
|
92 |
+
return self.__class__(self.intent_list + [name])
|
93 |
+
|
94 |
+
def __str__(self):
|
95 |
+
return "intent(%s)" % (",".join(self.intent_list))
|
96 |
+
|
97 |
+
def __repr__(self):
|
98 |
+
return "Intent(%r)" % (self.intent_list)
|
99 |
+
|
100 |
+
def is_intent(self, *names):
|
101 |
+
for name in names:
|
102 |
+
if name not in self.intent_list:
|
103 |
+
return False
|
104 |
+
return True
|
105 |
+
|
106 |
+
def is_intent_exact(self, *names):
|
107 |
+
return len(self.intent_list) == len(names) and self.is_intent(*names)
|
108 |
+
|
109 |
+
|
110 |
+
intent = Intent()
|
111 |
+
|
112 |
+
_type_names = [
|
113 |
+
"BOOL",
|
114 |
+
"BYTE",
|
115 |
+
"UBYTE",
|
116 |
+
"SHORT",
|
117 |
+
"USHORT",
|
118 |
+
"INT",
|
119 |
+
"UINT",
|
120 |
+
"LONG",
|
121 |
+
"ULONG",
|
122 |
+
"LONGLONG",
|
123 |
+
"ULONGLONG",
|
124 |
+
"FLOAT",
|
125 |
+
"DOUBLE",
|
126 |
+
"CFLOAT",
|
127 |
+
"STRING1",
|
128 |
+
"STRING5",
|
129 |
+
"CHARACTER",
|
130 |
+
]
|
131 |
+
|
132 |
+
_cast_dict = {"BOOL": ["BOOL"]}
|
133 |
+
_cast_dict["BYTE"] = _cast_dict["BOOL"] + ["BYTE"]
|
134 |
+
_cast_dict["UBYTE"] = _cast_dict["BOOL"] + ["UBYTE"]
|
135 |
+
_cast_dict["BYTE"] = ["BYTE"]
|
136 |
+
_cast_dict["UBYTE"] = ["UBYTE"]
|
137 |
+
_cast_dict["SHORT"] = _cast_dict["BYTE"] + ["UBYTE", "SHORT"]
|
138 |
+
_cast_dict["USHORT"] = _cast_dict["UBYTE"] + ["BYTE", "USHORT"]
|
139 |
+
_cast_dict["INT"] = _cast_dict["SHORT"] + ["USHORT", "INT"]
|
140 |
+
_cast_dict["UINT"] = _cast_dict["USHORT"] + ["SHORT", "UINT"]
|
141 |
+
|
142 |
+
_cast_dict["LONG"] = _cast_dict["INT"] + ["LONG"]
|
143 |
+
_cast_dict["ULONG"] = _cast_dict["UINT"] + ["ULONG"]
|
144 |
+
|
145 |
+
_cast_dict["LONGLONG"] = _cast_dict["LONG"] + ["LONGLONG"]
|
146 |
+
_cast_dict["ULONGLONG"] = _cast_dict["ULONG"] + ["ULONGLONG"]
|
147 |
+
|
148 |
+
_cast_dict["FLOAT"] = _cast_dict["SHORT"] + ["USHORT", "FLOAT"]
|
149 |
+
_cast_dict["DOUBLE"] = _cast_dict["INT"] + ["UINT", "FLOAT", "DOUBLE"]
|
150 |
+
|
151 |
+
_cast_dict["CFLOAT"] = _cast_dict["FLOAT"] + ["CFLOAT"]
|
152 |
+
|
153 |
+
_cast_dict['STRING1'] = ['STRING1']
|
154 |
+
_cast_dict['STRING5'] = ['STRING5']
|
155 |
+
_cast_dict['CHARACTER'] = ['CHARACTER']
|
156 |
+
|
157 |
+
# 32 bit system malloc typically does not provide the alignment required by
|
158 |
+
# 16 byte long double types this means the inout intent cannot be satisfied
|
159 |
+
# and several tests fail as the alignment flag can be randomly true or fals
|
160 |
+
# when numpy gains an aligned allocator the tests could be enabled again
|
161 |
+
#
|
162 |
+
# Furthermore, on macOS ARM64, LONGDOUBLE is an alias for DOUBLE.
|
163 |
+
if ((np.intp().dtype.itemsize != 4 or np.clongdouble().dtype.alignment <= 8)
|
164 |
+
and sys.platform != "win32"
|
165 |
+
and (platform.system(), platform.processor()) != ("Darwin", "arm")):
|
166 |
+
_type_names.extend(["LONGDOUBLE", "CDOUBLE", "CLONGDOUBLE"])
|
167 |
+
_cast_dict["LONGDOUBLE"] = _cast_dict["LONG"] + [
|
168 |
+
"ULONG",
|
169 |
+
"FLOAT",
|
170 |
+
"DOUBLE",
|
171 |
+
"LONGDOUBLE",
|
172 |
+
]
|
173 |
+
_cast_dict["CLONGDOUBLE"] = _cast_dict["LONGDOUBLE"] + [
|
174 |
+
"CFLOAT",
|
175 |
+
"CDOUBLE",
|
176 |
+
"CLONGDOUBLE",
|
177 |
+
]
|
178 |
+
_cast_dict["CDOUBLE"] = _cast_dict["DOUBLE"] + ["CFLOAT", "CDOUBLE"]
|
179 |
+
|
180 |
+
|
181 |
+
class Type:
|
182 |
+
_type_cache = {}
|
183 |
+
|
184 |
+
def __new__(cls, name):
|
185 |
+
if isinstance(name, np.dtype):
|
186 |
+
dtype0 = name
|
187 |
+
name = None
|
188 |
+
for n, i in typeinfo.items():
|
189 |
+
if not isinstance(i, type) and dtype0.type is i.type:
|
190 |
+
name = n
|
191 |
+
break
|
192 |
+
obj = cls._type_cache.get(name.upper(), None)
|
193 |
+
if obj is not None:
|
194 |
+
return obj
|
195 |
+
obj = object.__new__(cls)
|
196 |
+
obj._init(name)
|
197 |
+
cls._type_cache[name.upper()] = obj
|
198 |
+
return obj
|
199 |
+
|
200 |
+
def _init(self, name):
|
201 |
+
self.NAME = name.upper()
|
202 |
+
|
203 |
+
if self.NAME == 'CHARACTER':
|
204 |
+
info = typeinfo[self.NAME]
|
205 |
+
self.type_num = getattr(wrap, 'NPY_STRING')
|
206 |
+
self.elsize = 1
|
207 |
+
self.dtype = np.dtype('c')
|
208 |
+
elif self.NAME.startswith('STRING'):
|
209 |
+
info = typeinfo[self.NAME[:6]]
|
210 |
+
self.type_num = getattr(wrap, 'NPY_STRING')
|
211 |
+
self.elsize = int(self.NAME[6:] or 0)
|
212 |
+
self.dtype = np.dtype(f'S{self.elsize}')
|
213 |
+
else:
|
214 |
+
info = typeinfo[self.NAME]
|
215 |
+
self.type_num = getattr(wrap, 'NPY_' + self.NAME)
|
216 |
+
self.elsize = info.bits // 8
|
217 |
+
self.dtype = np.dtype(info.type)
|
218 |
+
|
219 |
+
assert self.type_num == info.num
|
220 |
+
self.type = info.type
|
221 |
+
self.dtypechar = info.char
|
222 |
+
|
223 |
+
def __repr__(self):
|
224 |
+
return (f"Type({self.NAME})|type_num={self.type_num},"
|
225 |
+
f" dtype={self.dtype},"
|
226 |
+
f" type={self.type}, elsize={self.elsize},"
|
227 |
+
f" dtypechar={self.dtypechar}")
|
228 |
+
|
229 |
+
def cast_types(self):
|
230 |
+
return [self.__class__(_m) for _m in _cast_dict[self.NAME]]
|
231 |
+
|
232 |
+
def all_types(self):
|
233 |
+
return [self.__class__(_m) for _m in _type_names]
|
234 |
+
|
235 |
+
def smaller_types(self):
|
236 |
+
bits = typeinfo[self.NAME].alignment
|
237 |
+
types = []
|
238 |
+
for name in _type_names:
|
239 |
+
if typeinfo[name].alignment < bits:
|
240 |
+
types.append(Type(name))
|
241 |
+
return types
|
242 |
+
|
243 |
+
def equal_types(self):
|
244 |
+
bits = typeinfo[self.NAME].alignment
|
245 |
+
types = []
|
246 |
+
for name in _type_names:
|
247 |
+
if name == self.NAME:
|
248 |
+
continue
|
249 |
+
if typeinfo[name].alignment == bits:
|
250 |
+
types.append(Type(name))
|
251 |
+
return types
|
252 |
+
|
253 |
+
def larger_types(self):
|
254 |
+
bits = typeinfo[self.NAME].alignment
|
255 |
+
types = []
|
256 |
+
for name in _type_names:
|
257 |
+
if typeinfo[name].alignment > bits:
|
258 |
+
types.append(Type(name))
|
259 |
+
return types
|
260 |
+
|
261 |
+
|
262 |
+
class Array:
|
263 |
+
|
264 |
+
def __repr__(self):
|
265 |
+
return (f'Array({self.type}, {self.dims}, {self.intent},'
|
266 |
+
f' {self.obj})|arr={self.arr}')
|
267 |
+
|
268 |
+
def __init__(self, typ, dims, intent, obj):
|
269 |
+
self.type = typ
|
270 |
+
self.dims = dims
|
271 |
+
self.intent = intent
|
272 |
+
self.obj_copy = copy.deepcopy(obj)
|
273 |
+
self.obj = obj
|
274 |
+
|
275 |
+
# arr.dtypechar may be different from typ.dtypechar
|
276 |
+
self.arr = wrap.call(typ.type_num,
|
277 |
+
typ.elsize,
|
278 |
+
dims, intent.flags, obj)
|
279 |
+
|
280 |
+
assert isinstance(self.arr, np.ndarray)
|
281 |
+
|
282 |
+
self.arr_attr = wrap.array_attrs(self.arr)
|
283 |
+
|
284 |
+
if len(dims) > 1:
|
285 |
+
if self.intent.is_intent("c"):
|
286 |
+
assert (intent.flags & wrap.F2PY_INTENT_C)
|
287 |
+
assert not self.arr.flags["FORTRAN"]
|
288 |
+
assert self.arr.flags["CONTIGUOUS"]
|
289 |
+
assert (not self.arr_attr[6] & wrap.FORTRAN)
|
290 |
+
else:
|
291 |
+
assert (not intent.flags & wrap.F2PY_INTENT_C)
|
292 |
+
assert self.arr.flags["FORTRAN"]
|
293 |
+
assert not self.arr.flags["CONTIGUOUS"]
|
294 |
+
assert (self.arr_attr[6] & wrap.FORTRAN)
|
295 |
+
|
296 |
+
if obj is None:
|
297 |
+
self.pyarr = None
|
298 |
+
self.pyarr_attr = None
|
299 |
+
return
|
300 |
+
|
301 |
+
if intent.is_intent("cache"):
|
302 |
+
assert isinstance(obj, np.ndarray), repr(type(obj))
|
303 |
+
self.pyarr = np.array(obj).reshape(*dims).copy()
|
304 |
+
else:
|
305 |
+
self.pyarr = np.array(
|
306 |
+
np.array(obj, dtype=typ.dtypechar).reshape(*dims),
|
307 |
+
order=self.intent.is_intent("c") and "C" or "F",
|
308 |
+
)
|
309 |
+
assert self.pyarr.dtype == typ
|
310 |
+
self.pyarr.setflags(write=self.arr.flags["WRITEABLE"])
|
311 |
+
assert self.pyarr.flags["OWNDATA"], (obj, intent)
|
312 |
+
self.pyarr_attr = wrap.array_attrs(self.pyarr)
|
313 |
+
|
314 |
+
if len(dims) > 1:
|
315 |
+
if self.intent.is_intent("c"):
|
316 |
+
assert not self.pyarr.flags["FORTRAN"]
|
317 |
+
assert self.pyarr.flags["CONTIGUOUS"]
|
318 |
+
assert (not self.pyarr_attr[6] & wrap.FORTRAN)
|
319 |
+
else:
|
320 |
+
assert self.pyarr.flags["FORTRAN"]
|
321 |
+
assert not self.pyarr.flags["CONTIGUOUS"]
|
322 |
+
assert (self.pyarr_attr[6] & wrap.FORTRAN)
|
323 |
+
|
324 |
+
assert self.arr_attr[1] == self.pyarr_attr[1] # nd
|
325 |
+
assert self.arr_attr[2] == self.pyarr_attr[2] # dimensions
|
326 |
+
if self.arr_attr[1] <= 1:
|
327 |
+
assert self.arr_attr[3] == self.pyarr_attr[3], repr((
|
328 |
+
self.arr_attr[3],
|
329 |
+
self.pyarr_attr[3],
|
330 |
+
self.arr.tobytes(),
|
331 |
+
self.pyarr.tobytes(),
|
332 |
+
)) # strides
|
333 |
+
assert self.arr_attr[5][-2:] == self.pyarr_attr[5][-2:], repr((
|
334 |
+
self.arr_attr[5], self.pyarr_attr[5]
|
335 |
+
)) # descr
|
336 |
+
assert self.arr_attr[6] == self.pyarr_attr[6], repr((
|
337 |
+
self.arr_attr[6],
|
338 |
+
self.pyarr_attr[6],
|
339 |
+
flags2names(0 * self.arr_attr[6] - self.pyarr_attr[6]),
|
340 |
+
flags2names(self.arr_attr[6]),
|
341 |
+
intent,
|
342 |
+
)) # flags
|
343 |
+
|
344 |
+
if intent.is_intent("cache"):
|
345 |
+
assert self.arr_attr[5][3] >= self.type.elsize
|
346 |
+
else:
|
347 |
+
assert self.arr_attr[5][3] == self.type.elsize
|
348 |
+
assert (self.arr_equal(self.pyarr, self.arr))
|
349 |
+
|
350 |
+
if isinstance(self.obj, np.ndarray):
|
351 |
+
if typ.elsize == Type(obj.dtype).elsize:
|
352 |
+
if not intent.is_intent("copy") and self.arr_attr[1] <= 1:
|
353 |
+
assert self.has_shared_memory()
|
354 |
+
|
355 |
+
def arr_equal(self, arr1, arr2):
|
356 |
+
if arr1.shape != arr2.shape:
|
357 |
+
return False
|
358 |
+
return (arr1 == arr2).all()
|
359 |
+
|
360 |
+
def __str__(self):
|
361 |
+
return str(self.arr)
|
362 |
+
|
363 |
+
def has_shared_memory(self):
|
364 |
+
"""Check that created array shares data with input array."""
|
365 |
+
if self.obj is self.arr:
|
366 |
+
return True
|
367 |
+
if not isinstance(self.obj, np.ndarray):
|
368 |
+
return False
|
369 |
+
obj_attr = wrap.array_attrs(self.obj)
|
370 |
+
return obj_attr[0] == self.arr_attr[0]
|
371 |
+
|
372 |
+
|
373 |
+
class TestIntent:
|
374 |
+
def test_in_out(self):
|
375 |
+
assert str(intent.in_.out) == "intent(in,out)"
|
376 |
+
assert intent.in_.c.is_intent("c")
|
377 |
+
assert not intent.in_.c.is_intent_exact("c")
|
378 |
+
assert intent.in_.c.is_intent_exact("c", "in")
|
379 |
+
assert intent.in_.c.is_intent_exact("in", "c")
|
380 |
+
assert not intent.in_.is_intent("c")
|
381 |
+
|
382 |
+
|
383 |
+
class TestSharedMemory:
|
384 |
+
|
385 |
+
@pytest.fixture(autouse=True, scope="class", params=_type_names)
|
386 |
+
def setup_type(self, request):
|
387 |
+
request.cls.type = Type(request.param)
|
388 |
+
request.cls.array = lambda self, dims, intent, obj: Array(
|
389 |
+
Type(request.param), dims, intent, obj)
|
390 |
+
|
391 |
+
@property
|
392 |
+
def num2seq(self):
|
393 |
+
if self.type.NAME.startswith('STRING'):
|
394 |
+
elsize = self.type.elsize
|
395 |
+
return ['1' * elsize, '2' * elsize]
|
396 |
+
return [1, 2]
|
397 |
+
|
398 |
+
@property
|
399 |
+
def num23seq(self):
|
400 |
+
if self.type.NAME.startswith('STRING'):
|
401 |
+
elsize = self.type.elsize
|
402 |
+
return [['1' * elsize, '2' * elsize, '3' * elsize],
|
403 |
+
['4' * elsize, '5' * elsize, '6' * elsize]]
|
404 |
+
return [[1, 2, 3], [4, 5, 6]]
|
405 |
+
|
406 |
+
def test_in_from_2seq(self):
|
407 |
+
a = self.array([2], intent.in_, self.num2seq)
|
408 |
+
assert not a.has_shared_memory()
|
409 |
+
|
410 |
+
def test_in_from_2casttype(self):
|
411 |
+
for t in self.type.cast_types():
|
412 |
+
obj = np.array(self.num2seq, dtype=t.dtype)
|
413 |
+
a = self.array([len(self.num2seq)], intent.in_, obj)
|
414 |
+
if t.elsize == self.type.elsize:
|
415 |
+
assert a.has_shared_memory(), repr((self.type.dtype, t.dtype))
|
416 |
+
else:
|
417 |
+
assert not a.has_shared_memory()
|
418 |
+
|
419 |
+
@pytest.mark.parametrize("write", ["w", "ro"])
|
420 |
+
@pytest.mark.parametrize("order", ["C", "F"])
|
421 |
+
@pytest.mark.parametrize("inp", ["2seq", "23seq"])
|
422 |
+
def test_in_nocopy(self, write, order, inp):
|
423 |
+
"""Test if intent(in) array can be passed without copies"""
|
424 |
+
seq = getattr(self, "num" + inp)
|
425 |
+
obj = np.array(seq, dtype=self.type.dtype, order=order)
|
426 |
+
obj.setflags(write=(write == 'w'))
|
427 |
+
a = self.array(obj.shape,
|
428 |
+
((order == 'C' and intent.in_.c) or intent.in_), obj)
|
429 |
+
assert a.has_shared_memory()
|
430 |
+
|
431 |
+
def test_inout_2seq(self):
|
432 |
+
obj = np.array(self.num2seq, dtype=self.type.dtype)
|
433 |
+
a = self.array([len(self.num2seq)], intent.inout, obj)
|
434 |
+
assert a.has_shared_memory()
|
435 |
+
|
436 |
+
try:
|
437 |
+
a = self.array([2], intent.in_.inout, self.num2seq)
|
438 |
+
except TypeError as msg:
|
439 |
+
if not str(msg).startswith(
|
440 |
+
"failed to initialize intent(inout|inplace|cache) array"):
|
441 |
+
raise
|
442 |
+
else:
|
443 |
+
raise SystemError("intent(inout) should have failed on sequence")
|
444 |
+
|
445 |
+
def test_f_inout_23seq(self):
|
446 |
+
obj = np.array(self.num23seq, dtype=self.type.dtype, order="F")
|
447 |
+
shape = (len(self.num23seq), len(self.num23seq[0]))
|
448 |
+
a = self.array(shape, intent.in_.inout, obj)
|
449 |
+
assert a.has_shared_memory()
|
450 |
+
|
451 |
+
obj = np.array(self.num23seq, dtype=self.type.dtype, order="C")
|
452 |
+
shape = (len(self.num23seq), len(self.num23seq[0]))
|
453 |
+
try:
|
454 |
+
a = self.array(shape, intent.in_.inout, obj)
|
455 |
+
except ValueError as msg:
|
456 |
+
if not str(msg).startswith(
|
457 |
+
"failed to initialize intent(inout) array"):
|
458 |
+
raise
|
459 |
+
else:
|
460 |
+
raise SystemError(
|
461 |
+
"intent(inout) should have failed on improper array")
|
462 |
+
|
463 |
+
def test_c_inout_23seq(self):
|
464 |
+
obj = np.array(self.num23seq, dtype=self.type.dtype)
|
465 |
+
shape = (len(self.num23seq), len(self.num23seq[0]))
|
466 |
+
a = self.array(shape, intent.in_.c.inout, obj)
|
467 |
+
assert a.has_shared_memory()
|
468 |
+
|
469 |
+
def test_in_copy_from_2casttype(self):
|
470 |
+
for t in self.type.cast_types():
|
471 |
+
obj = np.array(self.num2seq, dtype=t.dtype)
|
472 |
+
a = self.array([len(self.num2seq)], intent.in_.copy, obj)
|
473 |
+
assert not a.has_shared_memory()
|
474 |
+
|
475 |
+
def test_c_in_from_23seq(self):
|
476 |
+
a = self.array(
|
477 |
+
[len(self.num23seq), len(self.num23seq[0])], intent.in_,
|
478 |
+
self.num23seq)
|
479 |
+
assert not a.has_shared_memory()
|
480 |
+
|
481 |
+
def test_in_from_23casttype(self):
|
482 |
+
for t in self.type.cast_types():
|
483 |
+
obj = np.array(self.num23seq, dtype=t.dtype)
|
484 |
+
a = self.array(
|
485 |
+
[len(self.num23seq), len(self.num23seq[0])], intent.in_, obj)
|
486 |
+
assert not a.has_shared_memory()
|
487 |
+
|
488 |
+
def test_f_in_from_23casttype(self):
|
489 |
+
for t in self.type.cast_types():
|
490 |
+
obj = np.array(self.num23seq, dtype=t.dtype, order="F")
|
491 |
+
a = self.array(
|
492 |
+
[len(self.num23seq), len(self.num23seq[0])], intent.in_, obj)
|
493 |
+
if t.elsize == self.type.elsize:
|
494 |
+
assert a.has_shared_memory()
|
495 |
+
else:
|
496 |
+
assert not a.has_shared_memory()
|
497 |
+
|
498 |
+
def test_c_in_from_23casttype(self):
|
499 |
+
for t in self.type.cast_types():
|
500 |
+
obj = np.array(self.num23seq, dtype=t.dtype)
|
501 |
+
a = self.array(
|
502 |
+
[len(self.num23seq), len(self.num23seq[0])], intent.in_.c, obj)
|
503 |
+
if t.elsize == self.type.elsize:
|
504 |
+
assert a.has_shared_memory()
|
505 |
+
else:
|
506 |
+
assert not a.has_shared_memory()
|
507 |
+
|
508 |
+
def test_f_copy_in_from_23casttype(self):
|
509 |
+
for t in self.type.cast_types():
|
510 |
+
obj = np.array(self.num23seq, dtype=t.dtype, order="F")
|
511 |
+
a = self.array(
|
512 |
+
[len(self.num23seq), len(self.num23seq[0])], intent.in_.copy,
|
513 |
+
obj)
|
514 |
+
assert not a.has_shared_memory()
|
515 |
+
|
516 |
+
def test_c_copy_in_from_23casttype(self):
|
517 |
+
for t in self.type.cast_types():
|
518 |
+
obj = np.array(self.num23seq, dtype=t.dtype)
|
519 |
+
a = self.array(
|
520 |
+
[len(self.num23seq), len(self.num23seq[0])], intent.in_.c.copy,
|
521 |
+
obj)
|
522 |
+
assert not a.has_shared_memory()
|
523 |
+
|
524 |
+
def test_in_cache_from_2casttype(self):
|
525 |
+
for t in self.type.all_types():
|
526 |
+
if t.elsize != self.type.elsize:
|
527 |
+
continue
|
528 |
+
obj = np.array(self.num2seq, dtype=t.dtype)
|
529 |
+
shape = (len(self.num2seq), )
|
530 |
+
a = self.array(shape, intent.in_.c.cache, obj)
|
531 |
+
assert a.has_shared_memory()
|
532 |
+
|
533 |
+
a = self.array(shape, intent.in_.cache, obj)
|
534 |
+
assert a.has_shared_memory()
|
535 |
+
|
536 |
+
obj = np.array(self.num2seq, dtype=t.dtype, order="F")
|
537 |
+
a = self.array(shape, intent.in_.c.cache, obj)
|
538 |
+
assert a.has_shared_memory()
|
539 |
+
|
540 |
+
a = self.array(shape, intent.in_.cache, obj)
|
541 |
+
assert a.has_shared_memory(), repr(t.dtype)
|
542 |
+
|
543 |
+
try:
|
544 |
+
a = self.array(shape, intent.in_.cache, obj[::-1])
|
545 |
+
except ValueError as msg:
|
546 |
+
if not str(msg).startswith(
|
547 |
+
"failed to initialize intent(cache) array"):
|
548 |
+
raise
|
549 |
+
else:
|
550 |
+
raise SystemError(
|
551 |
+
"intent(cache) should have failed on multisegmented array")
|
552 |
+
|
553 |
+
def test_in_cache_from_2casttype_failure(self):
|
554 |
+
for t in self.type.all_types():
|
555 |
+
if t.NAME == 'STRING':
|
556 |
+
# string elsize is 0, so skipping the test
|
557 |
+
continue
|
558 |
+
if t.elsize >= self.type.elsize:
|
559 |
+
continue
|
560 |
+
obj = np.array(self.num2seq, dtype=t.dtype)
|
561 |
+
shape = (len(self.num2seq), )
|
562 |
+
try:
|
563 |
+
self.array(shape, intent.in_.cache, obj) # Should succeed
|
564 |
+
except ValueError as msg:
|
565 |
+
if not str(msg).startswith(
|
566 |
+
"failed to initialize intent(cache) array"):
|
567 |
+
raise
|
568 |
+
else:
|
569 |
+
raise SystemError(
|
570 |
+
"intent(cache) should have failed on smaller array")
|
571 |
+
|
572 |
+
def test_cache_hidden(self):
|
573 |
+
shape = (2, )
|
574 |
+
a = self.array(shape, intent.cache.hide, None)
|
575 |
+
assert a.arr.shape == shape
|
576 |
+
|
577 |
+
shape = (2, 3)
|
578 |
+
a = self.array(shape, intent.cache.hide, None)
|
579 |
+
assert a.arr.shape == shape
|
580 |
+
|
581 |
+
shape = (-1, 3)
|
582 |
+
try:
|
583 |
+
a = self.array(shape, intent.cache.hide, None)
|
584 |
+
except ValueError as msg:
|
585 |
+
if not str(msg).startswith(
|
586 |
+
"failed to create intent(cache|hide)|optional array"):
|
587 |
+
raise
|
588 |
+
else:
|
589 |
+
raise SystemError(
|
590 |
+
"intent(cache) should have failed on undefined dimensions")
|
591 |
+
|
592 |
+
def test_hidden(self):
|
593 |
+
shape = (2, )
|
594 |
+
a = self.array(shape, intent.hide, None)
|
595 |
+
assert a.arr.shape == shape
|
596 |
+
assert a.arr_equal(a.arr, np.zeros(shape, dtype=self.type.dtype))
|
597 |
+
|
598 |
+
shape = (2, 3)
|
599 |
+
a = self.array(shape, intent.hide, None)
|
600 |
+
assert a.arr.shape == shape
|
601 |
+
assert a.arr_equal(a.arr, np.zeros(shape, dtype=self.type.dtype))
|
602 |
+
assert a.arr.flags["FORTRAN"] and not a.arr.flags["CONTIGUOUS"]
|
603 |
+
|
604 |
+
shape = (2, 3)
|
605 |
+
a = self.array(shape, intent.c.hide, None)
|
606 |
+
assert a.arr.shape == shape
|
607 |
+
assert a.arr_equal(a.arr, np.zeros(shape, dtype=self.type.dtype))
|
608 |
+
assert not a.arr.flags["FORTRAN"] and a.arr.flags["CONTIGUOUS"]
|
609 |
+
|
610 |
+
shape = (-1, 3)
|
611 |
+
try:
|
612 |
+
a = self.array(shape, intent.hide, None)
|
613 |
+
except ValueError as msg:
|
614 |
+
if not str(msg).startswith(
|
615 |
+
"failed to create intent(cache|hide)|optional array"):
|
616 |
+
raise
|
617 |
+
else:
|
618 |
+
raise SystemError(
|
619 |
+
"intent(hide) should have failed on undefined dimensions")
|
620 |
+
|
621 |
+
def test_optional_none(self):
|
622 |
+
shape = (2, )
|
623 |
+
a = self.array(shape, intent.optional, None)
|
624 |
+
assert a.arr.shape == shape
|
625 |
+
assert a.arr_equal(a.arr, np.zeros(shape, dtype=self.type.dtype))
|
626 |
+
|
627 |
+
shape = (2, 3)
|
628 |
+
a = self.array(shape, intent.optional, None)
|
629 |
+
assert a.arr.shape == shape
|
630 |
+
assert a.arr_equal(a.arr, np.zeros(shape, dtype=self.type.dtype))
|
631 |
+
assert a.arr.flags["FORTRAN"] and not a.arr.flags["CONTIGUOUS"]
|
632 |
+
|
633 |
+
shape = (2, 3)
|
634 |
+
a = self.array(shape, intent.c.optional, None)
|
635 |
+
assert a.arr.shape == shape
|
636 |
+
assert a.arr_equal(a.arr, np.zeros(shape, dtype=self.type.dtype))
|
637 |
+
assert not a.arr.flags["FORTRAN"] and a.arr.flags["CONTIGUOUS"]
|
638 |
+
|
639 |
+
def test_optional_from_2seq(self):
|
640 |
+
obj = self.num2seq
|
641 |
+
shape = (len(obj), )
|
642 |
+
a = self.array(shape, intent.optional, obj)
|
643 |
+
assert a.arr.shape == shape
|
644 |
+
assert not a.has_shared_memory()
|
645 |
+
|
646 |
+
def test_optional_from_23seq(self):
|
647 |
+
obj = self.num23seq
|
648 |
+
shape = (len(obj), len(obj[0]))
|
649 |
+
a = self.array(shape, intent.optional, obj)
|
650 |
+
assert a.arr.shape == shape
|
651 |
+
assert not a.has_shared_memory()
|
652 |
+
|
653 |
+
a = self.array(shape, intent.optional.c, obj)
|
654 |
+
assert a.arr.shape == shape
|
655 |
+
assert not a.has_shared_memory()
|
656 |
+
|
657 |
+
def test_inplace(self):
|
658 |
+
obj = np.array(self.num23seq, dtype=self.type.dtype)
|
659 |
+
assert not obj.flags["FORTRAN"] and obj.flags["CONTIGUOUS"]
|
660 |
+
shape = obj.shape
|
661 |
+
a = self.array(shape, intent.inplace, obj)
|
662 |
+
assert obj[1][2] == a.arr[1][2], repr((obj, a.arr))
|
663 |
+
a.arr[1][2] = 54
|
664 |
+
assert obj[1][2] == a.arr[1][2] == np.array(54, dtype=self.type.dtype)
|
665 |
+
assert a.arr is obj
|
666 |
+
assert obj.flags["FORTRAN"] # obj attributes are changed inplace!
|
667 |
+
assert not obj.flags["CONTIGUOUS"]
|
668 |
+
|
669 |
+
def test_inplace_from_casttype(self):
|
670 |
+
for t in self.type.cast_types():
|
671 |
+
if t is self.type:
|
672 |
+
continue
|
673 |
+
obj = np.array(self.num23seq, dtype=t.dtype)
|
674 |
+
assert obj.dtype.type == t.type
|
675 |
+
assert obj.dtype.type is not self.type.type
|
676 |
+
assert not obj.flags["FORTRAN"] and obj.flags["CONTIGUOUS"]
|
677 |
+
shape = obj.shape
|
678 |
+
a = self.array(shape, intent.inplace, obj)
|
679 |
+
assert obj[1][2] == a.arr[1][2], repr((obj, a.arr))
|
680 |
+
a.arr[1][2] = 54
|
681 |
+
assert obj[1][2] == a.arr[1][2] == np.array(54,
|
682 |
+
dtype=self.type.dtype)
|
683 |
+
assert a.arr is obj
|
684 |
+
assert obj.flags["FORTRAN"] # obj attributes changed inplace!
|
685 |
+
assert not obj.flags["CONTIGUOUS"]
|
686 |
+
assert obj.dtype.type is self.type.type # obj changed inplace!
|
.venv/lib/python3.11/site-packages/numpy/f2py/tests/test_assumed_shape.py
ADDED
@@ -0,0 +1,49 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
import pytest
|
3 |
+
import tempfile
|
4 |
+
|
5 |
+
from . import util
|
6 |
+
|
7 |
+
|
8 |
+
class TestAssumedShapeSumExample(util.F2PyTest):
|
9 |
+
sources = [
|
10 |
+
util.getpath("tests", "src", "assumed_shape", "foo_free.f90"),
|
11 |
+
util.getpath("tests", "src", "assumed_shape", "foo_use.f90"),
|
12 |
+
util.getpath("tests", "src", "assumed_shape", "precision.f90"),
|
13 |
+
util.getpath("tests", "src", "assumed_shape", "foo_mod.f90"),
|
14 |
+
util.getpath("tests", "src", "assumed_shape", ".f2py_f2cmap"),
|
15 |
+
]
|
16 |
+
|
17 |
+
@pytest.mark.slow
|
18 |
+
def test_all(self):
|
19 |
+
r = self.module.fsum([1, 2])
|
20 |
+
assert r == 3
|
21 |
+
r = self.module.sum([1, 2])
|
22 |
+
assert r == 3
|
23 |
+
r = self.module.sum_with_use([1, 2])
|
24 |
+
assert r == 3
|
25 |
+
|
26 |
+
r = self.module.mod.sum([1, 2])
|
27 |
+
assert r == 3
|
28 |
+
r = self.module.mod.fsum([1, 2])
|
29 |
+
assert r == 3
|
30 |
+
|
31 |
+
|
32 |
+
class TestF2cmapOption(TestAssumedShapeSumExample):
|
33 |
+
def setup_method(self):
|
34 |
+
# Use a custom file name for .f2py_f2cmap
|
35 |
+
self.sources = list(self.sources)
|
36 |
+
f2cmap_src = self.sources.pop(-1)
|
37 |
+
|
38 |
+
self.f2cmap_file = tempfile.NamedTemporaryFile(delete=False)
|
39 |
+
with open(f2cmap_src, "rb") as f:
|
40 |
+
self.f2cmap_file.write(f.read())
|
41 |
+
self.f2cmap_file.close()
|
42 |
+
|
43 |
+
self.sources.append(self.f2cmap_file.name)
|
44 |
+
self.options = ["--f2cmap", self.f2cmap_file.name]
|
45 |
+
|
46 |
+
super().setup_method()
|
47 |
+
|
48 |
+
def teardown_method(self):
|
49 |
+
os.unlink(self.f2cmap_file.name)
|
.venv/lib/python3.11/site-packages/numpy/f2py/tests/test_block_docstring.py
ADDED
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import sys
|
2 |
+
import pytest
|
3 |
+
from . import util
|
4 |
+
|
5 |
+
from numpy.testing import IS_PYPY
|
6 |
+
|
7 |
+
|
8 |
+
class TestBlockDocString(util.F2PyTest):
|
9 |
+
sources = [util.getpath("tests", "src", "block_docstring", "foo.f")]
|
10 |
+
|
11 |
+
@pytest.mark.skipif(sys.platform == "win32",
|
12 |
+
reason="Fails with MinGW64 Gfortran (Issue #9673)")
|
13 |
+
@pytest.mark.xfail(IS_PYPY,
|
14 |
+
reason="PyPy cannot modify tp_doc after PyType_Ready")
|
15 |
+
def test_block_docstring(self):
|
16 |
+
expected = "bar : 'i'-array(2,3)\n"
|
17 |
+
assert self.module.block.__doc__ == expected
|
.venv/lib/python3.11/site-packages/numpy/f2py/tests/test_callback.py
ADDED
@@ -0,0 +1,243 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import math
|
2 |
+
import textwrap
|
3 |
+
import sys
|
4 |
+
import pytest
|
5 |
+
import threading
|
6 |
+
import traceback
|
7 |
+
import time
|
8 |
+
|
9 |
+
import numpy as np
|
10 |
+
from numpy.testing import IS_PYPY
|
11 |
+
from . import util
|
12 |
+
|
13 |
+
|
14 |
+
class TestF77Callback(util.F2PyTest):
|
15 |
+
sources = [util.getpath("tests", "src", "callback", "foo.f")]
|
16 |
+
|
17 |
+
@pytest.mark.parametrize("name", "t,t2".split(","))
|
18 |
+
def test_all(self, name):
|
19 |
+
self.check_function(name)
|
20 |
+
|
21 |
+
@pytest.mark.xfail(IS_PYPY,
|
22 |
+
reason="PyPy cannot modify tp_doc after PyType_Ready")
|
23 |
+
def test_docstring(self):
|
24 |
+
expected = textwrap.dedent("""\
|
25 |
+
a = t(fun,[fun_extra_args])
|
26 |
+
|
27 |
+
Wrapper for ``t``.
|
28 |
+
|
29 |
+
Parameters
|
30 |
+
----------
|
31 |
+
fun : call-back function
|
32 |
+
|
33 |
+
Other Parameters
|
34 |
+
----------------
|
35 |
+
fun_extra_args : input tuple, optional
|
36 |
+
Default: ()
|
37 |
+
|
38 |
+
Returns
|
39 |
+
-------
|
40 |
+
a : int
|
41 |
+
|
42 |
+
Notes
|
43 |
+
-----
|
44 |
+
Call-back functions::
|
45 |
+
|
46 |
+
def fun(): return a
|
47 |
+
Return objects:
|
48 |
+
a : int
|
49 |
+
""")
|
50 |
+
assert self.module.t.__doc__ == expected
|
51 |
+
|
52 |
+
def check_function(self, name):
|
53 |
+
t = getattr(self.module, name)
|
54 |
+
r = t(lambda: 4)
|
55 |
+
assert r == 4
|
56 |
+
r = t(lambda a: 5, fun_extra_args=(6, ))
|
57 |
+
assert r == 5
|
58 |
+
r = t(lambda a: a, fun_extra_args=(6, ))
|
59 |
+
assert r == 6
|
60 |
+
r = t(lambda a: 5 + a, fun_extra_args=(7, ))
|
61 |
+
assert r == 12
|
62 |
+
r = t(lambda a: math.degrees(a), fun_extra_args=(math.pi, ))
|
63 |
+
assert r == 180
|
64 |
+
r = t(math.degrees, fun_extra_args=(math.pi, ))
|
65 |
+
assert r == 180
|
66 |
+
|
67 |
+
r = t(self.module.func, fun_extra_args=(6, ))
|
68 |
+
assert r == 17
|
69 |
+
r = t(self.module.func0)
|
70 |
+
assert r == 11
|
71 |
+
r = t(self.module.func0._cpointer)
|
72 |
+
assert r == 11
|
73 |
+
|
74 |
+
class A:
|
75 |
+
def __call__(self):
|
76 |
+
return 7
|
77 |
+
|
78 |
+
def mth(self):
|
79 |
+
return 9
|
80 |
+
|
81 |
+
a = A()
|
82 |
+
r = t(a)
|
83 |
+
assert r == 7
|
84 |
+
r = t(a.mth)
|
85 |
+
assert r == 9
|
86 |
+
|
87 |
+
@pytest.mark.skipif(sys.platform == 'win32',
|
88 |
+
reason='Fails with MinGW64 Gfortran (Issue #9673)')
|
89 |
+
def test_string_callback(self):
|
90 |
+
def callback(code):
|
91 |
+
if code == "r":
|
92 |
+
return 0
|
93 |
+
else:
|
94 |
+
return 1
|
95 |
+
|
96 |
+
f = getattr(self.module, "string_callback")
|
97 |
+
r = f(callback)
|
98 |
+
assert r == 0
|
99 |
+
|
100 |
+
@pytest.mark.skipif(sys.platform == 'win32',
|
101 |
+
reason='Fails with MinGW64 Gfortran (Issue #9673)')
|
102 |
+
def test_string_callback_array(self):
|
103 |
+
# See gh-10027
|
104 |
+
cu1 = np.zeros((1, ), "S8")
|
105 |
+
cu2 = np.zeros((1, 8), "c")
|
106 |
+
cu3 = np.array([""], "S8")
|
107 |
+
|
108 |
+
def callback(cu, lencu):
|
109 |
+
if cu.shape != (lencu,):
|
110 |
+
return 1
|
111 |
+
if cu.dtype != "S8":
|
112 |
+
return 2
|
113 |
+
if not np.all(cu == b""):
|
114 |
+
return 3
|
115 |
+
return 0
|
116 |
+
|
117 |
+
f = getattr(self.module, "string_callback_array")
|
118 |
+
for cu in [cu1, cu2, cu3]:
|
119 |
+
res = f(callback, cu, cu.size)
|
120 |
+
assert res == 0
|
121 |
+
|
122 |
+
def test_threadsafety(self):
|
123 |
+
# Segfaults if the callback handling is not threadsafe
|
124 |
+
|
125 |
+
errors = []
|
126 |
+
|
127 |
+
def cb():
|
128 |
+
# Sleep here to make it more likely for another thread
|
129 |
+
# to call their callback at the same time.
|
130 |
+
time.sleep(1e-3)
|
131 |
+
|
132 |
+
# Check reentrancy
|
133 |
+
r = self.module.t(lambda: 123)
|
134 |
+
assert r == 123
|
135 |
+
|
136 |
+
return 42
|
137 |
+
|
138 |
+
def runner(name):
|
139 |
+
try:
|
140 |
+
for j in range(50):
|
141 |
+
r = self.module.t(cb)
|
142 |
+
assert r == 42
|
143 |
+
self.check_function(name)
|
144 |
+
except Exception:
|
145 |
+
errors.append(traceback.format_exc())
|
146 |
+
|
147 |
+
threads = [
|
148 |
+
threading.Thread(target=runner, args=(arg, ))
|
149 |
+
for arg in ("t", "t2") for n in range(20)
|
150 |
+
]
|
151 |
+
|
152 |
+
for t in threads:
|
153 |
+
t.start()
|
154 |
+
|
155 |
+
for t in threads:
|
156 |
+
t.join()
|
157 |
+
|
158 |
+
errors = "\n\n".join(errors)
|
159 |
+
if errors:
|
160 |
+
raise AssertionError(errors)
|
161 |
+
|
162 |
+
def test_hidden_callback(self):
|
163 |
+
try:
|
164 |
+
self.module.hidden_callback(2)
|
165 |
+
except Exception as msg:
|
166 |
+
assert str(msg).startswith("Callback global_f not defined")
|
167 |
+
|
168 |
+
try:
|
169 |
+
self.module.hidden_callback2(2)
|
170 |
+
except Exception as msg:
|
171 |
+
assert str(msg).startswith("cb: Callback global_f not defined")
|
172 |
+
|
173 |
+
self.module.global_f = lambda x: x + 1
|
174 |
+
r = self.module.hidden_callback(2)
|
175 |
+
assert r == 3
|
176 |
+
|
177 |
+
self.module.global_f = lambda x: x + 2
|
178 |
+
r = self.module.hidden_callback(2)
|
179 |
+
assert r == 4
|
180 |
+
|
181 |
+
del self.module.global_f
|
182 |
+
try:
|
183 |
+
self.module.hidden_callback(2)
|
184 |
+
except Exception as msg:
|
185 |
+
assert str(msg).startswith("Callback global_f not defined")
|
186 |
+
|
187 |
+
self.module.global_f = lambda x=0: x + 3
|
188 |
+
r = self.module.hidden_callback(2)
|
189 |
+
assert r == 5
|
190 |
+
|
191 |
+
# reproducer of gh18341
|
192 |
+
r = self.module.hidden_callback2(2)
|
193 |
+
assert r == 3
|
194 |
+
|
195 |
+
|
196 |
+
class TestF77CallbackPythonTLS(TestF77Callback):
|
197 |
+
"""
|
198 |
+
Callback tests using Python thread-local storage instead of
|
199 |
+
compiler-provided
|
200 |
+
"""
|
201 |
+
|
202 |
+
options = ["-DF2PY_USE_PYTHON_TLS"]
|
203 |
+
|
204 |
+
|
205 |
+
class TestF90Callback(util.F2PyTest):
|
206 |
+
sources = [util.getpath("tests", "src", "callback", "gh17797.f90")]
|
207 |
+
|
208 |
+
def test_gh17797(self):
|
209 |
+
def incr(x):
|
210 |
+
return x + 123
|
211 |
+
|
212 |
+
y = np.array([1, 2, 3], dtype=np.int64)
|
213 |
+
r = self.module.gh17797(incr, y)
|
214 |
+
assert r == 123 + 1 + 2 + 3
|
215 |
+
|
216 |
+
|
217 |
+
class TestGH18335(util.F2PyTest):
|
218 |
+
"""The reproduction of the reported issue requires specific input that
|
219 |
+
extensions may break the issue conditions, so the reproducer is
|
220 |
+
implemented as a separate test class. Do not extend this test with
|
221 |
+
other tests!
|
222 |
+
"""
|
223 |
+
sources = [util.getpath("tests", "src", "callback", "gh18335.f90")]
|
224 |
+
|
225 |
+
def test_gh18335(self):
|
226 |
+
def foo(x):
|
227 |
+
x[0] += 1
|
228 |
+
|
229 |
+
r = self.module.gh18335(foo)
|
230 |
+
assert r == 123 + 1
|
231 |
+
|
232 |
+
|
233 |
+
class TestGH25211(util.F2PyTest):
|
234 |
+
sources = [util.getpath("tests", "src", "callback", "gh25211.f"),
|
235 |
+
util.getpath("tests", "src", "callback", "gh25211.pyf")]
|
236 |
+
module_name = "callback2"
|
237 |
+
|
238 |
+
def test_gh18335(self):
|
239 |
+
def bar(x):
|
240 |
+
return x*x
|
241 |
+
|
242 |
+
res = self.module.foo(bar)
|
243 |
+
assert res == 110
|
.venv/lib/python3.11/site-packages/numpy/f2py/tests/test_character.py
ADDED
@@ -0,0 +1,636 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import pytest
|
2 |
+
import textwrap
|
3 |
+
from numpy.testing import assert_array_equal, assert_equal, assert_raises
|
4 |
+
import numpy as np
|
5 |
+
from numpy.f2py.tests import util
|
6 |
+
|
7 |
+
|
8 |
+
class TestCharacterString(util.F2PyTest):
|
9 |
+
# options = ['--debug-capi', '--build-dir', '/tmp/test-build-f2py']
|
10 |
+
suffix = '.f90'
|
11 |
+
fprefix = 'test_character_string'
|
12 |
+
length_list = ['1', '3', 'star']
|
13 |
+
|
14 |
+
code = ''
|
15 |
+
for length in length_list:
|
16 |
+
fsuffix = length
|
17 |
+
clength = dict(star='(*)').get(length, length)
|
18 |
+
|
19 |
+
code += textwrap.dedent(f"""
|
20 |
+
|
21 |
+
subroutine {fprefix}_input_{fsuffix}(c, o, n)
|
22 |
+
character*{clength}, intent(in) :: c
|
23 |
+
integer n
|
24 |
+
!f2py integer, depend(c), intent(hide) :: n = slen(c)
|
25 |
+
integer*1, dimension(n) :: o
|
26 |
+
!f2py intent(out) o
|
27 |
+
o = transfer(c, o)
|
28 |
+
end subroutine {fprefix}_input_{fsuffix}
|
29 |
+
|
30 |
+
subroutine {fprefix}_output_{fsuffix}(c, o, n)
|
31 |
+
character*{clength}, intent(out) :: c
|
32 |
+
integer n
|
33 |
+
integer*1, dimension(n), intent(in) :: o
|
34 |
+
!f2py integer, depend(o), intent(hide) :: n = len(o)
|
35 |
+
c = transfer(o, c)
|
36 |
+
end subroutine {fprefix}_output_{fsuffix}
|
37 |
+
|
38 |
+
subroutine {fprefix}_array_input_{fsuffix}(c, o, m, n)
|
39 |
+
integer m, i, n
|
40 |
+
character*{clength}, intent(in), dimension(m) :: c
|
41 |
+
!f2py integer, depend(c), intent(hide) :: m = len(c)
|
42 |
+
!f2py integer, depend(c), intent(hide) :: n = f2py_itemsize(c)
|
43 |
+
integer*1, dimension(m, n), intent(out) :: o
|
44 |
+
do i=1,m
|
45 |
+
o(i, :) = transfer(c(i), o(i, :))
|
46 |
+
end do
|
47 |
+
end subroutine {fprefix}_array_input_{fsuffix}
|
48 |
+
|
49 |
+
subroutine {fprefix}_array_output_{fsuffix}(c, o, m, n)
|
50 |
+
character*{clength}, intent(out), dimension(m) :: c
|
51 |
+
integer n
|
52 |
+
integer*1, dimension(m, n), intent(in) :: o
|
53 |
+
!f2py character(f2py_len=n) :: c
|
54 |
+
!f2py integer, depend(o), intent(hide) :: m = len(o)
|
55 |
+
!f2py integer, depend(o), intent(hide) :: n = shape(o, 1)
|
56 |
+
do i=1,m
|
57 |
+
c(i) = transfer(o(i, :), c(i))
|
58 |
+
end do
|
59 |
+
end subroutine {fprefix}_array_output_{fsuffix}
|
60 |
+
|
61 |
+
subroutine {fprefix}_2d_array_input_{fsuffix}(c, o, m1, m2, n)
|
62 |
+
integer m1, m2, i, j, n
|
63 |
+
character*{clength}, intent(in), dimension(m1, m2) :: c
|
64 |
+
!f2py integer, depend(c), intent(hide) :: m1 = len(c)
|
65 |
+
!f2py integer, depend(c), intent(hide) :: m2 = shape(c, 1)
|
66 |
+
!f2py integer, depend(c), intent(hide) :: n = f2py_itemsize(c)
|
67 |
+
integer*1, dimension(m1, m2, n), intent(out) :: o
|
68 |
+
do i=1,m1
|
69 |
+
do j=1,m2
|
70 |
+
o(i, j, :) = transfer(c(i, j), o(i, j, :))
|
71 |
+
end do
|
72 |
+
end do
|
73 |
+
end subroutine {fprefix}_2d_array_input_{fsuffix}
|
74 |
+
""")
|
75 |
+
|
76 |
+
@pytest.mark.parametrize("length", length_list)
|
77 |
+
def test_input(self, length):
|
78 |
+
fsuffix = {'(*)': 'star'}.get(length, length)
|
79 |
+
f = getattr(self.module, self.fprefix + '_input_' + fsuffix)
|
80 |
+
|
81 |
+
a = {'1': 'a', '3': 'abc', 'star': 'abcde' * 3}[length]
|
82 |
+
|
83 |
+
assert_array_equal(f(a), np.array(list(map(ord, a)), dtype='u1'))
|
84 |
+
|
85 |
+
@pytest.mark.parametrize("length", length_list[:-1])
|
86 |
+
def test_output(self, length):
|
87 |
+
fsuffix = length
|
88 |
+
f = getattr(self.module, self.fprefix + '_output_' + fsuffix)
|
89 |
+
|
90 |
+
a = {'1': 'a', '3': 'abc'}[length]
|
91 |
+
|
92 |
+
assert_array_equal(f(np.array(list(map(ord, a)), dtype='u1')),
|
93 |
+
a.encode())
|
94 |
+
|
95 |
+
@pytest.mark.parametrize("length", length_list)
|
96 |
+
def test_array_input(self, length):
|
97 |
+
fsuffix = length
|
98 |
+
f = getattr(self.module, self.fprefix + '_array_input_' + fsuffix)
|
99 |
+
|
100 |
+
a = np.array([{'1': 'a', '3': 'abc', 'star': 'abcde' * 3}[length],
|
101 |
+
{'1': 'A', '3': 'ABC', 'star': 'ABCDE' * 3}[length],
|
102 |
+
], dtype='S')
|
103 |
+
|
104 |
+
expected = np.array([[c for c in s] for s in a], dtype='u1')
|
105 |
+
assert_array_equal(f(a), expected)
|
106 |
+
|
107 |
+
@pytest.mark.parametrize("length", length_list)
|
108 |
+
def test_array_output(self, length):
|
109 |
+
fsuffix = length
|
110 |
+
f = getattr(self.module, self.fprefix + '_array_output_' + fsuffix)
|
111 |
+
|
112 |
+
expected = np.array(
|
113 |
+
[{'1': 'a', '3': 'abc', 'star': 'abcde' * 3}[length],
|
114 |
+
{'1': 'A', '3': 'ABC', 'star': 'ABCDE' * 3}[length]], dtype='S')
|
115 |
+
|
116 |
+
a = np.array([[c for c in s] for s in expected], dtype='u1')
|
117 |
+
assert_array_equal(f(a), expected)
|
118 |
+
|
119 |
+
@pytest.mark.parametrize("length", length_list)
|
120 |
+
def test_2d_array_input(self, length):
|
121 |
+
fsuffix = length
|
122 |
+
f = getattr(self.module, self.fprefix + '_2d_array_input_' + fsuffix)
|
123 |
+
|
124 |
+
a = np.array([[{'1': 'a', '3': 'abc', 'star': 'abcde' * 3}[length],
|
125 |
+
{'1': 'A', '3': 'ABC', 'star': 'ABCDE' * 3}[length]],
|
126 |
+
[{'1': 'f', '3': 'fgh', 'star': 'fghij' * 3}[length],
|
127 |
+
{'1': 'F', '3': 'FGH', 'star': 'FGHIJ' * 3}[length]]],
|
128 |
+
dtype='S')
|
129 |
+
expected = np.array([[[c for c in item] for item in row] for row in a],
|
130 |
+
dtype='u1', order='F')
|
131 |
+
assert_array_equal(f(a), expected)
|
132 |
+
|
133 |
+
|
134 |
+
class TestCharacter(util.F2PyTest):
|
135 |
+
# options = ['--debug-capi', '--build-dir', '/tmp/test-build-f2py']
|
136 |
+
suffix = '.f90'
|
137 |
+
fprefix = 'test_character'
|
138 |
+
|
139 |
+
code = textwrap.dedent(f"""
|
140 |
+
subroutine {fprefix}_input(c, o)
|
141 |
+
character, intent(in) :: c
|
142 |
+
integer*1 o
|
143 |
+
!f2py intent(out) o
|
144 |
+
o = transfer(c, o)
|
145 |
+
end subroutine {fprefix}_input
|
146 |
+
|
147 |
+
subroutine {fprefix}_output(c, o)
|
148 |
+
character :: c
|
149 |
+
integer*1, intent(in) :: o
|
150 |
+
!f2py intent(out) c
|
151 |
+
c = transfer(o, c)
|
152 |
+
end subroutine {fprefix}_output
|
153 |
+
|
154 |
+
subroutine {fprefix}_input_output(c, o)
|
155 |
+
character, intent(in) :: c
|
156 |
+
character o
|
157 |
+
!f2py intent(out) o
|
158 |
+
o = c
|
159 |
+
end subroutine {fprefix}_input_output
|
160 |
+
|
161 |
+
subroutine {fprefix}_inout(c, n)
|
162 |
+
character :: c, n
|
163 |
+
!f2py intent(in) n
|
164 |
+
!f2py intent(inout) c
|
165 |
+
c = n
|
166 |
+
end subroutine {fprefix}_inout
|
167 |
+
|
168 |
+
function {fprefix}_return(o) result (c)
|
169 |
+
character :: c
|
170 |
+
character, intent(in) :: o
|
171 |
+
c = transfer(o, c)
|
172 |
+
end function {fprefix}_return
|
173 |
+
|
174 |
+
subroutine {fprefix}_array_input(c, o)
|
175 |
+
character, intent(in) :: c(3)
|
176 |
+
integer*1 o(3)
|
177 |
+
!f2py intent(out) o
|
178 |
+
integer i
|
179 |
+
do i=1,3
|
180 |
+
o(i) = transfer(c(i), o(i))
|
181 |
+
end do
|
182 |
+
end subroutine {fprefix}_array_input
|
183 |
+
|
184 |
+
subroutine {fprefix}_2d_array_input(c, o)
|
185 |
+
character, intent(in) :: c(2, 3)
|
186 |
+
integer*1 o(2, 3)
|
187 |
+
!f2py intent(out) o
|
188 |
+
integer i, j
|
189 |
+
do i=1,2
|
190 |
+
do j=1,3
|
191 |
+
o(i, j) = transfer(c(i, j), o(i, j))
|
192 |
+
end do
|
193 |
+
end do
|
194 |
+
end subroutine {fprefix}_2d_array_input
|
195 |
+
|
196 |
+
subroutine {fprefix}_array_output(c, o)
|
197 |
+
character :: c(3)
|
198 |
+
integer*1, intent(in) :: o(3)
|
199 |
+
!f2py intent(out) c
|
200 |
+
do i=1,3
|
201 |
+
c(i) = transfer(o(i), c(i))
|
202 |
+
end do
|
203 |
+
end subroutine {fprefix}_array_output
|
204 |
+
|
205 |
+
subroutine {fprefix}_array_inout(c, n)
|
206 |
+
character :: c(3), n(3)
|
207 |
+
!f2py intent(in) n(3)
|
208 |
+
!f2py intent(inout) c(3)
|
209 |
+
do i=1,3
|
210 |
+
c(i) = n(i)
|
211 |
+
end do
|
212 |
+
end subroutine {fprefix}_array_inout
|
213 |
+
|
214 |
+
subroutine {fprefix}_2d_array_inout(c, n)
|
215 |
+
character :: c(2, 3), n(2, 3)
|
216 |
+
!f2py intent(in) n(2, 3)
|
217 |
+
!f2py intent(inout) c(2. 3)
|
218 |
+
integer i, j
|
219 |
+
do i=1,2
|
220 |
+
do j=1,3
|
221 |
+
c(i, j) = n(i, j)
|
222 |
+
end do
|
223 |
+
end do
|
224 |
+
end subroutine {fprefix}_2d_array_inout
|
225 |
+
|
226 |
+
function {fprefix}_array_return(o) result (c)
|
227 |
+
character, dimension(3) :: c
|
228 |
+
character, intent(in) :: o(3)
|
229 |
+
do i=1,3
|
230 |
+
c(i) = o(i)
|
231 |
+
end do
|
232 |
+
end function {fprefix}_array_return
|
233 |
+
|
234 |
+
function {fprefix}_optional(o) result (c)
|
235 |
+
character, intent(in) :: o
|
236 |
+
!f2py character o = "a"
|
237 |
+
character :: c
|
238 |
+
c = o
|
239 |
+
end function {fprefix}_optional
|
240 |
+
""")
|
241 |
+
|
242 |
+
@pytest.mark.parametrize("dtype", ['c', 'S1'])
|
243 |
+
def test_input(self, dtype):
|
244 |
+
f = getattr(self.module, self.fprefix + '_input')
|
245 |
+
|
246 |
+
assert_equal(f(np.array('a', dtype=dtype)), ord('a'))
|
247 |
+
assert_equal(f(np.array(b'a', dtype=dtype)), ord('a'))
|
248 |
+
assert_equal(f(np.array(['a'], dtype=dtype)), ord('a'))
|
249 |
+
assert_equal(f(np.array('abc', dtype=dtype)), ord('a'))
|
250 |
+
assert_equal(f(np.array([['a']], dtype=dtype)), ord('a'))
|
251 |
+
|
252 |
+
def test_input_varia(self):
|
253 |
+
f = getattr(self.module, self.fprefix + '_input')
|
254 |
+
|
255 |
+
assert_equal(f('a'), ord('a'))
|
256 |
+
assert_equal(f(b'a'), ord(b'a'))
|
257 |
+
assert_equal(f(''), 0)
|
258 |
+
assert_equal(f(b''), 0)
|
259 |
+
assert_equal(f(b'\0'), 0)
|
260 |
+
assert_equal(f('ab'), ord('a'))
|
261 |
+
assert_equal(f(b'ab'), ord('a'))
|
262 |
+
assert_equal(f(['a']), ord('a'))
|
263 |
+
|
264 |
+
assert_equal(f(np.array(b'a')), ord('a'))
|
265 |
+
assert_equal(f(np.array([b'a'])), ord('a'))
|
266 |
+
a = np.array('a')
|
267 |
+
assert_equal(f(a), ord('a'))
|
268 |
+
a = np.array(['a'])
|
269 |
+
assert_equal(f(a), ord('a'))
|
270 |
+
|
271 |
+
try:
|
272 |
+
f([])
|
273 |
+
except IndexError as msg:
|
274 |
+
if not str(msg).endswith(' got 0-list'):
|
275 |
+
raise
|
276 |
+
else:
|
277 |
+
raise SystemError(f'{f.__name__} should have failed on empty list')
|
278 |
+
|
279 |
+
try:
|
280 |
+
f(97)
|
281 |
+
except TypeError as msg:
|
282 |
+
if not str(msg).endswith(' got int instance'):
|
283 |
+
raise
|
284 |
+
else:
|
285 |
+
raise SystemError(f'{f.__name__} should have failed on int value')
|
286 |
+
|
287 |
+
@pytest.mark.parametrize("dtype", ['c', 'S1', 'U1'])
|
288 |
+
def test_array_input(self, dtype):
|
289 |
+
f = getattr(self.module, self.fprefix + '_array_input')
|
290 |
+
|
291 |
+
assert_array_equal(f(np.array(['a', 'b', 'c'], dtype=dtype)),
|
292 |
+
np.array(list(map(ord, 'abc')), dtype='i1'))
|
293 |
+
assert_array_equal(f(np.array([b'a', b'b', b'c'], dtype=dtype)),
|
294 |
+
np.array(list(map(ord, 'abc')), dtype='i1'))
|
295 |
+
|
296 |
+
def test_array_input_varia(self):
|
297 |
+
f = getattr(self.module, self.fprefix + '_array_input')
|
298 |
+
assert_array_equal(f(['a', 'b', 'c']),
|
299 |
+
np.array(list(map(ord, 'abc')), dtype='i1'))
|
300 |
+
assert_array_equal(f([b'a', b'b', b'c']),
|
301 |
+
np.array(list(map(ord, 'abc')), dtype='i1'))
|
302 |
+
|
303 |
+
try:
|
304 |
+
f(['a', 'b', 'c', 'd'])
|
305 |
+
except ValueError as msg:
|
306 |
+
if not str(msg).endswith(
|
307 |
+
'th dimension must be fixed to 3 but got 4'):
|
308 |
+
raise
|
309 |
+
else:
|
310 |
+
raise SystemError(
|
311 |
+
f'{f.__name__} should have failed on wrong input')
|
312 |
+
|
313 |
+
@pytest.mark.parametrize("dtype", ['c', 'S1', 'U1'])
|
314 |
+
def test_2d_array_input(self, dtype):
|
315 |
+
f = getattr(self.module, self.fprefix + '_2d_array_input')
|
316 |
+
|
317 |
+
a = np.array([['a', 'b', 'c'],
|
318 |
+
['d', 'e', 'f']], dtype=dtype, order='F')
|
319 |
+
expected = a.view(np.uint32 if dtype == 'U1' else np.uint8)
|
320 |
+
assert_array_equal(f(a), expected)
|
321 |
+
|
322 |
+
def test_output(self):
|
323 |
+
f = getattr(self.module, self.fprefix + '_output')
|
324 |
+
|
325 |
+
assert_equal(f(ord(b'a')), b'a')
|
326 |
+
assert_equal(f(0), b'\0')
|
327 |
+
|
328 |
+
def test_array_output(self):
|
329 |
+
f = getattr(self.module, self.fprefix + '_array_output')
|
330 |
+
|
331 |
+
assert_array_equal(f(list(map(ord, 'abc'))),
|
332 |
+
np.array(list('abc'), dtype='S1'))
|
333 |
+
|
334 |
+
def test_input_output(self):
|
335 |
+
f = getattr(self.module, self.fprefix + '_input_output')
|
336 |
+
|
337 |
+
assert_equal(f(b'a'), b'a')
|
338 |
+
assert_equal(f('a'), b'a')
|
339 |
+
assert_equal(f(''), b'\0')
|
340 |
+
|
341 |
+
@pytest.mark.parametrize("dtype", ['c', 'S1'])
|
342 |
+
def test_inout(self, dtype):
|
343 |
+
f = getattr(self.module, self.fprefix + '_inout')
|
344 |
+
|
345 |
+
a = np.array(list('abc'), dtype=dtype)
|
346 |
+
f(a, 'A')
|
347 |
+
assert_array_equal(a, np.array(list('Abc'), dtype=a.dtype))
|
348 |
+
f(a[1:], 'B')
|
349 |
+
assert_array_equal(a, np.array(list('ABc'), dtype=a.dtype))
|
350 |
+
|
351 |
+
a = np.array(['abc'], dtype=dtype)
|
352 |
+
f(a, 'A')
|
353 |
+
assert_array_equal(a, np.array(['Abc'], dtype=a.dtype))
|
354 |
+
|
355 |
+
def test_inout_varia(self):
|
356 |
+
f = getattr(self.module, self.fprefix + '_inout')
|
357 |
+
a = np.array('abc', dtype='S3')
|
358 |
+
f(a, 'A')
|
359 |
+
assert_array_equal(a, np.array('Abc', dtype=a.dtype))
|
360 |
+
|
361 |
+
a = np.array(['abc'], dtype='S3')
|
362 |
+
f(a, 'A')
|
363 |
+
assert_array_equal(a, np.array(['Abc'], dtype=a.dtype))
|
364 |
+
|
365 |
+
try:
|
366 |
+
f('abc', 'A')
|
367 |
+
except ValueError as msg:
|
368 |
+
if not str(msg).endswith(' got 3-str'):
|
369 |
+
raise
|
370 |
+
else:
|
371 |
+
raise SystemError(f'{f.__name__} should have failed on str value')
|
372 |
+
|
373 |
+
@pytest.mark.parametrize("dtype", ['c', 'S1'])
|
374 |
+
def test_array_inout(self, dtype):
|
375 |
+
f = getattr(self.module, self.fprefix + '_array_inout')
|
376 |
+
n = np.array(['A', 'B', 'C'], dtype=dtype, order='F')
|
377 |
+
|
378 |
+
a = np.array(['a', 'b', 'c'], dtype=dtype, order='F')
|
379 |
+
f(a, n)
|
380 |
+
assert_array_equal(a, n)
|
381 |
+
|
382 |
+
a = np.array(['a', 'b', 'c', 'd'], dtype=dtype)
|
383 |
+
f(a[1:], n)
|
384 |
+
assert_array_equal(a, np.array(['a', 'A', 'B', 'C'], dtype=dtype))
|
385 |
+
|
386 |
+
a = np.array([['a', 'b', 'c']], dtype=dtype, order='F')
|
387 |
+
f(a, n)
|
388 |
+
assert_array_equal(a, np.array([['A', 'B', 'C']], dtype=dtype))
|
389 |
+
|
390 |
+
a = np.array(['a', 'b', 'c', 'd'], dtype=dtype, order='F')
|
391 |
+
try:
|
392 |
+
f(a, n)
|
393 |
+
except ValueError as msg:
|
394 |
+
if not str(msg).endswith(
|
395 |
+
'th dimension must be fixed to 3 but got 4'):
|
396 |
+
raise
|
397 |
+
else:
|
398 |
+
raise SystemError(
|
399 |
+
f'{f.__name__} should have failed on wrong input')
|
400 |
+
|
401 |
+
@pytest.mark.parametrize("dtype", ['c', 'S1'])
|
402 |
+
def test_2d_array_inout(self, dtype):
|
403 |
+
f = getattr(self.module, self.fprefix + '_2d_array_inout')
|
404 |
+
n = np.array([['A', 'B', 'C'],
|
405 |
+
['D', 'E', 'F']],
|
406 |
+
dtype=dtype, order='F')
|
407 |
+
a = np.array([['a', 'b', 'c'],
|
408 |
+
['d', 'e', 'f']],
|
409 |
+
dtype=dtype, order='F')
|
410 |
+
f(a, n)
|
411 |
+
assert_array_equal(a, n)
|
412 |
+
|
413 |
+
def test_return(self):
|
414 |
+
f = getattr(self.module, self.fprefix + '_return')
|
415 |
+
|
416 |
+
assert_equal(f('a'), b'a')
|
417 |
+
|
418 |
+
@pytest.mark.skip('fortran function returning array segfaults')
|
419 |
+
def test_array_return(self):
|
420 |
+
f = getattr(self.module, self.fprefix + '_array_return')
|
421 |
+
|
422 |
+
a = np.array(list('abc'), dtype='S1')
|
423 |
+
assert_array_equal(f(a), a)
|
424 |
+
|
425 |
+
def test_optional(self):
|
426 |
+
f = getattr(self.module, self.fprefix + '_optional')
|
427 |
+
|
428 |
+
assert_equal(f(), b"a")
|
429 |
+
assert_equal(f(b'B'), b"B")
|
430 |
+
|
431 |
+
|
432 |
+
class TestMiscCharacter(util.F2PyTest):
|
433 |
+
# options = ['--debug-capi', '--build-dir', '/tmp/test-build-f2py']
|
434 |
+
suffix = '.f90'
|
435 |
+
fprefix = 'test_misc_character'
|
436 |
+
|
437 |
+
code = textwrap.dedent(f"""
|
438 |
+
subroutine {fprefix}_gh18684(x, y, m)
|
439 |
+
character(len=5), dimension(m), intent(in) :: x
|
440 |
+
character*5, dimension(m), intent(out) :: y
|
441 |
+
integer i, m
|
442 |
+
!f2py integer, intent(hide), depend(x) :: m = f2py_len(x)
|
443 |
+
do i=1,m
|
444 |
+
y(i) = x(i)
|
445 |
+
end do
|
446 |
+
end subroutine {fprefix}_gh18684
|
447 |
+
|
448 |
+
subroutine {fprefix}_gh6308(x, i)
|
449 |
+
integer i
|
450 |
+
!f2py check(i>=0 && i<12) i
|
451 |
+
character*5 name, x
|
452 |
+
common name(12)
|
453 |
+
name(i + 1) = x
|
454 |
+
end subroutine {fprefix}_gh6308
|
455 |
+
|
456 |
+
subroutine {fprefix}_gh4519(x)
|
457 |
+
character(len=*), intent(in) :: x(:)
|
458 |
+
!f2py intent(out) x
|
459 |
+
integer :: i
|
460 |
+
! Uncomment for debug printing:
|
461 |
+
!do i=1, size(x)
|
462 |
+
! print*, "x(",i,")=", x(i)
|
463 |
+
!end do
|
464 |
+
end subroutine {fprefix}_gh4519
|
465 |
+
|
466 |
+
pure function {fprefix}_gh3425(x) result (y)
|
467 |
+
character(len=*), intent(in) :: x
|
468 |
+
character(len=len(x)) :: y
|
469 |
+
integer :: i
|
470 |
+
do i = 1, len(x)
|
471 |
+
j = iachar(x(i:i))
|
472 |
+
if (j>=iachar("a") .and. j<=iachar("z") ) then
|
473 |
+
y(i:i) = achar(j-32)
|
474 |
+
else
|
475 |
+
y(i:i) = x(i:i)
|
476 |
+
endif
|
477 |
+
end do
|
478 |
+
end function {fprefix}_gh3425
|
479 |
+
|
480 |
+
subroutine {fprefix}_character_bc_new(x, y, z)
|
481 |
+
character, intent(in) :: x
|
482 |
+
character, intent(out) :: y
|
483 |
+
!f2py character, depend(x) :: y = x
|
484 |
+
!f2py character, dimension((x=='a'?1:2)), depend(x), intent(out) :: z
|
485 |
+
character, dimension(*) :: z
|
486 |
+
!f2py character, optional, check(x == 'a' || x == 'b') :: x = 'a'
|
487 |
+
!f2py callstatement (*f2py_func)(&x, &y, z)
|
488 |
+
!f2py callprotoargument character*, character*, character*
|
489 |
+
if (y.eq.x) then
|
490 |
+
y = x
|
491 |
+
else
|
492 |
+
y = 'e'
|
493 |
+
endif
|
494 |
+
z(1) = 'c'
|
495 |
+
end subroutine {fprefix}_character_bc_new
|
496 |
+
|
497 |
+
subroutine {fprefix}_character_bc_old(x, y, z)
|
498 |
+
character, intent(in) :: x
|
499 |
+
character, intent(out) :: y
|
500 |
+
!f2py character, depend(x) :: y = x[0]
|
501 |
+
!f2py character, dimension((*x=='a'?1:2)), depend(x), intent(out) :: z
|
502 |
+
character, dimension(*) :: z
|
503 |
+
!f2py character, optional, check(*x == 'a' || x[0] == 'b') :: x = 'a'
|
504 |
+
!f2py callstatement (*f2py_func)(x, y, z)
|
505 |
+
!f2py callprotoargument char*, char*, char*
|
506 |
+
if (y.eq.x) then
|
507 |
+
y = x
|
508 |
+
else
|
509 |
+
y = 'e'
|
510 |
+
endif
|
511 |
+
z(1) = 'c'
|
512 |
+
end subroutine {fprefix}_character_bc_old
|
513 |
+
""")
|
514 |
+
|
515 |
+
def test_gh18684(self):
|
516 |
+
# Test character(len=5) and character*5 usages
|
517 |
+
f = getattr(self.module, self.fprefix + '_gh18684')
|
518 |
+
x = np.array(["abcde", "fghij"], dtype='S5')
|
519 |
+
y = f(x)
|
520 |
+
|
521 |
+
assert_array_equal(x, y)
|
522 |
+
|
523 |
+
def test_gh6308(self):
|
524 |
+
# Test character string array in a common block
|
525 |
+
f = getattr(self.module, self.fprefix + '_gh6308')
|
526 |
+
|
527 |
+
assert_equal(self.module._BLNK_.name.dtype, np.dtype('S5'))
|
528 |
+
assert_equal(len(self.module._BLNK_.name), 12)
|
529 |
+
f("abcde", 0)
|
530 |
+
assert_equal(self.module._BLNK_.name[0], b"abcde")
|
531 |
+
f("12345", 5)
|
532 |
+
assert_equal(self.module._BLNK_.name[5], b"12345")
|
533 |
+
|
534 |
+
def test_gh4519(self):
|
535 |
+
# Test array of assumed length strings
|
536 |
+
f = getattr(self.module, self.fprefix + '_gh4519')
|
537 |
+
|
538 |
+
for x, expected in [
|
539 |
+
('a', dict(shape=(), dtype=np.dtype('S1'))),
|
540 |
+
('text', dict(shape=(), dtype=np.dtype('S4'))),
|
541 |
+
(np.array(['1', '2', '3'], dtype='S1'),
|
542 |
+
dict(shape=(3,), dtype=np.dtype('S1'))),
|
543 |
+
(['1', '2', '34'],
|
544 |
+
dict(shape=(3,), dtype=np.dtype('S2'))),
|
545 |
+
(['', ''], dict(shape=(2,), dtype=np.dtype('S1')))]:
|
546 |
+
r = f(x)
|
547 |
+
for k, v in expected.items():
|
548 |
+
assert_equal(getattr(r, k), v)
|
549 |
+
|
550 |
+
def test_gh3425(self):
|
551 |
+
# Test returning a copy of assumed length string
|
552 |
+
f = getattr(self.module, self.fprefix + '_gh3425')
|
553 |
+
# f is equivalent to bytes.upper
|
554 |
+
|
555 |
+
assert_equal(f('abC'), b'ABC')
|
556 |
+
assert_equal(f(''), b'')
|
557 |
+
assert_equal(f('abC12d'), b'ABC12D')
|
558 |
+
|
559 |
+
@pytest.mark.parametrize("state", ['new', 'old'])
|
560 |
+
def test_character_bc(self, state):
|
561 |
+
f = getattr(self.module, self.fprefix + '_character_bc_' + state)
|
562 |
+
|
563 |
+
c, a = f()
|
564 |
+
assert_equal(c, b'a')
|
565 |
+
assert_equal(len(a), 1)
|
566 |
+
|
567 |
+
c, a = f(b'b')
|
568 |
+
assert_equal(c, b'b')
|
569 |
+
assert_equal(len(a), 2)
|
570 |
+
|
571 |
+
assert_raises(Exception, lambda: f(b'c'))
|
572 |
+
|
573 |
+
|
574 |
+
class TestStringScalarArr(util.F2PyTest):
|
575 |
+
sources = [util.getpath("tests", "src", "string", "scalar_string.f90")]
|
576 |
+
|
577 |
+
def test_char(self):
|
578 |
+
for out in (self.module.string_test.string,
|
579 |
+
self.module.string_test.string77):
|
580 |
+
expected = ()
|
581 |
+
assert out.shape == expected
|
582 |
+
expected = '|S8'
|
583 |
+
assert out.dtype == expected
|
584 |
+
|
585 |
+
def test_char_arr(self):
|
586 |
+
for out in (self.module.string_test.strarr,
|
587 |
+
self.module.string_test.strarr77):
|
588 |
+
expected = (5,7)
|
589 |
+
assert out.shape == expected
|
590 |
+
expected = '|S12'
|
591 |
+
assert out.dtype == expected
|
592 |
+
|
593 |
+
class TestStringAssumedLength(util.F2PyTest):
|
594 |
+
sources = [util.getpath("tests", "src", "string", "gh24008.f")]
|
595 |
+
|
596 |
+
def test_gh24008(self):
|
597 |
+
self.module.greet("joe", "bob")
|
598 |
+
|
599 |
+
class TestStringOptionalInOut(util.F2PyTest):
|
600 |
+
sources = [util.getpath("tests", "src", "string", "gh24662.f90")]
|
601 |
+
|
602 |
+
def test_gh24662(self):
|
603 |
+
self.module.string_inout_optional()
|
604 |
+
a = np.array('hi', dtype='S32')
|
605 |
+
self.module.string_inout_optional(a)
|
606 |
+
assert "output string" in a.tobytes().decode()
|
607 |
+
with pytest.raises(Exception):
|
608 |
+
aa = "Hi"
|
609 |
+
self.module.string_inout_optional(aa)
|
610 |
+
|
611 |
+
|
612 |
+
@pytest.mark.slow
|
613 |
+
class TestNewCharHandling(util.F2PyTest):
|
614 |
+
# from v1.24 onwards, gh-19388
|
615 |
+
sources = [
|
616 |
+
util.getpath("tests", "src", "string", "gh25286.pyf"),
|
617 |
+
util.getpath("tests", "src", "string", "gh25286.f90")
|
618 |
+
]
|
619 |
+
module_name = "_char_handling_test"
|
620 |
+
|
621 |
+
def test_gh25286(self):
|
622 |
+
info = self.module.charint('T')
|
623 |
+
assert info == 2
|
624 |
+
|
625 |
+
@pytest.mark.slow
|
626 |
+
class TestBCCharHandling(util.F2PyTest):
|
627 |
+
# SciPy style, "incorrect" bindings with a hook
|
628 |
+
sources = [
|
629 |
+
util.getpath("tests", "src", "string", "gh25286_bc.pyf"),
|
630 |
+
util.getpath("tests", "src", "string", "gh25286.f90")
|
631 |
+
]
|
632 |
+
module_name = "_char_handling_test"
|
633 |
+
|
634 |
+
def test_gh25286(self):
|
635 |
+
info = self.module.charint('T')
|
636 |
+
assert info == 2
|
.venv/lib/python3.11/site-packages/numpy/f2py/tests/test_common.py
ADDED
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
import sys
|
3 |
+
import pytest
|
4 |
+
|
5 |
+
import numpy as np
|
6 |
+
from . import util
|
7 |
+
|
8 |
+
|
9 |
+
class TestCommonBlock(util.F2PyTest):
|
10 |
+
sources = [util.getpath("tests", "src", "common", "block.f")]
|
11 |
+
|
12 |
+
@pytest.mark.skipif(sys.platform == "win32",
|
13 |
+
reason="Fails with MinGW64 Gfortran (Issue #9673)")
|
14 |
+
def test_common_block(self):
|
15 |
+
self.module.initcb()
|
16 |
+
assert self.module.block.long_bn == np.array(1.0, dtype=np.float64)
|
17 |
+
assert self.module.block.string_bn == np.array("2", dtype="|S1")
|
18 |
+
assert self.module.block.ok == np.array(3, dtype=np.int32)
|
19 |
+
|
20 |
+
|
21 |
+
class TestCommonWithUse(util.F2PyTest):
|
22 |
+
sources = [util.getpath("tests", "src", "common", "gh19161.f90")]
|
23 |
+
|
24 |
+
@pytest.mark.skipif(sys.platform == "win32",
|
25 |
+
reason="Fails with MinGW64 Gfortran (Issue #9673)")
|
26 |
+
def test_common_gh19161(self):
|
27 |
+
assert self.module.data.x == 0
|
.venv/lib/python3.11/site-packages/numpy/f2py/tests/test_compile_function.py
ADDED
@@ -0,0 +1,117 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""See https://github.com/numpy/numpy/pull/11937.
|
2 |
+
|
3 |
+
"""
|
4 |
+
import sys
|
5 |
+
import os
|
6 |
+
import uuid
|
7 |
+
from importlib import import_module
|
8 |
+
import pytest
|
9 |
+
|
10 |
+
import numpy.f2py
|
11 |
+
|
12 |
+
from . import util
|
13 |
+
|
14 |
+
|
15 |
+
def setup_module():
|
16 |
+
if not util.has_c_compiler():
|
17 |
+
pytest.skip("Needs C compiler")
|
18 |
+
if not util.has_f77_compiler():
|
19 |
+
pytest.skip("Needs FORTRAN 77 compiler")
|
20 |
+
|
21 |
+
|
22 |
+
# extra_args can be a list (since gh-11937) or string.
|
23 |
+
# also test absence of extra_args
|
24 |
+
@pytest.mark.parametrize("extra_args",
|
25 |
+
[["--noopt", "--debug"], "--noopt --debug", ""])
|
26 |
+
@pytest.mark.leaks_references(reason="Imported module seems never deleted.")
|
27 |
+
def test_f2py_init_compile(extra_args):
|
28 |
+
# flush through the f2py __init__ compile() function code path as a
|
29 |
+
# crude test for input handling following migration from
|
30 |
+
# exec_command() to subprocess.check_output() in gh-11937
|
31 |
+
|
32 |
+
# the Fortran 77 syntax requires 6 spaces before any commands, but
|
33 |
+
# more space may be added/
|
34 |
+
fsource = """
|
35 |
+
integer function foo()
|
36 |
+
foo = 10 + 5
|
37 |
+
return
|
38 |
+
end
|
39 |
+
"""
|
40 |
+
# use various helper functions in util.py to enable robust build /
|
41 |
+
# compile and reimport cycle in test suite
|
42 |
+
moddir = util.get_module_dir()
|
43 |
+
modname = util.get_temp_module_name()
|
44 |
+
|
45 |
+
cwd = os.getcwd()
|
46 |
+
target = os.path.join(moddir, str(uuid.uuid4()) + ".f")
|
47 |
+
# try running compile() with and without a source_fn provided so
|
48 |
+
# that the code path where a temporary file for writing Fortran
|
49 |
+
# source is created is also explored
|
50 |
+
for source_fn in [target, None]:
|
51 |
+
# mimic the path changing behavior used by build_module() in
|
52 |
+
# util.py, but don't actually use build_module() because it has
|
53 |
+
# its own invocation of subprocess that circumvents the
|
54 |
+
# f2py.compile code block under test
|
55 |
+
with util.switchdir(moddir):
|
56 |
+
ret_val = numpy.f2py.compile(fsource,
|
57 |
+
modulename=modname,
|
58 |
+
extra_args=extra_args,
|
59 |
+
source_fn=source_fn)
|
60 |
+
|
61 |
+
# check for compile success return value
|
62 |
+
assert ret_val == 0
|
63 |
+
|
64 |
+
# we are not currently able to import the Python-Fortran
|
65 |
+
# interface module on Windows / Appveyor, even though we do get
|
66 |
+
# successful compilation on that platform with Python 3.x
|
67 |
+
if sys.platform != "win32":
|
68 |
+
# check for sensible result of Fortran function; that means
|
69 |
+
# we can import the module name in Python and retrieve the
|
70 |
+
# result of the sum operation
|
71 |
+
return_check = import_module(modname)
|
72 |
+
calc_result = return_check.foo()
|
73 |
+
assert calc_result == 15
|
74 |
+
# Removal from sys.modules, is not as such necessary. Even with
|
75 |
+
# removal, the module (dict) stays alive.
|
76 |
+
del sys.modules[modname]
|
77 |
+
|
78 |
+
|
79 |
+
def test_f2py_init_compile_failure():
|
80 |
+
# verify an appropriate integer status value returned by
|
81 |
+
# f2py.compile() when invalid Fortran is provided
|
82 |
+
ret_val = numpy.f2py.compile(b"invalid")
|
83 |
+
assert ret_val == 1
|
84 |
+
|
85 |
+
|
86 |
+
def test_f2py_init_compile_bad_cmd():
|
87 |
+
# verify that usage of invalid command in f2py.compile() returns
|
88 |
+
# status value of 127 for historic consistency with exec_command()
|
89 |
+
# error handling
|
90 |
+
|
91 |
+
# patch the sys Python exe path temporarily to induce an OSError
|
92 |
+
# downstream NOTE: how bad of an idea is this patching?
|
93 |
+
try:
|
94 |
+
temp = sys.executable
|
95 |
+
sys.executable = "does not exist"
|
96 |
+
|
97 |
+
# the OSError should take precedence over invalid Fortran
|
98 |
+
ret_val = numpy.f2py.compile(b"invalid")
|
99 |
+
assert ret_val == 127
|
100 |
+
finally:
|
101 |
+
sys.executable = temp
|
102 |
+
|
103 |
+
|
104 |
+
@pytest.mark.parametrize(
|
105 |
+
"fsource",
|
106 |
+
[
|
107 |
+
"program test_f2py\nend program test_f2py",
|
108 |
+
b"program test_f2py\nend program test_f2py",
|
109 |
+
],
|
110 |
+
)
|
111 |
+
def test_compile_from_strings(tmpdir, fsource):
|
112 |
+
# Make sure we can compile str and bytes gh-12796
|
113 |
+
with util.switchdir(tmpdir):
|
114 |
+
ret_val = numpy.f2py.compile(fsource,
|
115 |
+
modulename="test_compile_from_strings",
|
116 |
+
extension=".f90")
|
117 |
+
assert ret_val == 0
|
.venv/lib/python3.11/site-packages/numpy/f2py/tests/test_crackfortran.py
ADDED
@@ -0,0 +1,350 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import importlib
|
2 |
+
import codecs
|
3 |
+
import time
|
4 |
+
import unicodedata
|
5 |
+
import pytest
|
6 |
+
import numpy as np
|
7 |
+
from numpy.f2py.crackfortran import markinnerspaces, nameargspattern
|
8 |
+
from . import util
|
9 |
+
from numpy.f2py import crackfortran
|
10 |
+
import textwrap
|
11 |
+
import contextlib
|
12 |
+
import io
|
13 |
+
|
14 |
+
|
15 |
+
class TestNoSpace(util.F2PyTest):
|
16 |
+
# issue gh-15035: add handling for endsubroutine, endfunction with no space
|
17 |
+
# between "end" and the block name
|
18 |
+
sources = [util.getpath("tests", "src", "crackfortran", "gh15035.f")]
|
19 |
+
|
20 |
+
def test_module(self):
|
21 |
+
k = np.array([1, 2, 3], dtype=np.float64)
|
22 |
+
w = np.array([1, 2, 3], dtype=np.float64)
|
23 |
+
self.module.subb(k)
|
24 |
+
assert np.allclose(k, w + 1)
|
25 |
+
self.module.subc([w, k])
|
26 |
+
assert np.allclose(k, w + 1)
|
27 |
+
assert self.module.t0("23") == b"2"
|
28 |
+
|
29 |
+
|
30 |
+
class TestPublicPrivate:
|
31 |
+
def test_defaultPrivate(self):
|
32 |
+
fpath = util.getpath("tests", "src", "crackfortran", "privatemod.f90")
|
33 |
+
mod = crackfortran.crackfortran([str(fpath)])
|
34 |
+
assert len(mod) == 1
|
35 |
+
mod = mod[0]
|
36 |
+
assert "private" in mod["vars"]["a"]["attrspec"]
|
37 |
+
assert "public" not in mod["vars"]["a"]["attrspec"]
|
38 |
+
assert "private" in mod["vars"]["b"]["attrspec"]
|
39 |
+
assert "public" not in mod["vars"]["b"]["attrspec"]
|
40 |
+
assert "private" not in mod["vars"]["seta"]["attrspec"]
|
41 |
+
assert "public" in mod["vars"]["seta"]["attrspec"]
|
42 |
+
|
43 |
+
def test_defaultPublic(self, tmp_path):
|
44 |
+
fpath = util.getpath("tests", "src", "crackfortran", "publicmod.f90")
|
45 |
+
mod = crackfortran.crackfortran([str(fpath)])
|
46 |
+
assert len(mod) == 1
|
47 |
+
mod = mod[0]
|
48 |
+
assert "private" in mod["vars"]["a"]["attrspec"]
|
49 |
+
assert "public" not in mod["vars"]["a"]["attrspec"]
|
50 |
+
assert "private" not in mod["vars"]["seta"]["attrspec"]
|
51 |
+
assert "public" in mod["vars"]["seta"]["attrspec"]
|
52 |
+
|
53 |
+
def test_access_type(self, tmp_path):
|
54 |
+
fpath = util.getpath("tests", "src", "crackfortran", "accesstype.f90")
|
55 |
+
mod = crackfortran.crackfortran([str(fpath)])
|
56 |
+
assert len(mod) == 1
|
57 |
+
tt = mod[0]['vars']
|
58 |
+
assert set(tt['a']['attrspec']) == {'private', 'bind(c)'}
|
59 |
+
assert set(tt['b_']['attrspec']) == {'public', 'bind(c)'}
|
60 |
+
assert set(tt['c']['attrspec']) == {'public'}
|
61 |
+
|
62 |
+
def test_nowrap_private_proceedures(self, tmp_path):
|
63 |
+
fpath = util.getpath("tests", "src", "crackfortran", "gh23879.f90")
|
64 |
+
mod = crackfortran.crackfortran([str(fpath)])
|
65 |
+
assert len(mod) == 1
|
66 |
+
pyf = crackfortran.crack2fortran(mod)
|
67 |
+
assert 'bar' not in pyf
|
68 |
+
|
69 |
+
class TestModuleProcedure():
|
70 |
+
def test_moduleOperators(self, tmp_path):
|
71 |
+
fpath = util.getpath("tests", "src", "crackfortran", "operators.f90")
|
72 |
+
mod = crackfortran.crackfortran([str(fpath)])
|
73 |
+
assert len(mod) == 1
|
74 |
+
mod = mod[0]
|
75 |
+
assert "body" in mod and len(mod["body"]) == 9
|
76 |
+
assert mod["body"][1]["name"] == "operator(.item.)"
|
77 |
+
assert "implementedby" in mod["body"][1]
|
78 |
+
assert mod["body"][1]["implementedby"] == \
|
79 |
+
["item_int", "item_real"]
|
80 |
+
assert mod["body"][2]["name"] == "operator(==)"
|
81 |
+
assert "implementedby" in mod["body"][2]
|
82 |
+
assert mod["body"][2]["implementedby"] == ["items_are_equal"]
|
83 |
+
assert mod["body"][3]["name"] == "assignment(=)"
|
84 |
+
assert "implementedby" in mod["body"][3]
|
85 |
+
assert mod["body"][3]["implementedby"] == \
|
86 |
+
["get_int", "get_real"]
|
87 |
+
|
88 |
+
def test_notPublicPrivate(self, tmp_path):
|
89 |
+
fpath = util.getpath("tests", "src", "crackfortran", "pubprivmod.f90")
|
90 |
+
mod = crackfortran.crackfortran([str(fpath)])
|
91 |
+
assert len(mod) == 1
|
92 |
+
mod = mod[0]
|
93 |
+
assert mod['vars']['a']['attrspec'] == ['private', ]
|
94 |
+
assert mod['vars']['b']['attrspec'] == ['public', ]
|
95 |
+
assert mod['vars']['seta']['attrspec'] == ['public', ]
|
96 |
+
|
97 |
+
|
98 |
+
class TestExternal(util.F2PyTest):
|
99 |
+
# issue gh-17859: add external attribute support
|
100 |
+
sources = [util.getpath("tests", "src", "crackfortran", "gh17859.f")]
|
101 |
+
|
102 |
+
def test_external_as_statement(self):
|
103 |
+
def incr(x):
|
104 |
+
return x + 123
|
105 |
+
|
106 |
+
r = self.module.external_as_statement(incr)
|
107 |
+
assert r == 123
|
108 |
+
|
109 |
+
def test_external_as_attribute(self):
|
110 |
+
def incr(x):
|
111 |
+
return x + 123
|
112 |
+
|
113 |
+
r = self.module.external_as_attribute(incr)
|
114 |
+
assert r == 123
|
115 |
+
|
116 |
+
|
117 |
+
class TestCrackFortran(util.F2PyTest):
|
118 |
+
# gh-2848: commented lines between parameters in subroutine parameter lists
|
119 |
+
sources = [util.getpath("tests", "src", "crackfortran", "gh2848.f90")]
|
120 |
+
|
121 |
+
def test_gh2848(self):
|
122 |
+
r = self.module.gh2848(1, 2)
|
123 |
+
assert r == (1, 2)
|
124 |
+
|
125 |
+
|
126 |
+
class TestMarkinnerspaces:
|
127 |
+
# gh-14118: markinnerspaces does not handle multiple quotations
|
128 |
+
|
129 |
+
def test_do_not_touch_normal_spaces(self):
|
130 |
+
test_list = ["a ", " a", "a b c", "'abcdefghij'"]
|
131 |
+
for i in test_list:
|
132 |
+
assert markinnerspaces(i) == i
|
133 |
+
|
134 |
+
def test_one_relevant_space(self):
|
135 |
+
assert markinnerspaces("a 'b c' \\' \\'") == "a 'b@_@c' \\' \\'"
|
136 |
+
assert markinnerspaces(r'a "b c" \" \"') == r'a "b@_@c" \" \"'
|
137 |
+
|
138 |
+
def test_ignore_inner_quotes(self):
|
139 |
+
assert markinnerspaces("a 'b c\" \" d' e") == "a 'b@_@c\"@_@\"@_@d' e"
|
140 |
+
assert markinnerspaces("a \"b c' ' d\" e") == "a \"b@_@c'@_@'@_@d\" e"
|
141 |
+
|
142 |
+
def test_multiple_relevant_spaces(self):
|
143 |
+
assert markinnerspaces("a 'b c' 'd e'") == "a 'b@_@c' 'd@_@e'"
|
144 |
+
assert markinnerspaces(r'a "b c" "d e"') == r'a "b@_@c" "d@_@e"'
|
145 |
+
|
146 |
+
|
147 |
+
class TestDimSpec(util.F2PyTest):
|
148 |
+
"""This test suite tests various expressions that are used as dimension
|
149 |
+
specifications.
|
150 |
+
|
151 |
+
There exists two usage cases where analyzing dimensions
|
152 |
+
specifications are important.
|
153 |
+
|
154 |
+
In the first case, the size of output arrays must be defined based
|
155 |
+
on the inputs to a Fortran function. Because Fortran supports
|
156 |
+
arbitrary bases for indexing, for instance, `arr(lower:upper)`,
|
157 |
+
f2py has to evaluate an expression `upper - lower + 1` where
|
158 |
+
`lower` and `upper` are arbitrary expressions of input parameters.
|
159 |
+
The evaluation is performed in C, so f2py has to translate Fortran
|
160 |
+
expressions to valid C expressions (an alternative approach is
|
161 |
+
that a developer specifies the corresponding C expressions in a
|
162 |
+
.pyf file).
|
163 |
+
|
164 |
+
In the second case, when user provides an input array with a given
|
165 |
+
size but some hidden parameters used in dimensions specifications
|
166 |
+
need to be determined based on the input array size. This is a
|
167 |
+
harder problem because f2py has to solve the inverse problem: find
|
168 |
+
a parameter `p` such that `upper(p) - lower(p) + 1` equals to the
|
169 |
+
size of input array. In the case when this equation cannot be
|
170 |
+
solved (e.g. because the input array size is wrong), raise an
|
171 |
+
error before calling the Fortran function (that otherwise would
|
172 |
+
likely crash Python process when the size of input arrays is
|
173 |
+
wrong). f2py currently supports this case only when the equation
|
174 |
+
is linear with respect to unknown parameter.
|
175 |
+
|
176 |
+
"""
|
177 |
+
|
178 |
+
suffix = ".f90"
|
179 |
+
|
180 |
+
code_template = textwrap.dedent("""
|
181 |
+
function get_arr_size_{count}(a, n) result (length)
|
182 |
+
integer, intent(in) :: n
|
183 |
+
integer, dimension({dimspec}), intent(out) :: a
|
184 |
+
integer length
|
185 |
+
length = size(a)
|
186 |
+
end function
|
187 |
+
|
188 |
+
subroutine get_inv_arr_size_{count}(a, n)
|
189 |
+
integer :: n
|
190 |
+
! the value of n is computed in f2py wrapper
|
191 |
+
!f2py intent(out) n
|
192 |
+
integer, dimension({dimspec}), intent(in) :: a
|
193 |
+
end subroutine
|
194 |
+
""")
|
195 |
+
|
196 |
+
linear_dimspecs = [
|
197 |
+
"n", "2*n", "2:n", "n/2", "5 - n/2", "3*n:20", "n*(n+1):n*(n+5)",
|
198 |
+
"2*n, n"
|
199 |
+
]
|
200 |
+
nonlinear_dimspecs = ["2*n:3*n*n+2*n"]
|
201 |
+
all_dimspecs = linear_dimspecs + nonlinear_dimspecs
|
202 |
+
|
203 |
+
code = ""
|
204 |
+
for count, dimspec in enumerate(all_dimspecs):
|
205 |
+
lst = [(d.split(":")[0] if ":" in d else "1") for d in dimspec.split(',')]
|
206 |
+
code += code_template.format(
|
207 |
+
count=count,
|
208 |
+
dimspec=dimspec,
|
209 |
+
first=", ".join(lst),
|
210 |
+
)
|
211 |
+
|
212 |
+
@pytest.mark.parametrize("dimspec", all_dimspecs)
|
213 |
+
def test_array_size(self, dimspec):
|
214 |
+
|
215 |
+
count = self.all_dimspecs.index(dimspec)
|
216 |
+
get_arr_size = getattr(self.module, f"get_arr_size_{count}")
|
217 |
+
|
218 |
+
for n in [1, 2, 3, 4, 5]:
|
219 |
+
sz, a = get_arr_size(n)
|
220 |
+
assert a.size == sz
|
221 |
+
|
222 |
+
@pytest.mark.parametrize("dimspec", all_dimspecs)
|
223 |
+
def test_inv_array_size(self, dimspec):
|
224 |
+
|
225 |
+
count = self.all_dimspecs.index(dimspec)
|
226 |
+
get_arr_size = getattr(self.module, f"get_arr_size_{count}")
|
227 |
+
get_inv_arr_size = getattr(self.module, f"get_inv_arr_size_{count}")
|
228 |
+
|
229 |
+
for n in [1, 2, 3, 4, 5]:
|
230 |
+
sz, a = get_arr_size(n)
|
231 |
+
if dimspec in self.nonlinear_dimspecs:
|
232 |
+
# one must specify n as input, the call we'll ensure
|
233 |
+
# that a and n are compatible:
|
234 |
+
n1 = get_inv_arr_size(a, n)
|
235 |
+
else:
|
236 |
+
# in case of linear dependence, n can be determined
|
237 |
+
# from the shape of a:
|
238 |
+
n1 = get_inv_arr_size(a)
|
239 |
+
# n1 may be different from n (for instance, when `a` size
|
240 |
+
# is a function of some `n` fraction) but it must produce
|
241 |
+
# the same sized array
|
242 |
+
sz1, _ = get_arr_size(n1)
|
243 |
+
assert sz == sz1, (n, n1, sz, sz1)
|
244 |
+
|
245 |
+
|
246 |
+
class TestModuleDeclaration:
|
247 |
+
def test_dependencies(self, tmp_path):
|
248 |
+
fpath = util.getpath("tests", "src", "crackfortran", "foo_deps.f90")
|
249 |
+
mod = crackfortran.crackfortran([str(fpath)])
|
250 |
+
assert len(mod) == 1
|
251 |
+
assert mod[0]["vars"]["abar"]["="] == "bar('abar')"
|
252 |
+
|
253 |
+
|
254 |
+
class TestEval(util.F2PyTest):
|
255 |
+
def test_eval_scalar(self):
|
256 |
+
eval_scalar = crackfortran._eval_scalar
|
257 |
+
|
258 |
+
assert eval_scalar('123', {}) == '123'
|
259 |
+
assert eval_scalar('12 + 3', {}) == '15'
|
260 |
+
assert eval_scalar('a + b', dict(a=1, b=2)) == '3'
|
261 |
+
assert eval_scalar('"123"', {}) == "'123'"
|
262 |
+
|
263 |
+
|
264 |
+
class TestFortranReader(util.F2PyTest):
|
265 |
+
@pytest.mark.parametrize("encoding",
|
266 |
+
['ascii', 'utf-8', 'utf-16', 'utf-32'])
|
267 |
+
def test_input_encoding(self, tmp_path, encoding):
|
268 |
+
# gh-635
|
269 |
+
f_path = tmp_path / f"input_with_{encoding}_encoding.f90"
|
270 |
+
with f_path.open('w', encoding=encoding) as ff:
|
271 |
+
ff.write("""
|
272 |
+
subroutine foo()
|
273 |
+
end subroutine foo
|
274 |
+
""")
|
275 |
+
mod = crackfortran.crackfortran([str(f_path)])
|
276 |
+
assert mod[0]['name'] == 'foo'
|
277 |
+
|
278 |
+
|
279 |
+
class TestUnicodeComment(util.F2PyTest):
|
280 |
+
sources = [util.getpath("tests", "src", "crackfortran", "unicode_comment.f90")]
|
281 |
+
|
282 |
+
@pytest.mark.skipif(
|
283 |
+
(importlib.util.find_spec("charset_normalizer") is None),
|
284 |
+
reason="test requires charset_normalizer which is not installed",
|
285 |
+
)
|
286 |
+
def test_encoding_comment(self):
|
287 |
+
self.module.foo(3)
|
288 |
+
|
289 |
+
|
290 |
+
class TestNameArgsPatternBacktracking:
|
291 |
+
@pytest.mark.parametrize(
|
292 |
+
['adversary'],
|
293 |
+
[
|
294 |
+
('@)@bind@(@',),
|
295 |
+
('@)@bind @(@',),
|
296 |
+
('@)@bind foo bar baz@(@',)
|
297 |
+
]
|
298 |
+
)
|
299 |
+
def test_nameargspattern_backtracking(self, adversary):
|
300 |
+
'''address ReDOS vulnerability:
|
301 |
+
https://github.com/numpy/numpy/issues/23338'''
|
302 |
+
trials_per_batch = 12
|
303 |
+
batches_per_regex = 4
|
304 |
+
start_reps, end_reps = 15, 25
|
305 |
+
for ii in range(start_reps, end_reps):
|
306 |
+
repeated_adversary = adversary * ii
|
307 |
+
# test times in small batches.
|
308 |
+
# this gives us more chances to catch a bad regex
|
309 |
+
# while still catching it before too long if it is bad
|
310 |
+
for _ in range(batches_per_regex):
|
311 |
+
times = []
|
312 |
+
for _ in range(trials_per_batch):
|
313 |
+
t0 = time.perf_counter()
|
314 |
+
mtch = nameargspattern.search(repeated_adversary)
|
315 |
+
times.append(time.perf_counter() - t0)
|
316 |
+
# our pattern should be much faster than 0.2s per search
|
317 |
+
# it's unlikely that a bad regex will pass even on fast CPUs
|
318 |
+
assert np.median(times) < 0.2
|
319 |
+
assert not mtch
|
320 |
+
# if the adversary is capped with @)@, it becomes acceptable
|
321 |
+
# according to the old version of the regex.
|
322 |
+
# that should still be true.
|
323 |
+
good_version_of_adversary = repeated_adversary + '@)@'
|
324 |
+
assert nameargspattern.search(good_version_of_adversary)
|
325 |
+
|
326 |
+
|
327 |
+
class TestFunctionReturn(util.F2PyTest):
|
328 |
+
sources = [util.getpath("tests", "src", "crackfortran", "gh23598.f90")]
|
329 |
+
|
330 |
+
def test_function_rettype(self):
|
331 |
+
# gh-23598
|
332 |
+
assert self.module.intproduct(3, 4) == 12
|
333 |
+
|
334 |
+
|
335 |
+
class TestFortranGroupCounters(util.F2PyTest):
|
336 |
+
def test_end_if_comment(self):
|
337 |
+
# gh-23533
|
338 |
+
fpath = util.getpath("tests", "src", "crackfortran", "gh23533.f")
|
339 |
+
try:
|
340 |
+
crackfortran.crackfortran([str(fpath)])
|
341 |
+
except Exception as exc:
|
342 |
+
assert False, f"'crackfortran.crackfortran' raised an exception {exc}"
|
343 |
+
|
344 |
+
|
345 |
+
class TestF77CommonBlockReader():
|
346 |
+
def test_gh22648(self, tmp_path):
|
347 |
+
fpath = util.getpath("tests", "src", "crackfortran", "gh22648.pyf")
|
348 |
+
with contextlib.redirect_stdout(io.StringIO()) as stdout_f2py:
|
349 |
+
mod = crackfortran.crackfortran([str(fpath)])
|
350 |
+
assert "Mismatch" not in stdout_f2py.getvalue()
|
.venv/lib/python3.11/site-packages/numpy/f2py/tests/test_data.py
ADDED
@@ -0,0 +1,70 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
import pytest
|
3 |
+
import numpy as np
|
4 |
+
|
5 |
+
from . import util
|
6 |
+
from numpy.f2py.crackfortran import crackfortran
|
7 |
+
|
8 |
+
|
9 |
+
class TestData(util.F2PyTest):
|
10 |
+
sources = [util.getpath("tests", "src", "crackfortran", "data_stmts.f90")]
|
11 |
+
|
12 |
+
# For gh-23276
|
13 |
+
def test_data_stmts(self):
|
14 |
+
assert self.module.cmplxdat.i == 2
|
15 |
+
assert self.module.cmplxdat.j == 3
|
16 |
+
assert self.module.cmplxdat.x == 1.5
|
17 |
+
assert self.module.cmplxdat.y == 2.0
|
18 |
+
assert self.module.cmplxdat.pi == 3.1415926535897932384626433832795028841971693993751058209749445923078164062
|
19 |
+
assert self.module.cmplxdat.medium_ref_index == np.array(1.+0.j)
|
20 |
+
assert np.all(self.module.cmplxdat.z == np.array([3.5, 7.0]))
|
21 |
+
assert np.all(self.module.cmplxdat.my_array == np.array([ 1.+2.j, -3.+4.j]))
|
22 |
+
assert np.all(self.module.cmplxdat.my_real_array == np.array([ 1., 2., 3.]))
|
23 |
+
assert np.all(self.module.cmplxdat.ref_index_one == np.array([13.0 + 21.0j]))
|
24 |
+
assert np.all(self.module.cmplxdat.ref_index_two == np.array([-30.0 + 43.0j]))
|
25 |
+
|
26 |
+
def test_crackedlines(self):
|
27 |
+
mod = crackfortran(self.sources)
|
28 |
+
assert mod[0]['vars']['x']['='] == '1.5'
|
29 |
+
assert mod[0]['vars']['y']['='] == '2.0'
|
30 |
+
assert mod[0]['vars']['pi']['='] == '3.1415926535897932384626433832795028841971693993751058209749445923078164062d0'
|
31 |
+
assert mod[0]['vars']['my_real_array']['='] == '(/1.0d0, 2.0d0, 3.0d0/)'
|
32 |
+
assert mod[0]['vars']['ref_index_one']['='] == '(13.0d0, 21.0d0)'
|
33 |
+
assert mod[0]['vars']['ref_index_two']['='] == '(-30.0d0, 43.0d0)'
|
34 |
+
assert mod[0]['vars']['my_array']['='] == '(/(1.0d0, 2.0d0), (-3.0d0, 4.0d0)/)'
|
35 |
+
assert mod[0]['vars']['z']['='] == '(/3.5, 7.0/)'
|
36 |
+
|
37 |
+
class TestDataF77(util.F2PyTest):
|
38 |
+
sources = [util.getpath("tests", "src", "crackfortran", "data_common.f")]
|
39 |
+
|
40 |
+
# For gh-23276
|
41 |
+
def test_data_stmts(self):
|
42 |
+
assert self.module.mycom.mydata == 0
|
43 |
+
|
44 |
+
def test_crackedlines(self):
|
45 |
+
mod = crackfortran(str(self.sources[0]))
|
46 |
+
print(mod[0]['vars'])
|
47 |
+
assert mod[0]['vars']['mydata']['='] == '0'
|
48 |
+
|
49 |
+
|
50 |
+
class TestDataMultiplierF77(util.F2PyTest):
|
51 |
+
sources = [util.getpath("tests", "src", "crackfortran", "data_multiplier.f")]
|
52 |
+
|
53 |
+
# For gh-23276
|
54 |
+
def test_data_stmts(self):
|
55 |
+
assert self.module.mycom.ivar1 == 3
|
56 |
+
assert self.module.mycom.ivar2 == 3
|
57 |
+
assert self.module.mycom.ivar3 == 2
|
58 |
+
assert self.module.mycom.ivar4 == 2
|
59 |
+
assert self.module.mycom.evar5 == 0
|
60 |
+
|
61 |
+
|
62 |
+
class TestDataWithCommentsF77(util.F2PyTest):
|
63 |
+
sources = [util.getpath("tests", "src", "crackfortran", "data_with_comments.f")]
|
64 |
+
|
65 |
+
# For gh-23276
|
66 |
+
def test_data_stmts(self):
|
67 |
+
assert len(self.module.mycom.mytab) == 3
|
68 |
+
assert self.module.mycom.mytab[0] == 0
|
69 |
+
assert self.module.mycom.mytab[1] == 4
|
70 |
+
assert self.module.mycom.mytab[2] == 0
|
.venv/lib/python3.11/site-packages/numpy/f2py/tests/test_docs.py
ADDED
@@ -0,0 +1,55 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
import pytest
|
3 |
+
import numpy as np
|
4 |
+
from numpy.testing import assert_array_equal, assert_equal
|
5 |
+
from . import util
|
6 |
+
|
7 |
+
|
8 |
+
def get_docdir():
|
9 |
+
# assuming that documentation tests are run from a source
|
10 |
+
# directory
|
11 |
+
return os.path.abspath(os.path.join(
|
12 |
+
os.path.dirname(__file__),
|
13 |
+
'..', '..', '..',
|
14 |
+
'doc', 'source', 'f2py', 'code'))
|
15 |
+
|
16 |
+
|
17 |
+
pytestmark = pytest.mark.skipif(
|
18 |
+
not os.path.isdir(get_docdir()),
|
19 |
+
reason=('Could not find f2py documentation sources'
|
20 |
+
f' ({get_docdir()} does not exists)'))
|
21 |
+
|
22 |
+
|
23 |
+
def _path(*a):
|
24 |
+
return os.path.join(*((get_docdir(),) + a))
|
25 |
+
|
26 |
+
|
27 |
+
class TestDocAdvanced(util.F2PyTest):
|
28 |
+
# options = ['--debug-capi', '--build-dir', '/tmp/build-f2py']
|
29 |
+
sources = [_path('asterisk1.f90'), _path('asterisk2.f90'),
|
30 |
+
_path('ftype.f')]
|
31 |
+
|
32 |
+
def test_asterisk1(self):
|
33 |
+
foo = getattr(self.module, 'foo1')
|
34 |
+
assert_equal(foo(), b'123456789A12')
|
35 |
+
|
36 |
+
def test_asterisk2(self):
|
37 |
+
foo = getattr(self.module, 'foo2')
|
38 |
+
assert_equal(foo(2), b'12')
|
39 |
+
assert_equal(foo(12), b'123456789A12')
|
40 |
+
assert_equal(foo(24), b'123456789A123456789B')
|
41 |
+
|
42 |
+
def test_ftype(self):
|
43 |
+
ftype = self.module
|
44 |
+
ftype.foo()
|
45 |
+
assert_equal(ftype.data.a, 0)
|
46 |
+
ftype.data.a = 3
|
47 |
+
ftype.data.x = [1, 2, 3]
|
48 |
+
assert_equal(ftype.data.a, 3)
|
49 |
+
assert_array_equal(ftype.data.x,
|
50 |
+
np.array([1, 2, 3], dtype=np.float32))
|
51 |
+
ftype.data.x[1] = 45
|
52 |
+
assert_array_equal(ftype.data.x,
|
53 |
+
np.array([1, 45, 3], dtype=np.float32))
|
54 |
+
|
55 |
+
# TODO: implement test methods for other example Fortran codes
|
.venv/lib/python3.11/site-packages/numpy/f2py/tests/test_f2cmap.py
ADDED
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from . import util
|
2 |
+
import numpy as np
|
3 |
+
|
4 |
+
class TestF2Cmap(util.F2PyTest):
|
5 |
+
sources = [
|
6 |
+
util.getpath("tests", "src", "f2cmap", "isoFortranEnvMap.f90"),
|
7 |
+
util.getpath("tests", "src", "f2cmap", ".f2py_f2cmap")
|
8 |
+
]
|
9 |
+
|
10 |
+
# gh-15095
|
11 |
+
def test_long_long_map(self):
|
12 |
+
inp = np.ones(3)
|
13 |
+
out = self.module.func1(inp)
|
14 |
+
exp_out = 3
|
15 |
+
assert out == exp_out
|