From 4d8b37688cbd677112503d0cc314c12d6fc7bb2d Mon Sep 17 00:00:00 2001 From: Michael Carlstrom Date: Sat, 29 Jun 2024 11:57:10 -0400 Subject: [PATCH 1/4] tests passing --- include/pybind11/cast.h | 6 ++++++ include/pybind11/eigen/matrix.h | 4 ++-- include/pybind11/eigen/tensor.h | 2 +- include/pybind11/numpy.h | 2 +- tests/test_eigen_matrix.py | 22 +++++++++++----------- tests/test_eigen_tensor.py | 14 +++++++------- tests/test_numpy_array.py | 20 ++++++++++---------- tests/test_numpy_dtypes.py | 2 +- tests/test_numpy_vectorize.py | 10 +++++----- 9 files changed, 44 insertions(+), 38 deletions(-) diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index 624b8ebac..a0b83ab62 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -740,6 +740,12 @@ class type_caster> : public tuple_caster {} template class type_caster> : public tuple_caster {}; +template <> +class type_caster> : public tuple_caster { +public: + static constexpr auto name = const_name("tuple[()]"); +}; + /// Helper class which abstracts away certain actions. Users can provide specializations for /// custom holders, but it's only necessary if the type has a non-standard interface. template diff --git a/include/pybind11/eigen/matrix.h b/include/pybind11/eigen/matrix.h index 8d4342f81..098727f5a 100644 --- a/include/pybind11/eigen/matrix.h +++ b/include/pybind11/eigen/matrix.h @@ -224,7 +224,7 @@ struct EigenProps { = !show_c_contiguous && show_order && requires_col_major; static constexpr auto descriptor - = const_name("numpy.ndarray[") + npy_format_descriptor::name + const_name("[") + = const_name("numpy.typing.NDArray[") + npy_format_descriptor::name + const_name("[") + const_name(const_name<(size_t) rows>(), const_name("m")) + const_name(", ") + const_name(const_name<(size_t) cols>(), const_name("n")) + const_name("]") + @@ -232,7 +232,7 @@ struct EigenProps { // be satisfied: writeable=True (for a mutable reference), and, depending on the map's // stride options, possibly f_contiguous or c_contiguous. We include them in the // descriptor output to provide some hint as to why a TypeError is occurring (otherwise - // it can be confusing to see that a function accepts a 'numpy.ndarray[float64[3,2]]' and + // it can be confusing to see that a function accepts a 'numpy.typing.NDArray[float64[3,2]]' and // an error message that you *gave* a numpy.ndarray of the right type and dimensions. const_name(", flags.writeable", "") + const_name(", flags.c_contiguous", "") diff --git a/include/pybind11/eigen/tensor.h b/include/pybind11/eigen/tensor.h index d4ed6c0ca..b9f1736f5 100644 --- a/include/pybind11/eigen/tensor.h +++ b/include/pybind11/eigen/tensor.h @@ -127,7 +127,7 @@ struct get_tensor_descriptor { + const_name(Type::Layout) == static_cast(Eigen::RowMajor)>( ", flags.c_contiguous", ", flags.f_contiguous"); static constexpr auto value - = const_name("numpy.ndarray[") + npy_format_descriptor::name + = const_name("numpy.typing.NDArray[") + npy_format_descriptor::name + const_name("[") + eigen_tensor_helper>::dimensions_descriptor + const_name("]") + const_name(details, const_name("")) + const_name("]"); }; diff --git a/include/pybind11/numpy.h b/include/pybind11/numpy.h index 05ef3918b..b30acba65 100644 --- a/include/pybind11/numpy.h +++ b/include/pybind11/numpy.h @@ -2086,7 +2086,7 @@ vectorize_helper vectorize_extractor(const Func &f, Retur template struct handle_type_name> { static constexpr auto name - = const_name("numpy.ndarray[") + npy_format_descriptor::name + const_name("]"); + = const_name("numpy.typing.NDArray[") + npy_format_descriptor::name + const_name("]"); }; PYBIND11_NAMESPACE_END(detail) diff --git a/tests/test_eigen_matrix.py b/tests/test_eigen_matrix.py index e1d7433f1..6eee6d661 100644 --- a/tests/test_eigen_matrix.py +++ b/tests/test_eigen_matrix.py @@ -94,18 +94,18 @@ def test_mutator_descriptors(): with pytest.raises(TypeError) as excinfo: m.fixed_mutator_r(zc) assert ( - "(arg0: numpy.ndarray[numpy.float32[5, 6]," + "(arg0: numpy.typing.NDArray[numpy.float32[5, 6]," " flags.writeable, flags.c_contiguous]) -> None" in str(excinfo.value) ) with pytest.raises(TypeError) as excinfo: m.fixed_mutator_c(zr) assert ( - "(arg0: numpy.ndarray[numpy.float32[5, 6]," + "(arg0: numpy.typing.NDArray[numpy.float32[5, 6]," " flags.writeable, flags.f_contiguous]) -> None" in str(excinfo.value) ) with pytest.raises(TypeError) as excinfo: m.fixed_mutator_a(np.array([[1, 2], [3, 4]], dtype="float32")) - assert "(arg0: numpy.ndarray[numpy.float32[5, 6], flags.writeable]) -> None" in str( + assert "(arg0: numpy.typing.NDArray[numpy.float32[5, 6], flags.writeable]) -> None" in str( excinfo.value ) zr.flags.writeable = False @@ -200,7 +200,7 @@ def test_negative_stride_from_python(msg): msg(excinfo.value) == """ double_threer(): incompatible function arguments. The following argument types are supported: - 1. (arg0: numpy.ndarray[numpy.float32[1, 3], flags.writeable]) -> None + 1. (arg0: numpy.typing.NDArray[numpy.float32[1, 3], flags.writeable]) -> None Invoked with: """ + repr(np.array([5.0, 4.0, 3.0], dtype="float32")) @@ -212,7 +212,7 @@ def test_negative_stride_from_python(msg): msg(excinfo.value) == """ double_threec(): incompatible function arguments. The following argument types are supported: - 1. (arg0: numpy.ndarray[numpy.float32[3, 1], flags.writeable]) -> None + 1. (arg0: numpy.typing.NDArray[numpy.float32[3, 1], flags.writeable]) -> None Invoked with: """ + repr(np.array([7.0, 4.0, 1.0], dtype="float32")) @@ -697,25 +697,25 @@ def test_dense_signature(doc): assert ( doc(m.double_col) == """ - double_col(arg0: numpy.ndarray[numpy.float32[m, 1]]) -> numpy.ndarray[numpy.float32[m, 1]] + double_col(arg0: numpy.typing.NDArray[numpy.float32[m, 1]]) -> numpy.typing.NDArray[numpy.float32[m, 1]] """ ) assert ( doc(m.double_row) == """ - double_row(arg0: numpy.ndarray[numpy.float32[1, n]]) -> numpy.ndarray[numpy.float32[1, n]] + double_row(arg0: numpy.typing.NDArray[numpy.float32[1, n]]) -> numpy.typing.NDArray[numpy.float32[1, n]] """ ) assert doc(m.double_complex) == ( """ - double_complex(arg0: numpy.ndarray[numpy.complex64[m, 1]])""" - """ -> numpy.ndarray[numpy.complex64[m, 1]] + double_complex(arg0: numpy.typing.NDArray[numpy.complex64[m, 1]])""" + """ -> numpy.typing.NDArray[numpy.complex64[m, 1]] """ ) assert doc(m.double_mat_rm) == ( """ - double_mat_rm(arg0: numpy.ndarray[numpy.float32[m, n]])""" - """ -> numpy.ndarray[numpy.float32[m, n]] + double_mat_rm(arg0: numpy.typing.NDArray[numpy.float32[m, n]])""" + """ -> numpy.typing.NDArray[numpy.float32[m, n]] """ ) diff --git a/tests/test_eigen_tensor.py b/tests/test_eigen_tensor.py index a2b99d9d7..7379a2981 100644 --- a/tests/test_eigen_tensor.py +++ b/tests/test_eigen_tensor.py @@ -268,23 +268,23 @@ def test_round_trip_references_actually_refer(m): @pytest.mark.parametrize("m", submodules) def test_doc_string(m, doc): assert ( - doc(m.copy_tensor) == "copy_tensor() -> numpy.ndarray[numpy.float64[?, ?, ?]]" + doc(m.copy_tensor) == "copy_tensor() -> numpy.typing.NDArray[numpy.float64[?, ?, ?]]" ) assert ( doc(m.copy_fixed_tensor) - == "copy_fixed_tensor() -> numpy.ndarray[numpy.float64[3, 5, 2]]" + == "copy_fixed_tensor() -> numpy.typing.NDArray[numpy.float64[3, 5, 2]]" ) assert ( doc(m.reference_const_tensor) - == "reference_const_tensor() -> numpy.ndarray[numpy.float64[?, ?, ?]]" + == "reference_const_tensor() -> numpy.typing.NDArray[numpy.float64[?, ?, ?]]" ) order_flag = f"flags.{m.needed_options.lower()}_contiguous" assert doc(m.round_trip_view_tensor) == ( - f"round_trip_view_tensor(arg0: numpy.ndarray[numpy.float64[?, ?, ?], flags.writeable, {order_flag}])" - f" -> numpy.ndarray[numpy.float64[?, ?, ?], flags.writeable, {order_flag}]" + f"round_trip_view_tensor(arg0: numpy.typing.NDArray[numpy.float64[?, ?, ?], flags.writeable, {order_flag}])" + f" -> numpy.typing.NDArray[numpy.float64[?, ?, ?], flags.writeable, {order_flag}]" ) assert doc(m.round_trip_const_view_tensor) == ( - f"round_trip_const_view_tensor(arg0: numpy.ndarray[numpy.float64[?, ?, ?], {order_flag}])" - " -> numpy.ndarray[numpy.float64[?, ?, ?]]" + f"round_trip_const_view_tensor(arg0: numpy.typing.NDArray[numpy.float64[?, ?, ?], {order_flag}])" + " -> numpy.typing.NDArray[numpy.float64[?, ?, ?]]" ) diff --git a/tests/test_numpy_array.py b/tests/test_numpy_array.py index 4726a8e73..66eaf6c79 100644 --- a/tests/test_numpy_array.py +++ b/tests/test_numpy_array.py @@ -320,13 +320,13 @@ def test_overload_resolution(msg): msg(excinfo.value) == """ overloaded(): incompatible function arguments. The following argument types are supported: - 1. (arg0: numpy.ndarray[numpy.float64]) -> str - 2. (arg0: numpy.ndarray[numpy.float32]) -> str - 3. (arg0: numpy.ndarray[numpy.int32]) -> str - 4. (arg0: numpy.ndarray[numpy.uint16]) -> str - 5. (arg0: numpy.ndarray[numpy.int64]) -> str - 6. (arg0: numpy.ndarray[numpy.complex128]) -> str - 7. (arg0: numpy.ndarray[numpy.complex64]) -> str + 1. (arg0: numpy.typing.NDArray[numpy.float64]) -> str + 2. (arg0: numpy.typing.NDArray[numpy.float32]) -> str + 3. (arg0: numpy.typing.NDArray[numpy.int32]) -> str + 4. (arg0: numpy.typing.NDArray[numpy.uint16]) -> str + 5. (arg0: numpy.typing.NDArray[numpy.int64]) -> str + 6. (arg0: numpy.typing.NDArray[numpy.complex128]) -> str + 7. (arg0: numpy.typing.NDArray[numpy.complex64]) -> str Invoked with: 'not an array' """ @@ -342,8 +342,8 @@ def test_overload_resolution(msg): assert m.overloaded3(np.array([1], dtype="intc")) == "int" expected_exc = """ overloaded3(): incompatible function arguments. The following argument types are supported: - 1. (arg0: numpy.ndarray[numpy.int32]) -> str - 2. (arg0: numpy.ndarray[numpy.float64]) -> str + 1. (arg0: numpy.typing.NDArray[numpy.int32]) -> str + 2. (arg0: numpy.typing.NDArray[numpy.float64]) -> str Invoked with: """ @@ -527,7 +527,7 @@ def test_index_using_ellipsis(): ], ) def test_format_descriptors_for_floating_point_types(test_func): - assert "numpy.ndarray[numpy.float" in test_func.__doc__ + assert "numpy.typing.NDArray[numpy.float" in test_func.__doc__ @pytest.mark.parametrize("forcecast", [False, True]) diff --git a/tests/test_numpy_dtypes.py b/tests/test_numpy_dtypes.py index 8ae239ed8..f813d96e1 100644 --- a/tests/test_numpy_dtypes.py +++ b/tests/test_numpy_dtypes.py @@ -351,7 +351,7 @@ def test_complex_array(): def test_signature(doc): assert ( doc(m.create_rec_nested) - == "create_rec_nested(arg0: int) -> numpy.ndarray[NestedStruct]" + == "create_rec_nested(arg0: int) -> numpy.typing.NDArray[NestedStruct]" ) diff --git a/tests/test_numpy_vectorize.py b/tests/test_numpy_vectorize.py index ce38d72d9..55b2496b2 100644 --- a/tests/test_numpy_vectorize.py +++ b/tests/test_numpy_vectorize.py @@ -150,7 +150,7 @@ def test_docs(doc): assert ( doc(m.vectorized_func) == """ - vectorized_func(arg0: numpy.ndarray[numpy.int32], arg1: numpy.ndarray[numpy.float32], arg2: numpy.ndarray[numpy.float64]) -> object + vectorized_func(arg0: numpy.typing.NDArray[numpy.int32], arg1: numpy.typing.NDArray[numpy.float32], arg2: numpy.typing.NDArray[numpy.float64]) -> object """ ) @@ -212,12 +212,12 @@ def test_passthrough_arguments(doc): + ", ".join( [ "arg0: float", - "arg1: numpy.ndarray[numpy.float64]", - "arg2: numpy.ndarray[numpy.float64]", - "arg3: numpy.ndarray[numpy.int32]", + "arg1: numpy.typing.NDArray[numpy.float64]", + "arg2: numpy.typing.NDArray[numpy.float64]", + "arg3: numpy.typing.NDArray[numpy.int32]", "arg4: int", "arg5: m.numpy_vectorize.NonPODClass", - "arg6: numpy.ndarray[numpy.float64]", + "arg6: numpy.typing.NDArray[numpy.float64]", ] ) + ") -> object" From 0645585d2d363493a2691ff1563322c532edf5ba Mon Sep 17 00:00:00 2001 From: Michael Carlstrom Date: Sat, 29 Jun 2024 11:58:34 -0400 Subject: [PATCH 2/4] lint --- include/pybind11/eigen/matrix.h | 13 +++++++------ tests/test_eigen_matrix.py | 5 +++-- tests/test_eigen_tensor.py | 3 ++- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/include/pybind11/eigen/matrix.h b/include/pybind11/eigen/matrix.h index 098727f5a..47c7b9bbe 100644 --- a/include/pybind11/eigen/matrix.h +++ b/include/pybind11/eigen/matrix.h @@ -224,16 +224,17 @@ struct EigenProps { = !show_c_contiguous && show_order && requires_col_major; static constexpr auto descriptor - = const_name("numpy.typing.NDArray[") + npy_format_descriptor::name + const_name("[") - + const_name(const_name<(size_t) rows>(), const_name("m")) + const_name(", ") - + const_name(const_name<(size_t) cols>(), const_name("n")) + const_name("]") - + + = const_name("numpy.typing.NDArray[") + npy_format_descriptor::name + + const_name("[") + const_name(const_name<(size_t) rows>(), const_name("m")) + + const_name(", ") + const_name(const_name<(size_t) cols>(), const_name("n")) + + const_name("]") + // For a reference type (e.g. Ref) we have other constraints that might need to // be satisfied: writeable=True (for a mutable reference), and, depending on the map's // stride options, possibly f_contiguous or c_contiguous. We include them in the // descriptor output to provide some hint as to why a TypeError is occurring (otherwise - // it can be confusing to see that a function accepts a 'numpy.typing.NDArray[float64[3,2]]' and - // an error message that you *gave* a numpy.ndarray of the right type and dimensions. + // it can be confusing to see that a function accepts a + // 'numpy.typing.NDArray[float64[3,2]]' and an error message that you *gave* a + // numpy.ndarray of the right type and dimensions. const_name(", flags.writeable", "") + const_name(", flags.c_contiguous", "") + const_name(", flags.f_contiguous", "") + const_name("]"); diff --git a/tests/test_eigen_matrix.py b/tests/test_eigen_matrix.py index 6eee6d661..29e247514 100644 --- a/tests/test_eigen_matrix.py +++ b/tests/test_eigen_matrix.py @@ -105,8 +105,9 @@ def test_mutator_descriptors(): ) with pytest.raises(TypeError) as excinfo: m.fixed_mutator_a(np.array([[1, 2], [3, 4]], dtype="float32")) - assert "(arg0: numpy.typing.NDArray[numpy.float32[5, 6], flags.writeable]) -> None" in str( - excinfo.value + assert ( + "(arg0: numpy.typing.NDArray[numpy.float32[5, 6], flags.writeable]) -> None" + in str(excinfo.value) ) zr.flags.writeable = False with pytest.raises(TypeError): diff --git a/tests/test_eigen_tensor.py b/tests/test_eigen_tensor.py index 7379a2981..4723bb429 100644 --- a/tests/test_eigen_tensor.py +++ b/tests/test_eigen_tensor.py @@ -268,7 +268,8 @@ def test_round_trip_references_actually_refer(m): @pytest.mark.parametrize("m", submodules) def test_doc_string(m, doc): assert ( - doc(m.copy_tensor) == "copy_tensor() -> numpy.typing.NDArray[numpy.float64[?, ?, ?]]" + doc(m.copy_tensor) + == "copy_tensor() -> numpy.typing.NDArray[numpy.float64[?, ?, ?]]" ) assert ( doc(m.copy_fixed_tensor) From bbd574afa5df9ee1e3e7571b520cd01dba51ee7c Mon Sep 17 00:00:00 2001 From: Michael Carlstrom Date: Sat, 29 Jun 2024 12:10:31 -0400 Subject: [PATCH 3/4] add comment --- include/pybind11/cast.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index a0b83ab62..e41ad2abf 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -743,6 +743,7 @@ class type_caster> : public tuple_caster {} template <> class type_caster> : public tuple_caster { public: + // PEP 484 specifies this syntax for an empty tuple static constexpr auto name = const_name("tuple[()]"); }; From 6e5df0f99b834007ac67ad0ca056ac8f6262c528 Mon Sep 17 00:00:00 2001 From: Michael Carlstrom Date: Sun, 30 Jun 2024 11:01:10 -0400 Subject: [PATCH 4/4] remove empty tuple[()] --- include/pybind11/cast.h | 7 ------- 1 file changed, 7 deletions(-) diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index e41ad2abf..624b8ebac 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -740,13 +740,6 @@ class type_caster> : public tuple_caster {} template class type_caster> : public tuple_caster {}; -template <> -class type_caster> : public tuple_caster { -public: - // PEP 484 specifies this syntax for an empty tuple - static constexpr auto name = const_name("tuple[()]"); -}; - /// Helper class which abstracts away certain actions. Users can provide specializations for /// custom holders, but it's only necessary if the type has a non-standard interface. template