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-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

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

View File

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

View File

@ -15,7 +15,7 @@
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.1.0" rev: "v4.2.0"
hooks: hooks:
- id: check-added-large-files - id: check-added-large-files
- id: check-case-conflict - id: check-case-conflict
@ -32,7 +32,7 @@ repos:
# Upgrade old Python syntax # Upgrade old Python syntax
- repo: https://github.com/asottile/pyupgrade - repo: https://github.com/asottile/pyupgrade
rev: "v2.31.0" rev: "v2.32.0"
hooks: hooks:
- id: pyupgrade - id: pyupgrade
args: [--py36-plus] args: [--py36-plus]
@ -45,7 +45,7 @@ repos:
# Black, the code formatter, natively supports pre-commit # Black, the code formatter, natively supports pre-commit
- repo: https://github.com/psf/black - 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: hooks:
- id: black - id: black
@ -55,7 +55,7 @@ repos:
hooks: hooks:
- id: blacken-docs - id: blacken-docs
additional_dependencies: 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 # Changes tabs to spaces
- repo: https://github.com/Lucas-C/pre-commit-hooks - repo: https://github.com/Lucas-C/pre-commit-hooks
@ -64,16 +64,17 @@ repos:
- id: remove-tabs - id: remove-tabs
- repo: https://github.com/sirosen/texthooks - repo: https://github.com/sirosen/texthooks
rev: "0.2.2" rev: "0.3.1"
hooks: hooks:
- id: fix-ligatures - id: fix-ligatures
- id: fix-smartquotes - id: fix-smartquotes
# Autoremoves unused imports # Autoremoves unused imports
- repo: https://github.com/hadialqattan/pycln - repo: https://github.com/hadialqattan/pycln
rev: "v1.2.4" rev: "v1.3.1"
hooks: hooks:
- id: pycln - id: pycln
stages: [manual]
# Checking for common mistakes # Checking for common mistakes
- repo: https://github.com/pre-commit/pygrep-hooks - repo: https://github.com/pre-commit/pygrep-hooks
@ -106,7 +107,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.12.2" rev: "v2.13.5"
hooks: hooks:
- id: pylint - id: pylint
files: ^pybind11 files: ^pybind11
@ -122,16 +123,16 @@ 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.931" rev: "v0.942"
hooks: hooks:
- id: mypy - id: mypy
args: [--show-error-codes] args: []
exclude: ^(tests|docs)/ exclude: ^(tests|docs)/
additional_dependencies: [nox, rich] additional_dependencies: [nox, rich]
# 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.47" rev: "0.48"
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
@ -163,7 +164,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

@ -87,7 +87,7 @@ buffer objects (e.g. a NumPy matrix).
/* Request a buffer descriptor from Python */ /* Request a buffer descriptor from Python */
py::buffer_info info = b.request(); py::buffer_info info = b.request();
/* Some sanity checks ... */ /* Some basic validation checks ... */
if (info.format != py::format_descriptor<Scalar>::format()) if (info.format != py::format_descriptor<Scalar>::format())
throw std::runtime_error("Incompatible format: expected a double array!"); 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 Starting with version 1.8.0, pybind11 releases use a `semantic versioning
<http://semver.org>`_ policy. <http://semver.org>`_ policy.
Changes will be added here periodically from the "Suggested changelog entry"
block in pull request descriptions.
IN DEVELOPMENT 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) 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) target_link_libraries(example PRIVATE pybind11::module pybind11::lto pybind11::windows_extras)
pybind11_extension(example) pybind11_extension(example)
pybind11_strip(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" set_target_properties(example PROPERTIES CXX_VISIBILITY_PRESET "hidden"
CUDA_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> template <typename CharT>
struct type_caster<CharT, enable_if_t<is_std_char_type<CharT>::value>> { struct type_caster<CharT, enable_if_t<is_std_char_type<CharT>::value>> {
using StringType = std::basic_string<CharT>; using StringType = std::basic_string<CharT>;
using StringCaster = type_caster<StringType>; using StringCaster = make_caster<StringType>;
StringCaster str_caster; StringCaster str_caster;
bool none = false; bool none = false;
CharT one_char = 0; 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 // 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. // that only does anything in cases where pybind11::cast is valid.
template <typename T> 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 &&) { enable_if_t<cast_is_temporary_value_reference<T>::value, T> cast_safe(object &&) {
pybind11_fail("Internal error: cast_safe fallback invoked"); pybind11_fail("Internal error: cast_safe fallback invoked");
} }
template <> template <typename T>
inline void cast_safe<void>(object &&) {} 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) PYBIND11_NAMESPACE_END(detail)
@ -1243,8 +1246,8 @@ struct arg_v : arg {
private: private:
template <typename T> template <typename T>
arg_v(arg &&base, T &&x, const char *descr = nullptr) arg_v(arg &&base, T &&x, const char *descr = nullptr)
: arg(base), value(reinterpret_steal<object>( : arg(base), value(reinterpret_steal<object>(detail::make_caster<T>::cast(
detail::make_caster<T>::cast(x, return_value_policy::automatic, {}))), std::forward<T>(x), return_value_policy::automatic, {}))),
descr(descr) descr(descr)
#if !defined(NDEBUG) #if !defined(NDEBUG)
, ,
@ -1491,7 +1494,7 @@ private:
type_id<T>()); type_id<T>());
#endif #endif
} }
args_list.append(o); args_list.append(std::move(o));
} }
void process(list &args_list, detail::args_proxy ap) { void process(list &args_list, detail::args_proxy ap) {

View File

@ -992,6 +992,8 @@ constexpr const char
struct error_scope { struct error_scope {
PyObject *type, *value, *trace; PyObject *type, *value, *trace;
error_scope() { PyErr_Fetch(&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); } ~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) { if (throw_if_missing) {
std::string tname = tp.name(); std::string tname = tp.name();
detail::clean_type_id(tname); 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; 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), Type::Flags &(Eigen::RowMajor | Eigen::ColMajor),
StorageIndex>(shape[0].cast<Index>(), StorageIndex>(shape[0].cast<Index>(),
shape[1].cast<Index>(), shape[1].cast<Index>(),
nnz, std::move(nnz),
outerIndices.mutable_data(), outerIndices.mutable_data(),
innerIndices.mutable_data(), innerIndices.mutable_data(),
values.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 outerIndices((rowMajor ? src.rows() : src.cols()) + 1, src.outerIndexPtr());
array innerIndices(src.nonZeros(), src.innerIndexPtr()); 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())) std::make_pair(src.rows(), src.cols()))
.release(); .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()) { object eval(const char (&s)[N], object global = globals(), object local = object()) {
/* Support raw string literals by removing common leading whitespace */ /* Support raw string literals by removing common leading whitespace */
auto expr = (s[0] == '\n') ? str(module_::import("textwrap").attr("dedent")(s)) : str(s); 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()) { 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> template <size_t N>
void exec(const char (&s)[N], object global = globals(), object local = object()) { 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) #if defined(PYPY_VERSION)

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);
@ -540,18 +540,18 @@ public:
PYBIND11_OBJECT_DEFAULT(dtype, object, detail::npy_api::get().PyArrayDescr_Check_); PYBIND11_OBJECT_DEFAULT(dtype, object, detail::npy_api::get().PyArrayDescr_Check_);
explicit dtype(const buffer_info &info) { 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 // If info.itemsize == 0, use the value calculated from the format string
m_ptr = descr.strip_padding(info.itemsize != 0 ? info.itemsize : descr.itemsize()) m_ptr = descr.strip_padding(info.itemsize != 0 ? info.itemsize : descr.itemsize())
.release() .release()
.ptr(); .ptr();
} }
explicit dtype(const std::string &format) { explicit dtype(const pybind11::str &format) : dtype(from_args(format)) {}
m_ptr = from_args(pybind11::str(format)).release().ptr();
}
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) { dtype(list names, list formats, list offsets, ssize_t itemsize) {
dict args; dict args;
@ -559,11 +559,18 @@ 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)
: 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. /// 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();
@ -596,6 +603,23 @@ public:
return detail::array_descriptor_proxy(m_ptr)->type; 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: private:
static object _dtype_from_pep3118() { static object _dtype_from_pep3118() {
static PyObject *obj = module_::import("numpy.core._internal") static PyObject *obj = module_::import("numpy.core._internal")
@ -614,7 +638,7 @@ private:
} }
struct field_descr { struct field_descr {
PYBIND11_STR_TYPE name; pybind11::str name;
object format; object format;
pybind11::int_ offset; pybind11::int_ offset;
}; };
@ -629,7 +653,7 @@ private:
continue; continue;
} }
field_descriptors.push_back( 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(), std::sort(field_descriptors.begin(),
@ -640,9 +664,9 @@ private:
list names, formats, offsets; list names, formats, offsets;
for (auto &descr : field_descriptors) { for (auto &descr : field_descriptors) {
names.append(descr.name); names.append(std::move(descr.name));
formats.append(descr.format); formats.append(std::move(descr.format));
offsets.append(descr.offset); offsets.append(std::move(descr.offset));
} }
return dtype(std::move(names), std::move(formats), std::move(offsets), itemsize); 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 { 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()) throw index_error(msg + ": " + std::to_string(dim) + " (ndim = " + std::to_string(ndim())
+ ")"); + ')');
} }
template <typename... Ix> 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> template <size_t N>
struct format_descriptor<char[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> template <size_t N>
struct format_descriptor<std::array<char, 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> template <typename T>
@ -1288,7 +1312,8 @@ public:
static pybind11::dtype dtype() { static pybind11::dtype dtype() {
list shape; list shape;
array_info<T>::append_extents(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 + "` @ " pybind11_fail(std::string("NumPy: unsupported field dtype: `") + field.name + "` @ "
+ tinfo.name()); + tinfo.name());
} }
names.append(PYBIND11_STR_TYPE(field.name)); names.append(pybind11::str(field.name));
formats.append(field.descr); formats.append(field.descr);
offsets.append(pybind11::int_(field.offset)); offsets.append(pybind11::int_(field.offset));
} }
@ -1526,7 +1551,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

@ -561,14 +561,14 @@ protected:
for (auto *it = chain_start; it != nullptr; it = it->next) { for (auto *it = chain_start; it != nullptr; it = it->next) {
if (options::show_function_signatures()) { if (options::show_function_signatures()) {
if (index > 0) { if (index > 0) {
signatures += "\n"; signatures += '\n';
} }
if (chain) { if (chain) {
signatures += std::to_string(++index) + ". "; signatures += std::to_string(++index) + ". ";
} }
signatures += rec->name; signatures += rec->name;
signatures += it->signature; signatures += it->signature;
signatures += "\n"; signatures += '\n';
} }
if (it->doc && it->doc[0] != '\0' && options::show_user_defined_docstrings()) { if (it->doc && it->doc[0] != '\0' && options::show_user_defined_docstrings()) {
// If we're appending another docstring, and aren't printing function signatures, // If we're appending another docstring, and aren't printing function signatures,
@ -577,15 +577,15 @@ protected:
if (first_user_def) { if (first_user_def) {
first_user_def = false; first_user_def = false;
} else { } else {
signatures += "\n"; signatures += '\n';
} }
} }
if (options::show_function_signatures()) { if (options::show_function_signatures()) {
signatures += "\n"; signatures += '\n';
} }
signatures += it->doc; signatures += it->doc;
if (options::show_function_signatures()) { if (options::show_function_signatures()) {
signatures += "\n"; signatures += '\n';
} }
} }
} }
@ -1055,7 +1055,7 @@ protected:
msg += it2->signature; msg += it2->signature;
} }
msg += "\n"; msg += '\n';
} }
msg += "\nInvoked with: "; msg += "\nInvoked with: ";
auto args_ = reinterpret_borrow<tuple>(args_in); auto args_ = reinterpret_borrow<tuple>(args_in);
@ -1817,7 +1817,8 @@ private:
if (holder_ptr) { if (holder_ptr) {
init_holder_from_existing(v_h, holder_ptr, std::is_copy_constructible<holder_type>()); init_holder_from_existing(v_h, holder_ptr, std::is_copy_constructible<holder_type>());
v_h.set_holder_constructed(); 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>()); new (std::addressof(v_h.holder<holder_type>())) holder_type(v_h.value_ptr<type>());
v_h.set_holder_constructed(); v_h.set_holder_constructed();
} }
@ -2402,7 +2403,8 @@ template <return_value_policy Policy = return_value_policy::reference_internal,
typename Type, typename Type,
typename... Extra> typename... Extra>
iterator make_iterator(Type &value, Extra &&...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 /// 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 Type,
typename... Extra> typename... Extra>
iterator make_key_iterator(Type &value, Extra &&...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 /// 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 Type,
typename... Extra> typename... Extra>
iterator make_value_iterator(Type &value, Extra &&...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> template <typename InputType, typename OutputType>
@ -2485,7 +2489,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 \""
@ -2694,9 +2698,9 @@ get_type_override(const void *this_ptr, const type_info *this_type, const char *
d.ptr()); d.ptr());
if (result == nullptr) if (result == nullptr)
throw error_already_set(); throw error_already_set();
Py_DECREF(result);
if (d["self"].is_none()) if (d["self"].is_none())
return function(); return function();
Py_DECREF(result);
#endif #endif
return override; return override;

View File

@ -270,10 +270,7 @@ public:
/// Copy constructor; always increases the reference count /// Copy constructor; always increases the reference count
object(const object &o) : handle(o) { inc_ref(); } object(const object &o) : handle(o) { inc_ref(); }
/// Move constructor; steals the object from ``other`` and preserves its reference count /// Move constructor; steals the object from ``other`` and preserves its reference count
object(object &&other) noexcept { object(object &&other) noexcept : handle(other) { other.m_ptr = nullptr; }
m_ptr = other.m_ptr;
other.m_ptr = nullptr;
}
/// Destructor; automatically calls `handle::dec_ref()` /// Destructor; automatically calls `handle::dec_ref()`
~object() { dec_ref(); } ~object() { dec_ref(); }
@ -636,13 +633,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;
@ -650,7 +647,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;
@ -1071,12 +1068,12 @@ public:
Name(const object &o) \ Name(const object &o) \
: Parent(check_(o) ? o.inc_ref().ptr() : ConvertFun(o.ptr()), stolen_t{}) { \ : Parent(check_(o) ? o.inc_ref().ptr() : ConvertFun(o.ptr()), stolen_t{}) { \
if (!m_ptr) \ if (!m_ptr) \
throw error_already_set(); \ throw ::pybind11::error_already_set(); \
} \ } \
/* NOLINTNEXTLINE(google-explicit-constructor) */ \ /* NOLINTNEXTLINE(google-explicit-constructor) */ \
Name(object &&o) : Parent(check_(o) ? o.release().ptr() : ConvertFun(o.ptr()), stolen_t{}) { \ Name(object &&o) : Parent(check_(o) ? o.release().ptr() : ConvertFun(o.ptr()), stolen_t{}) { \
if (!m_ptr) \ if (!m_ptr) \
throw error_already_set(); \ throw ::pybind11::error_already_set(); \
} }
#define PYBIND11_OBJECT_CVT_DEFAULT(Name, Parent, CheckFun, ConvertFun) \ #define PYBIND11_OBJECT_CVT_DEFAULT(Name, Parent, CheckFun, ConvertFun) \
@ -1276,8 +1273,8 @@ public:
} }
char *buffer = nullptr; char *buffer = nullptr;
ssize_t length = 0; ssize_t length = 0;
if (PYBIND11_BYTES_AS_STRING_AND_SIZE(temp.ptr(), &buffer, &length)) { if (PyBytes_AsStringAndSize(temp.ptr(), &buffer, &length) != 0) {
pybind11_fail("Unable to extract string contents! (invalid type)"); throw error_already_set();
} }
return std::string(buffer, (size_t) length); return std::string(buffer, (size_t) length);
} }
@ -1332,14 +1329,7 @@ public:
explicit bytes(const pybind11::str &s); explicit bytes(const pybind11::str &s);
// NOLINTNEXTLINE(google-explicit-constructor) // NOLINTNEXTLINE(google-explicit-constructor)
operator std::string() const { operator std::string() const { return string_op<std::string>(); }
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);
}
#ifdef PYBIND11_HAS_STRING_VIEW #ifdef PYBIND11_HAS_STRING_VIEW
// enable_if is needed to avoid "ambiguous conversion" errors (see PR #3521). // 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 // valid so long as the `bytes` instance remains alive and so generally should not outlive the
// lifetime of the `bytes` instance. // lifetime of the `bytes` instance.
// NOLINTNEXTLINE(google-explicit-constructor) // 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; char *buffer = nullptr;
ssize_t length = 0; ssize_t length = 0;
if (PYBIND11_BYTES_AS_STRING_AND_SIZE(m_ptr, &buffer, &length)) { if (PyBytes_AsStringAndSize(m_ptr, &buffer, &length) != 0) {
pybind11_fail("Unable to extract bytes contents!"); throw error_already_set();
} }
return {buffer, static_cast<size_t>(length)}; return {buffer, static_cast<size_t>(length)};
} }
#endif
}; };
// Note: breathe >= 4.17.0 will fail to build docs if the below two constructors // 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 // 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())) { if (PyUnicode_Check(s.ptr())) {
temp = reinterpret_steal<object>(PyUnicode_AsUTF8String(s.ptr())); temp = reinterpret_steal<object>(PyUnicode_AsUTF8String(s.ptr()));
if (!temp) { if (!temp) {
pybind11_fail("Unable to extract string contents! (encoding issue)"); throw error_already_set();
} }
} }
char *buffer = nullptr; char *buffer = nullptr;
ssize_t length = 0; ssize_t length = 0;
if (PYBIND11_BYTES_AS_STRING_AND_SIZE(temp.ptr(), &buffer, &length)) { if (PyBytes_AsStringAndSize(temp.ptr(), &buffer, &length) != 0) {
pybind11_fail("Unable to extract string contents! (invalid type)"); throw error_already_set();
} }
auto obj = reinterpret_steal<object>(PYBIND11_BYTES_FROM_STRING_AND_SIZE(buffer, length)); auto obj = reinterpret_steal<object>(PYBIND11_BYTES_FROM_STRING_AND_SIZE(buffer, length));
if (!obj) { if (!obj) {
@ -1388,8 +1381,8 @@ inline bytes::bytes(const pybind11::str &s) {
inline str::str(const bytes &b) { inline str::str(const bytes &b) {
char *buffer = nullptr; char *buffer = nullptr;
ssize_t length = 0; ssize_t length = 0;
if (PYBIND11_BYTES_AS_STRING_AND_SIZE(b.ptr(), &buffer, &length)) { if (PyBytes_AsStringAndSize(b.ptr(), &buffer, &length) != 0) {
pybind11_fail("Unable to extract bytes contents!"); throw error_already_set();
} }
auto obj = reinterpret_steal<object>(PyUnicode_FromStringAndSize(buffer, length)); auto obj = reinterpret_steal<object>(PyUnicode_FromStringAndSize(buffer, length));
if (!obj) { if (!obj) {
@ -1556,8 +1549,8 @@ private:
class slice : public object { class slice : public object {
public: public:
PYBIND11_OBJECT_DEFAULT(slice, object, PySlice_Check) PYBIND11_OBJECT_DEFAULT(slice, object, PySlice_Check)
slice(handle start, handle stop, handle step) { slice(handle start, handle stop, handle step)
m_ptr = PySlice_New(start.ptr(), stop.ptr(), step.ptr()); : object(PySlice_New(start.ptr(), stop.ptr(), step.ptr()), stolen_t{}) {
if (!m_ptr) { if (!m_ptr) {
pybind11_fail("Could not allocate slice object!"); pybind11_fail("Could not allocate slice object!");
} }
@ -1607,7 +1600,7 @@ public:
void (*destructor)(PyObject *) = nullptr) void (*destructor)(PyObject *) = nullptr)
: object(PyCapsule_New(const_cast<void *>(value), name, destructor), stolen_t{}) { : object(PyCapsule_New(const_cast<void *>(value), name, destructor), stolen_t{}) {
if (!m_ptr) { 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 *)) capsule(const void *value, void (*destruct)(PyObject *))
: object(PyCapsule_New(const_cast<void *>(value), nullptr, destruct), stolen_t{}) { : object(PyCapsule_New(const_cast<void *>(value), nullptr, destruct), stolen_t{}) {
if (!m_ptr) { if (!m_ptr) {
pybind11_fail("Could not allocate capsule object!"); throw error_already_set();
} }
} }
capsule(const void *value, void (*destructor)(void *)) { capsule(const void *value, void (*destructor)(void *)) {
m_ptr = PyCapsule_New(const_cast<void *>(value), nullptr, [](PyObject *o) { m_ptr = PyCapsule_New(const_cast<void *>(value), nullptr, [](PyObject *o) {
auto destructor = reinterpret_cast<void (*)(void *)>(PyCapsule_GetContext(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); destructor(ptr);
}); });
if (!m_ptr) { if (!m_ptr || PyCapsule_SetContext(m_ptr, (void *) destructor) != 0) {
pybind11_fail("Could not allocate capsule object!"); throw error_already_set();
}
if (PyCapsule_SetContext(m_ptr, (void *) destructor) != 0) {
pybind11_fail("Could not set capsule context!");
} }
} }
explicit capsule(void (*destructor)()) { explicit capsule(void (*destructor)()) {
m_ptr = PyCapsule_New(reinterpret_cast<void *>(destructor), nullptr, [](PyObject *o) { 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(); destructor();
}); });
if (!m_ptr) { if (!m_ptr) {
pybind11_fail("Could not allocate capsule object!"); throw error_already_set();
} }
} }
@ -1657,8 +1660,7 @@ public:
const auto *name = this->name(); const auto *name = this->name();
T *result = static_cast<T *>(PyCapsule_GetPointer(m_ptr, name)); T *result = static_cast<T *>(PyCapsule_GetPointer(m_ptr, name));
if (!result) { if (!result) {
PyErr_Clear(); throw error_already_set();
pybind11_fail("Unable to extract capsule contents!");
} }
return result; return result;
} }
@ -1666,12 +1668,37 @@ public:
/// Replaces a capsule's pointer *without* calling the destructor on the existing one. /// Replaces a capsule's pointer *without* calling the destructor on the existing one.
void set_pointer(const void *value) { void set_pointer(const void *value) {
if (PyCapsule_SetPointer(m_ptr, const_cast<void *>(value)) != 0) { if (PyCapsule_SetPointer(m_ptr, const_cast<void *>(value)) != 0) {
PyErr_Clear(); throw error_already_set();
pybind11_fail("Could not set capsule pointer");
} }
} }
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 { class tuple : public object {
@ -1920,8 +1947,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);
} }
@ -1929,7 +1956,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

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

View File

@ -13,21 +13,28 @@
#include <string> #include <string>
#ifdef __has_include #ifdef __has_include
# if defined(PYBIND11_CPP17) && __has_include(<filesystem>) # if defined(PYBIND11_CPP17)
# include <filesystem> # if __has_include(<filesystem>) && \
# define PYBIND11_HAS_FILESYSTEM 1 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
#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 \ # 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 #endif
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
PYBIND11_NAMESPACE_BEGIN(detail) PYBIND11_NAMESPACE_BEGIN(detail)
#if defined(PYBIND11_HAS_FILESYSTEM) #if defined(PYBIND11_HAS_FILESYSTEM) || defined(PYBIND11_HAS_EXPERIMENTAL_FILESYSTEM)
template <typename T> template <typename T>
struct path_caster { struct path_caster {
@ -94,9 +101,16 @@ public:
PYBIND11_TYPE_CASTER(T, const_name("os.PathLike")); PYBIND11_TYPE_CASTER(T, const_name("os.PathLike"));
}; };
#endif // PYBIND11_HAS_FILESYSTEM || defined(PYBIND11_HAS_EXPERIMENTAL_FILESYSTEM)
#if defined(PYBIND11_HAS_FILESYSTEM)
template <> template <>
struct type_caster<std::filesystem::path> : public path_caster<std::filesystem::path> {}; 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(detail)
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE) PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)

View File

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

View File

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

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

@ -289,8 +289,9 @@ 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_));
return list; return list;
} }
@ -440,6 +441,34 @@ TEST_SUBMODULE(numpy_dtypes, m) {
} }
return list; 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", []() { m.def("test_dtype_methods", []() {
py::list list; py::list list;
auto dt1 = py::dtype::of<int32_t>(); auto dt1 = py::dtype::of<int32_t>();
@ -581,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

@ -160,6 +160,7 @@ def test_dtype(simple_dtype):
d1, d1,
np.dtype("uint32"), np.dtype("uint32"),
d2, d2,
np.dtype("d"),
] ]
assert m.test_dtype_methods() == [ assert m.test_dtype_methods() == [
@ -175,8 +176,13 @@ def test_dtype(simple_dtype):
np.zeros(1, m.trailing_padding_dtype()) np.zeros(1, m.trailing_padding_dtype())
) )
expected_chars = "bhilqBHILQefdgFDG?MmO"
assert m.test_dtype_kind() == list("iiiiiuuuuuffffcccbMmO") 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): def test_recarray(simple_dtype, packed_dtype):

View File

@ -11,6 +11,34 @@
#include <utility> #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_SUBMODULE(pytypes, m) {
// test_bool // test_bool
m.def("get_bool", [] { return py::bool_(false); }); m.def("get_bool", [] { return py::bool_(false); });
@ -131,6 +159,15 @@ TEST_SUBMODULE(pytypes, m) {
return py::capsule([]() { py::print("destructing capsule"); }); 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", []() { m.def("return_capsule_with_destructor_2", []() {
py::print("creating capsule"); py::print("creating capsule");
return py::capsule((void *) 1234, [](void *ptr) { 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", []() { m.def("return_capsule_with_name_and_destructor", []() {
auto capsule = py::capsule((void *) 12345, "pointer type description", [](PyObject *ptr) { auto capsule = py::capsule((void *) 12345, "pointer type description", [](PyObject *ptr) {
if (ptr) { if (ptr) {
@ -545,4 +593,9 @@ TEST_SUBMODULE(pytypes, m) {
py::detail::accessor_policies::tuple_item::set(o, (py::size_t) 0, s0); py::detail::accessor_policies::tuple_item::set(o, (py::size_t) 0, s0);
return o; 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: with capture:
a = m.return_capsule_with_destructor_2() a = m.return_capsule_with_destructor_2()
del a 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: with capture:
a = m.return_capsule_with_name_and_destructor() a = m.return_capsule_with_name_and_destructor()
del a del a
@ -634,3 +660,8 @@ def test_implementation_details():
assert m.tuple_item_set_ssize_t() == ("emely", "edmond") assert m.tuple_item_set_ssize_t() == ("emely", "edmond")
assert m.tuple_item_get_size_t(tup) == 93 assert m.tuple_item_get_size_t(tup) == 93
assert m.tuple_item_set_size_t() == ("candy", "cat") 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 // Test with `std::variant` in C++17 mode, or with `boost::variant` in C++11/14
#if defined(PYBIND11_HAS_VARIANT) #if defined(PYBIND11_HAS_VARIANT)
using std::variant; using std::variant;
# define PYBIND11_TEST_VARIANT 1
#elif defined(PYBIND11_TEST_BOOST) #elif defined(PYBIND11_TEST_BOOST)
# include <boost/variant.hpp> # include <boost/variant.hpp>
# define PYBIND11_HAS_VARIANT 1 # define PYBIND11_TEST_VARIANT 1
using boost::variant; using boost::variant;
namespace pybind11 { namespace pybind11 {
@ -424,7 +425,7 @@ TEST_SUBMODULE(stl, m) {
m.def("parent_path", [](const std::filesystem::path &p) { return p.parent_path(); }); m.def("parent_path", [](const std::filesystem::path &p) { return p.parent_path(); });
#endif #endif
#ifdef PYBIND11_HAS_VARIANT #ifdef PYBIND11_TEST_VARIANT
static_assert(std::is_same<py::detail::variant_caster_visitor::result_type, py::handle>::value, 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"); "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()(const std::string &) { return "std::string"; }
result_type operator()(double) { return "double"; } result_type operator()(double) { return "double"; }
result_type operator()(std::nullptr_t) { return "std::nullptr_t"; } 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 // test_variant
@ -448,6 +452,18 @@ TEST_SUBMODULE(stl, m) {
using V = variant<int, std::string>; using V = variant<int, std::string>;
return py::make_tuple(V(5), V("Hello")); 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 #endif
// #528: templated constructor // #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(): def test_vec_of_reference_wrapper():
"""#171: Can't return reference wrappers (or STL structures containing them)""" """#171: Can't return reference wrappers (or STL structures containing them)"""
assert ( assert (