[pypy-commit] cffi default: For interactive usage (playing around), add the option ffi.cdef("..",

arigo noreply at buildbot.pypy.org
Sun Jul 8 12:04:57 CEST 2012


Author: Armin Rigo <arigo at tunes.org>
Branch: 
Changeset: r597:ab05b68f4d1b
Date: 2012-07-08 12:04 +0200
http://bitbucket.org/cffi/cffi/changeset/ab05b68f4d1b/

Log:	For interactive usage (playing around), add the option
	ffi.cdef("..", override=True).

diff --git a/cffi/api.py b/cffi/api.py
--- a/cffi/api.py
+++ b/cffi/api.py
@@ -49,6 +49,7 @@
         self._cached_btypes = {}
         self._parsed_types = new.module('parsed_types').__dict__
         self._new_types = new.module('new_types').__dict__
+        self._function_caches = []
         if hasattr(backend, 'set_ffi'):
             backend.set_ffi(self)
         #
@@ -67,13 +68,16 @@
         #
         self.NULL = self.cast("void *", 0)
 
-    def cdef(self, csource):
+    def cdef(self, csource, override=False):
         """Parse the given C source.  This registers all declared functions,
         types, and global variables.  The functions and global variables can
         then be accessed via either 'ffi.dlopen()' or 'ffi.verify()'.
         The types can be used in 'ffi.new()' and other functions.
         """
-        self._parser.parse(csource)
+        self._parser.parse(csource, override=override)
+        if override:
+            for cache in self._function_caches:
+                cache.clear()
 
     def dlopen(self, name):
         """Load and return a dynamic library identified by 'name'.
@@ -83,7 +87,9 @@
         library we only look for the actual (untyped) symbols.
         """
         assert isinstance(name, str) or name is None
-        return _make_ffi_library(self, name)
+        lib, function_cache = _make_ffi_library(self, name)
+        self._function_caches.append(function_cache)
+        return lib
 
     def typeof(self, cdecl, consider_function_as_funcptr=False):
         """Parse the C type given as a string and return the
@@ -282,4 +288,4 @@
     #
     if libname is not None:
         FFILibrary.__name__ = 'FFILibrary_%s' % libname
-    return FFILibrary()
+    return FFILibrary(), function_cache
diff --git a/cffi/cparser.py b/cffi/cparser.py
--- a/cffi/cparser.py
+++ b/cffi/cparser.py
@@ -46,6 +46,7 @@
         self._declarations = {}
         self._anonymous_counter = 0
         self._structnode2type = weakref.WeakKeyDictionary()
+        self._override = False
 
     def _parse(self, csource):
         # XXX: for more efficiency we would need to poke into the
@@ -63,7 +64,15 @@
         ast = _get_parser().parse(csource)
         return ast, macros
 
-    def parse(self, csource):
+    def parse(self, csource, override=False):
+        prev_override = self._override
+        try:
+            self._override = override
+            self._internal_parse(csource)
+        finally:
+            self._override = prev_override
+
+    def _internal_parse(self, csource):
         ast, macros = self._parse(csource)
         # add the macros
         for key, value in macros.items():
@@ -139,7 +148,10 @@
         if name in self._declarations:
             if self._declarations[name] is obj:
                 return
-            raise api.FFIError("multiple declarations of %s" % (name,))
+            if not self._override:
+                raise api.FFIError(
+                    "multiple declarations of %s (for interactive usage, "
+                    "try cdef(xx, override=True))" % (name,))
         assert name != '__dotdotdot__'
         self._declarations[name] = obj
 
diff --git a/testing/test_parsing.py b/testing/test_parsing.py
--- a/testing/test_parsing.py
+++ b/testing/test_parsing.py
@@ -1,5 +1,5 @@
 import py, sys
-from cffi import FFI, CDefError, VerificationError
+from cffi import FFI, FFIError, CDefError, VerificationError
 
 class FakeBackend(object):
 
@@ -168,3 +168,12 @@
     assert repr(type_bar) == "<struct $1>"
     py.test.raises(VerificationError, type_bar.get_c_name)
     assert type_foo.get_c_name() == "foo_t"
+
+def test_override():
+    ffi = FFI(backend=FakeBackend())
+    C = ffi.dlopen(None)
+    ffi.cdef("int foo(void);")
+    py.test.raises(FFIError, ffi.cdef, "long foo(void);")
+    assert C.foo.BType == '<func (), <int>, False>'
+    ffi.cdef("long foo(void);", override=True)
+    assert C.foo.BType == '<func (), <long>, False>'


More information about the pypy-commit mailing list