[pypy-svn] r8843 - in pypy/dist/pypy: interpreter interpreter/test lib module objspace/std objspace/std/test

pedronis at codespeak.net pedronis at codespeak.net
Fri Feb 4 13:43:47 CET 2005


Author: pedronis
Date: Thu Feb  3 20:52:51 2005
New Revision: 8843

Modified:
   pypy/dist/pypy/interpreter/baseobjspace.py
   pypy/dist/pypy/interpreter/function.py
   pypy/dist/pypy/interpreter/pyframe.py
   pypy/dist/pypy/interpreter/pyopcode.py
   pypy/dist/pypy/interpreter/test/test_class.py
   pypy/dist/pypy/interpreter/test/test_function.py
   pypy/dist/pypy/interpreter/test/test_raise.py
   pypy/dist/pypy/lib/types.py
   pypy/dist/pypy/module/__builtin__module.py
   pypy/dist/pypy/objspace/std/objspace.py
   pypy/dist/pypy/objspace/std/test/test_dictproxy.py
   pypy/dist/pypy/objspace/std/test/test_floatobject.py
   pypy/dist/pypy/objspace/std/test/test_intobject.py
   pypy/dist/pypy/objspace/std/test/test_typeobject.py
   pypy/dist/pypy/objspace/std/test/test_userobject.py
   pypy/dist/pypy/objspace/std/typeobject.py
   pypy/dist/pypy/objspace/std/typetype.py
Log:
preparatory changes for old-style class integration

modified:
- type.__new__ with metaclass conflict logic and ingnoring old-style classes
mro computation to consider classic case
type lookup to be able to cope with old-style classes

- lower-level abstract_isinstance and abstract_issubclass in baseobspace
that can work also with old-style classes:
used to do proper class-kind-agnostic type-checking in function.Method
and exception catching

- exception raising works with old-style classes

- issubclass and isistance builtins

added dummy w_classobj and w_instance to baseobjspace, to be substituted
with the real thing, needed for example by type.__new__

they are also exposed in builtins as _classobj and _instance 




Modified: pypy/dist/pypy/interpreter/baseobjspace.py
==============================================================================
--- pypy/dist/pypy/interpreter/baseobjspace.py	(original)
+++ pypy/dist/pypy/interpreter/baseobjspace.py	Thu Feb  3 20:52:51 2005
@@ -189,7 +189,7 @@
                 return True
             try:
                 # Match subclasses.
-                if self.is_true(self.issubtype(w_exc_type, w_item)):
+                if self.is_true(self.abstract_issubclass(w_exc_type, w_item, failhard=True)):
                     return True
             except OperationError:
                 # Assume that this is a TypeError: w_item not a type,
@@ -219,6 +219,39 @@
         w_objtype = self.type(w_obj)
         return self.issubtype(w_objtype, w_type)
 
+    def abstract_issubclass(self, w_obj, w_cls, failhard=False):
+        try:
+            return self.issubtype(w_obj, w_cls)
+        except OperationError:
+            try:
+                self.getattr(w_cls, self.wrap('__bases__')) # type sanity check
+                return self.recursive_issubclass(w_obj, w_cls)
+            except OperationError:
+                if failhard:
+                    raise
+                else:
+                    return self.w_False
+
+    def recursive_issubclass(self, w_obj, w_cls):
+        if self.is_w(w_obj, w_cls):
+            return self.w_True
+        for w_base in self.unpackiterable(self.getattr(w_obj, 
+                                                       self.wrap('__bases__'))):
+            if self.is_true(self.recursive_issubclass(w_base, w_cls)):
+                return self.w_True
+        return self.w_False
+
+    def abstract_isinstance(self, w_obj, w_cls):
+        try:
+            return self.isinstance(w_obj, w_cls)
+        except OperationError:
+            try:
+                w_objcls = self.getattr(w_obj, self.wrap('__class__'))
+                return self.abstract_issubclass(w_objcls, w_cls)
+            except OperationError:
+                return self.w_False
+
+
     def eval(self, expression, w_globals, w_locals):
         "NOT_RPYTHON: For internal debugging."
         import types

Modified: pypy/dist/pypy/interpreter/function.py
==============================================================================
--- pypy/dist/pypy/interpreter/function.py	(original)
+++ pypy/dist/pypy/interpreter/function.py	Thu Feb  3 20:52:51 2005
@@ -55,8 +55,8 @@
                       not space.is_true(space.is_(w_obj, space.w_None)) or
                       space.is_true(space.is_(w_cls, space.type(space.w_None))))
         if asking_for_bound:
-            if w_cls == space.w_None:
-                w_cls = space.type(w_obj)
+            #if w_cls == space.w_None:
+            #    w_cls = space.type(w_obj)
             return wrap(Method(space, wrap(self), w_obj, w_cls))
         else:
             return wrap(Method(space, wrap(self), None, w_cls))
@@ -160,7 +160,7 @@
             # unbound method
             w_firstarg = args.firstarg()
             if w_firstarg is not None and self.space.is_true(
-                    self.space.isinstance(w_firstarg, self.w_class)):
+                    self.space.abstract_isinstance(w_firstarg, self.w_class)):
                 pass  # ok
             else:
                 msg = ("unbound method must be called with "
@@ -175,9 +175,9 @@
             return space.wrap(self)    # already bound
         else:
             # only allow binding to a more specific class than before
-            if w_cls == space.w_None:
-                w_cls = space.type(w_obj)
-            if not space.is_true(space.issubtype(w_cls, self.w_class)):
+            #if w_cls == space.w_None:
+            #    w_cls = space.type(w_obj)
+            if w_cls is not None and w_cls != space.w_None and not space.is_true(space.abstract_issubclass(w_cls, self.w_class)):
                 return space.wrap(self)   # subclass test failed
             return space.get(self.w_function, w_obj, w_cls)
 

Modified: pypy/dist/pypy/interpreter/pyframe.py
==============================================================================
--- pypy/dist/pypy/interpreter/pyframe.py	(original)
+++ pypy/dist/pypy/interpreter/pyframe.py	Thu Feb  3 20:52:51 2005
@@ -223,7 +223,7 @@
     # mistakes here usually show up as infinite recursion, which is fun.
     while isinstance(etype, tuple):
         etype = etype[0]
-    if isinstance(etype, type):
+    if isinstance(etype, (type, _classobj)):
         if not isinstance(value, etype):
             if value is None:
                 # raise Type: we assume we have to instantiate Type

Modified: pypy/dist/pypy/interpreter/pyopcode.py
==============================================================================
--- pypy/dist/pypy/interpreter/pyopcode.py	(original)
+++ pypy/dist/pypy/interpreter/pyopcode.py	Thu Feb  3 20:52:51 2005
@@ -417,7 +417,7 @@
         w_bases       = f.valuestack.pop()
         w_name        = f.valuestack.pop()
         w_metaclass = find_metaclass(f.space, w_bases,
-                                     w_methodsdict, f.w_globals)
+                                     w_methodsdict, f.w_globals, f.w_builtins)
         w_newclass = f.space.call_function(w_metaclass, w_name,
                                            w_bases, w_methodsdict)
         f.valuestack.push(w_newclass)
@@ -824,7 +824,7 @@
     stream.write("\n")
     file_softspace(stream, False)
 
-def app_find_metaclass(bases, namespace, globals):
+def app_find_metaclass(bases, namespace, globals, builtins):
     if '__metaclass__' in namespace:
         return namespace['__metaclass__']
     elif len(bases) > 0:
@@ -835,6 +835,8 @@
             return type(base)
     elif '__metaclass__' in globals:
         return globals['__metaclass__']
+    elif '__metaclass__' in builtins:
+        return builtins['__metaclass__']
     else:
         return type
 

Modified: pypy/dist/pypy/interpreter/test/test_class.py
==============================================================================
--- pypy/dist/pypy/interpreter/test/test_class.py	(original)
+++ pypy/dist/pypy/interpreter/test/test_class.py	Thu Feb  3 20:52:51 2005
@@ -2,7 +2,7 @@
 class AppTestClass: 
 
     def test_class(self):
-        class C:
+        class C(object):
             pass
         assert C.__class__ == type
         c = C()
@@ -124,7 +124,7 @@
         assert c.meth_doc.__doc__ == """this is a docstring"""
 
     def test_getattribute(self):
-        class C:
+        class C(object):
             def __getattribute__(self, attr):
                 if attr == 'one':
                     return 'two'

Modified: pypy/dist/pypy/interpreter/test/test_function.py
==============================================================================
--- pypy/dist/pypy/interpreter/test/test_function.py	(original)
+++ pypy/dist/pypy/interpreter/test/test_function.py	Thu Feb  3 20:52:51 2005
@@ -227,5 +227,5 @@
         assert meth4.call_args(args) == obj2
         # Check method returned from unbound_method.__get__()
         # --- with an incompatible class
-        w_meth5 = meth3.descr_method_get(space.wrap('hello'), space.w_None)
+        w_meth5 = meth3.descr_method_get(space.wrap('hello'), space.w_str)
         assert space.is_true(space.is_(w_meth5, w_meth3))

Modified: pypy/dist/pypy/interpreter/test/test_raise.py
==============================================================================
--- pypy/dist/pypy/interpreter/test/test_raise.py	(original)
+++ pypy/dist/pypy/interpreter/test/test_raise.py	Thu Feb  3 20:52:51 2005
@@ -117,9 +117,9 @@
         try:
             raise B
         except A, b:
-            assert type(b) == B
+            assert b.__class__ == B
         try:
             raise A, B(42)
         except B, b:
-            assert type(b) == B
+            assert b.__class__ == B
             assert b.x == 42

Modified: pypy/dist/pypy/lib/types.py
==============================================================================
--- pypy/dist/pypy/lib/types.py	(original)
+++ pypy/dist/pypy/lib/types.py	Thu Feb  3 20:52:51 2005
@@ -70,19 +70,16 @@
 del g
 
 # checking whether we can make copy_reg happy
-##class _C:
-##    def _m(self): pass
-##ClassType = type(_C)
-class ClassType: pass
 class _C:
-    def _m(self):pass
-## end of testing hack
+    def _m(self): pass
+
+ClassType = _classobj # from builtins
 try:
     UnboundMethodType = type(_C._m)         # Same as MethodType
 except AttributeError:
     pass
 _x = _C()
-InstanceType = type(_x)
+InstanceType = _instance # from builtins
 MethodType = type(_x._m)
 
 BuiltinFunctionType = type(len)

Modified: pypy/dist/pypy/module/__builtin__module.py
==============================================================================
--- pypy/dist/pypy/module/__builtin__module.py	(original)
+++ pypy/dist/pypy/module/__builtin__module.py	Thu Feb  3 20:52:51 2005
@@ -15,6 +15,11 @@
 file = __interplevel__eval('space.wrap(file)')
 open = file
 
+# old-style classes dummy support
+__builtins__['_classobj'] = __interplevel__eval('space.w_classobj')
+__builtins__['_instance'] = __interplevel__eval('space.w_instance')
+
+
 # TODO Fix this later to show Ctrl-D on Unix
 quit = exit = "Use Ctrl-Z (i.e. EOF) to exit."
 
@@ -174,6 +179,14 @@
 
     return initial
 
+def _recursive_issubclass(cls, klass_or_tuple):
+    if cls is klass_or_tuple:
+        return True
+    for base in cls.__bases__:
+        if _recursive_issubclass(base, klass_or_tuple):
+            return True
+    return False
+
 def issubclass(cls, klass_or_tuple):
     if _issubtype(type(klass_or_tuple), tuple):
         for klass in klass_or_tuple:
@@ -183,7 +196,12 @@
     try:
         return _issubtype(cls, klass_or_tuple)
     except TypeError:
