Skip to content

Commit 126294f

Browse files
committed
Fix exception handling when constructing C-level PathGenerator.
The PathGenerator constructor does not set a Python-level exception on failure. Switch to use a PyArg_ParseTuple-style converter to get proper error handling. (Also, CALL_CPP already converts py::exception to Python-level exceptions, so it doesn't need to be wrapped in a C++-level try... catch.)
1 parent a26f9a3 commit 126294f

File tree

6 files changed

+57
-68
lines changed

6 files changed

+57
-68
lines changed

lib/matplotlib/tests/test_agg.py

+7
Original file line numberDiff line numberDiff line change
@@ -244,3 +244,10 @@ def test_pil_kwargs_tiff():
244244
im = Image.open(buf)
245245
tags = {TiffTags.TAGS_V2[k].name: v for k, v in im.tag_v2.items()}
246246
assert tags["ImageDescription"] == "test image"
247+
248+
249+
def test_draw_path_collection_error_handling():
250+
fig, ax = plt.subplots()
251+
ax.scatter([1], [1]).set_paths(path.Path([(0, 1), (2, 3)]))
252+
with pytest.raises(TypeError):
253+
fig.canvas.draw()

src/_backend_agg_wrapper.cpp

+16-24
Original file line numberDiff line numberDiff line change
@@ -320,7 +320,7 @@ PyRendererAgg_draw_path_collection(PyRendererAgg *self, PyObject *args, PyObject
320320
{
321321
GCAgg gc;
322322
agg::trans_affine master_transform;
323-
PyObject *pathobj;
323+
py::PathGenerator paths;
324324
numpy::array_view<const double, 3> transforms;
325325
numpy::array_view<const double, 2> offsets;
326326
agg::trans_affine offset_trans;
@@ -333,12 +333,13 @@ PyRendererAgg_draw_path_collection(PyRendererAgg *self, PyObject *args, PyObject
333333
PyObject *offset_position; // offset position is no longer used
334334

335335
if (!PyArg_ParseTuple(args,
336-
"O&O&OO&O&O&O&O&O&O&O&OO:draw_path_collection",
336+
"O&O&O&O&O&O&O&O&O&O&O&OO:draw_path_collection",
337337
&convert_gcagg,
338338
&gc,
339339
&convert_trans_affine,
340340
&master_transform,
341-
&pathobj,
341+
&convert_pathgen,
342+
&paths,
342343
&convert_transforms,
343344
&transforms,
344345
&convert_points,
@@ -360,27 +361,18 @@ PyRendererAgg_draw_path_collection(PyRendererAgg *self, PyObject *args, PyObject
360361
return NULL;
361362
}
362363

363-
try
364-
{
365-
py::PathGenerator path(pathobj);
366-
367-
CALL_CPP("draw_path_collection",
368-
(self->x->draw_path_collection(gc,
369-
master_transform,
370-
path,
371-
transforms,
372-
offsets,
373-
offset_trans,
374-
facecolors,
375-
edgecolors,
376-
linewidths,
377-
dashes,
378-
antialiaseds)));
379-
}
380-
catch (const py::exception &)
381-
{
382-
return NULL;
383-
}
364+
CALL_CPP("draw_path_collection",
365+
(self->x->draw_path_collection(gc,
366+
master_transform,
367+
paths,
368+
transforms,
369+
offsets,
370+
offset_trans,
371+
facecolors,
372+
edgecolors,
373+
linewidths,
374+
dashes,
375+
antialiaseds)));
384376

385377
Py_RETURN_NONE;
386378
}

src/_path_wrapper.cpp

+22-38
Original file line numberDiff line numberDiff line change
@@ -269,17 +269,18 @@ const char *Py_get_path_collection_extents__doc__ =
269269
static PyObject *Py_get_path_collection_extents(PyObject *self, PyObject *args, PyObject *kwds)
270270
{
271271
agg::trans_affine master_transform;
272-
PyObject *pathsobj;
272+
py::PathGenerator paths;
273273
numpy::array_view<const double, 3> transforms;
274274
numpy::array_view<const double, 2> offsets;
275275
agg::trans_affine offset_trans;
276276
extent_limits e;
277277

278278
if (!PyArg_ParseTuple(args,
279-
"O&OO&O&O&:get_path_collection_extents",
279+
"O&O&O&O&O&:get_path_collection_extents",
280280
&convert_trans_affine,
281281
&master_transform,
282-
&pathsobj,
282+
&convert_pathgen,
283+
&paths,
283284
&convert_transforms,
284285
&transforms,
285286
&convert_points,
@@ -289,18 +290,9 @@ static PyObject *Py_get_path_collection_extents(PyObject *self, PyObject *args,
289290
return NULL;
290291
}
291292

292-
try
293-
{
294-
py::PathGenerator paths(pathsobj);
295-
296-
CALL_CPP("get_path_collection_extents",
297-
(get_path_collection_extents(
298-
master_transform, paths, transforms, offsets, offset_trans, e)));
299-
}
300-
catch (const py::exception &)
301-
{
302-
return NULL;
303-
}
293+
CALL_CPP("get_path_collection_extents",
294+
(get_path_collection_extents(
295+
master_transform, paths, transforms, offsets, offset_trans, e)));
304296

305297
npy_intp dims[] = { 2, 2 };
306298
numpy::array_view<double, 2> extents(dims);
@@ -327,7 +319,7 @@ static PyObject *Py_point_in_path_collection(PyObject *self, PyObject *args, PyO
327319
{
328320
double x, y, radius;
329321
agg::trans_affine master_transform;
330-
PyObject *pathsobj;
322+
py::PathGenerator paths;
331323
numpy::array_view<const double, 3> transforms;
332324
numpy::array_view<const double, 2> offsets;
333325
agg::trans_affine offset_trans;
@@ -336,13 +328,14 @@ static PyObject *Py_point_in_path_collection(PyObject *self, PyObject *args, PyO
336328
std::vector<int> result;
337329

338330
if (!PyArg_ParseTuple(args,
339-
"dddO&OO&O&O&O&O:point_in_path_collection",
331+
"dddO&O&O&O&O&O&O:point_in_path_collection",
340332
&x,
341333
&y,
342334
&radius,
343335
&convert_trans_affine,
344336
&master_transform,
345-
&pathsobj,
337+
&convert_pathgen,
338+
&paths,
346339
&convert_transforms,
347340
&transforms,
348341
&convert_points,
@@ -355,26 +348,17 @@ static PyObject *Py_point_in_path_collection(PyObject *self, PyObject *args, PyO
355348
return NULL;
356349
}
357350

358-
try
359-
{
360-
py::PathGenerator paths(pathsobj);
361-
362-
CALL_CPP("point_in_path_collection",
363-
(point_in_path_collection(x,
364-
y,
365-
radius,
366-
master_transform,
367-
paths,
368-
transforms,
369-
offsets,
370-
offset_trans,
371-
filled,
372-
result)));
373-
}
374-
catch (const py::exception &)
375-
{
376-
return NULL;
377-
}
351+
CALL_CPP("point_in_path_collection",
352+
(point_in_path_collection(x,
353+
y,
354+
radius,
355+
master_transform,
356+
paths,
357+
transforms,
358+
offsets,
359+
offset_trans,
360+
filled,
361+
result)));
378362

379363
npy_intp dims[] = {(npy_intp)result.size() };
380364
numpy::array_view<int, 1> pyresult(dims);

src/py_adaptors.h

+1-6
Original file line numberDiff line numberDiff line change
@@ -194,12 +194,7 @@ class PathGenerator
194194
public:
195195
typedef PathIterator path_iterator;
196196

197-
PathGenerator(PyObject *obj) : m_paths(NULL), m_npaths(0)
198-
{
199-
if (!set(obj)) {
200-
throw py::exception();
201-
}
202-
}
197+
PathGenerator() : m_paths(NULL), m_npaths(0) {}
203198

204199
~PathGenerator()
205200
{

src/py_converters.cpp

+10
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,16 @@ int convert_path(PyObject *obj, void *pathp)
415415
return status;
416416
}
417417

418+
int convert_pathgen(PyObject *obj, void *pathgenp)
419+
{
420+
py::PathGenerator *paths = (py::PathGenerator *)pathgenp;
421+
if (!paths->set(obj)) {
422+
PyErr_SetString(PyExc_TypeError, "Not an iterable of paths");
423+
return 0;
424+
}
425+
return 1;
426+
}
427+
418428
int convert_clippath(PyObject *clippath_tuple, void *clippathp)
419429
{
420430
ClipPath *clippath = (ClipPath *)clippathp;

src/py_converters.h

+1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ int convert_dashes(PyObject *dashobj, void *gcp);
3232
int convert_dashes_vector(PyObject *obj, void *dashesp);
3333
int convert_trans_affine(PyObject *obj, void *transp);
3434
int convert_path(PyObject *obj, void *pathp);
35+
int convert_pathgen(PyObject *obj, void *pathgenp);
3536
int convert_clippath(PyObject *clippath_tuple, void *clippathp);
3637
int convert_snap(PyObject *obj, void *snapp);
3738
int convert_sketch_params(PyObject *obj, void *sketchp);

0 commit comments

Comments
 (0)