Author: Armin Rigo <[email protected]>
Branch: ffi-backend
Changeset: r56660:c04cefc2a251
Date: 2012-08-08 20:50 +0200
http://bitbucket.org/pypy/pypy/changeset/c04cefc2a251/
Log: Allow weakrefs to any cdata object. Simplifies a bit the class
hierarchy in cdataobj.
diff --git a/pypy/module/_cffi_backend/ccallback.py
b/pypy/module/_cffi_backend/ccallback.py
--- a/pypy/module/_cffi_backend/ccallback.py
+++ b/pypy/module/_cffi_backend/ccallback.py
@@ -8,7 +8,7 @@
from pypy.rlib import clibffi, rweakref, rgc
from pypy.rlib.rarithmetic import r_ulonglong
-from pypy.module._cffi_backend.cdataobj import W_CData, W_CDataApplevelOwning
+from pypy.module._cffi_backend.cdataobj import W_CData
from pypy.module._cffi_backend.ctypefunc import SIZE_OF_FFI_ARG, BIG_ENDIAN
from pypy.module._cffi_backend.ctypefunc import W_CTypeFunc
from pypy.module._cffi_backend.ctypeprim import W_CTypePrimitiveSigned
@@ -18,7 +18,7 @@
# ____________________________________________________________
-class W_CDataCallback(W_CDataApplevelOwning):
+class W_CDataCallback(W_CData):
#_immutable_fields_ = ...
ll_error = lltype.nullptr(rffi.CCHARP.TO)
diff --git a/pypy/module/_cffi_backend/cdataobj.py
b/pypy/module/_cffi_backend/cdataobj.py
--- a/pypy/module/_cffi_backend/cdataobj.py
+++ b/pypy/module/_cffi_backend/cdataobj.py
@@ -12,7 +12,7 @@
class W_CData(Wrappable):
- _attrs_ = ['space', '_cdata', 'ctype']
+ _attrs_ = ['space', '_cdata', 'ctype', '_lifeline_']
_immutable_fields_ = ['_cdata', 'ctype']
_cdata = lltype.nullptr(rffi.CCHARP.TO)
@@ -29,10 +29,19 @@
keepalive_until_here(self)
return extra
+ def _repr_extra_owning(self):
+ from pypy.module._cffi_backend.ctypeptr import W_CTypePointer
+ ctype = self.ctype
+ if isinstance(ctype, W_CTypePointer):
+ num_bytes = ctype.ctitem.size
+ else:
+ num_bytes = self._sizeof()
+ return 'owning %d bytes' % num_bytes
+
def repr(self):
extra2 = self._repr_extra()
extra1 = ''
- if not isinstance(self, W_CDataApplevelOwning):
+ if not isinstance(self, W_CDataNewOwning):
# it's slightly confusing to get "<cdata 'struct foo' 0x...>"
# because the struct foo is not owned. Trying to make it
# clearer, write in this case "<cdata 'struct foo &' 0x...>".
@@ -206,35 +215,30 @@
return self.ctype.size
-class W_CDataApplevelOwning(W_CData):
- """This is the abstract base class for classes that are of the app-level
- type '_cffi_backend.CDataOwn'. These are weakrefable."""
- _attrs_ = ['_lifeline_'] # for weakrefs
-
- def _repr_extra(self):
- from pypy.module._cffi_backend.ctypeptr import W_CTypePointer
- ctype = self.ctype
- if isinstance(ctype, W_CTypePointer):
- num_bytes = ctype.ctitem.size
- else:
- num_bytes = self._sizeof()
- return 'owning %d bytes' % num_bytes
-
-
-class W_CDataNewOwning(W_CDataApplevelOwning):
- """This is the class used for the app-level type
- '_cffi_backend.CDataOwn' created by newp()."""
+class W_CDataMem(W_CData):
+ """This is the base class used for cdata objects that own and free
+ their memory. Used directly by the results of cffi.cast('int', x)
+ or other primitive explicitly-casted types. It is further subclassed
+ by W_CDataNewOwning."""
_attrs_ = []
def __init__(self, space, size, ctype):
cdata = lltype.malloc(rffi.CCHARP.TO, size, flavor='raw', zero=True)
- W_CDataApplevelOwning.__init__(self, space, cdata, ctype)
+ W_CData.__init__(self, space, cdata, ctype)
@rgc.must_be_light_finalizer
def __del__(self):
lltype.free(self._cdata, flavor='raw')
+class W_CDataNewOwning(W_CDataMem):
+ """This is the class used for the cata objects created by newp()."""
+ _attrs_ = []
+
+ def _repr_extra(self):
+ return self._repr_extra_owning()
+
+
class W_CDataNewOwningLength(W_CDataNewOwning):
"""Subclass with an explicit length, for allocated instances of
the C type 'foo[]'."""
@@ -255,38 +259,27 @@
return self.length
-class W_CDataPtrToStructOrUnion(W_CDataApplevelOwning):
+class W_CDataPtrToStructOrUnion(W_CData):
"""This subclass is used for the pointer returned by new('struct foo').
It has a strong reference to a W_CDataNewOwning that really owns the
- struct, which is the object returned by the app-level expression 'p[0]'."""
+ struct, which is the object returned by the app-level expression 'p[0]'.
+ But it is not itself owning any memory, although its repr says so;
+ it is merely a co-owner."""
_attrs_ = ['structobj']
_immutable_fields_ = ['structobj']
def __init__(self, space, cdata, ctype, structobj):
- W_CDataApplevelOwning.__init__(self, space, cdata, ctype)
+ W_CData.__init__(self, space, cdata, ctype)
self.structobj = structobj
+ def _repr_extra(self):
+ return self._repr_extra_owning()
+
def _do_getitem(self, ctype, i):
assert i == 0
return self.structobj
-class W_CDataCasted(W_CData):
- """This subclass is used by the results of cffi.cast('int', x)
- or other primitive explicitly-casted types. Relies on malloc'ing
- small bits of memory (e.g. just an 'int'). Its point is to not be
- a subclass of W_CDataApplevelOwning."""
- _attrs_ = []
-
- def __init__(self, space, size, ctype):
- cdata = lltype.malloc(rffi.CCHARP.TO, size, flavor='raw', zero=True)
- W_CData.__init__(self, space, cdata, ctype)
-
- @rgc.must_be_light_finalizer
- def __del__(self):
- lltype.free(self._cdata, flavor='raw')
-
-
W_CData.typedef = TypeDef(
'CData',
__module__ = '_cffi_backend',
@@ -311,12 +304,6 @@
__setattr__ = interp2app(W_CData.setattr),
__call__ = interp2app(W_CData.call),
__iter__ = interp2app(W_CData.iter),
+ __weakref__ = make_weakref_descr(W_CData),
)
W_CData.typedef.acceptable_as_base_class = False
-
-W_CDataApplevelOwning.typedef = TypeDef(
- 'CDataOwn', W_CData.typedef, # base typedef
- __module__ = '_cffi_backend',
- __weakref__ = make_weakref_descr(W_CDataApplevelOwning),
- )
-W_CDataApplevelOwning.typedef.acceptable_as_base_class = False
diff --git a/pypy/module/_cffi_backend/ctypeprim.py
b/pypy/module/_cffi_backend/ctypeprim.py
--- a/pypy/module/_cffi_backend/ctypeprim.py
+++ b/pypy/module/_cffi_backend/ctypeprim.py
@@ -61,7 +61,7 @@
value = r_ulonglong(value)
else:
value = misc.as_unsigned_long_long(space, w_ob, strict=False)
- w_cdata = cdataobj.W_CDataCasted(space, self.size, self)
+ w_cdata = cdataobj.W_CDataMem(space, self.size, self)
w_cdata.write_raw_integer_data(value)
return w_cdata
@@ -248,7 +248,7 @@
value = self.cast_str(w_ob)
else:
value = space.float_w(w_ob)
- w_cdata = cdataobj.W_CDataCasted(space, self.size, self)
+ w_cdata = cdataobj.W_CDataMem(space, self.size, self)
if not isinstance(self, W_CTypePrimitiveLongDouble):
w_cdata.write_raw_float_data(value)
else:
@@ -313,7 +313,7 @@
return self.space.wrap(value)
def convert_to_object(self, cdata):
- w_cdata = cdataobj.W_CDataCasted(self.space, self.size, self)
+ w_cdata = cdataobj.W_CDataMem(self.space, self.size, self)
self._copy_longdouble(cdata, w_cdata._cdata)
keepalive_until_here(w_cdata)
return w_cdata
diff --git a/pypy/module/_cffi_backend/ctypeptr.py
b/pypy/module/_cffi_backend/ctypeptr.py
--- a/pypy/module/_cffi_backend/ctypeptr.py
+++ b/pypy/module/_cffi_backend/ctypeptr.py
@@ -214,11 +214,13 @@
return cdata
def _check_subscript_index(self, w_cdata, i):
- if isinstance(w_cdata, cdataobj.W_CDataApplevelOwning) and i != 0:
- space = self.space
- raise operationerrfmt(space.w_IndexError,
- "cdata '%s' can only be indexed by 0",
- self.name)
+ if (isinstance(w_cdata, cdataobj.W_CDataNewOwning) or
+ isinstance(w_cdata, cdataobj.W_CDataPtrToStructOrUnion)):
+ if i != 0:
+ space = self.space
+ raise operationerrfmt(space.w_IndexError,
+ "cdata '%s' can only be indexed by 0",
+ self.name)
return self
def add(self, cdata, i):
diff --git a/pypy/module/_cffi_backend/libraryobj.py
b/pypy/module/_cffi_backend/libraryobj.py
--- a/pypy/module/_cffi_backend/libraryobj.py
+++ b/pypy/module/_cffi_backend/libraryobj.py
@@ -22,6 +22,8 @@
else:
mode = -1 # default value, corresponds to RTLD_LOCAL
with rffi.scoped_str2charp(filename) as ll_libname:
+ if filename is None:
+ filename = "<None>"
try:
self.handle = dlopen(ll_libname, mode)
except DLOpenError, e:
@@ -56,8 +58,9 @@
"function cdata expected, got '%s'",
ctype.name)
#
- cdata = dlsym(self.handle, name)
- if not cdata:
+ try:
+ cdata = dlsym(self.handle, name)
+ except KeyError:
raise operationerrfmt(space.w_KeyError,
"function '%s' not found in library '%s'",
name, self.name)
@@ -66,8 +69,9 @@
@unwrap_spec(ctype=W_CType, name=str)
def read_variable(self, ctype, name):
space = self.space
- cdata = dlsym(self.handle, name)
- if not cdata:
+ try:
+ cdata = dlsym(self.handle, name)
+ except KeyError:
raise operationerrfmt(space.w_KeyError,
"variable '%s' not found in library '%s'",
name, self.name)
@@ -76,8 +80,9 @@
@unwrap_spec(ctype=W_CType, name=str)
def write_variable(self, ctype, name, w_value):
space = self.space
- cdata = dlsym(self.handle, name)
- if not cdata:
+ try:
+ cdata = dlsym(self.handle, name)
+ except KeyError:
raise operationerrfmt(space.w_KeyError,
"variable '%s' not found in library '%s'",
name, self.name)
@@ -95,7 +100,7 @@
W_Library.acceptable_as_base_class = False
-@unwrap_spec(filename=str, is_global=int)
+@unwrap_spec(filename="str_or_None", is_global=int)
def load_library(space, filename, is_global=0):
lib = W_Library(space, filename, is_global)
return space.wrap(lib)
diff --git a/pypy/module/_cffi_backend/test/_backend_test_c.py
b/pypy/module/_cffi_backend/test/_backend_test_c.py
--- a/pypy/module/_cffi_backend/test/_backend_test_c.py
+++ b/pypy/module/_cffi_backend/test/_backend_test_c.py
@@ -16,7 +16,10 @@
def find_and_load_library(name, is_global=0):
import ctypes.util
- path = ctypes.util.find_library(name)
+ if name is None:
+ path = None
+ else:
+ path = ctypes.util.find_library(name)
return load_library(path, is_global)
def test_load_library():
@@ -287,6 +290,13 @@
p = newp(BIntPtrPtr, q)
assert p[0][0] == 43
+def test_load_standard_library():
+ x = find_and_load_library(None)
+ BVoidP = new_pointer_type(new_void_type())
+ assert x.load_function(BVoidP, 'strcpy')
+ py.test.raises(KeyError, x.load_function,
+ BVoidP, 'xxx_this_function_does_not_exist')
+
def test_hash_differences():
BChar = new_primitive_type("char")
BInt = new_primitive_type("int")
@@ -1137,8 +1147,8 @@
BPtr = new_pointer_type(BInt)
weakref.ref(BInt)
weakref.ref(newp(BPtr, 42))
- py.test.raises(TypeError, weakref.ref, cast(BPtr, 42))
- py.test.raises(TypeError, weakref.ref, cast(BInt, 42))
+ weakref.ref(cast(BPtr, 42))
+ weakref.ref(cast(BInt, 42))
def test_no_inheritance():
BInt = new_primitive_type("int")
diff --git a/pypy/module/_cffi_backend/test/test_c.py
b/pypy/module/_cffi_backend/test/test_c.py
--- a/pypy/module/_cffi_backend/test/test_c.py
+++ b/pypy/module/_cffi_backend/test/test_c.py
@@ -23,8 +23,11 @@
keepalive_funcs = []
def find_and_load_library_for_test(space, w_name, w_is_global=0):
- import ctypes.util
- path = ctypes.util.find_library(space.str_w(w_name))
+ if space.is_w(w_name, space.w_None):
+ path = None
+ else:
+ import ctypes.util
+ path = ctypes.util.find_library(space.str_w(w_name))
return space.appexec([space.wrap(path), w_is_global],
"""(path, is_global):
import _cffi_backend
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit