diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index bcdf641f4..5c89c8b43 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -101,6 +101,30 @@ inline std::string replace_newlines_and_squash(const char *text) { # define PYBIND11_COMPAT_STRDUP strdup #endif +/// Type trait checker for `descr`. +template +struct is_descr : std::false_type {}; + +template +struct is_descr> : std::true_type {}; + +template +struct is_descr> : std::true_type {}; + +/// Checks for `return_name` in `type_caster` to replace `name` for return type hints. +/// this is useful for having a different python type hint for args vs return value, +/// e.g., `std::filesystem::path` -> Arg: `Union[os.PathLike, str, bytes]`, return: `Path`. +template +struct as_return_type { + static constexpr auto name = T::name; +}; + +template +struct as_return_type::value>::type> { + static constexpr auto name = T::return_name; +}; + PYBIND11_NAMESPACE_END(detail) /// Wraps an arbitrary C++ function/method/lambda function/.. into a callable Python object @@ -319,8 +343,8 @@ protected: /* Generate a readable signature describing the function's arguments and return value types */ - static constexpr auto signature - = const_name("(") + cast_in::arg_names + const_name(") -> ") + cast_out::name; + static constexpr auto signature = const_name("(") + cast_in::arg_names + + const_name(") -> ") + as_return_type::name; PYBIND11_DESCR_CONSTEXPR auto types = decltype(signature)::types(); /* Register the function with Python from generic (non-templated) code */ diff --git a/include/pybind11/stl/filesystem.h b/include/pybind11/stl/filesystem.h index c16a9ae5c..a06248e38 100644 --- a/include/pybind11/stl/filesystem.h +++ b/include/pybind11/stl/filesystem.h @@ -106,7 +106,8 @@ public: return true; } - PYBIND11_TYPE_CASTER(T, const_name("os.PathLike")); + PYBIND11_TYPE_CASTER(T, const_name("Union[os.PathLike, str, bytes]")); + static constexpr auto return_name = const_name("Path"); }; #endif // PYBIND11_HAS_FILESYSTEM || defined(PYBIND11_HAS_EXPERIMENTAL_FILESYSTEM) diff --git a/tests/test_stl.cpp b/tests/test_stl.cpp index dd93d51d0..08456b3c0 100644 --- a/tests/test_stl.cpp +++ b/tests/test_stl.cpp @@ -454,6 +454,13 @@ TEST_SUBMODULE(stl, m) { // test_fs_path m.attr("has_filesystem") = true; m.def("parent_path", [](const std::filesystem::path &p) { return p.parent_path(); }); + m.def("parent_paths", [](const std::vector &p) { + std::vector result; + for (const auto &i : p) { + result.push_back(i.parent_path()); + } + return result; + }); #endif #ifdef PYBIND11_TEST_VARIANT diff --git a/tests/test_stl.py b/tests/test_stl.py index 6f548789e..2c3172703 100644 --- a/tests/test_stl.py +++ b/tests/test_stl.py @@ -245,7 +245,7 @@ def test_reference_sensitive_optional(): @pytest.mark.skipif(not hasattr(m, "has_filesystem"), reason="no ") -def test_fs_path(): +def test_fs_path(doc): from pathlib import Path class PseudoStrPath: @@ -261,6 +261,15 @@ def test_fs_path(): assert m.parent_path(b"foo/bar") == Path("foo") assert m.parent_path(PseudoStrPath()) == Path("foo") assert m.parent_path(PseudoBytesPath()) == Path("foo") + assert ( + doc(m.parent_path) + == "parent_path(arg0: Union[os.PathLike, str, bytes]) -> Path" + ) + assert m.parent_paths(["foo/bar", "foo/baz"]) == [Path("foo"), Path("foo")] + assert ( + doc(m.parent_paths) + == "parent_paths(arg0: list[Union[os.PathLike, str, bytes]]) -> list[Path]" + ) @pytest.mark.skipif(not hasattr(m, "load_variant"), reason="no ")