增加环绕侦察场景适配

This commit is contained in:
2026-01-08 15:44:38 +08:00
parent 3eba1f962b
commit 10c5bb5a8a
5441 changed files with 40219 additions and 379695 deletions

View File

@@ -1,5 +1,4 @@
from .f2py2e import main as main
from .f2py2e import run_main
from .f2py2e import main as main, run_main
__all__ = ["get_include", "run_main"]

View File

@@ -50,6 +50,7 @@ class MesonTemplate:
self.pipeline = [
self.initialize_template,
self.sources_substitution,
self.objects_substitution,
self.deps_substitution,
self.include_substitution,
self.libraries_substitution,
@@ -79,6 +80,11 @@ class MesonTemplate:
[f"{self.indent}'''{source}'''," for source in self.sources]
)
def objects_substitution(self) -> None:
self.substitutions["obj_list"] = ",\n".join(
[f"{self.indent}'''{obj}'''," for obj in self.objects]
)
def deps_substitution(self) -> None:
self.substitutions["dep_list"] = f",\n{self.indent}".join(
[f"{self.indent}dependency('{dep}')," for dep in self.deps]
@@ -186,6 +192,7 @@ class MesonBackend(Backend):
def compile(self) -> None:
self.sources = _prepare_sources(self.modulename, self.sources, self.build_dir)
_prepare_objects(self.modulename, self.extra_objects, self.build_dir)
self.write_meson_build(self.build_dir)
self.run_meson(self.build_dir)
self._move_exec_to_root(self.build_dir)
@@ -216,6 +223,12 @@ def _prepare_sources(mname, sources, bdir):
]
return extended_sources
def _prepare_objects(mname, objects, bdir):
Path(bdir).mkdir(parents=True, exist_ok=True)
# Copy objects
for obj in objects:
if Path(obj).exists() and Path(obj).is_file():
shutil.copy(obj, bdir)
def _get_flags(fc_flags):
flag_values = []

View File

@@ -1,8 +1,6 @@
from collections.abc import Callable
from pathlib import Path
from typing import Final
from typing import Literal as L
from typing import Final, Literal as L
from typing_extensions import override
from ._backend import Backend
@@ -42,6 +40,7 @@ class MesonTemplate:
#
def initialize_template(self) -> None: ...
def sources_substitution(self) -> None: ...
def objects_substitution(self) -> None: ...
def deps_substitution(self) -> None: ...
def libraries_substitution(self) -> None: ...
def include_substitution(self) -> None: ...

View File

