[pypy-commit] cffi default: Support dir(p), where p is a struct or pointer-to-struct, to obtain

arigo pypy.commits at gmail.com
Mon Jun 6 12:00:20 EDT 2016


Author: Armin Rigo <arigo at tunes.org>
Branch: 
Changeset: r2715:0a5f59abb0e0
Date: 2016-06-06 18:00 +0200
http://bitbucket.org/cffi/cffi/changeset/0a5f59abb0e0/

Log:	Support dir(p), where p is a struct or pointer-to-struct, to obtain
	the list of field names.

diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c
--- a/c/_cffi_backend.c
+++ b/c/_cffi_backend.c
@@ -2703,6 +2703,27 @@
     return res;
 }
 
+static PyObject *cdata_dir(PyObject *cd, PyObject *noarg)
+{
+    CTypeDescrObject *ct = ((CDataObject *)cd)->c_type;
+
+    /* replace the type 'pointer-to-t' with just 't' */
+    if (ct->ct_flags & CT_POINTER) {
+        ct = ct->ct_itemdescr;
+    }
+    if ((ct->ct_flags & (CT_STRUCT | CT_UNION)) &&
+        !(ct->ct_flags & CT_IS_OPAQUE)) {
+
+        /* for non-opaque structs or unions */
+        if (force_lazy_struct(ct) < 0)
+            return NULL;
+        return PyDict_Keys(ct->ct_stuff);
+    }
+    else {
+        return PyList_New(0);   /* empty list for the other cases */
+    }
+}
+
 static PyObject *cdata_iter(CDataObject *);
 
 static PyNumberMethods CData_as_number = {
@@ -2751,6 +2772,11 @@
     (objobjargproc)cdata_ass_sub, /*mp_ass_subscript*/
 };
 
+static PyMethodDef cdata_methods[] = {
+    {"__dir__",   cdata_dir,      METH_NOARGS},
+    {NULL,        NULL}           /* sentinel */
+};
+
 static PyTypeObject CData_Type = {
     PyVarObject_HEAD_INIT(NULL, 0)
     "_cffi_backend.CData",
@@ -2779,6 +2805,7 @@
     offsetof(CDataObject, c_weakreflist),       /* tp_weaklistoffset */
     (getiterfunc)cdata_iter,                    /* tp_iter */
     0,                                          /* tp_iternext */
+    cdata_methods,                              /* tp_methods */
 };
 
 static PyTypeObject CDataOwning_Type = {
diff --git a/c/test_c.py b/c/test_c.py
--- a/c/test_c.py
+++ b/c/test_c.py
@@ -88,8 +88,8 @@
     assert repr(p) == "<ctype 'signed char'>"
 
 def check_dir(p, expected):
-    got = set(name for name in dir(p) if not name.startswith('_'))
-    assert got == set(expected)
+    got = [name for name in dir(p) if not name.startswith('_')]
+    assert got == sorted(expected)
 
 def test_inspect_primitive_type():
     p = new_primitive_type("signed char")
@@ -3619,3 +3619,23 @@
     #
     py.test.raises(ValueError, unpack, p0, -1)
     py.test.raises(ValueError, unpack, p, -1)
+
+def test_cdata_dir():
+    BInt = new_primitive_type("int")
+    p = cast(BInt, 42)
+    check_dir(p, [])
+    p = newp(new_array_type(new_pointer_type(BInt), None), 5)
+    check_dir(p, [])
+    BStruct = new_struct_type("foo")
+    p = cast(new_pointer_type(BStruct), 0)
+    check_dir(p, [])    # opaque
+    complete_struct_or_union(BStruct, [('a2', BInt, -1),
+                                       ('a1', BInt, -1)])
+    check_dir(p, ['a1', 'a2'])   # always sorted
+    p = newp(new_pointer_type(BStruct), None)
+    check_dir(p, ['a1', 'a2'])
+    check_dir(p[0], ['a1', 'a2'])
+    pp = newp(new_pointer_type(new_pointer_type(BStruct)), p)
+    check_dir(pp, [])
+    check_dir(pp[0], ['a1', 'a2'])
+    check_dir(pp[0][0], ['a1', 'a2'])
diff --git a/doc/source/whatsnew.rst b/doc/source/whatsnew.rst
--- a/doc/source/whatsnew.rst
+++ b/doc/source/whatsnew.rst
@@ -28,7 +28,8 @@
   but failed if you make use the ``bool`` type (because that is rendered
   as the C ``_Bool`` type, which doesn't exist in C++).
 
-* ``help(lib)`` and ``help(lib.myfunc)`` now give useful information.
+* ``help(lib)`` and ``help(lib.myfunc)`` now give useful information,
+  as well as ``dir(p)`` where ``p`` is a struct or pointer-to-struct.
 
 
 v1.6


More information about the pypy-commit mailing list