Author: Armin Rigo <[email protected]>
Branch:
Changeset: r2652:efcb421203b3
Date: 2016-03-27 19:27 +0200
http://bitbucket.org/cffi/cffi/changeset/efcb421203b3/
Log: ffi.list_types()
diff --git a/c/ffi_obj.c b/c/ffi_obj.c
--- a/c/ffi_obj.c
+++ b/c/ffi_obj.c
@@ -862,6 +862,57 @@
return x;
}
+PyDoc_STRVAR(ffi_list_types_doc,
+"Build and return a list of all user type names known in this FFI instance.\n"
+"\n"
+"Contains typedef names (sorted in alphabetical order), followed by the\n"
+"'struct xxx' (sorted) and finally the 'union xxx' (sorted as well).");
+
+static PyObject *ffi_list_types(FFIObject *self, PyObject *noargs)
+{
+ int is_union, look_for_union;
+ Py_ssize_t i, n1 = self->types_builder.ctx.num_typenames;
+ Py_ssize_t n23 = self->types_builder.ctx.num_struct_unions;
+ PyObject *o, *result = PyList_New(n1);
+ if (result == NULL)
+ return NULL;
+
+ for (i = 0; i < n1; i++) {
+ o = PyText_FromString(self->types_builder.ctx.typenames[i].name);
+ if (o == NULL)
+ goto error;
+ PyList_SET_ITEM(result, i, o);
+ }
+
+ for (look_for_union = 0; look_for_union < 2; look_for_union++) {
+ for (i = 0; i < n23; i++) {
+ const struct _cffi_struct_union_s *s;
+ int err;
+
+ s = &self->types_builder.ctx.struct_unions[i];
+ if (s->name[0] == '$')
+ continue;
+
+ is_union = (s->flags & _CFFI_F_UNION) != 0;
+ if (is_union != look_for_union)
+ continue;
+
+ o = PyText_FromFormat(is_union ? "union %s" : "struct %s",
s->name);
+ if (o == NULL)
+ goto error;
+ err = PyList_Append(result, o);
+ Py_DECREF(o);
+ if (err < 0)
+ goto error;
+ }
+ }
+ return result;
+
+ error:
+ Py_DECREF(result);
+ return NULL;
+}
+
PyDoc_STRVAR(ffi_memmove_doc,
"ffi.memmove(dest, src, n) copies n bytes of memory from src to dest.\n"
"\n"
@@ -1030,6 +1081,7 @@
#endif
{"init_once", (PyCFunction)ffi_init_once, METH_VKW, ffi_init_once_doc},
{"integer_const",(PyCFunction)ffi_int_const,METH_VKW, ffi_int_const_doc},
+ {"list_types", (PyCFunction)ffi_list_types, METH_NOARGS, ffi_list_types_doc},
{"memmove", (PyCFunction)ffi_memmove, METH_VKW, ffi_memmove_doc},
{"new", (PyCFunction)ffi_new, METH_VKW, ffi_new_doc},
{"new_allocator",(PyCFunction)ffi_new_allocator,METH_VKW,ffi_new_allocator_doc},
diff --git a/cffi/api.py b/cffi/api.py
--- a/cffi/api.py
+++ b/cffi/api.py
@@ -721,6 +721,27 @@
raise ValueError("ffi.def_extern() is only available on API-mode FFI "
"objects")
+ def list_types(self):
+ """Build and return a list of all user type names known in this FFI
+ instance. Contains typedef names (sorted in alphabetical order),
+ followed by the 'struct xxx' (sorted) and finally the 'union xxx'
+ (sorted as well).
+ """
+ typedefs = []
+ structs = []
+ unions = []
+ for key in self._parser._declarations:
+ if key.startswith('typedef '):
+ typedefs.append(key[8:])
+ elif key.startswith('struct '):
+ structs.append(key)
+ elif key.startswith('union '):
+ unions.append(key)
+ typedefs.sort()
+ structs.sort()
+ unions.sort()
+ return typedefs + structs + unions
+
def _load_backend_lib(backend, name, flags):
if name is None:
diff --git a/cffi/recompiler.py b/cffi/recompiler.py
--- a/cffi/recompiler.py
+++ b/cffi/recompiler.py
@@ -1484,4 +1484,7 @@
def typeof_disabled(*args, **kwds):
raise NotImplementedError
ffi._typeof = typeof_disabled
+ for name in dir(ffi):
+ if not name.startswith('_') and not hasattr(module.ffi, name):
+ setattr(ffi, name, NotImplemented)
return module.lib
diff --git a/testing/cffi0/test_ffi_backend.py
b/testing/cffi0/test_ffi_backend.py
--- a/testing/cffi0/test_ffi_backend.py
+++ b/testing/cffi0/test_ffi_backend.py
@@ -423,3 +423,51 @@
def test_ffi_def_extern(self):
ffi = FFI()
py.test.raises(ValueError, ffi.def_extern)
+
+ def test_introspect_typedef(self):
+ ffi = FFI()
+ ffi.cdef("typedef int foo_t;")
+ assert ffi.list_types() == ['foo_t']
+ assert ffi.typeof('foo_t').kind == 'primitive'
+ assert ffi.typeof('foo_t').cname == 'int'
+ #
+ ffi.cdef("typedef signed char a_t, c_t, g_t, b_t;")
+ assert ffi.list_types() == ['a_t', 'b_t', 'c_t', 'foo_t', 'g_t']
+
+ def test_introspect_struct(self):
+ ffi = FFI()
+ ffi.cdef("struct foo_s { int a; };")
+ assert ffi.list_types() == ['struct foo_s']
+ assert ffi.typeof('struct foo_s').kind == 'struct'
+ assert ffi.typeof('struct foo_s').cname == 'struct foo_s'
+
+ def test_introspect_union(self):
+ ffi = FFI()
+ ffi.cdef("union foo_s { int a; };")
+ assert ffi.list_types() == ['union foo_s']
+ assert ffi.typeof('union foo_s').kind == 'union'
+ assert ffi.typeof('union foo_s').cname == 'union foo_s'
+
+ def test_introspect_struct_and_typedef(self):
+ ffi = FFI()
+ ffi.cdef("typedef struct { int a; } foo_t;")
+ assert ffi.list_types() == ['foo_t']
+ assert ffi.typeof('foo_t').kind == 'struct'
+ assert ffi.typeof('foo_t').cname == 'foo_t'
+
+ def test_introspect_included_type(self):
+ ffi1 = FFI()
+ ffi2 = FFI()
+ ffi1.cdef("typedef signed char schar_t; struct sint_t { int x; };")
+ ffi2.include(ffi1)
+ assert ffi1.list_types() == sorted(ffi2.list_types()) == [
+ 'schar_t', 'struct sint_t']
+
+ def test_introspect_order(self):
+ ffi = FFI()
+ ffi.cdef("union aaa { int a; }; typedef struct ccc { int a; } b;")
+ ffi.cdef("union g { int a; }; typedef struct cc { int a; } bbb;")
+ ffi.cdef("union aa { int a; }; typedef struct a { int a; } bb;")
+ assert ffi.list_types() == ['b', 'bb', 'bbb',
+ 'struct a', 'struct cc', 'struct ccc',
+ 'union aa', 'union aaa', 'union g']
diff --git a/testing/cffi1/test_recompiler.py b/testing/cffi1/test_recompiler.py
--- a/testing/cffi1/test_recompiler.py
+++ b/testing/cffi1/test_recompiler.py
@@ -1743,3 +1743,125 @@
lib.mycb1 = lib.foo
assert lib.mycb1(200) == 242
assert lib.indirect_call(300) == 342
+
+def test_introspect_function():
+ ffi = FFI()
+ ffi.cdef("float f1(double);")
+ lib = verify(ffi, 'test_introspect_function', """
+ float f1(double x) { return x; }
+ """)
+ assert dir(lib) == ['f1']
+ FUNC = ffi.typeof(lib.f1)
+ assert FUNC.kind == 'function'
+ assert FUNC.args[0].cname == 'double'
+ assert FUNC.result.cname == 'float'
+ assert ffi.typeof(ffi.addressof(lib, 'f1')) is FUNC
+
+def test_introspect_global_var():
+ ffi = FFI()
+ ffi.cdef("float g1;")
+ lib = verify(ffi, 'test_introspect_global_var', """
+ float g1;
+ """)
+ assert dir(lib) == ['g1']
+ FLOATPTR = ffi.typeof(ffi.addressof(lib, 'g1'))
+ assert FLOATPTR.kind == 'pointer'
+ assert FLOATPTR.item.cname == 'float'
+
+def test_introspect_global_var_array():
+ ffi = FFI()
+ ffi.cdef("float g1[100];")
+ lib = verify(ffi, 'test_introspect_global_var_array', """
+ float g1[100];
+ """)
+ assert dir(lib) == ['g1']
+ FLOATARRAYPTR = ffi.typeof(ffi.addressof(lib, 'g1'))
+ assert FLOATARRAYPTR.kind == 'pointer'
+ assert FLOATARRAYPTR.item.kind == 'array'
+ assert FLOATARRAYPTR.item.length == 100
+ assert ffi.typeof(lib.g1) is FLOATARRAYPTR.item
+
+def test_introspect_integer_const():
+ ffi = FFI()
+ ffi.cdef("#define FOO 42")
+ lib = verify(ffi, 'test_introspect_integer_const', """
+ #define FOO 42
+ """)
+ assert dir(lib) == ['FOO']
+ assert lib.FOO == ffi.integer_const('FOO') == 42
+
+def test_introspect_typedef():
+ ffi = FFI()
+ ffi.cdef("typedef int foo_t;")
+ lib = verify(ffi, 'test_introspect_typedef', """
+ typedef int foo_t;
+ """)
+ assert ffi.list_types() == ['foo_t']
+ assert ffi.typeof('foo_t').kind == 'primitive'
+ assert ffi.typeof('foo_t').cname == 'int'
+
+def test_introspect_typedef_multiple():
+ ffi = FFI()
+ ffi.cdef("typedef signed char a_t, c_t, g_t, b_t;")
+ lib = verify(ffi, 'test_introspect_typedef_multiple', """
+ typedef signed char a_t, c_t, g_t, b_t;
+ """)
+ assert ffi.list_types() == ['a_t', 'b_t', 'c_t', 'g_t']
+
+def test_introspect_struct():
+ ffi = FFI()
+ ffi.cdef("struct foo_s { int a; };")
+ lib = verify(ffi, 'test_introspect_struct', """
+ struct foo_s { int a; };
+ """)
+ assert ffi.list_types() == ['struct foo_s']
+ assert ffi.typeof('struct foo_s').kind == 'struct'
+ assert ffi.typeof('struct foo_s').cname == 'struct foo_s'
+
+def test_introspect_union():
+ ffi = FFI()
+ ffi.cdef("union foo_s { int a; };")
+ lib = verify(ffi, 'test_introspect_union', """
+ union foo_s { int a; };
+ """)
+ assert ffi.list_types() == ['union foo_s']
+ assert ffi.typeof('union foo_s').kind == 'union'
+ assert ffi.typeof('union foo_s').cname == 'union foo_s'
+
+def test_introspect_struct_and_typedef():
+ ffi = FFI()
+ ffi.cdef("typedef struct { int a; } foo_t;")
+ lib = verify(ffi, 'test_introspect_struct_and_typedef', """
+ typedef struct { int a; } foo_t;
+ """)
+ assert ffi.list_types() == ['foo_t']
+ assert ffi.typeof('foo_t').kind == 'struct'
+ assert ffi.typeof('foo_t').cname == 'foo_t'
+
+def test_introspect_included_type():
+ SOURCE = """
+ typedef signed char schar_t;
+ struct sint_t { int x; };
+ """
+ ffi1 = FFI()
+ ffi1.cdef(SOURCE)
+ ffi2 = FFI()
+ ffi2.include(ffi1)
+ verify(ffi1, "test_introspect_included_type_parent", SOURCE)
+ verify(ffi2, "test_introspect_included_type", SOURCE)
+ assert ffi1.list_types() == ffi2.list_types() == [
+ 'schar_t', 'struct sint_t']
+
+def test_introspect_order():
+ ffi = FFI()
+ ffi.cdef("union aaa { int a; }; typedef struct ccc { int a; } b;")
+ ffi.cdef("union g { int a; }; typedef struct cc { int a; } bbb;")
+ ffi.cdef("union aa { int a; }; typedef struct a { int a; } bb;")
+ verify(ffi, "test_introspect_order", """
+ union aaa { int a; }; typedef struct ccc { int a; } b;
+ union g { int a; }; typedef struct cc { int a; } bbb;
+ union aa { int a; }; typedef struct a { int a; } bb;
+ """)
+ assert ffi.list_types() == ['b', 'bb', 'bbb',
+ 'struct a', 'struct cc', 'struct ccc',
+ 'union aa', 'union aaa', 'union g']
diff --git a/testing/cffi1/test_verify1.py b/testing/cffi1/test_verify1.py
--- a/testing/cffi1/test_verify1.py
+++ b/testing/cffi1/test_verify1.py
@@ -694,25 +694,14 @@
assert ffi.string(ffi.cast('enum ee', 11)) == "EE2"
assert ffi.string(ffi.cast('enum ee', -10)) == "EE3"
#
- # try again
- ffi.verify("enum ee { EE1=10, EE2, EE3=-10, EE4 };")
- assert ffi.string(ffi.cast('enum ee', 11)) == "EE2"
- #
assert ffi.typeof("enum ee").relements == {'EE1': 10, 'EE2': 11, 'EE3':
-10}
assert ffi.typeof("enum ee").elements == {10: 'EE1', 11: 'EE2', -10: 'EE3'}
def test_full_enum():
ffi = FFI()
ffi.cdef("enum ee { EE1, EE2, EE3 };")
- ffi.verify("enum ee { EE1, EE2, EE3 };")
- py.test.raises(VerificationError, ffi.verify, "enum ee { EE1, EE2 };")
- # disabled: for now, we always accept and fix transparently constant values
- #e = py.test.raises(VerificationError, ffi.verify,
- # "enum ee { EE1, EE3, EE2 };")
- #assert str(e.value) == 'enum ee: EE2 has the real value 2, not 1'
- # extra items cannot be seen and have no bad consequence anyway
- lib = ffi.verify("enum ee { EE1, EE2, EE3, EE4 };")
- assert lib.EE3 == 2
+ lib = ffi.verify("enum ee { EE1, EE2, EE3 };")
+ assert [lib.EE1, lib.EE2, lib.EE3] == [0, 1, 2]
def test_enum_usage():
ffi = FFI()
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit