Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ jobs:
allow-prereleases: true

- name: Install uv
uses: astral-sh/setup-uv@v7
uses: astral-sh/setup-uv@v8.0.0
with:
enable-cache: true

Expand Down Expand Up @@ -302,7 +302,7 @@ jobs:
debug: ${{ matrix.python-debug }}

- name: Update CMake
uses: jwlawson/actions-setup-cmake@v2.1
uses: jwlawson/actions-setup-cmake@v2.2

- name: Valgrind cache
if: matrix.valgrind
Expand Down Expand Up @@ -570,7 +570,7 @@ jobs:
run: python3 -m pip install --upgrade pip

- name: Update CMake
uses: jwlawson/actions-setup-cmake@v2.1
uses: jwlawson/actions-setup-cmake@v2.2

- name: Configure
shell: bash
Expand Down Expand Up @@ -906,7 +906,7 @@ jobs:
${{ matrix.python == '3.13' && runner.os == 'Windows' }}

- name: Update CMake
uses: jwlawson/actions-setup-cmake@v2.1
uses: jwlawson/actions-setup-cmake@v2.2

- name: Prepare MSVC
uses: ilammy/msvc-dev-cmd@v1.13.0
Expand Down Expand Up @@ -956,7 +956,7 @@ jobs:
architecture: x86

- name: Update CMake
uses: jwlawson/actions-setup-cmake@v2.1
uses: jwlawson/actions-setup-cmake@v2.2

- name: Prepare MSVC
uses: ilammy/msvc-dev-cmd@v1.13.0
Expand Down Expand Up @@ -1007,7 +1007,7 @@ jobs:
run: python3 -m pip install -r tests/requirements.txt

- name: Update CMake
uses: jwlawson/actions-setup-cmake@v2.1
uses: jwlawson/actions-setup-cmake@v2.2

- name: Configure C++20
run: >
Expand Down Expand Up @@ -1189,7 +1189,7 @@ jobs:
python-version: ${{ matrix.python }}

- name: Update CMake
uses: jwlawson/actions-setup-cmake@v2.1
uses: jwlawson/actions-setup-cmake@v2.2

- name: Install ninja-build tool
uses: seanmiddleditch/gha-setup-ninja@v6
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/configure.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,15 +56,15 @@ jobs:
python-version: 3.11

- name: Install uv
uses: astral-sh/setup-uv@v7
uses: astral-sh/setup-uv@v8.0.0

- name: Prepare env
run: uv pip install --python=python --system -r tests/requirements.txt

# An action for adding a specific version of CMake:
# https://github.com/jwlawson/actions-setup-cmake
- name: Setup CMake ${{ matrix.cmake }}
uses: jwlawson/actions-setup-cmake@v2.1
uses: jwlawson/actions-setup-cmake@v2.2
with:
cmake-version: ${{ matrix.cmake }}

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/nightlies.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ jobs:
fetch-depth: 0

- name: Install uv
uses: astral-sh/setup-uv@v7
uses: astral-sh/setup-uv@v8.0.0

- name: Build SDist and wheels
run: |
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/pip.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ jobs:
python-version: 3.8

- name: Install uv
uses: astral-sh/setup-uv@v7
uses: astral-sh/setup-uv@v8.0.0

- name: Prepare env
run: uv pip install --system -r tests/requirements.txt
Expand All @@ -55,7 +55,7 @@ jobs:
python-version: 3.8

- name: Install uv
uses: astral-sh/setup-uv@v7
uses: astral-sh/setup-uv@v8.0.0

- name: Prepare env
run: uv pip install --system -r tests/requirements.txt twine nox
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/reusable-standard.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ jobs:
run: brew install boost

- name: Install uv
uses: astral-sh/setup-uv@v7
uses: astral-sh/setup-uv@v8.0.0
with:
enable-cache: true

Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/tests-cibw.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ jobs:
submodules: true
fetch-depth: 0

- uses: pypa/cibuildwheel@v3.3
- uses: pypa/cibuildwheel@v3.4
env:
PYODIDE_BUILD_EXPORTS: whole_archive
with:
Expand All @@ -45,7 +45,7 @@ jobs:
# We have to uninstall first because GH is now using a local tap to build cmake<4, iOS needs cmake>=4
- run: brew uninstall cmake && brew install cmake

- uses: pypa/cibuildwheel@v3.3
- uses: pypa/cibuildwheel@v3.4
env:
CIBW_PLATFORM: ios
CIBW_SKIP: cp314-* # https://github.com/pypa/cibuildwheel/issues/2494
Expand All @@ -70,7 +70,7 @@ jobs:
if: contains(matrix.runs-on, 'macos')
run: echo "CIBW_TEST_COMMAND=" >> "$GITHUB_ENV"

- uses: pypa/cibuildwheel@v3.3
- uses: pypa/cibuildwheel@v3.4
env:
CIBW_PLATFORM: android
with:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/upstream.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ jobs:
run: sudo apt-get install libboost-dev

- name: Update CMake
uses: jwlawson/actions-setup-cmake@v2.1
uses: jwlawson/actions-setup-cmake@v2.2

- name: Run pip installs
run: |
Expand Down
12 changes: 6 additions & 6 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,22 +25,22 @@ repos:

# Clang format the codebase automatically
- repo: https://github.com/pre-commit/mirrors-clang-format
rev: "v22.1.0"
rev: "v22.1.2"
hooks:
- id: clang-format
types_or: [c++, c, cuda]

# Ruff, the Python auto-correcting linter/formatter written in Rust
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.15.4
rev: v0.15.9
hooks:
- id: ruff-check
args: ["--fix", "--show-fixes"]
- id: ruff-format

# Check static types with mypy
- repo: https://github.com/pre-commit/mirrors-mypy
rev: "v1.19.1"
rev: "v1.20.0"
hooks:
- id: mypy
args: []
Expand Down Expand Up @@ -112,7 +112,7 @@ repos:
# Use tools/codespell_ignore_lines_from_errors.py
# to rebuild .codespell-ignore-lines
- repo: https://github.com/codespell-project/codespell
rev: "v2.4.1"
rev: "v2.4.2"
hooks:
- id: codespell
exclude: "(.supp|^pyproject.toml)$"
Expand All @@ -122,7 +122,7 @@ repos:
# Use mirror because pre-commit autoupdate confuses tags in the upstream repo.
# See https://github.com/crate-ci/typos/issues/390
- repo: https://github.com/adhtruong/mirrors-typos
rev: "v1.44.0"
rev: "v1.45.0"
hooks:
- id: typos
args: []
Expand Down Expand Up @@ -151,7 +151,7 @@ repos:

# Check schemas on some of our YAML files
- repo: https://github.com/python-jsonschema/check-jsonschema
rev: 0.37.0
rev: 0.37.1
hooks:
- id: check-readthedocs
- id: check-github-workflows
Expand Down
28 changes: 28 additions & 0 deletions docs/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,34 @@ Changes will be added here periodically from the "Suggested changelog
entry" block in pull request descriptions.


## Version 3.0.4 (April 18, 2026)

Bug fixes:

