Commits

Armin Rigo committed ac6fb07

Import cffi/6fee32c68e45

Comments (0)

Files changed (9)

lib_pypy/cffi/__init__.py

 from .api import FFI, CDefError, FFIError
 from .ffiplatform import VerificationError, VerificationMissing
 
-__version__ = "0.7"
-__version_info__ = (0, 7)
+__version__ = "0.7.2"
+__version_info__ = (0, 7, 2)

lib_pypy/cffi/api.py

             # _cffi_backend.so compiled.
             import _cffi_backend as backend
             from . import __version__
-            assert backend.__version__ == __version__
+            assert (backend.__version__ == __version__ or
+                    backend.__version__ == __version__[:3])
             # (If you insist you can also try to pass the option
             # 'backend=backend_ctypes.CTypesBackend()', but don't
             # rely on it!  It's probably not going to work well.)

lib_pypy/cffi/commontypes.py

         elif result in model.PrimitiveType.ALL_PRIMITIVE_TYPES:
             result = model.PrimitiveType(result)
         else:
-            assert commontype != result
+            if commontype == result:
+                raise api.FFIError("Unsupported type: %r.  Please file a bug "
+                                   "if you think it should be." % (commontype,))
             result = resolve_common_type(result)   # recursively
         assert isinstance(result, model.BaseTypeByIdentity)
         _CACHE[commontype] = result

lib_pypy/cffi/cparser.py

                 # assume a primitive type.  get it from .names, but reduce
                 # synonyms to a single chosen combination
                 names = list(type.names)
-                if names == ['signed'] or names == ['unsigned']:
-                    names.append('int')
-                if names[0] == 'signed' and names != ['signed', 'char']:
-                    names.pop(0)
-                if (len(names) > 1 and names[-1] == 'int'
-                        and names != ['unsigned', 'int']):
-                    names.pop()
+                if names != ['signed', 'char']:    # keep this unmodified
+                    prefixes = {}
+                    while names:
+                        name = names[0]
+                        if name in ('short', 'long', 'signed', 'unsigned'):
+                            prefixes[name] = prefixes.get(name, 0) + 1
+                            del names[0]
+                        else:
+                            break
+                    # ignore the 'signed' prefix below, and reorder the others
+                    newnames = []
+                    for prefix in ('unsigned', 'short', 'long'):
+                        for i in range(prefixes.get(prefix, 0)):
+                            newnames.append(prefix)
+                    if not names:
+                        names = ['int']    # implicitly
+                    if names == ['int']:   # but kill it if 'short' or 'long'
+                        if 'short' in prefixes or 'long' in prefixes:
+                            names = []
+                    names = newnames + names
                 ident = ' '.join(names)
                 if ident == 'void':
                     return model.void_type
                 self._partial_length = True
                 return None
         #
-        raise api.FFIError("unsupported non-constant or "
-                           "not immediately constant expression")
+        raise api.FFIError("unsupported expression: expected a "
+                           "simple numeric constant")
 
     def _build_enum_type(self, explicit_name, decls):
         if decls is not None:

lib_pypy/cffi/vengine_gen.py

     def load_library(self):
         # import it with the CFFI backend
         backend = self.ffi._backend
-        module = backend.load_library(self.verifier.modulefilename)
+        # needs to make a path that contains '/', on Posix
+        filename = os.path.join(os.curdir, self.verifier.modulefilename)
+        module = backend.load_library(filename)
         #
         # call loading_gen_struct() to get the struct layout inferred by
         # the C compiler

pypy/module/test_lib_pypy/cffi_tests/backend_tests.py

         typerepr = self.TypeRepr
         ffi = FFI(backend=self.Backend())
         ffi.cdef("struct foo { short a, b, c; };")
+        p = ffi.cast("short unsigned int", 0)
+        assert repr(p) == "<cdata 'unsigned short' 0>"
+        assert repr(ffi.typeof(p)) == typerepr % "unsigned short"
         p = ffi.cast("unsigned short int", 0)
         assert repr(p) == "<cdata 'unsigned short' 0>"
         assert repr(ffi.typeof(p)) == typerepr % "unsigned short"
         for c_type, expected_size in [
             ('char', 1),
             ('unsigned int', 4),
-            ('char *', SIZE_OF_LONG),
+            ('char *', SIZE_OF_PTR),
             ('int[5]', 20),
             ('struct foo', 12),
             ('union foo', 4),
             ]:
             size = ffi.sizeof(c_type)
-            assert size == expected_size
+            assert size == expected_size, (size, expected_size, ctype)
 
     def test_sizeof_cdata(self):
         ffi = FFI(backend=self.Backend())

pypy/module/test_lib_pypy/cffi_tests/callback_in_thread.py

     seen = []
     @ffi.callback('int(*)(int,int)')
     def mycallback(x, y):
+        time.sleep(0.022)
         seen.append((x, y))
         return 0
     lib.threaded_ballback_test(mycallback)

pypy/module/test_lib_pypy/cffi_tests/test_function.py

         sin100 = my_decorator(m.sin)
         x = sin100(1.23)
         assert x == math.sin(1.23) + 100
+
+    def test_free_callback_cycle(self):
+        if self.Backend is CTypesBackend:
+            py.test.skip("seems to fail with the ctypes backend on windows")
+        import weakref
+        def make_callback(data):
+            container = [data]
+            callback = ffi.callback('int()', lambda: len(container))
+            container.append(callback)
+            # Ref cycle: callback -> lambda (closure) -> container -> callback
+            return callback
+
+        class Data(object):
+            pass
+        ffi = FFI(backend=self.Backend())
+        data = Data()
+        callback = make_callback(data)
+        wr = weakref.ref(data)
+        del callback, data
+        for i in range(3):
+            if wr() is not None:
+                import gc; gc.collect()
+        assert wr() is None    # 'data' does not leak

pypy/module/test_lib_pypy/cffi_tests/test_version.py

 
 BACKEND_VERSIONS = {
     '0.4.2': '0.4',     # did not change
+    '0.7.1': '0.7',     # did not change
+    '0.7.2': '0.7',     # did not change
     }
 
 def test_version():
     content = open(p).read()
     #
     v = cffi.__version__
-    assert ("version = '%s'\n" % v) in content
+    assert ("version = '%s'\n" % BACKEND_VERSIONS.get(v, v)) in content
     assert ("release = '%s'\n" % v) in content
 
 def test_doc_version_file():
     v = cffi.__version__
     p = os.path.join(parent, 'c', 'test_c.py')
     content = open(p).read()
-    assert ('assert __version__ == "%s"' % v) in content
+    assert (('assert __version__ == "%s"' % BACKEND_VERSIONS.get(v, v))
+            in content)