mirror of
https://github.com/pybind/pybind11.git
synced 2025-02-24 01:19:23 +00:00
Merge branch 'pybind:master' into master
This commit is contained in:
commit
85b385d27b
2
.github/workflows/pip.yml
vendored
2
.github/workflows/pip.yml
vendored
@ -103,7 +103,7 @@ jobs:
|
|||||||
- uses: actions/download-artifact@v4
|
- uses: actions/download-artifact@v4
|
||||||
|
|
||||||
- name: Generate artifact attestation for sdist and wheel
|
- name: Generate artifact attestation for sdist and wheel
|
||||||
uses: actions/attest-build-provenance@c4fbc648846ca6f503a13a2281a5e7b98aa57202 # v2.0.1
|
uses: actions/attest-build-provenance@7668571508540a607bdfd90a87a560489fe372eb # v2.1.0
|
||||||
with:
|
with:
|
||||||
subject-path: "*/pybind11*"
|
subject-path: "*/pybind11*"
|
||||||
|
|
||||||
|
@ -1366,6 +1366,31 @@ object object_or_cast(T &&o) {
|
|||||||
return pybind11::cast(std::forward<T>(o));
|
return pybind11::cast(std::forward<T>(o));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Declared in pytypes.h:
|
||||||
|
// Implemented here so that make_caster<T> can be used.
|
||||||
|
template <typename D>
|
||||||
|
template <typename T>
|
||||||
|
str_attr_accessor object_api<D>::attr_with_type_hint(const char *key) const {
|
||||||
|
#if !defined(__cpp_inline_variables)
|
||||||
|
static_assert(always_false<T>::value,
|
||||||
|
"C++17 feature __cpp_inline_variables not available: "
|
||||||
|
"https://en.cppreference.com/w/cpp/language/static#Static_data_members");
|
||||||
|
#endif
|
||||||
|
object ann = annotations();
|
||||||
|
if (ann.contains(key)) {
|
||||||
|
throw std::runtime_error("__annotations__[\"" + std::string(key) + "\"] was set already.");
|
||||||
|
}
|
||||||
|
ann[key] = make_caster<T>::name.text;
|
||||||
|
return {derived(), key};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename D>
|
||||||
|
template <typename T>
|
||||||
|
obj_attr_accessor object_api<D>::attr_with_type_hint(handle key) const {
|
||||||
|
(void) attr_with_type_hint<T>(key.cast<std::string>().c_str());
|
||||||
|
return {derived(), reinterpret_borrow<object>(key)};
|
||||||
|
}
|
||||||
|
|
||||||
// Placeholder type for the unneeded (and dead code) static variable in the
|
// Placeholder type for the unneeded (and dead code) static variable in the
|
||||||
// PYBIND11_OVERRIDE_OVERRIDE macro
|
// PYBIND11_OVERRIDE_OVERRIDE macro
|
||||||
struct override_unused {};
|
struct override_unused {};
|
||||||
|
@ -12,51 +12,32 @@
|
|||||||
#define PYBIND11_PLATFORM_ABI_ID_STRINGIFY(x) #x
|
#define PYBIND11_PLATFORM_ABI_ID_STRINGIFY(x) #x
|
||||||
#define PYBIND11_PLATFORM_ABI_ID_TOSTRING(x) PYBIND11_PLATFORM_ABI_ID_STRINGIFY(x)
|
#define PYBIND11_PLATFORM_ABI_ID_TOSTRING(x) PYBIND11_PLATFORM_ABI_ID_STRINGIFY(x)
|
||||||
|
|
||||||
// On MSVC, debug and release builds are not ABI-compatible!
|
#ifdef PYBIND11_COMPILER_TYPE
|
||||||
#if defined(_MSC_VER) && defined(_DEBUG)
|
// // To maintain backward compatibility (see PR #5439).
|
||||||
# define PYBIND11_BUILD_TYPE "_debug"
|
# define PYBIND11_COMPILER_TYPE_LEADING_UNDERSCORE ""
|
||||||
#else
|
#else
|
||||||
# define PYBIND11_BUILD_TYPE ""
|
# define PYBIND11_COMPILER_TYPE_LEADING_UNDERSCORE "_"
|
||||||
#endif
|
# if defined(__MINGW32__)
|
||||||
|
# define PYBIND11_COMPILER_TYPE "mingw"
|
||||||
// Let's assume that different compilers are ABI-incompatible.
|
|
||||||
// A user can manually set this string if they know their
|
|
||||||
// compiler is compatible.
|
|
||||||
#ifndef PYBIND11_COMPILER_TYPE
|
|
||||||
# if defined(_MSC_VER)
|
|
||||||
# define PYBIND11_COMPILER_TYPE "_msvc"
|
|
||||||
# elif defined(__INTEL_COMPILER)
|
|
||||||
# define PYBIND11_COMPILER_TYPE "_icc"
|
|
||||||
# elif defined(__clang__)
|
|
||||||
# define PYBIND11_COMPILER_TYPE "_clang"
|
|
||||||
# elif defined(__PGI)
|
|
||||||
# define PYBIND11_COMPILER_TYPE "_pgi"
|
|
||||||
# elif defined(__MINGW32__)
|
|
||||||
# define PYBIND11_COMPILER_TYPE "_mingw"
|
|
||||||
# elif defined(__CYGWIN__)
|
# elif defined(__CYGWIN__)
|
||||||
# define PYBIND11_COMPILER_TYPE "_gcc_cygwin"
|
# define PYBIND11_COMPILER_TYPE "gcc_cygwin"
|
||||||
# elif defined(__GNUC__)
|
# elif defined(_MSC_VER)
|
||||||
# define PYBIND11_COMPILER_TYPE "_gcc"
|
# define PYBIND11_COMPILER_TYPE "msvc"
|
||||||
|
# elif defined(__clang__) || defined(__GNUC__)
|
||||||
|
# define PYBIND11_COMPILER_TYPE "system" // Assumed compatible with system compiler.
|
||||||
# else
|
# else
|
||||||
# define PYBIND11_COMPILER_TYPE "_unknown"
|
# error "Unknown PYBIND11_COMPILER_TYPE: PLEASE REVISE THIS CODE."
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Also standard libs
|
// PR #5439 made this macro obsolete. However, there are many manipulations of this macro in the
|
||||||
|
// wild. Therefore, to maintain backward compatibility, it is kept around.
|
||||||
#ifndef PYBIND11_STDLIB
|
#ifndef PYBIND11_STDLIB
|
||||||
# if defined(_LIBCPP_VERSION)
|
|
||||||
# define PYBIND11_STDLIB "_libcpp"
|
|
||||||
# elif defined(__GLIBCXX__) || defined(__GLIBCPP__)
|
|
||||||
# define PYBIND11_STDLIB "_libstdcpp"
|
|
||||||
# else
|
|
||||||
# define PYBIND11_STDLIB ""
|
# define PYBIND11_STDLIB ""
|
||||||
#endif
|
#endif
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef PYBIND11_BUILD_ABI
|
#ifndef PYBIND11_BUILD_ABI
|
||||||
# if defined(__GXX_ABI_VERSION) // Linux/OSX.
|
# if defined(_MSC_VER) // See PR #4953.
|
||||||
# define PYBIND11_BUILD_ABI "_cxxabi" PYBIND11_PLATFORM_ABI_ID_TOSTRING(__GXX_ABI_VERSION)
|
|
||||||
# elif defined(_MSC_VER) // See PR #4953.
|
|
||||||
# if defined(_MT) && defined(_DLL) // Corresponding to CL command line options /MD or /MDd.
|
# if defined(_MT) && defined(_DLL) // Corresponding to CL command line options /MD or /MDd.
|
||||||
# if (_MSC_VER) / 100 == 19
|
# if (_MSC_VER) / 100 == 19
|
||||||
# define PYBIND11_BUILD_ABI "_md_mscver19"
|
# define PYBIND11_BUILD_ABI "_md_mscver19"
|
||||||
@ -72,17 +53,35 @@
|
|||||||
# error "Unknown major version for MSC_VER: PLEASE REVISE THIS CODE."
|
# error "Unknown major version for MSC_VER: PLEASE REVISE THIS CODE."
|
||||||
# endif
|
# endif
|
||||||
# endif
|
# endif
|
||||||
# elif defined(__NVCOMPILER) // NVHPC (PGI-based).
|
# elif defined(_LIBCPP_ABI_VERSION) // https://libcxx.llvm.org/DesignDocs/ABIVersioning.html
|
||||||
# define PYBIND11_BUILD_ABI "" // TODO: What should be here, to prevent UB?
|
# define PYBIND11_BUILD_ABI \
|
||||||
|
"_libcpp_abi" PYBIND11_PLATFORM_ABI_ID_TOSTRING(_LIBCPP_ABI_VERSION)
|
||||||
|
# elif defined(_GLIBCXX_USE_CXX11_ABI) // See PR #5439.
|
||||||
|
# if defined(__NVCOMPILER)
|
||||||
|
// // Assume that NVHPC is in the 1xxx ABI family.
|
||||||
|
// // THIS ASSUMPTION IS NOT FUTURE PROOF but apparently the best we can do.
|
||||||
|
// // Please let us know if there is a way to validate the assumption here.
|
||||||
|
# elif !defined(__GXX_ABI_VERSION)
|
||||||
|
# error \
|
||||||
|
"Unknown platform or compiler (_GLIBCXX_USE_CXX11_ABI): PLEASE REVISE THIS CODE."
|
||||||
|
# endif
|
||||||
|
# if defined(__GXX_ABI_VERSION) && __GXX_ABI_VERSION < 1002 || __GXX_ABI_VERSION >= 2000
|
||||||
|
# error "Unknown platform or compiler (__GXX_ABI_VERSION): PLEASE REVISE THIS CODE."
|
||||||
|
# endif
|
||||||
|
# define PYBIND11_BUILD_ABI \
|
||||||
|
"_libstdcpp_gxx_abi_1xxx_use_cxx11_abi_" PYBIND11_PLATFORM_ABI_ID_TOSTRING( \
|
||||||
|
_GLIBCXX_USE_CXX11_ABI)
|
||||||
# else
|
# else
|
||||||
# error "Unknown platform or compiler: PLEASE REVISE THIS CODE."
|
# error "Unknown platform or compiler: PLEASE REVISE THIS CODE."
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef PYBIND11_INTERNALS_KIND
|
// On MSVC, debug and release builds are not ABI-compatible!
|
||||||
# define PYBIND11_INTERNALS_KIND ""
|
#if defined(_MSC_VER) && defined(_DEBUG)
|
||||||
|
# define PYBIND11_BUILD_TYPE "_debug"
|
||||||
|
#else
|
||||||
|
# define PYBIND11_BUILD_TYPE ""
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define PYBIND11_PLATFORM_ABI_ID \
|
#define PYBIND11_PLATFORM_ABI_ID \
|
||||||
PYBIND11_INTERNALS_KIND PYBIND11_COMPILER_TYPE PYBIND11_STDLIB PYBIND11_BUILD_ABI \
|
PYBIND11_COMPILER_TYPE PYBIND11_STDLIB PYBIND11_BUILD_ABI PYBIND11_BUILD_TYPE
|
||||||
PYBIND11_BUILD_TYPE
|
|
||||||
|
@ -627,6 +627,14 @@ struct instance {
|
|||||||
static_assert(std::is_standard_layout<instance>::value,
|
static_assert(std::is_standard_layout<instance>::value,
|
||||||
"Internal error: `pybind11::detail::instance` is not standard layout!");
|
"Internal error: `pybind11::detail::instance` is not standard layout!");
|
||||||
|
|
||||||
|
// Some older compilers (e.g. gcc 9.4.0) require
|
||||||
|
// static_assert(always_false<T>::value, "...");
|
||||||
|
// instead of
|
||||||
|
// static_assert(false, "...");
|
||||||
|
// to trigger the static_assert() in a template only if it is actually instantiated.
|
||||||
|
template <typename>
|
||||||
|
struct always_false : std::false_type {};
|
||||||
|
|
||||||
/// from __cpp_future__ import (convenient aliases from C++14/17)
|
/// from __cpp_future__ import (convenient aliases from C++14/17)
|
||||||
#if defined(PYBIND11_CPP14)
|
#if defined(PYBIND11_CPP14)
|
||||||
using std::conditional_t;
|
using std::conditional_t;
|
||||||
|
@ -272,11 +272,11 @@ struct type_info {
|
|||||||
|
|
||||||
#define PYBIND11_INTERNALS_ID \
|
#define PYBIND11_INTERNALS_ID \
|
||||||
"__pybind11_internals_v" PYBIND11_TOSTRING(PYBIND11_INTERNALS_VERSION) \
|
"__pybind11_internals_v" PYBIND11_TOSTRING(PYBIND11_INTERNALS_VERSION) \
|
||||||
PYBIND11_PLATFORM_ABI_ID "__"
|
PYBIND11_COMPILER_TYPE_LEADING_UNDERSCORE PYBIND11_PLATFORM_ABI_ID "__"
|
||||||
|
|
||||||
#define PYBIND11_MODULE_LOCAL_ID \
|
#define PYBIND11_MODULE_LOCAL_ID \
|
||||||
"__pybind11_module_local_v" PYBIND11_TOSTRING(PYBIND11_INTERNALS_VERSION) \
|
"__pybind11_module_local_v" PYBIND11_TOSTRING(PYBIND11_INTERNALS_VERSION) \
|
||||||
PYBIND11_PLATFORM_ABI_ID "__"
|
PYBIND11_COMPILER_TYPE_LEADING_UNDERSCORE PYBIND11_PLATFORM_ABI_ID "__"
|
||||||
|
|
||||||
/// Each module locally stores a pointer to the `internals` data. The data
|
/// Each module locally stores a pointer to the `internals` data. The data
|
||||||
/// itself is shared among modules with the same `PYBIND11_INTERNALS_ID`.
|
/// itself is shared among modules with the same `PYBIND11_INTERNALS_ID`.
|
||||||
|
@ -113,6 +113,17 @@ public:
|
|||||||
/// See above (the only difference is that the key is provided as a string literal)
|
/// See above (the only difference is that the key is provided as a string literal)
|
||||||
str_attr_accessor attr(const char *key) const;
|
str_attr_accessor attr(const char *key) const;
|
||||||
|
|
||||||
|
/** \rst
|
||||||
|
Similar to the above attr functions with the difference that the templated Type
|
||||||
|
is used to set the `__annotations__` dict value to the corresponding key. Worth noting
|
||||||
|
that attr_with_type_hint is implemented in cast.h.
|
||||||
|
\endrst */
|
||||||
|
template <typename T>
|
||||||
|
obj_attr_accessor attr_with_type_hint(handle key) const;
|
||||||
|
/// See above (the only difference is that the key is provided as a string literal)
|
||||||
|
template <typename T>
|
||||||
|
str_attr_accessor attr_with_type_hint(const char *key) const;
|
||||||
|
|
||||||
/** \rst
|
/** \rst
|
||||||
Matches * unpacking in Python, e.g. to unpack arguments out of a ``tuple``
|
Matches * unpacking in Python, e.g. to unpack arguments out of a ``tuple``
|
||||||
or ``list`` for a function call. Applying another * to the result yields
|
or ``list`` for a function call. Applying another * to the result yields
|
||||||
@ -182,6 +193,9 @@ public:
|
|||||||
/// Get or set the object's docstring, i.e. ``obj.__doc__``.
|
/// Get or set the object's docstring, i.e. ``obj.__doc__``.
|
||||||
str_attr_accessor doc() const;
|
str_attr_accessor doc() const;
|
||||||
|
|
||||||
|
/// Get or set the object's annotations, i.e. ``obj.__annotations__``.
|
||||||
|
object annotations() const;
|
||||||
|
|
||||||
/// Return the object's current reference count
|
/// Return the object's current reference count
|
||||||
ssize_t ref_count() const {
|
ssize_t ref_count() const {
|
||||||
#ifdef PYPY_VERSION
|
#ifdef PYPY_VERSION
|
||||||
@ -2558,6 +2572,19 @@ str_attr_accessor object_api<D>::doc() const {
|
|||||||
return attr("__doc__");
|
return attr("__doc__");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename D>
|
||||||
|
object object_api<D>::annotations() const {
|
||||||
|
#if PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION <= 9
|
||||||
|
// https://docs.python.org/3/howto/annotations.html#accessing-the-annotations-dict-of-an-object-in-python-3-9-and-older
|
||||||
|
if (!hasattr(derived(), "__annotations__")) {
|
||||||
|
setattr(derived(), "__annotations__", dict());
|
||||||
|
}
|
||||||
|
return attr("__annotations__");
|
||||||
|
#else
|
||||||
|
return getattr(derived(), "__annotations__", dict());
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
template <typename D>
|
template <typename D>
|
||||||
handle object_api<D>::get_type() const {
|
handle object_api<D>::get_type() const {
|
||||||
return type::handle_of(derived());
|
return type::handle_of(derived());
|
||||||
|
@ -82,6 +82,18 @@ class Optional : public object {
|
|||||||
using object::object;
|
using object::object;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class Final : public object {
|
||||||
|
PYBIND11_OBJECT_DEFAULT(Final, object, PyObject_Type)
|
||||||
|
using object::object;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class ClassVar : public object {
|
||||||
|
PYBIND11_OBJECT_DEFAULT(ClassVar, object, PyObject_Type)
|
||||||
|
using object::object;
|
||||||
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
class TypeGuard : public bool_ {
|
class TypeGuard : public bool_ {
|
||||||
using bool_::bool_;
|
using bool_::bool_;
|
||||||
@ -251,6 +263,16 @@ struct handle_type_name<typing::Optional<T>> {
|
|||||||
= const_name("Optional[") + as_return_type<make_caster<T>>::name + const_name("]");
|
= const_name("Optional[") + as_return_type<make_caster<T>>::name + const_name("]");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct handle_type_name<typing::Final<T>> {
|
||||||
|
static constexpr auto name = const_name("Final[") + make_caster<T>::name + const_name("]");
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct handle_type_name<typing::ClassVar<T>> {
|
||||||
|
static constexpr auto name = const_name("ClassVar[") + make_caster<T>::name + const_name("]");
|
||||||
|
};
|
||||||
|
|
||||||
// TypeGuard and TypeIs use as_return_type to use the return type if available, which is usually
|
// TypeGuard and TypeIs use as_return_type to use the return type if available, which is usually
|
||||||
// the narrower type.
|
// the narrower type.
|
||||||
|
|
||||||
|
@ -1037,6 +1037,38 @@ TEST_SUBMODULE(pytypes, m) {
|
|||||||
#else
|
#else
|
||||||
m.attr("defined_PYBIND11_TEST_PYTYPES_HAS_RANGES") = false;
|
m.attr("defined_PYBIND11_TEST_PYTYPES_HAS_RANGES") = false;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(__cpp_inline_variables)
|
||||||
|
// Exercises const char* overload:
|
||||||
|
m.attr_with_type_hint<py::typing::List<int>>("list_int") = py::list();
|
||||||
|
// Exercises py::handle overload:
|
||||||
|
m.attr_with_type_hint<py::typing::Set<py::str>>(py::str("set_str")) = py::set();
|
||||||
|
|
||||||
|
struct Empty {};
|
||||||
|
py::class_<Empty>(m, "EmptyAnnotationClass");
|
||||||
|
|
||||||
|
struct Static {};
|
||||||
|
auto static_class = py::class_<Static>(m, "Static");
|
||||||
|
static_class.def(py::init());
|
||||||
|
static_class.attr_with_type_hint<py::typing::ClassVar<float>>("x") = 1.0;
|
||||||
|
static_class.attr_with_type_hint<py::typing::ClassVar<py::typing::Dict<py::str, int>>>(
|
||||||
|
"dict_str_int")
|
||||||
|
= py::dict();
|
||||||
|
|
||||||
|
struct Instance {};
|
||||||
|
auto instance = py::class_<Instance>(m, "Instance", py::dynamic_attr());
|
||||||
|
instance.def(py::init());
|
||||||
|
instance.attr_with_type_hint<float>("y");
|
||||||
|
|
||||||
|
m.def("attr_with_type_hint_float_x",
|
||||||
|
[](py::handle obj) { obj.attr_with_type_hint<float>("x"); });
|
||||||
|
|
||||||
|
m.attr_with_type_hint<py::typing::Final<int>>("CONST_INT") = 3;
|
||||||
|
|
||||||
|
m.attr("defined___cpp_inline_variables") = true;
|
||||||
|
#else
|
||||||
|
m.attr("defined___cpp_inline_variables") = false;
|
||||||
|
#endif
|
||||||
m.def("half_of_number", [](const RealNumber &x) { return RealNumber{x.value / 2}; });
|
m.def("half_of_number", [](const RealNumber &x) { return RealNumber{x.value / 2}; });
|
||||||
// std::vector<T>
|
// std::vector<T>
|
||||||
m.def("half_of_number_vector", [](const std::vector<RealNumber> &x) {
|
m.def("half_of_number_vector", [](const std::vector<RealNumber> &x) {
|
||||||
|
@ -1103,6 +1103,96 @@ def test_dict_ranges(tested_dict, expected):
|
|||||||
assert m.transform_dict_plus_one(tested_dict) == expected
|
assert m.transform_dict_plus_one(tested_dict) == expected
|
||||||
|
|
||||||
|
|
||||||
|
# https://docs.python.org/3/howto/annotations.html#accessing-the-annotations-dict-of-an-object-in-python-3-9-and-older
|
||||||
|
def get_annotations_helper(o):
|
||||||
|
if isinstance(o, type):
|
||||||
|
return o.__dict__.get("__annotations__", None)
|
||||||
|
return getattr(o, "__annotations__", None)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skipif(
|
||||||
|
not m.defined___cpp_inline_variables,
|
||||||
|
reason="C++17 feature __cpp_inline_variables not available.",
|
||||||
|
)
|
||||||
|
def test_module_attribute_types() -> None:
|
||||||
|
module_annotations = get_annotations_helper(m)
|
||||||
|
|
||||||
|
assert module_annotations["list_int"] == "list[int]"
|
||||||
|
assert module_annotations["set_str"] == "set[str]"
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skipif(
|
||||||
|
not m.defined___cpp_inline_variables,
|
||||||
|
reason="C++17 feature __cpp_inline_variables not available.",
|
||||||
|
)
|
||||||
|
@pytest.mark.skipif(
|
||||||
|
sys.version_info < (3, 10),
|
||||||
|
reason="get_annotations function does not exist until Python3.10",
|
||||||
|
)
|
||||||
|
def test_get_annotations_compliance() -> None:
|
||||||
|
from inspect import get_annotations
|
||||||
|
|
||||||
|
module_annotations = get_annotations(m)
|
||||||
|
|
||||||
|
assert module_annotations["list_int"] == "list[int]"
|
||||||
|
assert module_annotations["set_str"] == "set[str]"
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skipif(
|
||||||
|
not m.defined___cpp_inline_variables,
|
||||||
|
reason="C++17 feature __cpp_inline_variables not available.",
|
||||||
|
)
|
||||||
|
def test_class_attribute_types() -> None:
|
||||||
|
empty_annotations = get_annotations_helper(m.EmptyAnnotationClass)
|
||||||
|
static_annotations = get_annotations_helper(m.Static)
|
||||||
|
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 m.Static.x == 1.0
|
||||||
|
|
||||||
|
m.Static.x = 3.0
|
||||||
|
static = m.Static()
|
||||||
|
assert static.x == 3.0
|
||||||
|
|
||||||
|
static.dict_str_int["hi"] = 3
|
||||||
|
assert m.Static().dict_str_int == {"hi": 3}
|
||||||
|
|
||||||
|
assert instance_annotations["y"] == "float"
|
||||||
|
instance1 = m.Instance()
|
||||||
|
instance1.y = 4.0
|
||||||
|
|
||||||
|
instance2 = m.Instance()
|
||||||
|
instance2.y = 5.0
|
||||||
|
|
||||||
|
assert instance1.y != instance2.y
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skipif(
|
||||||
|
not m.defined___cpp_inline_variables,
|
||||||
|
reason="C++17 feature __cpp_inline_variables not available.",
|
||||||
|
)
|
||||||
|
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"
|
||||||
|
with pytest.raises(
|
||||||
|
RuntimeError, match=r'^__annotations__\["x"\] was set already\.$'
|
||||||
|
):
|
||||||
|
m.attr_with_type_hint_float_x(obj)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skipif(
|
||||||
|
not m.defined___cpp_inline_variables,
|
||||||
|
reason="C++17 feature __cpp_inline_variables not available.",
|
||||||
|
)
|
||||||
|
def test_final_annotation() -> None:
|
||||||
|
module_annotations = get_annotations_helper(m)
|
||||||
|
assert module_annotations["CONST_INT"] == "Final[int]"
|
||||||
|
|
||||||
|
|
||||||
def test_arg_return_type_hints(doc):
|
def test_arg_return_type_hints(doc):
|
||||||
assert doc(m.half_of_number) == "half_of_number(arg0: Union[float, int]) -> float"
|
assert doc(m.half_of_number) == "half_of_number(arg0: Union[float, int]) -> float"
|
||||||
assert m.half_of_number(2.0) == 1.0
|
assert m.half_of_number(2.0) == 1.0
|
||||||
|
Loading…
Reference in New Issue
Block a user