Buffers: Better error messages + bugfix
authorDag Sverre Seljebotn <dagss@student.matnat.uio.no>
Mon, 13 Oct 2008 20:11:27 +0000 (22:11 +0200)
committerDag Sverre Seljebotn <dagss@student.matnat.uio.no>
Mon, 13 Oct 2008 20:11:27 +0000 (22:11 +0200)
Cython/Compiler/Buffer.py
tests/run/bufaccess.pyx
tests/run/numpy_test.pyx

index f1b5d89e6b234f432081e7f932557c74cc1efb07..e8f092e0812b35737c1e7628739d153160f054d1 100644 (file)
@@ -520,8 +520,7 @@ def create_typestringchecker(protocode, defcode, name, dtype):
 
     def put_assert(cond, msg):
         defcode.putln("if (!(%s)) {" % cond)
-        msg += ", got '%s'"
-        defcode.putln('PyErr_Format(PyExc_ValueError, "%s", ts);' % msg)
+        defcode.putln('PyErr_Format(PyExc_ValueError, "Buffer dtype mismatch (%s)", __Pyx_DescribeTokenInFormatString(ts));' % msg)
         defcode.putln("return NULL;")
         defcode.putln("}")
     
@@ -583,14 +582,7 @@ def create_typestringchecker(protocode, defcode, name, dtype):
                                   (char, ctype, against, ctype))
             defcode.putln("default: ok = 0;")
             defcode.putln("}")
-        defcode.putln("if (!ok) {")
-        if dtype.typestring is not None:
-            errmsg = "Buffer datatype mismatch (expected '%s', got '%%s')" % dtype.typestring
-        else:
-            errmsg = "Buffer datatype mismatch (rejecting on '%s')"
-        defcode.putln('PyErr_Format(PyExc_ValueError, "%s", ts);' % errmsg)
-        defcode.putln("return NULL;");
-        defcode.putln("}")
+        put_assert("ok", "expected %s, got %%s" % dtype)
         defcode.putln("++ts;")
     elif complex_possible:
         # Could be a struct representing a complex number, so allow
@@ -605,9 +597,7 @@ def create_typestringchecker(protocode, defcode, name, dtype):
                 real_t.declaration_code(""),
                 imag_t.declaration_code("")))
             defcode.putln('PyErr_SetString(PyExc_ValueError, "Cannot store complex number in \'%s\' as \'%s\' differs from \'%s\' in size.");' % (
-                dtype.declaration_code("", for_display=True),
-                real_t.declaration_code("", for_display=True),
-                imag_t.declaration_code("", for_display=True)))
+                dtype, real_t, imag_t))
             defcode.putln("return NULL;")
             defcode.putln("}")
             check_real, check_imag = [x[2] for x in field_blocks]
@@ -624,21 +614,23 @@ def create_typestringchecker(protocode, defcode, name, dtype):
         defcode.putln("int n, count;")
         defcode.putln("ts = __Pyx_ConsumeWhitespace(ts); if (!ts) return NULL;")
 
-        for n, type, checker in field_blocks:
+        next_types = [x[1] for x in field_blocks[1:]] + ["end"]
+        for (n, type, checker), next_type in zip(field_blocks, next_types):
             if n == 1:
                 defcode.putln("if (*ts == '1') ++ts;")
             else:
                 defcode.putln("n = %d;" % n);
                 defcode.putln("do {")
                 defcode.putln("ts = __Pyx_ParseTypestringRepeat(ts, &count); n -= count;")
+                put_assert("n >= 0", "expected %s, got %%s" % next_type)
 
             simple = type.is_simple_buffer_dtype()
             if not simple:
-                put_assert("*ts == 'T' && *(ts+1) == '{'", "Expected start of %s" % type.declaration_code("", for_display=True))
+                put_assert("*ts == 'T' && *(ts+1) == '{'", "expected %s, got %%s" % type)
                 defcode.putln("ts += 2;")
             defcode.putln("ts = %s(ts); if (!ts) return NULL;" % checker)
             if not simple:
-                put_assert("*ts == '}'", "Expected end of '%s'" % type.declaration_code("", for_display=True))
+                put_assert("*ts == '}'", "expected end of %s struct, got %%s" % type)
                 defcode.putln("++ts;")
 
             if n > 1:
@@ -689,7 +681,8 @@ def get_getbuffer_code(dtype, code):
             if (!ts) goto fail;
             if (*ts != 0) {
               PyErr_Format(PyExc_ValueError,
-                "Buffer format string specifies more data than '%(dtype_name)s' can hold (expected end, got '%%s')", ts);
+                "Buffer dtype mismatch (expected end, got %%s)",
+                __Pyx_DescribeTokenInFormatString(ts));
               goto fail;
             }
           } else {
@@ -822,6 +815,7 @@ static INLINE void __Pyx_SafeReleaseBuffer(Py_buffer* info);
 static INLINE void __Pyx_ZeroBuffer(Py_buffer* buf); /*proto*/
 static INLINE const char* __Pyx_ConsumeWhitespace(const char* ts); /*proto*/
 static void __Pyx_BufferNdimError(Py_buffer* buffer, int expected_ndim); /*proto*/
+static const char* __Pyx_DescribeTokenInFormatString(const char* ts); /*proto*/
 """, """
 static INLINE void __Pyx_SafeReleaseBuffer(Py_buffer* info) {
   if (info->buf == NULL) return;
@@ -864,6 +858,34 @@ static void __Pyx_BufferNdimError(Py_buffer* buffer, int expected_ndim) {
                expected_ndim, buffer->ndim);
 }
 
+static const char* __Pyx_DescribeTokenInFormatString(const char* ts) {
+  switch (*ts) {
+    case 'b': return "char";
+    case 'B': return "unsigned char";
+    case 'h': return "short";
+    case 'H': return "unsigned short";
+    case 'i': return "int";
+    case 'I': return "unsigned int";
+    case 'l': return "long";
+    case 'L': return "unsigned long";
+    case 'q': return "long long";
+    case 'Q': return "unsigned long long";
+    case 'f': return "float";
+    case 'd': return "double";
+    case 'g': return "long double";
+    case 'Z': switch (*(ts+1)) {
+        case 'f': return "complex float";
+        case 'd': return "complex double";
+        case 'g': return "complex long double";
+        default: return "unparseable format string";
+    }
+    case 'T': return "a struct";
+    case 'O': return "Python object";
+    case 'P': return "a pointer";
+    default: return "unparseable format string";
+  }
+}
+
 """]
 
 
index cdd7b4d324e57a21c7b7e1400eb54c6dff199aac..ce228cf4c805be736425b03eeb73a71a5278d9c6 100644 (file)
@@ -373,14 +373,14 @@ def alignment_string(object[int] buf):
 @testcase
 def wrong_string(object[int] buf):
     """
-    >>> wrong_string(IntMockBuffer(None, [1,2], format="iasdf"))
+    >>> wrong_string(IntMockBuffer(None, [1,2], format="if"))
     Traceback (most recent call last):
         ...
-    ValueError: Buffer format string specifies more data than 'int' can hold (expected end, got 'asdf')
+    ValueError: Buffer dtype mismatch (expected end, got float)
     >>> wrong_string(IntMockBuffer(None, [1,2], format="$$"))
     Traceback (most recent call last):
         ...
-    ValueError: Buffer datatype mismatch (expected 'i', got '$$')
+    ValueError: Buffer dtype mismatch (expected int, got unparseable format string)
     """
     print buf[1]
 
@@ -532,7 +532,7 @@ def fmtst1(buf):
     >>> fmtst1(IntMockBuffer("A", range(3)))
     Traceback (most recent call last):
         ...
-    ValueError: Buffer datatype mismatch (expected 'f', got 'i')
+    ValueError: Buffer dtype mismatch (expected float, got int)
     """
     cdef object[float] a = buf
 
@@ -542,7 +542,7 @@ def fmtst2(object[int] buf):
     >>> fmtst2(FloatMockBuffer("A", range(3)))
     Traceback (most recent call last):
         ...
-    ValueError: Buffer datatype mismatch (expected 'i', got 'f')
+    ValueError: Buffer dtype mismatch (expected int, got float)
     """
 
 @testcase
@@ -849,7 +849,7 @@ def printbuf_td_cy_int(object[td_cy_int] buf, shape):
     >>> printbuf_td_cy_int(ShortMockBuffer(None, range(3)), (3,))
     Traceback (most recent call last):
        ...
-    ValueError: Buffer datatype mismatch (rejecting on 'h')
+    ValueError: Buffer dtype mismatch (expected bufaccess.td_cy_int, got short)
     
     """
     cdef int i
@@ -865,7 +865,7 @@ def printbuf_td_h_short(object[td_h_short] buf, shape):
     >>> printbuf_td_h_short(IntMockBuffer(None, range(3)), (3,))
     Traceback (most recent call last):
        ...
-    ValueError: Buffer datatype mismatch (rejecting on 'i')
+    ValueError: Buffer dtype mismatch (expected bufaccess.td_h_short, got int)
     """    
     cdef int i
     for i in range(shape[0]):
@@ -880,7 +880,7 @@ def printbuf_td_h_cy_short(object[td_h_cy_short] buf, shape):
     >>> printbuf_td_h_cy_short(IntMockBuffer(None, range(3)), (3,))
     Traceback (most recent call last):
        ...
-    ValueError: Buffer datatype mismatch (rejecting on 'i')
+    ValueError: Buffer dtype mismatch (expected bufaccess.td_h_cy_short, got int)
     """
     cdef int i
     for i in range(shape[0]):
@@ -895,7 +895,7 @@ def printbuf_td_h_ushort(object[td_h_ushort] buf, shape):
     >>> printbuf_td_h_ushort(ShortMockBuffer(None, range(3)), (3,))
     Traceback (most recent call last):
        ...
-    ValueError: Buffer datatype mismatch (rejecting on 'h')
+    ValueError: Buffer dtype mismatch (expected bufaccess.td_h_ushort, got short)
     """
     cdef int i
     for i in range(shape[0]):
@@ -910,7 +910,7 @@ def printbuf_td_h_double(object[td_h_double] buf, shape):
     >>> printbuf_td_h_double(FloatMockBuffer(None, [0.25, 1, 3.125]), (3,))
     Traceback (most recent call last):
        ...
-    ValueError: Buffer datatype mismatch (rejecting on 'f')
+    ValueError: Buffer dtype mismatch (expected bufaccess.td_h_double, got float)
     """
     cdef int i
     for i in range(shape[0]):
@@ -1328,10 +1328,14 @@ def basic_struct(object[MyStruct] buf):
     1 2 3 4 5
     >>> basic_struct(MyStructMockBuffer(None, [(1, 2, 3, 4, 5)], format="bbqii"))
     1 2 3 4 5
+    >>> basic_struct(MyStructMockBuffer(None, [(1, 2, 3, 4, 5)], format="23bqii"))
+    Traceback (most recent call last):
+        ...
+    ValueError: Buffer dtype mismatch (expected long long, got char)
     >>> basic_struct(MyStructMockBuffer(None, [(1, 2, 3, 4, 5)], format="i"))
     Traceback (most recent call last):
         ...
-    ValueError: Buffer datatype mismatch (expected 'b', got 'i')
+    ValueError: Buffer dtype mismatch (expected char, got int)
     """
     print buf[0].a, buf[0].b, buf[0].c, buf[0].d, buf[0].e
 
@@ -1345,7 +1349,11 @@ def nested_struct(object[NestedStruct] buf):
     >>> nested_struct(NestedStructMockBuffer(None, [(1, 2, 3, 4, 5)], format="iiiii"))
     Traceback (most recent call last):
         ...
-    ValueError: Expected start of SmallStruct, got 'iiiii'
+    ValueError: Buffer dtype mismatch (expected SmallStruct, got int)
+    >>> nested_struct(NestedStructMockBuffer(None, [(1, 2, 3, 4, 5)], format="T{iii}T{ii}i"))
+    Traceback (most recent call last):
+        ...
+    ValueError: Buffer dtype mismatch (expected end of SmallStruct struct, got int)
     """
     print buf[0].x.a, buf[0].x.b, buf[0].y.a, buf[0].y.b, buf[0].z
 
index db514110c085c735db1f629eff44a87fec379ded..fb2113c68c9cb2764dc4b36639796504fb6ff758 100644 (file)
@@ -144,7 +144,7 @@ try:
         ])))
     Traceback (most recent call last):
         ...
-    ValueError: Buffer datatype mismatch (expected 'i', got 'f}T{ii}')
+    ValueError: Buffer dtype mismatch (expected int, got float)
 
     >>> test_good_cast()
     True