Skip to content

Commit c20a361

Browse files
committed
stl_bind: apply py::local attribute by default
This applies the `py::local` attribute by default to `stl_bind` types.
1 parent a3afc5d commit c20a361

File tree

4 files changed

+82
-4
lines changed

4 files changed

+82
-4
lines changed

include/pybind11/stl_bind.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -376,10 +376,10 @@ NAMESPACE_END(detail)
376376
// std::vector
377377
//
378378
template <typename Vector, typename holder_type = std::unique_ptr<Vector>, typename... Args>
379-
class_<Vector, holder_type> bind_vector(module &m, std::string const &name, Args&&... args) {
379+
class_<Vector, holder_type> bind_vector(handle scope, std::string const &name, Args&&... args) {
380380
using Class_ = class_<Vector, holder_type>;
381381

382-
Class_ cl(m, name.c_str(), std::forward<Args>(args)...);
382+
Class_ cl(scope, name.c_str(), pybind11::local(), std::forward<Args>(args)...);
383383

384384
// Declare the buffer interface if a buffer_protocol() is passed in
385385
detail::vector_buffer<Vector, Class_, Args...>(cl);
@@ -531,12 +531,12 @@ template <typename Map, typename Class_> auto map_if_insertion_operator(Class_ &
531531
NAMESPACE_END(detail)
532532

533533
template <typename Map, typename holder_type = std::unique_ptr<Map>, typename... Args>
534-
class_<Map, holder_type> bind_map(module &m, const std::string &name, Args&&... args) {
534+
class_<Map, holder_type> bind_map(handle scope, const std::string &name, Args&&... args) {
535535
using KeyType = typename Map::key_type;
536536
using MappedType = typename Map::mapped_type;
537537
using Class_ = class_<Map, holder_type>;
538538

539-
Class_ cl(m, name.c_str(), std::forward<Args>(args)...);
539+
Class_ cl(scope, name.c_str(), pybind11::local(), std::forward<Args>(args)...);
540540

541541
cl.def(init<>());
542542

tests/pybind11_local_bindings.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,22 @@ PYBIND11_MODULE(pybind11_local_bindings, m) {
3232
m.def("register_nonlocal", [m]() {
3333
bind_local<NonLocalType, 0>(m, "NonLocalType");
3434
});
35+
36+
// test_stl_bind_local
37+
// stl_bind.h binders defaults to py::local. Note that the value doesn't have to be local, even
38+
// if the overall container is:
39+
py::bind_vector<std::vector<LocalType>>(m, "LocalVec");
40+
py::bind_vector<std::vector<NonLocalType>>(m, "LocalVec2");
41+
py::bind_map<std::unordered_map<std::string, LocalType>>(m, "LocalMap");
42+
py::bind_map<std::unordered_map<std::string, NonLocalType>>(m, "LocalMap2");
43+
44+
// test_stl_bind_global
45+
// stl_bind binders can, however, be overridden to global using `py::local(false)` (in which
46+
// case this will fail):
47+
m.def("register_nonlocal_stl1", [m]() {
48+
py::bind_vector<std::vector<NonLocal2>>(m, "NonLocalVec", py::local(false));
49+
});
50+
m.def("register_nonlocal_stl2", [m]() {
51+
py::bind_map<std::unordered_map<std::string, NonLocal2>>(m, "NonLocalMap", py::local(false));
52+
});
3553
}

tests/test_local_bindings.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,4 +42,17 @@ TEST_SUBMODULE(local_bindings, m) {
4242
}
4343
else throw std::runtime_error("test_class not enabled");
4444
});
45+
46+
// test_stl_bind_local
47+
// stl_bind.h binders defaults to py::local:
48+
py::bind_vector<std::vector<LocalType>>(m, "LocalVec");
49+
py::bind_vector<std::vector<NonLocalType>>(m, "LocalVec2");
50+
py::bind_map<std::unordered_map<std::string, LocalType>>(m, "LocalMap");
51+
py::bind_map<std::unordered_map<std::string, NonLocalType>>(m, "LocalMap2");
52+
53+
// test_stl_bind_global
54+
// They can, however, be overridden to global using `py::local(false)`:
55+
bind_local<NonLocal2, 10>(m, "NonLocal2");
56+
py::bind_vector<std::vector<NonLocal2>>(m, "NonLocalVec", py::local(false));
57+
py::bind_map<std::unordered_map<std::string, NonLocal2>>(m, "NonLocalMap", py::local(false));
4558
}

tests/test_local_bindings.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,3 +50,50 @@ def test_duplicate_local():
5050
assert str(excinfo.value) == (
5151
'generic_type: type "LocalExternal" is already registered!'
5252
if hasattr(pybind11_tests, 'class_') else 'test_class not enabled')
53+
54+
55+
def test_stl_bind_local():
56+
import pybind11_local_bindings as m2
57+
58+
v1, v2 = m1.LocalVec(), m2.LocalVec()
59+
v1.append(m1.LocalType(1))
60+
v1.append(m1.LocalType(2))
61+
v2.append(m2.LocalType(1))
62+
v2.append(m2.LocalType(2))
63+
64+
with pytest.raises(TypeError):
65+
v1.append(m2.LocalType(3))
66+
with pytest.raises(TypeError):
67+
v2.append(m1.LocalType(3))
68+
69+
assert [i.get() for i in v1] == [0, 1]
70+
assert [i.get() for i in v2] == [2, 3]
71+
72+
v3, v4 = m1.LocalVec2(), m2.LocalVec2()
73+
v3.append(m1.NonLocalType(1))
74+
v3.append(m1.NonLocalType(2))
75+
v4.append(m1.NonLocalType(1))
76+
v4.append(m1.NonLocalType(2))
77+
78+
assert [i.get() for i in v3] == [1, 2]
79+
assert [i.get() for i in v4] == [1, 2]
80+
81+
d1, d2 = m1.LocalMap(), m2.LocalMap()
82+
d1["a"] = v1[0]
83+
d1["b"] = v1[1]
84+
d2["c"] = v2[0]
85+
d2["d"] = v2[1]
86+
assert {i: d1[i].get() for i in d1} == {'a': 0, 'b': 1}
87+
assert {i: d2[i].get() for i in d2} == {'c': 2, 'd': 3}
88+
89+
90+
def test_stl_bind_global():
91+
import pybind11_local_bindings as m2
92+
93+
with pytest.raises(RuntimeError) as excinfo:
94+
m2.register_nonlocal_stl1()
95+
assert str(excinfo.value) == 'generic_type: type "NonLocalVec" is already registered!'
96+
97+
with pytest.raises(RuntimeError) as excinfo:
98+
m2.register_nonlocal_stl2()
99+
assert str(excinfo.value) == 'generic_type: type "NonLocalMap" is already registered!'

0 commit comments

Comments
 (0)