Merge branch 'master' into sh_merge_master

This commit is contained in:
Ralf W. Grosse-Kunstleve 2024-01-16 21:10:28 -08:00
commit 37c617c7fa
9 changed files with 103 additions and 82 deletions

View File

@ -4,4 +4,8 @@ updates:
- package-ecosystem: "github-actions" - package-ecosystem: "github-actions"
directory: "/" directory: "/"
schedule: schedule:
interval: "daily" interval: "weekly"
groups:
actions:
patterns:
- "*"

View File

@ -801,7 +801,7 @@ jobs:
uses: jwlawson/actions-setup-cmake@v1.14 uses: jwlawson/actions-setup-cmake@v1.14
- name: Prepare MSVC - name: Prepare MSVC
uses: ilammy/msvc-dev-cmd@v1.12.1 uses: ilammy/msvc-dev-cmd@v1.13.0
with: with:
arch: x86 arch: x86
@ -854,7 +854,7 @@ jobs:
uses: jwlawson/actions-setup-cmake@v1.14 uses: jwlawson/actions-setup-cmake@v1.14
- name: Prepare MSVC - name: Prepare MSVC
uses: ilammy/msvc-dev-cmd@v1.12.1 uses: ilammy/msvc-dev-cmd@v1.13.0
with: with:
arch: x86 arch: x86
@ -960,7 +960,6 @@ jobs:
mingw-w64-${{matrix.env}}-gcc mingw-w64-${{matrix.env}}-gcc
mingw-w64-${{matrix.env}}-python-pip mingw-w64-${{matrix.env}}-python-pip
mingw-w64-${{matrix.env}}-python-numpy mingw-w64-${{matrix.env}}-python-numpy
mingw-w64-${{matrix.env}}-python-scipy
mingw-w64-${{matrix.env}}-cmake mingw-w64-${{matrix.env}}-cmake
mingw-w64-${{matrix.env}}-make mingw-w64-${{matrix.env}}-make
mingw-w64-${{matrix.env}}-python-pytest mingw-w64-${{matrix.env}}-python-pytest
@ -968,6 +967,14 @@ jobs:
mingw-w64-${{matrix.env}}-boost mingw-w64-${{matrix.env}}-boost
mingw-w64-${{matrix.env}}-catch mingw-w64-${{matrix.env}}-catch
- uses: msys2/setup-msys2@v2
if: matrix.sys == 'mingw64'
with:
msystem: ${{matrix.sys}}
install: >-
git
mingw-w64-${{matrix.env}}-python-scipy
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Configure C++11 - name: Configure C++11

View File

@ -32,7 +32,7 @@ repos:
# 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.1.6 rev: v0.1.9
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.7.1" rev: "v1.8.0"
hooks: hooks:
- id: mypy - id: mypy
args: [] args: []
@ -144,7 +144,7 @@ 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.0.1" rev: "v3.0.3"
hooks: hooks:
- id: pylint - id: pylint
files: ^pybind11 files: ^pybind11

View File

