t pushMerge branch 'master' of https://github.com/pybind/pybind11 into lazy-error-string

This commit is contained in:
Aaron Gokaslan 2022-04-23 12:29:56 -04:00
commit 98aff18132
26 changed files with 524 additions and 161 deletions

View File

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

View File

@ -32,6 +32,7 @@ jobs:
- '3.10'
- 'pypy-3.7'
- 'pypy-3.8'
- 'pypy-3.9'
# Items in here will either be added to the build matrix (if not
# present), or add new keys to an existing matrix element if all the
@ -45,6 +46,10 @@ jobs:
args: >
-DPYBIND11_FINDPYTHON=ON
-DCMAKE_CXX_FLAGS="-D_=1"
- runs-on: ubuntu-latest
python: 'pypy-3.8'
args: >
-DPYBIND11_FINDPYTHON=ON
- runs-on: windows-2019
python: '3.6'
args: >
@ -668,7 +673,7 @@ jobs:
# This verifies that the documentation is not horribly broken, and does a
# basic sanity check on the SDist.
# basic validation check on the SDist.
doxygen:
name: "Documentation build test"
runs-on: ubuntu-latest
@ -756,55 +761,60 @@ jobs:
- name: Python tests
run: cmake --build build -t pytest
win32-msvc2017:
name: "🐍 ${{ matrix.python }} • MSVC 2017 • x64"
runs-on: windows-2016
win32-debug:
strategy:
fail-fast: false
matrix:
python:
- 3.6
- 3.7
std:
- 14
- 3.8
- 3.9
include:
- python: 3.7
std: 17
args: >
-DCMAKE_CXX_FLAGS="/permissive- /EHsc /GR"
- python: 3.9
args: -DCMAKE_CXX_STANDARD=20
- python: 3.8
args: -DCMAKE_CXX_STANDARD=17
name: "🐍 ${{ matrix.python }} • MSVC 2019 (Debug) • x86 ${{ matrix.args }}"
runs-on: windows-2019
steps:
- uses: actions/checkout@v2
- name: Setup 🐍 ${{ matrix.python }}
- name: Setup Python ${{ matrix.python }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python }}
architecture: x86
- name: Update CMake
uses: jwlawson/actions-setup-cmake@v1.12
- name: Prepare MSVC
uses: ilammy/msvc-dev-cmd@v1.10.0
with:
arch: x86
- name: Prepare env
run: |
python -m pip install -r tests/requirements.txt
# First build - C++11 mode and inplace
- name: Configure
- name: Configure ${{ matrix.args }}
run: >
cmake -S . -B build
-G "Visual Studio 15 2017" -A x64
-G "Visual Studio 16 2019" -A Win32
-DCMAKE_BUILD_TYPE=Debug
-DPYBIND11_WERROR=ON
-DDOWNLOAD_CATCH=ON
-DDOWNLOAD_EIGEN=ON
-DCMAKE_CXX_STANDARD=${{ matrix.std }}
${{ matrix.args }}
- name: Build C++11
run: cmake --build build --config Debug -j 2
- name: Build ${{ matrix.std }}
run: cmake --build build -j 2
- name: Python tests
run: cmake --build build --config Debug -t pytest
- name: Run all checks
run: cmake --build build -t check
windows-2022:
strategy:

View File

@ -18,7 +18,7 @@ jobs:
matrix:
runs-on: [ubuntu-latest, macos-latest, windows-latest]
arch: [x64]
cmake: ["3.21"]
cmake: ["3.23"]
include:
- runs-on: ubuntu-latest
@ -29,12 +29,8 @@ jobs:
arch: x64
cmake: 3.7
- runs-on: windows-2016
arch: x86
cmake: 3.8
- runs-on: windows-2016
arch: x86
- runs-on: windows-2019
arch: x64 # x86 compilers seem to be missing on 2019 image
cmake: 3.18
name: 🐍 3.7 • CMake ${{ matrix.cmake }} • ${{ matrix.runs-on }}

View File

@ -15,7 +15,7 @@
repos:
# Standard hooks
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: "v4.1.0"
rev: "v4.2.0"
hooks:
- id: check-added-large-files
- id: check-case-conflict
@ -32,7 +32,7 @@ repos:
# Upgrade old Python syntax
- repo: https://github.com/asottile/pyupgrade
rev: "v2.31.0"
rev: "v2.32.0"
hooks:
- id: pyupgrade
args: [--py36-plus]
@ -45,7 +45,7 @@ repos:
# Black, the code formatter, natively supports pre-commit
- repo: https://github.com/psf/black
rev: "22.1.0" # Keep in sync with blacken-docs
rev: "22.3.0" # Keep in sync with blacken-docs
hooks:
- id: black
@ -55,7 +55,7 @@ repos:
hooks:
- id: blacken-docs
additional_dependencies:
- black==22.1.0 # keep in sync with black hook
- black==22.3.0 # keep in sync with black hook
# Changes tabs to spaces
- repo: https://github.com/Lucas-C/pre-commit-hooks
@ -64,16 +64,17 @@ repos:
- id: remove-tabs
- repo: https://github.com/sirosen/texthooks
rev: "0.2.2"
rev: "0.3.1"
hooks:
- id: fix-ligatures
- id: fix-smartquotes
# Autoremoves unused imports
- repo: https://github.com/hadialqattan/pycln
rev: "v1.2.4"
rev: "v1.3.1"
hooks:
- id: pycln
stages: [manual]
# Checking for common mistakes
- repo: https://github.com/pre-commit/pygrep-hooks
@ -106,7 +107,7 @@ repos:
# PyLint has native support - not always usable, but works for us
- repo: https://github.com/PyCQA/pylint
rev: "v2.12.2"
rev: "v2.13.5"
hooks:
- id: pylint
files: ^pybind11
@ -122,16 +123,16 @@ repos:
# Check static types with mypy
- repo: https://github.com/pre-commit/mirrors-mypy
rev: "v0.931"
rev: "v0.942"
hooks:
- id: mypy
args: [--show-error-codes]
args: []
exclude: ^(tests|docs)/
additional_dependencies: [nox, rich]
# Checks the manifest for missing files (native support)
- repo: https://github.com/mgedmin/check-manifest
rev: "0.47"
rev: "0.48"
hooks:
- id: check-manifest
# This is a slow hook, so only run this if --hook-stage manual is passed
@ -163,7 +164,7 @@ repos:
# Clang format the codebase automatically
- repo: https://github.com/pre-commit/mirrors-clang-format
rev: "v13.0.1"
rev: "v14.0.1"
hooks:
- id: clang-format
types_or: [c++, c, cuda]

