Commit c577c400 authored by Armin Rigo's avatar Armin Rigo
Browse files

Redo lib.__dict__, like in the in-line mode. Figured out that it's like

lib.__all__: a special attribute that can be shadowed if necessary
because it's not essential.
parent 3627637e5027
......@@ -404,6 +404,33 @@ static PyObject *_lib_dir1(LibObject *lib, int ignore_type)
return NULL;
static PyObject *_lib_dict(LibObject *lib)
const struct _cffi_global_s *g = lib->l_types_builder->ctx.globals;
int i, total = lib->l_types_builder->ctx.num_globals;
PyObject *name, *x, *d = PyDict_New();
if (d == NULL)
return NULL;
for (i = 0; i < total; i++) {
name = PyText_FromString(g[i].name);
if (name == NULL)
goto error;
LIB_GET_OR_CACHE_ADDR(x, lib, name, goto error);
if (PyDict_SetItem(d, name, x) < 0)
goto error;
return d;
return NULL;
static PyObject *lib_getattr(LibObject *lib, PyObject *name)
PyObject *x;
......@@ -420,6 +447,10 @@ static PyObject *lib_getattr(LibObject *lib, PyObject *name)
return _lib_dir1(lib, _CFFI_OP_GLOBAL_VAR);
if (strcmp(PyText_AsUTF8(name), "__dict__") == 0) {
return _lib_dict(lib);
return NULL;
......@@ -130,9 +130,9 @@ ffi`` returns an object of a type written in C, which does not let you
add random attributes to it (nor does it have all the
underscore-prefixed internal attributes of the Python version).
Similarly, the ``lib`` objects returned by the C version are read-only,
apart from writes to global variables. Also, ``lib.__dict__`` no
longer works (it now tries to look up a hypothetical symbol
``__dict__`` from the C library); use instead ``dir(lib)``.
apart from writes to global variables. Also, ``lib.__dict__`` does
not work before version 1.2 or if ``lib`` happens to declare a name
called ``__dict__`` (use instead ``dir(lib)``).
ffi.cdef(): declaring types and functions
......@@ -26,6 +26,10 @@ What's New
``*`` excludes the global variables; only the functions and constants
make sense to import like this.)
* ``lib.__dict__`` works again and gives you a copy of the
dict---assuming that ``lib`` has got no symbol called precisely
``__dict__``. (In general, it is safer to use ``dir(lib)``.)
......@@ -265,6 +265,15 @@ def test_dir():
lib.aa = 5
assert dir(lib) == ['aa', 'ff', 'my_constant']
aaobj = lib.__dict__['aa']
assert not isinstance(aaobj, int) # some internal object instead
assert lib.__dict__ == {
'ff': lib.ff,
'aa': aaobj,
'my_constant': -45}
lib.__dict__['ff'] = "??"
assert lib.ff(10) == 15
def test_verify_opaque_struct():
ffi = FFI()
......@@ -1052,5 +1061,5 @@ def test_import_from_lib():
assert sys.modules['_CFFI_test_import_from_lib.lib'] is lib
from _CFFI_test_import_from_lib.lib import MYFOO
assert MYFOO == 42
assert not hasattr(lib, '__dict__')
assert hasattr(lib, '__dict__')
assert lib.__all__ == ['MYFOO', 'mybar'] # but not 'myvar'
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment