summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Behnel <stefan_ml@behnel.de>2023-04-21 09:36:00 +0200
committerscoder <stefan_ml@behnel.de>2023-04-24 16:05:24 +0200
commit07a72c33dcceb861600449682aa4ed2492b5ac00 (patch)
tree7ca9502bcaa59d772682b3e8c13352066c455e4c
parentbe73c3cb8f30b79867bcc3e78cfc30e932486ec5 (diff)
downloadcython-07a72c33dcceb861600449682aa4ed2492b5ac00.tar.gz
Allow assigning ctuples from arbitrary sequences, not just tuples. The code was there anyway, just needed moving around a bit.
-rw-r--r--Cython/Utility/TypeConversion.c47
-rw-r--r--tests/run/ctuple.pyx29
2 files changed, 59 insertions, 17 deletions
diff --git a/Cython/Utility/TypeConversion.c b/Cython/Utility/TypeConversion.c
index 9ca29a0f0..75b95df0d 100644
--- a/Cython/Utility/TypeConversion.c
+++ b/Cython/Utility/TypeConversion.c
@@ -570,31 +570,41 @@ bad:
/////////////// FromPyCTupleUtility.proto ///////////////
-static {{struct_type_decl}} {{funcname}}(PyObject *);
+static CYTHON_INLINE {{struct_type_decl}} {{funcname}}(PyObject *);
/////////////// FromPyCTupleUtility ///////////////
-static {{struct_type_decl}} {{funcname}}(PyObject * o) {
+
+#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
+static {{struct_type_decl}} __Pyx_tuple_{{funcname}}(PyObject * o) {
{{struct_type_decl}} result;
- if (unlikely(!PyTuple_Check(o))) {
+ {{for ix, component in enumerate(components):}}
+ {{py:attr = "result.f%s" % ix}}
+ {{attr}} = {{component.from_py_function}}(PyTuple_GET_ITEM(o, {{ix}}));
+ if ({{component.error_condition(attr)}}) goto bad;
+ {{endfor}}
+
+ return result;
+bad:
+ return result;
+}
+#endif
+
+static {{struct_type_decl}} __Pyx_seq_{{funcname}}(PyObject * o) {
+ {{struct_type_decl}} result;
+
+ if (unlikely(!PySequence_Check(o))) {
__Pyx_TypeName o_type_name = __Pyx_PyType_GetName(Py_TYPE(o));
PyErr_Format(PyExc_TypeError,
- "Expected a tuple of size %zd, got " __Pyx_FMT_TYPENAME, (Py_ssize_t) {{size}}, o_type_name);
+ "Expected a sequence of size %zd, got " __Pyx_FMT_TYPENAME, (Py_ssize_t) {{size}}, o_type_name);
__Pyx_DECREF_TypeName(o_type_name);
goto bad;
- } else if (unlikely(PyTuple_GET_SIZE(o) != {{size}})) {
+ } else if (unlikely(PySequence_Length(o) != {{size}})) {
PyErr_Format(PyExc_TypeError,
- "Expected a tuple of size %zd, got size %zd", (Py_ssize_t) {{size}}, PyTuple_GET_SIZE(o));
+ "Expected a sequence of size %zd, got size %zd", (Py_ssize_t) {{size}}, PySequence_Length(o));
goto bad;
}
-#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
- {{for ix, component in enumerate(components):}}
- {{py:attr = "result.f%s" % ix}}
- {{attr}} = {{component.from_py_function}}(PyTuple_GET_ITEM(o, {{ix}}));
- if ({{component.error_condition(attr)}}) goto bad;
- {{endfor}}
-#else
{
PyObject *item;
{{for ix, component in enumerate(components):}}
@@ -605,13 +615,22 @@ static {{struct_type_decl}} {{funcname}}(PyObject * o) {
if ({{component.error_condition(attr)}}) goto bad;
{{endfor}}
}
-#endif
return result;
bad:
return result;
}
+static CYTHON_INLINE {{struct_type_decl}} {{funcname}}(PyObject * o) {
+ #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
+ if (likely(PyTuple_Check(o) && PyTuple_GET_SIZE(o) == {{size}})) {
+ return __Pyx_tuple_{{funcname}}(o);
+ }
+ #endif
+
+ return __Pyx_seq_{{funcname}}(o);
+}
+
/////////////// UnicodeAsUCS4.proto ///////////////
diff --git a/tests/run/ctuple.pyx b/tests/run/ctuple.pyx
index 9412a2cc3..88cfdddfb 100644
--- a/tests/run/ctuple.pyx
+++ b/tests/run/ctuple.pyx
@@ -1,5 +1,8 @@
+# mode: run
+
import cython
+
def simple_convert(*o):
"""
>>> simple_convert(1, 2)
@@ -8,15 +11,35 @@ def simple_convert(*o):
>>> simple_convert(1)
Traceback (most recent call last):
...
- TypeError: Expected a tuple of size 2, got size 1
+ TypeError: Expected a sequence of size 2, got size 1
>>> simple_convert(1, 2, 3)
Traceback (most recent call last):
...
- TypeError: Expected a tuple of size 2, got size 3
+ TypeError: Expected a sequence of size 2, got size 3
"""
cdef (int, double) xy = o
return xy
+
+def convert_from_list(*o):
+ """
+ >>> convert_from_list(1, 2)
+ (1, 2.0)
+
+ >>> convert_from_list(1)
+ Traceback (most recent call last):
+ ...
+ TypeError: Expected a sequence of size 2, got size 1
+ >>> convert_from_list(1, 2, 3)
+ Traceback (most recent call last):
+ ...
+ TypeError: Expected a sequence of size 2, got size 3
+ """
+ cdef object values = list(o)
+ cdef (int, double) xy = values
+ return xy
+
+
def indexing((int, double) xy):
"""
>>> indexing((1, 2))
@@ -231,7 +254,7 @@ def test_mul_to_ctuple((int, int) ab, int c):
(1, 2, 1, 2)
>>> test_mul_to_ctuple((1, 2), 3)
Traceback (most recent call last):
- TypeError: Expected a tuple of size 4, got size 6
+ TypeError: Expected a sequence of size 4, got size 6
"""
result: tuple[cython.int, cython.int, cython.int, cython.int] = ab * c
return result