View File

@ -87,7 +87,7 @@ buffer objects (e.g. a NumPy matrix).
/* Request a buffer descriptor from Python */
py::buffer_info info = b.request();
/* Some sanity checks ... */
/* Some basic validation checks ... */
if (info.format != py::format_descriptor<Scalar>::format())
throw std::runtime_error("Incompatible format: expected a double array!");

View File

@ -6,10 +6,129 @@ Changelog
Starting with version 1.8.0, pybind11 releases use a `semantic versioning
<http://semver.org>`_ policy.
Changes will be added here periodically from the "Suggested changelog entry"
block in pull request descriptions.
IN DEVELOPMENT
--------------
Changes will be added here periodically.
Removed support for Python 2.7, Python 3.5, and MSVC 2015. Support for MSVC
2017 is limited due to availability of CI runners; we highly recommend MSVC
2019 or 2022 be used.
New features:
* ``type_caster<std::monostate>`` was added. ``std::monostate`` is a tag type
that allows ``std::variant`` to act as an optional, or allows default
construction of a ``std::variant`` holding a non-default constructible type.
`#3818 <https://github.com/pybind/pybind11/pull/3818>`_
* Support bytearray casting to string.
`#3707 <https://github.com/pybind/pybind11/pull/3707>`_
Changes:
* Python 2 support was removed completely.
`#3688 <https://github.com/pybind/pybind11/pull/3688>`_
* The minimum version for MSVC is now 2017.
`#3722 <https://github.com/pybind/pybind11/pull/3722>`_
* Improve exception handling in python ``str`` bindings.
`#3826 <https://github.com/pybind/pybind11/pull/3826>`_
* The bindings for capsules now have more consistent exception handling.
`#3825 <https://github.com/pybind/pybind11/pull/3825>`_
* Fix exception handling when ``pybind11::weakref()`` fails.
`#3739 <https://github.com/pybind/pybind11/pull/3739>`_
Bug fixes:
* ``PYBIND11_OBJECT_CVT`` and ``PYBIND11_OBJECT_CVT_DEFAULT`` macro can be used
to define classes in namespaces other than pybind11.
`#3797 <https://github.com/pybind/pybind11/pull/3797>`_
Build system improvements:
* Add MSVC builds in debug mode to CI.
`#3784 <https://github.com/pybind/pybind11/pull/3784>`_
* MSVC 2022 C++20 coverage was added to GitHub Actions, including Eigen.
`#3732 <https://github.com/pybind/pybind11/pull/3732>`_,
`#3741 <https://github.com/pybind/pybind11/pull/3741>`_
* Avoid ``setup.py <command>`` usage in internal tests.
`#3734 <https://github.com/pybind/pybind11/pull/3734>`_
Backend and tidying up:
* Remove idioms in code comments. Use inclusive language.
`#3809 <https://github.com/pybind/pybind11/pull/3809>`_
Version 2.9.2 (Mar 29, 2022)
----------------------------
Changes:
* Enum now has an ``__index__`` method on Python <3.8 too.
`#3700 <https://github.com/pybind/pybind11/pull/3700>`_
* Local internals are now cleared after finalizing the interpreter.
`#3744 <https://github.com/pybind/pybind11/pull/3744>`_
Bug fixes:
* Better support for Python 3.11 alphas.
`#3694 <https://github.com/pybind/pybind11/pull/3694>`_
* ``PYBIND11_TYPE_CASTER`` now uses fully qualified symbols, so it can be used
outside of ``pybind11::detail``.
`#3758 <https://github.com/pybind/pybind11/pull/3758>`_
* Some fixes for PyPy 3.9.
`#3768 <https://github.com/pybind/pybind11/pull/3768>`_
* Fixed a potential memleak in PyPy in ``get_type_override``.
`#3774 <https://github.com/pybind/pybind11/pull/3774>`_
* Fix usage of ``VISIBILITY_INLINES_HIDDEN``.
`#3721 <https://github.com/pybind/pybind11/pull/3721>`_
Build system improvements:
* Uses ``sysconfig`` module to determine installation locations on Python >=
3.10, instead of ``distutils`` which has been deprecated.
`#3764 <https://github.com/pybind/pybind11/pull/3764>`_
* Support Catch 2.13.5+ (supporting GLIBC 2.34+).
`#3679 <https://github.com/pybind/pybind11/pull/3679>`_
* Fix test failures with numpy 1.22 by ignoring whitespace when comparing
``str()`` of dtypes.
`#3682 <https://github.com/pybind/pybind11/pull/3682>`_
Backend and tidying up:
* clang-tidy: added ``readability-qualified-auto``,
``readability-braces-around-statements``,
``cppcoreguidelines-prefer-member-initializer``,
``clang-analyzer-optin.performance.Padding``,
``cppcoreguidelines-pro-type-static-cast-downcast``, and
``readability-inconsistent-declaration-parameter-name``.
`#3702 <https://github.com/pybind/pybind11/pull/3702>`_,
`#3699 <https://github.com/pybind/pybind11/pull/3699>`_,
`#3716 <https://github.com/pybind/pybind11/pull/3716>`_,
`#3709 <https://github.com/pybind/pybind11/pull/3709>`_
* clang-format was added to the pre-commit actions, and the entire code base
automatically reformatted (after several iterations preparing for this leap).
`#3713 <https://github.com/pybind/pybind11/pull/3713>`_
Version 2.9.1 (Feb 2, 2022)

View File

@ -505,7 +505,10 @@ You can use these targets to build complex applications. For example, the
target_link_libraries(example PRIVATE pybind11::module pybind11::lto pybind11::windows_extras)
pybind11_extension(example)
if(NOT MSVC AND NOT ${CMAKE_BUILD_TYPE} MATCHES Debug|RelWithDebInfo)
# Strip unnecessary sections of the binary on Linux/macOS
pybind11_strip(example)
endif()
set_target_properties(example PROPERTIES CXX_VISIBILITY_PRESET "hidden"
CUDA_VISIBILITY_PRESET "hidden")

View File

