Merge branch 'master' into sh_merge_master

This commit is contained in:
Ralf W. Grosse-Kunstleve 2022-07-09 21:47:49 -07:00
commit 27ce64fc43
24 changed files with 333 additions and 97 deletions

View File

@ -5,7 +5,3 @@ updates:
directory: "/" directory: "/"
schedule: schedule:
interval: "daily" interval: "daily"
ignore:
# Official actions have moving tags like v1
- dependency-name: "actions/*"
update-types: ["version-update:semver-minor", "version-update:semver-patch"]

View File

@ -31,6 +31,7 @@ jobs:
- '3.6' - '3.6'
- '3.9' - '3.9'
- '3.10' - '3.10'
- '3.11-dev'
- 'pypy-3.7' - 'pypy-3.7'
- 'pypy-3.8' - 'pypy-3.8'
- 'pypy-3.9' - 'pypy-3.9'
@ -66,7 +67,7 @@ jobs:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- name: Setup Python ${{ matrix.python }} - name: Setup Python ${{ matrix.python }}
uses: actions/setup-python@v3 uses: actions/setup-python@v4
with: with:
python-version: ${{ matrix.python }} python-version: ${{ matrix.python }}
@ -186,8 +187,8 @@ jobs:
- python-version: "3.9" - python-version: "3.9"
python-debug: true python-debug: true
valgrind: true valgrind: true
# - python-version: "3.11-dev" - python-version: "3.11-dev"
# python-debug: false python-debug: false
name: "🐍 ${{ matrix.python-version }}${{ matrix.python-debug && '-dbg' || '' }} (deadsnakes)${{ matrix.valgrind && ' • Valgrind' || '' }} • x64" name: "🐍 ${{ matrix.python-version }}${{ matrix.python-debug && '-dbg' || '' }} (deadsnakes)${{ matrix.valgrind && ' • Valgrind' || '' }} • x64"
runs-on: ubuntu-latest runs-on: ubuntu-latest
@ -687,7 +688,9 @@ jobs:
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- uses: actions/setup-python@v3 - uses: actions/setup-python@v4
with:
python-version: "3.x"
- name: Install Doxygen - name: Install Doxygen
run: sudo apt-get install -y doxygen librsvg2-bin # Changed to rsvg-convert in 20.04 run: sudo apt-get install -y doxygen librsvg2-bin # Changed to rsvg-convert in 20.04
@ -735,7 +738,7 @@ jobs:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- name: Setup Python ${{ matrix.python }} - name: Setup Python ${{ matrix.python }}
uses: actions/setup-python@v3 uses: actions/setup-python@v4
with: with:
python-version: ${{ matrix.python }} python-version: ${{ matrix.python }}
architecture: x86 architecture: x86
@ -788,7 +791,7 @@ jobs:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- name: Setup Python ${{ matrix.python }} - name: Setup Python ${{ matrix.python }}
uses: actions/setup-python@v3 uses: actions/setup-python@v4
with: with:
python-version: ${{ matrix.python }} python-version: ${{ matrix.python }}
architecture: x86 architecture: x86
@ -836,7 +839,7 @@ jobs:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- name: Setup Python ${{ matrix.python }} - name: Setup Python ${{ matrix.python }}
uses: actions/setup-python@v3 uses: actions/setup-python@v4
with: with:
python-version: ${{ matrix.python }} python-version: ${{ matrix.python }}

View File

@ -41,7 +41,7 @@ jobs:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- name: Setup Python 3.7 - name: Setup Python 3.7
uses: actions/setup-python@v3 uses: actions/setup-python@v4
with: with:
python-version: 3.7 python-version: 3.7
architecture: ${{ matrix.arch }} architecture: ${{ matrix.arch }}

View File

@ -22,7 +22,9 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- uses: actions/setup-python@v3 - uses: actions/setup-python@v4
with:
python-version: "3.x"
- name: Add matchers - name: Add matchers
run: echo "::add-matcher::$GITHUB_WORKSPACE/.github/matchers/pylint.json" run: echo "::add-matcher::$GITHUB_WORKSPACE/.github/matchers/pylint.json"
- uses: pre-commit/action@v3.0.0 - uses: pre-commit/action@v3.0.0

View File

@ -28,7 +28,7 @@ jobs:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- name: Setup 🐍 3.6 - name: Setup 🐍 3.6
uses: actions/setup-python@v3 uses: actions/setup-python@v4
with: with:
python-version: 3.6 python-version: 3.6
@ -50,7 +50,7 @@ jobs:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- name: Setup 🐍 3.8 - name: Setup 🐍 3.8
uses: actions/setup-python@v3 uses: actions/setup-python@v4
with: with:
python-version: 3.8 python-version: 3.8
@ -91,7 +91,9 @@ jobs:
needs: [packaging] needs: [packaging]
steps: steps:
- uses: actions/setup-python@v3 - uses: actions/setup-python@v4
with:
python-version: "3.x"
# Downloads all to directories matching the artifact names # Downloads all to directories matching the artifact names
- uses: actions/download-artifact@v3 - uses: actions/download-artifact@v3

View File

@ -14,7 +14,7 @@ env:
jobs: jobs:
standard: standard:
name: "🐍 3.11 dev • ubuntu-latest • x64" name: "🐍 3.11 latest internals • ubuntu-latest • x64"
runs-on: ubuntu-latest runs-on: ubuntu-latest
if: "contains(github.event.pull_request.labels.*.name, 'python dev')" if: "contains(github.event.pull_request.labels.*.name, 'python dev')"
@ -22,7 +22,7 @@ jobs:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- name: Setup Python 3.11 - name: Setup Python 3.11
uses: actions/setup-python@v3 uses: actions/setup-python@v4
with: with:
python-version: "3.11-dev" python-version: "3.11-dev"

View File

@ -46,7 +46,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.3.0" # Keep in sync with blacken-docs rev: "22.6.0" # Keep in sync with blacken-docs
hooks: hooks:
- id: black - id: black
@ -56,11 +56,11 @@ repos:
hooks: hooks:
- id: blacken-docs - id: blacken-docs
additional_dependencies: additional_dependencies:
- black==22.3.0 # keep in sync with black hook - black==22.6.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
rev: "v1.2.0" rev: "v1.3.0"
hooks: hooks:
- id: remove-tabs - id: remove-tabs
exclude: (^docs/.*|\.patch)?$ exclude: (^docs/.*|\.patch)?$
@ -110,7 +110,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.14.3" rev: "v2.14.4"
hooks: hooks:
- id: pylint - id: pylint
files: ^pybind11 files: ^pybind11
@ -167,7 +167,7 @@ repos:
# Clang format the codebase automatically # Clang format the codebase automatically
- repo: https://github.com/pre-commit/mirrors-clang-format - repo: https://github.com/pre-commit/mirrors-clang-format
rev: "v14.0.5" rev: "v14.0.6"
hooks: hooks:
- id: clang-format - id: clang-format
types_or: [c++, c, cuda] types_or: [c++, c, cuda]

View File

@ -14,44 +14,164 @@ IN DEVELOPMENT
Removed support for Python 2.7, Python 3.5, and MSVC 2015. Support for MSVC 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 2017 is limited due to availability of CI runners; we highly recommend MSVC
2019 or 2022 be used. 2019 or 2022 be used. Initial support added for Python 3.11.
New features: New features:
* ``py::anyset`` & ``py::frozenset`` were added, with copying (cast) to
``std::set`` (similar to ``set``).
`#3901 <https://github.com/pybind/pybind11/pull/3901>`_
* Support bytearray casting to string.
`#3707 <https://github.com/pybind/pybind11/pull/3707>`_
* ``type_caster<std::monostate>`` was added. ``std::monostate`` is a tag type * ``type_caster<std::monostate>`` was added. ``std::monostate`` is a tag type
that allows ``std::variant`` to act as an optional, or allows default that allows ``std::variant`` to act as an optional, or allows default
construction of a ``std::variant`` holding a non-default constructible type. construction of a ``std::variant`` holding a non-default constructible type.
`#3818 <https://github.com/pybind/pybind11/pull/3818>`_ `#3818 <https://github.com/pybind/pybind11/pull/3818>`_
* Support bytearray casting to string. * ``pybind11::capsule::set_name`` added to mutate the name of the capsule instance.
`#3707 <https://github.com/pybind/pybind11/pull/3707>`_ `#3866 <https://github.com/pybind/pybind11/pull/3866>`_
* NumPy: dtype constructor from type number added, accessors corresponding to
Python API ``dtype.num``, ``dtype.byteorder``, ``dtype.flags`` and
``dtype.alignment`` added.
`#3868 <https://github.com/pybind/pybind11/pull/3868>`_
Changes: Changes:
* Python 2 support was removed completely. * Python 3.6 is now the minimum supported version.
`#3688 <https://github.com/pybind/pybind11/pull/3688>`_ `#3688 <https://github.com/pybind/pybind11/pull/3688>`_
`#3719 <https://github.com/pybind/pybind11/pull/3719>`_
* The minimum version for MSVC is now 2017. * The minimum version for MSVC is now 2017.
`#3722 <https://github.com/pybind/pybind11/pull/3722>`_ `#3722 <https://github.com/pybind/pybind11/pull/3722>`_
* Fix issues with CPython 3.11 betas and add to supported test matrix.
`#3923 <https://github.com/pybind/pybind11/pull/3923>`_
* ``error_already_set`` is now safer and more performant, especially for
exceptions with long tracebacks, by delaying computation.
`#1895 <https://github.com/pybind/pybind11/pull/1895>`_
* Improve exception handling in python ``str`` bindings. * Improve exception handling in python ``str`` bindings.
`#3826 <https://github.com/pybind/pybind11/pull/3826>`_ `#3826 <https://github.com/pybind/pybind11/pull/3826>`_
* The bindings for capsules now have more consistent exception handling. * The bindings for capsules now have more consistent exception handling.
`#3825 <https://github.com/pybind/pybind11/pull/3825>`_ `#3825 <https://github.com/pybind/pybind11/pull/3825>`_
* Fix exception handling when ``pybind11::weakref()`` fails. * ``PYBIND11_OBJECT_CVT`` and ``PYBIND11_OBJECT_CVT_DEFAULT`` macro can now be
`#3739 <https://github.com/pybind/pybind11/pull/3739>`_ used to define classes in namespaces other than pybind11.
`#3797 <https://github.com/pybind/pybind11/pull/3797>`_
* Error printing code now uses ``PYBIND11_DETAILED_ERROR_MESSAGES`` instead of
requiring ``NDEBUG``, allowing use with release builds if desired.
`#3913 <https://github.com/pybind/pybind11/pull/3913>`_
Bug fixes: Bug fixes:
* ``PYBIND11_OBJECT_CVT`` and ``PYBIND11_OBJECT_CVT_DEFAULT`` macro can be used * Fix exception handling when ``pybind11::weakref()`` fails.
to define classes in namespaces other than pybind11. `#3739 <https://github.com/pybind/pybind11/pull/3739>`_
`#3797 <https://github.com/pybind/pybind11/pull/3797>`_
* ``module_::def_submodule`` was missing proper error handling. This is fixed now.
`#3973 <https://github.com/pybind/pybind11/pull/3973>`_
* The behavior or ``error_already_set`` was made safer and the highly opaque
"Unknown internal error occurred" message was replaced with a more helpful
message.
`#3982 <https://github.com/pybind/pybind11/pull/3982>`_
* ``error_already_set::what()`` now handles non-normalized exceptions correctly.
`#3971 <https://github.com/pybind/pybind11/pull/3971>`_
* Support older C++ compilers where filesystem is not yet part of the standard
library and is instead included in ``std::experimental::filesystem``.
`#3840 <https://github.com/pybind/pybind11/pull/3840>`_
* Fix ``-Wfree-nonheap-object`` warnings produced by GCC by avoiding returning
pointers to static objects with ``return_value_policy::take_ownership``.
`#3946 <https://github.com/pybind/pybind11/pull/3946>`_
* Fix cast from pytype rvalue to another pytype.
`#3949 <https://github.com/pybind/pybind11/pull/3949>`_
* ``pybind11::detail::get_internals()`` is now resilient to in-flight Python
exceptions.
`#3981 <https://github.com/pybind/pybind11/pull/3981>`_
* Arrays with a dimension of size 0 are now properly converted to dynamic Eigen
matrices (more common in NumPy 1.23).
`#4038 <https://github.com/pybind/pybind11/pull/4038>`_
* Avoid catching unrelated errors when importing NumPy.
`#3974 <https://github.com/pybind/pybind11/pull/3974>`_
Performance and style:
* Added an accessor overload of ``(object &&key)`` to reference steal the
object when using python types as keys. This prevents unnecessary reference
count overhead for attr, dictionary, tuple, and sequence look ups. Added
additional regression tests. Fixed a performance bug the caused accessor
assignments to potentially perform unnecessary copies.
`#3970 <https://github.com/pybind/pybind11/pull/3970>`_
* Perfect forward all args of ``make_iterator``.
`#3980 <https://github.com/pybind/pybind11/pull/3980>`_
* Avoid potential bug in pycapsule destructor by adding an ``error_guard`` to
one of the dtors.
`#3958 <https://github.com/pybind/pybind11/pull/3958>`_
* Optimize dictionary access in ``strip_padding`` for numpy.
`#3994 <https://github.com/pybind/pybind11/pull/3994>`_
* ``stl_bind.h`` bindings now take slice args as a const-ref.
`#3852 <https://github.com/pybind/pybind11/pull/3852>`_
* Made slice constructor more consistent, and improve performance of some
casters by allowing reference stealing.
`#3845 <https://github.com/pybind/pybind11/pull/3845>`_
* Change numpy dtype from_args method to use const ref.
`#3878 <https://github.com/pybind/pybind11/pull/3878>`_
* Follow rule of three to ensure ``PyErr_Restore`` is called only once.
`#3872 <https://github.com/pybind/pybind11/pull/3872>`_
* Added missing perfect forwarding for ``make_iterator`` functions.
`#3860 <https://github.com/pybind/pybind11/pull/3860>`_
* Optimize c++ to python function casting by using the rvalue caster.
`#3966 <https://github.com/pybind/pybind11/pull/3966>`_
* Avoid potential implicit copy/assignment constructors causing double free in
``strdup_gaurd``.
`#3905 <https://github.com/pybind/pybind11/pull/3905>`_
* Enable clang-tidy checks ``misc-definitions-in-headers``,
``modernize-loop-convert``, and ``modernize-use-nullptr``.
`#3881 <https://github.com/pybind/pybind11/pull/3881>`_
`#3988 <https://github.com/pybind/pybind11/pull/3988>`_
Build system improvements: Build system improvements:
* CMake: Fix file extension on Windows with cp36 and cp37 using FindPython.
`#3919 <https://github.com/pybind/pybind11/pull/3919>`_
* CMake: Support multiple Python targets (such as on vcpkg).
`#3948 <https://github.com/pybind/pybind11/pull/3948>`_
* CMake: Fix issue with NVCC on Windows.
`#3947 <https://github.com/pybind/pybind11/pull/3947>`_
* CMake: Drop the bitness check on cross compiles (like targeting WebAssembly
via Emscripten).
`#3959 <https://github.com/pybind/pybind11/pull/3959>`_
* Add MSVC builds in debug mode to CI. * Add MSVC builds in debug mode to CI.
`#3784 <https://github.com/pybind/pybind11/pull/3784>`_ `#3784 <https://github.com/pybind/pybind11/pull/3784>`_
@ -59,15 +179,20 @@ Build system improvements:
`#3732 <https://github.com/pybind/pybind11/pull/3732>`_, `#3732 <https://github.com/pybind/pybind11/pull/3732>`_,
`#3741 <https://github.com/pybind/pybind11/pull/3741>`_ `#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: Backend and tidying up:
* Remove idioms in code comments. Use inclusive language. * Remove idioms in code comments. Use more inclusive language.
`#3809 <https://github.com/pybind/pybind11/pull/3809>`_ `#3809 <https://github.com/pybind/pybind11/pull/3809>`_
* ``#include <iostream>`` was removed from the ``pybind11/stl.h`` header. Your
project may break if it has a transitive dependency on this include. The fix
is to "Include What You Use".
`#3928 <https://github.com/pybind/pybind11/pull/3928>`_
* Avoid ``setup.py <command>`` usage in internal tests.
`#3734 <https://github.com/pybind/pybind11/pull/3734>`_
Version 2.9.2 (Mar 29, 2022) Version 2.9.2 (Mar 29, 2022)
---------------------------- ----------------------------

