[pypy-commit] pypy kill-multimethod: Remove pypy.objspace.std.multimethod and make tests pass again.
Manuel Jacob
noreply at buildbot.pypy.org
Tue Feb 25 06:00:27 CET 2014
Author: Manuel Jacob
Branch: kill-multimethod
Changeset: r69400:0f3b67d218ae
Date: 2014-02-25 05:38 +0100
http://bitbucket.org/pypy/pypy/changeset/0f3b67d218ae/
Log: Remove pypy.objspace.std.multimethod and make tests pass again.
diff --git a/pypy/objspace/std/builtinshortcut.py b/pypy/objspace/std/builtinshortcut.py
--- a/pypy/objspace/std/builtinshortcut.py
+++ b/pypy/objspace/std/builtinshortcut.py
@@ -1,7 +1,6 @@
from pypy.interpreter.baseobjspace import ObjSpace
from pypy.interpreter.error import OperationError
from pypy.objspace.descroperation import DescrOperation
-from pypy.objspace.std.multimethod import FailedToImplement
from pypy.objspace.std.boolobject import W_BoolObject
from rpython.tool.sourcetools import func_with_new_name
diff --git a/pypy/objspace/std/model.py b/pypy/objspace/std/model.py
--- a/pypy/objspace/std/model.py
+++ b/pypy/objspace/std/model.py
@@ -3,7 +3,6 @@
to provide in this version of PyPy, along with conversion rules.
"""
-from pypy.objspace.std.multimethod import MultiMethodTable, FailedToImplement
from pypy.interpreter.baseobjspace import W_Root, ObjSpace
import pypy.interpreter.pycode
import pypy.interpreter.special
@@ -266,88 +265,3 @@
class UnwrapError(Exception):
pass
-
-
-class StdObjSpaceMultiMethod(MultiMethodTable):
-
- def __init__(self, operatorsymbol, arity, specialnames=None, **extras):
- """NOT_RPYTHON: cannot create new multimethods dynamically.
- """
- MultiMethodTable.__init__(self, arity, W_ANY,
- argnames_before = ['space'])
- self.operatorsymbol = operatorsymbol
- if specialnames is None:
- specialnames = [operatorsymbol]
- assert isinstance(specialnames, list)
- self.specialnames = specialnames # e.g. ['__xxx__', '__rxxx__']
- self.extras = extras
- # transform '+' => 'add' etc.
- for line in ObjSpace.MethodTable:
- realname, symbolname = line[:2]
- if symbolname == operatorsymbol:
- self.name = realname
- break
- else:
- self.name = operatorsymbol
-
- if extras.get('general__args__', False):
- self.argnames_after = ['__args__']
- if extras.get('varargs_w', False):
- self.argnames_after = ['args_w']
- self.argnames_after += extras.get('extra_args', [])
-
- def install_not_sliced(self, typeorder, baked_perform_call=True):
- return self.install(prefix = '__mm_' + self.name,
- list_of_typeorders = [typeorder]*self.arity,
- baked_perform_call=baked_perform_call)
-
- def merge_with(self, other):
- # Make a new 'merged' multimethod including the union of the two
- # tables. In case of conflict, pick the entry from 'self'.
- if self.arity != other.arity:
- return self # XXX that's the case of '**'
- operatorsymbol = '%s_merge_%s' % (self.name, other.name)
- assert self.extras == other.extras
- mm = StdObjSpaceMultiMethod(operatorsymbol, self.arity, **self.extras)
- #
- def merge(node1, node2):
- assert type(node1) is type(node2)
- if isinstance(node1, dict):
- d = node1.copy()
- d.update(node2)
- for key in node1:
- if key in node2:
- d[key] = merge(node1[key], node2[key])
- return d
- else:
- assert isinstance(node1, list)
- assert node1
- return node1 # pick the entry from 'self'
- #
- mm.dispatch_tree = merge(self.dispatch_tree, other.dispatch_tree)
- return mm
-
-NOT_MULTIMETHODS = set(
- ['delattr', 'delete', 'get', 'id', 'inplace_div', 'inplace_floordiv',
- 'inplace_lshift', 'inplace_mod', 'inplace_pow', 'inplace_rshift',
- 'inplace_truediv', 'is_', 'set', 'setattr', 'type', 'userdel',
- 'isinstance', 'issubtype', 'int', 'ord'])
-# XXX should we just remove those from the method table or we're happy
-# with just not having multimethods?
-
-class MM:
- """StdObjSpace multimethods"""
-
- call = StdObjSpaceMultiMethod('call', 1, ['__call__'],
- general__args__=True)
- init = StdObjSpaceMultiMethod('__init__', 1, general__args__=True)
- getnewargs = StdObjSpaceMultiMethod('__getnewargs__', 1)
-
- # add all regular multimethods here
- for _name, _symbol, _arity, _specialnames in ObjSpace.MethodTable:
- if _name not in locals() and _name not in NOT_MULTIMETHODS:
- mm = StdObjSpaceMultiMethod(_symbol, _arity, _specialnames)
- locals()[_name] = mm
- del mm
-
- pow.extras['defaults'] = (None,)
diff --git a/pypy/objspace/std/multimethod.py b/pypy/objspace/std/multimethod.py
deleted file mode 100644
--- a/pypy/objspace/std/multimethod.py
+++ /dev/null
@@ -1,973 +0,0 @@
-
-from rpython.tool.sourcetools import compile2
-
-# This provide two compatible implementations of "multimethods". A
-# multimethod is a callable object which chooses and calls a real
-# function from a table of pre-registered functions. The choice depends
-# on the '__class__' of all arguments. For example usages see
-# test_multimethod.
-
-# These multimethods support delegation: for each class A we must
-# provide a "typeorder", which is list of pairs (B, converter) where B
-# is a class and 'converter' is a function that can convert from an
-# instance of A to an instance of B. If 'converter' is None it is
-# assumed that the instance needs no conversion. The first entry in the
-# typeorder of a class A must almost always be (A, None).
-
-# A slightly non-standard feature of PyPy's multimethods is the way in
-# which they interact with normal subclassing. Basically, they don't.
-# Suppose that A is a parent class of B. Then a function registered for
-# an argument class A only accepts an instance whose __class__ is A, not
-# B. To make it accept an instance of B, the typeorder for B must
-# contain (A, None). An exception to this strict rule is if C is
-# another subclass of A which is not mentioned at all in the typeorder;
-# in this case C is considered to be equivalent to A.
-
-
-class FailedToImplement(Exception):
- def __new__(cls, *args):
- if cls is FailedToImplement:
- assert not args, "use FailedToImplementArgs!"
- return Exception.__new__(cls, *args)
-
- def get_w_value(self, space):
- return None
-
- def get_w_type(self, space):
- return None
-
- def __str__(self):
- return '<FailedToImplement(None, None)>'
-
-class FailedToImplementArgs(FailedToImplement):
- def __init__(self, w_type=None, w_value=None):
- self.w_type = w_type
- self.w_value = w_value
-
- def get_w_value(self, space):
- # convenience: same semantics as with OperationError
- return self.w_value
-
- def get_w_type(self, space):
- return self.w_type
-
- def __str__(self):
- return '<FailedToImplement(%s, %s)>' % (self.w_type, self.w_value)
-
-
-
-def raiseFailedToImplement():
- raise FailedToImplement
-
-
-class MultiMethodTable:
-
- def __init__(self, arity, root_class, argnames_before=[], argnames_after=[]):
- """NOT_RPYTHON: cannot create new multimethods dynamically.
- MultiMethod-maker dispatching on exactly 'arity' arguments.
- """
- if arity < 1:
- raise ValueError, "multimethods cannot dispatch on nothing"
- self.arity = arity
- self.root_class = root_class
- self.dispatch_tree = {}
- self.argnames_before = list(argnames_before)
- self.argnames_after = list(argnames_after)
-
- def register(self, function, *types, **kwds):
- assert len(types) == self.arity
- assert kwds.keys() == [] or kwds.keys() == ['order']
- order = kwds.get('order', 0)
- node = self.dispatch_tree
- for type in types[:-1]:
- node = node.setdefault(type, {})
- lst = node.setdefault(types[-1], [])
- if order >= len(lst):
- lst += [None] * (order+1 - len(lst))
- assert lst[order] is None, "duplicate function for %r@%d" % (
- types, order)
- lst[order] = function
-
- def install(self, prefix, list_of_typeorders, baked_perform_call=True,
- base_typeorder=None, installercls=None):
- "NOT_RPYTHON: initialization-time only"
- assert len(list_of_typeorders) == self.arity
- installercls = installercls or Installer
- installer = installercls(self, prefix, list_of_typeorders,
- baked_perform_call=baked_perform_call,
- base_typeorder=base_typeorder)
- return installer.install()
-
- def install_if_not_empty(self, prefix, list_of_typeorders,
- base_typeorder=None, installercls=None):
- "NOT_RPYTHON: initialization-time only"
- assert len(list_of_typeorders) == self.arity
- installercls = installercls or Installer
- installer = installercls(self, prefix, list_of_typeorders,
- base_typeorder=base_typeorder)
- if installer.is_empty():
- return None
- else:
- return installer.install()
-
-
-
- # ____________________________________________________________
- # limited dict-like interface to the dispatch table
-
- def getfunctions(self, types):
- assert len(types) == self.arity
- node = self.dispatch_tree
- for type in types:
- node = node[type]
- return [fn for fn in node if fn is not None]
-
- def has_signature(self, types):
- try:
- self.getfunctions(types)
- except KeyError:
- return False
- else:
- return True
-
- def signatures(self):
- """NOT_RPYTHON"""
- result = []
- def enum_keys(types_so_far, node):
- for type, subnode in node.items():
- next_types = types_so_far+(type,)
- if isinstance(subnode, dict):
- enum_keys(next_types, subnode)
- else:
- assert len(next_types) == self.arity
- result.append(next_types)
- enum_keys((), self.dispatch_tree)
- return result
-
-# ____________________________________________________________
-# Installer version 1
-
-class InstallerVersion1:
- """NOT_RPYTHON"""
-
- instance_counter = 0
-
- mmfunccache = {}
-
- prefix_memo = {}
-
- def __init__(self, multimethod, prefix, list_of_typeorders,
- baked_perform_call=True, base_typeorder=None):
- self.__class__.instance_counter += 1
- self.multimethod = multimethod
- # avoid prefix clashes, user code should supply different prefixes
- # itself for nice names in tracebacks
- base_prefix = prefix
- n = 1
- while prefix in self.prefix_memo:
- n += 1
- prefix = "%s%d" % (base_prefix, n)
- self.prefix = prefix
- self.prefix_memo[prefix] = 1
- self.list_of_typeorders = list_of_typeorders
- self.check_typeorders()
- self.subtree_cache = {}
- self.to_install = []
- self.non_empty = self.build_tree([], multimethod.dispatch_tree)
-
- self.baked_perform_call = baked_perform_call
-
- if self.non_empty:
- perform = [(None, prefix, 0)]
- else:
- perform = []
-
- self.perform_call = self.build_function(None, prefix+'_perform_call',
- None, perform)
-
- def check_typeorders(self):
- # xxx we use a '__'-separated list of the '__name__' of the types
- # in build_single_method(), so types with the same __name__ or
- # with '__' in them would obscurely break this logic
- for typeorder in self.list_of_typeorders:
- for type in typeorder:
- assert '__' not in type.__name__, (
- "avoid '__' in the name of %r" % (type,))
- names = dict.fromkeys([type.__name__ for type in typeorder])
- assert len(names) == len(typeorder), (
- "duplicate type.__name__ in %r" % (typeorder,))
-
- def is_empty(self):
- return not self.non_empty
-
- def install(self):
- #f = open('LOGFILE', 'a')
- #print >> f, '_'*60
- #import pprint
- #pprint.pprint(self.list_of_typeorders, f)
-
- def class_key(cls):
- "Returns an object such that class_key(subcls) > class_key(cls)."
- return len(cls.__mro__)
-
- # Sort 'to_install' so that base classes come first, which is
- # necessary for the 'parentfunc' logic in the loop below to work.
- # Moreover, 'to_install' can contain two functions with the same
- # name for the root class: the default fallback one and the real
- # one. So we have to sort the real one just after the default one
- # so that the default one gets overridden.
- def key(target, funcname, func, source, fallback):
- if target is None:
- return ()
- return (class_key(target), not fallback)
- self.to_install.sort(lambda a, b: cmp(key(*a), key(*b)))
-
- for target, funcname, func, source, fallback in self.to_install:
- if target is not None:
- # If the parent class provides a method of the same
- # name which is actually the same 'func', we don't need
- # to install it again. Useful with fallback functions.
- parentfunc = getattr(target, funcname, None)
- parentfunc = getattr(parentfunc, 'im_func', None)
- if parentfunc is func:
- continue
- #print >> f, target.__name__, funcname
- #if source:
- # print >> f, source
- #else:
- # print >> f, '*\n'
- setattr(target, funcname, func)
- #f.close()
- return self.perform_call
-
- def build_tree(self, types_so_far, dispatch_node):
- key = tuple(types_so_far)
- if key in self.subtree_cache:
- return self.subtree_cache[key]
- non_empty = False
- typeorder = self.list_of_typeorders[len(types_so_far)]
- for next_type in typeorder:
- if self.build_single_method(typeorder, types_so_far, next_type,
- dispatch_node):
- non_empty = True
- self.subtree_cache[key] = non_empty
- return non_empty
-
- def build_single_method(self, typeorder, types_so_far, next_type,
- dispatch_node):
- funcname = '__'.join([self.prefix] + [t.__name__ for t in types_so_far])
-
- order = typeorder[next_type]
- #order = [(next_type, None)] + order
-
- things_to_call = []
- for type, conversion in order:
- if type not in dispatch_node:
- # there is no possible completion of types_so_far+[type]
- # that could lead to a registered function.
- continue
- match = dispatch_node[type]
- if isinstance(match, dict):
- if self.build_tree(types_so_far+[type], match):
- call = funcname + '__' + type.__name__
- call_selfarg_index = len(types_so_far) + 1
- things_to_call.append((conversion, call,
- call_selfarg_index))
- else:
- for func in match: # list of functions
- if func is not None:
- things_to_call.append((conversion, func, None))
-
- funcname = intern(funcname)
- self.build_function(next_type, funcname, len(types_so_far),
- things_to_call)
- return bool(things_to_call)
-
- def build_function(self, target, funcname, func_selfarg_index,
- things_to_call):
- # support for inventing names for the entries in things_to_call
- # which are real function objects instead of strings
- miniglobals = {'FailedToImplement': FailedToImplement, '__name__': __name__}
- def invent_name(obj):
- if isinstance(obj, str):
- return obj
- name = obj.__name__
- n = 1
- while name in miniglobals:
- n += 1
- name = '%s%d' % (obj.__name__, n)
- miniglobals[name] = obj
- return name
-
- funcargs = ['arg%d' % i for i in range(self.multimethod.arity)]
-
- bodylines = []
- for conversion, call, call_selfarg_index in things_to_call:
- callargs = funcargs[:]
- if conversion is not None:
- to_convert = func_selfarg_index
- convert_callargs = (self.multimethod.argnames_before +
- [callargs[to_convert]])
- callargs[to_convert] = '%s(%s)' % (
- invent_name(conversion), ', '.join(convert_callargs))
- callname = invent_name(call)
- if call_selfarg_index is not None:
- # fallback on root_class
- self.build_function(self.multimethod.root_class,
- callname, call_selfarg_index, [])
- callname = '%s.%s' % (callargs.pop(call_selfarg_index), callname)
- callargs = (self.multimethod.argnames_before +
- callargs + self.multimethod.argnames_after)
- bodylines.append('return %s(%s)' % (callname, ', '.join(callargs)))
-
- fallback = False
- if not bodylines:
- miniglobals['raiseFailedToImplement'] = raiseFailedToImplement
- bodylines = ['return raiseFailedToImplement()']
- fallback = True
- # NB. make sure that there is only one fallback function object,
- # i.e. the key used in the mmfunccache below is always the same
- # for all functions with the same name and an empty bodylines.
-
- # protect all lines apart from the last one by a try:except:
- for i in range(len(bodylines)-2, -1, -1):
- bodylines[i:i+1] = ['try:',
- ' ' + bodylines[i],
- 'except FailedToImplement:',
- ' pass']
-
- if func_selfarg_index is not None:
- selfargs = [funcargs.pop(func_selfarg_index)]
- else:
- selfargs = []
- funcargs = (selfargs + self.multimethod.argnames_before +
- funcargs + self.multimethod.argnames_after)
-
- if target is None and not self.baked_perform_call:
- return funcargs, bodylines[0][len('return '):], miniglobals, fallback
-
- # indent mode
- bodylines = [' ' + line for line in bodylines]
-
- bodylines.insert(0, 'def %s(%s):' % (funcname, ', '.join(funcargs)))
- bodylines.append('')
- source = '\n'.join(bodylines)
-
- # XXX find a better place (or way) to avoid duplicate functions
- l = miniglobals.items()
- l.sort()
- l = tuple(l)
- key = (source, l)
- try:
- func = self.mmfunccache[key]
- except KeyError:
- exec compile2(source) in miniglobals
- func = miniglobals[funcname]
- self.mmfunccache[key] = func
- #else:
- # print "avoided duplicate function", func
- self.to_install.append((target, funcname, func, source, fallback))
- return func
-
-# ____________________________________________________________
-# Installer version 2
-
-class MMDispatcher(object):
- """NOT_RPYTHON
- Explicit dispatcher class. The __call__ and dispatch() methods
- are only present for documentation purposes. The InstallerVersion2
- uses the expressions() method to precompute fast RPython-friendly
- dispatch tables.
- """
- _revcache = None
-
- def __init__(self, multimethod, list_of_typeorders):
- self.multimethod = multimethod
- self.list_of_typeorders = list_of_typeorders
-
- def __call__(self, *args):
- # for testing only: this is slow
- i = len(self.multimethod.argnames_before)
- j = i + self.multimethod.arity
- k = j + len(self.multimethod.argnames_after)
- assert len(args) == k
- prefixargs = args[:i]
- dispatchargs = args[i:j]
- suffixargs = args[j:]
- return self.dispatch([x.__class__ for x in dispatchargs],
- prefixargs,
- dispatchargs,
- suffixargs)
-
- def dispatch(self, argtypes, prefixargs, args, suffixargs):
- # for testing only: this is slow
- def expr(v):
- if isinstance(v, Call):
- return v.function(*[expr(w) for w in v.arguments])
- else:
- return v
- # XXX this is incomplete: for each type in argtypes but not
- # in the typeorder, we should look for the first base class
- # that is in the typeorder.
- e = None
- for v in self.expressions(argtypes, prefixargs, args, suffixargs):
- try:
- return expr(v)
- except FailedToImplement, e:
- pass
- else:
- raise e or FailedToImplement()
-
- def expressions(self, argtypes, prefixargs, args, suffixargs):
- """Lists the possible expressions that call the appropriate
- function for the given argument types. Each expression is a Call
- object. The intent is that at run-time the first Call that doesn't
- cause FailedToImplement to be raised is the good one.
- """
- prefixargs = tuple(prefixargs)
- suffixargs = tuple(suffixargs)
-
- def walktree(node, args_so_far):
- if isinstance(node, list):
- for func in node:
- if func is not None:
- result.append(Call(func, prefixargs +
- args_so_far +
- suffixargs))
- else:
- index = len(args_so_far)
- typeorder = self.list_of_typeorders[index]
- next_type = argtypes[index]
- for target_type, converter in typeorder[next_type]:
- if target_type not in node:
- continue
- next_arg = args[index]
- if converter:
- next_arg = Call(converter, prefixargs + (next_arg,))
- walktree(node[target_type], args_so_far + (next_arg,))
-
- result = []
- walktree(self.multimethod.dispatch_tree, ())
- return result
-
- def anychance(self, typesprefix):
- # is there any chance that a list of types starting with typesprefix
- # could lead to a successful dispatch?
- # (START-UP TIME OPTIMIZATION ONLY)
- if self._revcache is None:
-
- def build_tree(types_so_far, dispatch_node):
- non_empty = False
- typeorder = self.list_of_typeorders[len(types_so_far)]
- for next_type in typeorder:
- if build_single_method(typeorder, types_so_far, next_type,
- dispatch_node):
- non_empty = True
- if non_empty:
- self._revcache[types_so_far] = True
- return non_empty
-
- def build_single_method(typeorder, types_so_far, next_type,
- dispatch_node):
- order = typeorder[next_type]
- things_to_call = False
- for type, conversion in order:
- if type not in dispatch_node:
- # there is no possible completion of
- # types_so_far+[type] that could lead to a
- # registered function.
- continue
- match = dispatch_node[type]
- if isinstance(match, dict):
- if build_tree(types_so_far+(next_type,), match):
- things_to_call = True
- elif match:
- things_to_call = True
- return things_to_call
-
- self._revcache = {}
- build_tree((), self.multimethod.dispatch_tree)
- return tuple(typesprefix) in self._revcache
-
-
-class Call(object):
- """ Represents a call expression.
- The arguments may themselves be Call objects.
- """
- def __init__(self, function, arguments):
- self.function = function
- self.arguments = arguments
-
-
-class CompressedArray(object):
- def __init__(self, null_value):
- self.null_value = null_value
- self.items = [null_value]
-
- def ensure_length(self, newlen):
- if newlen > len(self.items):
- self.items.extend([self.null_value] * (newlen - len(self.items)))
-
- def insert_subarray(self, array):
- # insert the given array of numbers into the indexlist,
- # allowing null values to become non-null
- if array.count(self.null_value) == len(array):
- return 0
- test = 1
- while True:
- self.ensure_length(test+len(array))
- for i in xrange(len(array)):
- if not (array[i] == self.items[test+i] or
- array[i] == self.null_value or
- self.items[test+i] == self.null_value):
- break
- else:
- # success
- for i in range(len(array)):
- if array[i] != self.null_value:
- self.items[test+i] = array[i]
- return test
- test += 1
-
- def _freeze_(self):
- return True
-
-
-class MRDTable(object):
- # Multi-Method Dispatch Using Multiple Row Displacement,
- # Candy Pang, Wade Holst, Yuri Leontiev, and Duane Szafron
- # University of Alberta, Edmonton AB T6G 2H1 Canada
- # can be found on http://web.cs.ualberta.ca/~yuri/publ.htm
-
- Counter = 0
-
- def __init__(self, list_of_types):
- self.id = MRDTable.Counter
- MRDTable.Counter += 1
- self.list_of_types = list_of_types
- self.typenum = dict(zip(list_of_types, range(len(list_of_types))))
- self.attrname = '__mrd%d_typenum' % self.id
- for t1, num in self.typenum.items():
- setattr(t1, self.attrname, num)
- self.indexarray = CompressedArray(0)
-
- def get_typenum(self, cls):
- return self.typenum[cls]
-
- def is_anti_range(self, typenums):
- # NB. typenums should be sorted. Returns (a, b) if typenums contains
- # at least half of all typenums and its complement is range(a, b).
- # Returns (None, None) otherwise. Returns (0, 0) if typenums contains
- # everything.
- n = len(self.list_of_types)
- if len(typenums) <= n // 2:
- return (None, None)
- typenums = dict.fromkeys(typenums)
- complement = [typenum for typenum in range(n)
- if typenum not in typenums]
- if not complement:
- return (0, 0)
- a = min(complement)
- b = max(complement) + 1
- if complement == range(a, b):
- return (a, b)
- else:
- return (None, None)
-
- def normalize_length(self, next_array):
- # make sure that the indexarray is not smaller than any funcarray
- self.indexarray.ensure_length(len(next_array.items))
-
-
-def invent_name(miniglobals, obj):
- if isinstance(obj, str):
- return obj
- name = obj.__name__
- n = 1
- while name in miniglobals:
- n += 1
- name = '%s%d' % (obj.__name__, n)
- miniglobals[name] = obj
- return name
-
-
-class FuncEntry(object):
-
- def __init__(self, bodylines, miniglobals, fallback):
- self.body = '\n '.join(bodylines)
- self.miniglobals = miniglobals
- self.fallback = fallback
- self.possiblenames = []
- self.typetree = {}
- self._function = None
-
- def key(self):
- lst = self.miniglobals.items()
- lst.sort()
- return self.body, tuple(lst)
-
- def get_function_name(self):
- # pick a name consistently based on self.possiblenames
- length = min([len(parts) for parts in self.possiblenames])
- result = []
- for i in range(length):
- choices = {}
- for parts in self.possiblenames:
- choices[parts[i]] = True
- parts = choices.keys()
- res = str(len(parts))
- for part in parts:
- if type(part) is str: # there is a string at this pos
- if '0_fail' in choices:
- res = '0_fail'
- elif len(parts) == 1:
- res = part
- break
- else:
- # only types at this location, try to find a common base
- basecls = parts[0]
- for cls in parts[1:]:
- if issubclass(basecls, cls):
- basecls = cls
- for cls in parts[1:]:
- if not issubclass(cls, basecls):
- break # no common base
- else:
- res = basecls.__name__
- result.append(res)
- return '_'.join(result)
-
- def make_function(self, fnargs, nbargs_before, mrdtable):
- if self._function is not None:
- return self._function
- name = self.get_function_name()
- self.compress_typechecks(mrdtable)
- checklines = self.generate_typechecks(mrdtable, fnargs[nbargs_before:])
- if not checklines:
- body = self.body
- else:
- checklines.append(self.body)
- body = '\n '.join(checklines)
- source = 'def %s(%s):\n %s\n' % (name, ', '.join(fnargs), body)
- self.debug_dump(source)
- exec compile2(source) in self.miniglobals
- self._function = self.miniglobals[name]
- return self._function
-
- def debug_dump(self, source):
- if 0: # for debugging the generated mm sources
- name = self.get_function_name()
- f = open('/tmp/mm-source/%s' % name, 'a')
- for possiblename in self.possiblenames:
- print >> f, '#',
- for part in possiblename:
- print >> f, getattr(part, '__name__', part),
- print >> f
- print >> f
- print >> f, source
- f.close()
-
- def register_valid_types(self, types):
- node = self.typetree
- for t1 in types[:-1]:
- if node is True:
- return
- node = node.setdefault(t1, {})
- if node is True:
- return
- node[types[-1]] = True
-
- def no_typecheck(self):
- self.typetree = True
-
- def compress_typechecks(self, mrdtable):
- def full(node):
- if node is True:
- return 1
- fulls = 0
- for key, subnode in node.items():
- if full(subnode):
- node[key] = True
- fulls += 1
- if fulls == types_total:
- return 1
- return 0
-
- types_total = len(mrdtable.list_of_types)
- if full(self.typetree):
- self.typetree = True
-
- def generate_typechecks(self, mrdtable, args):
- attrname = mrdtable.attrname
- possibletypes = [{} for _ in args]
- any_type_is_ok = [False for _ in args]
-
- def generate(node, level=0):
- # this generates type-checking code like the following:
- #
- # _argtypenum = arg1.__typenum
- # if _argtypenum == 5:
- # ...
- # elif _argtypenum == 6 or _argtypenum == 8:
- # ...
- # else:
- # _failedtoimplement = True
- #
- # or, in the common particular case of an "anti-range", we optimize it to:
- #
- # _argtypenum = arg1.__typenum
- # if _argtypenum < 5 or _argtypenum >= 10:
- # ...
- # else:
- # _failedtoimplement = True
- #
- result = []
- indent = ' '*level
- if node is True:
- for i in range(level, len(args)):
- any_type_is_ok[i] = True
- result.append('%s_failedtoimplement = False' % (indent,))
- return result
- if not node:
- result.append('%s_failedtoimplement = True' % (indent,))
- return result
- result.append('%s_argtypenum = %s.%s' % (indent, args[level],
- attrname))
- cases = {}
- for key, subnode in node.items():
- possibletypes[level][key] = True
- casebody = tuple(generate(subnode, level+1))
- typenum = mrdtable.get_typenum(key)
- cases.setdefault(casebody, []).append(typenum)
- for casebody, typenums in cases.items():
- typenums.sort()
- cases = [(typenums, casebody)
- for (casebody, typenums) in cases.items()]
- cases.sort()
- if len(cases) == 1:
- typenums, casebody = cases[0]
- a, b = mrdtable.is_anti_range(typenums)
- else:
- a, b = None, None
- keyword = 'if'
- for typenums, casebody in cases:
- if a is not None:
- if b - a == 1:
- condition = '_argtypenum != %d' % a
- elif b == a:
- condition = 'True'
- else:
- condition = '_argtypenum < %d or _argtypenum >= %d' % (
- a, b)
- else:
- conditions = ['_argtypenum == %d' % typenum
- for typenum in typenums]
- condition = ' or '.join(conditions)
- result.append('%s%s %s:' % (indent, keyword, condition))
- result.extend(casebody)
- keyword = 'elif'
- result.append('%selse:' % (indent,))
- result.append('%s _failedtoimplement = True' % (indent,))
- return result
-
- result = []
- if self.typetree is not True:
- result.extend(generate(self.typetree))
- result.append('if _failedtoimplement:')
- result.append(' raise FailedToImplement')
- for level in range(len(args)):
- if not any_type_is_ok[level]:
- cls = commonbase(possibletypes[level].keys())
- clsname = invent_name(self.miniglobals, cls)
- result.append('assert isinstance(%s, %s)' % (args[level],
- clsname))
- return result
-
-
-def commonbase(classlist):
- def baseclasses(cls):
- result = set([cls])
- for base in cls.__bases__:
- if '_mixin_' not in base.__dict__:
- result |= baseclasses(base)
- return result
-
- bag = baseclasses(classlist[0])
- for cls in classlist[1:]:
- bag &= baseclasses(cls)
- _, candidate = max([(len(cls.__mro__), cls) for cls in bag])
- for cls in bag:
- assert issubclass(candidate, cls)
- return candidate
-
-
-class InstallerVersion2(object):
- """NOT_RPYTHON"""
-
- instance_counter = 0
- mrdtables = {}
-
- def __init__(self, multimethod, prefix, list_of_typeorders,
- baked_perform_call=True, base_typeorder=None):
- #print 'InstallerVersion2:', prefix
- self.__class__.instance_counter += 1
- self.multimethod = multimethod
- self.prefix = prefix
- self.list_of_typeorders = list_of_typeorders
- self.baked_perform_call = baked_perform_call
- self.mmfunccache = {}
- args = ['arg%d' % i for i in range(multimethod.arity)]
- self.fnargs = (multimethod.argnames_before + args +
- multimethod.argnames_after)
-
- # compute the complete table
- base_typeorder = base_typeorder or list_of_typeorders[0]
- for typeorder in list_of_typeorders:
- for t1 in typeorder:
- assert t1 in base_typeorder
-
- lst = list(base_typeorder)
- def clskey(cls):
- return cls.__mro__[::-1]
- lst.sort(lambda cls1, cls2: cmp(clskey(cls1), clskey(cls2)))
- key = tuple(lst)
- try:
- self.mrdtable = self.mrdtables[key]
- except KeyError:
- self.mrdtable = self.mrdtables[key] = MRDTable(key)
-
- dispatcher = MMDispatcher(multimethod, list_of_typeorders)
- self.table = {}
- def buildtable(prefixtypes):
- if len(prefixtypes) == multimethod.arity:
- calllist = dispatcher.expressions(prefixtypes,
- multimethod.argnames_before,
- args,
- multimethod.argnames_after)
- if calllist:
- self.table[prefixtypes] = calllist
- elif dispatcher.anychance(prefixtypes):
- typeorder = list_of_typeorders[len(prefixtypes)]
- for t1 in typeorder:
- buildtable(prefixtypes + (t1,))
- buildtable(())
- self.dispatcher = dispatcher
-
- def is_empty(self):
- return len(self.table) == 0
-
- def install(self):
- nskip = len(self.multimethod.argnames_before)
- null_entry = self.build_funcentry([self.prefix, '0_fail'], [])
- null_entry.no_typecheck()
- if self.is_empty():
- return self.answer(null_entry)
-
- entryarray = CompressedArray(null_entry)
- indexarray = self.mrdtable.indexarray
- lst = self.mrdtable.list_of_types
- indexline = []
-
- def compress(typesprefix, typesnum):
- if len(typesprefix) == self.multimethod.arity:
- calllist = self.table.get(typesprefix, [])
- funcname = [self.prefix]
- funcname.extend(typesprefix)
- entry = self.build_funcentry(funcname, calllist)
- entry.register_valid_types(typesprefix)
- return entry
- elif self.dispatcher.anychance(typesprefix):
- flatline = []
- for num1, t1 in enumerate(lst):
- item = compress(typesprefix + (t1,), typesnum + (num1,))
- flatline.append(item)
- if len(typesprefix) == self.multimethod.arity - 1:
- array = entryarray
- else:
- array = indexarray
- return array.insert_subarray(flatline)
- else:
- return 0
-
- master_index = compress((), ())
-
- null_func = null_entry.make_function(self.fnargs, nskip, self.mrdtable)
- funcarray = CompressedArray(null_func)
- # round up the length to a power of 2
- N = 1
- while N < len(entryarray.items):
- N *= 2
- funcarray.ensure_length(N)
- for i, entry in enumerate(entryarray.items):
- func = entry.make_function(self.fnargs, nskip, self.mrdtable)
- funcarray.items[i] = func
- self.mrdtable.normalize_length(funcarray)
-
- #print master_index
- #print indexarray.items
- #print funcarray.items
-
- attrname = self.mrdtable.attrname
- exprfn = "%d" % master_index
- for n in range(self.multimethod.arity-1):
- exprfn = "indexarray.items[%s + arg%d.%s]" % (exprfn, n, attrname)
- n = self.multimethod.arity-1
- exprfn = "funcarray.items[(%s + arg%d.%s) & mmmask]" % (exprfn, n,
- attrname)
- expr = Call(exprfn, self.fnargs)
- entry = self.build_funcentry([self.prefix, '0_perform_call'],
- [expr],
- indexarray = indexarray,
- funcarray = funcarray,
- mmmask = N-1)
- entry.no_typecheck()
- return self.answer(entry)
-
- def answer(self, entry):
- if self.baked_perform_call:
- nskip = len(self.multimethod.argnames_before)
- return entry.make_function(self.fnargs, nskip, self.mrdtable)
- else:
- assert entry.body.startswith('return ')
- expr = entry.body[len('return '):]
- entry.debug_dump(entry.body)
- return self.fnargs, expr, entry.miniglobals, entry.fallback
-
- def build_funcentry(self, funcnameparts, calllist, **extranames):
- def expr(v):
- if isinstance(v, Call):
- return '%s(%s)' % (invent_name(miniglobals, v.function),
- ', '.join([expr(w) for w in v.arguments]))
- else:
- return v
-
- fallback = len(calllist) == 0
- if fallback:
- miniglobals = {'raiseFailedToImplement': raiseFailedToImplement}
- bodylines = ['return raiseFailedToImplement()']
- else:
- miniglobals = {'FailedToImplement': FailedToImplement}
- miniglobals.update(extranames)
- bodylines = []
- for v in calllist[:-1]:
- bodylines.append('try:')
- bodylines.append(' return %s' % expr(v))
- bodylines.append('except FailedToImplement:')
- bodylines.append(' pass')
- bodylines.append('return %s' % expr(calllist[-1]))
-
- miniglobals['__name__'] = __name__
- entry = FuncEntry(bodylines, miniglobals, fallback)
- key = entry.key()
-
- try:
- entry = self.mmfunccache[key]
- except KeyError:
- self.mmfunccache[key] = entry
- entry.possiblenames.append(funcnameparts)
- return entry
-
-# ____________________________________________________________
-# Selection of the version to use
-
-Installer = InstallerVersion1 # modified by translate.py targetpypystandalone
diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py
--- a/pypy/objspace/std/objspace.py
+++ b/pypy/objspace/std/objspace.py
@@ -52,8 +52,6 @@
self.UnicodeObjectCls = W_UnicodeObject
- self._install_multimethods()
-
# singletons
self.w_None = W_NoneObject.w_None
self.w_False = W_BoolObject.w_False
@@ -87,39 +85,6 @@
def get_builtin_types(self):
return self.builtin_types
- def _install_multimethods(self):
- """Install all the MultiMethods into the space instance."""
- for name, mm in model.MM.__dict__.items():
- if not isinstance(mm, model.StdObjSpaceMultiMethod):
- continue
- if not hasattr(self, name):
- # int_w, str_w...: these do not return a wrapped object
- if name.endswith('_w'):
- func = mm.install_not_sliced(self.model.typeorder,
- baked_perform_call=True)
- else:
- unsliced = mm.install_not_sliced(self.model.typeorder,
- baked_perform_call=False)
- exprargs, expr, miniglobals, fallback = unsliced
- func = stdtypedef.make_perform_trampoline('__mm_'+name,
- exprargs, expr,
- miniglobals, mm)
-
- boundmethod = types.MethodType(func, self, self.__class__)
- setattr(self, name, boundmethod) # store into 'space' instance
- elif self.config.objspace.std.builtinshortcut:
- if name.startswith('inplace_'):
- fallback_name = name[len('inplace_'):]
- if fallback_name in ('or', 'and'):
- fallback_name += '_'
- fallback_mm = model.MM.__dict__[fallback_name]
- else:
- fallback_mm = None
- builtinshortcut.install(self, mm, fallback_mm)
- if self.config.objspace.std.builtinshortcut:
- builtinshortcut.install_is_true(self, model.MM.nonzero,
- model.MM.len)
-
def createexecutioncontext(self):
# add space specific fields to execution context
# note that this method must not call space methods that might need an
diff --git a/pypy/objspace/std/stdtypedef.py b/pypy/objspace/std/stdtypedef.py
--- a/pypy/objspace/std/stdtypedef.py
+++ b/pypy/objspace/std/stdtypedef.py
@@ -1,14 +1,9 @@
-from pypy.interpreter import gateway, baseobjspace, argument
-from pypy.interpreter.error import OperationError, oefmt
+from pypy.interpreter import baseobjspace
from pypy.interpreter.typedef import TypeDef, GetSetProperty, Member
from pypy.interpreter.typedef import descr_get_dict, descr_set_dict
from pypy.interpreter.typedef import descr_del_dict
from pypy.interpreter.baseobjspace import SpaceCache
-from pypy.objspace.std import model
-from pypy.objspace.std.model import StdObjSpaceMultiMethod
-from pypy.objspace.std.multimethod import FailedToImplement
from rpython.rlib import jit
-from rpython.tool.sourcetools import compile2
__all__ = ['StdTypeDef']
@@ -19,11 +14,6 @@
"NOT_RPYTHON: initialization-time only."
TypeDef.__init__(self, __name, __base, **rawdict)
self.any = type("W_Any"+__name.title(), (baseobjspace.W_Root,), {'typedef': self})
- self.local_multimethods = []
-
- def registermethods(self, namespace):
- "NOT_RPYTHON: initialization-time only."
- self.local_multimethods += hack_out_multimethods(namespace)
@jit.unroll_safe
def issubtypedef(a, b):
@@ -61,17 +51,6 @@
rawdict = typedef.rawdict
lazyloaders = {}
- if isinstance(typedef, StdTypeDef):
- # get all the sliced multimethods
- multimethods = slicemultimethods(space, typedef)
- for name, loader in multimethods.items():
- if name in rawdict:
- # the name specified in the rawdict has priority
- continue
- assert name not in lazyloaders, (
- 'name clash: %s in %s.lazyloaders' % (name, typedef.name))
- lazyloaders[name] = loader
-
# compute the bases
if typedef is W_ObjectObject.typedef:
bases_w = []
@@ -97,190 +76,3 @@
def ready(self, w_type):
w_type.ready()
-
-def hack_out_multimethods(ns):
- "NOT_RPYTHON: initialization-time only."
- result = []
- seen = {}
- for value in ns.itervalues():
- if isinstance(value, StdObjSpaceMultiMethod):
- if value.name in seen:
- raise Exception("duplicate multimethod name %r" %
- (value.name,))
- seen[value.name] = True
- result.append(value)
- return result
-
-def is_relevant_for_slice(target_type, typedef):
- targettypedef = getattr(target_type, 'typedef', None)
- if targettypedef == typedef:
- return True
- method = getattr(target_type, "is_implementation_for", lambda t: False)
- return method(typedef)
-
-def sliced_typeorders(typeorder, multimethod, typedef, i, local=False):
- """NOT_RPYTHON"""
- list_of_typeorders = [typeorder] * multimethod.arity
- prefix = '_mm_' + multimethod.name
- if not local:
- # slice
- sliced_typeorder = {}
- for type, order in typeorder.items():
- thistypedef = getattr(type, 'typedef', None)
- if issubtypedef(thistypedef, typedef):
- lst = []
- for target_type, conversion in order:
- if is_relevant_for_slice(target_type, typedef):
- lst.append((target_type, conversion))
- sliced_typeorder[type] = lst
- list_of_typeorders[i] = sliced_typeorder
- prefix += '_%sS%d' % (typedef.name, i)
- else:
- prefix = typedef.name +'_mth'+prefix
- return prefix, list_of_typeorders
-
-def _gettypeerrormsg(nbargs):
- if nbargs > 1:
- plural = 's'
- else:
- plural = ''
- return "unsupported operand type%s for %%s: %s" % (
- plural, ', '.join(["'%T'"] * nbargs))
-_gettypeerrormsg._annspecialcase_ = 'specialize:memo'
-
-def gettypeerror(space, operatorsymbol, *args_w):
- return oefmt(space.w_TypeError, _gettypeerrormsg(len(args_w)),
- operatorsymbol, *args_w)
-
-def make_perform_trampoline(prefix, exprargs, expr, miniglobals, multimethod, selfindex=0,
- allow_NotImplemented_results=False):
- """NOT_RPYTHON"""
- # mess to figure out how to put a gateway around executing expr
- argnames = ['_%d'%(i+1) for i in range(multimethod.arity)]
- explicit_argnames = multimethod.extras.get('argnames', [])
- argnames[len(argnames)-len(explicit_argnames):] = explicit_argnames
- solid_arglist = ['w_'+name for name in argnames]
- wrapper_arglist = solid_arglist[:]
- if multimethod.extras.get('varargs_w', False):
- wrapper_arglist.append('args_w')
- if multimethod.extras.get('keywords', False):
- raise Exception, "no longer supported, use __args__"
- if multimethod.extras.get('general__args__', False):
- wrapper_arglist.append('__args__')
- wrapper_arglist += multimethod.extras.get('extra_args', ())
-
- miniglobals.update({ 'OperationError': OperationError,
- 'gettypeerror': gettypeerror})
-
- app_defaults = multimethod.extras.get('defaults', ())
- i = len(argnames) - len(app_defaults)
- wrapper_signature = wrapper_arglist[:]
- unwrap_spec_kwds = {}
- for app_default in app_defaults:
- name = wrapper_signature[i]
- unwrap_spec_kwds[name] = gateway.WrappedDefault(app_default)
- i += 1
-
- wrapper_signature.insert(0, wrapper_signature.pop(selfindex))
- wrapper_sig = ', '.join(wrapper_signature)
-
- src = []
- dest = []
- for wrapper_arg,expr_arg in zip(['space']+wrapper_arglist, exprargs):
- if wrapper_arg != expr_arg:
- src.append(wrapper_arg)
- dest.append(expr_arg)
- renaming = ', '.join(dest) +" = "+', '.join(src)
-
- if allow_NotImplemented_results and (len(multimethod.specialnames) > 1 or
- multimethod.name.startswith('inplace_')):
- # turn FailedToImplement into NotImplemented
- code = """def %s_perform_call(space, %s):
- %s
- try:
- return %s
- except FailedToImplement, e:
- if e.get_w_type(space) is not None:
- raise OperationError(e.w_type, e.get_w_value(space))
- else:
- return space.w_NotImplemented
-""" % (prefix, wrapper_sig, renaming, expr)
- else:
- # turn FailedToImplement into nice TypeErrors
- code = """def %s_perform_call(space, %s):
- %s
- try:
- w_res = %s
- except FailedToImplement, e:
- if e.get_w_type(space) is not None:
- raise OperationError(e.w_type, e.get_w_value(space))
- else:
- raise gettypeerror(space, %r, %s)
- if w_res is None:
- w_res = space.w_None
- return w_res
-""" % (prefix, wrapper_sig, renaming, expr,
- multimethod.operatorsymbol, ', '.join(solid_arglist))
- exec compile2(code, '', 'exec') in miniglobals
- func = miniglobals["%s_perform_call" % prefix]
- if unwrap_spec_kwds:
- func = gateway.unwrap_spec(**unwrap_spec_kwds)(func)
- return func
-
-def wrap_trampoline_in_gateway(func, methname, multimethod):
- """NOT_RPYTHON"""
- if 'doc' in multimethod.extras:
- func.__doc__ = multimethod.extras['doc']
- return gateway.interp2app(func, app_name=methname)
-
-def slicemultimethod(space, multimethod, typedef, result, local=False):
- """NOT_RPYTHON"""
- for i in range(len(multimethod.specialnames)):
- methname = multimethod.specialnames[i]
- if methname in result:
- # conflict between e.g. __lt__ and
- # __lt__-as-reversed-version-of-__gt__
- loader = result[methname]
- if loader.bound_position < i:
- continue
-
- def multimethod_loader(i=i, methname=methname):
- """NOT_RPYTHON"""
- prefix, list_of_typeorders = sliced_typeorders(
- space.model.typeorder, multimethod, typedef, i, local=local)
- exprargs, expr, miniglobals, fallback = multimethod.install(prefix, list_of_typeorders,
- baked_perform_call=False,
- base_typeorder=space.model.typeorder)
- if fallback:
- return None # skip empty multimethods
- trampoline = make_perform_trampoline(prefix, exprargs, expr, miniglobals,
- multimethod, i,
- allow_NotImplemented_results=True)
- gw = wrap_trampoline_in_gateway(trampoline, methname, multimethod)
- return space.wrap(gw)
-
- multimethod_loader.bound_position = i # for the check above
- result[methname] = multimethod_loader
-
-def slicemultimethods(space, typedef):
- """NOT_RPYTHON"""
- result = {}
- # import and slice all multimethods of the MM container
- for multimethod in hack_out_multimethods(model.MM.__dict__):
- slicemultimethod(space, multimethod, typedef, result)
- # import all multimethods defined directly on the type without slicing
- for multimethod in typedef.local_multimethods:
- slicemultimethod(space, multimethod, typedef, result, local=True)
- return result
-
-def multimethods_defined_on(cls):
- """NOT_RPYTHON: enumerate the (multimethod, local_flag) for all the
- multimethods that have an implementation whose first typed argument
- is 'cls'.
- """
- typedef = cls.typedef
- for multimethod in hack_out_multimethods(model.MM.__dict__):
- if cls in multimethod.dispatch_tree:
- yield multimethod, False
- for multimethod in typedef.local_multimethods:
- yield multimethod, True
diff --git a/pypy/objspace/std/test/test_annmm.py b/pypy/objspace/std/test/test_annmm.py
deleted file mode 100644
--- a/pypy/objspace/std/test/test_annmm.py
+++ /dev/null
@@ -1,56 +0,0 @@
-from pypy.objspace.std.multimethod import *
-from rpython.annotator.annrpython import RPythonAnnotator
-
-class W_Root(object):
- pass
-
-class W_Int(W_Root):
- pass
-
-class W_Str(W_Root):
- pass
-
-
-str_w = MultiMethodTable(1, root_class=W_Root, argnames_before=['space'])
-int_w = MultiMethodTable(1, root_class=W_Root, argnames_before=['space'])
-
-
-def int_w__Int(space, w_x):
- assert space == 'space'
- assert isinstance(w_x, W_Int)
- return 1
-
-def str_w__Str(space, w_x):
- assert space == 'space'
- assert isinstance(w_x, W_Str)
- return "string"
-
-int_w.register(int_w__Int, W_Int)
-str_w.register(str_w__Str, W_Str)
-
-
-def setup_module(mod):
- typeorder = {
- W_Int: [(W_Int, None)],
- W_Str: [(W_Str, None)],
- }
- mod.typeorder = typeorder
- mod.str_w1 = str_w.install('__str_w', [typeorder])
- mod.int_w1 = int_w.install('__int_w', [typeorder])
-
-
-def test_str_w_ann():
- a = RPythonAnnotator()
- s1 = a.build_types(str_w1,[str, W_Str])
- s2 = a.build_types(str_w1,[str, W_Root])
- assert s1.knowntype == str
- assert s2.knowntype == str
-
-def test_int_w_ann():
- a = RPythonAnnotator()
- s1 = a.build_types(int_w1,[str, W_Int])
- s2 = a.build_types(int_w1,[str, W_Str])
- assert s1.knowntype == int
- assert s2.knowntype == int
-
-
diff --git a/pypy/objspace/std/test/test_builtinshortcut.py b/pypy/objspace/std/test/test_builtinshortcut.py
--- a/pypy/objspace/std/test/test_builtinshortcut.py
+++ b/pypy/objspace/std/test/test_builtinshortcut.py
@@ -7,9 +7,6 @@
class AppTestUserObject(test_userobject.AppTestUserObject):
spaceconfig = WITH_BUILTINSHORTCUT
-class AppTestWithMultiMethodVersion2(test_userobject.AppTestWithMultiMethodVersion2):
- spaceconfig = WITH_BUILTINSHORTCUT
-
class AppTestBug:
spaceconfig = WITH_BUILTINSHORTCUT
diff --git a/pypy/objspace/std/test/test_complexobject.py b/pypy/objspace/std/test/test_complexobject.py
--- a/pypy/objspace/std/test/test_complexobject.py
+++ b/pypy/objspace/std/test/test_complexobject.py
@@ -1,6 +1,5 @@
import py
from pypy.objspace.std.complexobject import W_ComplexObject, _split_complex
-from pypy.objspace.std.multimethod import FailedToImplement
from pypy.objspace.std import StdObjSpace
EPS = 1e-9
diff --git a/pypy/objspace/std/test/test_intobject.py b/pypy/objspace/std/test/test_intobject.py
--- a/pypy/objspace/std/test/test_intobject.py
+++ b/pypy/objspace/std/test/test_intobject.py
@@ -2,7 +2,6 @@
import py
import sys
from pypy.objspace.std import intobject as iobj
-from pypy.objspace.std.multimethod import FailedToImplement
from rpython.rlib.rarithmetic import r_uint, is_valid_int
from rpython.rlib.rbigint import rbigint
diff --git a/pypy/objspace/std/test/test_multimethod.py b/pypy/objspace/std/test/test_multimethod.py
deleted file mode 100644
--- a/pypy/objspace/std/test/test_multimethod.py
+++ /dev/null
@@ -1,264 +0,0 @@
-from py.test import raises
-
-from pypy.objspace.std import multimethod
-from pypy.objspace.std.multimethod import FailedToImplement
-from pypy.objspace.std.multimethod import FailedToImplementArgs
-
-
-class W_Root(object):
- pass
-
-class W_IntObject(W_Root):
- pass
-
-class W_BoolObject(W_Root):
- pass
-
-class W_StringObject(W_Root):
- pass
-
-def delegate_b2i(space, w_x):
- assert isinstance(w_x, W_BoolObject)
- return W_IntObject()
-
-def add__Int_Int(space, w_x, w_y):
- assert space == 'space'
- assert isinstance(w_x, W_IntObject)
- assert isinstance(w_y, W_IntObject)
- return 'fine'
-
-
-def test_failedtoimplement():
- f = FailedToImplement()
- assert f.get_w_type("space") is None
- assert f.get_w_value("space") is None
- f = FailedToImplementArgs("ab", "cd")
- assert f.get_w_type("space") == "ab"
- assert f.get_w_value("space") == "cd"
- # for testing it's good to get the following behavior:
- raises(AssertionError, FailedToImplement, "ab", "cd")
- # but the class FailedToImplement should have no __init__ for translation:
- assert '__init__' not in FailedToImplement.__dict__
-
-
-class TestMultiMethod1:
- Installer = multimethod.InstallerVersion1
-
- def setup_class(cls):
- cls.prev_installer = multimethod.Installer
- multimethod.Installer = cls.Installer
- add = multimethod.MultiMethodTable(2, root_class=W_Root,
- argnames_before=['space'])
- add.register(add__Int_Int, W_IntObject, W_IntObject)
- typeorder = {
- W_IntObject: [(W_IntObject, None), (W_Root, None)],
- W_BoolObject: [(W_BoolObject, None), (W_IntObject, delegate_b2i),
- (W_Root, None)],
- W_StringObject: [(W_StringObject, None), (W_Root, None)],
- }
- cls.typeorder = typeorder
- cls.add = add
- cls.add1 = staticmethod(add.install('__add', [typeorder, typeorder]))
-
- def teardown_class(cls):
- multimethod.Installer = cls.prev_installer
-
- def test_simple(self):
- space = 'space'
- w_x = W_IntObject()
- w_y = W_IntObject()
- assert self.add1(space, w_x, w_y) == 'fine'
-
- def test_failtoimplement(self):
- space = 'space'
- w_x = W_IntObject()
- w_s = W_StringObject()
- raises(FailedToImplement, "self.add1(space, w_x, w_s)")
- raises(FailedToImplement, "self.add1(space, w_s, w_x)")
-
- def test_delegate(self):
- space = 'space'
- w_x = W_IntObject()
- w_s = W_StringObject()
- w_b = W_BoolObject()
- assert self.add1(space, w_x, w_b) == 'fine'
- assert self.add1(space, w_b, w_x) == 'fine'
- assert self.add1(space, w_b, w_b) == 'fine'
- raises(FailedToImplement, "self.add1(space, w_b, w_s)")
- raises(FailedToImplement, "self.add1(space, w_s, w_b)")
-
- def test_not_baked(self):
- typeorder = self.typeorder
- add2 = self.add.install('__add2', [typeorder, typeorder],
- baked_perform_call=False)
- assert add2[0] == ['space', 'arg0', 'arg1']
- if multimethod.Installer is multimethod.InstallerVersion1:
- assert add2[1] == 'arg0.__add2(space, arg1)'
- assert isinstance(add2[2], dict)
- assert not add2[3]
-
- def test_empty(self):
- add3_installer = multimethod.Installer(self.add, '__add3', [{},{}])
- assert add3_installer.is_empty()
- if multimethod.Installer is multimethod.InstallerVersion1:
- assert len(add3_installer.to_install) == 1
- assert add3_installer.to_install[0][0] is None
-
- def test_empty_direct(self):
- assert not self.add.install_if_not_empty('__add4', [{},{}])
-
- def test_empty_not_baked(self):
- add5_installer = multimethod.Installer(self.add, '__add5', [{},{}],
- baked_perform_call=False)
- assert add5_installer.is_empty()
- if multimethod.Installer is multimethod.InstallerVersion1:
- assert len(add5_installer.to_install) == 0
- add5 = add5_installer.install()
- assert add5[0] == ['space', 'arg0', 'arg1']
- assert add5[1] == 'raiseFailedToImplement()'
- assert isinstance(add5[2], dict)
- assert add5[3]
-
- def test_mmdispatcher(self):
- typeorder = self.typeorder
- add2 = multimethod.MMDispatcher(self.add, [typeorder, typeorder])
- space = 'space'
- w_x = W_IntObject()
- w_s = W_StringObject()
- w_b1 = W_BoolObject()
- w_b2 = W_BoolObject()
- assert add2(space, w_x, w_b1) == 'fine'
- assert add2(space, w_b2, w_x) == 'fine'
- assert add2(space, w_b1, w_b2) == 'fine'
- raises(FailedToImplement, "add2(space, w_b2, w_s)")
- raises(FailedToImplement, "add2(space, w_s, w_b1)")
-
- def test_forbidden_subclasses(self):
- mul = multimethod.MultiMethodTable(2, root_class=W_Root,
- argnames_before=['space'])
- class UserW_StringObject(W_StringObject):
- pass
- def mul__Int_String(space, w_x, w_y):
- assert space == 'space'
- assert isinstance(w_x, W_IntObject)
- assert isinstance(w_y, W_StringObject)
- return 'fine'
- mul.register(mul__Int_String, W_IntObject, W_StringObject)
-
- mul1 = mul.install('__mul1', [self.typeorder, self.typeorder])
- assert mul1('space', W_IntObject(), W_StringObject()) == 'fine'
- assert mul1('space', W_IntObject(), UserW_StringObject()) == 'fine'
-
- ext_typeorder = self.typeorder.copy()
- ext_typeorder[UserW_StringObject] = []
- mul2 = mul.install('__mul2', [ext_typeorder, ext_typeorder])
- assert mul2('space', W_IntObject(), W_StringObject()) == 'fine'
- raises(FailedToImplement,
- mul2, 'baz', W_IntObject(), UserW_StringObject())
-
- def test_more_forbidden_subclasses(self):
- mul = multimethod.MultiMethodTable(2, root_class=W_Root,
- argnames_before=['space'])
- class UserW_StringObject(W_StringObject):
- pass
- def mul__String_String(space, w_x, w_y):
- assert space == 'space'
- assert isinstance(w_x, W_StringObject)
- assert isinstance(w_y, W_StringObject)
- return 'fine'
- mul.register(mul__String_String, W_StringObject, W_StringObject)
-
- ext_typeorder = {W_StringObject: [(W_StringObject, None)],
- UserW_StringObject: []}
- mul2 = mul.install('__mul2', [ext_typeorder, ext_typeorder])
- assert mul2('space', W_StringObject(), W_StringObject()) == 'fine'
- raises(FailedToImplement,
- mul2, 'baz', W_StringObject(), UserW_StringObject())
- raises(FailedToImplement,
- mul2, 'baz', UserW_StringObject(), W_StringObject())
- raises(FailedToImplement,
- mul2, 'baz', UserW_StringObject(), UserW_StringObject())
-
- def test_ANY(self):
- setattr = multimethod.MultiMethodTable(3, root_class=W_Root,
- argnames_before=['space'])
- def setattr__Int_ANY_ANY(space, w_x, w_y, w_z):
- assert space == 'space'
- assert isinstance(w_x, W_IntObject)
- assert isinstance(w_y, W_Root)
- assert isinstance(w_z, W_Root)
- return w_y.__class__.__name__ + w_z.__class__.__name__
- setattr.register(setattr__Int_ANY_ANY, W_IntObject, W_Root, W_Root)
- setattr1 = setattr.install('__setattr1', [self.typeorder]*3)
- for cls1 in self.typeorder:
- for cls2 in self.typeorder:
- assert setattr1('space', W_IntObject(), cls1(), cls2()) == (
- cls1.__name__ + cls2.__name__)
-
- def test_all_cases(self):
- import random
- space = 'space'
- w_x = W_IntObject()
- w_x.expected = [W_IntObject, W_Root]
- w_s = W_StringObject()
- w_s.expected = [W_StringObject, W_Root]
- w_b = W_BoolObject()
- w_b.expected = [W_BoolObject, W_IntObject, W_Root]
-
- def test(indices):
- sub = multimethod.MultiMethodTable(2, root_class=W_Root,
- argnames_before=['space'])
- def addimpl(cls1, cls2):
- token = random.random()
- def sub__cls1_cls2(space, w_x, w_y):
- assert space == 'space'
- assert isinstance(w_x, cls1)
- assert isinstance(w_y, cls2)
- return token
- sub.register(sub__cls1_cls2, cls1, cls2)
- return token
-
- def check(w1, w2):
- try:
- res = sub1(space, w1, w2)
- except FailedToImplement:
- res = FailedToImplement
- for cls1 in w1.expected:
- for cls2 in w2.expected:
- if (cls1, cls2) in expected:
- assert res == expected[cls1, cls2]
- return
- else:
- assert res is FailedToImplement
-
- random.shuffle(indices)
- expected = {}
- for index in indices:
- cls1, cls2 = choices[index]
- token = addimpl(cls1, cls2)
- expected[cls1, cls2] = token
-
- typeorder = self.typeorder
- sub1 = sub.install('__sub', [typeorder, typeorder])
- for w1 in [w_x, w_s, w_b]:
- for w2 in [w_x, w_s, w_b]:
- check(w1, w2)
-
- classes = [W_Root, W_StringObject, W_IntObject, W_BoolObject]
- choices = [(cls1, cls2) for cls1 in classes
- for cls2 in classes]
- # each choice is a pair of classes which can be implemented or
- # not by the multimethod 'sub'. Test all combinations that
- # involve at most three implemented choices.
- for i in range(len(choices)):
- test([i])
- for j in range(i+1, len(choices)):
- test([i, j])
- for k in range(j+1, len(choices)):
- test([i, j, k])
- #for l in range(k+1, len(choices)): -- for a 4th choice
- # test([i, j, k, l]) -- (takes a while)
-
-
-class TestMultiMethod2(TestMultiMethod1):
- Installer = multimethod.InstallerVersion2
diff --git a/pypy/objspace/std/test/test_userobject.py b/pypy/objspace/std/test/test_userobject.py
--- a/pypy/objspace/std/test/test_userobject.py
+++ b/pypy/objspace/std/test/test_userobject.py
@@ -273,22 +273,6 @@
i += 1
-class AppTestWithMultiMethodVersion2(AppTestUserObject):
- spaceconfig = {}
-
- def setup_class(cls):
- from pypy.objspace.std import multimethod
-
- cls.prev_installer = multimethod.Installer
- multimethod.Installer = multimethod.InstallerVersion2
- if cls.runappdirect:
- py.test.skip("Cannot run different installers when runappdirect")
-
- def teardown_class(cls):
- from pypy.objspace.std import multimethod
- multimethod.Installer = cls.prev_installer
-
-
class AppTestWithGetAttributeShortcut(AppTestUserObject):
spaceconfig = {"objspace.std.getattributeshortcut": True}
More information about the pypy-commit
mailing list