@ -514,7 +514,7 @@ struct type_caster<std::basic_string_view<CharT, Traits>,
template <typename CharT>
struct type_caster<CharT, enable_if_t<is_std_char_type<CharT>::value>> {
using StringType = std::basic_string<CharT>;
using StringCaster = type_caster<StringType>;
using StringCaster = make_caster<StringType>;
StringCaster str_caster;
bool none = false;
CharT one_char = 0;
@ -1155,15 +1155,18 @@ enable_if_t<!cast_is_temporary_value_reference<T>::value, T> cast_ref(object &&,
// static_assert, even though if it's in dead code, so we provide a "trampoline" to pybind11::cast
// that only does anything in cases where pybind11::cast is valid.
template <typename T>
enable_if_t<!cast_is_temporary_value_reference<T>::value, T> cast_safe(object &&o) {
return pybind11::cast<T>(std::move(o));
}
template <typename T>
enable_if_t<cast_is_temporary_value_reference<T>::value, T> cast_safe(object &&) {
pybind11_fail("Internal error: cast_safe fallback invoked");
}
template <>
inline void cast_safe<void>(object &&) {}
template <typename T>
enable_if_t<std::is_same<void, intrinsic_t<T>>::value, void> cast_safe(object &&) {}
template <typename T>
enable_if_t<detail::none_of<cast_is_temporary_value_reference<T>,
std::is_same<void, intrinsic_t<T>>>::value,
T>
cast_safe(object &&o) {
return pybind11::cast<T>(std::move(o));
}
PYBIND11_NAMESPACE_END(detail)
@ -1243,8 +1246,8 @@ struct arg_v : arg {
private:
template <typename T>
arg_v(arg &&base, T &&x, const char *descr = nullptr)
: arg(base), value(reinterpret_steal<object>(
detail::make_caster<T>::cast(x, return_value_policy::automatic, {}))),
: arg(base), value(reinterpret_steal<object>(detail::make_caster<T>::cast(
std::forward<T>(x), return_value_policy::automatic, {}))),
descr(descr)
#if !defined(NDEBUG)
,
@ -1491,7 +1494,7 @@ private:
type_id<T>());
#endif
}
args_list.append(o);
args_list.append(std::move(o));
}
void process(list &args_list, detail::args_proxy ap) {

View File

@ -992,6 +992,8 @@ constexpr const char
struct error_scope {
PyObject *type, *value, *trace;
error_scope() { PyErr_Fetch(&type, &value, &trace); }
error_scope(const error_scope &) = delete;
error_scope &operator=(const error_scope &) = delete;
~error_scope() { PyErr_Restore(type, value, trace); }
};

View File

@ -225,8 +225,8 @@ PYBIND11_NOINLINE detail::type_info *get_type_info(const std::type_index &tp,
if (throw_if_missing) {
std::string tname = tp.name();
detail::clean_type_id(tname);
pybind11_fail("pybind11::detail::get_type_info: unable to find type info for \"" + tname
+ "\"");
pybind11_fail("pybind11::detail::get_type_info: unable to find type info for \""
+ std::move(tname) + '"');
}
return nullptr;
}

View File

@ -668,7 +668,7 @@ struct type_caster<Type, enable_if_t<is_eigen_sparse<Type>::value>> {
Type::Flags &(Eigen::RowMajor | Eigen::ColMajor),
StorageIndex>(shape[0].cast<Index>(),
shape[1].cast<Index>(),
nnz,
std::move(nnz),
outerIndices.mutable_data(),
innerIndices.mutable_data(),
values.mutable_data());
@ -686,7 +686,8 @@ struct type_caster<Type, enable_if_t<is_eigen_sparse<Type>::value>> {
array outerIndices((rowMajor ? src.rows() : src.cols()) + 1, src.outerIndexPtr());
array innerIndices(src.nonZeros(), src.innerIndexPtr());
return matrix_type(std::make_tuple(data, innerIndices, outerIndices),
return matrix_type(std::make_tuple(
std::move(data), std::move(innerIndices), std::move(outerIndices)),
std::make_pair(src.rows(), src.cols()))
.release();
}

View File

@ -82,7 +82,7 @@ template <eval_mode mode = eval_expr, size_t N>
object eval(const char (&s)[N], object global = globals(), object local = object()) {
/* Support raw string literals by removing common leading whitespace */
auto expr = (s[0] == '\n') ? str(module_::import("textwrap").attr("dedent")(s)) : str(s);
return eval<mode>(expr, global, local);
return eval<mode>(expr, std::move(global), std::move(local));
}
inline void exec(const str &expr, object global = globals(), object local = object()) {
@ -91,7 +91,7 @@ inline void exec(const str &expr, object global = globals(), object local = obje
template <size_t N>
void exec(const char (&s)[N], object global = globals(), object local = object()) {
eval<eval_statements>(s, global, local);
eval<eval_statements>(s, std::move(global), std::move(local));
}
#if defined(PYPY_VERSION)

View File

@ -263,7 +263,7 @@ private:
static npy_api lookup() {
module_ m = module_::import("numpy.core.multiarray");
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;
#define DECL_NPY_API(Func) api.Func##_ = (decltype(api.Func##_)) api_ptr[API_##Func];
DECL_NPY_API(PyArray_GetNDArrayCFeatureVersion);
@ -540,18 +540,18 @@ public:
PYBIND11_OBJECT_DEFAULT(dtype, object, detail::npy_api::get().PyArrayDescr_Check_);
explicit dtype(const buffer_info &info) {
dtype descr(_dtype_from_pep3118()(PYBIND11_STR_TYPE(info.format)));
dtype descr(_dtype_from_pep3118()(pybind11::str(info.format)));
// If info.itemsize == 0, use the value calculated from the format string
m_ptr = descr.strip_padding(info.itemsize != 0 ? info.itemsize : descr.itemsize())
.release()
.ptr();
}
explicit dtype(const std::string &format) {
m_ptr = from_args(pybind11::str(format)).release().ptr();
}
explicit dtype(const pybind11::str &format) : dtype(from_args(format)) {}
explicit dtype(const char *format) : dtype(std::string(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) {
dict args;
@ -559,11 +559,18 @@ public:
args["formats"] = std::move(formats);
args["offsets"] = std::move(offsets);
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)
: object(detail::npy_api::get().PyArray_DescrFromType_(typenum), stolen_t{}) {
if (m_ptr == nullptr) {
throw error_already_set();
}
}
/// 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;
if ((detail::npy_api::get().PyArray_DescrConverter_(args.ptr(), &ptr) == 0) || !ptr) {
throw error_already_set();
@ -596,6 +603,23 @@ public:
return detail::array_descriptor_proxy(m_ptr)->type;
}
/// type number of dtype.
ssize_t num() const {
// Note: The signature, `dtype::num` follows the naming of NumPy's public
// Python API (i.e., ``dtype.num``), rather than its internal
// C API (``PyArray_Descr::type_num``).
return detail::array_descriptor_proxy(m_ptr)->type_num;
}
/// Single character for byteorder
char byteorder() const { return detail::array_descriptor_proxy(m_ptr)->byteorder; }
/// Alignment of the data type
int alignment() const { return detail::array_descriptor_proxy(m_ptr)->alignment; }
/// Flags for the array descriptor
char flags() const { return detail::array_descriptor_proxy(m_ptr)->flags; }
private:
static object _dtype_from_pep3118() {
static PyObject *obj = module_::import("numpy.core._internal")
@ -614,7 +638,7 @@ private:
}
struct field_descr {
PYBIND11_STR_TYPE name;
pybind11::str name;
object format;
pybind11::int_ offset;
};
@ -629,7 +653,7 @@ private:
continue;
}
field_descriptors.push_back(
{(PYBIND11_STR_TYPE) name, format.strip_padding(format.itemsize()), offset});
{(pybind11::str) name, format.strip_padding(format.itemsize()), offset});
}
std::sort(field_descriptors.begin(),
@ -640,9 +664,9 @@ private:
list names, formats, offsets;
for (auto &descr : field_descriptors) {
names.append(descr.name);
formats.append(descr.format);
offsets.append(descr.offset);
names.append(std::move(descr.name));
formats.append(std::move(descr.format));
offsets.append(std::move(descr.offset));
}
return dtype(std::move(names), std::move(formats), std::move(offsets), itemsize);
}
@ -940,7 +964,7 @@ protected:
void fail_dim_check(ssize_t dim, const std::string &msg) const {
throw index_error(msg + ": " + std::to_string(dim) + " (ndim = " + std::to_string(ndim())
+ ")");
+ ')');
}
template <typename... Ix>
@ -1144,11 +1168,11 @@ struct format_descriptor<T, detail::enable_if_t<detail::is_pod_struct<T>::value>
template <size_t N>
struct format_descriptor<char[N]> {
static std::string format() { return std::to_string(N) + "s"; }
static std::string format() { return std::to_string(N) + 's'; }
};
template <size_t N>
struct format_descriptor<std::array<char, N>> {
static std::string format() { return std::to_string(N) + "s"; }
static std::string format() { return std::to_string(N) + 's'; }
};
template <typename T>
@ -1288,7 +1312,8 @@ public:
static pybind11::dtype dtype() {
list shape;
array_info<T>::append_extents(shape);
return pybind11::dtype::from_args(pybind11::make_tuple(base_descr::dtype(), shape));
return pybind11::dtype::from_args(
pybind11::make_tuple(base_descr::dtype(), std::move(shape)));
}
};
@ -1334,7 +1359,7 @@ PYBIND11_NOINLINE void register_structured_dtype(any_container<field_descriptor>
pybind11_fail(std::string("NumPy: unsupported field dtype: `") + field.name + "` @ "
+ tinfo.name());
}
names.append(PYBIND11_STR_TYPE(field.name));
names.append(pybind11::str(field.name));
formats.append(field.descr);
offsets.append(pybind11::int_(field.offset));
}
@ -1526,7 +1551,7 @@ public:
void *data() const { return p_ptr; }
private:
char *p_ptr{0};
char *p_ptr{nullptr};
container_type m_strides;
};

