Updated script that can be controled by Nodejs web app
This commit is contained in:
15
lib/python3.13/site-packages/numpy/f2py/tests/__init__.py
Normal file
15
lib/python3.13/site-packages/numpy/f2py/tests/__init__.py
Normal file
@ -0,0 +1,15 @@
|
||||
from numpy.testing import IS_WASM, IS_EDITABLE
|
||||
import pytest
|
||||
|
||||
if IS_WASM:
|
||||
pytest.skip(
|
||||
"WASM/Pyodide does not use or support Fortran",
|
||||
allow_module_level=True
|
||||
)
|
||||
|
||||
|
||||
if IS_EDITABLE:
|
||||
pytest.skip(
|
||||
"Editable install doesn't support tests with a compile step",
|
||||
allow_module_level=True
|
||||
)
|
@ -0,0 +1,34 @@
|
||||
module ops_module
|
||||
|
||||
abstract interface
|
||||
subroutine op(x, y, z)
|
||||
integer, intent(in) :: x, y
|
||||
integer, intent(out) :: z
|
||||
end subroutine
|
||||
end interface
|
||||
|
||||
contains
|
||||
|
||||
subroutine foo(x, y, r1, r2)
|
||||
integer, intent(in) :: x, y
|
||||
integer, intent(out) :: r1, r2
|
||||
procedure (op) add1, add2
|
||||
procedure (op), pointer::p
|
||||
p=>add1
|
||||
call p(x, y, r1)
|
||||
p=>add2
|
||||
call p(x, y, r2)
|
||||
end subroutine
|
||||
end module
|
||||
|
||||
subroutine add1(x, y, z)
|
||||
integer, intent(in) :: x, y
|
||||
integer, intent(out) :: z
|
||||
z = x + y
|
||||
end subroutine
|
||||
|
||||
subroutine add2(x, y, z)
|
||||
integer, intent(in) :: x, y
|
||||
integer, intent(out) :: z
|
||||
z = x + 2 * y
|
||||
end subroutine
|
@ -0,0 +1,6 @@
|
||||
module test
|
||||
abstract interface
|
||||
subroutine foo()
|
||||
end subroutine
|
||||
end interface
|
||||
end module test
|
@ -0,0 +1,235 @@
|
||||
/*
|
||||
* 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),
|
||||
PyDataType_ALIGNMENT(PyArray_DESCR(arr)),
|
||||
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_LEGACY", NPY_NTYPES_LEGACY);
|
||||
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
|
||||
|
||||
#if Py_GIL_DISABLED
|
||||
// signal whether this module supports running with the GIL disabled
|
||||
PyUnstable_Module_SetGIL(m, Py_MOD_GIL_NOT_USED);
|
||||
#endif
|
||||
|
||||
return m;
|
||||
}
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -0,0 +1 @@
|
||||
dict(real=dict(rk="double"))
|
@ -0,0 +1,34 @@
|
||||
|
||||
subroutine sum(x, res)
|
||||
implicit none
|
||||
real, intent(in) :: x(:)
|
||||
real, intent(out) :: res
|
||||
|
||||
integer :: i
|
||||
|
||||
!print *, "sum: size(x) = ", size(x)
|
||||
|
||||
res = 0.0
|
||||
|
||||
do i = 1, size(x)
|
||||
res = res + x(i)
|
||||
enddo
|
||||
|
||||
end subroutine sum
|
||||
|
||||
function fsum(x) result (res)
|
||||
implicit none
|
||||
real, intent(in) :: x(:)
|
||||
real :: res
|
||||
|
||||
integer :: i
|
||||
|
||||
!print *, "fsum: size(x) = ", size(x)
|
||||
|
||||
res = 0.0
|
||||
|
||||
do i = 1, size(x)
|
||||
res = res + x(i)
|
||||
enddo
|
||||
|
||||
end function fsum
|
@ -0,0 +1,41 @@
|
||||
|
||||
module mod
|
||||
|
||||
contains
|
||||
|
||||
subroutine sum(x, res)
|
||||
implicit none
|
||||
real, intent(in) :: x(:)
|
||||
real, intent(out) :: res
|
||||
|
||||
integer :: i
|
||||
|
||||
!print *, "sum: size(x) = ", size(x)
|
||||
|
||||
res = 0.0
|
||||
|
||||
do i = 1, size(x)
|
||||
res = res + x(i)
|
||||
enddo
|
||||
|
||||
end subroutine sum
|
||||
|
||||
function fsum(x) result (res)
|
||||
implicit none
|
||||
real, intent(in) :: x(:)
|
||||
real :: res
|
||||
|
||||
integer :: i
|
||||
|
||||
!print *, "fsum: size(x) = ", size(x)
|
||||
|
||||
res = 0.0
|
||||
|
||||
do i = 1, size(x)
|
||||
res = res + x(i)
|
||||
enddo
|
||||
|
||||
end function fsum
|
||||
|
||||
|
||||
end module mod
|
@ -0,0 +1,19 @@
|
||||
subroutine sum_with_use(x, res)
|
||||
use precision
|
||||
|
||||
implicit none
|
||||
|
||||
real(kind=rk), intent(in) :: x(:)
|
||||
real(kind=rk), intent(out) :: res
|
||||
|
||||
integer :: i
|
||||
|
||||
!print *, "size(x) = ", size(x)
|
||||
|
||||
res = 0.0
|
||||
|
||||
do i = 1, size(x)
|
||||
res = res + x(i)
|
||||
enddo
|
||||
|
||||
end subroutine
|
@ -0,0 +1,4 @@
|
||||
module precision
|
||||
integer, parameter :: rk = selected_real_kind(8)
|
||||
integer, parameter :: ik = selected_real_kind(4)
|
||||
end module
|
@ -0,0 +1,6 @@
|
||||
SUBROUTINE FOO()
|
||||
INTEGER BAR(2, 3)
|
||||
|
||||
COMMON /BLOCK/ BAR
|
||||
RETURN
|
||||
END
|
@ -0,0 +1,62 @@
|
||||
subroutine t(fun,a)
|
||||
integer a
|
||||
cf2py intent(out) a
|
||||
external fun
|
||||
call fun(a)
|
||||
end
|
||||
|
||||
subroutine func(a)
|
||||
cf2py intent(in,out) a
|
||||
integer a
|
||||
a = a + 11
|
||||
end
|
||||
|
||||
subroutine func0(a)
|
||||
cf2py intent(out) a
|
||||
integer a
|
||||
a = 11
|
||||
end
|
||||
|
||||
subroutine t2(a)
|
||||
cf2py intent(callback) fun
|
||||
integer a
|
||||
cf2py intent(out) a
|
||||
external fun
|
||||
call fun(a)
|
||||
end
|
||||
|
||||
subroutine string_callback(callback, a)
|
||||
external callback
|
||||
double precision callback
|
||||
double precision a
|
||||
character*1 r
|
||||
cf2py intent(out) a
|
||||
r = 'r'
|
||||
a = callback(r)
|
||||
end
|
||||
|
||||
subroutine string_callback_array(callback, cu, lencu, a)
|
||||
external callback
|
||||
integer callback
|
||||
integer lencu
|
||||
character*8 cu(lencu)
|
||||
integer a
|
||||
cf2py intent(out) a
|
||||
|
||||
a = callback(cu, lencu)
|
||||
end
|
||||
|
||||
subroutine hidden_callback(a, r)
|
||||
external global_f
|
||||
cf2py intent(callback, hide) global_f
|
||||
integer a, r, global_f
|
||||
cf2py intent(out) r
|
||||
r = global_f(a)
|
||||
end
|
||||
|
||||
subroutine hidden_callback2(a, r)
|
||||
external global_f
|
||||
integer a, r, global_f
|
||||
cf2py intent(out) r
|
||||
r = global_f(a)
|
||||
end
|
@ -0,0 +1,7 @@
|
||||
function gh17797(f, y) result(r)
|
||||
external f
|
||||
integer(8) :: r, f
|
||||
integer(8), dimension(:) :: y
|
||||
r = f(0)
|
||||
r = r + sum(y)
|
||||
end function gh17797
|
@ -0,0 +1,17 @@
|
||||
! When gh18335_workaround is defined as an extension,
|
||||
! the issue cannot be reproduced.
|
||||
!subroutine gh18335_workaround(f, y)
|
||||
! implicit none
|
||||
! external f
|
||||
! integer(kind=1) :: y(1)
|
||||
! call f(y)
|
||||
!end subroutine gh18335_workaround
|
||||
|
||||
function gh18335(f) result (r)
|
||||
implicit none
|
||||
external f
|
||||
integer(kind=1) :: y(1), r
|
||||
y(1) = 123
|
||||
call f(y)
|
||||
r = y(1)
|
||||
end function gh18335
|
@ -0,0 +1,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
|
@ -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
|
@ -0,0 +1,6 @@
|
||||
python module test_22819
|
||||
interface
|
||||
subroutine hello()
|
||||
end subroutine hello
|
||||
end interface
|
||||
end python module test_22819
|
@ -0,0 +1,3 @@
|
||||
SUBROUTINE HI
|
||||
PRINT*, "HELLO WORLD"
|
||||
END SUBROUTINE
|
@ -0,0 +1,3 @@
|
||||
function hi()
|
||||
print*, "Hello World"
|
||||
end function
|
@ -0,0 +1,11 @@
|
||||
SUBROUTINE INITCB
|
||||
DOUBLE PRECISION LONG
|
||||
CHARACTER STRING
|
||||
INTEGER OK
|
||||
|
||||
COMMON /BLOCK/ LONG, STRING, OK
|
||||
LONG = 1.0
|
||||
STRING = '2'
|
||||
OK = 3
|
||||
RETURN
|
||||
END
|
@ -0,0 +1,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
|
@ -0,0 +1,13 @@
|
||||
module foo
|
||||
public
|
||||
type, private, bind(c) :: a
|
||||
integer :: i
|
||||
end type a
|
||||
type, bind(c) :: b_
|
||||
integer :: j
|
||||
end type b_
|
||||
public :: b_
|
||||
type :: c
|
||||
integer :: k
|
||||
end type c
|
||||
end module foo
|
@ -0,0 +1,8 @@
|
||||
BLOCK DATA PARAM_INI
|
||||
COMMON /MYCOM/ MYDATA
|
||||
DATA MYDATA /0/
|
||||
END
|
||||
SUBROUTINE SUB1
|
||||
COMMON /MYCOM/ MYDATA
|
||||
MYDATA = MYDATA + 1
|
||||
END
|
@ -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
|
@ -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
|
@ -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
|
@ -0,0 +1,6 @@
|
||||
module foo
|
||||
type bar
|
||||
character(len = 4) :: text
|
||||
end type bar
|
||||
type(bar), parameter :: abar = bar('abar')
|
||||
end module foo
|
@ -0,0 +1,16 @@
|
||||
subroutine subb(k)
|
||||
real(8), intent(inout) :: k(:)
|
||||
k=k+1
|
||||
endsubroutine
|
||||
|
||||
subroutine subc(w,k)
|
||||
real(8), intent(in) :: w(:)
|
||||
real(8), intent(out) :: k(size(w))
|
||||
k=w+1
|
||||
endsubroutine
|
||||
|
||||
function t0(value)
|
||||
character value
|
||||
character t0
|
||||
t0 = value
|
||||
endfunction
|
@ -0,0 +1,12 @@
|
||||
integer(8) function external_as_statement(fcn)
|
||||
implicit none
|
||||
external fcn
|
||||
integer(8) :: fcn
|
||||
external_as_statement = fcn(0)
|
||||
end
|
||||
|
||||
integer(8) function external_as_attribute(fcn)
|
||||
implicit none
|
||||
integer(8), external :: fcn
|
||||
external_as_attribute = fcn(0)
|
||||
end
|
@ -0,0 +1,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
|
@ -0,0 +1,5 @@
|
||||
SUBROUTINE EXAMPLE( )
|
||||
IF( .TRUE. ) THEN
|
||||
CALL DO_SOMETHING()
|
||||
END IF ! ** .TRUE. **
|
||||
END
|
@ -0,0 +1,4 @@
|
||||
integer function intproduct(a, b) result(res)
|
||||
integer, intent(in) :: a, b
|
||||
res = a*b
|
||||
end function
|
@ -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
|
@ -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
|
@ -0,0 +1,13 @@
|
||||
subroutine gh2848( &
|
||||
! first 2 parameters
|
||||
par1, par2,&
|
||||
! last 2 parameters
|
||||
par3, par4)
|
||||
|
||||
integer, intent(in) :: par1, par2
|
||||
integer, intent(out) :: par3, par4
|
||||
|
||||
par3 = par1
|
||||
par4 = par2
|
||||
|
||||
end subroutine gh2848
|
@ -0,0 +1,49 @@
|
||||
module foo
|
||||
type bar
|
||||
character(len = 32) :: item
|
||||
end type bar
|
||||
interface operator(.item.)
|
||||
module procedure item_int, item_real
|
||||
end interface operator(.item.)
|
||||
interface operator(==)
|
||||
module procedure items_are_equal
|
||||
end interface operator(==)
|
||||
interface assignment(=)
|
||||
module procedure get_int, get_real
|
||||
end interface assignment(=)
|
||||
contains
|
||||
function item_int(val) result(elem)
|
||||
integer, intent(in) :: val
|
||||
type(bar) :: elem
|
||||
|
||||
write(elem%item, "(I32)") val
|
||||
end function item_int
|
||||
|
||||
function item_real(val) result(elem)
|
||||
real, intent(in) :: val
|
||||
type(bar) :: elem
|
||||
|
||||
write(elem%item, "(1PE32.12)") val
|
||||
end function item_real
|
||||
|
||||
function items_are_equal(val1, val2) result(equal)
|
||||
type(bar), intent(in) :: val1, val2
|
||||
logical :: equal
|
||||
|
||||
equal = (val1%item == val2%item)
|
||||
end function items_are_equal
|
||||
|
||||
subroutine get_real(rval, item)
|
||||
real, intent(out) :: rval
|
||||
type(bar), intent(in) :: item
|
||||
|
||||
read(item%item, *) rval
|
||||
end subroutine get_real
|
||||
|
||||
subroutine get_int(rval, item)
|
||||
integer, intent(out) :: rval
|
||||
type(bar), intent(in) :: item
|
||||
|
||||
read(item%item, *) rval
|
||||
end subroutine get_int
|
||||
end module foo
|
@ -0,0 +1,11 @@
|
||||
module foo
|
||||
private
|
||||
integer :: a
|
||||
public :: setA
|
||||
integer :: b
|
||||
contains
|
||||
subroutine setA(v)
|
||||
integer, intent(in) :: v
|
||||
a = v
|
||||
end subroutine setA
|
||||
end module foo
|
@ -0,0 +1,10 @@
|
||||
module foo
|
||||
public
|
||||
integer, private :: a
|
||||
public :: setA
|
||||
contains
|
||||
subroutine setA(v)
|
||||
integer, intent(in) :: v
|
||||
a = v
|
||||
end subroutine setA
|
||||
end module foo
|
@ -0,0 +1,10 @@
|
||||
module foo
|
||||
public
|
||||
integer, private :: a
|
||||
integer :: b
|
||||
contains
|
||||
subroutine setA(v)
|
||||
integer, intent(in) :: v
|
||||
a = v
|
||||
end subroutine setA
|
||||
end module foo
|
@ -0,0 +1,4 @@
|
||||
subroutine foo(x)
|
||||
real(8), intent(in) :: x
|
||||
! Écrit à l'écran la valeur de x
|
||||
end subroutine
|
@ -0,0 +1 @@
|
||||
dict(real=dict(real32='float', real64='double'), integer=dict(int64='long_long'))
|
@ -0,0 +1,9 @@
|
||||
subroutine func1(n, x, res)
|
||||
use, intrinsic :: iso_fortran_env, only: int64, real64
|
||||
implicit none
|
||||
integer(int64), intent(in) :: n
|
||||
real(real64), intent(in) :: x(n)
|
||||
real(real64), intent(out) :: res
|
||||
!f2py intent(hide) :: n
|
||||
res = sum(x)
|
||||
end
|
@ -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
|
@ -0,0 +1,20 @@
|
||||
|
||||
|
||||
subroutine selectedrealkind(p, r, res)
|
||||
implicit none
|
||||
|
||||
integer, intent(in) :: p, r
|
||||
!f2py integer :: r=0
|
||||
integer, intent(out) :: res
|
||||
res = selected_real_kind(p, r)
|
||||
|
||||
end subroutine
|
||||
|
||||
subroutine selectedintkind(p, res)
|
||||
implicit none
|
||||
|
||||
integer, intent(in) :: p
|
||||
integer, intent(out) :: res
|
||||
res = selected_int_kind(p)
|
||||
|
||||
end subroutine
|
@ -0,0 +1,5 @@
|
||||
subroutine bar11(a)
|
||||
cf2py intent(out) a
|
||||
integer a
|
||||
a = 11
|
||||
end
|
@ -0,0 +1,8 @@
|
||||
module foo_fixed
|
||||
contains
|
||||
subroutine bar12(a)
|
||||
!f2py intent(out) a
|
||||
integer a
|
||||
a = 12
|
||||
end subroutine bar12
|
||||
end module foo_fixed
|
@ -0,0 +1,8 @@
|
||||
module foo_free
|
||||
contains
|
||||
subroutine bar13(a)
|
||||
!f2py intent(out) a
|
||||
integer a
|
||||
a = 13
|
||||
end subroutine bar13
|
||||
end module foo_free
|
@ -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
|
@ -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
|
@ -0,0 +1,21 @@
|
||||
module mod2
|
||||
implicit none
|
||||
private mod2_func1
|
||||
contains
|
||||
|
||||
subroutine mod2_func1()
|
||||
print*, "mod2_func1"
|
||||
end subroutine mod2_func1
|
||||
|
||||
end module mod2
|
||||
|
||||
module mod1
|
||||
implicit none
|
||||
private :: mod1_func1
|
||||
contains
|
||||
|
||||
subroutine mod1_func1()
|
||||
print*, "mod1_func1"
|
||||
end subroutine mod1_func1
|
||||
|
||||
end module mod1
|
@ -0,0 +1,21 @@
|
||||
module mod2
|
||||
implicit none
|
||||
PUBLIC :: mod2_func1
|
||||
contains
|
||||
|
||||
subroutine mod2_func1()
|
||||
print*, "mod2_func1"
|
||||
end subroutine mod2_func1
|
||||
|
||||
end module mod2
|
||||
|
||||
module mod1
|
||||
implicit none
|
||||
PUBLIC :: mod1_func1
|
||||
contains
|
||||
|
||||
subroutine mod1_func1()
|
||||
print*, "mod1_func1"
|
||||
end subroutine mod1_func1
|
||||
|
||||
end module mod1
|
@ -0,0 +1,12 @@
|
||||
module mod
|
||||
integer :: i
|
||||
integer :: x(4)
|
||||
real, dimension(2,3) :: a
|
||||
real, allocatable, dimension(:,:) :: b
|
||||
contains
|
||||
subroutine foo
|
||||
integer :: k
|
||||
k = 1
|
||||
a(1,2) = a(1,2)+3
|
||||
end subroutine foo
|
||||
end module mod
|
@ -0,0 +1,20 @@
|
||||
module mathops
|
||||
implicit none
|
||||
contains
|
||||
function add(a, b) result(c)
|
||||
integer, intent(in) :: a, b
|
||||
integer :: c
|
||||
c = a + b
|
||||
end function add
|
||||
end module mathops
|
||||
|
||||
module useops
|
||||
use mathops, only: add
|
||||
implicit none
|
||||
contains
|
||||
function sum_and_double(a, b) result(d)
|
||||
integer, intent(in) :: a, b
|
||||
integer :: d
|
||||
d = 2 * add(a, b)
|
||||
end function sum_and_double
|
||||
end module useops
|
@ -0,0 +1,7 @@
|
||||
subroutine foo(is_, ie_, arr, tout)
|
||||
implicit none
|
||||
integer :: is_,ie_
|
||||
real, intent(in) :: arr(is_:ie_)
|
||||
real, intent(out) :: tout(is_:ie_)
|
||||
tout = arr
|
||||
end
|
@ -0,0 +1,45 @@
|
||||
! Check that parameter arrays are correctly intercepted.
|
||||
subroutine foo_array(x, y, z)
|
||||
implicit none
|
||||
integer, parameter :: dp = selected_real_kind(15)
|
||||
integer, parameter :: pa = 2
|
||||
integer, parameter :: intparamarray(2) = (/ 3, 5 /)
|
||||
integer, dimension(pa), parameter :: pb = (/ 2, 10 /)
|
||||
integer, parameter, dimension(intparamarray(1)) :: pc = (/ 2, 10, 20 /)
|
||||
real(dp), parameter :: doubleparamarray(3) = (/ 3.14_dp, 4._dp, 6.44_dp /)
|
||||
real(dp), intent(inout) :: x(intparamarray(1))
|
||||
real(dp), intent(inout) :: y(intparamarray(2))
|
||||
real(dp), intent(out) :: z
|
||||
|
||||
x = x/pb(2)
|
||||
y = y*pc(2)
|
||||
z = doubleparamarray(1)*doubleparamarray(2) + doubleparamarray(3)
|
||||
|
||||
return
|
||||
end subroutine
|
||||
|
||||
subroutine foo_array_any_index(x, y)
|
||||
implicit none
|
||||
integer, parameter :: dp = selected_real_kind(15)
|
||||
integer, parameter, dimension(-1:1) :: myparamarray = (/ 6, 3, 1 /)
|
||||
integer, parameter, dimension(2) :: nested = (/ 2, 0 /)
|
||||
integer, parameter :: dim = 2
|
||||
real(dp), intent(in) :: x(myparamarray(-1))
|
||||
real(dp), intent(out) :: y(nested(1), myparamarray(nested(dim)))
|
||||
|
||||
y = reshape(x, (/nested(1), myparamarray(nested(2))/))
|
||||
|
||||
return
|
||||
end subroutine
|
||||
|
||||
subroutine foo_array_delims(x)
|
||||
implicit none
|
||||
integer, parameter :: dp = selected_real_kind(15)
|
||||
integer, parameter, dimension(2) :: myparamarray = (/ (6), 1 /)
|
||||
integer, parameter, dimension(3) :: test = (/2, 1, (3)/)
|
||||
real(dp), intent(out) :: x
|
||||
|
||||
x = myparamarray(1)+test(3)
|
||||
|
||||
return
|
||||
end subroutine
|
@ -0,0 +1,57 @@
|
||||
! Check that parameters are correct intercepted.
|
||||
! Constants with comma separations are commonly
|
||||
! used, for instance Pi = 3._dp
|
||||
subroutine foo(x)
|
||||
implicit none
|
||||
integer, parameter :: sp = selected_real_kind(6)
|
||||
integer, parameter :: dp = selected_real_kind(15)
|
||||
integer, parameter :: ii = selected_int_kind(9)
|
||||
integer, parameter :: il = selected_int_kind(18)
|
||||
real(dp), intent(inout) :: x
|
||||
dimension x(3)
|
||||
real(sp), parameter :: three_s = 3._sp
|
||||
real(dp), parameter :: three_d = 3._dp
|
||||
integer(ii), parameter :: three_i = 3_ii
|
||||
integer(il), parameter :: three_l = 3_il
|
||||
x(1) = x(1) + x(2) * three_s * three_i + x(3) * three_d * three_l
|
||||
x(2) = x(2) * three_s
|
||||
x(3) = x(3) * three_l
|
||||
return
|
||||
end subroutine
|
||||
|
||||
|
||||
subroutine foo_no(x)
|
||||
implicit none
|
||||
integer, parameter :: sp = selected_real_kind(6)
|
||||
integer, parameter :: dp = selected_real_kind(15)
|
||||
integer, parameter :: ii = selected_int_kind(9)
|
||||
integer, parameter :: il = selected_int_kind(18)
|
||||
real(dp), intent(inout) :: x
|
||||
dimension x(3)
|
||||
real(sp), parameter :: three_s = 3.
|
||||
real(dp), parameter :: three_d = 3.
|
||||
integer(ii), parameter :: three_i = 3
|
||||
integer(il), parameter :: three_l = 3
|
||||
x(1) = x(1) + x(2) * three_s * three_i + x(3) * three_d * three_l
|
||||
x(2) = x(2) * three_s
|
||||
x(3) = x(3) * three_l
|
||||
return
|
||||
end subroutine
|
||||
|
||||
subroutine foo_sum(x)
|
||||
implicit none
|
||||
integer, parameter :: sp = selected_real_kind(6)
|
||||
integer, parameter :: dp = selected_real_kind(15)
|
||||
integer, parameter :: ii = selected_int_kind(9)
|
||||
integer, parameter :: il = selected_int_kind(18)
|
||||
real(dp), intent(inout) :: x
|
||||
dimension x(3)
|
||||
real(sp), parameter :: three_s = 2._sp + 1._sp
|
||||
real(dp), parameter :: three_d = 1._dp + 2._dp
|
||||
integer(ii), parameter :: three_i = 2_ii + 1_ii
|
||||
integer(il), parameter :: three_l = 1_il + 2_il
|
||||
x(1) = x(1) + x(2) * three_s * three_i + x(3) * three_d * three_l
|
||||
x(2) = x(2) * three_s
|
||||
x(3) = x(3) * three_l
|
||||
return
|
||||
end subroutine
|
@ -0,0 +1,15 @@
|
||||
! Check that parameters are correct intercepted.
|
||||
! Constants with comma separations are commonly
|
||||
! used, for instance Pi = 3._dp
|
||||
subroutine foo_compound_int(x)
|
||||
implicit none
|
||||
integer, parameter :: ii = selected_int_kind(9)
|
||||
integer(ii), intent(inout) :: x
|
||||
dimension x(3)
|
||||
integer(ii), parameter :: three = 3_ii
|
||||
integer(ii), parameter :: two = 2_ii
|
||||
integer(ii), parameter :: six = three * 1_ii * two
|
||||
|
||||
x(1) = x(1) + x(2) + x(3) * six
|
||||
return
|
||||
end subroutine
|
@ -0,0 +1,22 @@
|
||||
! Check that parameters are correct intercepted.
|
||||
! Constants with comma separations are commonly
|
||||
! used, for instance Pi = 3._dp
|
||||
subroutine foo_int(x)
|
||||
implicit none
|
||||
integer, parameter :: ii = selected_int_kind(9)
|
||||
integer(ii), intent(inout) :: x
|
||||
dimension x(3)
|
||||
integer(ii), parameter :: three = 3_ii
|
||||
x(1) = x(1) + x(2) + x(3) * three
|
||||
return
|
||||
end subroutine
|
||||
|
||||
subroutine foo_long(x)
|
||||
implicit none
|
||||
integer, parameter :: ii = selected_int_kind(18)
|
||||
integer(ii), intent(inout) :: x
|
||||
dimension x(3)
|
||||
integer(ii), parameter :: three = 3_ii
|
||||
x(1) = x(1) + x(2) + x(3) * three
|
||||
return
|
||||
end subroutine
|
@ -0,0 +1,23 @@
|
||||
! Check that parameters are correct intercepted.
|
||||
! Specifically that types of constants without
|
||||
! compound kind specs are correctly inferred
|
||||
! adapted Gibbs iteration code from pymc
|
||||
! for this test case
|
||||
subroutine foo_non_compound_int(x)
|
||||
implicit none
|
||||
integer, parameter :: ii = selected_int_kind(9)
|
||||
|
||||
integer(ii) maxiterates
|
||||
parameter (maxiterates=2)
|
||||
|
||||
integer(ii) maxseries
|
||||
parameter (maxseries=2)
|
||||
|
||||
integer(ii) wasize
|
||||
parameter (wasize=maxiterates*maxseries)
|
||||
integer(ii), intent(inout) :: x
|
||||
dimension x(wasize)
|
||||
|
||||
x(1) = x(1) + x(2) + x(3) + x(4) * wasize
|
||||
return
|
||||
end subroutine
|
@ -0,0 +1,23 @@
|
||||
! Check that parameters are correct intercepted.
|
||||
! Constants with comma separations are commonly
|
||||
! used, for instance Pi = 3._dp
|
||||
subroutine foo_single(x)
|
||||
implicit none
|
||||
integer, parameter :: rp = selected_real_kind(6)
|
||||
real(rp), intent(inout) :: x
|
||||
dimension x(3)
|
||||
real(rp), parameter :: three = 3._rp
|
||||
x(1) = x(1) + x(2) + x(3) * three
|
||||
return
|
||||
end subroutine
|
||||
|
||||
subroutine foo_double(x)
|
||||
implicit none
|
||||
integer, parameter :: rp = selected_real_kind(15)
|
||||
real(rp), intent(inout) :: x
|
||||
dimension x(3)
|
||||
real(rp), parameter :: three = 3._rp
|
||||
x(1) = x(1) + x(2) + x(3) * three
|
||||
return
|
||||
end subroutine
|
||||
|
@ -0,0 +1,14 @@
|
||||
SUBROUTINE FOO(OUT1, OUT2, OUT3, OUT4, OUT5, OUT6)
|
||||
CHARACTER SINGLE, DOUBLE, SEMICOL, EXCLA, OPENPAR, CLOSEPAR
|
||||
PARAMETER (SINGLE="'", DOUBLE='"', SEMICOL=';', EXCLA="!",
|
||||
1 OPENPAR="(", CLOSEPAR=")")
|
||||
CHARACTER OUT1, OUT2, OUT3, OUT4, OUT5, OUT6
|
||||
Cf2py intent(out) OUT1, OUT2, OUT3, OUT4, OUT5, OUT6
|
||||
OUT1 = SINGLE
|
||||
OUT2 = DOUBLE
|
||||
OUT3 = SEMICOL
|
||||
OUT4 = EXCLA
|
||||
OUT5 = OPENPAR
|
||||
OUT6 = CLOSEPAR
|
||||
RETURN
|
||||
END
|
@ -0,0 +1 @@
|
||||
real(8) b, n, m
|
@ -0,0 +1,26 @@
|
||||
SUBROUTINE TESTSUB(
|
||||
& INPUT1, INPUT2, !Input
|
||||
& OUTPUT1, OUTPUT2) !Output
|
||||
|
||||
IMPLICIT NONE
|
||||
INTEGER, INTENT(IN) :: INPUT1, INPUT2
|
||||
INTEGER, INTENT(OUT) :: OUTPUT1, OUTPUT2
|
||||
|
||||
OUTPUT1 = INPUT1 + INPUT2
|
||||
OUTPUT2 = INPUT1 * INPUT2
|
||||
|
||||
RETURN
|
||||
END SUBROUTINE TESTSUB
|
||||
|
||||
SUBROUTINE TESTSUB2(OUTPUT)
|
||||
IMPLICIT NONE
|
||||
INTEGER, PARAMETER :: N = 10 ! Array dimension
|
||||
REAL, INTENT(OUT) :: OUTPUT(N)
|
||||
INTEGER :: I
|
||||
|
||||
DO I = 1, N
|
||||
OUTPUT(I) = I * 2.0
|
||||
END DO
|
||||
|
||||
RETURN
|
||||
END
|
@ -0,0 +1,5 @@
|
||||
C This is an invalid file, but it does compile with -ffixed-form
|
||||
subroutine mwe(
|
||||
& x)
|
||||
real x
|
||||
end subroutine mwe
|
@ -0,0 +1,9 @@
|
||||
SUBROUTINE TESTSUB(INPUT1, & ! Hello
|
||||
! commenty
|
||||
INPUT2, OUTPUT1, OUTPUT2) ! more comments
|
||||
INTEGER, INTENT(IN) :: INPUT1, INPUT2
|
||||
INTEGER, INTENT(OUT) :: OUTPUT1, OUTPUT2
|
||||
OUTPUT1 = INPUT1 + &
|
||||
INPUT2
|
||||
OUTPUT2 = INPUT1 * INPUT2
|
||||
END SUBROUTINE TESTSUB
|
@ -0,0 +1,5 @@
|
||||
function add(n,m) result(b)
|
||||
implicit none
|
||||
include 'AB.inc'
|
||||
b = n + m
|
||||
end function add
|
@ -0,0 +1,9 @@
|
||||
! Check that intent(in out) translates as intent(inout).
|
||||
! The separation seems to be a common usage.
|
||||
subroutine foo(x)
|
||||
implicit none
|
||||
real(4), intent(in out) :: x
|
||||
dimension x(3)
|
||||
x(1) = x(1) + x(2) + x(3)
|
||||
return
|
||||
end
|
@ -0,0 +1,45 @@
|
||||
function t0(value)
|
||||
character value
|
||||
character t0
|
||||
t0 = value
|
||||
end
|
||||
function t1(value)
|
||||
character*1 value
|
||||
character*1 t1
|
||||
t1 = value
|
||||
end
|
||||
function t5(value)
|
||||
character*5 value
|
||||
character*5 t5
|
||||
t5 = value
|
||||
end
|
||||
function ts(value)
|
||||
character*(*) value
|
||||
character*(*) ts
|
||||
ts = value
|
||||
end
|
||||
|
||||
subroutine s0(t0,value)
|
||||
character value
|
||||
character t0
|
||||
cf2py intent(out) t0
|
||||
t0 = value
|
||||
end
|
||||
subroutine s1(t1,value)
|
||||
character*1 value
|
||||
character*1 t1
|
||||
cf2py intent(out) t1
|
||||
t1 = value
|
||||
end
|
||||
subroutine s5(t5,value)
|
||||
character*5 value
|
||||
character*5 t5
|
||||
cf2py intent(out) t5
|
||||
t5 = value
|
||||
end
|
||||
subroutine ss(ts,value)
|
||||
character*(*) value
|
||||
character*10 ts
|
||||
cf2py intent(out) ts
|
||||
ts = value
|
||||
end
|
@ -0,0 +1,48 @@
|
||||
module f90_return_char
|
||||
contains
|
||||
function t0(value)
|
||||
character :: value
|
||||
character :: t0
|
||||
t0 = value
|
||||
end function t0
|
||||
function t1(value)
|
||||
character(len=1) :: value
|
||||
character(len=1) :: t1
|
||||
t1 = value
|
||||
end function t1
|
||||
function t5(value)
|
||||
character(len=5) :: value
|
||||
character(len=5) :: t5
|
||||
t5 = value
|
||||
end function t5
|
||||
function ts(value)
|
||||
character(len=*) :: value
|
||||
character(len=10) :: ts
|
||||
ts = value
|
||||
end function ts
|
||||
|
||||
subroutine s0(t0,value)
|
||||
character :: value
|
||||
character :: t0
|
||||
!f2py intent(out) t0
|
||||
t0 = value
|
||||
end subroutine s0
|
||||
subroutine s1(t1,value)
|
||||
character(len=1) :: value
|
||||
character(len=1) :: t1
|
||||
!f2py intent(out) t1
|
||||
t1 = value
|
||||
end subroutine s1
|
||||
subroutine s5(t5,value)
|
||||
character(len=5) :: value
|
||||
character(len=5) :: t5
|
||||
!f2py intent(out) t5
|
||||
t5 = value
|
||||
end subroutine s5
|
||||
subroutine ss(ts,value)
|
||||
character(len=*) :: value
|
||||
character(len=10) :: ts
|
||||
!f2py intent(out) ts
|
||||
ts = value
|
||||
end subroutine ss
|
||||
end module f90_return_char
|
@ -0,0 +1,45 @@
|
||||
function t0(value)
|
||||
complex value
|
||||
complex t0
|
||||
t0 = value
|
||||
end
|
||||
function t8(value)
|
||||
complex*8 value
|
||||
complex*8 t8
|
||||
t8 = value
|
||||
end
|
||||
function t16(value)
|
||||
complex*16 value
|
||||
complex*16 t16
|
||||
t16 = value
|
||||
end
|
||||
function td(value)
|
||||
double complex value
|
||||
double complex td
|
||||
td = value
|
||||
end
|
||||
|
||||
subroutine s0(t0,value)
|
||||
complex value
|
||||
complex t0
|
||||
cf2py intent(out) t0
|
||||
t0 = value
|
||||
end
|
||||
subroutine s8(t8,value)
|
||||
complex*8 value
|
||||
complex*8 t8
|
||||
cf2py intent(out) t8
|
||||
t8 = value
|
||||
end
|
||||
subroutine s16(t16,value)
|
||||
complex*16 value
|
||||
complex*16 t16
|
||||
cf2py intent(out) t16
|
||||
t16 = value
|
||||
end
|
||||
subroutine sd(td,value)
|
||||
double complex value
|
||||
double complex td
|
||||
cf2py intent(out) td
|
||||
td = value
|
||||
end
|
@ -0,0 +1,48 @@
|
||||
module f90_return_complex
|
||||
contains
|
||||
function t0(value)
|
||||
complex :: value
|
||||
complex :: t0
|
||||
t0 = value
|
||||
end function t0
|
||||
function t8(value)
|
||||
complex(kind=4) :: value
|
||||
complex(kind=4) :: t8
|
||||
t8 = value
|
||||
end function t8
|
||||
function t16(value)
|
||||
complex(kind=8) :: value
|
||||
complex(kind=8) :: t16
|
||||
t16 = value
|
||||
end function t16
|
||||
function td(value)
|
||||
double complex :: value
|
||||
double complex :: td
|
||||
td = value
|
||||
end function td
|
||||
|
||||
subroutine s0(t0,value)
|
||||
complex :: value
|
||||
complex :: t0
|
||||
!f2py intent(out) t0
|
||||
t0 = value
|
||||
end subroutine s0
|
||||
subroutine s8(t8,value)
|
||||
complex(kind=4) :: value
|
||||
complex(kind=4) :: t8
|
||||
!f2py intent(out) t8
|
||||
t8 = value
|
||||
end subroutine s8
|
||||
subroutine s16(t16,value)
|
||||
complex(kind=8) :: value
|
||||
complex(kind=8) :: t16
|
||||
!f2py intent(out) t16
|
||||
t16 = value
|
||||
end subroutine s16
|
||||
subroutine sd(td,value)
|
||||
double complex :: value
|
||||
double complex :: td
|
||||
!f2py intent(out) td
|
||||
td = value
|
||||
end subroutine sd
|
||||
end module f90_return_complex
|
@ -0,0 +1,56 @@
|
||||
function t0(value)
|
||||
integer value
|
||||
integer t0
|
||||
t0 = value
|
||||
end
|
||||
function t1(value)
|
||||
integer*1 value
|
||||
integer*1 t1
|
||||
t1 = value
|
||||
end
|
||||
function t2(value)
|
||||
integer*2 value
|
||||
integer*2 t2
|
||||
t2 = value
|
||||
end
|
||||
function t4(value)
|
||||
integer*4 value
|
||||
integer*4 t4
|
||||
t4 = value
|
||||
end
|
||||
function t8(value)
|
||||
integer*8 value
|
||||
integer*8 t8
|
||||
t8 = value
|
||||
end
|
||||
|
||||
subroutine s0(t0,value)
|
||||
integer value
|
||||
integer t0
|
||||
cf2py intent(out) t0
|
||||
t0 = value
|
||||
end
|
||||
subroutine s1(t1,value)
|
||||
integer*1 value
|
||||
integer*1 t1
|
||||
cf2py intent(out) t1
|
||||
t1 = value
|
||||
end
|
||||
subroutine s2(t2,value)
|
||||
integer*2 value
|
||||
integer*2 t2
|
||||
cf2py intent(out) t2
|
||||
t2 = value
|
||||
end
|
||||
subroutine s4(t4,value)
|
||||
integer*4 value
|
||||
integer*4 t4
|
||||
cf2py intent(out) t4
|
||||
t4 = value
|
||||
end
|
||||
subroutine s8(t8,value)
|
||||
integer*8 value
|
||||
integer*8 t8
|
||||
cf2py intent(out) t8
|
||||
t8 = value
|
||||
end
|
@ -0,0 +1,59 @@
|
||||
module f90_return_integer
|
||||
contains
|
||||
function t0(value)
|
||||
integer :: value
|
||||
integer :: t0
|
||||
t0 = value
|
||||
end function t0
|
||||
function t1(value)
|
||||
integer(kind=1) :: value
|
||||
integer(kind=1) :: t1
|
||||
t1 = value
|
||||
end function t1
|
||||
function t2(value)
|
||||
integer(kind=2) :: value
|
||||
integer(kind=2) :: t2
|
||||
t2 = value
|
||||
end function t2
|
||||
function t4(value)
|
||||
integer(kind=4) :: value
|
||||
integer(kind=4) :: t4
|
||||
t4 = value
|
||||
end function t4
|
||||
function t8(value)
|
||||
integer(kind=8) :: value
|
||||
integer(kind=8) :: t8
|
||||
t8 = value
|
||||
end function t8
|
||||
|
||||
subroutine s0(t0,value)
|
||||
integer :: value
|
||||
integer :: t0
|
||||
!f2py intent(out) t0
|
||||
t0 = value
|
||||
end subroutine s0
|
||||
subroutine s1(t1,value)
|
||||
integer(kind=1) :: value
|
||||
integer(kind=1) :: t1
|
||||
!f2py intent(out) t1
|
||||
t1 = value
|
||||
end subroutine s1
|
||||
subroutine s2(t2,value)
|
||||
integer(kind=2) :: value
|
||||
integer(kind=2) :: t2
|
||||
!f2py intent(out) t2
|
||||
t2 = value
|
||||
end subroutine s2
|
||||
subroutine s4(t4,value)
|
||||
integer(kind=4) :: value
|
||||
integer(kind=4) :: t4
|
||||
!f2py intent(out) t4
|
||||
t4 = value
|
||||
end subroutine s4
|
||||
subroutine s8(t8,value)
|
||||
integer(kind=8) :: value
|
||||
integer(kind=8) :: t8
|
||||
!f2py intent(out) t8
|
||||
t8 = value
|
||||
end subroutine s8
|
||||
end module f90_return_integer
|
@ -0,0 +1,56 @@
|
||||
function t0(value)
|
||||
logical value
|
||||
logical t0
|
||||
t0 = value
|
||||
end
|
||||
function t1(value)
|
||||
logical*1 value
|
||||
logical*1 t1
|
||||
t1 = value
|
||||
end
|
||||
function t2(value)
|
||||
logical*2 value
|
||||
logical*2 t2
|
||||
t2 = value
|
||||
end
|
||||
function t4(value)
|
||||
logical*4 value
|
||||
logical*4 t4
|
||||
t4 = value
|
||||
end
|
||||
c function t8(value)
|
||||
c logical*8 value
|
||||
c logical*8 t8
|
||||
c t8 = value
|
||||
c end
|
||||
|
||||
subroutine s0(t0,value)
|
||||
logical value
|
||||
logical t0
|
||||
cf2py intent(out) t0
|
||||
t0 = value
|
||||
end
|
||||
subroutine s1(t1,value)
|
||||
logical*1 value
|
||||
logical*1 t1
|
||||
cf2py intent(out) t1
|
||||
t1 = value
|
||||
end
|
||||
subroutine s2(t2,value)
|
||||
logical*2 value
|
||||
logical*2 t2
|
||||
cf2py intent(out) t2
|
||||
t2 = value
|
||||
end
|
||||
subroutine s4(t4,value)
|
||||
logical*4 value
|
||||
logical*4 t4
|
||||
cf2py intent(out) t4
|
||||
t4 = value
|
||||
end
|
||||
c subroutine s8(t8,value)
|
||||
c logical*8 value
|
||||
c logical*8 t8
|
||||
cf2py intent(out) t8
|
||||
c t8 = value
|
||||
c end
|
@ -0,0 +1,59 @@
|
||||
module f90_return_logical
|
||||
contains
|
||||
function t0(value)
|
||||
logical :: value
|
||||
logical :: t0
|
||||
t0 = value
|
||||
end function t0
|
||||
function t1(value)
|
||||
logical(kind=1) :: value
|
||||
logical(kind=1) :: t1
|
||||
t1 = value
|
||||
end function t1
|
||||
function t2(value)
|
||||
logical(kind=2) :: value
|
||||
logical(kind=2) :: t2
|
||||
t2 = value
|
||||
end function t2
|
||||
function t4(value)
|
||||
logical(kind=4) :: value
|
||||
logical(kind=4) :: t4
|
||||
t4 = value
|
||||
end function t4
|
||||
function t8(value)
|
||||
logical(kind=8) :: value
|
||||
logical(kind=8) :: t8
|
||||
t8 = value
|
||||
end function t8
|
||||
|
||||
subroutine s0(t0,value)
|
||||
logical :: value
|
||||
logical :: t0
|
||||
!f2py intent(out) t0
|
||||
t0 = value
|
||||
end subroutine s0
|
||||
subroutine s1(t1,value)
|
||||
logical(kind=1) :: value
|
||||
logical(kind=1) :: t1
|
||||
!f2py intent(out) t1
|
||||
t1 = value
|
||||
end subroutine s1
|
||||
subroutine s2(t2,value)
|
||||
logical(kind=2) :: value
|
||||
logical(kind=2) :: t2
|
||||
!f2py intent(out) t2
|
||||
t2 = value
|
||||
end subroutine s2
|
||||
subroutine s4(t4,value)
|
||||
logical(kind=4) :: value
|
||||
logical(kind=4) :: t4
|
||||
!f2py intent(out) t4
|
||||
t4 = value
|
||||
end subroutine s4
|
||||
subroutine s8(t8,value)
|
||||
logical(kind=8) :: value
|
||||
logical(kind=8) :: t8
|
||||
!f2py intent(out) t8
|
||||
t8 = value
|
||||
end subroutine s8
|
||||
end module f90_return_logical
|
@ -0,0 +1,45 @@
|
||||
function t0(value)
|
||||
real value
|
||||
real t0
|
||||
t0 = value
|
||||
end
|
||||
function t4(value)
|
||||
real*4 value
|
||||
real*4 t4
|
||||
t4 = value
|
||||
end
|
||||
function t8(value)
|
||||
real*8 value
|
||||
real*8 t8
|
||||
t8 = value
|
||||
end
|
||||
function td(value)
|
||||
double precision value
|
||||
double precision td
|
||||
td = value
|
||||
end
|
||||
|
||||
subroutine s0(t0,value)
|
||||
real value
|
||||
real t0
|
||||
cf2py intent(out) t0
|
||||
t0 = value
|
||||
end
|
||||
subroutine s4(t4,value)
|
||||
real*4 value
|
||||
real*4 t4
|
||||
cf2py intent(out) t4
|
||||
t4 = value
|
||||
end
|
||||
subroutine s8(t8,value)
|
||||
real*8 value
|
||||
real*8 t8
|
||||
cf2py intent(out) t8
|
||||
t8 = value
|
||||
end
|
||||
subroutine sd(td,value)
|
||||
double precision value
|
||||
double precision td
|
||||
cf2py intent(out) td
|
||||
td = value
|
||||
end
|
@ -0,0 +1,48 @@
|
||||
module f90_return_real
|
||||
contains
|
||||
function t0(value)
|
||||
real :: value
|
||||
real :: t0
|
||||
t0 = value
|
||||
end function t0
|
||||
function t4(value)
|
||||
real(kind=4) :: value
|
||||
real(kind=4) :: t4
|
||||
t4 = value
|
||||
end function t4
|
||||
function t8(value)
|
||||
real(kind=8) :: value
|
||||
real(kind=8) :: t8
|
||||
t8 = value
|
||||
end function t8
|
||||
function td(value)
|
||||
double precision :: value
|
||||
double precision :: td
|
||||
td = value
|
||||
end function td
|
||||
|
||||
subroutine s0(t0,value)
|
||||
real :: value
|
||||
real :: t0
|
||||
!f2py intent(out) t0
|
||||
t0 = value
|
||||
end subroutine s0
|
||||
subroutine s4(t4,value)
|
||||
real(kind=4) :: value
|
||||
real(kind=4) :: t4
|
||||
!f2py intent(out) t4
|
||||
t4 = value
|
||||
end subroutine s4
|
||||
subroutine s8(t8,value)
|
||||
real(kind=8) :: value
|
||||
real(kind=8) :: t8
|
||||
!f2py intent(out) t8
|
||||
t8 = value
|
||||
end subroutine s8
|
||||
subroutine sd(td,value)
|
||||
double precision :: value
|
||||
double precision :: td
|
||||
!f2py intent(out) td
|
||||
td = value
|
||||
end subroutine sd
|
||||
end module f90_return_real
|
@ -0,0 +1,44 @@
|
||||
|
||||
subroutine foo(a, n, m, b)
|
||||
implicit none
|
||||
|
||||
real, intent(in) :: a(n, m)
|
||||
integer, intent(in) :: n, m
|
||||
real, intent(out) :: b(size(a, 1))
|
||||
|
||||
integer :: i
|
||||
|
||||
do i = 1, size(b)
|
||||
b(i) = sum(a(i,:))
|
||||
enddo
|
||||
end subroutine
|
||||
|
||||
subroutine trans(x,y)
|
||||
implicit none
|
||||
real, intent(in), dimension(:,:) :: x
|
||||
real, intent(out), dimension( size(x,2), size(x,1) ) :: y
|
||||
integer :: N, M, i, j
|
||||
N = size(x,1)
|
||||
M = size(x,2)
|
||||
DO i=1,N
|
||||
do j=1,M
|
||||
y(j,i) = x(i,j)
|
||||
END DO
|
||||
END DO
|
||||
end subroutine trans
|
||||
|
||||
subroutine flatten(x,y)
|
||||
implicit none
|
||||
real, intent(in), dimension(:,:) :: x
|
||||
real, intent(out), dimension( size(x) ) :: y
|
||||
integer :: N, M, i, j, k
|
||||
N = size(x,1)
|
||||
M = size(x,2)
|
||||
k = 1
|
||||
DO i=1,N
|
||||
do j=1,M
|
||||
y(k) = x(i,j)
|
||||
k = k + 1
|
||||
END DO
|
||||
END DO
|
||||
end subroutine flatten
|
@ -0,0 +1,29 @@
|
||||
MODULE char_test
|
||||
|
||||
CONTAINS
|
||||
|
||||
SUBROUTINE change_strings(strings, n_strs, out_strings)
|
||||
IMPLICIT NONE
|
||||
|
||||
! Inputs
|
||||
INTEGER, INTENT(IN) :: n_strs
|
||||
CHARACTER, INTENT(IN), DIMENSION(2,n_strs) :: strings
|
||||
CHARACTER, INTENT(OUT), DIMENSION(2,n_strs) :: out_strings
|
||||
|
||||
!f2py INTEGER, INTENT(IN) :: n_strs
|
||||
!f2py CHARACTER, INTENT(IN), DIMENSION(2,n_strs) :: strings
|
||||
!f2py CHARACTER, INTENT(OUT), DIMENSION(2,n_strs) :: strings
|
||||
|
||||
! Misc.
|
||||
INTEGER*4 :: j
|
||||
|
||||
|
||||
DO j=1, n_strs
|
||||
out_strings(1,j) = strings(1,j)
|
||||
out_strings(2,j) = 'A'
|
||||
END DO
|
||||
|
||||
END SUBROUTINE change_strings
|
||||
|
||||
END MODULE char_test
|
||||
|
@ -0,0 +1,34 @@
|
||||
function sint(s) result(i)
|
||||
implicit none
|
||||
character(len=*) :: s
|
||||
integer :: j, i
|
||||
i = 0
|
||||
do j=len(s), 1, -1
|
||||
if (.not.((i.eq.0).and.(s(j:j).eq.' '))) then
|
||||
i = i + ichar(s(j:j)) * 10 ** (j - 1)
|
||||
endif
|
||||
end do
|
||||
return
|
||||
end function sint
|
||||
|
||||
function test_in_bytes4(a) result (i)
|
||||
implicit none
|
||||
integer :: sint
|
||||
character(len=4) :: a
|
||||
integer :: i
|
||||
i = sint(a)
|
||||
a(1:1) = 'A'
|
||||
return
|
||||
end function test_in_bytes4
|
||||
|
||||
function test_inout_bytes4(a) result (i)
|
||||
implicit none
|
||||
integer :: sint
|
||||
character(len=4), intent(inout) :: a
|
||||
integer :: i
|
||||
if (a(1:1).ne.' ') then
|
||||
a(1:1) = 'E'
|
||||
endif
|
||||
i = sint(a)
|
||||
return
|
||||
end function test_inout_bytes4
|
@ -0,0 +1,8 @@
|
||||
SUBROUTINE GREET(NAME, GREETING)
|
||||
CHARACTER NAME*(*), GREETING*(*)
|
||||
CHARACTER*(50) MESSAGE
|
||||
|
||||
MESSAGE = 'Hello, ' // NAME // ', ' // GREETING
|
||||
c$$$ PRINT *, MESSAGE
|
||||
|
||||
END SUBROUTINE GREET
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -0,0 +1,9 @@
|
||||
MODULE string_test
|
||||
|
||||
character(len=8) :: string
|
||||
character string77 * 8
|
||||
|
||||
character(len=12), dimension(5,7) :: strarr
|
||||
character strarr77(5,7) * 12
|
||||
|
||||
END MODULE string_test
|
@ -0,0 +1,12 @@
|
||||
C FILE: STRING.F
|
||||
SUBROUTINE FOO(A,B,C,D)
|
||||
CHARACTER*5 A, B
|
||||
CHARACTER*(*) C,D
|
||||
Cf2py intent(in) a,c
|
||||
Cf2py intent(inout) b,d
|
||||
A(1:1) = 'A'
|
||||
B(1:1) = 'B'
|
||||
C(1:1) = 'C'
|
||||
D(1:1) = 'D'
|
||||
END
|
||||
C END OF FILE STRING.F
|
@ -0,0 +1,9 @@
|
||||
module fortfuncs
|
||||
implicit none
|
||||
contains
|
||||
subroutine square(x,y)
|
||||
integer, intent(in), value :: x
|
||||
integer, intent(out) :: y
|
||||
y = x*x
|
||||
end subroutine square
|
||||
end module fortfuncs
|
@ -0,0 +1,26 @@
|
||||
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")
|
||||
@pytest.mark.slow
|
||||
class TestAbstractInterface(util.F2PyTest):
|
||||
sources = [util.getpath("tests", "src", "abstract_interface", "foo.f90")]
|
||||
|
||||
skip = ["add1", "add2"]
|
||||
|
||||
def test_abstract_interface(self):
|
||||
assert self.module.ops_module.foo(3, 5) == (8, 13)
|
||||
|
||||
def test_parse_abstract_interface(self):
|
||||
# Test gh18403
|
||||
fpath = util.getpath("tests", "src", "abstract_interface",
|
||||
"gh18403_mod.f90")
|
||||
mod = crackfortran.crackfortran([str(fpath)])
|
||||
assert len(mod) == 1
|
||||
assert len(mod[0]["body"]) == 1
|
||||
assert mod[0]["body"][0]["block"] == "abstract interface"
|
@ -0,0 +1,679 @@
|
||||
import os
|
||||
import sys
|
||||
import copy
|
||||
import platform
|
||||
import pytest
|
||||
from pathlib import Path
|
||||
|
||||
import numpy as np
|
||||
|
||||
from numpy.testing import assert_, assert_equal
|
||||
from numpy._core._type_aliases import c_names_dict as _c_names_dict
|
||||
from . import util
|
||||
|
||||
wrap = None
|
||||
|
||||
# Extend core typeinfo with CHARACTER to test dtype('c')
|
||||
c_names_dict = dict(
|
||||
CHARACTER=np.dtype("c"),
|
||||
**_c_names_dict
|
||||
)
|
||||
|
||||
|
||||
def get_testdir():
|
||||
testroot = Path(__file__).resolve().parent / "src"
|
||||
return testroot / "array_from_pyobj"
|
||||
|
||||
def setup_module():
|
||||
"""
|
||||
Build the required testing extension module
|
||||
|
||||
"""
|
||||
global wrap
|
||||
|
||||
if wrap is None:
|
||||
src = [
|
||||
get_testdir() / "wrapmodule.c",
|
||||
]
|
||||
wrap = util.build_meson(src, module_name = "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):
|
||||
return all(name in self.intent_list for name in names)
|
||||
|
||||
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 c_names_dict.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 = c_names_dict[self.NAME]
|
||||
self.type_num = getattr(wrap, 'NPY_STRING')
|
||||
self.elsize = 1
|
||||
self.dtype = np.dtype('c')
|
||||
elif self.NAME.startswith('STRING'):
|
||||
info = c_names_dict[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 = c_names_dict[self.NAME]
|
||||
self.type_num = getattr(wrap, 'NPY_' + self.NAME)
|
||||
self.elsize = info.itemsize
|
||||
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 = c_names_dict[self.NAME].alignment
|
||||
types = []
|
||||
for name in _type_names:
|
||||
if c_names_dict[name].alignment < bits:
|
||||
types.append(Type(name))
|
||||
return types
|
||||
|
||||
def equal_types(self):
|
||||
bits = c_names_dict[self.NAME].alignment
|
||||
types = []
|
||||
for name in _type_names:
|
||||
if name == self.NAME:
|
||||
continue
|
||||
if c_names_dict[name].alignment == bits:
|
||||
types.append(Type(name))
|
||||
return types
|
||||
|
||||
def larger_types(self):
|
||||
bits = c_names_dict[self.NAME].alignment
|
||||
types = []
|
||||
for name in _type_names:
|
||||
if c_names_dict[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
|
||||
is_int = np.issubdtype(t.dtype, np.integer)
|
||||
if is_int and int(self.num2seq[0]) > np.iinfo(t.dtype).max:
|
||||
# skip test if num2seq would trigger an overflow error
|
||||
continue
|
||||
obj = np.array(self.num2seq, dtype=t.dtype)
|
||||
shape = (len(self.num2seq), )
|
||||
try:
|
||||
self.array(shape, intent.in_.cache, obj) # Should succeed
|
||||
except ValueError as msg:
|
||||
if not str(msg).startswith(
|
||||
"failed to initialize intent(cache) array"):
|
||||
raise
|
||||
else:
|
||||
raise SystemError(
|
||||
"intent(cache) should have failed on smaller array")
|
||||
|
||||
def test_cache_hidden(self):
|
||||
shape = (2, )
|
||||
a = self.array(shape, intent.cache.hide, None)
|
||||
assert a.arr.shape == shape
|
||||
|
||||
shape = (2, 3)
|
||||
a = self.array(shape, intent.cache.hide, None)
|
||||
assert a.arr.shape == shape
|
||||
|
||||
shape = (-1, 3)
|
||||
try:
|
||||
a = self.array(shape, intent.cache.hide, None)
|
||||
except ValueError as msg:
|
||||
if not str(msg).startswith(
|
||||
"failed to create intent(cache|hide)|optional array"):
|
||||
raise
|
||||
else:
|
||||
raise SystemError(
|
||||
"intent(cache) should have failed on undefined dimensions")
|
||||
|
||||
def test_hidden(self):
|
||||
shape = (2, )
|
||||
a = self.array(shape, intent.hide, None)
|
||||
assert a.arr.shape == shape
|
||||
assert a.arr_equal(a.arr, np.zeros(shape, dtype=self.type.dtype))
|
||||
|
||||
shape = (2, 3)
|
||||
a = self.array(shape, intent.hide, None)
|
||||
assert a.arr.shape == shape
|
||||
assert a.arr_equal(a.arr, np.zeros(shape, dtype=self.type.dtype))
|
||||
assert a.arr.flags["FORTRAN"] and not a.arr.flags["CONTIGUOUS"]
|
||||
|
||||
shape = (2, 3)
|
||||
a = self.array(shape, intent.c.hide, None)
|
||||
assert a.arr.shape == shape
|
||||
assert a.arr_equal(a.arr, np.zeros(shape, dtype=self.type.dtype))
|
||||
assert not a.arr.flags["FORTRAN"] and a.arr.flags["CONTIGUOUS"]
|
||||
|
||||
shape = (-1, 3)
|
||||
try:
|
||||
a = self.array(shape, intent.hide, None)
|
||||
except ValueError as msg:
|
||||
if not str(msg).startswith(
|
||||
"failed to create intent(cache|hide)|optional array"):
|
||||
raise
|
||||
else:
|
||||
raise SystemError(
|
||||
"intent(hide) should have failed on undefined dimensions")
|
||||
|
||||
def test_optional_none(self):
|
||||
shape = (2, )
|
||||
a = self.array(shape, intent.optional, None)
|
||||
assert a.arr.shape == shape
|
||||
assert a.arr_equal(a.arr, np.zeros(shape, dtype=self.type.dtype))
|
||||
|
||||
shape = (2, 3)
|
||||
a = self.array(shape, intent.optional, None)
|
||||
assert a.arr.shape == shape
|
||||
assert a.arr_equal(a.arr, np.zeros(shape, dtype=self.type.dtype))
|
||||
assert a.arr.flags["FORTRAN"] and not a.arr.flags["CONTIGUOUS"]
|
||||
|
||||
shape = (2, 3)
|
||||
a = self.array(shape, intent.c.optional, None)
|
||||
assert a.arr.shape == shape
|
||||
assert a.arr_equal(a.arr, np.zeros(shape, dtype=self.type.dtype))
|
||||
assert not a.arr.flags["FORTRAN"] and a.arr.flags["CONTIGUOUS"]
|
||||
|
||||
def test_optional_from_2seq(self):
|
||||
obj = self.num2seq
|
||||
shape = (len(obj), )
|
||||
a = self.array(shape, intent.optional, obj)
|
||||
assert a.arr.shape == shape
|
||||
assert not a.has_shared_memory()
|
||||
|
||||
def test_optional_from_23seq(self):
|
||||
obj = self.num23seq
|
||||
shape = (len(obj), len(obj[0]))
|
||||
a = self.array(shape, intent.optional, obj)
|
||||
assert a.arr.shape == shape
|
||||
assert not a.has_shared_memory()
|
||||
|
||||
a = self.array(shape, intent.optional.c, obj)
|
||||
assert a.arr.shape == shape
|
||||
assert not a.has_shared_memory()
|
||||
|
||||
def test_inplace(self):
|
||||
obj = np.array(self.num23seq, dtype=self.type.dtype)
|
||||
assert not obj.flags["FORTRAN"] and obj.flags["CONTIGUOUS"]
|
||||
shape = obj.shape
|
||||
a = self.array(shape, intent.inplace, obj)
|
||||
assert obj[1][2] == a.arr[1][2], repr((obj, a.arr))
|
||||
a.arr[1][2] = 54
|
||||
assert obj[1][2] == a.arr[1][2] == np.array(54, dtype=self.type.dtype)
|
||||
assert a.arr is obj
|
||||
assert obj.flags["FORTRAN"] # obj attributes are changed inplace!
|
||||
assert not obj.flags["CONTIGUOUS"]
|
||||
|
||||
def test_inplace_from_casttype(self):
|
||||
for t in self.type.cast_types():
|
||||
if t is self.type:
|
||||
continue
|
||||
obj = np.array(self.num23seq, dtype=t.dtype)
|
||||
assert obj.dtype.type == t.type
|
||||
assert obj.dtype.type is not self.type.type
|
||||
assert not obj.flags["FORTRAN"] and obj.flags["CONTIGUOUS"]
|
||||
shape = obj.shape
|
||||
a = self.array(shape, intent.inplace, obj)
|
||||
assert obj[1][2] == a.arr[1][2], repr((obj, a.arr))
|
||||
a.arr[1][2] = 54
|
||||
assert obj[1][2] == a.arr[1][2] == np.array(54,
|
||||
dtype=self.type.dtype)
|
||||
assert a.arr is obj
|
||||
assert obj.flags["FORTRAN"] # obj attributes changed inplace!
|
||||
assert not obj.flags["CONTIGUOUS"]
|
||||
assert obj.dtype.type is self.type.type # obj changed inplace!
|
@ -0,0 +1,49 @@
|
||||
import os
|
||||
import pytest
|
||||
import tempfile
|
||||
|
||||
from . import util
|
||||
|
||||
|
||||
class TestAssumedShapeSumExample(util.F2PyTest):
|
||||
sources = [
|
||||
util.getpath("tests", "src", "assumed_shape", "foo_free.f90"),
|
||||
util.getpath("tests", "src", "assumed_shape", "foo_use.f90"),
|
||||
util.getpath("tests", "src", "assumed_shape", "precision.f90"),
|
||||
util.getpath("tests", "src", "assumed_shape", "foo_mod.f90"),
|
||||
util.getpath("tests", "src", "assumed_shape", ".f2py_f2cmap"),
|
||||
]
|
||||
|
||||
@pytest.mark.slow
|
||||
def test_all(self):
|
||||
r = self.module.fsum([1, 2])
|
||||
assert r == 3
|
||||
r = self.module.sum([1, 2])
|
||||
assert r == 3
|
||||
r = self.module.sum_with_use([1, 2])
|
||||
assert r == 3
|
||||
|
||||
r = self.module.mod.sum([1, 2])
|
||||
assert r == 3
|
||||
r = self.module.mod.fsum([1, 2])
|
||||
assert r == 3
|
||||
|
||||
|
||||
class TestF2cmapOption(TestAssumedShapeSumExample):
|
||||
def setup_method(self):
|
||||
# Use a custom file name for .f2py_f2cmap
|
||||
self.sources = list(self.sources)
|
||||
f2cmap_src = self.sources.pop(-1)
|
||||
|
||||
self.f2cmap_file = tempfile.NamedTemporaryFile(delete=False)
|
||||
with open(f2cmap_src, "rb") as f:
|
||||
self.f2cmap_file.write(f.read())
|
||||
self.f2cmap_file.close()
|
||||
|
||||
self.sources.append(self.f2cmap_file.name)
|
||||
self.options = ["--f2cmap", self.f2cmap_file.name]
|
||||
|
||||
super().setup_method()
|
||||
|
||||
def teardown_method(self):
|
||||
os.unlink(self.f2cmap_file.name)
|
@ -0,0 +1,18 @@
|
||||
import sys
|
||||
import pytest
|
||||
from . import util
|
||||
|
||||
from numpy.testing import IS_PYPY
|
||||
|
||||
|
||||
@pytest.mark.slow
|
||||
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
|
246
lib/python3.13/site-packages/numpy/f2py/tests/test_callback.py
Normal file
246
lib/python3.13/site-packages/numpy/f2py/tests/test_callback.py
Normal file
@ -0,0 +1,246 @@
|
||||
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(","))
|
||||
@pytest.mark.slow
|
||||
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")]
|
||||
|
||||
@pytest.mark.slow
|
||||
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")]
|
||||
|
||||
@pytest.mark.slow
|
||||
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_gh25211(self):
|
||||
def bar(x):
|
||||
return x*x
|
||||
|
||||
res = self.module.foo(bar)
|
||||
assert res == 110
|
639
lib/python3.13/site-packages/numpy/f2py/tests/test_character.py
Normal file
639
lib/python3.13/site-packages/numpy/f2py/tests/test_character.py
Normal file
@ -0,0 +1,639 @@
|
||||
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
|
||||
|
||||
|
||||
@pytest.mark.slow
|
||||
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
|
||||
""")
|
||||
|
||||
@pytest.mark.slow
|
||||
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")
|
||||
|
||||
@pytest.mark.slow
|
||||
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
|
20
lib/python3.13/site-packages/numpy/f2py/tests/test_common.py
Normal file
20
lib/python3.13/site-packages/numpy/f2py/tests/test_common.py
Normal file
@ -0,0 +1,20 @@
|
||||
import pytest
|
||||
import numpy as np
|
||||
from . import util
|
||||
|
||||
@pytest.mark.slow
|
||||
class TestCommonBlock(util.F2PyTest):
|
||||
sources = [util.getpath("tests", "src", "common", "block.f")]
|
||||
|
||||
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")]
|
||||
|
||||
def test_common_gh19161(self):
|
||||
assert self.module.data.x == 0
|
@ -0,0 +1,407 @@
|
||||
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
|
||||
if (a({first}).gt.0) then
|
||||
! print*, "a=", a
|
||||
endif
|
||||
end subroutine
|
||||
""")
|
||||
|
||||
linear_dimspecs = [
|
||||
"n", "2*n", "2:n", "n/2", "5 - n/2", "3*n:20", "n*(n+1):n*(n+5)",
|
||||
"2*n, n"
|
||||
]
|
||||
nonlinear_dimspecs = ["2*n:3*n*n+2*n"]
|
||||
all_dimspecs = linear_dimspecs + nonlinear_dimspecs
|
||||
|
||||
code = ""
|
||||
for count, dimspec in enumerate(all_dimspecs):
|
||||
lst = [(d.split(":")[0] if ":" in d else "1") for d in dimspec.split(',')]
|
||||
code += code_template.format(
|
||||
count=count,
|
||||
dimspec=dimspec,
|
||||
first=", ".join(lst),
|
||||
)
|
||||
|
||||
@pytest.mark.parametrize("dimspec", all_dimspecs)
|
||||
@pytest.mark.slow
|
||||
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'
|
||||
|
||||
|
||||
@pytest.mark.slow
|
||||
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")]
|
||||
|
||||
@pytest.mark.slow
|
||||
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()
|
||||
|
||||
class TestParamEval:
|
||||
# issue gh-11612, array parameter parsing
|
||||
def test_param_eval_nested(self):
|
||||
v = '(/3.14, 4./)'
|
||||
g_params = dict(kind=crackfortran._kind_func,
|
||||
selected_int_kind=crackfortran._selected_int_kind_func,
|
||||
selected_real_kind=crackfortran._selected_real_kind_func)
|
||||
params = {'dp': 8, 'intparamarray': {1: 3, 2: 5},
|
||||
'nested': {1: 1, 2: 2, 3: 3}}
|
||||
dimspec = '(2)'
|
||||
ret = crackfortran.param_eval(v, g_params, params, dimspec=dimspec)
|
||||
assert ret == {1: 3.14, 2: 4.0}
|
||||
|
||||
def test_param_eval_nonstandard_range(self):
|
||||
v = '(/ 6, 3, 1 /)'
|
||||
g_params = dict(kind=crackfortran._kind_func,
|
||||
selected_int_kind=crackfortran._selected_int_kind_func,
|
||||
selected_real_kind=crackfortran._selected_real_kind_func)
|
||||
params = {}
|
||||
dimspec = '(-1:1)'
|
||||
ret = crackfortran.param_eval(v, g_params, params, dimspec=dimspec)
|
||||
assert ret == {-1: 6, 0: 3, 1: 1}
|
||||
|
||||
def test_param_eval_empty_range(self):
|
||||
v = '6'
|
||||
g_params = dict(kind=crackfortran._kind_func,
|
||||
selected_int_kind=crackfortran._selected_int_kind_func,
|
||||
selected_real_kind=crackfortran._selected_real_kind_func)
|
||||
params = {}
|
||||
dimspec = ''
|
||||
pytest.raises(ValueError, crackfortran.param_eval, v, g_params, params,
|
||||
dimspec=dimspec)
|
||||
|
||||
def test_param_eval_non_array_param(self):
|
||||
v = '3.14_dp'
|
||||
g_params = dict(kind=crackfortran._kind_func,
|
||||
selected_int_kind=crackfortran._selected_int_kind_func,
|
||||
selected_real_kind=crackfortran._selected_real_kind_func)
|
||||
params = {}
|
||||
ret = crackfortran.param_eval(v, g_params, params, dimspec=None)
|
||||
assert ret == '3.14_dp'
|
||||
|
||||
def test_param_eval_too_many_dims(self):
|
||||
v = 'reshape((/ (i, i=1, 250) /), (/5, 10, 5/))'
|
||||
g_params = dict(kind=crackfortran._kind_func,
|
||||
selected_int_kind=crackfortran._selected_int_kind_func,
|
||||
selected_real_kind=crackfortran._selected_real_kind_func)
|
||||
params = {}
|
||||
dimspec = '(0:4, 3:12, 5)'
|
||||
pytest.raises(ValueError, crackfortran.param_eval, v, g_params, params,
|
||||
dimspec=dimspec)
|
71
lib/python3.13/site-packages/numpy/f2py/tests/test_data.py
Normal file
71
lib/python3.13/site-packages/numpy/f2py/tests/test_data.py
Normal file
@ -0,0 +1,71 @@
|
||||
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
|
||||
@pytest.mark.slow
|
||||
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
|
59
lib/python3.13/site-packages/numpy/f2py/tests/test_docs.py
Normal file
59
lib/python3.13/site-packages/numpy/f2py/tests/test_docs.py
Normal file
@ -0,0 +1,59 @@
|
||||
import pytest
|
||||
import numpy as np
|
||||
from numpy.testing import assert_array_equal, assert_equal
|
||||
from . import util
|
||||
from pathlib import Path
|
||||
|
||||
def get_docdir():
|
||||
parents = Path(__file__).resolve().parents
|
||||
try:
|
||||
# Assumes that spin is used to run tests
|
||||
nproot = parents[8]
|
||||
except IndexError:
|
||||
docdir = None
|
||||
else:
|
||||
docdir = nproot / "doc" / "source" / "f2py" / "code"
|
||||
if docdir and docdir.is_dir():
|
||||
return docdir
|
||||
# Assumes that an editable install is used to run tests
|
||||
return parents[3] / "doc" / "source" / "f2py" / "code"
|
||||
|
||||
pytestmark = pytest.mark.skipif(
|
||||
not get_docdir().is_dir(),
|
||||
reason=f"Could not find f2py documentation sources"
|
||||
f"({get_docdir()} does not exist)",
|
||||
)
|
||||
|
||||
def _path(*args):
|
||||
return get_docdir().joinpath(*args)
|
||||
|
||||
@pytest.mark.slow
|
||||
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(20), 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
|
15
lib/python3.13/site-packages/numpy/f2py/tests/test_f2cmap.py
Normal file
15
lib/python3.13/site-packages/numpy/f2py/tests/test_f2cmap.py
Normal file
@ -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_gh15095(self):
|
||||
inp = np.ones(3)
|
||||
out = self.module.func1(inp)
|
||||
exp_out = 3
|
||||
assert out == exp_out
|
959
lib/python3.13/site-packages/numpy/f2py/tests/test_f2py2e.py
Normal file
959
lib/python3.13/site-packages/numpy/f2py/tests/test_f2py2e.py
Normal file
@ -0,0 +1,959 @@
|
||||
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
|
||||
from numpy.testing._private.utils import NOGIL_BUILD
|
||||
|
||||
#######################
|
||||
# F2PY Test utilities #
|
||||
######################
|
||||
|
||||
# Tests for CLI commands which call meson will fail if no compilers are present, these are to be skipped
|
||||
|
||||
def compiler_check_f2pycli():
|
||||
if not util.has_fortran_compiler():
|
||||
pytest.skip("CLI command needs a Fortran compiler")
|
||||
else:
|
||||
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 #
|
||||
################
|
||||
|
||||
|
||||
@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
|
||||
|
||||
#########
|
||||
# Tests #
|
||||
#########
|
||||
|
||||
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(sys.version_info <= (3, 12), reason="Python 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):
|
||||
compiler_check_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):
|
||||
compiler_check_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.skip(reason="Consistently fails on CI; noisy so skip not xfail.")
|
||||
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(f"{sys.executable} -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.skip(reason="Consistently fails on CI; noisy so skip not xfail.")
|
||||
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(f"{sys.executable} -c \"import blah; blah.hi()\"")
|
||||
rout = subprocess.run(cmd_run, capture_output=True, encoding='UTF-8')
|
||||
eout = ' Hello World\n'
|
||||
assert rout.stdout == eout
|
||||
|
||||
|
||||
@pytest.mark.skipif((platform.system() != 'Linux') or sys.version_info <= (3, 12),
|
||||
reason='Compiler and Python 3.12 or newer required')
|
||||
def test_no_freethreading_compatible(hello_world_f90, monkeypatch):
|
||||
"""
|
||||
CLI :: --no-freethreading-compatible
|
||||
"""
|
||||
ipath = Path(hello_world_f90)
|
||||
monkeypatch.setattr(sys, "argv", f'f2py -m blah {ipath} -c --no-freethreading-compatible'.split())
|
||||
|
||||
with util.switchdir(ipath.parent):
|
||||
compiler_check_f2pycli()
|
||||
cmd = f"{sys.executable} -c \"import blah; blah.hi();"
|
||||
if NOGIL_BUILD:
|
||||
cmd += "import sys; assert sys._is_gil_enabled() is True\""
|
||||
else:
|
||||
cmd += "\""
|
||||
cmd_run = shlex.split(cmd)
|
||||
rout = subprocess.run(cmd_run, capture_output=True, encoding='UTF-8')
|
||||
eout = ' Hello World\n'
|
||||
assert rout.stdout == eout
|
||||
if NOGIL_BUILD:
|
||||
assert "The global interpreter lock (GIL) has been enabled to load module 'blah'" in rout.stderr
|
||||
assert rout.returncode == 0
|
||||
|
||||
|
||||
@pytest.mark.skipif((platform.system() != 'Linux') or sys.version_info <= (3, 12),
|
||||
reason='Compiler and Python 3.12 or newer required')
|
||||
def test_freethreading_compatible(hello_world_f90, monkeypatch):
|
||||
"""
|
||||
CLI :: --freethreading_compatible
|
||||
"""
|
||||
ipath = Path(hello_world_f90)
|
||||
monkeypatch.setattr(sys, "argv", f'f2py -m blah {ipath} -c --freethreading-compatible'.split())
|
||||
|
||||
with util.switchdir(ipath.parent):
|
||||
compiler_check_f2pycli()
|
||||
cmd = f"{sys.executable} -c \"import blah; blah.hi();"
|
||||
if NOGIL_BUILD:
|
||||
cmd += "import sys; assert sys._is_gil_enabled() is False\""
|
||||
else:
|
||||
cmd += "\""
|
||||
cmd_run = shlex.split(cmd)
|
||||
rout = subprocess.run(cmd_run, capture_output=True, encoding='UTF-8')
|
||||
eout = ' Hello World\n'
|
||||
assert rout.stdout == eout
|
||||
assert rout.stderr == ""
|
||||
assert rout.returncode == 0
|
||||
|
||||
|
||||
# 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
|
53
lib/python3.13/site-packages/numpy/f2py/tests/test_isoc.py
Normal file
53
lib/python3.13/site-packages/numpy/f2py/tests/test_isoc.py
Normal file
@ -0,0 +1,53 @@
|
||||
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
|
||||
@pytest.mark.slow
|
||||
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
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user