diff options
| author | Pearu Peterson <pearu.peterson@gmail.com> | 2021-02-09 20:49:18 +0200 |
|---|---|---|
| committer | Pearu Peterson <pearu.peterson@gmail.com> | 2021-02-09 20:49:18 +0200 |
| commit | 7df963b400f3dcf85e679e6f00af8c3c12971347 (patch) | |
| tree | c23cf43cae1fab777a6282875f179ed14f5273e1 | |
| parent | af44a8198524ab532a0c1b2410b5706768d5a77e (diff) | |
| download | numpy-7df963b400f3dcf85e679e6f00af8c3c12971347.tar.gz | |
BUG: fix regression in a hidden callback use case
| -rw-r--r-- | numpy/f2py/cb_rules.py | 18 | ||||
| -rw-r--r-- | numpy/f2py/cfuncs.py | 4 | ||||
| -rwxr-xr-x | numpy/f2py/rules.py | 7 | ||||
| -rw-r--r-- | numpy/f2py/tests/test_callback.py | 48 | ||||
| -rw-r--r-- | numpy/f2py/tests/util.py | 2 |
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)) |
