diff options
author | Stefan Behnel <stefan_ml@behnel.de> | 2023-04-21 09:36:00 +0200 |
---|---|---|
committer | scoder <stefan_ml@behnel.de> | 2023-04-24 16:05:24 +0200 |
commit | 07a72c33dcceb861600449682aa4ed2492b5ac00 (patch) | |
tree | 7ca9502bcaa59d772682b3e8c13352066c455e4c | |
parent | be73c3cb8f30b79867bcc3e78cfc30e932486ec5 (diff) | |
download | cython-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.c | 47 | ||||
-rw-r--r-- | tests/run/ctuple.pyx | 29 |
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 |