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

Reply via email to