Merge branch 'master' into sh_merge_master

This commit is contained in:
Ralf W. Grosse-Kunstleve 2024-11-07 09:35:12 -08:00
commit dca5623226
No known key found for this signature in database
11 changed files with 92 additions and 37 deletions

View File

@ -25,14 +25,14 @@ repos:
# Clang format the codebase automatically # Clang format the codebase automatically
- repo: https://github.com/pre-commit/mirrors-clang-format - repo: https://github.com/pre-commit/mirrors-clang-format
rev: "v18.1.8" rev: "v19.1.3"
hooks: hooks:
- id: clang-format - id: clang-format
types_or: [c++, c, cuda] types_or: [c++, c, cuda]
# Ruff, the Python auto-correcting linter/formatter written in Rust # Ruff, the Python auto-correcting linter/formatter written in Rust
- repo: https://github.com/astral-sh/ruff-pre-commit - repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.6.3 rev: v0.7.2
hooks: hooks:
- id: ruff - id: ruff
args: ["--fix", "--show-fixes"] args: ["--fix", "--show-fixes"]
@ -40,7 +40,7 @@ repos:
# Check static types with mypy # Check static types with mypy
- repo: https://github.com/pre-commit/mirrors-mypy - repo: https://github.com/pre-commit/mirrors-mypy
rev: "v1.11.2" rev: "v1.13.0"
hooks: hooks:
- id: mypy - id: mypy
args: [] args: []
@ -62,7 +62,7 @@ repos:
# Standard hooks # Standard hooks
- repo: https://github.com/pre-commit/pre-commit-hooks - repo: https://github.com/pre-commit/pre-commit-hooks
rev: "v4.6.0" rev: "v5.0.0"
hooks: hooks:
- id: check-added-large-files - id: check-added-large-files
- id: check-case-conflict - id: check-case-conflict
@ -80,7 +80,7 @@ repos:
# Also code format the docs # Also code format the docs
- repo: https://github.com/adamchainz/blacken-docs - repo: https://github.com/adamchainz/blacken-docs
rev: "1.18.0" rev: "1.19.1"
hooks: hooks:
- id: blacken-docs - id: blacken-docs
additional_dependencies: additional_dependencies:
@ -110,7 +110,7 @@ repos:
# Checks the manifest for missing files (native support) # Checks the manifest for missing files (native support)
- repo: https://github.com/mgedmin/check-manifest - repo: https://github.com/mgedmin/check-manifest
rev: "0.49" rev: "0.50"
hooks: hooks:
- id: check-manifest - id: check-manifest
# This is a slow hook, so only run this if --hook-stage manual is passed # This is a slow hook, so only run this if --hook-stage manual is passed
@ -144,14 +144,14 @@ repos:
# PyLint has native support - not always usable, but works for us # PyLint has native support - not always usable, but works for us
- repo: https://github.com/PyCQA/pylint - repo: https://github.com/PyCQA/pylint
rev: "v3.2.7" rev: "v3.3.1"
hooks: hooks:
- id: pylint - id: pylint
files: ^pybind11 files: ^pybind11
# Check schemas on some of our YAML files # Check schemas on some of our YAML files
- repo: https://github.com/python-jsonschema/check-jsonschema - repo: https://github.com/python-jsonschema/check-jsonschema
rev: 0.29.2 rev: 0.29.4
hooks: hooks:
- id: check-readthedocs - id: check-readthedocs
- id: check-github-workflows - id: check-github-workflows

View File

@ -24,7 +24,8 @@ changes are that:
function is not available anymore. function is not available anymore.
Due to NumPy changes, you may experience difficulties updating to NumPy 2. Due to NumPy changes, you may experience difficulties updating to NumPy 2.
Please see the [NumPy 2 migration guide](https://numpy.org/devdocs/numpy_2_0_migration_guide.html) for details. Please see the `NumPy 2 migration guide <https://numpy.org/devdocs/numpy_2_0_migration_guide.html>`_
for details.
For example, a more direct change could be that the default integer ``"int_"`` For example, a more direct change could be that the default integer ``"int_"``
(and ``"uint"``) is now ``ssize_t`` and not ``long`` (affects 64bit windows). (and ``"uint"``) is now ``ssize_t`` and not ``long`` (affects 64bit windows).

View File

@ -1150,14 +1150,14 @@ struct overload_cast_impl {
} }
template <typename Return, typename Class> template <typename Return, typename Class>
constexpr auto operator()(Return (Class::*pmf)(Args...), constexpr auto operator()(Return (Class::*pmf)(Args...), std::false_type = {}) const noexcept
std::false_type = {}) const noexcept -> decltype(pmf) { -> decltype(pmf) {
return pmf; return pmf;
} }
template <typename Return, typename Class> template <typename Return, typename Class>
constexpr auto operator()(Return (Class::*pmf)(Args...) const, constexpr auto operator()(Return (Class::*pmf)(Args...) const, std::true_type) const noexcept
std::true_type) const noexcept -> decltype(pmf) { -> decltype(pmf) {
return pmf; return pmf;
} }
}; };

View File

@ -156,9 +156,8 @@ constexpr auto concat(const descr<N, Ts...> &d, const Args &...args) {
} }
#else #else
template <size_t N, typename... Ts, typename... Args> template <size_t N, typename... Ts, typename... Args>
constexpr auto concat(const descr<N, Ts...> &d, constexpr auto concat(const descr<N, Ts...> &d, const Args &...args)
const Args &...args) -> decltype(std::declval<descr<N + 2, Ts...>>() -> decltype(std::declval<descr<N + 2, Ts...>>() + concat(args...)) {
+ concat(args...)) {
return d + const_name(", ") + concat(args...); return d + const_name(", ") + concat(args...);
} }
#endif #endif

View File

@ -697,8 +697,8 @@ inline std::uint64_t mix64(std::uint64_t z) {
} }
template <typename F> template <typename F>
inline auto with_instance_map(const void *ptr, inline auto with_instance_map(const void *ptr, const F &cb)
const F &cb) -> decltype(cb(std::declval<instance_map &>())) { -> decltype(cb(std::declval<instance_map &>())) {
auto &internals = get_internals(); auto &internals = get_internals();
#ifdef Py_GIL_DISABLED #ifdef Py_GIL_DISABLED

View File

@ -121,7 +121,6 @@ PYBIND11_NOINLINE void all_type_info_populate(PyTypeObject *t, std::vector<type_
for (handle parent : reinterpret_borrow<tuple>(t->tp_bases)) { for (handle parent : reinterpret_borrow<tuple>(t->tp_bases)) {
check.push_back((PyTypeObject *) parent.ptr()); check.push_back((PyTypeObject *) parent.ptr());
} }
auto const &type_dict = get_internals().registered_types_py; auto const &type_dict = get_internals().registered_types_py;
for (size_t i = 0; i < check.size(); i++) { for (size_t i = 0; i < check.size(); i++) {
auto *type = check[i]; auto *type = check[i];
@ -180,13 +179,7 @@ PYBIND11_NOINLINE void all_type_info_populate(PyTypeObject *t, std::vector<type_
* The value is cached for the lifetime of the Python type. * The value is cached for the lifetime of the Python type.
*/ */
inline const std::vector<detail::type_info *> &all_type_info(PyTypeObject *type) { inline const std::vector<detail::type_info *> &all_type_info(PyTypeObject *type) {
auto ins = all_type_info_get_cache(type); return all_type_info_get_cache(type).first->second;
if (ins.second) {
// New cache entry: populate it
all_type_info_populate(type, ins.first->second);
}
return ins.first->second;
} }
/** /**
@ -1535,14 +1528,14 @@ protected:
does not have a private operator new implementation. A comma operator is used in the does not have a private operator new implementation. A comma operator is used in the
decltype argument to apply SFINAE to the public copy/move constructors.*/ decltype argument to apply SFINAE to the public copy/move constructors.*/
template <typename T, typename = enable_if_t<is_copy_constructible<T>::value>> template <typename T, typename = enable_if_t<is_copy_constructible<T>::value>>
static auto make_copy_constructor(const T *) -> decltype(new T(std::declval<const T>()), static auto make_copy_constructor(const T *)
Constructor{}) { -> decltype(new T(std::declval<const T>()), Constructor{}) {
return [](const void *arg) -> void * { return new T(*reinterpret_cast<const T *>(arg)); }; return [](const void *arg) -> void * { return new T(*reinterpret_cast<const T *>(arg)); };
} }
template <typename T, typename = enable_if_t<is_move_constructible<T>::value>> template <typename T, typename = enable_if_t<is_move_constructible<T>::value>>
static auto make_move_constructor(const T *) -> decltype(new T(std::declval<T &&>()), static auto make_move_constructor(const T *)
Constructor{}) { -> decltype(new T(std::declval<T &&>()), Constructor{}) {
return [](const void *arg) -> void * { return [](const void *arg) -> void * {
return new T(std::move(*const_cast<T *>(reinterpret_cast<const T *>(arg)))); return new T(std::move(*const_cast<T *>(reinterpret_cast<const T *>(arg))));
}; };

View File

@ -124,9 +124,9 @@ struct eigen_tensor_helper<
template <typename Type, bool ShowDetails, bool NeedsWriteable = false> template <typename Type, bool ShowDetails, bool NeedsWriteable = false>
struct get_tensor_descriptor { struct get_tensor_descriptor {
static constexpr auto details static constexpr auto details
= const_name<NeedsWriteable>(", flags.writeable", "") = const_name<NeedsWriteable>(", flags.writeable", "") + const_name
+ const_name<static_cast<int>(Type::Layout) == static_cast<int>(Eigen::RowMajor)>( < static_cast<int>(Type::Layout)
", flags.c_contiguous", ", flags.f_contiguous"); == static_cast<int>(Eigen::RowMajor) > (", flags.c_contiguous", ", flags.f_contiguous");
static constexpr auto value static constexpr auto value
= const_name("numpy.ndarray[") + npy_format_descriptor<typename Type::Scalar>::name = const_name("numpy.ndarray[") + npy_format_descriptor<typename Type::Scalar>::name
+ const_name("[") + eigen_tensor_helper<remove_cv_t<Type>>::dimensions_descriptor + const_name("[") + eigen_tensor_helper<remove_cv_t<Type>>::dimensions_descriptor

View File

@ -2665,13 +2665,20 @@ keep_alive_impl(size_t Nurse, size_t Patient, function_call &call, handle ret) {
inline std::pair<decltype(internals::registered_types_py)::iterator, bool> inline std::pair<decltype(internals::registered_types_py)::iterator, bool>
all_type_info_get_cache(PyTypeObject *type) { all_type_info_get_cache(PyTypeObject *type) {
auto res = with_internals([type](internals &internals) { auto res = with_internals([type](internals &internals) {
return internals auto ins = internals
.registered_types_py .registered_types_py
#ifdef __cpp_lib_unordered_map_try_emplace #ifdef __cpp_lib_unordered_map_try_emplace
.try_emplace(type); .try_emplace(type);
#else #else
.emplace(type, std::vector<detail::type_info *>()); .emplace(type, std::vector<detail::type_info *>());
#endif #endif
if (ins.second) {
// For free-threading mode, this call must be under
// the with_internals() mutex lock, to avoid that other threads
// continue running with the empty ins.first->second.
all_type_info_populate(type, ins.first->second);
}
return ins;
}); });
if (res.second) { if (res.second) {
// New cache entry created; set up a weak reference to automatically remove it if the type // New cache entry created; set up a weak reference to automatically remove it if the type

View File

@ -128,4 +128,9 @@ PYBIND11_MODULE(pybind11_tests, m, py::mod_gil_not_used()) {
for (const auto &initializer : initializers()) { for (const auto &initializer : initializers()) {
initializer(m); initializer(m);
} }
py::class_<TestContext>(m, "TestContext")
.def(py::init<>(&TestContext::createNewContextForInit))
.def("__enter__", &TestContext::contextEnter)
.def("__exit__", &TestContext::contextExit);
} }

View File

@ -96,3 +96,24 @@ void ignoreOldStyleInitWarnings(F &&body) {
)", )",
py::dict(py::arg("body") = py::cpp_function(body))); py::dict(py::arg("body") = py::cpp_function(body)));
} }
// See PR #5419 for background.
class TestContext {
public:
TestContext() = delete;
TestContext(const TestContext &) = delete;
TestContext(TestContext &&) = delete;
static TestContext *createNewContextForInit() { return new TestContext("new-context"); }
pybind11::object contextEnter() {
py::object contextObj = py::cast(*this);
return contextObj;
}
void contextExit(const pybind11::object & /*excType*/,
const pybind11::object & /*excVal*/,
const pybind11::object & /*excTb*/) {}
private:
explicit TestContext(const std::string &context) : context(context) {}
std::string context;
};

View File

@ -1,5 +1,6 @@
from __future__ import annotations from __future__ import annotations
import sys
from unittest import mock from unittest import mock
import pytest import pytest
@ -520,3 +521,31 @@ def test_pr4220_tripped_over_this():
m.Empty0().get_msg() m.Empty0().get_msg()
== "This is really only meant to exercise successful compilation." == "This is really only meant to exercise successful compilation."
) )
@pytest.mark.skipif(sys.platform.startswith("emscripten"), reason="Requires threads")
def test_all_type_info_multithreaded():
# See PR #5419 for background.
import threading
from pybind11_tests import TestContext
class Context(TestContext):
pass
num_runs = 10
num_threads = 4
barrier = threading.Barrier(num_threads)
def func():
barrier.wait()
with Context():
pass
for _ in range(num_runs):
threads = [threading.Thread(target=func) for _ in range(num_threads)]
for thread in threads:
thread.start()
for thread in threads:
thread.join()