From ba9f919b857f12efd18d3fc43fc62e7ad724c6d9 Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Mon, 4 Oct 2021 17:37:27 -0400 Subject: [PATCH 01/22] chore: get back to work after 2.8.0 --- docs/changelog.rst | 6 ++++++ docs/release.rst | 2 ++ include/pybind11/detail/common.h | 6 +++--- pybind11/_version.py | 2 +- 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index 4a58f2d51..1dab8765f 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -6,6 +6,12 @@ Changelog Starting with version 1.8.0, pybind11 releases use a `semantic versioning `_ policy. + +IN DEVELOPMENT +-------------- + + + v2.8.0 (Oct 4, 2021) -------------------- diff --git a/docs/release.rst b/docs/release.rst index e4f3d1902..7fa254eaf 100644 --- a/docs/release.rst +++ b/docs/release.rst @@ -27,6 +27,7 @@ To release a new version of pybind11: ``include/pybind11/detail/common.h``. PATCH should be a simple integer. - Update the version HEX just below, as well. - Update ``pybind11/_version.py`` (match above) + - Run ``nox -s tests_packaging``` to ensure this was done correctly. - Ensure that all the information in ``setup.cfg`` is up-to-date, like supported Python versions. - Add release date in ``docs/changelog.rst``. @@ -64,6 +65,7 @@ To release a new version of pybind11: - Update version macros in ``include/pybind11/detail/common.h`` (set PATCH to ``0.dev1`` and increment MINOR). - Update ``_version.py`` to match + - Run ``nox -s tests_packaging``` to ensure this was done correctly. - Add a spot for in-development updates in ``docs/changelog.rst``. - ``git add``, ``git commit``, ``git push`` diff --git a/include/pybind11/detail/common.h b/include/pybind11/detail/common.h index 31716e5bf..9ad305a4e 100644 --- a/include/pybind11/detail/common.h +++ b/include/pybind11/detail/common.h @@ -10,12 +10,12 @@ #pragma once #define PYBIND11_VERSION_MAJOR 2 -#define PYBIND11_VERSION_MINOR 8 -#define PYBIND11_VERSION_PATCH 0 +#define PYBIND11_VERSION_MINOR 9 +#define PYBIND11_VERSION_PATCH 0.dev1 // Similar to Python's convention: https://docs.python.org/3/c-api/apiabiversion.html // Additional convention: 0xD = dev -#define PYBIND11_VERSION_HEX 0x02080000 +#define PYBIND11_VERSION_HEX 0x020900D1 #define PYBIND11_NAMESPACE_BEGIN(name) namespace name { #define PYBIND11_NAMESPACE_END(name) } diff --git a/pybind11/_version.py b/pybind11/_version.py index 704191b98..ce894a774 100644 --- a/pybind11/_version.py +++ b/pybind11/_version.py @@ -8,5 +8,5 @@ def _to_int(s): return s -__version__ = "2.8.0" +__version__ = "2.9.0.dev1" version_info = tuple(_to_int(s) for s in __version__.split(".")) From 47ed124f3728c7886d496c28c15b889c78599b99 Mon Sep 17 00:00:00 2001 From: Bruce Merry <1963944+bmerry@users.noreply.github.com> Date: Fri, 8 Oct 2021 14:27:38 +0200 Subject: [PATCH 02/22] Fix some formatting in the v2.8.0 changelog (#3339) [skipci] --- docs/changelog.rst | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index 1dab8765f..80c580b18 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -53,9 +53,10 @@ New features: `#3293 `_ * Improve the classes generated by ``bind_map``: `#3310 `_ - * Change ``.items`` from an iterator to a dictionary view. - * Add ``.keys`` and ``.values`` (both dictionary views). - * Allow ``__contains__`` to take any object. + + * Change ``.items`` from an iterator to a dictionary view. + * Add ``.keys`` and ``.values`` (both dictionary views). + * Allow ``__contains__`` to take any object. * ``pybind11::custom_type_setup`` was added, for customizing the ``PyHeapTypeObject`` corresponding to a class, which may be useful for From ed09664f063269dcf6a47298944e45fb957b40c4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 8 Oct 2021 08:27:52 -0400 Subject: [PATCH 03/22] chore(deps): bump ilammy/msvc-dev-cmd from 1.9.0 to 1.10.0 (#3338) Bumps [ilammy/msvc-dev-cmd](https://github.com/ilammy/msvc-dev-cmd) from 1.9.0 to 1.10.0. - [Release notes](https://github.com/ilammy/msvc-dev-cmd/releases) - [Commits](https://github.com/ilammy/msvc-dev-cmd/compare/v1.9.0...v1.10.0) --- updated-dependencies: - dependency-name: ilammy/msvc-dev-cmd dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6843a9243..5d5222f8b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -169,7 +169,7 @@ jobs: # MSVC, but for now, this action works: - name: Prepare compiler environment for Windows 🐍 2.7 if: matrix.python == 2.7 && runner.os == 'Windows' - uses: ilammy/msvc-dev-cmd@v1.9.0 + uses: ilammy/msvc-dev-cmd@v1.10.0 with: arch: x64 @@ -760,7 +760,7 @@ jobs: uses: jwlawson/actions-setup-cmake@v1.11 - name: Prepare MSVC - uses: ilammy/msvc-dev-cmd@v1.9.0 + uses: ilammy/msvc-dev-cmd@v1.10.0 with: arch: x86 @@ -806,7 +806,7 @@ jobs: uses: jwlawson/actions-setup-cmake@v1.11 - name: Prepare MSVC - uses: ilammy/msvc-dev-cmd@v1.9.0 + uses: ilammy/msvc-dev-cmd@v1.10.0 with: toolset: 14.0 From f4c81e0877a7d302eb580886f8552bc81d3b3d65 Mon Sep 17 00:00:00 2001 From: Aaron Gokaslan Date: Fri, 8 Oct 2021 08:38:04 -0400 Subject: [PATCH 04/22] maint: Add additional linter-related pre-commit hooks (#3337) * Add additional pygrep pre-commit hooks * Remove useless noqas with hook * Fix all single rst backticks * Simplify mypy pre-commit hook with upstream fixes * Add back missing comment * Add one last pygrep hook --- .pre-commit-config.yaml | 25 ++++++++++++++++++++----- docs/advanced/classes.rst | 2 +- docs/advanced/embedding.rst | 26 +++++++++++++------------- docs/advanced/exceptions.rst | 6 +++--- docs/advanced/functions.rst | 2 +- docs/advanced/misc.rst | 2 +- docs/advanced/pycpp/utilities.rst | 10 +++++----- docs/changelog.rst | 6 +++--- tests/test_buffers.py | 2 +- tests/test_builtin_casters.py | 2 +- tests/test_callbacks.py | 2 +- tests/test_enum.py | 6 +++--- tests/test_methods_and_attributes.py | 4 ++-- tests/test_pickling.py | 2 +- tests/test_pytypes.py | 4 ++-- tests/test_stl_binders.py | 2 +- 16 files changed, 59 insertions(+), 44 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 2df314606..17e67ded4 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -67,14 +67,32 @@ repos: hooks: - id: pycln +- repo: https://github.com/pre-commit/pygrep-hooks + rev: v1.9.0 + hooks: + - id: python-check-blanket-noqa + - id: python-check-blanket-type-ignore + - id: python-no-log-warn + - id: rst-backticks + - id: rst-directive-colons + - id: rst-inline-touching-normal + # Flake8 also supports pre-commit natively (same author) - repo: https://github.com/PyCQA/flake8 rev: 3.9.2 hooks: - id: flake8 - additional_dependencies: [flake8-bugbear, pep8-naming] + additional_dependencies: &flake8_dependencies + - flake8-bugbear + - pep8-naming exclude: ^(docs/.*|tools/.*)$ +- repo: https://github.com/asottile/yesqa + rev: v1.2.3 + hooks: + - id: yesqa + additional_dependencies: *flake8_dependencies + # CMake formatting - repo: https://github.com/cheshirekow/cmake-format-precommit rev: v0.6.13 @@ -86,12 +104,9 @@ repos: # Check static types with mypy - repo: https://github.com/pre-commit/mirrors-mypy - rev: v0.910 + rev: v0.910-1 hooks: - id: mypy - # The default Python type ignores .pyi files, so let's rerun if detected - types: [text] - files: ^pybind11.*\.pyi?$ # Running per-file misbehaves a bit, so just run on all files, it's fast pass_filenames: false additional_dependencies: [typed_ast] diff --git a/docs/advanced/classes.rst b/docs/advanced/classes.rst index 5f01a2f11..6330af5eb 100644 --- a/docs/advanced/classes.rst +++ b/docs/advanced/classes.rst @@ -1266,7 +1266,7 @@ Custom type setup ================= For advanced use cases, such as enabling garbage collection support, you may -wish to directly manipulate the `PyHeapTypeObject` corresponding to a +wish to directly manipulate the ``PyHeapTypeObject`` corresponding to a ``py::class_`` definition. You can do that using ``py::custom_type_setup``: diff --git a/docs/advanced/embedding.rst b/docs/advanced/embedding.rst index a435b8a75..dd980d483 100644 --- a/docs/advanced/embedding.rst +++ b/docs/advanced/embedding.rst @@ -40,15 +40,15 @@ The essential structure of the ``main.cpp`` file looks like this: } The interpreter must be initialized before using any Python API, which includes -all the functions and classes in pybind11. The RAII guard class `scoped_interpreter` +all the functions and classes in pybind11. The RAII guard class ``scoped_interpreter`` takes care of the interpreter lifetime. After the guard is destroyed, the interpreter shuts down and clears its memory. No Python functions can be called after this. Executing Python code ===================== -There are a few different ways to run Python code. One option is to use `eval`, -`exec` or `eval_file`, as explained in :ref:`eval`. Here is a quick example in +There are a few different ways to run Python code. One option is to use ``eval``, +``exec`` or ``eval_file``, as explained in :ref:`eval`. Here is a quick example in the context of an executable with an embedded interpreter: .. code-block:: cpp @@ -108,7 +108,7 @@ The two approaches can also be combined: Importing modules ================= -Python modules can be imported using `module_::import()`: +Python modules can be imported using ``module_::import()``: .. code-block:: cpp @@ -134,7 +134,7 @@ embedding the interpreter. This makes it easy to import local Python files: int n = result.cast(); assert(n == 3); -Modules can be reloaded using `module_::reload()` if the source is modified e.g. +Modules can be reloaded using ``module_::reload()`` if the source is modified e.g. by an external process. This can be useful in scenarios where the application imports a user defined data processing script which needs to be updated after changes by the user. Note that this function does not reload modules recursively. @@ -144,7 +144,7 @@ changes by the user. Note that this function does not reload modules recursively Adding embedded modules ======================= -Embedded binary modules can be added using the `PYBIND11_EMBEDDED_MODULE` macro. +Embedded binary modules can be added using the ``PYBIND11_EMBEDDED_MODULE`` macro. Note that the definition must be placed at global scope. They can be imported like any other module. @@ -170,7 +170,7 @@ like any other module. Unlike extension modules where only a single binary module can be created, on the embedded side an unlimited number of modules can be added using multiple -`PYBIND11_EMBEDDED_MODULE` definitions (as long as they have unique names). +``PYBIND11_EMBEDDED_MODULE`` definitions (as long as they have unique names). These modules are added to Python's list of builtins, so they can also be imported in pure Python files loaded by the interpreter. Everything interacts @@ -216,9 +216,9 @@ naturally: Interpreter lifetime ==================== -The Python interpreter shuts down when `scoped_interpreter` is destroyed. After +The Python interpreter shuts down when ``scoped_interpreter`` is destroyed. After this, creating a new instance will restart the interpreter. Alternatively, the -`initialize_interpreter` / `finalize_interpreter` pair of functions can be used +``initialize_interpreter`` / ``finalize_interpreter`` pair of functions can be used to directly set the state at any time. Modules created with pybind11 can be safely re-initialized after the interpreter @@ -230,8 +230,8 @@ global data. All the details can be found in the CPython documentation. .. warning:: - Creating two concurrent `scoped_interpreter` guards is a fatal error. So is - calling `initialize_interpreter` for a second time after the interpreter + Creating two concurrent ``scoped_interpreter`` guards is a fatal error. So is + calling ``initialize_interpreter`` for a second time after the interpreter has already been initialized. Do not use the raw CPython API functions ``Py_Initialize`` and @@ -242,7 +242,7 @@ global data. All the details can be found in the CPython documentation. Sub-interpreter support ======================= -Creating multiple copies of `scoped_interpreter` is not possible because it +Creating multiple copies of ``scoped_interpreter`` is not possible because it represents the main Python interpreter. Sub-interpreters are something different and they do permit the existence of multiple interpreters. This is an advanced feature of the CPython API and should be handled with care. pybind11 does not @@ -258,5 +258,5 @@ We'll just mention a couple of caveats the sub-interpreters support in pybind11: 2. Managing multiple threads, multiple interpreters and the GIL can be challenging and there are several caveats here, even within the pure CPython API (please refer to the Python docs for details). As for - pybind11, keep in mind that `gil_scoped_release` and `gil_scoped_acquire` + pybind11, keep in mind that ``gil_scoped_release`` and ``gil_scoped_acquire`` do not take sub-interpreters into account. diff --git a/docs/advanced/exceptions.rst b/docs/advanced/exceptions.rst index 2aaa0ad32..b4825cbcd 100644 --- a/docs/advanced/exceptions.rst +++ b/docs/advanced/exceptions.rst @@ -96,18 +96,18 @@ A matching function is available for registering a local exception translator: It is possible to specify base class for the exception using the third -parameter, a `handle`: +parameter, a ``handle``: .. code-block:: cpp py::register_exception(module, "PyExp", PyExc_RuntimeError); py::register_local_exception(module, "PyExp", PyExc_RuntimeError); -Then `PyExp` can be caught both as `PyExp` and `RuntimeError`. +Then ``PyExp`` can be caught both as ``PyExp`` and ``RuntimeError``. The class objects of the built-in Python exceptions are listed in the Python documentation on `Standard Exceptions `_. -The default base class is `PyExc_Exception`. +The default base class is ``PyExc_Exception``. When more advanced exception translation is needed, the functions ``py::register_exception_translator(translator)`` and diff --git a/docs/advanced/functions.rst b/docs/advanced/functions.rst index 1178d0726..abd1084ab 100644 --- a/docs/advanced/functions.rst +++ b/docs/advanced/functions.rst @@ -232,7 +232,7 @@ is equivalent to the following pseudocode: }); The only requirement is that ``T`` is default-constructible, but otherwise any -scope guard will work. This is very useful in combination with `gil_scoped_release`. +scope guard will work. This is very useful in combination with ``gil_scoped_release``. See :ref:`gil`. Multiple guards can also be specified as ``py::call_guard``. The diff --git a/docs/advanced/misc.rst b/docs/advanced/misc.rst index b3f3b2265..edab15fcb 100644 --- a/docs/advanced/misc.rst +++ b/docs/advanced/misc.rst @@ -84,7 +84,7 @@ could be realized as follows (important changes highlighted): }); } -The ``call_go`` wrapper can also be simplified using the `call_guard` policy +The ``call_go`` wrapper can also be simplified using the ``call_guard`` policy (see :ref:`call_policies`) which yields the same result: .. code-block:: cpp diff --git a/docs/advanced/pycpp/utilities.rst b/docs/advanced/pycpp/utilities.rst index bf90a62f8..af0f9cb2b 100644 --- a/docs/advanced/pycpp/utilities.rst +++ b/docs/advanced/pycpp/utilities.rst @@ -28,7 +28,7 @@ Capturing standard output from ostream Often, a library will use the streams ``std::cout`` and ``std::cerr`` to print, but this does not play well with Python's standard ``sys.stdout`` and ``sys.stderr`` -redirection. Replacing a library's printing with `py::print ` may not +redirection. Replacing a library's printing with ``py::print `` may not be feasible. This can be fixed using a guard around the library function that redirects output to the corresponding Python streams: @@ -62,9 +62,9 @@ This method respects flushes on the output streams and will flush if needed when the scoped guard is destroyed. This allows the output to be redirected in real time, such as to a Jupyter notebook. The two arguments, the C++ stream and the Python output, are optional, and default to standard output if not given. An -extra type, `py::scoped_estream_redirect `, is identical +extra type, ``py::scoped_estream_redirect ``, is identical except for defaulting to ``std::cerr`` and ``sys.stderr``; this can be useful with -`py::call_guard`, which allows multiple items, but uses the default constructor: +``py::call_guard``, which allows multiple items, but uses the default constructor: .. code-block:: cpp @@ -74,7 +74,7 @@ except for defaulting to ``std::cerr`` and ``sys.stderr``; this can be useful wi py::scoped_estream_redirect>()); The redirection can also be done in Python with the addition of a context -manager, using the `py::add_ostream_redirect() ` function: +manager, using the ``py::add_ostream_redirect() `` function: .. code-block:: cpp @@ -103,7 +103,7 @@ arguments to disable one of the streams if needed. Evaluating Python expressions from strings and files ==================================================== -pybind11 provides the `eval`, `exec` and `eval_file` functions to evaluate +pybind11 provides the ``eval``, ``exec`` and ``eval_file`` functions to evaluate Python expressions and statements. The following example illustrates how they can be used. diff --git a/docs/changelog.rst b/docs/changelog.rst index 80c580b18..0721020db 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -251,8 +251,8 @@ New features: Changes: -* ``py::str`` changed to exclusively hold `PyUnicodeObject`. Previously - ``py::str`` could also hold `bytes`, which is probably surprising, was +* ``py::str`` changed to exclusively hold ``PyUnicodeObject``. Previously + ``py::str`` could also hold ``bytes``, which is probably surprising, was never documented, and can mask bugs (e.g. accidental use of ``py::str`` instead of ``py::bytes``). `#2409 `_ @@ -1405,7 +1405,7 @@ v2.2.0 (August 31, 2017) * Intel C++ compiler compatibility fixes. `#937 `_. -* Fixed implicit conversion of `py::enum_` to integer types on Python 2.7. +* Fixed implicit conversion of ``py::enum_`` to integer types on Python 2.7. `#821 `_. * Added ``py::hash`` to fetch the hash value of Python objects, and diff --git a/tests/test_buffers.py b/tests/test_buffers.py index e3df7e04f..adf7cadff 100644 --- a/tests/test_buffers.py +++ b/tests/test_buffers.py @@ -5,7 +5,7 @@ import struct import pytest -import env # noqa: F401 +import env from pybind11_tests import ConstructorStats from pybind11_tests import buffers as m diff --git a/tests/test_builtin_casters.py b/tests/test_builtin_casters.py index 09b4b08c5..2a061c193 100644 --- a/tests/test_builtin_casters.py +++ b/tests/test_builtin_casters.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- import pytest -import env # noqa: F401 +import env from pybind11_tests import IncType, UserType from pybind11_tests import builtin_casters as m diff --git a/tests/test_callbacks.py b/tests/test_callbacks.py index edbb1890c..f41ad86e7 100644 --- a/tests/test_callbacks.py +++ b/tests/test_callbacks.py @@ -4,7 +4,7 @@ from threading import Thread import pytest -import env # NOQA: F401 +import env # noqa: F401 from pybind11_tests import callbacks as m diff --git a/tests/test_enum.py b/tests/test_enum.py index 85302b080..14c754e72 100644 --- a/tests/test_enum.py +++ b/tests/test_enum.py @@ -96,13 +96,13 @@ Members: y >= object() # noqa: B015 with pytest.raises(TypeError): - y | object() # noqa: B015 + y | object() with pytest.raises(TypeError): - y & object() # noqa: B015 + y & object() with pytest.raises(TypeError): - y ^ object() # noqa: B015 + y ^ object() assert int(m.UnscopedEnum.ETwo) == 2 assert str(m.UnscopedEnum(2)) == "UnscopedEnum.ETwo" diff --git a/tests/test_methods_and_attributes.py b/tests/test_methods_and_attributes.py index 21909654a..866b3cea1 100644 --- a/tests/test_methods_and_attributes.py +++ b/tests/test_methods_and_attributes.py @@ -102,7 +102,7 @@ def test_properties(): assert instance.def_property == 3 with pytest.raises(AttributeError) as excinfo: - dummy = instance.def_property_writeonly # noqa: F841 unused var + dummy = instance.def_property_writeonly # unused var assert "unreadable attribute" in str(excinfo.value) instance.def_property_writeonly = 4 @@ -127,7 +127,7 @@ def test_static_properties(): assert m.TestProperties.def_readwrite_static == 2 with pytest.raises(AttributeError) as excinfo: - dummy = m.TestProperties.def_writeonly_static # noqa: F841 unused var + dummy = m.TestProperties.def_writeonly_static # unused var assert "unreadable attribute" in str(excinfo.value) m.TestProperties.def_writeonly_static = 3 diff --git a/tests/test_pickling.py b/tests/test_pickling.py index e39463d20..9f68f37dc 100644 --- a/tests/test_pickling.py +++ b/tests/test_pickling.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- import pytest -import env # noqa: F401 +import env from pybind11_tests import pickling as m try: diff --git a/tests/test_pytypes.py b/tests/test_pytypes.py index cc27e60a1..5215b79bc 100644 --- a/tests/test_pytypes.py +++ b/tests/test_pytypes.py @@ -5,7 +5,7 @@ import sys import pytest -import env # noqa: F401 +import env from pybind11_tests import debug_enabled from pybind11_tests import pytypes as m @@ -610,7 +610,7 @@ def test_weakref(create_weakref, create_weakref_with_callback): obj = WeaklyReferenced() assert getweakrefcount(obj) == 0 - wr = create_weakref(obj) # noqa: F841 + wr = create_weakref(obj) assert getweakrefcount(obj) == 1 obj = WeaklyReferenced() diff --git a/tests/test_stl_binders.py b/tests/test_stl_binders.py index a68dcd31d..59c5ab6b5 100644 --- a/tests/test_stl_binders.py +++ b/tests/test_stl_binders.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- import pytest -import env # noqa: F401 +import env from pybind11_tests import stl_binders as m From 750e38dcfdac59231a615580d4e6cb3647b31779 Mon Sep 17 00:00:00 2001 From: NaDDu Date: Sun, 10 Oct 2021 00:38:34 +0900 Subject: [PATCH 05/22] Update eval.h (#3344) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit typo correction pybind11/exec.h → pybind11/eval.h --- include/pybind11/eval.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/pybind11/eval.h b/include/pybind11/eval.h index e0f58bcf4..6cc672e2d 100644 --- a/include/pybind11/eval.h +++ b/include/pybind11/eval.h @@ -1,5 +1,5 @@ /* - pybind11/exec.h: Support for evaluating Python expressions and statements + pybind11/eval.h: Support for evaluating Python expressions and statements from strings and files Copyright (c) 2016 Klemens Morgenstern and From 8a7c266d26e5c9de3beb478bedddcee26f026b04 Mon Sep 17 00:00:00 2001 From: Bruce Merry <1963944+bmerry@users.noreply.github.com> Date: Mon, 11 Oct 2021 17:35:39 +0200 Subject: [PATCH 06/22] Fix make_key_iterator/make_value_iterator for prvalue iterators (#3348) * Add a test showing a flaw in make_key_iterator/make_value_iterator If the iterator dereference operator returns a value rather than a reference (and that pair also does not *contain* references), make_key_iterator and make_value_iterator will return a reference to a temporary, causing a segfault. * Fix make_key_iterator/make_value_iterator for prvalue iterators If an iterator returns a pair rather than a reference to a pair or a pair of references, make_key_iterator and make_value_iterator would return a reference to a temporary, typically leading to a segfault. This is because the value category of member access to a prvalue is an xvalue, not a prvalue, so decltype produces an rvalue reference type. Fix the type calculation to handle this case. I also removed some decltype parentheses that weren't needed, either because the expression isn't one of the special cases for decltype or because decltype was only used for SFINAE. Hopefully that makes the code a bit more readable. Closes #3347 * Attempt a workaround for nvcc --- include/pybind11/pybind11.h | 47 ++++++++++++++++++++------ tests/test_sequences_and_iterators.cpp | 27 ++++++++++++++- tests/test_sequences_and_iterators.py | 7 ++++ 3 files changed, 69 insertions(+), 12 deletions(-) diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index 370e52cff..285f3b18c 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -1967,29 +1967,54 @@ struct iterator_state { }; // Note: these helpers take the iterator by non-const reference because some -// iterators in the wild can't be dereferenced when const. C++ needs the extra parens in decltype -// to enforce an lvalue. The & after Iterator is required for MSVC < 16.9. SFINAE cannot be -// reused for result_type due to bugs in ICC, NVCC, and PGI compilers. See PR #3293. -template ()))> +// iterators in the wild can't be dereferenced when const. The & after Iterator +// is required for MSVC < 16.9. SFINAE cannot be reused for result_type due to +// bugs in ICC, NVCC, and PGI compilers. See PR #3293. +template ())> struct iterator_access { - using result_type = decltype((*std::declval())); + using result_type = decltype(*std::declval()); // NOLINTNEXTLINE(readability-const-return-type) // PR #3263 result_type operator()(Iterator &it) const { return *it; } }; -template ()).first)) > -struct iterator_key_access { - using result_type = decltype(((*std::declval()).first)); +template ()).first) > +class iterator_key_access { +private: + using pair_type = decltype(*std::declval()); + +public: + /* If either the pair itself or the element of the pair is a reference, we + * want to return a reference, otherwise a value. When the decltype + * expression is parenthesized it is based on the value category of the + * expression; otherwise it is the declared type of the pair member. + * The use of declval in the second branch rather than directly + * using *std::declval() is a workaround for nvcc + * (it's not used in the first branch because going via decltype and back + * through declval does not perfectly preserve references). + */ + using result_type = conditional_t< + std::is_reference())>::value, + decltype(((*std::declval()).first)), + decltype(std::declval().first) + >; result_type operator()(Iterator &it) const { return (*it).first; } }; -template ()).second))> -struct iterator_value_access { - using result_type = decltype(((*std::declval()).second)); +template ()).second)> +class iterator_value_access { +private: + using pair_type = decltype(*std::declval()); + +public: + using result_type = conditional_t< + std::is_reference())>::value, + decltype(((*std::declval()).second)), + decltype(std::declval().second) + >; result_type operator()(Iterator &it) const { return (*it).second; } diff --git a/tests/test_sequences_and_iterators.cpp b/tests/test_sequences_and_iterators.cpp index 9de69338b..a378128ae 100644 --- a/tests/test_sequences_and_iterators.cpp +++ b/tests/test_sequences_and_iterators.cpp @@ -38,6 +38,17 @@ bool operator==(const NonZeroIterator>& it, const NonZeroSentine return !(*it).first || !(*it).second; } +/* Iterator where dereferencing returns prvalues instead of references. */ +template +class NonRefIterator { + const T* ptr_; +public: + explicit NonRefIterator(const T *ptr) : ptr_(ptr) {} + T operator*() const { return T(*ptr_); } + NonRefIterator& operator++() { ++ptr_; return *this; } + bool operator==(const NonRefIterator &other) const { return ptr_ == other.ptr_; } +}; + class NonCopyableInt { public: explicit NonCopyableInt(int value) : value_(value) {} @@ -331,7 +342,7 @@ TEST_SUBMODULE(sequences_and_iterators, m) { py::class_(m, "IntPairs") .def(py::init>>()) .def("nonzero", [](const IntPairs& s) { - return py::make_iterator(NonZeroIterator>(s.begin()), NonZeroSentinel()); + return py::make_iterator(NonZeroIterator>(s.begin()), NonZeroSentinel()); }, py::keep_alive<0, 1>()) .def("nonzero_keys", [](const IntPairs& s) { return py::make_key_iterator(NonZeroIterator>(s.begin()), NonZeroSentinel()); @@ -340,6 +351,20 @@ TEST_SUBMODULE(sequences_and_iterators, m) { return py::make_value_iterator(NonZeroIterator>(s.begin()), NonZeroSentinel()); }, py::keep_alive<0, 1>()) + // test iterator that returns values instead of references + .def("nonref", [](const IntPairs& s) { + return py::make_iterator(NonRefIterator>(s.begin()), + NonRefIterator>(s.end())); + }, py::keep_alive<0, 1>()) + .def("nonref_keys", [](const IntPairs& s) { + return py::make_key_iterator(NonRefIterator>(s.begin()), + NonRefIterator>(s.end())); + }, py::keep_alive<0, 1>()) + .def("nonref_values", [](const IntPairs& s) { + return py::make_value_iterator(NonRefIterator>(s.begin()), + NonRefIterator>(s.end())); + }, py::keep_alive<0, 1>()) + // test single-argument make_iterator .def("simple_iterator", [](IntPairs& self) { return py::make_iterator(self); diff --git a/tests/test_sequences_and_iterators.py b/tests/test_sequences_and_iterators.py index 38e2ab5b7..6985918a1 100644 --- a/tests/test_sequences_and_iterators.py +++ b/tests/test_sequences_and_iterators.py @@ -52,6 +52,13 @@ def test_generalized_iterators(): next(it) +def test_nonref_iterators(): + pairs = m.IntPairs([(1, 2), (3, 4), (0, 5)]) + assert list(pairs.nonref()) == [(1, 2), (3, 4), (0, 5)] + assert list(pairs.nonref_keys()) == [1, 3, 0] + assert list(pairs.nonref_values()) == [2, 4, 5] + + def test_generalized_iterators_simple(): assert list(m.IntPairs([(1, 2), (3, 4), (0, 5)]).simple_iterator()) == [ (1, 2), From 02c05573d9f580bb1bfcc351e2e22e0c9f539b2b Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 11 Oct 2021 16:03:19 -0400 Subject: [PATCH 07/22] [pre-commit.ci] pre-commit autoupdate (#3353) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/PyCQA/flake8: 3.9.2 → 4.0.1](https://github.com/PyCQA/flake8/compare/3.9.2...4.0.1) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 17e67ded4..c6652d836 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -79,7 +79,7 @@ repos: # Flake8 also supports pre-commit natively (same author) - repo: https://github.com/PyCQA/flake8 - rev: 3.9.2 + rev: 4.0.1 hooks: - id: flake8 additional_dependencies: &flake8_dependencies From 7c580586f853b5f48603594ff0c11a5211de9007 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Mon, 11 Oct 2021 13:13:01 -0700 Subject: [PATCH 08/22] Correct options on Eigen::MappedSparseMatrix & adding MSVC C4127 suppression around Eigen includes. (#3352) * Adding MSVC C4127 suppression around Eigen includes. * For MSVC 2015 only: also adding the C4127 suppression to test_eigen.cpp * Copying original change from PR #3343, with extra line breaks to not run past 99 columns (our desired but currently not enforced limit). --- include/pybind11/eigen.h | 18 +++++++++++++++++- tests/CMakeLists.txt | 4 ++-- tests/test_eigen.cpp | 3 +++ 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/include/pybind11/eigen.h b/include/pybind11/eigen.h index c0363827c..97b1d96b0 100644 --- a/include/pybind11/eigen.h +++ b/include/pybind11/eigen.h @@ -17,9 +17,23 @@ #include "numpy.h" +// The C4127 suppression was introduced for Eigen 3.4.0. In theory we could +// make it version specific, or even remove it later, but considering that +// 1. C4127 is generally far more distracting than useful for modern template code, and +// 2. we definitely want to ignore any MSVC warnings originating from Eigen code, +// it is probably best to keep this around indefinitely. +#if defined(_MSC_VER) +# pragma warning(push) +# pragma warning(disable: 4127) // C4127: conditional expression is constant +#endif + #include #include +#if defined(_MSC_VER) +# pragma warning(pop) +#endif + // Eigen prior to 3.2.7 doesn't have proper move constructors--but worse, some classes get implicit // move constructors that break things. We could detect this an explicitly copy, but an extra copy // of matrices seems highly undesirable. @@ -559,7 +573,9 @@ struct type_caster::value>> { if (!values || !innerIndices || !outerIndices) return false; - value = Eigen::MappedSparseMatrix( + value = Eigen::MappedSparseMatrix( shape[0].cast(), shape[1].cast(), nnz, outerIndices.mutable_data(), innerIndices.mutable_data(), values.mutable_data()); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 6ebcba9b6..d4e7b71e1 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -174,9 +174,9 @@ set(PYBIND11_CROSS_MODULE_GIL_TESTS test_gil_scoped.py) set(PYBIND11_EIGEN_REPO "https://gitlab.com/libeigen/eigen.git" CACHE STRING "Eigen repository to use for tests") -# This hash is for 3.3.8, using a hash for security reasons +# This hash is for 3.4.0, using a hash for security reasons set(PYBIND11_EIGEN_VERSION - "dc252fbf00079ccab57948a164b1421703fe4361" + "929bc0e191d0927b1735b9a1ddc0e8b77e3a25ec" CACHE STRING "Eigen version to use for tests") # Check if Eigen is available; if not, remove from PYBIND11_TEST_FILES (but diff --git a/tests/test_eigen.cpp b/tests/test_eigen.cpp index ad572b2ad..d22a94a1a 100644 --- a/tests/test_eigen.cpp +++ b/tests/test_eigen.cpp @@ -13,6 +13,9 @@ #include #if defined(_MSC_VER) +#if _MSC_VER < 1910 // VS 2015's MSVC +# pragma warning(disable: 4127) // C4127: conditional expression is constant +#endif # pragma warning(disable: 4996) // C4996: std::unary_negation is deprecated #endif From 56b49c2be27dbe440f4236a5ca711950aa788e63 Mon Sep 17 00:00:00 2001 From: Jerome Robert Date: Mon, 18 Oct 2021 03:38:41 +0200 Subject: [PATCH 09/22] ci: fix mingw checks by pinning (#3375) * Workaround for https://github.com/msys2/setup-msys2/issues/167 * Adapted from https://github.com/cocotb/cocotb/commit/05036cb24d10579647e81dc1a405b126f711a66f --- .github/workflows/ci.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5d5222f8b..e337770eb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -892,7 +892,8 @@ jobs: - { sys: mingw64, env: x86_64 } - { sys: mingw32, env: i686 } steps: - - uses: msys2/setup-msys2@v2 + # Force version because of https://github.com/msys2/setup-msys2/issues/167 + - uses: msys2/setup-msys2@v2.4.2 with: msystem: ${{matrix.sys}} install: >- From 931f66440f932c62a38e8112ea8ec2f7d962e64a Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Sun, 17 Oct 2021 21:40:10 -0400 Subject: [PATCH 10/22] ci: cancel in-progress on repeated pushes (#3370) --- .github/workflows/ci.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e337770eb..09b400056 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,6 +9,10 @@ on: - stable - v* +concurrency: + group: test-${{ github.ref }} + cancel-in-progress: true + jobs: # This is the "main" test suite, which tests a large number of different # versions of default compilers and Python versions in GitHub Actions. From f791dc8648e1f6ec33f402d679b6b116a76d4e1b Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Tue, 19 Oct 2021 14:39:29 -0400 Subject: [PATCH 11/22] fix: deprecate make_simple_namespace, fix Python 3.11 (#3374) * fix: deprecate make_simple_namespace, fix Python 3.11 * docs: update links --- docs/advanced/pycpp/object.rst | 13 +++---------- docs/changelog.rst | 8 ++++++-- docs/upgrade.rst | 13 ++++++++++++- include/pybind11/cast.h | 10 ---------- include/pybind11/pybind11.h | 9 +++++++++ tests/test_pytypes.cpp | 2 +- 6 files changed, 31 insertions(+), 24 deletions(-) diff --git a/docs/advanced/pycpp/object.rst b/docs/advanced/pycpp/object.rst index 8bffb83e1..93e1a94d8 100644 --- a/docs/advanced/pycpp/object.rst +++ b/docs/advanced/pycpp/object.rst @@ -41,24 +41,17 @@ A tuple of python objects can be instantiated using :func:`py::make_tuple`: Each element is converted to a supported Python type. A `simple namespace`_ can be instantiated using -:func:`py::make_simple_namespace`: .. code-block:: cpp - using namespace pybind11::literals; // to bring in the `_a` literal - py::object ns = py::make_simple_namespace("spam"_a=py::none(), "eggs"_a=42); + using namespace pybind11::literals; // to bring in the `_a` literal + py::object SimpleNamespace = py::module_::import("types").attr("SimpleNamespace"); + py::object ns = SimpleNamespace("spam"_a=py::none(), "eggs"_a=42); Attributes on a namespace can be modified with the :func:`py::delattr`, :func:`py::getattr`, and :func:`py::setattr` functions. Simple namespaces can be useful as lightweight stand-ins for class instances. -.. note:: - - ``make_simple_namespace`` is not available in Python 2. - -.. versionchanged:: 2.8 - ``make_simple_namespace`` added. - .. _simple namespace: https://docs.python.org/3/library/types.html#types.SimpleNamespace .. _casting_back_and_forth: diff --git a/docs/changelog.rst b/docs/changelog.rst index 0721020db..ee79a1871 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -10,6 +10,10 @@ Starting with version 1.8.0, pybind11 releases use a `semantic versioning IN DEVELOPMENT -------------- +* The simple namespace creation shortcut added in 2.8.0 was deprecated due to + usage of CPython internal API, and will be removed soon. Use + ``py::module_::import("types").attr("SimpleNamespace")``. + `#3374 `_ v2.8.0 (Oct 4, 2021) @@ -25,10 +29,10 @@ New features: ``register_local_exception_translator(ExceptionTranslator&& translator)`` instead of ``register_exception_translator(ExceptionTranslator&& translator)`` to keep your exception remapping code local to the module. - `#2650 `_ + `#2650 `_ * Add ``make_simple_namespace`` function for instantiating Python - ``SimpleNamespace`` objects. + ``SimpleNamespace`` objects. **Deprecated in 2.8.1.** `#2840 `_ * ``pybind11::scoped_interpreter`` and ``initialize_interpreter`` have new diff --git a/docs/upgrade.rst b/docs/upgrade.rst index b2b6b1245..69609ca28 100644 --- a/docs/upgrade.rst +++ b/docs/upgrade.rst @@ -8,7 +8,17 @@ to a new version. But it goes into more detail. This includes things like deprecated APIs and their replacements, build system changes, general code modernization and other useful information. -.. _upgrade-guide-2.6: +.. _upgrade-guide-2.9: + +v2.9 +==== + +* Any usage of the recently added ``py::make_simple_namespace`` should be + converted to using ``py::module_::import("types").attr("SimpleNamespace")`` + instead. + + +.. _upgrade-guide-2.7: v2.7 ==== @@ -34,6 +44,7 @@ to be common: careful review and custom fixes. +.. _upgrade-guide-2.6: v2.6 ==== diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index 1ec2080f8..20fbb3258 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -1036,16 +1036,6 @@ template = 0x03030000 -template ()>> -object make_simple_namespace(Args&&... args_) { - PyObject *ns = _PyNamespace_New(dict(std::forward(args_)...).ptr()); - if (!ns) throw error_already_set(); - return reinterpret_steal(ns); -} -#endif - /// \ingroup annotations /// Annotation for arguments struct arg { diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index 285f3b18c..095efd9c3 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -1124,6 +1124,15 @@ inline dict globals() { return reinterpret_borrow(p ? p : module_::import("__main__").attr("__dict__").ptr()); } +#if PY_VERSION_HEX >= 0x03030000 +template ()>> +PYBIND11_DEPRECATED("make_simple_namespace should be replaced with py::module_::import(\"types\").attr(\"SimpleNamespace\") ") +object make_simple_namespace(Args&&... args_) { + return module_::import("types").attr("SimpleNamespace")(std::forward(args_)...); +} +#endif + PYBIND11_NAMESPACE_BEGIN(detail) /// Generic support for creating new Python heap types class generic_type : public object { diff --git a/tests/test_pytypes.cpp b/tests/test_pytypes.cpp index 2157dc097..9a1e91881 100644 --- a/tests/test_pytypes.cpp +++ b/tests/test_pytypes.cpp @@ -84,7 +84,7 @@ TEST_SUBMODULE(pytypes, m) { #if PY_VERSION_HEX >= 0x03030000 // test_simple_namespace m.def("get_simple_namespace", []() { - auto ns = py::make_simple_namespace("attr"_a=42, "x"_a="foo", "wrong"_a=1); + auto ns = py::module_::import("types").attr("SimpleNamespace")("attr"_a=42, "x"_a="foo", "wrong"_a=1); py::delattr(ns, "wrong"); py::setattr(ns, "right", py::int_(2)); return ns; From 2d6014e417a9be926eb9a3c490570707be35cd42 Mon Sep 17 00:00:00 2001 From: Geoffrey Gunter <12984092+gmgunter@users.noreply.github.com> Date: Thu, 21 Oct 2021 07:37:54 -0700 Subject: [PATCH 12/22] docs: fix minor typo (#3390) --- include/pybind11/numpy.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/pybind11/numpy.h b/include/pybind11/numpy.h index b7747fae2..b43a77168 100644 --- a/include/pybind11/numpy.h +++ b/include/pybind11/numpy.h @@ -518,7 +518,7 @@ public: } /// Single-character for dtype's type. - /// For example, ``float`` is 'f', ``double`` 'd', ``int`` 'i', and ``long`` 'd'. + /// For example, ``float`` is 'f', ``double`` 'd', ``int`` 'i', and ``long`` 'l'. char char_() const { // Note: The signature, `dtype::char_` follows the naming of NumPy's // public Python API (i.e., ``dtype.char``), rather than its internal From 606f81a966e56d1ec0f17b0c032e8d6679430d67 Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Fri, 22 Oct 2021 16:38:40 -0400 Subject: [PATCH 13/22] style: drop pycln (#3397) --- .pre-commit-config.yaml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c6652d836..04166de9a 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -61,12 +61,6 @@ repos: hooks: - id: remove-tabs -# Autoremoves unused imports -- repo: https://github.com/hadialqattan/pycln - rev: v1.0.3 - hooks: - - id: pycln - - repo: https://github.com/pre-commit/pygrep-hooks rev: v1.9.0 hooks: From 076c89fc54d3859bb56581555897fda1c621405c Mon Sep 17 00:00:00 2001 From: Dmitry Yershov Date: Fri, 22 Oct 2021 17:09:15 -0400 Subject: [PATCH 14/22] tests: test recursive dispatch using visitor pattern (#3365) --- tests/test_virtual_functions.cpp | 40 ++++++++++++++++++++++++++++++++ tests/test_virtual_functions.py | 33 ++++++++++++++++++++++++++ 2 files changed, 73 insertions(+) diff --git a/tests/test_virtual_functions.cpp b/tests/test_virtual_functions.cpp index 1eba534dd..6e06db9fc 100644 --- a/tests/test_virtual_functions.cpp +++ b/tests/test_virtual_functions.cpp @@ -174,6 +174,25 @@ struct DispatchIssue : Base { } }; +// An abstract adder class that uses visitor pattern to add two data +// objects and send the result to the visitor functor +struct AdderBase { + struct Data {}; + using DataVisitor = std::function; + + virtual void operator()(const Data& first, const Data& second, const DataVisitor& visitor) const = 0; + virtual ~AdderBase() = default; + AdderBase() = default; + AdderBase(const AdderBase&) = delete; +}; + +struct Adder : AdderBase { + void operator()(const Data& first, const Data& second, const DataVisitor& visitor) const override { + PYBIND11_OVERRIDE_PURE_NAME(void, AdderBase, "__call__", operator(), first, second, visitor); + } +}; + + static void test_gil() { { py::gil_scoped_acquire lock; @@ -295,6 +314,27 @@ TEST_SUBMODULE(virtual_functions, m) { m.def("dispatch_issue_go", [](const Base * b) { return b->dispatch(); }); + // test_recursive_dispatch_issue + // #3357: Recursive dispatch fails to find python function override + pybind11::class_(m, "Adder") + .def(pybind11::init<>()) + .def("__call__", &AdderBase::operator()); + + pybind11::class_(m, "Data") + .def(pybind11::init<>()); + + m.def("add2", [](const AdderBase::Data& first, const AdderBase::Data& second, + const AdderBase& adder, const AdderBase::DataVisitor& visitor) { + adder(first, second, visitor); + }); + + m.def("add3", [](const AdderBase::Data& first, const AdderBase::Data& second, const AdderBase::Data& third, + const AdderBase& adder, const AdderBase::DataVisitor& visitor) { + adder(first, second, [&] (const AdderBase::Data& first_plus_second) { + adder(first_plus_second, third, visitor); + }); + }); + // test_override_ref // #392/397: overriding reference-returning functions class OverrideTest { diff --git a/tests/test_virtual_functions.py b/tests/test_virtual_functions.py index f7d3bd1e4..0b550992f 100644 --- a/tests/test_virtual_functions.py +++ b/tests/test_virtual_functions.py @@ -257,6 +257,39 @@ def test_dispatch_issue(msg): assert m.dispatch_issue_go(b) == "Yay.." +def test_recursive_dispatch_issue(msg): + """#3357: Recursive dispatch fails to find python function override""" + + class Data(m.Data): + def __init__(self, value): + super(Data, self).__init__() + self.value = value + + class Adder(m.Adder): + def __call__(self, first, second, visitor): + # lambda is a workaround, which adds extra frame to the + # current CPython thread. Removing lambda reveals the bug + # [https://github.com/pybind/pybind11/issues/3357] + (lambda: visitor(Data(first.value + second.value)))() + + class StoreResultVisitor: + def __init__(self): + self.result = None + + def __call__(self, data): + self.result = data.value + + store = StoreResultVisitor() + + m.add2(Data(1), Data(2), Adder(), store) + assert store.result == 3 + + # without lambda in Adder class, this function fails with + # RuntimeError: Tried to call pure virtual function "AdderBase::__call__" + m.add3(Data(1), Data(2), Data(3), Adder(), store) + assert store.result == 6 + + def test_override_ref(): """#392/397: overriding reference-returning functions""" o = m.OverrideTest("asdf") From 78ee782bd494debcbc166f717379a4f9c2093c0f Mon Sep 17 00:00:00 2001 From: Aaron Gokaslan Date: Sat, 23 Oct 2021 00:07:22 -0400 Subject: [PATCH 15/22] feat: Add C++ binding to throw AttributeError (#3387) * Add C++ bindings to throw AttributeError * Fix formatting bug --- docs/advanced/exceptions.rst | 4 +++- include/pybind11/detail/common.h | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/advanced/exceptions.rst b/docs/advanced/exceptions.rst index b4825cbcd..40f67d7b8 100644 --- a/docs/advanced/exceptions.rst +++ b/docs/advanced/exceptions.rst @@ -56,7 +56,9 @@ at its exception handler. +--------------------------------------+--------------------------------------+ | :class:`pybind11::buffer_error` | ``BufferError`` | +--------------------------------------+--------------------------------------+ -| :class:`pybind11::import_error` | ``import_error`` | +| :class:`pybind11::import_error` | ``ImportError`` | ++--------------------------------------+--------------------------------------+ +| :class:`pybind11::attribute_error` | ``AttributeError`` | +--------------------------------------+--------------------------------------+ | Any other exception | ``RuntimeError`` | +--------------------------------------+--------------------------------------+ diff --git a/include/pybind11/detail/common.h b/include/pybind11/detail/common.h index 9ad305a4e..862451fd1 100644 --- a/include/pybind11/detail/common.h +++ b/include/pybind11/detail/common.h @@ -831,6 +831,7 @@ PYBIND11_RUNTIME_EXCEPTION(value_error, PyExc_ValueError) PYBIND11_RUNTIME_EXCEPTION(type_error, PyExc_TypeError) PYBIND11_RUNTIME_EXCEPTION(buffer_error, PyExc_BufferError) PYBIND11_RUNTIME_EXCEPTION(import_error, PyExc_ImportError) +PYBIND11_RUNTIME_EXCEPTION(attribute_error, PyExc_AttributeError) PYBIND11_RUNTIME_EXCEPTION(cast_error, PyExc_RuntimeError) /// Thrown when pybind11::cast or handle::call fail due to a type casting error PYBIND11_RUNTIME_EXCEPTION(reference_cast_error, PyExc_RuntimeError) /// Used internally From 9379b399d99a784f7e226f135fb117aff6db8013 Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Mon, 25 Oct 2021 16:01:19 -0400 Subject: [PATCH 16/22] fix: MSVC 2017 C++17 on Python 3 regression (#3407) * fix: MSVC 2017 C++17 on Python 3 regression * ci: add 3.7 job on CI --- .github/workflows/ci.yml | 4 ++++ include/pybind11/functional.h | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 09b400056..b027640df 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -851,6 +851,10 @@ jobs: std: 17 args: > -DCMAKE_CXX_FLAGS="/permissive- /EHsc /GR" + - python: 3.7 + std: 17 + args: > + -DCMAKE_CXX_FLAGS="/permissive- /EHsc /GR" steps: - uses: actions/checkout@v2 diff --git a/include/pybind11/functional.h b/include/pybind11/functional.h index 24141ce38..ad5608c25 100644 --- a/include/pybind11/functional.h +++ b/include/pybind11/functional.h @@ -69,7 +69,7 @@ public: // ensure GIL is held during functor destruction struct func_handle { function f; -#if !(defined(_MSC_VER) && _MSC_VER == 1916 && defined(PYBIND11_CPP17) && PY_MAJOR_VERSION < 3) +#if !(defined(_MSC_VER) && _MSC_VER == 1916 && defined(PYBIND11_CPP17)) // This triggers a syntax error under very special conditions (very weird indeed). explicit #endif From d45a88105c3dab1dc2a1da831f1c83a0f3b57f8b Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 25 Oct 2021 16:06:13 -0400 Subject: [PATCH 17/22] [pre-commit.ci] pre-commit autoupdate (#3409) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/asottile/yesqa: v1.2.3 → v1.3.0](https://github.com/asottile/yesqa/compare/v1.2.3...v1.3.0) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 04166de9a..b3e517905 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -82,7 +82,7 @@ repos: exclude: ^(docs/.*|tools/.*)$ - repo: https://github.com/asottile/yesqa - rev: v1.2.3 + rev: v1.3.0 hooks: - id: yesqa additional_dependencies: *flake8_dependencies From c2d3e220bd1bfcf664e29d95ac2ed774fd6723f4 Mon Sep 17 00:00:00 2001 From: Ryan Cahoon Date: Mon, 25 Oct 2021 19:04:45 -0700 Subject: [PATCH 18/22] fix: the types for return_value_policy_override in optional_caster (#3376) * fix: the types for return_value_policy_override in optional_caster `return_value_policy_override` was not being applied correctly in `optional_caster` in two ways: - The `is_lvalue_reference` condition referenced `T`, which was the `optional` type parameter from the class, when it should have used `T_`, which was the parameter to the `cast` function. `T_` can potentially be a reference type, but `T` will never be. - The type parameter passed to `return_value_policy_override` should be `T::value_type`, not `T`. This matches the way that the other STL container type casters work. The result of these issues was that a method/property definition which used a `reference` or `reference_internal` return value policy would create a Python value that's bound by reference to a temporary C++ object, resulting in undefined behavior. For reasons that I was not able to figure out fully, it seems like this causes problems when using old versions of `boost::optional`, but not with recent versions of `boost::optional` or the `libstdc++` implementation of `std::optional`. The issue (that the override to `return_value_policy::move` is never being applied) is present for all implementations, it just seems like that somehow doesn't result in problems for the some implementation of `optional`. This change includes a regression type with a custom optional-like type which was able to reproduce the issue. Part of the issue with using the wrong types may have stemmed from the type variables `T` and `T_` having very similar names. This also changes the type variables in `optional_caster` to use slightly more descriptive names, which also more closely follow the naming convention used by the other STL casters. Fixes #3330 * Fix clang-tidy complaints * Add missing NOLINT * Apply a couple more fixes * fix: support GCC 4.8 * tests: avoid warning about unknown compiler for compilers missing C++17 * Remove unneeded test module attribute * Change test enum to have more unique int values Co-authored-by: Aaron Gokaslan Co-authored-by: Henry Schreiner --- include/pybind11/stl.h | 16 ++-- tests/CMakeLists.txt | 6 +- tests/test_stl.cpp | 189 ++++++++++++++++++++++++++++++++++++++++- tests/test_stl.py | 67 +++++++++++++++ 4 files changed, 265 insertions(+), 13 deletions(-) diff --git a/include/pybind11/stl.h b/include/pybind11/stl.h index 2c017b4fe..3608d2989 100644 --- a/include/pybind11/stl.h +++ b/include/pybind11/stl.h @@ -245,17 +245,17 @@ template , Key, Value> { }; // This type caster is intended to be used for std::optional and std::experimental::optional -template struct optional_caster { - using value_conv = make_caster; +template struct optional_caster { + using value_conv = make_caster; - template - static handle cast(T_ &&src, return_value_policy policy, handle parent) { + template + static handle cast(T &&src, return_value_policy policy, handle parent) { if (!src) return none().inc_ref(); if (!std::is_lvalue_reference::value) { - policy = return_value_policy_override::policy(policy); + policy = return_value_policy_override::policy(policy); } - return value_conv::cast(*std::forward(src), policy, parent); + return value_conv::cast(*std::forward(src), policy, parent); } bool load(handle src, bool convert) { @@ -269,11 +269,11 @@ template struct optional_caster { if (!inner_caster.load(src, convert)) return false; - value.emplace(cast_op(std::move(inner_caster))); + value.emplace(cast_op(std::move(inner_caster))); return true; } - PYBIND11_TYPE_CASTER(T, _("Optional[") + value_conv::name + _("]")); + PYBIND11_TYPE_CASTER(Type, _("Optional[") + value_conv::name + _("]")); }; #if defined(PYBIND11_HAS_OPTIONAL) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index d4e7b71e1..e1b18dd74 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -256,7 +256,9 @@ if(Boost_FOUND) endif() # Check if we need to add -lstdc++fs or -lc++fs or nothing -if(MSVC) +if(DEFINED CMAKE_CXX_STANDARD AND CMAKE_CXX_STANDARD LESS 17) + set(STD_FS_NO_LIB_NEEDED TRUE) +elseif(MSVC) set(STD_FS_NO_LIB_NEEDED TRUE) else() file( @@ -286,7 +288,7 @@ elseif(${STD_FS_NEEDS_CXXFS}) elseif(${STD_FS_NO_LIB_NEEDED}) set(STD_FS_LIB "") else() - message(WARNING "Unknown compiler - not passing -lstdc++fs") + message(WARNING "Unknown C++17 compiler - not passing -lstdc++fs") set(STD_FS_LIB "") endif() diff --git a/tests/test_stl.cpp b/tests/test_stl.cpp index 7e3363c5e..bc5c6553a 100644 --- a/tests/test_stl.cpp +++ b/tests/test_stl.cpp @@ -19,6 +19,18 @@ #include #include +#if defined(PYBIND11_TEST_BOOST) +#include + +namespace pybind11 { namespace detail { +template +struct type_caster> : optional_caster> {}; + +template <> +struct type_caster : void_caster {}; +}} // namespace pybind11::detail +#endif + // Test with `std::variant` in C++17 mode, or with `boost::variant` in C++11/14 #if defined(PYBIND11_HAS_VARIANT) using std::variant; @@ -59,7 +71,8 @@ namespace std { template