mirror of
https://github.com/pybind/pybind11.git
synced 2025-03-25 18:07:43 +00:00
feat(types): Use typing.SupportsInt
and typing.SupportsFloat
and fix other typing based bugs. (#5540)
* init Signed-off-by: Michael Carlstrom <rmc@carlstrom.com> * remove import Signed-off-by: Michael Carlstrom <rmc@carlstrom.com> * remove uneeded function Signed-off-by: Michael Carlstrom <rmc@carlstrom.com> * style: pre-commit fixes * Add missing import Signed-off-by: Michael Carlstrom <rmc@carlstrom.com> * style: pre-commit fixes * Fix type behind detailed_message_enabled flag Signed-off-by: Michael Carlstrom <rmc@carlstrom.com> * Fix type behind detailed_message_enabled flag Signed-off-by: Michael Carlstrom <rmc@carlstrom.com> * Add io_name comment Signed-off-by: Michael Carlstrom <rmc@carlstrom.com> * Extra loops to single function Signed-off-by: Michael Carlstrom <rmc@carlstrom.com> * style: pre-commit fixes * Remove unneeded forward declaration Signed-off-by: Michael Carlstrom <rmc@carlstrom.com> * Switch variable name away from macro Signed-off-by: Michael Carlstrom <rmc@carlstrom.com> * Switch variable name away from macro Signed-off-by: Michael Carlstrom <rmc@carlstrom.com> * Switch variable name away from macro Signed-off-by: Michael Carlstrom <rmc@carlstrom.com> * clang-tidy Signed-off-by: Michael Carlstrom <rmc@carlstrom.com> * remove stack import * Fix bug in std::function Callable type Signed-off-by: Michael Carlstrom <rmc@carlstrom.com> * style: pre-commit fixes * remove is_annotation argument Signed-off-by: Michael Carlstrom <rmc@carlstrom.com> * style: pre-commit fixes * Update function name and arg names Signed-off-by: Michael Carlstrom <rmc@carlstrom.com> * style: pre-commit fixes --------- Signed-off-by: Michael Carlstrom <rmc@carlstrom.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
This commit is contained in:
parent
16b5abd428
commit
dfe7e65b45
@ -241,7 +241,9 @@ public:
|
||||
return PyLong_FromUnsignedLongLong((unsigned long long) src);
|
||||
}
|
||||
|
||||
PYBIND11_TYPE_CASTER(T, const_name<std::is_integral<T>::value>("int", "float"));
|
||||
PYBIND11_TYPE_CASTER(T,
|
||||
io_name<std::is_integral<T>::value>(
|
||||
"typing.SupportsInt", "int", "typing.SupportsFloat", "float"));
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
@ -1231,7 +1233,7 @@ struct handle_type_name<buffer> {
|
||||
};
|
||||
template <>
|
||||
struct handle_type_name<int_> {
|
||||
static constexpr auto name = const_name("int");
|
||||
static constexpr auto name = io_name("typing.SupportsInt", "int");
|
||||
};
|
||||
template <>
|
||||
struct handle_type_name<iterable> {
|
||||
@ -1243,7 +1245,7 @@ struct handle_type_name<iterator> {
|
||||
};
|
||||
template <>
|
||||
struct handle_type_name<float_> {
|
||||
static constexpr auto name = const_name("float");
|
||||
static constexpr auto name = io_name("typing.SupportsFloat", "float");
|
||||
};
|
||||
template <>
|
||||
struct handle_type_name<function> {
|
||||
@ -1604,6 +1606,16 @@ inline void object::cast() && {
|
||||
|
||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
||||
|
||||
// forward declaration (definition in attr.h)
|
||||
struct function_record;
|
||||
|
||||
// forward declaration (definition in pybind11.h)
|
||||
std::string generate_function_signature(const char *type_caster_name_field,
|
||||
function_record *func_rec,
|
||||
const std::type_info *const *types,
|
||||
size_t &type_index,
|
||||
size_t &arg_index);
|
||||
|
||||
// Declared in pytypes.h:
|
||||
template <typename T, enable_if_t<!is_pyobject<T>::value, int>>
|
||||
object object_or_cast(T &&o) {
|
||||
@ -1624,7 +1636,11 @@ str_attr_accessor object_api<D>::attr_with_type_hint(const char *key) const {
|
||||
if (ann.contains(key)) {
|
||||
throw std::runtime_error("__annotations__[\"" + std::string(key) + "\"] was set already.");
|
||||
}
|
||||
ann[key] = make_caster<T>::name.text;
|
||||
|
||||
const char *text = make_caster<T>::name.text;
|
||||
|
||||
size_t unused = 0;
|
||||
ann[key] = generate_function_signature(text, nullptr, nullptr, unused, unused);
|
||||
return {derived(), key};
|
||||
}
|
||||
|
||||
|
@ -106,6 +106,19 @@ constexpr descr<N1 + N2 + 1> io_name(char const (&text1)[N1], char const (&text2
|
||||
+ const_name("@");
|
||||
}
|
||||
|
||||
// Ternary description for io_name (like the numeric type_caster)
|
||||
template <bool B, size_t N1, size_t N2, size_t N3, size_t N4>
|
||||
constexpr enable_if_t<B, descr<N1 + N2 + 1>>
|
||||
io_name(char const (&text1)[N1], char const (&text2)[N2], char const (&)[N3], char const (&)[N4]) {
|
||||
return io_name(text1, text2);
|
||||
}
|
||||
|
||||
template <bool B, size_t N1, size_t N2, size_t N3, size_t N4>
|
||||
constexpr enable_if_t<!B, descr<N3 + N4 + 1>>
|
||||
io_name(char const (&)[N1], char const (&)[N2], char const (&text3)[N3], char const (&text4)[N4]) {
|
||||
return io_name(text3, text4);
|
||||
}
|
||||
|
||||
// If "_" is defined as a macro, py::detail::_ cannot be provided.
|
||||
// It is therefore best to use py::detail::const_name universally.
|
||||
// This block is for backward compatibility only.
|
||||
|
@ -138,11 +138,12 @@ public:
|
||||
return cpp_function(std::forward<Func>(f_), policy).release();
|
||||
}
|
||||
|
||||
PYBIND11_TYPE_CASTER(type,
|
||||
const_name("Callable[[")
|
||||
+ ::pybind11::detail::concat(make_caster<Args>::name...)
|
||||
+ const_name("], ") + make_caster<retval_type>::name
|
||||
+ const_name("]"));
|
||||
PYBIND11_TYPE_CASTER(
|
||||
type,
|
||||
const_name("Callable[[")
|
||||
+ ::pybind11::detail::concat(::pybind11::detail::arg_descr(make_caster<Args>::name)...)
|
||||
+ const_name("], ") + ::pybind11::detail::return_descr(make_caster<retval_type>::name)
|
||||
+ const_name("]"));
|
||||
};
|
||||
|
||||
PYBIND11_NAMESPACE_END(detail)
|
||||
|
@ -104,6 +104,134 @@ inline std::string replace_newlines_and_squash(const char *text) {
|
||||
return result.substr(str_begin, str_range);
|
||||
}
|
||||
|
||||
/* Generate a proper function signature */
|
||||
inline std::string generate_function_signature(const char *type_caster_name_field,
|
||||
detail::function_record *func_rec,
|
||||
const std::type_info *const *types,
|
||||
size_t &type_index,
|
||||
size_t &arg_index) {
|
||||
std::string signature;
|
||||
bool is_starred = false;
|
||||
bool is_annotation = func_rec == nullptr;
|
||||
// `is_return_value.top()` is true if we are currently inside the return type of the
|
||||
// signature. Using `@^`/`@$` we can force types to be arg/return types while `@!` pops
|
||||
// back to the previous state.
|
||||
std::stack<bool> is_return_value({false});
|
||||
// The following characters have special meaning in the signature parsing. Literals
|
||||
// containing these are escaped with `!`.
|
||||
std::string special_chars("!@%{}-");
|
||||
for (const auto *pc = type_caster_name_field; *pc != '\0'; ++pc) {
|
||||
const auto c = *pc;
|
||||
if (c == '{') {
|
||||
// Write arg name for everything except *args and **kwargs.
|
||||
is_starred = *(pc + 1) == '*';
|
||||
if (is_starred) {
|
||||
continue;
|
||||
}
|
||||
// Separator for keyword-only arguments, placed before the kw
|
||||
// arguments start (unless we are already putting an *args)
|
||||
if (!func_rec->has_args && arg_index == func_rec->nargs_pos) {
|
||||
signature += "*, ";
|
||||
}
|
||||
if (arg_index < func_rec->args.size() && func_rec->args[arg_index].name) {
|
||||
signature += func_rec->args[arg_index].name;
|
||||
} else if (arg_index == 0 && func_rec->is_method) {
|
||||
signature += "self";
|
||||
} else {
|
||||
signature += "arg" + std::to_string(arg_index - (func_rec->is_method ? 1 : 0));
|
||||
}
|
||||
signature += ": ";
|
||||
} else if (c == '}') {
|
||||
// Write default value if available.
|
||||
if (!is_starred && arg_index < func_rec->args.size()
|
||||
&& func_rec->args[arg_index].descr) {
|
||||
signature += " = ";
|
||||
signature += detail::replace_newlines_and_squash(func_rec->args[arg_index].descr);
|
||||
}
|
||||
// Separator for positional-only arguments (placed after the
|
||||
// argument, rather than before like *
|
||||
if (func_rec->nargs_pos_only > 0 && (arg_index + 1) == func_rec->nargs_pos_only) {
|
||||
signature += ", /";
|
||||
}
|
||||
if (!is_starred) {
|
||||
arg_index++;
|
||||
}
|
||||
} else if (c == '%') {
|
||||
const std::type_info *t = types[type_index++];
|
||||
if (!t) {
|
||||
pybind11_fail("Internal error while parsing type signature (1)");
|
||||
}
|
||||
if (auto *tinfo = detail::get_type_info(*t)) {
|
||||
handle th((PyObject *) tinfo->type);
|
||||
signature += th.attr("__module__").cast<std::string>() + "."
|
||||
+ th.attr("__qualname__").cast<std::string>();
|
||||
} else if (func_rec->is_new_style_constructor && arg_index == 0) {
|
||||
// A new-style `__init__` takes `self` as `value_and_holder`.
|
||||
// Rewrite it to the proper class type.
|
||||
signature += func_rec->scope.attr("__module__").cast<std::string>() + "."
|
||||
+ func_rec->scope.attr("__qualname__").cast<std::string>();
|
||||
} else {
|
||||
signature += detail::quote_cpp_type_name(detail::clean_type_id(t->name()));
|
||||
}
|
||||
} else if (c == '!' && special_chars.find(*(pc + 1)) != std::string::npos) {
|
||||
// typing::Literal escapes special characters with !
|
||||
signature += *++pc;
|
||||
} else if (c == '@') {
|
||||
// `@^ ... @!` and `@$ ... @!` are used to force arg/return value type (see
|
||||
// typing::Callable/detail::arg_descr/detail::return_descr)
|
||||
if (*(pc + 1) == '^') {
|
||||
is_return_value.emplace(false);
|
||||
++pc;
|
||||
continue;
|
||||
}
|
||||
if (*(pc + 1) == '$') {
|
||||
is_return_value.emplace(true);
|
||||
++pc;
|
||||
continue;
|
||||
}
|
||||
if (*(pc + 1) == '!') {
|
||||
is_return_value.pop();
|
||||
++pc;
|
||||
continue;
|
||||
}
|
||||
// Handle types that differ depending on whether they appear
|
||||
// in an argument or a return value position (see io_name<text1, text2>).
|
||||
// For named arguments (py::arg()) with noconvert set, return value type is used.
|
||||
++pc;
|
||||
if (!is_return_value.top()
|
||||
&& (is_annotation
|
||||
|| !(arg_index < func_rec->args.size()
|
||||
&& !func_rec->args[arg_index].convert))) {
|
||||
while (*pc != '\0' && *pc != '@') {
|
||||
signature += *pc++;
|
||||
}
|
||||
if (*pc == '@') {
|
||||
++pc;
|
||||
}
|
||||
while (*pc != '\0' && *pc != '@') {
|
||||
++pc;
|
||||
}
|
||||
} else {
|
||||
while (*pc != '\0' && *pc != '@') {
|
||||
++pc;
|
||||
}
|
||||
if (*pc == '@') {
|
||||
++pc;
|
||||
}
|
||||
while (*pc != '\0' && *pc != '@') {
|
||||
signature += *pc++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (c == '-' && *(pc + 1) == '>') {
|
||||
is_return_value.emplace(true);
|
||||
}
|
||||
signature += c;
|
||||
}
|
||||
}
|
||||
return signature;
|
||||
}
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
# define PYBIND11_COMPAT_STRDUP _strdup
|
||||
#else
|
||||
@ -439,124 +567,9 @@ protected:
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Generate a proper function signature */
|
||||
std::string signature;
|
||||
size_t type_index = 0, arg_index = 0;
|
||||
bool is_starred = false;
|
||||
// `is_return_value.top()` is true if we are currently inside the return type of the
|
||||
// signature. Using `@^`/`@$` we can force types to be arg/return types while `@!` pops
|
||||
// back to the previous state.
|
||||
std::stack<bool> is_return_value({false});
|
||||
// The following characters have special meaning in the signature parsing. Literals
|
||||
// containing these are escaped with `!`.
|
||||
std::string special_chars("!@%{}-");
|
||||
for (const auto *pc = text; *pc != '\0'; ++pc) {
|
||||
const auto c = *pc;
|
||||
|
||||
if (c == '{') {
|
||||
// Write arg name for everything except *args and **kwargs.
|
||||
is_starred = *(pc + 1) == '*';
|
||||
if (is_starred) {
|
||||
continue;
|
||||
}
|
||||
// Separator for keyword-only arguments, placed before the kw
|
||||
// arguments start (unless we are already putting an *args)
|
||||
if (!rec->has_args && arg_index == rec->nargs_pos) {
|
||||
signature += "*, ";
|
||||
}
|
||||
if (arg_index < rec->args.size() && rec->args[arg_index].name) {
|
||||
signature += rec->args[arg_index].name;
|
||||
} else if (arg_index == 0 && rec->is_method) {
|
||||
signature += "self";
|
||||
} else {
|
||||
signature += "arg" + std::to_string(arg_index - (rec->is_method ? 1 : 0));
|
||||
}
|
||||
signature += ": ";
|
||||
} else if (c == '}') {
|
||||
// Write default value if available.
|
||||
if (!is_starred && arg_index < rec->args.size() && rec->args[arg_index].descr) {
|
||||
signature += " = ";
|
||||
signature += detail::replace_newlines_and_squash(rec->args[arg_index].descr);
|
||||
}
|
||||
// Separator for positional-only arguments (placed after the
|
||||
// argument, rather than before like *
|
||||
if (rec->nargs_pos_only > 0 && (arg_index + 1) == rec->nargs_pos_only) {
|
||||
signature += ", /";
|
||||
}
|
||||
if (!is_starred) {
|
||||
arg_index++;
|
||||
}
|
||||
} else if (c == '%') {
|
||||
const std::type_info *t = types[type_index++];
|
||||
if (!t) {
|
||||
pybind11_fail("Internal error while parsing type signature (1)");
|
||||
}
|
||||
if (auto *tinfo = detail::get_type_info(*t)) {
|
||||
handle th((PyObject *) tinfo->type);
|
||||
signature += th.attr("__module__").cast<std::string>() + "."
|
||||
+ th.attr("__qualname__").cast<std::string>();
|
||||
} else if (rec->is_new_style_constructor && arg_index == 0) {
|
||||
// A new-style `__init__` takes `self` as `value_and_holder`.
|
||||
// Rewrite it to the proper class type.
|
||||
signature += rec->scope.attr("__module__").cast<std::string>() + "."
|
||||
+ rec->scope.attr("__qualname__").cast<std::string>();
|
||||
} else {
|
||||
signature += detail::quote_cpp_type_name(detail::clean_type_id(t->name()));
|
||||
}
|
||||
} else if (c == '!' && special_chars.find(*(pc + 1)) != std::string::npos) {
|
||||
// typing::Literal escapes special characters with !
|
||||
signature += *++pc;
|
||||
} else if (c == '@') {
|
||||
// `@^ ... @!` and `@$ ... @!` are used to force arg/return value type (see
|
||||
// typing::Callable/detail::arg_descr/detail::return_descr)
|
||||
if (*(pc + 1) == '^') {
|
||||
is_return_value.emplace(false);
|
||||
++pc;
|
||||
continue;
|
||||
}
|
||||
if (*(pc + 1) == '$') {
|
||||
is_return_value.emplace(true);
|
||||
++pc;
|
||||
continue;
|
||||
}
|
||||
if (*(pc + 1) == '!') {
|
||||
is_return_value.pop();
|
||||
++pc;
|
||||
continue;
|
||||
}
|
||||
// Handle types that differ depending on whether they appear
|
||||
// in an argument or a return value position (see io_name<text1, text2>).
|
||||
// For named arguments (py::arg()) with noconvert set, return value type is used.
|
||||
++pc;
|
||||
if (!is_return_value.top()
|
||||
&& !(arg_index < rec->args.size() && !rec->args[arg_index].convert)) {
|
||||
while (*pc != '\0' && *pc != '@') {
|
||||
signature += *pc++;
|
||||
}
|
||||
if (*pc == '@') {
|
||||
++pc;
|
||||
}
|
||||
while (*pc != '\0' && *pc != '@') {
|
||||
++pc;
|
||||
}
|
||||
} else {
|
||||
while (*pc != '\0' && *pc != '@') {
|
||||
++pc;
|
||||
}
|
||||
if (*pc == '@') {
|
||||
++pc;
|
||||
}
|
||||
while (*pc != '\0' && *pc != '@') {
|
||||
signature += *pc++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (c == '-' && *(pc + 1) == '>') {
|
||||
is_return_value.emplace(true);
|
||||
}
|
||||
signature += c;
|
||||
}
|
||||
}
|
||||
std::string signature
|
||||
= detail::generate_function_signature(text, rec, types, type_index, arg_index);
|
||||
|
||||
if (arg_index != args - rec->has_args - rec->has_kwargs || types[type_index] != nullptr) {
|
||||
pybind11_fail("Internal error while parsing type signature (2)");
|
||||
|
@ -228,7 +228,9 @@ struct handle_type_name<typing::Optional<T>> {
|
||||
|
||||
template <typename T>
|
||||
struct handle_type_name<typing::Final<T>> {
|
||||
static constexpr auto name = const_name("Final[") + make_caster<T>::name + const_name("]");
|
||||
static constexpr auto name = const_name("Final[")
|
||||
+ ::pybind11::detail::return_descr(make_caster<T>::name)
|
||||
+ const_name("]");
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
|
@ -236,6 +236,10 @@ TEST_SUBMODULE(builtin_casters, m) {
|
||||
m.def("int_passthrough", [](int arg) { return arg; });
|
||||
m.def("int_passthrough_noconvert", [](int arg) { return arg; }, py::arg{}.noconvert());
|
||||
|
||||
// test_float_convert
|
||||
m.def("float_passthrough", [](float arg) { return arg; });
|
||||
m.def("float_passthrough_noconvert", [](float arg) { return arg; }, py::arg{}.noconvert());
|
||||
|
||||
// test_tuple
|
||||
m.def(
|
||||
"pair_passthrough",
|
||||
|
@ -247,7 +247,7 @@ def test_integer_casting():
|
||||
assert "incompatible function arguments" in str(excinfo.value)
|
||||
|
||||
|
||||
def test_int_convert():
|
||||
def test_int_convert(doc):
|
||||
class Int:
|
||||
def __int__(self):
|
||||
return 42
|
||||
@ -286,6 +286,9 @@ def test_int_convert():
|
||||
|
||||
convert, noconvert = m.int_passthrough, m.int_passthrough_noconvert
|
||||
|
||||
assert doc(convert) == "int_passthrough(arg0: typing.SupportsInt) -> int"
|
||||
assert doc(noconvert) == "int_passthrough_noconvert(arg0: int) -> int"
|
||||
|
||||
def requires_conversion(v):
|
||||
pytest.raises(TypeError, noconvert, v)
|
||||
|
||||
@ -318,6 +321,22 @@ def test_int_convert():
|
||||
requires_conversion(RaisingValueErrorOnIndex())
|
||||
|
||||
|
||||
def test_float_convert(doc):
|
||||
class Float:
|
||||
def __float__(self):
|
||||
return 41.45
|
||||
|
||||
convert, noconvert = m.float_passthrough, m.float_passthrough_noconvert
|
||||
assert doc(convert) == "float_passthrough(arg0: typing.SupportsFloat) -> float"
|
||||
assert doc(noconvert) == "float_passthrough_noconvert(arg0: float) -> float"
|
||||
|
||||
def requires_conversion(v):
|
||||
pytest.raises(TypeError, noconvert, v)
|
||||
|
||||
requires_conversion(Float())
|
||||
assert pytest.approx(convert(Float())) == 41.45
|
||||
|
||||
|
||||
def test_numpy_int_convert():
|
||||
np = pytest.importorskip("numpy")
|
||||
|
||||
@ -362,7 +381,7 @@ def test_tuple(doc):
|
||||
assert (
|
||||
doc(m.tuple_passthrough)
|
||||
== """
|
||||
tuple_passthrough(arg0: tuple[bool, str, int]) -> tuple[int, str, bool]
|
||||
tuple_passthrough(arg0: tuple[bool, str, typing.SupportsInt]) -> tuple[int, str, bool]
|
||||
|
||||
Return a triple in reversed order
|
||||
"""
|
||||
|
@ -138,8 +138,14 @@ def test_cpp_function_roundtrip():
|
||||
|
||||
|
||||
def test_function_signatures(doc):
|
||||
assert doc(m.test_callback3) == "test_callback3(arg0: Callable[[int], int]) -> str"
|
||||
assert doc(m.test_callback4) == "test_callback4() -> Callable[[int], int]"
|
||||
assert (
|
||||
doc(m.test_callback3)
|
||||
== "test_callback3(arg0: Callable[[typing.SupportsInt], int]) -> str"
|
||||
)
|
||||
assert (
|
||||
doc(m.test_callback4)
|
||||
== "test_callback4() -> Callable[[typing.SupportsInt], int]"
|
||||
)
|
||||
|
||||
|
||||
def test_movable_object():
|
||||
|
@ -155,13 +155,13 @@ def test_qualname(doc):
|
||||
assert (
|
||||
doc(m.NestBase.Nested.fn)
|
||||
== """
|
||||
fn(self: m.class_.NestBase.Nested, arg0: int, arg1: m.class_.NestBase, arg2: m.class_.NestBase.Nested) -> None
|
||||
fn(self: m.class_.NestBase.Nested, arg0: typing.SupportsInt, arg1: m.class_.NestBase, arg2: m.class_.NestBase.Nested) -> None
|
||||
"""
|
||||
)
|
||||
assert (
|
||||
doc(m.NestBase.Nested.fa)
|
||||
== """
|
||||
fa(self: m.class_.NestBase.Nested, a: int, b: m.class_.NestBase, c: m.class_.NestBase.Nested) -> None
|
||||
fa(self: m.class_.NestBase.Nested, a: typing.SupportsInt, b: m.class_.NestBase, c: m.class_.NestBase.Nested) -> None
|
||||
"""
|
||||
)
|
||||
assert m.NestBase.__module__ == "pybind11_tests.class_"
|
||||
|
@ -75,7 +75,7 @@ def test_noconvert_args(msg):
|
||||
msg(excinfo.value)
|
||||
== """
|
||||
ints_preferred(): incompatible function arguments. The following argument types are supported:
|
||||
1. (i: int) -> int
|
||||
1. (i: typing.SupportsInt) -> int
|
||||
|
||||
Invoked with: 4.0
|
||||
"""
|
||||
|
@ -19,9 +19,13 @@ def test_docstring_options():
|
||||
assert m.test_overloaded3.__doc__ == "Overload docstr"
|
||||
|
||||
# options.enable_function_signatures()
|
||||
assert m.test_function3.__doc__.startswith("test_function3(a: int, b: int) -> None")
|
||||
assert m.test_function3.__doc__.startswith(
|
||||
"test_function3(a: typing.SupportsInt, b: typing.SupportsInt) -> None"
|
||||
)
|
||||
|
||||
assert m.test_function4.__doc__.startswith("test_function4(a: int, b: int) -> None")
|
||||
assert m.test_function4.__doc__.startswith(
|
||||
"test_function4(a: typing.SupportsInt, b: typing.SupportsInt) -> None"
|
||||
)
|
||||
assert m.test_function4.__doc__.endswith("A custom docstring\n")
|
||||
|
||||
# options.disable_function_signatures()
|
||||
@ -32,7 +36,9 @@ def test_docstring_options():
|
||||
assert m.test_function6.__doc__ == "A custom docstring"
|
||||
|
||||
# RAII destructor
|
||||
assert m.test_function7.__doc__.startswith("test_function7(a: int, b: int) -> None")
|
||||
assert m.test_function7.__doc__.startswith(
|
||||
"test_function7(a: typing.SupportsInt, b: typing.SupportsInt) -> None"
|
||||
)
|
||||
assert m.test_function7.__doc__.endswith("A custom docstring\n")
|
||||
|
||||
# when all options are disabled, no docstring (instead of an empty one) should be generated
|
||||
|
@ -78,10 +78,10 @@ def test_init_factory_signature(msg):
|
||||
msg(excinfo.value)
|
||||
== """
|
||||
__init__(): incompatible constructor arguments. The following argument types are supported:
|
||||
1. m.factory_constructors.TestFactory1(arg0: m.factory_constructors.tag.unique_ptr_tag, arg1: int)
|
||||
1. m.factory_constructors.TestFactory1(arg0: m.factory_constructors.tag.unique_ptr_tag, arg1: typing.SupportsInt)
|
||||
2. m.factory_constructors.TestFactory1(arg0: str)
|
||||
3. m.factory_constructors.TestFactory1(arg0: m.factory_constructors.tag.pointer_tag)
|
||||
4. m.factory_constructors.TestFactory1(arg0: object, arg1: int, arg2: object)
|
||||
4. m.factory_constructors.TestFactory1(arg0: object, arg1: typing.SupportsInt, arg2: object)
|
||||
|
||||
Invoked with: 'invalid', 'constructor', 'arguments'
|
||||
"""
|
||||
@ -93,13 +93,13 @@ def test_init_factory_signature(msg):
|
||||
__init__(*args, **kwargs)
|
||||
Overloaded function.
|
||||
|
||||
1. __init__(self: m.factory_constructors.TestFactory1, arg0: m.factory_constructors.tag.unique_ptr_tag, arg1: int) -> None
|
||||
1. __init__(self: m.factory_constructors.TestFactory1, arg0: m.factory_constructors.tag.unique_ptr_tag, arg1: typing.SupportsInt) -> None
|
||||
|
||||
2. __init__(self: m.factory_constructors.TestFactory1, arg0: str) -> None
|
||||
|
||||
3. __init__(self: m.factory_constructors.TestFactory1, arg0: m.factory_constructors.tag.pointer_tag) -> None
|
||||
|
||||
4. __init__(self: m.factory_constructors.TestFactory1, arg0: object, arg1: int, arg2: object) -> None
|
||||
4. __init__(self: m.factory_constructors.TestFactory1, arg0: object, arg1: typing.SupportsInt, arg2: object) -> None
|
||||
"""
|
||||
)
|
||||
|
||||
|
@ -7,13 +7,31 @@ from pybind11_tests import kwargs_and_defaults as m
|
||||
|
||||
|
||||
def test_function_signatures(doc):
|
||||
assert doc(m.kw_func0) == "kw_func0(arg0: int, arg1: int) -> str"
|
||||
assert doc(m.kw_func1) == "kw_func1(x: int, y: int) -> str"
|
||||
assert doc(m.kw_func2) == "kw_func2(x: int = 100, y: int = 200) -> str"
|
||||
assert (
|
||||
doc(m.kw_func0)
|
||||
== "kw_func0(arg0: typing.SupportsInt, arg1: typing.SupportsInt) -> str"
|
||||
)
|
||||
assert (
|
||||
doc(m.kw_func1)
|
||||
== "kw_func1(x: typing.SupportsInt, y: typing.SupportsInt) -> str"
|
||||
)
|
||||
assert (
|
||||
doc(m.kw_func2)
|
||||
== "kw_func2(x: typing.SupportsInt = 100, y: typing.SupportsInt = 200) -> str"
|
||||
)
|
||||
assert doc(m.kw_func3) == "kw_func3(data: str = 'Hello world!') -> None"
|
||||
assert doc(m.kw_func4) == "kw_func4(myList: list[int] = [13, 17]) -> str"
|
||||
assert doc(m.kw_func_udl) == "kw_func_udl(x: int, y: int = 300) -> str"
|
||||
assert doc(m.kw_func_udl_z) == "kw_func_udl_z(x: int, y: int = 0) -> str"
|
||||
assert (
|
||||
doc(m.kw_func4)
|
||||
== "kw_func4(myList: list[typing.SupportsInt] = [13, 17]) -> str"
|
||||
)
|
||||
assert (
|
||||
doc(m.kw_func_udl)
|
||||
== "kw_func_udl(x: typing.SupportsInt, y: typing.SupportsInt = 300) -> str"
|
||||
)
|
||||
assert (
|
||||
doc(m.kw_func_udl_z)
|
||||
== "kw_func_udl_z(x: typing.SupportsInt, y: typing.SupportsInt = 0) -> str"
|
||||
)
|
||||
assert doc(m.args_function) == "args_function(*args) -> tuple"
|
||||
assert (
|
||||
doc(m.args_kwargs_function) == "args_kwargs_function(*args, **kwargs) -> tuple"
|
||||
@ -24,11 +42,11 @@ def test_function_signatures(doc):
|
||||
)
|
||||
assert (
|
||||
doc(m.KWClass.foo0)
|
||||
== "foo0(self: m.kwargs_and_defaults.KWClass, arg0: int, arg1: float) -> None"
|
||||
== "foo0(self: m.kwargs_and_defaults.KWClass, arg0: typing.SupportsInt, arg1: typing.SupportsFloat) -> None"
|
||||
)
|
||||
assert (
|
||||
doc(m.KWClass.foo1)
|
||||
== "foo1(self: m.kwargs_and_defaults.KWClass, x: int, y: float) -> None"
|
||||
== "foo1(self: m.kwargs_and_defaults.KWClass, x: typing.SupportsInt, y: typing.SupportsFloat) -> None"
|
||||
)
|
||||
assert (
|
||||
doc(m.kw_lb_func0)
|
||||
@ -120,7 +138,7 @@ def test_mixed_args_and_kwargs(msg):
|
||||
msg(excinfo.value)
|
||||
== """
|
||||
mixed_plus_args(): incompatible function arguments. The following argument types are supported:
|
||||
1. (arg0: int, arg1: float, *args) -> tuple
|
||||
1. (arg0: typing.SupportsInt, arg1: typing.SupportsFloat, *args) -> tuple
|
||||
|
||||
Invoked with: 1
|
||||
"""
|
||||
@ -131,7 +149,7 @@ def test_mixed_args_and_kwargs(msg):
|
||||
msg(excinfo.value)
|
||||
== """
|
||||
mixed_plus_args(): incompatible function arguments. The following argument types are supported:
|
||||
1. (arg0: int, arg1: float, *args) -> tuple
|
||||
1. (arg0: typing.SupportsInt, arg1: typing.SupportsFloat, *args) -> tuple
|
||||
|
||||
Invoked with:
|
||||
"""
|
||||
@ -165,7 +183,7 @@ def test_mixed_args_and_kwargs(msg):
|
||||
msg(excinfo.value)
|
||||
== """
|
||||
mixed_plus_args_kwargs_defaults(): incompatible function arguments. The following argument types are supported:
|
||||
1. (i: int = 1, j: float = 3.14159, *args, **kwargs) -> tuple
|
||||
1. (i: typing.SupportsInt = 1, j: typing.SupportsFloat = 3.14159, *args, **kwargs) -> tuple
|
||||
|
||||
Invoked with: 1; kwargs: i=1
|
||||
"""
|
||||
@ -176,7 +194,7 @@ def test_mixed_args_and_kwargs(msg):
|
||||
msg(excinfo.value)
|
||||
== """
|
||||
mixed_plus_args_kwargs_defaults(): incompatible function arguments. The following argument types are supported:
|
||||
1. (i: int = 1, j: float = 3.14159, *args, **kwargs) -> tuple
|
||||
1. (i: typing.SupportsInt = 1, j: typing.SupportsFloat = 3.14159, *args, **kwargs) -> tuple
|
||||
|
||||
Invoked with: 1, 2; kwargs: j=1
|
||||
"""
|
||||
@ -193,7 +211,7 @@ def test_mixed_args_and_kwargs(msg):
|
||||
msg(excinfo.value)
|
||||
== """
|
||||
args_kwonly(): incompatible function arguments. The following argument types are supported:
|
||||
1. (i: int, j: float, *args, z: int) -> tuple
|
||||
1. (i: typing.SupportsInt, j: typing.SupportsFloat, *args, z: typing.SupportsInt) -> tuple
|
||||
|
||||
Invoked with: 2, 2.5, 22
|
||||
"""
|
||||
@ -215,12 +233,12 @@ def test_mixed_args_and_kwargs(msg):
|
||||
)
|
||||
assert (
|
||||
m.args_kwonly_kwargs.__doc__
|
||||
== "args_kwonly_kwargs(i: int, j: float, *args, z: int, **kwargs) -> tuple\n"
|
||||
== "args_kwonly_kwargs(i: typing.SupportsInt, j: typing.SupportsFloat, *args, z: typing.SupportsInt, **kwargs) -> tuple\n"
|
||||
)
|
||||
|
||||
assert (
|
||||
m.args_kwonly_kwargs_defaults.__doc__
|
||||
== "args_kwonly_kwargs_defaults(i: int = 1, j: float = 3.14159, *args, z: int = 42, **kwargs) -> tuple\n"
|
||||
== "args_kwonly_kwargs_defaults(i: typing.SupportsInt = 1, j: typing.SupportsFloat = 3.14159, *args, z: typing.SupportsInt = 42, **kwargs) -> tuple\n"
|
||||
)
|
||||
assert m.args_kwonly_kwargs_defaults() == (1, 3.14159, (), 42, {})
|
||||
assert m.args_kwonly_kwargs_defaults(2) == (2, 3.14159, (), 42, {})
|
||||
@ -276,11 +294,11 @@ def test_keyword_only_args(msg):
|
||||
x.method(i=1, j=2)
|
||||
assert (
|
||||
m.first_arg_kw_only.__init__.__doc__
|
||||
== "__init__(self: pybind11_tests.kwargs_and_defaults.first_arg_kw_only, *, i: int = 0) -> None\n"
|
||||
== "__init__(self: pybind11_tests.kwargs_and_defaults.first_arg_kw_only, *, i: typing.SupportsInt = 0) -> None\n"
|
||||
)
|
||||
assert (
|
||||
m.first_arg_kw_only.method.__doc__
|
||||
== "method(self: pybind11_tests.kwargs_and_defaults.first_arg_kw_only, *, i: int = 1, j: int = 2) -> None\n"
|
||||
== "method(self: pybind11_tests.kwargs_and_defaults.first_arg_kw_only, *, i: typing.SupportsInt = 1, j: typing.SupportsInt = 2) -> None\n"
|
||||
)
|
||||
|
||||
|
||||
@ -326,7 +344,7 @@ def test_positional_only_args():
|
||||
# Mix it with args and kwargs:
|
||||
assert (
|
||||
m.args_kwonly_full_monty.__doc__
|
||||
== "args_kwonly_full_monty(arg0: int = 1, arg1: int = 2, /, j: float = 3.14159, *args, z: int = 42, **kwargs) -> tuple\n"
|
||||
== "args_kwonly_full_monty(arg0: typing.SupportsInt = 1, arg1: typing.SupportsInt = 2, /, j: typing.SupportsFloat = 3.14159, *args, z: typing.SupportsInt = 42, **kwargs) -> tuple\n"
|
||||
)
|
||||
assert m.args_kwonly_full_monty() == (1, 2, 3.14159, (), 42, {})
|
||||
assert m.args_kwonly_full_monty(8) == (8, 2, 3.14159, (), 42, {})
|
||||
@ -369,18 +387,30 @@ def test_positional_only_args():
|
||||
# https://github.com/pybind/pybind11/pull/3402#issuecomment-963341987
|
||||
assert (
|
||||
m.first_arg_kw_only.pos_only.__doc__
|
||||
== "pos_only(self: pybind11_tests.kwargs_and_defaults.first_arg_kw_only, /, i: int, j: int) -> None\n"
|
||||
== "pos_only(self: pybind11_tests.kwargs_and_defaults.first_arg_kw_only, /, i: typing.SupportsInt, j: typing.SupportsInt) -> None\n"
|
||||
)
|
||||
|
||||
|
||||
def test_signatures():
|
||||
assert m.kw_only_all.__doc__ == "kw_only_all(*, i: int, j: int) -> tuple\n"
|
||||
assert m.kw_only_mixed.__doc__ == "kw_only_mixed(i: int, *, j: int) -> tuple\n"
|
||||
assert m.pos_only_all.__doc__ == "pos_only_all(i: int, j: int, /) -> tuple\n"
|
||||
assert m.pos_only_mix.__doc__ == "pos_only_mix(i: int, /, j: int) -> tuple\n"
|
||||
assert (
|
||||
m.kw_only_all.__doc__
|
||||
== "kw_only_all(*, i: typing.SupportsInt, j: typing.SupportsInt) -> tuple\n"
|
||||
)
|
||||
assert (
|
||||
m.kw_only_mixed.__doc__
|
||||
== "kw_only_mixed(i: typing.SupportsInt, *, j: typing.SupportsInt) -> tuple\n"
|
||||
)
|
||||
assert (
|
||||
m.pos_only_all.__doc__
|
||||
== "pos_only_all(i: typing.SupportsInt, j: typing.SupportsInt, /) -> tuple\n"
|
||||
)
|
||||
assert (
|
||||
m.pos_only_mix.__doc__
|
||||
== "pos_only_mix(i: typing.SupportsInt, /, j: typing.SupportsInt) -> tuple\n"
|
||||
)
|
||||
assert (
|
||||
m.pos_kw_only_mix.__doc__
|
||||
== "pos_kw_only_mix(i: int, /, j: int, *, k: int) -> tuple\n"
|
||||
== "pos_kw_only_mix(i: typing.SupportsInt, /, j: typing.SupportsInt, *, k: typing.SupportsInt) -> tuple\n"
|
||||
)
|
||||
|
||||
|
||||
|
@ -251,7 +251,7 @@ def test_no_mixed_overloads():
|
||||
"#define PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for more details"
|
||||
if not detailed_error_messages_enabled
|
||||
else "error while attempting to bind static method ExampleMandA.overload_mixed1"
|
||||
"(arg0: float) -> str"
|
||||
"(arg0: typing.SupportsFloat) -> str"
|
||||
)
|
||||
)
|
||||
|
||||
@ -264,7 +264,7 @@ def test_no_mixed_overloads():
|
||||
"#define PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for more details"
|
||||
if not detailed_error_messages_enabled
|
||||
else "error while attempting to bind instance method ExampleMandA.overload_mixed2"
|
||||
"(self: pybind11_tests.methods_and_attributes.ExampleMandA, arg0: int, arg1: int)"
|
||||
"(self: pybind11_tests.methods_and_attributes.ExampleMandA, arg0: typing.SupportsInt, arg1: typing.SupportsInt)"
|
||||
" -> str"
|
||||
)
|
||||
)
|
||||
@ -479,7 +479,7 @@ def test_str_issue(msg):
|
||||
msg(excinfo.value)
|
||||
== """
|
||||
__init__(): incompatible constructor arguments. The following argument types are supported:
|
||||
1. m.methods_and_attributes.StrIssue(arg0: int)
|
||||
1. m.methods_and_attributes.StrIssue(arg0: typing.SupportsInt)
|
||||
2. m.methods_and_attributes.StrIssue()
|
||||
|
||||
Invoked with: 'no', 'such', 'constructor'
|
||||
@ -521,18 +521,22 @@ def test_overload_ordering():
|
||||
assert m.overload_order("string") == 1
|
||||
assert m.overload_order(0) == 4
|
||||
|
||||
assert "1. overload_order(arg0: int) -> int" in m.overload_order.__doc__
|
||||
assert (
|
||||
"1. overload_order(arg0: typing.SupportsInt) -> int" in m.overload_order.__doc__
|
||||
)
|
||||
assert "2. overload_order(arg0: str) -> int" in m.overload_order.__doc__
|
||||
assert "3. overload_order(arg0: str) -> int" in m.overload_order.__doc__
|
||||
assert "4. overload_order(arg0: int) -> int" in m.overload_order.__doc__
|
||||
assert (
|
||||
"4. overload_order(arg0: typing.SupportsInt) -> int" in m.overload_order.__doc__
|
||||
)
|
||||
|
||||
with pytest.raises(TypeError) as err:
|
||||
m.overload_order(1.1)
|
||||
|
||||
assert "1. (arg0: int) -> int" in str(err.value)
|
||||
assert "1. (arg0: typing.SupportsInt) -> int" in str(err.value)
|
||||
assert "2. (arg0: str) -> int" in str(err.value)
|
||||
assert "3. (arg0: str) -> int" in str(err.value)
|
||||
assert "4. (arg0: int) -> int" in str(err.value)
|
||||
assert "4. (arg0: typing.SupportsInt) -> int" in str(err.value)
|
||||
|
||||
|
||||
def test_rvalue_ref_param():
|
||||
|
@ -373,7 +373,7 @@ def test_complex_array():
|
||||
def test_signature(doc):
|
||||
assert (
|
||||
doc(m.create_rec_nested)
|
||||
== "create_rec_nested(arg0: int) -> numpy.typing.NDArray[NestedStruct]"
|
||||
== "create_rec_nested(arg0: typing.SupportsInt) -> numpy.typing.NDArray[NestedStruct]"
|
||||
)
|
||||
|
||||
|
||||
|
@ -211,11 +211,11 @@ def test_passthrough_arguments(doc):
|
||||
"vec_passthrough("
|
||||
+ ", ".join(
|
||||
[
|
||||
"arg0: float",
|
||||
"arg0: typing.SupportsFloat",
|
||||
"arg1: typing.Annotated[numpy.typing.ArrayLike, numpy.float64]",
|
||||
"arg2: typing.Annotated[numpy.typing.ArrayLike, numpy.float64]",
|
||||
"arg3: typing.Annotated[numpy.typing.ArrayLike, numpy.int32]",
|
||||
"arg4: int",
|
||||
"arg4: typing.SupportsInt",
|
||||
"arg5: m.numpy_vectorize.NonPODClass",
|
||||
"arg6: typing.Annotated[numpy.typing.ArrayLike, numpy.float64]",
|
||||
]
|
||||
|
@ -917,7 +917,7 @@ def test_inplace_rshift(a, b):
|
||||
def test_tuple_nonempty_annotations(doc):
|
||||
assert (
|
||||
doc(m.annotate_tuple_float_str)
|
||||
== "annotate_tuple_float_str(arg0: tuple[float, str]) -> None"
|
||||
== "annotate_tuple_float_str(arg0: tuple[typing.SupportsFloat, str]) -> None"
|
||||
)
|
||||
|
||||
|
||||
@ -930,19 +930,22 @@ def test_tuple_empty_annotations(doc):
|
||||
def test_tuple_variable_length_annotations(doc):
|
||||
assert (
|
||||
doc(m.annotate_tuple_variable_length)
|
||||
== "annotate_tuple_variable_length(arg0: tuple[float, ...]) -> None"
|
||||
== "annotate_tuple_variable_length(arg0: tuple[typing.SupportsFloat, ...]) -> None"
|
||||
)
|
||||
|
||||
|
||||
def test_dict_annotations(doc):
|
||||
assert (
|
||||
doc(m.annotate_dict_str_int)
|
||||
== "annotate_dict_str_int(arg0: dict[str, int]) -> None"
|
||||
== "annotate_dict_str_int(arg0: dict[str, typing.SupportsInt]) -> None"
|
||||
)
|
||||
|
||||
|
||||
def test_list_annotations(doc):
|
||||
assert doc(m.annotate_list_int) == "annotate_list_int(arg0: list[int]) -> None"
|
||||
assert (
|
||||
doc(m.annotate_list_int)
|
||||
== "annotate_list_int(arg0: list[typing.SupportsInt]) -> None"
|
||||
)
|
||||
|
||||
|
||||
def test_set_annotations(doc):
|
||||
@ -959,7 +962,7 @@ def test_iterable_annotations(doc):
|
||||
def test_iterator_annotations(doc):
|
||||
assert (
|
||||
doc(m.annotate_iterator_int)
|
||||
== "annotate_iterator_int(arg0: Iterator[int]) -> None"
|
||||
== "annotate_iterator_int(arg0: Iterator[typing.SupportsInt]) -> None"
|
||||
)
|
||||
|
||||
|
||||
@ -978,13 +981,15 @@ def test_fn_return_only(doc):
|
||||
|
||||
|
||||
def test_type_annotation(doc):
|
||||
assert doc(m.annotate_type) == "annotate_type(arg0: type[int]) -> type"
|
||||
assert (
|
||||
doc(m.annotate_type) == "annotate_type(arg0: type[typing.SupportsInt]) -> type"
|
||||
)
|
||||
|
||||
|
||||
def test_union_annotations(doc):
|
||||
assert (
|
||||
doc(m.annotate_union)
|
||||
== "annotate_union(arg0: list[Union[str, int, object]], arg1: str, arg2: int, arg3: object) -> list[Union[str, int, object]]"
|
||||
== "annotate_union(arg0: list[Union[str, typing.SupportsInt, object]], arg1: str, arg2: typing.SupportsInt, arg3: object) -> list[Union[str, int, object]]"
|
||||
)
|
||||
|
||||
|
||||
@ -998,7 +1003,7 @@ def test_union_typing_only(doc):
|
||||
def test_union_object_annotations(doc):
|
||||
assert (
|
||||
doc(m.annotate_union_to_object)
|
||||
== "annotate_union_to_object(arg0: Union[int, str]) -> object"
|
||||
== "annotate_union_to_object(arg0: Union[typing.SupportsInt, str]) -> object"
|
||||
)
|
||||
|
||||
|
||||
@ -1031,7 +1036,7 @@ def test_never_annotation(doc):
|
||||
def test_optional_object_annotations(doc):
|
||||
assert (
|
||||
doc(m.annotate_optional_to_object)
|
||||
== "annotate_optional_to_object(arg0: Optional[int]) -> object"
|
||||
== "annotate_optional_to_object(arg0: Optional[typing.SupportsInt]) -> object"
|
||||
)
|
||||
|
||||
|
||||
@ -1150,7 +1155,7 @@ def get_annotations_helper(o):
|
||||
def test_module_attribute_types() -> None:
|
||||
module_annotations = get_annotations_helper(m)
|
||||
|
||||
assert module_annotations["list_int"] == "list[int]"
|
||||
assert module_annotations["list_int"] == "list[typing.SupportsInt]"
|
||||
assert module_annotations["set_str"] == "set[str]"
|
||||
|
||||
|
||||
@ -1167,7 +1172,7 @@ def test_get_annotations_compliance() -> None:
|
||||
|
||||
module_annotations = get_annotations(m)
|
||||
|
||||
assert module_annotations["list_int"] == "list[int]"
|
||||
assert module_annotations["list_int"] == "list[typing.SupportsInt]"
|
||||
assert module_annotations["set_str"] == "set[str]"
|
||||
|
||||
|
||||
@ -1181,8 +1186,10 @@ def test_class_attribute_types() -> None:
|
||||
instance_annotations = get_annotations_helper(m.Instance)
|
||||
|
||||
assert empty_annotations is None
|
||||
assert static_annotations["x"] == "ClassVar[float]"
|
||||
assert static_annotations["dict_str_int"] == "ClassVar[dict[str, int]]"
|
||||
assert static_annotations["x"] == "ClassVar[typing.SupportsFloat]"
|
||||
assert (
|
||||
static_annotations["dict_str_int"] == "ClassVar[dict[str, typing.SupportsInt]]"
|
||||
)
|
||||
|
||||
assert m.Static.x == 1.0
|
||||
|
||||
@ -1193,7 +1200,7 @@ def test_class_attribute_types() -> None:
|
||||
static.dict_str_int["hi"] = 3
|
||||
assert m.Static().dict_str_int == {"hi": 3}
|
||||
|
||||
assert instance_annotations["y"] == "float"
|
||||
assert instance_annotations["y"] == "typing.SupportsFloat"
|
||||
instance1 = m.Instance()
|
||||
instance1.y = 4.0
|
||||
|
||||
@ -1210,7 +1217,7 @@ def test_class_attribute_types() -> None:
|
||||
def test_redeclaration_attr_with_type_hint() -> None:
|
||||
obj = m.Instance()
|
||||
m.attr_with_type_hint_float_x(obj)
|
||||
assert get_annotations_helper(obj)["x"] == "float"
|
||||
assert get_annotations_helper(obj)["x"] == "typing.SupportsFloat"
|
||||
with pytest.raises(
|
||||
RuntimeError, match=r'^__annotations__\["x"\] was set already\.$'
|
||||
):
|
||||
|
@ -20,7 +20,7 @@ def test_vector(doc):
|
||||
assert m.load_bool_vector((True, False))
|
||||
|
||||
assert doc(m.cast_vector) == "cast_vector() -> list[int]"
|
||||
assert doc(m.load_vector) == "load_vector(arg0: list[int]) -> bool"
|
||||
assert doc(m.load_vector) == "load_vector(arg0: list[typing.SupportsInt]) -> bool"
|
||||
|
||||
# Test regression caused by 936: pointers to stl containers weren't castable
|
||||
assert m.cast_ptr_vector() == ["lvalue", "lvalue"]
|
||||
@ -45,7 +45,7 @@ def test_array(doc):
|
||||
assert doc(m.cast_array) == "cast_array() -> Annotated[list[int], FixedSize(2)]"
|
||||
assert (
|
||||
doc(m.load_array)
|
||||
== "load_array(arg0: Annotated[list[int], FixedSize(2)]) -> bool"
|
||||
== "load_array(arg0: Annotated[list[typing.SupportsInt], FixedSize(2)]) -> bool"
|
||||
)
|
||||
|
||||
|
||||
@ -64,7 +64,9 @@ def test_valarray(doc):
|
||||
assert m.load_valarray(tuple(lst))
|
||||
|
||||
assert doc(m.cast_valarray) == "cast_valarray() -> list[int]"
|
||||
assert doc(m.load_valarray) == "load_valarray(arg0: list[int]) -> bool"
|
||||
assert (
|
||||
doc(m.load_valarray) == "load_valarray(arg0: list[typing.SupportsInt]) -> bool"
|
||||
)
|
||||
|
||||
|
||||
def test_map(doc):
|
||||
@ -325,7 +327,8 @@ def test_variant(doc):
|
||||
assert m.cast_variant() == (5, "Hello")
|
||||
|
||||
assert (
|
||||
doc(m.load_variant) == "load_variant(arg0: Union[int, str, float, None]) -> str"
|
||||
doc(m.load_variant)
|
||||
== "load_variant(arg0: Union[typing.SupportsInt, str, typing.SupportsFloat, None]) -> str"
|
||||
)
|
||||
|
||||
|
||||
@ -341,7 +344,7 @@ def test_variant_monostate(doc):
|
||||
|
||||
assert (
|
||||
doc(m.load_monostate_variant)
|
||||
== "load_monostate_variant(arg0: Union[None, int, str]) -> str"
|
||||
== "load_monostate_variant(arg0: Union[None, typing.SupportsInt, str]) -> str"
|
||||
)
|
||||
|
||||
|
||||
@ -361,7 +364,7 @@ def test_stl_pass_by_pointer(msg):
|
||||
msg(excinfo.value)
|
||||
== """
|
||||
stl_pass_by_pointer(): incompatible function arguments. The following argument types are supported:
|
||||
1. (v: list[int] = None) -> list[int]
|
||||
1. (v: list[typing.SupportsInt] = None) -> list[int]
|
||||
|
||||
Invoked with:
|
||||
"""
|
||||
@ -373,7 +376,7 @@ def test_stl_pass_by_pointer(msg):
|
||||
msg(excinfo.value)
|
||||
== """
|
||||
stl_pass_by_pointer(): incompatible function arguments. The following argument types are supported:
|
||||
1. (v: list[int] = None) -> list[int]
|
||||
1. (v: list[typing.SupportsInt] = None) -> list[int]
|
||||
|
||||
Invoked with: None
|
||||
"""
|
||||
|
@ -102,7 +102,9 @@ def test_return_list_pyobject_ptr_reference():
|
||||
|
||||
|
||||
def test_type_caster_name_via_incompatible_function_arguments_type_error():
|
||||
with pytest.raises(TypeError, match=r"1\. \(arg0: object, arg1: int\) -> None"):
|
||||
with pytest.raises(
|
||||
TypeError, match=r"1\. \(arg0: object, arg1: typing.SupportsInt\) -> None"
|
||||
):
|
||||
m.pass_pyobject_ptr_and_int(ValueHolder(101), ValueHolder(202))
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user