Merge pull request #8800 from radarhere/path_lists

Allow coords to be sequence of lists
This commit is contained in:
Andrew Murray 2025-03-06 04:15:55 +11:00 committed by GitHub
parent 5e9eea12f3
commit 5ba72a9b54
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 57 additions and 42 deletions

View File

@ -39,6 +39,8 @@ BBOX = (((X0, Y0), (X1, Y1)), [(X0, Y0), (X1, Y1)], (X0, Y0, X1, Y1), [X0, Y0, X
POINTS = (
((10, 10), (20, 40), (30, 30)),
[(10, 10), (20, 40), (30, 30)],
([10, 10], [20, 40], [30, 30]),
[[10, 10], [20, 40], [30, 30]],
(10, 10, 20, 40, 30, 30),
[10, 10, 20, 40, 30, 30],
)
@ -46,6 +48,8 @@ POINTS = (
KITE_POINTS = (
((10, 50), (70, 10), (90, 50), (70, 90), (10, 50)),
[(10, 50), (70, 10), (90, 50), (70, 90), (10, 50)],
([10, 50], [70, 10], [90, 50], [70, 90], [10, 50]),
[[10, 50], [70, 10], [90, 50], [70, 90], [10, 50]],
)

View File

@ -68,21 +68,10 @@ def test_path_constructors(
assert list(p) == [(0.0, 1.0)]
@pytest.mark.parametrize(
"coords",
(
("a", "b"),
([0, 1],),
[[0, 1]],
([0.0, 1.0],),
[[0.0, 1.0]],
),
)
def test_invalid_path_constructors(
coords: tuple[str, str] | Sequence[Sequence[int]],
) -> None:
def test_invalid_path_constructors() -> None:
# Arrange / Act
with pytest.raises(ValueError, match="incorrect coordinate type"):
ImagePath.Path(coords)
ImagePath.Path(("a", "b"))
@pytest.mark.parametrize(

View File

@ -109,6 +109,39 @@ path_dealloc(PyPathObject *path) {
#define PyPath_Check(op) (Py_TYPE(op) == &PyPathType)
static int
assign_item_to_array(double *xy, Py_ssize_t j, PyObject *op) {
if (PyFloat_Check(op)) {
xy[j++] = PyFloat_AS_DOUBLE(op);
} else if (PyLong_Check(op)) {
xy[j++] = (float)PyLong_AS_LONG(op);
} else if (PyNumber_Check(op)) {
xy[j++] = PyFloat_AsDouble(op);
} else if (PyList_Check(op)) {
for (int k = 0; k < 2; k++) {
PyObject *op1 = PyList_GetItemRef(op, k);
if (op1 == NULL) {
return -1;
}
j = assign_item_to_array(xy, j, op1);
Py_DECREF(op1);
if (j == -1) {
return -1;
}
}
} else {
double x, y;
if (PyArg_ParseTuple(op, "dd", &x, &y)) {
xy[j++] = x;
xy[j++] = y;
} else {
PyErr_SetString(PyExc_ValueError, "incorrect coordinate type");
return -1;
}
}
return j;
}
Py_ssize_t
PyPath_Flatten(PyObject *data, double **pxy) {
Py_ssize_t i, j, n;
@ -164,48 +197,32 @@ PyPath_Flatten(PyObject *data, double **pxy) {
return -1;
}
#define assign_item_to_array(op, decref) \
if (PyFloat_Check(op)) { \
xy[j++] = PyFloat_AS_DOUBLE(op); \
} else if (PyLong_Check(op)) { \
xy[j++] = (float)PyLong_AS_LONG(op); \
} else if (PyNumber_Check(op)) { \
xy[j++] = PyFloat_AsDouble(op); \
} else if (PyArg_ParseTuple(op, "dd", &x, &y)) { \
xy[j++] = x; \
xy[j++] = y; \
} else { \
PyErr_SetString(PyExc_ValueError, "incorrect coordinate type"); \
if (decref) { \
Py_DECREF(op); \
} \
free(xy); \
return -1; \
} \
if (decref) { \
Py_DECREF(op); \
}
/* Copy table to path array */
if (PyList_Check(data)) {
for (i = 0; i < n; i++) {
double x, y;
PyObject *op = PyList_GetItemRef(data, i);
if (op == NULL) {
free(xy);
return -1;
}
assign_item_to_array(op, 1);
j = assign_item_to_array(xy, j, op);
Py_DECREF(op);
if (j == -1) {
free(xy);
return -1;
}
}
} else if (PyTuple_Check(data)) {
for (i = 0; i < n; i++) {
double x, y;
PyObject *op = PyTuple_GET_ITEM(data, i);
assign_item_to_array(op, 0);
j = assign_item_to_array(xy, j, op);
if (j == -1) {
free(xy);
return -1;
}
}
} else {
for (i = 0; i < n; i++) {
double x, y;
PyObject *op = PySequence_GetItem(data, i);
if (!op) {
/* treat IndexError as end of sequence */
@ -217,7 +234,12 @@ PyPath_Flatten(PyObject *data, double **pxy) {
return -1;
}
}
assign_item_to_array(op, 1);
j = assign_item_to_array(xy, j, op);
Py_DECREF(op);
if (j == -1) {
free(xy);
return -1;
}
}
}