diff options
author | robot-piglet <robot-piglet@yandex-team.com> | 2024-04-11 17:06:57 +0300 |
---|---|---|
committer | robot-piglet <robot-piglet@yandex-team.com> | 2024-04-11 17:23:45 +0300 |
commit | 9b6896144521146a81c633555dd67ba846d5a98f (patch) | |
tree | 07253fcbb3ba2e7970caf4d5a10553ae37907bc7 /contrib | |
parent | afe9a2e8d0bd9c3e6c61ca56cb40ef9f108cfcd3 (diff) | |
download | ydb-9b6896144521146a81c633555dd67ba846d5a98f.tar.gz |
Intermediate changes
Diffstat (limited to 'contrib')
-rw-r--r-- | contrib/libs/pybind11/README.rst | 9 | ||||
-rw-r--r-- | contrib/libs/pybind11/include/pybind11/cast.h | 151 | ||||
-rw-r--r-- | contrib/libs/pybind11/include/pybind11/detail/class.h | 31 | ||||
-rw-r--r-- | contrib/libs/pybind11/include/pybind11/detail/common.h | 20 | ||||
-rw-r--r-- | contrib/libs/pybind11/include/pybind11/detail/init.h | 2 | ||||
-rw-r--r-- | contrib/libs/pybind11/include/pybind11/detail/internals.h | 21 | ||||
-rw-r--r-- | contrib/libs/pybind11/include/pybind11/detail/type_caster_base.h | 61 | ||||
-rw-r--r-- | contrib/libs/pybind11/include/pybind11/gil.h | 14 | ||||
-rw-r--r-- | contrib/libs/pybind11/include/pybind11/gil_safe_call_once.h | 91 | ||||
-rw-r--r-- | contrib/libs/pybind11/include/pybind11/numpy.h | 179 | ||||
-rw-r--r-- | contrib/libs/pybind11/include/pybind11/pybind11.h | 169 | ||||
-rw-r--r-- | contrib/libs/pybind11/include/pybind11/pytypes.h | 27 | ||||
-rw-r--r-- | contrib/libs/pybind11/include/pybind11/typing.h | 125 | ||||
-rw-r--r-- | contrib/libs/pybind11/ya.make | 4 | ||||
-rw-r--r-- | contrib/python/matplotlib/py3/matplotlib/backends/backend_webagg.py | 22 |
15 files changed, 800 insertions, 126 deletions
diff --git a/contrib/libs/pybind11/README.rst b/contrib/libs/pybind11/README.rst index 80213a4062..4032f97a57 100644 --- a/contrib/libs/pybind11/README.rst +++ b/contrib/libs/pybind11/README.rst @@ -36,10 +36,10 @@ with everything stripped away that isn't relevant for binding generation. Without comments, the core header files only require ~4K lines of code and depend on Python (3.6+, or PyPy) and the C++ standard library. This compact implementation was possible thanks to -some of the new C++11 language features (specifically: tuples, lambda -functions and variadic templates). Since its creation, this library has -grown beyond Boost.Python in many ways, leading to dramatically simpler -binding code in many common situations. +some C++11 language features (specifically: tuples, lambda functions and +variadic templates). Since its creation, this library has grown beyond +Boost.Python in many ways, leading to dramatically simpler binding code in many +common situations. Tutorial and reference documentation is provided at `pybind11.readthedocs.io <https://pybind11.readthedocs.io/en/latest>`_. @@ -71,6 +71,7 @@ pybind11 can map the following core C++ features to Python: - Internal references with correct reference counting - C++ classes with virtual (and pure virtual) methods can be extended in Python +- Integrated NumPy support (NumPy 2 requires pybind11 2.12+) Goodies ------- diff --git a/contrib/libs/pybind11/include/pybind11/cast.h b/contrib/libs/pybind11/include/pybind11/cast.h index aa7dd494ad..6a37d265c0 100644 --- a/contrib/libs/pybind11/include/pybind11/cast.h +++ b/contrib/libs/pybind11/include/pybind11/cast.h @@ -43,13 +43,15 @@ using make_caster = type_caster<intrinsic_t<type>>; // Shortcut for calling a caster's `cast_op_type` cast operator for casting a type_caster to a T template <typename T> typename make_caster<T>::template cast_op_type<T> cast_op(make_caster<T> &caster) { - return caster.operator typename make_caster<T>::template cast_op_type<T>(); + using result_t = typename make_caster<T>::template cast_op_type<T>; // See PR #4893 + return caster.operator result_t(); } template <typename T> typename make_caster<T>::template cast_op_type<typename std::add_rvalue_reference<T>::type> cast_op(make_caster<T> &&caster) { - return std::move(caster).operator typename make_caster<T>:: - template cast_op_type<typename std::add_rvalue_reference<T>::type>(); + using result_t = typename make_caster<T>::template cast_op_type< + typename std::add_rvalue_reference<T>::type>; // See PR #4893 + return std::move(caster).operator result_t(); } template <typename type> @@ -326,8 +328,9 @@ public: value = false; return true; } - if (convert || (std::strcmp("numpy.bool_", Py_TYPE(src.ptr())->tp_name) == 0)) { - // (allow non-implicit conversion for numpy booleans) + if (convert || is_numpy_bool(src)) { + // (allow non-implicit conversion for numpy booleans), use strncmp + // since NumPy 1.x had an additional trailing underscore. Py_ssize_t res = -1; if (src.is_none()) { @@ -359,6 +362,15 @@ public: return handle(src ? Py_True : Py_False).inc_ref(); } PYBIND11_TYPE_CASTER(bool, const_name("bool")); + +private: + // Test if an object is a NumPy boolean (without fetching the type). + static inline bool is_numpy_bool(handle object) { + const char *type_name = Py_TYPE(object.ptr())->tp_name; + // Name changed to `numpy.bool` in NumPy 2, `numpy.bool_` is needed for 1.x support + return std::strcmp("numpy.bool", type_name) == 0 + || std::strcmp("numpy.bool_", type_name) == 0; + } }; // Helper class for UTF-{8,16,32} C++ stl strings: @@ -687,8 +699,9 @@ public: return cast(*src, policy, parent); } - static constexpr auto name - = const_name("Tuple[") + concat(make_caster<Ts>::name...) + const_name("]"); + static constexpr auto name = const_name("tuple[") + + ::pybind11::detail::concat(make_caster<Ts>::name...) + + const_name("]"); template <typename T> using cast_op_type = type; @@ -896,10 +909,53 @@ struct is_holder_type template <typename base, typename deleter> struct is_holder_type<base, std::unique_ptr<base, deleter>> : std::true_type {}; +#ifdef PYBIND11_DISABLE_HANDLE_TYPE_NAME_DEFAULT_IMPLEMENTATION // See PR #4888 + +// This leads to compilation errors if a specialization is missing. +template <typename T> +struct handle_type_name; + +#else + template <typename T> struct handle_type_name { static constexpr auto name = const_name<T>(); }; + +#endif + +template <> +struct handle_type_name<object> { + static constexpr auto name = const_name("object"); +}; +template <> +struct handle_type_name<list> { + static constexpr auto name = const_name("list"); +}; +template <> +struct handle_type_name<dict> { + static constexpr auto name = const_name("dict"); +}; +template <> +struct handle_type_name<anyset> { + static constexpr auto name = const_name("Union[set, frozenset]"); +}; +template <> +struct handle_type_name<set> { + static constexpr auto name = const_name("set"); +}; +template <> +struct handle_type_name<frozenset> { + static constexpr auto name = const_name("frozenset"); +}; +template <> +struct handle_type_name<str> { + static constexpr auto name = const_name("str"); +}; +template <> +struct handle_type_name<tuple> { + static constexpr auto name = const_name("tuple"); +}; template <> struct handle_type_name<bool_> { static constexpr auto name = const_name("bool"); @@ -909,6 +965,10 @@ struct handle_type_name<bytes> { static constexpr auto name = const_name(PYBIND11_BYTES_NAME); }; template <> +struct handle_type_name<buffer> { + static constexpr auto name = const_name("Buffer"); +}; +template <> struct handle_type_name<int_> { static constexpr auto name = const_name("int"); }; @@ -925,10 +985,50 @@ struct handle_type_name<float_> { static constexpr auto name = const_name("float"); }; template <> +struct handle_type_name<function> { + static constexpr auto name = const_name("Callable"); +}; +template <> +struct handle_type_name<handle> { + static constexpr auto name = handle_type_name<object>::name; +}; +template <> struct handle_type_name<none> { static constexpr auto name = const_name("None"); }; template <> +struct handle_type_name<sequence> { + static constexpr auto name = const_name("Sequence"); +}; +template <> +struct handle_type_name<bytearray> { + static constexpr auto name = const_name("bytearray"); +}; +template <> +struct handle_type_name<memoryview> { + static constexpr auto name = const_name("memoryview"); +}; +template <> +struct handle_type_name<slice> { + static constexpr auto name = const_name("slice"); +}; +template <> +struct handle_type_name<type> { + static constexpr auto name = const_name("type"); +}; +template <> +struct handle_type_name<capsule> { + static constexpr auto name = const_name("capsule"); +}; +template <> +struct handle_type_name<ellipsis> { + static constexpr auto name = const_name("ellipsis"); +}; +template <> +struct handle_type_name<weakref> { + static constexpr auto name = const_name("weakref"); +}; +template <> struct handle_type_name<args> { static constexpr auto name = const_name("*args"); }; @@ -936,6 +1036,30 @@ template <> struct handle_type_name<kwargs> { static constexpr auto name = const_name("**kwargs"); }; +template <> +struct handle_type_name<obj_attr_accessor> { + static constexpr auto name = const_name<obj_attr_accessor>(); +}; +template <> +struct handle_type_name<str_attr_accessor> { + static constexpr auto name = const_name<str_attr_accessor>(); +}; +template <> +struct handle_type_name<item_accessor> { + static constexpr auto name = const_name<item_accessor>(); +}; +template <> +struct handle_type_name<sequence_accessor> { + static constexpr auto name = const_name<sequence_accessor>(); +}; +template <> +struct handle_type_name<list_accessor> { + static constexpr auto name = const_name<list_accessor>(); +}; +template <> +struct handle_type_name<tuple_accessor> { + static constexpr auto name = const_name<tuple_accessor>(); +}; template <typename type> struct pyobject_caster { @@ -1416,7 +1540,15 @@ inline namespace literals { /** \rst String literal version of `arg` \endrst */ -constexpr arg operator"" _a(const char *name, size_t) { return arg(name); } +constexpr arg +#if !defined(__clang__) && defined(__GNUC__) && __GNUC__ < 5 +operator"" _a // gcc 4.8.5 insists on having a space (hard error). +#else +operator""_a // clang 17 generates a deprecation warning if there is a space. +#endif + (const char *name, size_t) { + return arg(name); +} } // namespace literals PYBIND11_NAMESPACE_BEGIN(detail) @@ -1477,7 +1609,8 @@ public: static_assert(args_pos == -1 || args_pos == constexpr_first<argument_is_args, Args...>(), "py::args cannot be specified more than once"); - static constexpr auto arg_names = concat(type_descr(make_caster<Args>::name)...); + static constexpr auto arg_names + = ::pybind11::detail::concat(type_descr(make_caster<Args>::name)...); bool load_args(function_call &call) { return load_impl_sequence(call, indices{}); } diff --git a/contrib/libs/pybind11/include/pybind11/detail/class.h b/contrib/libs/pybind11/include/pybind11/detail/class.h index fd192530b5..2657148af2 100644 --- a/contrib/libs/pybind11/include/pybind11/detail/class.h +++ b/contrib/libs/pybind11/include/pybind11/detail/class.h @@ -86,17 +86,16 @@ inline PyTypeObject *make_static_property_type() { type->tp_descr_get = pybind11_static_get; type->tp_descr_set = pybind11_static_set; - if (PyType_Ready(type) < 0) { - pybind11_fail("make_static_property_type(): failure in PyType_Ready()!"); - } - # if PY_VERSION_HEX >= 0x030C0000 - // PRE 3.12 FEATURE FREEZE. PLEASE REVIEW AFTER FREEZE. // Since Python-3.12 property-derived types are required to // have dynamic attributes (to set `__doc__`) enable_dynamic_attributes(heap_type); # endif + if (PyType_Ready(type) < 0) { + pybind11_fail("make_static_property_type(): failure in PyType_Ready()!"); + } + setattr((PyObject *) type, "__module__", str("pybind11_builtins")); PYBIND11_SET_OLDPY_QUALNAME(type, name_obj); @@ -191,12 +190,10 @@ extern "C" inline PyObject *pybind11_meta_call(PyObject *type, PyObject *args, P return nullptr; } - // This must be a pybind11 instance - auto *instance = reinterpret_cast<detail::instance *>(self); - // Ensure that the base __init__ function(s) were called - for (const auto &vh : values_and_holders(instance)) { - if (!vh.holder_constructed()) { + values_and_holders vhs(self); + for (const auto &vh : vhs) { + if (!vh.holder_constructed() && !vhs.is_redundant_value_and_holder(vh)) { PyErr_Format(PyExc_TypeError, "%.200s.__init__() must be called when overriding __init__", get_fully_qualified_tp_name(vh.type->type).c_str()); @@ -379,7 +376,7 @@ extern "C" inline PyObject *pybind11_object_new(PyTypeObject *type, PyObject *, extern "C" inline int pybind11_object_init(PyObject *self, PyObject *, PyObject *) { PyTypeObject *type = Py_TYPE(self); std::string msg = get_fully_qualified_tp_name(type) + ": No constructor defined!"; - PyErr_SetString(PyExc_TypeError, msg.c_str()); + set_error(PyExc_TypeError, msg.c_str()); return -1; } @@ -553,8 +550,12 @@ extern "C" inline int pybind11_set_dict(PyObject *self, PyObject *new_dict, void /// dynamic_attr: Allow the garbage collector to traverse the internal instance `__dict__`. extern "C" inline int pybind11_traverse(PyObject *self, visitproc visit, void *arg) { +#if PY_VERSION_HEX >= 0x030D0000 + PyObject_VisitManagedDict(self, visit, arg); +#else PyObject *&dict = *_PyObject_GetDictPtr(self); Py_VISIT(dict); +#endif // https://docs.python.org/3/c-api/typeobj.html#c.PyTypeObject.tp_traverse #if PY_VERSION_HEX >= 0x03090000 Py_VISIT(Py_TYPE(self)); @@ -564,8 +565,12 @@ extern "C" inline int pybind11_traverse(PyObject *self, visitproc visit, void *a /// dynamic_attr: Allow the GC to clear the dictionary. extern "C" inline int pybind11_clear(PyObject *self) { +#if PY_VERSION_HEX >= 0x030D0000 + PyObject_ClearManagedDict(self); +#else PyObject *&dict = *_PyObject_GetDictPtr(self); Py_CLEAR(dict); +#endif return 0; } @@ -615,7 +620,7 @@ extern "C" inline int pybind11_getbuffer(PyObject *obj, Py_buffer *view, int fla if (view) { view->obj = nullptr; } - PyErr_SetString(PyExc_BufferError, "pybind11_getbuffer(): Internal error"); + set_error(PyExc_BufferError, "pybind11_getbuffer(): Internal error"); return -1; } std::memset(view, 0, sizeof(Py_buffer)); @@ -623,7 +628,7 @@ extern "C" inline int pybind11_getbuffer(PyObject *obj, Py_buffer *view, int fla if ((flags & PyBUF_WRITABLE) == PyBUF_WRITABLE && info->readonly) { delete info; // view->obj = nullptr; // Was just memset to 0, so not necessary - PyErr_SetString(PyExc_BufferError, "Writable buffer requested for readonly storage"); + set_error(PyExc_BufferError, "Writable buffer requested for readonly storage"); return -1; } view->obj = obj; diff --git a/contrib/libs/pybind11/include/pybind11/detail/common.h b/contrib/libs/pybind11/include/pybind11/detail/common.h index 601408153a..f14ea1238f 100644 --- a/contrib/libs/pybind11/include/pybind11/detail/common.h +++ b/contrib/libs/pybind11/include/pybind11/detail/common.h @@ -10,12 +10,12 @@ #pragma once #define PYBIND11_VERSION_MAJOR 2 -#define PYBIND11_VERSION_MINOR 11 -#define PYBIND11_VERSION_PATCH 1 +#define PYBIND11_VERSION_MINOR 12 +#define PYBIND11_VERSION_PATCH 0 // Similar to Python's convention: https://docs.python.org/3/c-api/apiabiversion.html // Additional convention: 0xD = dev -#define PYBIND11_VERSION_HEX 0x020B0100 +#define PYBIND11_VERSION_HEX 0x020C0000 // Define some generic pybind11 helper macros for warning management. // @@ -118,6 +118,14 @@ # endif #endif +#if defined(PYBIND11_CPP20) +# define PYBIND11_CONSTINIT constinit +# define PYBIND11_DTOR_CONSTEXPR constexpr +#else +# define PYBIND11_CONSTINIT +# define PYBIND11_DTOR_CONSTEXPR +#endif + // Compiler version assertions #if defined(__INTEL_COMPILER) # if __INTEL_COMPILER < 1800 @@ -285,6 +293,10 @@ PYBIND11_WARNING_DISABLE_MSVC(4505) # undef copysign #endif +#if defined(PYBIND11_NUMPY_1_ONLY) +# define PYBIND11_INTERNAL_NUMPY_1_ONLY_DETECTED +#endif + #if defined(PYPY_VERSION) && !defined(PYBIND11_SIMPLE_GIL_MANAGEMENT) # define PYBIND11_SIMPLE_GIL_MANAGEMENT #endif @@ -433,7 +445,7 @@ PYBIND11_WARNING_POP return nullptr; \ } \ catch (const std::exception &e) { \ - PyErr_SetString(PyExc_ImportError, e.what()); \ + ::pybind11::set_error(PyExc_ImportError, e.what()); \ return nullptr; \ } diff --git a/contrib/libs/pybind11/include/pybind11/detail/init.h b/contrib/libs/pybind11/include/pybind11/detail/init.h index ca5a5178c8..89a471f5b4 100644 --- a/contrib/libs/pybind11/include/pybind11/detail/init.h +++ b/contrib/libs/pybind11/include/pybind11/detail/init.h @@ -65,7 +65,7 @@ constexpr bool is_alias(void *) { } // Constructs and returns a new object; if the given arguments don't map to a constructor, we fall -// back to brace aggregate initiailization so that for aggregate initialization can be used with +// back to brace aggregate initialization so that for aggregate initialization can be used with // py::init, e.g. `py::init<int, int>` to initialize a `struct T { int a; int b; }`. For // non-aggregate types, we need to use an ordinary T(...) constructor (invoking as `T{...}` usually // works, but will not do the expected thing when `T` has an `initializer_list<T>` constructor). diff --git a/contrib/libs/pybind11/include/pybind11/detail/internals.h b/contrib/libs/pybind11/include/pybind11/detail/internals.h index 5f4ba6959a..049dbcaa19 100644 --- a/contrib/libs/pybind11/include/pybind11/detail/internals.h +++ b/contrib/libs/pybind11/include/pybind11/detail/internals.h @@ -36,8 +36,9 @@ /// further ABI-incompatible changes may be made before the ABI is officially /// changed to the new version. #ifndef PYBIND11_INTERNALS_VERSION -# if PY_VERSION_HEX >= 0x030C0000 +# if PY_VERSION_HEX >= 0x030C0000 || defined(_MSC_VER) // Version bump for Python 3.12+, before first 3.12 beta release. +// Version bump for MSVC piggy-backed on PR #4779. See comments there. # define PYBIND11_INTERNALS_VERSION 5 # else # define PYBIND11_INTERNALS_VERSION 4 @@ -68,9 +69,14 @@ inline PyObject *make_object_base_type(PyTypeObject *metaclass); // `Py_LIMITED_API` anyway. # if PYBIND11_INTERNALS_VERSION > 4 # define PYBIND11_TLS_KEY_REF Py_tss_t & -# if defined(__GNUC__) && !defined(__INTEL_COMPILER) -// Clang on macOS warns due to `Py_tss_NEEDS_INIT` not specifying an initializer -// for every field. +# if defined(__clang__) +# define PYBIND11_TLS_KEY_INIT(var) \ + _Pragma("clang diagnostic push") /**/ \ + _Pragma("clang diagnostic ignored \"-Wmissing-field-initializers\"") /**/ \ + Py_tss_t var \ + = Py_tss_NEEDS_INIT; \ + _Pragma("clang diagnostic pop") +# elif defined(__GNUC__) && !defined(__INTEL_COMPILER) # define PYBIND11_TLS_KEY_INIT(var) \ _Pragma("GCC diagnostic push") /**/ \ _Pragma("GCC diagnostic ignored \"-Wmissing-field-initializers\"") /**/ \ @@ -293,9 +299,12 @@ struct type_info { #endif /// On Linux/OSX, changes in __GXX_ABI_VERSION__ indicate ABI incompatibility. +/// On MSVC, changes in _MSC_VER may indicate ABI incompatibility (#2898). #ifndef PYBIND11_BUILD_ABI # if defined(__GXX_ABI_VERSION) # define PYBIND11_BUILD_ABI "_cxxabi" PYBIND11_TOSTRING(__GXX_ABI_VERSION) +# elif defined(_MSC_VER) +# define PYBIND11_BUILD_ABI "_mscver" PYBIND11_TOSTRING(_MSC_VER) # else # define PYBIND11_BUILD_ABI "" # endif @@ -365,7 +374,7 @@ inline bool raise_err(PyObject *exc_type, const char *msg) { return true; } #endif - PyErr_SetString(exc_type, msg); + set_error(exc_type, msg); return false; } @@ -462,6 +471,7 @@ inline object get_python_state_dict() { if (!state_dict) { #if PY_VERSION_HEX >= 0x03030000 raise_from(PyExc_SystemError, "pybind11::detail::get_python_state_dict() FAILED"); + throw error_already_set(); #else PyErr_SetString(PyExc_SystemError, "pybind11::detail::get_python_state_dict() FAILED"); #endif @@ -478,6 +488,7 @@ inline internals **get_internals_pp_from_capsule(handle obj) { if (raw_ptr == nullptr) { #if PY_VERSION_HEX >= 0x03030000 raise_from(PyExc_SystemError, "pybind11::detail::get_internals_pp_from_capsule() FAILED"); + throw error_already_set(); #else PyErr_SetString(PyExc_SystemError, "pybind11::detail::get_internals_pp_from_capsule() FAILED"); #endif diff --git a/contrib/libs/pybind11/include/pybind11/detail/type_caster_base.h b/contrib/libs/pybind11/include/pybind11/detail/type_caster_base.h index 245bf99d2d..4d5e322c2b 100644 --- a/contrib/libs/pybind11/include/pybind11/detail/type_caster_base.h +++ b/contrib/libs/pybind11/include/pybind11/detail/type_caster_base.h @@ -103,8 +103,22 @@ public: inline std::pair<decltype(internals::registered_types_py)::iterator, bool> all_type_info_get_cache(PyTypeObject *type); +// Band-aid workaround to fix a subtle but serious bug in a minimalistic fashion. See PR #4762. +inline void all_type_info_add_base_most_derived_first(std::vector<type_info *> &bases, + type_info *addl_base) { + for (auto it = bases.begin(); it != bases.end(); it++) { + type_info *existing_base = *it; + if (PyType_IsSubtype(addl_base->type, existing_base->type) != 0) { + bases.insert(it, addl_base); + return; + } + } + bases.push_back(addl_base); +} + // Populates a just-created cache entry. PYBIND11_NOINLINE void all_type_info_populate(PyTypeObject *t, std::vector<type_info *> &bases) { + assert(bases.empty()); std::vector<PyTypeObject *> check; for (handle parent : reinterpret_borrow<tuple>(t->tp_bases)) { check.push_back((PyTypeObject *) parent.ptr()); @@ -137,7 +151,7 @@ PYBIND11_NOINLINE void all_type_info_populate(PyTypeObject *t, std::vector<type_ } } if (!found) { - bases.push_back(tinfo); + all_type_info_add_base_most_derived_first(bases, tinfo); } } } else if (type->tp_bases) { @@ -323,18 +337,29 @@ public: explicit values_and_holders(instance *inst) : inst{inst}, tinfo(all_type_info(Py_TYPE(inst))) {} + explicit values_and_holders(PyObject *obj) + : inst{nullptr}, tinfo(all_type_info(Py_TYPE(obj))) { + if (!tinfo.empty()) { + inst = reinterpret_cast<instance *>(obj); + } + } + struct iterator { private: instance *inst = nullptr; const type_vec *types = nullptr; value_and_holder curr; friend struct values_and_holders; - iterator(instance *inst, const type_vec *tinfo) - : inst{inst}, types{tinfo}, - curr(inst /* instance */, - types->empty() ? nullptr : (*types)[0] /* type info */, - 0, /* vpos: (non-simple types only): the first vptr comes first */ - 0 /* index */) {} + iterator(instance *inst, const type_vec *tinfo) : inst{inst}, types{tinfo} { + if (inst != nullptr) { + assert(!types->empty()); + curr = value_and_holder( + inst /* instance */, + (*types)[0] /* type info */, + 0, /* vpos: (non-simple types only): the first vptr comes first */ + 0 /* index */); + } + } // Past-the-end iterator: explicit iterator(size_t end) : curr(end) {} @@ -365,6 +390,16 @@ public: } size_t size() { return tinfo.size(); } + + // Band-aid workaround to fix a subtle but serious bug in a minimalistic fashion. See PR #4762. + bool is_redundant_value_and_holder(const value_and_holder &vh) { + for (size_t i = 0; i < vh.index; i++) { + if (PyType_IsSubtype(tinfo[i]->type, tinfo[vh.index]->type) != 0) { + return true; + } + } + return false; + } }; /** @@ -496,8 +531,10 @@ inline PyThreadState *get_thread_state_unchecked() { return PyThreadState_GET(); #elif PY_VERSION_HEX < 0x03000000 return _PyThreadState_Current; -#else +#elif PY_VERSION_HEX < 0x030D0000 return _PyThreadState_UncheckedGet(); +#else + return PyThreadState_GetUnchecked(); #endif } @@ -796,7 +833,7 @@ public: std::string tname = rtti_type ? rtti_type->name() : cast_type.name(); detail::clean_type_id(tname); std::string msg = "Unregistered type : " + tname; - PyErr_SetString(PyExc_TypeError, msg.c_str()); + set_error(PyExc_TypeError, msg.c_str()); return {nullptr, nullptr}; } @@ -1174,13 +1211,17 @@ protected: static Constructor make_move_constructor(...) { return nullptr; } }; +inline std::string quote_cpp_type_name(const std::string &cpp_type_name) { + return cpp_type_name; // No-op for now. See PR #4888 +} + PYBIND11_NOINLINE std::string type_info_description(const std::type_info &ti) { if (auto *type_data = get_type_info(ti)) { handle th((PyObject *) type_data->type); return th.attr("__module__").cast<std::string>() + '.' + th.attr("__qualname__").cast<std::string>(); } - return clean_type_id(ti.name()); + return quote_cpp_type_name(clean_type_id(ti.name())); } PYBIND11_NAMESPACE_END(detail) diff --git a/contrib/libs/pybind11/include/pybind11/gil.h b/contrib/libs/pybind11/include/pybind11/gil.h index 570a5581d5..b9d8b88a3b 100644 --- a/contrib/libs/pybind11/include/pybind11/gil.h +++ b/contrib/libs/pybind11/include/pybind11/gil.h @@ -11,6 +11,8 @@ #include "detail/common.h" +#include <cassert> + #if defined(WITH_THREAD) && !defined(PYBIND11_SIMPLE_GIL_MANAGEMENT) # include "detail/internals.h" #endif @@ -137,7 +139,11 @@ private: class gil_scoped_release { public: + // PRECONDITION: The GIL must be held when this constructor is called. explicit gil_scoped_release(bool disassoc = false) : disassoc(disassoc) { +#ifdef PYBIND11_ASSERT_GIL_HELD_INCREF_DECREF + assert(PyGILState_Check()); +#endif // `get_internals()` must be called here unconditionally in order to initialize // `internals.tstate` for subsequent `gil_scoped_acquire` calls. Otherwise, an // initialization race could occur as multiple threads try `gil_scoped_acquire`. @@ -201,7 +207,13 @@ class gil_scoped_release { PyThreadState *state; public: - gil_scoped_release() : state{PyEval_SaveThread()} {} + // PRECONDITION: The GIL must be held when this constructor is called. + gil_scoped_release() { +#ifdef PYBIND11_ASSERT_GIL_HELD_INCREF_DECREF + assert(PyGILState_Check()); +#endif + state = PyEval_SaveThread(); + } gil_scoped_release(const gil_scoped_release &) = delete; gil_scoped_release &operator=(const gil_scoped_release &) = delete; ~gil_scoped_release() { PyEval_RestoreThread(state); } diff --git a/contrib/libs/pybind11/include/pybind11/gil_safe_call_once.h b/contrib/libs/pybind11/include/pybind11/gil_safe_call_once.h new file mode 100644 index 0000000000..eaf84d16e8 --- /dev/null +++ b/contrib/libs/pybind11/include/pybind11/gil_safe_call_once.h @@ -0,0 +1,91 @@ +// Copyright (c) 2023 The pybind Community. + +#pragma once + +#include "detail/common.h" +#include "gil.h" + +#include <cassert> +#include <mutex> + +PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) + +// Use the `gil_safe_call_once_and_store` class below instead of the naive +// +// static auto imported_obj = py::module_::import("module_name"); // BAD, DO NOT USE! +// +// which has two serious issues: +// +// 1. Py_DECREF() calls potentially after the Python interpreter was finalized already, and +// 2. deadlocks in multi-threaded processes (because of missing lock ordering). +// +// The following alternative avoids both problems: +// +// PYBIND11_CONSTINIT static py::gil_safe_call_once_and_store<py::object> storage; +// auto &imported_obj = storage // Do NOT make this `static`! +// .call_once_and_store_result([]() { +// return py::module_::import("module_name"); +// }) +// .get_stored(); +// +// The parameter of `call_once_and_store_result()` must be callable. It can make +// CPython API calls, and in particular, it can temporarily release the GIL. +// +// `T` can be any C++ type, it does not have to involve CPython API types. +// +// The behavior with regard to signals, e.g. `SIGINT` (`KeyboardInterrupt`), +// is not ideal. If the main thread is the one to actually run the `Callable`, +// then a `KeyboardInterrupt` will interrupt it if it is running normal Python +// code. The situation is different if a non-main thread runs the +// `Callable`, and then the main thread starts waiting for it to complete: +// a `KeyboardInterrupt` will not interrupt the non-main thread, but it will +// get processed only when it is the main thread's turn again and it is running +// normal Python code. However, this will be unnoticeable for quick call-once +// functions, which is usually the case. +template <typename T> +class gil_safe_call_once_and_store { +public: + // PRECONDITION: The GIL must be held when `call_once_and_store_result()` is called. + template <typename Callable> + gil_safe_call_once_and_store &call_once_and_store_result(Callable &&fn) { + if (!is_initialized_) { // This read is guarded by the GIL. + // Multiple threads may enter here, because the GIL is released in the next line and + // CPython API calls in the `fn()` call below may release and reacquire the GIL. + gil_scoped_release gil_rel; // Needed to establish lock ordering. + std::call_once(once_flag_, [&] { + // Only one thread will ever enter here. + gil_scoped_acquire gil_acq; + ::new (storage_) T(fn()); // fn may release, but will reacquire, the GIL. + is_initialized_ = true; // This write is guarded by the GIL. + }); + // All threads will observe `is_initialized_` as true here. + } + // Intentionally not returning `T &` to ensure the calling code is self-documenting. + return *this; + } + + // This must only be called after `call_once_and_store_result()` was called. + T &get_stored() { + assert(is_initialized_); + PYBIND11_WARNING_PUSH +#if !defined(__clang__) && defined(__GNUC__) && __GNUC__ < 5 + // Needed for gcc 4.8.5 + PYBIND11_WARNING_DISABLE_GCC("-Wstrict-aliasing") +#endif + return *reinterpret_cast<T *>(storage_); + PYBIND11_WARNING_POP + } + + constexpr gil_safe_call_once_and_store() = default; + PYBIND11_DTOR_CONSTEXPR ~gil_safe_call_once_and_store() = default; + +private: + alignas(T) char storage_[sizeof(T)] = {}; + std::once_flag once_flag_ = {}; + bool is_initialized_ = false; + // The `is_initialized_`-`storage_` pair is very similar to `std::optional`, + // but the latter does not have the triviality properties of former, + // therefore `std::optional` is not a viable alternative here. +}; + +PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE) diff --git a/contrib/libs/pybind11/include/pybind11/numpy.h b/contrib/libs/pybind11/include/pybind11/numpy.h index 8162908edd..b0af0a42ec 100644 --- a/contrib/libs/pybind11/include/pybind11/numpy.h +++ b/contrib/libs/pybind11/include/pybind11/numpy.h @@ -10,7 +10,10 @@ #pragma once #include "pybind11.h" +#include "detail/common.h" #include "complex.h" +#include "gil_safe_call_once.h" +#include "pytypes.h" #include <algorithm> #include <array> @@ -26,10 +29,15 @@ #include <utility> #include <vector> +#if defined(PYBIND11_NUMPY_1_ONLY) && !defined(PYBIND11_INTERNAL_NUMPY_1_ONLY_DETECTED) +# error PYBIND11_NUMPY_1_ONLY must be defined before any pybind11 header is included. +#endif + /* This will be true on all flat address space platforms and allows us to reduce the whole npy_intp / ssize_t / Py_intptr_t business down to just ssize_t for all size and dimension types (e.g. shape, strides, indexing), instead of inflicting this - upon the library user. */ + upon the library user. + Note that NumPy 2 now uses ssize_t for `npy_intp` to simplify this. */ static_assert(sizeof(::pybind11::ssize_t) == sizeof(Py_intptr_t), "ssize_t != Py_intptr_t"); static_assert(std::is_signed<Py_intptr_t>::value, "Py_intptr_t must be signed"); // We now can reinterpret_cast between py::ssize_t and Py_intptr_t (MSVC + PyPy cares) @@ -38,11 +46,17 @@ PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) PYBIND11_WARNING_DISABLE_MSVC(4127) +class dtype; // Forward declaration class array; // Forward declaration PYBIND11_NAMESPACE_BEGIN(detail) template <> +struct handle_type_name<dtype> { + static constexpr auto name = const_name("numpy.dtype"); +}; + +template <> struct handle_type_name<array> { static constexpr auto name = const_name("numpy.ndarray"); }; @@ -50,7 +64,8 @@ struct handle_type_name<array> { template <typename type, typename SFINAE = void> struct npy_format_descriptor; -struct PyArrayDescr_Proxy { +/* NumPy 1 proxy (always includes legacy fields) */ +struct PyArrayDescr1_Proxy { PyObject_HEAD PyObject *typeobj; char kind; @@ -65,6 +80,43 @@ struct PyArrayDescr_Proxy { PyObject *names; }; +#ifndef PYBIND11_NUMPY_1_ONLY +struct PyArrayDescr_Proxy { + PyObject_HEAD + PyObject *typeobj; + char kind; + char type; + char byteorder; + char _former_flags; + int type_num; + /* Additional fields are NumPy version specific. */ +}; +#else +/* NumPy 1.x only, we can expose all fields */ +using PyArrayDescr_Proxy = PyArrayDescr1_Proxy; +#endif + +/* NumPy 2 proxy, including legacy fields */ +struct PyArrayDescr2_Proxy { + PyObject_HEAD + PyObject *typeobj; + char kind; + char type; + char byteorder; + char _former_flags; + int type_num; + std::uint64_t flags; + ssize_t elsize; + ssize_t alignment; + PyObject *metadata; + Py_hash_t hash; + void *reserved_null[2]; + /* The following fields only exist if 0 <= type_num < 2056 */ + char *subarray; + PyObject *fields; + PyObject *names; +}; + struct PyArray_Proxy { PyObject_HEAD char *data; @@ -120,6 +172,28 @@ inline numpy_internals &get_numpy_internals() { return *ptr; } +PYBIND11_NOINLINE module_ import_numpy_core_submodule(const char *submodule_name) { + module_ numpy = module_::import("numpy"); + str version_string = numpy.attr("__version__"); + + module_ numpy_lib = module_::import("numpy.lib"); + object numpy_version = numpy_lib.attr("NumpyVersion")(version_string); + int major_version = numpy_version.attr("major").cast<int>(); + +#ifdef PYBIND11_NUMPY_1_ONLY + if (major_version >= 2) { + throw std::runtime_error( + "This extension was built with PYBIND11_NUMPY_1_ONLY defined, " + "but NumPy 2 is used in this process. For NumPy2 compatibility, " + "this extension needs to be rebuilt without the PYBIND11_NUMPY_1_ONLY define."); + } +#endif + /* `numpy.core` was renamed to `numpy._core` in NumPy 2.0 as it officially + became a private module. */ + std::string numpy_core_path = major_version >= 2 ? "numpy._core" : "numpy.core"; + return module_::import((numpy_core_path + "." + submodule_name).c_str()); +} + template <typename T> struct same_size { template <typename U> @@ -186,14 +260,16 @@ struct npy_api { NPY_ULONG_, NPY_ULONGLONG_, NPY_UINT_), }; + unsigned int PyArray_RUNTIME_VERSION_; + struct PyArray_Dims { Py_intptr_t *ptr; int len; }; static npy_api &get() { - static npy_api api = lookup(); - return api; + PYBIND11_CONSTINIT static gil_safe_call_once_and_store<npy_api> storage; + return storage.call_once_and_store_result(lookup).get_stored(); } bool PyArray_Check_(PyObject *obj) const { @@ -224,6 +300,7 @@ struct npy_api { PyObject *(*PyArray_FromAny_)(PyObject *, PyObject *, int, int, int, PyObject *); int (*PyArray_DescrConverter_)(PyObject *, PyObject **); bool (*PyArray_EquivTypes_)(PyObject *, PyObject *); +#ifdef PYBIND11_NUMPY_1_ONLY int (*PyArray_GetArrayParamsFromObject_)(PyObject *, PyObject *, unsigned char, @@ -232,6 +309,7 @@ struct npy_api { Py_intptr_t *, PyObject **, PyObject *); +#endif PyObject *(*PyArray_Squeeze_)(PyObject *); // Unused. Not removed because that affects ABI of the class. int (*PyArray_SetBaseObject_)(PyObject *, PyObject *); @@ -249,7 +327,8 @@ private: API_PyArray_DescrFromScalar = 57, API_PyArray_FromAny = 69, API_PyArray_Resize = 80, - API_PyArray_CopyInto = 82, + // CopyInto was slot 82 and 50 was effectively an alias. NumPy 2 removed 82. + API_PyArray_CopyInto = 50, API_PyArray_NewCopy = 85, API_PyArray_NewFromDescr = 94, API_PyArray_DescrNewFromType = 96, @@ -258,22 +337,29 @@ private: API_PyArray_View = 137, API_PyArray_DescrConverter = 174, API_PyArray_EquivTypes = 182, +#ifdef PYBIND11_NUMPY_1_ONLY API_PyArray_GetArrayParamsFromObject = 278, +#endif API_PyArray_SetBaseObject = 282 }; static npy_api lookup() { - module_ m = module_::import("numpy.core.multiarray"); + module_ m = detail::import_numpy_core_submodule("multiarray"); auto c = m.attr("_ARRAY_API"); #if PY_MAJOR_VERSION >= 3 void **api_ptr = (void **) PyCapsule_GetPointer(c.ptr(), nullptr); #else void **api_ptr = (void **) PyCObject_AsVoidPtr(c.ptr()); #endif + if (api_ptr == nullptr) { + raise_from(PyExc_SystemError, "FAILURE obtaining numpy _ARRAY_API pointer."); + throw error_already_set(); + } npy_api api; #define DECL_NPY_API(Func) api.Func##_ = (decltype(api.Func##_)) api_ptr[API_##Func]; DECL_NPY_API(PyArray_GetNDArrayCFeatureVersion); - if (api.PyArray_GetNDArrayCFeatureVersion_() < 0x7) { + api.PyArray_RUNTIME_VERSION_ = api.PyArray_GetNDArrayCFeatureVersion_(); + if (api.PyArray_RUNTIME_VERSION_ < 0x7) { pybind11_fail("pybind11 numpy support requires numpy >= 1.7.0"); } DECL_NPY_API(PyArray_Type); @@ -292,7 +378,9 @@ private: DECL_NPY_API(PyArray_View); DECL_NPY_API(PyArray_DescrConverter); DECL_NPY_API(PyArray_EquivTypes); +#ifdef PYBIND11_NUMPY_1_ONLY DECL_NPY_API(PyArray_GetArrayParamsFromObject); +#endif DECL_NPY_API(PyArray_SetBaseObject); #undef DECL_NPY_API @@ -314,6 +402,14 @@ inline const PyArrayDescr_Proxy *array_descriptor_proxy(const PyObject *ptr) { return reinterpret_cast<const PyArrayDescr_Proxy *>(ptr); } +inline const PyArrayDescr1_Proxy *array_descriptor1_proxy(const PyObject *ptr) { + return reinterpret_cast<const PyArrayDescr1_Proxy *>(ptr); +} + +inline const PyArrayDescr2_Proxy *array_descriptor2_proxy(const PyObject *ptr) { + return reinterpret_cast<const PyArrayDescr2_Proxy *>(ptr); +} + inline bool check_flags(const void *ptr, int flag) { return (flag == (array_proxy(ptr)->flags & flag)); } @@ -354,7 +450,7 @@ struct array_info<std::array<T, N>> { } static constexpr auto extents = const_name<array_info<T>::is_array>( - concat(const_name<N>(), array_info<T>::extents), const_name<N>()); + ::pybind11::detail::concat(const_name<N>(), array_info<T>::extents), const_name<N>()); }; // For numpy we have special handling for arrays of characters, so we don't include // the size in the array extents. @@ -593,10 +689,32 @@ public: } /// Size of the data type in bytes. +#ifdef PYBIND11_NUMPY_1_ONLY ssize_t itemsize() const { return detail::array_descriptor_proxy(m_ptr)->elsize; } +#else + ssize_t itemsize() const { + if (detail::npy_api::get().PyArray_RUNTIME_VERSION_ < 0x12) { + return detail::array_descriptor1_proxy(m_ptr)->elsize; + } + return detail::array_descriptor2_proxy(m_ptr)->elsize; + } +#endif /// Returns true for structured data types. +#ifdef PYBIND11_NUMPY_1_ONLY bool has_fields() const { return detail::array_descriptor_proxy(m_ptr)->names != nullptr; } +#else + bool has_fields() const { + if (detail::npy_api::get().PyArray_RUNTIME_VERSION_ < 0x12) { + return detail::array_descriptor1_proxy(m_ptr)->names != nullptr; + } + const auto *proxy = detail::array_descriptor2_proxy(m_ptr); + if (proxy->type_num < 0 || proxy->type_num >= 2056) { + return false; + } + return proxy->names != nullptr; + } +#endif /// Single-character code for dtype's kind. /// For example, floating point types are 'f' and integral types are 'i'. @@ -622,20 +740,39 @@ public: /// Single character for byteorder char byteorder() const { return detail::array_descriptor_proxy(m_ptr)->byteorder; } - /// Alignment of the data type +/// Alignment of the data type +#ifdef PYBIND11_NUMPY_1_ONLY int alignment() const { return detail::array_descriptor_proxy(m_ptr)->alignment; } +#else + ssize_t alignment() const { + if (detail::npy_api::get().PyArray_RUNTIME_VERSION_ < 0x12) { + return detail::array_descriptor1_proxy(m_ptr)->alignment; + } + return detail::array_descriptor2_proxy(m_ptr)->alignment; + } +#endif - /// Flags for the array descriptor +/// Flags for the array descriptor +#ifdef PYBIND11_NUMPY_1_ONLY char flags() const { return detail::array_descriptor_proxy(m_ptr)->flags; } +#else + std::uint64_t flags() const { + if (detail::npy_api::get().PyArray_RUNTIME_VERSION_ < 0x12) { + return (unsigned char) detail::array_descriptor1_proxy(m_ptr)->flags; + } + return detail::array_descriptor2_proxy(m_ptr)->flags; + } +#endif private: - static object _dtype_from_pep3118() { - static PyObject *obj = module_::import("numpy.core._internal") - .attr("_dtype_from_pep3118") - .cast<object>() - .release() - .ptr(); - return reinterpret_borrow<object>(obj); + static object &_dtype_from_pep3118() { + PYBIND11_CONSTINIT static gil_safe_call_once_and_store<object> storage; + return storage + .call_once_and_store_result([]() { + return detail::import_numpy_core_submodule("_internal") + .attr("_dtype_from_pep3118"); + }) + .get_stored(); } dtype strip_padding(ssize_t itemsize) { @@ -792,9 +929,7 @@ public: } /// Byte size of a single element - ssize_t itemsize() const { - return detail::array_descriptor_proxy(detail::array_proxy(m_ptr)->descr)->elsize; - } + ssize_t itemsize() const { return dtype().itemsize(); } /// Total number of bytes ssize_t nbytes() const { return size() * itemsize(); } @@ -1012,7 +1147,7 @@ protected: /// Create array from any object -- always returns a new reference static PyObject *raw_array(PyObject *ptr, int ExtraFlags = 0) { if (ptr == nullptr) { - PyErr_SetString(PyExc_ValueError, "cannot create a pybind11::array from a nullptr"); + set_error(PyExc_ValueError, "cannot create a pybind11::array from a nullptr"); return nullptr; } return detail::npy_api::get().PyArray_FromAny_( @@ -1159,7 +1294,7 @@ protected: /// Create array from any object -- always returns a new reference static PyObject *raw_array_t(PyObject *ptr) { if (ptr == nullptr) { - PyErr_SetString(PyExc_ValueError, "cannot create a pybind11::array_t from a nullptr"); + set_error(PyExc_ValueError, "cannot create a pybind11::array_t from a nullptr"); return nullptr; } return detail::npy_api::get().PyArray_FromAny_(ptr, diff --git a/contrib/libs/pybind11/include/pybind11/pybind11.h b/contrib/libs/pybind11/include/pybind11/pybind11.h index cd30063303..ffbf4db39a 100644 --- a/contrib/libs/pybind11/include/pybind11/pybind11.h +++ b/contrib/libs/pybind11/include/pybind11/pybind11.h @@ -14,7 +14,9 @@ #include "detail/init.h" #include "attr.h" #include "gil.h" +#include "gil_safe_call_once.h" #include "options.h" +#include "typing.h" #include <cstdlib> #include <cstring> @@ -52,6 +54,47 @@ PYBIND11_WARNING_DISABLE_MSVC(4127) PYBIND11_NAMESPACE_BEGIN(detail) +inline std::string replace_newlines_and_squash(const char *text) { + const char *whitespaces = " \t\n\r\f\v"; + std::string result(text); + bool previous_is_whitespace = false; + + if (result.size() >= 2) { + // Do not modify string representations + char first_char = result[0]; + char last_char = result[result.size() - 1]; + if (first_char == last_char && first_char == '\'') { + return result; + } + } + result.clear(); + + // Replace characters in whitespaces array with spaces and squash consecutive spaces + while (*text != '\0') { + if (std::strchr(whitespaces, *text)) { + if (!previous_is_whitespace) { + result += ' '; + previous_is_whitespace = true; + } + } else { + result += *text; + previous_is_whitespace = false; + } + ++text; + } + + // Strip leading and trailing whitespaces + const size_t str_begin = result.find_first_not_of(whitespaces); + if (str_begin == std::string::npos) { + return ""; + } + + const size_t str_end = result.find_last_not_of(whitespaces); + const size_t str_range = str_end - str_begin + 1; + + return result.substr(str_begin, str_range); +} + // Apply all the extensions translators from a list // Return true if one of the translators completed without raising an exception // itself. Return of false indicates that if there are other translators @@ -424,7 +467,7 @@ protected: // Write default value if available. if (!is_starred && arg_index < rec->args.size() && rec->args[arg_index].descr) { signature += " = "; - signature += rec->args[arg_index].descr; + signature += detail::replace_newlines_and_squash(rec->args[arg_index].descr); } // Separator for positional-only arguments (placed after the // argument, rather than before like * @@ -449,9 +492,7 @@ protected: signature += rec->scope.attr("__module__").cast<std::string>() + "." + rec->scope.attr("__qualname__").cast<std::string>(); } else { - std::string tname(t->name()); - detail::clean_type_id(tname); - signature += tname; + signature += detail::quote_cpp_type_name(detail::clean_type_id(t->name())); } } else { signature += c; @@ -689,7 +730,7 @@ protected: /* Iterator over the list of potentially admissible overloads */ const function_record *overloads = reinterpret_cast<function_record *>( PyCapsule_GetPointer(self, get_function_record_capsule_name())), - *it = overloads; + *current_overload = overloads; assert(overloads != nullptr); /* Need to know how many arguments + keyword arguments there are to pick the right @@ -703,9 +744,8 @@ protected: if (overloads->is_constructor) { if (!parent || !PyObject_TypeCheck(parent.ptr(), (PyTypeObject *) overloads->scope.ptr())) { - PyErr_SetString( - PyExc_TypeError, - "__init__(self, ...) called with invalid or missing `self` argument"); + set_error(PyExc_TypeError, + "__init__(self, ...) called with invalid or missing `self` argument"); return nullptr; } @@ -728,9 +768,10 @@ protected: std::vector<function_call> second_pass; // However, if there are no overloads, we can just skip the no-convert pass entirely - const bool overloaded = it != nullptr && it->next != nullptr; + const bool overloaded + = current_overload != nullptr && current_overload->next != nullptr; - for (; it != nullptr; it = it->next) { + for (; current_overload != nullptr; current_overload = current_overload->next) { /* For each overload: 1. Copy all positional arguments we were given, also checking to make sure that @@ -751,7 +792,7 @@ protected: a result other than PYBIND11_TRY_NEXT_OVERLOAD. */ - const function_record &func = *it; + const function_record &func = *current_overload; size_t num_args = func.nargs; // Number of positional arguments that we need if (func.has_args) { --num_args; // (but don't count py::args @@ -989,10 +1030,10 @@ protected: } if (result.ptr() != PYBIND11_TRY_NEXT_OVERLOAD) { - // The error reporting logic below expects 'it' to be valid, as it would be - // if we'd encountered this failure in the first-pass loop. + // The error reporting logic below expects 'current_overload' to be valid, + // as it would be if we'd encountered this failure in the first-pass loop. if (!result) { - it = &call.func; + current_overload = &call.func; } break; } @@ -1016,7 +1057,7 @@ protected: A translator may choose to do one of the following: - - catch the exception and call PyErr_SetString or PyErr_SetObject + - catch the exception and call py::set_error() to set a standard (or custom) Python exception, or - do nothing and let the exception fall through to the next translator, or - delegate translation to the next translator by throwing a new type of exception. @@ -1032,8 +1073,7 @@ protected: return nullptr; } - PyErr_SetString(PyExc_SystemError, - "Exception escaped from default exception translator!"); + set_error(PyExc_SystemError, "Exception escaped from default exception translator!"); return nullptr; } @@ -1111,7 +1151,7 @@ protected: } msg += "kwargs: "; bool first = true; - for (auto kwarg : kwargs) { + for (const auto &kwarg : kwargs) { if (first) { first = false; } else { @@ -1136,13 +1176,14 @@ protected: return nullptr; } #endif - PyErr_SetString(PyExc_TypeError, msg.c_str()); + set_error(PyExc_TypeError, msg.c_str()); return nullptr; } if (!result) { std::string msg = "Unable to convert function return value to a " "Python type! The signature was\n\t"; - msg += it->signature; + assert(current_overload != nullptr); + msg += current_overload->signature; append_note_if_missing_header_is_suspected(msg); #if PY_VERSION_HEX >= 0x03030000 // Attach additional error info to the exception if supported @@ -1151,7 +1192,7 @@ protected: return nullptr; } #endif - PyErr_SetString(PyExc_TypeError, msg.c_str()); + set_error(PyExc_TypeError, msg.c_str()); return nullptr; } if (overloads->is_constructor && !self_value_and_holder.holder_constructed()) { @@ -1162,6 +1203,15 @@ protected: } }; +PYBIND11_NAMESPACE_BEGIN(detail) + +template <> +struct handle_type_name<cpp_function> { + static constexpr auto name = const_name("Callable"); +}; + +PYBIND11_NAMESPACE_END(detail) + /// Wrapper for Python extension modules class module_ : public object { public: @@ -1305,6 +1355,15 @@ public: } }; +PYBIND11_NAMESPACE_BEGIN(detail) + +template <> +struct handle_type_name<module_> { + static constexpr auto name = const_name("module"); +}; + +PYBIND11_NAMESPACE_END(detail) + // When inside a namespace (or anywhere as long as it's not the first item on a line), // C++20 allows "module" to be used. This is provided for backward compatibility, and for // simplicity, if someone wants to use py::module for example, that is perfectly safe. @@ -2008,7 +2067,7 @@ struct enum_base { object type_name = type::handle_of(arg).attr("__name__"); return pybind11::str("{}.{}").format(std::move(type_name), enum_name(arg)); }, - name("name"), + name("__str__"), is_method(m_base)); if (options::show_enum_members_docstring()) { @@ -2429,7 +2488,7 @@ iterator make_iterator_impl(Iterator first, Sentinel last, Extra &&...extra) { Policy); } - return cast(state{first, last, true}); + return cast(state{std::forward<Iterator>(first), std::forward<Sentinel>(last), true}); } PYBIND11_NAMESPACE_END(detail) @@ -2440,13 +2499,15 @@ template <return_value_policy Policy = return_value_policy::reference_internal, typename Sentinel, typename ValueType = typename detail::iterator_access<Iterator>::result_type, typename... Extra> -iterator make_iterator(Iterator first, Sentinel last, Extra &&...extra) { +typing::Iterator<ValueType> make_iterator(Iterator first, Sentinel last, Extra &&...extra) { return detail::make_iterator_impl<detail::iterator_access<Iterator>, Policy, Iterator, Sentinel, ValueType, - Extra...>(first, last, std::forward<Extra>(extra)...); + Extra...>(std::forward<Iterator>(first), + std::forward<Sentinel>(last), + std::forward<Extra>(extra)...); } /// Makes a python iterator over the keys (`.first`) of a iterator over pairs from a @@ -2456,13 +2517,15 @@ template <return_value_policy Policy = return_value_policy::reference_internal, typename Sentinel, typename KeyType = typename detail::iterator_key_access<Iterator>::result_type, typename... Extra> -iterator make_key_iterator(Iterator first, Sentinel last, Extra &&...extra) { +typing::Iterator<KeyType> make_key_iterator(Iterator first, Sentinel last, Extra &&...extra) { return detail::make_iterator_impl<detail::iterator_key_access<Iterator>, Policy, Iterator, Sentinel, KeyType, - Extra...>(first, last, std::forward<Extra>(extra)...); + Extra...>(std::forward<Iterator>(first), + std::forward<Sentinel>(last), + std::forward<Extra>(extra)...); } /// Makes a python iterator over the values (`.second`) of a iterator over pairs from a @@ -2472,21 +2535,25 @@ template <return_value_policy Policy = return_value_policy::reference_internal, typename Sentinel, typename ValueType = typename detail::iterator_value_access<Iterator>::result_type, typename... Extra> -iterator make_value_iterator(Iterator first, Sentinel last, Extra &&...extra) { +typing::Iterator<ValueType> make_value_iterator(Iterator first, Sentinel last, Extra &&...extra) { return detail::make_iterator_impl<detail::iterator_value_access<Iterator>, Policy, Iterator, Sentinel, ValueType, - Extra...>(first, last, std::forward<Extra>(extra)...); + Extra...>(std::forward<Iterator>(first), + std::forward<Sentinel>(last), + std::forward<Extra>(extra)...); } /// Makes an iterator over values of an stl container or other container supporting /// `std::begin()`/`std::end()` template <return_value_policy Policy = return_value_policy::reference_internal, typename Type, + typename ValueType = typename detail::iterator_access< + decltype(std::begin(std::declval<Type &>()))>::result_type, typename... Extra> -iterator make_iterator(Type &value, Extra &&...extra) { +typing::Iterator<ValueType> make_iterator(Type &value, Extra &&...extra) { return make_iterator<Policy>( std::begin(value), std::end(value), std::forward<Extra>(extra)...); } @@ -2495,8 +2562,10 @@ iterator make_iterator(Type &value, Extra &&...extra) { /// `std::begin()`/`std::end()` template <return_value_policy Policy = return_value_policy::reference_internal, typename Type, + typename KeyType = typename detail::iterator_key_access< + decltype(std::begin(std::declval<Type &>()))>::result_type, typename... Extra> -iterator make_key_iterator(Type &value, Extra &&...extra) { +typing::Iterator<KeyType> make_key_iterator(Type &value, Extra &&...extra) { return make_key_iterator<Policy>( std::begin(value), std::end(value), std::forward<Extra>(extra)...); } @@ -2505,8 +2574,10 @@ iterator make_key_iterator(Type &value, Extra &&...extra) { /// `std::begin()`/`std::end()` template <return_value_policy Policy = return_value_policy::reference_internal, typename Type, + typename ValueType = typename detail::iterator_value_access< + decltype(std::begin(std::declval<Type &>()))>::result_type, typename... Extra> -iterator make_value_iterator(Type &value, Extra &&...extra) { +typing::Iterator<ValueType> make_value_iterator(Type &value, Extra &&...extra) { return make_value_iterator<Policy>( std::begin(value), std::end(value), std::forward<Extra>(extra)...); } @@ -2562,7 +2633,7 @@ inline void register_local_exception_translator(ExceptionTranslator &&translator /** * Wrapper to generate a new Python exception type. * - * This should only be used with PyErr_SetString for now. + * This should only be used with py::set_error() for now. * It is not (yet) possible to use as a py::base. * Template type argument is reserved for future use. */ @@ -2583,27 +2654,25 @@ public: } // Sets the current python exception to this exception object with the given message - void operator()(const char *message) { PyErr_SetString(m_ptr, message); } + PYBIND11_DEPRECATED("Please use py::set_error() instead " + "(https://github.com/pybind/pybind11/pull/4772)") + void operator()(const char *message) const { set_error(*this, message); } }; PYBIND11_NAMESPACE_BEGIN(detail) -// Returns a reference to a function-local static exception object used in the simple -// register_exception approach below. (It would be simpler to have the static local variable -// directly in register_exception, but that makes clang <3.5 segfault - issue #1349). -template <typename CppException> -exception<CppException> &get_exception_object() { - static exception<CppException> ex; - return ex; -} + +template <> +struct handle_type_name<exception<void>> { + static constexpr auto name = const_name("Exception"); +}; // Helper function for register_exception and register_local_exception template <typename CppException> exception<CppException> & register_exception_impl(handle scope, const char *name, handle base, bool isLocal) { - auto &ex = detail::get_exception_object<CppException>(); - if (!ex) { - ex = exception<CppException>(scope, name, base); - } + PYBIND11_CONSTINIT static gil_safe_call_once_and_store<exception<CppException>> exc_storage; + exc_storage.call_once_and_store_result( + [&]() { return exception<CppException>(scope, name, base); }); auto register_func = isLocal ? ®ister_local_exception_translator : ®ister_exception_translator; @@ -2615,10 +2684,10 @@ register_exception_impl(handle scope, const char *name, handle base, bool isLoca try { std::rethrow_exception(p); } catch (const CppException &e) { - detail::get_exception_object<CppException>()(e.what()); + set_error(exc_storage.get_stored(), e.what()); } }); - return ex; + return exc_storage.get_stored(); } PYBIND11_NAMESPACE_END(detail) @@ -2737,7 +2806,11 @@ get_type_override(const void *this_ptr, const type_info *this_type, const char * if ((std::string) str(f_code->co_name) == name && f_code->co_argcount > 0) { PyObject *locals = PyEval_GetLocals(); if (locals != nullptr) { +# if PY_VERSION_HEX >= 0x030b0000 + PyObject *co_varnames = PyCode_GetVarnames(f_code); +# else PyObject *co_varnames = PyObject_GetAttrString((PyObject *) f_code, "co_varnames"); +# endif PyObject *self_arg = PyTuple_GET_ITEM(co_varnames, 0); Py_DECREF(co_varnames); PyObject *self_caller = dict_getitem(locals, self_arg); diff --git a/contrib/libs/pybind11/include/pybind11/pytypes.h b/contrib/libs/pybind11/include/pybind11/pytypes.h index 6c255c6cde..e48ecf676f 100644 --- a/contrib/libs/pybind11/include/pybind11/pytypes.h +++ b/contrib/libs/pybind11/include/pybind11/pytypes.h @@ -59,6 +59,7 @@ struct sequence_item; struct list_item; struct tuple_item; } // namespace accessor_policies +// PLEASE KEEP handle_type_name SPECIALIZATIONS IN SYNC. using obj_attr_accessor = accessor<accessor_policies::obj_attr>; using str_attr_accessor = accessor<accessor_policies::str_attr>; using item_accessor = accessor<accessor_policies::generic_item>; @@ -310,19 +311,19 @@ private: "https://pybind11.readthedocs.io/en/stable/advanced/" "misc.html#common-sources-of-global-interpreter-lock-errors for debugging advice.\n" "If you are convinced there is no bug in your code, you can #define " - "PYBIND11_NO_ASSERT_GIL_HELD_INCREF_DECREF" + "PYBIND11_NO_ASSERT_GIL_HELD_INCREF_DECREF " "to disable this check. In that case you have to ensure this #define is consistently " "used for all translation units linked into a given pybind11 extension, otherwise " "there will be ODR violations.", function_name.c_str()); - fflush(stderr); if (Py_TYPE(m_ptr)->tp_name != nullptr) { fprintf(stderr, - "The failing %s call was triggered on a %s object.\n", + " The failing %s call was triggered on a %s object.", function_name.c_str(), Py_TYPE(m_ptr)->tp_name); - fflush(stderr); } + fprintf(stderr, "\n"); + fflush(stderr); throw std::runtime_error(function_name + " PyGILState_Check() failure."); } #endif @@ -339,6 +340,14 @@ public: #endif }; +inline void set_error(const handle &type, const char *message) { + PyErr_SetString(type.ptr(), message); +} + +inline void set_error(const handle &type, const handle &value) { + PyErr_SetObject(type.ptr(), value.ptr()); +} + /** \rst Holds a reference to a Python object (with reference counting) @@ -1639,7 +1648,15 @@ inline namespace literals { /** \rst String literal version of `str` \endrst */ -inline str operator"" _s(const char *s, size_t size) { return {s, size}; } +inline str +#if !defined(__clang__) && defined(__GNUC__) && __GNUC__ < 5 +operator"" _s // gcc 4.8.5 insists on having a space (hard error). +#else +operator""_s // clang 17 generates a deprecation warning if there is a space. +#endif + (const char *s, size_t size) { + return {s, size}; +} } // namespace literals /// \addtogroup pytypes diff --git a/contrib/libs/pybind11/include/pybind11/typing.h b/contrib/libs/pybind11/include/pybind11/typing.h new file mode 100644 index 0000000000..bc275fc50b --- /dev/null +++ b/contrib/libs/pybind11/include/pybind11/typing.h @@ -0,0 +1,125 @@ +/* + pybind11/typing.h: Convenience wrapper classes for basic Python types + with more explicit annotations. + + Copyright (c) 2023 Dustin Spicuzza <dustin@virtualroadside.com> + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#pragma once + +#include "detail/common.h" +#include "cast.h" +#include "pytypes.h" + +PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) +PYBIND11_NAMESPACE_BEGIN(typing) + +/* + The following types can be used to direct pybind11-generated docstrings + to have have more explicit types (e.g., `list[str]` instead of `list`). + Just use these in place of existing types. + + There is no additional enforcement of types at runtime. +*/ + +template <typename... Types> +class Tuple : public tuple { + using tuple::tuple; +}; + +template <typename K, typename V> +class Dict : public dict { + using dict::dict; +}; + +template <typename T> +class List : public list { + using list::list; +}; + +template <typename T> +class Set : public set { + using set::set; +}; + +template <typename T> +class Iterable : public iterable { + using iterable::iterable; +}; + +template <typename T> +class Iterator : public iterator { + using iterator::iterator; +}; + +template <typename Signature> +class Callable; + +template <typename Return, typename... Args> +class Callable<Return(Args...)> : public function { + using function::function; +}; + +PYBIND11_NAMESPACE_END(typing) + +PYBIND11_NAMESPACE_BEGIN(detail) + +template <typename... Types> +struct handle_type_name<typing::Tuple<Types...>> { + static constexpr auto name = const_name("tuple[") + + ::pybind11::detail::concat(make_caster<Types>::name...) + + const_name("]"); +}; + +template <> +struct handle_type_name<typing::Tuple<>> { + // PEP 484 specifies this syntax for an empty tuple + static constexpr auto name = const_name("tuple[()]"); +}; + +template <typename T> +struct handle_type_name<typing::Tuple<T, ellipsis>> { + // PEP 484 specifies this syntax for a variable-length tuple + static constexpr auto name + = const_name("tuple[") + make_caster<T>::name + const_name(", ...]"); +}; + +template <typename K, typename V> +struct handle_type_name<typing::Dict<K, V>> { + static constexpr auto name = const_name("dict[") + make_caster<K>::name + const_name(", ") + + make_caster<V>::name + const_name("]"); +}; + +template <typename T> +struct handle_type_name<typing::List<T>> { + static constexpr auto name = const_name("list[") + make_caster<T>::name + const_name("]"); +}; + +template <typename T> +struct handle_type_name<typing::Set<T>> { + static constexpr auto name = const_name("set[") + make_caster<T>::name + const_name("]"); +}; + +template <typename T> +struct handle_type_name<typing::Iterable<T>> { + static constexpr auto name = const_name("Iterable[") + make_caster<T>::name + const_name("]"); +}; + +template <typename T> +struct handle_type_name<typing::Iterator<T>> { + static constexpr auto name = const_name("Iterator[") + make_caster<T>::name + const_name("]"); +}; + +template <typename Return, typename... Args> +struct handle_type_name<typing::Callable<Return(Args...)>> { + using retval_type = conditional_t<std::is_same<Return, void>::value, void_type, Return>; + static constexpr auto name + = const_name("Callable[[") + ::pybind11::detail::concat(make_caster<Args>::name...) + + const_name("], ") + make_caster<retval_type>::name + const_name("]"); +}; + +PYBIND11_NAMESPACE_END(detail) +PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE) diff --git a/contrib/libs/pybind11/ya.make b/contrib/libs/pybind11/ya.make index 95a7f21ea3..8e7f534a2c 100644 --- a/contrib/libs/pybind11/ya.make +++ b/contrib/libs/pybind11/ya.make @@ -6,9 +6,9 @@ LICENSE(BSD-3-Clause) LICENSE_TEXTS(.yandex_meta/licenses.list.txt) -VERSION(2.11.1) +VERSION(2.12.0) -ORIGINAL_SOURCE(https://github.com/pybind/pybind11/archive/v2.11.1.tar.gz) +ORIGINAL_SOURCE(https://github.com/pybind/pybind11/archive/v2.12.0.tar.gz) ADDINCL( GLOBAL contrib/libs/pybind11/include diff --git a/contrib/python/matplotlib/py3/matplotlib/backends/backend_webagg.py b/contrib/python/matplotlib/py3/matplotlib/backends/backend_webagg.py index 14c0b525fb..030ab8519b 100644 --- a/contrib/python/matplotlib/py3/matplotlib/backends/backend_webagg.py +++ b/contrib/python/matplotlib/py3/matplotlib/backends/backend_webagg.py @@ -19,6 +19,10 @@ import random import sys import signal import threading +import tempfile +import os + +from library.python.resource import iteritems try: import tornado @@ -177,12 +181,14 @@ class WebAggApplication(tornado.web.Application): assert url_prefix[0] == '/' and url_prefix[-1] != '/', \ 'url_prefix must start with a "/" and not end with one.' + self._store_resources() + package_resources_abspath = os.path.join(self._stored_package_path, core.FigureManagerWebAgg.get_static_file_path()) super().__init__( [ # Static files for the CSS and JS (url_prefix + r'/_static/(.*)', tornado.web.StaticFileHandler, - {'path': core.FigureManagerWebAgg.get_static_file_path()}), + {'path': package_resources_abspath}), # Static images for the toolbar (url_prefix + r'/_images/(.*)', @@ -210,7 +216,19 @@ class WebAggApplication(tornado.web.Application): (url_prefix + r'/([0-9]+)/download.([a-z0-9.]+)', self.Download), ], - template_path=core.FigureManagerWebAgg.get_static_file_path()) + template_path=package_resources_abspath) + + def _store_resources(self): + self._stored_package_dir = tempfile.TemporaryDirectory() + self._stored_package_path = self._stored_package_dir.name + package_path = os.path.join(*"contrib/python/matplotlib/py3/".split("/")) + for key, data in iteritems(prefix="resfs/file/" + package_path, strip_prefix=True): + path = os.path.join(self._stored_package_path, *os.path.split(package_path), *os.path.split(key)) + dir = os.path.dirname(path) + if not os.path.exists(dir): + os.makedirs(dir) + with open(path, "wb") as file: + file.write(data) @classmethod def initialize(cls, url_prefix='', port=None, address=None): |