@@ -43,6 +43,9 @@ ${source_list},
include_directories: [
inc_np,
${inc_list}
],
objects: [
${obj_list}
],
dependencies : [
py_dep,

View File

@@ -1,9 +1,8 @@
import re
from _typeshed import StrOrBytesPath
from collections.abc import Mapping
from typing import Final
from _typeshed import StrOrBytesPath
routine_start_re: Final[re.Pattern[str]] = ...
routine_end_re: Final[re.Pattern[str]] = ...
function_start_re: Final[re.Pattern[str]] = ...

View File

@@ -1,9 +1,7 @@
from _typeshed import FileDescriptorOrPath
from collections.abc import Callable, Mapping
from pprint import pprint as show
from typing import Any, Final, Never, TypeAlias, TypeVar, overload
from typing import Literal as L
from _typeshed import FileDescriptorOrPath
from typing import Any, Final, Literal as L, Never, TypeAlias, TypeVar, overload
from .cfuncs import errmess

View File

@@ -1,9 +1,17 @@
import re
from collections.abc import Callable, Iterable, Mapping
from typing import IO, Any, Concatenate, Final, Never, ParamSpec, TypeAlias, overload
from typing import Literal as L
from _typeshed import StrOrBytesPath, StrPath
from collections.abc import Callable, Iterable, Mapping
from typing import (
IO,
Any,
Concatenate,
Final,
Literal as L,
Never,
ParamSpec,
TypeAlias,
overload,
)
from .__version__ import version
from .auxfuncs import isintent_dict as isintent_dict

View File

@@ -378,6 +378,8 @@ def callcrackfortran(files, options):
mod['gil_used'] = 'Py_MOD_GIL_USED'
else:
mod['gil_used'] = 'Py_MOD_GIL_NOT_USED'
# gh-26718 Reset global
crackfortran.f77modulename = ''
return postlist

View File

@@ -3,12 +3,10 @@ import pprint
from collections.abc import Hashable, Iterable, Mapping, MutableMapping, Sequence
from types import ModuleType
from typing import Any, Final, NotRequired, TypedDict, type_check_only
from typing_extensions import TypeVar, override
from .__version__ import version
from .auxfuncs import _Bool
from .auxfuncs import outmess as outmess
from .auxfuncs import _Bool, outmess as outmess
###

View File

@@ -77,7 +77,7 @@ def var2fixfortran(vars, a, fa=None, f90mode=None):
def useiso_c_binding(rout):
useisoc = False
for key, value in rout['vars'].items():
for value in rout['vars'].values():
kind_value = value.get('kindselector', {}).get('kind')
if kind_value in isoc_kindmap:
return True

View File

@@ -286,7 +286,7 @@ PyMODINIT_FUNC PyInit_#modulename#(void) {
#initcommonhooks#
#interface_usercode#
#if Py_GIL_DISABLED
#ifdef Py_GIL_DISABLED
// signal whether this module supports running with the GIL disabled
PyUnstable_Module_SetGIL(m , #gil_used#);
#endif

View File

@@ -1,7 +1,5 @@
from collections.abc import Callable, Iterable, Mapping
from typing import Any, Final, TypeAlias
from typing import Literal as L
from typing import Any, Final, Literal as L, TypeAlias
from typing_extensions import TypeVar
from .__version__ import version

View File

@@ -47,7 +47,7 @@ F2PySwapThreadLocalCallbackPtr(char *key, void *ptr)
"failed");
}
value = PyDict_GetItemString(local_dict, key);
value = PyDict_GetItemString(local_dict, key); // noqa: borrowed-ref OK
if (value != NULL) {
prev = PyLong_AsVoidPtr(value);
if (PyErr_Occurred()) {
@@ -87,7 +87,7 @@ F2PyGetThreadLocalCallbackPtr(char *key)
"F2PyGetThreadLocalCallbackPtr: PyThreadState_GetDict failed");
}
value = PyDict_GetItemString(local_dict, key);
value = PyDict_GetItemString(local_dict, key); // noqa: borrowed-ref OK
if (value != NULL) {
prev = PyLong_AsVoidPtr(value);
if (PyErr_Occurred()) {
@@ -365,7 +365,7 @@ fortran_getattr(PyFortranObject *fp, char *name)
if (fp->dict != NULL) {
// python 3.13 added PyDict_GetItemRef
#if PY_VERSION_HEX < 0x030D0000
PyObject *v = _PyDict_GetItemStringWithError(fp->dict, name);
PyObject *v = _PyDict_GetItemStringWithError(fp->dict, name); // noqa: borrowed-ref OK
if (v == NULL && PyErr_Occurred()) {
return NULL;
}
@@ -822,7 +822,7 @@ get_elsize(PyObject *obj) {
} else if (PyUnicode_Check(obj)) {
return PyUnicode_GET_LENGTH(obj);
} else if (PySequence_Check(obj)) {
PyObject* fast = PySequence_Fast(obj, "f2py:fortranobject.c:get_elsize");
PyObject* fast = PySequence_Fast(obj, "f2py:fortranobject.c:get_elsize"); // noqa: borrowed-ref OK
if (fast != NULL) {
Py_ssize_t i, n = PySequence_Fast_GET_SIZE(fast);
int sz, elsize = 0;

View File

@@ -155,14 +155,14 @@ def ewarn(message):
class Expr:
"""Represents a Fortran expression as a op-data pair.
"""Represents a Fortran expression as an op-data pair.
Expr instances are hashable and sortable.
"""
@staticmethod
def parse(s, language=Language.C):
"""Parse a Fortran expression to a Expr.
"""Parse a Fortran expression to an Expr.
"""
return fromstring(s, language=language)
@@ -1236,6 +1236,8 @@ def replace_parenthesis(s):
i = mn_i
j = s.find(right, i)
if j == -1:
raise ValueError(f'Mismatch of {left + right} parenthesis in {s!r}')
while s.count(left, i + 1, j) != s.count(right, i + 1, j):
j = s.find(right, j + 1)
@@ -1478,7 +1480,7 @@ class _FromStringWorker:
if isinstance(items, Expr):
return items
if paren in ['ROUNDDIV', 'SQUARE']:
# Expression is a array constructor
# Expression is an array constructor
if isinstance(items, Expr):
items = (items,)
return as_array(items)

View File

@@ -1,8 +1,6 @@
from collections.abc import Callable, Mapping
from enum import Enum
from typing import Any, Generic, ParamSpec, Self, TypeAlias, overload
from typing import Literal as L
from typing import Any, Generic, Literal as L, ParamSpec, Self, TypeAlias, overload
from typing_extensions import TypeVar
__all__ = ["Expr"]

View File

@@ -223,7 +223,7 @@ PyMODINIT_FUNC PyInit_test_array_from_pyobj_ext(void) {
on_exit(f2py_report_on_exit,(void*)"array_from_pyobj.wrap.call");
#endif
#if Py_GIL_DISABLED
#ifdef Py_GIL_DISABLED
// signal whether this module supports running with the GIL disabled
PyUnstable_Module_SetGIL(m, Py_MOD_GIL_NOT_USED);
#endif

View File

@@ -147,9 +147,9 @@ _cast_dict['CHARACTER'] = ['CHARACTER']
# and several tests fail as the alignment flag can be randomly true or false
# when numpy gains an aligned allocator the tests could be enabled again
#
# Furthermore, on macOS ARM64, LONGDOUBLE is an alias for DOUBLE.
# Furthermore, on macOS ARM64 and AIX, LONGDOUBLE is an alias for DOUBLE.
if ((np.intp().dtype.itemsize != 4 or np.clongdouble().dtype.alignment <= 8)
and sys.platform != "win32"
and sys.platform not in ["win32", "aix"]
and (platform.system(), platform.processor()) != ("Darwin", "arm")):
_type_names.extend(["LONGDOUBLE", "CDOUBLE", "CLONGDOUBLE"])
_cast_dict["LONGDOUBLE"] = _cast_dict["LONG"] + [

View File

@@ -60,5 +60,7 @@ class TestDocAdvanced(util.F2PyTest):
ftype.data.x[1] = 45
assert_array_equal(ftype.data.x,
np.array([1, 45, 3], dtype=np.float32))
# gh-26718 Cleanup for repeated test runs
ftype.data.a = 0
# TODO: implement test methods for other example Fortran codes

View File

@@ -673,6 +673,25 @@ def test_inclheader(capfd, hello_world_f90, monkeypatch):
assert "#include <stdbool.h>" in ocmr
assert "#include <stdio.h>" in ocmr
@pytest.mark.skipif((platform.system() != 'Linux'), reason='Compiler required')
def test_cli_obj(capfd, hello_world_f90, monkeypatch):
"""Ensures that the extra object can be specified when using meson backend
"""
ipath = Path(hello_world_f90)
mname = "blah"
odir = "tttmp"
obj = "extra.o"
monkeypatch.setattr(sys, "argv",
f'f2py --backend meson --build-dir {odir} -m {mname} -c {obj} {ipath}'.split())
with util.switchdir(ipath.parent):
Path(obj).touch()
compiler_check_f2pycli()
with Path(f"{odir}/meson.build").open() as mesonbuild:
mbld = mesonbuild.read()
assert "objects:" in mbld
assert f"'''{obj}'''" in mbld
def test_inclpath():
"""Add to the include directories

View File

@@ -5,13 +5,12 @@ import pytest
from numpy.f2py.crackfortran import (
_selected_int_kind_func as selected_int_kind,
)
from numpy.f2py.crackfortran import (
_selected_real_kind_func as selected_real_kind,
)
from . import util
IS_PPC_OR_AIX = platform.machine().lower().startswith("ppc") or platform.system() == 'AIX'
class TestKind(util.F2PyTest):
sources = [util.getpath("tests", "src", "kind", "foo.f90")]
@@ -39,7 +38,7 @@ class TestKind(util.F2PyTest):
i
), f"selectedrealkind({i}): expected {selected_real_kind(i)!r} but got {selectedrealkind(i)!r}"
@pytest.mark.xfail(platform.machine().lower().startswith("ppc"),
@pytest.mark.xfail(IS_PPC_OR_AIX,
reason="Some PowerPC may not support full IEEE 754 precision")
def test_quad_precision(self):
"""

View File

@@ -158,7 +158,7 @@ def test_gh26623():
@pytest.mark.slow
@pytest.mark.skipif(platform.system() not in ['Linux', 'Darwin'], reason='Unsupported on this platform for now')
@pytest.mark.skipif(platform.system() == "Windows", reason='Unsupported on this platform for now')
def test_gh25784():
# Compile dubious file using passed flags
try:
@@ -167,7 +167,7 @@ def test_gh25784():
options=[
# Meson will collect and dedup these to pass to fortran_args:
"--f77flags='-ffixed-form -O2'",
"--f90flags=\"-ffixed-form -Og\"",
"--f90flags=\"-ffixed-form -g\"",
],
module_name="Blah",
)

View File

@@ -29,8 +29,8 @@ class TestReturnInteger(util.F2PyTest):
pytest.raises(IndexError, t, [])
pytest.raises(IndexError, t, ())
pytest.raises(Exception, t, t)
pytest.raises(Exception, t, {})
pytest.raises(TypeError, t, t)
pytest.raises(TypeError, t, {})
if tname in ["t8", "s8"]:
pytest.raises(OverflowError, t, 100000000000000000000000)

View File

@@ -39,8 +39,8 @@ class TestReturnReal(util.F2PyTest):
pytest.raises(IndexError, t, [])
pytest.raises(IndexError, t, ())
pytest.raises(Exception, t, t)
pytest.raises(Exception, t, {})
pytest.raises(TypeError, t, t)
pytest.raises(TypeError, t, {})
try:
r = t(10**400)

View File

@@ -493,3 +493,8 @@ class TestSymbolic(util.F2PyTest):
assert (y(x) + x).polynomial_atoms() == {y(x), x}
assert (y(x) * x[y]).polynomial_atoms() == {y(x), x[y]}
assert (y(x)**x).polynomial_atoms() == {y(x)}
def test_unmatched_parenthesis_gh30268(self):
#gh - 30268
with pytest.raises(ValueError, match=r"Mismatch of \(\) parenthesis"):
Expr.parse("DATA (A, I=1, N", language=Language.Fortran)