[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