mirror of
https://github.com/pybind/pybind11.git
synced 2024-11-22 21:25:13 +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
|
- uses: actions/download-artifact@v3
|
||||||
|
|
||||||
- name: Publish standard package
|
- name: Publish standard package
|
||||||
uses: pypa/gh-action-pypi-publish@v1.6.1
|
uses: pypa/gh-action-pypi-publish@v1.6.4
|
||||||
with:
|
with:
|
||||||
password: ${{ secrets.pypi_password }}
|
password: ${{ secrets.pypi_password }}
|
||||||
packages_dir: standard/
|
packages_dir: standard/
|
||||||
|
|
||||||
- name: Publish global package
|
- name: Publish global package
|
||||||
uses: pypa/gh-action-pypi-publish@v1.6.1
|
uses: pypa/gh-action-pypi-publish@v1.6.4
|
||||||
with:
|
with:
|
||||||
password: ${{ secrets.pypi_password_global }}
|
password: ${{ secrets.pypi_password_global }}
|
||||||
packages_dir: global/
|
packages_dir: global/
|
||||||
|
@ -24,7 +24,7 @@ exclude: ^tools/JoinPaths.cmake$
|
|||||||
repos:
|
repos:
|
||||||
# Standard hooks
|
# Standard hooks
|
||||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||||
rev: "v4.3.0"
|
rev: "v4.4.0"
|
||||||
hooks:
|
hooks:
|
||||||
- id: check-added-large-files
|
- id: check-added-large-files
|
||||||
- id: check-case-conflict
|
- id: check-case-conflict
|
||||||
@ -42,7 +42,7 @@ repos:
|
|||||||
|
|
||||||
# Upgrade old Python syntax
|
# Upgrade old Python syntax
|
||||||
- repo: https://github.com/asottile/pyupgrade
|
- repo: https://github.com/asottile/pyupgrade
|
||||||
rev: "v3.2.0"
|
rev: "v3.3.0"
|
||||||
hooks:
|
hooks:
|
||||||
- id: pyupgrade
|
- id: pyupgrade
|
||||||
args: [--py36-plus]
|
args: [--py36-plus]
|
||||||
@ -82,7 +82,7 @@ repos:
|
|||||||
|
|
||||||
# Autoremoves unused imports
|
# Autoremoves unused imports
|
||||||
- repo: https://github.com/hadialqattan/pycln
|
- repo: https://github.com/hadialqattan/pycln
|
||||||
rev: "v2.1.1"
|
rev: "v2.1.2"
|
||||||
hooks:
|
hooks:
|
||||||
- id: pycln
|
- id: pycln
|
||||||
stages: [manual]
|
stages: [manual]
|
||||||
@ -111,7 +111,7 @@ repos:
|
|||||||
|
|
||||||
# Flake8 also supports pre-commit natively (same author)
|
# Flake8 also supports pre-commit natively (same author)
|
||||||
- repo: https://github.com/PyCQA/flake8
|
- repo: https://github.com/PyCQA/flake8
|
||||||
rev: "5.0.4"
|
rev: "6.0.0"
|
||||||
hooks:
|
hooks:
|
||||||
- id: flake8
|
- id: flake8
|
||||||
exclude: ^(docs/.*|tools/.*|ubench/.*)$
|
exclude: ^(docs/.*|tools/.*|ubench/.*)$
|
||||||
@ -119,7 +119,7 @@ repos:
|
|||||||
|
|
||||||
# PyLint has native support - not always usable, but works for us
|
# PyLint has native support - not always usable, but works for us
|
||||||
- repo: https://github.com/PyCQA/pylint
|
- repo: https://github.com/PyCQA/pylint
|
||||||
rev: "v2.15.5"
|
rev: "v2.15.8"
|
||||||
hooks:
|
hooks:
|
||||||
- id: pylint
|
- id: pylint
|
||||||
files: ^pybind11
|
files: ^pybind11
|
||||||
@ -135,7 +135,7 @@ repos:
|
|||||||
|
|
||||||
# Check static types with mypy
|
# Check static types with mypy
|
||||||
- repo: https://github.com/pre-commit/mirrors-mypy
|
- repo: https://github.com/pre-commit/mirrors-mypy
|
||||||
rev: "v0.982"
|
rev: "v0.991"
|
||||||
hooks:
|
hooks:
|
||||||
- id: mypy
|
- id: mypy
|
||||||
args: []
|
args: []
|
||||||
@ -144,7 +144,7 @@ repos:
|
|||||||
|
|
||||||
# Checks the manifest for missing files (native support)
|
# Checks the manifest for missing files (native support)
|
||||||
- repo: https://github.com/mgedmin/check-manifest
|
- repo: https://github.com/mgedmin/check-manifest
|
||||||
rev: "0.48"
|
rev: "0.49"
|
||||||
hooks:
|
hooks:
|
||||||
- id: check-manifest
|
- id: check-manifest
|
||||||
# This is a slow hook, so only run this if --hook-stage manual is passed
|
# 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
|
# Clang format the codebase automatically
|
||||||
- repo: https://github.com/pre-commit/mirrors-clang-format
|
- repo: https://github.com/pre-commit/mirrors-clang-format
|
||||||
rev: "v14.0.6"
|
rev: "v15.0.4"
|
||||||
hooks:
|
hooks:
|
||||||
- id: clang-format
|
- id: clang-format
|
||||||
types_or: [c++, c, cuda]
|
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");
|
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
|
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,
|
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.
|
the default settings are restored to prevent unwanted side effects.
|
||||||
|
@ -121,7 +121,8 @@ public:
|
|||||||
template <typename T_, \
|
template <typename T_, \
|
||||||
::pybind11::detail::enable_if_t< \
|
::pybind11::detail::enable_if_t< \
|
||||||
std::is_same<type, ::pybind11::detail::remove_cv_t<T_>>::value, \
|
std::is_same<type, ::pybind11::detail::remove_cv_t<T_>>::value, \
|
||||||
int> = 0> \
|
int> \
|
||||||
|
= 0> \
|
||||||
static ::pybind11::handle cast( \
|
static ::pybind11::handle cast( \
|
||||||
T_ *src, ::pybind11::return_value_policy policy, ::pybind11::handle parent) { \
|
T_ *src, ::pybind11::return_value_policy policy, ::pybind11::handle parent) { \
|
||||||
if (!src) \
|
if (!src) \
|
||||||
|
@ -34,17 +34,17 @@
|
|||||||
# define PYBIND11_WARNING_POP PYBIND11_PRAGMA(warning(pop))
|
# define PYBIND11_WARNING_POP PYBIND11_PRAGMA(warning(pop))
|
||||||
#elif defined(__INTEL_COMPILER)
|
#elif defined(__INTEL_COMPILER)
|
||||||
# define PYBIND11_COMPILER_INTEL
|
# 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_PUSH PYBIND11_PRAGMA(warning push)
|
||||||
# define PYBIND11_WARNING_POP PYBIND11_PRAGMA(warning pop)
|
# define PYBIND11_WARNING_POP PYBIND11_PRAGMA(warning pop)
|
||||||
#elif defined(__clang__)
|
#elif defined(__clang__)
|
||||||
# define PYBIND11_COMPILER_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_PUSH PYBIND11_PRAGMA(clang diagnostic push)
|
||||||
# define PYBIND11_WARNING_POP PYBIND11_PRAGMA(clang diagnostic push)
|
# define PYBIND11_WARNING_POP PYBIND11_PRAGMA(clang diagnostic push)
|
||||||
#elif defined(__GNUC__)
|
#elif defined(__GNUC__)
|
||||||
# define PYBIND11_COMPILER_GCC
|
# 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_PUSH PYBIND11_PRAGMA(GCC diagnostic push)
|
||||||
# define PYBIND11_WARNING_POP PYBIND11_PRAGMA(GCC diagnostic pop)
|
# define PYBIND11_WARNING_POP PYBIND11_PRAGMA(GCC diagnostic pop)
|
||||||
#endif
|
#endif
|
||||||
@ -323,6 +323,15 @@ PYBIND11_WARNING_POP
|
|||||||
# define PYBIND11_HAS_U8STRING
|
# define PYBIND11_HAS_U8STRING
|
||||||
#endif
|
#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
|
// #define PYBIND11_STR_LEGACY_PERMISSIVE
|
||||||
// If DEFINED, pybind11::str can hold PyUnicodeObject or PyBytesObject
|
// If DEFINED, pybind11::str can hold PyUnicodeObject or PyBytesObject
|
||||||
// (probably surprising and never documented, but this was the
|
// (probably surprising and never documented, but this was the
|
||||||
|
@ -282,10 +282,11 @@ struct constructor {
|
|||||||
extra...);
|
extra...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Class,
|
template <
|
||||||
typename... Extra,
|
typename Class,
|
||||||
enable_if_t<Class::has_alias && std::is_constructible<Cpp<Class>, Args...>::value,
|
typename... Extra,
|
||||||
int> = 0>
|
enable_if_t<Class::has_alias && std::is_constructible<Cpp<Class>, Args...>::value, int>
|
||||||
|
= 0>
|
||||||
static void execute(Class &cl, const Extra &...extra) {
|
static void execute(Class &cl, const Extra &...extra) {
|
||||||
cl.def(
|
cl.def(
|
||||||
"__init__",
|
"__init__",
|
||||||
@ -302,10 +303,11 @@ struct constructor {
|
|||||||
extra...);
|
extra...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Class,
|
template <
|
||||||
typename... Extra,
|
typename Class,
|
||||||
enable_if_t<Class::has_alias && !std::is_constructible<Cpp<Class>, Args...>::value,
|
typename... Extra,
|
||||||
int> = 0>
|
enable_if_t<Class::has_alias && !std::is_constructible<Cpp<Class>, Args...>::value, int>
|
||||||
|
= 0>
|
||||||
static void execute(Class &cl, const Extra &...extra) {
|
static void execute(Class &cl, const Extra &...extra) {
|
||||||
cl.def(
|
cl.def(
|
||||||
"__init__",
|
"__init__",
|
||||||
@ -321,10 +323,11 @@ struct constructor {
|
|||||||
// Implementing class for py::init_alias<...>()
|
// Implementing class for py::init_alias<...>()
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
struct alias_constructor {
|
struct alias_constructor {
|
||||||
template <typename Class,
|
template <
|
||||||
typename... Extra,
|
typename Class,
|
||||||
enable_if_t<Class::has_alias && std::is_constructible<Alias<Class>, Args...>::value,
|
typename... Extra,
|
||||||
int> = 0>
|
enable_if_t<Class::has_alias && std::is_constructible<Alias<Class>, Args...>::value, int>
|
||||||
|
= 0>
|
||||||
static void execute(Class &cl, const Extra &...extra) {
|
static void execute(Class &cl, const Extra &...extra) {
|
||||||
cl.def(
|
cl.def(
|
||||||
"__init__",
|
"__init__",
|
||||||
|
@ -1010,5 +1010,14 @@ protected:
|
|||||||
static Constructor make_move_constructor(...) { return nullptr; }
|
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(detail)
|
||||||
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
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:
|
case return_value_policy::take_ownership:
|
||||||
if (std::is_const<C>::value) {
|
if (std::is_const<C>::value) {
|
||||||
// This cast is ugly, and might be UB in some cases, but we don't have an
|
// 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));
|
Helper::free(const_cast<Type *>(src));
|
||||||
pybind11_fail("Cannot take ownership of a const reference");
|
pybind11_fail("Cannot take ownership of a const reference");
|
||||||
}
|
}
|
||||||
|
@ -1471,7 +1471,7 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Extract name, offset and format descriptor for a struct field
|
// 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
|
// The main idea of this macro is borrowed from https://github.com/swansontec/map-macro
|
||||||
// (C) William Swanson, Paul Fultz
|
// (C) William Swanson, Paul Fultz
|
||||||
|
@ -47,6 +47,16 @@ public:
|
|||||||
return *this;
|
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):
|
// Getter methods (return the global state):
|
||||||
|
|
||||||
static bool show_user_defined_docstrings() {
|
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_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.
|
// This type is not meant to be allocated on the heap.
|
||||||
void *operator new(size_t) = delete;
|
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_user_defined_docstrings = true; //< Include user-supplied texts in docstrings.
|
||||||
bool show_function_signatures = true; //< Include auto-generated function signatures
|
bool show_function_signatures = true; //< Include auto-generated function signatures
|
||||||
// in docstrings.
|
// in docstrings.
|
||||||
|
bool show_enum_members_docstring = true; //< Include auto-generated member list in enum
|
||||||
|
// docstrings.
|
||||||
};
|
};
|
||||||
|
|
||||||
static state &global_state() {
|
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) {
|
void call_operator_delete(T *p, size_t, size_t) {
|
||||||
T::operator delete(p);
|
T::operator delete(p);
|
||||||
}
|
}
|
||||||
template <
|
template <typename T,
|
||||||
typename T,
|
enable_if_t<!has_operator_delete<T>::value && has_operator_delete_size<T>::value, int>
|
||||||
enable_if_t<!has_operator_delete<T>::value && has_operator_delete_size<T>::value, int> = 0>
|
= 0>
|
||||||
void call_operator_delete(T *p, size_t s, size_t) {
|
void call_operator_delete(T *p, size_t s, size_t) {
|
||||||
T::operator delete(p, s);
|
T::operator delete(p, s);
|
||||||
}
|
}
|
||||||
@ -2227,29 +2227,35 @@ struct enum_base {
|
|||||||
name("name"),
|
name("name"),
|
||||||
is_method(m_base));
|
is_method(m_base));
|
||||||
|
|
||||||
m_base.attr("__doc__") = static_property(
|
if (options::show_enum_members_docstring()) {
|
||||||
cpp_function(
|
m_base.attr("__doc__") = static_property(
|
||||||
[](handle arg) -> std::string {
|
cpp_function(
|
||||||
std::string docstring;
|
[](handle arg) -> std::string {
|
||||||
dict entries = arg.attr("__entries");
|
std::string docstring;
|
||||||
if (((PyTypeObject *) arg.ptr())->tp_doc) {
|
dict entries = arg.attr("__entries");
|
||||||
docstring += std::string(((PyTypeObject *) arg.ptr())->tp_doc) + "\n\n";
|
if (((PyTypeObject *) arg.ptr())->tp_doc) {
|
||||||
}
|
docstring += std::string(
|
||||||
docstring += "Members:";
|
reinterpret_cast<PyTypeObject *>(arg.ptr())->tp_doc);
|
||||||
for (auto kv : entries) {
|
docstring += "\n\n";
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
docstring += "Members:";
|
||||||
return docstring;
|
for (auto kv : entries) {
|
||||||
},
|
auto key = std::string(pybind11::str(kv.first));
|
||||||
name("__doc__")),
|
auto comment = kv.second[int_(1)];
|
||||||
none(),
|
docstring += "\n\n ";
|
||||||
none(),
|
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(
|
m_base.attr("__members__") = static_property(cpp_function(
|
||||||
[](handle arg) -> dict {
|
[](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::enable_if_t<detail::all_of<detail::none_of<std::is_base_of<handle, T>,
|
||||||
detail::is_pyobj_ptr_or_nullptr_t<T>>,
|
detail::is_pyobj_ptr_or_nullptr_t<T>>,
|
||||||
std::is_convertible<T, PyObject *>>::value,
|
std::is_convertible<T, PyObject *>>::value,
|
||||||
int> = 0>
|
int>
|
||||||
|
= 0>
|
||||||
// NOLINTNEXTLINE(google-explicit-constructor)
|
// NOLINTNEXTLINE(google-explicit-constructor)
|
||||||
handle(T &obj) : m_ptr(obj) {}
|
handle(T &obj) : m_ptr(obj) {}
|
||||||
|
|
||||||
@ -248,6 +249,11 @@ public:
|
|||||||
const handle &inc_ref() const & {
|
const handle &inc_ref() const & {
|
||||||
#ifdef PYBIND11_HANDLE_REF_DEBUG
|
#ifdef PYBIND11_HANDLE_REF_DEBUG
|
||||||
inc_ref_counter(1);
|
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
|
#endif
|
||||||
Py_XINCREF(m_ptr);
|
Py_XINCREF(m_ptr);
|
||||||
return *this;
|
return *this;
|
||||||
@ -259,6 +265,11 @@ public:
|
|||||||
this function automatically. Returns a reference to itself.
|
this function automatically. Returns a reference to itself.
|
||||||
\endrst */
|
\endrst */
|
||||||
const handle &dec_ref() const & {
|
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);
|
Py_XDECREF(m_ptr);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
@ -10,10 +10,13 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "detail/common.h"
|
#include "detail/common.h"
|
||||||
|
#include "detail/type_caster_base.h"
|
||||||
|
#include "cast.h"
|
||||||
#include "operators.h"
|
#include "operators.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
||||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
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.");
|
"Return the canonical string representation of this map.");
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Map>
|
template <typename KeyType>
|
||||||
struct keys_view {
|
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 {
|
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 ↦
|
Map ↦
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Map>
|
template <typename Map, typename ValuesView>
|
||||||
struct items_view {
|
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 ↦
|
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) {
|
class_<Map, holder_type> bind_map(handle scope, const std::string &name, Args &&...args) {
|
||||||
using KeyType = typename Map::key_type;
|
using KeyType = typename Map::key_type;
|
||||||
using MappedType = typename Map::mapped_type;
|
using MappedType = typename Map::mapped_type;
|
||||||
using KeysView = detail::keys_view<Map>;
|
using StrippedKeyType = detail::remove_cvref_t<KeyType>;
|
||||||
using ValuesView = detail::values_view<Map>;
|
using StrippedMappedType = detail::remove_cvref_t<MappedType>;
|
||||||
using ItemsView = detail::items_view<Map>;
|
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>;
|
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;
|
// 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_ cl(scope, name.c_str(), pybind11::module_local(local), std::forward<Args>(args)...);
|
||||||
class_<KeysView> keys_view(
|
static constexpr auto key_type_descr = detail::make_caster<KeyType>::name;
|
||||||
scope, ("KeysView[" + name + "]").c_str(), pybind11::module_local(local));
|
static constexpr auto mapped_type_descr = detail::make_caster<MappedType>::name;
|
||||||
class_<ValuesView> values_view(
|
std::string key_type_name(key_type_descr.text), mapped_type_name(mapped_type_descr.text);
|
||||||
scope, ("ValuesView[" + name + "]").c_str(), pybind11::module_local(local));
|
|
||||||
class_<ItemsView> items_view(
|
// If key type isn't properly wrapped, fall back to C++ names
|
||||||
scope, ("ItemsView[" + name + "]").c_str(), pybind11::module_local(local));
|
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<>());
|
cl.def(init<>());
|
||||||
|
|
||||||
@ -698,19 +782,25 @@ class_<Map, holder_type> bind_map(handle scope, const std::string &name, Args &&
|
|||||||
|
|
||||||
cl.def(
|
cl.def(
|
||||||
"keys",
|
"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 */
|
keep_alive<0, 1>() /* Essential: keep map alive while view exists */
|
||||||
);
|
);
|
||||||
|
|
||||||
cl.def(
|
cl.def(
|
||||||
"values",
|
"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 */
|
keep_alive<0, 1>() /* Essential: keep map alive while view exists */
|
||||||
);
|
);
|
||||||
|
|
||||||
cl.def(
|
cl.def(
|
||||||
"items",
|
"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 */
|
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);
|
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;
|
return cl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,4 +85,57 @@ TEST_SUBMODULE(docstring_options, m) {
|
|||||||
&DocstringTestFoo::setValue,
|
&DocstringTestFoo::setValue,
|
||||||
"This is a property docstring");
|
"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
|
# Suppression of user-defined docstrings for non-function objects
|
||||||
assert not m.DocstringTestFoo.__doc__
|
assert not m.DocstringTestFoo.__doc__
|
||||||
assert not m.DocstringTestFoo.value_prop.__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"]
|
del um["ua"]
|
||||||
assert sorted(list(um)) == ["ub"]
|
assert sorted(list(um)) == ["ub"]
|
||||||
assert sorted(list(um.items())) == [("ub", 2.6)]
|
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 &)>;
|
using DataVisitor = std::function<void(const Data &)>;
|
||||||
|
|
||||||
virtual void
|
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;
|
virtual ~AdderBase() = default;
|
||||||
AdderBase() = default;
|
AdderBase() = default;
|
||||||
AdderBase(const AdderBase &) = delete;
|
AdderBase(const AdderBase &) = delete;
|
||||||
|
Loading…
Reference in New Issue
Block a user