summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian Berg <sebastian@sipsolutions.net>2021-03-17 20:41:49 -0500
committerSebastian Berg <sebastian@sipsolutions.net>2021-03-17 21:01:52 -0500
commitf473d571f58c78f89979138c8cc79fcf5db05f42 (patch)
tree233cc5690fe4aa406050940228cf1de0a5f25f67
parentf01b7f1c256bc5d1c8ea54d7aa8e9f9beb64c14c (diff)
downloadnumpy-f473d571f58c78f89979138c8cc79fcf5db05f42.tar.gz
TST: Add specific argument parsing tests
-rw-r--r--numpy/core/setup.py4
-rw-r--r--numpy/core/src/multiarray/_multiarray_tests.c.src23
-rw-r--r--numpy/core/tests/test_argparse.py62
3 files changed, 88 insertions, 1 deletions
diff --git a/numpy/core/setup.py b/numpy/core/setup.py
index 514ec1f23..8c34a3286 100644
--- a/numpy/core/setup.py
+++ b/numpy/core/setup.py
@@ -716,8 +716,10 @@ def configuration(parent_package='',top_path=None):
config.add_extension('_multiarray_tests',
sources=[join('src', 'multiarray', '_multiarray_tests.c.src'),
- join('src', 'common', 'mem_overlap.c')],
+ join('src', 'common', 'mem_overlap.c'),
+ join('src', 'common', 'npy_argparse.c')],
depends=[join('src', 'common', 'mem_overlap.h'),
+ join('src', 'common', 'npy_argparse.h'),
join('src', 'common', 'npy_extint128.h')],
libraries=['npymath'])
diff --git a/numpy/core/src/multiarray/_multiarray_tests.c.src b/numpy/core/src/multiarray/_multiarray_tests.c.src
index 3c8caefce..febcc8512 100644
--- a/numpy/core/src/multiarray/_multiarray_tests.c.src
+++ b/numpy/core/src/multiarray/_multiarray_tests.c.src
@@ -7,6 +7,7 @@
#include "numpy/npy_math.h"
#include "numpy/halffloat.h"
#include "common.h"
+#include "npy_argparse.h"
#include "mem_overlap.h"
#include "npy_extint128.h"
#include "array_method.h"
@@ -19,6 +20,25 @@
#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
+
+static PyObject *
+argparse_example_function(PyObject *NPY_UNUSED(mod),
+ PyObject *const *args, Py_ssize_t len_args, PyObject *kwnames)
+{
+ NPY_PREPARE_ARGPARSER;
+ int arg1;
+ PyObject *arg2, *arg3, *arg4;
+ if (npy_parse_arguments("func", args, len_args, kwnames,
+ "", &PyArray_PythonPyIntFromInt, &arg1,
+ "arg2", NULL, &arg2,
+ "|arg3", NULL, &arg3,
+ "$arg3", NULL, &arg4,
+ NULL, NULL, NULL) < 0) {
+ return NULL;
+ }
+ Py_RETURN_NONE;
+}
+
/* test PyArray_IsPythonScalar, before including private py3 compat header */
static PyObject *
IsPythonScalar(PyObject * dummy, PyObject *args)
@@ -2255,6 +2275,9 @@ run_intp_converter(PyObject* NPY_UNUSED(self), PyObject *args)
}
static PyMethodDef Multiarray_TestsMethods[] = {
+ {"argparse_example_function",
+ (PyCFunction)argparse_example_function,
+ METH_KEYWORDS | METH_FASTCALL, NULL},
{"IsPythonScalar",
IsPythonScalar,
METH_VARARGS, NULL},
diff --git a/numpy/core/tests/test_argparse.py b/numpy/core/tests/test_argparse.py
new file mode 100644
index 000000000..63a01dee4
--- /dev/null
+++ b/numpy/core/tests/test_argparse.py
@@ -0,0 +1,62 @@
+"""
+Tests for the private NumPy argument parsing functionality.
+They mainly exists to ensure good test coverage without having to try the
+weirder cases on actual numpy functions but test them in one place.
+
+The test function is defined in C to be equivalent to (errors may not always
+match exactly, and could be adjusted):
+
+ def func(arg1, /, arg2, *, arg3):
+ i = integer(arg1) # reproducing the 'i' parsing in Python.
+ return None
+"""
+
+import pytest
+
+import numpy as np
+from numpy.core._multiarray_tests import argparse_example_function as func
+
+
+def test_invalid_integers():
+ with pytest.raises(TypeError,
+ match="integer argument expected, got float"):
+ func(1.)
+ with pytest.raises(OverflowError):
+ func(2**100)
+
+
+def test_missing_arguments():
+ with pytest.raises(TypeError,
+ match="missing required positional argument 0"):
+ func()
+ with pytest.raises(TypeError,
+ match="missing required positional argument 0"):
+ func(arg2=1, arg3=4)
+ with pytest.raises(TypeError,
+ match=r"missing required argument \'arg2\' \(pos 1\)"):
+ func(1, arg3=5)
+
+
+def test_too_many_positional():
+ # the second argument is positional but can be passed as keyword.
+ with pytest.raises(TypeError,
+ match="takes from 2 to 3 positional arguments but 4 were given"):
+ func(1, 2, 3, 4)
+
+
+def test_multiple_values():
+ with pytest.raises(TypeError,
+ match=r"given by name \('arg2'\) and position \(position 1\)"):
+ func(1, 2, arg2=3)
+
+
+def test_string_fallbacks():
+ # We can (currently?) use numpy strings to test the "slow" fallbacks
+ # that should normally not be taken due to string interning.
+ arg2 = np.unicode_("arg2")
+ missing_arg = np.unicode_("missing_arg")
+ func(1, **{arg2: 3})
+ with pytest.raises(TypeError,
+ match="got an unexpected keyword argument 'missing_arg'"):
+ func(2, **{missing_arg: 3})
+