koichi12 commited on
Commit
70ec6c4
·
verified ·
1 Parent(s): adc48e1

Add files using upload-large-folder tool

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .gitattributes +3 -0
  2. .venv/lib/python3.11/site-packages/numpy/f2py/__init__.py +194 -0
  3. .venv/lib/python3.11/site-packages/numpy/f2py/__pycache__/__main__.cpython-311.pyc +0 -0
  4. .venv/lib/python3.11/site-packages/numpy/f2py/__pycache__/__version__.cpython-311.pyc +0 -0
  5. .venv/lib/python3.11/site-packages/numpy/f2py/__pycache__/_src_pyf.cpython-311.pyc +0 -0
  6. .venv/lib/python3.11/site-packages/numpy/f2py/__pycache__/cb_rules.cpython-311.pyc +0 -0
  7. .venv/lib/python3.11/site-packages/numpy/f2py/__pycache__/cfuncs.cpython-311.pyc +0 -0
  8. .venv/lib/python3.11/site-packages/numpy/f2py/__pycache__/common_rules.cpython-311.pyc +0 -0
  9. .venv/lib/python3.11/site-packages/numpy/f2py/__pycache__/diagnose.cpython-311.pyc +0 -0
  10. .venv/lib/python3.11/site-packages/numpy/f2py/__pycache__/f2py2e.cpython-311.pyc +0 -0
  11. .venv/lib/python3.11/site-packages/numpy/f2py/__pycache__/f90mod_rules.cpython-311.pyc +0 -0
  12. .venv/lib/python3.11/site-packages/numpy/f2py/__pycache__/func2subr.cpython-311.pyc +0 -0
  13. .venv/lib/python3.11/site-packages/numpy/f2py/_backends/__init__.py +9 -0
  14. .venv/lib/python3.11/site-packages/numpy/f2py/_backends/__pycache__/__init__.cpython-311.pyc +0 -0
  15. .venv/lib/python3.11/site-packages/numpy/f2py/_backends/__pycache__/_backend.cpython-311.pyc +0 -0
  16. .venv/lib/python3.11/site-packages/numpy/f2py/_backends/__pycache__/_distutils.cpython-311.pyc +0 -0
  17. .venv/lib/python3.11/site-packages/numpy/f2py/_backends/__pycache__/_meson.cpython-311.pyc +0 -0
  18. .venv/lib/python3.11/site-packages/numpy/f2py/_backends/_backend.py +46 -0
  19. .venv/lib/python3.11/site-packages/numpy/f2py/_backends/_distutils.py +75 -0
  20. .venv/lib/python3.11/site-packages/numpy/f2py/_backends/_meson.py +205 -0
  21. .venv/lib/python3.11/site-packages/numpy/f2py/_backends/meson.build.template +54 -0
  22. .venv/lib/python3.11/site-packages/numpy/f2py/_isocbind.py +62 -0
  23. .venv/lib/python3.11/site-packages/numpy/f2py/_src_pyf.py +239 -0
  24. .venv/lib/python3.11/site-packages/numpy/f2py/capi_maps.py +819 -0
  25. .venv/lib/python3.11/site-packages/numpy/f2py/common_rules.py +146 -0
  26. .venv/lib/python3.11/site-packages/numpy/f2py/crackfortran.py +0 -0
  27. .venv/lib/python3.11/site-packages/numpy/f2py/diagnose.py +154 -0
  28. .venv/lib/python3.11/site-packages/numpy/f2py/f2py2e.py +768 -0
  29. .venv/lib/python3.11/site-packages/numpy/f2py/func2subr.py +323 -0
  30. .venv/lib/python3.11/site-packages/numpy/f2py/rules.py +1568 -0
  31. .venv/lib/python3.11/site-packages/numpy/f2py/setup.py +74 -0
  32. .venv/lib/python3.11/site-packages/numpy/f2py/tests/__init__.py +0 -0
  33. .venv/lib/python3.11/site-packages/numpy/f2py/tests/__pycache__/test_abstract_interface.cpython-311.pyc +0 -0
  34. .venv/lib/python3.11/site-packages/numpy/f2py/tests/__pycache__/test_common.cpython-311.pyc +0 -0
  35. .venv/lib/python3.11/site-packages/numpy/f2py/tests/__pycache__/test_data.cpython-311.pyc +0 -0
  36. .venv/lib/python3.11/site-packages/numpy/f2py/tests/__pycache__/test_f2cmap.cpython-311.pyc +0 -0
  37. .venv/lib/python3.11/site-packages/numpy/f2py/tests/__pycache__/test_regression.cpython-311.pyc +0 -0
  38. .venv/lib/python3.11/site-packages/numpy/f2py/tests/__pycache__/test_semicolon_split.cpython-311.pyc +0 -0
  39. .venv/lib/python3.11/site-packages/numpy/f2py/tests/test_abstract_interface.py +25 -0
  40. .venv/lib/python3.11/site-packages/numpy/f2py/tests/test_array_from_pyobj.py +686 -0
  41. .venv/lib/python3.11/site-packages/numpy/f2py/tests/test_assumed_shape.py +49 -0
  42. .venv/lib/python3.11/site-packages/numpy/f2py/tests/test_block_docstring.py +17 -0
  43. .venv/lib/python3.11/site-packages/numpy/f2py/tests/test_callback.py +243 -0
  44. .venv/lib/python3.11/site-packages/numpy/f2py/tests/test_character.py +636 -0
  45. .venv/lib/python3.11/site-packages/numpy/f2py/tests/test_common.py +27 -0
  46. .venv/lib/python3.11/site-packages/numpy/f2py/tests/test_compile_function.py +117 -0
  47. .venv/lib/python3.11/site-packages/numpy/f2py/tests/test_crackfortran.py +350 -0
  48. .venv/lib/python3.11/site-packages/numpy/f2py/tests/test_data.py +70 -0
  49. .venv/lib/python3.11/site-packages/numpy/f2py/tests/test_docs.py +55 -0
  50. .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