summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPearu Peterson <pearu.peterson@gmail.com>2021-02-09 20:49:18 +0200
committerPearu Peterson <pearu.peterson@gmail.com>2021-02-09 20:49:18 +0200
commit7df963b400f3dcf85e679e6f00af8c3c12971347 (patch)
treec23cf43cae1fab777a6282875f179ed14f5273e1
parentaf44a8198524ab532a0c1b2410b5706768d5a77e (diff)
downloadnumpy-7df963b400f3dcf85e679e6f00af8c3c12971347.tar.gz
BUG: fix regression in a hidden callback use case
-rw-r--r--numpy/f2py/cb_rules.py18
-rw-r--r--numpy/f2py/cfuncs.py4
-rwxr-xr-xnumpy/f2py/rules.py7
-rw-r--r--numpy/f2py/tests/test_callback.py48
-rw-r--r--numpy/f2py/tests/util.py2
5 files changed, 54 insertions, 25 deletions
diff --git a/numpy/f2py/cb_rules.py b/numpy/f2py/cb_rules.py
index a4cb546a3..62aa2fca9 100644
--- a/numpy/f2py/cb_rules.py
+++ b/numpy/f2py/cb_rules.py
@@ -40,21 +40,11 @@ typedef struct {
jmp_buf jmpbuf;
} #name#_t;
-static void show_#name#(#name#_t *ptr) {
- if (ptr != NULL) {
- CFUNCSMESSPY(\"show_#name#: capi=\", ptr->capi);
- CFUNCSMESSPY(\"show_#name#: args_capi=\", ptr->args_capi);
- } else {
- CFUNCSMESS(\"show_#name#: ptr=NULL\\n");
- }
-}
-
#if defined(F2PY_THREAD_LOCAL_DECL) && !defined(F2PY_USE_PYTHON_TLS)
static F2PY_THREAD_LOCAL_DECL #name#_t *_active_#name# = NULL;
static #name#_t *swap_active_#name#(#name#_t *ptr) {
- CFUNCSMESS2(\"swap_active_#name#: active=%p, ptr=%p\\n", _active_#name#, ptr);
#name#_t *prev = _active_#name#;
_active_#name# = ptr;
return prev;
@@ -80,6 +70,7 @@ static #name#_t *get_active_#name#(void) {
/*typedef #rctype#(*#name#_typedef)(#optargs_td##args_td##strarglens_td##noargs#);*/
#static# #rctype# #callbackname# (#optargs##args##strarglens##noargs#) {
+ #name#_t cb_local = { NULL, NULL, 0 };
#name#_t *cb = NULL;
PyTupleObject *capi_arglist = NULL;
PyObject *capi_return = NULL;
@@ -92,11 +83,9 @@ static #name#_t *get_active_#name#(void) {
f2py_cb_start_clock();
#endif
cb = get_active_#name#();
- show_#name#(cb);
if (cb == NULL) {
capi_longjmp_ok = 0;
- PyErr_SetString(#modulename#_error,\"cb: No active callback #name#!\\n\");
- goto capi_fail;
+ cb = &cb_local;
}
capi_arglist = cb->args_capi;
CFUNCSMESS(\"cb:Call-back function #name# (maxnofargs=#maxnofargs#(-#nofoptargs#))\\n\");
@@ -104,6 +93,7 @@ f2py_cb_start_clock();
if (cb->capi==NULL) {
capi_longjmp_ok = 0;
cb->capi = PyObject_GetAttrString(#modulename#_module,\"#argname#\");
+ CFUNCSMESSPY(\"cb:#name#_capi=\",cb->capi);
}
if (cb->capi==NULL) {
PyErr_SetString(#modulename#_error,\"cb: Callback #argname# not defined (as an argument or module #modulename# attribute).\\n\");
@@ -196,7 +186,7 @@ capi_return_pt:
}
#endtitle#
""",
- 'need': ['setjmp.h', 'CFUNCSMESS', 'CFUNCSMESSPY', 'F2PY_THREAD_LOCAL_DECL'],
+ 'need': ['setjmp.h', 'CFUNCSMESS', 'F2PY_THREAD_LOCAL_DECL'],
'maxnofargs': '#maxnofargs#',
'nofoptargs': '#nofoptargs#',
'docstr': """\
diff --git a/numpy/f2py/cfuncs.py b/numpy/f2py/cfuncs.py
index c6e0a5795..40496ccf1 100644
--- a/numpy/f2py/cfuncs.py
+++ b/numpy/f2py/cfuncs.py
@@ -96,15 +96,11 @@ typedefs['string'] = """typedef char * string;"""
cppmacros['CFUNCSMESS'] = """\
#ifdef DEBUGCFUNCS
#define CFUNCSMESS(mess) fprintf(stderr,\"debug-capi:\"mess);
-#define CFUNCSMESS1(mess, arg) fprintf(stderr,\"debug-capi:\"mess, arg);
-#define CFUNCSMESS2(mess, arg1, arg2) fprintf(stderr,\"debug-capi:\"mess, arg1, arg2);
#define CFUNCSMESSPY(mess,obj) CFUNCSMESS(mess) \\
PyObject_Print((PyObject *)obj,stderr,Py_PRINT_RAW);\\
fprintf(stderr,\"\\n\");
#else
#define CFUNCSMESS(mess)
-#define CFUNCSMESS1(mess, arg)
-#define CFUNCSMESS2(mess, arg1, arg2)
#define CFUNCSMESSPY(mess,obj)
#endif
"""
diff --git a/numpy/f2py/rules.py b/numpy/f2py/rules.py
index 11767d15c..b9cbc5487 100755
--- a/numpy/f2py/rules.py
+++ b/numpy/f2py/rules.py
@@ -813,17 +813,12 @@ if (#varname#_cb.capi==Py_None) {
{l_not(isintent_callback): """ fprintf(stderr,\"#vardebugshowvalue# (call-back in C).\\n\",#cbname#);"""}]},
"""\
CFUNCSMESS(\"Saving callback variables for `#varname#`.\\n\");
- show_#cbname#(#varname#_cb_ptr);
- #varname#_cb_ptr = swap_active_#cbname#(#varname#_cb_ptr);
- show_#cbname#(#varname#_cb_ptr);
- """,
+ #varname#_cb_ptr = swap_active_#cbname#(#varname#_cb_ptr);""",
],
'cleanupfrompyobj':
"""\
CFUNCSMESS(\"Restoring callback variables for `#varname#`.\\n\");
- show_#cbname#(#varname#_cb_ptr);
#varname#_cb_ptr = swap_active_#cbname#(#varname#_cb_ptr);
- show_#cbname#(#varname#_cb_ptr);
Py_DECREF(#varname#_cb.args_capi);
}""",
'need': ['SWAP', 'create_cb_arglist'],
diff --git a/numpy/f2py/tests/test_callback.py b/numpy/f2py/tests/test_callback.py
index 4d4f2b443..2cb429ec2 100644
--- a/numpy/f2py/tests/test_callback.py
+++ b/numpy/f2py/tests/test_callback.py
@@ -61,6 +61,21 @@ 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
"""
@pytest.mark.parametrize('name', 't,t2'.split(','))
@@ -204,6 +219,39 @@ cf2py intent(out) a
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):
"""
diff --git a/numpy/f2py/tests/util.py b/numpy/f2py/tests/util.py
index cdac715b3..d5fa76fed 100644
--- a/numpy/f2py/tests/util.py
+++ b/numpy/f2py/tests/util.py
@@ -92,7 +92,7 @@ def build_module(source_files, options=[], skip=[], only=[], module_name=None):
Compile and import a f2py module, built from the given files.
"""
- options = options + ['--debug-capi']
+
code = ("import sys; sys.path = %s; import numpy.f2py as f2py2e; "
"f2py2e.main()" % repr(sys.path))