[pypy-commit] cffi default: Issue #22: Add ffi.inspecttype(). See the doc.
arigo
noreply at buildbot.pypy.org
Sat Nov 10 18:09:31 CET 2012
Author: Armin Rigo <arigo at tunes.org>
Branch:
Changeset: r1037:bde32d4f45e8
Date: 2012-11-10 18:09 +0100
http://bitbucket.org/cffi/cffi/changeset/bde32d4f45e8/
Log: Issue #22: Add ffi.inspecttype(). See the doc.
diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c
--- a/c/_cffi_backend.c
+++ b/c/_cffi_backend.c
@@ -3285,49 +3285,85 @@
return NULL;
}
-static PyObject *b__getfields(PyObject *self, PyObject *arg)
+static PyObject *b_inspecttype(PyObject *self, PyObject *arg)
{
CTypeDescrObject *ct = (CTypeDescrObject *)arg;
- PyObject *d, *res;
if (!CTypeDescr_Check(arg)) {
PyErr_SetString(PyExc_TypeError,"expected a 'ctype' object");
return NULL;
}
- d = (PyObject *)ct->ct_stuff;
- if (d == NULL) {
- res = Py_None;
- Py_INCREF(res);
- }
- else if (ct->ct_flags & (CT_STRUCT|CT_UNION)) {
- CFieldObject *cf;
- res = PyList_New(0);
- if (res == NULL)
- return NULL;
- for (cf = (CFieldObject *)ct->ct_extra; cf != NULL; cf = cf->cf_next) {
- int err;
- PyObject *o = PyTuple_Pack(2, get_field_name(ct, cf),
- (PyObject *)cf);
- err = (o != NULL) ? PyList_Append(res, o) : -1;
- Py_XDECREF(o);
- if (err < 0) {
- Py_DECREF(res);
+ if ((ct->ct_flags & CT_PRIMITIVE_ANY) && !(ct->ct_flags & CT_IS_ENUM)) {
+ return Py_BuildValue("ss", "primitive", ct->ct_name);
+ }
+ if (ct->ct_flags & CT_POINTER) {
+ return Py_BuildValue("sO", "pointer", ct->ct_itemdescr);
+ }
+ if (ct->ct_flags & CT_ARRAY) {
+ if (ct->ct_length < 0)
+ return Py_BuildValue("sOO", "array", ct->ct_itemdescr, Py_None);
+ else
+ return Py_BuildValue("sOn", "array", ct->ct_itemdescr,
+ ct->ct_length);
+ }
+ if (ct->ct_flags & CT_VOID) {
+ return Py_BuildValue("(s)", "void");
+ }
+ if (ct->ct_flags & (CT_STRUCT|CT_UNION)) {
+ PyObject *res;
+ char *kind, *name;
+ kind = (ct->ct_flags & CT_STRUCT) ? "struct" : "union";
+ name = ct->ct_name;
+ while (*name != ' ')
+ name++;
+ name++;
+ if (ct->ct_flags & CT_IS_OPAQUE) {
+ return Py_BuildValue("ssOOO", kind, name,
+ Py_None, Py_None, Py_None);
+ }
+ else {
+ CFieldObject *cf;
+ res = PyList_New(0);
+ if (res == NULL)
return NULL;
+ for (cf = (CFieldObject *)ct->ct_extra;
+ cf != NULL; cf = cf->cf_next) {
+ PyObject *o = PyTuple_Pack(2, get_field_name(ct, cf),
+ (PyObject *)cf);
+ int err = (o != NULL) ? PyList_Append(res, o) : -1;
+ Py_XDECREF(o);
+ if (err < 0) {
+ Py_DECREF(res);
+ return NULL;
+ }
}
+ return Py_BuildValue("ssOnn", kind, name,
+ res, ct->ct_size, ct->ct_length);
}
}
- else if (ct->ct_flags & CT_IS_ENUM) {
- res = PyDict_Items(PyTuple_GET_ITEM(d, 1));
+ if (ct->ct_flags & CT_IS_ENUM) {
+ PyObject *res = PyDict_Items(PyTuple_GET_ITEM(ct->ct_stuff, 1));
if (res == NULL)
return NULL;
if (PyList_Sort(res) < 0)
Py_CLEAR(res);
- }
- else {
- res = d;
- Py_INCREF(res);
- }
- return res;
+ return Py_BuildValue("sO", "enum", res);
+ }
+ if (ct->ct_flags & CT_FUNCTIONPTR) {
+ PyObject *t = ct->ct_stuff;
+ PyObject *s = PyTuple_GetSlice(t, 2, PyTuple_GET_SIZE(t));
+ PyObject *o;
+ if (s == NULL)
+ return NULL;
+ o = Py_BuildValue("sOOOO", "function", s,
+ PyTuple_GET_ITEM(t, 1),
+ ct->ct_extra ? Py_False : Py_True,
+ PyTuple_GET_ITEM(t, 0));
+ Py_DECREF(s);
+ return o;
+ }
+ PyErr_SetObject(PyExc_NotImplementedError, (PyObject *)ct);
+ return NULL;
}
struct funcbuilder_s {
@@ -4587,7 +4623,7 @@
{"complete_struct_or_union", b_complete_struct_or_union, METH_VARARGS},
{"new_function_type", b_new_function_type, METH_VARARGS},
{"new_enum_type", b_new_enum_type, METH_VARARGS},
- {"_getfields", b__getfields, METH_O},
+ {"inspecttype", b_inspecttype, METH_O},
{"newp", b_newp, METH_VARARGS},
{"cast", b_cast, METH_VARARGS},
{"callback", b_callback, METH_VARARGS},
diff --git a/c/test_c.py b/c/test_c.py
--- a/c/test_c.py
+++ b/c/test_c.py
@@ -1,6 +1,6 @@
import py
from _cffi_backend import *
-from _cffi_backend import _getfields, _testfunc, _get_types
+from _cffi_backend import _testfunc, _get_types
# ____________________________________________________________
@@ -82,6 +82,10 @@
p = new_primitive_type("signed char")
assert repr(p) == "<ctype 'signed char'>"
+def test_inspect_primitive_type():
+ p = new_primitive_type("signed char")
+ assert inspecttype(p) == ("primitive", "signed char")
+
def test_cast_to_signed_char():
p = new_primitive_type("signed char")
x = cast(p, -65 + 17*256)
@@ -219,6 +223,13 @@
p = new_pointer_type(p)
assert repr(p) == "<ctype 'int * * *'>"
+def test_inspect_pointer_type():
+ p1 = new_primitive_type("int")
+ p2 = new_pointer_type(p1)
+ assert inspecttype(p2) == ("pointer", p1)
+ p3 = new_pointer_type(p2)
+ assert inspecttype(p3) == ("pointer", p2)
+
def test_pointer_to_int():
BInt = new_primitive_type("int")
py.test.raises(TypeError, newp, BInt)
@@ -420,6 +431,10 @@
z = cast(BInt, y)
assert int(z) == 42
+def test_void_type():
+ p = new_void_type()
+ assert inspecttype(p) == ("void",)
+
def test_array_type():
p = new_primitive_type("int")
assert repr(p) == "<ctype 'int'>"
@@ -442,6 +457,13 @@
py.test.raises(OverflowError,
new_array_type, new_pointer_type(p), sys.maxsize // 3)
+def test_inspect_array_type():
+ p = new_primitive_type("int")
+ p1 = new_array_type(new_pointer_type(p), None)
+ assert inspecttype(p1) == ("array", p, None)
+ p1 = new_array_type(new_pointer_type(p), 42)
+ assert inspecttype(p1) == ("array", p, 42)
+
def test_array_instance():
LENGTH = 1423
p = new_primitive_type("int")
@@ -622,11 +644,14 @@
BChar = new_primitive_type("char")
BShort = new_primitive_type("short")
BStruct = new_struct_type("foo")
- assert _getfields(BStruct) is None
+ assert inspecttype(BStruct) == ("struct", "foo", None, None, None)
complete_struct_or_union(BStruct, [('a1', BLong, -1),
('a2', BChar, -1),
('a3', BShort, -1)])
- d = _getfields(BStruct)
+ k, n, d, s, a = inspecttype(BStruct)
+ assert k == "struct" and n == "foo"
+ assert s == sizeof(BLong) + 2 * sizeof(BShort)
+ assert a == sizeof(BLong)
assert len(d) == 3
assert d[0][0] == 'a1'
assert d[0][1].type is BLong
@@ -650,10 +675,12 @@
BLong = new_primitive_type("long")
BChar = new_primitive_type("char")
BUnion = new_union_type("foo")
- assert _getfields(BUnion) is None
+ assert inspecttype(BUnion) == ("union", "foo", None, None, None)
complete_struct_or_union(BUnion, [('a1', BLong, -1),
('a2', BChar, -1)])
- d = _getfields(BUnion)
+ k, n, d, s, a = inspecttype(BUnion)
+ assert k == "union" and n == "foo"
+ assert s == a == sizeof(BLong)
assert len(d) == 2
assert d[0][0] == 'a1'
assert d[0][1].type is BLong
@@ -774,6 +801,12 @@
BFunc2 = new_function_type((), BFunc, False)
assert repr(BFunc2) == "<ctype 'int(*(*)())(int, int)'>"
+def test_inspect_function_type():
+ BInt = new_primitive_type("int")
+ BFunc = new_function_type((BInt, BInt), BInt, False)
+ assert inspecttype(BFunc) == ("function", (BInt, BInt), BInt, False,
+ FFI_DEFAULT_ABI)
+
def test_function_type_taking_struct():
BChar = new_primitive_type("char")
BShort = new_primitive_type("short")
@@ -1190,10 +1223,10 @@
def test_enum_type():
BEnum = new_enum_type("foo", (), ())
assert repr(BEnum) == "<ctype 'enum foo'>"
- assert _getfields(BEnum) == []
+ assert inspecttype(BEnum) == ("enum", [])
#
BEnum = new_enum_type("foo", ('def', 'c', 'ab'), (0, 1, -20))
- assert _getfields(BEnum) == [(-20, 'ab'), (0, 'def'), (1, 'c')]
+ assert inspecttype(BEnum) == ("enum", [(-20, 'ab'), (0, 'def'), (1, 'c')])
def test_cast_to_enum():
BEnum = new_enum_type("foo", ('def', 'c', 'ab'), (0, 1, -20))
@@ -1287,7 +1320,7 @@
('a2', BLong, 2),
('a3', BLong, 3),
('a4', BLong, LONGBITS - 5)])
- d = _getfields(BStruct)
+ d = inspecttype(BStruct)[2]
assert d[0][1].offset == d[1][1].offset == d[2][1].offset == 0
assert d[3][1].offset == sizeof(BLong)
assert d[0][1].bitshift == 0
@@ -2164,7 +2197,7 @@
('a3', BChar, -1)])
assert sizeof(BInnerStruct) == sizeof(BInt) * 2 # with alignment
assert sizeof(BStruct) == sizeof(BInt) * 3 # 'a3' is placed after
- d = _getfields(BStruct)
+ d = inspecttype(BStruct)[2]
assert len(d) == 3
assert d[0][0] == 'a1'
assert d[0][1].type is BInt
diff --git a/cffi/api.py b/cffi/api.py
--- a/cffi/api.py
+++ b/cffi/api.py
@@ -312,6 +312,11 @@
self._typeof(self.getctype(ctype, '*')))
return self._backend.rawaddressof(ctypeptr, cdata, offset)
+ def inspecttype(self, cdecl):
+ if isinstance(cdecl, str):
+ cdecl = self._typeof(cdecl)
+ return self._backend.inspecttype(cdecl)
+
def _make_ffi_library(ffi, libname, flags):
import os
diff --git a/doc/source/index.rst b/doc/source/index.rst
--- a/doc/source/index.rst
+++ b/doc/source/index.rst
@@ -1085,6 +1085,14 @@
.. "versionadded:: 0.4" --- inlined in the previous paragraph
+``ffi.inspecttype(ctype)``: half-internal API. Returns a tuple whose
+first item is a string describing the kind of ``ctype``, and whose
+remaining items give a full deconstruction of the type. (Note that in
+the future the returned tuples may grow new items, as needed to
+represent new details of the type.) *New in version 0.4.*
+
+.. "versionadded:: 0.4" --- inlined in the previous paragraph
+
Unimplemented features
----------------------
diff --git a/testing/test_ffi_backend.py b/testing/test_ffi_backend.py
--- a/testing/test_ffi_backend.py
+++ b/testing/test_ffi_backend.py
@@ -20,3 +20,15 @@
"struct foo_s foo(void)", lambda: 42)
assert str(e.value) == ("<struct foo_s(*)(void)>: "
"cannot pass as argument or return value a struct with bit fields")
+
+ def test_inspecttype(self):
+ ffi = FFI(backend=self.Backend())
+ assert ffi.inspecttype("long") == ("primitive", "long")
+ assert ffi.inspecttype(ffi.typeof("long")) == ("primitive", "long")
+ pointer, LongP = ffi.inspecttype("long**")
+ assert pointer == "pointer"
+ pointer, Long = ffi.inspecttype(LongP)
+ assert pointer == "pointer"
+ assert ffi.inspecttype(Long) == ("primitive", "long")
+ assert ffi.inspecttype("long(*)(long, long, ...)")[:4] == (
+ "function", (Long, Long), Long, True)
More information about the pypy-commit
mailing list