about summary refs log tree commit diff
path: root/.venv/lib/python3.12/site-packages/numpy/f2py/tests
diff options
context:
space:
mode:
Diffstat (limited to '.venv/lib/python3.12/site-packages/numpy/f2py/tests')
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/__init__.py0
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/abstract_interface/foo.f9034
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/abstract_interface/gh18403_mod.f906
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/array_from_pyobj/wrapmodule.c230
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/assumed_shape/.f2py_f2cmap1
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/assumed_shape/foo_free.f9034
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/assumed_shape/foo_mod.f9041
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/assumed_shape/foo_use.f9019
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/assumed_shape/precision.f904
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/block_docstring/foo.f6
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/callback/foo.f62
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/callback/gh17797.f907
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/callback/gh18335.f9017
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/callback/gh25211.f10
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/callback/gh25211.pyf18
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/cli/gh_22819.pyf6
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/cli/hi77.f3
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/cli/hiworld.f903
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/common/block.f11
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/common/gh19161.f9010
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/crackfortran/accesstype.f9013
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/crackfortran/data_common.f8
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/crackfortran/data_multiplier.f5
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/crackfortran/data_stmts.f9020
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/crackfortran/data_with_comments.f8
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/crackfortran/foo_deps.f906
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/crackfortran/gh15035.f16
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/crackfortran/gh17859.f12
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/crackfortran/gh22648.pyf7
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/crackfortran/gh23533.f5
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/crackfortran/gh23598.f904
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/crackfortran/gh23598Warn.f9011
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/crackfortran/gh23879.f9020
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/crackfortran/gh2848.f9013
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/crackfortran/operators.f9049
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/crackfortran/privatemod.f9011
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/crackfortran/publicmod.f9010
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/crackfortran/pubprivmod.f9010
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/crackfortran/unicode_comment.f904
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/f2cmap/.f2py_f2cmap1
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/f2cmap/isoFortranEnvMap.f909
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/isocintrin/isoCtests.f9034
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/kind/foo.f9020
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/mixed/foo.f5
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/mixed/foo_fixed.f908
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/mixed/foo_free.f908
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/module_data/mod.modbin0 -> 412 bytes
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/module_data/module_data_docstring.f9012
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/negative_bounds/issue_20853.f907
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/parameter/constant_both.f9057
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/parameter/constant_compound.f9015
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/parameter/constant_integer.f9022
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/parameter/constant_non_compound.f9023
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/parameter/constant_real.f9023
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/quoted_character/foo.f14
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/regression/gh25337/data.f908
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/regression/gh25337/use_data.f906
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/regression/inout.f909
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/return_character/foo77.f45
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/return_character/foo90.f9048
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/return_complex/foo77.f45
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/return_complex/foo90.f9048
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/return_integer/foo77.f56
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/return_integer/foo90.f9059
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/return_logical/foo77.f56
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/return_logical/foo90.f9059
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/return_real/foo77.f45
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/return_real/foo90.f9048
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/size/foo.f9044
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/string/char.f9029
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/string/fixed_string.f9034
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/string/gh24008.f8
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/string/gh24662.f907
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/string/gh25286.f9014
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/string/gh25286.pyf12
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/string/gh25286_bc.pyf12
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/string/scalar_string.f909
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/string/string.f12
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/value_attrspec/gh21665.f909
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_abstract_interface.py25
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_array_from_pyobj.py686
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_assumed_shape.py49
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_block_docstring.py17
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_callback.py243
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_character.py636
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_common.py27
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_compile_function.py117
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_crackfortran.py350
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_data.py70
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_docs.py55
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_f2cmap.py15
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_f2py2e.py896
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_isoc.py52
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_kind.py47
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_mixed.py33
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_module_doc.py27
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_parameter.py112
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_pyf_src.py44
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_quoted_character.py16
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_regression.py77
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_return_character.py45
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_return_complex.py65
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_return_integer.py53
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_return_logical.py64
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_return_real.py107
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_semicolon_split.py74
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_size.py45
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_string.py100
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_symbolic.py494
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_value_attrspec.py14
-rw-r--r--.venv/lib/python3.12/site-packages/numpy/f2py/tests/util.py440
111 files changed, 6829 insertions, 0 deletions
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/__init__.py b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/__init__.py
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/abstract_interface/foo.f90 b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/abstract_interface/foo.f90
new file mode 100644
index 00000000..76d16aae
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/abstract_interface/foo.f90
@@ -0,0 +1,34 @@
+module ops_module
+
+  abstract interface
+    subroutine op(x, y, z)
+      integer, intent(in) :: x, y
+      integer, intent(out) :: z
+    end subroutine
+  end interface
+
+contains
+
+  subroutine foo(x, y, r1, r2)
+    integer, intent(in) :: x, y
+    integer, intent(out) :: r1, r2
+    procedure (op) add1, add2
+    procedure (op), pointer::p
+    p=>add1
+    call p(x, y, r1)
+    p=>add2
+    call p(x, y, r2)
+  end subroutine
+end module
+
+subroutine add1(x, y, z)
+  integer, intent(in) :: x, y
+  integer, intent(out) :: z
+  z = x + y
+end subroutine
+
+subroutine add2(x, y, z)
+  integer, intent(in) :: x, y
+  integer, intent(out) :: z
+  z = x + 2 * y
+end subroutine
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/abstract_interface/gh18403_mod.f90 b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/abstract_interface/gh18403_mod.f90
new file mode 100644
index 00000000..36791e46
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/abstract_interface/gh18403_mod.f90
@@ -0,0 +1,6 @@
+module test
+  abstract interface
+    subroutine foo()
+    end subroutine
+  end interface
+end module test
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/array_from_pyobj/wrapmodule.c b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/array_from_pyobj/wrapmodule.c
new file mode 100644
index 00000000..9a8b4a75
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/array_from_pyobj/wrapmodule.c
@@ -0,0 +1,230 @@
+/*
+ * This file was auto-generated with f2py (version:2_1330) and hand edited by
+ * Pearu for testing purposes.  Do not edit this file unless you know what you
+ * are doing!!!
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*********************** See f2py2e/cfuncs.py: includes ***********************/
+
+#define PY_SSIZE_T_CLEAN
+#include <Python.h>
+#include "fortranobject.h"
+#include <math.h>
+
+static PyObject *wrap_error;
+static PyObject *wrap_module;
+
+/************************************ call ************************************/
+static char doc_f2py_rout_wrap_call[] = "\
+Function signature:\n\
+  arr = call(type_num,dims,intent,obj)\n\
+Required arguments:\n"
+"  type_num : input int\n"
+"  dims : input int-sequence\n"
+"  intent : input int\n"
+"  obj : input python object\n"
+"Return objects:\n"
+"  arr : array";
+static PyObject *f2py_rout_wrap_call(PyObject *capi_self,
+                                     PyObject *capi_args) {
+  PyObject * volatile capi_buildvalue = NULL;
+  int type_num = 0;
+  int elsize = 0;
+  npy_intp *dims = NULL;
+  PyObject *dims_capi = Py_None;
+  int rank = 0;
+  int intent = 0;
+  PyArrayObject *capi_arr_tmp = NULL;
+  PyObject *arr_capi = Py_None;
+  int i;
+
+  if (!PyArg_ParseTuple(capi_args,"iiOiO|:wrap.call",\
+                        &type_num,&elsize,&dims_capi,&intent,&arr_capi))
+    return NULL;
+  rank = PySequence_Length(dims_capi);
+  dims = malloc(rank*sizeof(npy_intp));
+  for (i=0;i<rank;++i) {
+    PyObject *tmp;
+    tmp = PySequence_GetItem(dims_capi, i);
+    if (tmp == NULL) {
+        goto fail;
+    }
+    dims[i] = (npy_intp)PyLong_AsLong(tmp);
+    Py_DECREF(tmp);
+    if (dims[i] == -1 && PyErr_Occurred()) {
+        goto fail;
+    }
+  }
+  capi_arr_tmp = ndarray_from_pyobj(type_num,elsize,dims,rank,intent|F2PY_INTENT_OUT,arr_capi,"wrap.call failed");
+  if (capi_arr_tmp == NULL) {
+    free(dims);
+    return NULL;
+  }
+  capi_buildvalue = Py_BuildValue("N",capi_arr_tmp);
+  free(dims);
+  return capi_buildvalue;
+
+fail:
+  free(dims);
+  return NULL;
+}
+
+static char doc_f2py_rout_wrap_attrs[] = "\
+Function signature:\n\
+  arr = array_attrs(arr)\n\
+Required arguments:\n"
+"  arr : input array object\n"
+"Return objects:\n"
+"  data : data address in hex\n"
+"  nd : int\n"
+"  dimensions : tuple\n"
+"  strides : tuple\n"
+"  base : python object\n"
+"  (kind,type,type_num,elsize,alignment) : 4-tuple\n"
+"  flags : int\n"
+"  itemsize : int\n"
+;
+static PyObject *f2py_rout_wrap_attrs(PyObject *capi_self,
+                                      PyObject *capi_args) {
+  PyObject *arr_capi = Py_None;
+  PyArrayObject *arr = NULL;
+  PyObject *dimensions = NULL;
+  PyObject *strides = NULL;
+  char s[100];
+  int i;
+  memset(s,0,100);
+  if (!PyArg_ParseTuple(capi_args,"O!|:wrap.attrs",
+                        &PyArray_Type,&arr_capi))
+    return NULL;
+  arr = (PyArrayObject *)arr_capi;
+  sprintf(s,"%p",PyArray_DATA(arr));
+  dimensions = PyTuple_New(PyArray_NDIM(arr));
+  strides = PyTuple_New(PyArray_NDIM(arr));
+  for (i=0;i<PyArray_NDIM(arr);++i) {
+    PyTuple_SetItem(dimensions,i,PyLong_FromLong(PyArray_DIM(arr,i)));
+    PyTuple_SetItem(strides,i,PyLong_FromLong(PyArray_STRIDE(arr,i)));
+  }
+  return Py_BuildValue("siNNO(cciii)ii",s,PyArray_NDIM(arr),
+                       dimensions,strides,
+                       (PyArray_BASE(arr)==NULL?Py_None:PyArray_BASE(arr)),
+                       PyArray_DESCR(arr)->kind,
+                       PyArray_DESCR(arr)->type,
+                       PyArray_TYPE(arr),
+                       PyArray_ITEMSIZE(arr),
+                       PyArray_DESCR(arr)->alignment,
+                       PyArray_FLAGS(arr),
+                       PyArray_ITEMSIZE(arr));
+}
+
+static PyMethodDef f2py_module_methods[] = {
+
+  {"call",f2py_rout_wrap_call,METH_VARARGS,doc_f2py_rout_wrap_call},
+  {"array_attrs",f2py_rout_wrap_attrs,METH_VARARGS,doc_f2py_rout_wrap_attrs},
+  {NULL,NULL}
+};
+
+static struct PyModuleDef moduledef = {
+    PyModuleDef_HEAD_INIT,
+    "test_array_from_pyobj_ext",
+    NULL,
+    -1,
+    f2py_module_methods,
+    NULL,
+    NULL,
+    NULL,
+    NULL
+};
+
+PyMODINIT_FUNC PyInit_test_array_from_pyobj_ext(void) {
+  PyObject *m,*d, *s;
+  m = wrap_module = PyModule_Create(&moduledef);
+  Py_SET_TYPE(&PyFortran_Type, &PyType_Type);
+  import_array();
+  if (PyErr_Occurred())
+    Py_FatalError("can't initialize module wrap (failed to import numpy)");
+  d = PyModule_GetDict(m);
+  s = PyUnicode_FromString("This module 'wrap' is auto-generated with f2py (version:2_1330).\nFunctions:\n"
+                           "  arr = call(type_num,dims,intent,obj)\n"
+                           ".");
+  PyDict_SetItemString(d, "__doc__", s);
+  wrap_error = PyErr_NewException ("wrap.error", NULL, NULL);
+  Py_DECREF(s);
+
+#define ADDCONST(NAME, CONST)              \
+    s = PyLong_FromLong(CONST);             \
+    PyDict_SetItemString(d, NAME, s);      \
+    Py_DECREF(s)
+
+  ADDCONST("F2PY_INTENT_IN", F2PY_INTENT_IN);
+  ADDCONST("F2PY_INTENT_INOUT", F2PY_INTENT_INOUT);
+  ADDCONST("F2PY_INTENT_OUT", F2PY_INTENT_OUT);
+  ADDCONST("F2PY_INTENT_HIDE", F2PY_INTENT_HIDE);
+  ADDCONST("F2PY_INTENT_CACHE", F2PY_INTENT_CACHE);
+  ADDCONST("F2PY_INTENT_COPY", F2PY_INTENT_COPY);
+  ADDCONST("F2PY_INTENT_C", F2PY_INTENT_C);
+  ADDCONST("F2PY_OPTIONAL", F2PY_OPTIONAL);
+  ADDCONST("F2PY_INTENT_INPLACE", F2PY_INTENT_INPLACE);
+  ADDCONST("NPY_BOOL", NPY_BOOL);
+  ADDCONST("NPY_BYTE", NPY_BYTE);
+  ADDCONST("NPY_UBYTE", NPY_UBYTE);
+  ADDCONST("NPY_SHORT", NPY_SHORT);
+  ADDCONST("NPY_USHORT", NPY_USHORT);
+  ADDCONST("NPY_INT", NPY_INT);
+  ADDCONST("NPY_UINT", NPY_UINT);
+  ADDCONST("NPY_INTP", NPY_INTP);
+  ADDCONST("NPY_UINTP", NPY_UINTP);
+  ADDCONST("NPY_LONG", NPY_LONG);
+  ADDCONST("NPY_ULONG", NPY_ULONG);
+  ADDCONST("NPY_LONGLONG", NPY_LONGLONG);
+  ADDCONST("NPY_ULONGLONG", NPY_ULONGLONG);
+  ADDCONST("NPY_FLOAT", NPY_FLOAT);
+  ADDCONST("NPY_DOUBLE", NPY_DOUBLE);
+  ADDCONST("NPY_LONGDOUBLE", NPY_LONGDOUBLE);
+  ADDCONST("NPY_CFLOAT", NPY_CFLOAT);
+  ADDCONST("NPY_CDOUBLE", NPY_CDOUBLE);
+  ADDCONST("NPY_CLONGDOUBLE", NPY_CLONGDOUBLE);
+  ADDCONST("NPY_OBJECT", NPY_OBJECT);
+  ADDCONST("NPY_STRING", NPY_STRING);
+  ADDCONST("NPY_UNICODE", NPY_UNICODE);
+  ADDCONST("NPY_VOID", NPY_VOID);
+  ADDCONST("NPY_NTYPES", NPY_NTYPES);
+  ADDCONST("NPY_NOTYPE", NPY_NOTYPE);
+  ADDCONST("NPY_USERDEF", NPY_USERDEF);
+
+  ADDCONST("CONTIGUOUS", NPY_ARRAY_C_CONTIGUOUS);
+  ADDCONST("FORTRAN", NPY_ARRAY_F_CONTIGUOUS);
+  ADDCONST("OWNDATA", NPY_ARRAY_OWNDATA);
+  ADDCONST("FORCECAST", NPY_ARRAY_FORCECAST);
+  ADDCONST("ENSURECOPY", NPY_ARRAY_ENSURECOPY);
+  ADDCONST("ENSUREARRAY", NPY_ARRAY_ENSUREARRAY);
+  ADDCONST("ALIGNED", NPY_ARRAY_ALIGNED);
+  ADDCONST("WRITEABLE", NPY_ARRAY_WRITEABLE);
+  ADDCONST("WRITEBACKIFCOPY", NPY_ARRAY_WRITEBACKIFCOPY);
+
+  ADDCONST("BEHAVED", NPY_ARRAY_BEHAVED);
+  ADDCONST("BEHAVED_NS", NPY_ARRAY_BEHAVED_NS);
+  ADDCONST("CARRAY", NPY_ARRAY_CARRAY);
+  ADDCONST("FARRAY", NPY_ARRAY_FARRAY);
+  ADDCONST("CARRAY_RO", NPY_ARRAY_CARRAY_RO);
+  ADDCONST("FARRAY_RO", NPY_ARRAY_FARRAY_RO);
+  ADDCONST("DEFAULT", NPY_ARRAY_DEFAULT);
+  ADDCONST("UPDATE_ALL", NPY_ARRAY_UPDATE_ALL);
+
+#undef ADDCONST(
+
+  if (PyErr_Occurred())
+    Py_FatalError("can't initialize module wrap");
+
+#ifdef F2PY_REPORT_ATEXIT
+  on_exit(f2py_report_on_exit,(void*)"array_from_pyobj.wrap.call");
+#endif
+
+  return m;
+}
+#ifdef __cplusplus
+}
+#endif
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/assumed_shape/.f2py_f2cmap b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/assumed_shape/.f2py_f2cmap
new file mode 100644
index 00000000..2665f89b
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/assumed_shape/.f2py_f2cmap
@@ -0,0 +1 @@
+dict(real=dict(rk="double"))
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/assumed_shape/foo_free.f90 b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/assumed_shape/foo_free.f90
new file mode 100644
index 00000000..b301710f
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/assumed_shape/foo_free.f90
@@ -0,0 +1,34 @@
+
+subroutine sum(x, res)
+  implicit none
+  real, intent(in) :: x(:)
+  real, intent(out) :: res
+
+  integer :: i
+
+  !print *, "sum: size(x) = ", size(x)
+
+  res = 0.0
+
+  do i = 1, size(x)
+    res = res + x(i)
+  enddo
+
+end subroutine sum
+
+function fsum(x) result (res)
+  implicit none
+  real, intent(in) :: x(:)
+  real :: res
+
+  integer :: i
+
+  !print *, "fsum: size(x) = ", size(x)
+
+  res = 0.0
+
+  do i = 1, size(x)
+    res = res + x(i)
+  enddo
+
+end function fsum
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/assumed_shape/foo_mod.f90 b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/assumed_shape/foo_mod.f90
new file mode 100644
index 00000000..cbe6317e
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/assumed_shape/foo_mod.f90
@@ -0,0 +1,41 @@
+
+module mod
+
+contains
+
+subroutine sum(x, res)
+  implicit none
+  real, intent(in) :: x(:)
+  real, intent(out) :: res
+
+  integer :: i
+
+  !print *, "sum: size(x) = ", size(x)
+
+  res = 0.0
+
+  do i = 1, size(x)
+    res = res + x(i)
+  enddo
+
+end subroutine sum
+
+function fsum(x) result (res)
+  implicit none
+  real, intent(in) :: x(:)
+  real :: res
+
+  integer :: i
+
+  !print *, "fsum: size(x) = ", size(x)
+
+  res = 0.0
+
+  do i = 1, size(x)
+    res = res + x(i)
+  enddo
+
+end function fsum
+
+
+end module mod
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/assumed_shape/foo_use.f90 b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/assumed_shape/foo_use.f90
new file mode 100644
index 00000000..337465ac
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/assumed_shape/foo_use.f90
@@ -0,0 +1,19 @@
+subroutine sum_with_use(x, res)
+  use precision
+
+  implicit none
+
+  real(kind=rk), intent(in) :: x(:)
+  real(kind=rk), intent(out) :: res
+
+  integer :: i
+
+  !print *, "size(x) = ", size(x)
+
+  res = 0.0
+
+  do i = 1, size(x)
+    res = res + x(i)
+  enddo
+
+ end subroutine
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/assumed_shape/precision.f90 b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/assumed_shape/precision.f90
new file mode 100644
index 00000000..ed6c70cb
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/assumed_shape/precision.f90
@@ -0,0 +1,4 @@
+module precision
+  integer, parameter :: rk = selected_real_kind(8)
+  integer, parameter :: ik = selected_real_kind(4)
+end module
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/block_docstring/foo.f b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/block_docstring/foo.f
new file mode 100644
index 00000000..c8315f12
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/block_docstring/foo.f
@@ -0,0 +1,6 @@
+      SUBROUTINE FOO()
+      INTEGER BAR(2, 3)
+
+      COMMON  /BLOCK/ BAR
+      RETURN
+      END
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/callback/foo.f b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/callback/foo.f
new file mode 100644
index 00000000..ba397bb3
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/callback/foo.f
@@ -0,0 +1,62 @@
+       subroutine t(fun,a)
+       integer a
+cf2py  intent(out) a
+       external fun
+       call fun(a)
+       end
+
+       subroutine func(a)
+cf2py  intent(in,out) a
+       integer a
+       a = a + 11
+       end
+
+       subroutine func0(a)
+cf2py  intent(out) a
+       integer a
+       a = 11
+       end
+
+       subroutine t2(a)
+cf2py  intent(callback) fun
+       integer a
+cf2py  intent(out) a
+       external fun
+       call fun(a)
+       end
+
+       subroutine string_callback(callback, a)
+       external callback
+       double precision callback
+       double precision a
+       character*1 r
+cf2py  intent(out) a
+       r = 'r'
+       a = callback(r)
+       end
+
+       subroutine string_callback_array(callback, cu, lencu, a)
+       external callback
+       integer callback
+       integer lencu
+       character*8 cu(lencu)
+       integer a
+cf2py  intent(out) a
+
+       a = callback(cu, lencu)
+       end
+
+       subroutine hidden_callback(a, r)
+       external global_f
+cf2py  intent(callback, hide) global_f
+       integer a, r, global_f
+cf2py  intent(out) r
+       r = global_f(a)
+       end
+
+       subroutine hidden_callback2(a, r)
+       external global_f
+       integer a, r, global_f
+cf2py  intent(out) r
+       r = global_f(a)
+       end
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/callback/gh17797.f90 b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/callback/gh17797.f90
new file mode 100644
index 00000000..49853afd
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/callback/gh17797.f90
@@ -0,0 +1,7 @@
+function gh17797(f, y) result(r)
+  external f
+  integer(8) :: r, f
+  integer(8), dimension(:) :: y
+  r = f(0)
+  r = r + sum(y)
+end function gh17797
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/callback/gh18335.f90 b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/callback/gh18335.f90
new file mode 100644
index 00000000..92b6d754
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/callback/gh18335.f90
@@ -0,0 +1,17 @@
+        ! When gh18335_workaround is defined as an extension,
+        ! the issue cannot be reproduced.
+        !subroutine gh18335_workaround(f, y)
+        !  implicit none
+        !  external f
+        !  integer(kind=1) :: y(1)
+        !  call f(y)
+        !end subroutine gh18335_workaround
+
+        function gh18335(f) result (r)
+          implicit none
+          external f
+          integer(kind=1) :: y(1), r
+          y(1) = 123
+          call f(y)
+          r = y(1)
+        end function gh18335
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/callback/gh25211.f b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/callback/gh25211.f
new file mode 100644
index 00000000..ba727a10
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/callback/gh25211.f
@@ -0,0 +1,10 @@
+      SUBROUTINE FOO(FUN,R)
+      EXTERNAL FUN
+      INTEGER I
+      REAL*8 R, FUN
+Cf2py intent(out) r
+      R = 0D0
+      DO I=-5,5
+         R = R + FUN(I)
+      ENDDO
+      END
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/callback/gh25211.pyf b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/callback/gh25211.pyf
new file mode 100644
index 00000000..f1201115
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/callback/gh25211.pyf
@@ -0,0 +1,18 @@
+python module __user__routines
+    interface
+        function fun(i) result (r)
+            integer :: i
+            real*8 :: r
+        end function fun
+    end interface
+end python module __user__routines
+
+python module callback2
+    interface
+        subroutine foo(f,r)
+            use __user__routines, f=>fun
+            external f
+            real*8 intent(out) :: r
+        end subroutine foo
+    end interface
+end python module callback2
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/cli/gh_22819.pyf b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/cli/gh_22819.pyf
new file mode 100644
index 00000000..8eb5bb10
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/cli/gh_22819.pyf
@@ -0,0 +1,6 @@
+python module test_22819
+    interface
+        subroutine hello()
+        end subroutine hello
+    end interface
+end python module test_22819
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/cli/hi77.f b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/cli/hi77.f
new file mode 100644
index 00000000..8b916ebe
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/cli/hi77.f
@@ -0,0 +1,3 @@
+      SUBROUTINE HI
+        PRINT*, "HELLO WORLD"
+      END SUBROUTINE
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/cli/hiworld.f90 b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/cli/hiworld.f90
new file mode 100644
index 00000000..981f8775
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/cli/hiworld.f90
@@ -0,0 +1,3 @@
+function hi()
+  print*, "Hello World"
+end function
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/common/block.f b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/common/block.f
new file mode 100644
index 00000000..7ea7968f
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/common/block.f
@@ -0,0 +1,11 @@
+      SUBROUTINE INITCB
+      DOUBLE PRECISION LONG
+      CHARACTER        STRING
+      INTEGER          OK
+    
+      COMMON  /BLOCK/ LONG, STRING, OK
+      LONG = 1.0
+      STRING = '2'
+      OK = 3
+      RETURN
+      END
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/common/gh19161.f90 b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/common/gh19161.f90
new file mode 100644
index 00000000..a2f40735
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/common/gh19161.f90
@@ -0,0 +1,10 @@
+module typedefmod
+  use iso_fortran_env, only: real32
+end module typedefmod
+
+module data
+  use typedefmod, only: real32
+  implicit none
+  real(kind=real32) :: x
+  common/test/x
+end module data
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/crackfortran/accesstype.f90 b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/crackfortran/accesstype.f90
new file mode 100644
index 00000000..e2cbd445
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/crackfortran/accesstype.f90
@@ -0,0 +1,13 @@
+module foo
+  public
+  type, private, bind(c) :: a
+     integer :: i
+  end type a
+  type, bind(c) :: b_
+     integer :: j
+  end type b_
+  public :: b_
+  type :: c
+     integer :: k
+  end type c
+end module foo
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/crackfortran/data_common.f b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/crackfortran/data_common.f
new file mode 100644
index 00000000..5ffd865c
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/crackfortran/data_common.f
@@ -0,0 +1,8 @@
+        BLOCK DATA PARAM_INI
+        COMMON /MYCOM/ MYDATA
+            DATA MYDATA /0/
+        END
+        SUBROUTINE SUB1
+        COMMON /MYCOM/ MYDATA
+        MYDATA = MYDATA + 1
+        END
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/crackfortran/data_multiplier.f b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/crackfortran/data_multiplier.f
new file mode 100644
index 00000000..19ff8a83
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/crackfortran/data_multiplier.f
@@ -0,0 +1,5 @@
+      BLOCK DATA MYBLK
+      IMPLICIT DOUBLE PRECISION (A-H,O-Z)
+      COMMON /MYCOM/ IVAR1, IVAR2, IVAR3, IVAR4, EVAR5
+            DATA IVAR1, IVAR2, IVAR3, IVAR4, EVAR5 /2*3,2*2,0.0D0/
+      END
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/crackfortran/data_stmts.f90 b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/crackfortran/data_stmts.f90
new file mode 100644
index 00000000..576c5e48
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/crackfortran/data_stmts.f90
@@ -0,0 +1,20 @@
+! gh-23276
+module cmplxdat
+  implicit none
+  integer :: i, j
+  real :: x, y
+  real, dimension(2) :: z
+  real(kind=8) :: pi
+  complex(kind=8), target :: medium_ref_index
+  complex(kind=8), target :: ref_index_one, ref_index_two
+  complex(kind=8), dimension(2) :: my_array
+  real(kind=8), dimension(3) :: my_real_array = (/1.0d0, 2.0d0, 3.0d0/)
+
+  data i, j / 2, 3 /
+  data x, y / 1.5, 2.0 /
+  data z / 3.5, 7.0 /
+  data medium_ref_index / (1.d0, 0.d0) /
+  data ref_index_one, ref_index_two / (13.0d0, 21.0d0), (-30.0d0, 43.0d0) /
+  data my_array / (1.0d0, 2.0d0), (-3.0d0, 4.0d0) /
+  data pi / 3.1415926535897932384626433832795028841971693993751058209749445923078164062d0 /
+end module cmplxdat
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/crackfortran/data_with_comments.f b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/crackfortran/data_with_comments.f
new file mode 100644
index 00000000..4128f004
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/crackfortran/data_with_comments.f
@@ -0,0 +1,8 @@
+      BLOCK DATA PARAM_INI
+      COMMON /MYCOM/ MYTAB
+      INTEGER  MYTAB(3)
+      DATA MYTAB/
+     *   0, ! 1 and more commenty stuff
+     *   4, ! 2
+     *   0 /
+      END
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/crackfortran/foo_deps.f90 b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/crackfortran/foo_deps.f90
new file mode 100644
index 00000000..e327b25c
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/crackfortran/foo_deps.f90
@@ -0,0 +1,6 @@
+module foo
+  type bar
+    character(len = 4) :: text
+  end type bar
+  type(bar), parameter :: abar = bar('abar')
+end module foo
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/crackfortran/gh15035.f b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/crackfortran/gh15035.f
new file mode 100644
index 00000000..1bb2e674
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/crackfortran/gh15035.f
@@ -0,0 +1,16 @@
+        subroutine subb(k)
+          real(8), intent(inout) :: k(:)
+          k=k+1
+        endsubroutine
+
+        subroutine subc(w,k)
+          real(8), intent(in) :: w(:)
+          real(8), intent(out) :: k(size(w))
+          k=w+1
+        endsubroutine
+
+        function t0(value)
+          character value
+          character t0
+          t0 = value
+        endfunction
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/crackfortran/gh17859.f b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/crackfortran/gh17859.f
new file mode 100644
index 00000000..99595384
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/crackfortran/gh17859.f
@@ -0,0 +1,12 @@
+        integer(8) function external_as_statement(fcn)
+        implicit none
+        external fcn
+        integer(8) :: fcn
+        external_as_statement = fcn(0)
+        end
+
+        integer(8) function external_as_attribute(fcn)
+        implicit none
+        integer(8), external :: fcn
+        external_as_attribute = fcn(0)
+        end
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/crackfortran/gh22648.pyf b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/crackfortran/gh22648.pyf
new file mode 100644
index 00000000..b3454f18
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/crackfortran/gh22648.pyf
@@ -0,0 +1,7 @@
+python module iri16py ! in
+    interface  ! in :iri16py
+        block data  ! in :iri16py:iridreg_modified.for
+           COMMON /fircom/ eden,tabhe,tabla,tabmo,tabza,tabfl
+       end block data 
+    end interface 
+end python module iri16py
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/crackfortran/gh23533.f b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/crackfortran/gh23533.f
new file mode 100644
index 00000000..db522afa
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/crackfortran/gh23533.f
@@ -0,0 +1,5 @@
+      SUBROUTINE EXAMPLE( )
+        IF( .TRUE. ) THEN
+            CALL DO_SOMETHING()
+        END IF ! ** .TRUE. **
+      END
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/crackfortran/gh23598.f90 b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/crackfortran/gh23598.f90
new file mode 100644
index 00000000..e0dffb5e
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/crackfortran/gh23598.f90
@@ -0,0 +1,4 @@
+integer function intproduct(a, b) result(res)
+  integer, intent(in) :: a, b
+  res = a*b
+end function
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/crackfortran/gh23598Warn.f90 b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/crackfortran/gh23598Warn.f90
new file mode 100644
index 00000000..3b44efc5
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/crackfortran/gh23598Warn.f90
@@ -0,0 +1,11 @@
+module test_bug
+    implicit none
+    private
+    public :: intproduct
+
+contains
+    integer function intproduct(a, b) result(res)
+    integer, intent(in) :: a, b
+    res = a*b
+    end function
+end module
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/crackfortran/gh23879.f90 b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/crackfortran/gh23879.f90
new file mode 100644
index 00000000..fac262d5
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/crackfortran/gh23879.f90
@@ -0,0 +1,20 @@
+module gh23879
+    implicit none
+    private
+    public :: foo
+
+ contains
+
+    subroutine foo(a, b)
+       integer, intent(in) :: a
+       integer, intent(out) :: b
+       b = a
+       call bar(b)
+    end subroutine
+
+    subroutine bar(x)
+        integer, intent(inout) :: x
+        x = 2*x
+     end subroutine
+
+ end module gh23879
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/crackfortran/gh2848.f90 b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/crackfortran/gh2848.f90
new file mode 100644
index 00000000..31ea9327
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/crackfortran/gh2848.f90
@@ -0,0 +1,13 @@
+      subroutine gh2848( &
+        ! first 2 parameters
+        par1, par2,&
+        ! last 2 parameters
+        par3, par4)
+
+        integer, intent(in)  :: par1, par2
+        integer, intent(out) :: par3, par4
+
+        par3 = par1
+        par4 = par2
+
+      end subroutine gh2848
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/crackfortran/operators.f90 b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/crackfortran/operators.f90
new file mode 100644
index 00000000..1d060a3d
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/crackfortran/operators.f90
@@ -0,0 +1,49 @@
+module foo
+  type bar
+     character(len = 32) :: item
+  end type bar
+  interface operator(.item.)
+     module procedure item_int, item_real
+  end interface operator(.item.)
+  interface operator(==)
+     module procedure items_are_equal
+  end interface operator(==)
+  interface assignment(=)
+     module procedure get_int, get_real
+  end interface assignment(=)
+contains
+  function item_int(val) result(elem)
+    integer, intent(in) :: val
+    type(bar) :: elem
+
+    write(elem%item, "(I32)") val
+  end function item_int
+
+  function item_real(val) result(elem)
+    real, intent(in) :: val
+    type(bar) :: elem
+
+    write(elem%item, "(1PE32.12)") val
+  end function item_real
+
+  function items_are_equal(val1, val2) result(equal)
+    type(bar), intent(in) :: val1, val2
+    logical :: equal
+
+    equal = (val1%item == val2%item)
+  end function items_are_equal
+
+  subroutine get_real(rval, item)
+    real, intent(out) :: rval
+    type(bar), intent(in) :: item
+
+    read(item%item, *) rval
+  end subroutine get_real
+
+  subroutine get_int(rval, item)
+    integer, intent(out) :: rval
+    type(bar), intent(in) :: item
+
+    read(item%item, *) rval
+  end subroutine get_int
+end module foo
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/crackfortran/privatemod.f90 b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/crackfortran/privatemod.f90
new file mode 100644
index 00000000..2674c214
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/crackfortran/privatemod.f90
@@ -0,0 +1,11 @@
+module foo
+  private
+  integer :: a
+  public :: setA
+  integer :: b
+contains
+  subroutine setA(v)
+    integer, intent(in) :: v
+    a = v
+  end subroutine setA
+end module foo
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/crackfortran/publicmod.f90 b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/crackfortran/publicmod.f90
new file mode 100644
index 00000000..1db76e3f
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/crackfortran/publicmod.f90
@@ -0,0 +1,10 @@
+module foo
+  public
+  integer, private :: a
+  public :: setA
+contains
+  subroutine setA(v)
+    integer, intent(in) :: v
+    a = v
+  end subroutine setA
+end module foo
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/crackfortran/pubprivmod.f90 b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/crackfortran/pubprivmod.f90
new file mode 100644
index 00000000..46bef7cb
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/crackfortran/pubprivmod.f90
@@ -0,0 +1,10 @@
+module foo
+  public
+  integer, private :: a
+  integer :: b
+contains
+  subroutine setA(v)
+    integer, intent(in) :: v
+    a = v
+  end subroutine setA
+end module foo
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/crackfortran/unicode_comment.f90 b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/crackfortran/unicode_comment.f90
new file mode 100644
index 00000000..13515ce9
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/crackfortran/unicode_comment.f90
@@ -0,0 +1,4 @@
+subroutine foo(x)
+  real(8), intent(in) :: x
+  ! Écrit à l'écran la valeur de x
+end subroutine
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/f2cmap/.f2py_f2cmap b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/f2cmap/.f2py_f2cmap
new file mode 100644
index 00000000..a4425f88
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/f2cmap/.f2py_f2cmap
@@ -0,0 +1 @@
+dict(real=dict(real32='float', real64='double'), integer=dict(int64='long_long'))
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/f2cmap/isoFortranEnvMap.f90 b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/f2cmap/isoFortranEnvMap.f90
new file mode 100644
index 00000000..1e1dc1d4
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/f2cmap/isoFortranEnvMap.f90
@@ -0,0 +1,9 @@
+      subroutine func1(n, x, res)
+        use, intrinsic :: iso_fortran_env, only: int64, real64
+        implicit none
+        integer(int64), intent(in) :: n
+        real(real64), intent(in) :: x(n)
+        real(real64), intent(out) :: res
+!f2py   intent(hide) :: n
+        res = sum(x)
+      end
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/isocintrin/isoCtests.f90 b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/isocintrin/isoCtests.f90
new file mode 100644
index 00000000..765f7c1c
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/isocintrin/isoCtests.f90
@@ -0,0 +1,34 @@
+  module coddity
+    use iso_c_binding, only: c_double, c_int, c_int64_t
+    implicit none
+    contains
+      subroutine c_add(a, b, c) bind(c, name="c_add")
+        real(c_double), intent(in) :: a, b
+        real(c_double), intent(out) :: c
+        c = a + b
+      end subroutine c_add
+      ! gh-9693
+      function wat(x, y) result(z) bind(c)
+          integer(c_int), intent(in) :: x, y
+          integer(c_int) :: z
+
+          z = x + 7
+      end function wat
+      ! gh-25207
+      subroutine c_add_int64(a, b, c) bind(c)
+        integer(c_int64_t), intent(in) :: a, b
+        integer(c_int64_t), intent(out) :: c
+        c = a + b
+      end subroutine c_add_int64
+      ! gh-25207
+      subroutine add_arr(A, B, C)
+         integer(c_int64_t), intent(in) :: A(3)
+         integer(c_int64_t), intent(in) :: B(3)
+         integer(c_int64_t), intent(out) :: C(3)
+         integer :: j
+
+         do j = 1, 3
+            C(j) = A(j)+B(j)
+         end do
+      end subroutine
+  end module coddity
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/kind/foo.f90 b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/kind/foo.f90
new file mode 100644
index 00000000..d3d15cfb
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/kind/foo.f90
@@ -0,0 +1,20 @@
+
+
+subroutine selectedrealkind(p, r, res)
+  implicit none
+  
+  integer, intent(in) :: p, r
+  !f2py integer :: r=0
+  integer, intent(out) :: res
+  res = selected_real_kind(p, r)
+
+end subroutine
+
+subroutine selectedintkind(p, res)
+  implicit none
+
+  integer, intent(in) :: p
+  integer, intent(out) :: res
+  res = selected_int_kind(p)
+
+end subroutine
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/mixed/foo.f b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/mixed/foo.f
new file mode 100644
index 00000000..c3474257
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/mixed/foo.f
@@ -0,0 +1,5 @@
+      subroutine bar11(a)
+cf2py intent(out) a
+      integer a
+      a = 11
+      end
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/mixed/foo_fixed.f90 b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/mixed/foo_fixed.f90
new file mode 100644
index 00000000..7543a6ac
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/mixed/foo_fixed.f90
@@ -0,0 +1,8 @@
+      module foo_fixed
+      contains
+        subroutine bar12(a)
+!f2py intent(out) a
+          integer a
+          a = 12
+        end subroutine bar12
+      end module foo_fixed
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/mixed/foo_free.f90 b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/mixed/foo_free.f90
new file mode 100644
index 00000000..c1b641f1
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/mixed/foo_free.f90
@@ -0,0 +1,8 @@
+module foo_free
+contains
+  subroutine bar13(a)
+    !f2py intent(out) a
+    integer a
+    a = 13
+  end subroutine bar13
+end module foo_free
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/module_data/mod.mod b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/module_data/mod.mod
new file mode 100644
index 00000000..8670a97e
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/module_data/mod.mod
Binary files differdiff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/module_data/module_data_docstring.f90 b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/module_data/module_data_docstring.f90
new file mode 100644
index 00000000..4505e0cb
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/module_data/module_data_docstring.f90
@@ -0,0 +1,12 @@
+module mod
+  integer :: i
+  integer :: x(4)
+  real, dimension(2,3) :: a
+  real, allocatable, dimension(:,:) :: b
+contains
+  subroutine foo
+    integer :: k
+    k = 1
+    a(1,2) = a(1,2)+3
+  end subroutine foo
+end module mod
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/negative_bounds/issue_20853.f90 b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/negative_bounds/issue_20853.f90
new file mode 100644
index 00000000..bf1fa928
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/negative_bounds/issue_20853.f90
@@ -0,0 +1,7 @@
+subroutine foo(is_, ie_, arr, tout)
+ implicit none
+ integer :: is_,ie_
+ real, intent(in) :: arr(is_:ie_)
+ real, intent(out) :: tout(is_:ie_)
+ tout = arr
+end
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/parameter/constant_both.f90 b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/parameter/constant_both.f90
new file mode 100644
index 00000000..ac90cedc
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/parameter/constant_both.f90
@@ -0,0 +1,57 @@
+! Check that parameters are correct intercepted.
+! Constants with comma separations are commonly
+! used, for instance Pi = 3._dp
+subroutine foo(x)
+  implicit none
+  integer, parameter :: sp = selected_real_kind(6)
+  integer, parameter :: dp = selected_real_kind(15)
+  integer, parameter :: ii = selected_int_kind(9)
+  integer, parameter :: il = selected_int_kind(18)
+  real(dp), intent(inout) :: x
+  dimension x(3)
+  real(sp), parameter :: three_s = 3._sp
+  real(dp), parameter :: three_d = 3._dp
+  integer(ii), parameter :: three_i = 3_ii
+  integer(il), parameter :: three_l = 3_il
+  x(1) = x(1) + x(2) * three_s * three_i + x(3) * three_d * three_l
+  x(2) = x(2) * three_s
+  x(3) = x(3) * three_l
+  return
+end subroutine
+
+
+subroutine foo_no(x)
+  implicit none
+  integer, parameter :: sp = selected_real_kind(6)
+  integer, parameter :: dp = selected_real_kind(15)
+  integer, parameter :: ii = selected_int_kind(9)
+  integer, parameter :: il = selected_int_kind(18)
+  real(dp), intent(inout) :: x
+  dimension x(3)
+  real(sp), parameter :: three_s = 3.
+  real(dp), parameter :: three_d = 3.
+  integer(ii), parameter :: three_i = 3
+  integer(il), parameter :: three_l = 3
+  x(1) = x(1) + x(2) * three_s * three_i + x(3) * three_d * three_l
+  x(2) = x(2) * three_s
+  x(3) = x(3) * three_l
+  return
+end subroutine
+
+subroutine foo_sum(x)
+  implicit none
+  integer, parameter :: sp = selected_real_kind(6)
+  integer, parameter :: dp = selected_real_kind(15)
+  integer, parameter :: ii = selected_int_kind(9)
+  integer, parameter :: il = selected_int_kind(18)
+  real(dp), intent(inout) :: x
+  dimension x(3)
+  real(sp), parameter :: three_s = 2._sp + 1._sp
+  real(dp), parameter :: three_d = 1._dp + 2._dp
+  integer(ii), parameter :: three_i = 2_ii + 1_ii
+  integer(il), parameter :: three_l = 1_il + 2_il
+  x(1) = x(1) + x(2) * three_s * three_i + x(3) * three_d * three_l
+  x(2) = x(2) * three_s
+  x(3) = x(3) * three_l
+  return
+end subroutine
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/parameter/constant_compound.f90 b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/parameter/constant_compound.f90
new file mode 100644
index 00000000..e51f5e9b
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/parameter/constant_compound.f90
@@ -0,0 +1,15 @@
+! Check that parameters are correct intercepted.
+! Constants with comma separations are commonly
+! used, for instance Pi = 3._dp
+subroutine foo_compound_int(x)
+  implicit none
+  integer, parameter :: ii = selected_int_kind(9)
+  integer(ii), intent(inout) :: x
+  dimension x(3)
+  integer(ii), parameter :: three = 3_ii
+  integer(ii), parameter :: two = 2_ii
+  integer(ii), parameter :: six = three * 1_ii * two
+
+  x(1) = x(1) + x(2) + x(3) * six
+  return
+end subroutine
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/parameter/constant_integer.f90 b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/parameter/constant_integer.f90
new file mode 100644
index 00000000..aaa83d2e
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/parameter/constant_integer.f90
@@ -0,0 +1,22 @@
+! Check that parameters are correct intercepted.
+! Constants with comma separations are commonly
+! used, for instance Pi = 3._dp
+subroutine foo_int(x)
+  implicit none
+  integer, parameter :: ii = selected_int_kind(9)
+  integer(ii), intent(inout) :: x
+  dimension x(3)
+  integer(ii), parameter :: three = 3_ii
+  x(1) = x(1) + x(2) + x(3) * three
+  return
+end subroutine
+
+subroutine foo_long(x)
+  implicit none
+  integer, parameter :: ii = selected_int_kind(18)
+  integer(ii), intent(inout) :: x
+  dimension x(3)
+  integer(ii), parameter :: three = 3_ii
+  x(1) = x(1) + x(2) + x(3) * three
+  return
+end subroutine
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/parameter/constant_non_compound.f90 b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/parameter/constant_non_compound.f90
new file mode 100644
index 00000000..62c9a5b9
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/parameter/constant_non_compound.f90
@@ -0,0 +1,23 @@
+! Check that parameters are correct intercepted.
+! Specifically that types of constants without 
+! compound kind specs are correctly inferred
+! adapted Gibbs iteration code from pymc 
+! for this test case 
+subroutine foo_non_compound_int(x)
+  implicit none
+  integer, parameter :: ii = selected_int_kind(9)
+
+  integer(ii)   maxiterates
+  parameter (maxiterates=2)
+
+  integer(ii)   maxseries
+  parameter (maxseries=2)
+
+  integer(ii)   wasize
+  parameter (wasize=maxiterates*maxseries)
+  integer(ii), intent(inout) :: x
+  dimension x(wasize)
+
+  x(1) = x(1) + x(2) + x(3) + x(4) * wasize
+  return
+end subroutine
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/parameter/constant_real.f90 b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/parameter/constant_real.f90
new file mode 100644
index 00000000..02ac9dd9
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/parameter/constant_real.f90
@@ -0,0 +1,23 @@
+! Check that parameters are correct intercepted.
+! Constants with comma separations are commonly
+! used, for instance Pi = 3._dp
+subroutine foo_single(x)
+  implicit none
+  integer, parameter :: rp = selected_real_kind(6)
+  real(rp), intent(inout) :: x
+  dimension x(3)
+  real(rp), parameter :: three = 3._rp
+  x(1) = x(1) + x(2) + x(3) * three
+  return
+end subroutine
+
+subroutine foo_double(x)
+  implicit none
+  integer, parameter :: rp = selected_real_kind(15)
+  real(rp), intent(inout) :: x
+  dimension x(3)
+  real(rp), parameter :: three = 3._rp
+  x(1) = x(1) + x(2) + x(3) * three
+  return
+end subroutine
+
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/quoted_character/foo.f b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/quoted_character/foo.f
new file mode 100644
index 00000000..9dc1cfa4
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/quoted_character/foo.f
@@ -0,0 +1,14 @@
+      SUBROUTINE FOO(OUT1, OUT2, OUT3, OUT4, OUT5, OUT6)
+      CHARACTER SINGLE, DOUBLE, SEMICOL, EXCLA, OPENPAR, CLOSEPAR
+      PARAMETER (SINGLE="'", DOUBLE='"', SEMICOL=';', EXCLA="!",
+     1           OPENPAR="(", CLOSEPAR=")")
+      CHARACTER OUT1, OUT2, OUT3, OUT4, OUT5, OUT6
+Cf2py intent(out) OUT1, OUT2, OUT3, OUT4, OUT5, OUT6
+      OUT1 = SINGLE
+      OUT2 = DOUBLE
+      OUT3 = SEMICOL
+      OUT4 = EXCLA
+      OUT5 = OPENPAR
+      OUT6 = CLOSEPAR
+      RETURN
+      END
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/regression/gh25337/data.f90 b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/regression/gh25337/data.f90
new file mode 100644
index 00000000..483d13ce
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/regression/gh25337/data.f90
@@ -0,0 +1,8 @@
+module data
+   real(8) :: shift
+contains
+   subroutine set_shift(in_shift)
+      real(8), intent(in) :: in_shift
+      shift = in_shift
+   end subroutine set_shift
+end module data
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/regression/gh25337/use_data.f90 b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/regression/gh25337/use_data.f90
new file mode 100644
index 00000000..b3fae8b8
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/regression/gh25337/use_data.f90
@@ -0,0 +1,6 @@
+subroutine shift_a(dim_a, a)
+    use data, only: shift
+    integer, intent(in) :: dim_a
+    real(8), intent(inout), dimension(dim_a) :: a
+    a = a + shift
+end subroutine shift_a
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/regression/inout.f90 b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/regression/inout.f90
new file mode 100644
index 00000000..80cdad90
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/regression/inout.f90
@@ -0,0 +1,9 @@
+! Check that intent(in out) translates as intent(inout).
+! The separation seems to be a common usage.
+      subroutine foo(x)
+          implicit none
+          real(4), intent(in out) :: x
+          dimension x(3)
+          x(1) = x(1) + x(2) + x(3)
+          return
+      end
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/return_character/foo77.f b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/return_character/foo77.f
new file mode 100644
index 00000000..facae101
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/return_character/foo77.f
@@ -0,0 +1,45 @@
+       function t0(value)
+         character value
+         character t0
+         t0 = value
+       end
+       function t1(value)
+         character*1 value
+         character*1 t1
+         t1 = value
+       end
+       function t5(value)
+         character*5 value
+         character*5 t5
+         t5 = value
+       end
+       function ts(value)
+         character*(*) value
+         character*(*) ts
+         ts = value
+       end
+
+       subroutine s0(t0,value)
+         character value
+         character t0
+cf2py    intent(out) t0
+         t0 = value
+       end
+       subroutine s1(t1,value)
+         character*1 value
+         character*1 t1
+cf2py    intent(out) t1
+         t1 = value
+       end
+       subroutine s5(t5,value)
+         character*5 value
+         character*5 t5
+cf2py    intent(out) t5
+         t5 = value
+       end
+       subroutine ss(ts,value)
+         character*(*) value
+         character*10 ts
+cf2py    intent(out) ts
+         ts = value
+       end
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/return_character/foo90.f90 b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/return_character/foo90.f90
new file mode 100644
index 00000000..36182bcf
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/return_character/foo90.f90
@@ -0,0 +1,48 @@
+module f90_return_char
+  contains
+       function t0(value)
+         character :: value
+         character :: t0
+         t0 = value
+       end function t0
+       function t1(value)
+         character(len=1) :: value
+         character(len=1) :: t1
+         t1 = value
+       end function t1
+       function t5(value)
+         character(len=5) :: value
+         character(len=5) :: t5
+         t5 = value
+       end function t5
+       function ts(value)
+         character(len=*) :: value
+         character(len=10) :: ts
+         ts = value
+       end function ts
+
+       subroutine s0(t0,value)
+         character :: value
+         character :: t0
+!f2py    intent(out) t0
+         t0 = value
+       end subroutine s0
+       subroutine s1(t1,value)
+         character(len=1) :: value
+         character(len=1) :: t1
+!f2py    intent(out) t1
+         t1 = value
+       end subroutine s1
+       subroutine s5(t5,value)
+         character(len=5) :: value
+         character(len=5) :: t5
+!f2py    intent(out) t5
+         t5 = value
+       end subroutine s5
+       subroutine ss(ts,value)
+         character(len=*) :: value
+         character(len=10) :: ts
+!f2py    intent(out) ts
+         ts = value
+       end subroutine ss
+end module f90_return_char
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/return_complex/foo77.f b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/return_complex/foo77.f
new file mode 100644
index 00000000..37a1ec84
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/return_complex/foo77.f
@@ -0,0 +1,45 @@
+       function t0(value)
+         complex value
+         complex t0
+         t0 = value
+       end
+       function t8(value)
+         complex*8 value
+         complex*8 t8
+         t8 = value
+       end
+       function t16(value)
+         complex*16 value
+         complex*16 t16
+         t16 = value
+       end
+       function td(value)
+         double complex value
+         double complex td
+         td = value
+       end
+
+       subroutine s0(t0,value)
+         complex value
+         complex t0
+cf2py    intent(out) t0
+         t0 = value
+       end
+       subroutine s8(t8,value)
+         complex*8 value
+         complex*8 t8
+cf2py    intent(out) t8
+         t8 = value
+       end
+       subroutine s16(t16,value)
+         complex*16 value
+         complex*16 t16
+cf2py    intent(out) t16
+         t16 = value
+       end
+       subroutine sd(td,value)
+         double complex value
+         double complex td
+cf2py    intent(out) td
+         td = value
+       end
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/return_complex/foo90.f90 b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/return_complex/foo90.f90
new file mode 100644
index 00000000..adc27b47
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/return_complex/foo90.f90
@@ -0,0 +1,48 @@
+module f90_return_complex
+  contains
+       function t0(value)
+         complex :: value
+         complex :: t0
+         t0 = value
+       end function t0
+       function t8(value)
+         complex(kind=4) :: value
+         complex(kind=4) :: t8
+         t8 = value
+       end function t8
+       function t16(value)
+         complex(kind=8) :: value
+         complex(kind=8) :: t16
+         t16 = value
+       end function t16
+       function td(value)
+         double complex :: value
+         double complex :: td
+         td = value
+       end function td
+
+       subroutine s0(t0,value)
+         complex :: value
+         complex :: t0
+!f2py    intent(out) t0
+         t0 = value
+       end subroutine s0
+       subroutine s8(t8,value)
+         complex(kind=4) :: value
+         complex(kind=4) :: t8
+!f2py    intent(out) t8
+         t8 = value
+       end subroutine s8
+       subroutine s16(t16,value)
+         complex(kind=8) :: value
+         complex(kind=8) :: t16
+!f2py    intent(out) t16
+         t16 = value
+       end subroutine s16
+       subroutine sd(td,value)
+         double complex :: value
+         double complex :: td
+!f2py    intent(out) td
+         td = value
+       end subroutine sd
+end module f90_return_complex
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/return_integer/foo77.f b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/return_integer/foo77.f
new file mode 100644
index 00000000..1ab895b9
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/return_integer/foo77.f
@@ -0,0 +1,56 @@
+       function t0(value)
+         integer value
+         integer t0
+         t0 = value
+       end
+       function t1(value)
+         integer*1 value
+         integer*1 t1
+         t1 = value
+       end
+       function t2(value)
+         integer*2 value
+         integer*2 t2
+         t2 = value
+       end
+       function t4(value)
+         integer*4 value
+         integer*4 t4
+         t4 = value
+       end
+       function t8(value)
+         integer*8 value
+         integer*8 t8
+         t8 = value
+       end
+
+       subroutine s0(t0,value)
+         integer value
+         integer t0
+cf2py    intent(out) t0
+         t0 = value
+       end
+       subroutine s1(t1,value)
+         integer*1 value
+         integer*1 t1
+cf2py    intent(out) t1
+         t1 = value
+       end
+       subroutine s2(t2,value)
+         integer*2 value
+         integer*2 t2
+cf2py    intent(out) t2
+         t2 = value
+       end
+       subroutine s4(t4,value)
+         integer*4 value
+         integer*4 t4
+cf2py    intent(out) t4
+         t4 = value
+       end
+       subroutine s8(t8,value)
+         integer*8 value
+         integer*8 t8
+cf2py    intent(out) t8
+         t8 = value
+       end
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/return_integer/foo90.f90 b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/return_integer/foo90.f90
new file mode 100644
index 00000000..ba9249aa
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/return_integer/foo90.f90
@@ -0,0 +1,59 @@
+module f90_return_integer
+  contains
+       function t0(value)
+         integer :: value
+         integer :: t0
+         t0 = value
+       end function t0
+       function t1(value)
+         integer(kind=1) :: value
+         integer(kind=1) :: t1
+         t1 = value
+       end function t1
+       function t2(value)
+         integer(kind=2) :: value
+         integer(kind=2) :: t2
+         t2 = value
+       end function t2
+       function t4(value)
+         integer(kind=4) :: value
+         integer(kind=4) :: t4
+         t4 = value
+       end function t4
+       function t8(value)
+         integer(kind=8) :: value
+         integer(kind=8) :: t8
+         t8 = value
+       end function t8
+
+       subroutine s0(t0,value)
+         integer :: value
+         integer :: t0
+!f2py    intent(out) t0
+         t0 = value
+       end subroutine s0
+       subroutine s1(t1,value)
+         integer(kind=1) :: value
+         integer(kind=1) :: t1
+!f2py    intent(out) t1
+         t1 = value
+       end subroutine s1
+       subroutine s2(t2,value)
+         integer(kind=2) :: value
+         integer(kind=2) :: t2
+!f2py    intent(out) t2
+         t2 = value
+       end subroutine s2
+       subroutine s4(t4,value)
+         integer(kind=4) :: value
+         integer(kind=4) :: t4
+!f2py    intent(out) t4
+         t4 = value
+       end subroutine s4
+       subroutine s8(t8,value)
+         integer(kind=8) :: value
+         integer(kind=8) :: t8
+!f2py    intent(out) t8
+         t8 = value
+       end subroutine s8
+end module f90_return_integer
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/return_logical/foo77.f b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/return_logical/foo77.f
new file mode 100644
index 00000000..ef530145
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/return_logical/foo77.f
@@ -0,0 +1,56 @@
+       function t0(value)
+         logical value
+         logical t0
+         t0 = value
+       end
+       function t1(value)
+         logical*1 value
+         logical*1 t1
+         t1 = value
+       end
+       function t2(value)
+         logical*2 value
+         logical*2 t2
+         t2 = value
+       end
+       function t4(value)
+         logical*4 value
+         logical*4 t4
+         t4 = value
+       end
+c       function t8(value)
+c         logical*8 value
+c         logical*8 t8
+c         t8 = value
+c       end
+
+       subroutine s0(t0,value)
+         logical value
+         logical t0
+cf2py    intent(out) t0
+         t0 = value
+       end
+       subroutine s1(t1,value)
+         logical*1 value
+         logical*1 t1
+cf2py    intent(out) t1
+         t1 = value
+       end
+       subroutine s2(t2,value)
+         logical*2 value
+         logical*2 t2
+cf2py    intent(out) t2
+         t2 = value
+       end
+       subroutine s4(t4,value)
+         logical*4 value
+         logical*4 t4
+cf2py    intent(out) t4
+         t4 = value
+       end
+c       subroutine s8(t8,value)
+c         logical*8 value
+c         logical*8 t8
+cf2py    intent(out) t8
+c         t8 = value
+c       end
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/return_logical/foo90.f90 b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/return_logical/foo90.f90
new file mode 100644
index 00000000..a4526468
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/return_logical/foo90.f90
@@ -0,0 +1,59 @@
+module f90_return_logical
+  contains
+       function t0(value)
+         logical :: value
+         logical :: t0
+         t0 = value
+       end function t0
+       function t1(value)
+         logical(kind=1) :: value
+         logical(kind=1) :: t1
+         t1 = value
+       end function t1
+       function t2(value)
+         logical(kind=2) :: value
+         logical(kind=2) :: t2
+         t2 = value
+       end function t2
+       function t4(value)
+         logical(kind=4) :: value
+         logical(kind=4) :: t4
+         t4 = value
+       end function t4
+       function t8(value)
+         logical(kind=8) :: value
+         logical(kind=8) :: t8
+         t8 = value
+       end function t8
+
+       subroutine s0(t0,value)
+         logical :: value
+         logical :: t0
+!f2py    intent(out) t0
+         t0 = value
+       end subroutine s0
+       subroutine s1(t1,value)
+         logical(kind=1) :: value
+         logical(kind=1) :: t1
+!f2py    intent(out) t1
+         t1 = value
+       end subroutine s1
+       subroutine s2(t2,value)
+         logical(kind=2) :: value
+         logical(kind=2) :: t2
+!f2py    intent(out) t2
+         t2 = value
+       end subroutine s2
+       subroutine s4(t4,value)
+         logical(kind=4) :: value
+         logical(kind=4) :: t4
+!f2py    intent(out) t4
+         t4 = value
+       end subroutine s4
+       subroutine s8(t8,value)
+         logical(kind=8) :: value
+         logical(kind=8) :: t8
+!f2py    intent(out) t8
+         t8 = value
+       end subroutine s8
+end module f90_return_logical
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/return_real/foo77.f b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/return_real/foo77.f
new file mode 100644
index 00000000..bf43dbf1
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/return_real/foo77.f
@@ -0,0 +1,45 @@
+       function t0(value)
+         real value
+         real t0
+         t0 = value
+       end
+       function t4(value)
+         real*4 value
+         real*4 t4
+         t4 = value
+       end
+       function t8(value)
+         real*8 value
+         real*8 t8
+         t8 = value
+       end
+       function td(value)
+         double precision value
+         double precision td
+         td = value
+       end
+
+       subroutine s0(t0,value)
+         real value
+         real t0
+cf2py    intent(out) t0
+         t0 = value
+       end
+       subroutine s4(t4,value)
+         real*4 value
+         real*4 t4
+cf2py    intent(out) t4
+         t4 = value
+       end
+       subroutine s8(t8,value)
+         real*8 value
+         real*8 t8
+cf2py    intent(out) t8
+         t8 = value
+       end
+       subroutine sd(td,value)
+         double precision value
+         double precision td
+cf2py    intent(out) td
+         td = value
+       end
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/return_real/foo90.f90 b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/return_real/foo90.f90
new file mode 100644
index 00000000..df971998
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/return_real/foo90.f90
@@ -0,0 +1,48 @@
+module f90_return_real
+  contains
+       function t0(value)
+         real :: value
+         real :: t0
+         t0 = value
+       end function t0
+       function t4(value)
+         real(kind=4) :: value
+         real(kind=4) :: t4
+         t4 = value
+       end function t4
+       function t8(value)
+         real(kind=8) :: value
+         real(kind=8) :: t8
+         t8 = value
+       end function t8
+       function td(value)
+         double precision :: value
+         double precision :: td
+         td = value
+       end function td
+
+       subroutine s0(t0,value)
+         real :: value
+         real :: t0
+!f2py    intent(out) t0
+         t0 = value
+       end subroutine s0
+       subroutine s4(t4,value)
+         real(kind=4) :: value
+         real(kind=4) :: t4
+!f2py    intent(out) t4
+         t4 = value
+       end subroutine s4
+       subroutine s8(t8,value)
+         real(kind=8) :: value
+         real(kind=8) :: t8
+!f2py    intent(out) t8
+         t8 = value
+       end subroutine s8
+       subroutine sd(td,value)
+         double precision :: value
+         double precision :: td
+!f2py    intent(out) td
+         td = value
+       end subroutine sd
+end module f90_return_real
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/size/foo.f90 b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/size/foo.f90
new file mode 100644
index 00000000..5b66f8c4
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/size/foo.f90
@@ -0,0 +1,44 @@
+
+subroutine foo(a, n, m, b)
+  implicit none
+
+  real, intent(in) :: a(n, m)
+  integer, intent(in) :: n, m
+  real, intent(out) :: b(size(a, 1))
+
+  integer :: i
+
+  do i = 1, size(b)
+    b(i) = sum(a(i,:))
+  enddo
+end subroutine
+
+subroutine trans(x,y)
+  implicit none
+  real, intent(in), dimension(:,:) :: x
+  real, intent(out), dimension( size(x,2), size(x,1) ) :: y
+  integer :: N, M, i, j
+  N = size(x,1)
+  M = size(x,2)
+  DO i=1,N
+     do j=1,M
+        y(j,i) = x(i,j)
+     END DO
+  END DO
+end subroutine trans
+
+subroutine flatten(x,y)
+  implicit none
+  real, intent(in), dimension(:,:) :: x
+  real, intent(out), dimension( size(x) ) :: y
+  integer :: N, M, i, j, k
+  N = size(x,1)
+  M = size(x,2)
+  k = 1
+  DO i=1,N
+     do j=1,M
+        y(k) = x(i,j)
+        k = k + 1
+     END DO
+  END DO
+end subroutine flatten
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/string/char.f90 b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/string/char.f90
new file mode 100644
index 00000000..bb7985ce
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/string/char.f90
@@ -0,0 +1,29 @@
+MODULE char_test
+
+CONTAINS
+
+SUBROUTINE change_strings(strings, n_strs, out_strings)
+    IMPLICIT NONE
+
+    ! Inputs
+    INTEGER, INTENT(IN) :: n_strs
+    CHARACTER, INTENT(IN), DIMENSION(2,n_strs) :: strings
+    CHARACTER, INTENT(OUT), DIMENSION(2,n_strs) :: out_strings
+
+!f2py INTEGER, INTENT(IN) :: n_strs
+!f2py CHARACTER, INTENT(IN), DIMENSION(2,n_strs) :: strings
+!f2py CHARACTER, INTENT(OUT), DIMENSION(2,n_strs) :: strings
+
+    ! Misc.
+    INTEGER*4 :: j
+
+
+    DO j=1, n_strs
+        out_strings(1,j) = strings(1,j)
+        out_strings(2,j) = 'A'
+    END DO
+
+END SUBROUTINE change_strings
+
+END MODULE char_test
+
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/string/fixed_string.f90 b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/string/fixed_string.f90
new file mode 100644
index 00000000..7fd15854
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/string/fixed_string.f90
@@ -0,0 +1,34 @@
+function sint(s) result(i)
+   implicit none
+   character(len=*) :: s
+   integer :: j, i
+   i = 0
+   do j=len(s), 1, -1
+    if (.not.((i.eq.0).and.(s(j:j).eq.' '))) then
+      i = i + ichar(s(j:j)) * 10 ** (j - 1)
+    endif
+   end do
+   return
+ end function sint
+
+ function test_in_bytes4(a) result (i)
+   implicit none
+   integer :: sint
+   character(len=4) :: a
+   integer :: i
+   i = sint(a)
+   a(1:1) = 'A'
+   return
+ end function test_in_bytes4
+
+ function test_inout_bytes4(a) result (i)
+   implicit none
+   integer :: sint
+   character(len=4), intent(inout) :: a
+   integer :: i
+   if (a(1:1).ne.' ') then
+     a(1:1) = 'E'
+   endif
+   i = sint(a)
+   return
+ end function test_inout_bytes4
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/string/gh24008.f b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/string/gh24008.f
new file mode 100644
index 00000000..ab64cf77
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/string/gh24008.f
@@ -0,0 +1,8 @@
+      SUBROUTINE GREET(NAME, GREETING)
+      CHARACTER NAME*(*), GREETING*(*)
+      CHARACTER*(50) MESSAGE
+
+      MESSAGE = 'Hello, ' // NAME // ', ' // GREETING
+c$$$      PRINT *, MESSAGE
+
+      END SUBROUTINE GREET
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/string/gh24662.f90 b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/string/gh24662.f90
new file mode 100644
index 00000000..ca53413c
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/string/gh24662.f90
@@ -0,0 +1,7 @@
+subroutine string_inout_optional(output)
+    implicit none
+    character*(32), optional, intent(inout) :: output
+    if (present(output)) then
+      output="output string"
+    endif
+end subroutine
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/string/gh25286.f90 b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/string/gh25286.f90
new file mode 100644
index 00000000..db1c7100
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/string/gh25286.f90
@@ -0,0 +1,14 @@
+subroutine charint(trans, info)
+    character, intent(in) :: trans
+    integer, intent(out) :: info
+    if (trans == 'N') then
+        info = 1
+    else if (trans == 'T') then
+        info = 2
+    else if (trans == 'C') then
+        info = 3
+    else
+        info = -1
+    end if
+
+end subroutine charint
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/string/gh25286.pyf b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/string/gh25286.pyf
new file mode 100644
index 00000000..7b960907
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/string/gh25286.pyf
@@ -0,0 +1,12 @@
+python module _char_handling_test
+    interface
+    subroutine charint(trans, info)
+        callstatement (*f2py_func)(&trans, &info)
+        callprotoargument char*, int*
+
+        character, intent(in), check(trans=='N'||trans=='T'||trans=='C') :: trans = 'N'
+        integer intent(out) :: info
+
+    end subroutine charint
+    end interface
+end python module _char_handling_test
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/string/gh25286_bc.pyf b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/string/gh25286_bc.pyf
new file mode 100644
index 00000000..e7b10fa9
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/string/gh25286_bc.pyf
@@ -0,0 +1,12 @@
+python module _char_handling_test
+    interface
+    subroutine charint(trans, info)
+        callstatement (*f2py_func)(&trans, &info)
+        callprotoargument char*, int*
+
+        character, intent(in), check(*trans=='N'||*trans=='T'||*trans=='C') :: trans = 'N'
+        integer intent(out) :: info
+
+    end subroutine charint
+    end interface
+end python module _char_handling_test
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/string/scalar_string.f90 b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/string/scalar_string.f90
new file mode 100644
index 00000000..f8f07617
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/string/scalar_string.f90
@@ -0,0 +1,9 @@
+MODULE string_test
+
+  character(len=8) :: string
+  character string77 * 8
+
+  character(len=12), dimension(5,7) :: strarr
+  character strarr77(5,7) * 12
+
+END MODULE string_test
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/string/string.f b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/string/string.f
new file mode 100644
index 00000000..5210ca4d
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/string/string.f
@@ -0,0 +1,12 @@
+C FILE: STRING.F
+      SUBROUTINE FOO(A,B,C,D)
+      CHARACTER*5 A, B
+      CHARACTER*(*) C,D
+Cf2py intent(in) a,c
+Cf2py intent(inout) b,d
+      A(1:1) = 'A'
+      B(1:1) = 'B'
+      C(1:1) = 'C'
+      D(1:1) = 'D'
+      END
+C END OF FILE STRING.F
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/value_attrspec/gh21665.f90 b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/value_attrspec/gh21665.f90
new file mode 100644
index 00000000..7d9dc0fd
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/src/value_attrspec/gh21665.f90
@@ -0,0 +1,9 @@
+module fortfuncs
+  implicit none
+contains
+  subroutine square(x,y)
+    integer, intent(in), value :: x
+    integer, intent(out) :: y
+    y = x*x
+  end subroutine square
+end module fortfuncs
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_abstract_interface.py b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_abstract_interface.py
new file mode 100644
index 00000000..42902913
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_abstract_interface.py
@@ -0,0 +1,25 @@
+from pathlib import Path
+import pytest
+import textwrap
+from . import util
+from numpy.f2py import crackfortran
+from numpy.testing import IS_WASM
+
+
+@pytest.mark.skipif(IS_WASM, reason="Cannot start subprocess")
+class TestAbstractInterface(util.F2PyTest):
+    sources = [util.getpath("tests", "src", "abstract_interface", "foo.f90")]
+
+    skip = ["add1", "add2"]
+
+    def test_abstract_interface(self):
+        assert self.module.ops_module.foo(3, 5) == (8, 13)
+
+    def test_parse_abstract_interface(self):
+        # Test gh18403
+        fpath = util.getpath("tests", "src", "abstract_interface",
+                             "gh18403_mod.f90")
+        mod = crackfortran.crackfortran([str(fpath)])
+        assert len(mod) == 1
+        assert len(mod[0]["body"]) == 1
+        assert mod[0]["body"][0]["block"] == "abstract interface"
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_array_from_pyobj.py b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_array_from_pyobj.py
new file mode 100644
index 00000000..2b8c8def
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_array_from_pyobj.py
@@ -0,0 +1,686 @@
+import os
+import sys
+import copy
+import platform
+import pytest
+
+import numpy as np
+
+from numpy.testing import assert_, assert_equal
+from numpy.core.multiarray import typeinfo as _typeinfo
+from . import util
+
+wrap = None
+
+# Extend core typeinfo with CHARACTER to test dtype('c')
+_ti = _typeinfo['STRING']
+typeinfo = dict(
+    CHARACTER=type(_ti)(('c', _ti.num, 8, _ti.alignment, _ti.type)),
+    **_typeinfo)
+
+
+def setup_module():
+    """
+    Build the required testing extension module
+
+    """
+    global wrap
+
+    # Check compiler availability first
+    if not util.has_c_compiler():
+        pytest.skip("No C compiler available")
+
+    if wrap is None:
+        config_code = """
+        config.add_extension('test_array_from_pyobj_ext',
+                             sources=['wrapmodule.c', 'fortranobject.c'],
+                             define_macros=[])
+        """
+        d = os.path.dirname(__file__)
+        src = [
+            util.getpath("tests", "src", "array_from_pyobj", "wrapmodule.c"),
+            util.getpath("src", "fortranobject.c"),
+            util.getpath("src", "fortranobject.h"),
+        ]
+        wrap = util.build_module_distutils(src, config_code,
+                                           "test_array_from_pyobj_ext")
+
+
+def flags_info(arr):
+    flags = wrap.array_attrs(arr)[6]
+    return flags2names(flags)
+
+
+def flags2names(flags):
+    info = []
+    for flagname in [
+            "CONTIGUOUS",
+            "FORTRAN",
+            "OWNDATA",
+            "ENSURECOPY",
+            "ENSUREARRAY",
+            "ALIGNED",
+            "NOTSWAPPED",
+            "WRITEABLE",
+            "WRITEBACKIFCOPY",
+            "UPDATEIFCOPY",
+            "BEHAVED",
+            "BEHAVED_RO",
+            "CARRAY",
+            "FARRAY",
+    ]:
+        if abs(flags) & getattr(wrap, flagname, 0):
+            info.append(flagname)
+    return info
+
+
+class Intent:
+    def __init__(self, intent_list=[]):
+        self.intent_list = intent_list[:]
+        flags = 0
+        for i in intent_list:
+            if i == "optional":
+                flags |= wrap.F2PY_OPTIONAL
+            else:
+                flags |= getattr(wrap, "F2PY_INTENT_" + i.upper())
+        self.flags = flags
+
+    def __getattr__(self, name):
+        name = name.lower()
+        if name == "in_":
+            name = "in"
+        return self.__class__(self.intent_list + [name])
+
+    def __str__(self):
+        return "intent(%s)" % (",".join(self.intent_list))
+
+    def __repr__(self):
+        return "Intent(%r)" % (self.intent_list)
+
+    def is_intent(self, *names):
+        for name in names:
+            if name not in self.intent_list:
+                return False
+        return True
+
+    def is_intent_exact(self, *names):
+        return len(self.intent_list) == len(names) and self.is_intent(*names)
+
+
+intent = Intent()
+
+_type_names = [
+    "BOOL",
+    "BYTE",
+    "UBYTE",
+    "SHORT",
+    "USHORT",
+    "INT",
+    "UINT",
+    "LONG",
+    "ULONG",
+    "LONGLONG",
+    "ULONGLONG",
+    "FLOAT",
+    "DOUBLE",
+    "CFLOAT",
+    "STRING1",
+    "STRING5",
+    "CHARACTER",
+]
+
+_cast_dict = {"BOOL": ["BOOL"]}
+_cast_dict["BYTE"] = _cast_dict["BOOL"] + ["BYTE"]
+_cast_dict["UBYTE"] = _cast_dict["BOOL"] + ["UBYTE"]
+_cast_dict["BYTE"] = ["BYTE"]
+_cast_dict["UBYTE"] = ["UBYTE"]
+_cast_dict["SHORT"] = _cast_dict["BYTE"] + ["UBYTE", "SHORT"]
+_cast_dict["USHORT"] = _cast_dict["UBYTE"] + ["BYTE", "USHORT"]
+_cast_dict["INT"] = _cast_dict["SHORT"] + ["USHORT", "INT"]
+_cast_dict["UINT"] = _cast_dict["USHORT"] + ["SHORT", "UINT"]
+
+_cast_dict["LONG"] = _cast_dict["INT"] + ["LONG"]
+_cast_dict["ULONG"] = _cast_dict["UINT"] + ["ULONG"]
+
+_cast_dict["LONGLONG"] = _cast_dict["LONG"] + ["LONGLONG"]
+_cast_dict["ULONGLONG"] = _cast_dict["ULONG"] + ["ULONGLONG"]
+
+_cast_dict["FLOAT"] = _cast_dict["SHORT"] + ["USHORT", "FLOAT"]
+_cast_dict["DOUBLE"] = _cast_dict["INT"] + ["UINT", "FLOAT", "DOUBLE"]
+
+_cast_dict["CFLOAT"] = _cast_dict["FLOAT"] + ["CFLOAT"]
+
+_cast_dict['STRING1'] = ['STRING1']
+_cast_dict['STRING5'] = ['STRING5']
+_cast_dict['CHARACTER'] = ['CHARACTER']
+
+# 32 bit system malloc typically does not provide the alignment required by
+# 16 byte long double types this means the inout intent cannot be satisfied
+# and several tests fail as the alignment flag can be randomly true or fals
+# when numpy gains an aligned allocator the tests could be enabled again
+#
+# Furthermore, on macOS ARM64, LONGDOUBLE is an alias for DOUBLE.
+if ((np.intp().dtype.itemsize != 4 or np.clongdouble().dtype.alignment <= 8)
+        and sys.platform != "win32"
+        and (platform.system(), platform.processor()) != ("Darwin", "arm")):
+    _type_names.extend(["LONGDOUBLE", "CDOUBLE", "CLONGDOUBLE"])
+    _cast_dict["LONGDOUBLE"] = _cast_dict["LONG"] + [
+        "ULONG",
+        "FLOAT",
+        "DOUBLE",
+        "LONGDOUBLE",
+    ]
+    _cast_dict["CLONGDOUBLE"] = _cast_dict["LONGDOUBLE"] + [
+        "CFLOAT",
+        "CDOUBLE",
+        "CLONGDOUBLE",
+    ]
+    _cast_dict["CDOUBLE"] = _cast_dict["DOUBLE"] + ["CFLOAT", "CDOUBLE"]
+
+
+class Type:
+    _type_cache = {}
+
+    def __new__(cls, name):
+        if isinstance(name, np.dtype):
+            dtype0 = name
+            name = None
+            for n, i in typeinfo.items():
+                if not isinstance(i, type) and dtype0.type is i.type:
+                    name = n
+                    break
+        obj = cls._type_cache.get(name.upper(), None)
+        if obj is not None:
+            return obj
+        obj = object.__new__(cls)
+        obj._init(name)
+        cls._type_cache[name.upper()] = obj
+        return obj
+
+    def _init(self, name):
+        self.NAME = name.upper()
+
+        if self.NAME == 'CHARACTER':
+            info = typeinfo[self.NAME]
+            self.type_num = getattr(wrap, 'NPY_STRING')
+            self.elsize = 1
+            self.dtype = np.dtype('c')
+        elif self.NAME.startswith('STRING'):
+            info = typeinfo[self.NAME[:6]]
+            self.type_num = getattr(wrap, 'NPY_STRING')
+            self.elsize = int(self.NAME[6:] or 0)
+            self.dtype = np.dtype(f'S{self.elsize}')
+        else:
+            info = typeinfo[self.NAME]
+            self.type_num = getattr(wrap, 'NPY_' + self.NAME)
+            self.elsize = info.bits // 8
+            self.dtype = np.dtype(info.type)
+
+        assert self.type_num == info.num
+        self.type = info.type
+        self.dtypechar = info.char
+
+    def __repr__(self):
+        return (f"Type({self.NAME})|type_num={self.type_num},"
+                f" dtype={self.dtype},"
+                f" type={self.type}, elsize={self.elsize},"
+                f" dtypechar={self.dtypechar}")
+
+    def cast_types(self):
+        return [self.__class__(_m) for _m in _cast_dict[self.NAME]]
+
+    def all_types(self):
+        return [self.__class__(_m) for _m in _type_names]
+
+    def smaller_types(self):
+        bits = typeinfo[self.NAME].alignment
+        types = []
+        for name in _type_names:
+            if typeinfo[name].alignment < bits:
+                types.append(Type(name))
+        return types
+
+    def equal_types(self):
+        bits = typeinfo[self.NAME].alignment
+        types = []
+        for name in _type_names:
+            if name == self.NAME:
+                continue
+            if typeinfo[name].alignment == bits:
+                types.append(Type(name))
+        return types
+
+    def larger_types(self):
+        bits = typeinfo[self.NAME].alignment
+        types = []
+        for name in _type_names:
+            if typeinfo[name].alignment > bits:
+                types.append(Type(name))
+        return types
+
+
+class Array:
+
+    def __repr__(self):
+        return (f'Array({self.type}, {self.dims}, {self.intent},'
+                f' {self.obj})|arr={self.arr}')
+
+    def __init__(self, typ, dims, intent, obj):
+        self.type = typ
+        self.dims = dims
+        self.intent = intent
+        self.obj_copy = copy.deepcopy(obj)
+        self.obj = obj
+
+        # arr.dtypechar may be different from typ.dtypechar
+        self.arr = wrap.call(typ.type_num,
+                             typ.elsize,
+                             dims, intent.flags, obj)
+
+        assert isinstance(self.arr, np.ndarray)
+
+        self.arr_attr = wrap.array_attrs(self.arr)
+
+        if len(dims) > 1:
+            if self.intent.is_intent("c"):
+                assert (intent.flags & wrap.F2PY_INTENT_C)
+                assert not self.arr.flags["FORTRAN"]
+                assert self.arr.flags["CONTIGUOUS"]
+                assert (not self.arr_attr[6] & wrap.FORTRAN)
+            else:
+                assert (not intent.flags & wrap.F2PY_INTENT_C)
+                assert self.arr.flags["FORTRAN"]
+                assert not self.arr.flags["CONTIGUOUS"]
+                assert (self.arr_attr[6] & wrap.FORTRAN)
+
+        if obj is None:
+            self.pyarr = None
+            self.pyarr_attr = None
+            return
+
+        if intent.is_intent("cache"):
+            assert isinstance(obj, np.ndarray), repr(type(obj))
+            self.pyarr = np.array(obj).reshape(*dims).copy()
+        else:
+            self.pyarr = np.array(
+                np.array(obj, dtype=typ.dtypechar).reshape(*dims),
+                order=self.intent.is_intent("c") and "C" or "F",
+            )
+            assert self.pyarr.dtype == typ
+        self.pyarr.setflags(write=self.arr.flags["WRITEABLE"])
+        assert self.pyarr.flags["OWNDATA"], (obj, intent)
+        self.pyarr_attr = wrap.array_attrs(self.pyarr)
+
+        if len(dims) > 1:
+            if self.intent.is_intent("c"):
+                assert not self.pyarr.flags["FORTRAN"]
+                assert self.pyarr.flags["CONTIGUOUS"]
+                assert (not self.pyarr_attr[6] & wrap.FORTRAN)
+            else:
+                assert self.pyarr.flags["FORTRAN"]
+                assert not self.pyarr.flags["CONTIGUOUS"]
+                assert (self.pyarr_attr[6] & wrap.FORTRAN)
+
+        assert self.arr_attr[1] == self.pyarr_attr[1]  # nd
+        assert self.arr_attr[2] == self.pyarr_attr[2]  # dimensions
+        if self.arr_attr[1] <= 1:
+            assert self.arr_attr[3] == self.pyarr_attr[3], repr((
+                self.arr_attr[3],
+                self.pyarr_attr[3],
+                self.arr.tobytes(),
+                self.pyarr.tobytes(),
+            ))  # strides
+        assert self.arr_attr[5][-2:] == self.pyarr_attr[5][-2:], repr((
+            self.arr_attr[5], self.pyarr_attr[5]
+            ))  # descr
+        assert self.arr_attr[6] == self.pyarr_attr[6], repr((
+            self.arr_attr[6],
+            self.pyarr_attr[6],
+            flags2names(0 * self.arr_attr[6] - self.pyarr_attr[6]),
+            flags2names(self.arr_attr[6]),
+            intent,
+        ))  # flags
+
+        if intent.is_intent("cache"):
+            assert self.arr_attr[5][3] >= self.type.elsize
+        else:
+            assert self.arr_attr[5][3] == self.type.elsize
+            assert (self.arr_equal(self.pyarr, self.arr))
+
+        if isinstance(self.obj, np.ndarray):
+            if typ.elsize == Type(obj.dtype).elsize:
+                if not intent.is_intent("copy") and self.arr_attr[1] <= 1:
+                    assert self.has_shared_memory()
+
+    def arr_equal(self, arr1, arr2):
+        if arr1.shape != arr2.shape:
+            return False
+        return (arr1 == arr2).all()
+
+    def __str__(self):
+        return str(self.arr)
+
+    def has_shared_memory(self):
+        """Check that created array shares data with input array."""
+        if self.obj is self.arr:
+            return True
+        if not isinstance(self.obj, np.ndarray):
+            return False
+        obj_attr = wrap.array_attrs(self.obj)
+        return obj_attr[0] == self.arr_attr[0]
+
+
+class TestIntent:
+    def test_in_out(self):
+        assert str(intent.in_.out) == "intent(in,out)"
+        assert intent.in_.c.is_intent("c")
+        assert not intent.in_.c.is_intent_exact("c")
+        assert intent.in_.c.is_intent_exact("c", "in")
+        assert intent.in_.c.is_intent_exact("in", "c")
+        assert not intent.in_.is_intent("c")
+
+
+class TestSharedMemory:
+
+    @pytest.fixture(autouse=True, scope="class", params=_type_names)
+    def setup_type(self, request):
+        request.cls.type = Type(request.param)
+        request.cls.array = lambda self, dims, intent, obj: Array(
+            Type(request.param), dims, intent, obj)
+
+    @property
+    def num2seq(self):
+        if self.type.NAME.startswith('STRING'):
+            elsize = self.type.elsize
+            return ['1' * elsize, '2' * elsize]
+        return [1, 2]
+
+    @property
+    def num23seq(self):
+        if self.type.NAME.startswith('STRING'):
+            elsize = self.type.elsize
+            return [['1' * elsize, '2' * elsize, '3' * elsize],
+                    ['4' * elsize, '5' * elsize, '6' * elsize]]
+        return [[1, 2, 3], [4, 5, 6]]
+
+    def test_in_from_2seq(self):
+        a = self.array([2], intent.in_, self.num2seq)
+        assert not a.has_shared_memory()
+
+    def test_in_from_2casttype(self):
+        for t in self.type.cast_types():
+            obj = np.array(self.num2seq, dtype=t.dtype)
+            a = self.array([len(self.num2seq)], intent.in_, obj)
+            if t.elsize == self.type.elsize:
+                assert a.has_shared_memory(), repr((self.type.dtype, t.dtype))
+            else:
+                assert not a.has_shared_memory()
+
+    @pytest.mark.parametrize("write", ["w", "ro"])
+    @pytest.mark.parametrize("order", ["C", "F"])
+    @pytest.mark.parametrize("inp", ["2seq", "23seq"])
+    def test_in_nocopy(self, write, order, inp):
+        """Test if intent(in) array can be passed without copies"""
+        seq = getattr(self, "num" + inp)
+        obj = np.array(seq, dtype=self.type.dtype, order=order)
+        obj.setflags(write=(write == 'w'))
+        a = self.array(obj.shape,
+                       ((order == 'C' and intent.in_.c) or intent.in_), obj)
+        assert a.has_shared_memory()
+
+    def test_inout_2seq(self):
+        obj = np.array(self.num2seq, dtype=self.type.dtype)
+        a = self.array([len(self.num2seq)], intent.inout, obj)
+        assert a.has_shared_memory()
+
+        try:
+            a = self.array([2], intent.in_.inout, self.num2seq)
+        except TypeError as msg:
+            if not str(msg).startswith(
+                    "failed to initialize intent(inout|inplace|cache) array"):
+                raise
+        else:
+            raise SystemError("intent(inout) should have failed on sequence")
+
+    def test_f_inout_23seq(self):
+        obj = np.array(self.num23seq, dtype=self.type.dtype, order="F")
+        shape = (len(self.num23seq), len(self.num23seq[0]))
+        a = self.array(shape, intent.in_.inout, obj)
+        assert a.has_shared_memory()
+
+        obj = np.array(self.num23seq, dtype=self.type.dtype, order="C")
+        shape = (len(self.num23seq), len(self.num23seq[0]))
+        try:
+            a = self.array(shape, intent.in_.inout, obj)
+        except ValueError as msg:
+            if not str(msg).startswith(
+                    "failed to initialize intent(inout) array"):
+                raise
+        else:
+            raise SystemError(
+                "intent(inout) should have failed on improper array")
+
+    def test_c_inout_23seq(self):
+        obj = np.array(self.num23seq, dtype=self.type.dtype)
+        shape = (len(self.num23seq), len(self.num23seq[0]))
+        a = self.array(shape, intent.in_.c.inout, obj)
+        assert a.has_shared_memory()
+
+    def test_in_copy_from_2casttype(self):
+        for t in self.type.cast_types():
+            obj = np.array(self.num2seq, dtype=t.dtype)
+            a = self.array([len(self.num2seq)], intent.in_.copy, obj)
+            assert not a.has_shared_memory()
+
+    def test_c_in_from_23seq(self):
+        a = self.array(
+            [len(self.num23seq), len(self.num23seq[0])], intent.in_,
+            self.num23seq)
+        assert not a.has_shared_memory()
+
+    def test_in_from_23casttype(self):
+        for t in self.type.cast_types():
+            obj = np.array(self.num23seq, dtype=t.dtype)
+            a = self.array(
+                [len(self.num23seq), len(self.num23seq[0])], intent.in_, obj)
+            assert not a.has_shared_memory()
+
+    def test_f_in_from_23casttype(self):
+        for t in self.type.cast_types():
+            obj = np.array(self.num23seq, dtype=t.dtype, order="F")
+            a = self.array(
+                [len(self.num23seq), len(self.num23seq[0])], intent.in_, obj)
+            if t.elsize == self.type.elsize:
+                assert a.has_shared_memory()
+            else:
+                assert not a.has_shared_memory()
+
+    def test_c_in_from_23casttype(self):
+        for t in self.type.cast_types():
+            obj = np.array(self.num23seq, dtype=t.dtype)
+            a = self.array(
+                [len(self.num23seq), len(self.num23seq[0])], intent.in_.c, obj)
+            if t.elsize == self.type.elsize:
+                assert a.has_shared_memory()
+            else:
+                assert not a.has_shared_memory()
+
+    def test_f_copy_in_from_23casttype(self):
+        for t in self.type.cast_types():
+            obj = np.array(self.num23seq, dtype=t.dtype, order="F")
+            a = self.array(
+                [len(self.num23seq), len(self.num23seq[0])], intent.in_.copy,
+                obj)
+            assert not a.has_shared_memory()
+
+    def test_c_copy_in_from_23casttype(self):
+        for t in self.type.cast_types():
+            obj = np.array(self.num23seq, dtype=t.dtype)
+            a = self.array(
+                [len(self.num23seq), len(self.num23seq[0])], intent.in_.c.copy,
+                obj)
+            assert not a.has_shared_memory()
+
+    def test_in_cache_from_2casttype(self):
+        for t in self.type.all_types():
+            if t.elsize != self.type.elsize:
+                continue
+            obj = np.array(self.num2seq, dtype=t.dtype)
+            shape = (len(self.num2seq), )
+            a = self.array(shape, intent.in_.c.cache, obj)
+            assert a.has_shared_memory()
+
+            a = self.array(shape, intent.in_.cache, obj)
+            assert a.has_shared_memory()
+
+            obj = np.array(self.num2seq, dtype=t.dtype, order="F")
+            a = self.array(shape, intent.in_.c.cache, obj)
+            assert a.has_shared_memory()
+
+            a = self.array(shape, intent.in_.cache, obj)
+            assert a.has_shared_memory(), repr(t.dtype)
+
+            try:
+                a = self.array(shape, intent.in_.cache, obj[::-1])
+            except ValueError as msg:
+                if not str(msg).startswith(
+                        "failed to initialize intent(cache) array"):
+                    raise
+            else:
+                raise SystemError(
+                    "intent(cache) should have failed on multisegmented array")
+
+    def test_in_cache_from_2casttype_failure(self):
+        for t in self.type.all_types():
+            if t.NAME == 'STRING':
+                # string elsize is 0, so skipping the test
+                continue
+            if t.elsize >= self.type.elsize:
+                continue
+            obj = np.array(self.num2seq, dtype=t.dtype)
+            shape = (len(self.num2seq), )
+            try:
+                self.array(shape, intent.in_.cache, obj)  # Should succeed
+            except ValueError as msg:
+                if not str(msg).startswith(
+                        "failed to initialize intent(cache) array"):
+                    raise
+            else:
+                raise SystemError(
+                    "intent(cache) should have failed on smaller array")
+
+    def test_cache_hidden(self):
+        shape = (2, )
+        a = self.array(shape, intent.cache.hide, None)
+        assert a.arr.shape == shape
+
+        shape = (2, 3)
+        a = self.array(shape, intent.cache.hide, None)
+        assert a.arr.shape == shape
+
+        shape = (-1, 3)
+        try:
+            a = self.array(shape, intent.cache.hide, None)
+        except ValueError as msg:
+            if not str(msg).startswith(
+                    "failed to create intent(cache|hide)|optional array"):
+                raise
+        else:
+            raise SystemError(
+                "intent(cache) should have failed on undefined dimensions")
+
+    def test_hidden(self):
+        shape = (2, )
+        a = self.array(shape, intent.hide, None)
+        assert a.arr.shape == shape
+        assert a.arr_equal(a.arr, np.zeros(shape, dtype=self.type.dtype))
+
+        shape = (2, 3)
+        a = self.array(shape, intent.hide, None)
+        assert a.arr.shape == shape
+        assert a.arr_equal(a.arr, np.zeros(shape, dtype=self.type.dtype))
+        assert a.arr.flags["FORTRAN"] and not a.arr.flags["CONTIGUOUS"]
+
+        shape = (2, 3)
+        a = self.array(shape, intent.c.hide, None)
+        assert a.arr.shape == shape
+        assert a.arr_equal(a.arr, np.zeros(shape, dtype=self.type.dtype))
+        assert not a.arr.flags["FORTRAN"] and a.arr.flags["CONTIGUOUS"]
+
+        shape = (-1, 3)
+        try:
+            a = self.array(shape, intent.hide, None)
+        except ValueError as msg:
+            if not str(msg).startswith(
+                    "failed to create intent(cache|hide)|optional array"):
+                raise
+        else:
+            raise SystemError(
+                "intent(hide) should have failed on undefined dimensions")
+
+    def test_optional_none(self):
+        shape = (2, )
+        a = self.array(shape, intent.optional, None)
+        assert a.arr.shape == shape
+        assert a.arr_equal(a.arr, np.zeros(shape, dtype=self.type.dtype))
+
+        shape = (2, 3)
+        a = self.array(shape, intent.optional, None)
+        assert a.arr.shape == shape
+        assert a.arr_equal(a.arr, np.zeros(shape, dtype=self.type.dtype))
+        assert a.arr.flags["FORTRAN"] and not a.arr.flags["CONTIGUOUS"]
+
+        shape = (2, 3)
+        a = self.array(shape, intent.c.optional, None)
+        assert a.arr.shape == shape
+        assert a.arr_equal(a.arr, np.zeros(shape, dtype=self.type.dtype))
+        assert not a.arr.flags["FORTRAN"] and a.arr.flags["CONTIGUOUS"]
+
+    def test_optional_from_2seq(self):
+        obj = self.num2seq
+        shape = (len(obj), )
+        a = self.array(shape, intent.optional, obj)
+        assert a.arr.shape == shape
+        assert not a.has_shared_memory()
+
+    def test_optional_from_23seq(self):
+        obj = self.num23seq
+        shape = (len(obj), len(obj[0]))
+        a = self.array(shape, intent.optional, obj)
+        assert a.arr.shape == shape
+        assert not a.has_shared_memory()
+
+        a = self.array(shape, intent.optional.c, obj)
+        assert a.arr.shape == shape
+        assert not a.has_shared_memory()
+
+    def test_inplace(self):
+        obj = np.array(self.num23seq, dtype=self.type.dtype)
+        assert not obj.flags["FORTRAN"] and obj.flags["CONTIGUOUS"]
+        shape = obj.shape
+        a = self.array(shape, intent.inplace, obj)
+        assert obj[1][2] == a.arr[1][2], repr((obj, a.arr))
+        a.arr[1][2] = 54
+        assert obj[1][2] == a.arr[1][2] == np.array(54, dtype=self.type.dtype)
+        assert a.arr is obj
+        assert obj.flags["FORTRAN"]  # obj attributes are changed inplace!
+        assert not obj.flags["CONTIGUOUS"]
+
+    def test_inplace_from_casttype(self):
+        for t in self.type.cast_types():
+            if t is self.type:
+                continue
+            obj = np.array(self.num23seq, dtype=t.dtype)
+            assert obj.dtype.type == t.type
+            assert obj.dtype.type is not self.type.type
+            assert not obj.flags["FORTRAN"] and obj.flags["CONTIGUOUS"]
+            shape = obj.shape
+            a = self.array(shape, intent.inplace, obj)
+            assert obj[1][2] == a.arr[1][2], repr((obj, a.arr))
+            a.arr[1][2] = 54
+            assert obj[1][2] == a.arr[1][2] == np.array(54,
+                                                        dtype=self.type.dtype)
+            assert a.arr is obj
+            assert obj.flags["FORTRAN"]  # obj attributes changed inplace!
+            assert not obj.flags["CONTIGUOUS"]
+            assert obj.dtype.type is self.type.type  # obj changed inplace!
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_assumed_shape.py b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_assumed_shape.py
new file mode 100644
index 00000000..d4664cf8
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_assumed_shape.py
@@ -0,0 +1,49 @@
+import os
+import pytest
+import tempfile
+
+from . import util
+
+
+class TestAssumedShapeSumExample(util.F2PyTest):
+    sources = [
+        util.getpath("tests", "src", "assumed_shape", "foo_free.f90"),
+        util.getpath("tests", "src", "assumed_shape", "foo_use.f90"),
+        util.getpath("tests", "src", "assumed_shape", "precision.f90"),
+        util.getpath("tests", "src", "assumed_shape", "foo_mod.f90"),
+        util.getpath("tests", "src", "assumed_shape", ".f2py_f2cmap"),
+    ]
+
+    @pytest.mark.slow
+    def test_all(self):
+        r = self.module.fsum([1, 2])
+        assert r == 3
+        r = self.module.sum([1, 2])
+        assert r == 3
+        r = self.module.sum_with_use([1, 2])
+        assert r == 3
+
+        r = self.module.mod.sum([1, 2])
+        assert r == 3
+        r = self.module.mod.fsum([1, 2])
+        assert r == 3
+
+
+class TestF2cmapOption(TestAssumedShapeSumExample):
+    def setup_method(self):
+        # Use a custom file name for .f2py_f2cmap
+        self.sources = list(self.sources)
+        f2cmap_src = self.sources.pop(-1)
+
+        self.f2cmap_file = tempfile.NamedTemporaryFile(delete=False)
+        with open(f2cmap_src, "rb") as f:
+            self.f2cmap_file.write(f.read())
+        self.f2cmap_file.close()
+
+        self.sources.append(self.f2cmap_file.name)
+        self.options = ["--f2cmap", self.f2cmap_file.name]
+
+        super().setup_method()
+
+    def teardown_method(self):
+        os.unlink(self.f2cmap_file.name)
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_block_docstring.py b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_block_docstring.py
new file mode 100644
index 00000000..e0eacc03
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_block_docstring.py
@@ -0,0 +1,17 @@
+import sys
+import pytest
+from . import util
+
+from numpy.testing import IS_PYPY
+
+
+class TestBlockDocString(util.F2PyTest):
+    sources = [util.getpath("tests", "src", "block_docstring", "foo.f")]
+
+    @pytest.mark.skipif(sys.platform == "win32",
+                        reason="Fails with MinGW64 Gfortran (Issue #9673)")
+    @pytest.mark.xfail(IS_PYPY,
+                       reason="PyPy cannot modify tp_doc after PyType_Ready")
+    def test_block_docstring(self):
+        expected = "bar : 'i'-array(2,3)\n"
+        assert self.module.block.__doc__ == expected
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_callback.py b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_callback.py
new file mode 100644
index 00000000..5b6c294d
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_callback.py
@@ -0,0 +1,243 @@
+import math
+import textwrap
+import sys
+import pytest
+import threading
+import traceback
+import time
+
+import numpy as np
+from numpy.testing import IS_PYPY
+from . import util
+
+
+class TestF77Callback(util.F2PyTest):
+    sources = [util.getpath("tests", "src", "callback", "foo.f")]
+
+    @pytest.mark.parametrize("name", "t,t2".split(","))
+    def test_all(self, name):
+        self.check_function(name)
+
+    @pytest.mark.xfail(IS_PYPY,
+                       reason="PyPy cannot modify tp_doc after PyType_Ready")
+    def test_docstring(self):
+        expected = textwrap.dedent("""\
+        a = t(fun,[fun_extra_args])
+
+        Wrapper for ``t``.
+
+        Parameters
+        ----------
+        fun : call-back function
+
+        Other Parameters
+        ----------------
+        fun_extra_args : input tuple, optional
+            Default: ()
+
+        Returns
+        -------
+        a : int
+
+        Notes
+        -----
+        Call-back functions::
+
+            def fun(): return a
+            Return objects:
+                a : int
+        """)
+        assert self.module.t.__doc__ == expected
+
+    def check_function(self, name):
+        t = getattr(self.module, name)
+        r = t(lambda: 4)
+        assert r == 4
+        r = t(lambda a: 5, fun_extra_args=(6, ))
+        assert r == 5
+        r = t(lambda a: a, fun_extra_args=(6, ))
+        assert r == 6
+        r = t(lambda a: 5 + a, fun_extra_args=(7, ))
+        assert r == 12
+        r = t(lambda a: math.degrees(a), fun_extra_args=(math.pi, ))
+        assert r == 180
+        r = t(math.degrees, fun_extra_args=(math.pi, ))
+        assert r == 180
+
+        r = t(self.module.func, fun_extra_args=(6, ))
+        assert r == 17
+        r = t(self.module.func0)
+        assert r == 11
+        r = t(self.module.func0._cpointer)
+        assert r == 11
+
+        class A:
+            def __call__(self):
+                return 7
+
+            def mth(self):
+                return 9
+
+        a = A()
+        r = t(a)
+        assert r == 7
+        r = t(a.mth)
+        assert r == 9
+
+    @pytest.mark.skipif(sys.platform == 'win32',
+                        reason='Fails with MinGW64 Gfortran (Issue #9673)')
+    def test_string_callback(self):
+        def callback(code):
+            if code == "r":
+                return 0
+            else:
+                return 1
+
+        f = getattr(self.module, "string_callback")
+        r = f(callback)
+        assert r == 0
+
+    @pytest.mark.skipif(sys.platform == 'win32',
+                        reason='Fails with MinGW64 Gfortran (Issue #9673)')
+    def test_string_callback_array(self):
+        # See gh-10027
+        cu1 = np.zeros((1, ), "S8")
+        cu2 = np.zeros((1, 8), "c")
+        cu3 = np.array([""], "S8")
+
+        def callback(cu, lencu):
+            if cu.shape != (lencu,):
+                return 1
+            if cu.dtype != "S8":
+                return 2
+            if not np.all(cu == b""):
+                return 3
+            return 0
+
+        f = getattr(self.module, "string_callback_array")
+        for cu in [cu1, cu2, cu3]:
+            res = f(callback, cu, cu.size)
+            assert res == 0
+
+    def test_threadsafety(self):
+        # Segfaults if the callback handling is not threadsafe
+
+        errors = []
+
+        def cb():
+            # Sleep here to make it more likely for another thread
+            # to call their callback at the same time.
+            time.sleep(1e-3)
+
+            # Check reentrancy
+            r = self.module.t(lambda: 123)
+            assert r == 123
+
+            return 42
+
+        def runner(name):
+            try:
+                for j in range(50):
+                    r = self.module.t(cb)
+                    assert r == 42
+                    self.check_function(name)
+            except Exception:
+                errors.append(traceback.format_exc())
+
+        threads = [
+            threading.Thread(target=runner, args=(arg, ))
+            for arg in ("t", "t2") for n in range(20)
+        ]
+
+        for t in threads:
+            t.start()
+
+        for t in threads:
+            t.join()
+
+        errors = "\n\n".join(errors)
+        if errors:
+            raise AssertionError(errors)
+
+    def test_hidden_callback(self):
+        try:
+            self.module.hidden_callback(2)
+        except Exception as msg:
+            assert str(msg).startswith("Callback global_f not defined")
+
+        try:
+            self.module.hidden_callback2(2)
+        except Exception as msg:
+            assert str(msg).startswith("cb: Callback global_f not defined")
+
+        self.module.global_f = lambda x: x + 1
+        r = self.module.hidden_callback(2)
+        assert r == 3
+
+        self.module.global_f = lambda x: x + 2
+        r = self.module.hidden_callback(2)
+        assert r == 4
+
+        del self.module.global_f
+        try:
+            self.module.hidden_callback(2)
+        except Exception as msg:
+            assert str(msg).startswith("Callback global_f not defined")
+
+        self.module.global_f = lambda x=0: x + 3
+        r = self.module.hidden_callback(2)
+        assert r == 5
+
+        # reproducer of gh18341
+        r = self.module.hidden_callback2(2)
+        assert r == 3
+
+
+class TestF77CallbackPythonTLS(TestF77Callback):
+    """
+    Callback tests using Python thread-local storage instead of
+    compiler-provided
+    """
+
+    options = ["-DF2PY_USE_PYTHON_TLS"]
+
+
+class TestF90Callback(util.F2PyTest):
+    sources = [util.getpath("tests", "src", "callback", "gh17797.f90")]
+
+    def test_gh17797(self):
+        def incr(x):
+            return x + 123
+
+        y = np.array([1, 2, 3], dtype=np.int64)
+        r = self.module.gh17797(incr, y)
+        assert r == 123 + 1 + 2 + 3
+
+
+class TestGH18335(util.F2PyTest):
+    """The reproduction of the reported issue requires specific input that
+    extensions may break the issue conditions, so the reproducer is
+    implemented as a separate test class. Do not extend this test with
+    other tests!
+    """
+    sources = [util.getpath("tests", "src", "callback", "gh18335.f90")]
+
+    def test_gh18335(self):
+        def foo(x):
+            x[0] += 1
+
+        r = self.module.gh18335(foo)
+        assert r == 123 + 1
+
+
+class TestGH25211(util.F2PyTest):
+    sources = [util.getpath("tests", "src", "callback", "gh25211.f"),
+               util.getpath("tests", "src", "callback", "gh25211.pyf")]
+    module_name = "callback2"
+
+    def test_gh18335(self):
+        def bar(x):
+            return x*x
+
+        res = self.module.foo(bar)
+        assert res == 110
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_character.py b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_character.py
new file mode 100644
index 00000000..e55b1b6b
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_character.py
@@ -0,0 +1,636 @@
+import pytest
+import textwrap
+from numpy.testing import assert_array_equal, assert_equal, assert_raises
+import numpy as np
+from numpy.f2py.tests import util
+
+
+class TestCharacterString(util.F2PyTest):
+    # options = ['--debug-capi', '--build-dir', '/tmp/test-build-f2py']
+    suffix = '.f90'
+    fprefix = 'test_character_string'
+    length_list = ['1', '3', 'star']
+
+    code = ''
+    for length in length_list:
+        fsuffix = length
+        clength = dict(star='(*)').get(length, length)
+
+        code += textwrap.dedent(f"""
+
+        subroutine {fprefix}_input_{fsuffix}(c, o, n)
+          character*{clength}, intent(in) :: c
+          integer n
+          !f2py integer, depend(c), intent(hide) :: n = slen(c)
+          integer*1, dimension(n) :: o
+          !f2py intent(out) o
+          o = transfer(c, o)
+        end subroutine {fprefix}_input_{fsuffix}
+
+        subroutine {fprefix}_output_{fsuffix}(c, o, n)
+          character*{clength}, intent(out) :: c
+          integer n
+          integer*1, dimension(n), intent(in) :: o
+          !f2py integer, depend(o), intent(hide) :: n = len(o)
+          c = transfer(o, c)
+        end subroutine {fprefix}_output_{fsuffix}
+
+        subroutine {fprefix}_array_input_{fsuffix}(c, o, m, n)
+          integer m, i, n
+          character*{clength}, intent(in), dimension(m) :: c
+          !f2py integer, depend(c), intent(hide) :: m = len(c)
+          !f2py integer, depend(c), intent(hide) :: n = f2py_itemsize(c)
+          integer*1, dimension(m, n), intent(out) :: o
+          do i=1,m
+            o(i, :) = transfer(c(i), o(i, :))
+          end do
+        end subroutine {fprefix}_array_input_{fsuffix}
+
+        subroutine {fprefix}_array_output_{fsuffix}(c, o, m, n)
+          character*{clength}, intent(out), dimension(m) :: c
+          integer n
+          integer*1, dimension(m, n), intent(in) :: o
+          !f2py character(f2py_len=n) :: c
+          !f2py integer, depend(o), intent(hide) :: m = len(o)
+          !f2py integer, depend(o), intent(hide) :: n = shape(o, 1)
+          do i=1,m
+            c(i) = transfer(o(i, :), c(i))
+          end do
+        end subroutine {fprefix}_array_output_{fsuffix}
+
+        subroutine {fprefix}_2d_array_input_{fsuffix}(c, o, m1, m2, n)
+          integer m1, m2, i, j, n
+          character*{clength}, intent(in), dimension(m1, m2) :: c
+          !f2py integer, depend(c), intent(hide) :: m1 = len(c)
+          !f2py integer, depend(c), intent(hide) :: m2 = shape(c, 1)
+          !f2py integer, depend(c), intent(hide) :: n = f2py_itemsize(c)
+          integer*1, dimension(m1, m2, n), intent(out) :: o
+          do i=1,m1
+            do j=1,m2
+              o(i, j, :) = transfer(c(i, j), o(i, j, :))
+            end do
+          end do
+        end subroutine {fprefix}_2d_array_input_{fsuffix}
+        """)
+
+    @pytest.mark.parametrize("length", length_list)
+    def test_input(self, length):
+        fsuffix = {'(*)': 'star'}.get(length, length)
+        f = getattr(self.module, self.fprefix + '_input_' + fsuffix)
+
+        a = {'1': 'a', '3': 'abc', 'star': 'abcde' * 3}[length]
+
+        assert_array_equal(f(a), np.array(list(map(ord, a)), dtype='u1'))
+
+    @pytest.mark.parametrize("length", length_list[:-1])
+    def test_output(self, length):
+        fsuffix = length
+        f = getattr(self.module, self.fprefix + '_output_' + fsuffix)
+
+        a = {'1': 'a', '3': 'abc'}[length]
+
+        assert_array_equal(f(np.array(list(map(ord, a)), dtype='u1')),
+                           a.encode())
+
+    @pytest.mark.parametrize("length", length_list)
+    def test_array_input(self, length):
+        fsuffix = length
+        f = getattr(self.module, self.fprefix + '_array_input_' + fsuffix)
+
+        a = np.array([{'1': 'a', '3': 'abc', 'star': 'abcde' * 3}[length],
+                      {'1': 'A', '3': 'ABC', 'star': 'ABCDE' * 3}[length],
+                      ], dtype='S')
+
+        expected = np.array([[c for c in s] for s in a], dtype='u1')
+        assert_array_equal(f(a), expected)
+
+    @pytest.mark.parametrize("length", length_list)
+    def test_array_output(self, length):
+        fsuffix = length
+        f = getattr(self.module, self.fprefix + '_array_output_' + fsuffix)
+
+        expected = np.array(
+            [{'1': 'a', '3': 'abc', 'star': 'abcde' * 3}[length],
+             {'1': 'A', '3': 'ABC', 'star': 'ABCDE' * 3}[length]], dtype='S')
+
+        a = np.array([[c for c in s] for s in expected], dtype='u1')
+        assert_array_equal(f(a), expected)
+
+    @pytest.mark.parametrize("length", length_list)
+    def test_2d_array_input(self, length):
+        fsuffix = length
+        f = getattr(self.module, self.fprefix + '_2d_array_input_' + fsuffix)
+
+        a = np.array([[{'1': 'a', '3': 'abc', 'star': 'abcde' * 3}[length],
+                       {'1': 'A', '3': 'ABC', 'star': 'ABCDE' * 3}[length]],
+                      [{'1': 'f', '3': 'fgh', 'star': 'fghij' * 3}[length],
+                       {'1': 'F', '3': 'FGH', 'star': 'FGHIJ' * 3}[length]]],
+                     dtype='S')
+        expected = np.array([[[c for c in item] for item in row] for row in a],
+                            dtype='u1', order='F')
+        assert_array_equal(f(a), expected)
+
+
+class TestCharacter(util.F2PyTest):
+    # options = ['--debug-capi', '--build-dir', '/tmp/test-build-f2py']
+    suffix = '.f90'
+    fprefix = 'test_character'
+
+    code = textwrap.dedent(f"""
+       subroutine {fprefix}_input(c, o)
+          character, intent(in) :: c
+          integer*1 o
+          !f2py intent(out) o
+          o = transfer(c, o)
+       end subroutine {fprefix}_input
+
+       subroutine {fprefix}_output(c, o)
+          character :: c
+          integer*1, intent(in) :: o
+          !f2py intent(out) c
+          c = transfer(o, c)
+       end subroutine {fprefix}_output
+
+       subroutine {fprefix}_input_output(c, o)
+          character, intent(in) :: c
+          character o
+          !f2py intent(out) o
+          o = c
+       end subroutine {fprefix}_input_output
+
+       subroutine {fprefix}_inout(c, n)
+          character :: c, n
+          !f2py intent(in) n
+          !f2py intent(inout) c
+          c = n
+       end subroutine {fprefix}_inout
+
+       function {fprefix}_return(o) result (c)
+          character :: c
+          character, intent(in) :: o
+          c = transfer(o, c)
+       end function {fprefix}_return
+
+       subroutine {fprefix}_array_input(c, o)
+          character, intent(in) :: c(3)
+          integer*1 o(3)
+          !f2py intent(out) o
+          integer i
+          do i=1,3
+            o(i) = transfer(c(i), o(i))
+          end do
+       end subroutine {fprefix}_array_input
+
+       subroutine {fprefix}_2d_array_input(c, o)
+          character, intent(in) :: c(2, 3)
+          integer*1 o(2, 3)
+          !f2py intent(out) o
+          integer i, j
+          do i=1,2
+            do j=1,3
+              o(i, j) = transfer(c(i, j), o(i, j))
+            end do
+          end do
+       end subroutine {fprefix}_2d_array_input
+
+       subroutine {fprefix}_array_output(c, o)
+          character :: c(3)
+          integer*1, intent(in) :: o(3)
+          !f2py intent(out) c
+          do i=1,3
+            c(i) = transfer(o(i), c(i))
+          end do
+       end subroutine {fprefix}_array_output
+
+       subroutine {fprefix}_array_inout(c, n)
+          character :: c(3), n(3)
+          !f2py intent(in) n(3)
+          !f2py intent(inout) c(3)
+          do i=1,3
+            c(i) = n(i)
+          end do
+       end subroutine {fprefix}_array_inout
+
+       subroutine {fprefix}_2d_array_inout(c, n)
+          character :: c(2, 3), n(2, 3)
+          !f2py intent(in) n(2, 3)
+          !f2py intent(inout) c(2. 3)
+          integer i, j
+          do i=1,2
+            do j=1,3
+              c(i, j) = n(i, j)
+            end do
+          end do
+       end subroutine {fprefix}_2d_array_inout
+
+       function {fprefix}_array_return(o) result (c)
+          character, dimension(3) :: c
+          character, intent(in) :: o(3)
+          do i=1,3
+            c(i) = o(i)
+          end do
+       end function {fprefix}_array_return
+
+       function {fprefix}_optional(o) result (c)
+          character, intent(in) :: o
+          !f2py character o = "a"
+          character :: c
+          c = o
+       end function {fprefix}_optional
+    """)
+
+    @pytest.mark.parametrize("dtype", ['c', 'S1'])
+    def test_input(self, dtype):
+        f = getattr(self.module, self.fprefix + '_input')
+
+        assert_equal(f(np.array('a', dtype=dtype)), ord('a'))
+        assert_equal(f(np.array(b'a', dtype=dtype)), ord('a'))
+        assert_equal(f(np.array(['a'], dtype=dtype)), ord('a'))
+        assert_equal(f(np.array('abc', dtype=dtype)), ord('a'))
+        assert_equal(f(np.array([['a']], dtype=dtype)), ord('a'))
+
+    def test_input_varia(self):
+        f = getattr(self.module, self.fprefix + '_input')
+
+        assert_equal(f('a'), ord('a'))
+        assert_equal(f(b'a'), ord(b'a'))
+        assert_equal(f(''), 0)
+        assert_equal(f(b''), 0)
+        assert_equal(f(b'\0'), 0)
+        assert_equal(f('ab'), ord('a'))
+        assert_equal(f(b'ab'), ord('a'))
+        assert_equal(f(['a']), ord('a'))
+
+        assert_equal(f(np.array(b'a')), ord('a'))
+        assert_equal(f(np.array([b'a'])), ord('a'))
+        a = np.array('a')
+        assert_equal(f(a), ord('a'))
+        a = np.array(['a'])
+        assert_equal(f(a), ord('a'))
+
+        try:
+            f([])
+        except IndexError as msg:
+            if not str(msg).endswith(' got 0-list'):
+                raise
+        else:
+            raise SystemError(f'{f.__name__} should have failed on empty list')
+
+        try:
+            f(97)
+        except TypeError as msg:
+            if not str(msg).endswith(' got int instance'):
+                raise
+        else:
+            raise SystemError(f'{f.__name__} should have failed on int value')
+
+    @pytest.mark.parametrize("dtype", ['c', 'S1', 'U1'])
+    def test_array_input(self, dtype):
+        f = getattr(self.module, self.fprefix + '_array_input')
+
+        assert_array_equal(f(np.array(['a', 'b', 'c'], dtype=dtype)),
+                           np.array(list(map(ord, 'abc')), dtype='i1'))
+        assert_array_equal(f(np.array([b'a', b'b', b'c'], dtype=dtype)),
+                           np.array(list(map(ord, 'abc')), dtype='i1'))
+
+    def test_array_input_varia(self):
+        f = getattr(self.module, self.fprefix + '_array_input')
+        assert_array_equal(f(['a', 'b', 'c']),
+                           np.array(list(map(ord, 'abc')), dtype='i1'))
+        assert_array_equal(f([b'a', b'b', b'c']),
+                           np.array(list(map(ord, 'abc')), dtype='i1'))
+
+        try:
+            f(['a', 'b', 'c', 'd'])
+        except ValueError as msg:
+            if not str(msg).endswith(
+                    'th dimension must be fixed to 3 but got 4'):
+                raise
+        else:
+            raise SystemError(
+                f'{f.__name__} should have failed on wrong input')
+
+    @pytest.mark.parametrize("dtype", ['c', 'S1', 'U1'])
+    def test_2d_array_input(self, dtype):
+        f = getattr(self.module, self.fprefix + '_2d_array_input')
+
+        a = np.array([['a', 'b', 'c'],
+                      ['d', 'e', 'f']], dtype=dtype, order='F')
+        expected = a.view(np.uint32 if dtype == 'U1' else np.uint8)
+        assert_array_equal(f(a), expected)
+
+    def test_output(self):
+        f = getattr(self.module, self.fprefix + '_output')
+
+        assert_equal(f(ord(b'a')), b'a')
+        assert_equal(f(0), b'\0')
+
+    def test_array_output(self):
+        f = getattr(self.module, self.fprefix + '_array_output')
+
+        assert_array_equal(f(list(map(ord, 'abc'))),
+                           np.array(list('abc'), dtype='S1'))
+
+    def test_input_output(self):
+        f = getattr(self.module, self.fprefix + '_input_output')
+
+        assert_equal(f(b'a'), b'a')
+        assert_equal(f('a'), b'a')
+        assert_equal(f(''), b'\0')
+
+    @pytest.mark.parametrize("dtype", ['c', 'S1'])
+    def test_inout(self, dtype):
+        f = getattr(self.module, self.fprefix + '_inout')
+
+        a = np.array(list('abc'), dtype=dtype)
+        f(a, 'A')
+        assert_array_equal(a, np.array(list('Abc'), dtype=a.dtype))
+        f(a[1:], 'B')
+        assert_array_equal(a, np.array(list('ABc'), dtype=a.dtype))
+
+        a = np.array(['abc'], dtype=dtype)
+        f(a, 'A')
+        assert_array_equal(a, np.array(['Abc'], dtype=a.dtype))
+
+    def test_inout_varia(self):
+        f = getattr(self.module, self.fprefix + '_inout')
+        a = np.array('abc', dtype='S3')
+        f(a, 'A')
+        assert_array_equal(a, np.array('Abc', dtype=a.dtype))
+
+        a = np.array(['abc'], dtype='S3')
+        f(a, 'A')
+        assert_array_equal(a, np.array(['Abc'], dtype=a.dtype))
+
+        try:
+            f('abc', 'A')
+        except ValueError as msg:
+            if not str(msg).endswith(' got 3-str'):
+                raise
+        else:
+            raise SystemError(f'{f.__name__} should have failed on str value')
+
+    @pytest.mark.parametrize("dtype", ['c', 'S1'])
+    def test_array_inout(self, dtype):
+        f = getattr(self.module, self.fprefix + '_array_inout')
+        n = np.array(['A', 'B', 'C'], dtype=dtype, order='F')
+
+        a = np.array(['a', 'b', 'c'], dtype=dtype, order='F')
+        f(a, n)
+        assert_array_equal(a, n)
+
+        a = np.array(['a', 'b', 'c', 'd'], dtype=dtype)
+        f(a[1:], n)
+        assert_array_equal(a, np.array(['a', 'A', 'B', 'C'], dtype=dtype))
+
+        a = np.array([['a', 'b', 'c']], dtype=dtype, order='F')
+        f(a, n)
+        assert_array_equal(a, np.array([['A', 'B', 'C']], dtype=dtype))
+
+        a = np.array(['a', 'b', 'c', 'd'], dtype=dtype, order='F')
+        try:
+            f(a, n)
+        except ValueError as msg:
+            if not str(msg).endswith(
+                    'th dimension must be fixed to 3 but got 4'):
+                raise
+        else:
+            raise SystemError(
+                f'{f.__name__} should have failed on wrong input')
+
+    @pytest.mark.parametrize("dtype", ['c', 'S1'])
+    def test_2d_array_inout(self, dtype):
+        f = getattr(self.module, self.fprefix + '_2d_array_inout')
+        n = np.array([['A', 'B', 'C'],
+                      ['D', 'E', 'F']],
+                     dtype=dtype, order='F')
+        a = np.array([['a', 'b', 'c'],
+                      ['d', 'e', 'f']],
+                     dtype=dtype, order='F')
+        f(a, n)
+        assert_array_equal(a, n)
+
+    def test_return(self):
+        f = getattr(self.module, self.fprefix + '_return')
+
+        assert_equal(f('a'), b'a')
+
+    @pytest.mark.skip('fortran function returning array segfaults')
+    def test_array_return(self):
+        f = getattr(self.module, self.fprefix + '_array_return')
+
+        a = np.array(list('abc'), dtype='S1')
+        assert_array_equal(f(a), a)
+
+    def test_optional(self):
+        f = getattr(self.module, self.fprefix + '_optional')
+
+        assert_equal(f(), b"a")
+        assert_equal(f(b'B'), b"B")
+
+
+class TestMiscCharacter(util.F2PyTest):
+    # options = ['--debug-capi', '--build-dir', '/tmp/test-build-f2py']
+    suffix = '.f90'
+    fprefix = 'test_misc_character'
+
+    code = textwrap.dedent(f"""
+       subroutine {fprefix}_gh18684(x, y, m)
+         character(len=5), dimension(m), intent(in) :: x
+         character*5, dimension(m), intent(out) :: y
+         integer i, m
+         !f2py integer, intent(hide), depend(x) :: m = f2py_len(x)
+         do i=1,m
+           y(i) = x(i)
+         end do
+       end subroutine {fprefix}_gh18684
+
+       subroutine {fprefix}_gh6308(x, i)
+         integer i
+         !f2py check(i>=0 && i<12) i
+         character*5 name, x
+         common name(12)
+         name(i + 1) = x
+       end subroutine {fprefix}_gh6308
+
+       subroutine {fprefix}_gh4519(x)
+         character(len=*), intent(in) :: x(:)
+         !f2py intent(out) x
+         integer :: i
+         ! Uncomment for debug printing:
+         !do i=1, size(x)
+         !   print*, "x(",i,")=", x(i)
+         !end do
+       end subroutine {fprefix}_gh4519
+
+       pure function {fprefix}_gh3425(x) result (y)
+         character(len=*), intent(in) :: x
+         character(len=len(x)) :: y
+         integer :: i
+         do i = 1, len(x)
+           j = iachar(x(i:i))
+           if (j>=iachar("a") .and. j<=iachar("z") ) then
+             y(i:i) = achar(j-32)
+           else
+             y(i:i) = x(i:i)
+           endif
+         end do
+       end function {fprefix}_gh3425
+
+       subroutine {fprefix}_character_bc_new(x, y, z)
+         character, intent(in) :: x
+         character, intent(out) :: y
+         !f2py character, depend(x) :: y = x
+         !f2py character, dimension((x=='a'?1:2)), depend(x), intent(out) :: z
+         character, dimension(*) :: z
+         !f2py character, optional, check(x == 'a' || x == 'b') :: x = 'a'
+         !f2py callstatement (*f2py_func)(&x, &y, z)
+         !f2py callprotoargument character*, character*, character*
+         if (y.eq.x) then
+           y = x
+         else
+           y = 'e'
+         endif
+         z(1) = 'c'
+       end subroutine {fprefix}_character_bc_new
+
+       subroutine {fprefix}_character_bc_old(x, y, z)
+         character, intent(in) :: x
+         character, intent(out) :: y
+         !f2py character, depend(x) :: y = x[0]
+         !f2py character, dimension((*x=='a'?1:2)), depend(x), intent(out) :: z
+         character, dimension(*) :: z
+         !f2py character, optional, check(*x == 'a' || x[0] == 'b') :: x = 'a'
+         !f2py callstatement (*f2py_func)(x, y, z)
+         !f2py callprotoargument char*, char*, char*
+          if (y.eq.x) then
+           y = x
+         else
+           y = 'e'
+         endif
+         z(1) = 'c'
+       end subroutine {fprefix}_character_bc_old
+    """)
+
+    def test_gh18684(self):
+        # Test character(len=5) and character*5 usages
+        f = getattr(self.module, self.fprefix + '_gh18684')
+        x = np.array(["abcde", "fghij"], dtype='S5')
+        y = f(x)
+
+        assert_array_equal(x, y)
+
+    def test_gh6308(self):
+        # Test character string array in a common block
+        f = getattr(self.module, self.fprefix + '_gh6308')
+
+        assert_equal(self.module._BLNK_.name.dtype, np.dtype('S5'))
+        assert_equal(len(self.module._BLNK_.name), 12)
+        f("abcde", 0)
+        assert_equal(self.module._BLNK_.name[0], b"abcde")
+        f("12345", 5)
+        assert_equal(self.module._BLNK_.name[5], b"12345")
+
+    def test_gh4519(self):
+        # Test array of assumed length strings
+        f = getattr(self.module, self.fprefix + '_gh4519')
+
+        for x, expected in [
+                ('a', dict(shape=(), dtype=np.dtype('S1'))),
+                ('text', dict(shape=(), dtype=np.dtype('S4'))),
+                (np.array(['1', '2', '3'], dtype='S1'),
+                 dict(shape=(3,), dtype=np.dtype('S1'))),
+                (['1', '2', '34'],
+                 dict(shape=(3,), dtype=np.dtype('S2'))),
+                (['', ''], dict(shape=(2,), dtype=np.dtype('S1')))]:
+            r = f(x)
+            for k, v in expected.items():
+                assert_equal(getattr(r, k), v)
+
+    def test_gh3425(self):
+        # Test returning a copy of assumed length string
+        f = getattr(self.module, self.fprefix + '_gh3425')
+        # f is equivalent to bytes.upper
+
+        assert_equal(f('abC'), b'ABC')
+        assert_equal(f(''), b'')
+        assert_equal(f('abC12d'), b'ABC12D')
+
+    @pytest.mark.parametrize("state", ['new', 'old'])
+    def test_character_bc(self, state):
+        f = getattr(self.module, self.fprefix + '_character_bc_' + state)
+
+        c, a = f()
+        assert_equal(c, b'a')
+        assert_equal(len(a), 1)
+
+        c, a = f(b'b')
+        assert_equal(c, b'b')
+        assert_equal(len(a), 2)
+
+        assert_raises(Exception, lambda: f(b'c'))
+
+
+class TestStringScalarArr(util.F2PyTest):
+    sources = [util.getpath("tests", "src", "string", "scalar_string.f90")]
+
+    def test_char(self):
+        for out in (self.module.string_test.string,
+                    self.module.string_test.string77):
+            expected = ()
+            assert out.shape == expected
+            expected = '|S8'
+            assert out.dtype == expected
+
+    def test_char_arr(self):
+        for out in (self.module.string_test.strarr,
+                    self.module.string_test.strarr77):
+            expected = (5,7)
+            assert out.shape == expected
+            expected = '|S12'
+            assert out.dtype == expected
+
+class TestStringAssumedLength(util.F2PyTest):
+    sources = [util.getpath("tests", "src", "string", "gh24008.f")]
+
+    def test_gh24008(self):
+        self.module.greet("joe", "bob")
+
+class TestStringOptionalInOut(util.F2PyTest):
+    sources = [util.getpath("tests", "src", "string", "gh24662.f90")]
+
+    def test_gh24662(self):
+        self.module.string_inout_optional()
+        a = np.array('hi', dtype='S32')
+        self.module.string_inout_optional(a)
+        assert "output string" in a.tobytes().decode()
+        with pytest.raises(Exception):
+            aa = "Hi"
+            self.module.string_inout_optional(aa)
+
+
+@pytest.mark.slow
+class TestNewCharHandling(util.F2PyTest):
+    # from v1.24 onwards, gh-19388
+    sources = [
+        util.getpath("tests", "src", "string", "gh25286.pyf"),
+        util.getpath("tests", "src", "string", "gh25286.f90")
+    ]
+    module_name = "_char_handling_test"
+
+    def test_gh25286(self):
+        info = self.module.charint('T')
+        assert info == 2
+
+@pytest.mark.slow
+class TestBCCharHandling(util.F2PyTest):
+    # SciPy style, "incorrect" bindings with a hook
+    sources = [
+        util.getpath("tests", "src", "string", "gh25286_bc.pyf"),
+        util.getpath("tests", "src", "string", "gh25286.f90")
+    ]
+    module_name = "_char_handling_test"
+
+    def test_gh25286(self):
+        info = self.module.charint('T')
+        assert info == 2
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_common.py b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_common.py
new file mode 100644
index 00000000..68c1b3b3
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_common.py
@@ -0,0 +1,27 @@
+import os
+import sys
+import pytest
+
+import numpy as np
+from . import util
+
+
+class TestCommonBlock(util.F2PyTest):
+    sources = [util.getpath("tests", "src", "common", "block.f")]
+
+    @pytest.mark.skipif(sys.platform == "win32",
+                        reason="Fails with MinGW64 Gfortran (Issue #9673)")
+    def test_common_block(self):
+        self.module.initcb()
+        assert self.module.block.long_bn == np.array(1.0, dtype=np.float64)
+        assert self.module.block.string_bn == np.array("2", dtype="|S1")
+        assert self.module.block.ok == np.array(3, dtype=np.int32)
+
+
+class TestCommonWithUse(util.F2PyTest):
+    sources = [util.getpath("tests", "src", "common", "gh19161.f90")]
+
+    @pytest.mark.skipif(sys.platform == "win32",
+                        reason="Fails with MinGW64 Gfortran (Issue #9673)")
+    def test_common_gh19161(self):
+        assert self.module.data.x == 0
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_compile_function.py b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_compile_function.py
new file mode 100644
index 00000000..3c16f319
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_compile_function.py
@@ -0,0 +1,117 @@
+"""See https://github.com/numpy/numpy/pull/11937.
+
+"""
+import sys
+import os
+import uuid
+from importlib import import_module
+import pytest
+
+import numpy.f2py
+
+from . import util
+
+
+def setup_module():
+    if not util.has_c_compiler():
+        pytest.skip("Needs C compiler")
+    if not util.has_f77_compiler():
+        pytest.skip("Needs FORTRAN 77 compiler")
+
+
+# extra_args can be a list (since gh-11937) or string.
+# also test absence of extra_args
+@pytest.mark.parametrize("extra_args",
+                         [["--noopt", "--debug"], "--noopt --debug", ""])
+@pytest.mark.leaks_references(reason="Imported module seems never deleted.")
+def test_f2py_init_compile(extra_args):
+    # flush through the f2py __init__ compile() function code path as a
+    # crude test for input handling following migration from
+    # exec_command() to subprocess.check_output() in gh-11937
+
+    # the Fortran 77 syntax requires 6 spaces before any commands, but
+    # more space may be added/
+    fsource = """
+        integer function foo()
+        foo = 10 + 5
+        return
+        end
+    """
+    # use various helper functions in util.py to enable robust build /
+    # compile and reimport cycle in test suite
+    moddir = util.get_module_dir()
+    modname = util.get_temp_module_name()
+
+    cwd = os.getcwd()
+    target = os.path.join(moddir, str(uuid.uuid4()) + ".f")
+    # try running compile() with and without a source_fn provided so
+    # that the code path where a temporary file for writing Fortran
+    # source is created is also explored
+    for source_fn in [target, None]:
+        # mimic the path changing behavior used by build_module() in
+        # util.py, but don't actually use build_module() because it has
+        # its own invocation of subprocess that circumvents the
+        # f2py.compile code block under test
+        with util.switchdir(moddir):
+            ret_val = numpy.f2py.compile(fsource,
+                                         modulename=modname,
+                                         extra_args=extra_args,
+                                         source_fn=source_fn)
+
+            # check for compile success return value
+            assert ret_val == 0
+
+    # we are not currently able to import the Python-Fortran
+    # interface module on Windows / Appveyor, even though we do get
+    # successful compilation on that platform with Python 3.x
+    if sys.platform != "win32":
+        # check for sensible result of Fortran function; that means
+        # we can import the module name in Python and retrieve the
+        # result of the sum operation
+        return_check = import_module(modname)
+        calc_result = return_check.foo()
+        assert calc_result == 15
+        # Removal from sys.modules, is not as such necessary. Even with
+        # removal, the module (dict) stays alive.
+        del sys.modules[modname]
+
+
+def test_f2py_init_compile_failure():
+    # verify an appropriate integer status value returned by
+    # f2py.compile() when invalid Fortran is provided
+    ret_val = numpy.f2py.compile(b"invalid")
+    assert ret_val == 1
+
+
+def test_f2py_init_compile_bad_cmd():
+    # verify that usage of invalid command in f2py.compile() returns
+    # status value of 127 for historic consistency with exec_command()
+    # error handling
+
+    # patch the sys Python exe path temporarily to induce an OSError
+    # downstream NOTE: how bad of an idea is this patching?
+    try:
+        temp = sys.executable
+        sys.executable = "does not exist"
+
+        # the OSError should take precedence over invalid Fortran
+        ret_val = numpy.f2py.compile(b"invalid")
+        assert ret_val == 127
+    finally:
+        sys.executable = temp
+
+
+@pytest.mark.parametrize(
+    "fsource",
+    [
+        "program test_f2py\nend program test_f2py",
+        b"program test_f2py\nend program test_f2py",
+    ],
+)
+def test_compile_from_strings(tmpdir, fsource):
+    # Make sure we can compile str and bytes gh-12796
+    with util.switchdir(tmpdir):
+        ret_val = numpy.f2py.compile(fsource,
+                                     modulename="test_compile_from_strings",
+                                     extension=".f90")
+        assert ret_val == 0
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_crackfortran.py b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_crackfortran.py
new file mode 100644
index 00000000..c8d9ddb8
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_crackfortran.py
@@ -0,0 +1,350 @@
+import importlib
+import codecs
+import time
+import unicodedata
+import pytest
+import numpy as np
+from numpy.f2py.crackfortran import markinnerspaces, nameargspattern
+from . import util
+from numpy.f2py import crackfortran
+import textwrap
+import contextlib
+import io
+
+
+class TestNoSpace(util.F2PyTest):
+    # issue gh-15035: add handling for endsubroutine, endfunction with no space
+    # between "end" and the block name
+    sources = [util.getpath("tests", "src", "crackfortran", "gh15035.f")]
+
+    def test_module(self):
+        k = np.array([1, 2, 3], dtype=np.float64)
+        w = np.array([1, 2, 3], dtype=np.float64)
+        self.module.subb(k)
+        assert np.allclose(k, w + 1)
+        self.module.subc([w, k])
+        assert np.allclose(k, w + 1)
+        assert self.module.t0("23") == b"2"
+
+
+class TestPublicPrivate:
+    def test_defaultPrivate(self):
+        fpath = util.getpath("tests", "src", "crackfortran", "privatemod.f90")
+        mod = crackfortran.crackfortran([str(fpath)])
+        assert len(mod) == 1
+        mod = mod[0]
+        assert "private" in mod["vars"]["a"]["attrspec"]
+        assert "public" not in mod["vars"]["a"]["attrspec"]
+        assert "private" in mod["vars"]["b"]["attrspec"]
+        assert "public" not in mod["vars"]["b"]["attrspec"]
+        assert "private" not in mod["vars"]["seta"]["attrspec"]
+        assert "public" in mod["vars"]["seta"]["attrspec"]
+
+    def test_defaultPublic(self, tmp_path):
+        fpath = util.getpath("tests", "src", "crackfortran", "publicmod.f90")
+        mod = crackfortran.crackfortran([str(fpath)])
+        assert len(mod) == 1
+        mod = mod[0]
+        assert "private" in mod["vars"]["a"]["attrspec"]
+        assert "public" not in mod["vars"]["a"]["attrspec"]
+        assert "private" not in mod["vars"]["seta"]["attrspec"]
+        assert "public" in mod["vars"]["seta"]["attrspec"]
+
+    def test_access_type(self, tmp_path):
+        fpath = util.getpath("tests", "src", "crackfortran", "accesstype.f90")
+        mod = crackfortran.crackfortran([str(fpath)])
+        assert len(mod) == 1
+        tt = mod[0]['vars']
+        assert set(tt['a']['attrspec']) == {'private', 'bind(c)'}
+        assert set(tt['b_']['attrspec']) == {'public', 'bind(c)'}
+        assert set(tt['c']['attrspec']) == {'public'}
+
+    def test_nowrap_private_proceedures(self, tmp_path):
+        fpath = util.getpath("tests", "src", "crackfortran", "gh23879.f90")
+        mod = crackfortran.crackfortran([str(fpath)])
+        assert len(mod) == 1
+        pyf = crackfortran.crack2fortran(mod)
+        assert 'bar' not in pyf
+
+class TestModuleProcedure():
+    def test_moduleOperators(self, tmp_path):
+        fpath = util.getpath("tests", "src", "crackfortran", "operators.f90")
+        mod = crackfortran.crackfortran([str(fpath)])
+        assert len(mod) == 1
+        mod = mod[0]
+        assert "body" in mod and len(mod["body"]) == 9
+        assert mod["body"][1]["name"] == "operator(.item.)"
+        assert "implementedby" in mod["body"][1]
+        assert mod["body"][1]["implementedby"] == \
+            ["item_int", "item_real"]
+        assert mod["body"][2]["name"] == "operator(==)"
+        assert "implementedby" in mod["body"][2]
+        assert mod["body"][2]["implementedby"] == ["items_are_equal"]
+        assert mod["body"][3]["name"] == "assignment(=)"
+        assert "implementedby" in mod["body"][3]
+        assert mod["body"][3]["implementedby"] == \
+            ["get_int", "get_real"]
+
+    def test_notPublicPrivate(self, tmp_path):
+        fpath = util.getpath("tests", "src", "crackfortran", "pubprivmod.f90")
+        mod = crackfortran.crackfortran([str(fpath)])
+        assert len(mod) == 1
+        mod = mod[0]
+        assert mod['vars']['a']['attrspec'] == ['private', ]
+        assert mod['vars']['b']['attrspec'] == ['public', ]
+        assert mod['vars']['seta']['attrspec'] == ['public', ]
+
+
+class TestExternal(util.F2PyTest):
+    # issue gh-17859: add external attribute support
+    sources = [util.getpath("tests", "src", "crackfortran", "gh17859.f")]
+
+    def test_external_as_statement(self):
+        def incr(x):
+            return x + 123
+
+        r = self.module.external_as_statement(incr)
+        assert r == 123
+
+    def test_external_as_attribute(self):
+        def incr(x):
+            return x + 123
+
+        r = self.module.external_as_attribute(incr)
+        assert r == 123
+
+
+class TestCrackFortran(util.F2PyTest):
+    # gh-2848: commented lines between parameters in subroutine parameter lists
+    sources = [util.getpath("tests", "src", "crackfortran", "gh2848.f90")]
+
+    def test_gh2848(self):
+        r = self.module.gh2848(1, 2)
+        assert r == (1, 2)
+
+
+class TestMarkinnerspaces:
+    # gh-14118: markinnerspaces does not handle multiple quotations
+
+    def test_do_not_touch_normal_spaces(self):
+        test_list = ["a ", " a", "a b c", "'abcdefghij'"]
+        for i in test_list:
+            assert markinnerspaces(i) == i
+
+    def test_one_relevant_space(self):
+        assert markinnerspaces("a 'b c' \\' \\'") == "a 'b@_@c' \\' \\'"
+        assert markinnerspaces(r'a "b c" \" \"') == r'a "b@_@c" \" \"'
+
+    def test_ignore_inner_quotes(self):
+        assert markinnerspaces("a 'b c\" \" d' e") == "a 'b@_@c\"@_@\"@_@d' e"
+        assert markinnerspaces("a \"b c' ' d\" e") == "a \"b@_@c'@_@'@_@d\" e"
+
+    def test_multiple_relevant_spaces(self):
+        assert markinnerspaces("a 'b c' 'd e'") == "a 'b@_@c' 'd@_@e'"
+        assert markinnerspaces(r'a "b c" "d e"') == r'a "b@_@c" "d@_@e"'
+
+
+class TestDimSpec(util.F2PyTest):
+    """This test suite tests various expressions that are used as dimension
+    specifications.
+
+    There exists two usage cases where analyzing dimensions
+    specifications are important.
+
+    In the first case, the size of output arrays must be defined based
+    on the inputs to a Fortran function. Because Fortran supports
+    arbitrary bases for indexing, for instance, `arr(lower:upper)`,
+    f2py has to evaluate an expression `upper - lower + 1` where
+    `lower` and `upper` are arbitrary expressions of input parameters.
+    The evaluation is performed in C, so f2py has to translate Fortran
+    expressions to valid C expressions (an alternative approach is
+    that a developer specifies the corresponding C expressions in a
+    .pyf file).
+
+    In the second case, when user provides an input array with a given
+    size but some hidden parameters used in dimensions specifications
+    need to be determined based on the input array size. This is a
+    harder problem because f2py has to solve the inverse problem: find
+    a parameter `p` such that `upper(p) - lower(p) + 1` equals to the
+    size of input array. In the case when this equation cannot be
+    solved (e.g. because the input array size is wrong), raise an
+    error before calling the Fortran function (that otherwise would
+    likely crash Python process when the size of input arrays is
+    wrong). f2py currently supports this case only when the equation
+    is linear with respect to unknown parameter.
+
+    """
+
+    suffix = ".f90"
+
+    code_template = textwrap.dedent("""
+      function get_arr_size_{count}(a, n) result (length)
+        integer, intent(in) :: n
+        integer, dimension({dimspec}), intent(out) :: a
+        integer length
+        length = size(a)
+      end function
+
+      subroutine get_inv_arr_size_{count}(a, n)
+        integer :: n
+        ! the value of n is computed in f2py wrapper
+        !f2py intent(out) n
+        integer, dimension({dimspec}), intent(in) :: a
+      end subroutine
+    """)
+
+    linear_dimspecs = [
+        "n", "2*n", "2:n", "n/2", "5 - n/2", "3*n:20", "n*(n+1):n*(n+5)",
+        "2*n, n"
+    ]
+    nonlinear_dimspecs = ["2*n:3*n*n+2*n"]
+    all_dimspecs = linear_dimspecs + nonlinear_dimspecs
+
+    code = ""
+    for count, dimspec in enumerate(all_dimspecs):
+        lst = [(d.split(":")[0] if ":" in d else "1") for d in dimspec.split(',')]
+        code += code_template.format(
+            count=count,
+            dimspec=dimspec,
+            first=", ".join(lst),
+        )
+
+    @pytest.mark.parametrize("dimspec", all_dimspecs)
+    def test_array_size(self, dimspec):
+
+        count = self.all_dimspecs.index(dimspec)
+        get_arr_size = getattr(self.module, f"get_arr_size_{count}")
+
+        for n in [1, 2, 3, 4, 5]:
+            sz, a = get_arr_size(n)
+            assert a.size == sz
+
+    @pytest.mark.parametrize("dimspec", all_dimspecs)
+    def test_inv_array_size(self, dimspec):
+
+        count = self.all_dimspecs.index(dimspec)
+        get_arr_size = getattr(self.module, f"get_arr_size_{count}")
+        get_inv_arr_size = getattr(self.module, f"get_inv_arr_size_{count}")
+
+        for n in [1, 2, 3, 4, 5]:
+            sz, a = get_arr_size(n)
+            if dimspec in self.nonlinear_dimspecs:
+                # one must specify n as input, the call we'll ensure
+                # that a and n are compatible:
+                n1 = get_inv_arr_size(a, n)
+            else:
+                # in case of linear dependence, n can be determined
+                # from the shape of a:
+                n1 = get_inv_arr_size(a)
+            # n1 may be different from n (for instance, when `a` size
+            # is a function of some `n` fraction) but it must produce
+            # the same sized array
+            sz1, _ = get_arr_size(n1)
+            assert sz == sz1, (n, n1, sz, sz1)
+
+
+class TestModuleDeclaration:
+    def test_dependencies(self, tmp_path):
+        fpath = util.getpath("tests", "src", "crackfortran", "foo_deps.f90")
+        mod = crackfortran.crackfortran([str(fpath)])
+        assert len(mod) == 1
+        assert mod[0]["vars"]["abar"]["="] == "bar('abar')"
+
+
+class TestEval(util.F2PyTest):
+    def test_eval_scalar(self):
+        eval_scalar = crackfortran._eval_scalar
+
+        assert eval_scalar('123', {}) == '123'
+        assert eval_scalar('12 + 3', {}) == '15'
+        assert eval_scalar('a + b', dict(a=1, b=2)) == '3'
+        assert eval_scalar('"123"', {}) == "'123'"
+
+
+class TestFortranReader(util.F2PyTest):
+    @pytest.mark.parametrize("encoding",
+                             ['ascii', 'utf-8', 'utf-16', 'utf-32'])
+    def test_input_encoding(self, tmp_path, encoding):
+        # gh-635
+        f_path = tmp_path / f"input_with_{encoding}_encoding.f90"
+        with f_path.open('w', encoding=encoding) as ff:
+            ff.write("""
+                     subroutine foo()
+                     end subroutine foo
+                     """)
+        mod = crackfortran.crackfortran([str(f_path)])
+        assert mod[0]['name'] == 'foo'
+
+
+class TestUnicodeComment(util.F2PyTest):
+    sources = [util.getpath("tests", "src", "crackfortran", "unicode_comment.f90")]
+
+    @pytest.mark.skipif(
+        (importlib.util.find_spec("charset_normalizer") is None),
+        reason="test requires charset_normalizer which is not installed",
+    )
+    def test_encoding_comment(self):
+        self.module.foo(3)
+
+
+class TestNameArgsPatternBacktracking:
+    @pytest.mark.parametrize(
+        ['adversary'],
+        [
+            ('@)@bind@(@',),
+            ('@)@bind                         @(@',),
+            ('@)@bind foo bar baz@(@',)
+        ]
+    )
+    def test_nameargspattern_backtracking(self, adversary):
+        '''address ReDOS vulnerability:
+        https://github.com/numpy/numpy/issues/23338'''
+        trials_per_batch = 12
+        batches_per_regex = 4
+        start_reps, end_reps = 15, 25
+        for ii in range(start_reps, end_reps):
+            repeated_adversary = adversary * ii
+            # test times in small batches.
+            # this gives us more chances to catch a bad regex
+            # while still catching it before too long if it is bad
+            for _ in range(batches_per_regex):
+                times = []
+                for _ in range(trials_per_batch):
+                    t0 = time.perf_counter()
+                    mtch = nameargspattern.search(repeated_adversary)
+                    times.append(time.perf_counter() - t0)
+                # our pattern should be much faster than 0.2s per search
+                # it's unlikely that a bad regex will pass even on fast CPUs
+                assert np.median(times) < 0.2
+            assert not mtch
+            # if the adversary is capped with @)@, it becomes acceptable
+            # according to the old version of the regex.
+            # that should still be true.
+            good_version_of_adversary = repeated_adversary + '@)@'
+            assert nameargspattern.search(good_version_of_adversary)
+
+
+class TestFunctionReturn(util.F2PyTest):
+    sources = [util.getpath("tests", "src", "crackfortran", "gh23598.f90")]
+
+    def test_function_rettype(self):
+        # gh-23598
+        assert self.module.intproduct(3, 4) == 12
+
+
+class TestFortranGroupCounters(util.F2PyTest):
+    def test_end_if_comment(self):
+        # gh-23533
+        fpath = util.getpath("tests", "src", "crackfortran", "gh23533.f")
+        try:
+            crackfortran.crackfortran([str(fpath)])
+        except Exception as exc:
+            assert False, f"'crackfortran.crackfortran' raised an exception {exc}"
+
+
+class TestF77CommonBlockReader():
+    def test_gh22648(self, tmp_path):
+        fpath = util.getpath("tests", "src", "crackfortran", "gh22648.pyf")
+        with contextlib.redirect_stdout(io.StringIO()) as stdout_f2py:
+            mod = crackfortran.crackfortran([str(fpath)])
+        assert "Mismatch" not in stdout_f2py.getvalue()
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_data.py b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_data.py
new file mode 100644
index 00000000..4e5604c0
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_data.py
@@ -0,0 +1,70 @@
+import os
+import pytest
+import numpy as np
+
+from . import util
+from numpy.f2py.crackfortran import crackfortran
+
+
+class TestData(util.F2PyTest):
+    sources = [util.getpath("tests", "src", "crackfortran", "data_stmts.f90")]
+
+    # For gh-23276
+    def test_data_stmts(self):
+        assert self.module.cmplxdat.i == 2
+        assert self.module.cmplxdat.j == 3
+        assert self.module.cmplxdat.x == 1.5
+        assert self.module.cmplxdat.y == 2.0
+        assert self.module.cmplxdat.pi == 3.1415926535897932384626433832795028841971693993751058209749445923078164062
+        assert self.module.cmplxdat.medium_ref_index == np.array(1.+0.j)
+        assert np.all(self.module.cmplxdat.z == np.array([3.5, 7.0]))
+        assert np.all(self.module.cmplxdat.my_array == np.array([ 1.+2.j, -3.+4.j]))
+        assert np.all(self.module.cmplxdat.my_real_array == np.array([ 1., 2., 3.]))
+        assert np.all(self.module.cmplxdat.ref_index_one == np.array([13.0 + 21.0j]))
+        assert np.all(self.module.cmplxdat.ref_index_two == np.array([-30.0 + 43.0j]))
+
+    def test_crackedlines(self):
+        mod = crackfortran(self.sources)
+        assert mod[0]['vars']['x']['='] == '1.5'
+        assert mod[0]['vars']['y']['='] == '2.0'
+        assert mod[0]['vars']['pi']['='] == '3.1415926535897932384626433832795028841971693993751058209749445923078164062d0'
+        assert mod[0]['vars']['my_real_array']['='] == '(/1.0d0, 2.0d0, 3.0d0/)'
+        assert mod[0]['vars']['ref_index_one']['='] == '(13.0d0, 21.0d0)'
+        assert mod[0]['vars']['ref_index_two']['='] == '(-30.0d0, 43.0d0)'
+        assert mod[0]['vars']['my_array']['='] == '(/(1.0d0, 2.0d0), (-3.0d0, 4.0d0)/)'
+        assert mod[0]['vars']['z']['='] == '(/3.5,  7.0/)'
+
+class TestDataF77(util.F2PyTest):
+    sources = [util.getpath("tests", "src", "crackfortran", "data_common.f")]
+
+    # For gh-23276
+    def test_data_stmts(self):
+        assert self.module.mycom.mydata == 0
+
+    def test_crackedlines(self):
+        mod = crackfortran(str(self.sources[0]))
+        print(mod[0]['vars'])
+        assert mod[0]['vars']['mydata']['='] == '0'
+
+
+class TestDataMultiplierF77(util.F2PyTest):
+    sources = [util.getpath("tests", "src", "crackfortran", "data_multiplier.f")]
+
+    # For gh-23276
+    def test_data_stmts(self):
+        assert self.module.mycom.ivar1 == 3
+        assert self.module.mycom.ivar2 == 3
+        assert self.module.mycom.ivar3 == 2
+        assert self.module.mycom.ivar4 == 2
+        assert self.module.mycom.evar5 == 0
+
+
+class TestDataWithCommentsF77(util.F2PyTest):
+    sources = [util.getpath("tests", "src", "crackfortran", "data_with_comments.f")]
+
+    # For gh-23276
+    def test_data_stmts(self):
+        assert len(self.module.mycom.mytab) == 3
+        assert self.module.mycom.mytab[0] == 0
+        assert self.module.mycom.mytab[1] == 4
+        assert self.module.mycom.mytab[2] == 0
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_docs.py b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_docs.py
new file mode 100644
index 00000000..6631dd82
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_docs.py
@@ -0,0 +1,55 @@
+import os
+import pytest
+import numpy as np
+from numpy.testing import assert_array_equal, assert_equal
+from . import util
+
+
+def get_docdir():
+    # assuming that documentation tests are run from a source
+    # directory
+    return os.path.abspath(os.path.join(
+        os.path.dirname(__file__),
+        '..', '..', '..',
+        'doc', 'source', 'f2py', 'code'))
+
+
+pytestmark = pytest.mark.skipif(
+    not os.path.isdir(get_docdir()),
+    reason=('Could not find f2py documentation sources'
+            f' ({get_docdir()} does not exists)'))
+
+
+def _path(*a):
+    return os.path.join(*((get_docdir(),) + a))
+
+
+class TestDocAdvanced(util.F2PyTest):
+    # options = ['--debug-capi', '--build-dir', '/tmp/build-f2py']
+    sources = [_path('asterisk1.f90'), _path('asterisk2.f90'),
+               _path('ftype.f')]
+
+    def test_asterisk1(self):
+        foo = getattr(self.module, 'foo1')
+        assert_equal(foo(), b'123456789A12')
+
+    def test_asterisk2(self):
+        foo = getattr(self.module, 'foo2')
+        assert_equal(foo(2), b'12')
+        assert_equal(foo(12), b'123456789A12')
+        assert_equal(foo(24), b'123456789A123456789B')
+
+    def test_ftype(self):
+        ftype = self.module
+        ftype.foo()
+        assert_equal(ftype.data.a, 0)
+        ftype.data.a = 3
+        ftype.data.x = [1, 2, 3]
+        assert_equal(ftype.data.a, 3)
+        assert_array_equal(ftype.data.x,
+                           np.array([1, 2, 3], dtype=np.float32))
+        ftype.data.x[1] = 45
+        assert_array_equal(ftype.data.x,
+                           np.array([1, 45, 3], dtype=np.float32))
+
+    # TODO: implement test methods for other example Fortran codes
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_f2cmap.py b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_f2cmap.py
new file mode 100644
index 00000000..d2967e4f
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_f2cmap.py
@@ -0,0 +1,15 @@
+from . import util
+import numpy as np
+
+class TestF2Cmap(util.F2PyTest):
+    sources = [
+        util.getpath("tests", "src", "f2cmap", "isoFortranEnvMap.f90"),
+        util.getpath("tests", "src", "f2cmap", ".f2py_f2cmap")
+    ]
+
+    # gh-15095
+    def test_long_long_map(self):
+        inp = np.ones(3)
+        out = self.module.func1(inp)
+        exp_out = 3
+        assert out == exp_out
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_f2py2e.py b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_f2py2e.py
new file mode 100644
index 00000000..659e0e96
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_f2py2e.py
@@ -0,0 +1,896 @@
+import textwrap, re, sys, subprocess, shlex
+from pathlib import Path
+from collections import namedtuple
+import platform
+
+import pytest
+
+from . import util
+from numpy.f2py.f2py2e import main as f2pycli
+
+#########################
+# CLI utils and classes #
+#########################
+
+PPaths = namedtuple("PPaths", "finp, f90inp, pyf, wrap77, wrap90, cmodf")
+
+
+def get_io_paths(fname_inp, mname="untitled"):
+    """Takes in a temporary file for testing and returns the expected output and input paths
+
+    Here expected output is essentially one of any of the possible generated
+    files.
+
+    ..note::
+
+         Since this does not actually run f2py, none of these are guaranteed to
+         exist, and module names are typically incorrect
+
+    Parameters
+    ----------
+    fname_inp : str
+                The input filename
+    mname : str, optional
+                The name of the module, untitled by default
+
+    Returns
+    -------
+    genp : NamedTuple PPaths
+            The possible paths which are generated, not all of which exist
+    """
+    bpath = Path(fname_inp)
+    return PPaths(
+        finp=bpath.with_suffix(".f"),
+        f90inp=bpath.with_suffix(".f90"),
+        pyf=bpath.with_suffix(".pyf"),
+        wrap77=bpath.with_name(f"{mname}-f2pywrappers.f"),
+        wrap90=bpath.with_name(f"{mname}-f2pywrappers2.f90"),
+        cmodf=bpath.with_name(f"{mname}module.c"),
+    )
+
+
+##############
+# CLI Fixtures and Tests #
+#############
+
+
+@pytest.fixture(scope="session")
+def hello_world_f90(tmpdir_factory):
+    """Generates a single f90 file for testing"""
+    fdat = util.getpath("tests", "src", "cli", "hiworld.f90").read_text()
+    fn = tmpdir_factory.getbasetemp() / "hello.f90"
+    fn.write_text(fdat, encoding="ascii")
+    return fn
+
+
+@pytest.fixture(scope="session")
+def gh23598_warn(tmpdir_factory):
+    """F90 file for testing warnings in gh23598"""
+    fdat = util.getpath("tests", "src", "crackfortran", "gh23598Warn.f90").read_text()
+    fn = tmpdir_factory.getbasetemp() / "gh23598Warn.f90"
+    fn.write_text(fdat, encoding="ascii")
+    return fn
+
+
+@pytest.fixture(scope="session")
+def gh22819_cli(tmpdir_factory):
+    """F90 file for testing disallowed CLI arguments in ghff819"""
+    fdat = util.getpath("tests", "src", "cli", "gh_22819.pyf").read_text()
+    fn = tmpdir_factory.getbasetemp() / "gh_22819.pyf"
+    fn.write_text(fdat, encoding="ascii")
+    return fn
+
+
+@pytest.fixture(scope="session")
+def hello_world_f77(tmpdir_factory):
+    """Generates a single f77 file for testing"""
+    fdat = util.getpath("tests", "src", "cli", "hi77.f").read_text()
+    fn = tmpdir_factory.getbasetemp() / "hello.f"
+    fn.write_text(fdat, encoding="ascii")
+    return fn
+
+
+@pytest.fixture(scope="session")
+def retreal_f77(tmpdir_factory):
+    """Generates a single f77 file for testing"""
+    fdat = util.getpath("tests", "src", "return_real", "foo77.f").read_text()
+    fn = tmpdir_factory.getbasetemp() / "foo.f"
+    fn.write_text(fdat, encoding="ascii")
+    return fn
+
+@pytest.fixture(scope="session")
+def f2cmap_f90(tmpdir_factory):
+    """Generates a single f90 file for testing"""
+    fdat = util.getpath("tests", "src", "f2cmap", "isoFortranEnvMap.f90").read_text()
+    f2cmap = util.getpath("tests", "src", "f2cmap", ".f2py_f2cmap").read_text()
+    fn = tmpdir_factory.getbasetemp() / "f2cmap.f90"
+    fmap = tmpdir_factory.getbasetemp() / "mapfile"
+    fn.write_text(fdat, encoding="ascii")
+    fmap.write_text(f2cmap, encoding="ascii")
+    return fn
+
+
+def test_gh22819_cli(capfd, gh22819_cli, monkeypatch):
+    """Check that module names are handled correctly
+    gh-22819
+    Essentially, the -m name cannot be used to import the module, so the module
+    named in the .pyf needs to be used instead
+
+    CLI :: -m and a .pyf file
+    """
+    ipath = Path(gh22819_cli)
+    monkeypatch.setattr(sys, "argv", f"f2py -m blah {ipath}".split())
+    with util.switchdir(ipath.parent):
+        f2pycli()
+        gen_paths = [item.name for item in ipath.parent.rglob("*") if item.is_file()]
+        assert "blahmodule.c" not in gen_paths # shouldn't be generated
+        assert "blah-f2pywrappers.f" not in gen_paths
+        assert "test_22819-f2pywrappers.f" in gen_paths
+        assert "test_22819module.c" in gen_paths
+        assert "Ignoring blah"
+
+
+def test_gh22819_many_pyf(capfd, gh22819_cli, monkeypatch):
+    """Only one .pyf file allowed
+    gh-22819
+    CLI :: .pyf files
+    """
+    ipath = Path(gh22819_cli)
+    monkeypatch.setattr(sys, "argv", f"f2py -m blah {ipath} hello.pyf".split())
+    with util.switchdir(ipath.parent):
+        with pytest.raises(ValueError, match="Only one .pyf file per call"):
+            f2pycli()
+
+
+def test_gh23598_warn(capfd, gh23598_warn, monkeypatch):
+    foutl = get_io_paths(gh23598_warn, mname="test")
+    ipath = foutl.f90inp
+    monkeypatch.setattr(
+        sys, "argv",
+        f'f2py {ipath} -m test'.split())
+
+    with util.switchdir(ipath.parent):
+        f2pycli()  # Generate files
+        wrapper = foutl.wrap90.read_text()
+        assert "intproductf2pywrap, intpr" not in wrapper
+
+
+def test_gen_pyf(capfd, hello_world_f90, monkeypatch):
+    """Ensures that a signature file is generated via the CLI
+    CLI :: -h
+    """
+    ipath = Path(hello_world_f90)
+    opath = Path(hello_world_f90).stem + ".pyf"
+    monkeypatch.setattr(sys, "argv", f'f2py -h {opath} {ipath}'.split())
+
+    with util.switchdir(ipath.parent):
+        f2pycli()  # Generate wrappers
+        out, _ = capfd.readouterr()
+        assert "Saving signatures to file" in out
+        assert Path(f'{opath}').exists()
+
+
+def test_gen_pyf_stdout(capfd, hello_world_f90, monkeypatch):
+    """Ensures that a signature file can be dumped to stdout
+    CLI :: -h
+    """
+    ipath = Path(hello_world_f90)
+    monkeypatch.setattr(sys, "argv", f'f2py -h stdout {ipath}'.split())
+    with util.switchdir(ipath.parent):
+        f2pycli()
+        out, _ = capfd.readouterr()
+        assert "Saving signatures to file" in out
+        assert "function hi() ! in " in out
+
+
+def test_gen_pyf_no_overwrite(capfd, hello_world_f90, monkeypatch):
+    """Ensures that the CLI refuses to overwrite signature files
+    CLI :: -h without --overwrite-signature
+    """
+    ipath = Path(hello_world_f90)
+    monkeypatch.setattr(sys, "argv", f'f2py -h faker.pyf {ipath}'.split())
+
+    with util.switchdir(ipath.parent):
+        Path("faker.pyf").write_text("Fake news", encoding="ascii")
+        with pytest.raises(SystemExit):
+            f2pycli()  # Refuse to overwrite
+            _, err = capfd.readouterr()
+            assert "Use --overwrite-signature to overwrite" in err
+
+
+@pytest.mark.skipif((platform.system() != 'Linux') or (sys.version_info <= (3, 12)),
+                    reason='Compiler and 3.12 required')
+def test_untitled_cli(capfd, hello_world_f90, monkeypatch):
+    """Check that modules are named correctly
+
+    CLI :: defaults
+    """
+    ipath = Path(hello_world_f90)
+    monkeypatch.setattr(sys, "argv", f"f2py --backend meson -c {ipath}".split())
+    with util.switchdir(ipath.parent):
+        f2pycli()
+        out, _ = capfd.readouterr()
+        assert "untitledmodule.c" in out
+
+
+@pytest.mark.skipif((platform.system() != 'Linux') or (sys.version_info <= (3, 12)), reason='Compiler and 3.12 required')
+def test_no_py312_distutils_fcompiler(capfd, hello_world_f90, monkeypatch):
+    """Check that no distutils imports are performed on 3.12
+    CLI :: --fcompiler --help-link --backend distutils
+    """
+    MNAME = "hi"
+    foutl = get_io_paths(hello_world_f90, mname=MNAME)
+    ipath = foutl.f90inp
+    monkeypatch.setattr(
+        sys, "argv", f"f2py {ipath} -c --fcompiler=gfortran -m {MNAME}".split()
+    )
+    with util.switchdir(ipath.parent):
+        f2pycli()
+        out, _ = capfd.readouterr()
+        assert "--fcompiler cannot be used with meson" in out
+    monkeypatch.setattr(
+        sys, "argv", f"f2py --help-link".split()
+    )
+    with util.switchdir(ipath.parent):
+        f2pycli()
+        out, _ = capfd.readouterr()
+        assert "Use --dep for meson builds" in out
+    MNAME = "hi2" # Needs to be different for a new -c
+    monkeypatch.setattr(
+        sys, "argv", f"f2py {ipath} -c -m {MNAME} --backend distutils".split()
+    )
+    with util.switchdir(ipath.parent):
+        f2pycli()
+        out, _ = capfd.readouterr()
+        assert "Cannot use distutils backend with Python>=3.12" in out
+
+
+@pytest.mark.xfail
+def test_f2py_skip(capfd, retreal_f77, monkeypatch):
+    """Tests that functions can be skipped
+    CLI :: skip:
+    """
+    foutl = get_io_paths(retreal_f77, mname="test")
+    ipath = foutl.finp
+    toskip = "t0 t4 t8 sd s8 s4"
+    remaining = "td s0"
+    monkeypatch.setattr(
+        sys, "argv",
+        f'f2py {ipath} -m test skip: {toskip}'.split())
+
+    with util.switchdir(ipath.parent):
+        f2pycli()
+        out, err = capfd.readouterr()
+        for skey in toskip.split():
+            assert (
+                f'buildmodule: Could not found the body of interfaced routine "{skey}". Skipping.'
+                in err)
+        for rkey in remaining.split():
+            assert f'Constructing wrapper function "{rkey}"' in out
+
+
+def test_f2py_only(capfd, retreal_f77, monkeypatch):
+    """Test that functions can be kept by only:
+    CLI :: only:
+    """
+    foutl = get_io_paths(retreal_f77, mname="test")
+    ipath = foutl.finp
+    toskip = "t0 t4 t8 sd s8 s4"
+    tokeep = "td s0"
+    monkeypatch.setattr(
+        sys, "argv",
+        f'f2py {ipath} -m test only: {tokeep}'.split())
+
+    with util.switchdir(ipath.parent):
+        f2pycli()
+        out, err = capfd.readouterr()
+        for skey in toskip.split():
+            assert (
+                f'buildmodule: Could not find the body of interfaced routine "{skey}". Skipping.'
+                in err)
+        for rkey in tokeep.split():
+            assert f'Constructing wrapper function "{rkey}"' in out
+
+
+def test_file_processing_switch(capfd, hello_world_f90, retreal_f77,
+                                monkeypatch):
+    """Tests that it is possible to return to file processing mode
+    CLI :: :
+    BUG: numpy-gh #20520
+    """
+    foutl = get_io_paths(retreal_f77, mname="test")
+    ipath = foutl.finp
+    toskip = "t0 t4 t8 sd s8 s4"
+    ipath2 = Path(hello_world_f90)
+    tokeep = "td s0 hi"  # hi is in ipath2
+    mname = "blah"
+    monkeypatch.setattr(
+        sys,
+        "argv",
+        f'f2py {ipath} -m {mname} only: {tokeep} : {ipath2}'.split(
+        ),
+    )
+
+    with util.switchdir(ipath.parent):
+        f2pycli()
+        out, err = capfd.readouterr()
+        for skey in toskip.split():
+            assert (
+                f'buildmodule: Could not find the body of interfaced routine "{skey}". Skipping.'
+                in err)
+        for rkey in tokeep.split():
+            assert f'Constructing wrapper function "{rkey}"' in out
+
+
+def test_mod_gen_f77(capfd, hello_world_f90, monkeypatch):
+    """Checks the generation of files based on a module name
+    CLI :: -m
+    """
+    MNAME = "hi"
+    foutl = get_io_paths(hello_world_f90, mname=MNAME)
+    ipath = foutl.f90inp
+    monkeypatch.setattr(sys, "argv", f'f2py {ipath} -m {MNAME}'.split())
+    with util.switchdir(ipath.parent):
+        f2pycli()
+
+    # Always generate C module
+    assert Path.exists(foutl.cmodf)
+    # File contains a function, check for F77 wrappers
+    assert Path.exists(foutl.wrap77)
+
+
+def test_mod_gen_gh25263(capfd, hello_world_f77, monkeypatch):
+    """Check that pyf files are correctly generated with module structure
+    CLI :: -m <name> -h pyf_file
+    BUG: numpy-gh #20520
+    """
+    MNAME = "hi"
+    foutl = get_io_paths(hello_world_f77, mname=MNAME)
+    ipath = foutl.finp
+    monkeypatch.setattr(sys, "argv", f'f2py {ipath} -m {MNAME} -h hi.pyf'.split())
+    with util.switchdir(ipath.parent):
+        f2pycli()
+        with Path('hi.pyf').open() as hipyf:
+            pyfdat = hipyf.read()
+            assert "python module hi" in pyfdat
+
+
+def test_lower_cmod(capfd, hello_world_f77, monkeypatch):
+    """Lowers cases by flag or when -h is present
+
+    CLI :: --[no-]lower
+    """
+    foutl = get_io_paths(hello_world_f77, mname="test")
+    ipath = foutl.finp
+    capshi = re.compile(r"HI\(\)")
+    capslo = re.compile(r"hi\(\)")
+    # Case I: --lower is passed
+    monkeypatch.setattr(sys, "argv", f'f2py {ipath} -m test --lower'.split())
+    with util.switchdir(ipath.parent):
+        f2pycli()
+        out, _ = capfd.readouterr()
+        assert capslo.search(out) is not None
+        assert capshi.search(out) is None
+    # Case II: --no-lower is passed
+    monkeypatch.setattr(sys, "argv",
+                        f'f2py {ipath} -m test --no-lower'.split())
+    with util.switchdir(ipath.parent):
+        f2pycli()
+        out, _ = capfd.readouterr()
+        assert capslo.search(out) is None
+        assert capshi.search(out) is not None
+
+
+def test_lower_sig(capfd, hello_world_f77, monkeypatch):
+    """Lowers cases in signature files by flag or when -h is present
+
+    CLI :: --[no-]lower -h
+    """
+    foutl = get_io_paths(hello_world_f77, mname="test")
+    ipath = foutl.finp
+    # Signature files
+    capshi = re.compile(r"Block: HI")
+    capslo = re.compile(r"Block: hi")
+    # Case I: --lower is implied by -h
+    # TODO: Clean up to prevent passing --overwrite-signature
+    monkeypatch.setattr(
+        sys,
+        "argv",
+        f'f2py {ipath} -h {foutl.pyf} -m test --overwrite-signature'.split(),
+    )
+
+    with util.switchdir(ipath.parent):
+        f2pycli()
+        out, _ = capfd.readouterr()
+        assert capslo.search(out) is not None
+        assert capshi.search(out) is None
+
+    # Case II: --no-lower overrides -h
+    monkeypatch.setattr(
+        sys,
+        "argv",
+        f'f2py {ipath} -h {foutl.pyf} -m test --overwrite-signature --no-lower'
+        .split(),
+    )
+
+    with util.switchdir(ipath.parent):
+        f2pycli()
+        out, _ = capfd.readouterr()
+        assert capslo.search(out) is None
+        assert capshi.search(out) is not None
+
+
+def test_build_dir(capfd, hello_world_f90, monkeypatch):
+    """Ensures that the build directory can be specified
+
+    CLI :: --build-dir
+    """
+    ipath = Path(hello_world_f90)
+    mname = "blah"
+    odir = "tttmp"
+    monkeypatch.setattr(sys, "argv",
+                        f'f2py -m {mname} {ipath} --build-dir {odir}'.split())
+
+    with util.switchdir(ipath.parent):
+        f2pycli()
+        out, _ = capfd.readouterr()
+        assert f"Wrote C/API module \"{mname}\"" in out
+
+
+def test_overwrite(capfd, hello_world_f90, monkeypatch):
+    """Ensures that the build directory can be specified
+
+    CLI :: --overwrite-signature
+    """
+    ipath = Path(hello_world_f90)
+    monkeypatch.setattr(
+        sys, "argv",
+        f'f2py -h faker.pyf {ipath} --overwrite-signature'.split())
+
+    with util.switchdir(ipath.parent):
+        Path("faker.pyf").write_text("Fake news", encoding="ascii")
+        f2pycli()
+        out, _ = capfd.readouterr()
+        assert "Saving signatures to file" in out
+
+
+def test_latexdoc(capfd, hello_world_f90, monkeypatch):
+    """Ensures that TeX documentation is written out
+
+    CLI :: --latex-doc
+    """
+    ipath = Path(hello_world_f90)
+    mname = "blah"
+    monkeypatch.setattr(sys, "argv",
+                        f'f2py -m {mname} {ipath} --latex-doc'.split())
+
+    with util.switchdir(ipath.parent):
+        f2pycli()
+        out, _ = capfd.readouterr()
+        assert "Documentation is saved to file" in out
+        with Path(f"{mname}module.tex").open() as otex:
+            assert "\\documentclass" in otex.read()
+
+
+def test_nolatexdoc(capfd, hello_world_f90, monkeypatch):
+    """Ensures that TeX documentation is written out
+
+    CLI :: --no-latex-doc
+    """
+    ipath = Path(hello_world_f90)
+    mname = "blah"
+    monkeypatch.setattr(sys, "argv",
+                        f'f2py -m {mname} {ipath} --no-latex-doc'.split())
+
+    with util.switchdir(ipath.parent):
+        f2pycli()
+        out, _ = capfd.readouterr()
+        assert "Documentation is saved to file" not in out
+
+
+def test_shortlatex(capfd, hello_world_f90, monkeypatch):
+    """Ensures that truncated documentation is written out
+
+    TODO: Test to ensure this has no effect without --latex-doc
+    CLI :: --latex-doc --short-latex
+    """
+    ipath = Path(hello_world_f90)
+    mname = "blah"
+    monkeypatch.setattr(
+        sys,
+        "argv",
+        f'f2py -m {mname} {ipath} --latex-doc --short-latex'.split(),
+    )
+
+    with util.switchdir(ipath.parent):
+        f2pycli()
+        out, _ = capfd.readouterr()
+        assert "Documentation is saved to file" in out
+        with Path(f"./{mname}module.tex").open() as otex:
+            assert "\\documentclass" not in otex.read()
+
+
+def test_restdoc(capfd, hello_world_f90, monkeypatch):
+    """Ensures that RsT documentation is written out
+
+    CLI :: --rest-doc
+    """
+    ipath = Path(hello_world_f90)
+    mname = "blah"
+    monkeypatch.setattr(sys, "argv",
+                        f'f2py -m {mname} {ipath} --rest-doc'.split())
+
+    with util.switchdir(ipath.parent):
+        f2pycli()
+        out, _ = capfd.readouterr()
+        assert "ReST Documentation is saved to file" in out
+        with Path(f"./{mname}module.rest").open() as orst:
+            assert r".. -*- rest -*-" in orst.read()
+
+
+def test_norestexdoc(capfd, hello_world_f90, monkeypatch):
+    """Ensures that TeX documentation is written out
+
+    CLI :: --no-rest-doc
+    """
+    ipath = Path(hello_world_f90)
+    mname = "blah"
+    monkeypatch.setattr(sys, "argv",
+                        f'f2py -m {mname} {ipath} --no-rest-doc'.split())
+
+    with util.switchdir(ipath.parent):
+        f2pycli()
+        out, _ = capfd.readouterr()
+        assert "ReST Documentation is saved to file" not in out
+
+
+def test_debugcapi(capfd, hello_world_f90, monkeypatch):
+    """Ensures that debugging wrappers are written
+
+    CLI :: --debug-capi
+    """
+    ipath = Path(hello_world_f90)
+    mname = "blah"
+    monkeypatch.setattr(sys, "argv",
+                        f'f2py -m {mname} {ipath} --debug-capi'.split())
+
+    with util.switchdir(ipath.parent):
+        f2pycli()
+        with Path(f"./{mname}module.c").open() as ocmod:
+            assert r"#define DEBUGCFUNCS" in ocmod.read()
+
+
+@pytest.mark.xfail(reason="Consistently fails on CI.")
+def test_debugcapi_bld(hello_world_f90, monkeypatch):
+    """Ensures that debugging wrappers work
+
+    CLI :: --debug-capi -c
+    """
+    ipath = Path(hello_world_f90)
+    mname = "blah"
+    monkeypatch.setattr(sys, "argv",
+                        f'f2py -m {mname} {ipath} -c --debug-capi'.split())
+
+    with util.switchdir(ipath.parent):
+        f2pycli()
+        cmd_run = shlex.split("python3 -c \"import blah; blah.hi()\"")
+        rout = subprocess.run(cmd_run, capture_output=True, encoding='UTF-8')
+        eout = ' Hello World\n'
+        eerr = textwrap.dedent("""\
+debug-capi:Python C/API function blah.hi()
+debug-capi:float hi=:output,hidden,scalar
+debug-capi:hi=0
+debug-capi:Fortran subroutine `f2pywraphi(&hi)'
+debug-capi:hi=0
+debug-capi:Building return value.
+debug-capi:Python C/API function blah.hi: successful.
+debug-capi:Freeing memory.
+        """)
+        assert rout.stdout == eout
+        assert rout.stderr == eerr
+
+
+def test_wrapfunc_def(capfd, hello_world_f90, monkeypatch):
+    """Ensures that fortran subroutine wrappers for F77 are included by default
+
+    CLI :: --[no]-wrap-functions
+    """
+    # Implied
+    ipath = Path(hello_world_f90)
+    mname = "blah"
+    monkeypatch.setattr(sys, "argv", f'f2py -m {mname} {ipath}'.split())
+
+    with util.switchdir(ipath.parent):
+        f2pycli()
+    out, _ = capfd.readouterr()
+    assert r"Fortran 77 wrappers are saved to" in out
+
+    # Explicit
+    monkeypatch.setattr(sys, "argv",
+                        f'f2py -m {mname} {ipath} --wrap-functions'.split())
+
+    with util.switchdir(ipath.parent):
+        f2pycli()
+        out, _ = capfd.readouterr()
+        assert r"Fortran 77 wrappers are saved to" in out
+
+
+def test_nowrapfunc(capfd, hello_world_f90, monkeypatch):
+    """Ensures that fortran subroutine wrappers for F77 can be disabled
+
+    CLI :: --no-wrap-functions
+    """
+    ipath = Path(hello_world_f90)
+    mname = "blah"
+    monkeypatch.setattr(sys, "argv",
+                        f'f2py -m {mname} {ipath} --no-wrap-functions'.split())
+
+    with util.switchdir(ipath.parent):
+        f2pycli()
+        out, _ = capfd.readouterr()
+        assert r"Fortran 77 wrappers are saved to" not in out
+
+
+def test_inclheader(capfd, hello_world_f90, monkeypatch):
+    """Add to the include directories
+
+    CLI :: -include
+    TODO: Document this in the help string
+    """
+    ipath = Path(hello_world_f90)
+    mname = "blah"
+    monkeypatch.setattr(
+        sys,
+        "argv",
+        f'f2py -m {mname} {ipath} -include<stdbool.h> -include<stdio.h> '.
+        split(),
+    )
+
+    with util.switchdir(ipath.parent):
+        f2pycli()
+        with Path(f"./{mname}module.c").open() as ocmod:
+            ocmr = ocmod.read()
+            assert "#include <stdbool.h>" in ocmr
+            assert "#include <stdio.h>" in ocmr
+
+
+def test_inclpath():
+    """Add to the include directories
+
+    CLI :: --include-paths
+    """
+    # TODO: populate
+    pass
+
+
+def test_hlink():
+    """Add to the include directories
+
+    CLI :: --help-link
+    """
+    # TODO: populate
+    pass
+
+
+def test_f2cmap(capfd, f2cmap_f90, monkeypatch):
+    """Check that Fortran-to-Python KIND specs can be passed
+
+    CLI :: --f2cmap
+    """
+    ipath = Path(f2cmap_f90)
+    monkeypatch.setattr(sys, "argv", f'f2py -m blah {ipath} --f2cmap mapfile'.split())
+
+    with util.switchdir(ipath.parent):
+        f2pycli()
+        out, _ = capfd.readouterr()
+        assert "Reading f2cmap from 'mapfile' ..." in out
+        assert "Mapping \"real(kind=real32)\" to \"float\"" in out
+        assert "Mapping \"real(kind=real64)\" to \"double\"" in out
+        assert "Mapping \"integer(kind=int64)\" to \"long_long\"" in out
+        assert "Successfully applied user defined f2cmap changes" in out
+
+
+def test_quiet(capfd, hello_world_f90, monkeypatch):
+    """Reduce verbosity
+
+    CLI :: --quiet
+    """
+    ipath = Path(hello_world_f90)
+    monkeypatch.setattr(sys, "argv", f'f2py -m blah {ipath} --quiet'.split())
+
+    with util.switchdir(ipath.parent):
+        f2pycli()
+        out, _ = capfd.readouterr()
+        assert len(out) == 0
+
+
+def test_verbose(capfd, hello_world_f90, monkeypatch):
+    """Increase verbosity
+
+    CLI :: --verbose
+    """
+    ipath = Path(hello_world_f90)
+    monkeypatch.setattr(sys, "argv", f'f2py -m blah {ipath} --verbose'.split())
+
+    with util.switchdir(ipath.parent):
+        f2pycli()
+        out, _ = capfd.readouterr()
+        assert "analyzeline" in out
+
+
+def test_version(capfd, monkeypatch):
+    """Ensure version
+
+    CLI :: -v
+    """
+    monkeypatch.setattr(sys, "argv", 'f2py -v'.split())
+    # TODO: f2py2e should not call sys.exit() after printing the version
+    with pytest.raises(SystemExit):
+        f2pycli()
+        out, _ = capfd.readouterr()
+        import numpy as np
+        assert np.__version__ == out.strip()
+
+
+@pytest.mark.xfail(reason="Consistently fails on CI.")
+def test_npdistop(hello_world_f90, monkeypatch):
+    """
+    CLI :: -c
+    """
+    ipath = Path(hello_world_f90)
+    monkeypatch.setattr(sys, "argv", f'f2py -m blah {ipath} -c'.split())
+
+    with util.switchdir(ipath.parent):
+        f2pycli()
+        cmd_run = shlex.split("python -c \"import blah; blah.hi()\"")
+        rout = subprocess.run(cmd_run, capture_output=True, encoding='UTF-8')
+        eout = ' Hello World\n'
+        assert rout.stdout == eout
+
+
+# Numpy distutils flags
+# TODO: These should be tested separately
+
+
+def test_npd_fcompiler():
+    """
+    CLI :: -c --fcompiler
+    """
+    # TODO: populate
+    pass
+
+
+def test_npd_compiler():
+    """
+    CLI :: -c --compiler
+    """
+    # TODO: populate
+    pass
+
+
+def test_npd_help_fcompiler():
+    """
+    CLI :: -c --help-fcompiler
+    """
+    # TODO: populate
+    pass
+
+
+def test_npd_f77exec():
+    """
+    CLI :: -c --f77exec
+    """
+    # TODO: populate
+    pass
+
+
+def test_npd_f90exec():
+    """
+    CLI :: -c --f90exec
+    """
+    # TODO: populate
+    pass
+
+
+def test_npd_f77flags():
+    """
+    CLI :: -c --f77flags
+    """
+    # TODO: populate
+    pass
+
+
+def test_npd_f90flags():
+    """
+    CLI :: -c --f90flags
+    """
+    # TODO: populate
+    pass
+
+
+def test_npd_opt():
+    """
+    CLI :: -c --opt
+    """
+    # TODO: populate
+    pass
+
+
+def test_npd_arch():
+    """
+    CLI :: -c --arch
+    """
+    # TODO: populate
+    pass
+
+
+def test_npd_noopt():
+    """
+    CLI :: -c --noopt
+    """
+    # TODO: populate
+    pass
+
+
+def test_npd_noarch():
+    """
+    CLI :: -c --noarch
+    """
+    # TODO: populate
+    pass
+
+
+def test_npd_debug():
+    """
+    CLI :: -c --debug
+    """
+    # TODO: populate
+    pass
+
+
+def test_npd_link_auto():
+    """
+    CLI :: -c --link-<resource>
+    """
+    # TODO: populate
+    pass
+
+
+def test_npd_lib():
+    """
+    CLI :: -c -L/path/to/lib/ -l<libname>
+    """
+    # TODO: populate
+    pass
+
+
+def test_npd_define():
+    """
+    CLI :: -D<define>
+    """
+    # TODO: populate
+    pass
+
+
+def test_npd_undefine():
+    """
+    CLI :: -U<name>
+    """
+    # TODO: populate
+    pass
+
+
+def test_npd_incl():
+    """
+    CLI :: -I/path/to/include/
+    """
+    # TODO: populate
+    pass
+
+
+def test_npd_linker():
+    """
+    CLI :: <filename>.o <filename>.so <filename>.a
+    """
+    # TODO: populate
+    pass
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_isoc.py b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_isoc.py
new file mode 100644
index 00000000..594bd7ca
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_isoc.py
@@ -0,0 +1,52 @@
+from . import util
+import numpy as np
+import pytest
+from numpy.testing import assert_allclose
+
+class TestISOC(util.F2PyTest):
+    sources = [
+        util.getpath("tests", "src", "isocintrin", "isoCtests.f90"),
+    ]
+
+    # gh-24553
+    def test_c_double(self):
+        out = self.module.coddity.c_add(1, 2)
+        exp_out = 3
+        assert  out == exp_out
+
+    # gh-9693
+    def test_bindc_function(self):
+        out = self.module.coddity.wat(1, 20)
+        exp_out = 8
+        assert  out == exp_out
+
+    # gh-25207
+    def test_bindc_kinds(self):
+        out = self.module.coddity.c_add_int64(1, 20)
+        exp_out = 21
+        assert  out == exp_out
+
+    # gh-25207
+    def test_bindc_add_arr(self):
+        a = np.array([1,2,3])
+        b = np.array([1,2,3])
+        out = self.module.coddity.add_arr(a, b)
+        exp_out = a*2
+        assert_allclose(out, exp_out)
+
+
+def test_process_f2cmap_dict():
+    from numpy.f2py.auxfuncs import process_f2cmap_dict
+
+    f2cmap_all = {"integer": {"8": "rubbish_type"}}
+    new_map = {"INTEGER": {"4": "int"}}
+    c2py_map = {"int": "int", "rubbish_type": "long"}
+
+    exp_map, exp_maptyp = ({"integer": {"8": "rubbish_type", "4": "int"}}, ["int"])
+
+    # Call the function
+    res_map, res_maptyp = process_f2cmap_dict(f2cmap_all, new_map, c2py_map)
+
+    # Assert the result is as expected
+    assert res_map == exp_map
+    assert res_maptyp == exp_maptyp
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_kind.py b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_kind.py
new file mode 100644
index 00000000..69b85aaa
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_kind.py
@@ -0,0 +1,47 @@
+import os
+import pytest
+import platform
+
+from numpy.f2py.crackfortran import (
+    _selected_int_kind_func as selected_int_kind,
+    _selected_real_kind_func as selected_real_kind,
+)
+from . import util
+
+
+class TestKind(util.F2PyTest):
+    sources = [util.getpath("tests", "src", "kind", "foo.f90")]
+
+    def test_int(self):
+        """Test `int` kind_func for integers up to 10**40."""
+        selectedintkind = self.module.selectedintkind
+
+        for i in range(40):
+            assert selectedintkind(i) == selected_int_kind(
+                i
+            ), f"selectedintkind({i}): expected {selected_int_kind(i)!r} but got {selectedintkind(i)!r}"
+
+    def test_real(self):
+        """
+        Test (processor-dependent) `real` kind_func for real numbers
+        of up to 31 digits precision (extended/quadruple).
+        """
+        selectedrealkind = self.module.selectedrealkind
+
+        for i in range(32):
+            assert selectedrealkind(i) == selected_real_kind(
+                i
+            ), f"selectedrealkind({i}): expected {selected_real_kind(i)!r} but got {selectedrealkind(i)!r}"
+
+    @pytest.mark.xfail(platform.machine().lower().startswith("ppc"),
+                       reason="Some PowerPC may not support full IEEE 754 precision")
+    def test_quad_precision(self):
+        """
+        Test kind_func for quadruple precision [`real(16)`] of 32+ digits .
+        """
+        selectedrealkind = self.module.selectedrealkind
+
+        for i in range(32, 40):
+            assert selectedrealkind(i) == selected_real_kind(
+                i
+            ), f"selectedrealkind({i}): expected {selected_real_kind(i)!r} but got {selectedrealkind(i)!r}"
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_mixed.py b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_mixed.py
new file mode 100644
index 00000000..80653b7d
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_mixed.py
@@ -0,0 +1,33 @@
+import os
+import textwrap
+import pytest
+
+from numpy.testing import IS_PYPY
+from . import util
+
+
+class TestMixed(util.F2PyTest):
+    sources = [
+        util.getpath("tests", "src", "mixed", "foo.f"),
+        util.getpath("tests", "src", "mixed", "foo_fixed.f90"),
+        util.getpath("tests", "src", "mixed", "foo_free.f90"),
+    ]
+
+    def test_all(self):
+        assert self.module.bar11() == 11
+        assert self.module.foo_fixed.bar12() == 12
+        assert self.module.foo_free.bar13() == 13
+
+    @pytest.mark.xfail(IS_PYPY,
+                       reason="PyPy cannot modify tp_doc after PyType_Ready")
+    def test_docstring(self):
+        expected = textwrap.dedent("""\
+        a = bar11()
+
+        Wrapper for ``bar11``.
+
+        Returns
+        -------
+        a : int
+        """)
+        assert self.module.bar11.__doc__ == expected
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_module_doc.py b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_module_doc.py
new file mode 100644
index 00000000..28822d40
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_module_doc.py
@@ -0,0 +1,27 @@
+import os
+import sys
+import pytest
+import textwrap
+
+from . import util
+from numpy.testing import IS_PYPY
+
+
+class TestModuleDocString(util.F2PyTest):
+    sources = [
+        util.getpath("tests", "src", "module_data",
+                     "module_data_docstring.f90")
+    ]
+
+    @pytest.mark.skipif(sys.platform == "win32",
+                        reason="Fails with MinGW64 Gfortran (Issue #9673)")
+    @pytest.mark.xfail(IS_PYPY,
+                       reason="PyPy cannot modify tp_doc after PyType_Ready")
+    def test_module_docstring(self):
+        assert self.module.mod.__doc__ == textwrap.dedent("""\
+                     i : 'i'-scalar
+                     x : 'i'-array(4)
+                     a : 'f'-array(2,3)
+                     b : 'f'-array(-1,-1), not allocated\x00
+                     foo()\n
+                     Wrapper for ``foo``.\n\n""")
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_parameter.py b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_parameter.py
new file mode 100644
index 00000000..2f620eaa
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_parameter.py
@@ -0,0 +1,112 @@
+import os
+import pytest
+
+import numpy as np
+
+from . import util
+
+
+class TestParameters(util.F2PyTest):
+    # Check that intent(in out) translates as intent(inout)
+    sources = [
+        util.getpath("tests", "src", "parameter", "constant_real.f90"),
+        util.getpath("tests", "src", "parameter", "constant_integer.f90"),
+        util.getpath("tests", "src", "parameter", "constant_both.f90"),
+        util.getpath("tests", "src", "parameter", "constant_compound.f90"),
+        util.getpath("tests", "src", "parameter", "constant_non_compound.f90"),
+    ]
+
+    @pytest.mark.slow
+    def test_constant_real_single(self):
+        # non-contiguous should raise error
+        x = np.arange(6, dtype=np.float32)[::2]
+        pytest.raises(ValueError, self.module.foo_single, x)
+
+        # check values with contiguous array
+        x = np.arange(3, dtype=np.float32)
+        self.module.foo_single(x)
+        assert np.allclose(x, [0 + 1 + 2 * 3, 1, 2])
+
+    @pytest.mark.slow
+    def test_constant_real_double(self):
+        # non-contiguous should raise error
+        x = np.arange(6, dtype=np.float64)[::2]
+        pytest.raises(ValueError, self.module.foo_double, x)
+
+        # check values with contiguous array
+        x = np.arange(3, dtype=np.float64)
+        self.module.foo_double(x)
+        assert np.allclose(x, [0 + 1 + 2 * 3, 1, 2])
+
+    @pytest.mark.slow
+    def test_constant_compound_int(self):
+        # non-contiguous should raise error
+        x = np.arange(6, dtype=np.int32)[::2]
+        pytest.raises(ValueError, self.module.foo_compound_int, x)
+
+        # check values with contiguous array
+        x = np.arange(3, dtype=np.int32)
+        self.module.foo_compound_int(x)
+        assert np.allclose(x, [0 + 1 + 2 * 6, 1, 2])
+
+    @pytest.mark.slow
+    def test_constant_non_compound_int(self):
+        # check values
+        x = np.arange(4, dtype=np.int32)
+        self.module.foo_non_compound_int(x)
+        assert np.allclose(x, [0 + 1 + 2 + 3 * 4, 1, 2, 3])
+
+    @pytest.mark.slow
+    def test_constant_integer_int(self):
+        # non-contiguous should raise error
+        x = np.arange(6, dtype=np.int32)[::2]
+        pytest.raises(ValueError, self.module.foo_int, x)
+
+        # check values with contiguous array
+        x = np.arange(3, dtype=np.int32)
+        self.module.foo_int(x)
+        assert np.allclose(x, [0 + 1 + 2 * 3, 1, 2])
+
+    @pytest.mark.slow
+    def test_constant_integer_long(self):
+        # non-contiguous should raise error
+        x = np.arange(6, dtype=np.int64)[::2]
+        pytest.raises(ValueError, self.module.foo_long, x)
+
+        # check values with contiguous array
+        x = np.arange(3, dtype=np.int64)
+        self.module.foo_long(x)
+        assert np.allclose(x, [0 + 1 + 2 * 3, 1, 2])
+
+    @pytest.mark.slow
+    def test_constant_both(self):
+        # non-contiguous should raise error
+        x = np.arange(6, dtype=np.float64)[::2]
+        pytest.raises(ValueError, self.module.foo, x)
+
+        # check values with contiguous array
+        x = np.arange(3, dtype=np.float64)
+        self.module.foo(x)
+        assert np.allclose(x, [0 + 1 * 3 * 3 + 2 * 3 * 3, 1 * 3, 2 * 3])
+
+    @pytest.mark.slow
+    def test_constant_no(self):
+        # non-contiguous should raise error
+        x = np.arange(6, dtype=np.float64)[::2]
+        pytest.raises(ValueError, self.module.foo_no, x)
+
+        # check values with contiguous array
+        x = np.arange(3, dtype=np.float64)
+        self.module.foo_no(x)
+        assert np.allclose(x, [0 + 1 * 3 * 3 + 2 * 3 * 3, 1 * 3, 2 * 3])
+
+    @pytest.mark.slow
+    def test_constant_sum(self):
+        # non-contiguous should raise error
+        x = np.arange(6, dtype=np.float64)[::2]
+        pytest.raises(ValueError, self.module.foo_sum, x)
+
+        # check values with contiguous array
+        x = np.arange(3, dtype=np.float64)
+        self.module.foo_sum(x)
+        assert np.allclose(x, [0 + 1 * 3 * 3 + 2 * 3 * 3, 1 * 3, 2 * 3])
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_pyf_src.py b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_pyf_src.py
new file mode 100644
index 00000000..f77ded2f
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_pyf_src.py
@@ -0,0 +1,44 @@
+# This test is ported from numpy.distutils
+from numpy.f2py._src_pyf import process_str
+from numpy.testing import assert_equal
+
+
+pyf_src = """
+python module foo
+    <_rd=real,double precision>
+    interface
+        subroutine <s,d>foosub(tol)
+            <_rd>, intent(in,out) :: tol
+        end subroutine <s,d>foosub
+    end interface
+end python module foo
+"""
+
+expected_pyf = """
+python module foo
+    interface
+        subroutine sfoosub(tol)
+            real, intent(in,out) :: tol
+        end subroutine sfoosub
+        subroutine dfoosub(tol)
+            double precision, intent(in,out) :: tol
+        end subroutine dfoosub
+    end interface
+end python module foo
+"""
+
+
+def normalize_whitespace(s):
+    """
+    Remove leading and trailing whitespace, and convert internal
+    stretches of whitespace to a single space.
+    """
+    return ' '.join(s.split())
+
+
+def test_from_template():
+    """Regression test for gh-10712."""
+    pyf = process_str(pyf_src)
+    normalized_pyf = normalize_whitespace(pyf)
+    normalized_expected_pyf = normalize_whitespace(expected_pyf)
+    assert_equal(normalized_pyf, normalized_expected_pyf)
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_quoted_character.py b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_quoted_character.py
new file mode 100644
index 00000000..82671cd8
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_quoted_character.py
@@ -0,0 +1,16 @@
+"""See https://github.com/numpy/numpy/pull/10676.
+
+"""
+import sys
+import pytest
+
+from . import util
+
+
+class TestQuotedCharacter(util.F2PyTest):
+    sources = [util.getpath("tests", "src", "quoted_character", "foo.f")]
+
+    @pytest.mark.skipif(sys.platform == "win32",
+                        reason="Fails with MinGW64 Gfortran (Issue #9673)")
+    def test_quoted_character(self):
+        assert self.module.foo() == (b"'", b'"', b";", b"!", b"(", b")")
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_regression.py b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_regression.py
new file mode 100644
index 00000000..1c109783
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_regression.py
@@ -0,0 +1,77 @@
+import os
+import pytest
+
+import numpy as np
+
+from . import util
+
+
+class TestIntentInOut(util.F2PyTest):
+    # Check that intent(in out) translates as intent(inout)
+    sources = [util.getpath("tests", "src", "regression", "inout.f90")]
+
+    @pytest.mark.slow
+    def test_inout(self):
+        # non-contiguous should raise error
+        x = np.arange(6, dtype=np.float32)[::2]
+        pytest.raises(ValueError, self.module.foo, x)
+
+        # check values with contiguous array
+        x = np.arange(3, dtype=np.float32)
+        self.module.foo(x)
+        assert np.allclose(x, [3, 1, 2])
+
+
+class TestNegativeBounds(util.F2PyTest):
+    # Check that negative bounds work correctly
+    sources = [util.getpath("tests", "src", "negative_bounds", "issue_20853.f90")]
+
+    @pytest.mark.slow
+    def test_negbound(self):
+        xvec = np.arange(12)
+        xlow = -6
+        xhigh = 4
+        # Calculate the upper bound,
+        # Keeping the 1 index in mind
+        def ubound(xl, xh):
+            return xh - xl + 1
+        rval = self.module.foo(is_=xlow, ie_=xhigh,
+                        arr=xvec[:ubound(xlow, xhigh)])
+        expval = np.arange(11, dtype = np.float32)
+        assert np.allclose(rval, expval)
+
+
+class TestNumpyVersionAttribute(util.F2PyTest):
+    # Check that th attribute __f2py_numpy_version__ is present
+    # in the compiled module and that has the value np.__version__.
+    sources = [util.getpath("tests", "src", "regression", "inout.f90")]
+
+    @pytest.mark.slow
+    def test_numpy_version_attribute(self):
+
+        # Check that self.module has an attribute named "__f2py_numpy_version__"
+        assert hasattr(self.module, "__f2py_numpy_version__")
+
+        # Check that the attribute __f2py_numpy_version__ is a string
+        assert isinstance(self.module.__f2py_numpy_version__, str)
+
+        # Check that __f2py_numpy_version__ has the value numpy.__version__
+        assert np.__version__ == self.module.__f2py_numpy_version__
+
+
+def test_include_path():
+    incdir = np.f2py.get_include()
+    fnames_in_dir = os.listdir(incdir)
+    for fname in ("fortranobject.c", "fortranobject.h"):
+        assert fname in fnames_in_dir
+
+
+class TestModuleAndSubroutine(util.F2PyTest):
+    module_name = "example"
+    sources = [util.getpath("tests", "src", "regression", "gh25337", "data.f90"),
+               util.getpath("tests", "src", "regression", "gh25337", "use_data.f90")]
+
+    @pytest.mark.slow
+    def test_gh25337(self):
+        self.module.data.set_shift(3)
+        assert "data" in dir(self.module)
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_return_character.py b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_return_character.py
new file mode 100644
index 00000000..36c1f10f
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_return_character.py
@@ -0,0 +1,45 @@
+import pytest
+
+from numpy import array
+from . import util
+import platform
+
+IS_S390X = platform.machine() == "s390x"
+
+
+class TestReturnCharacter(util.F2PyTest):
+    def check_function(self, t, tname):
+        if tname in ["t0", "t1", "s0", "s1"]:
+            assert t("23") == b"2"
+            r = t("ab")
+            assert r == b"a"
+            r = t(array("ab"))
+            assert r == b"a"
+            r = t(array(77, "u1"))
+            assert r == b"M"
+        elif tname in ["ts", "ss"]:
+            assert t(23) == b"23"
+            assert t("123456789abcdef") == b"123456789a"
+        elif tname in ["t5", "s5"]:
+            assert t(23) == b"23"
+            assert t("ab") == b"ab"
+            assert t("123456789abcdef") == b"12345"
+        else:
+            raise NotImplementedError
+
+
+class TestFReturnCharacter(TestReturnCharacter):
+    sources = [
+        util.getpath("tests", "src", "return_character", "foo77.f"),
+        util.getpath("tests", "src", "return_character", "foo90.f90"),
+    ]
+
+    @pytest.mark.xfail(IS_S390X, reason="callback returns ' '")
+    @pytest.mark.parametrize("name", "t0,t1,t5,s0,s1,s5,ss".split(","))
+    def test_all_f77(self, name):
+        self.check_function(getattr(self.module, name), name)
+
+    @pytest.mark.xfail(IS_S390X, reason="callback returns ' '")
+    @pytest.mark.parametrize("name", "t0,t1,t5,ts,s0,s1,s5,ss".split(","))
+    def test_all_f90(self, name):
+        self.check_function(getattr(self.module.f90_return_char, name), name)
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_return_complex.py b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_return_complex.py
new file mode 100644
index 00000000..9df79632
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_return_complex.py
@@ -0,0 +1,65 @@
+import pytest
+
+from numpy import array
+from . import util
+
+
+class TestReturnComplex(util.F2PyTest):
+    def check_function(self, t, tname):
+        if tname in ["t0", "t8", "s0", "s8"]:
+            err = 1e-5
+        else:
+            err = 0.0
+        assert abs(t(234j) - 234.0j) <= err
+        assert abs(t(234.6) - 234.6) <= err
+        assert abs(t(234) - 234.0) <= err
+        assert abs(t(234.6 + 3j) - (234.6 + 3j)) <= err
+        # assert abs(t('234')-234.)<=err
+        # assert abs(t('234.6')-234.6)<=err
+        assert abs(t(-234) + 234.0) <= err
+        assert abs(t([234]) - 234.0) <= err
+        assert abs(t((234, )) - 234.0) <= err
+        assert abs(t(array(234)) - 234.0) <= err
+        assert abs(t(array(23 + 4j, "F")) - (23 + 4j)) <= err
+        assert abs(t(array([234])) - 234.0) <= err
+        assert abs(t(array([[234]])) - 234.0) <= err
+        assert abs(t(array([234]).astype("b")) + 22.0) <= err
+        assert abs(t(array([234], "h")) - 234.0) <= err
+        assert abs(t(array([234], "i")) - 234.0) <= err
+        assert abs(t(array([234], "l")) - 234.0) <= err
+        assert abs(t(array([234], "q")) - 234.0) <= err
+        assert abs(t(array([234], "f")) - 234.0) <= err
+        assert abs(t(array([234], "d")) - 234.0) <= err
+        assert abs(t(array([234 + 3j], "F")) - (234 + 3j)) <= err
+        assert abs(t(array([234], "D")) - 234.0) <= err
+
+        # pytest.raises(TypeError, t, array([234], 'a1'))
+        pytest.raises(TypeError, t, "abc")
+
+        pytest.raises(IndexError, t, [])
+        pytest.raises(IndexError, t, ())
+
+        pytest.raises(TypeError, t, t)
+        pytest.raises(TypeError, t, {})
+
+        try:
+            r = t(10**400)
+            assert repr(r) in ["(inf+0j)", "(Infinity+0j)"]
+        except OverflowError:
+            pass
+
+
+class TestFReturnComplex(TestReturnComplex):
+    sources = [
+        util.getpath("tests", "src", "return_complex", "foo77.f"),
+        util.getpath("tests", "src", "return_complex", "foo90.f90"),
+    ]
+
+    @pytest.mark.parametrize("name", "t0,t8,t16,td,s0,s8,s16,sd".split(","))
+    def test_all_f77(self, name):
+        self.check_function(getattr(self.module, name), name)
+
+    @pytest.mark.parametrize("name", "t0,t8,t16,td,s0,s8,s16,sd".split(","))
+    def test_all_f90(self, name):
+        self.check_function(getattr(self.module.f90_return_complex, name),
+                            name)
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_return_integer.py b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_return_integer.py
new file mode 100644
index 00000000..3b2f42e2
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_return_integer.py
@@ -0,0 +1,53 @@
+import pytest
+
+from numpy import array
+from . import util
+
+
+class TestReturnInteger(util.F2PyTest):
+    def check_function(self, t, tname):
+        assert t(123) == 123
+        assert t(123.6) == 123
+        assert t("123") == 123
+        assert t(-123) == -123
+        assert t([123]) == 123
+        assert t((123, )) == 123
+        assert t(array(123)) == 123
+        assert t(array(123, "b")) == 123
+        assert t(array(123, "h")) == 123
+        assert t(array(123, "i")) == 123
+        assert t(array(123, "l")) == 123
+        assert t(array(123, "B")) == 123
+        assert t(array(123, "f")) == 123
+        assert t(array(123, "d")) == 123
+
+        # pytest.raises(ValueError, t, array([123],'S3'))
+        pytest.raises(ValueError, t, "abc")
+
+        pytest.raises(IndexError, t, [])
+        pytest.raises(IndexError, t, ())
+
+        pytest.raises(Exception, t, t)
+        pytest.raises(Exception, t, {})
+
+        if tname in ["t8", "s8"]:
+            pytest.raises(OverflowError, t, 100000000000000000000000)
+            pytest.raises(OverflowError, t, 10000000011111111111111.23)
+
+
+class TestFReturnInteger(TestReturnInteger):
+    sources = [
+        util.getpath("tests", "src", "return_integer", "foo77.f"),
+        util.getpath("tests", "src", "return_integer", "foo90.f90"),
+    ]
+
+    @pytest.mark.parametrize("name",
+                             "t0,t1,t2,t4,t8,s0,s1,s2,s4,s8".split(","))
+    def test_all_f77(self, name):
+        self.check_function(getattr(self.module, name), name)
+
+    @pytest.mark.parametrize("name",
+                             "t0,t1,t2,t4,t8,s0,s1,s2,s4,s8".split(","))
+    def test_all_f90(self, name):
+        self.check_function(getattr(self.module.f90_return_integer, name),
+                            name)
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_return_logical.py b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_return_logical.py
new file mode 100644
index 00000000..92fb902a
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_return_logical.py
@@ -0,0 +1,64 @@
+import pytest
+
+from numpy import array
+from . import util
+
+
+class TestReturnLogical(util.F2PyTest):
+    def check_function(self, t):
+        assert t(True) == 1
+        assert t(False) == 0
+        assert t(0) == 0
+        assert t(None) == 0
+        assert t(0.0) == 0
+        assert t(0j) == 0
+        assert t(1j) == 1
+        assert t(234) == 1
+        assert t(234.6) == 1
+        assert t(234.6 + 3j) == 1
+        assert t("234") == 1
+        assert t("aaa") == 1
+        assert t("") == 0
+        assert t([]) == 0
+        assert t(()) == 0
+        assert t({}) == 0
+        assert t(t) == 1
+        assert t(-234) == 1
+        assert t(10**100) == 1
+        assert t([234]) == 1
+        assert t((234, )) == 1
+        assert t(array(234)) == 1
+        assert t(array([234])) == 1
+        assert t(array([[234]])) == 1
+        assert t(array([127], "b")) == 1
+        assert t(array([234], "h")) == 1
+        assert t(array([234], "i")) == 1
+        assert t(array([234], "l")) == 1
+        assert t(array([234], "f")) == 1
+        assert t(array([234], "d")) == 1
+        assert t(array([234 + 3j], "F")) == 1
+        assert t(array([234], "D")) == 1
+        assert t(array(0)) == 0
+        assert t(array([0])) == 0
+        assert t(array([[0]])) == 0
+        assert t(array([0j])) == 0
+        assert t(array([1])) == 1
+        pytest.raises(ValueError, t, array([0, 0]))
+
+
+class TestFReturnLogical(TestReturnLogical):
+    sources = [
+        util.getpath("tests", "src", "return_logical", "foo77.f"),
+        util.getpath("tests", "src", "return_logical", "foo90.f90"),
+    ]
+
+    @pytest.mark.slow
+    @pytest.mark.parametrize("name", "t0,t1,t2,t4,s0,s1,s2,s4".split(","))
+    def test_all_f77(self, name):
+        self.check_function(getattr(self.module, name))
+
+    @pytest.mark.slow
+    @pytest.mark.parametrize("name",
+                             "t0,t1,t2,t4,t8,s0,s1,s2,s4,s8".split(","))
+    def test_all_f90(self, name):
+        self.check_function(getattr(self.module.f90_return_logical, name))
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_return_real.py b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_return_real.py
new file mode 100644
index 00000000..a15d6475
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_return_real.py
@@ -0,0 +1,107 @@
+import platform
+import pytest
+import numpy as np
+
+from numpy import array
+from . import util
+
+
+class TestReturnReal(util.F2PyTest):
+    def check_function(self, t, tname):
+        if tname in ["t0", "t4", "s0", "s4"]:
+            err = 1e-5
+        else:
+            err = 0.0
+        assert abs(t(234) - 234.0) <= err
+        assert abs(t(234.6) - 234.6) <= err
+        assert abs(t("234") - 234) <= err
+        assert abs(t("234.6") - 234.6) <= err
+        assert abs(t(-234) + 234) <= err
+        assert abs(t([234]) - 234) <= err
+        assert abs(t((234, )) - 234.0) <= err
+        assert abs(t(array(234)) - 234.0) <= err
+        assert abs(t(array(234).astype("b")) + 22) <= err
+        assert abs(t(array(234, "h")) - 234.0) <= err
+        assert abs(t(array(234, "i")) - 234.0) <= err
+        assert abs(t(array(234, "l")) - 234.0) <= err
+        assert abs(t(array(234, "B")) - 234.0) <= err
+        assert abs(t(array(234, "f")) - 234.0) <= err
+        assert abs(t(array(234, "d")) - 234.0) <= err
+        if tname in ["t0", "t4", "s0", "s4"]:
+            assert t(1e200) == t(1e300)  # inf
+
+        # pytest.raises(ValueError, t, array([234], 'S1'))
+        pytest.raises(ValueError, t, "abc")
+
+        pytest.raises(IndexError, t, [])
+        pytest.raises(IndexError, t, ())
+
+        pytest.raises(Exception, t, t)
+        pytest.raises(Exception, t, {})
+
+        try:
+            r = t(10**400)
+            assert repr(r) in ["inf", "Infinity"]
+        except OverflowError:
+            pass
+
+
+@pytest.mark.skipif(
+    platform.system() == "Darwin",
+    reason="Prone to error when run with numpy/f2py/tests on mac os, "
+    "but not when run in isolation",
+)
+@pytest.mark.skipif(
+    np.dtype(np.intp).itemsize < 8,
+    reason="32-bit builds are buggy"
+)
+class TestCReturnReal(TestReturnReal):
+    suffix = ".pyf"
+    module_name = "c_ext_return_real"
+    code = """
+python module c_ext_return_real
+usercode \'\'\'
+float t4(float value) { return value; }
+void s4(float *t4, float value) { *t4 = value; }
+double t8(double value) { return value; }
+void s8(double *t8, double value) { *t8 = value; }
+\'\'\'
+interface
+  function t4(value)
+    real*4 intent(c) :: t4,value
+  end
+  function t8(value)
+    real*8 intent(c) :: t8,value
+  end
+  subroutine s4(t4,value)
+    intent(c) s4
+    real*4 intent(out) :: t4
+    real*4 intent(c) :: value
+  end
+  subroutine s8(t8,value)
+    intent(c) s8
+    real*8 intent(out) :: t8
+    real*8 intent(c) :: value
+  end
+end interface
+end python module c_ext_return_real
+    """
+
+    @pytest.mark.parametrize("name", "t4,t8,s4,s8".split(","))
+    def test_all(self, name):
+        self.check_function(getattr(self.module, name), name)
+
+
+class TestFReturnReal(TestReturnReal):
+    sources = [
+        util.getpath("tests", "src", "return_real", "foo77.f"),
+        util.getpath("tests", "src", "return_real", "foo90.f90"),
+    ]
+
+    @pytest.mark.parametrize("name", "t0,t4,t8,td,s0,s4,s8,sd".split(","))
+    def test_all_f77(self, name):
+        self.check_function(getattr(self.module, name), name)
+
+    @pytest.mark.parametrize("name", "t0,t4,t8,td,s0,s4,s8,sd".split(","))
+    def test_all_f90(self, name):
+        self.check_function(getattr(self.module.f90_return_real, name), name)
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_semicolon_split.py b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_semicolon_split.py
new file mode 100644
index 00000000..6d499046
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_semicolon_split.py
@@ -0,0 +1,74 @@
+import platform
+import pytest
+import numpy as np
+
+from . import util
+
+
+@pytest.mark.skipif(
+    platform.system() == "Darwin",
+    reason="Prone to error when run with numpy/f2py/tests on mac os, "
+    "but not when run in isolation",
+)
+@pytest.mark.skipif(
+    np.dtype(np.intp).itemsize < 8,
+    reason="32-bit builds are buggy"
+)
+class TestMultiline(util.F2PyTest):
+    suffix = ".pyf"
+    module_name = "multiline"
+    code = f"""
+python module {module_name}
+    usercode '''
+void foo(int* x) {{
+    char dummy = ';';
+    *x = 42;
+}}
+'''
+    interface
+        subroutine foo(x)
+            intent(c) foo
+            integer intent(out) :: x
+        end subroutine foo
+    end interface
+end python module {module_name}
+    """
+
+    def test_multiline(self):
+        assert self.module.foo() == 42
+
+
+@pytest.mark.skipif(
+    platform.system() == "Darwin",
+    reason="Prone to error when run with numpy/f2py/tests on mac os, "
+    "but not when run in isolation",
+)
+@pytest.mark.skipif(
+    np.dtype(np.intp).itemsize < 8,
+    reason="32-bit builds are buggy"
+)
+class TestCallstatement(util.F2PyTest):
+    suffix = ".pyf"
+    module_name = "callstatement"
+    code = f"""
+python module {module_name}
+    usercode '''
+void foo(int* x) {{
+}}
+'''
+    interface
+        subroutine foo(x)
+            intent(c) foo
+            integer intent(out) :: x
+            callprotoargument int*
+            callstatement {{ &
+                ; &
+                x = 42; &
+            }}
+        end subroutine foo
+    end interface
+end python module {module_name}
+    """
+
+    def test_callstatement(self):
+        assert self.module.foo() == 42
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_size.py b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_size.py
new file mode 100644
index 00000000..bd2c349d
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_size.py
@@ -0,0 +1,45 @@
+import os
+import pytest
+import numpy as np
+
+from . import util
+
+
+class TestSizeSumExample(util.F2PyTest):
+    sources = [util.getpath("tests", "src", "size", "foo.f90")]
+
+    @pytest.mark.slow
+    def test_all(self):
+        r = self.module.foo([[]])
+        assert r == [0]
+
+        r = self.module.foo([[1, 2]])
+        assert r == [3]
+
+        r = self.module.foo([[1, 2], [3, 4]])
+        assert np.allclose(r, [3, 7])
+
+        r = self.module.foo([[1, 2], [3, 4], [5, 6]])
+        assert np.allclose(r, [3, 7, 11])
+
+    @pytest.mark.slow
+    def test_transpose(self):
+        r = self.module.trans([[]])
+        assert np.allclose(r.T, np.array([[]]))
+
+        r = self.module.trans([[1, 2]])
+        assert np.allclose(r, [[1.], [2.]])
+
+        r = self.module.trans([[1, 2, 3], [4, 5, 6]])
+        assert np.allclose(r, [[1, 4], [2, 5], [3, 6]])
+
+    @pytest.mark.slow
+    def test_flatten(self):
+        r = self.module.flatten([[]])
+        assert np.allclose(r, [])
+
+        r = self.module.flatten([[1, 2]])
+        assert np.allclose(r, [1, 2])
+
+        r = self.module.flatten([[1, 2, 3], [4, 5, 6]])
+        assert np.allclose(r, [1, 2, 3, 4, 5, 6])
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_string.py b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_string.py
new file mode 100644
index 00000000..9e937188
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_string.py
@@ -0,0 +1,100 @@
+import os
+import pytest
+import textwrap
+import numpy as np
+from . import util
+
+
+class TestString(util.F2PyTest):
+    sources = [util.getpath("tests", "src", "string", "char.f90")]
+
+    @pytest.mark.slow
+    def test_char(self):
+        strings = np.array(["ab", "cd", "ef"], dtype="c").T
+        inp, out = self.module.char_test.change_strings(
+            strings, strings.shape[1])
+        assert inp == pytest.approx(strings)
+        expected = strings.copy()
+        expected[1, :] = "AAA"
+        assert out == pytest.approx(expected)
+
+
+class TestDocStringArguments(util.F2PyTest):
+    sources = [util.getpath("tests", "src", "string", "string.f")]
+
+    def test_example(self):
+        a = np.array(b"123\0\0")
+        b = np.array(b"123\0\0")
+        c = np.array(b"123")
+        d = np.array(b"123")
+
+        self.module.foo(a, b, c, d)
+
+        assert a.tobytes() == b"123\0\0"
+        assert b.tobytes() == b"B23\0\0"
+        assert c.tobytes() == b"123"
+        assert d.tobytes() == b"D23"
+
+
+class TestFixedString(util.F2PyTest):
+    sources = [util.getpath("tests", "src", "string", "fixed_string.f90")]
+
+    @staticmethod
+    def _sint(s, start=0, end=None):
+        """Return the content of a string buffer as integer value.
+
+        For example:
+          _sint('1234') -> 4321
+          _sint('123A') -> 17321
+        """
+        if isinstance(s, np.ndarray):
+            s = s.tobytes()
+        elif isinstance(s, str):
+            s = s.encode()
+        assert isinstance(s, bytes)
+        if end is None:
+            end = len(s)
+        i = 0
+        for j in range(start, min(end, len(s))):
+            i += s[j] * 10**j
+        return i
+
+    def _get_input(self, intent="in"):
+        if intent in ["in"]:
+            yield ""
+            yield "1"
+            yield "1234"
+            yield "12345"
+            yield b""
+            yield b"\0"
+            yield b"1"
+            yield b"\01"
+            yield b"1\0"
+            yield b"1234"
+            yield b"12345"
+        yield np.ndarray((), np.bytes_, buffer=b"")  # array(b'', dtype='|S0')
+        yield np.array(b"")  # array(b'', dtype='|S1')
+        yield np.array(b"\0")
+        yield np.array(b"1")
+        yield np.array(b"1\0")
+        yield np.array(b"\01")
+        yield np.array(b"1234")
+        yield np.array(b"123\0")
+        yield np.array(b"12345")
+
+    def test_intent_in(self):
+        for s in self._get_input():
+            r = self.module.test_in_bytes4(s)
+            # also checks that s is not changed inplace
+            expected = self._sint(s, end=4)
+            assert r == expected, s
+
+    def test_intent_inout(self):
+        for s in self._get_input(intent="inout"):
+            rest = self._sint(s, start=4)
+            r = self.module.test_inout_bytes4(s)
+            expected = self._sint(s, end=4)
+            assert r == expected
+
+            # check that the rest of input string is preserved
+            assert rest == self._sint(s, start=4)
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_symbolic.py b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_symbolic.py
new file mode 100644
index 00000000..84527831
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_symbolic.py
@@ -0,0 +1,494 @@
+import pytest
+
+from numpy.f2py.symbolic import (
+    Expr,
+    Op,
+    ArithOp,
+    Language,
+    as_symbol,
+    as_number,
+    as_string,
+    as_array,
+    as_complex,
+    as_terms,
+    as_factors,
+    eliminate_quotes,
+    insert_quotes,
+    fromstring,
+    as_expr,
+    as_apply,
+    as_numer_denom,
+    as_ternary,
+    as_ref,
+    as_deref,
+    normalize,
+    as_eq,
+    as_ne,
+    as_lt,
+    as_gt,
+    as_le,
+    as_ge,
+)
+from . import util
+
+
+class TestSymbolic(util.F2PyTest):
+    def test_eliminate_quotes(self):
+        def worker(s):
+            r, d = eliminate_quotes(s)
+            s1 = insert_quotes(r, d)
+            assert s1 == s
+
+        for kind in ["", "mykind_"]:
+            worker(kind + '"1234" // "ABCD"')
+            worker(kind + '"1234" // ' + kind + '"ABCD"')
+            worker(kind + "\"1234\" // 'ABCD'")
+            worker(kind + '"1234" // ' + kind + "'ABCD'")
+            worker(kind + '"1\\"2\'AB\'34"')
+            worker("a = " + kind + "'1\\'2\"AB\"34'")
+
+    def test_sanity(self):
+        x = as_symbol("x")
+        y = as_symbol("y")
+        z = as_symbol("z")
+
+        assert x.op == Op.SYMBOL
+        assert repr(x) == "Expr(Op.SYMBOL, 'x')"
+        assert x == x
+        assert x != y
+        assert hash(x) is not None
+
+        n = as_number(123)
+        m = as_number(456)
+        assert n.op == Op.INTEGER
+        assert repr(n) == "Expr(Op.INTEGER, (123, 4))"
+        assert n == n
+        assert n != m
+        assert hash(n) is not None
+
+        fn = as_number(12.3)
+        fm = as_number(45.6)
+        assert fn.op == Op.REAL
+        assert repr(fn) == "Expr(Op.REAL, (12.3, 4))"
+        assert fn == fn
+        assert fn != fm
+        assert hash(fn) is not None
+
+        c = as_complex(1, 2)
+        c2 = as_complex(3, 4)
+        assert c.op == Op.COMPLEX
+        assert repr(c) == ("Expr(Op.COMPLEX, (Expr(Op.INTEGER, (1, 4)),"
+                           " Expr(Op.INTEGER, (2, 4))))")
+        assert c == c
+        assert c != c2
+        assert hash(c) is not None
+
+        s = as_string("'123'")
+        s2 = as_string('"ABC"')
+        assert s.op == Op.STRING
+        assert repr(s) == "Expr(Op.STRING, (\"'123'\", 1))", repr(s)
+        assert s == s
+        assert s != s2
+
+        a = as_array((n, m))
+        b = as_array((n, ))
+        assert a.op == Op.ARRAY
+        assert repr(a) == ("Expr(Op.ARRAY, (Expr(Op.INTEGER, (123, 4)),"
+                           " Expr(Op.INTEGER, (456, 4))))")
+        assert a == a
+        assert a != b
+
+        t = as_terms(x)
+        u = as_terms(y)
+        assert t.op == Op.TERMS
+        assert repr(t) == "Expr(Op.TERMS, {Expr(Op.SYMBOL, 'x'): 1})"
+        assert t == t
+        assert t != u
+        assert hash(t) is not None
+
+        v = as_factors(x)
+        w = as_factors(y)
+        assert v.op == Op.FACTORS
+        assert repr(v) == "Expr(Op.FACTORS, {Expr(Op.SYMBOL, 'x'): 1})"
+        assert v == v
+        assert w != v
+        assert hash(v) is not None
+
+        t = as_ternary(x, y, z)
+        u = as_ternary(x, z, y)
+        assert t.op == Op.TERNARY
+        assert t == t
+        assert t != u
+        assert hash(t) is not None
+
+        e = as_eq(x, y)
+        f = as_lt(x, y)
+        assert e.op == Op.RELATIONAL
+        assert e == e
+        assert e != f
+        assert hash(e) is not None
+
+    def test_tostring_fortran(self):
+        x = as_symbol("x")
+        y = as_symbol("y")
+        z = as_symbol("z")
+        n = as_number(123)
+        m = as_number(456)
+        a = as_array((n, m))
+        c = as_complex(n, m)
+
+        assert str(x) == "x"
+        assert str(n) == "123"
+        assert str(a) == "[123, 456]"
+        assert str(c) == "(123, 456)"
+
+        assert str(Expr(Op.TERMS, {x: 1})) == "x"
+        assert str(Expr(Op.TERMS, {x: 2})) == "2 * x"
+        assert str(Expr(Op.TERMS, {x: -1})) == "-x"
+        assert str(Expr(Op.TERMS, {x: -2})) == "-2 * x"
+        assert str(Expr(Op.TERMS, {x: 1, y: 1})) == "x + y"
+        assert str(Expr(Op.TERMS, {x: -1, y: -1})) == "-x - y"
+        assert str(Expr(Op.TERMS, {x: 2, y: 3})) == "2 * x + 3 * y"
+        assert str(Expr(Op.TERMS, {x: -2, y: 3})) == "-2 * x + 3 * y"
+        assert str(Expr(Op.TERMS, {x: 2, y: -3})) == "2 * x - 3 * y"
+
+        assert str(Expr(Op.FACTORS, {x: 1})) == "x"
+        assert str(Expr(Op.FACTORS, {x: 2})) == "x ** 2"
+        assert str(Expr(Op.FACTORS, {x: -1})) == "x ** -1"
+        assert str(Expr(Op.FACTORS, {x: -2})) == "x ** -2"
+        assert str(Expr(Op.FACTORS, {x: 1, y: 1})) == "x * y"
+        assert str(Expr(Op.FACTORS, {x: 2, y: 3})) == "x ** 2 * y ** 3"
+
+        v = Expr(Op.FACTORS, {x: 2, Expr(Op.TERMS, {x: 1, y: 1}): 3})
+        assert str(v) == "x ** 2 * (x + y) ** 3", str(v)
+        v = Expr(Op.FACTORS, {x: 2, Expr(Op.FACTORS, {x: 1, y: 1}): 3})
+        assert str(v) == "x ** 2 * (x * y) ** 3", str(v)
+
+        assert str(Expr(Op.APPLY, ("f", (), {}))) == "f()"
+        assert str(Expr(Op.APPLY, ("f", (x, ), {}))) == "f(x)"
+        assert str(Expr(Op.APPLY, ("f", (x, y), {}))) == "f(x, y)"
+        assert str(Expr(Op.INDEXING, ("f", x))) == "f[x]"
+
+        assert str(as_ternary(x, y, z)) == "merge(y, z, x)"
+        assert str(as_eq(x, y)) == "x .eq. y"
+        assert str(as_ne(x, y)) == "x .ne. y"
+        assert str(as_lt(x, y)) == "x .lt. y"
+        assert str(as_le(x, y)) == "x .le. y"
+        assert str(as_gt(x, y)) == "x .gt. y"
+        assert str(as_ge(x, y)) == "x .ge. y"
+
+    def test_tostring_c(self):
+        language = Language.C
+        x = as_symbol("x")
+        y = as_symbol("y")
+        z = as_symbol("z")
+        n = as_number(123)
+
+        assert Expr(Op.FACTORS, {x: 2}).tostring(language=language) == "x * x"
+        assert (Expr(Op.FACTORS, {
+            x + y: 2
+        }).tostring(language=language) == "(x + y) * (x + y)")
+        assert Expr(Op.FACTORS, {
+            x: 12
+        }).tostring(language=language) == "pow(x, 12)"
+
+        assert as_apply(ArithOp.DIV, x,
+                        y).tostring(language=language) == "x / y"
+        assert (as_apply(ArithOp.DIV, x,
+                         x + y).tostring(language=language) == "x / (x + y)")
+        assert (as_apply(ArithOp.DIV, x - y, x +
+                         y).tostring(language=language) == "(x - y) / (x + y)")
+        assert (x + (x - y) / (x + y) +
+                n).tostring(language=language) == "123 + x + (x - y) / (x + y)"
+
+        assert as_ternary(x, y, z).tostring(language=language) == "(x?y:z)"
+        assert as_eq(x, y).tostring(language=language) == "x == y"
+        assert as_ne(x, y).tostring(language=language) == "x != y"
+        assert as_lt(x, y).tostring(language=language) == "x < y"
+        assert as_le(x, y).tostring(language=language) == "x <= y"
+        assert as_gt(x, y).tostring(language=language) == "x > y"
+        assert as_ge(x, y).tostring(language=language) == "x >= y"
+
+    def test_operations(self):
+        x = as_symbol("x")
+        y = as_symbol("y")
+        z = as_symbol("z")
+
+        assert x + x == Expr(Op.TERMS, {x: 2})
+        assert x - x == Expr(Op.INTEGER, (0, 4))
+        assert x + y == Expr(Op.TERMS, {x: 1, y: 1})
+        assert x - y == Expr(Op.TERMS, {x: 1, y: -1})
+        assert x * x == Expr(Op.FACTORS, {x: 2})
+        assert x * y == Expr(Op.FACTORS, {x: 1, y: 1})
+
+        assert +x == x
+        assert -x == Expr(Op.TERMS, {x: -1}), repr(-x)
+        assert 2 * x == Expr(Op.TERMS, {x: 2})
+        assert 2 + x == Expr(Op.TERMS, {x: 1, as_number(1): 2})
+        assert 2 * x + 3 * y == Expr(Op.TERMS, {x: 2, y: 3})
+        assert (x + y) * 2 == Expr(Op.TERMS, {x: 2, y: 2})
+
+        assert x**2 == Expr(Op.FACTORS, {x: 2})
+        assert (x + y)**2 == Expr(
+            Op.TERMS,
+            {
+                Expr(Op.FACTORS, {x: 2}): 1,
+                Expr(Op.FACTORS, {y: 2}): 1,
+                Expr(Op.FACTORS, {
+                    x: 1,
+                    y: 1
+                }): 2,
+            },
+        )
+        assert (x + y) * x == x**2 + x * y
+        assert (x + y)**2 == x**2 + 2 * x * y + y**2
+        assert (x + y)**2 + (x - y)**2 == 2 * x**2 + 2 * y**2
+        assert (x + y) * z == x * z + y * z
+        assert z * (x + y) == x * z + y * z
+
+        assert (x / 2) == as_apply(ArithOp.DIV, x, as_number(2))
+        assert (2 * x / 2) == x
+        assert (3 * x / 2) == as_apply(ArithOp.DIV, 3 * x, as_number(2))
+        assert (4 * x / 2) == 2 * x
+        assert (5 * x / 2) == as_apply(ArithOp.DIV, 5 * x, as_number(2))
+        assert (6 * x / 2) == 3 * x
+        assert ((3 * 5) * x / 6) == as_apply(ArithOp.DIV, 5 * x, as_number(2))
+        assert (30 * x**2 * y**4 / (24 * x**3 * y**3)) == as_apply(
+            ArithOp.DIV, 5 * y, 4 * x)
+        assert ((15 * x / 6) / 5) == as_apply(ArithOp.DIV, x,
+                                              as_number(2)), (15 * x / 6) / 5
+        assert (x / (5 / x)) == as_apply(ArithOp.DIV, x**2, as_number(5))
+
+        assert (x / 2.0) == Expr(Op.TERMS, {x: 0.5})
+
+        s = as_string('"ABC"')
+        t = as_string('"123"')
+
+        assert s // t == Expr(Op.STRING, ('"ABC123"', 1))
+        assert s // x == Expr(Op.CONCAT, (s, x))
+        assert x // s == Expr(Op.CONCAT, (x, s))
+
+        c = as_complex(1.0, 2.0)
+        assert -c == as_complex(-1.0, -2.0)
+        assert c + c == as_expr((1 + 2j) * 2)
+        assert c * c == as_expr((1 + 2j)**2)
+
+    def test_substitute(self):
+        x = as_symbol("x")
+        y = as_symbol("y")
+        z = as_symbol("z")
+        a = as_array((x, y))
+
+        assert x.substitute({x: y}) == y
+        assert (x + y).substitute({x: z}) == y + z
+        assert (x * y).substitute({x: z}) == y * z
+        assert (x**4).substitute({x: z}) == z**4
+        assert (x / y).substitute({x: z}) == z / y
+        assert x.substitute({x: y + z}) == y + z
+        assert a.substitute({x: y + z}) == as_array((y + z, y))
+
+        assert as_ternary(x, y,
+                          z).substitute({x: y + z}) == as_ternary(y + z, y, z)
+        assert as_eq(x, y).substitute({x: y + z}) == as_eq(y + z, y)
+
+    def test_fromstring(self):
+
+        x = as_symbol("x")
+        y = as_symbol("y")
+        z = as_symbol("z")
+        f = as_symbol("f")
+        s = as_string('"ABC"')
+        t = as_string('"123"')
+        a = as_array((x, y))
+
+        assert fromstring("x") == x
+        assert fromstring("+ x") == x
+        assert fromstring("-  x") == -x
+        assert fromstring("x + y") == x + y
+        assert fromstring("x + 1") == x + 1
+        assert fromstring("x * y") == x * y
+        assert fromstring("x * 2") == x * 2
+        assert fromstring("x / y") == x / y
+        assert fromstring("x ** 2", language=Language.Python) == x**2
+        assert fromstring("x ** 2 ** 3", language=Language.Python) == x**2**3
+        assert fromstring("(x + y) * z") == (x + y) * z
+
+        assert fromstring("f(x)") == f(x)
+        assert fromstring("f(x,y)") == f(x, y)
+        assert fromstring("f[x]") == f[x]
+        assert fromstring("f[x][y]") == f[x][y]
+
+        assert fromstring('"ABC"') == s
+        assert (normalize(
+            fromstring('"ABC" // "123" ',
+                       language=Language.Fortran)) == s // t)
+        assert fromstring('f("ABC")') == f(s)
+        assert fromstring('MYSTRKIND_"ABC"') == as_string('"ABC"', "MYSTRKIND")
+
+        assert fromstring("(/x, y/)") == a, fromstring("(/x, y/)")
+        assert fromstring("f((/x, y/))") == f(a)
+        assert fromstring("(/(x+y)*z/)") == as_array(((x + y) * z, ))
+
+        assert fromstring("123") == as_number(123)
+        assert fromstring("123_2") == as_number(123, 2)
+        assert fromstring("123_myintkind") == as_number(123, "myintkind")
+
+        assert fromstring("123.0") == as_number(123.0, 4)
+        assert fromstring("123.0_4") == as_number(123.0, 4)
+        assert fromstring("123.0_8") == as_number(123.0, 8)
+        assert fromstring("123.0e0") == as_number(123.0, 4)
+        assert fromstring("123.0d0") == as_number(123.0, 8)
+        assert fromstring("123d0") == as_number(123.0, 8)
+        assert fromstring("123e-0") == as_number(123.0, 4)
+        assert fromstring("123d+0") == as_number(123.0, 8)
+        assert fromstring("123.0_myrealkind") == as_number(123.0, "myrealkind")
+        assert fromstring("3E4") == as_number(30000.0, 4)
+
+        assert fromstring("(1, 2)") == as_complex(1, 2)
+        assert fromstring("(1e2, PI)") == as_complex(as_number(100.0),
+                                                     as_symbol("PI"))
+
+        assert fromstring("[1, 2]") == as_array((as_number(1), as_number(2)))
+
+        assert fromstring("POINT(x, y=1)") == as_apply(as_symbol("POINT"),
+                                                       x,
+                                                       y=as_number(1))
+        assert fromstring(
+            'PERSON(name="John", age=50, shape=(/34, 23/))') == as_apply(
+                as_symbol("PERSON"),
+                name=as_string('"John"'),
+                age=as_number(50),
+                shape=as_array((as_number(34), as_number(23))),
+            )
+
+        assert fromstring("x?y:z") == as_ternary(x, y, z)
+
+        assert fromstring("*x") == as_deref(x)
+        assert fromstring("**x") == as_deref(as_deref(x))
+        assert fromstring("&x") == as_ref(x)
+        assert fromstring("(*x) * (*y)") == as_deref(x) * as_deref(y)
+        assert fromstring("(*x) * *y") == as_deref(x) * as_deref(y)
+        assert fromstring("*x * *y") == as_deref(x) * as_deref(y)
+        assert fromstring("*x**y") == as_deref(x) * as_deref(y)
+
+        assert fromstring("x == y") == as_eq(x, y)
+        assert fromstring("x != y") == as_ne(x, y)
+        assert fromstring("x < y") == as_lt(x, y)
+        assert fromstring("x > y") == as_gt(x, y)
+        assert fromstring("x <= y") == as_le(x, y)
+        assert fromstring("x >= y") == as_ge(x, y)
+
+        assert fromstring("x .eq. y", language=Language.Fortran) == as_eq(x, y)
+        assert fromstring("x .ne. y", language=Language.Fortran) == as_ne(x, y)
+        assert fromstring("x .lt. y", language=Language.Fortran) == as_lt(x, y)
+        assert fromstring("x .gt. y", language=Language.Fortran) == as_gt(x, y)
+        assert fromstring("x .le. y", language=Language.Fortran) == as_le(x, y)
+        assert fromstring("x .ge. y", language=Language.Fortran) == as_ge(x, y)
+
+    def test_traverse(self):
+        x = as_symbol("x")
+        y = as_symbol("y")
+        z = as_symbol("z")
+        f = as_symbol("f")
+
+        # Use traverse to substitute a symbol
+        def replace_visit(s, r=z):
+            if s == x:
+                return r
+
+        assert x.traverse(replace_visit) == z
+        assert y.traverse(replace_visit) == y
+        assert z.traverse(replace_visit) == z
+        assert (f(y)).traverse(replace_visit) == f(y)
+        assert (f(x)).traverse(replace_visit) == f(z)
+        assert (f[y]).traverse(replace_visit) == f[y]
+        assert (f[z]).traverse(replace_visit) == f[z]
+        assert (x + y + z).traverse(replace_visit) == (2 * z + y)
+        assert (x +
+                f(y, x - z)).traverse(replace_visit) == (z +
+                                                         f(y, as_number(0)))
+        assert as_eq(x, y).traverse(replace_visit) == as_eq(z, y)
+
+        # Use traverse to collect symbols, method 1
+        function_symbols = set()
+        symbols = set()
+
+        def collect_symbols(s):
+            if s.op is Op.APPLY:
+                oper = s.data[0]
+                function_symbols.add(oper)
+                if oper in symbols:
+                    symbols.remove(oper)
+            elif s.op is Op.SYMBOL and s not in function_symbols:
+                symbols.add(s)
+
+        (x + f(y, x - z)).traverse(collect_symbols)
+        assert function_symbols == {f}
+        assert symbols == {x, y, z}
+
+        # Use traverse to collect symbols, method 2
+        def collect_symbols2(expr, symbols):
+            if expr.op is Op.SYMBOL:
+                symbols.add(expr)
+
+        symbols = set()
+        (x + f(y, x - z)).traverse(collect_symbols2, symbols)
+        assert symbols == {x, y, z, f}
+
+        # Use traverse to partially collect symbols
+        def collect_symbols3(expr, symbols):
+            if expr.op is Op.APPLY:
+                # skip traversing function calls
+                return expr
+            if expr.op is Op.SYMBOL:
+                symbols.add(expr)
+
+        symbols = set()
+        (x + f(y, x - z)).traverse(collect_symbols3, symbols)
+        assert symbols == {x}
+
+    def test_linear_solve(self):
+        x = as_symbol("x")
+        y = as_symbol("y")
+        z = as_symbol("z")
+
+        assert x.linear_solve(x) == (as_number(1), as_number(0))
+        assert (x + 1).linear_solve(x) == (as_number(1), as_number(1))
+        assert (2 * x).linear_solve(x) == (as_number(2), as_number(0))
+        assert (2 * x + 3).linear_solve(x) == (as_number(2), as_number(3))
+        assert as_number(3).linear_solve(x) == (as_number(0), as_number(3))
+        assert y.linear_solve(x) == (as_number(0), y)
+        assert (y * z).linear_solve(x) == (as_number(0), y * z)
+
+        assert (x + y).linear_solve(x) == (as_number(1), y)
+        assert (z * x + y).linear_solve(x) == (z, y)
+        assert ((z + y) * x + y).linear_solve(x) == (z + y, y)
+        assert (z * y * x + y).linear_solve(x) == (z * y, y)
+
+        pytest.raises(RuntimeError, lambda: (x * x).linear_solve(x))
+
+    def test_as_numer_denom(self):
+        x = as_symbol("x")
+        y = as_symbol("y")
+        n = as_number(123)
+
+        assert as_numer_denom(x) == (x, as_number(1))
+        assert as_numer_denom(x / n) == (x, n)
+        assert as_numer_denom(n / x) == (n, x)
+        assert as_numer_denom(x / y) == (x, y)
+        assert as_numer_denom(x * y) == (x * y, as_number(1))
+        assert as_numer_denom(n + x / y) == (x + n * y, y)
+        assert as_numer_denom(n + x / (y - x / n)) == (y * n**2, y * n - x)
+
+    def test_polynomial_atoms(self):
+        x = as_symbol("x")
+        y = as_symbol("y")
+        n = as_number(123)
+
+        assert x.polynomial_atoms() == {x}
+        assert n.polynomial_atoms() == set()
+        assert (y[x]).polynomial_atoms() == {y[x]}
+        assert (y(x)).polynomial_atoms() == {y(x)}
+        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)}
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_value_attrspec.py b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_value_attrspec.py
new file mode 100644
index 00000000..83aaf6c9
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/test_value_attrspec.py
@@ -0,0 +1,14 @@
+import os
+import pytest
+
+from . import util
+
+class TestValueAttr(util.F2PyTest):
+    sources = [util.getpath("tests", "src", "value_attrspec", "gh21665.f90")]
+
+    # gh-21665
+    def test_long_long_map(self):
+        inp = 2
+        out = self.module.fortfuncs.square(inp)
+        exp_out = 4
+        assert out == exp_out
diff --git a/.venv/lib/python3.12/site-packages/numpy/f2py/tests/util.py b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/util.py
new file mode 100644
index 00000000..6ed6c085
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/numpy/f2py/tests/util.py
@@ -0,0 +1,440 @@
+"""
+Utility functions for
+
+- building and importing modules on test time, using a temporary location
+- detecting if compilers are present
+- determining paths to tests
+
+"""
+import glob
+import os
+import sys
+import subprocess
+import tempfile
+import shutil
+import atexit
+import textwrap
+import re
+import pytest
+import contextlib
+import numpy
+
+from pathlib import Path
+from numpy.compat import asstr
+from numpy._utils import asunicode
+from numpy.testing import temppath, IS_WASM
+from importlib import import_module
+
+#
+# Maintaining a temporary module directory
+#
+
+_module_dir = None
+_module_num = 5403
+
+if sys.platform == "cygwin":
+    NUMPY_INSTALL_ROOT = Path(__file__).parent.parent.parent
+    _module_list = list(NUMPY_INSTALL_ROOT.glob("**/*.dll"))
+
+
+def _cleanup():
+    global _module_dir
+    if _module_dir is not None:
+        try:
+            sys.path.remove(_module_dir)
+        except ValueError:
+            pass
+        try:
+            shutil.rmtree(_module_dir)
+        except OSError:
+            pass
+        _module_dir = None
+
+
+def get_module_dir():
+    global _module_dir
+    if _module_dir is None:
+        _module_dir = tempfile.mkdtemp()
+        atexit.register(_cleanup)
+        if _module_dir not in sys.path:
+            sys.path.insert(0, _module_dir)
+    return _module_dir
+
+
+def get_temp_module_name():
+    # Assume single-threaded, and the module dir usable only by this thread
+    global _module_num
+    get_module_dir()
+    name = "_test_ext_module_%d" % _module_num
+    _module_num += 1
+    if name in sys.modules:
+        # this should not be possible, but check anyway
+        raise RuntimeError("Temporary module name already in use.")
+    return name
+
+
+def _memoize(func):
+    memo = {}
+
+    def wrapper(*a, **kw):
+        key = repr((a, kw))
+        if key not in memo:
+            try:
+                memo[key] = func(*a, **kw)
+            except Exception as e:
+                memo[key] = e
+                raise
+        ret = memo[key]
+        if isinstance(ret, Exception):
+            raise ret
+        return ret
+
+    wrapper.__name__ = func.__name__
+    return wrapper
+
+
+#
+# Building modules
+#
+
+
+@_memoize
+def build_module(source_files, options=[], skip=[], only=[], module_name=None):
+    """
+    Compile and import a f2py module, built from the given files.
+
+    """
+
+    code = f"import sys; sys.path = {sys.path!r}; import numpy.f2py; numpy.f2py.main()"
+
+    d = get_module_dir()
+
+    # Copy files
+    dst_sources = []
+    f2py_sources = []
+    for fn in source_files:
+        if not os.path.isfile(fn):
+            raise RuntimeError("%s is not a file" % fn)
+        dst = os.path.join(d, os.path.basename(fn))
+        shutil.copyfile(fn, dst)
+        dst_sources.append(dst)
+
+        base, ext = os.path.splitext(dst)
+        if ext in (".f90", ".f", ".c", ".pyf"):
+            f2py_sources.append(dst)
+
+    assert f2py_sources
+
+    # Prepare options
+    if module_name is None:
+        module_name = get_temp_module_name()
+    f2py_opts = ["-c", "-m", module_name] + options + f2py_sources
+    if skip:
+        f2py_opts += ["skip:"] + skip
+    if only:
+        f2py_opts += ["only:"] + only
+
+    # Build
+    cwd = os.getcwd()
+    try:
+        os.chdir(d)
+        cmd = [sys.executable, "-c", code] + f2py_opts
+        p = subprocess.Popen(cmd,
+                             stdout=subprocess.PIPE,
+                             stderr=subprocess.STDOUT)
+        out, err = p.communicate()
+        if p.returncode != 0:
+            raise RuntimeError("Running f2py failed: %s\n%s" %
+                               (cmd[4:], asunicode(out)))
+    finally:
+        os.chdir(cwd)
+
+        # Partial cleanup
+        for fn in dst_sources:
+            os.unlink(fn)
+
+    # Rebase (Cygwin-only)
+    if sys.platform == "cygwin":
+        # If someone starts deleting modules after import, this will
+        # need to change to record how big each module is, rather than
+        # relying on rebase being able to find that from the files.
+        _module_list.extend(
+            glob.glob(os.path.join(d, "{:s}*".format(module_name)))
+        )
+        subprocess.check_call(
+            ["/usr/bin/rebase", "--database", "--oblivious", "--verbose"]
+            + _module_list
+        )
+
+
+
+    # Import
+    return import_module(module_name)
+
+
+@_memoize
+def build_code(source_code,
+               options=[],
+               skip=[],
+               only=[],
+               suffix=None,
+               module_name=None):
+    """
+    Compile and import Fortran code using f2py.
+
+    """
+    if suffix is None:
+        suffix = ".f"
+    with temppath(suffix=suffix) as path:
+        with open(path, "w") as f:
+            f.write(source_code)
+        return build_module([path],
+                            options=options,
+                            skip=skip,
+                            only=only,
+                            module_name=module_name)
+
+
+#
+# Check if compilers are available at all...
+#
+
+_compiler_status = None
+
+
+def _get_compiler_status():
+    global _compiler_status
+    if _compiler_status is not None:
+        return _compiler_status
+
+    _compiler_status = (False, False, False)
+    if IS_WASM:
+        # Can't run compiler from inside WASM.
+        return _compiler_status
+
+    # XXX: this is really ugly. But I don't know how to invoke Distutils
+    #      in a safer way...
+    code = textwrap.dedent(f"""\
+        import os
+        import sys
+        sys.path = {repr(sys.path)}
+
+        def configuration(parent_name='',top_path=None):
+            global config
+            from numpy.distutils.misc_util import Configuration
+            config = Configuration('', parent_name, top_path)
+            return config
+
+        from numpy.distutils.core import setup
+        setup(configuration=configuration)
+
+        config_cmd = config.get_config_cmd()
+        have_c = config_cmd.try_compile('void foo() {{}}')
+        print('COMPILERS:%%d,%%d,%%d' %% (have_c,
+                                          config.have_f77c(),
+                                          config.have_f90c()))
+        sys.exit(99)
+        """)
+    code = code % dict(syspath=repr(sys.path))
+
+    tmpdir = tempfile.mkdtemp()
+    try:
+        script = os.path.join(tmpdir, "setup.py")
+
+        with open(script, "w") as f:
+            f.write(code)
+
+        cmd = [sys.executable, "setup.py", "config"]
+        p = subprocess.Popen(cmd,
+                             stdout=subprocess.PIPE,
+                             stderr=subprocess.STDOUT,
+                             cwd=tmpdir)
+        out, err = p.communicate()
+    finally:
+        shutil.rmtree(tmpdir)
+
+    m = re.search(br"COMPILERS:(\d+),(\d+),(\d+)", out)
+    if m:
+        _compiler_status = (
+            bool(int(m.group(1))),
+            bool(int(m.group(2))),
+            bool(int(m.group(3))),
+        )
+    # Finished
+    return _compiler_status
+
+
+def has_c_compiler():
+    return _get_compiler_status()[0]
+
+
+def has_f77_compiler():
+    return _get_compiler_status()[1]
+
+
+def has_f90_compiler():
+    return _get_compiler_status()[2]
+
+
+#
+# Building with distutils
+#
+
+
+@_memoize
+def build_module_distutils(source_files, config_code, module_name, **kw):
+    """
+    Build a module via distutils and import it.
+
+    """
+    d = get_module_dir()
+
+    # Copy files
+    dst_sources = []
+    for fn in source_files:
+        if not os.path.isfile(fn):
+            raise RuntimeError("%s is not a file" % fn)
+        dst = os.path.join(d, os.path.basename(fn))
+        shutil.copyfile(fn, dst)
+        dst_sources.append(dst)
+
+    # Build script
+    config_code = textwrap.dedent(config_code).replace("\n", "\n    ")
+
+    code = fr"""
+import os
+import sys
+sys.path = {repr(sys.path)}
+
+def configuration(parent_name='',top_path=None):
+    from numpy.distutils.misc_util import Configuration
+    config = Configuration('', parent_name, top_path)
+    {config_code}
+    return config
+
+if __name__ == "__main__":
+    from numpy.distutils.core import setup
+    setup(configuration=configuration)
+    """
+    script = os.path.join(d, get_temp_module_name() + ".py")
+    dst_sources.append(script)
+    with open(script, "wb") as f:
+        f.write(code.encode('latin1'))
+
+    # Build
+    cwd = os.getcwd()
+    try:
+        os.chdir(d)
+        cmd = [sys.executable, script, "build_ext", "-i"]
+        p = subprocess.Popen(cmd,
+                             stdout=subprocess.PIPE,
+                             stderr=subprocess.STDOUT)
+        out, err = p.communicate()
+        if p.returncode != 0:
+            raise RuntimeError("Running distutils build failed: %s\n%s" %
+                               (cmd[4:], asstr(out)))
+    finally:
+        os.chdir(cwd)
+
+        # Partial cleanup
+        for fn in dst_sources:
+            os.unlink(fn)
+
+    # Import
+    __import__(module_name)
+    return sys.modules[module_name]
+
+
+#
+# Unittest convenience
+#
+
+
+class F2PyTest:
+    code = None
+    sources = None
+    options = []
+    skip = []
+    only = []
+    suffix = ".f"
+    module = None
+
+    @property
+    def module_name(self):
+        cls = type(self)
+        return f'_{cls.__module__.rsplit(".",1)[-1]}_{cls.__name__}_ext_module'
+
+    def setup_method(self):
+        if sys.platform == "win32":
+            pytest.skip("Fails with MinGW64 Gfortran (Issue #9673)")
+
+        if self.module is not None:
+            return
+
+        # Check compiler availability first
+        if not has_c_compiler():
+            pytest.skip("No C compiler available")
+
+        codes = []
+        if self.sources:
+            codes.extend(self.sources)
+        if self.code is not None:
+            codes.append(self.suffix)
+
+        needs_f77 = False
+        needs_f90 = False
+        needs_pyf = False
+        for fn in codes:
+            if str(fn).endswith(".f"):
+                needs_f77 = True
+            elif str(fn).endswith(".f90"):
+                needs_f90 = True
+            elif str(fn).endswith(".pyf"):
+                needs_pyf = True
+        if needs_f77 and not has_f77_compiler():
+            pytest.skip("No Fortran 77 compiler available")
+        if needs_f90 and not has_f90_compiler():
+            pytest.skip("No Fortran 90 compiler available")
+        if needs_pyf and not (has_f90_compiler() or has_f77_compiler()):
+            pytest.skip("No Fortran compiler available")
+
+        # Build the module
+        if self.code is not None:
+            self.module = build_code(
+                self.code,
+                options=self.options,
+                skip=self.skip,
+                only=self.only,
+                suffix=self.suffix,
+                module_name=self.module_name,
+            )
+
+        if self.sources is not None:
+            self.module = build_module(
+                self.sources,
+                options=self.options,
+                skip=self.skip,
+                only=self.only,
+                module_name=self.module_name,
+            )
+
+
+#
+# Helper functions
+#
+
+
+def getpath(*a):
+    # Package root
+    d = Path(numpy.f2py.__file__).parent.resolve()
+    return d.joinpath(*a)
+
+
+@contextlib.contextmanager
+def switchdir(path):
+    curpath = Path.cwd()
+    os.chdir(path)
+    try:
+        yield
+    finally:
+        os.chdir(curpath)