View File

@ -482,7 +482,7 @@ The binding code for this example looks as follows:
.value("Cat", Pet::Kind::Cat) .value("Cat", Pet::Kind::Cat)
.export_values(); .export_values();
py::class_<Pet::Attributes> attributes(pet, "Attributes") py::class_<Pet::Attributes>(pet, "Attributes")
.def(py::init<>()) .def(py::init<>())
.def_readwrite("age", &Pet::Attributes::age); .def_readwrite("age", &Pet::Attributes::age);

View File

@ -345,9 +345,11 @@ struct type_record {
bases.append((PyObject *) base_info->type); bases.append((PyObject *) base_info->type);
if (base_info->type->tp_dictoffset != 0) { #if PY_VERSION_HEX < 0x030B0000
dynamic_attr = true; dynamic_attr |= base_info->type->tp_dictoffset != 0;
} #else
dynamic_attr |= (base_info->type->tp_flags & Py_TPFLAGS_MANAGED_DICT) != 0;
#endif
if (caster) { if (caster) {
base_info->implicit_casts.emplace_back(type, caster); base_info->implicit_casts.emplace_back(type, caster);

View File

@ -871,7 +871,7 @@ struct always_construct_holder {
/// Create a specialization for custom holder types (silently ignores std::shared_ptr) /// Create a specialization for custom holder types (silently ignores std::shared_ptr)
#define PYBIND11_DECLARE_HOLDER_TYPE(type, holder_type, ...) \ #define PYBIND11_DECLARE_HOLDER_TYPE(type, holder_type, ...) \
namespace pybind11 { \ PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) \
namespace detail { \ namespace detail { \
template <typename type> \ template <typename type> \
struct always_construct_holder<holder_type> : always_construct_holder<void, ##__VA_ARGS__> { \ struct always_construct_holder<holder_type> : always_construct_holder<void, ##__VA_ARGS__> { \
@ -880,7 +880,7 @@ struct always_construct_holder {
class type_caster<holder_type, enable_if_t<!is_shared_ptr<holder_type>::value>> \ class type_caster<holder_type, enable_if_t<!is_shared_ptr<holder_type>::value>> \
: public type_caster_holder<type, holder_type> {}; \ : public type_caster_holder<type, holder_type> {}; \
} \ } \
} PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
// PYBIND11_DECLARE_HOLDER_TYPE holder types: // PYBIND11_DECLARE_HOLDER_TYPE holder types:
template <typename base, typename holder> template <typename base, typename holder>
@ -1680,12 +1680,12 @@ handle type::handle_of() {
} }
#define PYBIND11_MAKE_OPAQUE(...) \ #define PYBIND11_MAKE_OPAQUE(...) \
namespace pybind11 { \ PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) \
namespace detail { \ namespace detail { \
template <> \ template <> \
class type_caster<__VA_ARGS__> : public type_caster_for_class_<__VA_ARGS__> {}; \ class type_caster<__VA_ARGS__> : public type_caster_for_class_<__VA_ARGS__> {}; \
} \ } \
} PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
/// Lets you pass a type containing a `,` through a macro parameter without needing a separate /// Lets you pass a type containing a `,` through a macro parameter without needing a separate
/// typedef, e.g.: /// typedef, e.g.:

View File

@ -533,6 +533,10 @@ extern "C" inline int pybind11_set_dict(PyObject *self, PyObject *new_dict, void
extern "C" inline int pybind11_traverse(PyObject *self, visitproc visit, void *arg) { extern "C" inline int pybind11_traverse(PyObject *self, visitproc visit, void *arg) {
PyObject *&dict = *_PyObject_GetDictPtr(self); PyObject *&dict = *_PyObject_GetDictPtr(self);
Py_VISIT(dict); Py_VISIT(dict);
// https://docs.python.org/3/c-api/typeobj.html#c.PyTypeObject.tp_traverse
#if PY_VERSION_HEX >= 0x03090000
Py_VISIT(Py_TYPE(self));
#endif
return 0; return 0;
} }
@ -547,8 +551,12 @@ extern "C" inline int pybind11_clear(PyObject *self) {
inline void enable_dynamic_attributes(PyHeapTypeObject *heap_type) { inline void enable_dynamic_attributes(PyHeapTypeObject *heap_type) {
auto *type = &heap_type->ht_type; auto *type = &heap_type->ht_type;
type->tp_flags |= Py_TPFLAGS_HAVE_GC; type->tp_flags |= Py_TPFLAGS_HAVE_GC;
#if PY_VERSION_HEX < 0x030B0000
type->tp_dictoffset = type->tp_basicsize; // place dict at the end type->tp_dictoffset = type->tp_basicsize; // place dict at the end
type->tp_basicsize += (ssize_t) sizeof(PyObject *); // and allocate enough space for it type->tp_basicsize += (ssize_t) sizeof(PyObject *); // and allocate enough space for it
#else
type->tp_flags |= Py_TPFLAGS_MANAGED_DICT;
#endif
type->tp_traverse = pybind11_traverse; type->tp_traverse = pybind11_traverse;
type->tp_clear = pybind11_clear; type->tp_clear = pybind11_clear;

View File

@ -38,6 +38,7 @@
# define PYBIND11_CPP17 # define PYBIND11_CPP17
# if __cplusplus >= 202002L # if __cplusplus >= 202002L
# define PYBIND11_CPP20 # define PYBIND11_CPP20
// Please update tests/pybind11_tests.cpp `cpp_std()` when adding a macro here.
# endif # endif
# endif # endif
# endif # endif

View File

@ -498,4 +498,4 @@ struct pickle_factory<Get, Set, RetState(Self), NewInstance(ArgState)> {
PYBIND11_NAMESPACE_END(initimpl) PYBIND11_NAMESPACE_END(initimpl)
PYBIND11_NAMESPACE_END(detail) PYBIND11_NAMESPACE_END(detail)
PYBIND11_NAMESPACE_END(pybind11) PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)

View File

@ -20,6 +20,7 @@
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
PYBIND11_NAMESPACE_BEGIN(detail) PYBIND11_NAMESPACE_BEGIN(detail)
/// Erase all occurrences of a substring /// Erase all occurrences of a substring
inline void erase_all(std::string &string, const std::string &search) { inline void erase_all(std::string &string, const std::string &search) {
for (size_t pos = 0;;) { for (size_t pos = 0;;) {
@ -46,14 +47,19 @@ PYBIND11_NOINLINE void clean_type_id(std::string &name) {
#endif #endif
detail::erase_all(name, "pybind11::"); detail::erase_all(name, "pybind11::");
} }
inline std::string clean_type_id(const char *typeid_name) {
std::string name(typeid_name);
detail::clean_type_id(name);
return name;
}
PYBIND11_NAMESPACE_END(detail) PYBIND11_NAMESPACE_END(detail)
/// Return a string representation of a C++ type /// Return a string representation of a C++ type
template <typename T> template <typename T>
static std::string type_id() { static std::string type_id() {
std::string name(typeid(T).name()); return detail::clean_type_id(typeid(T).name());
detail::clean_type_id(name);
return name;
} }
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE) PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)

View File

@ -111,10 +111,16 @@ struct EigenConformable {
bool stride_compatible() const { bool stride_compatible() const {
// To have compatible strides, we need (on both dimensions) one of fully dynamic strides, // To have compatible strides, we need (on both dimensions) one of fully dynamic strides,
// matching strides, or a dimension size of 1 (in which case the stride value is // matching strides, or a dimension size of 1 (in which case the stride value is
// irrelevant) // irrelevant). Alternatively, if any dimension size is 0, the strides are not relevant
return !negativestrides // (and numpy ≥ 1.23 sets the strides to 0 in that case, so we need to check explicitly).
&& (props::inner_stride == Eigen::Dynamic || props::inner_stride == stride.inner() if (negativestrides) {
|| (EigenRowMajor ? cols : rows) == 1) return false;
}
if (rows == 0 || cols == 0) {
return true;
}
return (props::inner_stride == Eigen::Dynamic || props::inner_stride == stride.inner()
|| (EigenRowMajor ? cols : rows) == 1)
&& (props::outer_stride == Eigen::Dynamic || props::outer_stride == stride.outer() && (props::outer_stride == Eigen::Dynamic || props::outer_stride == stride.outer()
|| (EigenRowMajor ? rows : cols) == 1); || (EigenRowMajor ? rows : cols) == 1);
} }

View File

@ -86,37 +86,6 @@ inline wchar_t *widen_chars(const char *safe_arg) {
return widened_arg; return widened_arg;
} }
/// Python 2.x/3.x-compatible version of `PySys_SetArgv`
inline void set_interpreter_argv(int argc, const char *const *argv, bool add_program_dir_to_path) {
// Before it was special-cased in python 3.8, passing an empty or null argv
// caused a segfault, so we have to reimplement the special case ourselves.
bool special_case = (argv == nullptr || argc <= 0);
const char *const empty_argv[]{"\0"};
const char *const *safe_argv = special_case ? empty_argv : argv;
if (special_case) {
argc = 1;
}
auto argv_size = static_cast<size_t>(argc);
// SetArgv* on python 3 takes wchar_t, so we have to convert.
std::unique_ptr<wchar_t *[]> widened_argv(new wchar_t *[argv_size]);
std::vector<std::unique_ptr<wchar_t[], wide_char_arg_deleter>> widened_argv_entries;
widened_argv_entries.reserve(argv_size);
for (size_t ii = 0; ii < argv_size; ++ii) {
widened_argv_entries.emplace_back(widen_chars(safe_argv[ii]));
if (!widened_argv_entries.back()) {
// A null here indicates a character-encoding failure or the python
// interpreter out of memory. Give up.
return;
}
widened_argv[ii] = widened_argv_entries.back().get();
}
auto *pysys_argv = widened_argv.get();
PySys_SetArgvEx(argc, pysys_argv, static_cast<int>(add_program_dir_to_path));
}
PYBIND11_NAMESPACE_END(detail) PYBIND11_NAMESPACE_END(detail)
/** \rst /** \rst
@ -146,9 +115,64 @@ inline void initialize_interpreter(bool init_signal_handlers = true,
pybind11_fail("The interpreter is already running"); pybind11_fail("The interpreter is already running");
} }
#if PY_VERSION_HEX < 0x030B0000
Py_InitializeEx(init_signal_handlers ? 1 : 0); Py_InitializeEx(init_signal_handlers ? 1 : 0);
detail::set_interpreter_argv(argc, argv, add_program_dir_to_path); // Before it was special-cased in python 3.8, passing an empty or null argv
// caused a segfault, so we have to reimplement the special case ourselves.
bool special_case = (argv == nullptr || argc <= 0);
const char *const empty_argv[]{"\0"};
const char *const *safe_argv = special_case ? empty_argv : argv;
if (special_case) {
argc = 1;
}
auto argv_size = static_cast<size_t>(argc);
// SetArgv* on python 3 takes wchar_t, so we have to convert.
std::unique_ptr<wchar_t *[]> widened_argv(new wchar_t *[argv_size]);
std::vector<std::unique_ptr<wchar_t[], detail::wide_char_arg_deleter>> widened_argv_entries;
widened_argv_entries.reserve(argv_size);
for (size_t ii = 0; ii < argv_size; ++ii) {
widened_argv_entries.emplace_back(detail::widen_chars(safe_argv[ii]));
if (!widened_argv_entries.back()) {
// A null here indicates a character-encoding failure or the python
// interpreter out of memory. Give up.
return;
}
widened_argv[ii] = widened_argv_entries.back().get();
}
auto *pysys_argv = widened_argv.get();
PySys_SetArgvEx(argc, pysys_argv, static_cast<int>(add_program_dir_to_path));
#else
PyConfig config;
PyConfig_InitIsolatedConfig(&config);
config.install_signal_handlers = init_signal_handlers ? 1 : 0;
PyStatus status = PyConfig_SetBytesArgv(&config, argc, const_cast<char *const *>(argv));
if (PyStatus_Exception(status)) {
// A failure here indicates a character-encoding failure or the python
// interpreter out of memory. Give up.
PyConfig_Clear(&config);
throw std::runtime_error(PyStatus_IsError(status) ? status.err_msg
: "Failed to prepare CPython");
}
status = Py_InitializeFromConfig(&config);
PyConfig_Clear(&config);
if (PyStatus_Exception(status)) {
throw std::runtime_error(PyStatus_IsError(status) ? status.err_msg
: "Failed to init CPython");
}
if (add_program_dir_to_path) {
PyRun_SimpleString("import sys, os.path; "
"sys.path.insert(0, "
"os.path.abspath(os.path.dirname(sys.argv[0])) "
"if sys.argv and os.path.exists(sys.argv[0]) else '')");
}
#endif
} }
/** \rst /** \rst

View File

@ -19,6 +19,7 @@ classifiers =
Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.8
Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.9
Programming Language :: Python :: 3.10 Programming Language :: Python :: 3.10
Programming Language :: Python :: 3.11
License :: OSI Approved :: BSD License License :: OSI Approved :: BSD License
Programming Language :: Python :: Implementation :: PyPy Programming Language :: Python :: Implementation :: PyPy
Programming Language :: Python :: Implementation :: CPython Programming Language :: Python :: Implementation :: CPython

View File

@ -13,7 +13,7 @@ import textwrap
import pytest import pytest
# Early diagnostic for failed imports # Early diagnostic for failed imports
import pybind11_tests # noqa: F401 import pybind11_tests
_long_marker = re.compile(r"([0-9])L") _long_marker = re.compile(r"([0-9])L")
_hexadecimal = re.compile(r"0x[0-9a-fA-F]+") _hexadecimal = re.compile(r"0x[0-9a-fA-F]+")
@ -198,3 +198,16 @@ def gc_collect():
def pytest_configure(): def pytest_configure():
pytest.suppress = suppress pytest.suppress = suppress
pytest.gc_collect = gc_collect pytest.gc_collect = gc_collect
def pytest_report_header(config):
del config # Unused.
assert (
pybind11_tests.compiler_info is not None
), "Please update pybind11_tests.cpp if this assert fails."
return (
"C++ Info:"
f" {pybind11_tests.compiler_info}"
f" {pybind11_tests.cpp_std}"
f" {pybind11_tests.PYBIND11_INTERNALS_ID}"
)

View File

@ -62,9 +62,34 @@ void bind_ConstructorStats(py::module_ &m) {
}); });
} }
const char *cpp_std() {
return
#if defined(PYBIND11_CPP20)
"C++20";
#elif defined(PYBIND11_CPP17)
"C++17";
#elif defined(PYBIND11_CPP14)
"C++14";
#else
"C++11";
#endif
}
PYBIND11_MODULE(pybind11_tests, m) { PYBIND11_MODULE(pybind11_tests, m) {
m.doc() = "pybind11 test module"; m.doc() = "pybind11 test module";
// Intentionally kept minimal to not create a maintenance chore
// ("just enough" to be conclusive).
#if defined(_MSC_FULL_VER)
m.attr("compiler_info") = "MSVC " PYBIND11_TOSTRING(_MSC_FULL_VER);
#elif defined(__VERSION__)
m.attr("compiler_info") = __VERSION__;
#else
m.attr("compiler_info") = py::none();
#endif
m.attr("cpp_std") = cpp_std();
m.attr("PYBIND11_INTERNALS_ID") = PYBIND11_INTERNALS_ID;
bind_ConstructorStats(m); bind_ConstructorStats(m);
#if defined(PYBIND11_DETAILED_ERROR_MESSAGES) #if defined(PYBIND11_DETAILED_ERROR_MESSAGES)

View File

@ -1,4 +1,4 @@
build==0.7.0 build==0.8.0
numpy==1.21.5; platform_python_implementation=="PyPy" and sys_platform=="linux" and python_version=="3.7" numpy==1.21.5; platform_python_implementation=="PyPy" and sys_platform=="linux" and python_version=="3.7"
numpy==1.19.3; platform_python_implementation!="PyPy" and python_version=="3.6" numpy==1.19.3; platform_python_implementation!="PyPy" and python_version=="3.6"
numpy==1.21.5; platform_python_implementation!="PyPy" and python_version>="3.7" and python_version<"3.10" numpy==1.21.5; platform_python_implementation!="PyPy" and python_version>="3.7" and python_version<"3.10"

View File

@ -345,10 +345,13 @@ TEST_SUBMODULE(eigen, m) {
}, },
py::arg{}.noconvert()); py::arg{}.noconvert());
// test_issue738 // test_issue738, test_zero_length
// Issue #738: 1xN or Nx1 2D matrices were neither accepted nor properly copied with an // Issue #738: 1×N or N×1 2D matrices were neither accepted nor properly copied with an
// incompatible stride value on the length-1 dimension--but that should be allowed (without // incompatible stride value on the length-1 dimension--but that should be allowed (without
// requiring a copy!) because the stride value can be safely ignored on a size-1 dimension. // requiring a copy!) because the stride value can be safely ignored on a size-1 dimension.
// Similarly, 0×N or N×0 matrices were not accepted--again, these should be allowed since
// they contain no data. This particularly affects numpy ≥ 1.23, which sets the strides to
// 0 if any dimension size is 0.
m.def("iss738_f1", m.def("iss738_f1",
&adjust_matrix<const Eigen::Ref<const Eigen::MatrixXd> &>, &adjust_matrix<const Eigen::Ref<const Eigen::MatrixXd> &>,
py::arg{}.noconvert()); py::arg{}.noconvert());

View File

@ -744,6 +744,13 @@ def test_issue738():
) )
@pytest.mark.parametrize("func", [m.iss738_f1, m.iss738_f2])
@pytest.mark.parametrize("sizes", [(0, 2), (2, 0)])
def test_zero_length(func, sizes):
"""Ignore strides on a length-0 dimension (even if they would be incompatible length > 1)"""
assert np.all(func(np.zeros(sizes)) == np.zeros(sizes))
def test_issue1105(): def test_issue1105():
"""Issue 1105: 1xN or Nx1 input arrays weren't accepted for eigen """Issue 1105: 1xN or Nx1 input arrays weren't accepted for eigen
compile-time row vectors or column vector""" compile-time row vectors or column vector"""

View File

@ -1,9 +1,21 @@
import sys
import pytest import pytest
import env # noqa: F401 import env # noqa: F401
from pybind11_tests import ConstructorStats from pybind11_tests import ConstructorStats
from pybind11_tests import methods_and_attributes as m from pybind11_tests import methods_and_attributes as m
NO_GETTER_MSG = (
"unreadable attribute" if sys.version_info < (3, 11) else "object has no getter"
)
NO_SETTER_MSG = (
"can't set attribute" if sys.version_info < (3, 11) else "object has no setter"
)
NO_DELETER_MSG = (
"can't delete attribute" if sys.version_info < (3, 11) else "object has no deleter"
)
def test_methods_and_attributes(): def test_methods_and_attributes():
instance1 = m.ExampleMandA() instance1 = m.ExampleMandA()
@ -102,32 +114,32 @@ def test_properties():
with pytest.raises(AttributeError) as excinfo: with pytest.raises(AttributeError) as excinfo:
dummy = instance.def_property_writeonly # unused var dummy = instance.def_property_writeonly # unused var
assert "unreadable attribute" in str(excinfo.value) assert NO_GETTER_MSG in str(excinfo.value)
instance.def_property_writeonly = 4 instance.def_property_writeonly = 4
assert instance.def_property_readonly == 4 assert instance.def_property_readonly == 4
with pytest.raises(AttributeError) as excinfo: with pytest.raises(AttributeError) as excinfo:
dummy = instance.def_property_impossible # noqa: F841 unused var dummy = instance.def_property_impossible # noqa: F841 unused var
assert "unreadable attribute" in str(excinfo.value) assert NO_GETTER_MSG in str(excinfo.value)
with pytest.raises(AttributeError) as excinfo: with pytest.raises(AttributeError) as excinfo:
instance.def_property_impossible = 5 instance.def_property_impossible = 5
assert "can't set attribute" in str(excinfo.value) assert NO_SETTER_MSG in str(excinfo.value)
def test_static_properties(): def test_static_properties():
assert m.TestProperties.def_readonly_static == 1 assert m.TestProperties.def_readonly_static == 1
with pytest.raises(AttributeError) as excinfo: with pytest.raises(AttributeError) as excinfo:
m.TestProperties.def_readonly_static = 2 m.TestProperties.def_readonly_static = 2
assert "can't set attribute" in str(excinfo.value) assert NO_SETTER_MSG in str(excinfo.value)
m.TestProperties.def_readwrite_static = 2 m.TestProperties.def_readwrite_static = 2
assert m.TestProperties.def_readwrite_static == 2 assert m.TestProperties.def_readwrite_static == 2
with pytest.raises(AttributeError) as excinfo: with pytest.raises(AttributeError) as excinfo:
dummy = m.TestProperties.def_writeonly_static # unused var dummy = m.TestProperties.def_writeonly_static # unused var
assert "unreadable attribute" in str(excinfo.value) assert NO_GETTER_MSG in str(excinfo.value)
m.TestProperties.def_writeonly_static = 3 m.TestProperties.def_writeonly_static = 3
assert m.TestProperties.def_readonly_static == 3 assert m.TestProperties.def_readonly_static == 3
@ -135,14 +147,14 @@ def test_static_properties():
assert m.TestProperties.def_property_readonly_static == 3 assert m.TestProperties.def_property_readonly_static == 3
with pytest.raises(AttributeError) as excinfo: with pytest.raises(AttributeError) as excinfo:
m.TestProperties.def_property_readonly_static = 99 m.TestProperties.def_property_readonly_static = 99
assert "can't set attribute" in str(excinfo.value) assert NO_SETTER_MSG in str(excinfo.value)
m.TestProperties.def_property_static = 4 m.TestProperties.def_property_static = 4
assert m.TestProperties.def_property_static == 4 assert m.TestProperties.def_property_static == 4
with pytest.raises(AttributeError) as excinfo: with pytest.raises(AttributeError) as excinfo:
dummy = m.TestProperties.def_property_writeonly_static dummy = m.TestProperties.def_property_writeonly_static
assert "unreadable attribute" in str(excinfo.value) assert NO_GETTER_MSG in str(excinfo.value)
m.TestProperties.def_property_writeonly_static = 5 m.TestProperties.def_property_writeonly_static = 5
assert m.TestProperties.def_property_static == 5 assert m.TestProperties.def_property_static == 5
@ -160,7 +172,7 @@ def test_static_properties():
with pytest.raises(AttributeError) as excinfo: with pytest.raises(AttributeError) as excinfo:
dummy = instance.def_property_writeonly_static # noqa: F841 unused var dummy = instance.def_property_writeonly_static # noqa: F841 unused var
assert "unreadable attribute" in str(excinfo.value) assert NO_GETTER_MSG in str(excinfo.value)
instance.def_property_writeonly_static = 4 instance.def_property_writeonly_static = 4
assert instance.def_property_static == 4 assert instance.def_property_static == 4
@ -180,7 +192,7 @@ def test_static_properties():
properties_override = m.TestPropertiesOverride() properties_override = m.TestPropertiesOverride()
with pytest.raises(AttributeError) as excinfo: with pytest.raises(AttributeError) as excinfo:
del properties_override.def_readonly del properties_override.def_readonly
assert "can't delete attribute" in str(excinfo.value) assert NO_DELETER_MSG in str(excinfo.value)
def test_static_cls(): def test_static_cls():