Skip to content

Commit 84017e8

Browse files
committed
Merge branch 'master' into sh_merge_master
2 parents 195a7c9 + 82845c3 commit 84017e8

16 files changed

+261
-135
lines changed

.github/workflows/pip.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ jobs:
104104
- uses: actions/download-artifact@v4
105105

106106
- name: Generate artifact attestation for sdist and wheel
107-
uses: actions/attest-build-provenance@7668571508540a607bdfd90a87a560489fe372eb # v2.1.0
107+
uses: actions/attest-build-provenance@520d128f165991a6c774bcb264f323e3d70747f4 # v2.2.0
108108
with:
109109
subject-path: "*/pybind11*"
110110

docs/advanced/cast/custom.rst

+6-8
Original file line numberDiff line numberDiff line change
@@ -61,27 +61,25 @@ type is explicitly allowed.
6161
6262
template <>
6363
struct type_caster<user_space::Point2D> {
64-
// This macro inserts a lot of boilerplate code and sets the default type hint to `tuple`
65-
PYBIND11_TYPE_CASTER(user_space::Point2D, const_name("tuple"));
66-
// `arg_name` and `return_name` may optionally be used to specify type hints separately for
67-
// arguments and return values.
64+
// This macro inserts a lot of boilerplate code and sets the type hint.
65+
// `io_name` is used to specify different type hints for arguments and return values.
6866
// The signature of our negate function would then look like:
6967
// `negate(Sequence[float]) -> tuple[float, float]`
70-
static constexpr auto arg_name = const_name("Sequence[float]");
71-
static constexpr auto return_name = const_name("tuple[float, float]");
68+
PYBIND11_TYPE_CASTER(user_space::Point2D, io_name("Sequence[float]", "tuple[float, float]"));
7269
7370
// C++ -> Python: convert `Point2D` to `tuple[float, float]`. The second and third arguments
7471
// are used to indicate the return value policy and parent object (for
7572
// return_value_policy::reference_internal) and are often ignored by custom casters.
76-
// The return value should reflect the type hint specified by `return_name`.
73+
// The return value should reflect the type hint specified by the second argument of `io_name`.
7774
static handle
7875
cast(const user_space::Point2D &number, return_value_policy /*policy*/, handle /*parent*/) {
7976
return py::make_tuple(number.x, number.y).release();
8077
}
8178
8279
// Python -> C++: convert a `PyObject` into a `Point2D` and return false upon failure. The
8380
// second argument indicates whether implicit conversions should be allowed.
84-
// The accepted types should reflect the type hint specified by `arg_name`.
81+
// The accepted types should reflect the type hint specified by the first argument of
82+
// `io_name`.
8583
bool load(handle src, bool /*convert*/) {
8684
// Check if handle is a Sequence
8785
if (!py::isinstance<py::sequence>(src)) {

docs/basics.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ On Linux, the above example can be compiled using the following command:
142142

143143
.. code-block:: bash
144144
145-
$ c++ -O3 -Wall -shared -std=c++11 -fPIC $(python3 -m pybind11 --includes) example.cpp -o example$(python3-config --extension-suffix)
145+
$ c++ -O3 -Wall -shared -std=c++11 -fPIC $(python3 -m pybind11 --includes) example.cpp -o example$(python3 -m pybind11 --extension-suffix)
146146
147147
.. note::
148148

include/pybind11/cast.h

+1-36
Original file line numberDiff line numberDiff line change
@@ -34,39 +34,6 @@ PYBIND11_WARNING_DISABLE_MSVC(4127)
3434

3535
PYBIND11_NAMESPACE_BEGIN(detail)
3636

37-
// Type trait checker for `descr`
38-
template <typename>
39-
struct is_descr : std::false_type {};
40-
41-
template <size_t N, typename... Ts>
42-
struct is_descr<descr<N, Ts...>> : std::true_type {};
43-
44-
template <size_t N, typename... Ts>
45-
struct is_descr<const descr<N, Ts...>> : std::true_type {};
46-
47-
// Use arg_name instead of name when available
48-
template <typename T, typename SFINAE = void>
49-
struct as_arg_type {
50-
static constexpr auto name = T::name;
51-
};
52-
53-
template <typename T>
54-
struct as_arg_type<T, typename std::enable_if<is_descr<decltype(T::arg_name)>::value>::type> {
55-
static constexpr auto name = T::arg_name;
56-
};
57-
58-
// Use return_name instead of name when available
59-
template <typename T, typename SFINAE = void>
60-
struct as_return_type {
61-
static constexpr auto name = T::name;
62-
};
63-
64-
template <typename T>
65-
struct as_return_type<T,
66-
typename std::enable_if<is_descr<decltype(T::return_name)>::value>::type> {
67-
static constexpr auto name = T::return_name;
68-
};
69-
7037
template <typename type, typename SFINAE = void>
7138
class type_caster : public type_caster_base<type> {};
7239
template <typename type>
@@ -1396,8 +1363,6 @@ struct pyobject_caster {
13961363
return src.inc_ref();
13971364
}
13981365
PYBIND11_TYPE_CASTER(type, handle_type_name<type>::name);
1399-
static constexpr auto arg_name = as_arg_type<handle_type_name<type>>::name;
1400-
static constexpr auto return_name = as_return_type<handle_type_name<type>>::name;
14011366
};
14021367

14031368
template <typename T>
@@ -1951,7 +1916,7 @@ class argument_loader {
19511916
"py::args cannot be specified more than once");
19521917

19531918
static constexpr auto arg_names
1954-
= ::pybind11::detail::concat(type_descr(as_arg_type<make_caster<Args>>::name)...);
1919+
= ::pybind11::detail::concat(type_descr(make_caster<Args>::name)...);
19551920

19561921
bool load_args(function_call &call) { return load_impl_sequence(call, indices{}); }
19571922

include/pybind11/detail/descr.h

+17
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,13 @@ constexpr descr<1, Type> const_name() {
9999
return {'%'};
100100
}
101101

102+
// Use a different name based on whether the parameter is used as input or output
103+
template <size_t N1, size_t N2>
104+
constexpr descr<N1 + N2 + 1> io_name(char const (&text1)[N1], char const (&text2)[N2]) {
105+
return const_name("@") + const_name(text1) + const_name("@") + const_name(text2)
106+
+ const_name("@");
107+
}
108+
102109
// If "_" is defined as a macro, py::detail::_ cannot be provided.
103110
// It is therefore best to use py::detail::const_name universally.
104111
// This block is for backward compatibility only.
@@ -167,5 +174,15 @@ constexpr descr<N + 2, Ts...> type_descr(const descr<N, Ts...> &descr) {
167174
return const_name("{") + descr + const_name("}");
168175
}
169176

177+
template <size_t N, typename... Ts>
178+
constexpr descr<N + 4, Ts...> arg_descr(const descr<N, Ts...> &descr) {
179+
return const_name("@^") + descr + const_name("@!");
180+
}
181+
182+
template <size_t N, typename... Ts>
183+
constexpr descr<N + 4, Ts...> return_descr(const descr<N, Ts...> &descr) {
184+
return const_name("@$") + descr + const_name("@!");
185+
}
186+
170187
PYBIND11_NAMESPACE_END(detail)
171188
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)

include/pybind11/pybind11.h

+60-2
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include <cstring>
2525
#include <memory>
2626
#include <new>
27+
#include <stack>
2728
#include <string>
2829
#include <utility>
2930
#include <vector>
@@ -338,8 +339,8 @@ class cpp_function : public function {
338339

339340
/* Generate a readable signature describing the function's arguments and return
340341
value types */
341-
static constexpr auto signature = const_name("(") + cast_in::arg_names
342-
+ const_name(") -> ") + as_return_type<cast_out>::name;
342+
static constexpr auto signature
343+
= const_name("(") + cast_in::arg_names + const_name(") -> ") + cast_out::name;
343344
PYBIND11_DESCR_CONSTEXPR auto types = decltype(signature)::types();
344345

345346
/* Register the function with Python from generic (non-templated) code */
@@ -442,6 +443,13 @@ class cpp_function : public function {
442443
std::string signature;
443444
size_t type_index = 0, arg_index = 0;
444445
bool is_starred = false;
446+
// `is_return_value.top()` is true if we are currently inside the return type of the
447+
// signature. Using `@^`/`@$` we can force types to be arg/return types while `@!` pops
448+
// back to the previous state.
449+
std::stack<bool> is_return_value({false});
450+
// The following characters have special meaning in the signature parsing. Literals
451+
// containing these are escaped with `!`.
452+
std::string special_chars("!@%{}-");
445453
for (const auto *pc = text; *pc != '\0'; ++pc) {
446454
const auto c = *pc;
447455

@@ -495,7 +503,57 @@ class cpp_function : public function {
495503
} else {
496504
signature += detail::quote_cpp_type_name(detail::clean_type_id(t->name()));
497505
}
506+
} else if (c == '!' && special_chars.find(*(pc + 1)) != std::string::npos) {
507+
// typing::Literal escapes special characters with !
508+
signature += *++pc;
509+
} else if (c == '@') {
510+
// `@^ ... @!` and `@$ ... @!` are used to force arg/return value type (see
511+
// typing::Callable/detail::arg_descr/detail::return_descr)
512+
if (*(pc + 1) == '^') {
513+
is_return_value.emplace(false);
514+
++pc;
515+
continue;
516+
}
517+
if (*(pc + 1) == '$') {
518+
is_return_value.emplace(true);
519+
++pc;
520+
continue;
521+
}
522+
if (*(pc + 1) == '!') {
523+
is_return_value.pop();
524+
++pc;
525+
continue;
526+
}
527+
// Handle types that differ depending on whether they appear
528+
// in an argument or a return value position (see io_name<text1, text2>).
529+
// For named arguments (py::arg()) with noconvert set, return value type is used.
530+
++pc;
531+
if (!is_return_value.top()
532+
&& !(arg_index < rec->args.size() && !rec->args[arg_index].convert)) {
533+
while (*pc != '\0' && *pc != '@') {
534+
signature += *pc++;
535+
}
536+
if (*pc == '@') {
537+
++pc;
538+
}
539+
while (*pc != '\0' && *pc != '@') {
540+
++pc;
541+
}
542+
} else {
543+
while (*pc != '\0' && *pc != '@') {
544+
++pc;
545+
}
546+
if (*pc == '@') {
547+
++pc;
548+
}
549+
while (*pc != '\0' && *pc != '@') {
550+
signature += *pc++;
551+
}
552+
}
498553
} else {
554+
if (c == '-' && *(pc + 1) == '>') {
555+
is_return_value.emplace(true);
556+
}
499557
signature += c;
500558
}
501559
}

include/pybind11/stl/filesystem.h

+1-3
Original file line numberDiff line numberDiff line change
@@ -106,9 +106,7 @@ struct path_caster {
106106
return true;
107107
}
108108

109-
PYBIND11_TYPE_CASTER(T, const_name("os.PathLike"));
110-
static constexpr auto arg_name = const_name("Union[os.PathLike, str, bytes]");
111-
static constexpr auto return_name = const_name("Path");
109+
PYBIND11_TYPE_CASTER(T, io_name("Union[os.PathLike, str, bytes]", "pathlib.Path"));
112110
};
113111

114112
#endif // PYBIND11_HAS_FILESYSTEM || defined(PYBIND11_HAS_EXPERIMENTAL_FILESYSTEM)

0 commit comments

Comments
 (0)