1"""
2Tests for the private NumPy argument parsing functionality.
3They mainly exists to ensure good test coverage without having to try the
4weirder cases on actual numpy functions but test them in one place.
5
6The test function is defined in C to be equivalent to (errors may not always
7match exactly, and could be adjusted):
8
9 def func(arg1, /, arg2, *, arg3):
10 i = integer(arg1) # reproducing the 'i' parsing in Python.
11 return None
12"""
13
14import threading
15
16import pytest
17
18import numpy as np
19from numpy._core._multiarray_tests import (
20 argparse_example_function as func,
21 threaded_argparse_example_function as thread_func,
22)
23from numpy.testing import IS_WASM
24
25
26@pytest.mark.skipif(IS_WASM, reason="wasm doesn't have support for threads")
27def test_thread_safe_argparse_cache():
28 b = threading.Barrier(8)
29
30 def call_thread_func():
31 b.wait()
32 thread_func(arg1=3, arg2=None)
33
34 tasks = [threading.Thread(target=call_thread_func) for _ in range(8)]
35 [t.start() for t in tasks]
36 [t.join() for t in tasks]
37
38
39def test_invalid_integers():
40 with pytest.raises(TypeError,
41 match="integer argument expected, got float"):
42 func(1.)
43 with pytest.raises(OverflowError):
44 func(2**100)
45
46
47def test_missing_arguments():
48 with pytest.raises(TypeError,
49 match="missing required positional argument 0"):
50 func()
51 with pytest.raises(TypeError,
52 match="missing required positional argument 0"):
53 func(arg2=1, arg3=4)
54 with pytest.raises(TypeError,
55 match=r"missing required argument \'arg2\' \(pos 1\)"):
56 func(1, arg3=5)
57
58
59def test_too_many_positional():
60 # the second argument is positional but can be passed as keyword.
61 with pytest.raises(TypeError,
62 match="takes from 2 to 3 positional arguments but 4 were given"):
63 func(1, 2, 3, 4)
64
65
66def test_multiple_values():
67 with pytest.raises(TypeError,
68 match=r"given by name \('arg2'\) and position \(position 1\)"):
69 func(1, 2, arg2=3)
70
71
72def test_string_fallbacks():
73 # We can (currently?) use numpy strings to test the "slow" fallbacks
74 # that should normally not be taken due to string interning.
75 arg2 = np.str_("arg2")
76 missing_arg = np.str_("missing_arg")
77 func(1, **{arg2: 3})
78 with pytest.raises(TypeError,
79 match="got an unexpected keyword argument 'missing_arg'"):
80 func(2, **{missing_arg: 3})
81
82
83def test_too_many_arguments_method_forwarding():
84 # Not directly related to the standard argument parsing, but we sometimes
85 # forward methods to Python: arr.mean() calls np._core._methods._mean()
86 # This adds code coverage for this `npy_forward_method`.
87 arr = np.arange(3)
88 args = range(1000)
89 with pytest.raises(TypeError):
90 arr.mean(*args)