3271 Commits

Author SHA1 Message Date
Matti Picus
6079989cf7 Pypy testing no longer xfails (#6077)
* test passes on PyPy macOS

* adjust tests for pypy HEAD

* fixes from review

* pypy 7.3.23 was released, drop some PyPy testing

* pin to pypy version 7.3.23

* Restore xfail for cross-module translator platforms

Keep the expected failure for Android and FreeBSD while limiting the PyPy-specific part to versions before 7.3.23. Android CIBW still raises RuntimeError for this test, matching the existing tracked platform issue.

---------

Co-authored-by: Ralf W. Grosse-Kunstleve <rgrossekunst@nvidia.com>
2026-05-27 08:07:53 -07:00
ymwang78
46ebf5031b feat(subinterpreter): reusable PyThreadState via subinterpreter_thread_state (#6073)
* feat(subinterpreter): add opt-in TLS-cached thread state mode

subinterpreter_scoped_activate previously created and destroyed a fresh
PyThreadState on every activation when the calling OS thread was not
already running the target interpreter. Workloads that repeatedly
re-enter the same sub-interpreter from the same thread therefore churn
thread states and lose per-thread interpreter state between activations
(see pybind/pybind11#6040).

Add an opt-in subinterpreter_thread_state::cached policy: on first use a
PyThreadState is created and stored in OS-thread-local storage keyed by
the target interpreter; subsequent activations on that thread only swap
it in/out and never destroy it. The default stays transient, so existing
behavior is unchanged.

Since pybind11 does not control thread lifetime, cleanup is explicit:
subinterpreter::release_cached_thread_state() releases the calling
thread's cached state for one interpreter, and the static
release_all_cached_thread_states() releases all of the calling thread's
cached states as an end-of-thread hook. The TLS map's destructor only
frees its own nodes and never touches the Python C API, so an
unreleased state leaks rather than crashing at thread exit.

Includes test coverage and embedding docs.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* style: pre-commit fixes

* refactor(subinterpreter): replace cached enum/TLS with subinterpreter_thread_state RAII

Address review feedback on the original "cached" mode by switching to an
explicit two-RAII design suggested by @b-pass:

  "Create a class ... to RAII-manage the PyThreadState but start its
   lifetime in an already released state. You could create another
   class (or modify scoped_activate) to scoped/RAII activate the
   inactive threadstate."

Removed
  - enum subinterpreter_thread_state { transient, cached } and the
    defaulted ctor parameter on subinterpreter_scoped_activate.
  - detail::subinterpreter_thread_state_cache thread_local map.
  - subinterpreter::release_cached_thread_state() and
    subinterpreter::release_all_cached_thread_states().

This eliminates: the hidden per-thread map, the "release_all" footgun
across pybind11 modules (the cache was module-local), and the implicit
"must not be active when called" contract on the release functions.

Added
  - Public class subinterpreter_thread_state that owns one PyThreadState
    for a given subinterpreter on its constructing OS thread, created in
    a released state (not current, no GIL). Non-copyable, non-movable
    (PyThreadState is bound to its creating OS thread).
  - subinterpreter_scoped_activate(subinterpreter_thread_state &)
    overload: swaps the owned PyThreadState in on entry, swaps it out
    on exit, does not touch its lifetime.

Behavior
  - The existing subinterpreter_scoped_activate(subinterpreter const &)
    overload is unchanged (still transient: New on entry, Delete on
    exit). All previously-working code keeps working.
  - With subinterpreter_thread_state, one OS thread can alternate
    between multiple subinterpreters and each PyThreadState is preserved
    across activations -- the use case that gil_scoped_release/acquire
    + a long-lived scoped_activate cannot solve alone (the per-thread
    internals.tstate slot holds only one inactive tstate).
  - The dtor of subinterpreter_thread_state guards against the
    "destroyed-while-active" contract violation: if Swap reveals the
    cached tstate was current, do not Swap back to a now-deleted
    pointer (the safe-when-active fix b-pass requested for the old
    release_* functions, applied at the natural location instead).

Lifetime contract is enforced by ordinary C++ scope: typical placement
is `thread_local`. No new release/cleanup APIs are required.

Tests cover (a) tstate identity preserved across activations on a
thread, (b) transient and reusing modes do not share state, (c)
different OS threads get distinct PyThreadStates, and (d) the
multi-subinterpreter alternation case.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(subinterpreter): address review on #6073 (same-thread checks, test scoping)

Per @b-pass's review:

- ~subinterpreter_thread_state(): add a PYBIND11_DETAILED_ERROR_MESSAGES-
  guarded check that destruction happens on the OS thread that created the
  PyThreadState (same PyThread_get_thread_native_id pattern as ~subinterpreter),
  failing with pybind11_fail otherwise.
- subinterpreter_scoped_activate(subinterpreter_thread_state &): add the
  matching DETAILED_ERROR_MESSAGES check that activation happens on the
  creating OS thread, enforcing the newly documented rule.
- docs: document that activating a subinterpreter_thread_state on another OS
  thread is illegal.
- tests: keep each subinterpreter (and its subinterpreter_thread_state) in an
  enclosing scope so destruction order is thread-state -> subinterpreter ->
  unsafe_reset_internals_for_single_interpreter(). The previous top-level
  declarations ran the reset while the subinterpreters were still alive, which
  is the likely cause of the CI crashes.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* docs: fix codespell (re-used -> reused) in embedding.rst

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2026-05-25 09:31:14 -04:00
ctmd1234567
f891299e6a Fix custom __str__ for enum_ (#6078)
* fix: prioritize custom enum __str__

* test: strengthen custom enum __str__ regression

* refactor: move enum __str__ handling into enum_

Keep class_::def() generic and let enum_ own the enum-specific
behavior for custom __str__ overloads. This avoids using the private
__entries attribute as a runtime sentinel for py::enum_ while preserving
the prepend behavior that lets user-defined enum __str__ methods take
precedence over the generated default.

One caveat is that this applies to normal py::enum_ API usage. Code that
intentionally upcasts an enum_ binding to class_& and then calls
class_::def("__str__", ...) will bypass this enum_ override and keep the
generic class_ behavior.

* fix: avoid enum def ambiguity on MinGW

Remove the inherited class_::def overload set from enum_ and add an explicit forwarding overload for non-string def() calls. GCC 15 on MinGW otherwise sees the duplicate dependent-base def(const char *, ...) template as ambiguous with enum_::def(const char *, ...), breaking the C++11 build.

---------

Co-authored-by: ctmd1234567 <ctmd1234567@users.noreply.github.com>
Co-authored-by: Ralf W. Grosse-Kunstleve <rgrossekunst@nvidia.com>
2026-05-24 21:04:39 -07:00
jjuang-apple
a2592ad9d6 Apply -undefined dynamic_lookup to all Apple platforms (#6075)
* Apply -undefined dynamic_lookup to all Apple platforms

* style: pre-commit fixes

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2026-05-24 11:28:53 -07:00
dependabot[bot]
5205df97fc chore(deps): bump idna from 3.7 to 3.15 in /docs (#6074)
Bumps [idna](https://github.com/kjd/idna) from 3.7 to 3.15.
- [Release notes](https://github.com/kjd/idna/releases)
- [Changelog](https://github.com/kjd/idna/blob/master/HISTORY.md)
- [Commits](https://github.com/kjd/idna/compare/v3.7...v3.15)

---
updated-dependencies:
- dependency-name: idna
  dependency-version: '3.15'
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-20 15:23:32 -07:00
Ralf W. Grosse-Kunstleve
28bbda9ddf [skip ci] test: reject shared_ptr casts for custom holders (#6069)
Lock down the current behavior discussed in issue #6064: py::cast() from std::shared_ptr<T> remains rejected for custom holder bindings that are not std::shared_ptr or py::smart_holder.

This extracts the incompatible-holder coverage from PR #6068 and adds a test shaped like issue #6064, while PR #6065 and PR #6066 explore alternative support paths.
2026-05-18 21:36:16 -07:00
Ralf W. Grosse-Kunstleve
3160c82392 ci: pin Ubuntu PyPy 3.11 to 7.3.21 (#6070) 2026-05-18 11:31:19 -07:00
Matthias Klumpp
5a5f21deb6 fix: Invert input/output context if a Python function is called from C++ (#6055)
When the Callable itself is an input (parameter) to a C++ function, its
arguments are outputs (C++ passes them to the Python callback), and vice
versa.
Therefore, we must invert them if C++ calls a Python function, but keep
them the same in the other direction.
2026-05-16 11:28:05 -07:00
pre-commit-ci[bot]
00a9c6244c chore(deps): update pre-commit hooks (#6054)
* chore(deps): update pre-commit hooks

updates:
- [github.com/pre-commit/mirrors-clang-format: v22.1.2 → v22.1.4](https://github.com/pre-commit/mirrors-clang-format/compare/v22.1.2...v22.1.4)
- [github.com/astral-sh/ruff-pre-commit: v0.15.9 → v0.15.12](https://github.com/astral-sh/ruff-pre-commit/compare/v0.15.9...v0.15.12)
- [github.com/pre-commit/mirrors-mypy: v1.20.0 → v1.20.2](https://github.com/pre-commit/mirrors-mypy/compare/v1.20.0...v1.20.2)
- [github.com/adhtruong/mirrors-typos: v1.45.0 → v1.46.0](https://github.com/adhtruong/mirrors-typos/compare/v1.45.0...v1.46.0)
- [github.com/python-jsonschema/check-jsonschema: 0.37.1 → 0.37.2](https://github.com/python-jsonschema/check-jsonschema/compare/0.37.1...0.37.2)

* fix: correct detailed error message comment wording

Clarify when detailed error messages are enabled and remove the typo caught by typos.

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Ralf W. Grosse-Kunstleve <rgrossekunst@nvidia.com>
2026-05-13 19:03:57 -07:00
dependabot[bot]
59a917db6b chore(deps): bump urllib3 from 2.6.3 to 2.7.0 in /docs (#6058)
Bumps [urllib3](https://github.com/urllib3/urllib3) from 2.6.3 to 2.7.0.
- [Release notes](https://github.com/urllib3/urllib3/releases)
- [Changelog](https://github.com/urllib3/urllib3/blob/main/CHANGES.rst)
- [Commits](https://github.com/urllib3/urllib3/compare/2.6.3...2.7.0)

---
updated-dependencies:
- dependency-name: urllib3
  dependency-version: 2.7.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-13 17:16:53 -07:00
Ralf W. Grosse-Kunstleve
81817aed7e ci: remove the deadsnakes job (#6052)
Drop the last remaining deadsnakes-based Linux job because it mostly duplicates the main Ubuntu coverage while failing in external Launchpad/PPA setup, and the old Valgrind/debug path it used to complement has already been retired.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-02 19:02:46 -07:00
Ralf W. Grosse-Kunstleve
9cc298a481 ci: pass explicit ARM64 Python artifacts on windows-11-arm (#6051)
Avoid relying on Python_ROOT_DIR alone because CMake FindPython can still resolve the hosted x64 python.org install on the Windows ARM runner and then fail at link time with an x64/arm64 mismatch.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-02 17:49:31 -07:00
Ralf W. Grosse-Kunstleve
c5b3ae8168 ci: pin PyPy 3.11 to 7.3.21 on macOS and Windows (#6050)
Temporarily pin the two failing PyPy 3.11 jobs while investigating the PyPy 7.3.22 import regression.

Refs #6049.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-02 16:03:42 -07:00
dependabot[bot]
ee1d83f6c1 chore(deps): bump the actions group with 2 updates (#6047)
Bumps the actions group with 2 updates: [astral-sh/setup-uv](https://github.com/astral-sh/setup-uv) and [scientific-python/upload-nightly-action](https://github.com/scientific-python/upload-nightly-action).


Updates `astral-sh/setup-uv` from 8.0.0 to 8.1.0
- [Release notes](https://github.com/astral-sh/setup-uv/releases)
- [Commits](https://github.com/astral-sh/setup-uv/compare/v8.0.0...v8.1.0)

Updates `scientific-python/upload-nightly-action` from 0.6.3 to 0.6.4
- [Release notes](https://github.com/scientific-python/upload-nightly-action/releases)
- [Commits](5748273c71...e76cfec8a4)

---
updated-dependencies:
- dependency-name: astral-sh/setup-uv
  dependency-version: 8.1.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: actions
- dependency-name: scientific-python/upload-nightly-action
  dependency-version: 0.6.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: actions
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-02 13:14:44 -07:00
Ralf W. Grosse-Kunstleve
0f8396e4ff [skip ci] ci: schedule recurring CI and CIBW runs (#6048)
Run ci.yml and tests-cibw.yml twice weekly so master bitrot is easier to spot and root-cause before weekend maintenance.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-02 11:47:01 -07:00
Christoph Grüninger
d4336108df [ci] Drop GitHub Action seanmiddleditch/gha-setup-ninja (#6044)
From the GitHub Action README: "This action is no longer
necessary, as ninja is now included on all default
GitHub runner instances."
2026-04-26 17:06:06 -07:00
Eisuke Kawashima
678b6735e4 build: support Eigen 5 (#6036)
* build: support Eigen 5

fix #6034

* build: probe Eigen 3 and 5 separately in CMake config mode

Avoid relying on package-specific handling of a bounded version range when discovering Eigen through Eigen3Config.cmake.

Made-with: Cursor

* [skip ci] build: clarify Eigen 5 module fallback comment

Explain that the MODULE-mode fallback only exists for older Eigen 3 setups so the remaining fallback path does not look like an unresolved Eigen 5 issue.

Made-with: Cursor

* [skip ci] docs: add Eigen 5 entry to v3.0.4 changelog

Document the Eigen 5 CMake package detection fix in the 3.0.4 release notes before merging the PR.

Made-with: Cursor

---------

Co-authored-by: Eisuke Kawashima <e-kwsm@users.noreply.github.com>
Co-authored-by: Ralf W. Grosse-Kunstleve <rgrossekunst@nvidia.com>
2026-04-18 15:10:30 -07:00
Ralf W. Grosse-Kunstleve
ae05b15566 [skip ci] docs: add v3.0.4 changelog updates. (#6041)
Document the post-v3.0.3 fixes and CI changes ahead of the patch release so the release prep can be reviewed before the version bump work.

Made-with: Cursor
2026-04-18 11:47:16 -07:00
Agis Kounelis
7029f99cc6 fix: segfault when moving scoped_ostream_redirect (#6033)
* fix: segfault when moving `scoped_ostream_redirect`

The default move constructor left the stream (`std::cout`) pointing at
the moved-from `pythonbuf`, whose internal buffer and streambuf pointers
were nulled by the move. Any subsequent write through the stream
dereferenced null, causing a segfault.

Replace `= default` with an explicit move constructor that re-points
the stream to the new buffer and disarms the moved-from destructor.

* fix: mark move constructor noexcept to satisfy clang-tidy

* fix: use bool flag instead of nullptr sentinel for moved-from state

Using `old == nullptr` as the moved-from sentinel was incorrect because
nullptr is a valid original rdbuf() value (e.g. `std::ostream os(nullptr)`).
Replace with an explicit `active` flag so the destructor correctly
restores nullptr buffers.

Add tests for the nullptr-rdbuf edge case.

* fix: remove noexcept and propagate active flag from source

- Remove noexcept: pythonbuf inherits from std::streambuf whose move
  is not guaranteed nothrow on all implementations. Suppress clang-tidy
  with NOLINTNEXTLINE instead.
- Initialize active from other.active so that moving an already
  moved-from object does not incorrectly re-activate the redirect.
- Only rebind the stream and disarm the source when active.

* test: add unflushed ostream redirect regression

Cover the buffered-before-move case for `scoped_ostream_redirect`, which still crashes despite the current move fix. This gives the PR a direct reproducer for the remaining bug path.

Made-with: Cursor

* fix: disarm moved-from pythonbuf after redirect move

The redirect guard now survives moves, but buffered output could still remain in the moved-from `pythonbuf` and be flushed during destruction through moved-out Python handles. Rebuild the destination put area from the transferred storage and clear the source put area so unflushed bytes follow the active redirect instead of crashing in the moved-from destructor.

Made-with: Cursor

---------

Co-authored-by: Ralf W. Grosse-Kunstleve <rgrossekunst@nvidia.com>
2026-04-15 21:08:06 -07:00
Henry Schreiner
288913638b ci: bump setup-uv to maintained tag scheme (#6035)
The old vX tags have been dropped to (force) (usually) better security practices. Dependabot will not update, however, leaving this v7 tag forever. Manually updating now.

See https://github.com/astral-sh/setup-uv/issues/830

Committed via https://github.com/asottile/all-repos
2026-04-11 22:45:57 -07:00
Max Bachmann
0db7f72dc2 Handle result from PyObject_VisitManagedDict (#6032)
* Handle result from PyObject_VisitManagedDict

* add unit test

* style: pre-commit fixes

* use different variable name

This avoids a warning on msvc about Py_Visit shadowing the vret variable.

* skip test_get_referrers on unsupported runtimes

The managed-dict referrer check is only known to work on CPython 3.13.13+ and 3.14.4+, while earlier releases and non-CPython interpreters can report different traversal behavior.

Made-with: Cursor

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Ralf W. Grosse-Kunstleve <rgrossekunst@nvidia.com>
2026-04-11 20:02:27 -07:00
pre-commit-ci[bot]
4158dcfe7d chore(deps): update pre-commit hooks (#6029)
* chore(deps): update pre-commit hooks

updates:
- [github.com/pre-commit/mirrors-clang-format: v22.1.0 → v22.1.2](https://github.com/pre-commit/mirrors-clang-format/compare/v22.1.0...v22.1.2)
- [github.com/astral-sh/ruff-pre-commit: v0.15.4 → v0.15.9](https://github.com/astral-sh/ruff-pre-commit/compare/v0.15.4...v0.15.9)
- [github.com/pre-commit/mirrors-mypy: v1.19.1 → v1.20.0](https://github.com/pre-commit/mirrors-mypy/compare/v1.19.1...v1.20.0)
- [github.com/codespell-project/codespell: v2.4.1 → v2.4.2](https://github.com/codespell-project/codespell/compare/v2.4.1...v2.4.2)
- [github.com/adhtruong/mirrors-typos: v1.44.0 → v1.45.0](https://github.com/adhtruong/mirrors-typos/compare/v1.44.0...v1.45.0)
- [github.com/python-jsonschema/check-jsonschema: 0.37.0 → 0.37.1](https://github.com/python-jsonschema/check-jsonschema/compare/0.37.0...0.37.1)

* fix: allow NumPy writeable spelling in typos

NumPy uses `writeable` in public flags and API names, so typos should treat that spelling as intentional instead of blocking pre-commit runs.

Made-with: Cursor

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Ralf W. Grosse-Kunstleve <rgrossekunst@nvidia.com>
2026-04-11 13:45:53 -07:00
Dustin Spicuzza
98e50b702d fix: avoid copy constructor instantiation in shared_ptr fallback cast (#6028)
* tests: add regressions for shared_ptr reference_internal fallback

* fix: avoid copy constructor instantiation in shared_ptr fallback cast

* Remove stray empty line

* tests: rename PyTorch shared_ptr regression test files

* refactor: add cast_non_owning helper for reference-like casts

Name the non-owning generic cast path so callers do not have to rediscover that
reference-like policies must pass null copy/move constructor callbacks. This
keeps the shared_ptr reference_internal fallback self-documenting and points
future maintainers toward the safe API.

Made-with: Cursor

* tests: guard deprecated-copy warning probes with __has_warning

Use __has_warning for the Clang-only regression test so older compiler jobs skip
unsupported warning groups instead of failing with -Wunknown-warning-option. A
simple __clang_major__ >= 13 guard would be shorter, but it bakes in a version
cutoff; __has_warning is slightly more verbose while being more robust to
vendor builds, backports, and future packaging differences.

Made-with: Cursor

---------

Co-authored-by: Ralf W. Grosse-Kunstleve <rgrossekunst@nvidia.com>
2026-04-06 08:50:55 -07:00
dependabot[bot]
bfd6cbda2f chore(deps): bump the actions group with 2 updates (#6027) 2026-03-31 23:43:00 -04:00
Ralf W. Grosse-Kunstleve
d2413f5bca docs: add v3.0.3 and v3.1.0 changelog updates. (#6023)
* [skip ci] docs: add v3.0.3 and v3.1.0 changelog updates.

Made-with: Cursor

* [skip ci] docs: set v3.0.3 release date: March 31, 2026
2026-03-30 20:35:57 -07:00
dependabot[bot]
50930ae765 chore(deps): bump pygments from 2.17.2 to 2.20.0 in /docs (#6024)
Bumps [pygments](https://github.com/pygments/pygments) from 2.17.2 to 2.20.0.
- [Release notes](https://github.com/pygments/pygments/releases)
- [Changelog](https://github.com/pygments/pygments/blob/master/CHANGES)
- [Commits](https://github.com/pygments/pygments/compare/2.17.2...2.20.0)

---
updated-dependencies:
- dependency-name: pygments
  dependency-version: 2.20.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-30 12:04:38 -07:00
Ralf W. Grosse-Kunstleve
609d2c812d Fix heap-buffer-overflow in pythonbuf with undersized buffers (#6019)
* Fix heap-buffer-overflow in pythonbuf with undersized buffers (gh-5886)

The _sync() UTF-8 remainder logic can leave pptr() past the end of
the allocated buffer when buf_size < 4: after moving up to 3 bytes
of an incomplete UTF-8 sequence to the front, pbump(remainder) pushes
pptr() beyond epptr() and the buffer boundary.  The next overflow()
then writes out of bounds.

Fix by clamping the buffer size to a minimum of 4 in the constructor,
ensuring the maximum UTF-8 remainder (3 bytes) plus the overflow slot
(1 byte) always fits within the allocated buffer.

Made-with: Cursor

* Avoid C++14 ODR-use linker error for minimum_buffer_size

std::max takes arguments by const&, which ODR-uses the static constexpr
member and requires an out-of-line definition in C++14. Replace with a
ternary expression that uses the value without taking its address.

Made-with: Cursor
2026-03-29 20:49:45 -07:00
Ralf W. Grosse-Kunstleve
83f71d8b82 fix: detect virtual inheritance in add_base to prevent pointer offset crash (#6017)
Virtual inheritance places the base subobject at a dynamic offset, but
load_impl Case 2a uses reinterpret_cast which assumes a fixed offset.
This caused segfaults when dispatching inherited methods through virtual
bases (e.g. SftVirtDerived2::name()).

Add an is_static_downcastable SFINAE trait that detects whether
static_cast<Derived*>(Base*) is valid. When it is not (virtual
inheritance), set multiple_inheritance = true in add_base to force the
implicit_casts path, which correctly adjusts pointers at runtime.

Remove the workaround .def("name", &SftVirtDerived2::name) from
test_smart_ptr.cpp that was papering over the issue.

Made-with: Cursor
2026-03-29 20:49:27 -07:00
Ralf W. Grosse-Kunstleve
524d72b36d fix: strdup "self" arg in def_property_static, partially revert #6010 (gh-5976) (#6015)
* fix: strdup args added after initialize_generic in def_property_static (gh-5976)

`def_property_static` calls `process_attributes::init` on already-initialized
function records (after `initialize_generic`'s strdup loop has run).
Args added at this stage (e.g. "self" via `append_self_arg_if_needed`) remain
as string literals, so `destruct()` would call `free()` on them.

Fix by strdup'ing name/descr of any args appended by the late
`process_attributes::init` call. Root cause introduced by gh-5486.

Made-with: Cursor

* Partially revert gh-6010: remove py_is_finalizing() workarounds

Now that the root cause (free of string literals in def_property_static,
gh-5976) is fixed in the previous commit, the py_is_finalizing() guards
introduced in gh-6010 are no longer needed:

- tp_dealloc_impl: remove early return during finalization (was leaking
  all function records instead of properly destroying them)
- destruct(): remove guard around arg.value.dec_ref()
- common.h: remove py_is_finalizing() helper (no remaining callers)

The genuine fix from gh-6010 (PyObject_Free + Py_DECREF ordering in
tp_dealloc_impl) is retained.

Made-with: Cursor

* test: add embedding test for py::enum_ across interpreter restart (gh-5976)

py::enum_ is the primary trigger for gh-5976 because its constructor
creates properties via def_property_static / def_property_readonly_static,
which call process_attributes::init on already-initialized function records.
Yet none of the existing embedding tests used py::enum_ at all.

Add an PYBIND11_EMBEDDED_MODULE with py::enum_ and a test case that imports
it, finalize/reinitializes the interpreter, and re-imports it. This exercises
the def_property_static code path that was fixed in the preceding commit.

Note: on Python 3.14.2 (and likely 3.12+), tp_dealloc_impl is not called
during Py_FinalizeEx for function record PyObjects — they simply leak because
types are effectively immortalized. As a result, this test cannot trigger the
original free()-on-string-literal crash on this Python version. However, it
remains valuable as a regression guard: on Python builds where finalization
does clean up function records (or if CPython changes this behavior), the
test would catch the crash. It also verifies that py::enum_ survives
interpreter restart correctly, which was previously untested.

Made-with: Cursor

* test: skip enum restart test on Python 3.12 (pre-existing crash)

Made-with: Cursor

* Add test_standalone_enum_module.py, standalone_enum_module.cpp

* Make standalone_enum_module.cpp more similar to #5976 reproducer. Also fix clang-tidy error.

* This crashes when testing locally:

( cd /wrk/forked/pybind11/tests && PYTHONPATH=/wrk/bld/pybind11_gcc_v3.14.2_df793163d58_default/lib /wrk/bld/pybind11_gcc_v3.14.2_df793163d58_default/TestVenv/bin/python3 -m pytest test_standalone_enum_module.py )

============================= test session starts ==============================
platform linux -- Python 3.14.2, pytest-9.0.2, pluggy-1.6.0
installed packages of interest: build==1.4.2 numpy==2.4.3 scipy==1.17.1
C++ Info: 13.3.0 C++20 __pybind11_internals_v12_system_libstdcpp_gxx_abi_1xxx_use_cxx11_abi_1__ PYBIND11_SIMPLE_GIL_MANAGEMENT=False
rootdir: /wrk/forked/pybind11/tests
configfile: pytest.ini
plugins: timeout-2.4.0, xdist-3.8.0
collected 1 item

test_standalone_enum_module.py F                                         [100%]

=================================== FAILURES ===================================
________________________ test_enum_import_exit_no_crash ________________________

    def test_enum_import_exit_no_crash():
        # Modeled after reproducer under issue #5976
>       env.check_script_success_in_subprocess(
            f"""
            import sys
            sys.path.insert(0, {os.path.dirname(env.__file__)!r})
            import standalone_enum_module as m
            assert m.SomeEnum.__class__.__name__ == "pybind11_type"
            """,
            rerun=1,
        )

test_standalone_enum_module.py:10:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

code = 'import sys\nsys.path.insert(0, \'/wrk/forked/pybind11/tests\')\nimport standalone_enum_module as m\nassert m.SomeEnum.__class__.__name__ == "pybind11_type"'

    def check_script_success_in_subprocess(code: str, *, rerun: int = 8) -> None:
        """Runs the given code in a subprocess."""
        import os
        import subprocess
        import sys
        import textwrap

        if ANDROID or IOS or sys.platform.startswith("emscripten"):
            pytest.skip("Requires subprocess support")

        code = textwrap.dedent(code).strip()
        try:
            for _ in range(rerun):  # run flakily failing test multiple times
                subprocess.check_output(
                    [sys.executable, "-c", code],
                    cwd=os.getcwd(),
                    stderr=subprocess.STDOUT,
                    text=True,
                )
        except subprocess.CalledProcessError as ex:
>           raise RuntimeError(
                f"Subprocess failed with exit code {ex.returncode}.\n\n"
                f"Code:\n"
                f"```python\n"
                f"{code}\n"
                f"```\n\n"
                f"Output:\n"
                f"{ex.output}"
            ) from None
E           RuntimeError: Subprocess failed with exit code -6.
E
E           Code:
E           ```python
E           import sys
E           sys.path.insert(0, '/wrk/forked/pybind11/tests')
E           import standalone_enum_module as m
E           assert m.SomeEnum.__class__.__name__ == "pybind11_type"
E           ```
E
E           Output:
E           munmap_chunk(): invalid pointer

_          = 0
code       = 'import sys\nsys.path.insert(0, \'/wrk/forked/pybind11/tests\')\nimport standalone_enum_module as m\nassert m.SomeEnum.__class__.__name__ == "pybind11_type"'
os         = <module 'os' (frozen)>
rerun      = 1
subprocess = <module 'subprocess' from '/wrk/cpython_installs/v3.14.2_df793163d58_default/lib/python3.14/subprocess.py'>
sys        = <module 'sys' (built-in)>
textwrap   = <module 'textwrap' from '/wrk/cpython_installs/v3.14.2_df793163d58_default/lib/python3.14/textwrap.py'>

env.py:68: RuntimeError
=========================== short test summary info ============================
FAILED test_standalone_enum_module.py::test_enum_import_exit_no_crash - Runti...
============================== 1 failed in 0.23s ===============================

ERROR: completed_process.returncode=1

* Add "Added in PR #6015" comments, for easy reference back to this PR

* test: use PYBIND11_CATCH2_SKIP_IF for Python 3.12 enum restart skip

Replace #if/#else/#endif preprocessor guard with runtime
PYBIND11_CATCH2_SKIP_IF so the test is always compiled and
shows [ SKIPPED ] in output on Python 3.12.

Made-with: Cursor

* fix: suppress MSVC C4127 in PYBIND11_CATCH2_SKIP_IF macro

The constant condition in PYBIND11_CATCH2_SKIP_IF triggers MSVC
warning C4127 (conditional expression is constant), which becomes
a build error under /WX.

Made-with: Cursor
2026-03-29 20:17:22 -07:00
Ralf W. Grosse-Kunstleve
e8cead1626 Harden PYBIND11_MODULE_PYINIT and get_internals() against crashes during module init (#6018)
* Wrap ensure_internals() in try-catch in PYBIND11_MODULE_PYINIT

Previously, ensure_internals() was called without exception handling
in the PyInit_* function (PYBIND11_MODULE_PYINIT), while the same call
in PYBIND11_MODULE_EXEC was already wrapped in try-catch. On MSVC,
a C++ exception propagating through the extern "C" PyInit_* boundary
is undefined behavior, which can manifest as an access violation
instead of a clean error message. This is a potential contributor to
crashes like gh-5993. Wrap the entire PyInit body in try/catch using
the existing PYBIND11_CATCH_INIT_EXCEPTIONS pattern.

Made-with: Cursor

* Add nullptr guards in get_internals() for better crash diagnostics

Add explicit null checks after get_pp() and create_pp_content_once()
in get_internals(), calling pybind11_fail() with descriptive messages.
These guards convert potential null-pointer dereferences (which produce
unhelpful access-violation crashes, especially on Windows) into clear
runtime_error messages that can be caught and reported as ImportError
by the try-catch added in the previous commit.

Made-with: Cursor
2026-03-29 08:03:41 -07:00
Ralf W. Grosse-Kunstleve
70b6fd30f4 Fix TSS key exhaustion in implicitly_convertible() (gh-5975) (#6020)
Replace `static thread_specific_storage<int>` with `thread_local bool`
in the implicit conversion reentrancy guard. Since implicitly_convertible
is a template function, each unique <InputType, OutputType> pair created
its own TSS key via PyThread_tss_create(). Projects with hundreds of
modules and many implicit conversions could exhaust PTHREAD_KEYS_MAX
(1024 on Linux, 512 on macOS), especially on Python 3.12+ where CPython
itself consumes more TSS keys for subinterpreter support.

thread_local bool is safe here because:
- bool is trivially destructible, so it works on all C++11 platforms
  including older macOS (the concern that motivated the TSS approach in
  PR #5777 applied only to types with non-trivial destructors needing
  __cxa_thread_atexit runtime support)
- Each thread gets its own copy, so it is thread-safe for free-threading
- Subinterpreter sharing is benign: the guard prevents recursive implicit
  conversions on the same thread regardless of which interpreter is active
- The v3.0.0 code already used thread_local bool under Py_GIL_DISABLED

This effectively reverts the core change from PR #5777 while keeping
the non-copyable/non-movable set_flag guard.

Made-with: Cursor
2026-03-29 08:03:31 -07:00
Ralf W. Grosse-Kunstleve
3b62426106 Fix static_pointer_cast build failure with virtual inheritance in holder_caster_foreign_helpers.h (#6014)
* Add regression test for #5989: static_pointer_cast fails with virtual inheritance

When a class uses virtual inheritance and its holder type is shared_ptr,
passing a shared_ptr of the derived type as a method argument triggers
a compilation error because static_pointer_cast cannot downcast through
a virtual base (dynamic_pointer_cast is needed instead).

Made-with: Cursor

* Fix #5989: use dynamic_pointer_cast for virtual inheritance in esft downcast

Replace the unconditional static_pointer_cast in set_via_shared_from_this
with a SFINAE-dispatched esft_downcast helper that falls back to
dynamic_pointer_cast when static_cast through a virtual base is ill-formed.

Also add a workaround in the test binding (.def("name") on SftVirtDerived2)
for a separate pre-existing issue with inherited method dispatch through
virtual bases.

Made-with: Cursor
2026-03-27 11:02:05 +01:00
Aaron Gokaslan
c0bbd8b709 fix: bind noexcept and ref-qualified methods from unregistered base classes (#5992)
* Strip noexcept from cpp17 function type bindings

* Fix a bug and increase test coverage

* Does this fix it?

* Silence clang-tidy issue

* Simplify method adapter with macro and add missing rvalue adaptors + tests

* Supress clang-tidy errors

* Improve test coverage

* Add additional static assert

* Try to resolve MSVC C4003 warning

* Simplify method adaptor into 2 template instatiations with enable_if_t

* Fix ambiguous STL template

* Close remaining qualifier consistency gaps for member pointer bindings.

A production-code review after #2234 showed that ref-qualified member pointers were still inconsistently handled across def_buffer, vectorize, and overload_cast, so this adds the missing overloads with focused tests for each newly-supported signature.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Clarify why def_buffer/vectorize omit rvalue-qualified overloads.

These comments were added while reviewing the qualifier coverage follow-up, to document that buffer/vectorized calls operate on existing Python-owned instances and should not move-from self.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Add compile-only overload_cast guard for ref-qualified methods.

This was added as a maintenance follow-up to the qualifier-consistency work, so future changes that introduce overload_cast ambiguity or wrong ref/noexcept resolution fail at compile time.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Refactor overload_cast_impl qualifier overloads with a macro.

As part of the qualifier-consistency maintenance follow-up, this reduces duplication in overload_cast_impl while preserving the same ref/noexcept coverage and keeping pedantic-clean macro expansion.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Expose __cpp_noexcept_function_type to Python tests and use explicit skip guards.

This replaces hasattr-based optional assertions with skipif-gated noexcept-only tests so skipped coverage is visible in pytest output while keeping non-noexcept checks always active.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Add static_assert in method_adaptor to guard that T is a member function pointer.

Suggested by @Skylion007 in PR #5992 review comment [T007].

Made-with: Cursor

* automatic clang-format change (because of #6002)

---------

Co-authored-by: Ralf W. Grosse-Kunstleve <rgrossekunst@nvidia.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-03-26 16:21:32 -07:00
dependabot[bot]
e4fbc05701 chore(deps): bump requests from 2.32.4 to 2.33.0 in /docs (#6013)
Bumps [requests](https://github.com/psf/requests) from 2.32.4 to 2.33.0.
- [Release notes](https://github.com/psf/requests/releases)
- [Changelog](https://github.com/psf/requests/blob/main/HISTORY.md)
- [Commits](https://github.com/psf/requests/compare/v2.32.4...v2.33.0)

---
updated-dependencies:
- dependency-name: requests
  dependency-version: 2.33.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-26 09:16:56 -07:00
Dustin Spicuzza
ce9f83c700 Fix crash in def_readwrite for non-smart-holder properties of smart-holder classes (v2) (#6008)
* Add tests that cause crash in def_readwrite

- Occurs with non-smart-holder property of smart-holder class

* Fix crash in def_readwrite for non-smart-holder properties of smart-holder classes

* Use default policy

* Address PR comments

* Add test for cast error path

* style: pre-commit fixes

* Revert "Use default policy"

This reverts commit b299f32104.

* Disable test_shared_ptr_return_for_unique_ptr_holder when PYBIND11_TEST_SMART_HOLDER=ON

* Add counterexample

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Ralf W. Grosse-Kunstleve <rgrossekunst@nvidia.com>
2026-03-24 07:58:42 -07:00
Marco Garten
2d1723c0d6 Resolve ambiguous factory spec. with nvcc+GCC (#6011)
Explicitly specify the 4th template parameter in the
single-factory partial specialization of `factory` to
disambiguate it from the dual-factory specialization
when compiled with nvcc + GCC 14. Fixes #5565.

Co-authored-by: Oz <oz-agent@warp.dev>
2026-03-23 21:25:38 -07:00
Yury Matveev
dd95d53f0a Fix memory leak: clear managed dict in pybind11_object_dealloc on Python 3.13+ (#5999)
* fix: clear managed dict in pybind11_object_dealloc on Python 3.13+

On Python 3.14, PyObject_GC_Del (tp_free) no longer implicitly clears
the managed dict of objects with Py_TPFLAGS_MANAGED_DICT. Without an
explicit PyObject_ClearManagedDict() call before tp_free(), objects
stored in the __dict__ of py::dynamic_attr() instances have their
refcounts permanently abandoned, causing memory leaks — capsule
destructors for numpy arrays (and other objects) never run.

Adds a regression test: stores a py::capsule in the __dict__ of a
DynamicClass instance and asserts the capsule destructor is called
when the instance is deleted.

* [tests]: mark test_dynamic_attr_dealloc_frees_dict_contents to be strict=False xfail on PYPY

* [docs]: clarify Python version comments in pybind11_object_dealloc

Distinguish between when the API is available (3.13+, where
PyObject_ClearManagedDict was introduced) and when the leak actually
manifests (3.14+, where tp_free stopped implicitly clearing the
managed dict).

---------

Co-authored-by: Yury Matveev <yury.matveev@desy.de>
2026-03-24 11:14:00 +07:00
Itamar Oren
0a45af2531 gh-5991: Fix segfault during finalization related to function_record (#6010)
* gh-5991: Fix segfault during finalization related to function_record

This patch was developed with assistance from  Claude Code Opus 4.6

Here's Claude's explanation of the crash mechanism and some reasoning for the difficulty to repro:

`tp_dealloc_impl` calls `cpp_function::destruct` which:
1. Calls `std::free()` on function_record string members (`name`, `doc`, `signature`)
2. Calls `arg.value.dec_ref()` on default argument values
3. Calls `delete rec` on the function_record

But it never calls `PyObject_Free(self)` or `Py_DECREF(Py_TYPE(self))`, which are
required for heap types.

During `_Py_Finalize`, final GC collects the heap types (which survive module dict
clearing via `tp_mro` self-references). This triggers a massive cascade:
`type_dealloc → property_dealloc → meth_dealloc → tp_dealloc_impl → destruct`.

At scale (~1,200+ function_records), the volume of `delete`/`free` calls corrupts
heap metadata, causing subsequent `std::free()` to receive garbage pointers → SEGV.

* Add detail::py_is_finalizing() wrapper to deduplicate version-guarded #ifdef blocks

Also fixes clang-tidy readability-implicit-bool-conversion warnings.

Made-with: Cursor

---------

Co-authored-by: Ralf W. Grosse-Kunstleve <rgrossekunst@nvidia.com>
2026-03-23 20:59:26 -07:00
Henry Schreiner
1c72409f7f chore: some minor CPython API cleanup (#6005)
* chore: use PyType_GetFlags

Signed-off-by: Henry Schreiner <henryfs@princeton.edu>

* chore: use public VectorCall in 3.9+

Signed-off-by: Henry Schreiner <henryfs@princeton.edu>

---------

Signed-off-by: Henry Schreiner <henryfs@princeton.edu>
2026-03-22 14:27:20 -07:00
pre-commit-ci[bot]
4d51aefc2c chore(deps): update pre-commit hooks (#6002)
* chore(deps): update pre-commit hooks

updates:
- [github.com/pre-commit/mirrors-clang-format: v21.1.8 → v22.1.0](https://github.com/pre-commit/mirrors-clang-format/compare/v21.1.8...v22.1.0)
- [github.com/astral-sh/ruff-pre-commit: v0.14.14 → v0.15.4](https://github.com/astral-sh/ruff-pre-commit/compare/v0.14.14...v0.15.4)
- [github.com/adhtruong/mirrors-typos: v1.42.3 → v1.44.0](https://github.com/adhtruong/mirrors-typos/compare/v1.42.3...v1.44.0)
- [github.com/PyCQA/pylint: v4.0.4 → v4.0.5](https://github.com/PyCQA/pylint/compare/v4.0.4...v4.0.5)
- [github.com/python-jsonschema/check-jsonschema: 0.36.1 → 0.37.0](https://github.com/python-jsonschema/check-jsonschema/compare/0.36.1...0.37.0)

* style: pre-commit fixes

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2026-03-22 14:23:00 -07:00
Malcolm Smith
cd538ed118 Re-enable Android tests in CIBW workflow (#6001)
* Re-enable Android tests in CIBW workflow

* Skip subprocess tests on Android

* Remove Android workarounds no longer necessary with current cibuildwheel version

* Skip more subprocess tests on Android
2026-03-02 15:03:46 -05:00
dependabot[bot]
9d8c57fee2 chore(deps): bump the actions group with 3 updates (#6000) 2026-03-01 08:34:07 -05:00
Yaakov Selkowitz
4a77b97725 Move tomlkit dependency to dev group (#5990)
tomlkit is used only in the packaging tests which are not ordinarily run as
part of the normal workflow of a user or downstream packager.

Signed-off-by: Yaakov Selkowitz <yselkowi@redhat.com>
2026-02-22 20:49:34 -08:00
Ralf W. Grosse-Kunstleve
1a863647c5 [ci skip] fix(tests): make async callback test deterministic (#5986)
Replace the fixed sleep in test_async_callbacks with a bounded wait for all expected callback results, so detached worker scheduling no longer causes sporadic CI failures.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-16 23:03:35 -08:00
Aaron Gokaslan
ac286c932f internals: optimize std::unordered_map internals with noexcept (#5960) 2026-02-16 23:00:56 -08:00
Scott Wolchok
ccb7129f54 Improve performance of enum_ operators by going back to specific implementation (#5887)
* Improve performance of enum_ operators by going back to specific implementation

test_enum needs a patch because ops are now overloaded and this affects their docstrings.

* outline call_impl to save on code size

This does cause more move constructions, as shown by the needed update to test_copy_move. Up to reviewers whether they want more code size or more moves.

* add function_ref.h to PYBIND11_HEADERS.

* Update test_copy_move tests with C++17 passing values just so we can see mostly-not-red tests

* Remove stray TODO

* fix clang-tidy

* fix clang-tidy again. add function_ref.h to test_files.py

* Add static assertion for function_ref lifetime safety in call_impl

Add a static_assert to document and enforce that function_ref is
trivially copyable, ensuring safe pass-by-value usage. This also
documents the lifetime safety guarantees: function_ref is created
from cap->f which lives in the capture object, and is only used
synchronously within call_impl without being stored beyond its scope.

* Add #undef cleanup for enum operator macros

Undefine all enum operator macros after their last use to prevent
macro pollution and follow the existing code pattern. This matches
the cleanup pattern used for the previous enum operator macros.

* Rename PYBIND11_THROW to PYBIND11_ENUM_OP_THROW_TYPE_ERROR

Rename the macro to be more specific and avoid potential clashes with
public macros. The new name clearly indicates it's scoped to enum
operations and describes its purpose (throwing a type error).

* Clarify comments in function_ref.h

Replace vague comments about 'extensions to <functional>' and 'functions'
with a clearer description that this is a header-only class template
similar to std::function but with non-owning semantics. This makes it
clear that it's template-only and requires no additional library linking.

---------

Co-authored-by: Ralf W. Grosse-Kunstleve <rgrossekunst@nvidia.com>
2026-02-16 23:00:21 -08:00
Michael Carlstrom
e8e8d6ab22 Expand float and complex strict mode to allow ints and ints/float (for PEP 484 compatibility). (#5879)
* init

Signed-off-by: Michael Carlstrom <rmc@carlstrom.com>

* Add constexpr to is_floating_point check

This is known at compile time so it can be constexpr

* Allow noconvert float to accept int

* Update noconvert documentation

* Allow noconvert complex to accept int and float

* Add complex strict test

* style: pre-commit fixes

* Update unit tests so int, becomes double.

* style: pre-commit fixes

* remove if (constexpr)

Signed-off-by: Michael Carlstrom <rmc@carlstrom.com>

* fix spelling error

* bump order in #else

* Switch order in c++11 only section

Signed-off-by: Michael Carlstrom <rmc@carlstrom.com>

* ci: trigger build

* ci: trigger build

* Allow casting from float to int

The int type caster allows anything that implements __int__ with explicit exception of the python float. I can't see any reason for this.
This modifies the int casting behaviour to accept a float.
If the argument is marked as noconvert() it will only accept int.

* tests for py::float into int

* Update complex_cast tests

* Add SupportsIndex to int and float

* style: pre-commit fixes

* fix assert

* Update docs to mention other conversions

* fix pypy __index__ problems

* style: pre-commit fixes

* extract out PyLong_AsLong __index__ deprecation

Signed-off-by: Michael Carlstrom <rmc@carlstrom.com>

* style: pre-commit fixes

* Add back env.deprecated_call

Signed-off-by: Michael Carlstrom <rmc@carlstrom.com>

* remove note

Signed-off-by: Michael Carlstrom <rmc@carlstrom.com>

* remove untrue comment

Signed-off-by: Michael Carlstrom <rmc@carlstrom.com>

* fix noconvert_args

Signed-off-by: Michael Carlstrom <rmc@carlstrom.com>

* resolve error

Signed-off-by: Michael Carlstrom <rmc@carlstrom.com>

* Add comment

Signed-off-by: Michael Carlstrom <rmc@carlstrom.com>

* [skip ci]

tests: Add overload resolution test for float/int breaking change

Add test_overload_resolution_float_int() to explicitly test the breaking
change where int arguments now match float overloads when registered first.

The existing tests verify conversion behavior (int -> float, int/float -> complex)
but do not test overload resolution when both float and int overloads exist.
This test fills that gap by:

- Testing that float overload registered before int overload matches int(42)
- Testing strict mode (noconvert) overload resolution breaking change
- Testing complex overload resolution with int/float/complex overloads
- Documenting the breaking change explicitly

This complements existing tests which verify 'can it convert?' by testing
'which overload wins when multiple can convert?'

* Add test to verify that custom __index__ objects (not PyLong) work correctly with complex conversion. These should be consistent across CPython, PyPy, and GraalPy.

* Improve comment clarity for PyPy __index__ handling

Replace cryptic 'So: PYBIND11_INDEX_CHECK(src.ptr())' comment with
clearer explanation of the logic:

- Explains that we need to call PyNumber_Index explicitly on PyPy
  for non-PyLong objects
- Clarifies the relationship to the outer condition: when convert
  is false, we only reach this point if PYBIND11_INDEX_CHECK passed
  above

This makes the code more maintainable and easier to understand
during review.

* Undo inconsequential change to regex in test_enum.py

During merge, HEAD's regex pattern was kept, but master's version is preferred.
The order of ` ` and `\|` in the character class is arbitrary. Keep master's order
(already fixed in PR #5891; sorry I missed looking back here when working on 5891).

* test_methods_and_attributes.py: Restore existing `m.overload_order(1.1)` call and clearly explain the behavior change.

* Reject float → int conversion even in convert mode

Enabling implicit float → int conversion in convert mode causes
silent truncation (e.g., 1.9 → 1). This is dangerous because:

1. It's implicit - users don't expect truncation when calling functions
2. It's silent - no warning or error
3. It can hide bugs - precision loss is hard to detect

This change restores the explicit rejection of PyFloat_Check for integer
casters, even in convert mode. This is more in line with Python's behavior
where int(1.9) must be explicit.

Note that the int → float conversion in noconvert mode is preserved,
as that's a safe widening conversion.

* Revert test changes that sidestepped implicit float→int conversion

This reverts all test modifications that were made to accommodate
implicit float→int conversion in convert mode. With the production
code change that explicitly rejects float→int conversion even in
convert mode, these test workarounds are no longer needed.

Changes reverted:
- test_builtin_casters.py: Restored cant_convert(3.14159) and
  np.float32 conversion with deprecated_call wrapper
- test_custom_type_casters.py: Restored TypeError expectation for
  m.ints_preferred(4.0)
- test_methods_and_attributes.py: Restored TypeError expectation
  for m.overload_order(1.1)
- test_stl.py: Restored float literals (2.0) that were replaced with
  strings to avoid conversion
- test_factory_constructors.py: Restored original constructor calls
  that were modified to avoid float→int conversion

Also removes the unused avoid_PyLong_AsLong_deprecation fixture
and related TypeVar imports, as all uses were removed.

* Replace env.deprecated_call() with pytest.deprecated_call()

The env.deprecated_call() function was removed, but two test cases
still reference it. Replace with pytest.deprecated_call(), which is
the standard pytest context manager for handling deprecation warnings.

Since we already require pytest>=6 (see tests/requirements.txt), the
compatibility function is obsolete and pytest.deprecated_call() is
available.

* Update test expectations for swapped NoisyAlloc overloads

PR 5879 swapped the order of NoisyAlloc constructor overloads:
- (int i, double) is now placement new (comes first)
- (double d, double) is now factory pointer (comes second)

This swap is necessary because pybind11 tries overloads in order
until one matches. With int → float conversion now allowed:

- create_and_destroy(4, 0.5): Without the swap, (double d, double)
  would match first (since int → double conversion is allowed),
  bypassing the more specific (int i, double) overload. With the
  swap, (int i, double) matches first (exact match), which is
  correct.

- create_and_destroy(3.5, 4.5): (int i, double) fails (float → int
  is rejected), then (double d, double) matches, which is correct.

The swap ensures exact int matches are preferred over double matches
when an int is provided, which is the expected overload resolution
behavior.

Update the test expectations to match the new overload resolution
order.

* Resolve clang-tidy error:

/__w/pybind11/pybind11/include/pybind11/cast.h:253:46: error: repeated branch body in conditional chain [bugprone-branch-clone,-warnings-as-errors]
  253 |         } else if (PyFloat_Check(src.ptr())) {
      |                                              ^
/__w/pybind11/pybind11/include/pybind11/cast.h:258:10: note: end of the original
  258 |         } else if (convert || PYBIND11_LONG_CHECK(src.ptr()) || PYBIND11_INDEX_CHECK(src.ptr())) {
      |          ^
/__w/pybind11/pybind11/include/pybind11/cast.h:283:16: note: clone 1 starts here
  283 |         } else {
      |                ^

* Add test coverage for __index__ and __int__ edge cases: incorrectly returning float

These tests ensure that:
- Invalid return types (floats) are properly rejected
- The fallback from __index__ to __int__ works correctly in convert mode
- noconvert mode correctly prevents fallback when __index__ fails

* Minor comment-only changes: add PR number, for easy future reference

* Ensure we are not leaking a Python error is something is wrong elsewhere (e.g. UB, or bug in Python beta testing).

See also: https://github.com/pybind/pybind11/pull/5879#issuecomment-3521099331

* [skip ci] Bump PYBIND11_INTERNALS_VERSION to 12 (for PRs 5879, 5887, 5960)

---------

Signed-off-by: Michael Carlstrom <rmc@carlstrom.com>
Co-authored-by: gentlegiantJGC <gentlegiantJGC@users.noreply.github.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Ralf W. Grosse-Kunstleve <rgrossekunst@nvidia.com>
2026-02-16 23:00:01 -08:00
Ralf W. Grosse-Kunstleve
2448bc5853 [skip ci] Bump version to v3.1.0a0 (#5987) 2026-02-16 21:12:56 -08:00
Ralf W. Grosse-Kunstleve
45fab4087e Update version number to v3.0.2 (final) and set release date in changelog.md to February 16, 2026 (#5985) v3.0.2 2026-02-16 20:31:46 -08:00
Ralf W. Grosse-Kunstleve
44a0cd241e [ci skip] docs/changelog.md updates for 3.0.2, to account for 5 additional PRs (#5984) 2026-02-16 09:33:30 -08:00