import unittest
+from test.support import MS_WINDOWS
import ctypes
from ctypes import POINTER, c_void_p
self.assertIsInstance(POINTER(Sub), p_meta)
self.assertIsSubclass(POINTER(Sub), Sub)
+
+ def test_bad_type_message(self):
+ """Verify the error message that lists all available type codes"""
+ # (The string is generated at runtime, so this checks the underlying
+ # set of types as well as correct construction of the string.)
+ with self.assertRaises(AttributeError) as cm:
+ class F(metaclass=PyCSimpleType):
+ _type_ = "\0"
+ message = str(cm.exception)
+ expected_type_chars = list('cbBhHiIlLdCEFfuzZqQPXOv?g')
+ if not hasattr(ctypes, 'c_float_complex'):
+ expected_type_chars.remove('C')
+ expected_type_chars.remove('E')
+ expected_type_chars.remove('F')
+ if not MS_WINDOWS:
+ expected_type_chars.remove('X')
+ self.assertIn("'" + ''.join(expected_type_chars) + "'", message)
[clinic start generated code]*/
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=dd4d9646c56f43a9]*/
-#if defined(Py_HAVE_C_COMPLEX) && defined(Py_FFI_SUPPORT_C_COMPLEX)
-static const char SIMPLE_TYPE_CHARS[] = "cbBhHiIlLdCEFfuzZqQPXOv?g";
-#else
-static const char SIMPLE_TYPE_CHARS[] = "cbBhHiIlLdfuzZqQPXOv?g";
-#endif
/*[clinic input]
_ctypes.c_wchar_p.from_param as c_wchar_p_from_param
"which must be a string of length 1");
goto error;
}
- if (!strchr(SIMPLE_TYPE_CHARS, *proto_str)) {
+ fmt = _ctypes_get_fielddesc(proto_str);
+ if (!fmt) {
PyErr_Format(PyExc_AttributeError,
"class must define a '_type_' attribute which must be\n"
- "a single character string containing one of '%s'.",
- SIMPLE_TYPE_CHARS);
- goto error;
- }
- fmt = _ctypes_get_fielddesc(proto_str);
- if (fmt == NULL) {
- PyErr_Format(PyExc_ValueError,
- "_type_ '%s' not supported", proto_str);
+ "a single character string containing one of the\n"
+ "supported types: '%s'.",
+ _ctypes_get_simple_type_chars());
goto error;
}
// always contains NULLs:
struct fielddesc fmt_nil;
+
+ // Result of _ctypes_get_simple_type_chars. Initialized just after
+ // the rest of formattable, so we stash it here.
+ char simple_type_chars[26];
};
static struct formattable formattable;
/* Delayed initialization. Windows cannot statically reference dynamically
loaded addresses from DLLs. */
-void
-_ctypes_init_fielddesc(void)
+static void
+_ctypes_init_fielddesc_locked(void)
{
/* Fixed-width integers */
TABLE_ENTRY_SW(d, &ffi_type_double);
#if defined(Py_HAVE_C_COMPLEX) && defined(Py_FFI_SUPPORT_C_COMPLEX)
- TABLE_ENTRY(C, &ffi_type_complex_double);
- TABLE_ENTRY(E, &ffi_type_complex_float);
- TABLE_ENTRY(F, &ffi_type_complex_longdouble);
+ if (Py_FFI_COMPLEX_AVAILABLE) {
+ TABLE_ENTRY(C, &ffi_type_complex_double);
+ TABLE_ENTRY(E, &ffi_type_complex_float);
+ TABLE_ENTRY(F, &ffi_type_complex_longdouble);
+ }
#endif
TABLE_ENTRY(g, &ffi_type_longdouble);
TABLE_ENTRY_SW(f, &ffi_type_float);
formattable.fmt_bool.code = '?';
formattable.fmt_bool.setfunc = bool_set;
formattable.fmt_bool.getfunc = bool_get;
+
+/*[python input]
+all_chars = "cbBhHiIlLdCEFfuzZqQPXOv?g"
+print(f' assert(sizeof(formattable.simple_type_chars) == {len(all_chars)+1});')
+print(f' int i = 0;')
+for char in all_chars:
+ ident_char = {'?': 'bool'}.get(char, char)
+ print(f" if (formattable.fmt_{ident_char}.code) "
+ + f"formattable.simple_type_chars[i++] = '{char}';")
+print(f" formattable.simple_type_chars[i] = 0;")
+[python start generated code]*/
+ assert(sizeof(formattable.simple_type_chars) == 26);
+ int i = 0;
+ if (formattable.fmt_c.code) formattable.simple_type_chars[i++] = 'c';
+ if (formattable.fmt_b.code) formattable.simple_type_chars[i++] = 'b';
+ if (formattable.fmt_B.code) formattable.simple_type_chars[i++] = 'B';
+ if (formattable.fmt_h.code) formattable.simple_type_chars[i++] = 'h';
+ if (formattable.fmt_H.code) formattable.simple_type_chars[i++] = 'H';
+ if (formattable.fmt_i.code) formattable.simple_type_chars[i++] = 'i';
+ if (formattable.fmt_I.code) formattable.simple_type_chars[i++] = 'I';
+ if (formattable.fmt_l.code) formattable.simple_type_chars[i++] = 'l';
+ if (formattable.fmt_L.code) formattable.simple_type_chars[i++] = 'L';
+ if (formattable.fmt_d.code) formattable.simple_type_chars[i++] = 'd';
+ if (formattable.fmt_C.code) formattable.simple_type_chars[i++] = 'C';
+ if (formattable.fmt_E.code) formattable.simple_type_chars[i++] = 'E';
+ if (formattable.fmt_F.code) formattable.simple_type_chars[i++] = 'F';
+ if (formattable.fmt_f.code) formattable.simple_type_chars[i++] = 'f';
+ if (formattable.fmt_u.code) formattable.simple_type_chars[i++] = 'u';
+ if (formattable.fmt_z.code) formattable.simple_type_chars[i++] = 'z';
+ if (formattable.fmt_Z.code) formattable.simple_type_chars[i++] = 'Z';
+ if (formattable.fmt_q.code) formattable.simple_type_chars[i++] = 'q';
+ if (formattable.fmt_Q.code) formattable.simple_type_chars[i++] = 'Q';
+ if (formattable.fmt_P.code) formattable.simple_type_chars[i++] = 'P';
+ if (formattable.fmt_X.code) formattable.simple_type_chars[i++] = 'X';
+ if (formattable.fmt_O.code) formattable.simple_type_chars[i++] = 'O';
+ if (formattable.fmt_v.code) formattable.simple_type_chars[i++] = 'v';
+ if (formattable.fmt_bool.code) formattable.simple_type_chars[i++] = '?';
+ if (formattable.fmt_g.code) formattable.simple_type_chars[i++] = 'g';
+ formattable.simple_type_chars[i] = 0;
+/*[python end generated code: output=e6e5098a02f4b606 input=72031a625eac00c1]*/
+
}
#undef FIXINT_FIELDDESC_FOR
_Py_COMP_DIAG_POP
-struct fielddesc *
-_ctypes_get_fielddesc(const char *fmt)
+static void
+_ctypes_init_fielddesc(void)
{
static bool initialized = false;
static PyMutex mutex = {0};
PyMutex_Lock(&mutex);
if (!initialized) {
- _ctypes_init_fielddesc();
+ _ctypes_init_fielddesc_locked();
initialized = true;
}
PyMutex_Unlock(&mutex);
+}
+
+char *
+_ctypes_get_simple_type_chars(void) {
+ _ctypes_init_fielddesc();
+ return formattable.simple_type_chars;
+}
+
+struct fielddesc *
+_ctypes_get_fielddesc(const char *fmt)
+{
+ _ctypes_init_fielddesc();
+
struct fielddesc *result = NULL;
switch(fmt[0]) {
/*[python input]