Author: Armin Rigo <[email protected]>
Branch:
Changeset: r1038:d63ceb231d7c
Date: 2012-11-11 07:48 +0100
http://bitbucket.org/cffi/cffi/changeset/d63ceb231d7c/
Log: Kill again ffi.inspecttype(), and replace it with read-only
attributes on the ctype objects themselves.
diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c
--- a/c/_cffi_backend.c
+++ b/c/_cffi_backend.c
@@ -298,6 +298,202 @@
return 0;
}
+
+static PyObject *nosuchattr(const char *attr)
+{
+ PyErr_SetString(PyExc_AttributeError, attr);
+ return NULL;
+}
+
+static PyObject *ctypeget_kind(CTypeDescrObject *ct, void *context)
+{
+ char *result;
+ if (ct->ct_flags & CT_PRIMITIVE_ANY) {
+ if (ct->ct_flags & CT_IS_ENUM)
+ result = "enum";
+ else
+ result = "primitive";
+ }
+ else if (ct->ct_flags & CT_POINTER) {
+ result = "pointer";
+ }
+ else if (ct->ct_flags & CT_ARRAY) {
+ result = "array";
+ }
+ else if (ct->ct_flags & CT_VOID) {
+ result = "void";
+ }
+ else if (ct->ct_flags & CT_STRUCT) {
+ result = "struct";
+ }
+ else if (ct->ct_flags & CT_UNION) {
+ result = "union";
+ }
+ else if (ct->ct_flags & CT_FUNCTIONPTR) {
+ result = "function";
+ }
+ else
+ result = "?";
+
+ return PyText_FromString(result);
+}
+
+static PyObject *ctypeget_cname(CTypeDescrObject *ct, void *context)
+{
+ return PyText_FromString(ct->ct_name);
+}
+
+static PyObject *ctypeget_item(CTypeDescrObject *ct, void *context)
+{
+ if (ct->ct_flags & (CT_POINTER | CT_ARRAY)) {
+ Py_INCREF(ct->ct_itemdescr);
+ return (PyObject *)ct->ct_itemdescr;
+ }
+ return nosuchattr("item");
+}
+
+static PyObject *ctypeget_length(CTypeDescrObject *ct, void *context)
+{
+ if (ct->ct_flags & CT_ARRAY) {
+ if (ct->ct_length >= 0) {
+ return PyInt_FromSsize_t(ct->ct_length);
+ }
+ else {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+ }
+ return nosuchattr("length");
+}
+
+static PyObject *
+get_field_name(CTypeDescrObject *ct, CFieldObject *cf); /* forward */
+
+static PyObject *ctypeget_fields(CTypeDescrObject *ct, void *context)
+{
+ if (ct->ct_flags & (CT_STRUCT | CT_UNION)) {
+ if (!(ct->ct_flags & CT_IS_OPAQUE)) {
+ CFieldObject *cf;
+ PyObject *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 res;
+ }
+ else {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+ }
+ return nosuchattr("fields");
+}
+
+static PyObject *ctypeget_args(CTypeDescrObject *ct, void *context)
+{
+ if (ct->ct_flags & CT_FUNCTIONPTR) {
+ PyObject *t = ct->ct_stuff;
+ return PyTuple_GetSlice(t, 2, PyTuple_GET_SIZE(t));
+ }
+ return nosuchattr("args");
+}
+
+static PyObject *ctypeget_result(CTypeDescrObject *ct, void *context)
+{
+ if (ct->ct_flags & CT_FUNCTIONPTR) {
+ PyObject *res = PyTuple_GetItem(ct->ct_stuff, 1);
+ Py_XINCREF(res);
+ return res;
+ }
+ return nosuchattr("result");
+}
+
+static PyObject *ctypeget_ellipsis(CTypeDescrObject *ct, void *context)
+{
+ if (ct->ct_flags & CT_FUNCTIONPTR) {
+ PyObject *res = ct->ct_extra ? Py_False : Py_True;
+ Py_INCREF(res);
+ return res;
+ }
+ return nosuchattr("ellipsis");
+}
+
+static PyObject *ctypeget_abi(CTypeDescrObject *ct, void *context)
+{
+ if (ct->ct_flags & CT_FUNCTIONPTR) {
+ PyObject *res = PyTuple_GetItem(ct->ct_stuff, 0);
+ Py_XINCREF(res);
+ return res;
+ }
+ return nosuchattr("abi");
+}
+
+static PyObject *ctypeget_elements(CTypeDescrObject *ct, void *context)
+{
+ if (ct->ct_flags & CT_IS_ENUM) {
+ PyObject *res = PyTuple_GetItem(ct->ct_stuff, 1);
+ Py_XINCREF(res);
+ return res;
+ }
+ return nosuchattr("elements");
+}
+
+static PyGetSetDef ctypedescr_getsets[] = {
+ {"kind", (getter)ctypeget_kind, NULL, "kind"},
+ {"cname", (getter)ctypeget_cname, NULL, "C name"},
+ {"item", (getter)ctypeget_item, NULL, "pointer to, or array of"},
+ {"length", (getter)ctypeget_length, NULL, "array length or None"},
+ {"fields", (getter)ctypeget_fields, NULL, "struct or union fields"},
+ {"args", (getter)ctypeget_args, NULL, "function argument types"},
+ {"result", (getter)ctypeget_result, NULL, "function result type"},
+ {"ellipsis", (getter)ctypeget_ellipsis, NULL, "function has '...'"},
+ {"abi", (getter)ctypeget_abi, NULL, "function ABI"},
+ {"elements", (getter)ctypeget_elements, NULL, "enum elements"},
+ {NULL} /* sentinel */
+};
+
+static PyObject *
+ctypedescr_dir(PyObject *ct, PyObject *noarg)
+{
+ int err;
+ struct PyGetSetDef *gsdef;
+ PyObject *res = PyList_New(0);
+ if (res == NULL)
+ return NULL;
+
+ for (gsdef = ctypedescr_getsets; gsdef->name; gsdef++) {
+ PyObject *x = PyObject_GetAttrString(ct, gsdef->name);
+ if (x == NULL) {
+ PyErr_Clear();
+ }
+ else {
+ Py_DECREF(x);
+ x = PyText_FromString(gsdef->name);
+ err = (x != NULL) ? PyList_Append(res, x) : -1;
+ Py_XDECREF(x);
+ if (err < 0) {
+ Py_DECREF(res);
+ return NULL;
+ }
+ }
+ }
+ return res;
+}
+
+static PyMethodDef ctypedescr_methods[] = {
+ {"__dir__", ctypedescr_dir, METH_NOARGS},
+ {NULL, NULL} /* sentinel */
+};
+
static PyTypeObject CTypeDescr_Type = {
PyVarObject_HEAD_INIT(NULL, 0)
"_cffi_backend.CTypeDescr",
@@ -324,6 +520,11 @@
(inquiry)ctypedescr_clear, /* tp_clear */
0, /* tp_richcompare */
offsetof(CTypeDescrObject, ct_weakreflist), /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ ctypedescr_methods, /* tp_methods */
+ 0, /* tp_members */
+ ctypedescr_getsets, /* tp_getset */
};
/************************************************************/
@@ -1210,7 +1411,7 @@
goto retry;
}
else {
- PyErr_Format(PyExc_TypeError, "ctype '%s' is of unknown alignment",
+ PyErr_Format(PyExc_ValueError, "ctype '%s' is of unknown alignment",
ct->ct_name);
return -1;
}
@@ -3285,87 +3486,6 @@
return NULL;
}
-static PyObject *b_inspecttype(PyObject *self, PyObject *arg)
-{
- CTypeDescrObject *ct = (CTypeDescrObject *)arg;
-
- if (!CTypeDescr_Check(arg)) {
- PyErr_SetString(PyExc_TypeError,"expected a 'ctype' object");
- return NULL;
- }
- 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);
- }
- }
- 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);
- 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 {
Py_ssize_t nb_bytes;
char *bufferp;
@@ -4623,7 +4743,6 @@
{"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},
- {"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
@@ -82,9 +82,15 @@
p = new_primitive_type("signed char")
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)
+
def test_inspect_primitive_type():
p = new_primitive_type("signed char")
- assert inspecttype(p) == ("primitive", "signed char")
+ assert p.kind == "primitive"
+ assert p.cname == "signed char"
+ check_dir(p, ['cname', 'kind'])
def test_cast_to_signed_char():
p = new_primitive_type("signed char")
@@ -226,9 +232,12 @@
def test_inspect_pointer_type():
p1 = new_primitive_type("int")
p2 = new_pointer_type(p1)
- assert inspecttype(p2) == ("pointer", p1)
+ assert p2.kind == "pointer"
+ assert p2.cname == "int *"
+ assert p2.item is p1
+ check_dir(p2, ['cname', 'kind', 'item'])
p3 = new_pointer_type(p2)
- assert inspecttype(p3) == ("pointer", p2)
+ assert p3.item is p2
def test_pointer_to_int():
BInt = new_primitive_type("int")
@@ -433,7 +442,9 @@
def test_void_type():
p = new_void_type()
- assert inspecttype(p) == ("void",)
+ assert p.kind == "void"
+ assert p.cname == "void"
+ check_dir(p, ['kind', 'cname'])
def test_array_type():
p = new_primitive_type("int")
@@ -460,9 +471,17 @@
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)
+ assert p1.kind == "array"
+ assert p1.cname == "int[]"
+ assert p1.item is p
+ assert p1.length is None
+ check_dir(p1, ['cname', 'kind', 'item', 'length'])
p1 = new_array_type(new_pointer_type(p), 42)
- assert inspecttype(p1) == ("array", p, 42)
+ assert p1.kind == "array"
+ assert p1.cname == "int[42]"
+ assert p1.item is p
+ assert p1.length == 42
+ check_dir(p1, ['cname', 'kind', 'item', 'length'])
def test_array_instance():
LENGTH = 1423
@@ -631,7 +650,8 @@
assert repr(BStruct) == "<ctype 'struct foo'>"
BPtr = new_pointer_type(BStruct)
assert repr(BPtr) == "<ctype 'struct foo *'>"
- py.test.raises(TypeError, alignof, BStruct)
+ py.test.raises(ValueError, sizeof, BStruct)
+ py.test.raises(ValueError, alignof, BStruct)
def test_new_union_type():
BUnion = new_union_type("foo")
@@ -644,14 +664,15 @@
BChar = new_primitive_type("char")
BShort = new_primitive_type("short")
BStruct = new_struct_type("foo")
- assert inspecttype(BStruct) == ("struct", "foo", None, None, None)
+ assert BStruct.kind == "struct"
+ assert BStruct.cname == "struct foo"
+ assert BStruct.fields is None
+ check_dir(BStruct, ['cname', 'kind', 'fields'])
+ #
complete_struct_or_union(BStruct, [('a1', BLong, -1),
('a2', BChar, -1),
('a3', BShort, -1)])
- k, n, d, s, a = inspecttype(BStruct)
- assert k == "struct" and n == "foo"
- assert s == sizeof(BLong) + 2 * sizeof(BShort)
- assert a == sizeof(BLong)
+ d = BStruct.fields
assert len(d) == 3
assert d[0][0] == 'a1'
assert d[0][1].type is BLong
@@ -675,12 +696,12 @@
BLong = new_primitive_type("long")
BChar = new_primitive_type("char")
BUnion = new_union_type("foo")
- assert inspecttype(BUnion) == ("union", "foo", None, None, None)
+ assert BUnion.kind == "union"
+ assert BUnion.cname == "union foo"
+ assert BUnion.fields is None
complete_struct_or_union(BUnion, [('a1', BLong, -1),
('a2', BChar, -1)])
- k, n, d, s, a = inspecttype(BUnion)
- assert k == "union" and n == "foo"
- assert s == a == sizeof(BLong)
+ d = BUnion.fields
assert len(d) == 2
assert d[0][0] == 'a1'
assert d[0][1].type is BLong
@@ -804,8 +825,12 @@
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)
+ assert BFunc.kind == "function"
+ assert BFunc.cname == "int(*)(int, int)"
+ assert BFunc.args == (BInt, BInt)
+ assert BFunc.result is BInt
+ assert BFunc.ellipsis is False
+ assert BFunc.abi == FFI_DEFAULT_ABI
def test_function_type_taking_struct():
BChar = new_primitive_type("char")
@@ -1223,10 +1248,13 @@
def test_enum_type():
BEnum = new_enum_type("foo", (), ())
assert repr(BEnum) == "<ctype 'enum foo'>"
- assert inspecttype(BEnum) == ("enum", [])
+ assert BEnum.kind == "enum"
+ assert BEnum.cname == "enum foo"
+ assert BEnum.elements == {}
#
BEnum = new_enum_type("foo", ('def', 'c', 'ab'), (0, 1, -20))
- assert inspecttype(BEnum) == ("enum", [(-20, 'ab'), (0, 'def'), (1, 'c')])
+ assert BEnum.kind == "enum"
+ assert BEnum.elements == {-20: 'ab', 0: 'def', 1: 'c'}
def test_cast_to_enum():
BEnum = new_enum_type("foo", ('def', 'c', 'ab'), (0, 1, -20))
@@ -1320,7 +1348,7 @@
('a2', BLong, 2),
('a3', BLong, 3),
('a4', BLong, LONGBITS - 5)])
- d = inspecttype(BStruct)[2]
+ d = BStruct.fields
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
@@ -1425,7 +1453,7 @@
py.test.raises(TypeError, "x - 1")
def test_void_errors():
- py.test.raises(TypeError, alignof, new_void_type())
+ py.test.raises(ValueError, alignof, new_void_type())
py.test.raises(TypeError, newp, new_pointer_type(new_void_type()), None)
x = cast(new_pointer_type(new_void_type()), 42)
py.test.raises(TypeError, "x + 1")
@@ -2197,7 +2225,7 @@
('a3', BChar, -1)])
assert sizeof(BInnerStruct) == sizeof(BInt) * 2 # with alignment
assert sizeof(BStruct) == sizeof(BInt) * 3 # 'a3' is placed after
- d = inspecttype(BStruct)[2]
+ d = BStruct.fields
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,11 +312,6 @@
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
@@ -1043,7 +1043,11 @@
as ``<cdata>`` and ``<ctype>`` in the rest of this document. Note
that some cdata objects may be actually of a subclass of
``ffi.CData``, and similarly with ctype, so you should check with
- ``if isinstance(x, ffi.CData)``.
+ ``if isinstance(x, ffi.CData)``. Also, ``<ctype>`` objects have
+ a number of attributes for introspection: ``kind`` and ``cname`` are
+ always present, and depending on the kind they may also have
+ ``item``, ``length``, ``fields``, ``args``, ``result``, ``ellipsis``,
+ ``abi`` and ``elements``.
``ffi.sizeof("C type" or cdata object)``: return the size of the
argument in bytes. The argument can be either a C type, or a cdata object,
@@ -1085,14 +1089,6 @@
.. "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
@@ -23,12 +23,7 @@
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)
+ assert ffi.typeof("long").kind == "primitive"
+ assert ffi.typeof("long(*)(long, long**, ...)").cname == (
+ "long(*)(long, long * *, ...)")
+ assert ffi.typeof("long(*)(long, long**, ...)").ellipsis is True
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit