diff options
Diffstat (limited to 'numpy/core')
-rw-r--r-- | numpy/core/setup.py | 4 | ||||
-rw-r--r-- | numpy/core/src/multiarray/_multiarray_tests.c.src | 23 | ||||
-rw-r--r-- | numpy/core/tests/test_argparse.py | 62 |
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}) + |