@ -172,7 +172,7 @@ struct list_caster {
auto s = reinterpret_borrow<sequence>(src); auto s = reinterpret_borrow<sequence>(src);
value.clear(); value.clear();
reserve_maybe(s, &value); reserve_maybe(s, &value);
for (auto it : s) { for (const auto &it : s) {
value_conv conv; value_conv conv;
if (!conv.load(it, convert)) { if (!conv.load(it, convert)) {
return false; return false;
@ -247,7 +247,7 @@ public:
return false; return false;
} }
size_t ctr = 0; size_t ctr = 0;
for (auto it : l) { for (const auto &it : l) {
value_conv conv; value_conv conv;
if (!conv.load(it, convert)) { if (!conv.load(it, convert)) {
return false; return false;

View File

@ -645,49 +645,50 @@ auto map_if_insertion_operator(Class_ &cl, std::string const &name)
"Return the canonical string representation of this map."); "Return the canonical string representation of this map.");
} }
template <typename KeyType>
struct keys_view { struct keys_view {
virtual size_t len() = 0; virtual size_t len() = 0;
virtual iterator iter() = 0; virtual iterator iter() = 0;
virtual bool contains(const KeyType &k) = 0; virtual bool contains(const handle &k) = 0;
virtual bool contains(const object &k) = 0;
virtual ~keys_view() = default; virtual ~keys_view() = default;
}; };
template <typename MappedType>
struct values_view { struct values_view {
virtual size_t len() = 0; virtual size_t len() = 0;
virtual iterator iter() = 0; virtual iterator iter() = 0;
virtual ~values_view() = default; virtual ~values_view() = default;
}; };
template <typename KeyType, typename MappedType>
struct items_view { struct items_view {
virtual size_t len() = 0; virtual size_t len() = 0;
virtual iterator iter() = 0; virtual iterator iter() = 0;
virtual ~items_view() = default; virtual ~items_view() = default;
}; };
template <typename Map, typename KeysView> template <typename Map>
struct KeysViewImpl : public KeysView { struct KeysViewImpl : public detail::keys_view {
explicit KeysViewImpl(Map &map) : map(map) {} explicit KeysViewImpl(Map &map) : map(map) {}
size_t len() override { return map.size(); } size_t len() override { return map.size(); }
iterator iter() override { return make_key_iterator(map.begin(), map.end()); } iterator iter() override { return make_key_iterator(map.begin(), map.end()); }
bool contains(const typename Map::key_type &k) override { return map.find(k) != map.end(); } bool contains(const handle &k) override {
bool contains(const object &) override { return false; } try {
return map.find(k.template cast<typename Map::key_type>()) != map.end();
} catch (const cast_error &) {
return false;
}
}
Map &map; Map &map;
}; };
template <typename Map, typename ValuesView> template <typename Map>
struct ValuesViewImpl : public ValuesView { struct ValuesViewImpl : public detail::values_view {
explicit ValuesViewImpl(Map &map) : map(map) {} explicit ValuesViewImpl(Map &map) : map(map) {}
size_t len() override { return map.size(); } size_t len() override { return map.size(); }
iterator iter() override { return make_value_iterator(map.begin(), map.end()); } iterator iter() override { return make_value_iterator(map.begin(), map.end()); }
Map &map; Map &map;
}; };
template <typename Map, typename ItemsView> template <typename Map>
struct ItemsViewImpl : public ItemsView { struct ItemsViewImpl : public detail::items_view {
explicit ItemsViewImpl(Map &map) : map(map) {} explicit ItemsViewImpl(Map &map) : map(map) {}
size_t len() override { return map.size(); } size_t len() override { return map.size(); }
iterator iter() override { return make_iterator(map.begin(), map.end()); } iterator iter() override { return make_iterator(map.begin(), map.end()); }
@ -700,11 +701,9 @@ template <typename Map, typename holder_type = default_holder_type<Map>, typenam
class_<Map, holder_type> bind_map(handle scope, const std::string &name, Args &&...args) { class_<Map, holder_type> bind_map(handle scope, const std::string &name, Args &&...args) {
using KeyType = typename Map::key_type; using KeyType = typename Map::key_type;
using MappedType = typename Map::mapped_type; using MappedType = typename Map::mapped_type;
using StrippedKeyType = detail::remove_cvref_t<KeyType>; using KeysView = detail::keys_view;
using StrippedMappedType = detail::remove_cvref_t<MappedType>; using ValuesView = detail::values_view;
using KeysView = detail::keys_view<StrippedKeyType>; using ItemsView = detail::items_view;
using ValuesView = detail::values_view<StrippedMappedType>;
using ItemsView = detail::items_view<StrippedKeyType, StrippedMappedType>;
using Class_ = class_<Map, holder_type>; using Class_ = class_<Map, holder_type>;
// If either type is a non-module-local bound type then make the map binding non-local as well; // If either type is a non-module-local bound type then make the map binding non-local as well;
@ -718,39 +717,20 @@ class_<Map, holder_type> bind_map(handle scope, const std::string &name, Args &&
} }
Class_ cl(scope, name.c_str(), pybind11::module_local(local), std::forward<Args>(args)...); Class_ cl(scope, name.c_str(), pybind11::module_local(local), std::forward<Args>(args)...);
static constexpr auto key_type_descr = detail::make_caster<KeyType>::name;
static constexpr auto mapped_type_descr = detail::make_caster<MappedType>::name;
std::string key_type_name(key_type_descr.text), mapped_type_name(mapped_type_descr.text);
// If key type isn't properly wrapped, fall back to C++ names // Wrap KeysView if it wasn't already wrapped
if (key_type_name == "%") {
key_type_name = detail::type_info_description(typeid(KeyType));
}
// Similarly for value type:
if (mapped_type_name == "%") {
mapped_type_name = detail::type_info_description(typeid(MappedType));
}
// Wrap KeysView[KeyType] if it wasn't already wrapped
if (!detail::get_type_info(typeid(KeysView))) { if (!detail::get_type_info(typeid(KeysView))) {
class_<KeysView> keys_view( class_<KeysView> keys_view(scope, "KeysView", pybind11::module_local(local));
scope, ("KeysView[" + key_type_name + "]").c_str(), pybind11::module_local(local));
keys_view.def("__len__", &KeysView::len); keys_view.def("__len__", &KeysView::len);
keys_view.def("__iter__", keys_view.def("__iter__",
&KeysView::iter, &KeysView::iter,
keep_alive<0, 1>() /* Essential: keep view alive while iterator exists */ keep_alive<0, 1>() /* Essential: keep view alive while iterator exists */
); );
keys_view.def("__contains__", keys_view.def("__contains__", &KeysView::contains);
static_cast<bool (KeysView::*)(const KeyType &)>(&KeysView::contains));
// Fallback for when the object is not of the key type
keys_view.def("__contains__",
static_cast<bool (KeysView::*)(const object &)>(&KeysView::contains));
} }
// Similarly for ValuesView: // Similarly for ValuesView:
if (!detail::get_type_info(typeid(ValuesView))) { if (!detail::get_type_info(typeid(ValuesView))) {
class_<ValuesView> values_view(scope, class_<ValuesView> values_view(scope, "ValuesView", pybind11::module_local(local));
("ValuesView[" + mapped_type_name + "]").c_str(),
pybind11::module_local(local));
values_view.def("__len__", &ValuesView::len); values_view.def("__len__", &ValuesView::len);
values_view.def("__iter__", values_view.def("__iter__",
&ValuesView::iter, &ValuesView::iter,
@ -759,10 +739,7 @@ class_<Map, holder_type> bind_map(handle scope, const std::string &name, Args &&
} }
// Similarly for ItemsView: // Similarly for ItemsView:
if (!detail::get_type_info(typeid(ItemsView))) { if (!detail::get_type_info(typeid(ItemsView))) {
class_<ItemsView> items_view( class_<ItemsView> items_view(scope, "ItemsView", pybind11::module_local(local));
scope,
("ItemsView[" + key_type_name + ", ").append(mapped_type_name + "]").c_str(),
pybind11::module_local(local));
items_view.def("__len__", &ItemsView::len); items_view.def("__len__", &ItemsView::len);
items_view.def("__iter__", items_view.def("__iter__",
&ItemsView::iter, &ItemsView::iter,
@ -788,25 +765,19 @@ class_<Map, holder_type> bind_map(handle scope, const std::string &name, Args &&
cl.def( cl.def(
"keys", "keys",
[](Map &m) { [](Map &m) { return std::unique_ptr<KeysView>(new detail::KeysViewImpl<Map>(m)); },
return std::unique_ptr<KeysView>(new detail::KeysViewImpl<Map, KeysView>(m));
},
keep_alive<0, 1>() /* Essential: keep map alive while view exists */ keep_alive<0, 1>() /* Essential: keep map alive while view exists */
); );
cl.def( cl.def(
"values", "values",
[](Map &m) { [](Map &m) { return std::unique_ptr<ValuesView>(new detail::ValuesViewImpl<Map>(m)); },
return std::unique_ptr<ValuesView>(new detail::ValuesViewImpl<Map, ValuesView>(m));
},
keep_alive<0, 1>() /* Essential: keep map alive while view exists */ keep_alive<0, 1>() /* Essential: keep map alive while view exists */
); );
cl.def( cl.def(
"items", "items",
[](Map &m) { [](Map &m) { return std::unique_ptr<ItemsView>(new detail::ItemsViewImpl<Map>(m)); },
return std::unique_ptr<ItemsView>(new detail::ItemsViewImpl<Map, ItemsView>(m));
},
keep_alive<0, 1>() /* Essential: keep map alive while view exists */ keep_alive<0, 1>() /* Essential: keep map alive while view exists */
); );

View File

@ -103,21 +103,26 @@ private:
int value; int value;
}; };
template <typename T>
std::unordered_set<T *> &pointer_set() {
// https://google.github.io/styleguide/cppguide.html#Static_and_Global_Variables
static auto singleton = new std::unordered_set<T *>();
return *singleton;
}
// test_unique_nodelete // test_unique_nodelete
// Object with a private destructor // Object with a private destructor
class MyObject4;
std::unordered_set<MyObject4 *> myobject4_instances;
class MyObject4 { class MyObject4 {
public: public:
explicit MyObject4(int value) : value{value} { explicit MyObject4(int value) : value{value} {
print_created(this); print_created(this);
myobject4_instances.insert(this); pointer_set<MyObject4>().insert(this);
} }
int value; int value;
static void cleanupAllInstances() { static void cleanupAllInstances() {
auto tmp = std::move(myobject4_instances); auto tmp = std::move(pointer_set<MyObject4>());
myobject4_instances.clear(); pointer_set<MyObject4>().clear();
for (auto *o : tmp) { for (auto *o : tmp) {
delete o; delete o;
} }
@ -125,7 +130,7 @@ public:
private: private:
~MyObject4() { ~MyObject4() {
myobject4_instances.erase(this); pointer_set<MyObject4>().erase(this);
print_destroyed(this); print_destroyed(this);
} }
}; };
@ -133,19 +138,17 @@ private:
// test_unique_deleter // test_unique_deleter
// Object with std::unique_ptr<T, D> where D is not matching the base class // Object with std::unique_ptr<T, D> where D is not matching the base class
// Object with a protected destructor // Object with a protected destructor
class MyObject4a;
std::unordered_set<MyObject4a *> myobject4a_instances;
class MyObject4a { class MyObject4a {
public: public:
explicit MyObject4a(int i) : value{i} { explicit MyObject4a(int i) : value{i} {
print_created(this); print_created(this);
myobject4a_instances.insert(this); pointer_set<MyObject4a>().insert(this);
}; };
int value; int value;
static void cleanupAllInstances() { static void cleanupAllInstances() {
auto tmp = std::move(myobject4a_instances); auto tmp = std::move(pointer_set<MyObject4a>());
myobject4a_instances.clear(); pointer_set<MyObject4a>().clear();
for (auto *o : tmp) { for (auto *o : tmp) {
delete o; delete o;
} }
@ -153,7 +156,7 @@ public:
protected: protected:
virtual ~MyObject4a() { virtual ~MyObject4a() {
myobject4a_instances.erase(this); pointer_set<MyObject4a>().erase(this);
print_destroyed(this); print_destroyed(this);
} }
}; };

View File

@ -192,6 +192,16 @@ TEST_SUBMODULE(stl_binders, m) {
py::bind_map<std::unordered_map<std::string, double const>>(m, py::bind_map<std::unordered_map<std::string, double const>>(m,
"UnorderedMapStringDoubleConst"); "UnorderedMapStringDoubleConst");
// test_map_view_types
py::bind_map<std::map<std::string, float>>(m, "MapStringFloat");
py::bind_map<std::unordered_map<std::string, float>>(m, "UnorderedMapStringFloat");
py::bind_map<std::map<std::pair<double, int>, int32_t>>(m, "MapPairDoubleIntInt32");
py::bind_map<std::map<std::pair<double, int>, int64_t>>(m, "MapPairDoubleIntInt64");
py::bind_map<std::map<int, py::object>>(m, "MapIntObject");
py::bind_map<std::map<std::string, py::object>>(m, "MapStringObject");
py::class_<E_nc>(m, "ENC").def(py::init<int>()).def_readwrite("value", &E_nc::value); py::class_<E_nc>(m, "ENC").def(py::init<int>()).def_readwrite("value", &E_nc::value);
// test_noncopyable_containers // test_noncopyable_containers

View File

@ -317,9 +317,9 @@ def test_map_view_types():
map_string_double_const = m.MapStringDoubleConst() map_string_double_const = m.MapStringDoubleConst()
unordered_map_string_double_const = m.UnorderedMapStringDoubleConst() unordered_map_string_double_const = m.UnorderedMapStringDoubleConst()
assert map_string_double.keys().__class__.__name__ == "KeysView[str]" assert map_string_double.keys().__class__.__name__ == "KeysView"
assert map_string_double.values().__class__.__name__ == "ValuesView[float]" assert map_string_double.values().__class__.__name__ == "ValuesView"
assert map_string_double.items().__class__.__name__ == "ItemsView[str, float]" assert map_string_double.items().__class__.__name__ == "ItemsView"
keys_type = type(map_string_double.keys()) keys_type = type(map_string_double.keys())
assert type(unordered_map_string_double.keys()) is keys_type assert type(unordered_map_string_double.keys()) is keys_type
@ -336,6 +336,30 @@ def test_map_view_types():
assert type(map_string_double_const.items()) is items_type assert type(map_string_double_const.items()) is items_type
assert type(unordered_map_string_double_const.items()) is items_type assert type(unordered_map_string_double_const.items()) is items_type
map_string_float = m.MapStringFloat()
unordered_map_string_float = m.UnorderedMapStringFloat()
assert type(map_string_float.keys()) is keys_type
assert type(unordered_map_string_float.keys()) is keys_type
assert type(map_string_float.values()) is values_type
assert type(unordered_map_string_float.values()) is values_type
assert type(map_string_float.items()) is items_type
assert type(unordered_map_string_float.items()) is items_type
map_pair_double_int_int32 = m.MapPairDoubleIntInt32()
map_pair_double_int_int64 = m.MapPairDoubleIntInt64()
assert type(map_pair_double_int_int32.values()) is values_type
assert type(map_pair_double_int_int64.values()) is values_type
map_int_object = m.MapIntObject()
map_string_object = m.MapStringObject()
assert type(map_int_object.keys()) is keys_type
assert type(map_string_object.keys()) is keys_type
assert type(map_int_object.items()) is items_type
assert type(map_string_object.items()) is items_type
def test_recursive_vector(): def test_recursive_vector():
recursive_vector = m.RecursiveVector() recursive_vector = m.RecursiveVector()

View File

@ -110,14 +110,16 @@ if(NOT DEFINED ${_Python}_EXECUTABLE)
endif() endif()
if(NOT ${_Python}_EXECUTABLE STREQUAL PYBIND11_PYTHON_EXECUTABLE_LAST) if(DEFINED PYBIND11_PYTHON_EXECUTABLE_LAST AND NOT ${_Python}_EXECUTABLE STREQUAL
PYBIND11_PYTHON_EXECUTABLE_LAST)
# Detect changes to the Python version/binary in subsequent CMake runs, and refresh config if needed # Detect changes to the Python version/binary in subsequent CMake runs, and refresh config if needed
unset(PYTHON_IS_DEBUG CACHE) unset(PYTHON_IS_DEBUG CACHE)
unset(PYTHON_MODULE_EXTENSION CACHE) unset(PYTHON_MODULE_EXTENSION CACHE)
set(PYBIND11_PYTHON_EXECUTABLE_LAST endif()
set(PYBIND11_PYTHON_EXECUTABLE_LAST
"${${_Python}_EXECUTABLE}" "${${_Python}_EXECUTABLE}"
CACHE INTERNAL "Python executable during the last CMake run") CACHE INTERNAL "Python executable during the last CMake run")
endif()
if(NOT DEFINED PYTHON_IS_DEBUG) if(NOT DEFINED PYTHON_IS_DEBUG)
# Debug check - see https://stackoverflow.com/questions/646518/python-how-to-detect-debug-Interpreter # Debug check - see https://stackoverflow.com/questions/646518/python-how-to-detect-debug-Interpreter