-        raise TypeError, "arg 2 must be a class or type or a tuple thereof"
+        if not hasattr(cls, '__bases__'):
+            raise TypeError, "arg 1 must be a class or type"
+        if not hasattr(klass_or_tuple, '__bases__'):
+            raise TypeError, "arg 2 must be a class or type or a tuple thereof"
+        return _recursive_issubclass(cls, klass_or_tuple)
+        
 
 def isinstance(obj, klass_or_tuple):
     if issubclass(type(obj), klass_or_tuple):
@@ -441,6 +459,7 @@
 
 # The following must be the last import from __interplevel__ because it
 # overwrites the special __import__ hook with the normal one.
+
 from __interplevel__ import __import__
 
 
@@ -455,7 +474,7 @@
             index += 1
     return do_enumerate(it)
 
-class xrange:
+class xrange(object):
     def __init__(self, start, stop=None, step=1):
         if not isinstance(start, (int, long, float)):
             raise TypeError('an integer is required')
@@ -927,7 +946,7 @@
 
 # ________________________________________________________________________
 
-class buffer:
+class buffer(object):
     def __init__(self, object, offset=None, size=None):
         raise NotImplementedError, "XXX nobody needs this anyway"
 
@@ -953,3 +972,7 @@
 
 #from _file import file
 #open = file
+
+#default __metaclass__
+# XXX can use _classobj when we have a working one integrated
+__metaclass__ = type

Modified: pypy/dist/pypy/objspace/std/objspace.py
==============================================================================
--- pypy/dist/pypy/objspace/std/objspace.py	(original)
+++ pypy/dist/pypy/objspace/std/objspace.py	Thu Feb  3 20:52:51 2005
@@ -202,6 +202,10 @@
             w_type = self.gettypeobject(typedef)
             setattr(self, 'w_' + typedef.name, w_type)
             for_builtins[typedef.name] = w_type
+
+        # dummy old-style classes types
+        self.w_classobj = W_TypeObject(self, 'classobj', [self.w_object], {})
+        self.w_instance = W_TypeObject(self, 'instance', [self.w_object], {})
         
         # exceptions
         ##for_builtins.update(self.clone_exception_hierarchy())

Modified: pypy/dist/pypy/objspace/std/test/test_dictproxy.py
==============================================================================
--- pypy/dist/pypy/objspace/std/test/test_dictproxy.py	(original)
+++ pypy/dist/pypy/objspace/std/test/test_dictproxy.py	Thu Feb  3 20:52:51 2005
@@ -4,7 +4,7 @@
 
 class AppTestUserObject:
     def test_dictproxy(self):
-        class NotEmpty:
+        class NotEmpty(object):
             a = 1
         assert isinstance(NotEmpty.__dict__, dict) == False
         assert 'a' in NotEmpty.__dict__

Modified: pypy/dist/pypy/objspace/std/test/test_floatobject.py
==============================================================================
--- pypy/dist/pypy/objspace/std/test/test_floatobject.py	(original)
+++ pypy/dist/pypy/objspace/std/test/test_floatobject.py	Thu Feb  3 20:52:51 2005
@@ -87,4 +87,4 @@
 
         class b: 
             pass 
-        raises(TypeError, float, b()) 
+        raises((AttributeError, TypeError), float, b()) 

Modified: pypy/dist/pypy/objspace/std/test/test_intobject.py
==============================================================================
--- pypy/dist/pypy/objspace/std/test/test_intobject.py	(original)
+++ pypy/dist/pypy/objspace/std/test/test_intobject.py	Thu Feb  3 20:52:51 2005
@@ -345,7 +345,7 @@
 
         class b: 
             pass 
-        raises(TypeError, int, b()) 
+        raises((AttributeError,TypeError), int, b()) 
 
     def test_special_long(self):
         class a:
@@ -358,4 +358,4 @@
 
         class b: 
             pass 
-        raises(TypeError, int, b()) 
+        raises((AttributeError,TypeError), long, b()) 

Modified: pypy/dist/pypy/objspace/std/test/test_typeobject.py
==============================================================================
--- pypy/dist/pypy/objspace/std/test/test_typeobject.py	(original)
+++ pypy/dist/pypy/objspace/std/test/test_typeobject.py	Thu Feb  3 20:52:51 2005
@@ -57,7 +57,8 @@
 class AppTestTypeObject:
     def test_bases(self):
         assert int.__bases__ == (object,)
-        class X: pass
+        class X:
+            __metaclass__ = type
         assert X.__bases__ ==  (object,)
         class Y(X): pass
         assert Y.__bases__ ==  (X,)
@@ -191,3 +192,47 @@
             raise AssertionError, '__doc__ should not be writable'
 
         assert ImmutableDoc.__doc__ == 'foo'
+
+    def test_metaclass_conflict(self):
+
+        class T1(type):
+            pass
+        class T2(type):
+            pass
+        class D1:
+            __metaclass__ = T1
+        class D2:
+            __metaclass__ = T2
+        def conflict():
+            class C(D1,D2):
+                pass
+        raises(TypeError, conflict)
+
+    def test_metaclass_choice(self):
+        events = []
+        
+        class T1(type):
+            def __new__(*args):
+                events.append(args)
+                return type.__new__(*args)
+
+        class D1:
+            __metaclass__ = T1
+
+        class C(D1):
+            pass
+
+        class F(object):
+            pass
+
+        class G(F,D1):
+            pass
+
+        assert len(events) == 3
+        assert type(D1) is T1
+        assert type(C) is T1
+        assert type(G) is T1
+            
+
+        
+        

Modified: pypy/dist/pypy/objspace/std/test/test_userobject.py
==============================================================================
--- pypy/dist/pypy/objspace/std/test/test_userobject.py	(original)
+++ pypy/dist/pypy/objspace/std/test/test_userobject.py	Thu Feb  3 20:52:51 2005
@@ -58,15 +58,15 @@
 
     def test_descr_get(self):
         class C:
-            class desc:
+            class desc(object):
                 def __get__(self, ob, cls=None):
                     return 42
             prop = desc()
         assert C().prop == 42
 
     def test_descr_set(self):
-        class C:
-            class desc:
+        class C(object):
+            class desc(object):
                 def __set__(self, ob, val):
                     ob.wibble = val
             prop = desc()
@@ -75,8 +75,8 @@
         assert c.wibble == 32
 
     def test_descr_delete(self):
-        class C:
-            class desc:
+        class C(object):
+            class desc(object):
                 def __set__(self, ob, val):
                     oogabooga
                 def __delete__(self, ob):
@@ -110,7 +110,7 @@
         assert c1("hello", "world") == ("hello", "world")
 
     def test_getattribute(self):
-        class C:
+        class C(object):
             def __getattribute__(self, name):
                 return '->' + name
         c1 = C()

Modified: pypy/dist/pypy/objspace/std/typeobject.py
==============================================================================
--- pypy/dist/pypy/objspace/std/typeobject.py	(original)
+++ pypy/dist/pypy/objspace/std/typeobject.py	Thu Feb  3 20:52:51 2005
@@ -1,6 +1,7 @@
 from pypy.objspace.std.objspace import *
 from pypy.interpreter.function import Function, StaticMethod
 from pypy.interpreter.argument import Arguments
+from pypy.interpreter import gateway
 from pypy.objspace.std.stdtypedef import std_dict_descr, issubtypedef
 from pypy.objspace.std.objecttype import object_typedef
 
@@ -15,13 +16,15 @@
         w_self.dict_w = dict_w
         w_self.ensure_static__new__()
 
-        w_self.mro_w = compute_C3_mro(w_self)
+        w_self.mro_w = compute_C3_mro(space, w_self)
         if overridetypedef is not None:
             w_self.instancetypedef = overridetypedef
         else:
             # find the most specific typedef
             instancetypedef = object_typedef
             for w_base in bases_w:
+                if not space.is_true(space.isinstance(w_base, space.w_type)):
+                    continue
                 if issubtypedef(w_base.instancetypedef, instancetypedef):
                     instancetypedef = w_base.instancetypedef
                 elif not issubtypedef(instancetypedef, w_base.instancetypedef):
@@ -56,7 +59,14 @@
         space = w_self.space
         for w_class in w_self.mro_w:
             try:
