Merge branch 'master' into sh_merge_master

This commit is contained in:
Ralf W. Grosse-Kunstleve 2022-05-02 12:41:48 -07:00
commit 2ee1e6445d
26 changed files with 176 additions and 136 deletions

View File

@ -25,11 +25,12 @@ modernize-replace-random-shuffle,
modernize-shrink-to-fit, modernize-shrink-to-fit,
modernize-use-auto, modernize-use-auto,
modernize-use-bool-literals, modernize-use-bool-literals,
modernize-use-default-member-init,
modernize-use-equals-default, modernize-use-equals-default,
modernize-use-equals-delete, modernize-use-equals-delete,
modernize-use-default-member-init,
modernize-use-noexcept,
modernize-use-emplace, modernize-use-emplace,
modernize-use-noexcept,
modernize-use-nullptr,
modernize-use-override, modernize-use-override,
modernize-use-using, modernize-use-using,
*performance*, *performance*,

View File

@ -7,10 +7,5 @@ updates:
interval: "daily" interval: "daily"
ignore: ignore:
# Official actions have moving tags like v1 # Official actions have moving tags like v1
# that are used, so they don't need updates here - dependency-name: "actions/*"
- dependency-name: "actions/checkout" update-types: ["version-update:semver-minor", "version-update:semver-patch"]
- dependency-name: "actions/setup-python"
- dependency-name: "actions/cache"
- dependency-name: "actions/upload-artifact"
- dependency-name: "actions/download-artifact"
- dependency-name: "actions/labeler"

View File

@ -63,10 +63,10 @@ jobs:
runs-on: ${{ matrix.runs-on }} runs-on: ${{ matrix.runs-on }}
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v3
- name: Setup Python ${{ matrix.python }} - name: Setup Python ${{ matrix.python }}
uses: actions/setup-python@v2 uses: actions/setup-python@v3
with: with:
python-version: ${{ matrix.python }} python-version: ${{ matrix.python }}
@ -84,7 +84,7 @@ jobs:
- name: Cache wheels - name: Cache wheels
if: runner.os == 'macOS' if: runner.os == 'macOS'
uses: actions/cache@v2 uses: actions/cache@v3
with: with:
# This path is specific to macOS - we really only need it for PyPy NumPy wheels # This path is specific to macOS - we really only need it for PyPy NumPy wheels
# See https://github.com/actions/cache/blob/master/examples.md#python---pip # See https://github.com/actions/cache/blob/master/examples.md#python---pip
@ -193,7 +193,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v3
- name: Setup Python ${{ matrix.python-version }} (deadsnakes) - name: Setup Python ${{ matrix.python-version }} (deadsnakes)
uses: deadsnakes/action@v2.1.1 uses: deadsnakes/action@v2.1.1
@ -206,7 +206,7 @@ jobs:
- name: Valgrind cache - name: Valgrind cache
if: matrix.valgrind if: matrix.valgrind
uses: actions/cache@v2 uses: actions/cache@v3
id: cache-valgrind id: cache-valgrind
with: with:
path: valgrind path: valgrind
@ -286,7 +286,7 @@ jobs:
container: "silkeh/clang:${{ matrix.clang }}" container: "silkeh/clang:${{ matrix.clang }}"
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v3
- name: Add wget and python3 - name: Add wget and python3
run: apt-get update && apt-get install -y python3-dev python3-numpy python3-pytest libeigen3-dev run: apt-get update && apt-get install -y python3-dev python3-numpy python3-pytest libeigen3-dev
@ -320,7 +320,7 @@ jobs:
container: nvidia/cuda:11.0-devel-ubuntu20.04 container: nvidia/cuda:11.0-devel-ubuntu20.04
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v3
# tzdata will try to ask for the timezone, so set the DEBIAN_FRONTEND # tzdata will try to ask for the timezone, so set the DEBIAN_FRONTEND
- name: Install 🐍 3 - name: Install 🐍 3
@ -344,7 +344,7 @@ jobs:
# container: centos:8 # container: centos:8
# #
# steps: # steps:
# - uses: actions/checkout@v2 # - uses: actions/checkout@v3
# #
# - name: Add Python 3 and a few requirements # - name: Add Python 3 and a few requirements
# run: yum update -y && yum install -y git python3-devel python3-numpy python3-pytest make environment-modules # run: yum update -y && yum install -y git python3-devel python3-numpy python3-pytest make environment-modules
@ -387,7 +387,7 @@ jobs:
container: centos:7 container: centos:7
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v3
- name: Add Python 3 and a few requirements - name: Add Python 3 and a few requirements
run: yum update -y && yum install -y epel-release && yum install -y git python3-devel make environment-modules cmake3 run: yum update -y && yum install -y epel-release && yum install -y git python3-devel make environment-modules cmake3
@ -448,7 +448,7 @@ jobs:
container: "gcc:${{ matrix.gcc }}" container: "gcc:${{ matrix.gcc }}"
steps: steps:
- uses: actions/checkout@v1 - uses: actions/checkout@v3
- name: Add Python 3 - name: Add Python 3
run: apt-get update; apt-get install -y python3-dev python3-numpy python3-pytest python3-pip libeigen3-dev run: apt-get update; apt-get install -y python3-dev python3-numpy python3-pytest python3-pip libeigen3-dev
@ -490,7 +490,7 @@ jobs:
name: "🐍 3 • ICC latest • x64" name: "🐍 3 • ICC latest • x64"
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v3
- name: Add apt repo - name: Add apt repo
run: | run: |
@ -593,7 +593,7 @@ jobs:
container: "quay.io/centos/centos:${{ matrix.centos }}" container: "quay.io/centos/centos:${{ matrix.centos }}"
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v3
- name: Add Python 3 - name: Add Python 3
run: yum update -y && yum install -y python3-devel gcc-c++ make git run: yum update -y && yum install -y python3-devel gcc-c++ make git
@ -636,7 +636,7 @@ jobs:
container: i386/debian:buster container: i386/debian:buster
steps: steps:
- uses: actions/checkout@v1 - uses: actions/checkout@v3
- name: Install requirements - name: Install requirements
run: | run: |
@ -679,9 +679,9 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v3
- uses: actions/setup-python@v2 - uses: actions/setup-python@v3
- name: Install Doxygen - name: Install Doxygen
run: sudo apt-get install -y doxygen librsvg2-bin # Changed to rsvg-convert in 20.04 run: sudo apt-get install -y doxygen librsvg2-bin # Changed to rsvg-convert in 20.04
@ -726,10 +726,10 @@ jobs:
runs-on: windows-2019 runs-on: windows-2019
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v3
- name: Setup Python ${{ matrix.python }} - name: Setup Python ${{ matrix.python }}
uses: actions/setup-python@v2 uses: actions/setup-python@v3
with: with:
python-version: ${{ matrix.python }} python-version: ${{ matrix.python }}
architecture: x86 architecture: x86
@ -779,10 +779,10 @@ jobs:
runs-on: windows-2019 runs-on: windows-2019
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v3
- name: Setup Python ${{ matrix.python }} - name: Setup Python ${{ matrix.python }}
uses: actions/setup-python@v2 uses: actions/setup-python@v3
with: with:
python-version: ${{ matrix.python }} python-version: ${{ matrix.python }}
architecture: x86 architecture: x86
@ -827,10 +827,10 @@ jobs:
runs-on: windows-2022 runs-on: windows-2022
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v3
- name: Setup Python ${{ matrix.python }} - name: Setup Python ${{ matrix.python }}
uses: actions/setup-python@v2 uses: actions/setup-python@v3
with: with:
python-version: ${{ matrix.python }} python-version: ${{ matrix.python }}
@ -890,7 +890,7 @@ jobs:
mingw-w64-${{matrix.env}}-boost mingw-w64-${{matrix.env}}-boost
mingw-w64-${{matrix.env}}-catch mingw-w64-${{matrix.env}}-catch
- uses: actions/checkout@v2 - uses: actions/checkout@v3
- name: Configure C++11 - name: Configure C++11
# LTO leads to many undefined reference like # LTO leads to many undefined reference like

View File

@ -38,10 +38,10 @@ jobs:
runs-on: ${{ matrix.runs-on }} runs-on: ${{ matrix.runs-on }}
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v3
- name: Setup Python 3.7 - name: Setup Python 3.7
uses: actions/setup-python@v2 uses: actions/setup-python@v3
with: with:
python-version: 3.7 python-version: 3.7
architecture: ${{ matrix.arch }} architecture: ${{ matrix.arch }}

View File

@ -21,8 +21,8 @@ jobs:
name: Format name: Format
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v3
- uses: actions/setup-python@v2 - uses: actions/setup-python@v3
- name: Add matchers - name: Add matchers
run: echo "::add-matcher::$GITHUB_WORKSPACE/.github/matchers/pylint.json" run: echo "::add-matcher::$GITHUB_WORKSPACE/.github/matchers/pylint.json"
- uses: pre-commit/action@v2.0.3 - uses: pre-commit/action@v2.0.3
@ -37,7 +37,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: silkeh/clang:12 container: silkeh/clang:12
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v3
- name: Install requirements - name: Install requirements
run: apt-get update && apt-get install -y python3-dev python3-pytest run: apt-get update && apt-get install -y python3-dev python3-pytest

View File

@ -25,10 +25,10 @@ jobs:
runs-on: windows-latest runs-on: windows-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v3
- name: Setup 🐍 3.6 - name: Setup 🐍 3.6
uses: actions/setup-python@v2 uses: actions/setup-python@v3
with: with:
python-version: 3.6 python-version: 3.6
@ -47,10 +47,10 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v3
- name: Setup 🐍 3.8 - name: Setup 🐍 3.8
uses: actions/setup-python@v2 uses: actions/setup-python@v3
with: with:
python-version: 3.8 python-version: 3.8
@ -70,13 +70,13 @@ jobs:
run: twine check dist/* run: twine check dist/*
- name: Save standard package - name: Save standard package
uses: actions/upload-artifact@v2 uses: actions/upload-artifact@v3
with: with:
name: standard name: standard
path: dist/pybind11-* path: dist/pybind11-*
- name: Save global package - name: Save global package
uses: actions/upload-artifact@v2 uses: actions/upload-artifact@v3
with: with:
name: global name: global
path: dist/pybind11_global-* path: dist/pybind11_global-*
@ -91,10 +91,10 @@ jobs:
needs: [packaging] needs: [packaging]
steps: steps:
- uses: actions/setup-python@v2 - uses: actions/setup-python@v3
# Downloads all to directories matching the artifact names # Downloads all to directories matching the artifact names
- uses: actions/download-artifact@v2 - uses: actions/download-artifact@v3
- name: Publish standard package - name: Publish standard package
uses: pypa/gh-action-pypi-publish@v1.5.0 uses: pypa/gh-action-pypi-publish@v1.5.0

View File

@ -19,10 +19,10 @@ jobs:
if: "contains(github.event.pull_request.labels.*.name, 'python dev')" if: "contains(github.event.pull_request.labels.*.name, 'python dev')"
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v3
- name: Setup Python 3.11 - name: Setup Python 3.11
uses: actions/setup-python@v2 uses: actions/setup-python@v3
with: with:
python-version: "3.11-dev" python-version: "3.11-dev"

View File

@ -73,7 +73,7 @@ repos:
# Autoremoves unused imports # Autoremoves unused imports
- repo: https://github.com/hadialqattan/pycln - repo: https://github.com/hadialqattan/pycln
rev: "v1.2.5" rev: "v1.3.1"
hooks: hooks:
- id: pycln - id: pycln
stages: [manual] stages: [manual]
@ -167,7 +167,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: "v13.0.1" rev: "v14.0.1"
hooks: hooks:
- id: clang-format - id: clang-format
types_or: [c++, c, cuda] types_or: [c++, c, cuda]

View File

@ -10,6 +10,7 @@
#pragma once #pragma once
#include "detail/common.h"
#include "cast.h" #include "cast.h"
#include <functional> #include <functional>
@ -477,7 +478,7 @@ struct process_attribute<arg_v> : process_attribute_default<arg_v> {
} }
if (!a.value) { if (!a.value) {
#if !defined(NDEBUG) #if defined(PYBIND11_DETAILED_ERROR_MESSAGES)
std::string descr("'"); std::string descr("'");
if (a.name) { if (a.name) {
descr += std::string(a.name) + ": "; descr += std::string(a.name) + ": ";
@ -498,7 +499,8 @@ struct process_attribute<arg_v> : process_attribute_default<arg_v> {
#else #else
pybind11_fail("arg(): could not convert default argument " pybind11_fail("arg(): could not convert default argument "
"into a Python object (type not registered yet?). " "into a Python object (type not registered yet?). "
"Compile in debug mode for more information."); "#define PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for "
"more information.");
#endif #endif
} }
r->args.emplace_back(a.name, a.descr, a.value.inc_ref(), !a.flag_noconvert, a.flag_none); r->args.emplace_back(a.name, a.descr, a.value.inc_ref(), !a.flag_noconvert, a.flag_none);

View File

@ -798,8 +798,9 @@ protected:
return true; return true;
} }
throw cast_error("Unable to cast from non-held to held instance (T& to Holder<T>) " throw cast_error("Unable to cast from non-held to held instance (T& to Holder<T>) "
#if defined(NDEBUG) #if !defined(PYBIND11_DETAILED_ERROR_MESSAGES)
"(compile in debug mode for type information)"); "(#define PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for "
"type information)");
#else #else
"of type '" "of type '"
+ type_id<holder_type>() + "''"); + type_id<holder_type>() + "''");
@ -1029,9 +1030,9 @@ struct return_value_policy_override<
template <typename T, typename SFINAE> template <typename T, typename SFINAE>
type_caster<T, SFINAE> &load_type(type_caster<T, SFINAE> &conv, const handle &handle) { type_caster<T, SFINAE> &load_type(type_caster<T, SFINAE> &conv, const handle &handle) {
if (!conv.load(handle, true)) { if (!conv.load(handle, true)) {
#if defined(NDEBUG) #if !defined(PYBIND11_DETAILED_ERROR_MESSAGES)
throw cast_error( throw cast_error("Unable to cast Python instance to C++ type (#define "
"Unable to cast Python instance to C++ type (compile in debug mode for details)"); "PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for details)");
#else #else
throw cast_error("Unable to cast Python instance of type " throw cast_error("Unable to cast Python instance of type "
+ (std::string) str(type::handle_of(handle)) + " to C++ type '" + (std::string) str(type::handle_of(handle)) + " to C++ type '"
@ -1096,10 +1097,10 @@ inline void handle::cast() const {
template <typename T> template <typename T>
detail::enable_if_t<!detail::move_never<T>::value, T> move(object &&obj) { detail::enable_if_t<!detail::move_never<T>::value, T> move(object &&obj) {
if (obj.ref_count() > 1) { if (obj.ref_count() > 1) {
#if defined(NDEBUG) #if !defined(PYBIND11_DETAILED_ERROR_MESSAGES)
throw cast_error( throw cast_error(
"Unable to cast Python instance to C++ rvalue: instance has multiple references" "Unable to cast Python instance to C++ rvalue: instance has multiple references"
" (compile in debug mode for details)"); " (#define PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for details)");
#else #else
throw cast_error("Unable to move from Python " + (std::string) str(type::handle_of(obj)) throw cast_error("Unable to move from Python " + (std::string) str(type::handle_of(obj))
+ " instance to C++ " + type_id<T>() + " instance to C++ " + type_id<T>()
@ -1200,10 +1201,10 @@ PYBIND11_NAMESPACE_END(detail)
// The overloads could coexist, i.e. the #if is not strictly speaking needed, // The overloads could coexist, i.e. the #if is not strictly speaking needed,
// but it is an easy minor optimization. // but it is an easy minor optimization.
#if defined(NDEBUG) #if !defined(PYBIND11_DETAILED_ERROR_MESSAGES)
inline cast_error cast_error_unable_to_convert_call_arg() { inline cast_error cast_error_unable_to_convert_call_arg() {
return cast_error( return cast_error("Unable to convert call argument to Python object (#define "
"Unable to convert call argument to Python object (compile in debug mode for details)"); "PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for details)");
} }
#else #else
inline cast_error cast_error_unable_to_convert_call_arg(const std::string &name, inline cast_error cast_error_unable_to_convert_call_arg(const std::string &name,
@ -1225,7 +1226,7 @@ tuple make_tuple(Args &&...args_) {
detail::make_caster<Args>::cast(std::forward<Args>(args_), policy, nullptr))...}}; detail::make_caster<Args>::cast(std::forward<Args>(args_), policy, nullptr))...}};
for (size_t i = 0; i < args.size(); i++) { for (size_t i = 0; i < args.size(); i++) {
if (!args[i]) { if (!args[i]) {
#if defined(NDEBUG) #if !defined(PYBIND11_DETAILED_ERROR_MESSAGES)
throw cast_error_unable_to_convert_call_arg(); throw cast_error_unable_to_convert_call_arg();
#else #else
std::array<std::string, size> argtypes{{type_id<Args>()...}}; std::array<std::string, size> argtypes{{type_id<Args>()...}};
@ -1277,7 +1278,7 @@ private:
: arg(base), value(reinterpret_steal<object>(detail::make_caster<T>::cast( : arg(base), value(reinterpret_steal<object>(detail::make_caster<T>::cast(
std::forward<T>(x), return_value_policy::automatic, {}))), std::forward<T>(x), return_value_policy::automatic, {}))),
descr(descr) descr(descr)
#if !defined(NDEBUG) #if defined(PYBIND11_DETAILED_ERROR_MESSAGES)
, ,
type(type_id<T>()) type(type_id<T>())
#endif #endif
@ -1317,7 +1318,7 @@ public:
object value; object value;
/// The (optional) description of the default value /// The (optional) description of the default value
const char *descr; const char *descr;
#if !defined(NDEBUG) #if defined(PYBIND11_DETAILED_ERROR_MESSAGES)
/// The C++ type name of the default value (only available when compiled in debug mode) /// The C++ type name of the default value (only available when compiled in debug mode)
std::string type; std::string type;
#endif #endif
@ -1515,7 +1516,7 @@ private:
auto o = reinterpret_steal<object>( auto o = reinterpret_steal<object>(
detail::make_caster<T>::cast(std::forward<T>(x), policy, {})); detail::make_caster<T>::cast(std::forward<T>(x), policy, {}));
if (!o) { if (!o) {
#if defined(NDEBUG) #if !defined(PYBIND11_DETAILED_ERROR_MESSAGES)
throw cast_error_unable_to_convert_call_arg(); throw cast_error_unable_to_convert_call_arg();
#else #else
throw cast_error_unable_to_convert_call_arg(std::to_string(args_list.size()), throw cast_error_unable_to_convert_call_arg(std::to_string(args_list.size()),
@ -1533,21 +1534,21 @@ private:
void process(list & /*args_list*/, arg_v a) { void process(list & /*args_list*/, arg_v a) {
if (!a.name) { if (!a.name) {
#if defined(NDEBUG) #if !defined(PYBIND11_DETAILED_ERROR_MESSAGES)
nameless_argument_error(); nameless_argument_error();
#else #else
nameless_argument_error(a.type); nameless_argument_error(a.type);
#endif #endif
} }
if (m_kwargs.contains(a.name)) { if (m_kwargs.contains(a.name)) {
#if defined(NDEBUG) #if !defined(PYBIND11_DETAILED_ERROR_MESSAGES)
multiple_values_error(); multiple_values_error();
#else #else
multiple_values_error(a.name); multiple_values_error(a.name);
#endif #endif
} }
if (!a.value) { if (!a.value) {
#if defined(NDEBUG) #if !defined(PYBIND11_DETAILED_ERROR_MESSAGES)
throw cast_error_unable_to_convert_call_arg(); throw cast_error_unable_to_convert_call_arg();
#else #else
throw cast_error_unable_to_convert_call_arg(a.name, a.type); throw cast_error_unable_to_convert_call_arg(a.name, a.type);
@ -1562,7 +1563,7 @@ private:
} }
for (auto k : reinterpret_borrow<dict>(kp)) { for (auto k : reinterpret_borrow<dict>(kp)) {
if (m_kwargs.contains(k.first)) { if (m_kwargs.contains(k.first)) {
#if defined(NDEBUG) #if !defined(PYBIND11_DETAILED_ERROR_MESSAGES)
multiple_values_error(); multiple_values_error();
#else #else
multiple_values_error(str(k.first)); multiple_values_error(str(k.first));
@ -1573,9 +1574,10 @@ private:
} }
[[noreturn]] static void nameless_argument_error() { [[noreturn]] static void nameless_argument_error() {
throw type_error("Got kwargs without a name; only named arguments " throw type_error(
"may be passed via py::arg() to a python function call. " "Got kwargs without a name; only named arguments "
"(compile in debug mode for details)"); "may be passed via py::arg() to a python function call. "
"(#define PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for details)");
} }
[[noreturn]] static void nameless_argument_error(const std::string &type) { [[noreturn]] static void nameless_argument_error(const std::string &type) {
throw type_error("Got kwargs without a name of type '" + type throw type_error("Got kwargs without a name of type '" + type
@ -1583,8 +1585,9 @@ private:
"arguments may be passed via py::arg() to a python function call. "); "arguments may be passed via py::arg() to a python function call. ");
} }
[[noreturn]] static void multiple_values_error() { [[noreturn]] static void multiple_values_error() {
throw type_error("Got multiple values for keyword argument " throw type_error(
"(compile in debug mode for details)"); "Got multiple values for keyword argument "
"(#define PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for details)");
} }
[[noreturn]] static void multiple_values_error(const std::string &name) { [[noreturn]] static void multiple_values_error(const std::string &name) {
@ -1631,7 +1634,7 @@ unpacking_collector<policy> collect_arguments(Args &&...args) {
template <typename Derived> template <typename Derived>
template <return_value_policy policy, typename... Args> template <return_value_policy policy, typename... Args>
object object_api<Derived>::operator()(Args &&...args) const { object object_api<Derived>::operator()(Args &&...args) const {
#ifndef NDEBUG #if defined(PYBIND11_DETAILED_ERROR_MESSAGES)
if (!PyGILState_Check()) { if (!PyGILState_Check()) {
pybind11_fail("pybind11::object_api<>::operator() PyGILState_Check() failure."); pybind11_fail("pybind11::object_api<>::operator() PyGILState_Check() failure.");
} }

View File

@ -1169,5 +1169,12 @@ constexpr inline bool silence_msvc_c4127(bool cond) { return cond; }
# define PYBIND11_SILENCE_MSVC_C4127(...) __VA_ARGS__ # define PYBIND11_SILENCE_MSVC_C4127(...) __VA_ARGS__
#endif #endif
// Pybind offers detailed error messages by default for all builts that are debug (through the
// negation of ndebug). This can also be manually enabled by users, for any builds, through
// defining PYBIND11_DETAILED_ERROR_MESSAGES.
#if !defined(PYBIND11_DETAILED_ERROR_MESSAGES) && !defined(NDEBUG)
# define PYBIND11_DETAILED_ERROR_MESSAGES
#endif
PYBIND11_NAMESPACE_END(detail) PYBIND11_NAMESPACE_END(detail)
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE) PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)

View File

@ -394,15 +394,16 @@ instance::get_value_and_holder(const type_info *find_type /*= nullptr default in
return value_and_holder(); return value_and_holder();
} }
#if defined(NDEBUG) #if defined(PYBIND11_DETAILED_ERROR_MESSAGES)
pybind11_fail("pybind11::detail::instance::get_value_and_holder: "
"type is not a pybind11 base of the given instance "
"(compile in debug mode for type details)");
#else
pybind11_fail("pybind11::detail::instance::get_value_and_holder: `" pybind11_fail("pybind11::detail::instance::get_value_and_holder: `"
+ get_fully_qualified_tp_name(find_type->type) + get_fully_qualified_tp_name(find_type->type)
+ "' is not a pybind11 base of the given `" + "' is not a pybind11 base of the given `"
+ get_fully_qualified_tp_name(Py_TYPE(this)) + "' instance"); + get_fully_qualified_tp_name(Py_TYPE(this)) + "' instance");
#else
pybind11_fail(
"pybind11::detail::instance::get_value_and_holder: "
"type is not a pybind11 base of the given instance "
"(#define PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for type details)");
#endif #endif
} }
@ -612,14 +613,15 @@ public:
if (copy_constructor) { if (copy_constructor) {
valueptr = copy_constructor(src); valueptr = copy_constructor(src);
} else { } else {
#if defined(NDEBUG) #if defined(PYBIND11_DETAILED_ERROR_MESSAGES)
throw cast_error("return_value_policy = copy, but type is "
"non-copyable! (compile in debug mode for details)");
#else
std::string type_name(tinfo->cpptype->name()); std::string type_name(tinfo->cpptype->name());
detail::clean_type_id(type_name); detail::clean_type_id(type_name);
throw cast_error("return_value_policy = copy, but type " + type_name throw cast_error("return_value_policy = copy, but type " + type_name
+ " is non-copyable!"); + " is non-copyable!");
#else
throw cast_error("return_value_policy = copy, but type is "
"non-copyable! (#define PYBIND11_DETAILED_ERROR_MESSAGES or "
"compile in debug mode for details)");
#endif #endif
} }
wrapper->owned = true; wrapper->owned = true;
@ -631,15 +633,16 @@ public:
} else if (copy_constructor) { } else if (copy_constructor) {
valueptr = copy_constructor(src); valueptr = copy_constructor(src);
} else { } else {
#if defined(NDEBUG) #if defined(PYBIND11_DETAILED_ERROR_MESSAGES)
throw cast_error("return_value_policy = move, but type is neither "
"movable nor copyable! "
"(compile in debug mode for details)");
#else
std::string type_name(tinfo->cpptype->name()); std::string type_name(tinfo->cpptype->name());
detail::clean_type_id(type_name); detail::clean_type_id(type_name);
throw cast_error("return_value_policy = move, but type " + type_name throw cast_error("return_value_policy = move, but type " + type_name
+ " is neither movable nor copyable!"); + " is neither movable nor copyable!");
#else
throw cast_error("return_value_policy = move, but type is neither "
"movable nor copyable! "
"(#define PYBIND11_DETAILED_ERROR_MESSAGES or compile in "
"debug mode for details)");
#endif #endif
} }
wrapper->owned = true; wrapper->owned = true;

View File

@ -62,7 +62,7 @@ public:
if (!tstate) { if (!tstate) {
tstate = PyThreadState_New(internals.istate); tstate = PyThreadState_New(internals.istate);
# if !defined(NDEBUG) # if defined(PYBIND11_DETAILED_ERROR_MESSAGES)
if (!tstate) { if (!tstate) {
pybind11_fail("scoped_acquire: could not create thread state!"); pybind11_fail("scoped_acquire: could not create thread state!");
} }
@ -84,7 +84,7 @@ public:
PYBIND11_NOINLINE void dec_ref() { PYBIND11_NOINLINE void dec_ref() {
--tstate->gilstate_counter; --tstate->gilstate_counter;
# if !defined(NDEBUG) # if defined(PYBIND11_DETAILED_ERROR_MESSAGES)
if (detail::get_thread_state_unchecked() != tstate) { if (detail::get_thread_state_unchecked() != tstate) {
pybind11_fail("scoped_acquire::dec_ref(): thread state must be current!"); pybind11_fail("scoped_acquire::dec_ref(): thread state must be current!");
} }
@ -93,7 +93,7 @@ public:
} }
# endif # endif
if (tstate->gilstate_counter == 0) { if (tstate->gilstate_counter == 0) {
# if !defined(NDEBUG) # if defined(PYBIND11_DETAILED_ERROR_MESSAGES)
if (!release) { if (!release) {
pybind11_fail("scoped_acquire::dec_ref(): internal error!"); pybind11_fail("scoped_acquire::dec_ref(): internal error!");
} }

View File

@ -263,7 +263,7 @@ private:
static npy_api lookup() { static npy_api lookup() {
module_ m = module_::import("numpy.core.multiarray"); module_ m = module_::import("numpy.core.multiarray");
auto c = m.attr("_ARRAY_API"); auto c = m.attr("_ARRAY_API");
void **api_ptr = (void **) PyCapsule_GetPointer(c.ptr(), NULL); void **api_ptr = (void **) PyCapsule_GetPointer(c.ptr(), nullptr);
npy_api api; npy_api api;
#define DECL_NPY_API(Func) api.Func##_ = (decltype(api.Func##_)) api_ptr[API_##Func]; #define DECL_NPY_API(Func) api.Func##_ = (decltype(api.Func##_)) api_ptr[API_##Func];
DECL_NPY_API(PyArray_GetNDArrayCFeatureVersion); DECL_NPY_API(PyArray_GetNDArrayCFeatureVersion);
@ -547,9 +547,11 @@ public:
.ptr(); .ptr();
} }
explicit dtype(const std::string &format) : dtype(from_args(pybind11::str(format))) {} explicit dtype(const pybind11::str &format) : dtype(from_args(format)) {}
explicit dtype(const char *format) : dtype(from_args(pybind11::str(format))) {} explicit dtype(const std::string &format) : dtype(pybind11::str(format)) {}
explicit dtype(const char *format) : dtype(pybind11::str(format)) {}
dtype(list names, list formats, list offsets, ssize_t itemsize) { dtype(list names, list formats, list offsets, ssize_t itemsize) {
dict args; dict args;
@ -557,7 +559,7 @@ public:
args["formats"] = std::move(formats); args["formats"] = std::move(formats);
args["offsets"] = std::move(offsets); args["offsets"] = std::move(offsets);
args["itemsize"] = pybind11::int_(itemsize); args["itemsize"] = pybind11::int_(itemsize);
m_ptr = from_args(std::move(args)).release().ptr(); m_ptr = from_args(args).release().ptr();
} }
explicit dtype(int typenum) explicit dtype(int typenum)
@ -568,7 +570,7 @@ public:
} }
/// This is essentially the same as calling numpy.dtype(args) in Python. /// This is essentially the same as calling numpy.dtype(args) in Python.
static dtype from_args(object args) { static dtype from_args(const object &args) {
PyObject *ptr = nullptr; PyObject *ptr = nullptr;
if ((detail::npy_api::get().PyArray_DescrConverter_(args.ptr(), &ptr) == 0) || !ptr) { if ((detail::npy_api::get().PyArray_DescrConverter_(args.ptr(), &ptr) == 0) || !ptr) {
throw error_already_set(); throw error_already_set();
@ -645,8 +647,9 @@ private:
for (auto field : attr("fields").attr("items")()) { for (auto field : attr("fields").attr("items")()) {
auto spec = field.cast<tuple>(); auto spec = field.cast<tuple>();
auto name = spec[0].cast<pybind11::str>(); auto name = spec[0].cast<pybind11::str>();
auto format = spec[1].cast<tuple>()[0].cast<dtype>(); auto spec_fo = spec[1].cast<tuple>();
auto offset = spec[1].cast<tuple>()[1].cast<pybind11::int_>(); auto format = spec_fo[0].cast<dtype>();
auto offset = spec_fo[1].cast<pybind11::int_>();
if ((len(name) == 0u) && format.kind() == 'V') { if ((len(name) == 0u) && format.kind() == 'V') {
continue; continue;
} }
@ -1549,7 +1552,7 @@ public:
void *data() const { return p_ptr; } void *data() const { return p_ptr; }
private: private:
char *p_ptr{0}; char *p_ptr{nullptr};
container_type m_strides; container_type m_strides;
}; };

View File

@ -313,6 +313,10 @@ protected:
// along the way. // along the way.
class strdup_guard { class strdup_guard {
public: public:
strdup_guard() = default;
strdup_guard(const strdup_guard &) = delete;
strdup_guard &operator=(const strdup_guard &) = delete;
~strdup_guard() { ~strdup_guard() {
for (auto *s : strings) { for (auto *s : strings) {
std::free(s); std::free(s);
@ -367,7 +371,7 @@ protected:
rec->is_constructor = (std::strcmp(rec->name, "__init__") == 0) rec->is_constructor = (std::strcmp(rec->name, "__init__") == 0)
|| (std::strcmp(rec->name, "__setstate__") == 0); || (std::strcmp(rec->name, "__setstate__") == 0);
#if !defined(NDEBUG) && !defined(PYBIND11_DISABLE_NEW_STYLE_INIT_WARNING) #if defined(PYBIND11_DETAILED_ERROR_MESSAGES) && !defined(PYBIND11_DISABLE_NEW_STYLE_INIT_WARNING)
if (rec->is_constructor && !rec->is_new_style_constructor) { if (rec->is_constructor && !rec->is_new_style_constructor) {
const auto class_name const auto class_name
= detail::get_fully_qualified_tp_name((PyTypeObject *) rec->scope.ptr()); = detail::get_fully_qualified_tp_name((PyTypeObject *) rec->scope.ptr());
@ -515,8 +519,9 @@ protected:
if (chain->is_method != rec->is_method) { if (chain->is_method != rec->is_method) {
pybind11_fail( pybind11_fail(
"overloading a method with both static and instance methods is not supported; " "overloading a method with both static and instance methods is not supported; "
#if defined(NDEBUG) #if !defined(PYBIND11_DETAILED_ERROR_MESSAGES)
"compile in debug mode for more details" "#define PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for more "
"details"
#else #else
"error while attempting to bind " "error while attempting to bind "
+ std::string(rec->is_method ? "instance" : "static") + " method " + std::string(rec->is_method ? "instance" : "static") + " method "
@ -903,7 +908,7 @@ protected:
// 5. Put everything in a vector. Not technically step 5, we've been building it // 5. Put everything in a vector. Not technically step 5, we've been building it
// in `call.args` all along. // in `call.args` all along.
#if !defined(NDEBUG) #if defined(PYBIND11_DETAILED_ERROR_MESSAGES)
if (call.args.size() != func.nargs || call.args_convert.size() != func.nargs) { if (call.args.size() != func.nargs || call.args_convert.size() != func.nargs) {
pybind11_fail("Internal error: function call dispatcher inserted wrong number " pybind11_fail("Internal error: function call dispatcher inserted wrong number "
"of arguments!"); "of arguments!");
@ -2592,7 +2597,7 @@ public:
exception(handle scope, const char *name, handle base = PyExc_Exception) { exception(handle scope, const char *name, handle base = PyExc_Exception) {
std::string full_name std::string full_name
= scope.attr("__name__").cast<std::string>() + std::string(".") + name; = scope.attr("__name__").cast<std::string>() + std::string(".") + name;
m_ptr = PyErr_NewException(const_cast<char *>(full_name.c_str()), base.ptr(), NULL); m_ptr = PyErr_NewException(const_cast<char *>(full_name.c_str()), base.ptr(), nullptr);
if (hasattr(scope, "__dict__") && scope.attr("__dict__").contains(name)) { if (hasattr(scope, "__dict__") && scope.attr("__dict__").contains(name)) {
pybind11_fail("Error during initialization: multiple incompatible " pybind11_fail("Error during initialization: multiple incompatible "
"definitions with name \"" "definitions with name \""

View File

@ -600,13 +600,13 @@ inline handle get_function(handle value) {
inline PyObject *dict_getitemstring(PyObject *v, const char *key) { inline PyObject *dict_getitemstring(PyObject *v, const char *key) {
PyObject *kv = nullptr, *rv = nullptr; PyObject *kv = nullptr, *rv = nullptr;
kv = PyUnicode_FromString(key); kv = PyUnicode_FromString(key);
if (kv == NULL) { if (kv == nullptr) {
throw error_already_set(); throw error_already_set();
} }
rv = PyDict_GetItemWithError(v, kv); rv = PyDict_GetItemWithError(v, kv);
Py_DECREF(kv); Py_DECREF(kv);
if (rv == NULL && PyErr_Occurred()) { if (rv == nullptr && PyErr_Occurred()) {
throw error_already_set(); throw error_already_set();
} }
return rv; return rv;
@ -614,7 +614,7 @@ inline PyObject *dict_getitemstring(PyObject *v, const char *key) {
inline PyObject *dict_getitem(PyObject *v, PyObject *key) { inline PyObject *dict_getitem(PyObject *v, PyObject *key) {
PyObject *rv = PyDict_GetItemWithError(v, key); PyObject *rv = PyDict_GetItemWithError(v, key);
if (rv == NULL && PyErr_Occurred()) { if (rv == nullptr && PyErr_Occurred()) {
throw error_already_set(); throw error_already_set();
} }
return rv; return rv;
@ -1914,8 +1914,8 @@ public:
return memoryview::from_buffer(reinterpret_cast<void *>(ptr), return memoryview::from_buffer(reinterpret_cast<void *>(ptr),
sizeof(T), sizeof(T),
format_descriptor<T>::value, format_descriptor<T>::value,
shape, std::move(shape),
strides, std::move(strides),
readonly); readonly);
} }
@ -1923,7 +1923,8 @@ public:
static memoryview from_buffer(const T *ptr, static memoryview from_buffer(const T *ptr,
detail::any_container<ssize_t> shape, detail::any_container<ssize_t> shape,
detail::any_container<ssize_t> strides) { detail::any_container<ssize_t> strides) {
return memoryview::from_buffer(const_cast<T *>(ptr), shape, strides, true); return memoryview::from_buffer(
const_cast<T *>(ptr), std::move(shape), std::move(strides), true);
} }
/** \rst /** \rst

View File

@ -46,4 +46,4 @@ max-line-length = 120
show_source = True show_source = True
exclude = .git, __pycache__, build, dist, docs, tools, venv exclude = .git, __pycache__, build, dist, docs, tools, venv
extend-ignore = E203, E722, B950 extend-ignore = E203, E722, B950
select = C,E,F,N,W,B,B9 extend-select = B9

View File

@ -25,8 +25,8 @@ void gil_acquire() { py::gil_scoped_acquire gil; }
constexpr char kModuleName[] = "cross_module_gil_utils"; constexpr char kModuleName[] = "cross_module_gil_utils";
struct PyModuleDef moduledef struct PyModuleDef moduledef = {
= {PyModuleDef_HEAD_INIT, kModuleName, NULL, 0, NULL, NULL, NULL, NULL, NULL}; PyModuleDef_HEAD_INIT, kModuleName, nullptr, 0, nullptr, nullptr, nullptr, nullptr, nullptr};
} // namespace } // namespace
@ -34,7 +34,7 @@ extern "C" PYBIND11_EXPORT PyObject *PyInit_cross_module_gil_utils() {
PyObject *m = PyModule_Create(&moduledef); PyObject *m = PyModule_Create(&moduledef);
if (m != NULL) { if (m != nullptr) {
static_assert(sizeof(&gil_acquire) == sizeof(void *), static_assert(sizeof(&gil_acquire) == sizeof(void *),
"Function pointer must have the same size as void*"); "Function pointer must have the same size as void*");
PyModule_AddObject( PyModule_AddObject(

View File

@ -67,10 +67,10 @@ PYBIND11_MODULE(pybind11_tests, m) {
bind_ConstructorStats(m); bind_ConstructorStats(m);
#if !defined(NDEBUG) #if defined(PYBIND11_DETAILED_ERROR_MESSAGES)
m.attr("debug_enabled") = true; m.attr("detailed_error_messages_enabled") = true;
#else #else
m.attr("debug_enabled") = false; m.attr("detailed_error_messages_enabled") = false;
#endif #endif
py::class_<UserType>(m, "UserType", "A `py::class_` type for testing") py::class_<UserType>(m, "UserType", "A `py::class_` type for testing")

View File

@ -361,10 +361,10 @@ TEST_SUBMODULE(methods_and_attributes, m) {
// test_bad_arg_default // test_bad_arg_default
// Issue/PR #648: bad arg default debugging output // Issue/PR #648: bad arg default debugging output
#if !defined(NDEBUG) #if defined(PYBIND11_DETAILED_ERROR_MESSAGES)
m.attr("debug_enabled") = true; m.attr("detailed_error_messages_enabled") = true;
#else #else
m.attr("debug_enabled") = false; m.attr("detailed_error_messages_enabled") = false;
#endif #endif
m.def("bad_arg_def_named", [] { m.def("bad_arg_def_named", [] {
auto m = py::module_::import("pybind11_tests"); auto m = py::module_::import("pybind11_tests");

View File

@ -216,15 +216,15 @@ def test_metaclass_override():
def test_no_mixed_overloads(): def test_no_mixed_overloads():
from pybind11_tests import debug_enabled from pybind11_tests import detailed_error_messages_enabled
with pytest.raises(RuntimeError) as excinfo: with pytest.raises(RuntimeError) as excinfo:
m.ExampleMandA.add_mixed_overloads1() m.ExampleMandA.add_mixed_overloads1()
assert str( assert str(
excinfo.value excinfo.value
) == "overloading a method with both static and instance methods is not supported; " + ( ) == "overloading a method with both static and instance methods is not supported; " + (
"compile in debug mode for more details" "#define PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for more details"
if not debug_enabled if not detailed_error_messages_enabled
else "error while attempting to bind static method ExampleMandA.overload_mixed1" else "error while attempting to bind static method ExampleMandA.overload_mixed1"
"(arg0: float) -> str" "(arg0: float) -> str"
) )
@ -234,8 +234,8 @@ def test_no_mixed_overloads():
assert str( assert str(
excinfo.value excinfo.value
) == "overloading a method with both static and instance methods is not supported; " + ( ) == "overloading a method with both static and instance methods is not supported; " + (
"compile in debug mode for more details" "#define PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for more details"
if not debug_enabled if not detailed_error_messages_enabled
else "error while attempting to bind instance method ExampleMandA.overload_mixed2" else "error while attempting to bind instance method ExampleMandA.overload_mixed2"
"(self: pybind11_tests.methods_and_attributes.ExampleMandA, arg0: int, arg1: int)" "(self: pybind11_tests.methods_and_attributes.ExampleMandA, arg0: int, arg1: int)"
" -> str" " -> str"
@ -344,16 +344,16 @@ def test_cyclic_gc():
def test_bad_arg_default(msg): def test_bad_arg_default(msg):
from pybind11_tests import debug_enabled from pybind11_tests import detailed_error_messages_enabled
with pytest.raises(RuntimeError) as excinfo: with pytest.raises(RuntimeError) as excinfo:
m.bad_arg_def_named() m.bad_arg_def_named()
assert msg(excinfo.value) == ( assert msg(excinfo.value) == (
"arg(): could not convert default argument 'a: UnregisteredType' in function " "arg(): could not convert default argument 'a: UnregisteredType' in function "
"'should_fail' into a Python object (type not registered yet?)" "'should_fail' into a Python object (type not registered yet?)"
if debug_enabled if detailed_error_messages_enabled
else "arg(): could not convert default argument into a Python object (type not registered " else "arg(): could not convert default argument into a Python object (type not registered "
"yet?). Compile in debug mode for more information." "yet?). #define PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for more information."
) )
with pytest.raises(RuntimeError) as excinfo: with pytest.raises(RuntimeError) as excinfo:
@ -361,9 +361,9 @@ def test_bad_arg_default(msg):
assert msg(excinfo.value) == ( assert msg(excinfo.value) == (
"arg(): could not convert default argument 'UnregisteredType' in function " "arg(): could not convert default argument 'UnregisteredType' in function "
"'should_fail' into a Python object (type not registered yet?)" "'should_fail' into a Python object (type not registered yet?)"
if debug_enabled if detailed_error_messages_enabled
else "arg(): could not convert default argument into a Python object (type not registered " else "arg(): could not convert default argument into a Python object (type not registered "
"yet?). Compile in debug mode for more information." "yet?). #define PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for more information."
) )

View File

@ -289,8 +289,8 @@ py::list test_dtype_ctors() {
dict["itemsize"] = py::int_(20); dict["itemsize"] = py::int_(20);
list.append(py::dtype::from_args(dict)); list.append(py::dtype::from_args(dict));
list.append(py::dtype(names, formats, offsets, 20)); list.append(py::dtype(names, formats, offsets, 20));
list.append(py::dtype(py::buffer_info((void *) 0, sizeof(unsigned int), "I", 1))); list.append(py::dtype(py::buffer_info((void *) nullptr, sizeof(unsigned int), "I", 1)));
list.append(py::dtype(py::buffer_info((void *) 0, 0, "T{i:a:f:b:}", 1))); list.append(py::dtype(py::buffer_info((void *) nullptr, 0, "T{i:a:f:b:}", 1)));
list.append(py::dtype(py::detail::npy_api::NPY_DOUBLE_)); list.append(py::dtype(py::detail::npy_api::NPY_DOUBLE_));
return list; return list;
} }
@ -610,5 +610,5 @@ TEST_SUBMODULE(numpy_dtypes, m) {
[]() { PYBIND11_NUMPY_DTYPE(SimpleStruct, bool_, uint_, float_, ldbl_); }); []() { PYBIND11_NUMPY_DTYPE(SimpleStruct, bool_, uint_, float_, ldbl_); });
// test_str_leak // test_str_leak
m.def("dtype_wrapper", [](py::object d) { return py::dtype::from_args(std::move(d)); }); m.def("dtype_wrapper", [](const py::object &d) { return py::dtype::from_args(d); });
} }

View File

@ -61,6 +61,8 @@ void wrap(py::module m) {
} // namespace exercise_trampoline } // namespace exercise_trampoline
TEST_SUBMODULE(pickling, m) { TEST_SUBMODULE(pickling, m) {
m.def("simple_callable", []() { return 20220426; });
// test_roundtrip // test_roundtrip
class Pickleable { class Pickleable {
public: public:

View File

@ -1,4 +1,5 @@
import pickle import pickle
import re
import pytest import pytest
@ -6,6 +7,20 @@ import env
from pybind11_tests import pickling as m from pybind11_tests import pickling as m
def test_pickle_simple_callable():
assert m.simple_callable() == 20220426
if env.PYPY:
serialized = pickle.dumps(m.simple_callable)
deserialized = pickle.loads(serialized)
assert deserialized() == 20220426
else:
# To document broken behavior: currently it fails universally with
# all C Python versions.
with pytest.raises(TypeError) as excinfo:
pickle.dumps(m.simple_callable)
assert re.search("can.*t pickle .*PyCapsule.* object", str(excinfo.value))
@pytest.mark.parametrize("cls_name", ["Pickleable", "PickleableNew"]) @pytest.mark.parametrize("cls_name", ["Pickleable", "PickleableNew"])
def test_roundtrip(cls_name): def test_roundtrip(cls_name):
cls = getattr(m, cls_name) cls = getattr(m, cls_name)

View File

@ -4,7 +4,7 @@ import sys
import pytest import pytest
import env import env
from pybind11_tests import debug_enabled from pybind11_tests import detailed_error_messages_enabled
from pybind11_tests import pytypes as m from pybind11_tests import pytypes as m
@ -416,8 +416,8 @@ def test_print(capture):
m.print_failure() m.print_failure()
assert str(excinfo.value) == "Unable to convert call argument " + ( assert str(excinfo.value) == "Unable to convert call argument " + (
"'1' of type 'UnregisteredType' to Python object" "'1' of type 'UnregisteredType' to Python object"
if debug_enabled if detailed_error_messages_enabled
else "to Python object (compile in debug mode for details)" else "to Python object (#define PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for details)"
) )

View File

@ -14,6 +14,7 @@ def test_vector(doc):
assert m.cast_bool_vector() == [True, False] assert m.cast_bool_vector() == [True, False]
assert m.load_bool_vector([True, False]) assert m.load_bool_vector([True, False])
assert m.load_bool_vector(tuple([True, False]))
assert doc(m.cast_vector) == "cast_vector() -> List[int]" assert doc(m.cast_vector) == "cast_vector() -> List[int]"
assert doc(m.load_vector) == "load_vector(arg0: List[int]) -> bool" assert doc(m.load_vector) == "load_vector(arg0: List[int]) -> bool"
@ -36,6 +37,7 @@ def test_array(doc):
lst = m.cast_array() lst = m.cast_array()
assert lst == [1, 2] assert lst == [1, 2]
assert m.load_array(lst) assert m.load_array(lst)
assert m.load_array(tuple(lst))
assert doc(m.cast_array) == "cast_array() -> List[int[2]]" assert doc(m.cast_array) == "cast_array() -> List[int[2]]"
assert doc(m.load_array) == "load_array(arg0: List[int[2]]) -> bool" assert doc(m.load_array) == "load_array(arg0: List[int[2]]) -> bool"
@ -46,6 +48,7 @@ def test_valarray(doc):
lst = m.cast_valarray() lst = m.cast_valarray()
assert lst == [1, 4, 9] assert lst == [1, 4, 9]
assert m.load_valarray(lst) assert m.load_valarray(lst)
assert m.load_valarray(tuple(lst))
assert doc(m.cast_valarray) == "cast_valarray() -> List[int]" assert doc(m.cast_valarray) == "cast_valarray() -> List[int]"
assert doc(m.load_valarray) == "load_valarray(arg0: List[int]) -> bool" assert doc(m.load_valarray) == "load_valarray(arg0: List[int]) -> bool"