mirror of
https://github.com/pybind/pybind11.git
synced 2024-11-22 13:15:12 +00:00
Merge branch 'master' into sh_merge_master
This commit is contained in:
commit
0be972a9c1
4
.github/workflows/pip.yml
vendored
4
.github/workflows/pip.yml
vendored
@ -99,13 +99,13 @@ jobs:
|
||||
- uses: actions/download-artifact@v3
|
||||
|
||||
- name: Publish standard package
|
||||
uses: pypa/gh-action-pypi-publish@v1.6.1
|
||||
uses: pypa/gh-action-pypi-publish@v1.6.4
|
||||
with:
|
||||
password: ${{ secrets.pypi_password }}
|
||||
packages_dir: standard/
|
||||
|
||||
- name: Publish global package
|
||||
uses: pypa/gh-action-pypi-publish@v1.6.1
|
||||
uses: pypa/gh-action-pypi-publish@v1.6.4
|
||||
with:
|
||||
password: ${{ secrets.pypi_password_global }}
|
||||
packages_dir: global/
|
||||
|
@ -24,7 +24,7 @@ exclude: ^tools/JoinPaths.cmake$
|
||||
repos:
|
||||
# Standard hooks
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: "v4.3.0"
|
||||
rev: "v4.4.0"
|
||||
hooks:
|
||||
- id: check-added-large-files
|
||||
- id: check-case-conflict
|
||||
@ -42,7 +42,7 @@ repos:
|
||||
|
||||
# Upgrade old Python syntax
|
||||
- repo: https://github.com/asottile/pyupgrade
|
||||
rev: "v3.2.0"
|
||||
rev: "v3.3.0"
|
||||
hooks:
|
||||
- id: pyupgrade
|
||||
args: [--py36-plus]
|
||||
@ -82,7 +82,7 @@ repos:
|
||||
|
||||
# Autoremoves unused imports
|
||||
- repo: https://github.com/hadialqattan/pycln
|
||||
rev: "v2.1.1"
|
||||
rev: "v2.1.2"
|
||||
hooks:
|
||||
- id: pycln
|
||||
stages: [manual]
|
||||
@ -111,7 +111,7 @@ repos:
|
||||
|
||||
# Flake8 also supports pre-commit natively (same author)
|
||||
- repo: https://github.com/PyCQA/flake8
|
||||
rev: "5.0.4"
|
||||
rev: "6.0.0"
|
||||
hooks:
|
||||
- id: flake8
|
||||
exclude: ^(docs/.*|tools/.*|ubench/.*)$
|
||||
@ -119,7 +119,7 @@ repos:
|
||||
|
||||
# PyLint has native support - not always usable, but works for us
|
||||
- repo: https://github.com/PyCQA/pylint
|
||||
rev: "v2.15.5"
|
||||
rev: "v2.15.8"
|
||||
hooks:
|
||||
- id: pylint
|
||||
files: ^pybind11
|
||||
@ -135,7 +135,7 @@ repos:
|
||||
|
||||
# Check static types with mypy
|
||||
- repo: https://github.com/pre-commit/mirrors-mypy
|
||||
rev: "v0.982"
|
||||
rev: "v0.991"
|
||||
hooks:
|
||||
- id: mypy
|
||||
args: []
|
||||
@ -144,7 +144,7 @@ repos:
|
||||
|
||||
# Checks the manifest for missing files (native support)
|
||||
- repo: https://github.com/mgedmin/check-manifest
|
||||
rev: "0.48"
|
||||
rev: "0.49"
|
||||
hooks:
|
||||
- id: check-manifest
|
||||
# This is a slow hook, so only run this if --hook-stage manual is passed
|
||||
@ -178,7 +178,7 @@ repos:
|
||||
|
||||
# Clang format the codebase automatically
|
||||
- repo: https://github.com/pre-commit/mirrors-clang-format
|
||||
rev: "v14.0.6"
|
||||
rev: "v15.0.4"
|
||||
hooks:
|
||||
- id: clang-format
|
||||
types_or: [c++, c, cuda]
|
||||
|
@ -324,6 +324,15 @@ The class ``options`` allows you to selectively suppress auto-generated signatur
|
||||
m.def("add", [](int a, int b) { return a + b; }, "A function which adds two numbers");
|
||||
}
|
||||
|
||||
pybind11 also appends all members of an enum to the resulting enum docstring.
|
||||
This default behavior can be disabled by using the ``disable_enum_members_docstring()``
|
||||
function of the ``options`` class.
|
||||
|
||||
With ``disable_user_defined_docstrings()`` all user defined docstrings of
|
||||
``module_::def()``, ``class_::def()`` and ``enum_()`` are disabled, but the
|
||||
function signatures and enum members are included in the docstring, unless they
|
||||
are disabled separately.
|
||||
|
||||
Note that changes to the settings affect only function bindings created during the
|
||||
lifetime of the ``options`` instance. When it goes out of scope at the end of the module's init function,
|
||||
the default settings are restored to prevent unwanted side effects.
|
||||
|
@ -121,7 +121,8 @@ public:
|
||||
template <typename T_, \
|
||||
::pybind11::detail::enable_if_t< \
|
||||
std::is_same<type, ::pybind11::detail::remove_cv_t<T_>>::value, \
|
||||
int> = 0> \
|
||||
int> \
|
||||
= 0> \
|
||||
static ::pybind11::handle cast( \
|
||||
T_ *src, ::pybind11::return_value_policy policy, ::pybind11::handle parent) { \
|
||||
if (!src) \
|
||||
|
@ -34,17 +34,17 @@
|
||||
# define PYBIND11_WARNING_POP PYBIND11_PRAGMA(warning(pop))
|
||||
#elif defined(__INTEL_COMPILER)
|
||||
# define PYBIND11_COMPILER_INTEL
|
||||
# define PYBIND11_PRAGMA(...) _Pragma(# __VA_ARGS__)
|
||||
# define PYBIND11_PRAGMA(...) _Pragma(#__VA_ARGS__)
|
||||
# define PYBIND11_WARNING_PUSH PYBIND11_PRAGMA(warning push)
|
||||
# define PYBIND11_WARNING_POP PYBIND11_PRAGMA(warning pop)
|
||||
#elif defined(__clang__)
|
||||
# define PYBIND11_COMPILER_CLANG
|
||||
# define PYBIND11_PRAGMA(...) _Pragma(# __VA_ARGS__)
|
||||
# define PYBIND11_PRAGMA(...) _Pragma(#__VA_ARGS__)
|
||||
# define PYBIND11_WARNING_PUSH PYBIND11_PRAGMA(clang diagnostic push)
|
||||
# define PYBIND11_WARNING_POP PYBIND11_PRAGMA(clang diagnostic push)
|
||||
#elif defined(__GNUC__)
|
||||
# define PYBIND11_COMPILER_GCC
|
||||
# define PYBIND11_PRAGMA(...) _Pragma(# __VA_ARGS__)
|
||||
# define PYBIND11_PRAGMA(...) _Pragma(#__VA_ARGS__)
|
||||
# define PYBIND11_WARNING_PUSH PYBIND11_PRAGMA(GCC diagnostic push)
|
||||
# define PYBIND11_WARNING_POP PYBIND11_PRAGMA(GCC diagnostic pop)
|
||||
#endif
|
||||
@ -323,6 +323,15 @@ PYBIND11_WARNING_POP
|
||||
# define PYBIND11_HAS_U8STRING
|
||||
#endif
|
||||
|
||||
// See description of PR #4246:
|
||||
#if !defined(NDEBUG) && !defined(PY_ASSERT_GIL_HELD_INCREF_DECREF) \
|
||||
&& !(defined(PYPY_VERSION) \
|
||||
&& defined(_MSC_VER)) /* PyPy Windows: pytest hangs indefinitely at the end of the \
|
||||
process (see PR #4268) */ \
|
||||
&& !defined(PYBIND11_ASSERT_GIL_HELD_INCREF_DECREF)
|
||||
# define PYBIND11_ASSERT_GIL_HELD_INCREF_DECREF
|
||||
#endif
|
||||
|
||||
// #define PYBIND11_STR_LEGACY_PERMISSIVE
|
||||
// If DEFINED, pybind11::str can hold PyUnicodeObject or PyBytesObject
|
||||
// (probably surprising and never documented, but this was the
|
||||
|
@ -282,10 +282,11 @@ struct constructor {
|
||||
extra...);
|
||||
}
|
||||
|
||||
template <typename Class,
|
||||
typename... Extra,
|
||||
enable_if_t<Class::has_alias && std::is_constructible<Cpp<Class>, Args...>::value,
|
||||
int> = 0>
|
||||
template <
|
||||
typename Class,
|
||||
typename... Extra,
|
||||
enable_if_t<Class::has_alias && std::is_constructible<Cpp<Class>, Args...>::value, int>
|
||||
= 0>
|
||||
static void execute(Class &cl, const Extra &...extra) {
|
||||
cl.def(
|
||||
"__init__",
|
||||
@ -302,10 +303,11 @@ struct constructor {
|
||||
extra...);
|
||||
}
|
||||
|
||||
template <typename Class,
|
||||
typename... Extra,
|
||||
enable_if_t<Class::has_alias && !std::is_constructible<Cpp<Class>, Args...>::value,
|
||||
int> = 0>
|
||||
template <
|
||||
typename Class,
|
||||
typename... Extra,
|
||||
enable_if_t<Class::has_alias && !std::is_constructible<Cpp<Class>, Args...>::value, int>
|
||||
= 0>
|
||||
static void execute(Class &cl, const Extra &...extra) {
|
||||
cl.def(
|
||||
"__init__",
|
||||
@ -321,10 +323,11 @@ struct constructor {
|
||||
// Implementing class for py::init_alias<...>()
|
||||
template <typename... Args>
|
||||
struct alias_constructor {
|
||||
template <typename Class,
|
||||
typename... Extra,
|
||||
enable_if_t<Class::has_alias && std::is_constructible<Alias<Class>, Args...>::value,
|
||||
int> = 0>
|
||||
template <
|
||||
typename Class,
|
||||
typename... Extra,
|
||||
enable_if_t<Class::has_alias && std::is_constructible<Alias<Class>, Args...>::value, int>
|
||||
= 0>
|
||||
static void execute(Class &cl, const Extra &...extra) {
|
||||
cl.def(
|
||||
"__init__",
|
||||
|
@ -1010,5 +1010,14 @@ protected:
|
||||
static Constructor make_move_constructor(...) { return nullptr; }
|
||||
};
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
PYBIND11_NAMESPACE_END(detail)
|
||||
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
||||
|
@ -279,7 +279,7 @@ struct type_caster<Type, typename eigen_tensor_helper<Type>::ValidType> {
|
||||
case return_value_policy::take_ownership:
|
||||
if (std::is_const<C>::value) {
|
||||
// This cast is ugly, and might be UB in some cases, but we don't have an
|
||||
// alterantive here as we must free that memory
|
||||
// alternative here as we must free that memory
|
||||
Helper::free(const_cast<Type *>(src));
|
||||
pybind11_fail("Cannot take ownership of a const reference");
|
||||
}
|
||||
|
@ -1471,7 +1471,7 @@ private:
|
||||
}
|
||||
|
||||
// Extract name, offset and format descriptor for a struct field
|
||||
# define PYBIND11_FIELD_DESCRIPTOR(T, Field) PYBIND11_FIELD_DESCRIPTOR_EX(T, Field, # Field)
|
||||
# define PYBIND11_FIELD_DESCRIPTOR(T, Field) PYBIND11_FIELD_DESCRIPTOR_EX(T, Field, #Field)
|
||||
|
||||
// The main idea of this macro is borrowed from https://github.com/swansontec/map-macro
|
||||
// (C) William Swanson, Paul Fultz
|
||||
|
@ -47,6 +47,16 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
options &disable_enum_members_docstring() & {
|
||||
global_state().show_enum_members_docstring = false;
|
||||
return *this;
|
||||
}
|
||||
|
||||
options &enable_enum_members_docstring() & {
|
||||
global_state().show_enum_members_docstring = true;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Getter methods (return the global state):
|
||||
|
||||
static bool show_user_defined_docstrings() {
|
||||
@ -55,6 +65,10 @@ public:
|
||||
|
||||
static bool show_function_signatures() { return global_state().show_function_signatures; }
|
||||
|
||||
static bool show_enum_members_docstring() {
|
||||
return global_state().show_enum_members_docstring;
|
||||
}
|
||||
|
||||
// This type is not meant to be allocated on the heap.
|
||||
void *operator new(size_t) = delete;
|
||||
|
||||
@ -63,6 +77,8 @@ private:
|
||||
bool show_user_defined_docstrings = true; //< Include user-supplied texts in docstrings.
|
||||
bool show_function_signatures = true; //< Include auto-generated function signatures
|
||||
// in docstrings.
|
||||
bool show_enum_members_docstring = true; //< Include auto-generated member list in enum
|
||||
// docstrings.
|
||||
};
|
||||
|
||||
static state &global_state() {
|
||||
|
@ -1428,9 +1428,9 @@ template <typename T, enable_if_t<has_operator_delete<T>::value, int> = 0>
|
||||
void call_operator_delete(T *p, size_t, size_t) {
|
||||
T::operator delete(p);
|
||||
}
|
||||
template <
|
||||
typename T,
|
||||
enable_if_t<!has_operator_delete<T>::value && has_operator_delete_size<T>::value, int> = 0>
|
||||
template <typename T,
|
||||
enable_if_t<!has_operator_delete<T>::value && has_operator_delete_size<T>::value, int>
|
||||
= 0>
|
||||
void call_operator_delete(T *p, size_t s, size_t) {
|
||||
T::operator delete(p, s);
|
||||
}
|
||||
@ -2227,29 +2227,35 @@ struct enum_base {
|
||||
name("name"),
|
||||
is_method(m_base));
|
||||
|
||||
m_base.attr("__doc__") = static_property(
|
||||
cpp_function(
|
||||
[](handle arg) -> std::string {
|
||||
std::string docstring;
|
||||
dict entries = arg.attr("__entries");
|
||||
if (((PyTypeObject *) arg.ptr())->tp_doc) {
|
||||
docstring += std::string(((PyTypeObject *) arg.ptr())->tp_doc) + "\n\n";
|
||||
}
|
||||
docstring += "Members:";
|
||||
for (auto kv : entries) {
|
||||
auto key = std::string(pybind11::str(kv.first));
|
||||
auto comment = kv.second[int_(1)];
|
||||
docstring += "\n\n " + key;
|
||||
if (!comment.is_none()) {
|
||||
docstring += " : " + (std::string) pybind11::str(comment);
|
||||
if (options::show_enum_members_docstring()) {
|
||||
m_base.attr("__doc__") = static_property(
|
||||
cpp_function(
|
||||
[](handle arg) -> std::string {
|
||||
std::string docstring;
|
||||
dict entries = arg.attr("__entries");
|
||||
if (((PyTypeObject *) arg.ptr())->tp_doc) {
|
||||
docstring += std::string(
|
||||
reinterpret_cast<PyTypeObject *>(arg.ptr())->tp_doc);
|
||||
docstring += "\n\n";
|
||||
}
|
||||
}
|
||||
return docstring;
|
||||
},
|
||||
name("__doc__")),
|
||||
none(),
|
||||
none(),
|
||||
"");
|
||||
docstring += "Members:";
|
||||
for (auto kv : entries) {
|
||||
auto key = std::string(pybind11::str(kv.first));
|
||||
auto comment = kv.second[int_(1)];
|
||||
docstring += "\n\n ";
|
||||
docstring += key;
|
||||
if (!comment.is_none()) {
|
||||
docstring += " : ";
|
||||
docstring += pybind11::str(comment).cast<std::string>();
|
||||
}
|
||||
}
|
||||
return docstring;
|
||||
},
|
||||
name("__doc__")),
|
||||
none(),
|
||||
none(),
|
||||
"");
|
||||
}
|
||||
|
||||
m_base.attr("__members__") = static_property(cpp_function(
|
||||
[](handle arg) -> dict {
|
||||
|
@ -232,7 +232,8 @@ public:
|
||||
detail::enable_if_t<detail::all_of<detail::none_of<std::is_base_of<handle, T>,
|
||||
detail::is_pyobj_ptr_or_nullptr_t<T>>,
|
||||
std::is_convertible<T, PyObject *>>::value,
|
||||
int> = 0>
|
||||
int>
|
||||
= 0>
|
||||
// NOLINTNEXTLINE(google-explicit-constructor)
|
||||
handle(T &obj) : m_ptr(obj) {}
|
||||
|
||||
@ -248,6 +249,11 @@ public:
|
||||
const handle &inc_ref() const & {
|
||||
#ifdef PYBIND11_HANDLE_REF_DEBUG
|
||||
inc_ref_counter(1);
|
||||
#endif
|
||||
#if defined(PYBIND11_ASSERT_GIL_HELD_INCREF_DECREF)
|
||||
if (m_ptr != nullptr && !PyGILState_Check()) {
|
||||
throw std::runtime_error("pybind11::handle::inc_ref() PyGILState_Check() failure.");
|
||||
}
|
||||
#endif
|
||||
Py_XINCREF(m_ptr);
|
||||
return *this;
|
||||
@ -259,6 +265,11 @@ public:
|
||||
this function automatically. Returns a reference to itself.
|
||||
\endrst */
|
||||
const handle &dec_ref() const & {
|
||||
#if defined(PYBIND11_ASSERT_GIL_HELD_INCREF_DECREF)
|
||||
if (m_ptr != nullptr && !PyGILState_Check()) {
|
||||
throw std::runtime_error("pybind11::handle::dec_ref() PyGILState_Check() failure.");
|
||||
}
|
||||
#endif
|
||||
Py_XDECREF(m_ptr);
|
||||
return *this;
|
||||
}
|
||||
|
@ -10,10 +10,13 @@
|
||||
#pragma once
|
||||
|
||||
#include "detail/common.h"
|
||||
#include "detail/type_caster_base.h"
|
||||
#include "cast.h"
|
||||
#include "operators.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
#include <type_traits>
|
||||
|
||||
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
||||
@ -636,18 +639,52 @@ auto map_if_insertion_operator(Class_ &cl, std::string const &name)
|
||||
"Return the canonical string representation of this map.");
|
||||
}
|
||||
|
||||
template <typename Map>
|
||||
template <typename KeyType>
|
||||
struct keys_view {
|
||||
Map ↦
|
||||
virtual size_t len() = 0;
|
||||
virtual iterator iter() = 0;
|
||||
virtual bool contains(const KeyType &k) = 0;
|
||||
virtual bool contains(const object &k) = 0;
|
||||
virtual ~keys_view() = default;
|
||||
};
|
||||
|
||||
template <typename Map>
|
||||
template <typename MappedType>
|
||||
struct values_view {
|
||||
virtual size_t len() = 0;
|
||||
virtual iterator iter() = 0;
|
||||
virtual ~values_view() = default;
|
||||
};
|
||||
|
||||
template <typename KeyType, typename MappedType>
|
||||
struct items_view {
|
||||
virtual size_t len() = 0;
|
||||
virtual iterator iter() = 0;
|
||||
virtual ~items_view() = default;
|
||||
};
|
||||
|
||||
template <typename Map, typename KeysView>
|
||||
struct KeysViewImpl : public KeysView {
|
||||
explicit KeysViewImpl(Map &map) : map(map) {}
|
||||
size_t len() override { return map.size(); }
|
||||
iterator iter() override { return make_key_iterator(map.begin(), map.end()); }
|
||||
bool contains(const typename Map::key_type &k) override { return map.find(k) != map.end(); }
|
||||
bool contains(const object &) override { return false; }
|
||||
Map ↦
|
||||
};
|
||||
|
||||
template <typename Map>
|
||||
struct items_view {
|
||||
template <typename Map, typename ValuesView>
|
||||
struct ValuesViewImpl : public ValuesView {
|
||||
explicit ValuesViewImpl(Map &map) : map(map) {}
|
||||
size_t len() override { return map.size(); }
|
||||
iterator iter() override { return make_value_iterator(map.begin(), map.end()); }
|
||||
Map ↦
|
||||
};
|
||||
|
||||
template <typename Map, typename ItemsView>
|
||||
struct ItemsViewImpl : public ItemsView {
|
||||
explicit ItemsViewImpl(Map &map) : map(map) {}
|
||||
size_t len() override { return map.size(); }
|
||||
iterator iter() override { return make_iterator(map.begin(), map.end()); }
|
||||
Map ↦
|
||||
};
|
||||
|
||||
@ -657,9 +694,11 @@ template <typename Map, typename holder_type = default_holder_type<Map>, typenam
|
||||
class_<Map, holder_type> bind_map(handle scope, const std::string &name, Args &&...args) {
|
||||
using KeyType = typename Map::key_type;
|
||||
using MappedType = typename Map::mapped_type;
|
||||
using KeysView = detail::keys_view<Map>;
|
||||
using ValuesView = detail::values_view<Map>;
|
||||
using ItemsView = detail::items_view<Map>;
|
||||
using StrippedKeyType = detail::remove_cvref_t<KeyType>;
|
||||
using StrippedMappedType = detail::remove_cvref_t<MappedType>;
|
||||
using KeysView = detail::keys_view<StrippedKeyType>;
|
||||
using ValuesView = detail::values_view<StrippedMappedType>;
|
||||
using ItemsView = detail::items_view<StrippedKeyType, StrippedMappedType>;
|
||||
using Class_ = class_<Map, holder_type>;
|
||||
|
||||
// If either type is a non-module-local bound type then make the map binding non-local as well;
|
||||
@ -673,12 +712,57 @@ class_<Map, holder_type> bind_map(handle scope, const std::string &name, Args &&
|
||||
}
|
||||
|
||||
Class_ cl(scope, name.c_str(), pybind11::module_local(local), std::forward<Args>(args)...);
|
||||
class_<KeysView> keys_view(
|
||||
scope, ("KeysView[" + name + "]").c_str(), pybind11::module_local(local));
|
||||
class_<ValuesView> values_view(
|
||||
scope, ("ValuesView[" + name + "]").c_str(), pybind11::module_local(local));
|
||||
class_<ItemsView> items_view(
|
||||
scope, ("ItemsView[" + name + "]").c_str(), pybind11::module_local(local));
|
||||
static constexpr auto key_type_descr = detail::make_caster<KeyType>::name;
|
||||
static constexpr auto mapped_type_descr = detail::make_caster<MappedType>::name;
|
||||
std::string key_type_name(key_type_descr.text), mapped_type_name(mapped_type_descr.text);
|
||||
|
||||
// If key type isn't properly wrapped, fall back to C++ names
|
||||
if (key_type_name == "%") {
|
||||
key_type_name = detail::type_info_description(typeid(KeyType));
|
||||
}
|
||||
// Similarly for value type:
|
||||
if (mapped_type_name == "%") {
|
||||
mapped_type_name = detail::type_info_description(typeid(MappedType));
|
||||
}
|
||||
|
||||
// Wrap KeysView[KeyType] if it wasn't already wrapped
|
||||
if (!detail::get_type_info(typeid(KeysView))) {
|
||||
class_<KeysView> keys_view(
|
||||
scope, ("KeysView[" + key_type_name + "]").c_str(), pybind11::module_local(local));
|
||||
keys_view.def("__len__", &KeysView::len);
|
||||
keys_view.def("__iter__",
|
||||
&KeysView::iter,
|
||||
keep_alive<0, 1>() /* Essential: keep view alive while iterator exists */
|
||||
);
|
||||
keys_view.def("__contains__",
|
||||
static_cast<bool (KeysView::*)(const KeyType &)>(&KeysView::contains));
|
||||
// Fallback for when the object is not of the key type
|
||||
keys_view.def("__contains__",
|
||||
static_cast<bool (KeysView::*)(const object &)>(&KeysView::contains));
|
||||
}
|
||||
// Similarly for ValuesView:
|
||||
if (!detail::get_type_info(typeid(ValuesView))) {
|
||||
class_<ValuesView> values_view(scope,
|
||||
("ValuesView[" + mapped_type_name + "]").c_str(),
|
||||
pybind11::module_local(local));
|
||||
values_view.def("__len__", &ValuesView::len);
|
||||
values_view.def("__iter__",
|
||||
&ValuesView::iter,
|
||||
keep_alive<0, 1>() /* Essential: keep view alive while iterator exists */
|
||||
);
|
||||
}
|
||||
// Similarly for ItemsView:
|
||||
if (!detail::get_type_info(typeid(ItemsView))) {
|
||||
class_<ItemsView> items_view(
|
||||
scope,
|
||||
("ItemsView[" + key_type_name + ", ").append(mapped_type_name + "]").c_str(),
|
||||
pybind11::module_local(local));
|
||||
items_view.def("__len__", &ItemsView::len);
|
||||
items_view.def("__iter__",
|
||||
&ItemsView::iter,
|
||||
keep_alive<0, 1>() /* Essential: keep view alive while iterator exists */
|
||||
);
|
||||
}
|
||||
|
||||
cl.def(init<>());
|
||||
|
||||
@ -698,19 +782,25 @@ class_<Map, holder_type> bind_map(handle scope, const std::string &name, Args &&
|
||||
|
||||
cl.def(
|
||||
"keys",
|
||||
[](Map &m) { return KeysView{m}; },
|
||||
[](Map &m) {
|
||||
return std::unique_ptr<KeysView>(new detail::KeysViewImpl<Map, KeysView>(m));
|
||||
},
|
||||
keep_alive<0, 1>() /* Essential: keep map alive while view exists */
|
||||
);
|
||||
|
||||
cl.def(
|
||||
"values",
|
||||
[](Map &m) { return ValuesView{m}; },
|
||||
[](Map &m) {
|
||||
return std::unique_ptr<ValuesView>(new detail::ValuesViewImpl<Map, ValuesView>(m));
|
||||
},
|
||||
keep_alive<0, 1>() /* Essential: keep map alive while view exists */
|
||||
);
|
||||
|
||||
cl.def(
|
||||
"items",
|
||||
[](Map &m) { return ItemsView{m}; },
|
||||
[](Map &m) {
|
||||
return std::unique_ptr<ItemsView>(new detail::ItemsViewImpl<Map, ItemsView>(m));
|
||||
},
|
||||
keep_alive<0, 1>() /* Essential: keep map alive while view exists */
|
||||
);
|
||||
|
||||
@ -749,36 +839,6 @@ class_<Map, holder_type> bind_map(handle scope, const std::string &name, Args &&
|
||||
|
||||
cl.def("__len__", &Map::size);
|
||||
|
||||
keys_view.def("__len__", [](KeysView &view) { return view.map.size(); });
|
||||
keys_view.def(
|
||||
"__iter__",
|
||||
[](KeysView &view) { return make_key_iterator(view.map.begin(), view.map.end()); },
|
||||
keep_alive<0, 1>() /* Essential: keep view alive while iterator exists */
|
||||
);
|
||||
keys_view.def("__contains__", [](KeysView &view, const KeyType &k) -> bool {
|
||||
auto it = view.map.find(k);
|
||||
if (it == view.map.end()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
// Fallback for when the object is not of the key type
|
||||
keys_view.def("__contains__", [](KeysView &, const object &) -> bool { return false; });
|
||||
|
||||
values_view.def("__len__", [](ValuesView &view) { return view.map.size(); });
|
||||
values_view.def(
|
||||
"__iter__",
|
||||
[](ValuesView &view) { return make_value_iterator(view.map.begin(), view.map.end()); },
|
||||
keep_alive<0, 1>() /* Essential: keep view alive while iterator exists */
|
||||
);
|
||||
|
||||
items_view.def("__len__", [](ItemsView &view) { return view.map.size(); });
|
||||
items_view.def(
|
||||
"__iter__",
|
||||
[](ItemsView &view) { return make_iterator(view.map.begin(), view.map.end()); },
|
||||
keep_alive<0, 1>() /* Essential: keep view alive while iterator exists */
|
||||
);
|
||||
|
||||
return cl;
|
||||
}
|
||||
|
||||
|
@ -85,4 +85,57 @@ TEST_SUBMODULE(docstring_options, m) {
|
||||
&DocstringTestFoo::setValue,
|
||||
"This is a property docstring");
|
||||
}
|
||||
|
||||
{
|
||||
enum class DocstringTestEnum1 { Member1, Member2 };
|
||||
|
||||
py::enum_<DocstringTestEnum1>(m, "DocstringTestEnum1", "Enum docstring")
|
||||
.value("Member1", DocstringTestEnum1::Member1)
|
||||
.value("Member2", DocstringTestEnum1::Member2);
|
||||
}
|
||||
|
||||
{
|
||||
py::options options;
|
||||
options.enable_enum_members_docstring();
|
||||
|
||||
enum class DocstringTestEnum2 { Member1, Member2 };
|
||||
|
||||
py::enum_<DocstringTestEnum2>(m, "DocstringTestEnum2", "Enum docstring")
|
||||
.value("Member1", DocstringTestEnum2::Member1)
|
||||
.value("Member2", DocstringTestEnum2::Member2);
|
||||
}
|
||||
|
||||
{
|
||||
py::options options;
|
||||
options.disable_enum_members_docstring();
|
||||
|
||||
enum class DocstringTestEnum3 { Member1, Member2 };
|
||||
|
||||
py::enum_<DocstringTestEnum3>(m, "DocstringTestEnum3", "Enum docstring")
|
||||
.value("Member1", DocstringTestEnum3::Member1)
|
||||
.value("Member2", DocstringTestEnum3::Member2);
|
||||
}
|
||||
|
||||
{
|
||||
py::options options;
|
||||
options.disable_user_defined_docstrings();
|
||||
|
||||
enum class DocstringTestEnum4 { Member1, Member2 };
|
||||
|
||||
py::enum_<DocstringTestEnum4>(m, "DocstringTestEnum4", "Enum docstring")
|
||||
.value("Member1", DocstringTestEnum4::Member1)
|
||||
.value("Member2", DocstringTestEnum4::Member2);
|
||||
}
|
||||
|
||||
{
|
||||
py::options options;
|
||||
options.disable_user_defined_docstrings();
|
||||
options.disable_enum_members_docstring();
|
||||
|
||||
enum class DocstringTestEnum5 { Member1, Member2 };
|
||||
|
||||
py::enum_<DocstringTestEnum5>(m, "DocstringTestEnum5", "Enum docstring")
|
||||
.value("Member1", DocstringTestEnum5::Member1)
|
||||
.value("Member2", DocstringTestEnum5::Member2);
|
||||
}
|
||||
}
|
||||
|
@ -39,3 +39,26 @@ def test_docstring_options():
|
||||
# Suppression of user-defined docstrings for non-function objects
|
||||
assert not m.DocstringTestFoo.__doc__
|
||||
assert not m.DocstringTestFoo.value_prop.__doc__
|
||||
|
||||
# Check existig behaviour of enum docstings
|
||||
assert (
|
||||
m.DocstringTestEnum1.__doc__
|
||||
== "Enum docstring\n\nMembers:\n\n Member1\n\n Member2"
|
||||
)
|
||||
|
||||
# options.enable_enum_members_docstring()
|
||||
assert (
|
||||
m.DocstringTestEnum2.__doc__
|
||||
== "Enum docstring\n\nMembers:\n\n Member1\n\n Member2"
|
||||
)
|
||||
|
||||
# options.disable_enum_members_docstring()
|
||||
assert m.DocstringTestEnum3.__doc__ == "Enum docstring"
|
||||
|
||||
# options.disable_user_defined_docstrings()
|
||||
assert m.DocstringTestEnum4.__doc__ == "Members:\n\n Member1\n\n Member2"
|
||||
|
||||
# options.disable_user_defined_docstrings()
|
||||
# options.disable_enum_members_docstring()
|
||||
# When all options are disabled, no docstring (instead of an empty one) should be generated
|
||||
assert m.DocstringTestEnum5.__doc__ is None
|
||||
|
@ -309,3 +309,29 @@ def test_map_delitem():
|
||||
del um["ua"]
|
||||
assert sorted(list(um)) == ["ub"]
|
||||
assert sorted(list(um.items())) == [("ub", 2.6)]
|
||||
|
||||
|
||||
def test_map_view_types():
|
||||
map_string_double = m.MapStringDouble()
|
||||
unordered_map_string_double = m.UnorderedMapStringDouble()
|
||||
map_string_double_const = m.MapStringDoubleConst()
|
||||
unordered_map_string_double_const = m.UnorderedMapStringDoubleConst()
|
||||
|
||||
assert map_string_double.keys().__class__.__name__ == "KeysView[str]"
|
||||
assert map_string_double.values().__class__.__name__ == "ValuesView[float]"
|
||||
assert map_string_double.items().__class__.__name__ == "ItemsView[str, float]"
|
||||
|
||||
keys_type = type(map_string_double.keys())
|
||||
assert type(unordered_map_string_double.keys()) is keys_type
|
||||
assert type(map_string_double_const.keys()) is keys_type
|
||||
assert type(unordered_map_string_double_const.keys()) is keys_type
|
||||
|
||||
values_type = type(map_string_double.values())
|
||||
assert type(unordered_map_string_double.values()) is values_type
|
||||
assert type(map_string_double_const.values()) is values_type
|
||||
assert type(unordered_map_string_double_const.values()) is values_type
|
||||
|
||||
items_type = type(map_string_double.items())
|
||||
assert type(unordered_map_string_double.items()) is items_type
|
||||
assert type(map_string_double_const.items()) is items_type
|
||||
assert type(unordered_map_string_double_const.items()) is items_type
|
||||
|
@ -173,7 +173,8 @@ struct AdderBase {
|
||||
using DataVisitor = std::function<void(const Data &)>;
|
||||
|
||||
virtual void
|
||||
operator()(const Data &first, const Data &second, const DataVisitor &visitor) const = 0;
|
||||
operator()(const Data &first, const Data &second, const DataVisitor &visitor) const
|
||||
= 0;
|
||||
virtual ~AdderBase() = default;
|
||||
AdderBase() = default;
|
||||
AdderBase(const AdderBase &) = delete;
|
||||
|
Loading…
Reference in New Issue
Block a user