View File

@ -561,14 +561,14 @@ protected:
for (auto *it = chain_start; it != nullptr; it = it->next) {
if (options::show_function_signatures()) {
if (index > 0) {
signatures += "\n";
signatures += '\n';
}
if (chain) {
signatures += std::to_string(++index) + ". ";
}
signatures += rec->name;
signatures += it->signature;
signatures += "\n";
signatures += '\n';
}
if (it->doc && it->doc[0] != '\0' && options::show_user_defined_docstrings()) {
// If we're appending another docstring, and aren't printing function signatures,
@ -577,15 +577,15 @@ protected:
if (first_user_def) {
first_user_def = false;
} else {
signatures += "\n";
signatures += '\n';
}
}
if (options::show_function_signatures()) {
signatures += "\n";
signatures += '\n';
}
signatures += it->doc;
if (options::show_function_signatures()) {
signatures += "\n";
signatures += '\n';
}
}
}
@ -1055,7 +1055,7 @@ protected:
msg += it2->signature;
}
msg += "\n";
msg += '\n';
}
msg += "\nInvoked with: ";
auto args_ = reinterpret_borrow<tuple>(args_in);
@ -1817,7 +1817,8 @@ private:
if (holder_ptr) {
init_holder_from_existing(v_h, holder_ptr, std::is_copy_constructible<holder_type>());
v_h.set_holder_constructed();
} else if (inst->owned || detail::always_construct_holder<holder_type>::value) {
} else if (PYBIND11_SILENCE_MSVC_C4127(detail::always_construct_holder<holder_type>::value)
|| inst->owned) {
new (std::addressof(v_h.holder<holder_type>())) holder_type(v_h.value_ptr<type>());
v_h.set_holder_constructed();
}
@ -2402,7 +2403,8 @@ template <return_value_policy Policy = return_value_policy::reference_internal,
typename Type,
typename... Extra>
iterator make_iterator(Type &value, Extra &&...extra) {
return make_iterator<Policy>(std::begin(value), std::end(value), extra...);
return make_iterator<Policy>(
std::begin(value), std::end(value), std::forward<Extra>(extra)...);
}
/// Makes an iterator over the keys (`.first`) of a stl map-like container supporting
@ -2411,7 +2413,8 @@ template <return_value_policy Policy = return_value_policy::reference_internal,
typename Type,
typename... Extra>
iterator make_key_iterator(Type &value, Extra &&...extra) {
return make_key_iterator<Policy>(std::begin(value), std::end(value), extra...);
return make_key_iterator<Policy>(
std::begin(value), std::end(value), std::forward<Extra>(extra)...);
}
/// Makes an iterator over the values (`.second`) of a stl map-like container supporting
@ -2420,7 +2423,8 @@ template <return_value_policy Policy = return_value_policy::reference_internal,
typename Type,
typename... Extra>
iterator make_value_iterator(Type &value, Extra &&...extra) {
return make_value_iterator<Policy>(std::begin(value), std::end(value), extra...);
return make_value_iterator<Policy>(
std::begin(value), std::end(value), std::forward<Extra>(extra)...);
}
template <typename InputType, typename OutputType>
@ -2485,7 +2489,7 @@ public:
exception(handle scope, const char *name, handle base = PyExc_Exception) {
std::string full_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)) {
pybind11_fail("Error during initialization: multiple incompatible "
"definitions with name \""
@ -2694,9 +2698,9 @@ get_type_override(const void *this_ptr, const type_info *this_type, const char *
d.ptr());
if (result == nullptr)
throw error_already_set();
Py_DECREF(result);
if (d["self"].is_none())
return function();
Py_DECREF(result);
#endif
return override;

View File

@ -270,10 +270,7 @@ public:
/// Copy constructor; always increases the reference count
object(const object &o) : handle(o) { inc_ref(); }
/// Move constructor; steals the object from ``other`` and preserves its reference count
object(object &&other) noexcept {
m_ptr = other.m_ptr;
other.m_ptr = nullptr;
}
object(object &&other) noexcept : handle(other) { other.m_ptr = nullptr; }
/// Destructor; automatically calls `handle::dec_ref()`
~object() { dec_ref(); }
@ -636,13 +633,13 @@ inline handle get_function(handle value) {
inline PyObject *dict_getitemstring(PyObject *v, const char *key) {
PyObject *kv = nullptr, *rv = nullptr;
kv = PyUnicode_FromString(key);
if (kv == NULL) {
if (kv == nullptr) {
throw error_already_set();
}
rv = PyDict_GetItemWithError(v, kv);
Py_DECREF(kv);
if (rv == NULL && PyErr_Occurred()) {
if (rv == nullptr && PyErr_Occurred()) {
throw error_already_set();
}
return rv;
@ -650,7 +647,7 @@ inline PyObject *dict_getitemstring(PyObject *v, const char *key) {
inline PyObject *dict_getitem(PyObject *v, PyObject *key) {
PyObject *rv = PyDict_GetItemWithError(v, key);
if (rv == NULL && PyErr_Occurred()) {
if (rv == nullptr && PyErr_Occurred()) {
throw error_already_set();
}
return rv;
@ -1071,12 +1068,12 @@ public:
Name(const object &o) \
: Parent(check_(o) ? o.inc_ref().ptr() : ConvertFun(o.ptr()), stolen_t{}) { \
if (!m_ptr) \
throw error_already_set(); \
throw ::pybind11::error_already_set(); \
} \
/* NOLINTNEXTLINE(google-explicit-constructor) */ \
Name(object &&o) : Parent(check_(o) ? o.release().ptr() : ConvertFun(o.ptr()), stolen_t{}) { \
if (!m_ptr) \
throw error_already_set(); \
throw ::pybind11::error_already_set(); \
}
#define PYBIND11_OBJECT_CVT_DEFAULT(Name, Parent, CheckFun, ConvertFun) \
@ -1276,8 +1273,8 @@ public:
}
char *buffer = nullptr;
ssize_t length = 0;
if (PYBIND11_BYTES_AS_STRING_AND_SIZE(temp.ptr(), &buffer, &length)) {
pybind11_fail("Unable to extract string contents! (invalid type)");
if (PyBytes_AsStringAndSize(temp.ptr(), &buffer, &length) != 0) {
throw error_already_set();
}
return std::string(buffer, (size_t) length);
}
@ -1332,14 +1329,7 @@ public:
explicit bytes(const pybind11::str &s);
// NOLINTNEXTLINE(google-explicit-constructor)
operator std::string() const {
char *buffer = nullptr;
ssize_t length = 0;
if (PYBIND11_BYTES_AS_STRING_AND_SIZE(m_ptr, &buffer, &length)) {
pybind11_fail("Unable to extract bytes contents!");
}
return std::string(buffer, (size_t) length);
}
operator std::string() const { return string_op<std::string>(); }
#ifdef PYBIND11_HAS_STRING_VIEW
// enable_if is needed to avoid "ambiguous conversion" errors (see PR #3521).
@ -1351,15 +1341,18 @@ public:
// valid so long as the `bytes` instance remains alive and so generally should not outlive the
// lifetime of the `bytes` instance.
// NOLINTNEXTLINE(google-explicit-constructor)
operator std::string_view() const {
operator std::string_view() const { return string_op<std::string_view>(); }
#endif
private:
template <typename T>
T string_op() const {
char *buffer = nullptr;
ssize_t length = 0;
if (PYBIND11_BYTES_AS_STRING_AND_SIZE(m_ptr, &buffer, &length)) {
pybind11_fail("Unable to extract bytes contents!");
if (PyBytes_AsStringAndSize(m_ptr, &buffer, &length) != 0) {
throw error_already_set();
}
return {buffer, static_cast<size_t>(length)};
}
#endif
};
// Note: breathe >= 4.17.0 will fail to build docs if the below two constructors
// are included in the doxygen group; close here and reopen after as a workaround
@ -1370,13 +1363,13 @@ inline bytes::bytes(const pybind11::str &s) {
if (PyUnicode_Check(s.ptr())) {
temp = reinterpret_steal<object>(PyUnicode_AsUTF8String(s.ptr()));
if (!temp) {
pybind11_fail("Unable to extract string contents! (encoding issue)");
throw error_already_set();
}
}
char *buffer = nullptr;
ssize_t length = 0;
if (PYBIND11_BYTES_AS_STRING_AND_SIZE(temp.ptr(), &buffer, &length)) {
pybind11_fail("Unable to extract string contents! (invalid type)");
if (PyBytes_AsStringAndSize(temp.ptr(), &buffer, &length) != 0) {
throw error_already_set();
}
auto obj = reinterpret_steal<object>(PYBIND11_BYTES_FROM_STRING_AND_SIZE(buffer, length));
if (!obj) {
@ -1388,8 +1381,8 @@ inline bytes::bytes(const pybind11::str &s) {
inline str::str(const bytes &b) {
char *buffer = nullptr;
ssize_t length = 0;
if (PYBIND11_BYTES_AS_STRING_AND_SIZE(b.ptr(), &buffer, &length)) {
pybind11_fail("Unable to extract bytes contents!");
if (PyBytes_AsStringAndSize(b.ptr(), &buffer, &length) != 0) {
throw error_already_set();
}
auto obj = reinterpret_steal<object>(PyUnicode_FromStringAndSize(buffer, length));
if (!obj) {
@ -1556,8 +1549,8 @@ private:
class slice : public object {
public:
PYBIND11_OBJECT_DEFAULT(slice, object, PySlice_Check)
slice(handle start, handle stop, handle step) {
m_ptr = PySlice_New(start.ptr(), stop.ptr(), step.ptr());
slice(handle start, handle stop, handle step)
: object(PySlice_New(start.ptr(), stop.ptr(), step.ptr()), stolen_t{}) {
if (!m_ptr) {
pybind11_fail("Could not allocate slice object!");
}
@ -1607,7 +1600,7 @@ public:
void (*destructor)(PyObject *) = nullptr)
: object(PyCapsule_New(const_cast<void *>(value), name, destructor), stolen_t{}) {
if (!m_ptr) {
pybind11_fail("Could not allocate capsule object!");
throw error_already_set();
}
}
@ -1615,34 +1608,44 @@ public:
capsule(const void *value, void (*destruct)(PyObject *))
: object(PyCapsule_New(const_cast<void *>(value), nullptr, destruct), stolen_t{}) {
if (!m_ptr) {
pybind11_fail("Could not allocate capsule object!");
throw error_already_set();
}
}
capsule(const void *value, void (*destructor)(void *)) {
m_ptr = PyCapsule_New(const_cast<void *>(value), nullptr, [](PyObject *o) {
auto destructor = reinterpret_cast<void (*)(void *)>(PyCapsule_GetContext(o));
void *ptr = PyCapsule_GetPointer(o, nullptr);
if (destructor == nullptr) {
if (PyErr_Occurred()) {
throw error_already_set();
}
pybind11_fail("Unable to get capsule context");
}
const char *name = get_name_in_error_scope(o);
void *ptr = PyCapsule_GetPointer(o, name);
if (ptr == nullptr) {
throw error_already_set();
}
destructor(ptr);
});
if (!m_ptr) {
pybind11_fail("Could not allocate capsule object!");
}
if (PyCapsule_SetContext(m_ptr, (void *) destructor) != 0) {
pybind11_fail("Could not set capsule context!");
if (!m_ptr || PyCapsule_SetContext(m_ptr, (void *) destructor) != 0) {
throw error_already_set();
}
}
explicit capsule(void (*destructor)()) {
m_ptr = PyCapsule_New(reinterpret_cast<void *>(destructor), nullptr, [](PyObject *o) {
auto destructor = reinterpret_cast<void (*)()>(PyCapsule_GetPointer(o, nullptr));
const char *name = get_name_in_error_scope(o);
auto destructor = reinterpret_cast<void (*)()>(PyCapsule_GetPointer(o, name));
if (destructor == nullptr) {
throw error_already_set();
}
destructor();
});
if (!m_ptr) {
pybind11_fail("Could not allocate capsule object!");
throw error_already_set();
}
}
@ -1657,8 +1660,7 @@ public:
const auto *name = this->name();
T *result = static_cast<T *>(PyCapsule_GetPointer(m_ptr, name));
if (!result) {
PyErr_Clear();
pybind11_fail("Unable to extract capsule contents!");
throw error_already_set();
}
return result;
}
@ -1666,12 +1668,37 @@ public:
/// Replaces a capsule's pointer *without* calling the destructor on the existing one.
void set_pointer(const void *value) {
if (PyCapsule_SetPointer(m_ptr, const_cast<void *>(value)) != 0) {
PyErr_Clear();
pybind11_fail("Could not set capsule pointer");
throw error_already_set();
}
}
const char *name() const { return PyCapsule_GetName(m_ptr); }
const char *name() const {
const char *name = PyCapsule_GetName(m_ptr);
if ((name == nullptr) && PyErr_Occurred()) {
throw error_already_set();
}
return name;
}
/// Replaces a capsule's name *without* calling the destructor on the existing one.
void set_name(const char *new_name) {
if (PyCapsule_SetName(m_ptr, new_name) != 0) {
throw error_already_set();
}
}
private:
static const char *get_name_in_error_scope(PyObject *o) {
error_scope error_guard;
const char *name = PyCapsule_GetName(o);
if ((name == nullptr) && PyErr_Occurred()) {
// write out and consume error raised by call to PyCapsule_GetName
PyErr_WriteUnraisable(o);
}
return name;
}
};
class tuple : public object {
@ -1920,8 +1947,8 @@ public:
return memoryview::from_buffer(reinterpret_cast<void *>(ptr),
sizeof(T),
format_descriptor<T>::value,
shape,
strides,
std::move(shape),
std::move(strides),
readonly);
}
@ -1929,7 +1956,8 @@ public:
static memoryview from_buffer(const T *ptr,
detail::any_container<ssize_t> shape,
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

View File

@ -79,7 +79,7 @@ struct set_caster {
for (auto &&value : src) {
auto value_ = reinterpret_steal<object>(
key_conv::cast(forward_like<T>(value), policy, parent));
if (!value_ || !s.add(value_)) {
if (!value_ || !s.add(std::move(value_))) {
return handle();
}
}
@ -372,7 +372,7 @@ struct variant_caster<V<Ts...>> {
bool load_alternative(handle src, bool convert, type_list<U, Us...>) {
auto caster = make_caster<U>();
if (caster.load(src, convert)) {
value = cast_op<U>(caster);
value = cast_op<U>(std::move(caster));
return true;
}
return load_alternative(src, convert, type_list<Us...>{});
@ -406,6 +406,9 @@ struct variant_caster<V<Ts...>> {
#if defined(PYBIND11_HAS_VARIANT)
template <typename... Ts>
struct type_caster<std::variant<Ts...>> : variant_caster<std::variant<Ts...>> {};
template <>
struct type_caster<std::monostate> : public void_caster<std::monostate> {};
#endif
PYBIND11_NAMESPACE_END(detail)

View File

@ -13,21 +13,28 @@
#include <string>
#ifdef __has_include
# if defined(PYBIND11_CPP17) && __has_include(<filesystem>)
# if defined(PYBIND11_CPP17)
# if __has_include(<filesystem>) && \
PY_VERSION_HEX >= 0x03060000
# include <filesystem>
# define PYBIND11_HAS_FILESYSTEM 1
# elif __has_include(<experimental/filesystem>)
# include <experimental/filesystem>
# define PYBIND11_HAS_EXPERIMENTAL_FILESYSTEM 1
# endif
# endif
#endif
#if !defined(PYBIND11_HAS_FILESYSTEM) && !defined(PYBIND11_HAS_FILESYSTEM_IS_OPTIONAL)
#if !defined(PYBIND11_HAS_FILESYSTEM) && !defined(PYBIND11_HAS_EXPERIMENTAL_FILESYSTEM) \
&& !defined(PYBIND11_HAS_FILESYSTEM_IS_OPTIONAL)
# error \
"#include <filesystem> is not available. (Use -DPYBIND11_HAS_FILESYSTEM_IS_OPTIONAL to ignore.)"
"Neither #include <filesystem> nor #include <experimental/filesystem is available. (Use -DPYBIND11_HAS_FILESYSTEM_IS_OPTIONAL to ignore.)"
#endif
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
PYBIND11_NAMESPACE_BEGIN(detail)
#if defined(PYBIND11_HAS_FILESYSTEM)
#if defined(PYBIND11_HAS_FILESYSTEM) || defined(PYBIND11_HAS_EXPERIMENTAL_FILESYSTEM)
template <typename T>
struct path_caster {
@ -94,9 +101,16 @@ public:
PYBIND11_TYPE_CASTER(T, const_name("os.PathLike"));
};
#endif // PYBIND11_HAS_FILESYSTEM || defined(PYBIND11_HAS_EXPERIMENTAL_FILESYSTEM)
#if defined(PYBIND11_HAS_FILESYSTEM)
template <>
struct type_caster<std::filesystem::path> : public path_caster<std::filesystem::path> {};
#endif // PYBIND11_HAS_FILESYSTEM
#elif defined(PYBIND11_HAS_EXPERIMENTAL_FILESYSTEM)
template <>
struct type_caster<std::experimental::filesystem::path>
: public path_caster<std::experimental::filesystem::path> {};
#endif
PYBIND11_NAMESPACE_END(detail)
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)

View File

@ -232,7 +232,7 @@ void vector_modifiers(
/// Slicing protocol
cl.def(
"__getitem__",
[](const Vector &v, slice slice) -> Vector * {
[](const Vector &v, const slice &slice) -> Vector * {
size_t start = 0, stop = 0, step = 0, slicelength = 0;
if (!slice.compute(v.size(), &start, &stop, &step, &slicelength)) {
@ -253,7 +253,7 @@ void vector_modifiers(
cl.def(
"__setitem__",
[](Vector &v, slice slice, const Vector &value) {
[](Vector &v, const slice &slice, const Vector &value) {
size_t start = 0, stop = 0, step = 0, slicelength = 0;
if (!slice.compute(v.size(), &start, &stop, &step, &slicelength)) {
throw error_already_set();
@ -281,7 +281,7 @@ void vector_modifiers(
cl.def(
"__delitem__",
[](Vector &v, slice slice) {
[](Vector &v, const slice &slice) {
size_t start = 0, stop = 0, step = 0, slicelength = 0;
if (!slice.compute(v.size(), &start, &stop, &step, &slicelength)) {

View File

@ -24,8 +24,10 @@ profile = "black"
[tool.mypy]
files = ["pybind11"]
python_version = "3.6"
warn_unused_configs = true
strict = true
show_error_codes = true
enable_error_code = ["ignore-without-code", "redundant-expr", "truthy-bool"]
warn_unreachable = true
[[tool.mypy.overrides]]
module = ["ghapi.*", "setuptools.*"]

View File

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

View File

@ -289,8 +289,9 @@ py::list test_dtype_ctors() {
dict["itemsize"] = py::int_(20);
list.append(py::dtype::from_args(dict));
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 *) 0, 0, "T{i:a:f:b:}", 1)));
list.append(py::dtype(py::buffer_info((void *) nullptr, sizeof(unsigned int), "I", 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_));
return list;
}
@ -440,6 +441,34 @@ TEST_SUBMODULE(numpy_dtypes, m) {
}
return list;
});
m.def("test_dtype_num", [dtype_names]() {
py::list list;
for (const auto &dt_name : dtype_names) {
list.append(py::dtype(dt_name).num());
}
return list;
});
m.def("test_dtype_byteorder", [dtype_names]() {
py::list list;
for (const auto &dt_name : dtype_names) {
list.append(py::dtype(dt_name).byteorder());
}
return list;
});
m.def("test_dtype_alignment", [dtype_names]() {
py::list list;
for (const auto &dt_name : dtype_names) {
list.append(py::dtype(dt_name).alignment());
}
return list;
});
m.def("test_dtype_flags", [dtype_names]() {
py::list list;
for (const auto &dt_name : dtype_names) {
list.append(py::dtype(dt_name).flags());
}
return list;
});
m.def("test_dtype_methods", []() {
py::list list;
auto dt1 = py::dtype::of<int32_t>();
@ -581,5 +610,5 @@ TEST_SUBMODULE(numpy_dtypes, m) {
[]() { PYBIND11_NUMPY_DTYPE(SimpleStruct, bool_, uint_, float_, ldbl_); });
// 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

@ -160,6 +160,7 @@ def test_dtype(simple_dtype):
d1,
np.dtype("uint32"),
d2,
np.dtype("d"),
]
assert m.test_dtype_methods() == [
@ -175,8 +176,13 @@ def test_dtype(simple_dtype):
np.zeros(1, m.trailing_padding_dtype())
)
expected_chars = "bhilqBHILQefdgFDG?MmO"
assert m.test_dtype_kind() == list("iiiiiuuuuuffffcccbMmO")
assert m.test_dtype_char_() == list("bhilqBHILQefdgFDG?MmO")
assert m.test_dtype_char_() == list(expected_chars)
assert m.test_dtype_num() == [np.dtype(ch).num for ch in expected_chars]
assert m.test_dtype_byteorder() == [np.dtype(ch).byteorder for ch in expected_chars]
assert m.test_dtype_alignment() == [np.dtype(ch).alignment for ch in expected_chars]
assert m.test_dtype_flags() == [chr(np.dtype(ch).flags) for ch in expected_chars]
def test_recarray(simple_dtype, packed_dtype):

View File

@ -11,6 +11,34 @@
#include <utility>
namespace external {
namespace detail {
bool check(PyObject *o) { return PyFloat_Check(o) != 0; }
PyObject *conv(PyObject *o) {
PyObject *ret = nullptr;
if (PyLong_Check(o)) {
double v = PyLong_AsDouble(o);
if (!(v == -1.0 && PyErr_Occurred())) {
ret = PyFloat_FromDouble(v);
}
} else {
PyErr_SetString(PyExc_TypeError, "Unexpected type");
}
return ret;
}
PyObject *default_constructed() { return PyFloat_FromDouble(0.0); }
} // namespace detail
class float_ : public py::object {
PYBIND11_OBJECT_CVT(float_, py::object, external::detail::check, external::detail::conv)
float_() : py::object(external::detail::default_constructed(), stolen_t{}) {}
double get_value() const { return PyFloat_AsDouble(this->ptr()); }
};
} // namespace external
TEST_SUBMODULE(pytypes, m) {
// test_bool
m.def("get_bool", [] { return py::bool_(false); });
@ -131,6 +159,15 @@ TEST_SUBMODULE(pytypes, m) {
return py::capsule([]() { py::print("destructing capsule"); });
});
m.def("return_renamed_capsule_with_destructor", []() {
py::print("creating capsule");
auto cap = py::capsule([]() { py::print("destructing capsule"); });
static const char *capsule_name = "test_name1";
py::print("renaming capsule");
cap.set_name(capsule_name);
return cap;
});
m.def("return_capsule_with_destructor_2", []() {
py::print("creating capsule");
return py::capsule((void *) 1234, [](void *ptr) {
@ -138,6 +175,17 @@ TEST_SUBMODULE(pytypes, m) {
});
});
m.def("return_renamed_capsule_with_destructor_2", []() {
py::print("creating capsule");
auto cap = py::capsule((void *) 1234, [](void *ptr) {
py::print("destructing capsule: {}"_s.format((size_t) ptr));
});
static const char *capsule_name = "test_name2";
py::print("renaming capsule");
cap.set_name(capsule_name);
return cap;
});
m.def("return_capsule_with_name_and_destructor", []() {
auto capsule = py::capsule((void *) 12345, "pointer type description", [](PyObject *ptr) {
if (ptr) {
@ -545,4 +593,9 @@ TEST_SUBMODULE(pytypes, m) {
py::detail::accessor_policies::tuple_item::set(o, (py::size_t) 0, s0);
return o;
});
m.def("square_float_", [](const external::float_ &x) -> double {
double v = x.get_value();
return v * v;
});
}

View File

@ -195,6 +195,19 @@ def test_capsule(capture):
"""
)
with capture:
a = m.return_renamed_capsule_with_destructor()
del a
pytest.gc_collect()
assert (
capture.unordered
== """
creating capsule
renaming capsule
destructing capsule
"""
)
with capture:
a = m.return_capsule_with_destructor_2()
del a
@ -207,6 +220,19 @@ def test_capsule(capture):
"""
)
with capture:
a = m.return_renamed_capsule_with_destructor_2()
del a
pytest.gc_collect()
assert (
capture.unordered
== """
creating capsule
renaming capsule
destructing capsule: 1234
"""
)
with capture:
a = m.return_capsule_with_name_and_destructor()
del a
@ -634,3 +660,8 @@ def test_implementation_details():
assert m.tuple_item_set_ssize_t() == ("emely", "edmond")
assert m.tuple_item_get_size_t(tup) == 93
assert m.tuple_item_set_size_t() == ("candy", "cat")
def test_external_float_():
r1 = m.square_float_(2.0)
assert r1 == 4.0

View File

@ -37,9 +37,10 @@ struct type_caster<boost::none_t> : void_caster<boost::none_t> {};
// Test with `std::variant` in C++17 mode, or with `boost::variant` in C++11/14
#if defined(PYBIND11_HAS_VARIANT)
using std::variant;
# define PYBIND11_TEST_VARIANT 1
#elif defined(PYBIND11_TEST_BOOST)
# include <boost/variant.hpp>
# define PYBIND11_HAS_VARIANT 1
# define PYBIND11_TEST_VARIANT 1
using boost::variant;
namespace pybind11 {
@ -424,7 +425,7 @@ TEST_SUBMODULE(stl, m) {
m.def("parent_path", [](const std::filesystem::path &p) { return p.parent_path(); });
#endif
#ifdef PYBIND11_HAS_VARIANT
#ifdef PYBIND11_TEST_VARIANT
static_assert(std::is_same<py::detail::variant_caster_visitor::result_type, py::handle>::value,
"visitor::result_type is required by boost::variant in C++11 mode");
@ -435,6 +436,9 @@ TEST_SUBMODULE(stl, m) {
result_type operator()(const std::string &) { return "std::string"; }
result_type operator()(double) { return "double"; }
result_type operator()(std::nullptr_t) { return "std::nullptr_t"; }
# if defined(PYBIND11_HAS_VARIANT)
result_type operator()(std::monostate) { return "std::monostate"; }
# endif
};
// test_variant
@ -448,6 +452,18 @@ TEST_SUBMODULE(stl, m) {
using V = variant<int, std::string>;
return py::make_tuple(V(5), V("Hello"));
});
# if defined(PYBIND11_HAS_VARIANT)
// std::monostate tests.
m.def("load_monostate_variant",
[](const variant<std::monostate, int, std::string> &v) -> const char * {
return py::detail::visit_helper<variant>::call(visitor(), v);
});
m.def("cast_monostate_variant", []() {
using V = variant<std::monostate, int, std::string>;
return py::make_tuple(V{}, V(5), V("Hello"));
});
# endif
#endif
// #528: templated constructor

View File

@ -263,6 +263,22 @@ def test_variant(doc):
)
@pytest.mark.skipif(
not hasattr(m, "load_monostate_variant"), reason="no std::monostate"
)
def test_variant_monostate(doc):
assert m.load_monostate_variant(None) == "std::monostate"
assert m.load_monostate_variant(1) == "int"
assert m.load_monostate_variant("1") == "std::string"
assert m.cast_monostate_variant() == (None, 5, "Hello")
assert (
doc(m.load_monostate_variant)
== "load_monostate_variant(arg0: Union[None, int, str]) -> str"
)
def test_vec_of_reference_wrapper():
"""#171: Can't return reference wrappers (or STL structures containing them)"""
assert (