virtuelle Umgebung teil20b
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -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,230 @@
|
||||
/*
|
||||
* This file was auto-generated with f2py (version:2_1330) and hand edited by
|
||||
* Pearu for testing purposes. Do not edit this file unless you know what you
|
||||
* are doing!!!
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************** See f2py2e/cfuncs.py: includes ***********************/
|
||||
|
||||
#define PY_SSIZE_T_CLEAN
|
||||
#include <Python.h>
|
||||
#include "fortranobject.h"
|
||||
#include <math.h>
|
||||
|
||||
static PyObject *wrap_error;
|
||||
static PyObject *wrap_module;
|
||||
|
||||
/************************************ call ************************************/
|
||||
static char doc_f2py_rout_wrap_call[] = "\
|
||||
Function signature:\n\
|
||||
arr = call(type_num,dims,intent,obj)\n\
|
||||
Required arguments:\n"
|
||||
" type_num : input int\n"
|
||||
" dims : input int-sequence\n"
|
||||
" intent : input int\n"
|
||||
" obj : input python object\n"
|
||||
"Return objects:\n"
|
||||
" arr : array";
|
||||
static PyObject *f2py_rout_wrap_call(PyObject *capi_self,
|
||||
PyObject *capi_args) {
|
||||
PyObject * volatile capi_buildvalue = NULL;
|
||||
int type_num = 0;
|
||||
int elsize = 0;
|
||||
npy_intp *dims = NULL;
|
||||
PyObject *dims_capi = Py_None;
|
||||
int rank = 0;
|
||||
int intent = 0;
|
||||
PyArrayObject *capi_arr_tmp = NULL;
|
||||
PyObject *arr_capi = Py_None;
|
||||
int i;
|
||||
|
||||
if (!PyArg_ParseTuple(capi_args,"iiOiO|:wrap.call",\
|
||||
&type_num,&elsize,&dims_capi,&intent,&arr_capi))
|
||||
return NULL;
|
||||
rank = PySequence_Length(dims_capi);
|
||||
dims = malloc(rank*sizeof(npy_intp));
|
||||
for (i=0;i<rank;++i) {
|
||||
PyObject *tmp;
|
||||
tmp = PySequence_GetItem(dims_capi, i);
|
||||
if (tmp == NULL) {
|
||||
goto fail;
|
||||
}
|
||||
dims[i] = (npy_intp)PyLong_AsLong(tmp);
|
||||
Py_DECREF(tmp);
|
||||
if (dims[i] == -1 && PyErr_Occurred()) {
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
capi_arr_tmp = ndarray_from_pyobj(type_num,elsize,dims,rank,intent|F2PY_INTENT_OUT,arr_capi,"wrap.call failed");
|
||||
if (capi_arr_tmp == NULL) {
|
||||
free(dims);
|
||||
return NULL;
|
||||
}
|
||||
capi_buildvalue = Py_BuildValue("N",capi_arr_tmp);
|
||||
free(dims);
|
||||
return capi_buildvalue;
|
||||
|
||||
fail:
|
||||
free(dims);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static char doc_f2py_rout_wrap_attrs[] = "\
|
||||
Function signature:\n\
|
||||
arr = array_attrs(arr)\n\
|
||||
Required arguments:\n"
|
||||
" arr : input array object\n"
|
||||
"Return objects:\n"
|
||||
" data : data address in hex\n"
|
||||
" nd : int\n"
|
||||
" dimensions : tuple\n"
|
||||
" strides : tuple\n"
|
||||
" base : python object\n"
|
||||
" (kind,type,type_num,elsize,alignment) : 4-tuple\n"
|
||||
" flags : int\n"
|
||||
" itemsize : int\n"
|
||||
;
|
||||
static PyObject *f2py_rout_wrap_attrs(PyObject *capi_self,
|
||||
PyObject *capi_args) {
|
||||
PyObject *arr_capi = Py_None;
|
||||
PyArrayObject *arr = NULL;
|
||||
PyObject *dimensions = NULL;
|
||||
PyObject *strides = NULL;
|
||||
char s[100];
|
||||
int i;
|
||||
memset(s,0,100);
|
||||
if (!PyArg_ParseTuple(capi_args,"O!|:wrap.attrs",
|
||||
&PyArray_Type,&arr_capi))
|
||||
return NULL;
|
||||
arr = (PyArrayObject *)arr_capi;
|
||||
sprintf(s,"%p",PyArray_DATA(arr));
|
||||
dimensions = PyTuple_New(PyArray_NDIM(arr));
|
||||
strides = PyTuple_New(PyArray_NDIM(arr));
|
||||
for (i=0;i<PyArray_NDIM(arr);++i) {
|
||||
PyTuple_SetItem(dimensions,i,PyLong_FromLong(PyArray_DIM(arr,i)));
|
||||
PyTuple_SetItem(strides,i,PyLong_FromLong(PyArray_STRIDE(arr,i)));
|
||||
}
|
||||
return Py_BuildValue("siNNO(cciii)ii",s,PyArray_NDIM(arr),
|
||||
dimensions,strides,
|
||||
(PyArray_BASE(arr)==NULL?Py_None:PyArray_BASE(arr)),
|
||||
PyArray_DESCR(arr)->kind,
|
||||
PyArray_DESCR(arr)->type,
|
||||
PyArray_TYPE(arr),
|
||||
PyArray_ITEMSIZE(arr),
|
||||
PyArray_DESCR(arr)->alignment,
|
||||
PyArray_FLAGS(arr),
|
||||
PyArray_ITEMSIZE(arr));
|
||||
}
|
||||
|
||||
static PyMethodDef f2py_module_methods[] = {
|
||||
|
||||
{"call",f2py_rout_wrap_call,METH_VARARGS,doc_f2py_rout_wrap_call},
|
||||
{"array_attrs",f2py_rout_wrap_attrs,METH_VARARGS,doc_f2py_rout_wrap_attrs},
|
||||
{NULL,NULL}
|
||||
};
|
||||
|
||||
static struct PyModuleDef moduledef = {
|
||||
PyModuleDef_HEAD_INIT,
|
||||
"test_array_from_pyobj_ext",
|
||||
NULL,
|
||||
-1,
|
||||
f2py_module_methods,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
PyMODINIT_FUNC PyInit_test_array_from_pyobj_ext(void) {
|
||||
PyObject *m,*d, *s;
|
||||
m = wrap_module = PyModule_Create(&moduledef);
|
||||
Py_SET_TYPE(&PyFortran_Type, &PyType_Type);
|
||||
import_array();
|
||||
if (PyErr_Occurred())
|
||||
Py_FatalError("can't initialize module wrap (failed to import numpy)");
|
||||
d = PyModule_GetDict(m);
|
||||
s = PyUnicode_FromString("This module 'wrap' is auto-generated with f2py (version:2_1330).\nFunctions:\n"
|
||||
" arr = call(type_num,dims,intent,obj)\n"
|
||||
".");
|
||||
PyDict_SetItemString(d, "__doc__", s);
|
||||
wrap_error = PyErr_NewException ("wrap.error", NULL, NULL);
|
||||
Py_DECREF(s);
|
||||
|
||||
#define ADDCONST(NAME, CONST) \
|
||||
s = PyLong_FromLong(CONST); \
|
||||
PyDict_SetItemString(d, NAME, s); \
|
||||
Py_DECREF(s)
|
||||
|
||||
ADDCONST("F2PY_INTENT_IN", F2PY_INTENT_IN);
|
||||
ADDCONST("F2PY_INTENT_INOUT", F2PY_INTENT_INOUT);
|
||||
ADDCONST("F2PY_INTENT_OUT", F2PY_INTENT_OUT);
|
||||
ADDCONST("F2PY_INTENT_HIDE", F2PY_INTENT_HIDE);
|
||||
ADDCONST("F2PY_INTENT_CACHE", F2PY_INTENT_CACHE);
|
||||
ADDCONST("F2PY_INTENT_COPY", F2PY_INTENT_COPY);
|
||||
ADDCONST("F2PY_INTENT_C", F2PY_INTENT_C);
|
||||
ADDCONST("F2PY_OPTIONAL", F2PY_OPTIONAL);
|
||||
ADDCONST("F2PY_INTENT_INPLACE", F2PY_INTENT_INPLACE);
|
||||
ADDCONST("NPY_BOOL", NPY_BOOL);
|
||||
ADDCONST("NPY_BYTE", NPY_BYTE);
|
||||
ADDCONST("NPY_UBYTE", NPY_UBYTE);
|
||||
ADDCONST("NPY_SHORT", NPY_SHORT);
|
||||
ADDCONST("NPY_USHORT", NPY_USHORT);
|
||||
ADDCONST("NPY_INT", NPY_INT);
|
||||
ADDCONST("NPY_UINT", NPY_UINT);
|
||||
ADDCONST("NPY_INTP", NPY_INTP);
|
||||
ADDCONST("NPY_UINTP", NPY_UINTP);
|
||||
ADDCONST("NPY_LONG", NPY_LONG);
|
||||
ADDCONST("NPY_ULONG", NPY_ULONG);
|
||||
ADDCONST("NPY_LONGLONG", NPY_LONGLONG);
|
||||
ADDCONST("NPY_ULONGLONG", NPY_ULONGLONG);
|
||||
ADDCONST("NPY_FLOAT", NPY_FLOAT);
|
||||
ADDCONST("NPY_DOUBLE", NPY_DOUBLE);
|
||||
ADDCONST("NPY_LONGDOUBLE", NPY_LONGDOUBLE);
|
||||
ADDCONST("NPY_CFLOAT", NPY_CFLOAT);
|
||||
ADDCONST("NPY_CDOUBLE", NPY_CDOUBLE);
|
||||
ADDCONST("NPY_CLONGDOUBLE", NPY_CLONGDOUBLE);
|
||||
ADDCONST("NPY_OBJECT", NPY_OBJECT);
|
||||
ADDCONST("NPY_STRING", NPY_STRING);
|
||||
ADDCONST("NPY_UNICODE", NPY_UNICODE);
|
||||
ADDCONST("NPY_VOID", NPY_VOID);
|
||||
ADDCONST("NPY_NTYPES", NPY_NTYPES);
|
||||
ADDCONST("NPY_NOTYPE", NPY_NOTYPE);
|
||||
ADDCONST("NPY_USERDEF", NPY_USERDEF);
|
||||
|
||||
ADDCONST("CONTIGUOUS", NPY_ARRAY_C_CONTIGUOUS);
|
||||
ADDCONST("FORTRAN", NPY_ARRAY_F_CONTIGUOUS);
|
||||
ADDCONST("OWNDATA", NPY_ARRAY_OWNDATA);
|
||||
ADDCONST("FORCECAST", NPY_ARRAY_FORCECAST);
|
||||
ADDCONST("ENSURECOPY", NPY_ARRAY_ENSURECOPY);
|
||||
ADDCONST("ENSUREARRAY", NPY_ARRAY_ENSUREARRAY);
|
||||
ADDCONST("ALIGNED", NPY_ARRAY_ALIGNED);
|
||||
ADDCONST("WRITEABLE", NPY_ARRAY_WRITEABLE);
|
||||
ADDCONST("WRITEBACKIFCOPY", NPY_ARRAY_WRITEBACKIFCOPY);
|
||||
|
||||
ADDCONST("BEHAVED", NPY_ARRAY_BEHAVED);
|
||||
ADDCONST("BEHAVED_NS", NPY_ARRAY_BEHAVED_NS);
|
||||
ADDCONST("CARRAY", NPY_ARRAY_CARRAY);
|
||||
ADDCONST("FARRAY", NPY_ARRAY_FARRAY);
|
||||
ADDCONST("CARRAY_RO", NPY_ARRAY_CARRAY_RO);
|
||||
ADDCONST("FARRAY_RO", NPY_ARRAY_FARRAY_RO);
|
||||
ADDCONST("DEFAULT", NPY_ARRAY_DEFAULT);
|
||||
ADDCONST("UPDATE_ALL", NPY_ARRAY_UPDATE_ALL);
|
||||
|
||||
#undef ADDCONST(
|
||||
|
||||
if (PyErr_Occurred())
|
||||
Py_FatalError("can't initialize module wrap");
|
||||
|
||||
#ifdef F2PY_REPORT_ATEXIT
|
||||
on_exit(f2py_report_on_exit,(void*)"array_from_pyobj.wrap.call");
|
||||
#endif
|
||||
|
||||
return m;
|
||||
}
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@@ -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,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,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,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,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
|
||||
Cf2py intent(hide) :: n
|
||||
res = sum(x)
|
||||
end
|
@@ -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
|
Binary file not shown.
@@ -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,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,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,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,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,25 @@
|
||||
from pathlib import Path
|
||||
import pytest
|
||||
import textwrap
|
||||
from . import util
|
||||
from numpy.f2py import crackfortran
|
||||
from numpy.testing import IS_WASM
|
||||
|
||||
|
||||
@pytest.mark.skipif(IS_WASM, reason="Cannot start subprocess")
|
||||
class TestAbstractInterface(util.F2PyTest):
|
||||
sources = [util.getpath("tests", "src", "abstract_interface", "foo.f90")]
|
||||
|
||||
skip = ["add1", "add2"]
|
||||
|
||||
def test_abstract_interface(self):
|
||||
assert self.module.ops_module.foo(3, 5) == (8, 13)
|
||||
|
||||
def test_parse_abstract_interface(self):
|
||||
# Test gh18403
|
||||
fpath = util.getpath("tests", "src", "abstract_interface",
|
||||
"gh18403_mod.f90")
|
||||
mod = crackfortran.crackfortran([str(fpath)])
|
||||
assert len(mod) == 1
|
||||
assert len(mod[0]["body"]) == 1
|
||||
assert mod[0]["body"][0]["block"] == "abstract interface"
|
@@ -0,0 +1,686 @@
|
||||
import os
|
||||
import sys
|
||||
import copy
|
||||
import platform
|
||||
import pytest
|
||||
|
||||
import numpy as np
|
||||
|
||||
from numpy.testing import assert_, assert_equal
|
||||
from numpy.core.multiarray import typeinfo as _typeinfo
|
||||
from . import util
|
||||
|
||||
wrap = None
|
||||
|
||||
# Extend core typeinfo with CHARACTER to test dtype('c')
|
||||
_ti = _typeinfo['STRING']
|
||||
typeinfo = dict(
|
||||
CHARACTER=type(_ti)(('c', _ti.num, 8, _ti.alignment, _ti.type)),
|
||||
**_typeinfo)
|
||||
|
||||
|
||||
def setup_module():
|
||||
"""
|
||||
Build the required testing extension module
|
||||
|
||||
"""
|
||||
global wrap
|
||||
|
||||
# Check compiler availability first
|
||||
if not util.has_c_compiler():
|
||||
pytest.skip("No C compiler available")
|
||||
|
||||
if wrap is None:
|
||||
config_code = """
|
||||
config.add_extension('test_array_from_pyobj_ext',
|
||||
sources=['wrapmodule.c', 'fortranobject.c'],
|
||||
define_macros=[])
|
||||
"""
|
||||
d = os.path.dirname(__file__)
|
||||
src = [
|
||||
util.getpath("tests", "src", "array_from_pyobj", "wrapmodule.c"),
|
||||
util.getpath("src", "fortranobject.c"),
|
||||
util.getpath("src", "fortranobject.h"),
|
||||
]
|
||||
wrap = util.build_module_distutils(src, config_code,
|
||||
"test_array_from_pyobj_ext")
|
||||
|
||||
|
||||
def flags_info(arr):
|
||||
flags = wrap.array_attrs(arr)[6]
|
||||
return flags2names(flags)
|
||||
|
||||
|
||||
def flags2names(flags):
|
||||
info = []
|
||||
for flagname in [
|
||||
"CONTIGUOUS",
|
||||
"FORTRAN",
|
||||
"OWNDATA",
|
||||
"ENSURECOPY",
|
||||
"ENSUREARRAY",
|
||||
"ALIGNED",
|
||||
"NOTSWAPPED",
|
||||
"WRITEABLE",
|
||||
"WRITEBACKIFCOPY",
|
||||
"UPDATEIFCOPY",
|
||||
"BEHAVED",
|
||||
"BEHAVED_RO",
|
||||
"CARRAY",
|
||||
"FARRAY",
|
||||
]:
|
||||
if abs(flags) & getattr(wrap, flagname, 0):
|
||||
info.append(flagname)
|
||||
return info
|
||||
|
||||
|
||||
class Intent:
|
||||
def __init__(self, intent_list=[]):
|
||||
self.intent_list = intent_list[:]
|
||||
flags = 0
|
||||
for i in intent_list:
|
||||
if i == "optional":
|
||||
flags |= wrap.F2PY_OPTIONAL
|
||||
else:
|
||||
flags |= getattr(wrap, "F2PY_INTENT_" + i.upper())
|
||||
self.flags = flags
|
||||
|
||||
def __getattr__(self, name):
|
||||
name = name.lower()
|
||||
if name == "in_":
|
||||
name = "in"
|
||||
return self.__class__(self.intent_list + [name])
|
||||
|
||||
def __str__(self):
|
||||
return "intent(%s)" % (",".join(self.intent_list))
|
||||
|
||||
def __repr__(self):
|
||||
return "Intent(%r)" % (self.intent_list)
|
||||
|
||||
def is_intent(self, *names):
|
||||
for name in names:
|
||||
if name not in self.intent_list:
|
||||
return False
|
||||
return True
|
||||
|
||||
def is_intent_exact(self, *names):
|
||||
return len(self.intent_list) == len(names) and self.is_intent(*names)
|
||||
|
||||
|
||||
intent = Intent()
|
||||
|
||||
_type_names = [
|
||||
"BOOL",
|
||||
"BYTE",
|
||||
"UBYTE",
|
||||
"SHORT",
|
||||
"USHORT",
|
||||
"INT",
|
||||
"UINT",
|
||||
"LONG",
|
||||
"ULONG",
|
||||
"LONGLONG",
|
||||
"ULONGLONG",
|
||||
"FLOAT",
|
||||
"DOUBLE",
|
||||
"CFLOAT",
|
||||
"STRING1",
|
||||
"STRING5",
|
||||
"CHARACTER",
|
||||
]
|
||||
|
||||
_cast_dict = {"BOOL": ["BOOL"]}
|
||||
_cast_dict["BYTE"] = _cast_dict["BOOL"] + ["BYTE"]
|
||||
_cast_dict["UBYTE"] = _cast_dict["BOOL"] + ["UBYTE"]
|
||||
_cast_dict["BYTE"] = ["BYTE"]
|
||||
_cast_dict["UBYTE"] = ["UBYTE"]
|
||||
_cast_dict["SHORT"] = _cast_dict["BYTE"] + ["UBYTE", "SHORT"]
|
||||
_cast_dict["USHORT"] = _cast_dict["UBYTE"] + ["BYTE", "USHORT"]
|
||||
_cast_dict["INT"] = _cast_dict["SHORT"] + ["USHORT", "INT"]
|
||||
_cast_dict["UINT"] = _cast_dict["USHORT"] + ["SHORT", "UINT"]
|
||||
|
||||
_cast_dict["LONG"] = _cast_dict["INT"] + ["LONG"]
|
||||
_cast_dict["ULONG"] = _cast_dict["UINT"] + ["ULONG"]
|
||||
|
||||
_cast_dict["LONGLONG"] = _cast_dict["LONG"] + ["LONGLONG"]
|
||||
_cast_dict["ULONGLONG"] = _cast_dict["ULONG"] + ["ULONGLONG"]
|
||||
|
||||
_cast_dict["FLOAT"] = _cast_dict["SHORT"] + ["USHORT", "FLOAT"]
|
||||
_cast_dict["DOUBLE"] = _cast_dict["INT"] + ["UINT", "FLOAT", "DOUBLE"]
|
||||
|
||||
_cast_dict["CFLOAT"] = _cast_dict["FLOAT"] + ["CFLOAT"]
|
||||
|
||||
_cast_dict['STRING1'] = ['STRING1']
|
||||
_cast_dict['STRING5'] = ['STRING5']
|
||||
_cast_dict['CHARACTER'] = ['CHARACTER']
|
||||
|
||||
# 32 bit system malloc typically does not provide the alignment required by
|
||||
# 16 byte long double types this means the inout intent cannot be satisfied
|
||||
# and several tests fail as the alignment flag can be randomly true or fals
|
||||
# when numpy gains an aligned allocator the tests could be enabled again
|
||||
#
|
||||
# Furthermore, on macOS ARM64, LONGDOUBLE is an alias for DOUBLE.
|
||||
if ((np.intp().dtype.itemsize != 4 or np.clongdouble().dtype.alignment <= 8)
|
||||
and sys.platform != "win32"
|
||||
and (platform.system(), platform.processor()) != ("Darwin", "arm")):
|
||||
_type_names.extend(["LONGDOUBLE", "CDOUBLE", "CLONGDOUBLE"])
|
||||
_cast_dict["LONGDOUBLE"] = _cast_dict["LONG"] + [
|
||||
"ULONG",
|
||||
"FLOAT",
|
||||
"DOUBLE",
|
||||
"LONGDOUBLE",
|
||||
]
|
||||
_cast_dict["CLONGDOUBLE"] = _cast_dict["LONGDOUBLE"] + [
|
||||
"CFLOAT",
|
||||
"CDOUBLE",
|
||||
"CLONGDOUBLE",
|
||||
]
|
||||
_cast_dict["CDOUBLE"] = _cast_dict["DOUBLE"] + ["CFLOAT", "CDOUBLE"]
|
||||
|
||||
|
||||
class Type:
|
||||
_type_cache = {}
|
||||
|
||||
def __new__(cls, name):
|
||||
if isinstance(name, np.dtype):
|
||||
dtype0 = name
|
||||
name = None
|
||||
for n, i in typeinfo.items():
|
||||
if not isinstance(i, type) and dtype0.type is i.type:
|
||||
name = n
|
||||
break
|
||||
obj = cls._type_cache.get(name.upper(), None)
|
||||
if obj is not None:
|
||||
return obj
|
||||
obj = object.__new__(cls)
|
||||
obj._init(name)
|
||||
cls._type_cache[name.upper()] = obj
|
||||
return obj
|
||||
|
||||
def _init(self, name):
|
||||
self.NAME = name.upper()
|
||||
|
||||
if self.NAME == 'CHARACTER':
|
||||
info = typeinfo[self.NAME]
|
||||
self.type_num = getattr(wrap, 'NPY_STRING')
|
||||
self.elsize = 1
|
||||
self.dtype = np.dtype('c')
|
||||
elif self.NAME.startswith('STRING'):
|
||||
info = typeinfo[self.NAME[:6]]
|
||||
self.type_num = getattr(wrap, 'NPY_STRING')
|
||||
self.elsize = int(self.NAME[6:] or 0)
|
||||
self.dtype = np.dtype(f'S{self.elsize}')
|
||||
else:
|
||||
info = typeinfo[self.NAME]
|
||||
self.type_num = getattr(wrap, 'NPY_' + self.NAME)
|
||||
self.elsize = info.bits // 8
|
||||
self.dtype = np.dtype(info.type)
|
||||
|
||||
assert self.type_num == info.num
|
||||
self.type = info.type
|
||||
self.dtypechar = info.char
|
||||
|
||||
def __repr__(self):
|
||||
return (f"Type({self.NAME})|type_num={self.type_num},"
|
||||
f" dtype={self.dtype},"
|
||||
f" type={self.type}, elsize={self.elsize},"
|
||||
f" dtypechar={self.dtypechar}")
|
||||
|
||||
def cast_types(self):
|
||||
return [self.__class__(_m) for _m in _cast_dict[self.NAME]]
|
||||
|
||||
def all_types(self):
|
||||
return [self.__class__(_m) for _m in _type_names]
|
||||
|
||||
def smaller_types(self):
|
||||
bits = typeinfo[self.NAME].alignment
|
||||
types = []
|
||||
for name in _type_names:
|
||||
if typeinfo[name].alignment < bits:
|
||||
types.append(Type(name))
|
||||
return types
|
||||
|
||||
def equal_types(self):
|
||||
bits = typeinfo[self.NAME].alignment
|
||||
types = []
|
||||
for name in _type_names:
|
||||
if name == self.NAME:
|
||||
continue
|
||||
if typeinfo[name].alignment == bits:
|
||||
types.append(Type(name))
|
||||
return types
|
||||
|
||||
def larger_types(self):
|
||||
bits = typeinfo[self.NAME].alignment
|
||||
types = []
|
||||
for name in _type_names:
|
||||
if typeinfo[name].alignment > bits:
|
||||
types.append(Type(name))
|
||||
return types
|
||||
|
||||
|
||||
class Array:
|
||||
|
||||
def __repr__(self):
|
||||
return (f'Array({self.type}, {self.dims}, {self.intent},'
|
||||
f' {self.obj})|arr={self.arr}')
|
||||
|
||||
def __init__(self, typ, dims, intent, obj):
|
||||
self.type = typ
|
||||
self.dims = dims
|
||||
self.intent = intent
|
||||
self.obj_copy = copy.deepcopy(obj)
|
||||
self.obj = obj
|
||||
|
||||
# arr.dtypechar may be different from typ.dtypechar
|
||||
self.arr = wrap.call(typ.type_num,
|
||||
typ.elsize,
|
||||
dims, intent.flags, obj)
|
||||
|
||||
assert isinstance(self.arr, np.ndarray)
|
||||
|
||||
self.arr_attr = wrap.array_attrs(self.arr)
|
||||
|
||||
if len(dims) > 1:
|
||||
if self.intent.is_intent("c"):
|
||||
assert (intent.flags & wrap.F2PY_INTENT_C)
|
||||
assert not self.arr.flags["FORTRAN"]
|
||||
assert self.arr.flags["CONTIGUOUS"]
|
||||
assert (not self.arr_attr[6] & wrap.FORTRAN)
|
||||
else:
|
||||
assert (not intent.flags & wrap.F2PY_INTENT_C)
|
||||
assert self.arr.flags["FORTRAN"]
|
||||
assert not self.arr.flags["CONTIGUOUS"]
|
||||
assert (self.arr_attr[6] & wrap.FORTRAN)
|
||||
|
||||
if obj is None:
|
||||
self.pyarr = None
|
||||
self.pyarr_attr = None
|
||||
return
|
||||
|
||||
if intent.is_intent("cache"):
|
||||
assert isinstance(obj, np.ndarray), repr(type(obj))
|
||||
self.pyarr = np.array(obj).reshape(*dims).copy()
|
||||
else:
|
||||
self.pyarr = np.array(
|
||||
np.array(obj, dtype=typ.dtypechar).reshape(*dims),
|
||||
order=self.intent.is_intent("c") and "C" or "F",
|
||||
)
|
||||
assert self.pyarr.dtype == typ
|
||||
self.pyarr.setflags(write=self.arr.flags["WRITEABLE"])
|
||||
assert self.pyarr.flags["OWNDATA"], (obj, intent)
|
||||
self.pyarr_attr = wrap.array_attrs(self.pyarr)
|
||||
|
||||
if len(dims) > 1:
|
||||
if self.intent.is_intent("c"):
|
||||
assert not self.pyarr.flags["FORTRAN"]
|
||||
assert self.pyarr.flags["CONTIGUOUS"]
|
||||
assert (not self.pyarr_attr[6] & wrap.FORTRAN)
|
||||
else:
|
||||
assert self.pyarr.flags["FORTRAN"]
|
||||
assert not self.pyarr.flags["CONTIGUOUS"]
|
||||
assert (self.pyarr_attr[6] & wrap.FORTRAN)
|
||||
|
||||
assert self.arr_attr[1] == self.pyarr_attr[1] # nd
|
||||
assert self.arr_attr[2] == self.pyarr_attr[2] # dimensions
|
||||
if self.arr_attr[1] <= 1:
|
||||
assert self.arr_attr[3] == self.pyarr_attr[3], repr((
|
||||
self.arr_attr[3],
|
||||
self.pyarr_attr[3],
|
||||
self.arr.tobytes(),
|
||||
self.pyarr.tobytes(),
|
||||
)) # strides
|
||||
assert self.arr_attr[5][-2:] == self.pyarr_attr[5][-2:], repr((
|
||||
self.arr_attr[5], self.pyarr_attr[5]
|
||||
)) # descr
|
||||
assert self.arr_attr[6] == self.pyarr_attr[6], repr((
|
||||
self.arr_attr[6],
|
||||
self.pyarr_attr[6],
|
||||
flags2names(0 * self.arr_attr[6] - self.pyarr_attr[6]),
|
||||
flags2names(self.arr_attr[6]),
|
||||
intent,
|
||||
)) # flags
|
||||
|
||||
if intent.is_intent("cache"):
|
||||
assert self.arr_attr[5][3] >= self.type.elsize
|
||||
else:
|
||||
assert self.arr_attr[5][3] == self.type.elsize
|
||||
assert (self.arr_equal(self.pyarr, self.arr))
|
||||
|
||||
if isinstance(self.obj, np.ndarray):
|
||||
if typ.elsize == Type(obj.dtype).elsize:
|
||||
if not intent.is_intent("copy") and self.arr_attr[1] <= 1:
|
||||
assert self.has_shared_memory()
|
||||
|
||||
def arr_equal(self, arr1, arr2):
|
||||
if arr1.shape != arr2.shape:
|
||||
return False
|
||||
return (arr1 == arr2).all()
|
||||
|
||||
def __str__(self):
|
||||
return str(self.arr)
|
||||
|
||||
def has_shared_memory(self):
|
||||
"""Check that created array shares data with input array."""
|
||||
if self.obj is self.arr:
|
||||
return True
|
||||
if not isinstance(self.obj, np.ndarray):
|
||||
return False
|
||||
obj_attr = wrap.array_attrs(self.obj)
|
||||
return obj_attr[0] == self.arr_attr[0]
|
||||
|
||||
|
||||
class TestIntent:
|
||||
def test_in_out(self):
|
||||
assert str(intent.in_.out) == "intent(in,out)"
|
||||
assert intent.in_.c.is_intent("c")
|
||||
assert not intent.in_.c.is_intent_exact("c")
|
||||
assert intent.in_.c.is_intent_exact("c", "in")
|
||||
assert intent.in_.c.is_intent_exact("in", "c")
|
||||
assert not intent.in_.is_intent("c")
|
||||
|
||||
|
||||
class TestSharedMemory:
|
||||
|
||||
@pytest.fixture(autouse=True, scope="class", params=_type_names)
|
||||
def setup_type(self, request):
|
||||
request.cls.type = Type(request.param)
|
||||
request.cls.array = lambda self, dims, intent, obj: Array(
|
||||
Type(request.param), dims, intent, obj)
|
||||
|
||||
@property
|
||||
def num2seq(self):
|
||||
if self.type.NAME.startswith('STRING'):
|
||||
elsize = self.type.elsize
|
||||
return ['1' * elsize, '2' * elsize]
|
||||
return [1, 2]
|
||||
|
||||
@property
|
||||
def num23seq(self):
|
||||
if self.type.NAME.startswith('STRING'):
|
||||
elsize = self.type.elsize
|
||||
return [['1' * elsize, '2' * elsize, '3' * elsize],
|
||||
['4' * elsize, '5' * elsize, '6' * elsize]]
|
||||
return [[1, 2, 3], [4, 5, 6]]
|
||||
|
||||
def test_in_from_2seq(self):
|
||||
a = self.array([2], intent.in_, self.num2seq)
|
||||
assert not a.has_shared_memory()
|
||||
|
||||
def test_in_from_2casttype(self):
|
||||
for t in self.type.cast_types():
|
||||
obj = np.array(self.num2seq, dtype=t.dtype)
|
||||
a = self.array([len(self.num2seq)], intent.in_, obj)
|
||||
if t.elsize == self.type.elsize:
|
||||
assert a.has_shared_memory(), repr((self.type.dtype, t.dtype))
|
||||
else:
|
||||
assert not a.has_shared_memory()
|
||||
|
||||
@pytest.mark.parametrize("write", ["w", "ro"])
|
||||
@pytest.mark.parametrize("order", ["C", "F"])
|
||||
@pytest.mark.parametrize("inp", ["2seq", "23seq"])
|
||||
def test_in_nocopy(self, write, order, inp):
|
||||
"""Test if intent(in) array can be passed without copies"""
|
||||
seq = getattr(self, "num" + inp)
|
||||
obj = np.array(seq, dtype=self.type.dtype, order=order)
|
||||
obj.setflags(write=(write == 'w'))
|
||||
a = self.array(obj.shape,
|
||||
((order == 'C' and intent.in_.c) or intent.in_), obj)
|
||||
assert a.has_shared_memory()
|
||||
|
||||
def test_inout_2seq(self):
|
||||
obj = np.array(self.num2seq, dtype=self.type.dtype)
|
||||
a = self.array([len(self.num2seq)], intent.inout, obj)
|
||||
assert a.has_shared_memory()
|
||||
|
||||
try:
|
||||
a = self.array([2], intent.in_.inout, self.num2seq)
|
||||
except TypeError as msg:
|
||||
if not str(msg).startswith(
|
||||
"failed to initialize intent(inout|inplace|cache) array"):
|
||||
raise
|
||||
else:
|
||||
raise SystemError("intent(inout) should have failed on sequence")
|
||||
|
||||
def test_f_inout_23seq(self):
|
||||
obj = np.array(self.num23seq, dtype=self.type.dtype, order="F")
|
||||
shape = (len(self.num23seq), len(self.num23seq[0]))
|
||||
a = self.array(shape, intent.in_.inout, obj)
|
||||
assert a.has_shared_memory()
|
||||
|
||||
obj = np.array(self.num23seq, dtype=self.type.dtype, order="C")
|
||||
shape = (len(self.num23seq), len(self.num23seq[0]))
|
||||
try:
|
||||
a = self.array(shape, intent.in_.inout, obj)
|
||||
except ValueError as msg:
|
||||
if not str(msg).startswith(
|
||||
"failed to initialize intent(inout) array"):
|
||||
raise
|
||||
else:
|
||||
raise SystemError(
|
||||
"intent(inout) should have failed on improper array")
|
||||
|
||||
def test_c_inout_23seq(self):
|
||||
obj = np.array(self.num23seq, dtype=self.type.dtype)
|
||||
shape = (len(self.num23seq), len(self.num23seq[0]))
|
||||
a = self.array(shape, intent.in_.c.inout, obj)
|
||||
assert a.has_shared_memory()
|
||||
|
||||
def test_in_copy_from_2casttype(self):
|
||||
for t in self.type.cast_types():
|
||||
obj = np.array(self.num2seq, dtype=t.dtype)
|
||||
a = self.array([len(self.num2seq)], intent.in_.copy, obj)
|
||||
assert not a.has_shared_memory()
|
||||
|
||||
def test_c_in_from_23seq(self):
|
||||
a = self.array(
|
||||
[len(self.num23seq), len(self.num23seq[0])], intent.in_,
|
||||
self.num23seq)
|
||||
assert not a.has_shared_memory()
|
||||
|
||||
def test_in_from_23casttype(self):
|
||||
for t in self.type.cast_types():
|
||||
obj = np.array(self.num23seq, dtype=t.dtype)
|
||||
a = self.array(
|
||||
[len(self.num23seq), len(self.num23seq[0])], intent.in_, obj)
|
||||
assert not a.has_shared_memory()
|
||||
|
||||
def test_f_in_from_23casttype(self):
|
||||
for t in self.type.cast_types():
|
||||
obj = np.array(self.num23seq, dtype=t.dtype, order="F")
|
||||
a = self.array(
|
||||
[len(self.num23seq), len(self.num23seq[0])], intent.in_, obj)
|
||||
if t.elsize == self.type.elsize:
|
||||
assert a.has_shared_memory()
|
||||
else:
|
||||
assert not a.has_shared_memory()
|
||||
|
||||
def test_c_in_from_23casttype(self):
|
||||
for t in self.type.cast_types():
|
||||
obj = np.array(self.num23seq, dtype=t.dtype)
|
||||
a = self.array(
|
||||
[len(self.num23seq), len(self.num23seq[0])], intent.in_.c, obj)
|
||||
if t.elsize == self.type.elsize:
|
||||
assert a.has_shared_memory()
|
||||
else:
|
||||
assert not a.has_shared_memory()
|
||||
|
||||
def test_f_copy_in_from_23casttype(self):
|
||||
for t in self.type.cast_types():
|
||||
obj = np.array(self.num23seq, dtype=t.dtype, order="F")
|
||||
a = self.array(
|
||||
[len(self.num23seq), len(self.num23seq[0])], intent.in_.copy,
|
||||
obj)
|
||||
assert not a.has_shared_memory()
|
||||
|
||||
def test_c_copy_in_from_23casttype(self):
|
||||
for t in self.type.cast_types():
|
||||
obj = np.array(self.num23seq, dtype=t.dtype)
|
||||
a = self.array(
|
||||
[len(self.num23seq), len(self.num23seq[0])], intent.in_.c.copy,
|
||||
obj)
|
||||
assert not a.has_shared_memory()
|
||||
|
||||
def test_in_cache_from_2casttype(self):
|
||||
for t in self.type.all_types():
|
||||
if t.elsize != self.type.elsize:
|
||||
continue
|
||||
obj = np.array(self.num2seq, dtype=t.dtype)
|
||||
shape = (len(self.num2seq), )
|
||||
a = self.array(shape, intent.in_.c.cache, obj)
|
||||
assert a.has_shared_memory()
|
||||
|
||||
a = self.array(shape, intent.in_.cache, obj)
|
||||
assert a.has_shared_memory()
|
||||
|
||||
obj = np.array(self.num2seq, dtype=t.dtype, order="F")
|
||||
a = self.array(shape, intent.in_.c.cache, obj)
|
||||
assert a.has_shared_memory()
|
||||
|
||||
a = self.array(shape, intent.in_.cache, obj)
|
||||
assert a.has_shared_memory(), repr(t.dtype)
|
||||
|
||||
try:
|
||||
a = self.array(shape, intent.in_.cache, obj[::-1])
|
||||
except ValueError as msg:
|
||||
if not str(msg).startswith(
|
||||
"failed to initialize intent(cache) array"):
|
||||
raise
|
||||
else:
|
||||
raise SystemError(
|
||||
"intent(cache) should have failed on multisegmented array")
|
||||
|
||||
def test_in_cache_from_2casttype_failure(self):
|
||||
for t in self.type.all_types():
|
||||
if t.NAME == 'STRING':
|
||||
# string elsize is 0, so skipping the test
|
||||
continue
|
||||
if t.elsize >= self.type.elsize:
|
||||
continue
|
||||
obj = np.array(self.num2seq, dtype=t.dtype)
|
||||
shape = (len(self.num2seq), )
|
||||
try:
|
||||
self.array(shape, intent.in_.cache, obj) # Should succeed
|
||||
except ValueError as msg:
|
||||
if not str(msg).startswith(
|
||||
"failed to initialize intent(cache) array"):
|
||||
raise
|
||||
else:
|
||||
raise SystemError(
|
||||
"intent(cache) should have failed on smaller array")
|
||||
|
||||
def test_cache_hidden(self):
|
||||
shape = (2, )
|
||||
a = self.array(shape, intent.cache.hide, None)
|
||||
assert a.arr.shape == shape
|
||||
|
||||
shape = (2, 3)
|
||||
a = self.array(shape, intent.cache.hide, None)
|
||||
assert a.arr.shape == shape
|
||||
|
||||
shape = (-1, 3)
|
||||
try:
|
||||
a = self.array(shape, intent.cache.hide, None)
|
||||
except ValueError as msg:
|
||||
if not str(msg).startswith(
|
||||
"failed to create intent(cache|hide)|optional array"):
|
||||
raise
|
||||
else:
|
||||
raise SystemError(
|
||||
"intent(cache) should have failed on undefined dimensions")
|
||||
|
||||
def test_hidden(self):
|
||||
shape = (2, )
|
||||
a = self.array(shape, intent.hide, None)
|
||||
assert a.arr.shape == shape
|
||||
assert a.arr_equal(a.arr, np.zeros(shape, dtype=self.type.dtype))
|
||||
|
||||
shape = (2, 3)
|
||||
a = self.array(shape, intent.hide, None)
|
||||
assert a.arr.shape == shape
|
||||
assert a.arr_equal(a.arr, np.zeros(shape, dtype=self.type.dtype))
|
||||
assert a.arr.flags["FORTRAN"] and not a.arr.flags["CONTIGUOUS"]
|
||||
|
||||
shape = (2, 3)
|
||||
a = self.array(shape, intent.c.hide, None)
|
||||
assert a.arr.shape == shape
|
||||
assert a.arr_equal(a.arr, np.zeros(shape, dtype=self.type.dtype))
|
||||
assert not a.arr.flags["FORTRAN"] and a.arr.flags["CONTIGUOUS"]
|
||||
|
||||
shape = (-1, 3)
|
||||
try:
|
||||
a = self.array(shape, intent.hide, None)
|
||||
except ValueError as msg:
|
||||
if not str(msg).startswith(
|
||||
"failed to create intent(cache|hide)|optional array"):
|
||||
raise
|
||||
else:
|
||||
raise SystemError(
|
||||
"intent(hide) should have failed on undefined dimensions")
|
||||
|
||||
def test_optional_none(self):
|
||||
shape = (2, )
|
||||
a = self.array(shape, intent.optional, None)
|
||||
assert a.arr.shape == shape
|
||||
assert a.arr_equal(a.arr, np.zeros(shape, dtype=self.type.dtype))
|
||||
|
||||
shape = (2, 3)
|
||||
a = self.array(shape, intent.optional, None)
|
||||
assert a.arr.shape == shape
|
||||
assert a.arr_equal(a.arr, np.zeros(shape, dtype=self.type.dtype))
|
||||
assert a.arr.flags["FORTRAN"] and not a.arr.flags["CONTIGUOUS"]
|
||||
|
||||
shape = (2, 3)
|
||||
a = self.array(shape, intent.c.optional, None)
|
||||
assert a.arr.shape == shape
|
||||
assert a.arr_equal(a.arr, np.zeros(shape, dtype=self.type.dtype))
|
||||
assert not a.arr.flags["FORTRAN"] and a.arr.flags["CONTIGUOUS"]
|
||||
|
||||
def test_optional_from_2seq(self):
|
||||
obj = self.num2seq
|
||||
shape = (len(obj), )
|
||||
a = self.array(shape, intent.optional, obj)
|
||||
assert a.arr.shape == shape
|
||||
assert not a.has_shared_memory()
|
||||
|
||||
def test_optional_from_23seq(self):
|
||||
obj = self.num23seq
|
||||
shape = (len(obj), len(obj[0]))
|
||||
a = self.array(shape, intent.optional, obj)
|
||||
assert a.arr.shape == shape
|
||||
assert not a.has_shared_memory()
|
||||
|
||||
a = self.array(shape, intent.optional.c, obj)
|
||||
assert a.arr.shape == shape
|
||||
assert not a.has_shared_memory()
|
||||
|
||||
def test_inplace(self):
|
||||
obj = np.array(self.num23seq, dtype=self.type.dtype)
|
||||
assert not obj.flags["FORTRAN"] and obj.flags["CONTIGUOUS"]
|
||||
shape = obj.shape
|
||||
a = self.array(shape, intent.inplace, obj)
|
||||
assert obj[1][2] == a.arr[1][2], repr((obj, a.arr))
|
||||
a.arr[1][2] = 54
|
||||
assert obj[1][2] == a.arr[1][2] == np.array(54, dtype=self.type.dtype)
|
||||
assert a.arr is obj
|
||||
assert obj.flags["FORTRAN"] # obj attributes are changed inplace!
|
||||
assert not obj.flags["CONTIGUOUS"]
|
||||
|
||||
def test_inplace_from_casttype(self):
|
||||
for t in self.type.cast_types():
|
||||
if t is self.type:
|
||||
continue
|
||||
obj = np.array(self.num23seq, dtype=t.dtype)
|
||||
assert obj.dtype.type == t.type
|
||||
assert obj.dtype.type is not self.type.type
|
||||
assert not obj.flags["FORTRAN"] and obj.flags["CONTIGUOUS"]
|
||||
shape = obj.shape
|
||||
a = self.array(shape, intent.inplace, obj)
|
||||
assert obj[1][2] == a.arr[1][2], repr((obj, a.arr))
|
||||
a.arr[1][2] = 54
|
||||
assert obj[1][2] == a.arr[1][2] == np.array(54,
|
||||
dtype=self.type.dtype)
|
||||
assert a.arr is obj
|
||||
assert obj.flags["FORTRAN"] # obj attributes changed inplace!
|
||||
assert not obj.flags["CONTIGUOUS"]
|
||||
assert obj.dtype.type is self.type.type # obj changed inplace!
|
@@ -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,17 @@
|
||||
import sys
|
||||
import pytest
|
||||
from . import util
|
||||
|
||||
from numpy.testing import IS_PYPY
|
||||
|
||||
|
||||
class TestBlockDocString(util.F2PyTest):
|
||||
sources = [util.getpath("tests", "src", "block_docstring", "foo.f")]
|
||||
|
||||
@pytest.mark.skipif(sys.platform == "win32",
|
||||
reason="Fails with MinGW64 Gfortran (Issue #9673)")
|
||||
@pytest.mark.xfail(IS_PYPY,
|
||||
reason="PyPy cannot modify tp_doc after PyType_Ready")
|
||||
def test_block_docstring(self):
|
||||
expected = "bar : 'i'-array(2,3)\n"
|
||||
assert self.module.block.__doc__ == expected
|
@@ -0,0 +1,230 @@
|
||||
import math
|
||||
import textwrap
|
||||
import sys
|
||||
import pytest
|
||||
import threading
|
||||
import traceback
|
||||
import time
|
||||
|
||||
import numpy as np
|
||||
from numpy.testing import IS_PYPY
|
||||
from . import util
|
||||
|
||||
|
||||
class TestF77Callback(util.F2PyTest):
|
||||
sources = [util.getpath("tests", "src", "callback", "foo.f")]
|
||||
|
||||
@pytest.mark.parametrize("name", "t,t2".split(","))
|
||||
def test_all(self, name):
|
||||
self.check_function(name)
|
||||
|
||||
@pytest.mark.xfail(IS_PYPY,
|
||||
reason="PyPy cannot modify tp_doc after PyType_Ready")
|
||||
def test_docstring(self):
|
||||
expected = textwrap.dedent("""\
|
||||
a = t(fun,[fun_extra_args])
|
||||
|
||||
Wrapper for ``t``.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
fun : call-back function
|
||||
|
||||
Other Parameters
|
||||
----------------
|
||||
fun_extra_args : input tuple, optional
|
||||
Default: ()
|
||||
|
||||
Returns
|
||||
-------
|
||||
a : int
|
||||
|
||||
Notes
|
||||
-----
|
||||
Call-back functions::
|
||||
|
||||
def fun(): return a
|
||||
Return objects:
|
||||
a : int
|
||||
""")
|
||||
assert self.module.t.__doc__ == expected
|
||||
|
||||
def check_function(self, name):
|
||||
t = getattr(self.module, name)
|
||||
r = t(lambda: 4)
|
||||
assert r == 4
|
||||
r = t(lambda a: 5, fun_extra_args=(6, ))
|
||||
assert r == 5
|
||||
r = t(lambda a: a, fun_extra_args=(6, ))
|
||||
assert r == 6
|
||||
r = t(lambda a: 5 + a, fun_extra_args=(7, ))
|
||||
assert r == 12
|
||||
r = t(lambda a: math.degrees(a), fun_extra_args=(math.pi, ))
|
||||
assert r == 180
|
||||
r = t(math.degrees, fun_extra_args=(math.pi, ))
|
||||
assert r == 180
|
||||
|
||||
r = t(self.module.func, fun_extra_args=(6, ))
|
||||
assert r == 17
|
||||
r = t(self.module.func0)
|
||||
assert r == 11
|
||||
r = t(self.module.func0._cpointer)
|
||||
assert r == 11
|
||||
|
||||
class A:
|
||||
def __call__(self):
|
||||
return 7
|
||||
|
||||
def mth(self):
|
||||
return 9
|
||||
|
||||
a = A()
|
||||
r = t(a)
|
||||
assert r == 7
|
||||
r = t(a.mth)
|
||||
assert r == 9
|
||||
|
||||
@pytest.mark.skipif(sys.platform == 'win32',
|
||||
reason='Fails with MinGW64 Gfortran (Issue #9673)')
|
||||
def test_string_callback(self):
|
||||
def callback(code):
|
||||
if code == "r":
|
||||
return 0
|
||||
else:
|
||||
return 1
|
||||
|
||||
f = getattr(self.module, "string_callback")
|
||||
r = f(callback)
|
||||
assert r == 0
|
||||
|
||||
@pytest.mark.skipif(sys.platform == 'win32',
|
||||
reason='Fails with MinGW64 Gfortran (Issue #9673)')
|
||||
def test_string_callback_array(self):
|
||||
# See gh-10027
|
||||
cu1 = np.zeros((1, ), "S8")
|
||||
cu2 = np.zeros((1, 8), "c")
|
||||
cu3 = np.array([""], "S8")
|
||||
|
||||
def callback(cu, lencu):
|
||||
if cu.shape != (lencu,):
|
||||
return 1
|
||||
if cu.dtype != "S8":
|
||||
return 2
|
||||
if not np.all(cu == b""):
|
||||
return 3
|
||||
return 0
|
||||
|
||||
f = getattr(self.module, "string_callback_array")
|
||||
for cu in [cu1, cu2, cu3]:
|
||||
res = f(callback, cu, cu.size)
|
||||
assert res == 0
|
||||
|
||||
def test_threadsafety(self):
|
||||
# Segfaults if the callback handling is not threadsafe
|
||||
|
||||
errors = []
|
||||
|
||||
def cb():
|
||||
# Sleep here to make it more likely for another thread
|
||||
# to call their callback at the same time.
|
||||
time.sleep(1e-3)
|
||||
|
||||
# Check reentrancy
|
||||
r = self.module.t(lambda: 123)
|
||||
assert r == 123
|
||||
|
||||
return 42
|
||||
|
||||
def runner(name):
|
||||
try:
|
||||
for j in range(50):
|
||||
r = self.module.t(cb)
|
||||
assert r == 42
|
||||
self.check_function(name)
|
||||
except Exception:
|
||||
errors.append(traceback.format_exc())
|
||||
|
||||
threads = [
|
||||
threading.Thread(target=runner, args=(arg, ))
|
||||
for arg in ("t", "t2") for n in range(20)
|
||||
]
|
||||
|
||||
for t in threads:
|
||||
t.start()
|
||||
|
||||
for t in threads:
|
||||
t.join()
|
||||
|
||||
errors = "\n\n".join(errors)
|
||||
if errors:
|
||||
raise AssertionError(errors)
|
||||
|
||||
def test_hidden_callback(self):
|
||||
try:
|
||||
self.module.hidden_callback(2)
|
||||
except Exception as msg:
|
||||
assert str(msg).startswith("Callback global_f not defined")
|
||||
|
||||
try:
|
||||
self.module.hidden_callback2(2)
|
||||
except Exception as msg:
|
||||
assert str(msg).startswith("cb: Callback global_f not defined")
|
||||
|
||||
self.module.global_f = lambda x: x + 1
|
||||
r = self.module.hidden_callback(2)
|
||||
assert r == 3
|
||||
|
||||
self.module.global_f = lambda x: x + 2
|
||||
r = self.module.hidden_callback(2)
|
||||
assert r == 4
|
||||
|
||||
del self.module.global_f
|
||||
try:
|
||||
self.module.hidden_callback(2)
|
||||
except Exception as msg:
|
||||
assert str(msg).startswith("Callback global_f not defined")
|
||||
|
||||
self.module.global_f = lambda x=0: x + 3
|
||||
r = self.module.hidden_callback(2)
|
||||
assert r == 5
|
||||
|
||||
# reproducer of gh18341
|
||||
r = self.module.hidden_callback2(2)
|
||||
assert r == 3
|
||||
|
||||
|
||||
class TestF77CallbackPythonTLS(TestF77Callback):
|
||||
"""
|
||||
Callback tests using Python thread-local storage instead of
|
||||
compiler-provided
|
||||
"""
|
||||
|
||||
options = ["-DF2PY_USE_PYTHON_TLS"]
|
||||
|
||||
|
||||
class TestF90Callback(util.F2PyTest):
|
||||
sources = [util.getpath("tests", "src", "callback", "gh17797.f90")]
|
||||
|
||||
def test_gh17797(self):
|
||||
def incr(x):
|
||||
return x + 123
|
||||
|
||||
y = np.array([1, 2, 3], dtype=np.int64)
|
||||
r = self.module.gh17797(incr, y)
|
||||
assert r == 123 + 1 + 2 + 3
|
||||
|
||||
|
||||
class TestGH18335(util.F2PyTest):
|
||||
"""The reproduction of the reported issue requires specific input that
|
||||
extensions may break the issue conditions, so the reproducer is
|
||||
implemented as a separate test class. Do not extend this test with
|
||||
other tests!
|
||||
"""
|
||||
sources = [util.getpath("tests", "src", "callback", "gh18335.f90")]
|
||||
|
||||
def test_gh18335(self):
|
||||
def foo(x):
|
||||
x[0] += 1
|
||||
|
||||
r = self.module.gh18335(foo)
|
||||
assert r == 123 + 1
|
@@ -0,0 +1,593 @@
|
||||
import pytest
|
||||
import textwrap
|
||||
from numpy.testing import assert_array_equal, assert_equal, assert_raises
|
||||
import numpy as np
|
||||
from numpy.f2py.tests import util
|
||||
|
||||
|
||||
class TestCharacterString(util.F2PyTest):
|
||||
# options = ['--debug-capi', '--build-dir', '/tmp/test-build-f2py']
|
||||
suffix = '.f90'
|
||||
fprefix = 'test_character_string'
|
||||
length_list = ['1', '3', 'star']
|
||||
|
||||
code = ''
|
||||
for length in length_list:
|
||||
fsuffix = length
|
||||
clength = dict(star='(*)').get(length, length)
|
||||
|
||||
code += textwrap.dedent(f"""
|
||||
|
||||
subroutine {fprefix}_input_{fsuffix}(c, o, n)
|
||||
character*{clength}, intent(in) :: c
|
||||
integer n
|
||||
!f2py integer, depend(c), intent(hide) :: n = slen(c)
|
||||
integer*1, dimension(n) :: o
|
||||
!f2py intent(out) o
|
||||
o = transfer(c, o)
|
||||
end subroutine {fprefix}_input_{fsuffix}
|
||||
|
||||
subroutine {fprefix}_output_{fsuffix}(c, o, n)
|
||||
character*{clength}, intent(out) :: c
|
||||
integer n
|
||||
integer*1, dimension(n), intent(in) :: o
|
||||
!f2py integer, depend(o), intent(hide) :: n = len(o)
|
||||
c = transfer(o, c)
|
||||
end subroutine {fprefix}_output_{fsuffix}
|
||||
|
||||
subroutine {fprefix}_array_input_{fsuffix}(c, o, m, n)
|
||||
integer m, i, n
|
||||
character*{clength}, intent(in), dimension(m) :: c
|
||||
!f2py integer, depend(c), intent(hide) :: m = len(c)
|
||||
!f2py integer, depend(c), intent(hide) :: n = f2py_itemsize(c)
|
||||
integer*1, dimension(m, n), intent(out) :: o
|
||||
do i=1,m
|
||||
o(i, :) = transfer(c(i), o(i, :))
|
||||
end do
|
||||
end subroutine {fprefix}_array_input_{fsuffix}
|
||||
|
||||
subroutine {fprefix}_array_output_{fsuffix}(c, o, m, n)
|
||||
character*{clength}, intent(out), dimension(m) :: c
|
||||
integer n
|
||||
integer*1, dimension(m, n), intent(in) :: o
|
||||
!f2py character(f2py_len=n) :: c
|
||||
!f2py integer, depend(o), intent(hide) :: m = len(o)
|
||||
!f2py integer, depend(o), intent(hide) :: n = shape(o, 1)
|
||||
do i=1,m
|
||||
c(i) = transfer(o(i, :), c(i))
|
||||
end do
|
||||
end subroutine {fprefix}_array_output_{fsuffix}
|
||||
|
||||
subroutine {fprefix}_2d_array_input_{fsuffix}(c, o, m1, m2, n)
|
||||
integer m1, m2, i, j, n
|
||||
character*{clength}, intent(in), dimension(m1, m2) :: c
|
||||
!f2py integer, depend(c), intent(hide) :: m1 = len(c)
|
||||
!f2py integer, depend(c), intent(hide) :: m2 = shape(c, 1)
|
||||
!f2py integer, depend(c), intent(hide) :: n = f2py_itemsize(c)
|
||||
integer*1, dimension(m1, m2, n), intent(out) :: o
|
||||
do i=1,m1
|
||||
do j=1,m2
|
||||
o(i, j, :) = transfer(c(i, j), o(i, j, :))
|
||||
end do
|
||||
end do
|
||||
end subroutine {fprefix}_2d_array_input_{fsuffix}
|
||||
""")
|
||||
|
||||
@pytest.mark.parametrize("length", length_list)
|
||||
def test_input(self, length):
|
||||
fsuffix = {'(*)': 'star'}.get(length, length)
|
||||
f = getattr(self.module, self.fprefix + '_input_' + fsuffix)
|
||||
|
||||
a = {'1': 'a', '3': 'abc', 'star': 'abcde' * 3}[length]
|
||||
|
||||
assert_array_equal(f(a), np.array(list(map(ord, a)), dtype='u1'))
|
||||
|
||||
@pytest.mark.parametrize("length", length_list[:-1])
|
||||
def test_output(self, length):
|
||||
fsuffix = length
|
||||
f = getattr(self.module, self.fprefix + '_output_' + fsuffix)
|
||||
|
||||
a = {'1': 'a', '3': 'abc'}[length]
|
||||
|
||||
assert_array_equal(f(np.array(list(map(ord, a)), dtype='u1')),
|
||||
a.encode())
|
||||
|
||||
@pytest.mark.parametrize("length", length_list)
|
||||
def test_array_input(self, length):
|
||||
fsuffix = length
|
||||
f = getattr(self.module, self.fprefix + '_array_input_' + fsuffix)
|
||||
|
||||
a = np.array([{'1': 'a', '3': 'abc', 'star': 'abcde' * 3}[length],
|
||||
{'1': 'A', '3': 'ABC', 'star': 'ABCDE' * 3}[length],
|
||||
], dtype='S')
|
||||
|
||||
expected = np.array([[c for c in s] for s in a], dtype='u1')
|
||||
assert_array_equal(f(a), expected)
|
||||
|
||||
@pytest.mark.parametrize("length", length_list)
|
||||
def test_array_output(self, length):
|
||||
fsuffix = length
|
||||
f = getattr(self.module, self.fprefix + '_array_output_' + fsuffix)
|
||||
|
||||
expected = np.array(
|
||||
[{'1': 'a', '3': 'abc', 'star': 'abcde' * 3}[length],
|
||||
{'1': 'A', '3': 'ABC', 'star': 'ABCDE' * 3}[length]], dtype='S')
|
||||
|
||||
a = np.array([[c for c in s] for s in expected], dtype='u1')
|
||||
assert_array_equal(f(a), expected)
|
||||
|
||||
@pytest.mark.parametrize("length", length_list)
|
||||
def test_2d_array_input(self, length):
|
||||
fsuffix = length
|
||||
f = getattr(self.module, self.fprefix + '_2d_array_input_' + fsuffix)
|
||||
|
||||
a = np.array([[{'1': 'a', '3': 'abc', 'star': 'abcde' * 3}[length],
|
||||
{'1': 'A', '3': 'ABC', 'star': 'ABCDE' * 3}[length]],
|
||||
[{'1': 'f', '3': 'fgh', 'star': 'fghij' * 3}[length],
|
||||
{'1': 'F', '3': 'FGH', 'star': 'FGHIJ' * 3}[length]]],
|
||||
dtype='S')
|
||||
expected = np.array([[[c for c in item] for item in row] for row in a],
|
||||
dtype='u1', order='F')
|
||||
assert_array_equal(f(a), expected)
|
||||
|
||||
|
||||
class TestCharacter(util.F2PyTest):
|
||||
# options = ['--debug-capi', '--build-dir', '/tmp/test-build-f2py']
|
||||
suffix = '.f90'
|
||||
fprefix = 'test_character'
|
||||
|
||||
code = textwrap.dedent(f"""
|
||||
subroutine {fprefix}_input(c, o)
|
||||
character, intent(in) :: c
|
||||
integer*1 o
|
||||
!f2py intent(out) o
|
||||
o = transfer(c, o)
|
||||
end subroutine {fprefix}_input
|
||||
|
||||
subroutine {fprefix}_output(c, o)
|
||||
character :: c
|
||||
integer*1, intent(in) :: o
|
||||
!f2py intent(out) c
|
||||
c = transfer(o, c)
|
||||
end subroutine {fprefix}_output
|
||||
|
||||
subroutine {fprefix}_input_output(c, o)
|
||||
character, intent(in) :: c
|
||||
character o
|
||||
!f2py intent(out) o
|
||||
o = c
|
||||
end subroutine {fprefix}_input_output
|
||||
|
||||
subroutine {fprefix}_inout(c, n)
|
||||
character :: c, n
|
||||
!f2py intent(in) n
|
||||
!f2py intent(inout) c
|
||||
c = n
|
||||
end subroutine {fprefix}_inout
|
||||
|
||||
function {fprefix}_return(o) result (c)
|
||||
character :: c
|
||||
character, intent(in) :: o
|
||||
c = transfer(o, c)
|
||||
end function {fprefix}_return
|
||||
|
||||
subroutine {fprefix}_array_input(c, o)
|
||||
character, intent(in) :: c(3)
|
||||
integer*1 o(3)
|
||||
!f2py intent(out) o
|
||||
integer i
|
||||
do i=1,3
|
||||
o(i) = transfer(c(i), o(i))
|
||||
end do
|
||||
end subroutine {fprefix}_array_input
|
||||
|
||||
subroutine {fprefix}_2d_array_input(c, o)
|
||||
character, intent(in) :: c(2, 3)
|
||||
integer*1 o(2, 3)
|
||||
!f2py intent(out) o
|
||||
integer i, j
|
||||
do i=1,2
|
||||
do j=1,3
|
||||
o(i, j) = transfer(c(i, j), o(i, j))
|
||||
end do
|
||||
end do
|
||||
end subroutine {fprefix}_2d_array_input
|
||||
|
||||
subroutine {fprefix}_array_output(c, o)
|
||||
character :: c(3)
|
||||
integer*1, intent(in) :: o(3)
|
||||
!f2py intent(out) c
|
||||
do i=1,3
|
||||
c(i) = transfer(o(i), c(i))
|
||||
end do
|
||||
end subroutine {fprefix}_array_output
|
||||
|
||||
subroutine {fprefix}_array_inout(c, n)
|
||||
character :: c(3), n(3)
|
||||
!f2py intent(in) n(3)
|
||||
!f2py intent(inout) c(3)
|
||||
do i=1,3
|
||||
c(i) = n(i)
|
||||
end do
|
||||
end subroutine {fprefix}_array_inout
|
||||
|
||||
subroutine {fprefix}_2d_array_inout(c, n)
|
||||
character :: c(2, 3), n(2, 3)
|
||||
!f2py intent(in) n(2, 3)
|
||||
!f2py intent(inout) c(2. 3)
|
||||
integer i, j
|
||||
do i=1,2
|
||||
do j=1,3
|
||||
c(i, j) = n(i, j)
|
||||
end do
|
||||
end do
|
||||
end subroutine {fprefix}_2d_array_inout
|
||||
|
||||
function {fprefix}_array_return(o) result (c)
|
||||
character, dimension(3) :: c
|
||||
character, intent(in) :: o(3)
|
||||
do i=1,3
|
||||
c(i) = o(i)
|
||||
end do
|
||||
end function {fprefix}_array_return
|
||||
|
||||
function {fprefix}_optional(o) result (c)
|
||||
character, intent(in) :: o
|
||||
!f2py character o = "a"
|
||||
character :: c
|
||||
c = o
|
||||
end function {fprefix}_optional
|
||||
""")
|
||||
|
||||
@pytest.mark.parametrize("dtype", ['c', 'S1'])
|
||||
def test_input(self, dtype):
|
||||
f = getattr(self.module, self.fprefix + '_input')
|
||||
|
||||
assert_equal(f(np.array('a', dtype=dtype)), ord('a'))
|
||||
assert_equal(f(np.array(b'a', dtype=dtype)), ord('a'))
|
||||
assert_equal(f(np.array(['a'], dtype=dtype)), ord('a'))
|
||||
assert_equal(f(np.array('abc', dtype=dtype)), ord('a'))
|
||||
assert_equal(f(np.array([['a']], dtype=dtype)), ord('a'))
|
||||
|
||||
def test_input_varia(self):
|
||||
f = getattr(self.module, self.fprefix + '_input')
|
||||
|
||||
assert_equal(f('a'), ord('a'))
|
||||
assert_equal(f(b'a'), ord(b'a'))
|
||||
assert_equal(f(''), 0)
|
||||
assert_equal(f(b''), 0)
|
||||
assert_equal(f(b'\0'), 0)
|
||||
assert_equal(f('ab'), ord('a'))
|
||||
assert_equal(f(b'ab'), ord('a'))
|
||||
assert_equal(f(['a']), ord('a'))
|
||||
|
||||
assert_equal(f(np.array(b'a')), ord('a'))
|
||||
assert_equal(f(np.array([b'a'])), ord('a'))
|
||||
a = np.array('a')
|
||||
assert_equal(f(a), ord('a'))
|
||||
a = np.array(['a'])
|
||||
assert_equal(f(a), ord('a'))
|
||||
|
||||
try:
|
||||
f([])
|
||||
except IndexError as msg:
|
||||
if not str(msg).endswith(' got 0-list'):
|
||||
raise
|
||||
else:
|
||||
raise SystemError(f'{f.__name__} should have failed on empty list')
|
||||
|
||||
try:
|
||||
f(97)
|
||||
except TypeError as msg:
|
||||
if not str(msg).endswith(' got int instance'):
|
||||
raise
|
||||
else:
|
||||
raise SystemError(f'{f.__name__} should have failed on int value')
|
||||
|
||||
@pytest.mark.parametrize("dtype", ['c', 'S1', 'U1'])
|
||||
def test_array_input(self, dtype):
|
||||
f = getattr(self.module, self.fprefix + '_array_input')
|
||||
|
||||
assert_array_equal(f(np.array(['a', 'b', 'c'], dtype=dtype)),
|
||||
np.array(list(map(ord, 'abc')), dtype='i1'))
|
||||
assert_array_equal(f(np.array([b'a', b'b', b'c'], dtype=dtype)),
|
||||
np.array(list(map(ord, 'abc')), dtype='i1'))
|
||||
|
||||
def test_array_input_varia(self):
|
||||
f = getattr(self.module, self.fprefix + '_array_input')
|
||||
assert_array_equal(f(['a', 'b', 'c']),
|
||||
np.array(list(map(ord, 'abc')), dtype='i1'))
|
||||
assert_array_equal(f([b'a', b'b', b'c']),
|
||||
np.array(list(map(ord, 'abc')), dtype='i1'))
|
||||
|
||||
try:
|
||||
f(['a', 'b', 'c', 'd'])
|
||||
except ValueError as msg:
|
||||
if not str(msg).endswith(
|
||||
'th dimension must be fixed to 3 but got 4'):
|
||||
raise
|
||||
else:
|
||||
raise SystemError(
|
||||
f'{f.__name__} should have failed on wrong input')
|
||||
|
||||
@pytest.mark.parametrize("dtype", ['c', 'S1', 'U1'])
|
||||
def test_2d_array_input(self, dtype):
|
||||
f = getattr(self.module, self.fprefix + '_2d_array_input')
|
||||
|
||||
a = np.array([['a', 'b', 'c'],
|
||||
['d', 'e', 'f']], dtype=dtype, order='F')
|
||||
expected = a.view(np.uint32 if dtype == 'U1' else np.uint8)
|
||||
assert_array_equal(f(a), expected)
|
||||
|
||||
def test_output(self):
|
||||
f = getattr(self.module, self.fprefix + '_output')
|
||||
|
||||
assert_equal(f(ord(b'a')), b'a')
|
||||
assert_equal(f(0), b'\0')
|
||||
|
||||
def test_array_output(self):
|
||||
f = getattr(self.module, self.fprefix + '_array_output')
|
||||
|
||||
assert_array_equal(f(list(map(ord, 'abc'))),
|
||||
np.array(list('abc'), dtype='S1'))
|
||||
|
||||
def test_input_output(self):
|
||||
f = getattr(self.module, self.fprefix + '_input_output')
|
||||
|
||||
assert_equal(f(b'a'), b'a')
|
||||
assert_equal(f('a'), b'a')
|
||||
assert_equal(f(''), b'\0')
|
||||
|
||||
@pytest.mark.parametrize("dtype", ['c', 'S1'])
|
||||
def test_inout(self, dtype):
|
||||
f = getattr(self.module, self.fprefix + '_inout')
|
||||
|
||||
a = np.array(list('abc'), dtype=dtype)
|
||||
f(a, 'A')
|
||||
assert_array_equal(a, np.array(list('Abc'), dtype=a.dtype))
|
||||
f(a[1:], 'B')
|
||||
assert_array_equal(a, np.array(list('ABc'), dtype=a.dtype))
|
||||
|
||||
a = np.array(['abc'], dtype=dtype)
|
||||
f(a, 'A')
|
||||
assert_array_equal(a, np.array(['Abc'], dtype=a.dtype))
|
||||
|
||||
def test_inout_varia(self):
|
||||
f = getattr(self.module, self.fprefix + '_inout')
|
||||
a = np.array('abc', dtype='S3')
|
||||
f(a, 'A')
|
||||
assert_array_equal(a, np.array('Abc', dtype=a.dtype))
|
||||
|
||||
a = np.array(['abc'], dtype='S3')
|
||||
f(a, 'A')
|
||||
assert_array_equal(a, np.array(['Abc'], dtype=a.dtype))
|
||||
|
||||
try:
|
||||
f('abc', 'A')
|
||||
except ValueError as msg:
|
||||
if not str(msg).endswith(' got 3-str'):
|
||||
raise
|
||||
else:
|
||||
raise SystemError(f'{f.__name__} should have failed on str value')
|
||||
|
||||
@pytest.mark.parametrize("dtype", ['c', 'S1'])
|
||||
def test_array_inout(self, dtype):
|
||||
f = getattr(self.module, self.fprefix + '_array_inout')
|
||||
n = np.array(['A', 'B', 'C'], dtype=dtype, order='F')
|
||||
|
||||
a = np.array(['a', 'b', 'c'], dtype=dtype, order='F')
|
||||
f(a, n)
|
||||
assert_array_equal(a, n)
|
||||
|
||||
a = np.array(['a', 'b', 'c', 'd'], dtype=dtype)
|
||||
f(a[1:], n)
|
||||
assert_array_equal(a, np.array(['a', 'A', 'B', 'C'], dtype=dtype))
|
||||
|
||||
a = np.array([['a', 'b', 'c']], dtype=dtype, order='F')
|
||||
f(a, n)
|
||||
assert_array_equal(a, np.array([['A', 'B', 'C']], dtype=dtype))
|
||||
|
||||
a = np.array(['a', 'b', 'c', 'd'], dtype=dtype, order='F')
|
||||
try:
|
||||
f(a, n)
|
||||
except ValueError as msg:
|
||||
if not str(msg).endswith(
|
||||
'th dimension must be fixed to 3 but got 4'):
|
||||
raise
|
||||
else:
|
||||
raise SystemError(
|
||||
f'{f.__name__} should have failed on wrong input')
|
||||
|
||||
@pytest.mark.parametrize("dtype", ['c', 'S1'])
|
||||
def test_2d_array_inout(self, dtype):
|
||||
f = getattr(self.module, self.fprefix + '_2d_array_inout')
|
||||
n = np.array([['A', 'B', 'C'],
|
||||
['D', 'E', 'F']],
|
||||
dtype=dtype, order='F')
|
||||
a = np.array([['a', 'b', 'c'],
|
||||
['d', 'e', 'f']],
|
||||
dtype=dtype, order='F')
|
||||
f(a, n)
|
||||
assert_array_equal(a, n)
|
||||
|
||||
def test_return(self):
|
||||
f = getattr(self.module, self.fprefix + '_return')
|
||||
|
||||
assert_equal(f('a'), b'a')
|
||||
|
||||
@pytest.mark.skip('fortran function returning array segfaults')
|
||||
def test_array_return(self):
|
||||
f = getattr(self.module, self.fprefix + '_array_return')
|
||||
|
||||
a = np.array(list('abc'), dtype='S1')
|
||||
assert_array_equal(f(a), a)
|
||||
|
||||
def test_optional(self):
|
||||
f = getattr(self.module, self.fprefix + '_optional')
|
||||
|
||||
assert_equal(f(), b"a")
|
||||
assert_equal(f(b'B'), b"B")
|
||||
|
||||
|
||||
class TestMiscCharacter(util.F2PyTest):
|
||||
# options = ['--debug-capi', '--build-dir', '/tmp/test-build-f2py']
|
||||
suffix = '.f90'
|
||||
fprefix = 'test_misc_character'
|
||||
|
||||
code = textwrap.dedent(f"""
|
||||
subroutine {fprefix}_gh18684(x, y, m)
|
||||
character(len=5), dimension(m), intent(in) :: x
|
||||
character*5, dimension(m), intent(out) :: y
|
||||
integer i, m
|
||||
!f2py integer, intent(hide), depend(x) :: m = f2py_len(x)
|
||||
do i=1,m
|
||||
y(i) = x(i)
|
||||
end do
|
||||
end subroutine {fprefix}_gh18684
|
||||
|
||||
subroutine {fprefix}_gh6308(x, i)
|
||||
integer i
|
||||
!f2py check(i>=0 && i<12) i
|
||||
character*5 name, x
|
||||
common name(12)
|
||||
name(i + 1) = x
|
||||
end subroutine {fprefix}_gh6308
|
||||
|
||||
subroutine {fprefix}_gh4519(x)
|
||||
character(len=*), intent(in) :: x(:)
|
||||
!f2py intent(out) x
|
||||
integer :: i
|
||||
! Uncomment for debug printing:
|
||||
!do i=1, size(x)
|
||||
! print*, "x(",i,")=", x(i)
|
||||
!end do
|
||||
end subroutine {fprefix}_gh4519
|
||||
|
||||
pure function {fprefix}_gh3425(x) result (y)
|
||||
character(len=*), intent(in) :: x
|
||||
character(len=len(x)) :: y
|
||||
integer :: i
|
||||
do i = 1, len(x)
|
||||
j = iachar(x(i:i))
|
||||
if (j>=iachar("a") .and. j<=iachar("z") ) then
|
||||
y(i:i) = achar(j-32)
|
||||
else
|
||||
y(i:i) = x(i:i)
|
||||
endif
|
||||
end do
|
||||
end function {fprefix}_gh3425
|
||||
|
||||
subroutine {fprefix}_character_bc_new(x, y, z)
|
||||
character, intent(in) :: x
|
||||
character, intent(out) :: y
|
||||
!f2py character, depend(x) :: y = x
|
||||
!f2py character, dimension((x=='a'?1:2)), depend(x), intent(out) :: z
|
||||
character, dimension(*) :: z
|
||||
!f2py character, optional, check(x == 'a' || x == 'b') :: x = 'a'
|
||||
!f2py callstatement (*f2py_func)(&x, &y, z)
|
||||
!f2py callprotoargument character*, character*, character*
|
||||
if (y.eq.x) then
|
||||
y = x
|
||||
else
|
||||
y = 'e'
|
||||
endif
|
||||
z(1) = 'c'
|
||||
end subroutine {fprefix}_character_bc_new
|
||||
|
||||
subroutine {fprefix}_character_bc_old(x, y, z)
|
||||
character, intent(in) :: x
|
||||
character, intent(out) :: y
|
||||
!f2py character, depend(x) :: y = x[0]
|
||||
!f2py character, dimension((*x=='a'?1:2)), depend(x), intent(out) :: z
|
||||
character, dimension(*) :: z
|
||||
!f2py character, optional, check(*x == 'a' || x[0] == 'b') :: x = 'a'
|
||||
!f2py callstatement (*f2py_func)(x, y, z)
|
||||
!f2py callprotoargument char*, char*, char*
|
||||
if (y.eq.x) then
|
||||
y = x
|
||||
else
|
||||
y = 'e'
|
||||
endif
|
||||
z(1) = 'c'
|
||||
end subroutine {fprefix}_character_bc_old
|
||||
""")
|
||||
|
||||
def test_gh18684(self):
|
||||
# Test character(len=5) and character*5 usages
|
||||
f = getattr(self.module, self.fprefix + '_gh18684')
|
||||
x = np.array(["abcde", "fghij"], dtype='S5')
|
||||
y = f(x)
|
||||
|
||||
assert_array_equal(x, y)
|
||||
|
||||
def test_gh6308(self):
|
||||
# Test character string array in a common block
|
||||
f = getattr(self.module, self.fprefix + '_gh6308')
|
||||
|
||||
assert_equal(self.module._BLNK_.name.dtype, np.dtype('S5'))
|
||||
assert_equal(len(self.module._BLNK_.name), 12)
|
||||
f("abcde", 0)
|
||||
assert_equal(self.module._BLNK_.name[0], b"abcde")
|
||||
f("12345", 5)
|
||||
assert_equal(self.module._BLNK_.name[5], b"12345")
|
||||
|
||||
def test_gh4519(self):
|
||||
# Test array of assumed length strings
|
||||
f = getattr(self.module, self.fprefix + '_gh4519')
|
||||
|
||||
for x, expected in [
|
||||
('a', dict(shape=(), dtype=np.dtype('S1'))),
|
||||
('text', dict(shape=(), dtype=np.dtype('S4'))),
|
||||
(np.array(['1', '2', '3'], dtype='S1'),
|
||||
dict(shape=(3,), dtype=np.dtype('S1'))),
|
||||
(['1', '2', '34'],
|
||||
dict(shape=(3,), dtype=np.dtype('S2'))),
|
||||
(['', ''], dict(shape=(2,), dtype=np.dtype('S1')))]:
|
||||
r = f(x)
|
||||
for k, v in expected.items():
|
||||
assert_equal(getattr(r, k), v)
|
||||
|
||||
def test_gh3425(self):
|
||||
# Test returning a copy of assumed length string
|
||||
f = getattr(self.module, self.fprefix + '_gh3425')
|
||||
# f is equivalent to bytes.upper
|
||||
|
||||
assert_equal(f('abC'), b'ABC')
|
||||
assert_equal(f(''), b'')
|
||||
assert_equal(f('abC12d'), b'ABC12D')
|
||||
|
||||
@pytest.mark.parametrize("state", ['new', 'old'])
|
||||
def test_character_bc(self, state):
|
||||
f = getattr(self.module, self.fprefix + '_character_bc_' + state)
|
||||
|
||||
c, a = f()
|
||||
assert_equal(c, b'a')
|
||||
assert_equal(len(a), 1)
|
||||
|
||||
c, a = f(b'b')
|
||||
assert_equal(c, b'b')
|
||||
assert_equal(len(a), 2)
|
||||
|
||||
assert_raises(Exception, lambda: f(b'c'))
|
||||
|
||||
|
||||
class TestStringScalarArr(util.F2PyTest):
|
||||
sources = [util.getpath("tests", "src", "string", "scalar_string.f90")]
|
||||
|
||||
@pytest.mark.slow
|
||||
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
|
||||
|
||||
@pytest.mark.slow
|
||||
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
|
@@ -0,0 +1,18 @@
|
||||
import os
|
||||
import sys
|
||||
import pytest
|
||||
|
||||
import numpy as np
|
||||
from . import util
|
||||
|
||||
|
||||
class TestCommonBlock(util.F2PyTest):
|
||||
sources = [util.getpath("tests", "src", "common", "block.f")]
|
||||
|
||||
@pytest.mark.skipif(sys.platform == "win32",
|
||||
reason="Fails with MinGW64 Gfortran (Issue #9673)")
|
||||
def test_common_block(self):
|
||||
self.module.initcb()
|
||||
assert self.module.block.long_bn == np.array(1.0, dtype=np.float64)
|
||||
assert self.module.block.string_bn == np.array("2", dtype="|S1")
|
||||
assert self.module.block.ok == np.array(3, dtype=np.int32)
|
@@ -0,0 +1,117 @@
|
||||
"""See https://github.com/numpy/numpy/pull/11937.
|
||||
|
||||
"""
|
||||
import sys
|
||||
import os
|
||||
import uuid
|
||||
from importlib import import_module
|
||||
import pytest
|
||||
|
||||
import numpy.f2py
|
||||
|
||||
from . import util
|
||||
|
||||
|
||||
def setup_module():
|
||||
if not util.has_c_compiler():
|
||||
pytest.skip("Needs C compiler")
|
||||
if not util.has_f77_compiler():
|
||||
pytest.skip("Needs FORTRAN 77 compiler")
|
||||
|
||||
|
||||
# extra_args can be a list (since gh-11937) or string.
|
||||
# also test absence of extra_args
|
||||
@pytest.mark.parametrize("extra_args",
|
||||
[["--noopt", "--debug"], "--noopt --debug", ""])
|
||||
@pytest.mark.leaks_references(reason="Imported module seems never deleted.")
|
||||
def test_f2py_init_compile(extra_args):
|
||||
# flush through the f2py __init__ compile() function code path as a
|
||||
# crude test for input handling following migration from
|
||||
# exec_command() to subprocess.check_output() in gh-11937
|
||||
|
||||
# the Fortran 77 syntax requires 6 spaces before any commands, but
|
||||
# more space may be added/
|
||||
fsource = """
|
||||
integer function foo()
|
||||
foo = 10 + 5
|
||||
return
|
||||
end
|
||||
"""
|
||||
# use various helper functions in util.py to enable robust build /
|
||||
# compile and reimport cycle in test suite
|
||||
moddir = util.get_module_dir()
|
||||
modname = util.get_temp_module_name()
|
||||
|
||||
cwd = os.getcwd()
|
||||
target = os.path.join(moddir, str(uuid.uuid4()) + ".f")
|
||||
# try running compile() with and without a source_fn provided so
|
||||
# that the code path where a temporary file for writing Fortran
|
||||
# source is created is also explored
|
||||
for source_fn in [target, None]:
|
||||
# mimic the path changing behavior used by build_module() in
|
||||
# util.py, but don't actually use build_module() because it has
|
||||
# its own invocation of subprocess that circumvents the
|
||||
# f2py.compile code block under test
|
||||
with util.switchdir(moddir):
|
||||
ret_val = numpy.f2py.compile(fsource,
|
||||
modulename=modname,
|
||||
extra_args=extra_args,
|
||||
source_fn=source_fn)
|
||||
|
||||
# check for compile success return value
|
||||
assert ret_val == 0
|
||||
|
||||
# we are not currently able to import the Python-Fortran
|
||||
# interface module on Windows / Appveyor, even though we do get
|
||||
# successful compilation on that platform with Python 3.x
|
||||
if sys.platform != "win32":
|
||||
# check for sensible result of Fortran function; that means
|
||||
# we can import the module name in Python and retrieve the
|
||||
# result of the sum operation
|
||||
return_check = import_module(modname)
|
||||
calc_result = return_check.foo()
|
||||
assert calc_result == 15
|
||||
# Removal from sys.modules, is not as such necessary. Even with
|
||||
# removal, the module (dict) stays alive.
|
||||
del sys.modules[modname]
|
||||
|
||||
|
||||
def test_f2py_init_compile_failure():
|
||||
# verify an appropriate integer status value returned by
|
||||
# f2py.compile() when invalid Fortran is provided
|
||||
ret_val = numpy.f2py.compile(b"invalid")
|
||||
assert ret_val == 1
|
||||
|
||||
|
||||
def test_f2py_init_compile_bad_cmd():
|
||||
# verify that usage of invalid command in f2py.compile() returns
|
||||
# status value of 127 for historic consistency with exec_command()
|
||||
# error handling
|
||||
|
||||
# patch the sys Python exe path temporarily to induce an OSError
|
||||
# downstream NOTE: how bad of an idea is this patching?
|
||||
try:
|
||||
temp = sys.executable
|
||||
sys.executable = "does not exist"
|
||||
|
||||
# the OSError should take precedence over invalid Fortran
|
||||
ret_val = numpy.f2py.compile(b"invalid")
|
||||
assert ret_val == 127
|
||||
finally:
|
||||
sys.executable = temp
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"fsource",
|
||||
[
|
||||
"program test_f2py\nend program test_f2py",
|
||||
b"program test_f2py\nend program test_f2py",
|
||||
],
|
||||
)
|
||||
def test_compile_from_strings(tmpdir, fsource):
|
||||
# Make sure we can compile str and bytes gh-12796
|
||||
with util.switchdir(tmpdir):
|
||||
ret_val = numpy.f2py.compile(fsource,
|
||||
modulename="test_compile_from_strings",
|
||||
extension=".f90")
|
||||
assert ret_val == 0
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user