- Fixed test builds with installed Eigen 5 by improving `Eigen3` CMake package detection.
[#6036](https://github.com/pybind/pybind11/pull/6036)

- Fixed move semantics of `scoped_ostream_redirect` to preserve buffered output and avoid crashes when moved redirects restore stream buffers.
[#6033](https://github.com/pybind/pybind11/pull/6033)

- Fixed `py::dynamic_attr()` traversal on Python 3.13+ to correctly propagate `PyObject_VisitManagedDict()` results.
[#6032](https://github.com/pybind/pybind11/pull/6032)

- Fixed `std::shared_ptr<T>` fallback casting to avoid unnecessary copy-constructor instantiation in `reference_internal` paths.
[#6028](https://github.com/pybind/pybind11/pull/6028)

CI:

- Updated `setup-uv` to the maintained GitHub Action tag scheme.
[#6035](https://github.com/pybind/pybind11/pull/6035)

- Updated pre-commit hooks.
[#6029](https://github.com/pybind/pybind11/pull/6029)

- Updated GitHub Actions dependencies, including `actions-setup-cmake` and `cibuildwheel`.
[#6027](https://github.com/pybind/pybind11/pull/6027)


## Version 3.0.3 (March 31, 2026)

Bug fixes:
Expand Down
2 changes: 1 addition & 1 deletion include/pybind11/cast.h
Original file line number Diff line number Diff line change
Expand Up @@ -1026,7 +1026,7 @@ struct copyable_holder_caster<
}

if (parent) {
return type_caster_base<type>::cast(
return type_caster_generic::cast_non_owning(
srcs, return_value_policy::reference_internal, parent);
}

Expand Down
5 changes: 4 additions & 1 deletion include/pybind11/detail/class.h
Original file line number Diff line number Diff line change
Expand Up @@ -578,7 +578,10 @@ inline PyObject *make_object_base_type(PyTypeObject *metaclass) {
/// dynamic_attr: Allow the garbage collector to traverse the internal instance `__dict__`.
extern "C" inline int pybind11_traverse(PyObject *self, visitproc visit, void *arg) {
#if PY_VERSION_HEX >= 0x030D0000
PyObject_VisitManagedDict(self, visit, arg);
int ret = PyObject_VisitManagedDict(self, visit, arg);
if (ret) {
return ret;
}
#else
PyObject *&dict = *_PyObject_GetDictPtr(self);
Py_VISIT(dict);
Expand Down
4 changes: 2 additions & 2 deletions include/pybind11/detail/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,15 @@
/* -- start version constants -- */
#define PYBIND11_VERSION_MAJOR 3
#define PYBIND11_VERSION_MINOR 0
#define PYBIND11_VERSION_MICRO 3
#define PYBIND11_VERSION_MICRO 4
// ALPHA = 0xA, BETA = 0xB, GAMMA = 0xC (release candidate), FINAL = 0xF (stable release)
// - The release level is set to "alpha" for development versions.
// Use 0xA0 (LEVEL=0xA, SERIAL=0) for development versions.
// - For stable releases, set the serial to 0.
#define PYBIND11_VERSION_RELEASE_LEVEL PY_RELEASE_LEVEL_FINAL
#define PYBIND11_VERSION_RELEASE_SERIAL 0
// String version of (micro, release level, release serial), e.g.: 0a0, 0b1, 0rc1, 0
#define PYBIND11_VERSION_PATCH 3
#define PYBIND11_VERSION_PATCH 4
/* -- end version constants -- */

#if !defined(Py_PACK_FULL_VERSION)
Expand Down
12 changes: 12 additions & 0 deletions include/pybind11/detail/type_caster_base.h
Original file line number Diff line number Diff line change
Expand Up @@ -1004,6 +1004,18 @@ class type_caster_generic {
return cast(srcs, policy, parent, copy_constructor, move_constructor, existing_holder);
}

static handle cast_non_owning(const cast_sources &srcs,
return_value_policy policy,
handle parent,
const void *existing_holder = nullptr) {
// Reference-like policies alias an existing C++ object instead of creating
// a new one, so copy/move constructor callbacks must remain null here.
assert(policy == return_value_policy::reference
|| policy == return_value_policy::reference_internal
|| policy == return_value_policy::automatic_reference);
return cast(srcs, policy, parent, nullptr, nullptr, existing_holder);
}

PYBIND11_NOINLINE static handle cast(const cast_sources &srcs,
return_value_policy policy,
handle parent,
Expand Down
34 changes: 31 additions & 3 deletions include/pybind11/iostream.h
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,22 @@ class pythonbuf : public std::streambuf {
setp(d_buffer.get(), d_buffer.get() + buf_size - 1);
}

pythonbuf(pythonbuf &&) = default;
pythonbuf(pythonbuf &&other) noexcept
: buf_size(other.buf_size), d_buffer(std::move(other.d_buffer)),
pywrite(std::move(other.pywrite)), pyflush(std::move(other.pyflush)) {
const auto pending = (other.pbase() != nullptr && other.pptr() != nullptr)
? static_cast<int>(other.pptr() - other.pbase())
: 0;
if (d_buffer != nullptr) {
// Rebuild the put area from the transferred storage.
setp(d_buffer.get(), d_buffer.get() + buf_size - 1);
pbump(pending);
} else {
setp(nullptr, nullptr);
}
// Prevent the moved-from destructor from flushing through moved-out handles.
other.setp(nullptr, nullptr);
}

/// Sync before destroy
~pythonbuf() override { _sync(); }
Expand Down Expand Up @@ -169,6 +184,7 @@ class scoped_ostream_redirect {
std::streambuf *old;
std::ostream &costream;
detail::pythonbuf buffer;
bool active = true;

public:
explicit scoped_ostream_redirect(std::ostream &costream = std::cout,
Expand All @@ -178,10 +194,22 @@ class scoped_ostream_redirect {
old = costream.rdbuf(&buffer);
}

~scoped_ostream_redirect() { costream.rdbuf(old); }
~scoped_ostream_redirect() {
if (active) {
costream.rdbuf(old);
}
}

scoped_ostream_redirect(const scoped_ostream_redirect &) = delete;
scoped_ostream_redirect(scoped_ostream_redirect &&other) = default;
// NOLINTNEXTLINE(performance-noexcept-move-constructor)
scoped_ostream_redirect(scoped_ostream_redirect &&other)
: old(other.old), costream(other.costream), buffer(std::move(other.buffer)),
active(other.active) {
if (active) {
costream.rdbuf(&buffer); // Re-point stream to our buffer
other.active = false;
}
}
scoped_ostream_redirect &operator=(const scoped_ostream_redirect &) = delete;
scoped_ostream_redirect &operator=(scoped_ostream_redirect &&) = delete;
};
Expand Down
4 changes: 4 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,10 @@ fo = "fo"
quater = "quater"
optin = "optin"
othr = "othr"
# NumPy uses "writeable" in public API names and flags.
writeable = "writeable"
Writeable = "Writeable"
WRITEABLE = "WRITEABLE"

#[tool.typos.type.cpp.extend-words]
setp = "setp"
Expand Down
8 changes: 8 additions & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ set(PYBIND11_TEST_FILES
test_operator_overloading
test_pickling
test_potentially_slicing_weak_ptr
test_pytorch_shared_ptr_cast_regression
test_python_multiple_inheritance
test_pytypes
test_scoped_critical_section
Expand Down Expand Up @@ -299,10 +300,17 @@ if(PYBIND11_TEST_FILES_EIGEN_I GREATER -1)

else()
find_package(Eigen3 3.2.7 QUIET CONFIG)
if(NOT Eigen3_FOUND)
find_package(Eigen3 5 QUIET CONFIG)
endif()
set(EIGEN3_FOUND ${Eigen3_FOUND})
set(EIGEN3_VERSION ${Eigen3_VERSION})

if(NOT EIGEN3_FOUND)
# Couldn't load via target, so fall back to allowing module mode finding, which will pick up
# tools/FindEigen3.cmake
# This MODULE-mode fallback is for older Eigen 3 setups; Eigen 5 is expected to be found
# via the CONFIG-mode probes above.
find_package(Eigen3 3.2.7 QUIET)
endif()
endif()
Expand Down
Loading
Loading