Skip to content

Commit 70906c0

Browse files
committed
Propagate exceptions in sequence::size() (pybind#2076)
1 parent 07e2259 commit 70906c0

File tree

3 files changed

+26
-1
lines changed

3 files changed

+26
-1
lines changed

include/pybind11/pytypes.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1242,7 +1242,12 @@ class dict : public object {
12421242
class sequence : public object {
12431243
public:
12441244
PYBIND11_OBJECT_DEFAULT(sequence, object, PySequence_Check)
1245-
size_t size() const { return (size_t) PySequence_Size(m_ptr); }
1245+
size_t size() const {
1246+
const auto result = PySequence_Size(m_ptr);
1247+
if (result == -1)
1248+
throw error_already_set();
1249+
return static_cast<size_t>(result);
1250+
}
12461251
bool empty() const { return size() == 0; }
12471252
detail::sequence_accessor operator[](size_t index) const { return {*this, index}; }
12481253
detail::item_accessor operator[](handle h) const { return object::operator[](h); }

tests/test_sequences_and_iterators.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,9 @@ TEST_SUBMODULE(sequences_and_iterators, m) {
319319
return l;
320320
});
321321

322+
// test_sequence_length: check that Python sequences can be converted to py::sequence.
323+
m.def("sequence_length", [](py::sequence seq) { return seq.size(); });
324+
322325
// Make sure that py::iterator works with std algorithms
323326
m.def("count_none", [](py::object o) {
324327
return std::count_if(o.begin(), o.end(), [](py::handle h) { return h.is_none(); });

tests/test_sequences_and_iterators.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,23 @@ def test_sequence():
100100
assert cstats.move_assignments == 0
101101

102102

103+
def test_sequence_length():
104+
"""#2076: Exception raised by len(arg) should be propagated """
105+
class BadLen(RuntimeError):
106+
pass
107+
class SequenceLike():
108+
def __getitem__(self, i):
109+
return None
110+
def __len__(self):
111+
raise BadLen()
112+
113+
with pytest.raises(BadLen):
114+
m.sequence_length(SequenceLike())
115+
116+
assert m.sequence_length([1, 2, 3]) == 3
117+
assert m.sequence_length("hello") == 5
118+
119+
103120
def test_map_iterator():
104121
sm = m.StringMap({'hi': 'bye', 'black': 'white'})
105122
assert sm['hi'] == 'bye'

0 commit comments

Comments
 (0)