[pypy-commit] pypy default: merge heads

mattip noreply at buildbot.pypy.org
Sat Nov 1 21:48:46 CET 2014


Author: mattip <matti.picus at gmail.com>
Branch: 
Changeset: r74325:eb7acf87bbaf
Date: 2014-11-01 22:48 +0200
http://bitbucket.org/pypy/pypy/changeset/eb7acf87bbaf/

Log:	merge heads

diff --git a/pypy/objspace/std/formatting.py b/pypy/objspace/std/formatting.py
--- a/pypy/objspace/std/formatting.py
+++ b/pypy/objspace/std/formatting.py
@@ -1,15 +1,15 @@
-"""
-String formatting routines.
-"""
+"""String formatting routines"""
 import sys
-from pypy.interpreter.error import OperationError, oefmt
+
 from rpython.rlib import jit
-from rpython.rlib.rfloat import formatd, DTSF_ALT, isnan, isinf
+from rpython.rlib.rarithmetic import INT_MAX
+from rpython.rlib.rfloat import DTSF_ALT, formatd, isnan, isinf
 from rpython.rlib.rstring import StringBuilder, UnicodeBuilder
 from rpython.rlib.unroll import unrolling_iterable
-from rpython.rlib.rarithmetic import INT_MAX
 from rpython.tool.sourcetools import func_with_new_name
 
+from pypy.interpreter.error import OperationError, oefmt
+
 
 class BaseStringFormatter(object):
     def __init__(self, space, values_w, w_valuedict):
diff --git a/pypy/objspace/std/objectobject.py b/pypy/objspace/std/objectobject.py
--- a/pypy/objspace/std/objectobject.py
+++ b/pypy/objspace/std/objectobject.py
@@ -1,7 +1,10 @@
+"""The builtin object type implementation"""
+
 from pypy.interpreter.baseobjspace import W_Root
 from pypy.interpreter.error import OperationError, oefmt
 from pypy.interpreter.gateway import applevel, interp2app, unwrap_spec
-from pypy.interpreter.typedef import GetSetProperty, default_identity_hash, TypeDef
+from pypy.interpreter.typedef import (
+    GetSetProperty, TypeDef, default_identity_hash)
 from pypy.objspace.descroperation import Object
 
 
@@ -25,7 +28,7 @@
     else:
         args = getnewargs()
         if not isinstance(args, tuple):
-            raise TypeError, "__getnewargs__ should return a tuple"
+            raise TypeError("__getnewargs__ should return a tuple")
 
     try:
         getstate = obj.__getstate__
@@ -46,15 +49,8 @@
     else:
         state = getstate()
 
-    if isinstance(obj, list):
-        listitems = iter(obj)
-    else:
-        listitems = None
-
-    if isinstance(obj, dict):
-        dictitems = obj.iteritems()
-    else:
-        dictitems = None
+    listitems = iter(obj) if isinstance(obj, list) else None
+    dictitems = obj.iteritems() if isinstance(obj, dict) else None
 
     import copy_reg
     newobj = copy_reg.__newobj__
@@ -74,7 +70,7 @@
     import copy_reg
     slotnames = copy_reg._slotnames(cls)
     if not isinstance(slotnames, list) and slotnames is not None:
-        raise TypeError, "copy_reg._slotnames didn't return a list or None"
+        raise TypeError("copy_reg._slotnames didn't return a list or None")
     return slotnames
 ''', filename=__file__)
 
@@ -94,14 +90,13 @@
     # don't allow arguments if the default object.__init__() is about
     # to be called
     w_type = _precheck_for_new(space, w_type)
-    w_parentinit, w_ignored = w_type.lookup_where('__init__')
+    w_parentinit, _ = w_type.lookup_where('__init__')
     if w_parentinit is space.w_object:
         try:
             __args__.fixedunpack(0)
         except ValueError:
-            raise OperationError(space.w_TypeError,
-                                 space.wrap("default __new__ takes "
-                                            "no parameters"))
+            raise oefmt(space.w_TypeError,
+                        "default __new__ takes no parameters")
     if w_type.is_abstract():
         _abstract_method_error(space, w_type)
     w_obj = space.allocate_instance(W_ObjectObject, w_type)
@@ -120,8 +115,8 @@
         try:
             __args__.fixedunpack(0)
         except ValueError:
-            raise OperationError(space.w_TypeError,
-                space.wrap("object.__init__() takes no parameters"))
+            raise oefmt(space.w_TypeError,
+                        "object.__init__() takes no parameters")
 
 
 def descr_get___class__(space, w_obj):
@@ -135,11 +130,12 @@
                     "__class__ must be set to new-style class, not '%T' "
                     "object", w_newcls)
     if not w_newcls.is_heaptype():
-        raise OperationError(space.w_TypeError,
-                             space.wrap("__class__ assignment: only for heap types"))
+        raise oefmt(space.w_TypeError,
+                    "__class__ assignment: only for heap types")
     w_oldcls = space.type(w_obj)
     assert isinstance(w_oldcls, W_TypeObject)
-    if w_oldcls.get_full_instance_layout() == w_newcls.get_full_instance_layout():
+    if (w_oldcls.get_full_instance_layout() ==
+        w_newcls.get_full_instance_layout()):
         w_obj.setclass(space, w_newcls)
     else:
         raise oefmt(space.w_TypeError,
@@ -167,8 +163,8 @@
     w_type = space.type(w_obj)
     w_impl = w_type.lookup("__repr__")
     if w_impl is None:
-        raise OperationError(space.w_TypeError,      # can it really occur?
-                             space.wrap("operand does not support unary str"))
+        # can it really occur?
+        raise oefmt(space.w_TypeError, "operand does not support unary str")
     return space.get_and_call_function(w_impl, w_obj)
 
 
diff --git a/pypy/objspace/std/util.py b/pypy/objspace/std/util.py
--- a/pypy/objspace/std/util.py
+++ b/pypy/objspace/std/util.py
@@ -1,6 +1,7 @@
-from pypy.interpreter.error import oefmt, OperationError
 from rpython.rlib.rstring import InvalidBaseError
 
+from pypy.interpreter.error import OperationError, oefmt
+
 
 IDTAG_INT     = 1
 IDTAG_LONG    = 3
diff --git a/rpython/annotator/description.py b/rpython/annotator/description.py
--- a/rpython/annotator/description.py
+++ b/rpython/annotator/description.py
@@ -1,6 +1,7 @@
 from __future__ import absolute_import
-import types, py
-from rpython.annotator.signature import enforce_signature_args, enforce_signature_return
+import types
+from rpython.annotator.signature import (
+    enforce_signature_args, enforce_signature_return)
 from rpython.flowspace.model import Constant, FunctionGraph
 from rpython.flowspace.bytecode import cpython_code_signature
 from rpython.annotator.argument import rawshape, ArgErr
@@ -15,10 +16,10 @@
     'd1~d2 if d1 and d2 might be called at the same call site'.
     """
     normalized = False
-    modified   = True
+    modified = True
 
     def __init__(self, desc):
-        self.descs = { desc: True }
+        self.descs = {desc: True}
         self.calltables = {}  # see calltable_lookup_row()
         self.total_calltable_size = 0
 
@@ -29,7 +30,7 @@
         for shape, table in other.calltables.items():
             for row in table:
                 self.calltable_add_row(shape, row)
-    absorb = update # UnionFind API
+    absorb = update  # UnionFind API
 
     def calltable_lookup_row(self, callshape, row):
         # this code looks up a table of which graph to
@@ -68,7 +69,7 @@
         self.descs.update(other.descs)
         self.read_locations.update(other.read_locations)
         self.attrs.update(other.attrs)
-    absorb = update # UnionFind API
+    absorb = update  # UnionFind API
 
     def get_s_value(self, attrname):
         try:
@@ -97,7 +98,7 @@
 
     def __init__(self, desc):
         from rpython.annotator.model import s_ImpossibleValue
-        self.descs = { desc: True }
+        self.descs = {desc: True}
         self.read_locations = {}     # set of position_keys
         self.s_value = s_ImpossibleValue    # union of possible values
 
@@ -106,7 +107,7 @@
         self.descs.update(other.descs)
         self.read_locations.update(other.read_locations)
         self.s_value = unionof(self.s_value, other.s_value)
-    absorb = update # UnionFind API
+    absorb = update  # UnionFind API
 
     def get_s_value(self, attrname):
         return self.s_value
@@ -164,9 +165,9 @@
     def bind_under(self, classdef, name):
         return self
 
+    @staticmethod
     def simplify_desc_set(descs):
         pass
-    simplify_desc_set = staticmethod(simplify_desc_set)
 
 
 class NoStandardGraph(Exception):
@@ -218,7 +219,7 @@
         [graph] = self._cache.values()
         relax_sig_check = getattr(self.pyobj, "relax_sig_check", False)
         if (graph.signature != self.signature or
-            graph.defaults  != self.defaults) and not relax_sig_check:
+                graph.defaults != self.defaults) and not relax_sig_check:
             raise NoStandardGraph(self)
         return graph
 
@@ -229,7 +230,7 @@
             def nameof(thing):
                 if isinstance(thing, str):
                     return thing
-                elif hasattr(thing, '__name__'): # mostly types and functions
+                elif hasattr(thing, '__name__'):  # mostly types and functions
                     return thing.__name__
                 elif hasattr(thing, 'name') and isinstance(thing.name, str):
                     return thing.name            # mostly ClassDescs
@@ -240,7 +241,7 @@
 
             if key is not None and alt_name is None:
                 postfix = valid_identifier(nameof(key))
-                alt_name = "%s__%s"%(self.name, postfix)
+                alt_name = "%s__%s" % (self.name, postfix)
             graph = self.buildgraph(alt_name, builder)
             self._cache[key] = graph
             return graph
@@ -268,7 +269,7 @@
 
     def specialize(self, inputcells, op=None):
         if (op is None and
-            getattr(self.bookkeeper, "position_key", None) is not None):
+                getattr(self.bookkeeper, "position_key", None) is not None):
             _, block, i = self.bookkeeper.position_key
             op = block.operations[i]
         if self.specializer is None:
@@ -280,15 +281,16 @@
         enforceargs = getattr(self.pyobj, '_annenforceargs_', None)
         signature = getattr(self.pyobj, '_signature_', None)
         if enforceargs and signature:
-            raise Exception("%r: signature and enforceargs cannot both be used" % (self,))
+            raise Exception("%r: signature and enforceargs cannot both be "
+                            "used" % (self,))
         if enforceargs:
             if not callable(enforceargs):
                 from rpython.annotator.signature import Sig
                 enforceargs = Sig(*enforceargs)
                 self.pyobj._annenforceargs_ = enforceargs
-            enforceargs(self, inputcells) # can modify inputcells in-place
+            enforceargs(self, inputcells)  # can modify inputcells in-place
         if signature:
-            enforce_signature_args(self, signature[0], inputcells) # mutates inputcells
+            enforce_signature_args(self, signature[0], inputcells)  # mutates inputcells
         if getattr(self.pyobj, '_annspecialcase_', '').endswith("call_location"):
             return self.specializer(self, inputcells, op)
         else:
@@ -309,7 +311,8 @@
             if signature:
                 sigresult = enforce_signature_return(self, signature[1], result)
                 if sigresult is not None:
-                    self.bookkeeper.annotator.addpendingblock(graph, graph.returnblock, [sigresult])
+                    self.bookkeeper.annotator.addpendingblock(
+                        graph, graph.returnblock, [sigresult])
                     result = sigresult
         # Some specializations may break the invariant of returning
         # annotations that are always more general than the previous time.
@@ -325,12 +328,13 @@
                                              None,       # selfclassdef
                                              name)
 
+    @staticmethod
     def consider_call_site(bookkeeper, family, descs, args, s_result, op):
         shape = rawshape(args)
         row = FunctionDesc.row_to_consider(descs, args, op)
         family.calltable_add_row(shape, row)
-    consider_call_site = staticmethod(consider_call_site)
 
+    @staticmethod
     def variant_for_call_site(bookkeeper, family, descs, args, op):
         shape = rawshape(args)
         bookkeeper.enter(None)
@@ -340,11 +344,11 @@
             bookkeeper.leave()
         index = family.calltable_lookup_row(shape, row)
         return shape, index
-    variant_for_call_site = staticmethod(variant_for_call_site)
 
     def rowkey(self):
         return self
 
+    @staticmethod
     def row_to_consider(descs, args, op):
         # see comments in CallFamily
         from rpython.annotator.model import s_ImpossibleValue
@@ -356,7 +360,6 @@
             desc.pycall(enlist, args, s_ImpossibleValue, op)
             assert row
         return row
-    row_to_consider = staticmethod(row_to_consider)
 
     def get_s_signatures(self, shape):
         family = self.getcallfamily()
@@ -385,6 +388,9 @@
 
             return s_sigs
 
+def is_mixin(cls):
+    return cls.__dict__.get('_mixin_', False)
+
 NODEFAULT = object()
 
 class ClassDesc(Desc):
@@ -394,95 +400,92 @@
     settled = False
     _detect_invalid_attrs = None
 
-    def __init__(self, bookkeeper, pyobj=None,
+    def __init__(self, bookkeeper, cls,
                  name=None, basedesc=None, classdict=None,
                  specialize=None):
-        super(ClassDesc, self).__init__(bookkeeper, pyobj)
+        super(ClassDesc, self).__init__(bookkeeper, cls)
 
         if name is None:
-            name = pyobj.__module__ + '.' + pyobj.__name__
+            name = cls.__module__ + '.' + cls.__name__
         self.name = name
         self.basedesc = basedesc
         if classdict is None:
             classdict = {}    # populated below
         self.classdict = classdict     # {attr: Constant-or-Desc}
         if specialize is None:
-            specialize = pyobj.__dict__.get('_annspecialcase_', '')
+            specialize = cls.__dict__.get('_annspecialcase_', '')
         self.specialize = specialize
         self._classdefs = {}
 
-        if pyobj is not None:
-            assert pyobj.__module__ != '__builtin__'
-            cls = pyobj
-            base = object
-            baselist = list(cls.__bases__)
+        if is_mixin(cls):
+            raise AnnotatorError("cannot use directly the class %r because "
+                                 "it is a _mixin_" % (cls,))
 
-            if cls.__dict__.get('_mixin_', False):
-                raise AnnotatorError("cannot use directly the class %r because "
-                                     "it is a _mixin_" % (cls,))
+        assert cls.__module__ != '__builtin__'
+        baselist = list(cls.__bases__)
 
-            # special case: skip BaseException in Python 2.5, and pretend
-            # that all exceptions ultimately inherit from Exception instead
-            # of BaseException (XXX hack)
-            if cls is Exception:
-                baselist = []
-            elif baselist == [py.builtin.BaseException]:
-                baselist = [Exception]
+        # special case: skip BaseException, and pretend
+        # that all exceptions ultimately inherit from Exception instead
+        # of BaseException (XXX hack)
+        if cls is Exception:
+            baselist = []
+        elif baselist == [BaseException]:
+            baselist = [Exception]
 
-            mixins_before = []
-            mixins_after = []
-            for b1 in baselist:
-                if b1 is object:
-                    continue
-                if b1.__dict__.get('_mixin_', False):
-                    if base is object:
-                        mixins_before.append(b1)
-                    else:
-                        mixins_after.append(b1)
+        mixins_before = []
+        mixins_after = []
+        base = object
+        for b1 in baselist:
+            if b1 is object:
+                continue
+            if is_mixin(b1):
+                if base is object:
+                    mixins_before.append(b1)
                 else:
-                    assert base is object, ("multiple inheritance only supported "
-                                            "with _mixin_: %r" % (cls,))
-                    base = b1
-            if mixins_before and mixins_after:
-                raise Exception("unsupported: class %r has mixin bases both"
-                                " before and after the regular base" % (self,))
-            self.add_mixins(mixins_after, check_not_in=base)
-            self.add_mixins(mixins_before)
-            self.add_sources_for_class(cls)
+                    mixins_after.append(b1)
+            else:
+                assert base is object, ("multiple inheritance only supported "
+                                        "with _mixin_: %r" % (cls,))
+                base = b1
+        if mixins_before and mixins_after:
+            raise Exception("unsupported: class %r has mixin bases both"
+                            " before and after the regular base" % (self,))
+        self.add_mixins(mixins_after, check_not_in=base)
+        self.add_mixins(mixins_before)
+        self.add_sources_for_class(cls)
 
-            if base is not object:
-                self.basedesc = bookkeeper.getdesc(base)
+        if base is not object:
+            self.basedesc = bookkeeper.getdesc(base)
 
-            if '_settled_' in cls.__dict__:
-                self.settled = bool(cls.__dict__['_settled_'])
+        if '_settled_' in cls.__dict__:
+            self.settled = bool(cls.__dict__['_settled_'])
 
-            if '__slots__' in cls.__dict__ or '_attrs_' in cls.__dict__:
-                attrs = {}
-                for decl in ('__slots__', '_attrs_'):
-                    decl = cls.__dict__.get(decl, [])
-                    if isinstance(decl, str):
-                        decl = (decl,)
-                    decl = dict.fromkeys(decl)
-                    attrs.update(decl)
-                if self.basedesc is not None:
-                    if self.basedesc.all_enforced_attrs is None:
-                        raise Exception("%r has slots or _attrs_, "
-                                        "but not its base class"
-                                        % (pyobj,))
-                    attrs.update(self.basedesc.all_enforced_attrs)
-                self.all_enforced_attrs = attrs
+        if '__slots__' in cls.__dict__ or '_attrs_' in cls.__dict__:
+            attrs = {}
+            for decl in ('__slots__', '_attrs_'):
+                decl = cls.__dict__.get(decl, [])
+                if isinstance(decl, str):
+                    decl = (decl,)
+                decl = dict.fromkeys(decl)
+                attrs.update(decl)
+            if self.basedesc is not None:
+                if self.basedesc.all_enforced_attrs is None:
+                    raise Exception("%r has slots or _attrs_, "
+                                    "but not its base class" % (cls,))
+                attrs.update(self.basedesc.all_enforced_attrs)
+            self.all_enforced_attrs = attrs
 
-            if (self.is_builtin_exception_class() and
+        if (self.is_builtin_exception_class() and
                 self.all_enforced_attrs is None):
-                from rpython.annotator import classdef
-                if self.pyobj not in classdef.FORCE_ATTRIBUTES_INTO_CLASSES:
-                    self.all_enforced_attrs = []    # no attribute allowed
+            from rpython.annotator import classdef
+            if cls not in classdef.FORCE_ATTRIBUTES_INTO_CLASSES:
+                self.all_enforced_attrs = []    # no attribute allowed
 
     def add_source_attribute(self, name, value, mixin=False):
         if isinstance(value, types.FunctionType):
             # for debugging
             if not hasattr(value, 'class_'):
-                value.class_ = self.pyobj # remember that this is really a method
+                value.class_ = self.pyobj
             if self.specialize:
                 # make a custom funcdesc that specializes on its first
                 # argument (i.e. 'self').
@@ -507,7 +510,7 @@
         if isinstance(value, staticmethod) and mixin:
             # make a new copy of staticmethod
             func = value.__get__(42)
-            value =  staticmethod(func_with_new_name(func, func.__name__))
+            value = staticmethod(func_with_new_name(func, func.__name__))
 
         if type(value) in MemberDescriptorTypes:
             # skip __slots__, showing up in the class as 'member' objects
@@ -539,8 +542,8 @@
         add(check_not_in)
         #
         for base in reversed(mro):
-            assert base.__dict__.get("_mixin_", False), ("Mixin class %r has non"
-                "mixin base class %r" % (mixins, base))
+            assert is_mixin(base), (
+                "Mixin class %r has non mixin base class %r" % (mixins, base))
             for name, value in base.__dict__.items():
                 if name in skip:
                     continue
@@ -557,18 +560,18 @@
         try:
             return self._classdefs[key]
         except KeyError:
-            from rpython.annotator.classdef import ClassDef, FORCE_ATTRIBUTES_INTO_CLASSES
+            from rpython.annotator.classdef import (
+                ClassDef, FORCE_ATTRIBUTES_INTO_CLASSES)
             classdef = ClassDef(self.bookkeeper, self)
             self.bookkeeper.classdefs.append(classdef)
             self._classdefs[key] = classdef
 
             # forced attributes
-            if self.pyobj is not None:
-                cls = self.pyobj
-                if cls in FORCE_ATTRIBUTES_INTO_CLASSES:
-                    for name, s_value in FORCE_ATTRIBUTES_INTO_CLASSES[cls].items():
-                        classdef.generalize_attr(name, s_value)
-                        classdef.find_attribute(name).modified(classdef)
+            cls = self.pyobj
+            if cls in FORCE_ATTRIBUTES_INTO_CLASSES:
+                for name, s_value in FORCE_ATTRIBUTES_INTO_CLASSES[cls].items():
+                    classdef.generalize_attr(name, s_value)
+                    classdef.find_attribute(name).modified(classdef)
 
             # register all class attributes as coming from this ClassDesc
             # (as opposed to prebuilt instances)
@@ -635,8 +638,7 @@
         return s_instance
 
     def is_exception_class(self):
-        return self.pyobj is not None and issubclass(self.pyobj,
-                                                     py.builtin.BaseException)
+        return issubclass(self.pyobj, BaseException)
 
     def is_builtin_exception_class(self):
         if self.is_exception_class():
@@ -703,14 +705,12 @@
     def find_source_for(self, name):
         if name in self.classdict:
             return self
-        if self.pyobj is not None:
-            # check whether in the case the classdesc corresponds to a real class
-            # there is a new attribute
-            cls = self.pyobj
-            if name in cls.__dict__:
-                self.add_source_attribute(name, cls.__dict__[name])
-                if name in self.classdict:
-                    return self
+        # check whether there is a new attribute
+        cls = self.pyobj
+        if name in cls.__dict__:
+            self.add_source_attribute(name, cls.__dict__[name])
+            if name in self.classdict:
+                return self
         return None
 
     def maybe_return_immutable_list(self, attr, s_result):
@@ -718,7 +718,7 @@
         # either 'lst[*]' or 'lst?[*]'
         # should really return an immutable list as a result.  Implemented
         # by changing the result's annotation (but not, of course, doing an
-        # actual copy in the rtyper).  Tested in rpython.rtyper.test.test_rlist,
+        # actual copy in the rtyper). Tested in rpython.rtyper.test.test_rlist,
         # test_immutable_list_out_of_instance.
         if self._detect_invalid_attrs and attr in self._detect_invalid_attrs:
             raise Exception("field %r was migrated to %r from a subclass in "
@@ -730,7 +730,7 @@
         while cdesc is not None:
             if '_immutable_fields_' in cdesc.classdict:
                 if (search1 in cdesc.classdict['_immutable_fields_'].value or
-                    search2 in cdesc.classdict['_immutable_fields_'].value):
+                        search2 in cdesc.classdict['_immutable_fields_'].value):
                     s_result.listdef.never_resize()
                     s_copy = s_result.listdef.offspring()
                     s_copy.listdef.mark_as_immutable()
@@ -746,6 +746,7 @@
             cdesc = cdesc.basedesc
         return s_result     # common case
 
+    @staticmethod
     def consider_call_site(bookkeeper, family, descs, args, s_result, op):
         from rpython.annotator.model import SomeInstance, SomePBC, s_None
         if len(descs) == 1:
@@ -792,7 +793,6 @@
             initfamily = initdescs[0].getcallfamily()
             MethodDesc.consider_call_site(bookkeeper, initfamily, initdescs,
                                           args, s_None, op)
-    consider_call_site = staticmethod(consider_call_site)
 
     def getallbases(self):
         desc = self
@@ -800,6 +800,7 @@
             yield desc
             desc = desc.basedesc
 
+    @staticmethod
     def getcommonbase(descs):
         commondesc = descs[0]
         for desc in descs[1:]:
@@ -809,7 +810,6 @@
                 desc = desc.basedesc
             commondesc = desc
         return commondesc
-    getcommonbase = staticmethod(getcommonbase)
 
     def rowkey(self):
         return self
@@ -868,7 +868,7 @@
         from rpython.annotator.model import SomeInstance
         if self.selfclassdef is None:
             raise Exception("calling %r" % (self,))
-        s_instance = SomeInstance(self.selfclassdef, flags = self.flags)
+        s_instance = SomeInstance(self.selfclassdef, flags=self.flags)
         args = args.prepend(s_instance)
         return self.funcdesc.pycall(schedule, args, s_previous_result, op)
 
@@ -896,6 +896,7 @@
         # FunctionDesc to use as a key in that family.
         return self.funcdesc
 
+    @staticmethod
     def simplify_desc_set(descs):
         # Some hacking needed to make contains() happy on SomePBC: if the
         # set of MethodDescs contains some "redundant" ones, i.e. ones that
@@ -942,7 +943,6 @@
                         if cdef1 is not cdef2 and cdef1.issubclass(cdef2):
                             descs.remove(desc1)
                             break
-    simplify_desc_set = staticmethod(simplify_desc_set)
 
 
 def new_or_old_class(c):
@@ -960,7 +960,7 @@
         self._read_attribute = read_attribute
         self.attrcache = {}
         self.knowntype = new_or_old_class(pyobj)
-        assert bool(pyobj), "__nonzero__ unsupported on frozen PBC %r" %(pyobj,)
+        assert bool(pyobj), "__nonzero__ unsupported on frozen PBC %r" % (pyobj,)
 
     def has_attribute(self, attr):
         if attr in self.attrcache:
diff --git a/rpython/annotator/test/test_description.py b/rpython/annotator/test/test_description.py
--- a/rpython/annotator/test/test_description.py
+++ b/rpython/annotator/test/test_description.py
@@ -1,4 +1,4 @@
-from rpython.annotator.description import ClassDesc
+from rpython.annotator.description import ClassDesc, is_mixin
 
 class FakeBookkeeper:
     def __init__(self):
@@ -20,3 +20,13 @@
     dC = bk.getdesc(C)
     dD = bk.getdesc(D)
     assert ClassDesc.getcommonbase([dC, dD]) is dA
+
+def test_is_mixin():
+    class Mixin1(object):
+        _mixin_ = True
+
+    class A(Mixin1):
+        pass
+
+    assert is_mixin(Mixin1)
+    assert not is_mixin(A)


More information about the pypy-commit mailing list