From be560f00f5ae964fd7c0342390a3fa23c8e7c312 Mon Sep 17 00:00:00 2001 From: Christoph Gohlke Date: Sun, 21 Oct 2012 11:01:14 -0500 Subject: [PATCH] py3k: Allow slicing for paths This is Gohlke's fix for two issues: negative indexes on paths were not resolved to the correct index, and path slicing didn't work. His fix for slicing is related to the one found at: http://renesd.blogspot.com/2009/07/python3-c-api-simple-slicing-sqslice.html With this commit, all 79 tests (82 minus the three skipped ones) run successfully on Python 2.6.8, Python 2.7.3rc2, and Python 3.2.3. --- path.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/path.c b/path.c index af0f4951d..a27b59156 100644 --- a/path.c +++ b/path.c @@ -370,6 +370,8 @@ path_getbbox(PyPathObject* self, PyObject* args) static PyObject* path_getitem(PyPathObject* self, int i) { + if (i < 0) + i = self->count + i; if (i < 0 || i >= self->count) { PyErr_SetString(PyExc_IndexError, "path index out of range"); return NULL; @@ -559,6 +561,47 @@ static struct PyGetSetDef getsetters[] = { { NULL } }; +static PyObject* +path_subscript(PyPathObject* self, PyObject* item) { + if (PyIndex_Check(item)) { + Py_ssize_t i; + i = PyNumber_AsSsize_t(item, PyExc_IndexError); + if (i == -1 && PyErr_Occurred()) + return NULL; + return path_getitem(self, i); + } + if (PySlice_Check(item)) { + int len = 4; + Py_ssize_t start, stop, step, slicelength; + +#if PY_VERSION_HEX >= 0x03000000 + if (PySlice_GetIndicesEx(item, len, &start, &stop, &step, &slicelength) < 0) + return NULL; +#else + if (PySlice_GetIndicesEx((PySliceObject*)item, len, &start, &stop, &step, &slicelength) < 0) + return NULL; +#endif + + if (slicelength <= 0) { + double *xy = alloc_array(0); + return (PyObject*) path_new(0, xy, 0); + } + else if (step == 1) { + return path_getslice(self, start, stop); + } + else { + PyErr_SetString(PyExc_TypeError, "slice steps not supported"); + return NULL; + } + } + else { + PyErr_Format(PyExc_TypeError, + "Path indices must be integers, not %.200s", + Py_TYPE(&item)->tp_name); + return NULL; + } +} + static PySequenceMethods path_as_sequence = { (lenfunc)path_len, /*sq_length*/ (binaryfunc)0, /*sq_concat*/ @@ -569,6 +612,12 @@ static PySequenceMethods path_as_sequence = { (ssizessizeobjargproc)0, /*sq_ass_slice*/ }; +static PyMappingMethods path_as_mapping = { + (lenfunc)path_len, + (binaryfunc)path_subscript, + NULL +}; + static PyTypeObject PyPathType = { PyVarObject_HEAD_INIT(NULL, 0) "Path", /*tp_name*/ @@ -583,7 +632,7 @@ static PyTypeObject PyPathType = { 0, /*tp_repr*/ 0, /*tp_as_number */ &path_as_sequence, /*tp_as_sequence */ - 0, /*tp_as_mapping */ + &path_as_mapping, /*tp_as_mapping */ 0, /*tp_hash*/ 0, /*tp_call*/ 0, /*tp_str*/