From 76b885811096421eff6ccd612de93e328ff3461f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20W=C3=BCrtz?= Date: Wed, 23 Aug 2023 18:49:35 +0200 Subject: [PATCH 01/11] fix: Different MSVC versions may be ABI incompatible, guard with _MSC_VER (#2898) (#4779) --- include/pybind11/detail/internals.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/pybind11/detail/internals.h b/include/pybind11/detail/internals.h index 228dd764b..a9136fa8e 100644 --- a/include/pybind11/detail/internals.h +++ b/include/pybind11/detail/internals.h @@ -291,9 +291,12 @@ struct type_info { #endif /// On Linux/OSX, changes in __GXX_ABI_VERSION__ indicate ABI incompatibility. +/// On MSVC, changes in _MSC_VER may indicate ABI incompatibility (#2898). #ifndef PYBIND11_BUILD_ABI # if defined(__GXX_ABI_VERSION) # define PYBIND11_BUILD_ABI "_cxxabi" PYBIND11_TOSTRING(__GXX_ABI_VERSION) +# elif defined(_MSC_VER) +# define PYBIND11_BUILD_ABI "_mscver" PYBIND11_TOSTRING(_MSC_VER) # else # define PYBIND11_BUILD_ABI "" # endif From 1adac5a5b104be5f0a8caae75667640df125594a Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Wed, 30 Aug 2023 10:05:24 -0700 Subject: [PATCH 02/11] `PYBIND11_INTERNALS_VERSION` bump for MSVC, piggy-backed on PR #4779. See comments there. (#4819) --- include/pybind11/detail/internals.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/pybind11/detail/internals.h b/include/pybind11/detail/internals.h index a9136fa8e..e2c94ea96 100644 --- a/include/pybind11/detail/internals.h +++ b/include/pybind11/detail/internals.h @@ -34,8 +34,9 @@ /// further ABI-incompatible changes may be made before the ABI is officially /// changed to the new version. #ifndef PYBIND11_INTERNALS_VERSION -# if PY_VERSION_HEX >= 0x030C0000 +# if PY_VERSION_HEX >= 0x030C0000 || defined(_MSC_VER) // Version bump for Python 3.12+, before first 3.12 beta release. +// Version bump for MSVC piggy-backed on PR #4779. See comments there. # define PYBIND11_INTERNALS_VERSION 5 # else # define PYBIND11_INTERNALS_VERSION 4 From e705fb5f2764446a6ae7b4ae4f51dcef8c107006 Mon Sep 17 00:00:00 2001 From: Sergei Izmailov Date: Thu, 31 Aug 2023 06:20:46 +0900 Subject: [PATCH 03/11] Fix enum's `__str__` docstring (#4827) * fix: Enum __str__ function name * tests: Test enum.__str__.__doc__ --- include/pybind11/pybind11.h | 2 +- tests/test_enum.py | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index db91639dc..e6c9ad0ac 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -2014,7 +2014,7 @@ struct enum_base { object type_name = type::handle_of(arg).attr("__name__"); return pybind11::str("{}.{}").format(std::move(type_name), enum_name(arg)); }, - name("name"), + name("__str__"), is_method(m_base)); if (options::show_enum_members_docstring()) { diff --git a/tests/test_enum.py b/tests/test_enum.py index 4e85d29c3..b97b0fa56 100644 --- a/tests/test_enum.py +++ b/tests/test_enum.py @@ -264,3 +264,8 @@ def test_docstring_signatures(): for attr in enum_type.__dict__.values(): # Issue #2623/PR #2637: Add argument names to enum_ methods assert "arg0" not in (attr.__doc__ or "") + + +def test_str_signature(): + for enum_type in [m.ScopedEnum, m.UnscopedEnum]: + assert enum_type.__str__.__doc__.startswith("__str__") From db412e6e8648a5687d73ef4cf28738d1e7f0e53f Mon Sep 17 00:00:00 2001 From: Sergei Izmailov Date: Thu, 31 Aug 2023 14:43:01 +0900 Subject: [PATCH 04/11] fix: Render `py::function` as `Callable` (#4829) * fix: Render `py::function` as `Callable` * style: pre-commit fixes --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- include/pybind11/cast.h | 4 ++++ tests/test_callbacks.py | 7 +++++++ 2 files changed, 11 insertions(+) diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index b3c8ebe17..8a4e2e647 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -898,6 +898,10 @@ struct handle_type_name { static constexpr auto name = const_name("float"); }; template <> +struct handle_type_name { + static constexpr auto name = const_name("Callable"); +}; +template <> struct handle_type_name { static constexpr auto name = const_name("None"); }; diff --git a/tests/test_callbacks.py b/tests/test_callbacks.py index 4a652f53e..86c767455 100644 --- a/tests/test_callbacks.py +++ b/tests/test_callbacks.py @@ -216,3 +216,10 @@ def test_custom_func(): def test_custom_func2(): assert m.custom_function2(3) == 27 assert m.roundtrip(m.custom_function2)(3) == 27 + + +def test_callback_docstring(): + assert ( + m.test_tuple_unpacking.__doc__.strip() + == "test_tuple_unpacking(arg0: Callable) -> object" + ) From c9638a1927ca6cfe731bd27eeef885cfc26a762b Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Fri, 1 Sep 2023 11:31:22 -0700 Subject: [PATCH 05/11] Help Coverty avoid generating a false positive. (#4817) * Change variable name `it` to `curr_overl` to improve readability, add `assert()` in the only place where `curr_overl` could become `nullptr`. * Move the `assert()` to where Coverty generates a false positive. * variable name as suggested by @henryiii --- include/pybind11/pybind11.h | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index e6c9ad0ac..0a82f8dd7 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -719,7 +719,7 @@ protected: /* Iterator over the list of potentially admissible overloads */ const function_record *overloads = reinterpret_cast( PyCapsule_GetPointer(self, get_function_record_capsule_name())), - *it = overloads; + *current_overload = overloads; assert(overloads != nullptr); /* Need to know how many arguments + keyword arguments there are to pick the right @@ -757,9 +757,10 @@ protected: std::vector second_pass; // However, if there are no overloads, we can just skip the no-convert pass entirely - const bool overloaded = it != nullptr && it->next != nullptr; + const bool overloaded + = current_overload != nullptr && current_overload->next != nullptr; - for (; it != nullptr; it = it->next) { + for (; current_overload != nullptr; current_overload = current_overload->next) { /* For each overload: 1. Copy all positional arguments we were given, also checking to make sure that @@ -780,7 +781,7 @@ protected: a result other than PYBIND11_TRY_NEXT_OVERLOAD. */ - const function_record &func = *it; + const function_record &func = *current_overload; size_t num_args = func.nargs; // Number of positional arguments that we need if (func.has_args) { --num_args; // (but don't count py::args @@ -1018,10 +1019,10 @@ protected: } if (result.ptr() != PYBIND11_TRY_NEXT_OVERLOAD) { - // The error reporting logic below expects 'it' to be valid, as it would be - // if we'd encountered this failure in the first-pass loop. + // The error reporting logic below expects 'current_overload' to be valid, + // as it would be if we'd encountered this failure in the first-pass loop. if (!result) { - it = &call.func; + current_overload = &call.func; } break; } @@ -1168,7 +1169,8 @@ protected: if (!result) { std::string msg = "Unable to convert function return value to a " "Python type! The signature was\n\t"; - msg += it->signature; + assert(current_overload != nullptr); + msg += current_overload->signature; append_note_if_missing_header_is_suspected(msg); // Attach additional error info to the exception if supported if (PyErr_Occurred()) { From 467fe27bd9f4f335bd1423d532927fa894446bec Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 6 Sep 2023 06:04:27 -0700 Subject: [PATCH 06/11] chore(deps): update pre-commit hooks (#4838) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore(deps): update pre-commit hooks updates: - [github.com/astral-sh/ruff-pre-commit: v0.0.281 → v0.0.287](https://github.com/astral-sh/ruff-pre-commit/compare/v0.0.281...v0.0.287) - [github.com/pre-commit/mirrors-mypy: v1.4.1 → v1.5.1](https://github.com/pre-commit/mirrors-mypy/compare/v1.4.1...v1.5.1) - [github.com/asottile/blacken-docs: 1.15.0 → 1.16.0](https://github.com/asottile/blacken-docs/compare/1.15.0...1.16.0) - [github.com/Lucas-C/pre-commit-hooks: v1.5.1 → v1.5.4](https://github.com/Lucas-C/pre-commit-hooks/compare/v1.5.1...v1.5.4) - [github.com/PyCQA/pylint: v3.0.0a6 → v3.0.0a7](https://github.com/PyCQA/pylint/compare/v3.0.0a6...v3.0.0a7) * style: pre-commit fixes * Update pyproject.toml --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Henry Schreiner --- .pre-commit-config.yaml | 10 +++++----- docs/benchmark.py | 2 +- pyproject.toml | 2 +- tests/test_stl_binders.py | 6 +++--- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 4102ee3b9..f1fb4ae11 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -38,14 +38,14 @@ repos: # Ruff, the Python auto-correcting linter written in Rust - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.0.281 + rev: v0.0.287 hooks: - id: ruff args: ["--fix", "--show-fixes"] # Check static types with mypy - repo: https://github.com/pre-commit/mirrors-mypy - rev: "v1.4.1" + rev: "v1.5.1" hooks: - id: mypy args: [] @@ -84,7 +84,7 @@ repos: # Also code format the docs - repo: https://github.com/asottile/blacken-docs - rev: "1.15.0" + rev: "1.16.0" hooks: - id: blacken-docs additional_dependencies: @@ -92,7 +92,7 @@ repos: # Changes tabs to spaces - repo: https://github.com/Lucas-C/pre-commit-hooks - rev: "v1.5.1" + rev: "v1.5.4" hooks: - id: remove-tabs @@ -147,7 +147,7 @@ repos: # PyLint has native support - not always usable, but works for us - repo: https://github.com/PyCQA/pylint - rev: "v3.0.0a6" + rev: "v3.0.0a7" hooks: - id: pylint files: ^pybind11 diff --git a/docs/benchmark.py b/docs/benchmark.py index 2150b6ca7..fb49fd048 100644 --- a/docs/benchmark.py +++ b/docs/benchmark.py @@ -70,7 +70,7 @@ def generate_dummy_code_boost(nclasses=10): for codegen in [generate_dummy_code_pybind11, generate_dummy_code_boost]: print("{") - for i in range(0, 10): + for i in range(10): nclasses = 2**i with open("test.cpp", "w") as f: f.write(codegen(nclasses)) diff --git a/pyproject.toml b/pyproject.toml index 59c15ea63..ef2a8736b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -94,5 +94,5 @@ line-length = 120 isort.known-first-party = ["env", "pybind11_cross_module_tests", "pybind11_tests"] [tool.ruff.per-file-ignores] -"tests/**" = ["EM", "N"] +"tests/**" = ["EM", "N", "E721"] "tests/test_call_policies.py" = ["PLC1901"] diff --git a/tests/test_stl_binders.py b/tests/test_stl_binders.py index e002f5b67..79923f482 100644 --- a/tests/test_stl_binders.py +++ b/tests/test_stl_binders.py @@ -209,7 +209,7 @@ def test_map_string_double_const(): def test_noncopyable_containers(): # std::vector vnc = m.get_vnc(5) - for i in range(0, 5): + for i in range(5): assert vnc[i].value == i + 1 for i, j in enumerate(vnc, start=1): @@ -217,7 +217,7 @@ def test_noncopyable_containers(): # std::deque dnc = m.get_dnc(5) - for i in range(0, 5): + for i in range(5): assert dnc[i].value == i + 1 i = 1 @@ -252,7 +252,7 @@ def test_noncopyable_containers(): # nested std::map nvnc = m.get_nvnc(5) for i in range(1, 6): - for j in range(0, 5): + for j in range(5): assert nvnc[i][j].value == j + 1 # Note: maps do not have .values() From 4a2f7e4681cc912d4251a74c04a96c8c5a3896fe Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 6 Sep 2023 15:57:18 -0400 Subject: [PATCH 07/11] chore(deps): bump actions/checkout from 1 to 4 (#4836) * chore(deps): bump actions/checkout from 1 to 4 Bumps [actions/checkout](https://github.com/actions/checkout) from 1 to 4. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v1...v4) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] * Update .github/workflows/ci.yml * actions/checkout@v1 for centos:7 * Fix oversight: centos:7 actually works with actions/checkout@v3 --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Henry Schreiner Co-authored-by: Ralf W. Grosse-Kunstleve --- .github/workflows/ci.yml | 40 +++++++++++++++++++-------------- .github/workflows/configure.yml | 2 +- .github/workflows/format.yml | 4 ++-- .github/workflows/pip.yml | 4 ++-- .github/workflows/upstream.yml | 2 +- 5 files changed, 29 insertions(+), 23 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ee8bdd870..9fcf0ca52 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -69,7 +69,7 @@ jobs: runs-on: ${{ matrix.runs-on }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Setup Python ${{ matrix.python }} uses: actions/setup-python@v4 @@ -205,7 +205,7 @@ jobs: runs-on: ubuntu-20.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Setup Python ${{ matrix.python-version }} (deadsnakes) uses: deadsnakes/action@v3.0.1 @@ -310,7 +310,7 @@ jobs: container: "silkeh/clang:${{ matrix.clang }}${{ matrix.container_suffix }}" steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Add wget and python3 run: apt-get update && apt-get install -y python3-dev python3-numpy python3-pytest libeigen3-dev @@ -344,7 +344,7 @@ jobs: container: nvidia/cuda:12.2.0-devel-ubuntu22.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 # tzdata will try to ask for the timezone, so set the DEBIAN_FRONTEND - name: Install 🐍 3 @@ -368,7 +368,7 @@ jobs: # container: centos:8 # # steps: -# - uses: actions/checkout@v3 +# - uses: actions/checkout@v4 # # - name: Add Python 3 and a few requirements # run: yum update -y && yum install -y git python3-devel python3-numpy python3-pytest make environment-modules @@ -413,7 +413,7 @@ jobs: # tzdata will try to ask for the timezone, so set the DEBIAN_FRONTEND DEBIAN_FRONTEND: 'noninteractive' steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Add NVHPC Repo run: | @@ -475,7 +475,7 @@ jobs: container: "gcc:${{ matrix.gcc }}" steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Add Python 3 run: apt-get update; apt-get install -y python3-dev python3-numpy python3-pytest python3-pip libeigen3-dev @@ -535,7 +535,7 @@ jobs: name: "🐍 3 • ICC latest • x64" steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Add apt repo run: | @@ -639,7 +639,13 @@ jobs: container: "${{ matrix.container }}" steps: - - uses: actions/checkout@v3 + - name: Latest actions/checkout + uses: actions/checkout@v4 + if: matrix.container != 'centos:7' + + - name: Pin actions/checkout as required for centos:7 + uses: actions/checkout@v3 + if: matrix.container == 'centos:7' - name: Add Python 3 (RHEL 7) if: matrix.container == 'centos:7' @@ -687,7 +693,7 @@ jobs: container: i386/debian:buster steps: - - uses: actions/checkout@v1 # Required to run inside docker + - uses: actions/checkout@v1 # v1 is required to run inside docker - name: Install requirements run: | @@ -730,7 +736,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions/setup-python@v4 with: @@ -782,7 +788,7 @@ jobs: runs-on: windows-2019 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Setup Python ${{ matrix.python }} uses: actions/setup-python@v4 @@ -835,7 +841,7 @@ jobs: runs-on: windows-2019 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Setup Python ${{ matrix.python }} uses: actions/setup-python@v4 @@ -883,7 +889,7 @@ jobs: runs-on: windows-2022 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Setup Python ${{ matrix.python }} uses: actions/setup-python@v4 @@ -961,7 +967,7 @@ jobs: mingw-w64-${{matrix.env}}-boost mingw-w64-${{matrix.env}}-catch - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Configure C++11 # LTO leads to many undefined reference like @@ -1032,7 +1038,7 @@ jobs: run: env - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set up Clang uses: egor-tensin/setup-clang@v1 @@ -1101,7 +1107,7 @@ jobs: run: env - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Show Clang++ version before brew install llvm run: clang++ --version diff --git a/.github/workflows/configure.yml b/.github/workflows/configure.yml index ec7cd612d..a49d8d252 100644 --- a/.github/workflows/configure.yml +++ b/.github/workflows/configure.yml @@ -49,7 +49,7 @@ jobs: runs-on: ${{ matrix.runs-on }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Setup Python 3.7 uses: actions/setup-python@v4 diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml index b8242ee52..9b2da5944 100644 --- a/.github/workflows/format.yml +++ b/.github/workflows/format.yml @@ -25,7 +25,7 @@ jobs: name: Format runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions/setup-python@v4 with: python-version: "3.x" @@ -43,7 +43,7 @@ jobs: runs-on: ubuntu-latest container: silkeh/clang:15-bullseye steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install requirements run: apt-get update && apt-get install -y git python3-dev python3-pytest diff --git a/.github/workflows/pip.yml b/.github/workflows/pip.yml index d6687b441..5bc7c4b9c 100644 --- a/.github/workflows/pip.yml +++ b/.github/workflows/pip.yml @@ -28,7 +28,7 @@ jobs: runs-on: windows-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Setup 🐍 3.6 uses: actions/setup-python@v4 @@ -50,7 +50,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Setup 🐍 3.8 uses: actions/setup-python@v4 diff --git a/.github/workflows/upstream.yml b/.github/workflows/upstream.yml index dd8a1c960..5d893cd85 100644 --- a/.github/workflows/upstream.yml +++ b/.github/workflows/upstream.yml @@ -25,7 +25,7 @@ jobs: if: "contains(github.event.pull_request.labels.*.name, 'python dev')" steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Setup Python 3.12 uses: actions/setup-python@v4 From c83605936b5e09ae806c40fe798d1e0b1143e272 Mon Sep 17 00:00:00 2001 From: Sergei Izmailov Date: Thu, 7 Sep 2023 21:57:39 +0900 Subject: [PATCH 08/11] feature: Support move-only iterators in `py::make_*iterator` (#4834) * feature: Support move-only iterators in `py::make_*iterator` * fix: Missing static assertion message * fixup: Missing `explicit` in single argument constructors * fix: Simplify tests: make existing iterator move-only * fix: Missing `noexcept` --- include/pybind11/pybind11.h | 14 ++++++++++---- tests/test_sequences_and_iterators.cpp | 19 +++++++++++++++++++ 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index 0a82f8dd7..5e3c5c657 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -2434,7 +2434,7 @@ iterator make_iterator_impl(Iterator first, Sentinel last, Extra &&...extra) { Policy); } - return cast(state{first, last, true}); + return cast(state{std::forward(first), std::forward(last), true}); } PYBIND11_NAMESPACE_END(detail) @@ -2451,7 +2451,9 @@ iterator make_iterator(Iterator first, Sentinel last, Extra &&...extra) { Iterator, Sentinel, ValueType, - Extra...>(first, last, std::forward(extra)...); + Extra...>(std::forward(first), + std::forward(last), + std::forward(extra)...); } /// Makes a python iterator over the keys (`.first`) of a iterator over pairs from a @@ -2467,7 +2469,9 @@ iterator make_key_iterator(Iterator first, Sentinel last, Extra &&...extra) { Iterator, Sentinel, KeyType, - Extra...>(first, last, std::forward(extra)...); + Extra...>(std::forward(first), + std::forward(last), + std::forward(extra)...); } /// Makes a python iterator over the values (`.second`) of a iterator over pairs from a @@ -2483,7 +2487,9 @@ iterator make_value_iterator(Iterator first, Sentinel last, Extra &&...extra) { Iterator, Sentinel, ValueType, - Extra...>(first, last, std::forward(extra)...); + Extra...>(std::forward(first), + std::forward(last), + std::forward(extra)...); } /// Makes an iterator over values of an stl container or other container supporting diff --git a/tests/test_sequences_and_iterators.cpp b/tests/test_sequences_and_iterators.cpp index 1de65edbf..4a1d37f4d 100644 --- a/tests/test_sequences_and_iterators.cpp +++ b/tests/test_sequences_and_iterators.cpp @@ -28,6 +28,13 @@ class NonZeroIterator { public: explicit NonZeroIterator(const T *ptr) : ptr_(ptr) {} + + // Make the iterator non-copyable and movable + NonZeroIterator(const NonZeroIterator &) = delete; + NonZeroIterator(NonZeroIterator &&) noexcept = default; + NonZeroIterator &operator=(const NonZeroIterator &) = delete; + NonZeroIterator &operator=(NonZeroIterator &&) noexcept = default; + const T &operator*() const { return *ptr_; } NonZeroIterator &operator++() { ++ptr_; @@ -78,6 +85,7 @@ private: int value_; }; using NonCopyableIntPair = std::pair; + PYBIND11_MAKE_OPAQUE(std::vector); PYBIND11_MAKE_OPAQUE(std::vector); @@ -375,6 +383,17 @@ TEST_SUBMODULE(sequences_and_iterators, m) { private: std::vector> data_; }; + + { + // #4383 : Make sure `py::make_*iterator` functions work with move-only iterators + using iterator_t = NonZeroIterator>; + + static_assert(std::is_move_assignable::value, ""); + static_assert(std::is_move_constructible::value, ""); + static_assert(!std::is_copy_assignable::value, ""); + static_assert(!std::is_copy_constructible::value, ""); + } + py::class_(m, "IntPairs") .def(py::init>>()) .def( From c9149d995c801831632b654e0e8e65f2f2f31e2b Mon Sep 17 00:00:00 2001 From: Sergei Izmailov Date: Wed, 13 Sep 2023 04:46:58 +0900 Subject: [PATCH 09/11] fix: Use lowercase builtin collection names (#4833) --- include/pybind11/cast.h | 2 +- include/pybind11/stl.h | 8 ++++---- tests/test_builtin_casters.py | 4 ++-- tests/test_kwargs_and_defaults.py | 2 +- tests/test_stl.py | 24 ++++++++++++------------ 5 files changed, 20 insertions(+), 20 deletions(-) diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index 8a4e2e647..99bf4fac3 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -661,7 +661,7 @@ public: } static constexpr auto name - = const_name("Tuple[") + concat(make_caster::name...) + const_name("]"); + = const_name("tuple[") + concat(make_caster::name...) + const_name("]"); template using cast_op_type = type; diff --git a/include/pybind11/stl.h b/include/pybind11/stl.h index f39f44f7c..6eb485991 100644 --- a/include/pybind11/stl.h +++ b/include/pybind11/stl.h @@ -100,7 +100,7 @@ public: return s.release(); } - PYBIND11_TYPE_CASTER(type, const_name("Set[") + key_conv::name + const_name("]")); + PYBIND11_TYPE_CASTER(type, const_name("set[") + key_conv::name + const_name("]")); }; template @@ -157,7 +157,7 @@ public: } PYBIND11_TYPE_CASTER(Type, - const_name("Dict[") + key_conv::name + const_name(", ") + value_conv::name + const_name("dict[") + key_conv::name + const_name(", ") + value_conv::name + const_name("]")); }; @@ -208,7 +208,7 @@ public: return l.release(); } - PYBIND11_TYPE_CASTER(Type, const_name("List[") + value_conv::name + const_name("]")); + PYBIND11_TYPE_CASTER(Type, const_name("list[") + value_conv::name + const_name("]")); }; template @@ -274,7 +274,7 @@ public: PYBIND11_TYPE_CASTER(ArrayType, const_name(const_name(""), const_name("Annotated[")) - + const_name("List[") + value_conv::name + const_name("]") + + const_name("list[") + value_conv::name + const_name("]") + const_name(const_name(""), const_name(", FixedSize(") + const_name() + const_name(")]"))); diff --git a/tests/test_builtin_casters.py b/tests/test_builtin_casters.py index b1f57bdd9..dbac1cbc2 100644 --- a/tests/test_builtin_casters.py +++ b/tests/test_builtin_casters.py @@ -352,7 +352,7 @@ def test_tuple(doc): assert ( doc(m.pair_passthrough) == """ - pair_passthrough(arg0: Tuple[bool, str]) -> Tuple[str, bool] + pair_passthrough(arg0: tuple[bool, str]) -> tuple[str, bool] Return a pair in reversed order """ @@ -360,7 +360,7 @@ def test_tuple(doc): assert ( doc(m.tuple_passthrough) == """ - tuple_passthrough(arg0: Tuple[bool, str, int]) -> Tuple[int, str, bool] + tuple_passthrough(arg0: tuple[bool, str, int]) -> tuple[int, str, bool] Return a triple in reversed order """ diff --git a/tests/test_kwargs_and_defaults.py b/tests/test_kwargs_and_defaults.py index b57700197..9d9738de7 100644 --- a/tests/test_kwargs_and_defaults.py +++ b/tests/test_kwargs_and_defaults.py @@ -8,7 +8,7 @@ def test_function_signatures(doc): assert doc(m.kw_func1) == "kw_func1(x: int, y: int) -> str" assert doc(m.kw_func2) == "kw_func2(x: int = 100, y: int = 200) -> str" assert doc(m.kw_func3) == "kw_func3(data: str = 'Hello world!') -> None" - assert doc(m.kw_func4) == "kw_func4(myList: List[int] = [13, 17]) -> str" + assert doc(m.kw_func4) == "kw_func4(myList: list[int] = [13, 17]) -> str" assert doc(m.kw_func_udl) == "kw_func_udl(x: int, y: int = 300) -> str" assert doc(m.kw_func_udl_z) == "kw_func_udl_z(x: int, y: int = 0) -> str" assert doc(m.args_function) == "args_function(*args) -> tuple" diff --git a/tests/test_stl.py b/tests/test_stl.py index 8a614f8b8..b08bd4680 100644 --- a/tests/test_stl.py +++ b/tests/test_stl.py @@ -16,8 +16,8 @@ def test_vector(doc): assert m.load_bool_vector([True, False]) assert m.load_bool_vector((True, False)) - assert doc(m.cast_vector) == "cast_vector() -> List[int]" - assert doc(m.load_vector) == "load_vector(arg0: List[int]) -> bool" + assert doc(m.cast_vector) == "cast_vector() -> list[int]" + assert doc(m.load_vector) == "load_vector(arg0: list[int]) -> bool" # Test regression caused by 936: pointers to stl containers weren't castable assert m.cast_ptr_vector() == ["lvalue", "lvalue"] @@ -39,10 +39,10 @@ def test_array(doc): assert m.load_array(lst) assert m.load_array(tuple(lst)) - assert doc(m.cast_array) == "cast_array() -> Annotated[List[int], FixedSize(2)]" + assert doc(m.cast_array) == "cast_array() -> Annotated[list[int], FixedSize(2)]" assert ( doc(m.load_array) - == "load_array(arg0: Annotated[List[int], FixedSize(2)]) -> bool" + == "load_array(arg0: Annotated[list[int], FixedSize(2)]) -> bool" ) @@ -53,8 +53,8 @@ def test_valarray(doc): assert m.load_valarray(lst) assert m.load_valarray(tuple(lst)) - assert doc(m.cast_valarray) == "cast_valarray() -> List[int]" - assert doc(m.load_valarray) == "load_valarray(arg0: List[int]) -> bool" + assert doc(m.cast_valarray) == "cast_valarray() -> list[int]" + assert doc(m.load_valarray) == "load_valarray(arg0: list[int]) -> bool" def test_map(doc): @@ -66,8 +66,8 @@ def test_map(doc): assert "key2" in d assert m.load_map(d) - assert doc(m.cast_map) == "cast_map() -> Dict[str, str]" - assert doc(m.load_map) == "load_map(arg0: Dict[str, str]) -> bool" + assert doc(m.cast_map) == "cast_map() -> dict[str, str]" + assert doc(m.load_map) == "load_map(arg0: dict[str, str]) -> bool" def test_set(doc): @@ -78,8 +78,8 @@ def test_set(doc): assert m.load_set(s) assert m.load_set(frozenset(s)) - assert doc(m.cast_set) == "cast_set() -> Set[str]" - assert doc(m.load_set) == "load_set(arg0: Set[str]) -> bool" + assert doc(m.cast_set) == "cast_set() -> set[str]" + assert doc(m.load_set) == "load_set(arg0: set[str]) -> bool" def test_recursive_casting(): @@ -303,7 +303,7 @@ def test_stl_pass_by_pointer(msg): msg(excinfo.value) == """ stl_pass_by_pointer(): incompatible function arguments. The following argument types are supported: - 1. (v: List[int] = None) -> List[int] + 1. (v: list[int] = None) -> list[int] Invoked with: """ @@ -315,7 +315,7 @@ def test_stl_pass_by_pointer(msg): msg(excinfo.value) == """ stl_pass_by_pointer(): incompatible function arguments. The following argument types are supported: - 1. (v: List[int] = None) -> List[int] + 1. (v: list[int] = None) -> list[int] Invoked with: None """ From b4573674bc65a7842b49be45d63b582f4c15d1b4 Mon Sep 17 00:00:00 2001 From: Sergei Izmailov Date: Wed, 13 Sep 2023 04:47:39 +0900 Subject: [PATCH 10/11] Update render for buffer sequence and handle (#4831) * fix: Add capitalize render name of `py::buffer` and `py::sequence` * fix: Render `py::handle` same way as `py::object` * tests: Fix tests `handle` -> `object` * tests: Test capitaliation of `py::sequence` and `py::buffer` * style: pre-commit fixes * fix: Render `py::object` as `Any` * Revert "fix: Render `py::object` as `Any`" This reverts commit 7861dcfabb78ac210b4c67c35a0d47fb67525a96. --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Ralf W. Grosse-Kunstleve --- include/pybind11/cast.h | 12 ++++++++++++ tests/test_buffers.py | 7 +++++++ tests/test_factory_constructors.py | 4 ++-- tests/test_sequences_and_iterators.py | 4 ++++ 4 files changed, 25 insertions(+), 2 deletions(-) diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index 99bf4fac3..3c9b7c927 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -882,6 +882,10 @@ struct handle_type_name { static constexpr auto name = const_name(PYBIND11_BYTES_NAME); }; template <> +struct handle_type_name { + static constexpr auto name = const_name("Buffer"); +}; +template <> struct handle_type_name { static constexpr auto name = const_name("int"); }; @@ -902,10 +906,18 @@ struct handle_type_name { static constexpr auto name = const_name("Callable"); }; template <> +struct handle_type_name { + static constexpr auto name = handle_type_name::name; +}; +template <> struct handle_type_name { static constexpr auto name = const_name("None"); }; template <> +struct handle_type_name { + static constexpr auto name = const_name("Sequence"); +}; +template <> struct handle_type_name { static constexpr auto name = const_name("*args"); }; diff --git a/tests/test_buffers.py b/tests/test_buffers.py index 63d9d869f..5d33625ba 100644 --- a/tests/test_buffers.py +++ b/tests/test_buffers.py @@ -219,3 +219,10 @@ def test_ctypes_from_buffer(): assert cinfo.shape == pyinfo.shape assert cinfo.strides == pyinfo.strides assert not cinfo.readonly + + +def test_buffer_docstring(): + assert ( + m.get_buffer_info.__doc__.strip() + == "get_buffer_info(arg0: Buffer) -> pybind11_tests.buffers.buffer_info" + ) diff --git a/tests/test_factory_constructors.py b/tests/test_factory_constructors.py index 04df80260..a9004cbf6 100644 --- a/tests/test_factory_constructors.py +++ b/tests/test_factory_constructors.py @@ -77,7 +77,7 @@ def test_init_factory_signature(msg): 1. m.factory_constructors.TestFactory1(arg0: m.factory_constructors.tag.unique_ptr_tag, arg1: int) 2. m.factory_constructors.TestFactory1(arg0: str) 3. m.factory_constructors.TestFactory1(arg0: m.factory_constructors.tag.pointer_tag) - 4. m.factory_constructors.TestFactory1(arg0: handle, arg1: int, arg2: handle) + 4. m.factory_constructors.TestFactory1(arg0: object, arg1: int, arg2: object) Invoked with: 'invalid', 'constructor', 'arguments' """ @@ -95,7 +95,7 @@ def test_init_factory_signature(msg): 3. __init__(self: m.factory_constructors.TestFactory1, arg0: m.factory_constructors.tag.pointer_tag) -> None - 4. __init__(self: m.factory_constructors.TestFactory1, arg0: handle, arg1: int, arg2: handle) -> None + 4. __init__(self: m.factory_constructors.TestFactory1, arg0: object, arg1: int, arg2: object) -> None """ ) diff --git a/tests/test_sequences_and_iterators.py b/tests/test_sequences_and_iterators.py index dc129f2bf..acbe9d898 100644 --- a/tests/test_sequences_and_iterators.py +++ b/tests/test_sequences_and_iterators.py @@ -171,6 +171,10 @@ def test_sequence_length(): assert m.sequence_length("hello") == 5 +def test_sequence_doc(): + assert m.sequence_length.__doc__.strip() == "sequence_length(arg0: Sequence) -> int" + + def test_map_iterator(): sm = m.StringMap({"hi": "bye", "black": "white"}) assert sm["hi"] == "bye" From 8c7b8dd0ae74b36b7d42f77b0dd4096ebb7f4ab1 Mon Sep 17 00:00:00 2001 From: Sergei Izmailov Date: Wed, 13 Sep 2023 04:48:27 +0900 Subject: [PATCH 11/11] fix: Missing typed variants of `iterator` and `iterable` (#4832) --- include/pybind11/typing.h | 20 ++++++++++++++++++++ tests/test_pytypes.cpp | 2 ++ tests/test_pytypes.py | 14 ++++++++++++++ 3 files changed, 36 insertions(+) diff --git a/include/pybind11/typing.h b/include/pybind11/typing.h index 74fd82eac..b7b1a4e54 100644 --- a/include/pybind11/typing.h +++ b/include/pybind11/typing.h @@ -45,6 +45,16 @@ class Set : public set { using set::set; }; +template +class Iterable : public iterable { + using iterable::iterable; +}; + +template +class Iterator : public iterator { + using iterator::iterator; +}; + template class Callable; @@ -85,6 +95,16 @@ struct handle_type_name> { static constexpr auto name = const_name("set[") + make_caster::name + const_name("]"); }; +template +struct handle_type_name> { + static constexpr auto name = const_name("Iterable[") + make_caster::name + const_name("]"); +}; + +template +struct handle_type_name> { + static constexpr auto name = const_name("Iterator[") + make_caster::name + const_name("]"); +}; + template struct handle_type_name> { using retval_type = conditional_t::value, void_type, Return>; diff --git a/tests/test_pytypes.cpp b/tests/test_pytypes.cpp index b03f5624e..0a587680f 100644 --- a/tests/test_pytypes.cpp +++ b/tests/test_pytypes.cpp @@ -828,6 +828,8 @@ TEST_SUBMODULE(pytypes, m) { m.def("annotate_dict_str_int", [](const py::typing::Dict &) {}); m.def("annotate_list_int", [](const py::typing::List &) {}); m.def("annotate_set_str", [](const py::typing::Set &) {}); + m.def("annotate_iterable_str", [](const py::typing::Iterable &) {}); + m.def("annotate_iterator_int", [](const py::typing::Iterator &) {}); m.def("annotate_fn", [](const py::typing::Callable, py::str)> &) {}); } diff --git a/tests/test_pytypes.py b/tests/test_pytypes.py index e88a9328f..2b2027316 100644 --- a/tests/test_pytypes.py +++ b/tests/test_pytypes.py @@ -926,6 +926,20 @@ def test_set_annotations(doc): assert doc(m.annotate_set_str) == "annotate_set_str(arg0: set[str]) -> None" +def test_iterable_annotations(doc): + assert ( + doc(m.annotate_iterable_str) + == "annotate_iterable_str(arg0: Iterable[str]) -> None" + ) + + +def test_iterator_annotations(doc): + assert ( + doc(m.annotate_iterator_int) + == "annotate_iterator_int(arg0: Iterator[int]) -> None" + ) + + def test_fn_annotations(doc): assert ( doc(m.annotate_fn)