From 04730b1ee513ffc1e1f0ab070507c5e8a34068a4 Mon Sep 17 00:00:00 2001 From: Daniel Vanzo Date: Mon, 11 Sep 2023 13:53:12 +0200 Subject: [PATCH 1/4] BUG: Fix numpy.f2py to enable use of string optional inout argument --- numpy/f2py/cfuncs.py | 1 + 1 file changed, 1 insertion(+) diff --git a/numpy/f2py/cfuncs.py b/numpy/f2py/cfuncs.py index f89793061bad..3251c8d50f02 100644 --- a/numpy/f2py/cfuncs.py +++ b/numpy/f2py/cfuncs.py @@ -649,6 +649,7 @@ STRINGCOPYN(buf, str, n); return 1; } + return -1; capi_fail: PRINTPYOBJERR(obj); PyErr_SetString(#modulename#_error, \"try_pyarr_from_string failed\"); From 2aff3136499a20f588e2b2a6cd4c40ea607fb917 Mon Sep 17 00:00:00 2001 From: Rohit Goswami Date: Sun, 19 Nov 2023 22:27:48 +0000 Subject: [PATCH 2/4] MAINT: Be explicit about failure modes [f2py-str] --- numpy/f2py/cfuncs.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/numpy/f2py/cfuncs.py b/numpy/f2py/cfuncs.py index 3251c8d50f02..cc43e28eb608 100644 --- a/numpy/f2py/cfuncs.py +++ b/numpy/f2py/cfuncs.py @@ -634,6 +634,8 @@ fprintf(stderr, "try_pyarr_from_string(str='%s', len=%d, obj=%p)\\n", (char*)str,len, obj); #endif + if (!obj) return -2; /* Object missing */ + if (obj == Py_None) return -1; /* None */ if (PyArray_Check(obj)) { PyArrayObject *arr = (PyArrayObject *)obj; assert(ISCONTIGUOUS(arr)); @@ -649,7 +651,6 @@ STRINGCOPYN(buf, str, n); return 1; } - return -1; capi_fail: PRINTPYOBJERR(obj); PyErr_SetString(#modulename#_error, \"try_pyarr_from_string failed\"); From 7f435912dc83a61b5fec6b136b18abcc11d2f2b9 Mon Sep 17 00:00:00 2001 From: Rohit Goswami Date: Sun, 19 Nov 2023 22:51:02 +0000 Subject: [PATCH 3/4] TST: Add gh-24781 for string inout optional [f2py] --- numpy/f2py/tests/src/string/gh24662.f90 | 7 +++++++ numpy/f2py/tests/test_character.py | 9 +++++++++ 2 files changed, 16 insertions(+) create mode 100644 numpy/f2py/tests/src/string/gh24662.f90 diff --git a/numpy/f2py/tests/src/string/gh24662.f90 b/numpy/f2py/tests/src/string/gh24662.f90 new file mode 100644 index 000000000000..ca53413cc9b4 --- /dev/null +++ b/numpy/f2py/tests/src/string/gh24662.f90 @@ -0,0 +1,7 @@ +subroutine string_inout_optional(output) + implicit none + character*(32), optional, intent(inout) :: output + if (present(output)) then + output="output string" + endif +end subroutine diff --git a/numpy/f2py/tests/test_character.py b/numpy/f2py/tests/test_character.py index 373262bf96a6..93f7188625b4 100644 --- a/numpy/f2py/tests/test_character.py +++ b/numpy/f2py/tests/test_character.py @@ -595,3 +595,12 @@ class TestStringAssumedLength(util.F2PyTest): def test_gh24008(self): self.module.greet("joe", "bob") + +class TestStringOptionalInOut(util.F2PyTest): + sources = [util.getpath("tests", "src", "string", "gh24662.f90")] + + def test_gh24662(self): + self.module.string_inout_optional() + a = np.array('hi', dtype='S32') + self.module.string_inout_optional(a) + assert "output string" in a.tobytes().decode() From 6c2615ef48c675cec20b7d97dc50ace5b129ecc7 Mon Sep 17 00:00:00 2001 From: Rohit Goswami Date: Sun, 19 Nov 2023 23:18:03 +0000 Subject: [PATCH 4/4] TST: Add a check for non-ndarray string types --- numpy/f2py/cfuncs.py | 1 + numpy/f2py/tests/test_character.py | 3 +++ 2 files changed, 4 insertions(+) diff --git a/numpy/f2py/cfuncs.py b/numpy/f2py/cfuncs.py index cc43e28eb608..37c2f6df0879 100644 --- a/numpy/f2py/cfuncs.py +++ b/numpy/f2py/cfuncs.py @@ -636,6 +636,7 @@ #endif if (!obj) return -2; /* Object missing */ if (obj == Py_None) return -1; /* None */ + if (!PyArray_Check(obj)) goto capi_fail; /* not an ndarray */ if (PyArray_Check(obj)) { PyArrayObject *arr = (PyArrayObject *)obj; assert(ISCONTIGUOUS(arr)); diff --git a/numpy/f2py/tests/test_character.py b/numpy/f2py/tests/test_character.py index 93f7188625b4..c928e38741a1 100644 --- a/numpy/f2py/tests/test_character.py +++ b/numpy/f2py/tests/test_character.py @@ -604,3 +604,6 @@ def test_gh24662(self): a = np.array('hi', dtype='S32') self.module.string_inout_optional(a) assert "output string" in a.tobytes().decode() + with pytest.raises(Exception): + aa = "Hi" + self.module.string_inout_optional(aa)