[pypy-commit] pypy py3.6: cpython3 compatibility for raising when calling methods on abstract classes

mattip pypy.commits at gmail.com
Sun Aug 25 03:40:31 EDT 2019


Author: Matti Picus <matti.picus at gmail.com>
Branch: py3.6
Changeset: r97255:544f648a1d31
Date: 2019-08-25 10:36 +0300
http://bitbucket.org/pypy/pypy/changeset/544f648a1d31/

Log:	cpython3 compatibility for raising when calling methods on abstract
	classes

diff --git a/lib_pypy/_ctypes/array.py b/lib_pypy/_ctypes/array.py
--- a/lib_pypy/_ctypes/array.py
+++ b/lib_pypy/_ctypes/array.py
@@ -108,27 +108,29 @@
         # array accepts very strange parameters as part of structure
         # or function argument...
         from ctypes import c_char, c_wchar
-        if issubclass(self._type_, c_char):
-            if isinstance(value, bytes):
-                if len(value) > self._length_:
-                    raise ValueError("Invalid length")
-                value = self(*value)
-            elif not isinstance(value, self):
-                raise TypeError("expected bytes, %s found"
-                                % (value.__class__.__name__,))
-        elif issubclass(self._type_, c_wchar):
-            if isinstance(value, str):
-                if len(value) > self._length_:
-                    raise ValueError("Invalid length")
-                value = self(*value)
-            elif not isinstance(value, self):
-                raise TypeError("expected unicode string, %s found"
-                                % (value.__class__.__name__,))
-        else:
-            if isinstance(value, tuple):
-                if len(value) > self._length_:
-                    raise RuntimeError("Invalid length")
-                value = self(*value)
+        if isinstance(value, self):
+            return value
+        if hasattr(self, '_type_'):
+            if issubclass(self._type_, c_char):
+                if isinstance(value, bytes):
+                    if len(value) > self._length_:
+                        raise ValueError("Invalid length")
+                    value = self(*value)
+                elif not isinstance(value, self):
+                    raise TypeError("expected bytes, %s found"
+                                    % (value.__class__.__name__,))
+            elif issubclass(self._type_, c_wchar):
+                if isinstance(value, str):
+                    if len(value) > self._length_:
+                        raise ValueError("Invalid length")
+                    value = self(*value)
+                elif not isinstance(value, self):
+                    raise TypeError("expected unicode string, %s found"
+                                    % (value.__class__.__name__,))
+        if isinstance(value, tuple):
+            if len(value) > self._length_:
+                raise RuntimeError("Invalid length")
+            value = self(*value)
         return _CDataMeta.from_param(self, value)
 
     def _build_ffiargtype(self):
diff --git a/lib_pypy/_ctypes/basics.py b/lib_pypy/_ctypes/basics.py
--- a/lib_pypy/_ctypes/basics.py
+++ b/lib_pypy/_ctypes/basics.py
@@ -45,6 +45,9 @@
         self.details = details
 
 class _CDataMeta(type):
+    def _is_abstract(self):
+        return getattr(self, '_type_', 'abstract') == 'abstract'
+
     def from_param(self, value):
         if isinstance(value, self):
             return value
@@ -95,6 +98,8 @@
         return self.from_address(dll.__pypy_dll__.getaddressindll(name))
 
     def from_buffer(self, obj, offset=0):
+        if self._is_abstract():
+            raise TypeError('abstract class')
         size = self._sizeofinstances()
         buf = memoryview(obj)
         if buf.nbytes < offset + size:
@@ -111,6 +116,8 @@
         return result
 
     def from_buffer_copy(self, obj, offset=0):
+        if self._is_abstract():
+            raise TypeError('abstract class')
         size = self._sizeofinstances()
         buf = memoryview(obj)
         if buf.nbytes < offset + size:
diff --git a/lib_pypy/_ctypes/pointer.py b/lib_pypy/_ctypes/pointer.py
--- a/lib_pypy/_ctypes/pointer.py
+++ b/lib_pypy/_ctypes/pointer.py
@@ -40,14 +40,17 @@
     def from_param(self, value):
         if value is None:
             return self(None)
-        # If we expect POINTER(<type>), but receive a <type> instance, accept
-        # it by calling byref(<type>).
-        if isinstance(value, self._type_):
-            return byref(value)
-        # Array instances are also pointers when the item types are the same.
-        if isinstance(value, (_Pointer, Array)):
-            if issubclass(type(value)._type_, self._type_):
-                return value
+        if isinstance(value, self):
+            return value
+        if hasattr(self, '_type_'):
+            # If we expect POINTER(<type>), but receive a <type> instance, accept
+            # it by calling byref(<type>).
+            if isinstance(value, self._type_):
+                return byref(value)
+            # Array instances are also pointers when the item types are the same.
+            if isinstance(value, (_Pointer, Array)):
+                if issubclass(type(value)._type_, self._type_):
+                    return value
         return _CDataMeta.from_param(self, value)
 
     def _sizeofinstances(self):
@@ -60,6 +63,8 @@
         return True
 
     def set_type(self, TP):
+        if self._is_abstract():
+            raise TypeError('abstract class')
         ffiarray = _rawffi.Array('P')
         def __init__(self, value=None):
             if not hasattr(self, '_buffer'):
@@ -179,6 +184,7 @@
         klass = type(_Pointer)("LP_%s" % cls,
                                (_Pointer,),
                                {})
+        klass._type_ = 'P'
         _pointer_type_cache[id(klass)] = klass
         return klass
     else:
diff --git a/lib_pypy/_ctypes/primitive.py b/lib_pypy/_ctypes/primitive.py
--- a/lib_pypy/_ctypes/primitive.py
+++ b/lib_pypy/_ctypes/primitive.py
@@ -158,6 +158,8 @@
                     break
             else:
                 raise AttributeError("cannot find _type_ attribute")
+        if tp == 'abstract':
+            tp = 'i'
         if (not isinstance(tp, str) or
             not len(tp) == 1 or
             tp not in SIMPLE_TYPE_CHARS):
@@ -341,7 +343,8 @@
     def from_param(self, value):
         if isinstance(value, self):
             return value
-
+        if self._type_ == 'abstract':
+            raise TypeError('abstract class')
         from_param_f = FROM_PARAM_BY_TYPE.get(self._type_)
         if from_param_f:
             res = from_param_f(self, value)
@@ -371,7 +374,7 @@
         return self._type_ in "sPzUZXO"
 
 class _SimpleCData(_CData, metaclass=SimpleType):
-    _type_ = 'i'
+    _type_ = 'abstract'
 
     def __init__(self, value=DEFAULT_VALUE):
         if not hasattr(self, '_buffer'):
diff --git a/lib_pypy/_ctypes/structure.py b/lib_pypy/_ctypes/structure.py
--- a/lib_pypy/_ctypes/structure.py
+++ b/lib_pypy/_ctypes/structure.py
@@ -119,6 +119,8 @@
         if self.is_bitfield:
             # bitfield member, use direct access
             return obj._buffer.__getattr__(self.name)
+        elif not isinstance(obj, _CData):
+            raise(TypeError, 'not a ctype instance') 
         else:
             fieldtype = self.ctype
             offset = self.num
@@ -142,6 +144,8 @@
             from ctypes import memmove
             dest = obj._buffer.fieldaddress(self.name)
             memmove(dest, arg, fieldtype._fficompositesize_)
+        elif not isinstance(obj, _CData):
+            raise(TypeError, 'not a ctype instance') 
         else:
             obj._buffer.__setattr__(self.name, arg)
 
@@ -209,6 +213,9 @@
 
     __setattr__ = struct_setattr
 
+    def _is_abstract(self):
+        return False
+
     def from_address(self, address):
         instance = StructOrUnion.__new__(self)
         if isinstance(address, _rawffi.StructureInstance):


More information about the pypy-commit mailing list