-                return w_class.dict_w[key]
+                if isinstance(w_class, W_TypeObject):
+                    return w_class.dict_w[key]
+                else:
+                    try:
+                        return space.getitem(space.getdict(w_class),space.wrap(key))
+                    except OperationError,e:
+                        if not e.match(space, space.w_KeyError):
+                            raise
             except KeyError:
                 pass
         return None
@@ -67,7 +77,14 @@
         space = w_self.space
         for w_class in w_self.mro_w:
             try:
-                return w_class, w_class.dict_w[key]
+                if isinstance(w_class, W_TypeObject):
+                    return w_class, w_class.dict_w[key]
+                else:
+                    try:
+                        return w_class, space.getitem(space.getdict(w_class),space.wrap(key))
+                    except OperationError,e:
+                        if not e.match(space, space.w_KeyError):
+                            raise                
             except KeyError:
                 pass
         return None, None
@@ -167,9 +184,31 @@
 
 # ____________________________________________________________
 
-def compute_C3_mro(cls):
+
+def app_abstract_mro(klass): # abstract/classic mro
+    mro = []
+    def fill_mro(klass):
+        if klass not in mro:
+            mro.append(klass)
+        assert isinstance(klass.__bases__, tuple)
+        for base in klass.__bases__:
+            fill_mro(base)
+    fill_mro(klass)
+    return mro
+
+abstract_mro = gateway.app2interp(app_abstract_mro)
+    
+
+def get_mro(space, klass):
+    if isinstance(klass, W_TypeObject):
+        return list(klass.mro_w)
+    else:
+        return space.unpackiterable(abstract_mro(space, klass))
+
+
+def compute_C3_mro(space, cls):
     order = []
-    orderlists = [list(base.mro_w) for base in cls.bases_w]
+    orderlists = [get_mro(space, base) for base in cls.bases_w]
     orderlists.append([cls] + cls.bases_w)
     while orderlists:
         for candidatelist in orderlists:

Modified: pypy/dist/pypy/objspace/std/typetype.py
==============================================================================
--- pypy/dist/pypy/objspace/std/typetype.py	(original)
+++ pypy/dist/pypy/objspace/std/typetype.py	Thu Feb  3 20:52:51 2005
@@ -1,3 +1,4 @@
+from pypy.interpreter.error import OperationError
 from pypy.objspace.std.stdtypedef import *
 from pypy.objspace.std.dictproxyobject import dictproxy_descr
 
@@ -5,10 +6,33 @@
 def descr__new__(space, w_typetype, w_name, w_bases, w_dict):
     "This is used to create user-defined classes only."
     from pypy.objspace.std.typeobject import W_TypeObject
-    # XXX check types
+    # XXX check types 
+    bases_w = space.unpackiterable(w_bases)
+
+    w_winner = w_typetype
+    for base in bases_w:
+        w_typ = space.type(base)
+        if space.is_w(w_typ, space.w_classobj):
+            continue # special-case old-style classes
+        if space.is_true(space.issubtype(w_winner, w_typ)):
+            continue
+        if space.is_true(space.issubtype(w_typ, w_winner)):
+            w_winner = w_typ
+            continue
+        raise OperationError(space.w_TypeError,
+                             space.wrap("metaclass conflict: "
+                                        "the metaclass of a derived class "
+                                        "must be a (non-strict) subclass "
+                                        "of the metaclasses of all its bases"))
+
+    if not space.is_w(w_winner, w_typetype):
+        newfunc = space.getattr(w_winner, space.wrap('__new__'))
+        if not space.is_w(newfunc, space.getattr(space.w_type, space.wrap('__new__'))):
+            return space.call_function(newfunc, w_winner, w_name, w_bases, w_dict)
+        w_typetype = w_winner
+        
     name = space.str_w(w_name)
     assert isinstance(name, str)
-    bases_w = space.unpackiterable(w_bases)
     dict_w = {}
     dictkeys_w = space.unpackiterable(w_dict)
     for w_key in dictkeys_w:



More information about the Pypy-commit mailing list