Skip to content

Commit 2e65376

Browse files
committed
writer: roll back buffer after exceptions
If an exception was caught on the Python side, then the item that caused the exception would remain in the buffer and be written out with the next valid item. Fixes #212.
1 parent fe34b21 commit 2e65376

File tree

2 files changed

+84
-0
lines changed

2 files changed

+84
-0
lines changed

lib/simple_writer.cc

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,12 @@ class SimpleWriter
3030

3131
void add_osmium_object(const osmium::OSMObject& o)
3232
{
33+
if (!buffer) {
34+
throw std::runtime_error{"Writer already closed."};
35+
}
36+
37+
buffer.rollback();
38+
3339
buffer.add_item(o);
3440
flush_buffer();
3541
}
@@ -40,6 +46,8 @@ class SimpleWriter
4046
throw std::runtime_error{"Writer already closed."};
4147
}
4248

49+
buffer.rollback();
50+
4351
if (py::isinstance<osmium::Node>(o)) {
4452
buffer.add_item(o.cast<osmium::Node &>());
4553
} else {
@@ -65,6 +73,8 @@ class SimpleWriter
6573
throw std::runtime_error{"Writer already closed."};
6674
}
6775

76+
buffer.rollback();
77+
6878
if (py::isinstance<osmium::Way>(o)) {
6979
buffer.add_item(o.cast<osmium::Way &>());
7080
} else {
@@ -88,6 +98,8 @@ class SimpleWriter
8898
throw std::runtime_error{"Writer already closed."};
8999
}
90100

101+
buffer.rollback();
102+
91103
if (py::isinstance<osmium::Relation>(o)) {
92104
buffer.add_item(o.cast<osmium::Relation &>());
93105
} else {

test/test_writer.py

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,3 +246,75 @@ def test_add_relation_after_close(tmp_path, simple_handler):
246246

247247
with pytest.raises(RuntimeError, match='closed'):
248248
simple_handler(node_opl, relation=lambda o: writer.add_relation(o))
249+
250+
251+
@pytest.mark.parametrize("final_item", (True, False))
252+
def test_catch_errors_in_add_node(tmp_path, final_item):
253+
test_file = tmp_path / 'test.opl'
254+
255+
writer = o.SimpleWriter(str(test_file), 4000)
256+
257+
try:
258+
writer.add_node(o.osm.mutable.Node(id=123))
259+
with pytest.raises(TypeError):
260+
writer.add_node(o.osm.mutable.Node(id=124, tags=34))
261+
if not final_item:
262+
writer.add_node(o.osm.mutable.Node(id=125))
263+
finally:
264+
writer.close()
265+
266+
output = test_file.read_text()
267+
268+
expected = 'n123 v0 dV c0 t i0 u T x y\n'
269+
if not final_item:
270+
expected += 'n125 v0 dV c0 t i0 u T x y\n'
271+
272+
assert output == expected
273+
274+
275+
@pytest.mark.parametrize("final_item", (True, False))
276+
def test_catch_errors_in_add_way(tmp_path, final_item):
277+
test_file = tmp_path / 'test.opl'
278+
279+
writer = o.SimpleWriter(str(test_file), 4000)
280+
281+
try:
282+
writer.add_way(o.osm.mutable.Way(id=123, nodes=[1, 2, 3]))
283+
with pytest.raises(TypeError):
284+
writer.add_way(o.osm.mutable.Way(id=124, nodes=34))
285+
if not final_item:
286+
writer.add_way(o.osm.mutable.Way(id=125, nodes=[11, 12]))
287+
finally:
288+
writer.close()
289+
290+
output = test_file.read_text()
291+
292+
expected = 'w123 v0 dV c0 t i0 u T Nn1,n2,n3\n'
293+
if not final_item:
294+
expected += 'w125 v0 dV c0 t i0 u T Nn11,n12\n'
295+
296+
assert output == expected
297+
298+
299+
@pytest.mark.parametrize("final_item", (True, False))
300+
def test_catch_errors_in_add_relation(tmp_path, final_item):
301+
test_file = tmp_path / 'test.opl'
302+
303+
writer = o.SimpleWriter(str(test_file), 4000)
304+
305+
try:
306+
writer.add_relation(o.osm.mutable.Relation(id=123))
307+
with pytest.raises(TypeError):
308+
writer.add_relation(o.osm.mutable.Relation(id=124, members=34))
309+
if not final_item:
310+
writer.add_relation(o.osm.mutable.Relation(id=125))
311+
finally:
312+
writer.close()
313+
314+
output = test_file.read_text()
315+
316+
expected = 'r123 v0 dV c0 t i0 u T M\n'
317+
if not final_item:
318+
expected += 'r125 v0 dV c0 t i0 u T M\n'
319+
320+
assert output == expected

0 commit comments

Comments
 (0)