PKK\8I$$dispatch/ast_builder.pyfrom token import tok_name, NAME, NUMBER, STRING, ISNONTERMINAL from symbol import sym_name from new import instancemethod import token, symbol, parser, sys __all__ = [ 'parse_expr', 'build' ] _name = lambda builder,nodelist: builder.Name(nodelist[1]) _const = lambda builder,nodelist: builder.Const(eval(nodelist[1])) production = { NAME: _name, NUMBER: _const, STRING: _const, } ops = { token.LEFTSHIFT: 'LeftShift', token.RIGHTSHIFT: 'RightShift', token.PLUS: 'Add', token.MINUS: 'Sub', token.STAR: 'Mul', token.SLASH: 'Div', token.PERCENT: 'Mod', token.DOUBLESLASH: 'FloorDiv', } def left_assoc(builder, nodelist): return getattr(builder,ops[nodelist[-2][0]])(nodelist[:-2],nodelist[-1]) def curry(f,*args): for arg in args: f = instancemethod(f,arg,type(arg)) return f def com_binary(opname, builder,nodelist): "Compile 'NODE (OP NODE)*' into (type, [ node1, ..., nodeN ])." items = [nodelist[i] for i in range(1,len(nodelist),2)] return getattr(builder,opname)(items) # testlist: test (',' test)* [','] # subscriptlist: subscript (',' subscript)* [','] testlist = subscriptlist = curry(com_binary, 'Tuple') # testlist_gexp test (gen_for | (',' test)* [',']) testlist_gexp = testlist # XXX # test: and_test ('or' and_test)* | lambdef test = curry(com_binary, 'Or') if sys.version>='2.5': or_test = test # test: or_test ['if' or_test 'else' test] | lambdef def test(builder, nodelist): return builder.IfElse(nodelist[1], nodelist[3], nodelist[5]) # and_test: not_test ('and' not_test)* and_test = curry(com_binary, 'And') # not_test: 'not' not_test | comparison def not_test(builder, nodelist): return builder.Not(nodelist[2]) # comparison: expr (comp_op expr)* def comparison(builder, nodelist): if len(nodelist)>4 and builder.simplify_comparisons: # Reduce (x < y < z ...) to (x' | '>=' | '<=' | '<>' | '!=' | '==' # | 'in' | 'not' 'in' | 'is' | 'is' 'not' n = nl[1] if n[0] == token.NAME: type = n[1] if len(nl) == 3: if type == 'not': type = 'not in' else: type = 'is not' else: type = n[1] results.append((type, nodelist[i])) return builder.Compare(nodelist[1], results) # expr: xor_expr ('|' xor_expr)* expr = curry(com_binary, 'Bitor') # xor_expr: and_expr ('^' and_expr)* xor_expr = curry(com_binary, 'Bitxor') # and_expr: shift_expr ('&' shift_expr)* and_expr = curry(com_binary, 'Bitand') # shift_expr: arith_expr ('<<'|'>>' arith_expr)* # arith_expr: term (('+'|'-') term)* # term: factor (('*'|'/'|'%'|'//') factor)* shift_expr = arith_expr = term = left_assoc unary_ops = { token.PLUS: 'UnaryPlus', token.MINUS: 'UnaryMinus', token.TILDE: 'Invert', } # factor: ('+'|'-'|'~') factor | power def factor(builder, nodelist): return getattr(builder,unary_ops[nodelist[1][0]])(nodelist[2]) # power: atom trailer* ['**' factor] def power(builder, nodelist): if nodelist[-2][0]==token.DOUBLESTAR: return builder.Power(nodelist[:-2], nodelist[-1]) node = nodelist[-1] nodelist = nodelist[:-1] t = node[1][0] # trailer: '(' [arglist] ')' | '[' subscriptlist ']' | '.' NAME if t == token.LPAR: return com_call_function(builder,nodelist,node[2]) elif t == token.DOT: return builder.Getattr(nodelist, node[2][1]) elif t == token.LSQB: item = node[2] while len(item)==2: item = item[1] if item[0]==token.COLON: lineno = item[2] return builder.Subscript(nodelist, (symbol.subscript, (token.STRING,`0`,lineno), item, (token.STRING,`sys.maxint`,lineno) ) ) return builder.Subscript(nodelist, item) raise AssertionError("Unknown power", nodelist) # atom: '(' [testlist_gexp] ')' | # '[' [listmaker] ']' | # '{' [dictmaker] '}' | # '`' testlist1 '`' | # NAME | NUMBER | STRING+ def atom(builder, nodelist): t = nodelist[1][0] if t == token.LPAR: if nodelist[2][0] == token.RPAR: return builder.Tuple(()) return build(builder,nodelist[2]) elif t==token.LSQB: if nodelist[2][0] == token.RSQB: return builder.List(()) return listmaker(builder,nodelist[2]) elif t==token.LBRACE: if nodelist[2][0] == token.RBRACE: items = () else: dm = nodelist[2] items = [(dm[i],dm[i+2]) for i in range(1,len(dm),4)] return builder.Dict(items) elif t==token.BACKQUOTE: return builder.Backquote(nodelist[2]) elif t==token.STRING: return builder.Const(eval(' '.join([n[1] for n in nodelist[1:]]))) raise AssertionError("Unknown atom", nodelist) # arglist: (argument ',')* (argument [',']| '*' test [',' '**' test] | '**' test) def com_call_function(builder, primaryNode, nodelist): if nodelist[0] == token.RPAR: return builder.CallFunc(primaryNode,(),(),None,None) args = []; kw = [] len_nodelist = len(nodelist) for i in range(1, len_nodelist, 2): node = nodelist[i] if node[0] == token.STAR or node[0] == token.DOUBLESTAR: break iskw, result = com_argument(node, kw) if iskw: kw.append(result) else: args.append(result) else: # No broken by star arg, so skip the last one we processed. i = i + 1 if i < len_nodelist and nodelist[i][0] == token.COMMA: # need to accept an application that looks like "f(a, b,)" i = i + 1 star_node = dstar_node = None while i < len_nodelist: tok = nodelist[i] ch = nodelist[i+1] i = i + 3 if tok[0]==token.STAR: star_node = ch elif tok[0]==token.DOUBLESTAR: dstar_node = ch else: raise AssertionError, 'unknown node type: %s' % (tok,) return builder.CallFunc(primaryNode, args, kw, star_node, dstar_node) # argument: [test '='] test [gen_for] (Really [keyword '='] test) def com_argument(nodelist, kw): # XXX Python 2.4 needs genexp handling here if len(nodelist) == 2: if kw: raise SyntaxError, "non-keyword arg after keyword arg" return 0, nodelist[1] n = nodelist[1] while len(n) == 2 and n[0] != token.NAME: n = n[1] if n[0] != token.NAME: raise SyntaxError, "keyword can't be an expression (%r)" % (n,) return 1, ((token.STRING,`n[1]`,n[2]), nodelist[3]) # listmaker: test ( list_for | (',' test)* [','] ) def listmaker(builder, nodelist): values = [] for i in range(1, len(nodelist)): #if nodelist[i][0] == symbol.list_for: # assert len(nodelist[i:]) == 1 # return com_list_comprehension(builder,values[0],nodelist[i]) if nodelist[i][0] == token.COMMA: continue values.append(nodelist[i]) return builder.List(values) # subscript: '.' '.' '.' | test | [test] ':' [test] [sliceop] # sliceop: ':' [test] def subscript(builder, nodelist): if nodelist[1][0]==token.DOT: return builder.Const(Ellipsis) item = nodelist; nl = len(nodelist) while type(item[1]) is tuple: item=item[1] # find token, to get a line# lineno = item[-1] have_stride = nodelist[-1][0]==symbol.sliceop if have_stride: start = stop = stride = (token.STRING, 'None', lineno) if len(nodelist[-1])==3: stride = nodelist[-1][2] else: start = (token.NUMBER,`0`,lineno) stop = (token.NUMBER,`sys.maxint`,lineno) if nl==5: start,stop = nodelist[1],nodelist[3] # test : test sliceop elif nl==4: if nodelist[1][0]==token.COLON: # : test sliceop stop = nodelist[2] elif have_stride: # test : sliceop start = nodelist[1] else: start, stop = nodelist[1], nodelist[3] # test : test elif nl==3: if nodelist[1][0]==token.COLON: if not have_stride: stop = nodelist[2] # : test else: start = nodelist[1] # test : else: raise AssertionError("Unrecognized subscript", nodelist) if have_stride: return builder.Sliceobj(start,stop,stride) return builder.Slice(start,stop) for sym,name in sym_name.items(): if name in globals(): production[sym] = globals()[name] def build(builder, nodelist): while len(nodelist)==2: nodelist = nodelist[1] return production[nodelist[0]](builder,nodelist) def parse_expr(expr,builder): # include line numbers in parse data so valid symbols are never of length 2 return build(builder, parser.expr(expr).totuple(1)[1]) PKK\8NnvIvIdispatch/predicates.pyfrom __future__ import generators from dispatch import * from dispatch.strategy import Inequality, Signature, ExprBase, default from dispatch.strategy import SubclassCriterion, NullCriterion from dispatch.strategy import AbstractCriterion, Pointer, Predicate from dispatch.ast_builder import build import protocols, operator, dispatch from types import NoneType __all__ = [ 'Call', 'AndCriterion', 'NotCriterion', 'TruthCriterion', 'ExprBuilder', 'Const', 'Getattr', 'Tuple', 'dispatch_by_truth', 'OrExpr', 'AndExpr', 'CriteriaBuilder', 'expressionSignature', 'IfElse', ] # Helper functions for operations not supplied by the 'operator' module def is_(o1,o2): return o1 is o2 def in_(o1,o2): return o1 in o2 def is_not(o1,o2): return o1 is not o2 def not_in(o1,o2): return o1 not in o2 def add_dict(d1,d2): d1 = d1.copy() d1.update(d2) return d1 try: frozenset except NameError: from sets import ImmutableSet as frozenset # XXX var, let, ??? class ExprBuilder: simplify_comparisons = True def __init__(self,arguments,*namespaces): self.arguments = arguments self.namespaces = namespaces def Name(self,name): if name in self.arguments: return self.arguments[name] for ns in self.namespaces: if name in ns: return Const(ns[name]) raise NameError(name) def Const(self,value): return Const(value) _cmp_ops = { '>': operator.gt, '>=': operator.ge, '<': operator.lt, '<=': operator.le, '<>': operator.ne, '!=': operator.ne, '==':operator.eq, 'in': in_, 'not in': not_in, 'is': is_, 'is not': is_not } def Compare(self,initExpr,((op,other),)): return Call( self._cmp_ops[op], build(self,initExpr), build(self,other) ) def IfElse(self, tval, cond, fval): return IfElse(build(self,tval), build(self,cond), build(self,fval)) def mkBinOp(op): def method(self,left,right): return Call(op, build(self,left), build(self,right)) return method LeftShift = mkBinOp(operator.lshift) Power = mkBinOp(pow) RightShift = mkBinOp(operator.rshift) Add = mkBinOp(operator.add) Sub = mkBinOp(operator.sub) Mul = mkBinOp(operator.mul) Div = mkBinOp(operator.div) Mod = mkBinOp(operator.mod) FloorDiv = mkBinOp(operator.floordiv) def multiOp(op): def method(self,items): result = build(self,items[0]) for item in items[1:]: result = Call(op, result, build(self,item)) return result return method Bitor = multiOp(operator.or_) Bitxor = multiOp(operator.xor) Bitand = multiOp(operator.and_) def unaryOp(op): def method(self,expr): return Call(op, build(self,expr)) return method UnaryPlus = unaryOp(operator.pos) UnaryMinus = unaryOp(operator.neg) Invert = unaryOp(operator.invert) Backquote = unaryOp(repr) Not = unaryOp(operator.not_) def tupleOp(op): def method(self,items): return Tuple(op,*[build(self,item) for item in items]) return method Tuple = tupleOp(tuple) List = tupleOp(list) def Dict(self, items): keys = Tuple(tuple, *[build(self,k) for k,v in items]) vals = Tuple(tuple, *[build(self,v) for k,v in items]) return Call(dict, Call(zip, keys, vals)) def Subscript(self,left,right): left, right = build(self,left), build(self,right) if isinstance(right,tuple): return Call(operator.getslice,left,*right) else: return Call(operator.getitem,left,right) def Slice(self,start,stop): return build(self,start), build(self,stop) def Sliceobj(self,*args): return Call(slice,*[build(self,arg) for arg in args]) def Getattr(self,expr,attr): expr = build(self,expr) if isinstance(expr,Const): return Const(getattr(expr.value,attr)) return Getattr(expr,attr) def And(self,items): return AndExpr(*[build(self,expr) for expr in items]) def Or(self,items): return OrExpr(*[build(self,expr) for expr in items]) def CallFunc(self,funcExpr,args,kw,star,dstar): func = build(self,funcExpr) if isinstance(func,Const) and not kw and not star and not dstar: return Call(func.value, *[build(self,arg) for arg in args]) elif kw or dstar or args or star: if args: args = Tuple(tuple,*[build(self,arg) for arg in args]) if star: args = Call( operator.add, args, Call(tuple,build(self,star)) ) elif star: args = build(self,star) if kw or dstar: args = args or Const(()) if kw: kw = self.Dict(kw) if dstar: kw = Call(add_dict, kw, build(self,dstar)) elif dstar: kw = build(self,dstar) return Call(apply, func, args, kw) else: return Call(apply, func, args) else: return Call(apply,func) class LogicalExpr(ExprBase): def __new__(klass,*argexprs): for arg in argexprs: if not isinstance(arg,Const): return ExprBase.__new__(klass,*argexprs) return Const(klass.immediate([arg.value for arg in argexprs])) def __init__(self,*argexprs): self.argexprs = argexprs self.hash = hash((type(self),argexprs)) def __eq__(self,other): return type(self) is type(other) and other.argexprs == self.argexprs class OrExpr(LogicalExpr): """Lazily compute logical 'or' of exprs""" def asFuncAndIds(self,generic): argIds = map(generic.getExpressionId,self.argexprs) def or_(get): for arg in argIds: val = get(arg) if val: break return val return or_, (EXPR_GETTER_ID,) [as(classmethod)] def immediate(klass,seq): for item in seq: if item: break return item class AndExpr(LogicalExpr): """Lazily compute logical 'and' of exprs""" def asFuncAndIds(self,generic): argIds = map(generic.getExpressionId,self.argexprs) def and_(get): for arg in argIds: val = get(arg) if not val: break return val return and_, (EXPR_GETTER_ID,) [as(classmethod)] def immediate(klass,seq): for item in seq: if not item: break return item class IfElse(LogicalExpr): """Python 2.5 conditional expression""" def asFuncAndIds(self,generic): argIds = map(generic.getExpressionId, self.argexprs) def ifelse(get): if get(argIds[1]): return get(argIds[0]) return get(argIds[2]) return ifelse, (EXPR_GETTER_ID,) [as(classmethod)] def immediate(klass,seq): if seq[1]: return seq[0] return seq[2] class Tuple(ExprBase): """Compute an expression by calling a function with an argument tuple""" def __new__(klass,function=tuple,*argexprs): for arg in argexprs: if not isinstance(arg,Const): return ExprBase.__new__(klass,function,*argexprs) return Const(function([arg.value for arg in argexprs])) def __init__(self,function=tuple,*argexprs): self.function = function self.argexprs = argexprs self.hash = hash((type(self),function,argexprs)) def __eq__(self,other): return isinstance(other,Tuple) and \ (other.function==self.function) and \ (other.argexprs==self.argexprs) def asFuncAndIds(self,generic): return lambda *args: self.function(args), tuple( map(generic.getExpressionId, self.argexprs) ) def __repr__(self): return 'Tuple%r' % (((self.function,)+self.argexprs),) class Getattr(ExprBase): """Compute an expression by calling a function with 0 or more arguments""" def __init__(self,ob_expr,attr_name): self.ob_expr = ob_expr self.attr_name = attr_name self.hash = hash((type(self),ob_expr,attr_name)) def __eq__(self,other): return isinstance(other,Getattr) and \ (other.ob_expr==self.ob_expr) and \ (other.attr_name==self.attr_name) def asFuncAndIds(self,generic): return eval("lambda ob: ob.%s" % self.attr_name), ( generic.getExpressionId(self.ob_expr), ) class Const(ExprBase): """Compute a 'constant' value""" def __init__(self,value): self.value = value try: self.hash = hash((type(self),value)) except TypeError: self.hash = hash((type(self),id(value))) def __eq__(self,other): return isinstance(other,Const) and (other.value==self.value) def asFuncAndIds(self,generic): return lambda:self.value,() def __repr__(self): return 'Const(%r)' % (self.value,) class Call(ExprBase): """Compute an expression by calling a function with 0 or more arguments""" def __new__(klass,function,*argexprs): if not argexprs: return ExprBase.__new__(klass,function) for arg in argexprs: if not isinstance(arg,Const): return ExprBase.__new__(klass,function,*argexprs) return Const(function(*[arg.value for arg in argexprs])) def __init__(self,function,*argexprs): self.function = function self.argexprs = argexprs self.hash = hash((type(self),function,argexprs)) def __eq__(self,other): return isinstance(other,Call) and \ (other.function==self.function) and \ (other.argexprs==self.argexprs) def asFuncAndIds(self,generic): return self.function,tuple(map(generic.getExpressionId, self.argexprs)) def __repr__(self): return 'Call%r' % (((self.function,)+self.argexprs),) class MultiCriterion(AbstractCriterion): """Abstract base for boolean combinations of criteria""" __slots__ = 'node_type' criteria = AbstractCriterion.subject # alias criteria <-> subject enumerable = False def __new__(klass,*criteria): criteria, all = map(ISeededCriterion,criteria), [] nt = criteria[0].node_type for c in criteria: if c.node_type is not nt: raise ValueError("Mismatched dispatch types", criteria) if c.__class__ is klass: # flatten nested criteria all.extend([c for c in c.criteria if c not in all]) elif c not in all: all.append(c) if len(all)==1: return all[0] self = object.__new__(klass) self.node_type = nt AbstractCriterion.__init__(self,frozenset(all)) return self def seeds(self): seeds = {} for criterion in self.criteria: for seed in criterion.seeds(): seeds[seed]=True return seeds.keys() def subscribe(self,listener): for criterion in self.criteria: criterion.subscribe(listener) def unsubscribe(listener): for criterion in self.criteria: criterion.unsubscribe(listener) def __repr__(self): return '%s%r' % (self.__class__.__name__,tuple(self.criteria)) def __invert__(self): raise NotImplementedError def __init__(self,*criteria): pass class AndCriterion(MultiCriterion): """All criteria must return true for expression""" __slots__ = () def __contains__(self,key): for criterion in self.criteria: if key not in criterion: return False return True class NotCriterion(MultiCriterion): __slots__ = () __new__ = AbstractCriterion.__new__ def __init__(self, criterion): criterion = ISeededCriterion(criterion) AbstractCriterion.__init__(self,(criterion,)) self.node_type = criterion.node_type def __invert__(self): return self.criteria[0] def __contains__(self,key): return key not in self.criteria[0] def dispatch_by_truth(table,ob): return table.get(bool(ob)) class TruthCriterion(AbstractCriterion): """Criterion representing truth or falsity of an expression""" __slots__ = () truth = AbstractCriterion.subject dispatch_function = staticmethod(dispatch_by_truth) def __init__(self,truth=True): AbstractCriterion.__init__(self,bool(truth)) def seeds(self): return True,False def __contains__(self,key): return key==self.truth def __invert__(self): return TruthCriterion(not self.truth) def matches(self,table): return self.truth, def __repr__(self): return "TruthCriterion(%r)" % self.truth [dispatch.generic()] def expressionSignature(expr,criterion): """Return an ISignature that applies 'criterion' to 'expr'""" [expressionSignature.when(default)] def expressionSignature(expr,criterion): return Signature([(expr,criterion)]) class CriteriaBuilder: bind_globals = True simplify_comparisons = True mode = TruthCriterion(True) def __init__(self,arguments,*namespaces): self.expr_builder = ExprBuilder(arguments,*namespaces) def mkOp(name): op = getattr(ExprBuilder,name) def method(self,*args): return expressionSignature(op(self.expr_builder,*args), self.mode) return method for opname in dir(ExprBuilder): if opname[0].isalpha() and opname[0]==opname[0].upper(): locals()[opname] = mkOp(opname) def Not(self,expr): try: self.__class__ = NotBuilder return build(self,expr) finally: self.__class__ = CriteriaBuilder _mirror_ops = { '>': '<', '>=': '<=', '=>':'<=', '<': '>', '<=': '>=', '=<':'>=', '<>': '<>', '!=': '<>', '==':'==', 'is': 'is', 'is not': 'is not' } _rev_ops = { '>': '<=', '>=': '<', '=>': '<', '<': '>=', '<=': '>', '=<': '>', '<>': '==', '!=': '==', '==':'!=', 'in': 'not in', 'not in': 'in', 'is': 'is not', 'is not': 'is' } def Compare(self,initExpr,((op,other),)): left = build(self.expr_builder,initExpr) right = build(self.expr_builder,other) if isinstance(left,Const) and op in self._mirror_ops: left,right,op = right,left,self._mirror_ops[op] if isinstance(right,Const): if not self.mode.truth: op = self._rev_ops[op] if op=='in' or op=='not in': cond = compileIn(left,right.value,op=='in') if cond is not None: return cond else: if op=='is' or op=='is not': if right.value is None: right = ICriterion(NoneType) else: right = ICriterion(Pointer(right.value)) if op=='is not': right = ~right else: right = Inequality(op,right.value) return Signature([(left, right)]) # Both sides involve variables or an un-optimizable constant, # so it's a generic boolean criterion :( return expressionSignature( self.expr_builder.Compare(initExpr,((op,other),)), self.mode ) def And(self,items): return reduce(operator.and_,[build(self,expr) for expr in items]) def Or(self,items): return reduce(operator.or_,[build(self,expr) for expr in items]) def compileIn(expr,criterion,truth): """Return a signature or predicate (or None) for 'expr in criterion'""" try: iter(criterion) except TypeError: return applyCriterion(expr,criterion,truth) if truth: return or_criteria(expr,[Inequality('==',v) for v in criterion]) else: return and_criteria(expr,[Inequality('<>',v) for v in criterion]) [dispatch.on('criterion')] def applyCriterion(expr,criterion,truth): """Apply 'criterion' to 'expr' (ala 'expr in criterion') -> sig or pred""" [applyCriterion.when(ICriterion)] def applyICriterion(expr,criterion,truth): if not truth: criterion = ~criterion return Signature([(expr,criterion)]) [applyCriterion.when(object)] def applyDefault(expr,criterion,truth): return None # no special application possible def or_criteria(expr,seq): seq = [Signature([(expr,v)]) for v in seq] if len(seq)==1: return seq[0] return Predicate(seq) def and_criteria(expr,seq): it = iter(seq) for val in it: break else: raise ValueError("No criteria supplied!") for next in it: val &= next return Signature([(expr,val)]) class NotBuilder(CriteriaBuilder): mode = TruthCriterion(False) def Not(self,expr): try: self.__class__ = CriteriaBuilder return build(self,expr) finally: self.__class__ = NotBuilder # Negative logic for and/or And = CriteriaBuilder.Or Or = CriteriaBuilder.And def _yield_tuples(ob): if isinstance(ob,tuple): for i1 in ob: for i2 in _yield_tuples(i1): yield i2 else: yield ob [expressionSignature.when( # matches 'isinstance(expr,Const)' "expr in Call and expr.function is isinstance" " and len(expr.argexprs)==2 and expr.argexprs[1] in Const" )] def convertIsInstanceToClassCriterion(expr,criterion): seq = _yield_tuples(expr.argexprs[1].value) expr = expr.argexprs[0] if not criterion.truth: return and_criteria(expr,[~ICriterion(cls) for cls in seq]) return or_criteria(expr,map(ICriterion,seq)) [expressionSignature.when( # matches 'issubclass(expr,Const)' "expr in Call and expr.function is issubclass" " and len(expr.argexprs)==2 and expr.argexprs[1] in Const" )] def convertIsSubclassToSubClassCriterion(expr,criterion): seq = _yield_tuples(expr.argexprs[1].value) expr = expr.argexprs[0] if not criterion.truth: return and_criteria(expr,[~SubclassCriterion(cls) for cls in seq]) return or_criteria(expr,map(SubclassCriterion,seq)) PKK\8dispatch/__init__.py"""Multiple/Predicate Dispatch Framework This framework refines the algorithms of Chambers and Chen in their 1999 paper, "Efficient Multiple and Predicate Dispatching", to make them suitable for Python, while adding a few other enhancements like incremental index building and lazy expansion of the dispatch DAG. Also, their algorithm was designed only for class selection and true/false tests, while this framework can be used with any kind of test, such as numeric ranges, or custom tests such as categorization/hierarchy membership. NOTE: this package is not yet ready for prime-time. APIs are subject to change randomly without notice. You have been warned! TODO * Support DAG-walking for visualization, debugging, and ambiguity detection """ from dispatch.interfaces import * from types import ClassType as _ClassType _cls = _ClassType,type def generic(combiner=None): """Use the following function as the skeleton for a generic function Decorate a Python function so that it wraps an instance of 'dispatch.functions.GenericFunction' that has been configured with the decorated function's name, docstring, argument signature, and default arguments. The decorated function will have additional attributes besides those of a normal function. (See 'dispatch.IGenericFunction' for more information on these special attributes/methods.) Most commonly, you will use the 'when()' method of the decorated function to define "rules" or "methods" of the generic function. For example:: import dispatch @dispatch.generic() def someFunction(*args): '''This is a generic function''' @someFunction.when("len(args)>0") def argsPassed(*args): print "Arguments were passed!" @someFunction.when("len(args)==0") def noArgsPassed(*args): print "No arguments were passed!" someFunction() # prints "No args passed" someFunction(1) # prints "args passed" Note that when using older Python versions, you must use '[dispatch.generic()]' instead of '@dispatch.generic()'. """ from dispatch.functions import GenericFunction, AbstractGeneric from peak.util.decorators import decorate_assignment if combiner is None: def callback(frm,name,value,old_locals): return GenericFunction(value).delegate elif isinstance(combiner,_cls) and issubclass(combiner,AbstractGeneric): def callback(frm,name,value,old_locals): return combiner(value).delegate else: def callback(frm,name,value,old_locals): gf = GenericFunction(value) gf.combine = combiner return gf.delegate return decorate_assignment(callback) def as(*decorators): """Use Python 2.4 decorators w/Python 2.2+ Example: import dispatch class Foo(object): [dispatch.as(classmethod)] def something(cls,etc): \"""This is a classmethod\""" """ if len(decorators)>1: decorators = list(decorators) decorators.reverse() def callback(frame,k,v,old_locals): for d in decorators: v = d(v) return v from peak.util.decorators import decorate_assignment return decorate_assignment(callback) def on(argument_name): """Decorate the following function as a single-dispatch generic function Single-dispatch generic functions may have a slight speed advantage over predicate-dispatch generic functions when you only need to dispatch based on a single argument's type or protocol, and do not need arbitrary predicates. Also, single-dispatch functions do not require you to adapt the dispatch argument when dispatching based on protocol or interface, and if the dispatch argument has a '__conform__' method, it will attempt to use it, rather than simply dispatching based on class information the way predicate dispatch functions do. The created generic function will use the documentation from the supplied function as its docstring. And, it will dispatch methods based on the argument named by 'argument_name', and otherwise keeping the same argument signature, defaults, etc. For example:: @dispatch.on('y') def doSomething(x,y,z): '''Doc for 'doSomething()' generic function goes here''' @doSomething.when([SomeClass,OtherClass]) def doSomething(x,y,z): # do something when 'isinstance(y,(SomeClass,OtherClass))' @doSomething.when(IFoo) def doSomething(x,y,z): # do something to a 'y' that has been adapted to 'IFoo' """ def callback(frm,name,value,old_locals): return _mkGeneric(value,argument_name) from dispatch.functions import _mkGeneric from peak.util.decorators import decorate_assignment return decorate_assignment(callback) PKK\83(hdispatch/interfaces.pyfrom protocols import Interface, Attribute __all__ = [ 'IDispatchFunction', 'ICriterion', 'ISignature', 'IDispatchPredicate', 'IDispatcher', 'AmbiguousMethod', 'NoApplicableMethods', 'IDispatchableExpression', 'IGenericFunction', 'IDispatchTable', 'EXPR_GETTER_ID','IExtensibleFunction', 'DispatchError', 'ISeededCriterion', ] class DispatchError(Exception): """A dispatch error has occurred""" def __call__(self,*args,**kw): raise self.__class__(*self.args+(args,kw)) def __repr__(self): # This method is needed so doctests for 2.3/2.4 match 2.5 return self.__class__.__name__+repr(self.args) class AmbiguousMethod(DispatchError): """More than one choice of method is possible""" class NoApplicableMethods(DispatchError): """No applicable method has been defined for the given arguments""" EXPR_GETTER_ID = -1 class ICriterion(Interface): """A criterion to be applied to an expression A criterion comprises a "node type" (that determines how the criterion will be checked, such as an 'isinstance()' check or range comparison) and a value or values that the expression must match. Note that a criterion describes only the check(s) to be performed, not the expression to be checked.""" node_type = Attribute( """The type of object that will actually do the dispatching""" ) def __and__(other): """Apply multiple criteria of the same node type to the same expr""" def __hash__(): """Equal criteria should have equal hashes""" def __eq__(other): """Return true if equal""" def __ne__(other): """Return false if equal""" def __invert__(): """Return an inverse version of this criterion (i.e. '~criterion')""" def implies(other): """Return true if truth of this criterion implies truth of 'other'""" def subscribe(listener): """Call 'listener.criterionChanged()' if applicability changes Multiple calls with the same listener should be treated as a no-op.""" def unsubscribe(listener): """Stop calling 'listener.criterionChanged()' Unsubscribing a listener that was not subscribed should be a no-op.""" class ISeededCriterion(ICriterion): """A criterion that works with a SeededIndex""" enumerable = Attribute( """Can criterion enumerate its implications via ``parent_seeds()``?""" ) leaf_seed = Attribute( """If ``enumerable``, this must be the most-specific parent seed""" ) def seeds(): """Return iterable of known-good keys The keys returned will be used to build outgoing edges in generic functions' dispatch tables, which will be passed to the 'dispatch_function' for interpretation.""" def __contains__(key): """Return true if criterion is true for 'key' This method will be passed each seed provided by this or any other criteria with the same 'dispatch_function' that are being applied to the same expression.""" def matches(table): """Return iterable of keys from 'table' that this criterion matches""" def parent_criteria(): """Iterable of all the criteria implied by this criterions""" class IDispatchFunction(Interface): """Determine what path to take at a dispatch node, given an expression""" def __call__(table,ob): """Return entry from 'table' that matches 'ob' ('None' if not found) 'table' is an 'IDispatchTable' mapping criterion seeds to dispatch nodes. The dispatch function should return the appropriate entry from the dictionary.""" def __eq__(other): """Return true if equal""" def __ne__(other): """Return false if equal""" def __hash__(): """Return hashcode""" class IDispatchTable(Interface): """A dispatch node for dispatch functions to search""" def __contains__(key): """True if 'key' is in table""" def __getitem__(key): """Return dispatch node for 'key', or raise 'KeyError'""" def reseed(key): """Add 'key' to dispatch table and return the node it should have""" class ISignature(Interface): """Ordered mapping from expression id -> criterion that should be applied Note that signatures do not/should not interpret expression IDs; the IDs may be any object that can be used as a dictionary key. """ def items(): """Sequence of '((id,disp_func),criterion)' pairs for this signature""" def get(expr_id): """Return this signature's 'ICriterion' for 'expr_id'""" def implies(otherSig): """Return true if this signature implies 'otherSig'""" def __eq__(other): """Return true if equal""" def __ne__(other): """Return false if equal""" class IDispatchPredicate(Interface): """Sequence of "or"-ed signatures""" def __iter__(): """Iterate over "or"-ed signatures""" def __eq__(other): """Return true if equal""" def __ne__(other): """Return false if equal""" class IDispatchableExpression(Interface): """Expression definition suitable for dispatching""" def asFuncAndIds(generic): """Return '(func,idtuple)' pair for expression computation""" def __eq__(other): """Return true if equal""" def __ne__(other): """Return false if equal""" def __hash__(): """Return hashcode""" class IDispatcher(Interface): """Multi-dispatch mapping object""" def __getitem__(argtuple): """Return the rule body (or combo thereof) that matches 'argtuple'""" def __setitem__(signature,body): """Store 'body' as the rule body for arg tuples matching 'signature'""" def parse(expr_string, local_dict, global_dict): """Parse 'expr_string' --> ISignature or IDispatchPredicate""" def getExpressionId(expr): """Return an expression ID for use in 'asFuncAndIds()' 'idtuple' Note that the constant 'EXPR_GETTER_ID' may be used in place of calling This method, if you want the ID corresponding to a function that will return the value of any other expression whose ID is passed to it.""" def criterionChanged(): """Notify that a criterion has changed meaning, invalidating indexes""" def clear(): """Empty all signatures, methods, criteria, expressions, etc.""" class IExtensibleFunction(Interface): def __call__(*__args,**__kw): """Invoke the function and return results""" def addMethod(predicate,method): """Call 'method' when input matches 'predicate' (Note that single and multiple-dispatch functions use different predicate types: type/class/sequence vs. 'IDispatchPredicate'). """ def when(cond): """Add following function to this GF, w/'cond' as a guard This is used to add a method to a generic function. E.g.:: import foo @foo.barFunc.when(XYZ) def whatever(x,y,z): # code for situation XYZ After the execution of this alternate form, 'whatever' will be bound to the 'whatever' function as shown, but it will also have been added to 'foo.barFunc' under condition 'XYZ'. """ class IGenericFunction(IExtensibleFunction, IDispatcher): """Extensible function that stores methods in an IDispatcher""" # copy() ? PKK\8OecKcKdispatch/functions.py"""Generic function implementations""" from __future__ import generators from dispatch.interfaces import * import protocols, inspect, sys, dispatch from peak.util.decorators import decorate_assignment, frameinfo, decorate_class from protocols.interfaces import allocate_lock from new import instancemethod from types import FunctionType, ClassType, InstanceType ClassTypes = (ClassType, type) __all__ = [ 'GenericFunction', 'Dispatcher', 'AbstractGeneric', ] _NF = (0,None, NoApplicableMethods(), (None,None)) try: frozenset except NameError: from sets import ImmutableSet as frozenset def _mkGeneric(oldfunc,argname): funcname = oldfunc.__name__ args, varargs, kwargs, defaults = inspect.getargspec(oldfunc) if defaults: tmpd = ["=__gfDefaults[%s]" % i for i in range(len(defaults))] else: tmpd = None argspec = inspect.formatargspec( args, varargs, kwargs, tmpd, formatvalue=lambda x:x) outargs = inspect.formatargspec(args,varargs,kwargs) protocol = protocols.Protocol() d={} s= """ def setup(__gfProtocol, __gfDefaults): def %(funcname)s%(argspec)s: __gfWhat = __gfProtocol(%(argname)s,None) if __gfWhat is None: raise NoApplicableMethods(%(argname)s) else: %(argname)s = __gfWhat[0] return __gfWhat[1]%(outargs)s return %(funcname)s """ % locals() exec s in globals(),d; func = d['setup'](protocol,defaults) def when(cond): """Add following function to this GF, using 'cond' as a guard""" def callback(frm,name,value,old_locals): declarePredicate(cond, protocol, lambda ob: (ob,value)) if old_locals.get(name) is func: return func return value return decorate_assignment(callback) def addMethod(cond,func): """Use 'func' when dispatch argument matches 'cond'""" declarePredicate(cond, protocol, lambda ob: (ob,func)) def clone(): """Return a simple generic function that "inherits" from this one""" f = _mkGeneric(oldfunc,argname) protocols.declareAdapter( protocols.NO_ADAPTER_NEEDED,[f.protocol],forProtocols=[protocol] ) return f func.addMethod = addMethod func.when = when func.clone = clone func.protocol = protocol func.__doc__ = oldfunc.__doc__ protocols.adviseObject(func,provides=[IExtensibleFunction]) return func # Bootstrap SimpleGeneric declaration helper function -- itself a SimpleGeneric [dispatch.on('ob')] def declarePredicate(ob,proto,factory): """Declare a SimpleGeneric dispatch predicate""" declarePredicate = _mkGeneric(declarePredicate,'ob') proto = declarePredicate.protocol def declareForType(typ,proto,factory): protocols.declareAdapter(factory,provides=[proto],forTypes=[typ]) def declareForProto(pro,proto,factory): protocols.declareAdapter(factory,provides=[proto],forProtocols=[pro]) def declareForSequence(seq,proto,factory): for item in seq: declarePredicate(item,proto,factory) declareForType(ClassType, proto, lambda ob:(ob,declareForType)) declareForType(type, proto, lambda ob:(ob,declareForType)) declareForProto(protocols.IOpenProtocol,proto, lambda ob:(ob,declareForProto)) declareForProto(protocols.IBasicSequence,proto, lambda ob:(ob,declareForSequence)) class ExprCache(object): __slots__ = 'cache','argtuple','expr_defs' def __init__(self,argtuple,expr_defs): self.argtuple = argtuple self.expr_defs = expr_defs self.cache = {} def __getitem__(self,item): if item==EXPR_GETTER_ID: return self.__getitem__ try: return self.argtuple[item] except IndexError: pass try: return self.cache[item] except KeyError: pass f,args = self.expr_defs[item] f = self.cache[item] = f(*map(self.__getitem__,args)) return f class BaseDispatcher: def __getitem__(self,argtuple): argct = self.argct node = self._dispatcher or self._startNode() or _NF expr, factory, func, init = node while factory: if func is None: self._acquire() try: if node[2] is None: node[2] = func = factory(*init) finally: self._release() if expr'method'""" cond = self.parseRule(signature) if cond is not None: for signature in IDispatchPredicate(cond): self[signature] = method return self._acquire() try: signature = strategy.Signature( [(self._dispatch_id(expr,criterion),criterion) for expr,criterion in ISignature(signature).items() if criterion is not strategy.NullCriterion ] ) self._addCase((signature, method)) self._addConstraints(signature) finally: self._release() [dispatch.on('rule')] def parseRule(self,rule,frame=None,depth=3): """Parse 'rule' if it's a string/unicode, otherwise return 'None'""" [parseRule.when([str,unicode])] def parseRule(self,rule,frame,depth): frame = frame or sys._getframe(depth) return self.parse(rule, frame.f_locals, frame.f_globals) [parseRule.when(object)] def parseRule(self,rule,frame,depth): return None def combine(self,cases): return strategy.single_best(cases) def _best_split(self, cases, disp_ids): """Return best (disp_id,method_map,remaining_ids) for current subtree""" best_id = None best_map = None best_spread = None remaining_ids = list(disp_ids) active_cases = len(cases) disabled = self.constraints.successors(remaining_ids) skipped = [] to_do = remaining_ids[:] for disp_id in to_do: if disp_id in disabled: # Skip criteria that have unchecked prerequisites skipped.append(disp_id) continue index = self.disp_indexes[disp_id] lindex, total_cases = index.count_for(cases) if total_cases == active_cases * lindex: # None of the index keys for this expression eliminate any # cases, so this expression isn't needed for dispatching remaining_ids.remove(disp_id) disabled = self.constraints.successors(remaining_ids) to_do.extend(skipped); skipped=[] continue spread = float(total_cases) / lindex if spread < best_spread or best_spread is None: best_spread = spread best_id = disp_id if best_id is not None: remaining_ids.remove(best_id) return best_id, tuple(remaining_ids) def _dispatch_id(self,(expr,disp_func),criterion): """Replace expr/criterion with a local key""" criterion.subscribe(self) expr = self.getExpressionId(expr) disp = expr, criterion.node_type if disp not in self.disp_indexes: self.disp_indexes[disp] = criterion.node_type.make_index() return expr def getExpressionId(self,expr): """Replace 'expr' with a local expression ID number""" # XXX this isn't threadsafe if not called from 'asFuncAndIds' try: return self.expr_map[expr] except KeyError: expr_def = IDispatchableExpression(expr).asFuncAndIds(self) try: return self.expr_map[expr_def] except KeyError: expr_id = len(self.expr_defs) self.expr_map[expr] = self.expr_map[expr_def] = expr_id self.expr_defs.append(expr_def) return expr_id def _addConstraints(self, signature): pre = [] for key,criterion in signature.items(): if key[0] >= self.argct: # constrain non-argument exprs for item in pre: self.constraints.add(item,key) pre.append(key) class AbstractGeneric(Dispatcher): protocols.advise(instancesProvide=[IGenericFunction]) delegate = None def __init__(self,func): self.delegate, args = _mkNormalizer(func, self) self.delegate.__dict__ = dict( [(k,getattr(self,k)) for k in dir(self.__class__) if not k.startswith('_')] ) self.delegate.__doc__ = self.__doc__ = func.__doc__ protocols.adviseObject(self.delegate,[IGenericFunction]) self.__name__ = func.__name__; self.__call__ = self.delegate Dispatcher.__init__(self,args) # We can't be used as a method, but make pydoc think we're a callable __get__ = None def addMethod(self,predicate,function,qualifier=None): if qualifier is not None: function = qualifier,function for signature in IDispatchPredicate(predicate): self[signature] = function def combine(self,cases): raise NotImplementedError( "The purpose of this class is to support *custom* method combiners" ) def __call__(__self,*args,**kw): return __self.delegate(*args,**kw) def _decorate(self,cond,qualifier=None,frame=None,depth=2): # XXX frame = frame or sys._getframe(depth) cond = self.parseRule(cond,frame=frame) or cond def registerMethod(frm,name,value,old_locals): if qualifier is None: func = value else: func = qualifier,value kind,module,locals_,globals_ = frameinfo(frm) if kind=='class': # 'when()' in class body; defer adding the method def registerClassSpecificMethod(cls): req = strategy.Signature( [(strategy.Argument(0),ICriterion(cls))] ) self.addMethod(req & cond, func) return cls decorate_class(registerClassSpecificMethod,frame=frm) else: self.addMethod(cond,func) if old_locals.get(name) in (self,self.delegate): return self.delegate return value return decorate_assignment(registerMethod,frame=frame) class GenericFunction(AbstractGeneric): """Extensible predicate dispatch generic function""" def combine(self,cases): strict = [strategy.ordered_signatures,strategy.safe_methods] loose = [strategy.ordered_signatures,strategy.all_methods] cases = strategy.separate_qualifiers( cases, around = strict, before = loose, primary = strict, after =loose, ) primary = strategy.method_chain(cases.get('primary',[])) if cases.get('after') or cases.get('before'): befores = strategy.method_list(cases.get('before',[])) afters = strategy.method_list(list(cases.get('after',[]))[::-1]) def chain(*args,**kw): for tmp in befores(*args,**kw): pass # toss return values result = primary(*args,**kw) for tmp in afters(*args,**kw): pass # toss return values return result else: chain = primary if cases.get('around'): chain = strategy.method_chain(list(cases['around'])+[chain]) return chain def around(self,cond): """Add function as an "around" method w/'cond' as a guard If 'cond' is parseable, it will be parsed using the caller's frame locals and globals. """ return self._decorate(cond,"around") def before(self,cond): """Add function as a "before" method w/'cond' as a guard If 'cond' is parseable, it will be parsed using the caller's frame locals and globals. """ return self._decorate(cond,"before") def after(self,cond): """Add function as an "after" method w/'cond' as a guard If 'cond' is parseable, it will be parsed using the caller's frame locals and globals. """ return self._decorate(cond,"after") def when(self,cond): """Add following function to this GF, w/'cond' as a guard If 'cond' is parseable, it will be parsed using the caller's frame locals and globals. """ return self._decorate(cond) def _mkNormalizer(func,dispatcher): funcname = func.__name__ if funcname=='': funcname = "anonymous" args, varargs, kwargs, defaults = inspect.getargspec(func) if defaults: tmpd = ["=__gfDefaults[%s]" % i for i in range(len(defaults))] else: tmpd = None argspec = inspect.formatargspec( args, varargs, kwargs, tmpd, formatvalue=lambda x:x) allargs = inspect.formatargspec(args,varargs,kwargs) outargs = inspect.formatargspec(args, varargs, kwargs, formatvarargs=lambda name:name, formatvarkw=lambda name:name, join=lambda seq:','.join(seq)) outargs = outargs[1:-1]+',' if outargs==',': outargs='' retargs = [] else: retargs = filter(None,outargs.replace(' ','').split(',')) d ={} s = """ def setup(__dispatcher,__gfDefaults): def %(funcname)s%(argspec)s: return __dispatcher((%(outargs)s))%(allargs)s return %(funcname)s """ % locals() exec s in globals(),d return d['setup'](dispatcher.__getitem__,defaults), retargs defaultNormalize = lambda *__args: __args PKK\8L`dispatch/combiners.py"""Method combining subclasses of Dispatcher and GenericFunction""" from strategy import ordered_signatures from interfaces import AmbiguousMethod from functions import Dispatcher class MapDispatcher(Dispatcher): """Abstract base class for method combiners that merge metadata To use this class, subclass it and override the 'getItems()' method (and optionally the 'shouldStop()' method to support your particular kind of metadata. Then use the subclass as a method combiner for a dispatcher or generic function. See 'combiners.txt' for sample code. """ def getItems(self,signature,method): """Return an iterable of '(key,value)' pairs for given rule""" raise NotImplementedError def shouldStop(self,signature,method): """Return truth if combining should stop at this precedence level""" def combine(self,items): """Build a dictionary from a sequence of '(signature,method)' pairs""" d = {} should_stop = False for level in ordered_signatures(items): current = {} for item in level: should_stop = should_stop or self.shouldStop(*item) for k,v in self.getItems(*item): if k in d: # already defined continue if k in current and current[k]<>v: return AmbiguousMethod(k,v,current[k]) current[k] = v d.update(current) if should_stop: break return d PKK\8Eradispatch/strategy.py"""Indexing and Method Combination Strategies ProtocolCriterion -- Index handler for checking that an expression adapts to a protocol ClassCriterion -- Index handler for checking that an expression is of a type or class SubclassCriterion -- Index handler for checking that an expression is a subclass of a given class Inequality -- Index handler for checking that an expression has a range relation (i.e. <,>,<=,>=,==,!=) to a constant value IdentityCriterion -- Index handler for checking that an expression 'is' a particular object Min, Max -- Extreme values for use with 'Inequality' Pointer -- hashable/comparable object pointer, with weakref support, used to implement 'IdentityCriterion' Predicate, Signature, PositionalSignature, Argument -- primitives to implement indexable multiple dispatch predicates most_specific_signatures, ordered_signatures, method_chain, method_list, all_methods, safe_methods, separate_qualifiers -- utility functions for creating method combinations validateCriterion -- check if a criterion's implementation is sane """ from __future__ import generators from protocols import Protocol, Adapter, StickyAdapter from protocols.advice import getMRO import protocols, operator, inspect from types import ClassType, InstanceType ClassTypes = (ClassType, type) from sys import _getframe, maxint from weakref import WeakKeyDictionary, ref from dispatch.interfaces import * from new import instancemethod import dispatch from peak.util.extremes import Min, Max __all__ = [ 'ProtocolCriterion', 'ClassCriterion', 'SubclassCriterion', 'Inequality', 'Min', 'Max', 'Predicate', 'Signature', 'PositionalSignature', 'Argument', 'most_specific_signatures', 'ordered_signatures', 'separate_qualifiers', 'method_chain', 'method_list', 'all_methods', 'safe_methods', 'Pointer', 'default', 'IdentityCriterion', 'NullCriterion', 'validateCriterion', 'DispatchNode', 'SeededIndex', ] rev_ops = { '>': '<=', '>=': '<', '=>': '<', '<': '>=', '<=': '>', '=<': '>', '<>': '==', '!=': '==', '==':'!=' } try: set except NameError: from sets import Set as set from sets import ImmutableSet as frozenset class SeededIndex(object): """Index connecting seeds and results""" __slots__ = ( 'dispatch_function', 'allSeeds', 'matchingSeeds', 'criteria', 'enumerables','impliedSeeds' ) def __init__(self,dispatch_function): self.dispatch_function = dispatch_function self.clear() def clear(self): """Reset index to empty""" self.allSeeds = {} # set of all seeds self.matchingSeeds = {} # case -> applicable seeds self.criteria = {} # criterion -> applicable seeds self.enumerables = {} # enumerable -> applicable seeds (reg'd) self.impliedSeeds = {} # enumerable -> applicable seeds (all) def __setitem__(self,criterion,case): """Register 'case' under each of the criterion's seeds""" if criterion.enumerable: enumerables = self.enumerables if criterion not in enumerables: seed = criterion.leaf_seed seeds = self.allSeeds new_seed = seed not in seeds impliedSeeds = self.impliedSeeds for cri in criterion.parent_criteria(): if new_seed or cri not in enumerables: impliedSeeds.setdefault(cri,[]).append(seed) enumerables[criterion] = impliedSeeds[criterion] add = self.addSeed for key in criterion.seeds(): if key not in seeds: add(key,False) self.matchingSeeds[case] = enumerables[criterion] return criteria = self.criteria if criterion not in criteria: seeds = self.allSeeds add = self.addSeed for key in criterion.seeds(): if key not in seeds: add(key) criteria[criterion] = list(criterion.matches(seeds)) self.matchingSeeds[case] = criteria[criterion] def count_for(self,cases): """Get the total count of outgoing branches, given incoming cases""" get = self.matchingSeeds.get dflt = self.allSeeds return len(self.allSeeds), sum([len(get(case,dflt)) for case in cases]) def casemap_for(self,cases): """Return a mapping from seeds->caselists for the given cases""" get = self.matchingSeeds.get dflt = self.allSeeds casemap = dict([(key,[]) for key in dflt]) for case in cases: for key in get(case,dflt): casemap[key].append(case) return casemap def addSeed(self,seed, reseed=True): """Add a previously-missing seed""" if seed in self.allSeeds: return # avoid duping entries if this is a reseed via dispatcher for criterion,itsSeeds in self.criteria.items(): if seed in criterion: itsSeeds.append(seed) if reseed: for criterion,itsSeeds in self.enumerables.items(): if seed in criterion: itsSeeds.append(seed) self.allSeeds[seed] = None def mkNode(self,*args): node = DispatchNode(*args) return instancemethod(self.dispatch_function,node,DispatchNode) class DispatchNode(dict): """A mapping w/lazy population and supporting 'reseed()' operations""" protocols.advise(instancesProvide=[IDispatchTable]) __slots__ = 'index','cases','build','lock' def __init__(self, index, cases, build, lock): self.index = index self.cases = cases self.build = build self.lock = lock dict.__init__( self, [(key,build(subcases)) for key,subcases in index.casemap_for(cases).items()] ) def reseed(self,key): self.lock.acquire() try: self.index.addSeed(key) self[key] = retval = self.build( self.index.casemap_for(self.cases)[key] ) return retval finally: self.lock.release() _memo = {} def make_node_type(dispatch_function): if dispatch_function not in _memo: class Node(DispatchNode): def make_index(cls): return SeededIndex(dispatch_function) make_index = classmethod(make_index) # XXX can't use disp.as! _memo[dispatch_function] = Node return _memo[dispatch_function] def validateCriterion(criterion, node_type, seeded=True, parents=None): """Does 'criterion' have a sane implementation?""" criterion = ICriterion(criterion) hash(criterion) assert criterion.node_type is node_type assert criterion==criterion, (criterion, "should equal itself") assert criterion!=NullCriterion,(criterion,"shouldn't equal NullCriterion") assert criterion!=~criterion,(criterion,"shouldn't equal its inverse") assert criterion==~~criterion,(criterion,"should equal its double-inverse") assert criterion.implies(NullCriterion), ( criterion,"should imply NullCriterion" ) assert criterion.implies(criterion), (criterion,"should imply itself") assert not (~criterion).implies(criterion), ( criterion,"should not be implied by its inverse" ) assert not criterion.implies(~criterion), ( criterion,"should not imply its inverse", ~criterion ) d = {} criterion.subscribe(d) criterion.unsubscribe(d) if seeded: criterion = ISeededCriterion(criterion) for seed in criterion.seeds(): d[seed] = seed in criterion matches = list(criterion.matches(d)) for seed in matches: assert d[seed], (criterion,"should have contained",seed) del d[seed] for value in d.values(): assert not value,(criterion,"should've included",seed,"in matches") _parents = set(criterion.parent_criteria()) if parents is not None: # check specific parent assertion assert _parents == set(parents), (_parents,set(parents)) elif criterion.enumerable: assert _parents, ( criterion,"is enumerable and so should have parents" ) assert criterion in _parents, ( criterion,"does not include itself in its parent criteria" ) assert _parents == set([criterion]), ( criterion,"has too many parents, or you should be specifying" " the `parents` argument to ``validateCriterion()``", _parents ) else: assert not _parents, ( criterion, "is not enumerable and so should not have parents", _parents ) for parent in _parents: assert criterion.leaf_seed in parent assert criterion.implies(parent) class TGraph: """Simple transitive dependency graph""" def __init__(self): self.data = {} def add(self,s,e): self.data.setdefault(s,{}) for old_s,old_es in self.data.items(): if s in old_es or s is old_s: g = self.data.setdefault(old_s,{}) g[e] = 1 for ee in self.data.get(e,()): g[ee] = 1 def items(self): """List of current edges""" return [(s,e) for s in self.data for e in self.data[s]] def successors(self,items): """Return a truth map of the acyclic sucessors of 'items'""" d = {} get = self.data.get for s in items: for e in get(s,()): if s not in get(e,()): d[e] = 1 return d def dispatch_by_mro(table,ob): """Lookup '__class__' of 'ob' in 'table' using its MRO order""" try: klass = ob.__class__ except AttributeError: klass = type(ob) while True: if klass in table: return table[klass] try: klass, = klass.__bases__ except ValueError: if klass.__bases__: # Fixup for multiple inheritance return table.reseed(klass) else: break if isinstance(ob,InstanceType) and InstanceType in table: return table[InstanceType] if klass is not object and object in table: return table[object] def dispatch_by_subclass(table,ob): if isinstance(ob,ClassTypes): while 1: if ob in table: return table[ob] try: ob, = ob.__bases__ except ValueError: if ob.__bases__: return table.reseed(ob) break return table[None] class AbstractCriterion(object): """Common behaviors for typical criteria""" class __metaclass__(type): def __init__(cls,name,bases,cdict): if 'dispatch_function' in cdict: cls.node_type = make_node_type(cls.dispatch_function) __slots__ = 'hash','subject' enumerable = True protocols.advise(instancesProvide=[ISeededCriterion]) def __init__(self,subject=None): self.subject = subject self.hash = hash(subject) def __eq__(self,other): return type(self) is type(other) and self.subject==other.subject def __ne__(self,other): return not self==other def matches(self,table): for key in table: if key in self: yield key def __invert__(self): from predicates import NotCriterion return NotCriterion(self) def subscribe(self,listener): pass def unsubscribe(self,listener): pass def __contains__(self,key): raise NotImplementedError def __and__(self,other): from predicates import AndCriterion return AndCriterion(self,other) def implies(self,other): other = ISeededCriterion(other) if self.enumerable: return self.leaf_seed in other for seed in self.seeds(): if seed in self and seed not in other: return False for seed in other.seeds(): if seed in self and seed not in other: return False return True def parent_criteria(self): if self.enumerable: yield self # Alias subject -> leaf_seed by default AbstractCriterion.leaf_seed = AbstractCriterion.subject # Hack to make hashing faster, by bypassing function call and attr lookup AbstractCriterion.__hash__ = instancemethod( AbstractCriterion.hash.__get__, None, AbstractCriterion ) try: from _d_speedups import dispatch_by_mro except ImportError: pass class ClassCriterion(AbstractCriterion): """Criterion that indicates expr is of a particular class""" __slots__ = () protocols.advise( instancesProvide=[ISeededCriterion], asAdapterForTypes=ClassTypes ) dispatch_function = staticmethod(dispatch_by_mro) def __init__(self,cls): AbstractCriterion.__init__(self,cls) def seeds(self): return [self.subject,object] def __contains__(self,ob): if isinstance(ob,ClassTypes): return ( self.subject is object or issubclass(ob,self.subject) or (self.subject is InstanceType and isinstance(ob,ClassType)) ) return False def __repr__(self): return self.subject.__name__ def parent_criteria(self): for cls in getMRO(self.subject,True): yield self.__class__(cls) _guard = object() class Pointer(int): __slots__ = 'ref' def __new__(cls,ob): self = Pointer.__base__.__new__(cls,id(ob)&maxint) try: self.ref=ref(ob) except TypeError: self.ref=lambda ob=ob: ob return self def __eq__(self,other): return self is other or int(self)==other and self.ref() is not None def __repr__(self): if self.ref() is None: return "Pointer()" % hex(self) else: return "Pointer(%r)" % self.ref() def dispatch_by_identity(table,ob): oid = id(ob)&maxint if oid in table: return table[oid] return table[None] class IdentityCriterion(AbstractCriterion): """Criterion that is true when target object is the same""" protocols.advise( instancesProvide=[ISeededCriterion],asAdapterForTypes=[Pointer] ) __slots__ = () dispatch_function = staticmethod(dispatch_by_identity) def __init__(self,ptr): AbstractCriterion.__init__(self,ptr) def seeds(self): return None,self.subject def matches(self,table): return self.subject, def __contains__(self,ob): return ob==self.subject def __repr__(self): return `self.subject` class NullCriterion(AbstractCriterion): """A "wildcard" Criterion that is always true""" node_type = None def seeds(self): return () def __contains__(self,ob): return True def implies(self,other): return False def __repr__(self): return "NullCriterion" def matches(self,table): return list(table) NullCriterion = NullCriterion() class SubclassCriterion(ClassCriterion): """Criterion that indicates expr is a subclass of a particular class""" __slots__ = () dispatch_function = staticmethod(dispatch_by_subclass) def seeds(self): return [self.subject,None] def __repr__(self): return "SubclassCriterion(%s)" % (self.subject.__name__,) def dispatch_by_inequalities(table,ob): key = ob,ob try: return table[key] except KeyError: if None not in table: table[None] = ranges = concatenate_ranges(table) else: ranges = table[None] lo = 0; hi = len(ranges) while loth: lo = mid+1 else: return table[ranges[mid]] def concatenate_ranges(range_map): ranges = range_map.keys(); ranges.sort() output = [] last = Min for (l,h) in ranges: if l applicable seeds self.last_cases = None self.last_out = None def __setitem__(self,criterion,case): """Register 'case' under each of the criterion's seeds""" self.criteria[case] = criterion for (lo,hi) in criterion.ranges: self.allSeeds[lo] = self.allSeeds[hi] = None def addSeed(self,seed): raise NotImplementedError def casemap_for(self,cases): """Return a mapping from seeds->caselists for the given cases""" if cases is self.last_cases or cases==self.last_cases: return self.last_out tmp = {} out = {} get = self.criteria.get all = Inequality('..',[(Min,Max)]) have_ineq = False for case in cases: for (lo,hi) in get(case,all).ranges: if lo not in tmp: tmp[lo] = [],[],[] if lo==hi: tmp[lo][2].append(case) else: have_ineq = True if hi not in tmp: tmp[hi] = [],[],[] tmp[lo][0].append(case) if hi is not Max: tmp[hi][1].append(case) if have_ineq: keys = tmp.keys() keys.sort() current = frozenset(tmp.get(Min,[[]])[0]) hi = Min for val in keys: add,remove,eq = tmp[val] lo,hi = hi,val out[lo,hi] = current current = current.difference(remove) out[val,val] = current.union(eq) current = current.union(add) else: out[Min,Max] = [] # default for val,(add,remove,eq) in tmp.items(): out[val,val] = eq self.last_out = out self.last_cases = cases return out class Inequality(object): """Criterion that indicates target matches specified const. inequalities""" __slots__ = 'hash','ranges' protocols.advise(instancesProvide=[ICriterion]) class node_type(DispatchNode): make_index = InequalityIndex def __init__(self,op,val): ranges = [] if op=='..': ranges.extend(val) else: if op=='!=': op = '<>' # easier to process this way if '<' in op: ranges.append((Min,val)) if '=' in op: ranges.append((val,val)) if '>' in op: ranges.append((val,Max)) if not ranges or [c for c in op if c not in '<=>']: raise ValueError("Invalid inequality operator", op) self.ranges = ranges = tuple(ranges) self.hash = hash(ranges) def implies(self,other): for r in self.ranges: if not r in other: return False return True def __repr__(self): return 'Inequality("..",%r)' % (self.ranges,) def __contains__(self,ob): for r in self.ranges: if ob==r: return True elif ob[0]==ob[1]: # single point must be *inside* the range if ob[0]>r[0] and ob[1]=r[0] and ob[1]<=r[1]: # for range, overlap allowed return True return False def __and__(self, other): ranges = [] for r in self.ranges: if r in other: ranges.append(r) else: l1, h1 = r for l2,h2 in other.ranges: if l2>h1 or h2Min and (last,lo) not in self: ranges[last,lo] = 1 last = hi if lo<>hi and lo<>Min and (lo,lo) not in self: ranges[lo,lo] = 1 if last is not Max: if (last,last) not in self: ranges[last,last]=1 ranges[last,Max]=1 ranges = list(ranges); ranges.sort() return self.__class__('..',ranges) # Hack to make hashing faster, by bypassing function call and attr lookup Inequality.__hash__ = instancemethod( Inequality.hash.__get__, None, Inequality ) class _Notifier(Protocol): """Helper class that forwards class registration info""" def __init__(self,baseProto): Protocol.__init__(self) from weakref import WeakKeyDictionary self.__subscribers = WeakKeyDictionary() baseProto.addImpliedProtocol(self, protocols.NO_ADAPTER_NEEDED, 1) def subscribe(self,listener): self._Protocol__lock.acquire() try: self.__subscribers[listener] = 1 finally: self._Protocol__lock.release() def unsubscribe(self,listener): self._Protocol__lock.acquire() try: if listener in self.__subscribers: del self.__subscriber[listener] finally: self._Protocol__lock.release() def registerImplementation(self,klass,adapter=protocols.NO_ADAPTER_NEEDED,depth=1): old_reg = Protocol.registerImplementation.__get__(self,self.__class__) result = old_reg(klass,adapter,depth) self._Protocol__lock.acquire() try: if self.__subscribers: for subscriber in self.__subscribers.keys(): subscriber.criterionChanged() finally: self._Protocol__lock.release() return result class ProtocolCriterion(StickyAdapter,AbstractCriterion): """Criterion that indicates instances of expr's class provide a protocol""" protocols.advise( instancesProvide=[ISeededCriterion], asAdapterForTypes=[Protocol] ) attachForProtocols = (ICriterion,ISeededCriterion) dispatch_function = staticmethod(dispatch_by_mro) enumerable = False # Just to be safe def __init__(self,ob): self.notifier = _Notifier(ob) StickyAdapter.__init__(self,ob) AbstractCriterion.__init__(self,ob) def subscribe(self,listener): self.notifier.subscribe(listener) def unsubscribe(self,listener): self.notifier.unsubscribe(listener) def seeds(self): return self.notifier._Protocol__adapters.keys() + [object] def __contains__(self,ob): if isinstance(ob,ClassTypes): bases = self.subject._Protocol__adapters for base in getMRO(ob,True): if base in bases: return bases[base][0] is not protocols.DOES_NOT_SUPPORT return False def implies(self,other): other = ISeededCriterion(other) if other is NullCriterion: return True for base in self.notifier._Protocol__adapters.keys(): if base not in other: return False return True def __repr__(self): return self.subject.__name__ def most_specific_signatures(cases): """List the most specific '(signature,method)' pairs from 'cases' 'cases' is a list of '(signature,method)' pairs, where each 'signature' must provide 'ISignature'. This routine checks the implication relationships between pairs of signatures, and then returns a shorter list of '(signature,method)' pairs such that no other signature from the original list implies a signature in the new list. """ if len(cases)==1: # Shortcut for common case return list(cases) best, rest = list(cases[:1]), list(cases[1:]) for new_sig,new_meth in rest: for old_sig, old_meth in best[:]: # copy so we can modify inplace new_implies_old = new_sig.implies(old_sig) old_implies_new = old_sig.implies(new_sig) if new_implies_old: if not old_implies_new: # better, remove the old one best.remove((old_sig, old_meth)) elif old_implies_new: # worse, skip adding the new one break else: # new_sig has passed the gauntlet, as it has not been implied # by any of the current "best" items best.append((new_sig,new_meth)) return best def ordered_signatures(cases): """Return list of lists of cases sorted into partial implication order Each list within the returned list contains cases whose signatures are overlapping, equivalent, or disjoint with one another, but are more specific than any other case in the lists that follow.""" rest = list(cases) while rest: best = most_specific_signatures(rest) map(rest.remove,best) yield best def all_methods(grouped_cases): """Yield all methods in 'grouped_cases'""" for group in grouped_cases: for signature,method in group: yield method def safe_methods(grouped_cases): """Yield non-ambiguous methods (plus optional raiser of AmbiguousMethod)""" for group in grouped_cases: if len(group)>1: yield AmbiguousMethod(group) break for signature,method in group: yield method def method_list(methods): """Return callable that yields results of calling 'methods' w/same args""" methods = list(methods) # ensure it's re-iterable def combined(*args,**kw): for m in methods: yield m(*args,**kw) return combined def method_chain(methods): """Chain 'methods' such that each may call the next""" methods = iter(methods) # ensure that nested calls will see only the tail for method in methods: try: args = inspect.getargspec(method)[0] except TypeError: return method # not a function, therefore not chainable if args and args[0]=='next_method': if getattr(method,'im_self',None) is None: next_method = method_chain(methods) return instancemethod(method,next_method,type(next_method)) return method return NoApplicableMethods() def single_best(cases): for method in safe_methods(ordered_signatures(cases)): return method else: return NoApplicableMethods() def separate_qualifiers(qualified_cases, **postprocessors): """list[qualified_case] -> dict[qualifier:list[unqualified_case]] Turn a list of cases with possibly-qualified methods into a dictionary mapping qualifiers to (possibly post-processed) case lists. If a given method is not qualified, it's treated as though it had the qualifier '"primary"'. Keyword arguments supplied to this function are treated as a mapping from qualifiers to lists of functions that should be applied to the list of cases to that qualifier. So, for example, this:: cases = separate_qualifiers(cases, primary=[strategy.ordered_signatures,strategy.safe_methods], ) is equivalent to:: cases = separate_qualifiers(cases) if "primary" in cases: cases["primary"]=safe_methods(ordered_signatures(cases["primary"])) Notice, by the way, that the postprocessing functions must be listed in order of *application* (i.e. outermost last). """ cases = {} for signature,method in qualified_cases: if isinstance(method,tuple): qualifier,method = method else: qualifier="primary" cases.setdefault(qualifier,[]).append((signature,method)) for k,v in cases.items(): if k in postprocessors: for p in postprocessors[k]: v = p(v) cases[k] = v return cases class ExprBase(object): protocols.advise(instancesProvide=[IDispatchableExpression]) def __ne__(self,other): return not self.__eq__(other) def __hash__(self): return self.hash def asFuncAndIds(self,generic): raise NotImplementedError class Argument(ExprBase): """The most basic kind of dispatch expression: an argument specifier""" def __init__(self,pos=None,name=None): if pos is None and name is None: raise ValueError("Argument name or position must be specified") self.pos = pos self.name = name self.hash = hash((type(self),self.pos,self.name)) def __eq__(self,other): return isinstance(other,Argument) and \ (other.pos==self.pos) and \ (other.name==self.name) def asFuncAndIds(self,generic): raise NameError("%r is not known to %s" % (self,generic)) def __repr__(self): if self.name: return self.name return 'Argument(%r)' % self.pos class Predicate(object): """A set of alternative signatures in disjunctive normal form""" protocols.advise( instancesProvide=[IDispatchPredicate], asAdapterForProtocols = [protocols.sequenceOf(ISignature)], ) def __init__(self,items): self.items = all = [] for item in map(ISignature,items): if item not in all: all.append(item) def __iter__(self): return iter(self.items) def __and__(self,other): return Predicate( [(a & b) for a in self for b in IDispatchPredicate(other)]) def __or__(self,other): sig = ISignature(other,None) if sig is not None: if len(self.items)==1: return self.items[0] | sig return Predicate(self.items+[sig]) return Predicate(list(self)+list(other)) def __eq__(self,other): return self is other or self.items==list(other) def __ne__(self,other): return not self.__eq__(other) def __repr__(self): return `self.items` protocols.declareAdapter( lambda ob: Predicate([ob]), [IDispatchPredicate], forProtocols=[ISignature] ) class Signature(object): """A set of criteria (in conjunctive normal form) applied to expressions""" protocols.advise(instancesProvide=[ISignature]) __slots__ = 'data','keys' def __init__(self, __id_to_test=(), **kw): items = list(__id_to_test)+[(Argument(name=k),v) for k,v in kw.items()] self.data = data = {}; self.keys = keys = [] for k,v in items: v = ICriterion(v) k = k,v.node_type if k in data: data[k] &= v else: data[k] = v; keys.append(k) def implies(self,otherSig): otherSig = ISignature(otherSig) for expr_id,otherCriterion in otherSig.items(): if not self.get(expr_id).implies(otherCriterion): return False return True def items(self): return [(k,self.data[k]) for k in self.keys] def get(self,expr_id): return self.data.get(expr_id,NullCriterion) def __repr__(self): return 'Signature(%s)' % (','.join( [('%r=%r' % (k,v)) for k,v in self.data.items()] ),) def __and__(self,other): me = self.data.items() if not me: return other if IDispatchPredicate(other) is other: return Predicate([self]) & other they = ISignature(other).items() if not they: return self return Signature( [(k[0],self.data[k]) for k in self.keys] + [(k,v) for (k,d),v in they] ) def __or__(self,other): me = self.data.items() if not me: return self # Always true if IDispatchPredicate(other) is other: return Predicate([self]) | other they = ISignature(other).items() if not they: return other # Always true return Predicate([self,other]) def __eq__(self,other): if other is self: return True other = ISignature(other,None) if other is None or other is NullCriterion: return False for k,v in self.items(): if v!=other.get(k): return False for k,v in other.items(): if v!=self.get(k): return False return True def __ne__(self,other): return not self.__eq__(other) class PositionalSignature(Signature): protocols.advise( instancesProvide=[ISignature], asAdapterForProtocols=[protocols.sequenceOf(ICriterion)] ) __slots__ = () def __init__(self,criteria,proto=None): Signature.__init__(self, zip(map(Argument,range(len(criteria))), criteria) ) default = Signature() PKK\8hhdispatch/combiners.txt================== Result Combination ================== Sometimes, more than one method of a generic function (or ``Dispatcher`` entry) applies in a given circumstance. For example, you might need to sum the results of a series of pricing rules in order to compute a product's price. Or, sometimes you'd like a method to be able to modify the result of a less-specific method. For these scenarios, you will want to use one of several "result combination" techniques, ranging from using a provided subclass of ``GenericFunction`` or ``Dispatcher``, to rolling your own entirely custom combination approach. >>> import dispatch >>> from dispatch import strategy, functions, combiners, NoApplicableMethods .. contents:: **Table of Contents** -------------------------- The "Standard" Combination -------------------------- The default ``Dispatcher`` class only supports returning the most-specific value, or raising ``NoApplicableMethods`` or ``AmbiguousMethod`` errors. But, the default ``GenericFunction`` class implements a result combination strategy similar to the "standard method combination" for generic functions in the Common Lisp Object System (CLOS). Specifically, it supports methods calling the "next method", and it supports "before", "after", and "around" methods, in an ordering similar to that of CLOS. Let's go over each of these concepts in turn. But as we do, please keep in mind that because of PyProtocols' "logical implication" approach to method ordering, before/after/around methods should be needed less often than they would be in CLOS. So, make sure you actually need a particular feature before making your code more complicated than it needs to be. Using ``next_method`` ===================== By default, a ``GenericFunction`` will only invoke the most-specific applicable method. However, if you add a ``next_method`` argument to the beginning of an individual method's signature, you can use it to call the "next method" that applies. That is, the second-most-specific method. If that method also has a ``next_method`` argument, it too will be able to invoke the next method after it, and so on, down through all the applicable methods. For example:: >>> class NextMethodExample: ... [dispatch.generic()] ... def foo(self,bar,baz): ... """Foo bar and baz""" ... ... [foo.when("bar>1 and baz=='spam'")] ... def foo_one_spam(next_method, self, bar, baz): ... return bar + next_method(self,bar,baz) ... ... [foo.when("baz=='spam'")] ... def foo_spam(self, bar, baz): ... return 42 ... ... [foo.when("baz=='blue'")] ... def foo_spam(next_method, self, bar, baz): ... ... # if next_method is an instance of DispatchError, it means ... # that calling it will raise that error (NoApplicableMethods ... # or AmbiguousMethod) ... assert isinstance(next_method, dispatch.DispatchError) ... ... # but we'll call it anyway, just to demo the error ... return 22 + next_method(self,bar,baz) >>> NextMethodExample().foo(2,"spam") # 2 + 42 44 >>> NextMethodExample().foo(2,"blue") # 22 + ...no next method! Traceback (most recent call last): File ... combiners.txt... in foo_spam return 22 + next_method(self,bar,baz) ... NoApplicableMethods: ... Notice that ``next_method`` comes *before* ``self`` in the arguments if the generic function is an instance method. (If used, it must be the *very first* argument of the method.) Its value is supplied automatically by the generic function machinery, so when you call ``next_method`` you do not have to care whether the next method needs to know *its* next method; just pass in all of the *other* arguments (including ``self`` if applicable) and the ``next_method`` implementation will do the rest. (For implementation details, see the ``strategy.method_chain()`` function, which is described in the `Method Combination Utilities`_ section below.) Also notice that methods that do not call their next method do not need to have a ``next_method`` argument. If a method calls ``next_method`` when there are no further methods available, ``NoApplicableMethods`` is raised. Similarly, if there is more than one "next method" and they are all equally specific (i.e. ambiguous), then ``AmbiguousMethod`` is raised. Most of the time, you will know when writing a routine whether it's safe to call ``next_method``. But sometimes you need a routine to behave differently depending on whether a next method is available. If calling ``next_method`` will raise an error, then ``next_method`` will be an instance of the error class, so you can detect it with ``isinstance()``. If there are no remaining methods, then ``next_method`` will be an instance of ``NoApplicableMethods``, and if the next method is ambiguous, it will be an ``AmbiguousMethod`` instance. In either case, calling ``next_method`` will raise that error with the supplied arguments. Before/After Methods ==================== Sometimes you'd like for some additional validation or notification to occur before or after the "normal" or "primary" methods. This is what "before", "after", and "around" methods are for. For example:: >>> class BankAccount: ... ... def __init__(self,balance,protection=0): ... self.balance = balance ... self.protection = protection ... ... [dispatch.generic()] ... def withdraw(self,amount): ... """Withdraw 'amount' from bank""" ... ... [withdraw.when(strategy.default)] # nominal case ... def withdraw(self,amount): ... self.balance -= amount ... ... [withdraw.before("amount>self.balance and self.protection==0")] ... def prevent_overdraft(self,amount): ... raise ValueError("Insufficient funds") ... ... [withdraw.after("amount>self.balance")] ... def automatic_overdraft(self,amount): ... print "Transferring",-self.balance,"from overdraft protection" ... self.protection += self.balance ... self.balance = 0 >>> acct = BankAccount(200) >>> acct.withdraw(400) Traceback (most recent call last): ... ValueError: Insufficient funds >>> acct.protection = 300 >>> acct.withdraw(400) Transferring 200 from overdraft protection >>> acct.balance 0 >>> acct.protection 100 This specific example could have been written entirely with normal ``when()`` methods, by using more complex conditions. But, in more complex scenarios, where different modules may be adding rules to the same generic function, it's not possible for one module to predict whether its conditions will be more specific than another's, and whether it will need to call ``next_method``, etc. So, generic functions offer ``before()`` and ``after()`` methods, that run before and after the ``when()`` (aka "primary") methods, respectively. Unlike primary methods, ``before()`` and ``after()`` methods: * Are allowed to have ambiguous conditions (and if they do, they execute in the order in which they were added to the generic function) * Are *always* run when their conditions apply, with no need to call ``next_method`` to invoke the next method * Cannot return a useful value and do not have access to the return value of any other method The overall order of method execution is: 1. All applicable ``before()`` methods, from most-specific to least-specific, methods at the same level of specificity execute in the order they were added. 2. Most-specifc primary method, which may optionally chain to less-specific primary methods. ``AmbiguousMethod`` or ``NoApplicableMethods`` may be raised if the most-specific method is ambiguous or no primary methods are applicable. 3. All applicable ``after()`` methods, from *least-specific* to most-specific, with methods at the same level of specificity executing in the reverse order from the order they were added. (In other words, the more specific the ``after()`` condition, the "more after" it gets run!) If any of these methods raises an uncaught exception, the overall function execution terminates at that point, and methods later in the order are not run. "Around" Methods ================ Sometimes you need to recognize certain special cases, and perhaps not run the entire generic function, or need to alter its return value in some way, or perhaps trap and handle certain exceptions, etc. You can do this with "around" methods, which run "around" the entire "before/primary/after" sequence described in the previous section. A good way to think of this is that it's as if the "around" methods form a separate generic function, whose default (least-specific) method is the original, "inner" generic function. When "around" methods are applicable on a given invocation of the generic function, the most-specific "around" method is invoked. It may then choose to call its ``next_method`` to invoke the next-most-specific "around" method, and so on. When there are no more "around" methods, calling ``next_method`` instead invokes the "before", "primary", and "after" methods, according to the sequence described in the previous section. For example:: >>> if [BankAccount.withdraw.around("amount > self.balance")]: # Python 2.3 ... def overdraft_fee(next_method,self,amount): ... print "Adding overdraft fee of $25" ... return next_method(self,amount+25) >>> acct.withdraw(20) Adding overdraft fee of $25 Transferring 45 from overdraft protection (Note: the ``if`` block should be replaced by a decorator in normal code; it needs to be as shown for ``doctest`` to properly parse the above test in Python versions < 2.4.) ------------------------- Custom Result Combination ------------------------- If none of the supplied ``Dispatcher`` or ``GenericFunction`` subclasses directly meet your needs, you'll want to implement a custom subclass that overides the ``combine()`` method to implement your custom algorithm. The ``combine()`` method takes one argument: a sequence of ``(signature,res)`` tuples (also known as "cases"), where ``res`` is either a dispatcher result or a generic function method, and ``signature`` is an ``ISignature`` describing the condition under which that result or method should apply. The ``combine()`` method must then return a single callable (for generic functions) or a single result (for dispatcher classes). It may raise ``AmbiguousMethod`` or ``NoApplicableMethods`` to indicate an error condition. Initially, the input sequence will be in definition order. That is, each case (``(signature,res)`` pair) will appear in the order it was added to the dispatcher or generic function. It is up to the ``combine()`` method to do any re-ordering or sorting desired. For your convenience, the ``dispatch.strategy`` module includes several useful functions for sorting, filtering, and combining methods from the input sequence. Method Combination Utilities ============================ The following method combination utilities are available from the ``dispatch.strategy`` module. They can be assembled in various ways to create interesting method combinations: ``single_best(cases)`` Return the single "best" method or value from `cases`. That is, the method or value of the case whose signature is most specific. If it's ambiguous as to which is most specific, an ``AmbiguousMethod`` instance is returned. If ``cases`` is empty, then a ``NoApplicableMethods`` instance is returned:: >>> strategy.single_best([]) NoApplicableMethods() >>> strategy.single_best([(strategy.Signature(x=int),1)]) 1 >>> strategy.single_best( ... [(strategy.Signature(x=object),1),(strategy.Signature(x=int),2)] ... ) 2 >>> strategy.single_best( ... [(strategy.Signature(x=int),1),(strategy.Signature(x=int),2)] ... ) AmbiguousMethod([(Signature((x...int), 1), (Signature((x...int), 2)],) This function implements the default ``Dispatcher`` combination strategy, or the generic function strategy in the absence of ``next_method`` and before/after/around methods. ``ordered_signatures(cases)`` Yields a series of cases grouped by specificity, such that each group is a set of equally-specific cases, but which are more specific than the cases in groups that follow. The grouped cases can then be passed to ``safe_methods()`` or ``all_methods()`` in order to extract methods for combining. Note that groups containing more than one case are *ambiguous*. That is, it is not statically determinable which cases are more specific than the others. In general, a dispatcher should raise ``AmbiguousMethod`` if the first group yielded by this function has a length greater than 1. ``safe_methods(grouped_cases)`` Yields methods from the grouped cases until an ambiguous group is found or the input is exhausted. An ambiguous group in the input will be replaced by a callable in the output that raises ``AmbiguousMethod`` when called. >>> list(strategy.safe_methods([])) [] >>> list(strategy.safe_methods([[(1,2)],[(3,4)],[(5,6)]])) [2, 4, 6] >>> list(strategy.safe_methods([[(1,2)],[(3,4),(5,6)]])) [2, AmbiguousMethod([(3, 4), (5, 6)],)] ``all_methods(grouped_cases)`` Yields all methods from the grouped cases, including ones in ambiguous groups. >>> list(strategy.all_methods([])) [] >>> list(strategy.all_methods([[(1,2)],[(3,4),(5,6)]])) [2, 4, 6] ``method_chain(methods)`` Returns a callable that invokes the first method in ``methods``. If that method has a ``next_method`` parameter, then when called it will be passed an extra argument, pointing to the next applicable method in ``methods``, and so on recursively, until a method without a ``next_method`` parameter is reached. (Thus, if the first method in ``methods`` does not have a ``next_method`` parameter, it is returned directly.) If there are no methods in ``methods``, then a dummy method is returned that raises ``NoApplicableMethods`` when called. >>> def f1(next_method): print "f1"; return next_method() >>> def f2(next_method): print "f2"; return next_method() >>> def f3(): print "f3"; return "done" >>> strategy.method_chain([f1,f2,f3])() f1 f2 f3 'done' >>> strategy.method_chain([])() Traceback (most recent call last): ... NoApplicableMethods... >>> mc1 = strategy.method_chain([f2,f3]) >>> mc1() f2 f3 'done' >>> mc2 = strategy.method_chain([f1,mc1]) >>> mc2() f1 f2 f3 'done' ``method_list(methods)`` Returns a callable that when called, yields the results of calling each of the supplied methods in turn with the same arguments: >>> def f1(x): return "f1"+x >>> def f2(x): return "f2"+x >>> for item in strategy.method_list([f1,f2])("y"): print item f1y f2y >>> list(strategy.method_list([])()) # empty method list yields no results [] Custom Method Qualfiers ======================= If the standard before/after/around/when decorators don't work for your application, you can create custom ones by subclassing ``AbstractGeneric`` and defining your own "method qualifiers". Here's an example of a "pricing rules" generic function that accomodates tax and discounts as well as upcharges. (Don't worry if you don't understand it at first glance; we'll go over the individual parts in detail later.):: >>> class Pricing(functions.AbstractGeneric): ... """Implement a generic pricing rule with add-ons, tax, etc.""" ... ... def add_when(self,cond): self._decorate(cond,"add") ... def tax_when(self,cond): self._decorate(cond,"tax") ... def discount_when(self,cond): self._decorate(cond,"discount") ... ... def combine(self,cases): ... cases = strategy.separate_qualifiers( ... cases, add=[ ... strategy.ordered_signatures, strategy.all_methods, ... strategy.method_list ... ], ... ) ... discount = strategy.single_best(cases.get('discount',())) ... tax = strategy.single_best(cases.get('tax',())) ... ... def combined(*args,**kw): ... price = sum(cases['add'](*args,**kw)) ... if not isinstance(discount,NoApplicableMethods): ... price -= discount(*args,**kw) * price ... if not isinstance(tax,NoApplicableMethods): ... price += tax(*args,**kw) * price ... return price ... ... return combined The ``_decorate`` method of ``AbstractGeneric`` implements a simple function decorator similar to ``when()`` et al., so ``Pricing`` generic functions will have ``add_when()``, ``tax_when()``, and ``discount_when()`` decorator methods. The functions decorated by these methods are then tracked with "qualifiers" indicating what kind of method they are, so that ``combine()`` can then separate them out of the list of applicable methods for a given situation. ``combine()`` then creates a closure (``combined``) that combines the effects of the applicable methods. We can now use this pricing class to implement a generic function:: >>> class Product: ... [dispatch.generic(Pricing)] ... def getPrice(product,customer=None,options=()): ... """Get this product's price""" ... ... [getPrice.add_when(strategy.default)] ... def __addBasePrice(product,customer,options): ... """Always include the product's base price""" ... return product.base_price >>> shoes = Product() >>> shoes.base_price = 42 And then we can create some pricing rules (again, these "if" blocks should be decorators; they have to be this way to support running the doctests in Python 2.3):: >>> if [Product.getPrice.add_when("'blue suede' in options")]: ... def blueSuedeUpcharge(product,customer,options): ... return 24 ... >>> if [Product.getPrice.discount_when( ... "customer=='Elvis' and 'blue suede' in options and product is shoes" ... )]: ... def ElvisGetsTenPercentOff(product,customer,options): ... return .1 And now we can try them out:: >>> shoes.getPrice() 42 >>> shoes.getPrice(options=['blue suede']) 66 >>> print shoes.getPrice('Elvis',options=['blue suede']) 59.4 >>> shoes.getPrice('Elvis') # no suede, no discount! 42 Now, let's look at the function that was used in ``combine()`` to separate and preprocess the applicable methods. ``separate_qualifiers(qualified_cases, **postprocess)`` Turn a list of cases with possibly-qualified methods into a dictionary mapping qualifiers to (possibly post-processed) case lists. If a given method is not qualified, it's treated as though it had the qualifier '"primary"'. Keyword arguments supplied to this function are treated as a mapping from qualifiers to lists of functions that should be applied to the list of cases to that qualifier. So, for example, this:: cases = separate_qualifiers(cases, primary=[strategy.ordered_signatures,strategy.safe_methods], ) is equivalent to:: cases = separate_qualifiers(cases) if "primary" in cases: cases["primary"]=safe_methods(ordered_signatures(cases["primary"])) Notice, by the way, that the postprocessing functions must be listed in order of *application* (i.e. outermost last). Some examples/tests:: >>> def f1(x): pass >>> def f2(x): pass >>> def f3(x): pass >>> mixed = [(1,("x",f1)),(2,("x",f2)),(3,("y",f3))] >>> strategy.separate_qualifiers(mixed) # doctest: +NORMALIZE_WHITESPACE {'y': [(3, )], 'x': [(1, ), (2, )]} >>> flat = [(1,f1),(2,f2),(3,("y",f3))] >>> strategy.separate_qualifiers(flat) # doctest: +NORMALIZE_WHITESPACE {'y': [(3, )], 'primary': [(1, ), (2, )]} >>> strategy.separate_qualifiers(flat,primary=[strategy.method_chain]) {'y': [(3, )], 'primary': (1, )} So, now that you know how ``separate_qualifiers()`` works, you can go back and see what the ``Pricing.combine()`` method is doing, and begin thinking about when you might want to create custom combinations of your own. Map Dispatchers =============== Map dispatchers are ``Dispatcher`` subclasses, typically used for class and attribute metadata such as what command line options are associated with a class' attributes. Map dispatchers merge the metadata that was defined for a class and its ancestors, detecting any ambiguities between specific metadata items defined in different base classes, or defined by multiple rules for the same class. (Actually, they use normal implication precedence, but for simple metadata registries, this usually maps directly to the inheritance structure of the target classes.) In essence, one defines the metadata as a set of keys and values. The map combiner builds a map of the "most specific" applicable values. The keys and values are extracted from each applicable rule or method in the dispatcher or generic function, and then they are merged in precedence order. If there are two rules at the same precedence level, and they share any keys, the values they provide for those keys must be equal, or an ambiguity occurs. (Unless, that is, those keys were already unambiguously defined at a higher precedence level.) To start, we'll define a basic class hierarchy, shaped basically like this:: A / \ B C \ / D By creating these classes, and some signatures to use in their place:: >>> class A: pass >>> class B(A): pass >>> class C(A): pass >>> class D(B,C): pass >>> a = strategy.Signature(x=A) >>> b = strategy.Signature(x=B) >>> c = strategy.Signature(x=C) >>> d = strategy.Signature(x=D) Our example map combiner will use functions as its rules, with function attributes serving as keys and values. We'll define some functions that have the same keys but different values, some with the same keys and same values, and some with different keys. And, we'll also create a rule that means "ignore any lower-precedence rules":: >>> def r1(): pass >>> r1.key_a = 1 >>> def r2(): pass >>> r2.key_a = 2 # same key, different value >>> def r3(): pass >>> r3.key_a = 2 # same key, same value >>> def r4(): pass >>> r4.key_a = 4 # same key, different value >>> r4.key_b = 42 # different key >>> def r5(): pass >>> r5.stop = True # "stop processing rules" Next, we'll need a ``MapDispatcher`` subclass that can interpret this rule schema:: >>> class ExampleDispatcher(combiners.MapDispatcher): ... def getItems(self,signature,rule): ... # get function attributes ... return [kv for kv in rule.__dict__.items() if kv[0]<>'stop'] ... def shouldStop(self,signature,rule): ... return getattr(rule,'stop',False) And we need an instance of it to use as a dispatcher, whose ``combine`` method we'll be testing:: >>> disp = ExampleDispatcher(['x']) >>> combine = disp.combine In the simplest possible case, combining no results should return an empty dictionary:: >>> combine([]) {} And supplying a single result will return a dictionary containing that rule's attributes:: >>> combine([(a,r1)]) {'key_a': 1} >>> combine([(a,r4)]) {'key_a': 4, 'key_b': 42} When supplying more than one result, the one with higher precedence should take effect, regardless of the order in which they are supplied:: >>> combine([(b,r2),(a,r1)]) # most-specific first {'key_a': 2} >>> combine([(a,r1),(b,r2)]) # least-specific first {'key_a': 2} And values for keys on lower-precedence rules should still "show through" if there is no higher-precedence value defined for a given key:: >>> combine([(b,r2),(a,r4)]) {'key_a': 2, 'key_b': 42} But rules at the same precedence levels with the same keys should return an ``AmbiguousMethod`` instance:: >>> combine([(b,r1),(c,r2)]) AmbiguousMethod('key_a', 2, 1) Unless of course the keys have the same values:: >>> combine([(b,r2),(c,r3)]) {'key_a': 2} >>> combine([(b,r2),(c,r3),(a,r4)]) # should still merge other key {'key_a': 2, 'key_b': 42} Or the conflicting key is already given a value with higher precedence:: >>> combine([(b,r1),(c,r2),(d,r4)]) {'key_a': 4, 'key_b': 42} Or if a "stop" is requested at a higher precedence:: >>> combine([(b,r1),(c,r2),(d,r5)]) {} Notice that once a "stop" takes effect, no lower-precedence rules are handled:: >>> combine([(c,r1),(b,r5),(a,r4)]) {'key_a': 1} So, now that we've verified that our ``combine()`` method works, we should be able to use our dispatcher as if it were a normal ``Dispatcher`` instance (but which provides appropriately-combined results):: >>> disp["x in A"] = r4 >>> disp["x in B"] = r1 >>> disp["x in C"] = r2 >>> disp["x in D"] = r3 >>> disp[A(),] {'key_a': 4, 'key_b': 42} >>> disp[B(),] {'key_a': 1, 'key_b': 42} >>> disp[C(),] {'key_a': 2, 'key_b': 42} >>> disp[D(),] {'key_a': 2, 'key_b': 42} Voila! Now we can make direct use of the metadata mapping that's returned by the dispatcher for an instance of a given class. Note, by the way, that the results are cached by the dispatcher, so a given set of methods is only combined once (unless new methods are added or criteria such as protocols are updated):: >>> disp[D(),] is disp[D(),] # same object returned from two calls 1 Finally, let's verify that adding an ambiguous or conflicting definition results in an error at dispatch time:: >>> disp["x in D"] = r1 # we previously defined it as r3 >>> disp[D(),] Traceback (most recent call last): ... AmbiguousMethod: ('key_a', 1, 2, (<...D instance at ...>,), {}) As you can see, ``r1`` and ``r3`` have conflicting definitions for the value of ``'key_a'``, so making them both applicable to ``D`` instances creates an ambiguity. PK:8YOdispatch/_d_speedups.pydMZ@ !L!This program cannot be run in DOS mode. $PELRnH# 8b= R ` .text`b``.dataf@.rdatapl@@.bss.edataRr@@.idata t@.reloc` ~@BUWVS } |$]M\$ $Zƃ 1t[tE 9rtЋ9st&$^1҉$^uuF1t&e[^_] t&$^tlZvZ&v'9rtЋ9st&$16^=$^o*^ 1_'UET$L$$]ɃÍUEL$T$$]ÐU]ZUVS uEEED$ED$D$ <D$ ED$E $EEE$@u+^EF 8u F P$REF 'D$ MS>u F4$PE8u EP$RE8u EP$RډЃ [^]UWVS}E@D$$NÅuDPD$$dƅuD ;u C$P$ÅuDx D$4$XEuDs>u F4$P ;u C$PE$@EtDU :u B$P]Ut ;u C$Pt>u F4$P}tE8u UB$P$0KQ?u G<$P؃[^_]UWVS }E $ÅuDm<$ƅuDF9E ;u C$P>u F4$P}tU B;Gt>_9t ;u C$Pt>u F4$P$TLP?u G<$PE 8u U B$P؃ [^_]USUB Z :u B$P؃[]UWVS]EEU =D$ uD$ D$E$CIuDU $ƅuDE$EuD;uE>u F4$PU :u B$PE}t[U BU;BEtB$DƅuD?u G<$PKUB$DEuD?u G<$P}EE$DƅuDuED$t$<$\yDBm>u F4$PE$DEÅQDE$DƅuDED$t$<$\yD}E>u F4$PE$DEÅD*E$DƅuDED$t$<$\yD}E>u F4$PE$DEÅD_E$DƅuDED$t$<$\yD}E>u F4$PE$DEÅDE$DƅuDRED$t$<$\yD}E>u F4$PE$DEÅ%DE$DƅuDED$t$<$\yDWEE>u F4$PE$DEÅucD At>u F4$P}tE8u UB$P$|JI?u G<$PE8u UB$PE 8u U B$P؃[^_]UWVSu F4$PuED$$@Eԅ?u G<$P}ED$$A ;u C$PED$UT$4$\xm}ED$|$4$\i}ED$E$dÅM$E܅Mp x$EԅCU܉P D$$XE܅= ;u C$PE8u UԋB$PEE8u U܋B$PEE8u UB$P}E8u U؋B$PEUDDDDvD^DFD.DDt ;u C$P}tU :u B$P}tE8u U؋B$P}tE8u UԋB$P$RBE8u UB$PE8u UB$PE8u UB$P>u F4$P?u G<$PE8u EP$RډЃ<[^_]UWVSu F4$P޻F EED$UԉT$E$\mE8u UԋB$PE}t}]FEED$UЉT$E$\xd}EE8u UЋB$PE}t G}t$E$lÉDž%=D.DDt ;u C$P}tE8u UԋB$P}tE8u UЋB$P$ؐ=E8u U܋B$PE8u U؋B$P>u F4$PE8u EP$RE8u EP$RЃ<[^_]UWVSu F4$PE8u EP$RE8u EP$RډЃ [^]UWVSEEEU =E$DÅuD*ED$\$U $\yD*P}E ;u C$P}t<ФD$E$dÉƅiD+U T$UB $lÉƅ,D-t ;u C$PD$$,ÅuD.n$E ;u C$P}C$KL1b/ÅuD.8u @$PE D$UB$lÉƅ<D1t ;u C$PD$$+ÅuD2~$E ;u C$P}S$K\0r.ÅuD2!8u @$PE D$UB$lÅuD5D$$+EuD5?u G<$P}ED$$5+EuD5\E8u UB$PEEED$$!+yD5  ;u C$PD$$1*EuD6ФD$U$dEuD6$ÅuD6XEC US\$E$XEuD6U :u B$P ;u C$PE$EuD6U :u B$PEED$<$XÅuD6zU :u B$PE?u G<$P߉\$E D$UB$yD6 ;u C$P]t ;u C$P}tE8u UB$P}tE8u UB$P$d,?u G<$PE8u UB$PE8u UB$PE 8u U B$P[^_]UWVSLEEEEEEU =EUEE P;tAD$$u+$ DMU $uDPEܡD$E$dEuDQaE$xyDQ6AE8u EP$RE D$U$dEuDQ$EuDQED$E$XEuDQvE8u EP$REE8u EP$REE$xyDQu E8u EP$R@E?u G<$P}EG @EE8u U؋B$PEEEG @EU :u B$PEEEU9E9$0D$U$dE&$ED$E$XEE8u EP$REE8u EP$REE8u EP$RE$DEuD[ED$<$lEuD[E8u EP$RE;E؋E8u EP$RE_G @ EE$EuD\2E8u EP$REED$E؉$XEuD\E8u EP$RE$DEuD\ED$ED$<$yD\aE8u EP$REEU :u B$PEE8u EP$REEE}tE8u EP$RE}tE8u EP$RE}tE8u EP$REED$ED$E$@D$U$dƅ$ED$4$XE>u F4$PE8u EP$REE8u EP$RE}} }}}:G 04$@T>u F4$P;]U D E$E-UP EED$Eԉ$XEE8u EP$REE$xu E8u EP$R@E?u G<$P}EG @EU :u B$PEEEG @EU :u B$PEEEgPD$U$dƅd$EdE EU P EpED$0$XECE8u EP$REE8u UЋB$PEEE$DEuDuL ED$UЉ$lEuDu E8u EP$RE$ƅuDu EF Et$Eԉ$XEuDu >u F4$PE$xyDuM u E8u EP$R@E?u G<$P}EG @EU :u B$PEEEG @EU :u B$PEEEU9E9q0D$U$dEe$ED$E$XƅE8u EP$REE8u EP$RE>u F4$P$DEuD|ED$<$lEuD|E8u EP$RE;E؋E8u EP$RESG @ EE$EuD}&E8u EP$REED$E؉$XEuD}E8u EP$RE$DƅuD}ED$t$<$yD}Y>u F4$PEU :u B$PEE8u EP$REEE}tE8u EP$RE}tE8u EP$RE}tE8u EP$RE}tE8u EP$REt>u F4$P}tE8u EP$REED$ED$E$@D$U$dEV$ƅZD$E$XEZE8u EP$RE>u F4$PE8u EP$RE}} }}o}G EE$@E E8u EP$RE]ȋE9U D E$EEUB EED$Eԉ$XƅE8u EP$RE4$xEȅu>u F4$P5@?u G<$P$DED$UЉ$lE~E8u EP$RE$EaUP EED$Eԉ$XENE8u EP$REE$xEȅ2u E8u EP$R@E?u G<$P}EG @EU :u B$PEEEG pU :u B$PuԾDzDzDjDOD4ED$ED$E$EEEDDDDDvD^DFD.DDz}tE8u EP$RE}tE8u EP$RE}tE8u EP$RE}tE8u EP$RE}tE8u EP$REt>u F4$PED$ED$E$EȡU :u B$PEЃtX!EED$ED$E$UȉEEEL0D$Eԉ$tU $EuDED$Eԉ$XEuDE8u EP$REE8u EP$REUU8DYjDYOD`4D`D`ED$ED$E$EEEDbDdDdvDf^DsFDs.DsDY}tE8u EP$R}tE8u EP$R}tE8u EP$Rt>u F4$P}tE8u EP$R}tE8u EP$R$8E?u G<$PE8u U؋B$PE8u UԋB$PE8u UЋB$PE8u UB$PE 8u U B$PẼL[^_]UED$$P US]{ tC 8u C P$RC$[]UUz tED$B $U …uUS]{ tC 8u C P$RC []UED$$PP PU]uu~tF8u FP$R{ tC 8u C P$R{tC8u CP$RF4$]u]U]u}} u]{tt$C$׉…u5{ tt$C $׉…u{tt$C$׉…uЋ]u}]US]{tC8u CP$RC{ tC 8u C P$RC {tC8u CP$RC[]UVSuE $Døt$F@8\$4$P ;u C$P[^]UED$$UEP$U]U]UVSuE $Døt$F@8\$4$P ;u C$P[^]UWVSED$D$ D$D$$ТuD $"8uDD$D$.Т$yD$yD|$yDQ 0@P`$@yD|D$@D$;Т$yD| @`$@yD bD$@D$HТ$yD %0@$@yDID$@D$RТ$yDI@@$LÅuDzD$`D$Т$|yD@ ;u C$P$LÅuDУS УS B\$0$ƅuD ;u C$PУD$4$dÅuDj 8u P$R D$4$dÅuD08u0P$R0>u F4$P$LƅuDV t$$ÅuDq>u F4$PD$$dƅuD.8uP$R5 ;u C$PP8uPP$RP D$pD$Т$|yD $DÅuD \$ƅuD .D$ $XDžuD >u F4$P$ƅuD F F$LEuD pUB EP BUB xB p @8u@P$RE@E$DÅuD$DžuDX G|$ $XƅuDk?u G<$Pt$D$Т$|yD>u F4$P$DEuD$ÅuDUP CE\$ $XDžuD^ ;u C$P|$D$Т$|yD?uoG<$Pdt ;u C$Pt>u F4$Pt?u G<$P}tE8u UB$P$b[^_]U(]uu] uD$q($c}t95t9^t\$F$t5F@ D$C D$ ED$D$,$]u]UWVS,u EED$$hÅtkuu$LDžteEТ$Pƅt:Et-ED$UT$t$ ED$D$ʓ$TEt?u G<$Pt ;u C$P}tE8u UB$PE,[^_]U]uu t$E$dÅut$$$؋]u]UD$ϓ0$USE D$E$Åu $t؃[]UE D$E$…t8u @$Pk UWVS ]} uttt95u>u F4$P,t(F;tD$,$u!=ڋ[  :u B$PC;tD$C$t $C;D$C$urC;tg;<u;9=tD$,$P?u G<$Pߋ[$C@ D$D$P,$t$|$$u F4$P [^_]UH4P8@u F4$P}tE8u UB$P}tE8u UB$P}tE8u UB$PL[^_]Ð%%@%%d%%X%%D%\%L%p%H%%%%l%%%%%% %x%%%t%%8%%`%%|%%h%P%T%%%%%%%%%%%4%U] U`8t `QA`uÍ&USot)t'oKu$j*Y[]1=o @ou뾍'US`u5o `t$tt&oKu$j躥X[]1=o @ouÐUpQpr]ÐU]HUBSdT$U1ۉT$$ uFJx|*Au Jy;G@S \gnP"`@pƒ0(\p̒dR`0@ERRP=RT2BS`(ES1TP1SLU9!U (8UBUUn$E)a@pcmprrepOO_d_speedups._ExtremeType.__init___d_speedups._ExtremeType.__hash___d_speedups._ExtremeType.__cmp__self_d_speedups._ExtremeType.__richcmp__range_mapO_d_speedups.concatenate_rangestableob_d_speedups.dispatch_by_inequalities_d_speedups.dispatch_by_mroargtupleexpr_defs_d_speedups.ExprCache.__init___d_speedups.__getitem___d_speedups.ExprCache.__getitem___d_speedups.BaseDispatcher.__getitem__DispatchErrorIndexErrorInstanceTypeKeyErrorMaxMinNoApplicableMethodsTypeError__all____bases____class____getitem____hash____nbases_acquire_dispatcher_release_startNodeappendconcatenate_rangesdispatch_by_inequalitiesdispatch_by_mrokeysmapobjectreseedsorttypes_d_speedups._ExtremeType_d_speedups.ExprCache_d_speedups.BaseDispatcher_d_speedups__builtin____builtins___ExtremeTypeExprCacheBaseDispatcher_d_speedups.pyxMissing type objectArgument '%s' has incorrect type (expected %s, got %s)__import__OOOOunpack sequence of wrong sizeraise: arg 3 must be a traceback or Noneinstance exception may not have a separate valueexceptions must be strings, classes, or instances, not %s-LIBGCCW32-EH-2-SJLJ-GTHR-MINGW32w32_sharedptr->size == sizeof(W32_EH_SHARED)%s:%u: failed assertion `%s' ../../gcc/gcc/config/i386/w32-shared-ptr.cGetAtomNameA (atom, s, sizeof(s)) != 0RnH2(,0UB_d_speedups.pydinit_d_speedupsTlh$,8DLXx ,H\l|$8H`t 4Pdx 4Ll(8L$,8DLXx ,H\l|$8H`t 4Pdx 4Ll(8LAddAtomAFindAtomAGetAtomNameA$__dllonexit_errno_iobabort0fflush9fprintf?freermallocPyArg_ParseTupleAndKeywordsPyBaseObject_Type(PyClass_Type*PyCode_NewJPyDict_GetItemPPyDict_NewUPyDict_Type\PyErr_Clear^PyErr_ExceptionMatches_PyErr_Fetch`PyErr_FormatdPyErr_NormalizeExceptionePyErr_OccurrediPyErr_RestorevPyErr_SetNonewPyErr_SetObjectxPyErr_SetStringPyExc_AssertionErrorPyExc_AttributeErrorPyExc_IndexErrorPyExc_NameErrorPyExc_SystemErrorPyExc_TypeErrorPyExc_ValueErrorPyFrame_NewPyImport_AddModulePyInstance_TypePyInt_AsLongPyInt_FromLong PyIter_NextPyList_NewFPyModule_GetDictPyObject_CallFunctionPyObject_CallObjectPyObject_CmpPyObject_GC_DelPyObject_GetAttrPyObject_GetAttrStringPyObject_GetItemPyObject_GetIterPyObject_IsInstancePyObject_IsTruePyObject_SetAttrPyObject_SetAttrStringPyObject_SetItemPyObject_SizePyObject_TypePySequence_GetItemPySequence_TuplePyString_FromStringPyString_FromStringAndSizePyString_InternFromString PyString_TypePyThreadState_Get5PyTraceBack_Here7PyTraceBack_Type;PyTuple_New=PyTuple_Size>PyTuple_TypeAPyType_IsSubtypeBPyType_ReadyCPyType_TypePy_InitModule4_Py_NoneStructKERNEL32.dllmsvcrt.dll((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((python23.dllC0M0q0000001,1b1l111122;2C2w2~222233"3(363C3N3U3[333333333 444"4(444444455556(656M6T6Z6o6z6666666%70777=7i7u7|77777778 88>8P8W8]888888888 99"9(9R9]9d9j999999999:(:/:5:R:[:b:h::::::::;;&;-;3;j;|;;;;;;;;;;;0<>^>n>y>>>>>>>>>>>D?O?V?\????????? T00$01080>001A1Q1h111D2K2Q2_2f2l2z222222222222222223 3333S4[4n444444445.5>5{55555555556 66W6g6p6w6}66666i778#8/868<8G8N8T8_8f8l88999999999::3:::@:V:b:i:o:}::::::8;?;E;S;c;;;;;;;;<<# >(>>>>>>>????????000"00070=0H0O0U0`0g0m0x0000000001111=2h2o2u22 33%30373=3]3f3m3s33333334 44,454H4O4U4g4444444445%585?5E5W555555555666Z6a6g6666666777$70777=7S7^7e7k77777777848?8F8L888889999999::: :':-:B:L:S:Y:j:z:::::::::; ;;;0;<;C;I;e;q;x;~;;;;; <<<<<<>&>,>e>q>x>~>>>>>>>>????@L 0#0;0001G1{11!212H2x222222 333#3V3a3h3n3333333334444444V5b5i5o55555566$6*6c6o6v6|666666666B8H8M8]8u88/989999:):D:y:::;;;;;;;;;;;;;;<<)/>7>Q>>>>>>>>>??"?(?}???????????????P 00>0E0K0Y0`0f0t0{000000000000000001Y22!3,373X4~444_555555555 666 6'6-6;6G6L6U6^6e6k6{666666666666666667 7777&7-737D7L7Q7Z7c7j7p77777777777777777788 888#848<8A8J8S8Z8`8o8s8888888888889 999(9/999E9X9_9e99999999999999 ::$:F:Q:X:^:l:v:::::::::::: ;,;3;?;M;R;W;`;i;r;{;;;;;;;;;;;;; <<<=->4>:>P>[>b>h>|>>>>>>>>>>>>?z??????` 000P0U0^0x000000=1L1W1q1v111111262\2f2k2v2222222223 333!3,3Y3^3i3|333$4@4Z4`4s4t5566-6<6E6]6n6t66667 77777788"828B8R8b8r88888888899"929B9R9b9r999999999::":2:B:R:b:r::::::::;#;-;>;I;i;r;};;;;;;;;<1%>0>;>F>Q>\>d>n>>>>>>?#?B?R?b?r????????<0@0H0P0T00000111 11111 1$1(1,1014181<1@1D1H1L1P1T1X1\1`1d1h1l1p1t1x1|11111111111111111111111111122 2222L2X2h2l2p2t2x2|22222222 3,3L3X3p3t3x3333333 4,4L4X4p4t4x4444445555 5$5,5@5D5`5PK:8d**dispatch/ast_builder.pyc; ^Gc@sdklZlZlZlZlZdklZdkl Z dkZdkZdk Z dk Z ddgZ dZ dZhee <ee<ee scCs|it|dS(Ni(sbuildersConstsevalsnodelist(sbuildersnodelist((s-build\bdist.win32\egg\dispatch\ast_builder.pys ss LeftShifts RightShiftsAddsSubsMulsDivsModsFloorDivcCs.t|t|dd|d |dSdS(Niii(sgetattrsbuildersopssnodelist(sbuildersnodelist((s-build\bdist.win32\egg\dispatch\ast_builder.pys left_assoc scGs1x&|D]}t||t|}qW|SdS(N(sargssargsinstancemethodsfstype(sfsargssarg((s-build\bdist.win32\egg\dispatch\ast_builder.pyscurry*scCsTgi}tdt|dD]}|||q ~}t|||SdS(s=Compile 'NODE (OP NODE)*' into (type, [ node1, ..., nodeN ]).iiN( sappends_[1]srangeslensnodelistsisitemssgetattrsbuildersopname(sopnamesbuildersnodelistsisitemss_[1]((s-build\bdist.win32\egg\dispatch\ast_builder.pys com_binary0s=sTuplesOrs2.5cCs#|i|d|d|dSdS(Niii(sbuildersIfElsesnodelist(sbuildersnodelist((s-build\bdist.win32\egg\dispatch\ast_builder.pystestCssAndcCs|i|dSdS(Ni(sbuildersNotsnodelist(sbuildersnodelist((s-build\bdist.win32\egg\dispatch\ast_builder.pysnot_testLsc CsHt|djo|io[|igi}tdt|ddD]#}||d |||d!qG~Sng}xtdt|dD]}||d}|d}|dt i joB|d}t|djo!|djo d}qd}qn |d}|i|||fqW|i|d|SdS( Niiiiisnotsnot insis not(slensnodelistsbuilderssimplify_comparisonssAndsappends_[1]srangesisresultssnlsnstokensNAMEstypesCompare(sbuildersnodelistsisresultssns_[1]snlstype((s-build\bdist.win32\egg\dispatch\ast_builder.pys comparisonTs [     sBitorsBitxorsBitands UnaryPluss UnaryMinussInvertcCs't|t|dd|dSdS(Niii(sgetattrsbuilders unary_opssnodelist(sbuildersnodelist((s-build\bdist.win32\egg\dispatch\ast_builder.pysfactorscCsn|ddtijo|i|d |dSn|d}|d }|dd}|tijot|||dSn|ti jo|i ||ddSn|ti jo|d}x"t |djo|d}qW|dtijoJ|d}|i|titid |f|titi |ffSn|i||Sntd|dS(Niiiiis Unknown power(snodeliststokens DOUBLESTARsbuildersPowersnodestsLPARscom_call_functionsDOTsGetattrsLSQBsitemslensCOLONslinenos Subscriptssymbols subscriptsSTRINGssyssmaxintsAssertionError(sbuildersnodelistsnodesitemstslineno((s-build\bdist.win32\egg\dispatch\ast_builder.pyspowers(     7cCs|dd}|tijo>|ddtijo|ifSnt||dSne|tijo>|ddti jo|i fSnt ||dSn|ti jo|ddti jo f}nV|d}gi}tdt|dD]"}|||||dfq~}|i|Sn|tijo|i|dSnZ|tijoI|itdigi}|dD]}||dq~Sntd|dS(Niiiis s Unknown atom(snodelistststokensLPARsRPARsbuildersTuplesbuildsLSQBsRSQBsLists listmakersLBRACEsRBRACEsitemssdmsappends_[1]srangeslensisDicts BACKQUOTEs BackquotesSTRINGsConstsevalsjoinsnsAssertionError(sbuildersnodelistsdmsisitemssns_[1]st((s-build\bdist.win32\egg\dispatch\ast_builder.pysatoms(  KIcCs|dtijo|i|ffttSng}g} t |}xt d|dD]w}||}|dtijp|dtijoPnt|| \} } | o| i| q\|i| q\W|d}||jo||dtijo|d}nt} }x||jor||} ||d}|d}| dtijo |} q!| dtijo |}q!td| fq!W|i||| | |SdS(Niiiisunknown node type: %s(snodeliststokensRPARsbuildersCallFuncs primaryNodesNonesargsskwslens len_nodelistsrangesisnodesSTARs DOUBLESTARs com_argumentsiskwsresultsappendsCOMMAs star_nodes dstar_nodestokschsAssertionError(sbuilders primaryNodesnodelistsnodeschs len_nodelists dstar_nodesargssiskwsresultsiskws star_nodestok((s-build\bdist.win32\egg\dispatch\ast_builder.pyscom_call_functions8   ( %      cCst|djo&|o tdnd|dfSn|d}x6t|djo|dtijo|d}qFW|dtijotd|fndti|d |df|dffSdS(Nis!non-keyword arg after keyword argiis#keyword can't be an expression (%r)i(slensnodelistskws SyntaxErrorsnstokensNAMEsSTRING(snodelistskwsn((s-build\bdist.win32\egg\dispatch\ast_builder.pys com_argument"s  'cCsgg}xMtdt|D]6}||dtijoqn|i||qW|i |SdS(Nii( svaluessrangeslensnodelistsistokensCOMMAsappendsbuildersList(sbuildersnodelistsisvalues((s-build\bdist.win32\egg\dispatch\ast_builder.pys listmaker6sc Cs|ddtijo|itSn|}t|}x&t |dt jo|d}q>W|d}|ddt i j}|oGtid|f}}}t|ddjo|dd}qn*tid |f}titi |f}|djo|d|df\}}n|djoY|ddtijo|d}q|o|d}q|d|df\}}n]|djo@|ddtijo| o|d}qq|d}ntd ||o|i|||Sn|i||SdS( NiiisNoneiiiisUnrecognized subscript(snodeliststokensDOTsbuildersConstsEllipsissitemslensnlstypestupleslinenossymbolssliceops have_stridesSTRINGsstartsstopsstridesNUMBERssyssmaxintsCOLONsAssertionErrorsSliceobjsSlice( sbuildersnodelists have_stridesnlsstartsstopsitemsstrideslineno((s-build\bdist.win32\egg\dispatch\ast_builder.pys subscriptLs>    cCs>x"t|djo|d}qWt|d||SdS(Niii(slensnodelists productionsbuilder(sbuildersnodelist((s-build\bdist.win32\egg\dispatch\ast_builder.pysbuildwscCs't|ti|iddSdS(Ni(sbuildsbuildersparsersexprstotuple(sexprsbuilder((s-build\bdist.win32\egg\dispatch\ast_builder.pys parse_expr}s(:stokenstok_namesNAMEsNUMBERsSTRINGs ISNONTERMINALssymbolssym_namesnewsinstancemethodsparserssyss__all__s_names_consts productions LEFTSHIFTs RIGHTSHIFTsPLUSsMINUSsSTARsSLASHsPERCENTs DOUBLESLASHsopss left_assocscurrys com_binarystestlists subscriptlists testlist_gexpstestsversionsor_testsand_testsnot_tests comparisonsexprsxor_exprsand_exprs shift_exprs arith_exprstermsTILDEs unary_opssfactorspowersatomscom_call_functions com_arguments listmakers subscriptsitemsssymsnamesglobalssbuilds parse_expr(-s parse_exprsparsersNUMBERs com_binaryssyssnot_tests listmakersatomsxor_exprs__all__s shift_exprs testlist_gexpssym_names_consts productionsbuildsfactorstests subscripts subscriptlistsand_exprscom_call_functionsSTRINGspowersopsssymbolstestlistsand_testsinstancemethodssyms unary_opss comparisonsnames ISNONTERMINALstermsNAMEs arith_exprs com_argumentstok_names left_assocsor_tests_namestokensexprscurry((s-build\bdist.win32\egg\dispatch\ast_builder.pys?sL%  $   !f     *  - % )   &  PK:8=,dispatch/predicates.pyc; ^Gc@s=dklZdkTdklZlZlZlZdklZl Z dkl Z l Z l Z dk lZdkZdkZdkZdklZdd d d d d ddddddddgZdZdZdZdZdZyeWn ej odklZnXd fdYZdefdYZdefdYZdefd YZ defd!YZ!defd"YZ"defd#YZ#d efd$YZ$defd%YZ%d&e fd'YZ&d e&fd(YZ'd e&fd)YZ(d*Z)d e fd+YZ*ei+gd,Z,e,i-egd-Z,dfd.YZ.d/Z/ei0d0gd1Z1e1i-e2gd2Z3e1i-e4gd3Z5d4Z6d5Z7d6e.fd7YZ8d8Z9e,i-d9gd:Z:e,i-d;gd<Z;dS(=(s generators(s*(s Inequalitys SignaturesExprBasesdefault(sSubclassCriterions NullCriterion(sAbstractCriterionsPointers Predicate(sbuildN(sNoneTypesCalls AndCriterions NotCriterionsTruthCriterions ExprBuildersConstsGetattrsTuplesdispatch_by_truthsOrExprsAndExprsCriteriaBuildersexpressionSignaturesIfElsecCs||jSdS(N(so1so2(so1so2((s,build\bdist.win32\egg\dispatch\predicates.pysis_scCs||jSdS(N(so1so2(so1so2((s,build\bdist.win32\egg\dispatch\predicates.pysin_scCs||j SdS(N(so1so2(so1so2((s,build\bdist.win32\egg\dispatch\predicates.pysis_notscCs||jSdS(N(so1so2(so1so2((s,build\bdist.win32\egg\dispatch\predicates.pysnot_inscCs!|i}|i||SdS(N(sd1scopysupdatesd2(sd1sd2((s,build\bdist.win32\egg\dispatch\predicates.pysadd_dict s  (s ImmutableSetcBs6tZeZdZdZdZhdei<dei <dei <dei <dei <d ei <d ei <d e<d e<d e<dedZ?dZ@dZAdZBdZCdZDdZEdZFRS(NcGs||_||_dS(N(s argumentssselfs namespaces(sselfs argumentss namespaces((s,build\bdist.win32\egg\dispatch\predicates.pys__init__.s cCsb||ijo|i|Snx0|iD]%}||jot||Sq)q)Wt|dS(N(snamesselfs argumentss namespacessnssConsts NameError(sselfsnamesns((s,build\bdist.win32\egg\dispatch\predicates.pysName2s  cCst|SdS(N(sConstsvalue(sselfsvalue((s,build\bdist.win32\egg\dispatch\predicates.pysConst<ss>s>=ss!=s==sinsnot insissis notcCs<|\\}}t|i|t||t||SdS(N(sopsothersCallsselfs_cmp_opssbuildsinitExpr(sselfsinitExprs.4sopsother((s,build\bdist.win32\egg\dispatch\predicates.pysCompareGscCs/tt||t||t||SdS(N(sIfElsesbuildsselfstvalscondsfval(sselfstvalscondsfval((s,build\bdist.win32\egg\dispatch\predicates.pysIfElseLscsd}|SdS(Ncs&tt||t||SdS(N(sCallsopsbuildsselfsleftsright(sselfsleftsright(sop(s,build\bdist.win32\egg\dispatch\predicates.pysmethodTs(smethod(sopsmethod((sops,build\bdist.win32\egg\dispatch\predicates.pysmkBinOpSs csd}|SdS(NcsKt||d}x-|dD]!}t|t||}qW|SdS(Nii(sbuildsselfsitemssresultsitemsCallsop(sselfsitemssitemsresult(sop(s,build\bdist.win32\egg\dispatch\predicates.pysmethodcs  (smethod(sopsmethod((sops,build\bdist.win32\egg\dispatch\predicates.pysmultiOpbs csd}|SdS(Ncstt||SdS(N(sCallsopsbuildsselfsexpr(sselfsexpr(sop(s,build\bdist.win32\egg\dispatch\predicates.pysmethodos(smethod(sopsmethod((sops,build\bdist.win32\egg\dispatch\predicates.pysunaryOpns csd}|SdS(Ncs;tgi}|D]}|t||q~SdS(N(sTuplesopsappends_[1]sitemssitemsbuildsself(sselfsitemss_[1]sitem(sop(s,build\bdist.win32\egg\dispatch\predicates.pysmethod}s(smethod(sopsmethod((sops,build\bdist.win32\egg\dispatch\predicates.pystupleOp|s cCsttgi}|D]\}}|t||q~}ttgi}|D]\}}|t||qS~}t t t t ||SdS(N(sTuplestuplesappends_[1]sitemssksvsbuildsselfskeyssvalssCallsdictszip(sselfsitemsskeyss_[1]svsvalssk((s,build\bdist.win32\egg\dispatch\predicates.pysDicts??cCsbt||t||f\}}t|totti||Sntti ||SdS(N( sbuildsselfsleftsrights isinstancestuplesCallsoperatorsgetslicesgetitem(sselfsleftsright((s,build\bdist.win32\egg\dispatch\predicates.pys Subscripts$cCs t||t||fSdS(N(sbuildsselfsstartsstop(sselfsstartsstop((s,build\bdist.win32\egg\dispatch\predicates.pysSlicescGs;ttgi}|D]}|t||q~SdS(N(sCallsslicesappends_[1]sargssargsbuildsself(sselfsargss_[1]sarg((s,build\bdist.win32\egg\dispatch\predicates.pysSliceobjscCsJt||}t|tott|i|Snt||SdS(N( sbuildsselfsexprs isinstancesConstsgetattrsvaluesattrsGetattr(sselfsexprsattr((s,build\bdist.win32\egg\dispatch\predicates.pysGetattrscCs8tgi}|D]}|t||q~SdS(N(sAndExprsappends_[1]sitemssexprsbuildsself(sselfsitemss_[1]sexpr((s,build\bdist.win32\egg\dispatch\predicates.pysAndscCs8tgi}|D]}|t||q~SdS(N(sOrExprsappends_[1]sitemssexprsbuildsself(sselfsitemss_[1]sexpr((s,build\bdist.win32\egg\dispatch\predicates.pysOrsc Cst||}t|to| o | o| o>t |i gi }|D]}|t||qN~Sn`|p|p |p|o6|oottgi }|D]}|t||q~}|o+t ti|t tt||}q!n|ot||}n|p|o|p tf}|o9|i|}|ot t|t||}qn|ot||}nt t|||Sqt t||Snt t|SdS(N(sbuildsselfsfuncExprsfuncs isinstancesConstskwsstarsdstarsCallsvaluesappends_[1]sargssargsTuplestuplesoperatorsaddsDictsadd_dictsapply( sselfsfuncExprsargsskwsstarsdstars_[1]sfuncsarg((s,build\bdist.win32\egg\dispatch\predicates.pysCallFuncs*(>9/#(Gs__name__s __module__sTruessimplify_comparisonss__init__sNamesConstsoperatorsgtsgesltslesneseqsin_snot_insis_sis_nots_cmp_opssComparesIfElsesmkBinOpslshifts LeftShiftspowsPowersrshifts RightShiftsaddsAddssubsSubsmulsMulsdivsDivsmodsModsfloordivsFloorDivsmultiOpsor_sBitorsxorsBitxorsand_sBitandsunaryOpsposs UnaryPlussnegs UnaryMinussinvertsInvertsreprs Backquotesnot_sNotstupleOpstuplesTupleslistsListsDicts SubscriptsSlicesSliceobjsGetattrsAndsOrsCallFunc(((s,build\bdist.win32\egg\dispatch\predicates.pys ExprBuilder*sL  ~                 s LogicalExprcBs#tZdZdZdZRS(NcGsqx3|D]+}t|t oti||SqqWt|igi}|D]}||i qM~SdS(N( sargexprssargs isinstancesConstsExprBases__new__sklasss immediatesappends_[1]svalue(sklasssargexprss_[1]sarg((s,build\bdist.win32\egg\dispatch\predicates.pys__new__s cGs(||_tt||f|_dS(N(sargexprssselfshashstype(sselfsargexprs((s,build\bdist.win32\egg\dispatch\predicates.pys__init__s cCs-t|t|jo|i|ijSdS(N(stypesselfsothersargexprs(sselfsother((s,build\bdist.win32\egg\dispatch\predicates.pys__eq__s(s__name__s __module__s__new__s__init__s__eq__(((s,build\bdist.win32\egg\dispatch\predicates.pys LogicalExprs  cBs-tZdZdZeegdZRS(s$Lazily compute logical 'or' of exprscs2t|i|id}|tffSdS(Ncs1x&D]}||}|oPqqW|SdS(N(sargIdssargsgetsval(sgetsargsval(sargIds(s,build\bdist.win32\egg\dispatch\predicates.pysor_s   (smapsgenericsgetExpressionIdsselfsargexprssargIdssor_sEXPR_GETTER_ID(sselfsgenericsargIdssor_((sargIdss,build\bdist.win32\egg\dispatch\predicates.pys asFuncAndIdss cCs%x|D]}|oPqqW|SdS(N(sseqsitem(sklasssseqsitem((s,build\bdist.win32\egg\dispatch\predicates.pys immediates  (s__name__s __module__s__doc__s asFuncAndIdssass classmethods immediate(((s,build\bdist.win32\egg\dispatch\predicates.pysOrExprs  cBs-tZdZdZeegdZRS(s%Lazily compute logical 'and' of exprscs2t|i|id}|tffSdS(Ncs2x'D]}||}| oPqqW|SdS(N(sargIdssargsgetsval(sgetsargsval(sargIds(s,build\bdist.win32\egg\dispatch\predicates.pysand_s   (smapsgenericsgetExpressionIdsselfsargexprssargIdssand_sEXPR_GETTER_ID(sselfsgenericsargIdssand_((sargIdss,build\bdist.win32\egg\dispatch\predicates.pys asFuncAndIdss cCs&x|D]}| oPqqW|SdS(N(sseqsitem(sklasssseqsitem((s,build\bdist.win32\egg\dispatch\predicates.pys immediates  (s__name__s __module__s__doc__s asFuncAndIdssass classmethods immediate(((s,build\bdist.win32\egg\dispatch\predicates.pysAndExprs  cBs-tZdZdZeegdZRS(s!Python 2.5 conditional expressioncs2t|i|id}|tffSdS(Ncs5|do|dSn|dSdS(Niii(sgetsargIds(sget(sargIds(s,build\bdist.win32\egg\dispatch\predicates.pysifelses(smapsgenericsgetExpressionIdsselfsargexprssargIdssifelsesEXPR_GETTER_ID(sselfsgenericsargIdssifelse((sargIdss,build\bdist.win32\egg\dispatch\predicates.pys asFuncAndIdss cCs#|do |dSn|dSdS(Niii(sseq(sklasssseq((s,build\bdist.win32\egg\dispatch\predicates.pys immediates (s__name__s __module__s__doc__s asFuncAndIdssass classmethods immediate(((s,build\bdist.win32\egg\dispatch\predicates.pysIfElses   cBsAtZdZedZedZdZdZdZRS(sBCompute an expression by calling a function with an argument tuplecGsqx6|D].}t|t oti|||SqqWt|gi}|D]}||i qM~SdS(N( sargexprssargs isinstancesConstsExprBases__new__sklasssfunctionsappends_[1]svalue(sklasssfunctionsargexprss_[1]sarg((s,build\bdist.win32\egg\dispatch\predicates.pys__new__#s cGs4||_||_tt|||f|_dS(N(sfunctionsselfsargexprsshashstype(sselfsfunctionsargexprs((s,build\bdist.win32\egg\dispatch\predicates.pys__init__)s  cCs7t|to#|i|ijo|i|ijSdS(N(s isinstancesothersTuplesfunctionsselfsargexprs(sselfsother((s,build\bdist.win32\egg\dispatch\predicates.pys__eq__.scs)dtt|iifSdS(Ncs i|S(N(sselfsfunctionsargs(sargs(sself(s,build\bdist.win32\egg\dispatch\predicates.pys4s(stuplesmapsgenericsgetExpressionIdsselfsargexprs(sselfsgeneric((sselfs,build\bdist.win32\egg\dispatch\predicates.pys asFuncAndIds3scCsd|if|ifSdS(NsTuple%r(sselfsfunctionsargexprs(sself((s,build\bdist.win32\egg\dispatch\predicates.pys__repr__8s( s__name__s __module__s__doc__stuples__new__s__init__s__eq__s asFuncAndIdss__repr__(((s,build\bdist.win32\egg\dispatch\predicates.pysTuple s     cBs)tZdZdZdZdZRS(sDCompute an expression by calling a function with 0 or more argumentscCs4||_||_tt|||f|_dS(N(sob_exprsselfs attr_nameshashstype(sselfsob_exprs attr_name((s,build\bdist.win32\egg\dispatch\predicates.pys__init__Ls  cCs7t|to#|i|ijo|i|ijSdS(N(s isinstancesothersGetattrsob_exprsselfs attr_name(sselfsother((s,build\bdist.win32\egg\dispatch\predicates.pys__eq__QscCs*td|i|i|iffSdS(Nslambda ob: ob.%s(sevalsselfs attr_namesgenericsgetExpressionIdsob_expr(sselfsgeneric((s,build\bdist.win32\egg\dispatch\predicates.pys asFuncAndIdsVs(s__name__s __module__s__doc__s__init__s__eq__s asFuncAndIds(((s,build\bdist.win32\egg\dispatch\predicates.pysGetattrIs   cBs2tZdZdZdZdZdZRS(sCompute a 'constant' valuecCsc||_ytt||f|_Wn4tj o(tt|t|f|_nXdS(N(svaluesselfshashstypes TypeErrorsid(sselfsvalue((s,build\bdist.win32\egg\dispatch\predicates.pys__init___s  cCs$t|to|i|ijSdS(N(s isinstancesothersConstsvaluesself(sselfsother((s,build\bdist.win32\egg\dispatch\predicates.pys__eq__fscsdffSdS(NcsiS(N(sselfsvalue((sself(s,build\bdist.win32\egg\dispatch\predicates.pysjs((sselfsgeneric((sselfs,build\bdist.win32\egg\dispatch\predicates.pys asFuncAndIdsiscCsd|ifSdS(Ns Const(%r)(sselfsvalue(sself((s,build\bdist.win32\egg\dispatch\predicates.pys__repr__ls(s__name__s __module__s__doc__s__init__s__eq__s asFuncAndIdss__repr__(((s,build\bdist.win32\egg\dispatch\predicates.pysConst\s    cBs;tZdZdZdZdZdZdZRS(sDCompute an expression by calling a function with 0 or more argumentscGs| oti||Snx6|D].}t|t oti|||Sq#q#Wt|gi}|D]}||i qi~SdS(N( sargexprssExprBases__new__sklasssfunctionsargs isinstancesConstsappends_[1]svalue(sklasssfunctionsargexprss_[1]sarg((s,build\bdist.win32\egg\dispatch\predicates.pys__new__vscGs4||_||_tt|||f|_dS(N(sfunctionsselfsargexprsshashstype(sselfsfunctionsargexprs((s,build\bdist.win32\egg\dispatch\predicates.pys__init__~s  cCs7t|to#|i|ijo|i|ijSdS(N(s isinstancesothersCallsfunctionsselfsargexprs(sselfsother((s,build\bdist.win32\egg\dispatch\predicates.pys__eq__scCs&|itt|i|ifSdS(N(sselfsfunctionstuplesmapsgenericsgetExpressionIdsargexprs(sselfsgeneric((s,build\bdist.win32\egg\dispatch\predicates.pys asFuncAndIdsscCsd|if|ifSdS(NsCall%r(sselfsfunctionsargexprs(sself((s,build\bdist.win32\egg\dispatch\predicates.pys__repr__s(s__name__s __module__s__doc__s__new__s__init__s__eq__s asFuncAndIdss__repr__(((s,build\bdist.win32\egg\dispatch\predicates.pysCallrs     sMultiCriterioncBsbtZdZdZeiZeZdZ dZ dZ dZ dZ dZdZRS( s2Abstract base for boolean combinations of criterias node_typecGs%tt|gf\}}|di}x|D]}|i|j otd|n|i|joF|i gi }|iD]!}||jo||qq~q/||jo|i |q/q/Wt |djo |dSnti|}||_ti|t||SdS(NisMismatched dispatch typesi(smapsISeededCriterionscriteriasalls node_typesntscs ValueErrors __class__sklasssextendsappends_[1]slensobjects__new__sselfsAbstractCriterions__init__s frozenset(sklassscriteriasallsselfscs_[1]snt((s,build\bdist.win32\egg\dispatch\predicates.pys__new__s  F   cCsIh}x2|iD]'}x|iD]}t||s=s<=s=>s=s!=s==sissis notsinsnot incCs|\\}}t|i|}t|i|}t|t o ||i jo#|||i |f\}}}nt|t o|i i o|i |}n|djp |djo4t||i|dj}|tj o|Sqq|djp |djoQ|itjott}ntt|i}|djo |}qpnt||i}t||fgSnt|ii|||ff|i SdS(Nsinsnot insissis not(sopsothersbuildsselfs expr_buildersinitExprsleftsrights isinstancesConsts _mirror_opssmodestruths_rev_opss compileInsvaluescondsNones ICriterionsNoneTypesPointers Inequalitys SignaturesexpressionSignaturesCompare(sselfsinitExprs.4sopsothersrightscondsleft((s,build\bdist.win32\egg\dispatch\predicates.pysCompare?s( #   cCs>ttigi}|D]}|t||q~SdS(N( sreducesoperatorsand_sappends_[1]sitemssexprsbuildsself(sselfsitemss_[1]sexpr((s,build\bdist.win32\egg\dispatch\predicates.pysAnd`scCs>ttigi}|D]}|t||q~SdS(N( sreducesoperatorsor_sappends_[1]sitemssexprsbuildsself(sselfsitemss_[1]sexpr((s,build\bdist.win32\egg\dispatch\predicates.pysOrcs(s__name__s __module__sTrues bind_globalsssimplify_comparisonssTruthCriterionsmodes__init__smkOpsdirs ExprBuildersopnamesisalphasupperslocalssNots _mirror_opss_rev_opssComparesAndsOr(((s,build\bdist.win32\egg\dispatch\predicates.pysCriteriaBuilders    , i{ ! cCsyt|Wn#tj ot|||SnX|o;t|gi}|D]}|t d|qO~Sn8t |gi}|D]}|t d|q~SdS(sAReturn a signature or predicate (or None) for 'expr in criterion's==s<>N( siters criterions TypeErrorsapplyCriterionsexprstruths or_criteriasappends_[1]svs Inequalitys and_criteria(sexprs criterionstruths_[1]sv((s,build\bdist.win32\egg\dispatch\predicates.pys compileInhs;s criterioncCsdS(sDApply 'criterion' to 'expr' (ala 'expr in criterion') -> sig or predN((sexprs criterionstruth((s,build\bdist.win32\egg\dispatch\predicates.pysapplyCriterionuscCs*| o |}nt||fgSdS(N(struths criterions Signaturesexpr(sexprs criterionstruth((s,build\bdist.win32\egg\dispatch\predicates.pysapplyICriterionzs cCstSdS(N(sNone(sexprs criterionstruth((s,build\bdist.win32\egg\dispatch\predicates.pys applyDefaultscCscgi}|D]}|t||fgq~}t|djo |dSnt|SdS(Nii(sappends_[1]sseqsvs Signaturesexprslens Predicate(sexprsseqsvs_[1]((s,build\bdist.win32\egg\dispatch\predicates.pys or_criterias6 cCs\t|}x|D]}PqWtdx|D]}||M}q1Wt||fgSdS(NsNo criteria supplied!(sitersseqsitsvals ValueErrorsnexts Signaturesexpr(sexprsseqsvalsitsnext((s,build\bdist.win32\egg\dispatch\predicates.pys and_criterias  s NotBuildercBs/tZeeZdZeiZeiZRS(NcCs+zt|_t||SWdt|_XdS(N(sCriteriaBuildersselfs __class__sbuildsexprs NotBuilder(sselfsexpr((s,build\bdist.win32\egg\dispatch\predicates.pysNots  ( s__name__s __module__sTruthCriterionsFalsesmodesNotsCriteriaBuildersOrsAnd(((s,build\bdist.win32\egg\dispatch\predicates.pys NotBuilders   ccsHt|to0x1|D]!}xt|D] }|Vq*WqWn|VdS(N(s isinstancesobstuplesi1s _yield_tuplessi2(sobsi1si2((s,build\bdist.win32\egg\dispatch\predicates.pys _yield_tupless sdexpr in Call and expr.function is isinstance and len(expr.argexprs)==2 and expr.argexprs[1] in ConstcCst|idi}|id}|i o9t|gi}|D]}|t |qB~Snt |t t |SdS(Nii(s _yield_tuplessexprsargexprssvaluesseqs criterionstruths and_criteriasappends_[1]sclss ICriterions or_criteriasmap(sexprs criterionsseqs_[1]scls((s,build\bdist.win32\egg\dispatch\predicates.pys!convertIsInstanceToClassCriterions   9sdexpr in Call and expr.function is issubclass and len(expr.argexprs)==2 and expr.argexprs[1] in ConstcCst|idi}|id}|i o9t|gi}|D]}|t |qB~Snt |t t |SdS(Nii(s _yield_tuplessexprsargexprssvaluesseqs criterionstruths and_criteriasappends_[1]sclssSubclassCriterions or_criteriasmap(sexprs criterionsseqs_[1]scls((s,build\bdist.win32\egg\dispatch\predicates.pys$convertIsSubclassToSubClassCriterions   9(<s __future__s generatorssdispatchsdispatch.strategys Inequalitys SignaturesExprBasesdefaultsSubclassCriterions NullCriterionsAbstractCriterionsPointers Predicatesdispatch.ast_buildersbuilds protocolssoperatorstypessNoneTypes__all__sis_sin_sis_notsnot_insadd_dicts frozensets NameErrorssetss ImmutableSets ExprBuilders LogicalExprsOrExprsAndExprsIfElsesTuplesGetattrsConstsCallsMultiCriterions AndCriterions NotCriterionsdispatch_by_truthsTruthCriterionsgenericsexpressionSignatureswhensCriteriaBuilders compileInsonsapplyCriterions ICriterionsapplyICriterionsobjects applyDefaults or_criterias and_criterias NotBuilders _yield_tupless!convertIsInstanceToClassCriterions$convertIsSubclassToSubClassCriterion(0s ExprBuildersConsts NullCriterions Signaturesdispatchsdispatch_by_truthsSubclassCriterionsCallsCriteriaBuildersoperators applyDefaults compileIns Predicatesin_s _yield_tuplessExprBasesTuplesapplyCriterions generatorssbuildsIfElsesexpressionSignatures!convertIsInstanceToClassCriterionsis_sapplyICriterionsTruthCriterions NotCriterions InequalitysOrExprs or_criterias frozensets AndCriterions LogicalExprs and_criterias protocolssnot_ins__all__sAbstractCriterionsdefaults NotBuildersGetattrsMultiCriterionsis_notsadd_dictsAndExprsPointersNoneTypes$convertIsSubclassToSubClassCriterion((s,build\bdist.win32\egg\dispatch\predicates.pys?sf   0     ))2     R      )  PK:8ŏdispatch/__init__.pyc; ^Gc@sHdZdkTdklZeefZedZdZ dZ dS(sMultiple/Predicate Dispatch Framework This framework refines the algorithms of Chambers and Chen in their 1999 paper, "Efficient Multiple and Predicate Dispatching", to make them suitable for Python, while adding a few other enhancements like incremental index building and lazy expansion of the dispatch DAG. Also, their algorithm was designed only for class selection and true/false tests, while this framework can be used with any kind of test, such as numeric ranges, or custom tests such as categorization/hierarchy membership. NOTE: this package is not yet ready for prime-time. APIs are subject to change randomly without notice. You have been warned! TODO * Support DAG-walking for visualization, debugging, and ambiguity detection (s*(s ClassTypecsdkll}dkl}tjod}n@tt o t |od}nd}||SdS(sUse the following function as the skeleton for a generic function Decorate a Python function so that it wraps an instance of 'dispatch.functions.GenericFunction' that has been configured with the decorated function's name, docstring, argument signature, and default arguments. The decorated function will have additional attributes besides those of a normal function. (See 'dispatch.IGenericFunction' for more information on these special attributes/methods.) Most commonly, you will use the 'when()' method of the decorated function to define "rules" or "methods" of the generic function. For example:: import dispatch @dispatch.generic() def someFunction(*args): '''This is a generic function''' @someFunction.when("len(args)>0") def argsPassed(*args): print "Arguments were passed!" @someFunction.when("len(args)==0") def noArgsPassed(*args): print "No arguments were passed!" someFunction() # prints "No args passed" someFunction(1) # prints "args passed" Note that when using older Python versions, you must use '[dispatch.generic()]' instead of '@dispatch.generic()'. (sGenericFunctionsAbstractGeneric(sdecorate_assignmentcs|iSdS(N(sGenericFunctionsvaluesdelegate(sfrmsnamesvalues old_locals(sGenericFunction(s*build\bdist.win32\egg\dispatch\__init__.pyscallbackTscs|iSdS(N(scombinersvaluesdelegate(sfrmsnamesvalues old_locals(scombiner(s*build\bdist.win32\egg\dispatch\__init__.pyscallbackWscs |}|_|iSdS(N(sGenericFunctionsvaluesgfscombinerscombinesdelegate(sfrmsnamesvalues old_localssgf(scombinersGenericFunction(s*build\bdist.win32\egg\dispatch\__init__.pyscallbackZs  N( sdispatch.functionssGenericFunctionsAbstractGenericspeak.util.decoratorssdecorate_assignmentscombinersNonescallbacks isinstances_clss issubclass(scombinersGenericFunctionscallbacksAbstractGenericsdecorate_assignment((scombinersGenericFunctions*build\bdist.win32\egg\dispatch\__init__.pysgeneric*s!   csTtdjotind}dkl}||SdS(sUse Python 2.4 decorators w/Python 2.2+ Example: import dispatch class Foo(object): [dispatch.as(classmethod)] def something(cls,etc): """This is a classmethod""" ics%xD]}||}qW|SdS(N(s decoratorssdsv(sframesksvs old_localssd(s decorators(s*build\bdist.win32\egg\dispatch\__init__.pyscallbackss(sdecorate_assignmentN(slens decoratorsslistsreversescallbackspeak.util.decoratorssdecorate_assignment(s decoratorssdecorate_assignmentscallback((s decoratorss*build\bdist.win32\egg\dispatch\__init__.pysasbs    cs7d}dkldkl}||SdS(sADecorate the following function as a single-dispatch generic function Single-dispatch generic functions may have a slight speed advantage over predicate-dispatch generic functions when you only need to dispatch based on a single argument's type or protocol, and do not need arbitrary predicates. Also, single-dispatch functions do not require you to adapt the dispatch argument when dispatching based on protocol or interface, and if the dispatch argument has a '__conform__' method, it will attempt to use it, rather than simply dispatching based on class information the way predicate dispatch functions do. The created generic function will use the documentation from the supplied function as its docstring. And, it will dispatch methods based on the argument named by 'argument_name', and otherwise keeping the same argument signature, defaults, etc. For example:: @dispatch.on('y') def doSomething(x,y,z): '''Doc for 'doSomething()' generic function goes here''' @doSomething.when([SomeClass,OtherClass]) def doSomething(x,y,z): # do something when 'isinstance(y,(SomeClass,OtherClass))' @doSomething.when(IFoo) def doSomething(x,y,z): # do something to a 'y' that has been adapted to 'IFoo' cs|SdS(N(s _mkGenericsvalues argument_name(sfrmsnamesvalues old_locals(s _mkGenerics argument_name(s*build\bdist.win32\egg\dispatch\__init__.pyscallbacks(s _mkGeneric(sdecorate_assignmentN(scallbacksdispatch.functionss _mkGenericspeak.util.decoratorssdecorate_assignment(s argument_names _mkGenericscallbacksdecorate_assignment((s argument_names _mkGenerics*build\bdist.win32\egg\dispatch\__init__.pyson|s   N( s__doc__sdispatch.interfacesstypess ClassTypes _ClassTypestypes_clssNonesgenericsasson(sonsgenerics _ClassTypesass_cls((s*build\bdist.win32\egg\dispatch\__init__.pys?s    8 PK:8T׳<<dispatch/interfaces.pyc; ^Gc@sndklZlZddddddddd d d d d dgZd efdYZdefdYZdefdYZdZdefdYZ de fdYZ defdYZ d efdYZ defdYZ defdYZdefdYZdefdYZd efdYZd eefdYZdS((s Interfaces AttributesIDispatchFunctions ICriterions ISignaturesIDispatchPredicates IDispatchersAmbiguousMethodsNoApplicableMethodssIDispatchableExpressionsIGenericFunctionsIDispatchTablesEXPR_GETTER_IDsIExtensibleFunctions DispatchErrorsISeededCriterioncBs tZdZdZdZRS(sA dispatch error has occurredcOs |i|i||fdS(N(sselfs __class__sargsskw(sselfsargsskw((s,build\bdist.win32\egg\dispatch\interfaces.pys__call__scCs|iit|iSdS(N(sselfs __class__s__name__sreprsargs(sself((s,build\bdist.win32\egg\dispatch\interfaces.pys__repr__s(s__name__s __module__s__doc__s__call__s__repr__(((s,build\bdist.win32\egg\dispatch\interfaces.pys DispatchError s  cBstZdZRS(s*More than one choice of method is possible(s__name__s __module__s__doc__(((s,build\bdist.win32\egg\dispatch\interfaces.pysAmbiguousMethods cBstZdZRS(s=No applicable method has been defined for the given arguments(s__name__s __module__s__doc__(((s,build\bdist.win32\egg\dispatch\interfaces.pysNoApplicableMethodss icBsbtZdZedZdZdZdZdZdZ dZ dZ d Z RS( shA criterion to be applied to an expression A criterion comprises a "node type" (that determines how the criterion will be checked, such as an 'isinstance()' check or range comparison) and a value or values that the expression must match. Note that a criterion describes only the check(s) to be performed, not the expression to be checked.s8The type of object that will actually do the dispatchingcCsdS(s>Apply multiple criteria of the same node type to the same exprN((sother((s,build\bdist.win32\egg\dispatch\interfaces.pys__and__7scCsdS(s'Equal criteria should have equal hashesN((((s,build\bdist.win32\egg\dispatch\interfaces.pys__hash__:scCsdS(sReturn true if equalN((sother((s,build\bdist.win32\egg\dispatch\interfaces.pys__eq__=scCsdS(sReturn false if equalN((sother((s,build\bdist.win32\egg\dispatch\interfaces.pys__ne__@scCsdS(s?Return an inverse version of this criterion (i.e. '~criterion')N((((s,build\bdist.win32\egg\dispatch\interfaces.pys __invert__CscCsdS(s?Return true if truth of this criterion implies truth of 'other'N((sother((s,build\bdist.win32\egg\dispatch\interfaces.pysimpliesFscCsdS(sCall 'listener.criterionChanged()' if applicability changes Multiple calls with the same listener should be treated as a no-op.N((slistener((s,build\bdist.win32\egg\dispatch\interfaces.pys subscribeIscCsdS(swStop calling 'listener.criterionChanged()' Unsubscribing a listener that was not subscribed should be a no-op.N((slistener((s,build\bdist.win32\egg\dispatch\interfaces.pys unsubscribeNs( s__name__s __module__s__doc__s Attributes node_types__and__s__hash__s__eq__s__ne__s __invert__simpliess subscribes unsubscribe(((s,build\bdist.win32\egg\dispatch\interfaces.pys ICriterion*s         cBsJtZdZedZedZdZdZdZdZ RS(s)A criterion that works with a SeededIndexs@Can criterion enumerate its implications via ``parent_seeds()``?s=If ``enumerable``, this must be the most-specific parent seedcCsdS(sReturn iterable of known-good keys The keys returned will be used to build outgoing edges in generic functions' dispatch tables, which will be passed to the 'dispatch_function' for interpretation.N((((s,build\bdist.win32\egg\dispatch\interfaces.pysseeds^scCsdS(sReturn true if criterion is true for 'key' This method will be passed each seed provided by this or any other criteria with the same 'dispatch_function' that are being applied to the same expression.N((skey((s,build\bdist.win32\egg\dispatch\interfaces.pys __contains__escCsdS(s@Return iterable of keys from 'table' that this criterion matchesN((stable((s,build\bdist.win32\egg\dispatch\interfaces.pysmatcheslscCsdS(s7Iterable of all the criteria implied by this criterionsN((((s,build\bdist.win32\egg\dispatch\interfaces.pysparent_criteriaos( s__name__s __module__s__doc__s Attributes enumerables leaf_seedsseedss __contains__smatchessparent_criteria(((s,build\bdist.win32\egg\dispatch\interfaces.pysISeededCriterionSs      cBs2tZdZdZdZdZdZRS(sCDetermine what path to take at a dispatch node, given an expressioncCsdS(sReturn entry from 'table' that matches 'ob' ('None' if not found) 'table' is an 'IDispatchTable' mapping criterion seeds to dispatch nodes. The dispatch function should return the appropriate entry from the dictionary.N((stablesob((s,build\bdist.win32\egg\dispatch\interfaces.pys__call__scCsdS(sReturn true if equalN((sother((s,build\bdist.win32\egg\dispatch\interfaces.pys__eq__scCsdS(sReturn false if equalN((sother((s,build\bdist.win32\egg\dispatch\interfaces.pys__ne__scCsdS(sReturn hashcodeN((((s,build\bdist.win32\egg\dispatch\interfaces.pys__hash__s(s__name__s __module__s__doc__s__call__s__eq__s__ne__s__hash__(((s,build\bdist.win32\egg\dispatch\interfaces.pysIDispatchFunction|s    cBs)tZdZdZdZdZRS(s0A dispatch node for dispatch functions to searchcCsdS(sTrue if 'key' is in tableN((skey((s,build\bdist.win32\egg\dispatch\interfaces.pys __contains__scCsdS(s3Return dispatch node for 'key', or raise 'KeyError'N((skey((s,build\bdist.win32\egg\dispatch\interfaces.pys __getitem__scCsdS(s>Add 'key' to dispatch table and return the node it should haveN((skey((s,build\bdist.win32\egg\dispatch\interfaces.pysreseeds(s__name__s __module__s__doc__s __contains__s __getitem__sreseed(((s,build\bdist.win32\egg\dispatch\interfaces.pysIDispatchTables   cBs;tZdZdZdZdZdZdZRS(sOrdered mapping from expression id -> criterion that should be applied Note that signatures do not/should not interpret expression IDs; the IDs may be any object that can be used as a dictionary key. cCsdS(sASequence of '((id,disp_func),criterion)' pairs for this signatureN((((s,build\bdist.win32\egg\dispatch\interfaces.pysitemsscCsdS(s2Return this signature's 'ICriterion' for 'expr_id'N((sexpr_id((s,build\bdist.win32\egg\dispatch\interfaces.pysgetscCsdS(s0Return true if this signature implies 'otherSig'N((sotherSig((s,build\bdist.win32\egg\dispatch\interfaces.pysimpliesscCsdS(sReturn true if equalN((sother((s,build\bdist.win32\egg\dispatch\interfaces.pys__eq__scCsdS(sReturn false if equalN((sother((s,build\bdist.win32\egg\dispatch\interfaces.pys__ne__s(s__name__s __module__s__doc__sitemssgetsimpliess__eq__s__ne__(((s,build\bdist.win32\egg\dispatch\interfaces.pys ISignatures     cBs)tZdZdZdZdZRS(sSequence of "or"-ed signaturescCsdS(sIterate over "or"-ed signaturesN((((s,build\bdist.win32\egg\dispatch\interfaces.pys__iter__scCsdS(sReturn true if equalN((sother((s,build\bdist.win32\egg\dispatch\interfaces.pys__eq__scCsdS(sReturn false if equalN((sother((s,build\bdist.win32\egg\dispatch\interfaces.pys__ne__s(s__name__s __module__s__doc__s__iter__s__eq__s__ne__(((s,build\bdist.win32\egg\dispatch\interfaces.pysIDispatchPredicates   cBs2tZdZdZdZdZdZRS(s.Expression definition suitable for dispatchingcCsdS(s7Return '(func,idtuple)' pair for expression computationN((sgeneric((s,build\bdist.win32\egg\dispatch\interfaces.pys asFuncAndIdsscCsdS(sReturn true if equalN((sother((s,build\bdist.win32\egg\dispatch\interfaces.pys__eq__scCsdS(sReturn false if equalN((sother((s,build\bdist.win32\egg\dispatch\interfaces.pys__ne__scCsdS(sReturn hashcodeN((((s,build\bdist.win32\egg\dispatch\interfaces.pys__hash__s(s__name__s __module__s__doc__s asFuncAndIdss__eq__s__ne__s__hash__(((s,build\bdist.win32\egg\dispatch\interfaces.pysIDispatchableExpressions    cBsDtZdZdZdZdZdZdZdZRS(sMulti-dispatch mapping objectcCsdS(s?Return the rule body (or combo thereof) that matches 'argtuple'N((sargtuple((s,build\bdist.win32\egg\dispatch\interfaces.pys __getitem__scCsdS(sAStore 'body' as the rule body for arg tuples matching 'signature'N((s signaturesbody((s,build\bdist.win32\egg\dispatch\interfaces.pys __setitem__scCsdS(s8Parse 'expr_string' --> ISignature or IDispatchPredicateN((s expr_strings local_dicts global_dict((s,build\bdist.win32\egg\dispatch\interfaces.pysparsescCsdS(s'Return an expression ID for use in 'asFuncAndIds()' 'idtuple' Note that the constant 'EXPR_GETTER_ID' may be used in place of calling This method, if you want the ID corresponding to a function that will return the value of any other expression whose ID is passed to it.N((sexpr((s,build\bdist.win32\egg\dispatch\interfaces.pysgetExpressionIdscCsdS(sANotify that a criterion has changed meaning, invalidating indexesN((((s,build\bdist.win32\egg\dispatch\interfaces.pyscriterionChanged scCsdS(s:Empty all signatures, methods, criteria, expressions, etc.N((((s,build\bdist.win32\egg\dispatch\interfaces.pysclears( s__name__s __module__s__doc__s __getitem__s __setitem__sparsesgetExpressionIdscriterionChangedsclear(((s,build\bdist.win32\egg\dispatch\interfaces.pys IDispatchers      cBs#tZdZdZdZRS(NcOsdS(s&Invoke the function and return resultsN((s_IExtensibleFunction__argss_IExtensibleFunction__kw((s,build\bdist.win32\egg\dispatch\interfaces.pys__call__"scCsdS(sCall 'method' when input matches 'predicate' (Note that single and multiple-dispatch functions use different predicate types: type/class/sequence vs. 'IDispatchPredicate'). N((s predicatesmethod((s,build\bdist.win32\egg\dispatch\interfaces.pys addMethod%scCsdS(sAdd following function to this GF, w/'cond' as a guard This is used to add a method to a generic function. E.g.:: import foo @foo.barFunc.when(XYZ) def whatever(x,y,z): # code for situation XYZ After the execution of this alternate form, 'whatever' will be bound to the 'whatever' function as shown, but it will also have been added to 'foo.barFunc' under condition 'XYZ'. N((scond((s,build\bdist.win32\egg\dispatch\interfaces.pyswhen,s(s__name__s __module__s__call__s addMethodswhen(((s,build\bdist.win32\egg\dispatch\interfaces.pysIExtensibleFunction s  cBstZdZRS(s9Extensible function that stores methods in an IDispatcher(s__name__s __module__s__doc__(((s,build\bdist.win32\egg\dispatch\interfaces.pysIGenericFunction=s N(s protocolss Interfaces Attributes__all__s Exceptions DispatchErrorsAmbiguousMethodsNoApplicableMethodssEXPR_GETTER_IDs ICriterionsISeededCriterionsIDispatchFunctionsIDispatchTables ISignaturesIDispatchPredicatesIDispatchableExpressions IDispatchersIExtensibleFunctionsIGenericFunction(s DispatchErrorsIGenericFunctionsIExtensibleFunctions__all__sIDispatchTables Attributes ISignatures ICriterionsIDispatchPredicates IDispatchersIDispatchFunctionsNoApplicableMethodss InterfacesIDispatchableExpressionsAmbiguousMethodsEXPR_GETTER_IDsISeededCriterion((s,build\bdist.win32\egg\dispatch\interfaces.pys?s0  ))))PK:8pvDlDldispatch/functions.pyc; ^Gc@s:dZdklZdkTdkZdkZdkZdkZdkl Z l Z l Z dk l Z dklZdklZlZlZeefZdd d gZd eeeeffZyeWn ej od klZnXd ZeidgdZ ee dZ e i!Z"dZ#dZ$dZ%e#ee"de#ee"de$ei&e"de$ei'e"dde(fdYZ)dfdYZ*ydk+l*Z*Wne,j onXd e*fdYZ-d e-fdYZ.de.fdYZ/dZ0dZ1dS( s Generic function implementations(s generators(s*N(sdecorate_assignments frameinfosdecorate_class(s allocate_lock(sinstancemethod(s FunctionTypes ClassTypes InstanceTypesGenericFunctions DispatchersAbstractGenerici(s ImmutableSetc s\i}ei\}} }}|o;gi }e e |D]}|d|qE~}ne}ei|| ||dd}ei|| |}eih} de}|e| U| d|d}d} d} | _|_| __i_eid e gSdS( Ns=__gfDefaults[%s]s formatvaluecCs|S(N(sx(sx((s+build\bdist.win32\egg\dispatch\functions.pys3ssJ def setup(__gfProtocol, __gfDefaults): def %(funcname)s%(argspec)s: __gfWhat = __gfProtocol(%(argname)s,None) if __gfWhat is None: raise NoApplicableMethods(%(argname)s) else: %(argname)s = __gfWhat[0] return __gfWhat[1]%(outargs)s return %(funcname)s ssetupcs d}t|SdS(s:Add following function to this GF, using 'cond' as a guardcs<td|i|joSnSdS(Ncs |fS(N(sobsvalue(sob(svalue(s+build\bdist.win32\egg\dispatch\functions.pysKs(sdeclarePredicatescondsprotocols old_localssgetsnamesfuncsvalue(sfrmsnamesvalues old_locals(sprotocolscondsfunc(svalues+build\bdist.win32\egg\dispatch\functions.pyscallbackJsN(scallbacksdecorate_assignment(scondscallback(sprotocolsfunc(sconds+build\bdist.win32\egg\dispatch\functions.pyswhenHscst|ddS(s0Use 'func' when dispatch argument matches 'cond'cs |fS(N(sobsfunc(sob(sfunc(s+build\bdist.win32\egg\dispatch\functions.pysUsN(sdeclarePredicatescondsprotocol(scondsfunc(sprotocol(sfuncs+build\bdist.win32\egg\dispatch\functions.pys addMethodSscs9t}titi|igdg|SdS(s>Return a simple generic function that "inherits" from this ones forProtocolsN(s _mkGenericsoldfuncsargnamesfs protocolssdeclareAdaptersNO_ADAPTER_NEEDEDsprotocol(sf(sprotocolsoldfuncsargname(s+build\bdist.win32\egg\dispatch\functions.pyscloneWs"sprovides(!soldfuncs__name__sfuncnamesinspects getargspecsargssvarargsskwargssdefaultssappends_[1]srangeslensistmpdsNones formatargspecsargspecsoutargss protocolssProtocolsprotocolsdslocalssssglobalssfuncswhens addMethodsclones__doc__s adviseObjectsIExtensibleFunction(soldfuncsargnamesprotocolsoutargsswhenssskwargssargsstmpdsclones addMethodsfuncsvarargssdsisfuncnames_[1]sargspecsdefaults((soldfuncsargnamesprotocolsfuncs+build\bdist.win32\egg\dispatch\functions.pys _mkGeneric*s* ;!         sobcCsdS(s*Declare a SimpleGeneric dispatch predicateN((sobsprotosfactory((s+build\bdist.win32\egg\dispatch\functions.pysdeclarePredicatescCs#ti|d|gd|gdS(NsprovidessforTypes(s protocolssdeclareAdaptersfactorysprotostyp(stypsprotosfactory((s+build\bdist.win32\egg\dispatch\functions.pysdeclareForTypescCs#ti|d|gd|gdS(Nsprovidess forProtocols(s protocolssdeclareAdaptersfactorysprotospro(sprosprotosfactory((s+build\bdist.win32\egg\dispatch\functions.pysdeclareForProtoscCs%x|D]}t|||qWdS(N(sseqsitemsdeclarePredicatesprotosfactory(sseqsprotosfactorysitem((s+build\bdist.win32\egg\dispatch\functions.pysdeclareForSequencescCs |tfS(N(sobsdeclareForType(sob((s+build\bdist.win32\egg\dispatch\functions.pysscCs |tfS(N(sobsdeclareForProto(sob((s+build\bdist.win32\egg\dispatch\functions.pysscCs |tfS(N(sobsdeclareForSequence(sob((s+build\bdist.win32\egg\dispatch\functions.pysss ExprCachecBs)tZdddfZdZdZRS(Nscachesargtuples expr_defscCs||_||_h|_dS(N(sargtuplesselfs expr_defsscache(sselfsargtuples expr_defs((s+build\bdist.win32\egg\dispatch\functions.pys__init__s  cCs|tjo |iSny|i|SWntj onXy|i|SWntj onX|i|\}}|t |i|}|i|<|SdS(N( sitemsEXPR_GETTER_IDsselfs __getitem__sargtuples IndexErrorscachesKeyErrors expr_defssfsargssmap(sselfsitemsfsargs((s+build\bdist.win32\egg\dispatch\functions.pys __getitem__s  #(s__name__s __module__s __slots__s__init__s __getitem__(((s+build\bdist.win32\egg\dispatch\functions.pys ExprCaches sBaseDispatchercBstZdZRS(Nc Cs|i}|ip|ipt}|\}}}}x|o|t joI|i z-|dt jo|||d<}nWd|i Xn||jo+|||pt\}}}}}q;t||i}z|||pt\}}}}}x|o|t joI|i z-|dt jo|||d<}nWd|i Xn||jo+|||pt\}}}}}q|||pt\}}}}}qWPWdt }Xq;Wt|to||n|SdS(Ni(sselfsargcts _dispatchers _startNodes_NFsnodesexprsfactorysfuncsinitsNones_acquires_releasesargtuples ExprCaches expr_defsscaches isinstances DispatchError( sselfsargtuplesnodesfuncsexprscachesargctsfactorysinit((s+build\bdist.win32\egg\dispatch\functions.pys __getitem__sF    +'   +, (s__name__s __module__s __getitem__(((s+build\bdist.win32\egg\dispatch\functions.pysBaseDispatchers(sBaseDispatchercBstZdZeidegdZdZdZdZ e e e dZ dZ dZ d Zd Zd Zd Zeid ge ddZeieeggdZeiegdZdZdZdZdZdZRS(s(Extensible multi-dispatch mapping objectsinstancesProvidecCs||_t||_dkatgi}|D]"}||ti d|fq2~|_ t }|_ |i|_|i|_|idS(Nsname(sargssselfslensargctsstrategysdictsappends_[1]snamesArgumentsargMaps allocate_lockslocks_locksacquires_acquiresreleases_releasesclear(sselfsargssnameslocks_[1]((s+build\bdist.win32\egg\dispatch\functions.pys__init__%s  B  cCs*|iz|iWd|iXdS(N(sselfs_acquires_clears_release(sself((s+build\bdist.win32\egg\dispatch\functions.pysclear0s  cCsJt|_g|_h|_h|_t|_ti |_ |i dS(N( sFalsesselfsdirtyscasess disp_indexessexpr_mapsNones _dispatchersstrategysTGraphs constraintss _setupArgs(sself((s+build\bdist.win32\egg\dispatch\functions.pys_clear8s     cCsCdkl}dkl}||i||t}|||SdS(N(sCriteriaBuilder(s parse_expr( sdispatch.predicatessCriteriaBuildersdispatch.ast_builders parse_exprsselfsargMaps local_dicts global_dicts __builtins__sbuilders expr_string(sselfs expr_strings local_dicts global_dicts parse_exprsCriteriaBuildersbuilder((s+build\bdist.win32\egg\dispatch\functions.pysparseBs  c Cs|tjo>|ittt|i}t|i }h}nt |t ot|}n| o f}n||f} | |jo || Sn| o]t |}|idt|igi} |D]}| |i|q~ tg}n|i||\}}tt|i||i||i} |tjo| |}n6|i |}|d|it||| |ifg}||| <|SdS(Ni(smemosNonesselfs_rebuild_indexess frozensetsrangeslenscasesstuples disp_indexessdisp_idss isinstanceskeyslistssortscombinesappends_[1]snsnodes _best_splitsbest_ids remaining_idssinstancemethods_build_dispatchers __class__sbuildsindexsmkNodes_lock( sselfsmemosdisp_idsscasessnodes remaining_idssindexsbest_idsns_[1]sbuildskey((s+build\bdist.win32\egg\dispatch\functions.pys_build_dispatcherIs0       G  ( cCsg|ioY|igf\}|_t|_x!|iiD]}|iq;Wt|i |ndS(N( sselfsdirtyscasessFalses disp_indexessvaluessindsclearsmaps_addCase(sselfsindscases((s+build\bdist.win32\egg\dispatch\functions.pys_rebuild_indexesrs  cCs2|izt|_t|_Wd|iXdS(N(sselfs_acquiresTruesdirtysNones _dispatchers_release(sself((s+build\bdist.win32\egg\dispatch\functions.pyscriterionChangedys    cCstg|i|_xnt|iD]]\}}||it i d|<||it i d|<||it i d|d|'method'N(sselfs parseRules signaturescondsNonesIDispatchPredicatesmethods_acquiresstrategys Signaturesappends_[1]s ISignaturesitemssexprs criterions NullCriterions _dispatch_ids_addCases_addConstraintss_release(sselfs signaturesmethodsexprs criterions_[1]scond((s+build\bdist.win32\egg\dispatch\functions.pys __setitem__s   hsruleicCsdS(s>Parse 'rule' if it's a string/unicode, otherwise return 'None'N((sselfsrulesframesdepth((s+build\bdist.win32\egg\dispatch\functions.pys parseRulescCs3|p ti|}|i||i|iSdS(N( sframessyss _getframesdepthsselfsparsesrulesf_localss f_globals(sselfsrulesframesdepth((s+build\bdist.win32\egg\dispatch\functions.pys parseRulescCstSdS(N(sNone(sselfsrulesframesdepth((s+build\bdist.win32\egg\dispatch\functions.pys parseRulescCsti|SdS(N(sstrategys single_bestscases(sselfscases((s+build\bdist.win32\egg\dispatch\functions.pyscombinescCsSt}t}t}t|} t|}|i i | } g}| }x|D]} | | jo|i| qPn|i| }|i|\} }||| jo9| i| |i i | } |i|g}qPnt|| } | |jp |tjo| }| }qPqPW|tj o| i|n|t| fSdS(sBReturn best (disp_id,method_map,remaining_ids) for current subtreeN(sNonesbest_idsbest_maps best_spreadslistsdisp_idss remaining_idsslenscasess active_casessselfs constraintss successorssdisabledsskippedsto_dosdisp_idsappends disp_indexessindexs count_forslindexs total_casessremovesextendsfloatsspreadstuple(sselfscasessdisp_idssindexsskippedsto_dosbest_maps total_casessbest_idsdisabledsspreads remaining_idssdisp_idslindexs best_spreads active_cases((s+build\bdist.win32\egg\dispatch\functions.pys _best_splits8       cCsi|\}}|i||i|}||if}||ijo|ii |i|s anonymouss=__gfDefaults[%s]s formatvaluecCs|S(N(sx(sx((s+build\bdist.win32\egg\dispatch\functions.pysss formatvarargscCs|S(N(sname(sname((s+build\bdist.win32\egg\dispatch\functions.pysss formatvarkwsjoincCs di|S(Ns,(sjoinsseq(sseq((s+build\bdist.win32\egg\dispatch\functions.pyssiis,ss s def setup(__dispatcher,__gfDefaults): def %(funcname)s%(argspec)s: return __dispatcher((%(outargs)s))%(allargs)s return %(funcname)s ssetup(sfuncs__name__sfuncnamesinspects getargspecsargssvarargsskwargssdefaultssappends_[1]srangeslensistmpdsNones formatargspecsargspecsallargssoutargssretargssfiltersreplacessplitsdslocalssssglobalss dispatchers __getitem__(sfuncs dispatchersretargssoutargss_[1]sallargsskwargsstmpdsargssvarargssdsisfuncnamesssargspecsdefaults((s+build\bdist.win32\egg\dispatch\functions.pys _mkNormalizers*   ;!  $  cGs|S(N(s__args(s__args((s+build\bdist.win32\egg\dispatch\functions.pyss(2s__doc__s __future__s generatorssdispatch.interfacess protocolssinspectssyssdispatchspeak.util.decoratorssdecorate_assignments frameinfosdecorate_classsprotocols.interfacess allocate_locksnewsinstancemethodstypess FunctionTypes ClassTypes InstanceTypestypes ClassTypess__all__sNonesNoApplicableMethodss_NFs frozensets NameErrorssetss ImmutableSets _mkGenericsonsdeclarePredicatesprotocolsprotosdeclareForTypesdeclareForProtosdeclareForSequences IOpenProtocolsIBasicSequencesobjects ExprCachesBaseDispatchersdispatch._d_speedupss ImportErrors DispatchersAbstractGenericsGenericFunctions _mkNormalizersdefaultNormalize(s ExprCachesdeclarePredicatesdeclareForProtosdeclareForTypesdispatchsAbstractGenericsdeclareForSequences _mkGenerics__all__sprotosdecorate_classs generatorss _mkNormalizers_NFs InstanceTypesBaseDispatchersinspectsinstancemethods frozensets ClassTypessdefaultNormalizes protocolsssyssGenericFunctions frameinfos allocate_locks ClassTypes Dispatchersdecorate_assignments FunctionType((s+build\bdist.win32\egg\dispatch\functions.pys?sN $    T         ))&RR &PK:8ng? ? dispatch/combiners.pyc; ^Gc@sGdZdklZdklZdklZdefdYZdS(s=Method combining subclasses of Dispatcher and GenericFunction(sordered_signatures(sAmbiguousMethod(s Dispatchers MapDispatchercBs)tZdZdZdZdZRS(seAbstract base class for method combiners that merge metadata To use this class, subclass it and override the 'getItems()' method (and optionally the 'shouldStop()' method to support your particular kind of metadata. Then use the subclass as a method combiner for a dispatcher or generic function. See 'combiners.txt' for sample code. cCs tdS(s8Return an iterable of '(key,value)' pairs for given ruleN(sNotImplementedError(sselfs signaturesmethod((s+build\bdist.win32\egg\dispatch\combiners.pysgetItemsscCsdS(s>Return truth if combining should stop at this precedence levelN((sselfs signaturesmethod((s+build\bdist.win32\egg\dispatch\combiners.pys shouldStopsc Csh}t}xt|D]}h}x|D]}|p |i |}xq|i |D]`\}}||joqXn||jo|||jot ||||Sn|||de1fd=YZ?e?Z?d e9fd>YZ@d?ZAd@ZBy#dAk7lBZBlAZAlZlZWne8j onXdBe&fdCYZCde%fdDYZDeeDi4i5e,eDeD_6dEefdFYZEd ee1fdGYZFdHZGdIZHdJZIdKZJdLZKdMZLdNZMdOZNdPe%fdQYZOdeOfdRYZPde%fdSYZQeiRdTeSgdUeTgde%fdVYZUdeUfdWYZVeUZWdS(XsIndexing and Method Combination Strategies ProtocolCriterion -- Index handler for checking that an expression adapts to a protocol ClassCriterion -- Index handler for checking that an expression is of a type or class SubclassCriterion -- Index handler for checking that an expression is a subclass of a given class Inequality -- Index handler for checking that an expression has a range relation (i.e. <,>,<=,>=,==,!=) to a constant value IdentityCriterion -- Index handler for checking that an expression 'is' a particular object Min, Max -- Extreme values for use with 'Inequality' Pointer -- hashable/comparable object pointer, with weakref support, used to implement 'IdentityCriterion' Predicate, Signature, PositionalSignature, Argument -- primitives to implement indexable multiple dispatch predicates most_specific_signatures, ordered_signatures, method_chain, method_list, all_methods, safe_methods, separate_qualifiers -- utility functions for creating method combinations validateCriterion -- check if a criterion's implementation is sane (s generators(sProtocolsAdapters StickyAdapter(sgetMRON(s ClassTypes InstanceType(s _getframesmaxint(sWeakKeyDictionarysref(s*(sinstancemethod(sMinsMaxsProtocolCriterionsClassCriterionsSubclassCriterions InequalitysMinsMaxs Predicates SignaturesPositionalSignaturesArgumentsmost_specific_signaturessordered_signaturessseparate_qualifierss method_chains method_lists all_methodss safe_methodssPointersdefaultsIdentityCriterions NullCriterionsvalidateCriterions DispatchNodes SeededIndexs>s<=s>=ss=s==s!=(sSet(s ImmutableSetcBshtZdZddddddfZdZdZd Zd Zd Ze d Z d Z RS(s"Index connecting seeds and resultssdispatch_functionsallSeedss matchingSeedsscriterias enumerabless impliedSeedscCs||_|idS(N(sdispatch_functionsselfsclear(sselfsdispatch_function((s*build\bdist.win32\egg\dispatch\strategy.pys__init__[s cCs1h|_h|_h|_h|_h|_dS(sReset index to emptyN(sselfsallSeedss matchingSeedsscriterias enumerabless impliedSeeds(sself((s*build\bdist.win32\egg\dispatch\strategy.pysclear_s     c Cs|io|i} || jo|i}|i} || j}|i }xE|i D]7} |p | | jo|i | gi |qTqTW||| |<|i}x6|iD]$}|| jo||tqqWn| ||i|Get the total count of outgoing branches, given incoming casesN( sselfs matchingSeedssgetsallSeedssdfltslenssumsappends_[1]scasesscase(sselfscasesscasesdfltsgets_[1]((s*build\bdist.win32\egg\dispatch\strategy.pys count_fors  cCs|ii}|i}tgi}|D]}||gfq&~}x9|D]1}x(|||D]}||i|qeWqOW|SdS(s:Return a mapping from seeds->caselists for the given casesN( sselfs matchingSeedssgetsallSeedssdfltsdictsappends_[1]skeyscasemapscasesscase(sselfscasesscasesdfltsgets_[1]scasemapskey((s*build\bdist.win32\egg\dispatch\strategy.pys casemap_fors  3cCs||ijodSnx;|iiD]*\}}||jo|i|q(q(W|oBx?|i iD]*\}}||jo|i|qmqmWnt |i|!s( sPointers__base__s__new__sclssidsobsmaxintsselfsrefs TypeError(sclssobsself((s*build\bdist.win32\egg\dispatch\strategy.pys__new__s cCs4||jp#t||jo|itj SdS(N(sselfsothersintsrefsNone(sselfsother((s*build\bdist.win32\egg\dispatch\strategy.pys__eq__$scCs7|itjodt|Snd|iSdS(NsPointer()s Pointer(%r)(sselfsrefsNoneshex(sself((s*build\bdist.win32\egg\dispatch\strategy.pys__repr__'s(s__name__s __module__s __slots__s__new__s__eq__s__repr__(((s*build\bdist.win32\egg\dispatch\strategy.pysPointers  cCs5t|t@}||jo ||Sn|tSdS(N(sidsobsmaxintsoidstablesNone(stablesobsoid((s*build\bdist.win32\egg\dispatch\strategy.pysdispatch_by_identity.s  cBsitZdZeidegdegfZee Z dZ dZ dZ dZdZRS(s5Criterion that is true when target object is the samesinstancesProvidesasAdapterForTypescCsti||dS(N(sAbstractCriterions__init__sselfsptr(sselfsptr((s*build\bdist.win32\egg\dispatch\strategy.pys__init__HscCst|ifSdS(N(sNonesselfssubject(sself((s*build\bdist.win32\egg\dispatch\strategy.pysseedsKscCs|ifSdS(N(sselfssubject(sselfstable((s*build\bdist.win32\egg\dispatch\strategy.pysmatchesNscCs||ijSdS(N(sobsselfssubject(sselfsob((s*build\bdist.win32\egg\dispatch\strategy.pys __contains__QscCs |i SdS(N(sselfssubject(sself((s*build\bdist.win32\egg\dispatch\strategy.pys__repr__Ts(s__name__s __module__s__doc__s protocolssadvisesISeededCriterionsPointers __slots__s staticmethodsdispatch_by_identitysdispatch_functions__init__sseedssmatchess __contains__s__repr__(((s*build\bdist.win32\egg\dispatch\strategy.pysIdentityCriterion?s      cBsAtZdZeZdZdZdZdZdZ RS(s*A "wildcard" Criterion that is always truecCsfSdS(N((sself((s*build\bdist.win32\egg\dispatch\strategy.pysseeds]scCstSdS(N(sTrue(sselfsob((s*build\bdist.win32\egg\dispatch\strategy.pys __contains__^scCstSdS(N(sFalse(sselfsother((s*build\bdist.win32\egg\dispatch\strategy.pysimplies_scCsdSdS(Ns NullCriterion((sself((s*build\bdist.win32\egg\dispatch\strategy.pys__repr__`scCst|SdS(N(sliststable(sselfstable((s*build\bdist.win32\egg\dispatch\strategy.pysmatchesas( s__name__s __module__s__doc__sNones node_typesseedss __contains__simpliess__repr__smatches(((s*build\bdist.win32\egg\dispatch\strategy.pys NullCriterionXs     cBs2tZdZfZeeZdZdZRS(sACriterion that indicates expr is a subclass of a particular classcCs|itgSdS(N(sselfssubjectsNone(sself((s*build\bdist.win32\egg\dispatch\strategy.pysseedsoscCsd|iifSdS(NsSubclassCriterion(%s)(sselfssubjects__name__(sself((s*build\bdist.win32\egg\dispatch\strategy.pys__repr__rs( s__name__s __module__s__doc__s __slots__s staticmethodsdispatch_by_subclasssdispatch_functionsseedss__repr__(((s*build\bdist.win32\egg\dispatch\strategy.pysSubclassCriterionhs   c Cs||f}y ||SWntj ot|jot||t<}n |t}d}t|}xs||jo`||d}||\}}||jo |}qm||jo|d}qm|||SqmWnXdS(Niii( sobskeystablesKeyErrorsNonesconcatenate_rangessrangessloslenshismidstlsth( stablesobsmidslosrangesstlshiskeysth((s*build\bdist.win32\egg\dispatch\strategy.pysdispatch_by_inequalitiess         cCs{|i}|ig}t}xN|D]F\}}||jp ||joq)n|i ||f|}q)W|SdS(N( s range_mapskeyssrangesssortsoutputsMinslastslshsappend(s range_mapslastshslsrangessoutput((s*build\bdist.win32\egg\dispatch\strategy.pysconcatenate_rangess  (sconcatenate_rangessdispatch_by_inequalitiessMinsMaxsInequalityIndexcBsVtZddfZeeZdZdZdZdZ dZ dZ RS( Ns last_casesslast_outcCs|idS(N(sselfsclear(sself((s*build\bdist.win32\egg\dispatch\strategy.pys__init__scCsV|i|}t|tgi}|iD]}|t|q/~fSdS(s>Get the total count of outgoing branches, given incoming casesN( sselfs casemap_forscasesscasemapslenssumsappends_[1]s itervaluessx(sselfscasess_[1]scasemapsx((s*build\bdist.win32\egg\dispatch\strategy.pys count_forscCs(h|_h|_t|_t|_dS(sReset index to emptyN(sselfsallSeedsscriteriasNones last_casesslast_out(sself((s*build\bdist.win32\egg\dispatch\strategy.pysclears    cCsC||i|caselists for the given casess..iiiN(scasessselfs last_casesslast_outstmpsoutscriteriasgets InequalitysMinsMaxsallsFalses have_ineqscasesrangessloshisappendsTrueskeysssorts frozensetscurrentsvalsaddsremoveseqs differencesunionsitems(sselfscasessallseqsoutstmpsvalscurrentsaddsgetskeysshiscasesremoveslos have_ineq((s*build\bdist.win32\egg\dispatch\strategy.pys casemap_forsT        !     ( s__name__s __module__s __slots__s staticmethodsdispatch_by_inequalitiessdispatch_functions__init__s count_forsclears __setitem__saddSeeds casemap_for(((s*build\bdist.win32\egg\dispatch\strategy.pysInequalityIndexs       cBstZdZddfZeidegdefdYZdZ dZ dZ d Z d Z d Zd Zd ZdZdZRS(sECriterion that indicates target matches specified const. inequalitiesshashsrangessinstancesProvides node_typecBstZeZRS(N(s__name__s __module__sInequalityIndexs make_index(((s*build\bdist.win32\egg\dispatch\strategy.pys node_typescCs!g}|djo|i|n|djo d}nd|jo|it|fnd|jo|i||fnd|jo|i|tfn| p6gi}|D]!}|djo||qq~ot d|nt ||_}t ||_ dS( Ns..s!=s<>ss<=>sInvalid inequality operator( srangessopsextendsvalsappendsMinsMaxs_[1]scs ValueErrorstuplesselfshash(sselfsopsvals_[1]scsranges((s*build\bdist.win32\egg\dispatch\strategy.pys__init__s      AcCs2x'|iD]}||j otSq q WtSdS(N(sselfsrangessrsothersFalsesTrue(sselfsothersr((s*build\bdist.win32\egg\dispatch\strategy.pysimplies&s   cCsd|ifSdS(NsInequality("..",%r)(sselfsranges(sself((s*build\bdist.win32\egg\dispatch\strategy.pys__repr__-scCsx|iD]}||jotSq |d|djo6|d|djo|d|djotSqq |d|djo|d|djotSq q WtSdS(Nii(sselfsrangessrsobsTruesFalse(sselfsobsr((s*build\bdist.win32\egg\dispatch\strategy.pys __contains__5s  * * c Csg}x|iD]} | |jo|i| q| \}}x~|iD]s\}}||jp ||joPnt ||}t ||}||jo|i||f|}qJqJWqW|i d|SdS(Ns..(srangessselfsrsothersappendsl1sh1sl2sh2smaxslsminshs __class__( sselfsothershsh2sh1slsrangessl2sl1sr((s*build\bdist.win32\egg\dispatch\strategy.pys__and__@s      cCs-t|t|jo|i|ijSdS(N(stypesselfsothersranges(sselfsother((s*build\bdist.win32\egg\dispatch\strategy.pys__eq__QscCs||j SdS(N(sselfsother(sselfsother((s*build\bdist.win32\egg\dispatch\strategy.pys__ne__TscCsdS(N((sselfslistener((s*build\bdist.win32\egg\dispatch\strategy.pys subscribeWscCsdS(N((sselfslistener((s*build\bdist.win32\egg\dispatch\strategy.pys unsubscribeZscCsh}t}x|iD]\}}|tjo||f|jod|||f dict[qualifier:list[unqualified_case]] Turn a list of cases with possibly-qualified methods into a dictionary mapping qualifiers to (possibly post-processed) case lists. If a given method is not qualified, it's treated as though it had the qualifier '"primary"'. Keyword arguments supplied to this function are treated as a mapping from qualifiers to lists of functions that should be applied to the list of cases to that qualifier. So, for example, this:: cases = separate_qualifiers(cases, primary=[strategy.ordered_signatures,strategy.safe_methods], ) is equivalent to:: cases = separate_qualifiers(cases) if "primary" in cases: cases["primary"]=safe_methods(ordered_signatures(cases["primary"])) Notice, by the way, that the postprocessing functions must be listed in order of *application* (i.e. outermost last). sprimaryN(scasessqualified_casess signaturesmethods isinstancestuples qualifiers setdefaultsappendsitemssksvspostprocessorssp( squalified_casesspostprocessorss qualifiersksvsps signaturescasessmethod((s*build\bdist.win32\egg\dispatch\strategy.pysseparate_qualifiers}s  #   sExprBasecBs6tZeidegdZdZdZRS(NsinstancesProvidecCs|i| SdS(N(sselfs__eq__sother(sselfsother((s*build\bdist.win32\egg\dispatch\strategy.pys__ne__scCs |iSdS(N(sselfshash(sself((s*build\bdist.win32\egg\dispatch\strategy.pys__hash__scCs tdS(N(sNotImplementedError(sselfsgeneric((s*build\bdist.win32\egg\dispatch\strategy.pys asFuncAndIdss(s__name__s __module__s protocolssadvisesIDispatchableExpressions__ne__s__hash__s asFuncAndIds(((s*build\bdist.win32\egg\dispatch\strategy.pysExprBases  cBs8tZdZeedZdZdZdZRS(sAThe most basic kind of dispatch expression: an argument specifiercCsd|tjo |tjotdn||_||_tt||i|if|_dS(Ns+Argument name or position must be specified(spossNonesnames ValueErrorsselfshashstype(sselfspossname((s*build\bdist.win32\egg\dispatch\strategy.pys__init__s   cCs7t|to#|i|ijo|i|ijSdS(N(s isinstancesothersArgumentspossselfsname(sselfsother((s*build\bdist.win32\egg\dispatch\strategy.pys__eq__scCstd||fdS(Ns%r is not known to %s(s NameErrorsselfsgeneric(sselfsgeneric((s*build\bdist.win32\egg\dispatch\strategy.pys asFuncAndIdsscCs$|io |iSnd|iSdS(Ns Argument(%r)(sselfsnamespos(sself((s*build\bdist.win32\egg\dispatch\strategy.pys__repr__s  (s__name__s __module__s__doc__sNones__init__s__eq__s asFuncAndIdss__repr__(((s*build\bdist.win32\egg\dispatch\strategy.pysArguments   cBsrtZdZeidegdeiegdZdZ dZ dZ dZ dZ d ZRS( s:A set of alternative signatures in disjunctive normal formsinstancesProvidesasAdapterForProtocolscCsIg|_}x5tt|D]$}||jo|i|qqWdS(N(sselfsitemssallsmaps ISignaturesitemsappend(sselfsitemssallsitem((s*build\bdist.win32\egg\dispatch\strategy.pys__init__s   cCst|iSdS(N(sitersselfsitems(sself((s*build\bdist.win32\egg\dispatch\strategy.pys__iter__scCsFtgi}|D]'}t|D]}|||@q!q~SdS(N(s Predicatesappends_[1]sselfsasIDispatchPredicatesothersb(sselfsothersasbs_[1]((s*build\bdist.win32\egg\dispatch\strategy.pys__and__ scCs{t|t}|tj oAt|idjo|id|BSnt|i|gSntt|t|SdS(Nii( s ISignaturesothersNonessigslensselfsitemss Predicateslist(sselfsotherssig((s*build\bdist.win32\egg\dispatch\strategy.pys__or__ s  cCs$||jp|it|jSdS(N(sselfsothersitemsslist(sselfsother((s*build\bdist.win32\egg\dispatch\strategy.pys__eq__scCs|i| SdS(N(sselfs__eq__sother(sselfsother((s*build\bdist.win32\egg\dispatch\strategy.pys__ne__scCs |i SdS(N(sselfsitems(sself((s*build\bdist.win32\egg\dispatch\strategy.pys__repr__s(s__name__s __module__s__doc__s protocolssadvisesIDispatchPredicates sequenceOfs ISignatures__init__s__iter__s__and__s__or__s__eq__s__ne__s__repr__(((s*build\bdist.win32\egg\dispatch\strategy.pys Predicates      cCs t|gS(N(s Predicatesob(sob((s*build\bdist.win32\egg\dispatch\strategy.pys"ss forProtocolscBstZdZeidegddfZfdZdZdZ dZ dZ d Z d Z d Zd ZRS( sEA set of criteria (in conjunctive normal form) applied to expressionssinstancesProvidesdataskeysc Kst|gi}|iD]%\}}|td||fq~}h|_ }g|_ }xg|D]_\}}t |}||i f}||jo||c|MscCs|ii|tSdS(N(sselfsdatasgetsexpr_ids NullCriterion(sselfsexpr_id((s*build\bdist.win32\egg\dispatch\strategy.pysgetAscCsRddigi}|iiD] \}}|d||fq ~fSdS(Ns Signature(%s)s,s%r=%r(sjoinsappends_[1]sselfsdatasitemssksv(sselfs_[1]sksv((s*build\bdist.win32\egg\dispatch\strategy.pys__repr__DscCs|ii}| o|Snt||jot|g|@Snt|i}| o|Snt gi }|i D]!}||d|i|fq}~gi }|D]"\\}}}|||fq~SdS(Ni(sselfsdatasitemssmesothersIDispatchPredicates Predicates ISignaturestheys Signaturesappends_[1]skeyssksdsv(sselfsothersmesdsvs_[1]stheysk((s*build\bdist.win32\egg\dispatch\strategy.pys__and__JscCs}|ii}| o|Snt||jot|g|BSnt|i}| o|Snt||gSdS(N( sselfsdatasitemssmesIDispatchPredicatesothers Predicates ISignaturesthey(sselfsothersmesthey((s*build\bdist.win32\egg\dispatch\strategy.pys__or__\scCs||jotSnt|t}|tjp |tjotSnx8|iD]*\}}||i |jotSqSqSWx8|iD]*\}}||i |jotSqqWtSdS(N( sothersselfsTrues ISignaturesNones NullCriterionsFalsesitemssksvsget(sselfsothersvsk((s*build\bdist.win32\egg\dispatch\strategy.pys__eq__ss     cCs|i| SdS(N(sselfs__eq__sother(sselfsother((s*build\bdist.win32\egg\dispatch\strategy.pys__ne__s(s__name__s __module__s__doc__s protocolssadvises ISignatures __slots__s__init__simpliessitemssgets__repr__s__and__s__or__s__eq__s__ne__(((s*build\bdist.win32\egg\dispatch\strategy.pys Signature%s         cBs?tZeidegdeiegfZedZ RS(NsinstancesProvidesasAdapterForProtocolscCs2ti|ttttt||dS(N( s Signatures__init__sselfszipsmapsArgumentsrangeslenscriteria(sselfscriteriasproto((s*build\bdist.win32\egg\dispatch\strategy.pys__init__s ( s__name__s __module__s protocolssadvises ISignatures sequenceOfs ICriterions __slots__sNones__init__(((s*build\bdist.win32\egg\dispatch\strategy.pysPositionalSignatures(Xs__doc__s __future__s generatorss protocolssProtocolsAdapters StickyAdaptersprotocols.advicesgetMROsoperatorsinspectstypess ClassTypes InstanceTypestypes ClassTypesssyss _getframesmaxintsweakrefsWeakKeyDictionarysrefsdispatch.interfacessnewsinstancemethodsdispatchspeak.util.extremessMinsMaxs__all__srev_opsssets NameErrorssetssSets ImmutableSets frozensetsobjects SeededIndexsdicts DispatchNodes_memosmake_node_typesTruesNonesvalidateCriterionsTGraphsdispatch_by_mrosdispatch_by_subclasssAbstractCriterionssubjects leaf_seedshashs__get__s__hash__s _d_speedupss ImportErrorsClassCriterions_guardsintsPointersdispatch_by_identitysIdentityCriterions NullCriterionsSubclassCriterionsdispatch_by_inequalitiessconcatenate_rangessInequalityIndexs Inequalitys _NotifiersProtocolCriterionsmost_specific_signaturessordered_signaturess all_methodss safe_methodss method_lists method_chains single_bestsseparate_qualifierssExprBasesArguments PredicatesdeclareAdaptersIDispatchPredicates ISignatures SignaturesPositionalSignaturesdefault(;ssetsrev_opssMinsdispatch_by_identitys single_bestsdispatchsPositionalSignaturesSubclassCriterionsmaxints all_methodssseparate_qualifierssoperatorsordered_signaturess_memos NullCriterions PredicatesWeakKeyDictionarys__all__s _NotifiersMaxsExprBases StickyAdaptersconcatenate_rangess Signatures generatorssmake_node_typesdispatch_by_inequalitiessgetMROsdispatch_by_subclasssrefs InstanceTypes method_chains SeededIndexs_guardsvalidateCriterionsmost_specific_signaturessAdaptersinspectsinstancemethodsdispatch_by_mros frozensets ClassTypess protocolssProtocolCriterionsIdentityCriterionsProtocolsTGraphsAbstractCriterions safe_methodssdefaults ClassTypesClassCriterionsArguments Inequalitys _getframes DispatchNodes method_listsPointersInequalityIndex((s*build\bdist.win32\egg\dispatch\strategy.pys?s     N W  { R)  @ )   )  #Re)R )      ))))fPK:8Gdispatch/_d_speedups.pydef __bootstrap__(): global __bootstrap__, __loader__, __file__ import sys, pkg_resources, imp __file__ = pkg_resources.resource_filename(__name__,'_d_speedups.pyd') del __bootstrap__, __loader__ imp.load_dynamic(__name__,__file__) __bootstrap__() PK:88))dispatch/_d_speedups.pyc; RnHc@sdatdS(cCsGdk}dk}dk}|itdabb|ittdS(Ns_d_speedups.pyd( ssyss pkg_resourcessimpsresource_filenames__name__s__file__s __bootstrap__s __loader__s load_dynamic(s pkg_resourcesssyssimp((s-build\bdist.win32\egg\dispatch\_d_speedups.pys __bootstrap__s N(s __bootstrap__(((s-build\bdist.win32\egg\dispatch\_d_speedups.pys?s PKK\8W||dispatch/tests/test_parsing.py"""Test generic functions expression parsing""" from unittest import TestCase, makeSuite, TestSuite from dispatch import *; from dispatch.functions import * from dispatch.predicates import *; from dispatch.strategy import * from dispatch.ast_builder import * from dispatch import predicates import operator,sys,types,dispatch MAXINT = `sys.maxint` class StringBuilder: """Simple parse event receiver to test the AST build functions""" def Name(self,name): return name def Const(self,const): return repr(const) def Compare(self,initExpr,comparisons): data = [build(self,initExpr)] for op,val in comparisons: data.append(op) data.append(build(self,val)) return 'Compare(%s)' % ' '.join(data) def Getattr(self,left,right): return 'Getattr(%s,%r)' % (build(self,left), right) def Dict(self, items): return '{%s}' % ','.join([ '%s:%s' % (build(self,k),build(self,v)) for k,v in items ]) def Sliceobj(self,start,stop,stride): return 'Sliceobj(%s,%s,%s)' % ( build(self,start),build(self,stop),build(self,stride) ) def mkBinOp(op): pat = '%s(%%s,%%s)' % op def method(self,left,right): return pat % (build(self,left),build(self,right)) return method def multiOp(fmt,sep=','): def method(self,items): return fmt % sep.join([build(self,item) for item in items]) return method def unaryOp(fmt): def method(self,expr): return fmt % build(self,expr) return method UnaryPlus = unaryOp('Plus(%s)') UnaryMinus = unaryOp('Minus(%s)') Invert = unaryOp('Invert(%s)') Backquote = unaryOp('repr(%s)') Not = unaryOp('Not(%s)') And = multiOp('And(%s)') Or = multiOp('Or(%s)') Tuple = multiOp('Tuple(%s)') List = multiOp('List(%s)') Bitor = multiOp('Bitor(%s)') Bitxor = multiOp('Bitxor(%s)') Bitand = multiOp('Bitand(%s)') LeftShift = mkBinOp('LeftShift') Power = mkBinOp('Power') RightShift = mkBinOp('RightShift') Add = mkBinOp('Add') Sub = mkBinOp('Sub') Mul = mkBinOp('Mul') Div = mkBinOp('Div') Mod = mkBinOp('Mod') FloorDiv = mkBinOp('FloorDiv') Slice = mkBinOp('Slice') Subscript = mkBinOp('Getitem') def CallFunc(self, func, args, kw, star_node, dstar_node): if star_node: star_node=build(self,star_node) else: star_node = 'None' if dstar_node: dstar_node=build(self,dstar_node) else: dstar_node = 'None' return 'Call(%s,%s,%s,%s,%s)' % ( build(self,func),self.Tuple(args),self.Dict(kw),star_node,dstar_node ) def IfElse(self, trueVal, condition, falseVal): return 'IfElse(%s,%s,%s)' % ( build(self, trueVal), build(self, condition), build(self, falseVal) ) sb = StringBuilder() pe = lambda s: parse_expr(s,sb) class EventTests(TestCase): """Test that AST builder supports all syntax and issues correct events""" def testTokens(self): self.assertEqual(pe("a"), "a") self.assertEqual(pe("b"), "b") self.assertEqual(pe("123"), "123") self.assertEqual(pe("'xyz'"), "'xyz'") self.assertEqual(pe("'abc' 'xyz'"), "'abcxyz'") def testSimpleBinaries(self): self.assertEqual(pe("a+b"), "Add(a,b)") self.assertEqual(pe("b-a"), "Sub(b,a)") self.assertEqual(pe("c*d"), "Mul(c,d)") self.assertEqual(pe("c/d"), "Div(c,d)") self.assertEqual(pe("c%d"), "Mod(c,d)") self.assertEqual(pe("c//d"), "FloorDiv(c,d)") self.assertEqual(pe("a<>b"), "RightShift(a,b)") self.assertEqual(pe("a**b"), "Power(a,b)") self.assertEqual(pe("a.b"), "Getattr(a,'b')") self.assertEqual(pe("a|b"), "Bitor(a,b)") self.assertEqual(pe("a&b"), "Bitand(a,b)") self.assertEqual(pe("a^b"), "Bitxor(a,b)") def testSimpleUnaries(self): self.assertEqual(pe("~a"), "Invert(a)") self.assertEqual(pe("+a"), "Plus(a)") self.assertEqual(pe("-a"), "Minus(a)") self.assertEqual(pe("not a"), "Not(a)") self.assertEqual(pe("`a`"), "repr(a)") if sys.version>='2.5': def testIfElse(self): self.assertEqual(pe("a if b else c"), "IfElse(a,b,c)") def testSequences(self): self.assertEqual(pe("a,"), "Tuple(a)") self.assertEqual(pe("a,b"), "Tuple(a,b)") self.assertEqual(pe("a,b,c"), "Tuple(a,b,c)") self.assertEqual(pe("a,b,c,"), "Tuple(a,b,c)") self.assertEqual(pe("()"), "Tuple()") self.assertEqual(pe("(a)"), "a") self.assertEqual(pe("(a,)"), "Tuple(a)") self.assertEqual(pe("(a,b)"), "Tuple(a,b)") self.assertEqual(pe("(a,b,)"), "Tuple(a,b)") self.assertEqual(pe("(a,b,c)"), "Tuple(a,b,c)") self.assertEqual(pe("(a,b,c,)"), "Tuple(a,b,c)") self.assertEqual(pe("[]"), "List()") self.assertEqual(pe("[a]"), "List(a)") self.assertEqual(pe("[a,]"), "List(a)") self.assertEqual(pe("[a,b]"), "List(a,b)") self.assertEqual(pe("[a,b,]"), "List(a,b)") self.assertEqual(pe("[a,b,c]"), "List(a,b,c)") self.assertEqual(pe("[a,b,c,]"), "List(a,b,c)") self.assertEqual(pe("{}"), "{}") self.assertEqual(pe("{a:b}"), "{a:b}") self.assertEqual(pe("{a:b,}"), "{a:b}") self.assertEqual(pe("{a:b,c:d}"), "{a:b,c:d}") self.assertEqual(pe("{a:b,c:d,1:2}"), "{a:b,c:d,1:2}") self.assertEqual(pe("{a:b,c:d,1:2,}"), "{a:b,c:d,1:2}") self.assertEqual( pe("{(a,b):c+d,e:[f,g]}"), "{Tuple(a,b):Add(c,d),e:List(f,g)}" ) def testCalls(self): self.assertEqual(pe("a()"), "Call(a,Tuple(),{},None,None)") self.assertEqual(pe("a(1,2)"), "Call(a,Tuple(1,2),{},None,None)") self.assertEqual(pe("a(1,2,)"), "Call(a,Tuple(1,2),{},None,None)") self.assertEqual(pe("a(b=3)"), "Call(a,Tuple(),{'b':3},None,None)") self.assertEqual(pe("a(1,2,b=3)"), "Call(a,Tuple(1,2),{'b':3},None,None)" ) self.assertEqual(pe("a(*x)"), "Call(a,Tuple(),{},x,None)") self.assertEqual(pe("a(1,*x)"), "Call(a,Tuple(1),{},x,None)") self.assertEqual(pe("a(b=3,*x)"), "Call(a,Tuple(),{'b':3},x,None)") self.assertEqual(pe("a(1,2,b=3,*x)"), "Call(a,Tuple(1,2),{'b':3},x,None)" ) self.assertEqual(pe("a(**y)"), "Call(a,Tuple(),{},None,y)") self.assertEqual(pe("a(1,**y)"), "Call(a,Tuple(1),{},None,y)") self.assertEqual(pe("a(b=3,**y)"), "Call(a,Tuple(),{'b':3},None,y)") self.assertEqual(pe("a(1,2,b=3,**y)"), "Call(a,Tuple(1,2),{'b':3},None,y)" ) self.assertEqual(pe("a(*x,**y)"), "Call(a,Tuple(),{},x,y)") self.assertEqual(pe("a(1,*x,**y)"), "Call(a,Tuple(1),{},x,y)") self.assertEqual(pe("a(b=3,*x,**y)"), "Call(a,Tuple(),{'b':3},x,y)") self.assertEqual(pe("a(1,2,b=3,*x,**y)"), "Call(a,Tuple(1,2),{'b':3},x,y)" ) self.assertRaises(SyntaxError, pe, "a(1=2)") # expr as kw self.assertRaises(SyntaxError, pe, "a(b=2,c)") # kw before positional def testSubscripts(self): self.assertEqual(pe("a[1]"), "Getitem(a,1)") self.assertEqual(pe("a[2,3]"), "Getitem(a,Tuple(2,3))") self.assertEqual(pe("a[...]"), "Getitem(a,Ellipsis)") # 2-element slices (getslice) self.assertEqual(pe("a[:]"), "Getitem(a,Slice(0,%s))" % MAXINT) self.assertEqual(pe("a[1:2]"), "Getitem(a,Slice(1,2))") self.assertEqual(pe("a[1:]"), "Getitem(a,Slice(1,%s))" % MAXINT) self.assertEqual(pe("a[:2]"), "Getitem(a,Slice(0,2))") # 3-part slice objects (getitem(slice()) self.assertEqual(pe("a[::]"), "Getitem(a,Sliceobj(None,None,None))") self.assertEqual(pe("a[1::]"), "Getitem(a,Sliceobj(1,None,None))") self.assertEqual(pe("a[:2:]"), "Getitem(a,Sliceobj(None,2,None))") self.assertEqual(pe("a[1:2:]"), "Getitem(a,Sliceobj(1,2,None))") self.assertEqual(pe("a[::3]"), "Getitem(a,Sliceobj(None,None,3))") self.assertEqual(pe("a[1::3]"), "Getitem(a,Sliceobj(1,None,3))") self.assertEqual(pe("a[:2:3]"), "Getitem(a,Sliceobj(None,2,3))") self.assertEqual(pe("a[1:2:3]"),"Getitem(a,Sliceobj(1,2,3))") def testCompare(self): self.assertEqual(pe("a>b"), "Compare(a > b)") self.assertEqual(pe("a>=b"), "Compare(a >= b)") self.assertEqual(pe("ab"), "Compare(a <> b)") self.assertEqual(pe("a!=b"), "Compare(a != b)") self.assertEqual(pe("a==b"), "Compare(a == b)") self.assertEqual(pe("a in b"), "Compare(a in b)") self.assertEqual(pe("a is b"), "Compare(a is b)") self.assertEqual(pe("a not in b"), "Compare(a not in b)") self.assertEqual(pe("a is not b"), "Compare(a is not b)") sb.simplify_comparisons = True self.assertEqual(pe("1<2<3"), "And(Compare(1 < 2),Compare(2 < 3))") self.assertEqual(pe("a>=b>c= b),Compare(b > c),Compare(c < d))") sb.simplify_comparisons = False self.assertEqual(pe("1<2<3"), "Compare(1 < 2 < 3)") self.assertEqual(pe("a>=b>c= b > c < d)") def testMultiOps(self): self.assertEqual(pe("a and b"), "And(a,b)") self.assertEqual(pe("a or b"), "Or(a,b)") self.assertEqual(pe("a and b and c"), "And(a,b,c)") self.assertEqual(pe("a or b or c"), "Or(a,b,c)") self.assertEqual(pe("a and b and c and d"), "And(a,b,c,d)") self.assertEqual(pe("a or b or c or d"), "Or(a,b,c,d)") self.assertEqual(pe("a&b&c"), "Bitand(a,b,c)") self.assertEqual(pe("a|b|c"), "Bitor(a,b,c)") self.assertEqual(pe("a^b^c"), "Bitxor(a,b,c)") self.assertEqual(pe("a&b&c&d"), "Bitand(a,b,c,d)") self.assertEqual(pe("a|b|c|d"), "Bitor(a,b,c,d)") self.assertEqual(pe("a^b^c^d"), "Bitxor(a,b,c,d)") def testAssociativity(self): # Mostly this is sanity checking, since associativity and precedence # are primarily grammar-driven, but there are a few places where the # ast_builder library is responsible for correct associativity. self.assertEqual(pe("a+b+c"), "Add(Add(a,b),c)") self.assertEqual(pe("a*b*c"), "Mul(Mul(a,b),c)") self.assertEqual(pe("a/b/c"), "Div(Div(a,b),c)") self.assertEqual(pe("a//b//c"), "FloorDiv(FloorDiv(a,b),c)") self.assertEqual(pe("a%b%c"), "Mod(Mod(a,b),c)") self.assertEqual(pe("a<>b>>c"), "RightShift(RightShift(a,b),c)") self.assertEqual(pe("a.b.c"), "Getattr(Getattr(a,'b'),'c')") self.assertEqual(pe("a()()"), "Call(Call(a,Tuple(),{},None,None),Tuple(),{},None,None)" ) self.assertEqual(pe("a[b][c]"), "Getitem(Getitem(a,b),c)") # power is right-associative self.assertEqual(pe("a**b**c"), "Power(a,Power(b,c))") # sanity check on arithmetic precedence self.assertEqual(pe("5*x**2 + 4*x + -1"), "Add(Add(Mul(5,Power(x,2)),Mul(4,x)),Minus(1))" ) class ExprBuilderTests(TestCase): """Test that expression builder builds correct IDispatchableExpressions""" def setUp(self): self.arguments = arguments = dict( [(n,Argument(name=n)) for n in 'abcdefg'] ) self.namespaces = namespaces = locals(),globals(),__builtins__ self.builder = builder = ExprBuilder(arguments,*namespaces) def parse(self,expr): return parse_expr(expr, self.builder) def checkConstOrVar(self,items): # Verify builder's handling of global/builtin namespaces self.builder.bind_globals = True for name,val in items: # If bind_globals is true, return a constant for the current value self.assertEqual(self.builder.Name(name),Const(val),name) def testTokens(self): self.assertEqual(self.builder.Const(123), Const(123)) for arg in self.arguments: self.assertEqual(self.parse(arg), Argument(name=arg)) self.assertEqual(self.parse("123"), Const(123)) self.assertEqual(self.parse("'xyz'"), Const('xyz')) self.assertEqual(self.parse("'abc' 'xyz'"), Const('abcxyz')) if sys.version>='2.5': def testIfElse(self): a,b,c = Argument(name='a'), Argument(name='b'), Argument(name='c') self.assertEqual(self.parse("a if b else c"), IfElse(a,b,c)) def testSimpleBinariesAndUnaries(self): pe = self.parse a,b,c = Argument(name='a'), Argument(name='b'), Argument(name='c') self.assertEqual(pe("a+b"), Call(operator.add, a, b)) self.assertEqual(pe("a-b"), Call(operator.sub, a, b)) self.assertEqual(pe("b*c"), Call(operator.mul, b, c)) self.assertEqual(pe("b/c"), Call(operator.div, b, c)) self.assertEqual(pe("b%c"), Call(operator.mod, b, c)) self.assertEqual(pe("b//c"), Call(operator.floordiv, b, c)) self.assertEqual(pe("a<>b"), Call(operator.rshift, a, b)) self.assertEqual(pe("a**b"), Call(pow, a, b)) self.assertEqual(pe("a.b"), Getattr(a,'b')) self.assertEqual(pe("a|b"), Call(operator.or_, a, b)) self.assertEqual(pe("a&b"), Call(operator.and_, a, b)) self.assertEqual(pe("a^b"), Call(operator.xor, a, b)) self.assertEqual(pe("~a"), Call(operator.invert, a)) self.assertEqual(pe("+a"), Call(operator.pos, a)) self.assertEqual(pe("-a"), Call(operator.neg, a)) self.assertEqual(pe("not a"), Call(operator.not_,a)) self.assertEqual(pe("`a`"), Call(repr,a)) self.assertEqual(pe("a and b"), AndExpr(a,b)) self.assertEqual(pe("a or b"), OrExpr(a,b)) def testConstantFolding(self): pe = self.parse self.assertEqual(pe("1+2"), Const(3)) self.assertEqual(pe("2-1"), Const(1)) self.assertEqual(pe("7*9"), Const(63)) self.assertEqual(pe("25/10.0"), Const(2.5)) self.assertEqual(pe("25%3"), Const(1)) self.assertEqual(pe("25//10.0"), Const(2)) self.assertEqual(pe("16<<4"), Const(256)) self.assertEqual(pe("256>>4"), Const(16)) self.assertEqual(pe("2**4"), Const(16)) self.assertEqual(pe("dict.__class__"), Const(type)) self.assertEqual(pe("1|5"), Const(5)) self.assertEqual(pe("5&1"), Const(1)) self.assertEqual(pe("1^2"), Const(3)) self.assertEqual(pe("~1"), Const(-2)) self.assertEqual(pe("+1"), Const(1)) self.assertEqual(pe("-1"), Const(-1)) self.assertEqual(pe("not True"), Const(False)) self.assertEqual(pe("`27`"), Const("27")) self.assertEqual(pe('1,2'), Const((1,2))) self.assertEqual(pe('[1,2]'), Const([1,2])) self.assertEqual(pe('{1:2}'), Const({1:2})) self.assertEqual(pe('1 and 2'), Const(2)) self.assertEqual(pe('"" and 2'), Const("")) self.assertEqual(pe('"" or 53 or 27'), Const(53)) if sys.version>="2.5": self.assertEqual(pe('1 if 2 else 3'), Const(1)) self.assertEqual(pe('1 if not 2 else 3'), Const(3)) def testSequences(self): pe = self.parse a,b,c = Argument(name='a'), Argument(name='b'), Argument(name='c') d,e,f = Argument(name='d'), Argument(name='e'), Argument(name='f') g = Argument(name='g') self.assertEqual(pe("a,"), Tuple(tuple,a)) self.assertEqual(pe("a,b"), Tuple(tuple,a,b)) self.assertEqual(pe("a,b,c"), Tuple(tuple,a,b,c)) self.assertEqual(pe("a,b,c,"), Tuple(tuple,a,b,c)) self.assertEqual(pe("()"), Tuple(tuple)) self.assertEqual(pe("(a)"), a) self.assertEqual(pe("(a,)"), Tuple(tuple,a)) self.assertEqual(pe("(a,b)"), Tuple(tuple,a,b)) self.assertEqual(pe("(a,b,)"), Tuple(tuple,a,b)) self.assertEqual(pe("(a,b,c)"), Tuple(tuple,a,b,c)) self.assertEqual(pe("(a,b,c,)"), Tuple(tuple,a,b,c)) self.assertEqual(pe("[]"), Tuple(list)) self.assertEqual(pe("[a]"), Tuple(list,a)) self.assertEqual(pe("[a,]"), Tuple(list,a)) self.assertEqual(pe("[a,b]"), Tuple(list,a,b)) self.assertEqual(pe("[a,b,]"), Tuple(list,a,b)) self.assertEqual(pe("[a,b,c]"), Tuple(list,a,b,c)) self.assertEqual(pe("[a,b,c,]"), Tuple(list,a,b,c)) md = lambda k,v: Call(dict,Call(zip,Tuple(tuple,*k),Tuple(tuple,*v))) self.assertEqual(pe("{}"),md((),())) self.assertEqual(pe("{a:b}"),md([a],[b])) self.assertEqual(pe("{a:b,}"),md([a],[b])) self.assertEqual(pe("{a:b,c:d}"),md([a,c],[b,d])) self.assertEqual(pe("{a:b,c:d,1:2}"),md([a,c,Const(1)],[b,d,Const(2)])) self.assertEqual(pe("{a:b,c:d,1:2,}"),md([a,c,Const(1)],[b,d,Const(2)])) self.assertEqual( pe("{(a,b):c+d,e:[f,g]}"), md([Tuple(tuple,a,b),e], [Call(operator.add,c,d),Tuple(list,f,g)]) ) def testCalls(self): pe = self.parse a,b,c,d = map(self.arguments.__getitem__, "abcd") md = lambda k,v: Call(dict,Call(zip,Tuple(tuple,*k),Tuple(tuple,*v))) one_two = Const((1,2)) b_three = Const({'b':3}) empty = Const(()) self.assertEqual(pe("a()"), Call(apply,a)) self.assertEqual(pe("dict()"), Call(dict)) self.assertEqual(pe("int(a)"), Call(int,a)) self.assertEqual(pe("a(1,2)"), Call(apply,a,one_two)) self.assertEqual(pe("a(1,2,)"), Call(apply,a,one_two)) self.assertEqual(pe("a(b=3)"), Call(apply,a,empty,b_three)) self.assertEqual(pe("a(1,2,b=3)"), Call(apply,a,one_two,b_three)) self.assertEqual(pe("a(*b)"), Call(apply,a,b)) self.assertEqual(pe("a(1,2,*b)"), Call(apply,a,Call(operator.add,one_two,Call(tuple,b)))) self.assertEqual(pe("a(b=3,*c)"), Call(apply,a,c,b_three)) self.assertEqual(pe("a(1,2,b=3,*c)"), Call(apply,a,Call(operator.add,one_two,Call(tuple,c)),b_three)) self.assertEqual(pe("a(**c)"), Call(apply,a,Const(()),c)) self.assertEqual(pe("a(1,2,**c)"), Call(apply,a,one_two,c)) self.assertEqual(pe("a(b=3,**c)"), Call(apply,a,Const(()),Call(predicates.add_dict, b_three, c))) self.assertEqual(pe("a(1,2,b=3,**c)"), Call(apply,a,one_two,Call(predicates.add_dict, b_three, c))) self.assertEqual(pe("a(b=3,*c,**d)"), Call(apply,a,c,Call(predicates.add_dict,b_three,d))) self.assertEqual(pe("a(1,2,b=3,*c,**d)"), Call(apply,a,Call(operator.add,one_two,Call(tuple,c)), Call(predicates.add_dict, b_three, d))) self.assertEqual(pe("a(*c,**d)"), Call(apply,a,c,d)) self.assertEqual(pe("a(1,2,*c,**d)"), Call(apply,a,Call(operator.add,one_two,Call(tuple,c)),d)) def testMultiOps(self): pe = self.parse a,b,c = Argument(name='a'), Argument(name='b'), Argument(name='c') d = Argument(name='d') self.assertEqual(pe("a and b and c"), AndExpr(a,b,c)) self.assertEqual(pe("a or b or c"), OrExpr(a,b,c)) self.assertEqual(pe("a and b and c and d"), AndExpr(a,b,c,d)) self.assertEqual(pe("a or b or c or d"), OrExpr(a,b,c,d)) self.assertEqual(pe("a&b&c"), Call(operator.and_,Call(operator.and_,a,b),c)) self.assertEqual(pe("a|b|c"), Call(operator.or_,Call(operator.or_,a,b),c)) self.assertEqual(pe("a^b^c"), Call(operator.xor,Call(operator.xor,a,b),c)) def testSubscripts(self): pe = self.parse a,b,c = Argument(name='a'), Argument(name='b'), Argument(name='c') gi = lambda ob,key: Call(operator.getitem,ob,key) gs = lambda ob,start,stop: Call(operator.getslice,ob,start,stop) gso = lambda ob,*x: gi(ob, Call(slice,*map(Const,x))) self.assertEqual(pe("a[1]"), gi(a,Const(1))) self.assertEqual(pe("a[2,3]"), gi(a,Tuple(tuple,Const(2),Const(3)))) self.assertEqual(pe("a[...]"), gi(a,Const(Ellipsis))) # 2-element slices (getslice) self.assertEqual(pe("a[:]"), gs(a,Const(0),Const(sys.maxint))) self.assertEqual(pe("a[1:2]"), gs(a,Const(1),Const(2))) self.assertEqual(pe("a[1:]"), gs(a,Const(1),Const(sys.maxint))) self.assertEqual(pe("a[:2]"), gs(a,Const(0),Const(2))) # 3-part slice objects (getitem(slice()) self.assertEqual(pe("a[::]"), gso(a,None,None,None)) self.assertEqual(pe("a[1::]"), gso(a,1,None,None)) self.assertEqual(pe("a[:2:]"), gso(a,None,2,None)) self.assertEqual(pe("a[1:2:]"), gso(a,1,2,None)) self.assertEqual(pe("a[::3]"), gso(a,None,None,3)) self.assertEqual(pe("a[1::3]"), gso(a,1,None,3)) self.assertEqual(pe("a[:2:3]"), gso(a,None,2,3)) self.assertEqual(pe("a[1:2:3]"),gso(a,1,2,3)) def testCompare(self): pe = self.parse a,b,c = Argument(name='a'), Argument(name='b'), Argument(name='c') d = Argument(name='d') self.assertEqual(pe("a>b"), Call(operator.gt,a,b)) self.assertEqual(pe("a>=b"), Call(operator.ge,a,b)) self.assertEqual(pe("ab"), Call(operator.ne,a,b)) self.assertEqual(pe("a!=b"), Call(operator.ne,a,b)) self.assertEqual(pe("a==b"), Call(operator.eq,a,b)) self.assertEqual(pe("a in b"), Call(predicates.in_,a,b)) self.assertEqual(pe("a is b"), Call(predicates.is_,a,b)) self.assertEqual(pe("a not in b"), Call(predicates.not_in,a,b)) self.assertEqual(pe("a is not b"), Call(predicates.is_not,a,b)) self.assertEqual(pe("1<2<3"), Const(True)) self.assertEqual(pe("a>=b>c', '<', '<=','gt','le'), ('<', '>', '>=','lt','ge'), ('==','==','!=','eq','ne'), ('<>','<>','==','ne','eq'), ]: fwd_sig = Signature(x=Inequality(op,1)) self.assertEqual(pe('x %s 1' % op), fwd_sig) self.assertEqual(pe('1 %s x' % mirror_op), fwd_sig) rev_sig = Signature(x=Inequality(mirror_op,1)) self.assertEqual(pe('x %s 1' % mirror_op), rev_sig) self.assertEqual(pe('1 %s x' % op), rev_sig) not_sig = Signature(x=Inequality(not_op,1)) self.assertEqual(pe('not x %s 1' % op), not_sig) self.assertEqual(pe('not x %s 1' % not_op), fwd_sig) self.assertEqual(pe('x %s y' % op), x_cmp_y(name)) self.assertEqual(pe('x %s y' % not_op), x_cmp_y(not_name)) self.assertEqual(pe('not x %s y' % op),x_cmp_y(name,False)) self.assertEqual(pe('not x %s y' % not_op),x_cmp_y(not_name,False)) def testParseMembership(self): parse = GenericFunction(lambda x,y,z:None).parse pe = lambda e: parse(e,locals(),globals()) self.assertEqual(pe('x in int'), Signature(x=int)) self.assertEqual(pe('x not in int'), Signature(x=NotCriterion(int))) self.assertEqual(pe('x in (1,2,3)'), predicates.compileIn(Argument(name='x'),[1,2,3],True)) self.assertEqual(pe('x not in (1,2,3)'), predicates.compileIn(Argument(name='x'),[1,2,3],False)) self.assertEqual(pe('x is y'), Signature([(Call(predicates.is_,Argument(name='x'), Argument(name='y')),TruthCriterion())] ) ) self.assertEqual(pe('x is not y'), Signature([(Call(predicates.is_not,Argument(name='x'), Argument(name='y')),TruthCriterion())] ) ) self.assertEqual(pe('x is TestCase'), Signature([(Argument(name='x'),ICriterion(Pointer(TestCase)))]) ) self.assertEqual(pe('x is not TestCase'), Signature([(Argument(name='x'),~ICriterion(Pointer(TestCase)))]) ) # optimization when 'is None' and type tests occur on an expression self.assertEqual(pe('x is None'),Signature(x=types.NoneType)) self.assertEqual(pe('x is not None'), Signature(x=NotCriterion(types.NoneType))) self.assertEqual(pe('not (x is not None)'),Signature(x=types.NoneType)) self.assertEqual(pe('not (x is None)'), Signature(x=NotCriterion(types.NoneType))) def testParseExpressionMatching(self): parse = GenericFunction(lambda x,y,z:None).parse pe = lambda e: parse(e,locals(),globals()) self.assertEqual(pe('isinstance(x,int)'), Signature(x=int)) self.assertEqual(pe('isinstance(x,(str,unicode))'), Signature(x=str)|Signature(x=unicode)) self.assertEqual(pe('isinstance(x,(int,(str,unicode)))'), Signature(x=int)|Signature(x=str)|Signature(x=unicode)) self.assertEqual(pe('not isinstance(x,(int,(str,unicode)))'), Signature(x=~ICriterion(int)&~ICriterion(str)&~ICriterion(unicode)) ) self.assertEqual( pe('issubclass(x,int)'), Signature(x=SubclassCriterion(int))) self.assertEqual(pe('issubclass(x,(str,unicode))'), Signature(x=SubclassCriterion(str)) | Signature(x=SubclassCriterion(unicode)) ) self.assertEqual(pe('issubclass(x,(int,(str,unicode)))'), Signature(x=SubclassCriterion(int)) | Signature(x=SubclassCriterion(str)) | Signature(x=SubclassCriterion(unicode)) ) self.assertEqual(pe('not issubclass(x,(int,(str,unicode)))'), Signature( x=AndCriterion( *[~SubclassCriterion(x) for x in (int,str,unicode)]) ) ) def testCompileIn(self): x = Argument(name='x') in_expr = predicates.compileIn(x,[1,2,3],True) not_in = predicates.compileIn(x,[1,2,3],False) self.failUnless(isinstance(not_in,Signature)) self.failUnless(isinstance(in_expr,Predicate)) self.assertEqual(in_expr, Predicate([Signature(x=Inequality('==',v)) for v in 1,2,3]) ) self.assertEqual(not_in, Signature([ (x,reduce(operator.and_,[Inequality('<>',v) for v in 1,2,3])) ]) ) def testParseDNF(self): parse = GenericFunction(lambda x,y,z:None).parse pe = lambda e: parse(e,locals(),globals()) # and => Signature self.assertEqual(pe('x in int and y in str'),Signature(x=int,y=str)) # or => Predicate self.assertEqual(pe('x in int or y in str'),Predicate([ Signature(x=int), Signature(y=str) ])) # Verify 'not' pushes down to the operators self.assertEqual( pe('not(x in int or y in str)'), Signature(x=NotCriterion(int),y=NotCriterion(str)) ) self.assertEqual(pe('not( x in int and y in str)'),Predicate([ Signature(x=NotCriterion(int)), Signature(y=NotCriterion(str)) ])) # ...and cancels out nested not's self.assertEqual( pe('not(x not in int or y not in str)'), Signature(x=int,y=str) ) self.assertEqual(pe('not( x not in int and y not in str)'),Predicate([ Signature(x=int), Signature(y=str) ])) # mixed and/or self.assertEqual(pe('x in int and y in int or z in str'),Predicate([ Signature(x=int,y=int), Signature(z=str) ])) def testSimplePreds(self): [dispatch.generic()] def classify(age): """Stereotype for age""" def defmethod(gf,s,func): gf.addMethod(gf.parse(s,locals(),globals()),func) defmethod(classify,'not not age<2', lambda age:"infant") defmethod(classify,'age<13', lambda age:"preteen") defmethod(classify,'age<5', lambda age:"preschooler") defmethod(classify,'20>age', lambda age:"teenager") defmethod(classify,'not age<20',lambda age:"adult") defmethod(classify,'age>=55',lambda age:"senior") defmethod(classify,'age==16',lambda age:"sweet sixteen") self.assertEqual(classify(25),"adult") self.assertEqual(classify(17),"teenager") self.assertEqual(classify(13),"teenager") self.assertEqual(classify(12.99),"preteen") self.assertEqual(classify(0),"infant") self.assertEqual(classify(4),"preschooler") self.assertEqual(classify(55),"senior") self.assertEqual(classify(54.9),"adult") self.assertEqual(classify(14.5),"teenager") self.assertEqual(classify(16),"sweet sixteen") self.assertEqual(classify(16.5),"teenager") self.assertEqual(classify(99),"senior") self.assertEqual(classify(Min),"infant") self.assertEqual(classify(Max),"senior") TestClasses = ( EventTests, ExprBuilderTests, PredicateTests, ) def test_suite(): s = [] for t in TestClasses: s.append(makeSuite(t,'test')) return TestSuite(s) PKK\8  dispatch/tests/__init__.pyfrom unittest import TestSuite, TestCase, makeSuite def test_suite(): from dispatch.tests import test_dispatch, test_parsing tests = [ test_dispatch.test_suite(), test_parsing.test_suite(), ] return TestSuite( tests ) PKK\8>>dispatch/tests/test_dispatch.py"""Test generic functions""" from unittest import TestCase, makeSuite, TestSuite import operator, sys from types import ClassType, InstanceType from sys import maxint, version import dispatch,protocols from dispatch import * from dispatch.predicates import *; from dispatch.functions import * from protocols import Interface,advise,declareImplementation from protocols.advice import getMRO from dispatch import strategy, functions from dispatch.strategy import * class Vehicle(object): pass class LandVehicle(Vehicle): pass class WaterVehicle(Vehicle): pass class Wheeled(Interface): pass class FourWheeled(Wheeled): pass class TwoWheeled(Wheeled): pass class GasPowered: pass class HumanPowered: pass class Bicycle(HumanPowered,LandVehicle): advise(instancesProvide=[TwoWheeled]) class Hummer(GasPowered,LandVehicle): advise(instancesProvide=[FourWheeled]) class Speedboat(GasPowered,WaterVehicle): pass class PaddleBoat(HumanPowered,WaterVehicle): pass class RiverBoat(WaterVehicle): advise(instancesProvide=[TwoWheeled]) class TestGraph(TestCase): def testItems(self): g = strategy.TGraph() self.assertEqual(g.items(),[]) g.add(2,3) self.assertEqual(g.items(),[(2,3)]) g.add(1,2) items = g.items(); items.sort() self.assertEqual(items,[(1,2),(1,3),(2,3)]) g = strategy.TGraph() self.assertEqual(g.items(),[]) g.add(1,2) self.assertEqual(g.items(),[(1,2)]) g.add(2,3) items = g.items(); items.sort() self.assertEqual(items,[(1,2),(1,3),(2,3)]) g.add(1,5); g.add(2,6) items = g.items(); items.sort() self.assertEqual(items,[(1,2),(1,3),(1,5),(1,6),(2,3),(2,6)]) def testSuccessors(self): g = strategy.TGraph() g.add(1,2) self.assertEqual(g.successors([1]),{2:1}) self.assertEqual(g.successors([2]),{}) self.assertEqual(g.successors([3]),{}) g.add(2,3) self.assertEqual(g.successors([1]),{2:1, 3:1}) self.assertEqual(g.successors([2]),{3:1}) self.assertEqual(g.successors([1,2]),{2:1, 3:1}) self.assertEqual(g.successors([3]),{}) g.add(3,1) self.assertEqual(g.successors([1,2,3]),{}) items = g.items(); items.sort() self.assertEqual(items, [(1,1),(1,2),(1,3),(2,1),(2,2),(2,3),(3,1),(3,2),(3,3)]) class CriteriaTests(TestCase): def testClassCriteriaMembership(self): hp = ISeededCriterion(HumanPowered) self.failUnless(PaddleBoat in hp) self.failUnless(Bicycle in hp) self.failIf(Vehicle in hp) self.failIf(Speedboat in hp) self.failIf(Hummer in hp) self.failIf(object in hp) it = ISeededCriterion(InstanceType) ob = ISeededCriterion(object) for klass in (GasPowered,HumanPowered): self.failUnless(klass in it) self.failUnless(klass in ob) for klass in (Vehicle,LandVehicle,WaterVehicle,Bicycle,Hummer, Speedboat,PaddleBoat ): self.failIf(klass in it) self.failUnless(klass in ob) def testTestImplication(self): self.failUnless(ICriterion(Bicycle).implies(Wheeled)) self.failUnless(ICriterion(PaddleBoat).implies(HumanPowered)) self.failUnless(ICriterion(Hummer).implies(FourWheeled)) self.failUnless(ICriterion(Hummer).implies(LandVehicle)) self.failUnless(ICriterion(Speedboat).implies(Vehicle)) self.failUnless(ICriterion(Wheeled).implies(object)) self.failUnless(ICriterion(GasPowered).implies(InstanceType)) self.failUnless(ICriterion(Wheeled).implies(Vehicle)) self.failIf(ICriterion(object).implies(Speedboat)) def testNullCriterion(self): # Null test has no seeds self.failIf(list(NullCriterion.seeds())) # and it matches anything self.failUnless(object in NullCriterion) self.failUnless(Speedboat in NullCriterion) # is implied by everything self.failUnless(ICriterion(Vehicle).implies(NullCriterion)) # and implies nothing self.failIf(NullCriterion.implies(object)) def testClassCriteriaSeedsAndDispatchFunctions(self): for klass in (Vehicle,LandVehicle,WaterVehicle,HumanPowered,GasPowered): seeds = list(ISeededCriterion(klass).seeds()) self.failUnless(klass in seeds) self.failUnless(object in seeds) self.failIf(len(seeds)<>2) validateCriterion(klass, strategy.make_node_type(strategy.dispatch_by_mro), parents=[ICriterion(cls) for cls in getMRO(klass,True)]) def testCriterionAdaptation(self): self.failUnless(Hummer in ISeededCriterion(Wheeled)) self.failIf(ICriterion(Hummer).implies(Speedboat)) self.failUnless(ICriterion(Speedboat).implies(WaterVehicle)) self.failUnless(object in list(ISeededCriterion(InstanceType).seeds())) def testProtocolCriterion(self): self.failUnless(Bicycle in ISeededCriterion(Wheeled)) seeds = list(ISeededCriterion(Wheeled).seeds()) self.failUnless(Hummer in seeds) self.failUnless(Bicycle in seeds) self.failUnless(object in seeds) self.failUnless(len(seeds)==4) class BrokenBike(Bicycle): advise(instancesDoNotProvide=[Wheeled]) self.failIf(BrokenBike in ISeededCriterion(Wheeled)) def testSignatures(self): a0 = Argument(0); a1 = Argument(1) d1 = {a0:ICriterion(LandVehicle), a1:ICriterion(WaterVehicle)} d2 = {a0:ICriterion(Hummer), a1:ICriterion(Speedboat)} d3 = {a0:ICriterion(WaterVehicle), a1:ICriterion(LandVehicle)} d4 = {a0:ICriterion(LandVehicle), a1:ICriterion(LandVehicle)} for d in d1,d2,d3,d4: self.assertEqual( dict(Signature(d.items()).items()), dict([((k,v.node_type),v) for k,v in d.items()]) ) s1 = Signature(d1.items()) s2 = Signature(d2.items()) s3 = Signature(d3.items()) s4 = Signature(d4.items()) s5 = PositionalSignature( (ICriterion(LandVehicle),ICriterion(WaterVehicle), ICriterion(object)) ) self.failUnless(s2.implies(s1)); self.failIf(s1.implies(s2)) self.failUnless(s5.implies(s1)); self.failIf(s1.implies(s3)) self.failIf(s1.implies(s4)); self.failIf(s2.implies(s3)) self.failIf(s2.implies(s4)); self.failIf(s1.implies(s5)) all_sigs = [(s1,0),(s2,0),(s3,0),(s4,0),(s5,0)] self.assertEqual( most_specific_signatures(all_sigs), [(s2,0),(s3,0),(s4,0),(s5,0)] ) self.assertEqual( most_specific_signatures([(s1,0),(s2,0)]), [(s2,0)] ) self.assertEqual( list(ordered_signatures(all_sigs)), [[(s2,0),(s3,0),(s4,0),(s5,0)],[(s1,0)]] ) self.assertEqual( list(ordered_signatures([(s1,0),(s2,0)])), [[(s2,0)],[(s1,0)]] ) def testMinMax(self): self.failUnless(Min < Max) self.failUnless(Max > Min) self.failUnless(Max == Max) self.failUnless(Min == Min) self.failIf(Min==Max or Max==Min) self.failUnless(Max > "xyz") self.failUnless(Min < "xyz") self.failUnless(Max > 999999) self.failUnless(Min < -999999) data = [(27,Max),(Min,99),(53,Max),(Min,27),(53,56)] data.sort() self.assertEqual(data, [(Min,27),(Min,99),(27,Max),(53,56),(53,Max)] ) class X: """Ensure rich comparisons work correctly with classic classes""" x = X() for v1,v2 in [(Min,x),(x,Max)]: self.failUnless(v1 < v2) self.failUnless(v1 <= v2) self.failIf(v1 == v2) self.failUnless(v1 != v2) self.failUnless(v2 > v1) self.failUnless(v2 >= v2) def testIdentityDispatch(self): ob1, ob2, ob3 = object(),object(),object() id1, id2, id3 = [id(ob)&maxint for ob in [ob1,ob2,ob3]] table = {id1:1,id2:2,None:3} self.assertEqual(strategy.dispatch_by_identity(table, Vehicle), 3) self.assertEqual(strategy.dispatch_by_identity(table, ob1), 1) self.assertEqual(strategy.dispatch_by_identity(table, ob2), 2) self.assertEqual(strategy.dispatch_by_identity(table, ob3), 3) def testTruth(self): for t in True,False: validateCriterion(TruthCriterion(t), strategy.make_node_type(strategy.dispatch_by_truth)) def testPointers(self): anOb = object() ptr = Pointer(anOb) self.assertEqual(id(anOb)&maxint,ptr) self.assertEqual(hash(id(anOb)&maxint),hash(ptr)) class X: pass anOb = X() ptr = Pointer(anOb) oid = id(anOb)&maxint self.assertEqual(oid,ptr) self.assertEqual(hash(oid),hash(ptr)) del anOb self.assertNotEqual(oid,ptr) self.assertEqual(ptr,ptr) self.assertEqual(hash(oid),hash(ptr)) def testIdentityCriterion(self): ob = object() i = Pointer(ob) validateCriterion(i, strategy.make_node_type(strategy.dispatch_by_identity)) i = ISeededCriterion(i) self.assertEqual(list(i.seeds()),[None,id(ob)&maxint]) def testSeededIndex(self): i = SeededIndex(None) # XXX i[SubclassCriterion(int)] = 42 self.assertEqual(i.casemap_for([42]), {int:[42],None:[]}) i.addSeed(int) # make sure seed isn't duplicated self.assertEqual(i.casemap_for([42]), {int:[42],None:[]}) i = SeededIndex(None) # XXX def testSubclassCriterion(self): s = SubclassCriterion(Vehicle) validateCriterion(s, strategy.make_node_type(strategy.dispatch_by_subclass), parents=[SubclassCriterion(c) for c in getMRO(Vehicle,True)] ) # seeds() self.assertEqual( s.seeds(), [Vehicle,None]) # __contains__ for klass in Vehicle,LandVehicle,WaterVehicle: self.failUnless(klass in s) for klass in None,GasPowered,object,Wheeled: self.failUnless(klass not in s) # implies() self.failUnless( s.implies(SubclassCriterion(object)) ) self.failUnless( SubclassCriterion(LandVehicle).implies(s) ) self.failIf( s.implies(SubclassCriterion(LandVehicle)) ) self.failIf( SubclassCriterion(object).implies(s) ) # eq/ne/invert self.assertEqual( s, SubclassCriterion(Vehicle)) self.assertNotEqual( s, SubclassCriterion(LandVehicle)) # matches() table = {LandVehicle:1,object:2,None:3} items = list(s.matches(table)) self.assertEqual(items,[LandVehicle]) # dispatch table = {Vehicle:1,object:2,None:3} self.assertEqual(strategy.dispatch_by_subclass(table, Vehicle), 1) self.assertEqual(strategy.dispatch_by_subclass(table, LandVehicle), 1) self.assertEqual(strategy.dispatch_by_subclass(table, object), 2) self.assertEqual(strategy.dispatch_by_subclass(table, None), 3) self.assertRaises(AttributeError, strategy.dispatch_by_subclass, table, Bicycle) def testInequalities(self): self.assertRaises(ValueError, Inequality, '', 1) self.assertRaises(ValueError, Inequality, 'xyz', 2) t1 = Inequality('>',55); t2 = Inequality('>=',100) self.failIf( (55,55) in t1 ) self.failIf( (55,55) in t2 ) self.failUnless( (100,100) in t2 ) self.failUnless( (100,100) in t1 ) self.failUnless( (101,101) in t2 ) self.failUnless( (110,Max) in t2 ) self.failUnless(t2.implies(t1)) self.failIf(t1.implies(t2)) t3 = Inequality('<',99) self.failIf(t1.implies(t3) or t2.implies(t3)) self.failIf(t3.implies(t1) or t3.implies(t2)) t4 = Inequality('<',"abc") self.failUnless(("a","a") in t4); self.failIf(("b","b") in t4) t5 = Inequality('==',99) i = strategy.InequalityIndex() for t in t1,t2,t3,t4,t5: validateCriterion(t,Inequality.node_type,seeded=False) i[t] = repr(t) ct, size = i.count_for(map(repr,[t1,t2,t3,t4,t5])) # Min, ..., 55, ..., 99, ..., 100, ..., 'abc', ..., Max self.assertEqual(ct, 11) # >55: 8, >=100: 5, <99: 4, <'abc': 8, ==99: 1 ---> 26 self.assertEqual(size,26) # Test intersection of overlapping open intervals t6=Inequality('>=',6); t8=Inequality('<=',8); t68 = t6&t8 self.assertEqual(t6.ranges, ((6,6),(6,Max))) self.assertEqual(t8.ranges, ((Min,8),(8,8))) self.assertEqual(t68.ranges, ((6,6),(6,8),(8,8))) def testInequalitySeeds(self): self.assertEqual( strategy.concatenate_ranges( {(Min,27):[], (27,27):[], (27,Max):[], (Min,19):[], (19,19):[], (19,27): [], } ), [(Min,19),(19,27),(27,Max)], ) self.assertEqual( strategy.concatenate_ranges( {(Min,19):[], (27,27):[], (19,Max):[], (19,27):[], (19,19):[], (27,Max):[], } ), [(Min,19),(19,27),(27,Max)], ) def testClasslessDispatch(self): class Classic: pass # Classic classes have no __class_ attribute strategy.dispatch_by_mro({},Classic) def testInequalityDispatch(self): classify = GenericFunction(lambda age:None) classify[(Inequality('<',2),)] = lambda age:"infant" classify[(Inequality('<',13),)] = lambda age:"preteen" classify[(Inequality('<',5),)] = lambda age:"preschooler" classify[(Inequality('<',20),)] = lambda age:"teenager" classify[(Inequality('>=',20),)] = lambda age:"adult" classify[(Inequality('>=',55),)] = lambda age:"senior" classify[(Inequality('=',16),)] = lambda age:"sweet sixteen" self.assertEqual(classify(25),"adult") self.assertEqual(classify(17),"teenager") self.assertEqual(classify(13),"teenager") self.assertEqual(classify(12.99),"preteen") self.assertEqual(classify(0),"infant") self.assertEqual(classify(4),"preschooler") self.assertEqual(classify(55),"senior") self.assertEqual(classify(54.9),"adult") self.assertEqual(classify(14.5),"teenager") self.assertEqual(classify(16),"sweet sixteen") self.assertEqual(classify(16.5),"teenager") self.assertEqual(classify(99),"senior") self.assertEqual(classify(Min),"infant") self.assertEqual(classify(Max),"senior") def testTruth(self): self.assertEqual(TruthCriterion(27), TruthCriterion("abc")) self.assertNotEqual(TruthCriterion(1), TruthCriterion(False)) self.failUnless(True in TruthCriterion(1)) self.failUnless(False not in TruthCriterion(1)) self.failUnless(True not in TruthCriterion(0)) self.failUnless(False in TruthCriterion(0)) self.failIf(TruthCriterion(1).implies(TruthCriterion(0))) self.failIf(TruthCriterion(0).implies(TruthCriterion(1))) self.failUnless(TruthCriterion(0).implies(TruthCriterion(0))) self.failUnless(TruthCriterion(1).implies(TruthCriterion(1))) self.assertEqual(TruthCriterion(42).seeds(), (True,False)) self.assertEqual(TruthCriterion(None).seeds(), (True,False)) def testAndOr(self): equals_two = Inequality('==',2) less_than_four = Inequality('<',4) lo_primes = Inequality('>',1) & less_than_four #2, 3 odd_primes = (~equals_two) & lo_primes self.failIf((4,4) in lo_primes) self.failUnless((3,3) in lo_primes) even_primes = equals_two & less_than_four self.failUnless((3,3) in less_than_four) self.failIf((4,4) in less_than_four) self.failIf((3,3) in even_primes) self.failUnless((2,2) in even_primes) self.failUnless(even_primes.implies(equals_two)) self.failUnless(even_primes.implies(less_than_four)) self.failUnless(even_primes.implies(NullCriterion)) self.assertRaises(protocols.AdaptationFailure, lambda: TruthCriterion(1) & Inequality('==',1) ) def testRangeIntersection(self): ten_to_twenty = Inequality('>=',10)&Inequality('<=',20) fifteen_to_nineteen = ( Inequality('>=',15) & Inequality('<=',19)) self.failUnless( (5,5) not in ten_to_twenty ) self.failUnless( (5,5) not in fifteen_to_nineteen ) self.failUnless( (15,15) in ten_to_twenty ) self.failUnless( (15,15) in fifteen_to_nineteen ) self.failUnless( (10,10) in ten_to_twenty ) self.failUnless( (16,17) in fifteen_to_nineteen) self.failUnless( fifteen_to_nineteen.implies(ten_to_twenty) ) self.failIf(ten_to_twenty.implies(fifteen_to_nineteen)) self.failUnless( (~ten_to_twenty).implies(~fifteen_to_nineteen) ) self.failIf( (~fifteen_to_nineteen).implies(~ten_to_twenty) ) for item in fifteen_to_nineteen, ten_to_twenty: self.failUnless( item.implies(NullCriterion) ) self.failUnless( (~item).implies(NullCriterion) ) def testClassIntersections(self): self.failUnless( Hummer in AndCriterion(LandVehicle,GasPowered) ) self.failUnless( Speedboat in NotCriterion(LandVehicle) ) self.failUnless( AndCriterion(LandVehicle,GasPowered).implies( GasPowered) ) # This implication doesn't hold true because RiverBoat is a Wheeled # non-LandVehicle; if Riverboat didn't exist the implication would hold self.failIf( NotCriterion(LandVehicle).implies(NotCriterion(Wheeled)) ) def testSimplifications(self): self.assertEqual((~TruthCriterion(1)), TruthCriterion(0)) self.assertEqual((~(~TruthCriterion(1))), TruthCriterion(27)) self.assertEqual( Inequality('>=',10) & Inequality('<=',20) & Inequality('==',15), Inequality('..', [(15,15)]) ) def testInequalityInverses(self): self.assertEqual(~Inequality(">=",27), Inequality("<",27)) for op,rev in strategy.rev_ops.items(): self.assertEqual(Inequality(op,27), ~Inequality(rev,27)) def testTruthDispatch(self): x_gt_y = Call(operator.gt, Argument(name='x'), Argument(name='y')) greater = GenericFunction(lambda x,y:None) greater[Signature([(x_gt_y, TruthCriterion(False))])]= lambda x,y:False greater[Signature([(x_gt_y, TruthCriterion(True))])] = lambda x,y:True self.failIf(greater(1,10)) self.failIf(greater(1,1)) self.failUnless(greater(2,1)) def testSignatureArithmetic(self): x_gt_10 = Signature(x=Inequality('>',10)) x_lt_20 = Signature(x=Inequality('<',20)) y_in_LandVehicle = Signature(y=LandVehicle) empty = Signature() self.assertEqual((x_gt_10 & x_lt_20), Signature(x=Inequality('>',10) & Inequality('<',20)) ) self.assertEqual((x_gt_10 & y_in_LandVehicle), Signature(x=Inequality('>',10),y=LandVehicle) ) self.assertEqual((x_gt_10 & x_gt_10), x_gt_10) self.assertEqual((x_gt_10 & empty), x_gt_10) self.assertEqual((empty & x_gt_10), x_gt_10) self.assertEqual((x_gt_10 | empty), empty) self.assertEqual((empty | x_gt_10), empty) self.assertEqual((x_gt_10 | x_lt_20), Predicate([x_gt_10, x_lt_20])) self.assertEqual((x_gt_10 | y_in_LandVehicle), Predicate([x_gt_10,y_in_LandVehicle]) ) # sig | pred self.assertEqual((x_gt_10 | Predicate([y_in_LandVehicle])), Predicate([x_gt_10,y_in_LandVehicle]) ) # sig & pred self.assertEqual((x_gt_10 & Predicate([y_in_LandVehicle])), Predicate([x_gt_10 & y_in_LandVehicle])) # pred & sig self.assertEqual((Predicate([y_in_LandVehicle]) & x_gt_10), Predicate([x_gt_10 & y_in_LandVehicle])) # pred | pred self.assertEqual((Predicate([x_gt_10]) | Predicate([y_in_LandVehicle])), Predicate([x_gt_10, y_in_LandVehicle]) ) # pred & pred self.assertEqual((Predicate([x_gt_10]) & Predicate([y_in_LandVehicle])), Predicate([x_gt_10 & y_in_LandVehicle]) ) # Ensure ordering preserved among conditions within a signature self.assertNotEqual( (x_gt_10 & y_in_LandVehicle).items(), (y_in_LandVehicle & x_gt_10).items()) self.assertNotEqual( (x_gt_10 & y_in_LandVehicle & x_lt_20).items(), (y_in_LandVehicle & x_gt_10 & x_lt_20).items()) def testSignatureOrdering(self): gt_10 = Argument(0),Inequality('>',10) lt_20 = Argument(1),Inequality('<',20) for data in [gt_10,lt_20], [lt_20,gt_10]: # Verify both the raw signature, and an 'and'-ed version for s in Signature(data), Signature(data[:1])&Signature(data[1:]): self.assertEqual(s.items(), [((k,v.node_type),v) for k,v in data] ) def testIndexEnumerables(self): i = SeededIndex(strategy.dispatch_by_mro) i[ClassCriterion(LandVehicle)] = 1 self.assertEqual(i.casemap_for([1]), {LandVehicle:[1], object:[]}) i[ClassCriterion(Bicycle)] = 2 self.assertEqual(i.casemap_for([2]), {Bicycle:[2], object:[], LandVehicle:[]}) i[ClassCriterion(HumanPowered)] = 3 self.assertEqual(i.casemap_for([3]), {Bicycle:[3], object:[], LandVehicle:[], HumanPowered:[3]}) def testIndexAnd(self): i = SeededIndex(strategy.dispatch_by_mro) i[ClassCriterion(LandVehicle) & ClassCriterion(HumanPowered)] = 1 self.assertEqual(i.casemap_for([1]), {HumanPowered:[], object:[], LandVehicle:[]}) i[ClassCriterion(Bicycle)] = 2 self.assertEqual(i.casemap_for([1,2]), {HumanPowered:[], object:[], LandVehicle:[], Bicycle:[1,2]}) i[ClassCriterion(LandVehicle)] = 3 self.assertEqual(i.casemap_for([1,2,3]), {HumanPowered:[], object:[], LandVehicle:[3], Bicycle:[1,2,3]}) def testIndexNot(self): i = SeededIndex(strategy.dispatch_by_mro) i[ClassCriterion(LandVehicle)] = 1 i[~ClassCriterion(Bicycle)] = 2 self.assertEqual(i.casemap_for([1,2]), {object:[2], LandVehicle:[1,2], Bicycle:[1]}) i[ClassCriterion(Bicycle)] = 3 self.assertEqual(i.casemap_for([1,2,3]), {object:[2], LandVehicle:[1,2], Bicycle:[1,3]}) class ExpressionTests(TestCase): def testArgumentBasics(self): self.assertRaises(ValueError, Argument) # must specify name or posn self.failUnless(Argument(0) == Argument(0)) self.failIf( Argument(0) == Argument(1)) self.failUnless(Argument(name="x") == Argument(name="x")) self.failIf( Argument(name="x") == Argument(name="y")) self.failIf( Argument(name="x") == Argument(1,"x")) self.failIf( Argument(1,"x") == Argument(name="x")) self.failIf( Argument(1) == Argument(1,"x")) self.failIf( Argument(1,"x") == Argument(1)) self.failUnless(Argument(0,"x") == Argument(0,"x")) self.failIf( Argument(0,"x") == Argument(0,"y")) self.failIf( Argument(0,"x") == Argument(1,"x")) self.failIf( Argument(0,"x") == Argument(1,"y")) a1 = Argument(0,"x"); a2 = Argument(0,"x") self.assertEqual(hash(a1), hash(a2)) a1 = Argument(1); a2 = Argument(1) self.assertEqual(hash(a1), hash(a2)) a1 = Argument(name="x"); a2 = Argument(name="x") self.assertEqual(hash(a1), hash(a2)) def testArgumentCanonicalization(self): f = GenericFunction(lambda v1,v2:None) self.assertEqual( f.getExpressionId(Argument(name='v1')), f.getExpressionId(Argument(0)) ) self.assertEqual( f.getExpressionId(Argument(name='v2')), f.getExpressionId(Argument(1)) ) def testCalls(self): self.assertEqual(Call(operator.add,1,2), Call(operator.add,1,2)) self.assertNotEqual(Call(operator.sub,1,2), Call(operator.add,1,2)) self.assertNotEqual(Call(operator.add,2,1), Call(operator.add,1,2)) c1 = Call(operator.add, Argument(name='x'), Argument(name='y')) c2 = Call(operator.add, Argument(name='x'), Argument(name='y')) self.assertEqual(hash(c1), hash(c2)) c3 = Call(operator.sub, Argument(name='x'), Argument(name='y')) self.assertNotEqual(hash(c1), hash(c3)) f = GenericFunction(lambda x,y:None) self.assertEqual(f.getExpressionId(c1), f.getExpressionId(c2)) self.assertNotEqual(f.getExpressionId(c1), f.getExpressionId(c3)) self.assertEqual( f.getExpressionId(c3), f.getExpressionId( Call(operator.sub, Argument(name='x'), Argument(name='y')) ) ) # Make the function handle 'x+y > 100' f[Signature([(c1,Inequality('>',100))])] = lambda x,y: "yes" f[Signature([])] = lambda x,y: "no" self.assertEqual(f(51,49), "no") self.assertEqual(f(99,10), "yes") self.assertEqual(f(27,89), "yes") def testConsts(self): f = GenericFunction(lambda x:None) x_plus_two = Call(operator.add,Argument(name='x'),Const(2)) f[Signature([(x_plus_two,Inequality('>',10))])] = lambda x: True f[Signature([])] = lambda x: False self.failUnless(f(9)) self.failIf(f(8)) foo, bar, fourA, fourB = Const("foo"),Const("bar"),Const(4),Const(4) self.assertEqual(fourA,fourB) self.assertEqual(hash(fourA),hash(fourB)) self.assertNotEqual(bar,foo) self.assertNotEqual(hash(bar),hash(foo)) def testGetattr(self): vehicle_mpg = Getattr(Argument(name='v'),'mpg') test_mpg = lambda test,val: (vehicle_mpg,Inequality(test,val)) fuel_efficient = GenericFunction(lambda v:None) fuel_efficient[Signature([test_mpg('==','N/A')])] = lambda v: True fuel_efficient[Signature([test_mpg('>',35)])] = lambda v: True fuel_efficient[Signature([])] = lambda v: False b=Bicycle(); b.mpg = 'N/A'; h=Hummer(); h.mpg = 10 self.failUnless(fuel_efficient(b)) self.failIf(fuel_efficient(h)) vm2 = Getattr(Argument(name='v'),'mpg') xm = Getattr(Argument(name='x'),'mpg') vg = Getattr(Argument(name='v'),'gpm') self.assertEqual(vehicle_mpg, vm2) self.assertEqual(hash(vehicle_mpg), hash(vm2)) for item in xm,vg: self.assertNotEqual(vehicle_mpg, item) self.assertNotEqual(hash(vehicle_mpg), hash(item)) def testTuple(self): xy = Tuple(tuple,Argument(name='x'),Argument(name='y')) xy_is_one_two = GenericFunction(lambda x,y:None) xy_is_one_two[Signature([(xy,Inequality('==',(1,2)))])]=lambda x,y:True xy_is_one_two[Signature([])] = lambda x,y: False self.failUnless(xy_is_one_two(1,2)) self.failIf(xy_is_one_two(1,3)) self.failIf(xy_is_one_two(2,1)) xy2 = Tuple(tuple,Argument(name='x'),Argument(name='y')) yx = Tuple(tuple,Argument(name='y'),Argument(name='x')) lx = Tuple(list,Argument(name='x'),Argument(name='y')) zz = Tuple(tuple,Argument(name='z'),Argument(name='z')) self.assertEqual(xy, xy2) self.assertEqual(hash(xy), hash(xy2)) for item in yx,lx,zz: self.assertNotEqual(xy, item) self.assertNotEqual(hash(xy), hash(item)) if sys.version>='2.5': def testIfElse(self): x,y,z = Argument(name='x'), Argument(name='y'), Argument(name='z') xyz = IfElse(x,y,z) ie = GenericFunction(lambda x,y,z:None) ie[Signature([(xyz, TruthCriterion())])] = lambda x,y,z:True ie[Signature([])] = lambda x,y,z: False self.assertEqual(ie(1,0,0), False) self.assertEqual(ie(1,1,0), True) self.assertEqual(ie(0,1,1), False) self.assertEqual(ie(0,0,1), True) def testOrExpr(self): x, y = Argument(name='x'), Argument(name='y') z = Call(operator.div,Argument(name='y'),Argument(name='z')) xyz = OrExpr(x,y,z) or_ = GenericFunction(lambda x,y,z:None) or_[Signature([(xyz,TruthCriterion())])] = lambda x,y,z:True or_[Signature([])] = lambda x,y,z: False self.failUnless(or_(1,0,1)) self.failIf(or_(0,0,1)) self.assertRaises(ZeroDivisionError,or_,0,0,0) zyx = OrExpr(z,y,x) xyz2 = OrExpr(x,y,z) xy = OrExpr(x,y) self.assertEqual(xyz, xyz2) self.assertEqual(hash(xyz), hash(xyz2)) for item in xy,zyx: self.assertNotEqual(xyz, item) self.assertNotEqual(hash(xyz), hash(item)) or_eq_23 = GenericFunction(lambda x,y:None) or_eq_23[Signature([(xy,Inequality('==',23))])] = lambda x,y:True or_eq_23[Signature([])] = lambda x,y: False self.failUnless(or_eq_23(23,0)) self.failUnless(or_eq_23(0,23)) self.failIf(or_eq_23(0,0)) self.failIf(or_eq_23(15,15)) or_eq_None = GenericFunction(lambda x,y:None) or_eq_None[Signature([(xy,Inequality('==',None))])] = lambda x,y:True or_eq_None[Signature([])] = lambda x,y: False self.failUnless(or_eq_None(None,None)) self.failUnless(or_eq_None(0,None)) self.failIf(or_eq_None(1,None)) self.failIf(or_eq_None(None,1)) def testAndExpr(self): x, y = Argument(name='x'), Argument(name='y') z = Call(operator.div,Argument(name='y'),Argument(name='z')) xyz = AndExpr(x,y,z) and_ = GenericFunction(lambda x,y,z:None) and_[Signature([(xyz,TruthCriterion())])] = lambda x,y,z:True and_[Signature([])] = lambda x,y,z: False self.failUnless(and_(True,True,True)) self.failIf(and_(False,True,True)) self.failIf(and_(False,27,0)) self.assertRaises(ZeroDivisionError,and_,15,27,0) zyx = AndExpr(z,y,x) xyz2 = AndExpr(x,y,z) xy = AndExpr(x,y) self.assertEqual(xyz, xyz2) self.assertEqual(hash(xyz), hash(xyz2)) for item in xy,zyx: self.assertNotEqual(xyz, item) self.assertNotEqual(hash(xyz), hash(item)) and_eq_23 = GenericFunction(lambda x,y:None) and_eq_23[Signature([(xy,Inequality('==',23))])] = lambda x,y:True and_eq_23[Signature([])] = lambda x,y: False self.failUnless(and_eq_23(3,23)) self.failUnless(and_eq_23(23,23)) self.failIf(and_eq_23(23,15)) self.failIf(and_eq_23(23,0)) and_eq_None = GenericFunction(lambda x,y:None) and_eq_None[Signature([(xy,Inequality('==',None))])] = lambda x,y:True and_eq_None[Signature([])] = lambda x,y: False self.failUnless(and_eq_None(None,None)) self.failUnless(and_eq_None(1,None)) self.failIf(and_eq_None(0,1)) self.failIf(and_eq_None(1,0)) class SimpleGenerics(TestCase): def testTrivialities(self): [dispatch.on('x')] def f1(x,*y,**z): "foo bar" [dispatch.on('x')] def f2(x,*y,**z): "baz spam" for f,doc in (f1,"foo bar"),(f2,"baz spam"): self.assertEqual(f.__doc__, doc) # Empty generic should raise NoApplicableMethods self.assertRaises(dispatch.NoApplicableMethods, f, 1, 2, 3) self.assertRaises(dispatch.NoApplicableMethods, f, "x", y="z") # Must have at least one argument to do dispatching self.assertRaises(TypeError, f) self.assertRaises(TypeError, f, foo="bar") def testSimpleDefinitions(self): [dispatch.on('xx')] def g(xx,*y,**z): pass class Classic: pass class NewStyle(object): pass class IFoo(protocols.Interface): pass class Impl: protocols.advise(instancesProvide=[IFoo]) c=Classic() n=NewStyle() i=Impl() for item in c,n,i,1,"blue",TestCase: self.assertRaises(dispatch.NoApplicableMethods, g, item) g.addMethod(Classic,lambda *args,**kw: ("classic!",args,kw)) g.addMethod(NewStyle,lambda *args,**kw: ("new!",args,kw)) g.addMethod(IFoo,lambda *args,**kw: ("foo!",args,kw)) self.assertEqual(g(c,"foo"), ("classic!",(c,"foo",),{})) self.assertEqual(g(n,foo="bar"), ("new!",(n,),{'foo':'bar'})) self.assertEqual(g(i,"foo",x="y"), ("foo!",(i,"foo",),{"x":"y"})) for item in 1,"blue",TestCase: self.assertRaises(dispatch.NoApplicableMethods, g, item) def testMultiDefinition(self): class Classic: pass class NewStyle(object): pass class IFoo(protocols.Interface): pass class Impl: protocols.advise(instancesProvide=[IFoo]) c=Classic() n=NewStyle() i=Impl() [dispatch.on('xx')] def g(xx,q=27,*y,**z): pass [g.when([Classic,NewStyle,IFoo])] def g(*args,**kw): return ("yes!",args,kw) self.assertEqual(g(c,"foo"), ("yes!",(c,"foo",),{})) self.assertEqual(g(n,foo="bar"), ("yes!",(n,27),{'foo':'bar'})) self.assertEqual(g(i,"foo",x="y"), ("yes!",(i,"foo",),{"x":"y"})) for item in 1,"blue",TestCase: self.assertRaises(dispatch.NoApplicableMethods, g, item) def testAdaptedDefinition(self): class Classic: pass class IFoo(protocols.Interface): pass class A(protocols.Adapter): protocols.advise( instancesProvide=[IFoo],asAdapterForTypes=[Classic] ) [dispatch.on('xx')] def g(xx,*y,**z): pass [g.when(IFoo)] def g(thing, *args,**kw): return thing c=Classic(); it = g(c) self.assertNotEqual(it, c) self.failUnless(IFoo(it) is it) def testWhenMethods(self): m = GenericFunction(lambda v:None) m.when(Signature(v=LandVehicle)) def foo(v): return "land" import types self.failUnless(isinstance(m,GenericFunction)) self.failUnless(isinstance(foo,types.FunctionType)) m.when(Signature(v=WaterVehicle)) def m(v): return "water" self.failUnless(isinstance(m,types.FunctionType)) self.assertEqual(m(LandVehicle()),"land") self.assertEqual(m(WaterVehicle()),"water") [dispatch.on('v')] def s(v): """Blah""" [s.when(LandVehicle)] def bar(v): return "land" self.failUnless(hasattr(s,'when')) self.failUnless(isinstance(bar,types.FunctionType)) [s.when(WaterVehicle)] def s(v): return "water" self.failUnless(hasattr(s,'when')) self.assertEqual(s(LandVehicle()),"land") self.assertEqual(s(WaterVehicle()),"water") def testAltArg(self): [dispatch.on('v')] def s(x,v): """X""" [s.when(LandVehicle)] def bar(x,v): return "land" [s.when(WaterVehicle)] def s(x,v): return "water" self.assertEqual(s(None,LandVehicle()),"land") self.assertEqual(s(None,v=WaterVehicle()),"water") def testInstanceMethod(self): class X: [dispatch.on('v')] def s(x,v): """X""" [s.when(LandVehicle)] def bar(x,v): return "land" [s.when(WaterVehicle)] def s(x,v): return "water" class Y: s = X.s.clone() [s.when(WaterVehicle)] def s(x,v): return "splash!" self.assertEqual(X().s(v=LandVehicle()),"land") self.assertEqual(X().s(WaterVehicle()),"water") self.assertEqual(Y().s(WaterVehicle()),"splash!") class GenericTests(TestCase): def testBasicSingleDispatch(self): m = GenericFunction(lambda v:None) m[(LandVehicle,)] = lambda v: "land" m[(WaterVehicle,)] = lambda v: "water" self.assertEquals(m(Hummer()), "land") self.assertEquals(m(Speedboat()), "water") self.assertRaises(NoApplicableMethods, m, GasPowered()) def testSimpleDoubleDispatchAndNamedArgs(self): faster = GenericFunction(lambda v1,v2:None) faster[Signature(v1=GasPowered,v2=HumanPowered)] = lambda v1,v2: True faster[Signature(v1=Hummer,v2=Speedboat)] = lambda v1,v2: True faster[(object,object)] = lambda v1,v2: "dunno" faster[Signature(v1=HumanPowered,v2=GasPowered)] = lambda v1,v2: False faster[Signature(v2=Hummer,v1=Speedboat)] = lambda v1,v2: False self.assertEqual(faster(Hummer(),Bicycle()), True) def testAmbiguity(self): add = GenericFunction(lambda addend,augend:None) add[(object, int)] = operator.add add[(int, object)] = operator.sub self.assertRaises(AmbiguousMethod, add, 1, 2) def testDynamic(self): roll = GenericFunction(lambda vehicle:None) class Tricycle(HumanPowered,LandVehicle): pass roll[Signature(vehicle=Wheeled)] = lambda ob: "We're rolling" self.assertRaises(NoApplicableMethods, roll, Tricycle()) declareImplementation(Tricycle,[Wheeled]) self.assertEqual(roll(Tricycle()),"We're rolling") def testMRO(self): t = GenericFunction(lambda vehicle,num:None) t[Signature(vehicle=HumanPowered,num=Inequality('<',10))]=lambda v,n:False t[Signature(vehicle=WaterVehicle,num=Inequality('<',5))]=lambda v,n:True self.assertRaises(AmbiguousMethod, t, PaddleBoat(), 4) def testSimpleChaining(self): def both_vehicles(ob1,ob2): return "They're both vehicles." def both_land(next_method,ob1,ob2): return next_method(ob1,ob2)+" They are both land vehicles." def both_sea(next_method,ob1,ob2): return next_method(ob1,ob2)+" They are both sea vehicles." def mixed_vehicles(next_method,ob1,ob2): return next_method(ob1,ob2)+ \ " One vehicle is a land vehicle, the other is a sea vehicle." [dispatch.generic()] def compare(v1,v2): pass compare.addMethod([(Vehicle, Vehicle)], both_vehicles) compare.addMethod([(LandVehicle, LandVehicle)],both_land) compare.addMethod([(WaterVehicle, WaterVehicle)],both_sea) compare.addMethod( [(LandVehicle, WaterVehicle),(WaterVehicle, LandVehicle)], mixed_vehicles ) land = Bicycle() sea = Speedboat() self.assertEqual( compare(land, land), "They're both vehicles. They are both land vehicles.") self.assertEqual( compare(sea, sea), "They're both vehicles. They are both sea vehicles.") self.assertEqual( compare(land, sea), "They're both vehicles. \ One vehicle is a land vehicle, the other is a sea vehicle.") self.assertEqual( compare(sea, land), "They're both vehicles. \ One vehicle is a land vehicle, the other is a sea vehicle.") def testSubexpressionOrderingConstraints(self): g = GenericFunction(lambda x,y:None) self.assertEqual(g.constraints.items(),[]) df = Inequality.node_type yx = Call(operator.div, Argument(name='y'), Argument(name='x')) yxid = g.getExpressionId(yx), df xid = g.getExpressionId(Argument(name='x')), df yid = g.getExpressionId(Argument(name='y')), df [g.when('x==2 and y>10 and x<27')] def x(x,y): return "foo" self.assertEqual(g.constraints.items(),[]) [g.when('x>0 and y/x>10')] def x(x,y): return "bar" self.assertEqual(g.constraints.items(),[(xid,yxid)]) [g.when('x==1 and y>0 and y/x>10')] def x(x,y): return "bar" items = g.constraints.items(); items.sort() expected = [(xid,yxid),(yid,yxid)]; expected.sort() self.assertEqual(items,expected) self.assertEqual(g.constraints.successors([yid,yxid]),{yxid:1}) self.assertEqual(g.constraints.successors([xid,yxid]),{yxid:1}) best_id, remaining_ids = g._best_split(range(len(g.cases)), [yxid,yid]) self.assertEqual(best_id, yid) best_id, remaining_ids = g._best_split(range(len(g.cases)), [yxid,xid]) self.assertEqual(best_id, xid) def testSimpleMultiDispatch(self): class A: pass class B(A): pass class C: pass class D(A,C): pass def m1(*x): return "m1" def m2(*x): return "m2" def m3(*x): return "m3" def m4(*x): return "m4" def m5(*x): return "m5" class T: pass class F: pass tf = [F(),T()] g = GenericFunction( lambda f1,f1_x,f2,f1x_at_not_B, f1_y_eq_f2_y: None) # f1, f1.x, f2, f1.x@!B, f1.y=f2.y g.addMethod([(A,A,NullCriterion,T,T)], m1) g.addMethod([(B,B),(C,B,A)], m2) g.addMethod([(C,NullCriterion,C)], m3) g.addMethod([(C,)], m4) g.addMethod([(T,)], m5) def w(f1,f1x,f2,ymatches=F()): return g(f1,f1x,f2,tf[not isinstance(f1x,B)],ymatches) for time in 1,2: self.assertEqual( w(A(),A(),C(),T()), "m1") self.assertEqual( w(B(),B(),C()), "m2") self.assertEqual( w(C(),B(),B()), "m2") self.assertEqual( w(C(),C(),C()), "m3") self.assertEqual( w(C(),A(),A()), "m4") self.assertEqual( g(T(),None,None,None,None), "m5") g.criterionChanged() def testInstanceMethods(self): class X: [dispatch.generic()] def s(self,v): """X""" [s.when("v in LandVehicle")] def bar(self,v): return "land" [s.when("v in WaterVehicle")] def s(self,v): return "water" class Y(X): s = X.s [s.when("v in WaterVehicle")] def s(self,v): return "splash!" self.assertEqual(Y().s(WaterVehicle()),"splash!") self.assertEqual(X().s(v=LandVehicle()),"land") self.assertEqual(X().s(WaterVehicle()),"water") def testSubclassDispatch(self): [dispatch.generic()] def gm (t) : pass [gm.when(default)] def gm (t) : return 'default' [gm.when('issubclass(t,int)')] def gm2 (t) : return 'int' self.assertEqual(gm(int),"int") self.assertEqual(gm(object),"default") self.assertEqual(gm(float),"default") def testArgNormalization(self): from dispatch.functions import _mkNormalizer class dispatcher: def __getitem__(self,argtuple): return lambda *_,**__: argtuple f,a = _mkNormalizer(lambda foo: None, dispatcher()) self.assertEqual(a,['foo']) self.assertEqual(f("bar"), ("bar",)) self.assertEqual(f(foo="bar"), ("bar",)) f,a = _mkNormalizer(lambda foo=42: None, dispatcher()) self.assertEqual(a,['foo']) self.assertEqual(f("bar"), ("bar",)) self.assertEqual(f(foo="bar"), ("bar",)) self.assertEqual(f(), (42,)) f,a = _mkNormalizer(lambda foo,*z: None, dispatcher()) self.assertEqual(a,['foo','z']) self.assertEqual(f("bar","baz"), ("bar",("baz",))) self.assertEqual(f(foo="bar"), ("bar",())) f,a = _mkNormalizer(lambda foo="shoo",blue=42,*z: None, dispatcher()) self.assertEqual(a,['foo','blue','z']) self.assertEqual(f("bar","baz"), ("bar","baz",())) self.assertEqual(f("bar","baz","spam"), ("bar","baz",("spam",))) self.assertEqual(f(foo="bar"), ("bar",42,())) self.assertEqual(f(blue="two"), ("shoo","two",())) self.assertEqual(f(1,2,3,4), (1,2,(3,4))) self.assertEqual(f(), ("shoo",42,())) f,a = _mkNormalizer(lambda (x,y): None, dispatcher()) self.assertEqual(a,['x','y']) self.assertEqual(f((1,2)), (1,2)) f,a = _mkNormalizer(lambda foo,(x,y),*z,**zz: None, dispatcher()) self.assertEqual(a,['foo','x','y','z','zz']) self.assertEqual( f("foo",(1,2),fizz="fuzz"), ("foo",1,2,(),{'fizz':'fuzz'}) ) def testKwArgHandling(self): [dispatch.generic()] def f(**fiz): """Test of kw handling""" [f.when("'x' in fiz")] def f(**fiz): return "x" [f.when("'y' in fiz")] def f(**fiz): return "y" self.assertEqual(f(x=1),"x") self.assertEqual(f(y=1),"y") self.assertRaises(AmbiguousMethod, f, x=1, y=1) def testVarArgHandling(self): [dispatch.generic()] def f(*fiz): """Test of vararg handling""" [f.when("'x' in fiz")] def f(*fiz): return "x" [f.when("'y' in fiz")] def f(*fiz): return "y" self.assertEqual(f("foo","x"),"x") self.assertEqual(f("bar","q","y"),"y") self.assertEqual(f("bar","q","y"),"y") self.assertEqual(f("y","q",),"y") self.assertRaises(AmbiguousMethod, f, "x","y") def test_NoApplicableMethods_is_raised(self): [dispatch.generic()] def demo_func(number): pass demo_func.when("number < 10")(lambda x: 0) self.assertEqual(demo_func(3),0) self.assertRaises(dispatch.NoApplicableMethods, demo_func, 33) TestClasses = ( TestGraph, CriteriaTests, ExpressionTests, SimpleGenerics, GenericTests, ) def test_combiners(): import doctest return doctest.DocFileSuite( 'combiners.txt', optionflags=doctest.ELLIPSIS, package='dispatch', ) def test_suite(): return TestSuite( [test_combiners()] + [makeSuite(t,'test') for t in TestClasses] ) PKK\8fv dispatch/tests/doctest.py# Module doctest. # Released to the public domain 16-Jan-2001, by Tim Peters (tim@python.org). # Major enhancements and refactoring by: # Jim Fulton # Edward Loper # Provided as-is; use at your own risk; no warranty; no promises; enjoy! try: basestring except NameError: basestring = str,unicode try: enumerate except NameError: def enumerate(seq): return zip(range(len(seq)),seq) r"""Module doctest -- a framework for running examples in docstrings. In simplest use, end each module M to be tested with: def _test(): import doctest doctest.testmod() if __name__ == "__main__": _test() Then running the module as a script will cause the examples in the docstrings to get executed and verified: python M.py This won't display anything unless an example fails, in which case the failing example(s) and the cause(s) of the failure(s) are printed to stdout (why not stderr? because stderr is a lame hack <0.2 wink>), and the final line of output is "Test failed.". Run it with the -v switch instead: python M.py -v and a detailed report of all examples tried is printed to stdout, along with assorted summaries at the end. You can force verbose mode by passing "verbose=True" to testmod, or prohibit it by passing "verbose=False". In either of those cases, sys.argv is not examined by testmod. There are a variety of other ways to run doctests, including integration with the unittest framework, and support for running non-Python text files containing doctests. There are also many ways to override parts of doctest's default behaviors. See the Library Reference Manual for details. """ __docformat__ = 'reStructuredText en' __all__ = [ # 0, Option Flags 'register_optionflag', 'DONT_ACCEPT_TRUE_FOR_1', 'DONT_ACCEPT_BLANKLINE', 'NORMALIZE_WHITESPACE', 'ELLIPSIS', 'IGNORE_EXCEPTION_DETAIL', 'COMPARISON_FLAGS', 'REPORT_UDIFF', 'REPORT_CDIFF', 'REPORT_NDIFF', 'REPORT_ONLY_FIRST_FAILURE', 'REPORTING_FLAGS', # 1. Utility Functions 'is_private', # 2. Example & DocTest 'Example', 'DocTest', # 3. Doctest Parser 'DocTestParser', # 4. Doctest Finder 'DocTestFinder', # 5. Doctest Runner 'DocTestRunner', 'OutputChecker', 'DocTestFailure', 'UnexpectedException', 'DebugRunner', # 6. Test Functions 'testmod', 'testfile', 'run_docstring_examples', # 7. Tester 'Tester', # 8. Unittest Support 'DocTestSuite', 'DocFileSuite', 'set_unittest_reportflags', # 9. Debugging Support 'script_from_examples', 'testsource', 'debug_src', 'debug', ] import __future__ import sys, traceback, inspect, linecache, os, re, types import unittest, difflib, pdb, tempfile import warnings from StringIO import StringIO # Don't whine about the deprecated is_private function in this # module's tests. warnings.filterwarnings("ignore", "is_private", DeprecationWarning, __name__, 0) # There are 4 basic classes: # - Example: a pair, plus an intra-docstring line number. # - DocTest: a collection of examples, parsed from a docstring, plus # info about where the docstring came from (name, filename, lineno). # - DocTestFinder: extracts DocTests from a given object's docstring and # its contained objects' docstrings. # - DocTestRunner: runs DocTest cases, and accumulates statistics. # # So the basic picture is: # # list of: # +------+ +---------+ +-------+ # |object| --DocTestFinder-> | DocTest | --DocTestRunner-> |results| # +------+ +---------+ +-------+ # | Example | # | ... | # | Example | # +---------+ # Option constants. OPTIONFLAGS_BY_NAME = {} def register_optionflag(name): flag = 1 << len(OPTIONFLAGS_BY_NAME) OPTIONFLAGS_BY_NAME[name] = flag return flag DONT_ACCEPT_TRUE_FOR_1 = register_optionflag('DONT_ACCEPT_TRUE_FOR_1') DONT_ACCEPT_BLANKLINE = register_optionflag('DONT_ACCEPT_BLANKLINE') NORMALIZE_WHITESPACE = register_optionflag('NORMALIZE_WHITESPACE') ELLIPSIS = register_optionflag('ELLIPSIS') IGNORE_EXCEPTION_DETAIL = register_optionflag('IGNORE_EXCEPTION_DETAIL') COMPARISON_FLAGS = (DONT_ACCEPT_TRUE_FOR_1 | DONT_ACCEPT_BLANKLINE | NORMALIZE_WHITESPACE | ELLIPSIS | IGNORE_EXCEPTION_DETAIL) REPORT_UDIFF = register_optionflag('REPORT_UDIFF') REPORT_CDIFF = register_optionflag('REPORT_CDIFF') REPORT_NDIFF = register_optionflag('REPORT_NDIFF') REPORT_ONLY_FIRST_FAILURE = register_optionflag('REPORT_ONLY_FIRST_FAILURE') REPORTING_FLAGS = (REPORT_UDIFF | REPORT_CDIFF | REPORT_NDIFF | REPORT_ONLY_FIRST_FAILURE) # Special string markers for use in `want` strings: BLANKLINE_MARKER = '' ELLIPSIS_MARKER = '...' ###################################################################### ## Table of Contents ###################################################################### # 1. Utility Functions # 2. Example & DocTest -- store test cases # 3. DocTest Parser -- extracts examples from strings # 4. DocTest Finder -- extracts test cases from objects # 5. DocTest Runner -- runs test cases # 6. Test Functions -- convenient wrappers for testing # 7. Tester Class -- for backwards compatibility # 8. Unittest Support # 9. Debugging Support # 10. Example Usage ###################################################################### ## 1. Utility Functions ###################################################################### def is_private(prefix, base): """prefix, base -> true iff name prefix + "." + base is "private". Prefix may be an empty string, and base does not contain a period. Prefix is ignored (although functions you write conforming to this protocol may make use of it). Return true iff base begins with an (at least one) underscore, but does not both begin and end with (at least) two underscores. >>> is_private("a.b", "my_func") False >>> is_private("____", "_my_func") True >>> is_private("someclass", "__init__") False >>> is_private("sometypo", "__init_") True >>> is_private("x.y.z", "_") True >>> is_private("_x.y.z", "__") False >>> is_private("", "") # senseless but consistent False """ warnings.warn("is_private is deprecated; it wasn't useful; " "examine DocTestFinder.find() lists instead", DeprecationWarning, stacklevel=2) return base[:1] == "_" and not base[:2] == "__" == base[-2:] def _extract_future_flags(globs): """ Return the compiler-flags associated with the future features that have been imported into the given namespace (globs). """ flags = 0 for fname in __future__.all_feature_names: feature = globs.get(fname, None) if feature is getattr(__future__, fname): flags |= feature.compiler_flag return flags def _normalize_module(module, depth=2): """ Return the module specified by `module`. In particular: - If `module` is a module, then return module. - If `module` is a string, then import and return the module with that name. - If `module` is None, then return the calling module. The calling module is assumed to be the module of the stack frame at the given depth in the call stack. """ if inspect.ismodule(module): return module elif isinstance(module, (str, unicode)): return __import__(module, globals(), locals(), ["*"]) elif module is None: return sys.modules[sys._getframe(depth).f_globals['__name__']] else: raise TypeError("Expected a module, string, or None") def _indent(s, indent=4): """ Add the given number of space characters to the beginning every non-blank line in `s`, and return the result. """ # This regexp matches the start of non-blank lines: return re.sub('(?m)^(?!$)', indent*' ', s) def _exception_traceback(exc_info): """ Return a string containing a traceback message for the given exc_info tuple (as returned by sys.exc_info()). """ # Get a traceback message. excout = StringIO() exc_type, exc_val, exc_tb = exc_info traceback.print_exception(exc_type, exc_val, exc_tb, file=excout) return excout.getvalue() # Override some StringIO methods. class _SpoofOut(StringIO): def getvalue(self): result = StringIO.getvalue(self) # If anything at all was written, make sure there's a trailing # newline. There's no way for the expected output to indicate # that a trailing newline is missing. if result and not result.endswith("\n"): result += "\n" # Prevent softspace from screwing up the next test case, in # case they used print with a trailing comma in an example. if hasattr(self, "softspace"): del self.softspace return result def truncate(self, size=None): StringIO.truncate(self, size) if hasattr(self, "softspace"): del self.softspace # Worst-case linear-time ellipsis matching. def _ellipsis_match(want, got): """ Essentially the only subtle case: >>> _ellipsis_match('aa...aa', 'aaa') False """ if want.find(ELLIPSIS_MARKER)==-1: return want == got # Find "the real" strings. ws = want.split(ELLIPSIS_MARKER) assert len(ws) >= 2 # Deal with exact matches possibly needed at one or both ends. startpos, endpos = 0, len(got) w = ws[0] if w: # starts with exact match if got.startswith(w): startpos = len(w) del ws[0] else: return False w = ws[-1] if w: # ends with exact match if got.endswith(w): endpos -= len(w) del ws[-1] else: return False if startpos > endpos: # Exact end matches required more characters than we have, as in # _ellipsis_match('aa...aa', 'aaa') return False # For the rest, we only need to find the leftmost non-overlapping # match for each piece. If there's no overall match that way alone, # there's no overall match period. for w in ws: # w may be '' at times, if there are consecutive ellipses, or # due to an ellipsis at the start or end of `want`. That's OK. # Search for an empty string succeeds, and doesn't change startpos. startpos = got.find(w, startpos, endpos) if startpos < 0: return False startpos += len(w) return True def _comment_line(line): "Return a commented form of the given line" line = line.rstrip() if line: return '# '+line else: return '#' class _OutputRedirectingPdb(pdb.Pdb): """ A specialized version of the python debugger that redirects stdout to a given stream when interacting with the user. Stdout is *not* redirected when traced code is executed. """ def __init__(self, out): self.__out = out pdb.Pdb.__init__(self) def trace_dispatch(self, *args): # Redirect stdout to the given stream. save_stdout = sys.stdout sys.stdout = self.__out # Call Pdb's trace dispatch method. try: return pdb.Pdb.trace_dispatch(self, *args) finally: sys.stdout = save_stdout # [XX] Normalize with respect to os.path.pardir? def _module_relative_path(module, path): if not inspect.ismodule(module): raise TypeError, 'Expected a module: %r' % module if path.startswith('/'): raise ValueError, 'Module-relative files may not have absolute paths' # Find the base directory for the path. if hasattr(module, '__file__'): # A normal module/package basedir = os.path.split(module.__file__)[0] elif module.__name__ == '__main__': # An interactive session. if len(sys.argv)>0 and sys.argv[0] != '': basedir = os.path.split(sys.argv[0])[0] else: basedir = os.curdir else: # A module w/o __file__ (this includes builtins) raise ValueError("Can't resolve paths relative to the module " + module + " (it has no __file__)") # Combine the base directory and the path. return os.path.join(basedir, *(path.split('/'))) ###################################################################### ## 2. Example & DocTest ###################################################################### ## - An "example" is a pair, where "source" is a ## fragment of source code, and "want" is the expected output for ## "source." The Example class also includes information about ## where the example was extracted from. ## ## - A "doctest" is a collection of examples, typically extracted from ## a string (such as an object's docstring). The DocTest class also ## includes information about where the string was extracted from. class Example: """ A single doctest example, consisting of source code and expected output. `Example` defines the following attributes: - source: A single Python statement, always ending with a newline. The constructor adds a newline if needed. - want: The expected output from running the source code (either from stdout, or a traceback in case of exception). `want` ends with a newline unless it's empty, in which case it's an empty string. The constructor adds a newline if needed. - exc_msg: The exception message generated by the example, if the example is expected to generate an exception; or `None` if it is not expected to generate an exception. This exception message is compared against the return value of `traceback.format_exception_only()`. `exc_msg` ends with a newline unless it's `None`. The constructor adds a newline if needed. - lineno: The line number within the DocTest string containing this Example where the Example begins. This line number is zero-based, with respect to the beginning of the DocTest. - indent: The example's indentation in the DocTest string. I.e., the number of space characters that preceed the example's first prompt. - options: A dictionary mapping from option flags to True or False, which is used to override default options for this example. Any option flags not contained in this dictionary are left at their default value (as specified by the DocTestRunner's optionflags). By default, no options are set. """ def __init__(self, source, want, exc_msg=None, lineno=0, indent=0, options=None): # Normalize inputs. if not source.endswith('\n'): source += '\n' if want and not want.endswith('\n'): want += '\n' if exc_msg is not None and not exc_msg.endswith('\n'): exc_msg += '\n' # Store properties. self.source = source self.want = want self.lineno = lineno self.indent = indent if options is None: options = {} self.options = options self.exc_msg = exc_msg class DocTest: """ A collection of doctest examples that should be run in a single namespace. Each `DocTest` defines the following attributes: - examples: the list of examples. - globs: The namespace (aka globals) that the examples should be run in. - name: A name identifying the DocTest (typically, the name of the object whose docstring this DocTest was extracted from). - filename: The name of the file that this DocTest was extracted from, or `None` if the filename is unknown. - lineno: The line number within filename where this DocTest begins, or `None` if the line number is unavailable. This line number is zero-based, with respect to the beginning of the file. - docstring: The string that the examples were extracted from, or `None` if the string is unavailable. """ def __init__(self, examples, globs, name, filename, lineno, docstring): """ Create a new DocTest containing the given examples. The DocTest's globals are initialized with a copy of `globs`. """ assert not isinstance(examples, basestring), \ "DocTest no longer accepts str; use DocTestParser instead" self.examples = examples self.docstring = docstring self.globs = globs.copy() self.name = name self.filename = filename self.lineno = lineno def __repr__(self): if len(self.examples) == 0: examples = 'no examples' elif len(self.examples) == 1: examples = '1 example' else: examples = '%d examples' % len(self.examples) return ('' % (self.name, self.filename, self.lineno, examples)) # This lets us sort tests by name: def __cmp__(self, other): if not isinstance(other, DocTest): return -1 return cmp((self.name, self.filename, self.lineno, id(self)), (other.name, other.filename, other.lineno, id(other))) ###################################################################### ## 3. DocTestParser ###################################################################### class DocTestParser: """ A class used to parse strings containing doctest examples. """ # This regular expression is used to find doctest examples in a # string. It defines three groups: `source` is the source code # (including leading indentation and prompts); `indent` is the # indentation of the first (PS1) line of the source code; and # `want` is the expected output (including leading indentation). _EXAMPLE_RE = re.compile(r''' # Source consists of a PS1 line followed by zero or more PS2 lines. (?P (?:^(?P [ ]*) >>> .*) # PS1 line (?:\n [ ]* \.\.\. .*)*) # PS2 lines \n? # Want consists of any non-blank lines that do not start with PS1. (?P (?:(?![ ]*$) # Not a blank line (?![ ]*>>>) # Not a line starting with PS1 .*$\n? # But any other line )*) ''', re.MULTILINE | re.VERBOSE) # A regular expression for handling `want` strings that contain # expected exceptions. It divides `want` into three pieces: # - the traceback header line (`hdr`) # - the traceback stack (`stack`) # - the exception message (`msg`), as generated by # traceback.format_exception_only() # `msg` may have multiple lines. We assume/require that the # exception message is the first non-indented line starting with a word # character following the traceback header line. _EXCEPTION_RE = re.compile(r""" # Grab the traceback header. Different versions of Python have # said different things on the first traceback line. ^(?P Traceback\ \( (?: most\ recent\ call\ last | innermost\ last ) \) : ) \s* $ # toss trailing whitespace on the header. (?P .*?) # don't blink: absorb stuff until... ^ (?P \w+ .*) # a line *starts* with alphanum. """, re.VERBOSE | re.MULTILINE | re.DOTALL) # A callable returning a true value iff its argument is a blank line # or contains a single comment. _IS_BLANK_OR_COMMENT = re.compile(r'^[ ]*(#.*)?$').match def parse(self, string, name=''): """ Divide the given string into examples and intervening text, and return them as a list of alternating Examples and strings. Line numbers for the Examples are 0-based. The optional argument `name` is a name identifying this string, and is only used for error messages. """ string = string.expandtabs() # If all lines begin with the same indentation, then strip it. min_indent = self._min_indent(string) if min_indent > 0: string = '\n'.join([l[min_indent:] for l in string.split('\n')]) output = [] charno, lineno = 0, 0 # Find all doctest examples in the string: for m in self._EXAMPLE_RE.finditer(string): # Add the pre-example text to `output`. output.append(string[charno:m.start()]) # Update lineno (lines before this example) lineno += string.count('\n', charno, m.start()) # Extract info from the regexp match. (source, options, want, exc_msg) = \ self._parse_example(m, name, lineno) # Create an Example, and add it to the list. if not self._IS_BLANK_OR_COMMENT(source): output.append( Example(source, want, exc_msg, lineno=lineno, indent=min_indent+len(m.group('indent')), options=options) ) # Update lineno (lines inside this example) lineno += string.count('\n', m.start(), m.end()) # Update charno. charno = m.end() # Add any remaining post-example text to `output`. output.append(string[charno:]) return output def get_doctest(self, string, globs, name, filename, lineno): """ Extract all doctest examples from the given string, and collect them into a `DocTest` object. `globs`, `name`, `filename`, and `lineno` are attributes for the new `DocTest` object. See the documentation for `DocTest` for more information. """ return DocTest(self.get_examples(string, name), globs, name, filename, lineno, string) def get_examples(self, string, name=''): """ Extract all doctest examples from the given string, and return them as a list of `Example` objects. Line numbers are 0-based, because it's most common in doctests that nothing interesting appears on the same line as opening triple-quote, and so the first interesting line is called \"line 1\" then. The optional argument `name` is a name identifying this string, and is only used for error messages. """ return [x for x in self.parse(string, name) if isinstance(x, Example)] def _parse_example(self, m, name, lineno): """ Given a regular expression match from `_EXAMPLE_RE` (`m`), return a pair `(source, want)`, where `source` is the matched example's source code (with prompts and indentation stripped); and `want` is the example's expected output (with indentation stripped). `name` is the string's name, and `lineno` is the line number where the example starts; both are used for error messages. """ # Get the example's indentation level. indent = len(m.group('indent')) # Divide source into lines; check that they're properly # indented; and then strip their indentation & prompts. source_lines = m.group('source').split('\n') self._check_prompt_blank(source_lines, indent, name, lineno) self._check_prefix(source_lines[1:], ' '*indent + '.', name, lineno) source = '\n'.join([sl[indent+4:] for sl in source_lines]) # Divide want into lines; check that it's properly indented; and # then strip the indentation. Spaces before the last newline should # be preserved, so plain rstrip() isn't good enough. want = m.group('want') want_lines = want.split('\n') if len(want_lines) > 1 and re.match(r' *$', want_lines[-1]): del want_lines[-1] # forget final newline & spaces after it self._check_prefix(want_lines, ' '*indent, name, lineno + len(source_lines)) want = '\n'.join([wl[indent:] for wl in want_lines]) # If `want` contains a traceback message, then extract it. m = self._EXCEPTION_RE.match(want) if m: exc_msg = m.group('msg') else: exc_msg = None # Extract options from the source. options = self._find_options(source, name, lineno) return source, options, want, exc_msg # This regular expression looks for option directives in the # source code of an example. Option directives are comments # starting with "doctest:". Warning: this may give false # positives for string-literals that contain the string # "#doctest:". Eliminating these false positives would require # actually parsing the string; but we limit them by ignoring any # line containing "#doctest:" that is *followed* by a quote mark. _OPTION_DIRECTIVE_RE = re.compile(r'#\s*doctest:\s*([^\n\'"]*)$', re.MULTILINE) def _find_options(self, source, name, lineno): """ Return a dictionary containing option overrides extracted from option directives in the given source string. `name` is the string's name, and `lineno` is the line number where the example starts; both are used for error messages. """ options = {} # (note: with the current regexp, this will match at most once:) for m in self._OPTION_DIRECTIVE_RE.finditer(source): option_strings = m.group(1).replace(',', ' ').split() for option in option_strings: if (option[0] not in '+-' or option[1:] not in OPTIONFLAGS_BY_NAME): raise ValueError('line %r of the doctest for %s ' 'has an invalid option: %r' % (lineno+1, name, option)) flag = OPTIONFLAGS_BY_NAME[option[1:]] options[flag] = (option[0] == '+') if options and self._IS_BLANK_OR_COMMENT(source): raise ValueError('line %r of the doctest for %s has an option ' 'directive on a line with no example: %r' % (lineno, name, source)) return options # This regular expression finds the indentation of every non-blank # line in a string. _INDENT_RE = re.compile('^([ ]*)(?=\S)', re.MULTILINE) def _min_indent(self, s): "Return the minimum indentation of any non-blank line in `s`" indents = [len(indent) for indent in self._INDENT_RE.findall(s)] if len(indents) > 0: return min(indents) else: return 0 def _check_prompt_blank(self, lines, indent, name, lineno): """ Given the lines of a source string (including prompts and leading indentation), check to make sure that every prompt is followed by a space character. If any line is not followed by a space character, then raise ValueError. """ for i, line in enumerate(lines): if len(line) >= indent+4 and line[indent+3] != ' ': raise ValueError('line %r of the docstring for %s ' 'lacks blank after %s: %r' % (lineno+i+1, name, line[indent:indent+3], line)) def _check_prefix(self, lines, prefix, name, lineno): """ Check that every line in the given list starts with the given prefix; if any line does not, then raise a ValueError. """ for i, line in enumerate(lines): if line and not line.startswith(prefix): raise ValueError('line %r of the docstring for %s has ' 'inconsistent leading whitespace: %r' % (lineno+i+1, name, line)) ###################################################################### ## 4. DocTest Finder ###################################################################### class DocTestFinder: """ A class used to extract the DocTests that are relevant to a given object, from its docstring and the docstrings of its contained objects. Doctests can currently be extracted from the following object types: modules, functions, classes, methods, staticmethods, classmethods, and properties. """ def __init__(self, verbose=False, parser=DocTestParser(), recurse=True, _namefilter=None, exclude_empty=True): """ Create a new doctest finder. The optional argument `parser` specifies a class or function that should be used to create new DocTest objects (or objects that implement the same interface as DocTest). The signature for this factory function should match the signature of the DocTest constructor. If the optional argument `recurse` is false, then `find` will only examine the given object, and not any contained objects. If the optional argument `exclude_empty` is false, then `find` will include tests for objects with empty docstrings. """ self._parser = parser self._verbose = verbose self._recurse = recurse self._exclude_empty = exclude_empty # _namefilter is undocumented, and exists only for temporary backward- # compatibility support of testmod's deprecated isprivate mess. self._namefilter = _namefilter def find(self, obj, name=None, module=None, globs=None, extraglobs=None): """ Return a list of the DocTests that are defined by the given object's docstring, or by any of its contained objects' docstrings. The optional parameter `module` is the module that contains the given object. If the module is not specified or is None, then the test finder will attempt to automatically determine the correct module. The object's module is used: - As a default namespace, if `globs` is not specified. - To prevent the DocTestFinder from extracting DocTests from objects that are imported from other modules. - To find the name of the file containing the object. - To help find the line number of the object within its file. Contained objects whose module does not match `module` are ignored. If `module` is False, no attempt to find the module will be made. This is obscure, of use mostly in tests: if `module` is False, or is None but cannot be found automatically, then all objects are considered to belong to the (non-existent) module, so all contained objects will (recursively) be searched for doctests. The globals for each DocTest is formed by combining `globs` and `extraglobs` (bindings in `extraglobs` override bindings in `globs`). A new copy of the globals dictionary is created for each DocTest. If `globs` is not specified, then it defaults to the module's `__dict__`, if specified, or {} otherwise. If `extraglobs` is not specified, then it defaults to {}. """ # If name was not specified, then extract it from the object. if name is None: name = getattr(obj, '__name__', None) if name is None: raise ValueError("DocTestFinder.find: name must be given " "when obj.__name__ doesn't exist: %r" % (type(obj),)) # Find the module that contains the given object (if obj is # a module, then module=obj.). Note: this may fail, in which # case module will be None. if module is False: module = None elif module is None: module = inspect.getmodule(obj) # Read the module's source code. This is used by # DocTestFinder._find_lineno to find the line number for a # given object's docstring. try: file = inspect.getsourcefile(obj) or inspect.getfile(obj) source_lines = linecache.getlines(file) if not source_lines: source_lines = None except TypeError: source_lines = None # Initialize globals, and merge in extraglobs. if globs is None: if module is None: globs = {} else: globs = module.__dict__.copy() else: globs = globs.copy() if extraglobs is not None: globs.update(extraglobs) # Recursively expore `obj`, extracting DocTests. tests = [] self._find(tests, obj, name, module, source_lines, globs, {}) return tests def _filter(self, obj, prefix, base): """ Return true if the given object should not be examined. """ return (self._namefilter is not None and self._namefilter(prefix, base)) def _from_module(self, module, object): """ Return true if the given object is defined in the given module. """ if module is None: return True elif inspect.isfunction(object): return module.__dict__ is object.func_globals elif inspect.isclass(object): return module.__name__ == object.__module__ elif inspect.getmodule(object) is not None: return module is inspect.getmodule(object) elif hasattr(object, '__module__'): return module.__name__ == object.__module__ elif isinstance(object, property): return True # [XX] no way not be sure. else: raise ValueError("object must be a class or function") def _find(self, tests, obj, name, module, source_lines, globs, seen): """ Find tests for the given object and any contained objects, and add them to `tests`. """ if self._verbose: print 'Finding tests in %s' % name # If we've already processed this object, then ignore it. if id(obj) in seen: return seen[id(obj)] = 1 # Find a test for this object, and add it to the list of tests. test = self._get_test(obj, name, module, globs, source_lines) if test is not None: tests.append(test) # Look for tests in a module's contained objects. if inspect.ismodule(obj) and self._recurse: for valname, val in obj.__dict__.items(): # Check if this contained object should be ignored. if self._filter(val, name, valname): continue valname = '%s.%s' % (name, valname) # Recurse to functions & classes. if ((inspect.isfunction(val) or inspect.isclass(val)) and self._from_module(module, val)): self._find(tests, val, valname, module, source_lines, globs, seen) # Look for tests in a module's __test__ dictionary. if inspect.ismodule(obj) and self._recurse: for valname, val in getattr(obj, '__test__', {}).items(): if not isinstance(valname, basestring): raise ValueError("DocTestFinder.find: __test__ keys " "must be strings: %r" % (type(valname),)) if not (inspect.isfunction(val) or inspect.isclass(val) or inspect.ismethod(val) or inspect.ismodule(val) or isinstance(val, basestring)): raise ValueError("DocTestFinder.find: __test__ values " "must be strings, functions, methods, " "classes, or modules: %r" % (type(val),)) valname = '%s.__test__.%s' % (name, valname) self._find(tests, val, valname, module, source_lines, globs, seen) # Look for tests in a class's contained objects. if inspect.isclass(obj) and self._recurse: for valname, val in obj.__dict__.items(): # Check if this contained object should be ignored. if self._filter(val, name, valname): continue # Special handling for staticmethod/classmethod. if isinstance(val, staticmethod): val = getattr(obj, valname) if isinstance(val, classmethod): val = getattr(obj, valname).im_func # Recurse to methods, properties, and nested classes. if ((inspect.isfunction(val) or inspect.isclass(val) or isinstance(val, property)) and self._from_module(module, val)): valname = '%s.%s' % (name, valname) self._find(tests, val, valname, module, source_lines, globs, seen) def _get_test(self, obj, name, module, globs, source_lines): """ Return a DocTest for the given object, if it defines a docstring; otherwise, return None. """ # Extract the object's docstring. If it doesn't have one, # then return None (no test for this object). if isinstance(obj, basestring): docstring = obj else: try: if obj.__doc__ is None: docstring = '' else: docstring = obj.__doc__ if not isinstance(docstring, basestring): docstring = str(docstring) except (TypeError, AttributeError): docstring = '' # Find the docstring's location in the file. lineno = self._find_lineno(obj, source_lines) # Don't bother if the docstring is empty. if self._exclude_empty and not docstring: return None # Return a DocTest for this object. if module is None: filename = None else: filename = getattr(module, '__file__', module.__name__) if filename[-4:] in (".pyc", ".pyo"): filename = filename[:-1] return self._parser.get_doctest(docstring, globs, name, filename, lineno) def _find_lineno(self, obj, source_lines): """ Return a line number of the given object's docstring. Note: this method assumes that the object has a docstring. """ lineno = None # Find the line number for modules. if inspect.ismodule(obj): lineno = 0 # Find the line number for classes. # Note: this could be fooled if a class is defined multiple # times in a single file. if inspect.isclass(obj): if source_lines is None: return None pat = re.compile(r'^\s*class\s*%s\b' % getattr(obj, '__name__', '-')) for i, line in enumerate(source_lines): if pat.match(line): lineno = i break # Find the line number for functions & methods. if inspect.ismethod(obj): obj = obj.im_func if inspect.isfunction(obj): obj = obj.func_code if inspect.istraceback(obj): obj = obj.tb_frame if inspect.isframe(obj): obj = obj.f_code if inspect.iscode(obj): lineno = getattr(obj, 'co_firstlineno', None)-1 # Find the line number where the docstring starts. Assume # that it's the first line that begins with a quote mark. # Note: this could be fooled by a multiline function # signature, where a continuation line begins with a quote # mark. if lineno is not None: if source_lines is None: return lineno+1 pat = re.compile('(^|.*:)\s*\w*("|\')') for lineno in range(lineno, len(source_lines)): if pat.match(source_lines[lineno]): return lineno # We couldn't find the line number. return None ###################################################################### ## 5. DocTest Runner ###################################################################### class DocTestRunner: """ A class used to run DocTest test cases, and accumulate statistics. The `run` method is used to process a single DocTest case. It returns a tuple `(f, t)`, where `t` is the number of test cases tried, and `f` is the number of test cases that failed. >>> tests = DocTestFinder().find(_TestClass) >>> runner = DocTestRunner(verbose=False) >>> for test in tests: ... print runner.run(test) (0, 2) (0, 1) (0, 2) (0, 2) The `summarize` method prints a summary of all the test cases that have been run by the runner, and returns an aggregated `(f, t)` tuple: >>> runner.summarize(verbose=1) 4 items passed all tests: 2 tests in _TestClass 2 tests in _TestClass.__init__ 2 tests in _TestClass.get 1 tests in _TestClass.square 7 tests in 4 items. 7 passed and 0 failed. Test passed. (0, 7) The aggregated number of tried examples and failed examples is also available via the `tries` and `failures` attributes: >>> runner.tries 7 >>> runner.failures 0 The comparison between expected outputs and actual outputs is done by an `OutputChecker`. This comparison may be customized with a number of option flags; see the documentation for `testmod` for more information. If the option flags are insufficient, then the comparison may also be customized by passing a subclass of `OutputChecker` to the constructor. The test runner's display output can be controlled in two ways. First, an output function (`out) can be passed to `TestRunner.run`; this function will be called with strings that should be displayed. It defaults to `sys.stdout.write`. If capturing the output is not sufficient, then the display output can be also customized by subclassing DocTestRunner, and overriding the methods `report_start`, `report_success`, `report_unexpected_exception`, and `report_failure`. """ # This divider string is used to separate failure messages, and to # separate sections of the summary. DIVIDER = "*" * 70 def __init__(self, checker=None, verbose=None, optionflags=0): """ Create a new test runner. Optional keyword arg `checker` is the `OutputChecker` that should be used to compare the expected outputs and actual outputs of doctest examples. Optional keyword arg 'verbose' prints lots of stuff if true, only failures if false; by default, it's true iff '-v' is in sys.argv. Optional argument `optionflags` can be used to control how the test runner compares expected output to actual output, and how it displays failures. See the documentation for `testmod` for more information. """ self._checker = checker or OutputChecker() if verbose is None: verbose = '-v' in sys.argv self._verbose = verbose self.optionflags = optionflags self.original_optionflags = optionflags # Keep track of the examples we've run. self.tries = 0 self.failures = 0 self._name2ft = {} # Create a fake output target for capturing doctest output. self._fakeout = _SpoofOut() #///////////////////////////////////////////////////////////////// # Reporting methods #///////////////////////////////////////////////////////////////// def report_start(self, out, test, example): """ Report that the test runner is about to process the given example. (Only displays a message if verbose=True) """ if self._verbose: if example.want: out('Trying:\n' + _indent(example.source) + 'Expecting:\n' + _indent(example.want)) else: out('Trying:\n' + _indent(example.source) + 'Expecting nothing\n') def report_success(self, out, test, example, got): """ Report that the given example ran successfully. (Only displays a message if verbose=True) """ if self._verbose: out("ok\n") def report_failure(self, out, test, example, got): """ Report that the given example failed. """ out(self._failure_header(test, example) + self._checker.output_difference(example, got, self.optionflags)) def report_unexpected_exception(self, out, test, example, exc_info): """ Report that the given example raised an unexpected exception. """ out(self._failure_header(test, example) + 'Exception raised:\n' + _indent(_exception_traceback(exc_info))) def _failure_header(self, test, example): out = [self.DIVIDER] if test.filename: if test.lineno is not None and example.lineno is not None: lineno = test.lineno + example.lineno + 1 else: lineno = '?' out.append('File "%s", line %s, in %s' % (test.filename, lineno, test.name)) else: out.append('Line %s, in %s' % (example.lineno+1, test.name)) out.append('Failed example:') source = example.source out.append(_indent(source)) return '\n'.join(out) #///////////////////////////////////////////////////////////////// # DocTest Running #///////////////////////////////////////////////////////////////// def __run(self, test, compileflags, out): """ Run the examples in `test`. Write the outcome of each example with one of the `DocTestRunner.report_*` methods, using the writer function `out`. `compileflags` is the set of compiler flags that should be used to execute examples. Return a tuple `(f, t)`, where `t` is the number of examples tried, and `f` is the number of examples that failed. The examples are run in the namespace `test.globs`. """ # Keep track of the number of failures and tries. failures = tries = 0 # Save the option flags (since option directives can be used # to modify them). original_optionflags = self.optionflags SUCCESS, FAILURE, BOOM = range(3) # `outcome` state check = self._checker.check_output # Process each example. for examplenum, example in enumerate(test.examples): # If REPORT_ONLY_FIRST_FAILURE is set, then supress # reporting after the first failure. quiet = (self.optionflags & REPORT_ONLY_FIRST_FAILURE and failures > 0) # Merge in the example's options. self.optionflags = original_optionflags if example.options: for (optionflag, val) in example.options.items(): if val: self.optionflags |= optionflag else: self.optionflags &= ~optionflag # Record that we started this example. tries += 1 if not quiet: self.report_start(out, test, example) # Use a special filename for compile(), so we can retrieve # the source code during interactive debugging (see # __patched_linecache_getlines). filename = '' % (test.name, examplenum) # Run the example in the given context (globs), and record # any exception that gets raised. (But don't intercept # keyboard interrupts.) try: # Don't blink! This is where the user's code gets run. exec compile(example.source, filename, "single", compileflags, 1) in test.globs self.debugger.set_continue() # ==== Example Finished ==== exception = None except KeyboardInterrupt: raise except: exception = sys.exc_info() self.debugger.set_continue() # ==== Example Finished ==== got = self._fakeout.getvalue() # the actual output self._fakeout.truncate(0) outcome = FAILURE # guilty until proved innocent or insane # If the example executed without raising any exceptions, # verify its output. if exception is None: if check(example.want, got, self.optionflags): outcome = SUCCESS # The example raised an exception: check if it was expected. else: exc_info = sys.exc_info() exc_msg = traceback.format_exception_only(*exc_info[:2])[-1] if not quiet: got += _exception_traceback(exc_info) # If `example.exc_msg` is None, then we weren't expecting # an exception. if example.exc_msg is None: outcome = BOOM # We expected an exception: see whether it matches. elif check(example.exc_msg, exc_msg, self.optionflags): outcome = SUCCESS # Another chance if they didn't care about the detail. elif self.optionflags & IGNORE_EXCEPTION_DETAIL: m1 = re.match(r'[^:]*:', example.exc_msg) m2 = re.match(r'[^:]*:', exc_msg) if m1 and m2 and check(m1.group(0), m2.group(0), self.optionflags): outcome = SUCCESS # Report the outcome. if outcome is SUCCESS: if not quiet: self.report_success(out, test, example, got) elif outcome is FAILURE: if not quiet: self.report_failure(out, test, example, got) failures += 1 elif outcome is BOOM: if not quiet: self.report_unexpected_exception(out, test, example, exc_info) failures += 1 else: assert False, ("unknown outcome", outcome) # Restore the option flags (in case they were modified) self.optionflags = original_optionflags # Record and return the number of failures and tries. self.__record_outcome(test, failures, tries) return failures, tries def __record_outcome(self, test, f, t): """ Record the fact that the given DocTest (`test`) generated `f` failures out of `t` tried examples. """ f2, t2 = self._name2ft.get(test.name, (0,0)) self._name2ft[test.name] = (f+f2, t+t2) self.failures += f self.tries += t __LINECACHE_FILENAME_RE = re.compile(r'[\w\.]+)' r'\[(?P\d+)\]>$') def __patched_linecache_getlines(self, filename, module_globals=None): m = self.__LINECACHE_FILENAME_RE.match(filename) if m and m.group('name') == self.test.name: example = self.test.examples[int(m.group('examplenum'))] return example.source.splitlines(True) elif self.save_linecache_getlines.func_code.co_argcount>1: return self.save_linecache_getlines(filename, module_globals) else: return self.save_linecache_getlines(filename) def run(self, test, compileflags=None, out=None, clear_globs=True): """ Run the examples in `test`, and display the results using the writer function `out`. The examples are run in the namespace `test.globs`. If `clear_globs` is true (the default), then this namespace will be cleared after the test runs, to help with garbage collection. If you would like to examine the namespace after the test completes, then use `clear_globs=False`. `compileflags` gives the set of flags that should be used by the Python compiler when running the examples. If not specified, then it will default to the set of future-import flags that apply to `globs`. The output of each example is checked using `DocTestRunner.check_output`, and the results are formatted by the `DocTestRunner.report_*` methods. """ self.test = test if compileflags is None: compileflags = _extract_future_flags(test.globs) save_stdout = sys.stdout if out is None: out = save_stdout.write sys.stdout = self._fakeout # Patch pdb.set_trace to restore sys.stdout during interactive # debugging (so it's not still redirected to self._fakeout). # Note that the interactive output will go to *our* # save_stdout, even if that's not the real sys.stdout; this # allows us to write test cases for the set_trace behavior. save_set_trace = pdb.set_trace self.debugger = _OutputRedirectingPdb(save_stdout) self.debugger.reset() pdb.set_trace = self.debugger.set_trace # Patch linecache.getlines, so we can see the example's source # when we're inside the debugger. self.save_linecache_getlines = linecache.getlines linecache.getlines = self.__patched_linecache_getlines try: return self.__run(test, compileflags, out) finally: sys.stdout = save_stdout pdb.set_trace = save_set_trace linecache.getlines = self.save_linecache_getlines if clear_globs: test.globs.clear() #///////////////////////////////////////////////////////////////// # Summarization #///////////////////////////////////////////////////////////////// def summarize(self, verbose=None): """ Print a summary of all the test cases that have been run by this DocTestRunner, and return a tuple `(f, t)`, where `f` is the total number of failed examples, and `t` is the total number of tried examples. The optional `verbose` argument controls how detailed the summary is. If the verbosity is not specified, then the DocTestRunner's verbosity is used. """ if verbose is None: verbose = self._verbose notests = [] passed = [] failed = [] totalt = totalf = 0 for x in self._name2ft.items(): name, (f, t) = x assert f <= t totalt += t totalf += f if t == 0: notests.append(name) elif f == 0: passed.append( (name, t) ) else: failed.append(x) if verbose: if notests: print len(notests), "items had no tests:" notests.sort() for thing in notests: print " ", thing if passed: print len(passed), "items passed all tests:" passed.sort() for thing, count in passed: print " %3d tests in %s" % (count, thing) if failed: print self.DIVIDER print len(failed), "items had failures:" failed.sort() for thing, (f, t) in failed: print " %3d of %3d in %s" % (f, t, thing) if verbose: print totalt, "tests in", len(self._name2ft), "items." print totalt - totalf, "passed and", totalf, "failed." if totalf: print "***Test Failed***", totalf, "failures." elif verbose: print "Test passed." return totalf, totalt #///////////////////////////////////////////////////////////////// # Backward compatibility cruft to maintain doctest.master. #///////////////////////////////////////////////////////////////// def merge(self, other): d = self._name2ft for name, (f, t) in other._name2ft.items(): if name in d: print "*** DocTestRunner.merge: '" + name + "' in both" \ " testers; summing outcomes." f2, t2 = d[name] f = f + f2 t = t + t2 d[name] = f, t class OutputChecker: """ A class used to check the whether the actual output from a doctest example matches the expected output. `OutputChecker` defines two methods: `check_output`, which compares a given pair of outputs, and returns true if they match; and `output_difference`, which returns a string describing the differences between two outputs. """ def check_output(self, want, got, optionflags): """ Return True iff the actual output from an example (`got`) matches the expected output (`want`). These strings are always considered to match if they are identical; but depending on what option flags the test runner is using, several non-exact match types are also possible. See the documentation for `TestRunner` for more information about option flags. """ # Handle the common case first, for efficiency: # if they're string-identical, always return true. if got == want: return True # The values True and False replaced 1 and 0 as the return # value for boolean comparisons in Python 2.3. if not (optionflags & DONT_ACCEPT_TRUE_FOR_1): if (got,want) == ("True\n", "1\n"): return True if (got,want) == ("False\n", "0\n"): return True # can be used as a special sequence to signify a # blank line, unless the DONT_ACCEPT_BLANKLINE flag is used. if not (optionflags & DONT_ACCEPT_BLANKLINE): # Replace in want with a blank line. want = re.sub('(?m)^%s\s*?$' % re.escape(BLANKLINE_MARKER), '', want) # If a line in got contains only spaces, then remove the # spaces. got = re.sub('(?m)^\s*?$', '', got) if got == want: return True # This flag causes doctest to ignore any differences in the # contents of whitespace strings. Note that this can be used # in conjunction with the ELLIPSIS flag. if optionflags & NORMALIZE_WHITESPACE: got = ' '.join(got.split()) want = ' '.join(want.split()) if got == want: return True # The ELLIPSIS flag says to let the sequence "..." in `want` # match any substring in `got`. if optionflags & ELLIPSIS: if _ellipsis_match(want, got): return True # We didn't find any match; return false. return False # Should we do a fancy diff? def _do_a_fancy_diff(self, want, got, optionflags): # Not unless they asked for a fancy diff. if not optionflags & (REPORT_UDIFF | REPORT_CDIFF | REPORT_NDIFF): return False # If expected output uses ellipsis, a meaningful fancy diff is # too hard ... or maybe not. In two real-life failures Tim saw, # a diff was a major help anyway, so this is commented out. # [todo] _ellipsis_match() knows which pieces do and don't match, # and could be the basis for a kick-ass diff in this case. ##if optionflags & ELLIPSIS and ELLIPSIS_MARKER in want: ## return False # ndiff does intraline difference marking, so can be useful even # for 1-line differences. if optionflags & REPORT_NDIFF: return True # The other diff types need at least a few lines to be helpful. return want.count('\n') > 2 and got.count('\n') > 2 def output_difference(self, example, got, optionflags): """ Return a string describing the differences between the expected output for a given example (`example`) and the actual output (`got`). `optionflags` is the set of option flags used to compare `want` and `got`. """ want = example.want # If s are being used, then replace blank lines # with in the actual output string. if not (optionflags & DONT_ACCEPT_BLANKLINE): got = re.sub('(?m)^[ ]*(?=\n)', BLANKLINE_MARKER, got) # Check if we should use diff. if self._do_a_fancy_diff(want, got, optionflags): # Split want & got into lines. want_lines = want.splitlines(True) # True == keep line ends got_lines = got.splitlines(True) # Use difflib to find their differences. if optionflags & REPORT_UDIFF: diff = difflib.unified_diff(want_lines, got_lines, n=2) diff = list(diff)[2:] # strip the diff header kind = 'unified diff with -expected +actual' elif optionflags & REPORT_CDIFF: diff = difflib.context_diff(want_lines, got_lines, n=2) diff = list(diff)[2:] # strip the diff header kind = 'context diff with expected followed by actual' elif optionflags & REPORT_NDIFF: engine = difflib.Differ(charjunk=difflib.IS_CHARACTER_JUNK) diff = list(engine.compare(want_lines, got_lines)) kind = 'ndiff with -expected +actual' else: assert 0, 'Bad diff option' # Remove trailing whitespace on diff output. diff = [line.rstrip() + '\n' for line in diff] return 'Differences (%s):\n' % kind + _indent(''.join(diff)) # If we're not using diff, then simply list the expected # output followed by the actual output. if want and got: return 'Expected:\n%sGot:\n%s' % (_indent(want), _indent(got)) elif want: return 'Expected:\n%sGot nothing\n' % _indent(want) elif got: return 'Expected nothing\nGot:\n%s' % _indent(got) else: return 'Expected nothing\nGot nothing\n' class DocTestFailure(Exception): """A DocTest example has failed in debugging mode. The exception instance has variables: - test: the DocTest object being run - excample: the Example object that failed - got: the actual output """ def __init__(self, test, example, got): self.test = test self.example = example self.got = got def __str__(self): return str(self.test) class UnexpectedException(Exception): """A DocTest example has encountered an unexpected exception The exception instance has variables: - test: the DocTest object being run - excample: the Example object that failed - exc_info: the exception info """ def __init__(self, test, example, exc_info): self.test = test self.example = example self.exc_info = exc_info def __str__(self): return str(self.test) class DebugRunner(DocTestRunner): r"""Run doc tests but raise an exception as soon as there is a failure. If an unexpected exception occurs, an UnexpectedException is raised. It contains the test, the example, and the original exception: >>> runner = DebugRunner(verbose=False) >>> test = DocTestParser().get_doctest('>>> raise KeyError\n42', ... {}, 'foo', 'foo.py', 0) >>> try: ... runner.run(test) ... except UnexpectedException, failure: ... pass >>> failure.test is test True >>> failure.example.want '42\n' >>> exc_info = failure.exc_info >>> raise exc_info[0], exc_info[1], exc_info[2] Traceback (most recent call last): ... KeyError We wrap the original exception to give the calling application access to the test and example information. If the output doesn't match, then a DocTestFailure is raised: >>> test = DocTestParser().get_doctest(''' ... >>> x = 1 ... >>> x ... 2 ... ''', {}, 'foo', 'foo.py', 0) >>> try: ... runner.run(test) ... except DocTestFailure, failure: ... pass DocTestFailure objects provide access to the test: >>> failure.test is test True As well as to the example: >>> failure.example.want '2\n' and the actual output: >>> failure.got '1\n' If a failure or error occurs, the globals are left intact: >>> del test.globs['__builtins__'] >>> test.globs {'x': 1} >>> test = DocTestParser().get_doctest(''' ... >>> x = 2 ... >>> raise KeyError ... ''', {}, 'foo', 'foo.py', 0) >>> runner.run(test) Traceback (most recent call last): ... UnexpectedException: >>> del test.globs['__builtins__'] >>> test.globs {'x': 2} But the globals are cleared if there is no error: >>> test = DocTestParser().get_doctest(''' ... >>> x = 2 ... ''', {}, 'foo', 'foo.py', 0) >>> runner.run(test) (0, 1) >>> test.globs {} """ def run(self, test, compileflags=None, out=None, clear_globs=True): r = DocTestRunner.run(self, test, compileflags, out, False) if clear_globs: test.globs.clear() return r def report_unexpected_exception(self, out, test, example, exc_info): raise UnexpectedException(test, example, exc_info) def report_failure(self, out, test, example, got): raise DocTestFailure(test, example, got) ###################################################################### ## 6. Test Functions ###################################################################### # These should be backwards compatible. # For backward compatibility, a global instance of a DocTestRunner # class, updated by testmod. master = None def testmod(m=None, name=None, globs=None, verbose=None, isprivate=None, report=True, optionflags=0, extraglobs=None, raise_on_error=False, exclude_empty=False): """m=None, name=None, globs=None, verbose=None, isprivate=None, report=True, optionflags=0, extraglobs=None, raise_on_error=False, exclude_empty=False Test examples in docstrings in functions and classes reachable from module m (or the current module if m is not supplied), starting with m.__doc__. Unless isprivate is specified, private names are not skipped. Also test examples reachable from dict m.__test__ if it exists and is not None. m.__test__ maps names to functions, classes and strings; function and class docstrings are tested even if the name is private; strings are tested directly, as if they were docstrings. Return (#failures, #tests). See doctest.__doc__ for an overview. Optional keyword arg "name" gives the name of the module; by default use m.__name__. Optional keyword arg "globs" gives a dict to be used as the globals when executing examples; by default, use m.__dict__. A copy of this dict is actually used for each docstring, so that each docstring's examples start with a clean slate. Optional keyword arg "extraglobs" gives a dictionary that should be merged into the globals that are used to execute examples. By default, no extra globals are used. This is new in 2.4. Optional keyword arg "verbose" prints lots of stuff if true, prints only failures if false; by default, it's true iff "-v" is in sys.argv. Optional keyword arg "report" prints a summary at the end when true, else prints nothing at the end. In verbose mode, the summary is detailed, else very brief (in fact, empty if all tests passed). Optional keyword arg "optionflags" or's together module constants, and defaults to 0. This is new in 2.3. Possible values (see the docs for details): DONT_ACCEPT_TRUE_FOR_1 DONT_ACCEPT_BLANKLINE NORMALIZE_WHITESPACE ELLIPSIS IGNORE_EXCEPTION_DETAIL REPORT_UDIFF REPORT_CDIFF REPORT_NDIFF REPORT_ONLY_FIRST_FAILURE Optional keyword arg "raise_on_error" raises an exception on the first unexpected exception or failure. This allows failures to be post-mortem debugged. Deprecated in Python 2.4: Optional keyword arg "isprivate" specifies a function used to determine whether a name is private. The default function is treat all functions as public. Optionally, "isprivate" can be set to doctest.is_private to skip over functions marked as private using the underscore naming convention; see its docs for details. Advanced tomfoolery: testmod runs methods of a local instance of class doctest.Tester, then merges the results into (or creates) global Tester instance doctest.master. Methods of doctest.master can be called directly too, if you want to do something unusual. Passing report=0 to testmod is especially useful then, to delay displaying a summary. Invoke doctest.master.summarize(verbose) when you're done fiddling. """ global master if isprivate is not None: warnings.warn("the isprivate argument is deprecated; " "examine DocTestFinder.find() lists instead", DeprecationWarning) # If no module was given, then use __main__. if m is None: # DWA - m will still be None if this wasn't invoked from the command # line, in which case the following TypeError is about as good an error # as we should expect m = sys.modules.get('__main__') # Check that we were actually given a module. if not inspect.ismodule(m): raise TypeError("testmod: module required; %r" % (m,)) # If no name was given, then use the module's name. if name is None: name = m.__name__ # Find, parse, and run all tests in the given module. finder = DocTestFinder(_namefilter=isprivate, exclude_empty=exclude_empty) if raise_on_error: runner = DebugRunner(verbose=verbose, optionflags=optionflags) else: runner = DocTestRunner(verbose=verbose, optionflags=optionflags) for test in finder.find(m, name, globs=globs, extraglobs=extraglobs): runner.run(test) if report: runner.summarize() if master is None: master = runner else: master.merge(runner) return runner.failures, runner.tries def testfile(filename, module_relative=True, name=None, package=None, globs=None, verbose=None, report=True, optionflags=0, extraglobs=None, raise_on_error=False, parser=DocTestParser()): """ Test examples in the given file. Return (#failures, #tests). Optional keyword arg "module_relative" specifies how filenames should be interpreted: - If "module_relative" is True (the default), then "filename" specifies a module-relative path. By default, this path is relative to the calling module's directory; but if the "package" argument is specified, then it is relative to that package. To ensure os-independence, "filename" should use "/" characters to separate path segments, and should not be an absolute path (i.e., it may not begin with "/"). - If "module_relative" is False, then "filename" specifies an os-specific path. The path may be absolute or relative (to the current working directory). Optional keyword arg "name" gives the name of the test; by default use the file's basename. Optional keyword argument "package" is a Python package or the name of a Python package whose directory should be used as the base directory for a module relative filename. If no package is specified, then the calling module's directory is used as the base directory for module relative filenames. It is an error to specify "package" if "module_relative" is False. Optional keyword arg "globs" gives a dict to be used as the globals when executing examples; by default, use {}. A copy of this dict is actually used for each docstring, so that each docstring's examples start with a clean slate. Optional keyword arg "extraglobs" gives a dictionary that should be merged into the globals that are used to execute examples. By default, no extra globals are used. Optional keyword arg "verbose" prints lots of stuff if true, prints only failures if false; by default, it's true iff "-v" is in sys.argv. Optional keyword arg "report" prints a summary at the end when true, else prints nothing at the end. In verbose mode, the summary is detailed, else very brief (in fact, empty if all tests passed). Optional keyword arg "optionflags" or's together module constants, and defaults to 0. Possible values (see the docs for details): DONT_ACCEPT_TRUE_FOR_1 DONT_ACCEPT_BLANKLINE NORMALIZE_WHITESPACE ELLIPSIS IGNORE_EXCEPTION_DETAIL REPORT_UDIFF REPORT_CDIFF REPORT_NDIFF REPORT_ONLY_FIRST_FAILURE Optional keyword arg "raise_on_error" raises an exception on the first unexpected exception or failure. This allows failures to be post-mortem debugged. Optional keyword arg "parser" specifies a DocTestParser (or subclass) that should be used to extract tests from the files. Advanced tomfoolery: testmod runs methods of a local instance of class doctest.Tester, then merges the results into (or creates) global Tester instance doctest.master. Methods of doctest.master can be called directly too, if you want to do something unusual. Passing report=0 to testmod is especially useful then, to delay displaying a summary. Invoke doctest.master.summarize(verbose) when you're done fiddling. """ global master if package and not module_relative: raise ValueError("Package may only be specified for module-" "relative paths.") # Relativize the path if module_relative: package = _normalize_module(package) filename = _module_relative_path(package, filename) # If no name was given, then use the file's name. if name is None: name = os.path.basename(filename) # Assemble the globals. if globs is None: globs = {} else: globs = globs.copy() if extraglobs is not None: globs.update(extraglobs) if raise_on_error: runner = DebugRunner(verbose=verbose, optionflags=optionflags) else: runner = DocTestRunner(verbose=verbose, optionflags=optionflags) # Read the file, convert it to a test, and run it. s = open(filename).read() test = parser.get_doctest(s, globs, name, filename, 0) runner.run(test) if report: runner.summarize() if master is None: master = runner else: master.merge(runner) return runner.failures, runner.tries def run_docstring_examples(f, globs, verbose=False, name="NoName", compileflags=None, optionflags=0): """ Test examples in the given object's docstring (`f`), using `globs` as globals. Optional argument `name` is used in failure messages. If the optional argument `verbose` is true, then generate output even if there are no failures. `compileflags` gives the set of flags that should be used by the Python compiler when running the examples. If not specified, then it will default to the set of future-import flags that apply to `globs`. Optional keyword arg `optionflags` specifies options for the testing and output. See the documentation for `testmod` for more information. """ # Find, parse, and run all tests in the given module. finder = DocTestFinder(verbose=verbose, recurse=False) runner = DocTestRunner(verbose=verbose, optionflags=optionflags) for test in finder.find(f, name, globs=globs): runner.run(test, compileflags=compileflags) ###################################################################### ## 7. Tester ###################################################################### # This is provided only for backwards compatibility. It's not # actually used in any way. class Tester: def __init__(self, mod=None, globs=None, verbose=None, isprivate=None, optionflags=0): warnings.warn("class Tester is deprecated; " "use class doctest.DocTestRunner instead", DeprecationWarning, stacklevel=2) if mod is None and globs is None: raise TypeError("Tester.__init__: must specify mod or globs") if mod is not None and not inspect.ismodule(mod): raise TypeError("Tester.__init__: mod must be a module; %r" % (mod,)) if globs is None: globs = mod.__dict__ self.globs = globs self.verbose = verbose self.isprivate = isprivate self.optionflags = optionflags self.testfinder = DocTestFinder(_namefilter=isprivate) self.testrunner = DocTestRunner(verbose=verbose, optionflags=optionflags) def runstring(self, s, name): test = DocTestParser().get_doctest(s, self.globs, name, None, None) if self.verbose: print "Running string", name (f,t) = self.testrunner.run(test) if self.verbose: print f, "of", t, "examples failed in string", name return (f,t) def rundoc(self, object, name=None, module=None): f = t = 0 tests = self.testfinder.find(object, name, module=module, globs=self.globs) for test in tests: (f2, t2) = self.testrunner.run(test) (f,t) = (f+f2, t+t2) return (f,t) def rundict(self, d, name, module=None): import new m = new.module(name) m.__dict__.update(d) if module is None: module = False return self.rundoc(m, name, module) def run__test__(self, d, name): import new m = new.module(name) m.__test__ = d return self.rundoc(m, name) def summarize(self, verbose=None): return self.testrunner.summarize(verbose) def merge(self, other): self.testrunner.merge(other.testrunner) ###################################################################### ## 8. Unittest Support ###################################################################### _unittest_reportflags = 0 def set_unittest_reportflags(flags): """Sets the unittest option flags. The old flag is returned so that a runner could restore the old value if it wished to: >>> old = _unittest_reportflags >>> set_unittest_reportflags(REPORT_NDIFF | ... REPORT_ONLY_FIRST_FAILURE) == old True >>> import doctest >>> doctest._unittest_reportflags == (REPORT_NDIFF | ... REPORT_ONLY_FIRST_FAILURE) True Only reporting flags can be set: >>> set_unittest_reportflags(ELLIPSIS) Traceback (most recent call last): ... ValueError: ('Only reporting flags allowed', 8) >>> set_unittest_reportflags(old) == (REPORT_NDIFF | ... REPORT_ONLY_FIRST_FAILURE) True """ global _unittest_reportflags if (flags & REPORTING_FLAGS) != flags: raise ValueError("Only reporting flags allowed", flags) old = _unittest_reportflags _unittest_reportflags = flags return old class DocTestCase(unittest.TestCase): def __init__(self, test, optionflags=0, setUp=None, tearDown=None, checker=None): unittest.TestCase.__init__(self) self._dt_optionflags = optionflags self._dt_checker = checker self._dt_test = test self._dt_setUp = setUp self._dt_tearDown = tearDown def setUp(self): test = self._dt_test if self._dt_setUp is not None: self._dt_setUp(test) def tearDown(self): test = self._dt_test if self._dt_tearDown is not None: self._dt_tearDown(test) test.globs.clear() def runTest(self): test = self._dt_test old = sys.stdout new = StringIO() optionflags = self._dt_optionflags if not (optionflags & REPORTING_FLAGS): # The option flags don't include any reporting flags, # so add the default reporting flags optionflags |= _unittest_reportflags runner = DocTestRunner(optionflags=optionflags, checker=self._dt_checker, verbose=False) try: runner.DIVIDER = "-"*70 failures, tries = runner.run( test, out=new.write, clear_globs=False) finally: sys.stdout = old if failures: raise self.failureException(self.format_failure(new.getvalue())) def format_failure(self, err): test = self._dt_test if test.lineno is None: lineno = 'unknown line number' else: lineno = '%s' % test.lineno lname = '.'.join(test.name.split('.')[-1:]) return ('Failed doctest test for %s\n' ' File "%s", line %s, in %s\n\n%s' % (test.name, test.filename, lineno, lname, err) ) def debug(self): r"""Run the test case without results and without catching exceptions The unit test framework includes a debug method on test cases and test suites to support post-mortem debugging. The test code is run in such a way that errors are not caught. This way a caller can catch the errors and initiate post-mortem debugging. The DocTestCase provides a debug method that raises UnexpectedException errors if there is an unexepcted exception: >>> test = DocTestParser().get_doctest('>>> raise KeyError\n42', ... {}, 'foo', 'foo.py', 0) >>> case = DocTestCase(test) >>> try: ... case.debug() ... except UnexpectedException, failure: ... pass The UnexpectedException contains the test, the example, and the original exception: >>> failure.test is test True >>> failure.example.want '42\n' >>> exc_info = failure.exc_info >>> raise exc_info[0], exc_info[1], exc_info[2] Traceback (most recent call last): ... KeyError If the output doesn't match, then a DocTestFailure is raised: >>> test = DocTestParser().get_doctest(''' ... >>> x = 1 ... >>> x ... 2 ... ''', {}, 'foo', 'foo.py', 0) >>> case = DocTestCase(test) >>> try: ... case.debug() ... except DocTestFailure, failure: ... pass DocTestFailure objects provide access to the test: >>> failure.test is test True As well as to the example: >>> failure.example.want '2\n' and the actual output: >>> failure.got '1\n' """ self.setUp() runner = DebugRunner(optionflags=self._dt_optionflags, checker=self._dt_checker, verbose=False) runner.run(self._dt_test) self.tearDown() def id(self): return self._dt_test.name def __repr__(self): name = self._dt_test.name.split('.') return "%s (%s)" % (name[-1], '.'.join(name[:-1])) __str__ = __repr__ def shortDescription(self): return "Doctest: " + self._dt_test.name def DocTestSuite(module=None, globs=None, extraglobs=None, test_finder=None, **options): """ Convert doctest tests for a module to a unittest test suite. This converts each documentation string in a module that contains doctest tests to a unittest test case. If any of the tests in a doc string fail, then the test case fails. An exception is raised showing the name of the file containing the test and a (sometimes approximate) line number. The `module` argument provides the module to be tested. The argument can be either a module or a module name. If no argument is given, the calling module is used. A number of options may be provided as keyword arguments: setUp A set-up function. This is called before running the tests in each file. The setUp function will be passed a DocTest object. The setUp function can access the test globals as the globs attribute of the test passed. tearDown A tear-down function. This is called after running the tests in each file. The tearDown function will be passed a DocTest object. The tearDown function can access the test globals as the globs attribute of the test passed. globs A dictionary containing initial global variables for the tests. optionflags A set of doctest option flags expressed as an integer. """ if test_finder is None: test_finder = DocTestFinder() module = _normalize_module(module) tests = test_finder.find(module, globs=globs, extraglobs=extraglobs) if globs is None: globs = module.__dict__ if not tests: # Why do we want to do this? Because it reveals a bug that might # otherwise be hidden. raise ValueError(module, "has no tests") tests.sort() suite = unittest.TestSuite() for test in tests: if len(test.examples) == 0: continue if not test.filename: filename = module.__file__ if filename[-4:] in (".pyc", ".pyo"): filename = filename[:-1] test.filename = filename suite.addTest(DocTestCase(test, **options)) return suite class DocFileCase(DocTestCase): def id(self): return '_'.join(self._dt_test.name.split('.')) def __repr__(self): return self._dt_test.filename __str__ = __repr__ def format_failure(self, err): return ('Failed doctest test for %s\n File "%s", line 0\n\n%s' % (self._dt_test.name, self._dt_test.filename, err) ) def DocFileTest(path, module_relative=True, package=None, globs=None, parser=DocTestParser(), **options): if globs is None: globs = {} if package and not module_relative: raise ValueError("Package may only be specified for module-" "relative paths.") # Relativize the path. if module_relative: package = _normalize_module(package) path = _module_relative_path(package, path) # Find the file and read it. name = os.path.basename(path) doc = open(path).read() # Convert it to a test, and wrap it in a DocFileCase. test = parser.get_doctest(doc, globs, name, path, 0) return DocFileCase(test, **options) def DocFileSuite(*paths, **kw): """A unittest suite for one or more doctest files. The path to each doctest file is given as a string; the interpretation of that string depends on the keyword argument "module_relative". A number of options may be provided as keyword arguments: module_relative If "module_relative" is True, then the given file paths are interpreted as os-independent module-relative paths. By default, these paths are relative to the calling module's directory; but if the "package" argument is specified, then they are relative to that package. To ensure os-independence, "filename" should use "/" characters to separate path segments, and may not be an absolute path (i.e., it may not begin with "/"). If "module_relative" is False, then the given file paths are interpreted as os-specific paths. These paths may be absolute or relative (to the current working directory). package A Python package or the name of a Python package whose directory should be used as the base directory for module relative paths. If "package" is not specified, then the calling module's directory is used as the base directory for module relative filenames. It is an error to specify "package" if "module_relative" is False. setUp A set-up function. This is called before running the tests in each file. The setUp function will be passed a DocTest object. The setUp function can access the test globals as the globs attribute of the test passed. tearDown A tear-down function. This is called after running the tests in each file. The tearDown function will be passed a DocTest object. The tearDown function can access the test globals as the globs attribute of the test passed. globs A dictionary containing initial global variables for the tests. optionflags A set of doctest option flags expressed as an integer. parser A DocTestParser (or subclass) that should be used to extract tests from the files. """ suite = unittest.TestSuite() # We do this here so that _normalize_module is called at the right # level. If it were called in DocFileTest, then this function # would be the caller and we might guess the package incorrectly. if kw.get('module_relative', True): kw['package'] = _normalize_module(kw.get('package')) for path in paths: suite.addTest(DocFileTest(path, **kw)) return suite ###################################################################### ## 9. Debugging Support ###################################################################### def script_from_examples(s): r"""Extract script from text with examples. Converts text with examples to a Python script. Example input is converted to regular code. Example output and all other words are converted to comments: >>> text = ''' ... Here are examples of simple math. ... ... Python has super accurate integer addition ... ... >>> 2 + 2 ... 5 ... ... And very friendly error messages: ... ... >>> 1/0 ... To Infinity ... And ... Beyond ... ... You can use logic if you want: ... ... >>> if 0: ... ... blah ... ... blah ... ... ... ... Ho hum ... ''' >>> print script_from_examples(text) # Here are examples of simple math. # # Python has super accurate integer addition # 2 + 2 # Expected: ## 5 # # And very friendly error messages: # 1/0 # Expected: ## To Infinity ## And ## Beyond # # You can use logic if you want: # if 0: blah blah # # Ho hum """ output = [] for piece in DocTestParser().parse(s): if isinstance(piece, Example): # Add the example's source code (strip trailing NL) output.append(piece.source[:-1]) # Add the expected output: want = piece.want if want: output.append('# Expected:') output += ['## '+l for l in want.split('\n')[:-1]] else: # Add non-example text. output += [_comment_line(l) for l in piece.split('\n')[:-1]] # Trim junk on both ends. while output and output[-1] == '#': output.pop() while output and output[0] == '#': output.pop(0) # Combine the output, and return it. return '\n'.join(output) def testsource(module, name): """Extract the test sources from a doctest docstring as a script. Provide the module (or dotted name of the module) containing the test to be debugged and the name (within the module) of the object with the doc string with tests to be debugged. """ module = _normalize_module(module) tests = DocTestFinder().find(module) test = [t for t in tests if t.name == name] if not test: raise ValueError(name, "not found in tests") test = test[0] testsrc = script_from_examples(test.docstring) return testsrc def debug_src(src, pm=False, globs=None): """Debug a single doctest docstring, in argument `src`'""" testsrc = script_from_examples(src) debug_script(testsrc, pm, globs) def debug_script(src, pm=False, globs=None): "Debug a test script. `src` is the script, as a string." import pdb # Note that tempfile.NameTemporaryFile() cannot be used. As the # docs say, a file so created cannot be opened by name a second time # on modern Windows boxes, and execfile() needs to open it. srcfilename = tempfile.mktemp(".py", "doctestdebug") f = open(srcfilename, 'w') f.write(src) f.close() try: if globs: globs = globs.copy() else: globs = {} if pm: try: execfile(srcfilename, globs, globs) except: print sys.exc_info()[1] pdb.post_mortem(sys.exc_info()[2]) else: # Note that %r is vital here. '%s' instead can, e.g., cause # backslashes to get treated as metacharacters on Windows. pdb.run("execfile(%r)" % srcfilename, globs, globs) finally: os.remove(srcfilename) def debug(module, name, pm=False): """Debug a single doctest docstring. Provide the module (or dotted name of the module) containing the test to be debugged and the name (within the module) of the object with the docstring with tests to be debugged. """ module = _normalize_module(module) testsrc = testsource(module, name) debug_script(testsrc, pm, module.__dict__) ###################################################################### ## 10. Example Usage ###################################################################### class _TestClass: """ A pointless class, for sanity-checking of docstring testing. Methods: square() get() >>> _TestClass(13).get() + _TestClass(-12).get() 1 >>> hex(_TestClass(13).square().get()) '0xa9' """ def __init__(self, val): """val -> _TestClass object with associated value val. >>> t = _TestClass(123) >>> print t.get() 123 """ self.val = val def square(self): """square() -> square TestClass's associated value >>> _TestClass(13).square().get() 169 """ self.val = self.val ** 2 return self def get(self): """get() -> return TestClass's associated value. >>> x = _TestClass(-42) >>> print x.get() -42 """ return self.val __test__ = {"_TestClass": _TestClass, "string": r""" Example of a string object, searched as-is. >>> x = 1; y = 2 >>> x + y, x * y (3, 2) """, "bool-int equivalence": r""" In 2.2, boolean expressions displayed 0 or 1. By default, we still accept them. This can be disabled by passing DONT_ACCEPT_TRUE_FOR_1 to the new optionflags argument. >>> 4 == 4 1 >>> 4 == 4 True >>> 4 > 4 0 >>> 4 > 4 False """, "blank lines": r""" Blank lines can be marked with : >>> print 'foo\n\nbar\n' foo bar """, "ellipsis": r""" If the ellipsis flag is used, then '...' can be used to elide substrings in the desired output: >>> print range(1000) #doctest: +ELLIPSIS [0, 1, 2, ..., 999] """, "whitespace normalization": r""" If the whitespace normalization flag is used, then differences in whitespace are ignored. >>> print range(30) #doctest: +NORMALIZE_WHITESPACE [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29] """, } def _test(): r = unittest.TextTestRunner() r.run(DocTestSuite()) if __name__ == "__main__": _test() PK:8ʳLLdispatch/tests/test_parsing.pyc; ^Gc@sdZdklZlZlZdkTdkTdkTdkTdk Tdkl Z dk Z dk Z dk Z dkZe i ZdfdYZeZdZdefd YZd efd YZd efd YZeeefZdZdS(s)Test generic functions expression parsing(sTestCases makeSuites TestSuite(s*(s predicatesNs StringBuildercBstZdZdZdZdZdZdZdZdZ dd Z d Z e d Z e d Z e d Ze dZe dZe dZe dZe dZe dZe dZe dZe dZe dZe dZe dZe dZe dZe dZe dZe dZe dZ e d Z!e d!Z"d"Z#d#Z$RS($s;Simple parse event receiver to test the AST build functionscCs|SdS(N(sname(sselfsname((s4build\bdist.win32\egg\dispatch\tests\test_parsing.pysNamescCst|SdS(N(sreprsconst(sselfsconst((s4build\bdist.win32\egg\dispatch\tests\test_parsing.pysConstscCsat||g}x7|D]/\}}|i||it||qWddi|SdS(Ns Compare(%s)s ( sbuildsselfsinitExprsdatas comparisonssopsvalsappendsjoin(sselfsinitExprs comparisonssvalsdatasop((s4build\bdist.win32\egg\dispatch\tests\test_parsing.pysCompares   cCsdt|||fSdS(NsGetattr(%s,%r)(sbuildsselfsleftsright(sselfsleftsright((s4build\bdist.win32\egg\dispatch\tests\test_parsing.pysGetattrsc CsXddigi}|D]2\}}|dt||t||fq~SdS(Ns{%s}s,s%s:%s(sjoinsappends_[1]sitemssksvsbuildsself(sselfsitemss_[1]svsk((s4build\bdist.win32\egg\dispatch\tests\test_parsing.pysDictscCs0dt||t||t||fSdS(NsSliceobj(%s,%s,%s)(sbuildsselfsstartsstopsstride(sselfsstartsstopsstride((s4build\bdist.win32\egg\dispatch\tests\test_parsing.pysSliceobj$scsd|d}|SdS(Ns %s(%%s,%%s)cs$t||t||fSdS(N(spatsbuildsselfsleftsright(sselfsleftsright(spat(s4build\bdist.win32\egg\dispatch\tests\test_parsing.pysmethod,s(sopspatsmethod(sopspatsmethod((spats4build\bdist.win32\egg\dispatch\tests\test_parsing.pysmkBinOp*s  s,csd}|SdS(Ncs?igi}|D]}|t||q~SdS(N( sfmtssepsjoinsappends_[1]sitemssitemsbuildsself(sselfsitemss_[1]sitem(ssepsfmt(s4build\bdist.win32\egg\dispatch\tests\test_parsing.pysmethod1s(smethod(sfmtssepsmethod((sfmtsseps4build\bdist.win32\egg\dispatch\tests\test_parsing.pysmultiOp0scsd}|SdS(Ncst||SdS(N(sfmtsbuildsselfsexpr(sselfsexpr(sfmt(s4build\bdist.win32\egg\dispatch\tests\test_parsing.pysmethod6s(smethod(sfmtsmethod((sfmts4build\bdist.win32\egg\dispatch\tests\test_parsing.pysunaryOp5s sPlus(%s)s Minus(%s)s Invert(%s)srepr(%s)sNot(%s)sAnd(%s)sOr(%s)s Tuple(%s)sList(%s)s Bitor(%s)s Bitxor(%s)s Bitand(%s)s LeftShiftsPowers RightShiftsAddsSubsMulsDivsModsFloorDivsSlicesGetitemcCsv|ot||}nd}|ot||}nd}dt|||i||i|||fSdS(NsNonesCall(%s,%s,%s,%s,%s)( s star_nodesbuildsselfs dstar_nodesfuncsTuplesargssDictskw(sselfsfuncsargsskws star_nodes dstar_node((s4build\bdist.win32\egg\dispatch\tests\test_parsing.pysCallFuncSscCs0dt||t||t||fSdS(NsIfElse(%s,%s,%s)(sbuildsselfstrueVals conditionsfalseVal(sselfstrueVals conditionsfalseVal((s4build\bdist.win32\egg\dispatch\tests\test_parsing.pysIfElse`s(%s__name__s __module__s__doc__sNamesConstsComparesGetattrsDictsSliceobjsmkBinOpsmultiOpsunaryOps UnaryPluss UnaryMinussInverts BackquotesNotsAndsOrsTuplesListsBitorsBitxorsBitands LeftShiftsPowers RightShiftsAddsSubsMulsDivsModsFloorDivsSlices SubscriptsCallFuncsIfElse(((s4build\bdist.win32\egg\dispatch\tests\test_parsing.pys StringBuilder sF                                  cCs t|tS(N(s parse_exprssssb(ss((s4build\bdist.win32\egg\dispatch\tests\test_parsing.pys}ss EventTestscBs|tZdZdZdZdZeidjo dZndZ dZ dZ d Z d Z d ZRS( sCTest that AST builder supports all syntax and issues correct eventscCsr|itdd|itdd|itdd|itdd|itdddS(Nsasbs123s'xyz's 'abc' 'xyz's'abcxyz'(sselfs assertEqualspe(sself((s4build\bdist.win32\egg\dispatch\tests\test_parsing.pys testTokenss cCs"|itdd|itdd|itdd|itdd|itd d |itd d |itd d|itdd|itdd|itdd|itdd|itdd|itdddS(Nsa+bsAdd(a,b)sb-asSub(b,a)sc*dsMul(c,d)sc/dsDiv(c,d)sc%dsMod(c,d)sc//ds FloorDiv(c,d)sa<>bsRightShift(a,b)sa**bs Power(a,b)sa.bsGetattr(a,'b')sa|bs Bitor(a,b)sa&bs Bitand(a,b)sa^bs Bitxor(a,b)(sselfs assertEqualspe(sself((s4build\bdist.win32\egg\dispatch\tests\test_parsing.pystestSimpleBinariesscCsr|itdd|itdd|itdd|itdd|itd d dS( Ns~as Invert(a)s+asPlus(a)s-asMinus(a)snot asNot(a)s`a`srepr(a)(sselfs assertEqualspe(sself((s4build\bdist.win32\egg\dispatch\tests\test_parsing.pystestSimpleUnariess s2.5cCs|itdddS(Ns a if b else cs IfElse(a,b,c)(sselfs assertEqualspe(sself((s4build\bdist.win32\egg\dispatch\tests\test_parsing.pys testIfElsescCs*|itdd|itdd|itdd|itdd|itdd |itd d |itd d|itd d|itdd|itdd|itdd|itdd|itdd|itdd|itdd|itdd|itdd|itdd|itdd|itdd|itdd|itdd|itd d |itd!d |itd"d#dS($Nsa,sTuple(a)sa,bs Tuple(a,b)sa,b,cs Tuple(a,b,c)sa,b,c,s()sTuple()s(a)sas(a,)s(a,b)s(a,b,)s(a,b,c)s(a,b,c,)s[]sList()s[a]sList(a)s[a,]s[a,b]s List(a,b)s[a,b,]s[a,b,c]s List(a,b,c)s[a,b,c,]s{}s{a:b}s{a:b,}s {a:b,c:d}s {a:b,c:d,1:2}s{a:b,c:d,1:2,}s{(a,b):c+d,e:[f,g]}s!{Tuple(a,b):Add(c,d),e:List(f,g)}(sselfs assertEqualspe(sself((s4build\bdist.win32\egg\dispatch\tests\test_parsing.pys testSequencess4cCs|itdd|itdd|itdd|itdd|itdd |itd d |itd d |itdd|itdd|itdd|itdd|itdd|itdd|itdd|itdd|itdd|itd d!|ittd"|ittd#dS($Nsa()sCall(a,Tuple(),{},None,None)sa(1,2)sCall(a,Tuple(1,2),{},None,None)sa(1,2,)sa(b=3)s!Call(a,Tuple(),{'b':3},None,None)s a(1,2,b=3)s$Call(a,Tuple(1,2),{'b':3},None,None)sa(*x)sCall(a,Tuple(),{},x,None)sa(1,*x)sCall(a,Tuple(1),{},x,None)s a(b=3,*x)sCall(a,Tuple(),{'b':3},x,None)s a(1,2,b=3,*x)s!Call(a,Tuple(1,2),{'b':3},x,None)sa(**y)sCall(a,Tuple(),{},None,y)sa(1,**y)sCall(a,Tuple(1),{},None,y)s a(b=3,**y)sCall(a,Tuple(),{'b':3},None,y)sa(1,2,b=3,**y)s!Call(a,Tuple(1,2),{'b':3},None,y)s a(*x,**y)sCall(a,Tuple(),{},x,y)s a(1,*x,**y)sCall(a,Tuple(1),{},x,y)s a(b=3,*x,**y)sCall(a,Tuple(),{'b':3},x,y)sa(1,2,b=3,*x,**y)sCall(a,Tuple(1,2),{'b':3},x,y)sa(1=2)sa(b=2,c)(sselfs assertEqualspes assertRaisess SyntaxError(sself((s4build\bdist.win32\egg\dispatch\tests\test_parsing.pys testCallss.cCsV|itdd|itdd|itdd|itddt|itd d |itd d t|itd d|itdd|itdd|itdd|itdd|itdd|itdd|itdd|itdddS(Nsa[1]s Getitem(a,1)sa[2,3]sGetitem(a,Tuple(2,3))sa[...]sGetitem(a,Ellipsis)sa[:]sGetitem(a,Slice(0,%s))sa[1:2]sGetitem(a,Slice(1,2))sa[1:]sGetitem(a,Slice(1,%s))sa[:2]sGetitem(a,Slice(0,2))sa[::]s#Getitem(a,Sliceobj(None,None,None))sa[1::]s Getitem(a,Sliceobj(1,None,None))sa[:2:]s Getitem(a,Sliceobj(None,2,None))sa[1:2:]sGetitem(a,Sliceobj(1,2,None))sa[::3]s Getitem(a,Sliceobj(None,None,3))sa[1::3]sGetitem(a,Sliceobj(1,None,3))sa[:2:3]sGetitem(a,Sliceobj(None,2,3))sa[1:2:3]sGetitem(a,Sliceobj(1,2,3))(sselfs assertEqualspesMAXINT(sself((s4build\bdist.win32\egg\dispatch\tests\test_parsing.pystestSubscriptsscCs`|itdd|itdd|itdd|itdd|itd d |itd d |itd d|itdd|itdd|itdd|itddtt_|itdd|itddtt_|itdd|itdddS(Nsa>bsCompare(a > b)sa>=bsCompare(a >= b)sabsCompare(a <> b)sa!=bsCompare(a != b)sa==bsCompare(a == b)sa in bsCompare(a in b)sa is bsCompare(a is b)s a not in bsCompare(a not in b)s a is not bsCompare(a is not b)s1<2<3s"And(Compare(1 < 2),Compare(2 < 3))sa>=b>c= b),Compare(b > c),Compare(c < d))sCompare(1 < 2 < 3)sCompare(a >= b > c < d)(sselfs assertEqualspesTruessbssimplify_comparisonssFalse(sself((s4build\bdist.win32\egg\dispatch\tests\test_parsing.pys testCompare s$  cCs |itdd|itdd|itdd|itdd|itd d |itd d |itd d|itdd|itdd|itdd|itdd|itdddS(Nsa and bsAnd(a,b)sa or bsOr(a,b)s a and b and cs And(a,b,c)s a or b or cs Or(a,b,c)sa and b and c and ds And(a,b,c,d)sa or b or c or ds Or(a,b,c,d)sa&b&cs Bitand(a,b,c)sa|b|cs Bitor(a,b,c)sa^b^cs Bitxor(a,b,c)sa&b&c&dsBitand(a,b,c,d)sa|b|c|dsBitor(a,b,c,d)sa^b^c^dsBitxor(a,b,c,d)(sselfs assertEqualspe(sself((s4build\bdist.win32\egg\dispatch\tests\test_parsing.pys testMultiOps scCs |itdd|itdd|itdd|itdd|itd d |itd d |itd d|itdd|itdd|itdd|itdd|itdddS(Nsa+b+csAdd(Add(a,b),c)sa*b*csMul(Mul(a,b),c)sa/b/csDiv(Div(a,b),c)sa//b//csFloorDiv(FloorDiv(a,b),c)sa%b%csMod(Mod(a,b),c)sa<>b>>csRightShift(RightShift(a,b),c)sa.b.csGetattr(Getattr(a,'b'),'c')sa()()s7Call(Call(a,Tuple(),{},None,None),Tuple(),{},None,None)sa[b][c]sGetitem(Getitem(a,b),c)sa**b**csPower(a,Power(b,c))s5*x**2 + 4*x + -1s-Add(Add(Mul(5,Power(x,2)),Mul(4,x)),Minus(1))(sselfs assertEqualspe(sself((s4build\bdist.win32\egg\dispatch\tests\test_parsing.pystestAssociativity1s(s__name__s __module__s__doc__s testTokensstestSimpleBinariesstestSimpleUnariesssyssversions testIfElses testSequencess testCallsstestSubscriptss testCompares testMultiOpsstestAssociativity(((s4build\bdist.win32\egg\dispatch\tests\test_parsing.pys EventTestss      ) )   sExprBuilderTestscBstZdZdZdZdZdZeidjo dZ ndZ dZ d Z d Z d Zd Zd ZdZdZRS(sDTest that expression builder builds correct IDispatchableExpressionscCsytgi}dD]}||td|fq~|_}ttt f|_ }t |||_ }dS(Nsabcdefgsname( sdictsappends_[1]snsArgumentsselfs argumentsslocalssglobalss __builtins__s namespacess ExprBuildersbuilder(sselfsns_[1]s argumentss namespacessbuilder((s4build\bdist.win32\egg\dispatch\tests\test_parsing.pyssetUpMsCcCst||iSdS(N(s parse_exprsexprsselfsbuilder(sselfsexpr((s4build\bdist.win32\egg\dispatch\tests\test_parsing.pysparseTscCsLt|i_x9|D]1\}}|i|ii|t ||qWdS(N( sTruesselfsbuilders bind_globalssitemssnamesvals assertEqualsNamesConst(sselfsitemssnamesval((s4build\bdist.win32\egg\dispatch\tests\test_parsing.pyscheckConstOrVarWs  cCs|i|iidtdx3|iD](}|i|i|td|q,W|i|idtd|i|idtd|i|idtddS(Ni{snames123s'xyz'sxyzs 'abc' 'xyz'sabcxyz(sselfs assertEqualsbuildersConsts argumentssargsparsesArgument(sselfsarg((s4build\bdist.win32\egg\dispatch\tests\test_parsing.pys testTokens_s" &s2.5cCs\tddtddtddf\}}}|i|idt|||dS(Nsnamesasbscs a if b else c(sArgumentsasbscsselfs assertEqualsparsesIfElse(sselfsascsb((s4build\bdist.win32\egg\dispatch\tests\test_parsing.pys testIfElsehs3cCs|i}tddtddtddf\}}}|i|dtt i |||i|dtt i |||i|dtt i |||i|dtt i |||i|d tt i|||i|d tt i|||i|d tt i|||i|d tt i|||i|d tt|||i|dt|d|i|dtt i|||i|dtt i|||i|dtt i|||i|dtt i||i|dtt i||i|dtt i||i|dtt i||i|dtt||i|dt|||i|dt||dS(Nsnamesasbscsa+bsa-bsb*csb/csb%csb//csa<>bsa**bsa.bsa|bsa&bsa^bs~as+as-asnot as`a`sa and bsa or b(sselfsparsespesArgumentsasbscs assertEqualsCallsoperatorsaddssubsmulsdivsmodsfloordivslshiftsrshiftspowsGetattrsor_sand_sxorsinvertspossnegsnot_sreprsAndExprsOrExpr(sselfsascsbspe((s4build\bdist.win32\egg\dispatch\tests\test_parsing.pystestSimpleBinariesAndUnariesrs, 3%%%%%%%%"%%%""""cCs|i}|i|dtd|i|dtd|i|dtd|i|dtd|i|d td|i|d td |i|d td |i|dtd|i|dtd|i|dtt|i|dtd|i|dtd|i|dtd|i|dtd|i|dtd|i|dtd|i|dtt|i|dtd|i|dtdd f|i|dtdd g|i|d thdd <|i|d!td |i|d"td#|i|d$td%tid&jo<|i|d'td|i|d(tdndS()Ns1+2is2-1is7*9i?s25/10.0f2.5s25%3s25//10.0is16<<4is256>>4is2**4sdict.__class__s1|5is5&1s1^2s~1is+1s-1isnot Trues`27`s27s1,2s[1,2]s{1:2}s1 and 2s"" and 2ss"" or 53 or 27i5s2.5s 1 if 2 else 3s1 if not 2 else 3( sselfsparsespes assertEqualsConststypesFalsessyssversion(sselfspe((s4build\bdist.win32\egg\dispatch\tests\test_parsing.pystestConstantFoldings8 ""%c Cs=|i} tddtddtddf\}}}tddtddtddf\}}}tdd}|i | d t t ||i | d t t |||i | d t t ||||i | d t t ||||i | d t t |i | d||i | dt t ||i | dt t |||i | dt t |||i | dt t ||||i | dt t ||||i | dt t|i | dt t||i | dt t||i | dt t|||i | dt t|||i | dt t||||i | dt t|||d}|i | d|ff|i | d||g|g|i | d||g|g|i | d|||g||g|i | d |||td!g||td"g|i | d#|||td!g||td"g|i | d$|t t |||gtti||t t||gdS(%Nsnamesasbscsdsesfsgsa,sa,bsa,b,csa,b,c,s()s(a)s(a,)s(a,b)s(a,b,)s(a,b,c)s(a,b,c,)s[]s[a]s[a,]s[a,b]s[a,b,]s[a,b,c]s[a,b,c,]cCs+tttttt|tt|S(N(sCallsdictszipsTuplestuplesksv(sksv((s4build\bdist.win32\egg\dispatch\tests\test_parsing.pysss{}s{a:b}s{a:b,}s {a:b,c:d}s {a:b,c:d,1:2}iis{a:b,c:d,1:2,}s{(a,b):c+d,e:[f,g]}(sselfsparsespesArgumentsasbscsdsesfsgs assertEqualsTuplestupleslistsmdsConstsCallsoperatorsadd( sselfsasmdscsbsesdsgsfspe((s4build\bdist.win32\egg\dispatch\tests\test_parsing.pys testSequencess> 33"%%""%%""%% %%+==c Cs|i}t|iid\}}}}d}t ddf}t hdd<}t f} |i|dtt||i|dtt|i|d tt||i|d tt|||i|d tt|||i|d tt|| ||i|d tt||||i|dtt|||i|dtt|tti|tt||i|dtt||||i|dtt|tti|tt|||i|dtt|t f||i|dtt||||i|dtt|t ftti|||i|dtt||tti|||i|dtt||tti|||i|dtt|tti|tt|tti|||i|dtt||||i|dtt|tti|tt||dS(NsabcdcCs+tttttt|tt|S(N(sCallsdictszipsTuplestuplesksv(sksv((s4build\bdist.win32\egg\dispatch\tests\test_parsing.pyssiisbisa()sdict()sint(a)sa(1,2)sa(1,2,)sa(b=3)s a(1,2,b=3)sa(*b)s a(1,2,*b)s a(b=3,*c)s a(1,2,b=3,*c)sa(**c)s a(1,2,**c)s a(b=3,**c)sa(1,2,b=3,**c)s a(b=3,*c,**d)sa(1,2,b=3,*c,**d)s a(*c,**d)s a(1,2,*c,**d)(sselfsparsespesmaps argumentss __getitem__sasbscsdsmdsConstsone_twosb_threesemptys assertEqualsCallsapplysdictsintsoperatorsaddstuples predicatessadd_dict( sselfsascsbsdsmdsone_twospesb_threesempty((s4build\bdist.win32\egg\dispatch\tests\test_parsing.pys testCallssB !  ""%%"+%.+%+%%$%cCsy|i}tddtddtddf\}}}tdd}|i|dt ||||i|dt ||||i|dt |||||i|d t |||||i|d t t i t t i ||||i|d t t it t i||||i|d t t it t i|||dS( Nsnamesasbscsds a and b and cs a or b or csa and b and c and dsa or b or c or dsa&b&csa|b|csa^b^c(sselfsparsespesArgumentsasbscsds assertEqualsAndExprsOrExprsCallsoperatorsand_sor_sxor(sselfsascsbsdspe((s4build\bdist.win32\egg\dispatch\tests\test_parsing.pys testMultiOps#s 3""%%%%c s|i}tddtddtddf\}}}dd}d}|i |d|t d |i |d |t t t d t d |i |d |t t|i |d||t dt ti|i |d||t d t d |i |d||t d t ti|i |d||t dt d |i |d||ttt|i |d||d tt|i |d||td t|i |d||d d t|i |d||ttd |i |d||d td |i |d||td d |i |d||d d d dS(NsnamesasbsccCstti||S(N(sCallsoperatorsgetitemsobskey(sobskey((s4build\bdist.win32\egg\dispatch\tests\test_parsing.pysCscCstti|||S(N(sCallsoperatorsgetslicesobsstartsstop(sobsstartsstop((s4build\bdist.win32\egg\dispatch\tests\test_parsing.pysDscs|tttt|S(N(sgisobsCallsslicesmapsConstsx(sobsx(sgi(s4build\bdist.win32\egg\dispatch\tests\test_parsing.pysEssa[1]isa[2,3]iisa[...]sa[:]isa[1:2]sa[1:]sa[:2]sa[::]sa[1::]sa[:2:]sa[1:2:]sa[::3]sa[1::3]sa[:2:3]sa[1:2:3](sselfsparsespesArgumentsasbscsgisgssgsos assertEqualsConstsTuplestuplesEllipsisssyssmaxintsNone(sselfsascsbsgssgsospesgi((sgis4build\bdist.win32\egg\dispatch\tests\test_parsing.pystestSubscripts?s( 3   %7%1.1.%%%%%%%c CsQ|i}tddtddtddf\}}}tdd}|i|dt t i |||i|dt t i |||i|dt t i |||i|d t t i|||i|d t t i|||i|d t t i|||i|d t t i|||i|d t ti|||i|dt ti|||i|dt ti|||i|dt ti|||i|dtt|i|dtt t i ||t t i ||t t i ||dS(Nsnamesasbscsdsa>bsa>=bsabsa!=bsa==bsa in bsa is bs a not in bs a is not bs1<2<3sa>=b>ctZdZdZdZdZdZdZRS(Ncs*tdid} td} tddtddf\xddd d d fddd d dfdddddfdddddfgD]\} }}}}t dt| d}|i| d| ||i| d||t dt|d}|i| d|||i| d| |t dt|d}|i| d| ||i| d|||i| d| | ||i| d|| ||i| d| | |t|i| d|| |tqWdS(NcCstS(N(sNone(sxsysz((s4build\bdist.win32\egg\dispatch\tests\test_parsing.pysscs|ttS(N(sparseseslocalssglobals(se(sparse(s4build\bdist.win32\egg\dispatch\tests\test_parsing.pysscs.tttt|t|fgS(N( s SignaturesCallsgetattrsoperatorsnsxsysTruthCriterionst(snst(sysx(s4build\bdist.win32\egg\dispatch\tests\test_parsing.pysssnamesxsys>s=sltsges==s!=seqsnes<>isx %s 1s1 %s xs not x %s 1sx %s ys not x %s y(sGenericFunctionsparsespesTruesx_cmp_ysArgumentsxsysops mirror_opsnot_opsnamesnot_names Signatures Inequalitysfwd_sigsselfs assertEqualsrev_sigsnot_sigsFalse(sselfsnamesnot_sigsnot_opsfwd_sigsparses mirror_opsrev_sigsnot_namesx_cmp_yspesysxsop((sparsesysxs4build\bdist.win32\egg\dispatch\tests\test_parsing.pystestParseInequalitiess& $O  #c sotdid}|i|dtdt|i|dtdtt|i|dti t dddd d gt |i|d ti t dddd d gt |i|d tt tit ddt dd tfg|i|dtt tit ddt dd tfg|i|dtt ddtttfg|i|dtt ddtttfg|i|dtdti|i|dtdtti|i|dtdti|i|dtdttidS(NcCstS(N(sNone(sxsysz((s4build\bdist.win32\egg\dispatch\tests\test_parsing.pysscs|ttS(N(sparseseslocalssglobals(se(sparse(s4build\bdist.win32\egg\dispatch\tests\test_parsing.pysssx in intsxs x not in ints x in (1,2,3)snameiiisx not in (1,2,3)sx is ysys x is not ys x is TestCasesx is not TestCases x is Nones x is not Nonesnot (x is not None)snot (x is None)(sGenericFunctionsparsespesselfs assertEquals Signaturesints NotCriterions predicatess compileInsArgumentsTruesFalsesCallsis_sTruthCriterionsis_nots ICriterionsPointersTestCasestypessNoneType(sselfspesparse((sparses4build\bdist.win32\egg\dispatch\tests\test_parsing.pystestParseMemberships0 %((""+,""c stdid}|i|dtdt|i|dtdttdtB|i|dtdttdtBtdtB|i|dtdt tt t@t t@|i|dtdt t|i|d tdt ttdt tB|i|d tdt ttdt tBtdt tB|i|d tdt gi }tttfD]}|t |q~dS( NcCstS(N(sNone(sxsysz((s4build\bdist.win32\egg\dispatch\tests\test_parsing.pys scs|ttS(N(sparseseslocalssglobals(se(sparse(s4build\bdist.win32\egg\dispatch\tests\test_parsing.pysssisinstance(x,int)sxsisinstance(x,(str,unicode))s!isinstance(x,(int,(str,unicode)))s%not isinstance(x,(int,(str,unicode)))sissubclass(x,int)sissubclass(x,(str,unicode))s!issubclass(x,(int,(str,unicode)))s%not issubclass(x,(int,(str,unicode)))(sGenericFunctionsparsespesselfs assertEquals Signaturesintsstrsunicodes ICriterionsSubclassCriterions AndCriterionsappends_[1]sx(sselfs_[1]spesparsesx((sparses4build\bdist.win32\egg\dispatch\tests\test_parsing.pystestParseExpressionMatching s  *-%)<c Cs+tdd}ti|dddgt}ti|dddgt}|i t |t |i t |t |i |t gi}dddfD]"}|t dtd|q~|i |t |ttigi}dddfD]}|td|q~fgdS(Nsnamesxiiis==s<>(sArgumentsxs predicatess compileInsTruesin_exprsFalsesnot_insselfs failUnlesss isinstances Signatures Predicates assertEqualsappends_[1]svs Inequalitysreducesoperatorsand_(sselfsnot_insvs_[1]sxsin_expr((s4build\bdist.win32\egg\dispatch\tests\test_parsing.pys testCompileIn5s I cstdid}|i|dtdtdt|i|dttdttdtg|i|dtdt tdt t|i|dttdt ttdt tg|i|d tdtdt|i|d ttdttdtg|i|d ttdtdttd tgdS( NcCstS(N(sNone(sxsysz((s4build\bdist.win32\egg\dispatch\tests\test_parsing.pys`scs|ttS(N(sparseseslocalssglobals(se(sparse(s4build\bdist.win32\egg\dispatch\tests\test_parsing.pysassx in int and y in strsxsysx in int or y in strsnot(x in int or y in str)snot( x in int and y in str)s!not(x not in int or y not in str)s#not( x not in int and y not in str)s!x in int and y in int or z in strsz( sGenericFunctionsparsespesselfs assertEquals Signaturesintsstrs Predicates NotCriterion(sselfspesparse((sparses4build\bdist.win32\egg\dispatch\tests\test_parsing.pys testParseDNF^s %4"@%4cCstigd}d}||dd||dd||dd||d d ||d d ||d d||dd|i|dd|i|dd|i|dd|i|dd|i|dd|i|dd|i|dd|i|dd|i|dd|i|d d!|i|d"d|i|d#d|i|td|i|tddS($NcCsdS(sStereotype for ageN((sage((s4build\bdist.win32\egg\dispatch\tests\test_parsing.pysclassifyscCs)|i|i|tt|dS(N(sgfs addMethodsparsessslocalssglobalssfunc(sgfsssfunc((s4build\bdist.win32\egg\dispatch\tests\test_parsing.pys defmethodss not not age<2cCsdS(Nsinfant((sage((s4build\bdist.win32\egg\dispatch\tests\test_parsing.pysssage<13cCsdS(Nspreteen((sage((s4build\bdist.win32\egg\dispatch\tests\test_parsing.pysssage<5cCsdS(Ns preschooler((sage((s4build\bdist.win32\egg\dispatch\tests\test_parsing.pysss20>agecCsdS(Nsteenager((sage((s4build\bdist.win32\egg\dispatch\tests\test_parsing.pysss not age<20cCsdS(Nsadult((sage((s4build\bdist.win32\egg\dispatch\tests\test_parsing.pysssage>=55cCsdS(Nssenior((sage((s4build\bdist.win32\egg\dispatch\tests\test_parsing.pysssage==16cCsdS(Ns sweet sixteen((sage((s4build\bdist.win32\egg\dispatch\tests\test_parsing.pyssisadultisteenageri f12.99spreteenisinfantis preschooleri7sseniorf54.899999999999999f14.5is sweet sixteenf16.5ic(sdispatchsgenericsclassifys defmethodsselfs assertEqualsMinsMax(sselfs defmethodsclassify((s4build\bdist.win32\egg\dispatch\tests\test_parsing.pystestSimplePredss0   (s__name__s __module__stestParseInequalitiesstestParseMembershipstestParseExpressionMatchings testCompileIns testParseDNFstestSimplePreds(((s4build\bdist.win32\egg\dispatch\tests\test_parsing.pysPredicateTestss  ' ) ) ) )cCs;g}x$tD]}|it|dq Wt|SdS(Nstest(sss TestClassesstsappends makeSuites TestSuite(ssst((s4build\bdist.win32\egg\dispatch\tests\test_parsing.pys test_suites (s__doc__sunittestsTestCases makeSuites TestSuitesdispatchsdispatch.functionssdispatch.predicatessdispatch.strategysdispatch.ast_builders predicatessoperatorssysstypessmaxintsMAXINTs StringBuilderssbspes EventTestssExprBuilderTestssPredicateTestss TestClassess test_suite(s TestSuites TestClassess EventTestss StringBuilders makeSuitesPredicateTestssdispatchsTestCasesoperatorsMAXINTssyssExprBuilderTestsspes predicatesssbs test_suitestypes((s4build\bdist.win32\egg\dispatch\tests\test_parsing.pys?s  $ q  rPK:8=Q|dispatch/tests/__init__.pyc; ^Gc@s&dklZlZlZdZdS((s TestSuitesTestCases makeSuitecCs9dkl}l}|i|ig}t|SdS(N(s test_dispatchs test_parsing(sdispatch.testss test_dispatchs test_parsings test_suitestestss TestSuite(s test_dispatchstestss test_parsing((s0build\bdist.win32\egg\dispatch\tests\__init__.pys test_suitesN(sunittests TestSuitesTestCases makeSuites test_suite(sTestCases TestSuites makeSuites test_suite((s0build\bdist.win32\egg\dispatch\tests\__init__.pys?sPK:84Is00 dispatch/tests/test_dispatch.pyc; ^Gc@s{dZdklZlZlZdkZdkZdklZl Z dkl Z l Z dk Z dk Z dk TdkTdkTdk lZlZlZdklZdk lZlZdkTd efd YZd efd YZd efdYZdefdYZdefdYZdefdYZdfdYZdfdYZ de efdYZ!deefdYZ"deefdYZ#de efd YZ$d!efd"YZ%d#efd$YZ&d%efd&YZ'd'efd(YZ(d)efd*YZ)d+efd,YZ*e&e'e(e)e*fZ+d-Z,d.Z-dS(/sTest generic functions(sTestCases makeSuites TestSuiteN(s ClassTypes InstanceType(smaxintsversion(s*(s InterfacesadvisesdeclareImplementation(sgetMRO(sstrategys functionssVehiclecBstZRS(N(s__name__s __module__(((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pysVehicless LandVehiclecBstZRS(N(s__name__s __module__(((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pys LandVehicless WaterVehiclecBstZRS(N(s__name__s __module__(((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pys WaterVehiclessWheeledcBstZRS(N(s__name__s __module__(((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pysWheeledss FourWheeledcBstZRS(N(s__name__s __module__(((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pys FourWheeledss TwoWheeledcBstZRS(N(s__name__s __module__(((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pys TwoWheeledss GasPoweredcBstZRS(N(s__name__s __module__(((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pys GasPoweredss HumanPoweredcBstZRS(N(s__name__s __module__(((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pys HumanPowered ssBicyclecBstZedegRS(NsinstancesProvide(s__name__s __module__sadvises TwoWheeled(((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pysBicycle#ssHummercBstZedegRS(NsinstancesProvide(s__name__s __module__sadvises FourWheeled(((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pysHummer$ss SpeedboatcBstZRS(N(s__name__s __module__(((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pys Speedboat%ss PaddleBoatcBstZRS(N(s__name__s __module__(((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pys PaddleBoat&ss RiverBoatcBstZedegRS(NsinstancesProvide(s__name__s __module__sadvises TwoWheeled(((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pys RiverBoat'ss TestGraphcBstZdZdZRS(Nc Csti}|i|ig|idd|i|iddfg|idd|i}|i|i|ddfddfddfgti}|i|ig|idd|i|iddfg|idd|i}|i|i|ddfddfddfg|idd|idd|i}|i|i|ddfddfddfddfddfddfgdS(Niiiii(sstrategysTGraphsgsselfs assertEqualsitemssaddssort(sselfsitemssg((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pys testItems,s" + + c Csti}|idd|i|idghdd<|i|idgh|i|idgh|idd|i|idghdd<dd<|i|idghdd<|i|iddghdd<dd<|i|idgh|idd|i|idddgh|i}|i|i|ddfddfddfddfddfddfddfddfddfg dS(Niii( sstrategysTGraphsgsaddsselfs assertEquals successorssitemsssort(sselfsitemssg((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pystestSuccessorsAs %.%1" (s__name__s __module__s testItemsstestSuccessors(((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pys TestGraph*s s CriteriaTestscBstZdZdZdZdZdZdZdZdZ d Z d Z d Z d Z d ZdZdZdZdZdZdZ dZdZdZdZdZdZdZdZdZdZdZRS(NcCs#tt}|it|j|it|j|it|j|it |j|it |j|it |jtt }tt }x:ttfD],}|i||j|i||jqWxIttttt t tfD],}|i||j|i||jqWdS(N(sISeededCriterions HumanPoweredshpsselfs failUnlesss PaddleBoatsBicyclesfailIfsVehicles SpeedboatsHummersobjects InstanceTypesitsobs GasPoweredsklasss LandVehicles WaterVehicle(sselfsobsitshpsklass((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pystestClassCriteriaMembershipUs"    cCs|ittit|ittit|ittit |ittit |itt it |ittit |ittit|ittit |itt it dS(N(sselfs failUnlesss ICriterionsBicyclesimpliessWheeleds PaddleBoats HumanPoweredsHummers FourWheeleds LandVehicles SpeedboatsVehiclesobjects GasPowereds InstanceTypesfailIf(sself((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pystestTestImplicationoscCsu|itti|ittj|ittj|itt i t|iti tdS(N( sselfsfailIfslists NullCriterionsseedss failUnlesssobjects Speedboats ICriterionsVehiclesimplies(sself((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pystestNullCriterion|s c CsxtttttfD]}tt|i}|i ||j|i t |j|i t |djt|titidgi}t|tD]}|t|q~qWdS(Nisparents(sVehicles LandVehicles WaterVehicles HumanPowereds GasPoweredsklassslistsISeededCriterionsseedssselfs failUnlesssobjectsfailIfslensvalidateCriterionsstrategysmake_node_typesdispatch_by_mrosappends_[1]sgetMROsTruesclss ICriterion(sselfs_[1]sseedssclssklass((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pys*testClassCriteriaSeedsAndDispatchFunctionsscCsz|itttj|ittit|ittit |it t tt i jdS(N(sselfs failUnlesssHummersISeededCriterionsWheeledsfailIfs ICriterionsimpliess Speedboats WaterVehiclesobjectslists InstanceTypesseeds(sself((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pystestCriterionAdaptationscCs|itttjttti}|it|j|it|j|it|j|it |djdtfdY}|i |ttjdS(Nis BrokenBikecBstZedegRS(NsinstancesDoNotProvide(s__name__s __module__sadvisesWheeled(((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pys BrokenBikes( sselfs failUnlesssBicyclesISeededCriterionsWheeledslistsseedssHummersobjectslens BrokenBikesfailIf(sselfs BrokenBikesseeds((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pystestProtocolCriterionsc Cstd} td} h| tt<| tt<}h| tt<| tt<}h| tt<| tt<}h| tt<| tt<}x||||fD]p} |itt| iitgi}| iD]%\} }|| |if|fq~qWt|i}t|i}t|i}t|i}tttttttf}|i|i||i |i||i|i||i |i||i |i||i |i||i |i||i |i||df|df|df|df|dfg} |it"| |df|df|df|dfg|it"|df|dfg|dfg|it#t$| |df|df|df|dfg|dfgg|it#t$|df|dfg|dfg|dfggdS(Nii(%sArgumentsa0sa1s ICriterions LandVehicles WaterVehiclesd1sHummers Speedboatsd2sd3sd4sdsselfs assertEqualsdicts Signaturesitemssappends_[1]sksvs node_typess1ss2ss3ss4sPositionalSignaturesobjectss5s failUnlesssimpliessfailIfsall_sigssmost_specific_signaturesslistsordered_signatures(sselfss5sd4sd2sd3sd1ss3ss2ss4sa1sa0sall_sigssdsks_[1]svss1((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pystestSignaturess2$$$$!M',,,,3:1:'cCs|ittj|ittj|ittj|ittj|ittjp ttj|itdj|itdj|itdj|itdjdtftdfdtftdfddfg}|i|i|tdftdfdtfddfdtfgdfd Y}|}xt|f|tfgD]~\}}|i||j|i||j|i||j|i||j|i||j|i||jqgWdS( Nsxyzi?Biiici5i8sXcBstZdZRS(s;Ensure rich comparisons work correctly with classic classes(s__name__s __module__s__doc__(((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pysXs ( sselfs failUnlesssMinsMaxsfailIfsdatassorts assertEqualsXsxsv1sv2(sselfsv1sv2sXsxsdata((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pys testMinMaxs. 3  4  c Cstttf\} }}gi}| ||gD]}|t|t@q8~\}}}h|d<|d<t d<}|iti|td|iti|| d|iti||d|iti||ddS(Niii(sobjectsob1sob2sob3sappends_[1]sobsidsmaxintsid1sid2sid3sNonestablesselfs assertEqualsstrategysdispatch_by_identitysVehicle( sselfsobsid2sid3sid1s_[1]stablesob2sob3sob1((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pystestIdentityDispatchs!C!cCs:x3ttfD]%}tt|titiq WdS(N(sTruesFalsestsvalidateCriterionsTruthCriterionsstrategysmake_node_typesdispatch_by_truth(sselfst((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pys testTruths  cCst}t|}|it|t@||itt|t@t|dfdY}|}t|}t|t@}|i|||it|t|~|i |||i|||it|t|dS(NsXcBstZRS(N(s__name__s __module__(((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pysXs( sobjectsanObsPointersptrsselfs assertEqualsidsmaxintshashsXsoidsassertNotEqual(sselfsoidsXsptrsanOb((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pys testPointerss  &  cCsjt}t|}t|titit|}|i t |i t t|t@gdS(N(sobjectsobsPointersisvalidateCriterionsstrategysmake_node_typesdispatch_by_identitysISeededCriterionsselfs assertEqualslistsseedssNonesidsmaxint(sselfsisob((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pystestIdentityCriterion s    cCstt}d|tt<|i|idghtdg<tg<|it|i|idghtdg<tg<tt}dS(Ni*( s SeededIndexsNonesisSubclassCriterionsintsselfs assertEquals casemap_forsaddSeed(sselfsi((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pystestSeededIndexs  1 1c Csgtt}t|titidgi}t tt D]}|t|q;~|i |ittgx*tttfD]}|i||jqWx-ttttfD]}|i||jqW|i|itt|itti||i|itt|itti||i |tt|i|tthtd<td<td<}t|i|}|i |tghtd<td<td<}|i ti|td|i ti|td|i ti|td|i ti|td|itti|t dS(Nsparentsiii(!sSubclassCriterionsVehiclesssvalidateCriterionsstrategysmake_node_typesdispatch_by_subclasssappends_[1]sgetMROsTruescsselfs assertEqualsseedssNones LandVehicles WaterVehiclesklasss failUnlesss GasPoweredsobjectsWheeledsimpliessfailIfsassertNotEqualstableslistsmatchessitemss assertRaisessAttributeErrorsBicycle(sselfstablescsitemss_[1]sssklass((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pystestSubclassCriterion s6 :!! c Cs|ittdd|ittddtdd} tdd}|iddf| j|iddf|j|iddf|j|iddf| j|id d f|j|id tf|j|i|i | |i| i |td d } |i| i | p |i | |i| i | p | i |td d }|iddf|j|iddf|jtdd }t i}xC| || ||fD],} t| tidtt| || i7s>=idieinsscCsdS(Nsinfant((sage((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pyssssi cCsdS(Ns preschooler((sage((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pyssicCsdS(Nsteenager((sage((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pyssicCsdS(Nsadult((sage((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pysss>=cCsdS(Nssenior((sage((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pyssi7cCsdS(Ns sweet sixteen((sage((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pysss=iisadultisteenagerf12.99spreteenisinfantis preschoolersseniorf54.899999999999999f14.5s sweet sixteenf16.5ic(sGenericFunctionsclassifys Inequalitysselfs assertEqualsMinsMax(sselfsclassify((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pystestInequalityDispatchs,cCsl|itdtd|itdtt|ittdj|ittdj|ittdj|ittdj|itditd|itditd|itditd|itditd|itdi ttf|itt i ttfdS(Nisabciii*( sselfs assertEqualsTruthCriterionsassertNotEqualsFalses failUnlesssTruesfailIfsimpliessseedssNone(sself((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pys testTruths"""""cCs8tdd}tdd}tdd|@}||@}|iddf|j|iddf|j||@}|iddf|j|iddf|j|iddf|j|iddf|j|i|i ||i|i ||i|i t |i t i ddS( Ns==isiicCstdtdd@S(Nis==(sTruthCriterions Inequality(((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pyss(s Inequalitys equals_twosless_than_fours lo_primess odd_primessselfsfailIfs failUnlesss even_primessimpliess NullCriterions assertRaisess protocolssAdaptationFailure(sselfs even_primess lo_primess equals_twosless_than_fours odd_primes((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pys testAndOrs    cCsrtddtdd@}tddtdd@}|iddf|j|iddf|j|iddf|j|iddf|j|iddf|j|idd f|j|i|i||i|i||i|i||i|i|xA||fD]3}|i|it|i|itq7WdS( Ns>=i s<=iiiiii( s Inequalitys ten_to_twentysfifteen_to_nineteensselfs failUnlesssimpliessfailIfsitems NullCriterion(sselfsfifteen_to_nineteens ten_to_twentysitem((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pystestRangeIntersections  cCsz|ittttj|itttj|itttit|i ttitt dS(N( sselfs failUnlesssHummers AndCriterions LandVehicles GasPowereds Speedboats NotCriterionsimpliessfailIfsWheeled(sself((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pystestClassIntersectionsscCs|itdtd|itdtd|itddtdd@tdd @td d d fgdS( Niiis>=i s<=is==is..(sselfs assertEqualsTruthCriterions Inequality(sself((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pystestSimplificationss,cCsj|itddtddx@tiiD]/\}}|it|dt|dq3WdS(Ns>=is<(sselfs assertEquals Inequalitysstrategysrev_opssitemssopsrev(sselfsrevsop((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pystestInequalityInversess# cCsttitddtdd}td}d|t|tt fg(scCstS(N(sFalse(sxsy((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pys)scCstS(N(sTrue(sxsy((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pys*sii i(sCallsoperatorsgtsArgumentsx_gt_ysGenericFunctionsgreaters SignaturesTruthCriterionsFalsesTruesselfsfailIfs failUnless(sselfsx_gt_ysgreater((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pystestTruthDispatch&s'""cCstdtdd}tdtdd}tdt}t}|i||@tdtddtdd@|i||@tdtdddt|i||@||i||@||i||@||i||B||i||B||i||Bt ||g|i||Bt ||g|i|t |gBt ||g|i|t |g@t ||@g|it |g|@t ||@g|it |gt |gBt ||g|it |gt |g@t ||@g|i ||@i ||@i |i ||@|@i ||@|@i dS(Nsxs>i si isssnamesv1isv2i(sGenericFunctionsfsselfs assertEqualsgetExpressionIdsArgument(sselfsf((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pystestArgumentCanonicalizations c CsT|ittiddttidd|ittiddttidd|ittiddttiddttitddtdd}ttitddtdd}|it |t |ttitddtdd}|it |t |t d}|i|i||i||i|i||i||i|i||ittitddtddd|t|tdd fgscCsdS(Nsyes((sxsy((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pysss>idcCsdS(Nsno((sxsy((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pyssi3i1snoici syesiiY(sselfs assertEqualsCallsoperatorsaddsassertNotEqualssubsArgumentsc1sc2shashsc3sGenericFunctionsfsgetExpressionIds Signatures Inequality(sselfsfsc3sc2sc1((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pys testCallss$...'''""1%cCs#td}ttitddtd}d|t|t ddfg ssnamesxicCstS(N(sTrue(sx((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pysss>i cCstS(N(sFalse(sx((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pyssi isfoosbari(sGenericFunctionsfsCallsoperatorsaddsArgumentsConsts x_plus_twos Signatures Inequalitysselfs failUnlesssfailIfsfoosbarsfourAsfourBs assertEqualshashsassertNotEqual(sselfsbarsfourBsfs x_plus_twosfourAsfoo((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pys testConsts s$%6c sttdddd}td}d|t|ddgscCstS(N(sNone(sv((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pys scCstS(N(sTrue(sv((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pys!ss==sN/As>i#cCstS(N(sFalse(sv((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pys#si sxsgpm(sGetattrsArguments vehicle_mpgstest_mpgsGenericFunctionsfuel_efficients SignaturesBicyclesbsmpgsHummershsselfs failUnlesssfailIfsvm2sxmsvgs assertEqualshashsitemsassertNotEqual( sselfsbsfuel_efficientsvm2shsxmsitemstest_mpgsvgs vehicle_mpg((s vehicle_mpgs5build\bdist.win32\egg\dispatch\tests\test_dispatch.pys testGetattrs$ $ cCstttddtdd}td}d|t|tdddffg7scCstS(N(sTrue(sxsy((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pys8ss==iicCstS(N(sFalse(sxsy((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pys9sisz(sTuplestuplesArgumentsxysGenericFunctions xy_is_one_twos Signatures Inequalitysselfs failUnlesssfailIfsxy2syxslistslxszzs assertEqualshashsitemsassertNotEqual(sselfsxy2sitemsyxsxyslxszzs xy_is_one_two((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pys testTuple5s"$+$$$$s2.5cCstddtddtddf\}}}t|||}td}d|t|t fgNscCstS(N(sTrue(sxsysz((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pysOscCstS(N(sFalse(sxsysz((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pysPsii(sArgumentsxsyszsIfElsesxyzsGenericFunctionsies SignaturesTruthCriterionsselfs assertEqualsFalsesTrue(sselfsysxszsiesxyz((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pys testIfElseKs3c Cstddtddf\} }ttitddtdd} t| || }t d}d|t |t fgcscCstS(N(sTrue(sxsysz((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pysdscCstS(N(sFalse(sxsysz((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pysesiicCstS(N(sNone(sxsy((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pysuscCstS(N(sTrue(sxsy((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pysvss==icCstS(N(sFalse(sxsy((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pyswsi(sArgumentsxsysCallsoperatorsdivszsOrExprsxyzsGenericFunctionsor_s SignaturesTruthCriterionsselfs failUnlesssfailIfs assertRaisessZeroDivisionErrorszyxsxyz2sxys assertEqualshashsitemsassertNotEqualsor_eq_23s Inequalitys or_eq_NonesNone( sselfsxyzsxyz2sxys or_eq_Nonesor_sitemszyxsysxszsor_eq_23((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pys testOrExpr^s@$'  %%c Cstddtddf\}} ttitddtdd} t|| | }t d}d|t |t fgscCstS(N(sTrue(sxsysz((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pysscCstS(N(sFalse(sxsysz((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pyssiiicCstS(N(sNone(sxsy((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pysscCstS(N(sTrue(sxsy((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pysss==icCstS(N(sFalse(sxsy((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pyssii(sArgumentsxsysCallsoperatorsdivszsAndExprsxyzsGenericFunctionsand_s SignaturesTruthCriterionsselfs failUnlesssTruesfailIfsFalses assertRaisessZeroDivisionErrorszyxsxyz2sxys assertEqualshashsitemsassertNotEquals and_eq_23s Inequalitys and_eq_NonesNone( sselfsxyzsxyz2sand_sxys and_eq_23sxs and_eq_Nonesitemsyszszyx((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pys testAndExprsB$'  %%( s__name__s __module__stestArgumentBasicsstestArgumentCanonicalizations testCallss testConstss testGetattrs testTuplessyssversions testIfElses testOrExprs testAndExpr(((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pysExpressionTestss '      )sSimpleGenericscBsGtZdZdZdZdZdZdZdZRS(NcCstidgd}tidgd}x|df|dffD]}\}}|i|i||i ti |ddd|i ti |dd d |i t ||i t |d d qKWdS( NsxcOsdS(sfoo barN((sxsysz((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pysf1scOsdS(sbaz spamN((sxsysz((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pysf2ssfoo barsbaz spamiiisyszsfoosbar( sdispatchsonsf1sf2sfsdocsselfs assertEquals__doc__s assertRaisessNoApplicableMethodss TypeError(sselfsf1sf2sfsdoc((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pystestTrivialitiess   c stidgd}dfdY}dtfdY} dtifdYd fd Y}|}| }|}x6|||d d t fD]}|iti||qW|i|d |i| d|id|i||dd|dfhf|i||ddd|fhddscOs d||fS(Nsnew!(sargsskw(sargsskw((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pysscOs d||fS(Nsfoo!(sargsskw(sargsskw((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pysssfoosclassic!sbarsnew!sxsysfoo!(sdispatchsonsgsClassicsobjectsNewStyles protocolss InterfacesIFoosImplscsnsisTestCasesitemsselfs assertRaisessNoApplicableMethodss addMethods assertEqual( sselfscsIFoosgsClassicsisnsitemsImplsNewStyle((sIFoos5build\bdist.win32\egg\dispatch\tests\test_dispatch.pystestSimpleDefinitionss*    (17c sxdfdY}dtfdY} dtifdYdfdY}|}| }|}t i d gd d }|i || ggd }|i||d d|d fhf|i||d dd|d fhd dssvcCsdSdS(Nsland((sv((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pysfooscCsdSdS(Nswater((sv((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pysmsslandswatercCsdS(sBlahN((sv((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pyssscCsdSdS(Nsland((sv((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pysbarsswhencCsdSdS(Nswater((sv((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pyss!s(sGenericFunctionsmswhens Signatures LandVehiclesfoostypessselfs failUnlesss isinstances FunctionTypes WaterVehicles assertEqualsdispatchsonsssbarshasattr(sselfsmsssbarsfoostypes((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pystestWhenMethodss,      cCstidgd}|itgd}|itgd}|i|t td|i|t dtddS(NsvcCsdS(sXN((sxsv((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pyss-scCsdSdS(Nsland((sxsv((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pysbar1scCsdSdS(Nswater((sxsv((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pyss5sslandswater( sdispatchsonssswhens LandVehiclesbars WaterVehiclesselfs assertEqualsNone(sselfsbarss((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pys testAltArg+s   csdfdYdfdY}|iidtd|iitd|i|itddS( NsXcBsStZeidgdZeiegdZeiegdZRS(NsvcCsdS(sXN((sxsv((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pyss>scCsdSdS(Nsland((sxsv((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pysbarBscCsdSdS(Nswater((sxsv((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pyssFs( s__name__s __module__sdispatchsonssswhens LandVehiclesbars WaterVehicle(((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pysX<s   sYcs0tZiiZeiegdZRS(NcCsdSdS(Nssplash!((sxsv((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pyssLs(s__name__s __module__sXssscloneswhens WaterVehicle((sX(s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pysYIssvslandswaterssplash!(sXsYsselfs assertEqualsss LandVehicles WaterVehicle(sselfsYsX((sXs5build\bdist.win32\egg\dispatch\tests\test_dispatch.pystestInstanceMethod;s  "( s__name__s __module__stestTrivialitiesstestSimpleDefinitionsstestMultiDefinitionstestAdaptedDefinitionstestWhenMethodss testAltArgstestInstanceMethod(((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pysSimpleGenericss     ) s GenericTestscBstZdZdZdZdZdZdZdZdZ d Z d Z d Z d Z d ZdZRS(NcCs{td}d|tfWscCsdS(Nsland((sv((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pysXscCsdS(Nswater((sv((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pysYsslandswater( sGenericFunctionsms LandVehicles WaterVehiclesselfs assertEqualssHummers Speedboats assertRaisessNoApplicableMethodss GasPowered(sselfsm((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pystestBasicSingleDispatchVs cCstd}d|tdtdt`scCstS(N(sTrue(sv1sv2((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pysassv1sv2cCsdS(Nsdunno((sv1sv2((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pyscscCstS(N(sFalse(sv1sv2((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pysds( sGenericFunctionsfasters Signatures GasPowereds HumanPoweredsHummers Speedboatsobjectsselfs assertEqualsBicyclesTrue(sselfsfaster((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pys$testSimpleDoubleDispatchAndNamedArgs_scCsOtd}ti|ttfisii( sGenericFunctionsaddsoperatorsobjectsintssubsselfs assertRaisessAmbiguousMethod(sselfsadd((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pys testAmbiguityhscCstd}dttfdY}d|tdt<|it ||t |tg|i ||ddS(NcCstS(N(sNone(svehicle((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pysossTricyclecBstZRS(N(s__name__s __module__(((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pysTricyclepscCsdS(Ns We're rolling((sob((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pysqssvehicles We're rolling( sGenericFunctionsrolls HumanPowereds LandVehiclesTricycles SignaturesWheeledsselfs assertRaisessNoApplicableMethodssdeclareImplementations assertEqual(sselfsTricyclesroll((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pys testDynamicns c Csvtd}d|tdtdtddwscCstS(N(sFalse(svsn((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pysxssvehiclesnumsysii( sGenericFunctionsts Signatures HumanPowereds Inequalitys WaterVehiclesselfs assertRaisessAmbiguousMethods PaddleBoat(sselfst((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pystestMROvs%%cCs!d}d}d}d}tigd}|ittfg||it t fg||it t fg||it t ft t fg|t }t }|i|||d|i|||d|i|||d|i|||ddS( NcCsdSdS(NsThey're both vehicles.((sob1sob2((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pys both_vehiclesscCs|||dSdS(Ns They are both land vehicles.(s next_methodsob1sob2(s next_methodsob1sob2((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pys both_landscCs|||dSdS(Ns They are both sea vehicles.(s next_methodsob1sob2(s next_methodsob1sob2((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pysboth_seascCs|||dSdS(Ns< One vehicle is a land vehicle, the other is a sea vehicle.(s next_methodsob1sob2(s next_methodsob1sob2((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pysmixed_vehiclesscCsdS(N((sv1sv2((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pyscomparess4They're both vehicles. They are both land vehicles.s3They're both vehicles. They are both sea vehicles.sRThey're both vehicles. One vehicle is a land vehicle, the other is a sea vehicle.(s both_vehicless both_landsboth_seasmixed_vehiclessdispatchsgenericscompares addMethodsVehicles LandVehicles WaterVehiclesBicycleslands Speedboatsseasselfs assertEqual(sselfs both_vehiclesscompareslandsboth_seasmixed_vehiclessseas both_land((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pystestSimpleChaining}s*        c CsNtd}|i|iigti}t t i t ddt dd}|i||f}|it dd|f} |it dd|f}|idgd} |i|iig|idgd} |i|ii| |fg|id gd} |ii}|i| |f||fg} | i|i|| |i|ii||gh|d <|i|ii| |gh|d <|itt|i||g\}}|i|||itt|i|| g\}}|i|| dS( NcCstS(N(sNone(sxsy((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pysssnamesysxsx==2 and y>10 and x<27cCsdSdS(Nsfoo((sxsy((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pysxssx>0 and y/x>10cCsdSdS(Nsbar((sxsy((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pysxssx==1 and y>0 and y/x>10i(sGenericFunctionsgsselfs assertEquals constraintssitemss Inequalitys node_typesdfsCallsoperatorsdivsArgumentsyxsgetExpressionIdsyxidsxidsyidswhensxssortsexpecteds successorss _best_splitsrangeslenscasessbest_ids remaining_ids( sselfsyidsgsdfsitemssbest_idsyxidsyxs remaining_idssxsxidsexpected((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pys$testSubexpressionOrderingConstraintss0 '  " "++--c sydfdY}d|fdYdfdY}d||fdY}d } d } d } d } d }dfdY} dfdY}|| gt di||t| | fg| if||fg| i|t|fg| i|fg| i| fg||d}xddfD]}|i||||| d|i||d|i||d|i||||d|i||||d|i| ttttdiq}WdS(NsAcBstZRS(N(s__name__s __module__(((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pysAssBcBstZRS(N(s__name__s __module__(((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pysBssCcBstZRS(N(s__name__s __module__(((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pysCssDcBstZRS(N(s__name__s __module__(((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pysDscGsdSdS(Nsm1((sx((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pysm1scGsdSdS(Nsm2((sx((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pysm2scGsdSdS(Nsm3((sx((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pysm3scGsdSdS(Nsm4((sx((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pysm4scGsdSdS(Nsm5((sx((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pysm5ssTcBstZRS(N(s__name__s __module__(((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pysTssFcBstZRS(N(s__name__s __module__(((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pysFscCstS(N(sNone(sf1sf1_xsf2s f1x_at_not_Bs f1_y_eq_f2_y((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pysscs(|||t| |SdS(N(sgsf1sf1xsf2stfs isinstancesBsymatches(sf1sf1xsf2symatches(sBsgstf(s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pyswsiism1sm2sm3sm4sm5(sAsBsCsDsm1sm2sm3sm4sm5sTsFstfsGenericFunctionsgs addMethods NullCriterionswstimesselfs assertEqualsNonescriterionChanged(sselfsAsCsBsDsgsFstimesm5sm4sm1sTsm3sm2stfsw((sBsgstfs5build\bdist.win32\egg\dispatch\tests\test_dispatch.pystestSimpleMultiDispatchs8     "% +%%%%%csdfdYdfdY}|i|itd|iidtd|iitddS( NsXcBsPtZeigdZeidgdZeidgdZRS(NcCsdS(sXN((sselfsv((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pyssssv in LandVehiclecCsdSdS(Nsland((sselfsv((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pysbarssv in WaterVehiclecCsdSdS(Nswater((sselfsv((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pysss(s__name__s __module__sdispatchsgenericssswhensbar(((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pysXs    sYcs*tZiZeidgdZRS(Nsv in WaterVehiclecCsdSdS(Nssplash!((sselfsv((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pyss s(s__name__s __module__sXssswhen((sX(s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pysYs ssplash!svslandswater(sXsYsselfs assertEqualsss WaterVehicles LandVehicle(sselfsYsX((sXs5build\bdist.win32\egg\dispatch\tests\test_dispatch.pystestInstanceMethodss  "cCstigd}|itgd}|idgd}|i|td|i|t d|i|t ddS(NcCsdS(N((st((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pysgmscCsdSdS(Nsdefault((st((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pysgmssissubclass(t,int)cCsdSdS(Nsint((st((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pysgm2ssintsdefault( sdispatchsgenericsgmswhensdefaultsgm2sselfs assertEqualsintsobjectsfloat(sselfsgm2sgm((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pystestSubclassDispatchs    c CsQdkl}dfdY}|d|\}}|i|dg|i|ddf|i|dddf|dd|\}}|i|dg|i|ddf|i|dddf|i|df|d|\}}|i|dd g|i|dd dd ff|i|dddff|d dd |\}}|i|dd d g|i|dd dd ff|i|dd ddd dff|i|ddddff|i|d dd dff|i|ddddddddff|i|d dff|d|\}}|i|ddg|i|ddfddf|d|\}}|i|dddd dg|i|dddfdddddfhdd%s((sselfsargtuple((sargtuples5build\bdist.win32\egg\dispatch\tests\test_dispatch.pys __getitem__$s(s__name__s __module__s __getitem__(((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pys dispatcher#scCstS(N(sNone(sfoo((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pys'ssfoosbari*cGstS(N(sNone(sfoosz((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pys2sszsbazsshoocGstS(N(sNone(sfoosbluesz((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pys7ssbluesspamstwoiiiicCs|\}}tS(N(sxsysNone(s.0sxsy((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pys@ssxsycOs|\}}tS(N(sxsysNone(sfoos.2szszzsxsy((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pysDsszzsfizzsfuzz(sdispatch.functionss _mkNormalizers dispatchersfsasselfs assertEqual(sselfsasfs dispatchers _mkNormalizer((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pystestArgNormalization!s: "!"(""."cCstigd}|idgd}|idgd}|i|ddd|i|ddd|it|dddddS( NcKsdS(sTest of kw handlingN((sfiz((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pysfLss 'x' in fizcKsdSdS(Nsx((sfiz((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pysfOss 'y' in fizcKsdSdS(Nsy((sfiz((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pysfRssxisy(sdispatchsgenericsfswhensselfs assertEquals assertRaisessAmbiguousMethod(sselfsf((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pystestKwArgHandlingJs    cCstigd}|idgd}|idgd}|i|ddd|i|dd d d |i|dd d d |i|d d d |it|dd dS( NcGsdS(sTest of vararg handlingN((sfiz((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pysfZss 'x' in fizcGsdSdS(Nsx((sfiz((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pysf]ss 'y' in fizcGsdSdS(Nsy((sfiz((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pysf`ssfoosxsbarsqsy(sdispatchsgenericsfswhensselfs assertEquals assertRaisessAmbiguousMethod(sselfsf((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pystestVarArgHandlingXs    cCs\tigd}|idd|i|dd|iti|ddS(NcCsdS(N((snumber((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pys demo_funcjss number < 10cCsdS(Ni((sx((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pyslsiii!(sdispatchsgenerics demo_funcswhensselfs assertEquals assertRaisessNoApplicableMethods(sselfs demo_func((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pys"test_NoApplicableMethods_is_raisedhs   (s__name__s __module__stestBasicSingleDispatchs$testSimpleDoubleDispatchAndNamedArgss testAmbiguitys testDynamicstestMROstestSimpleChainings$testSubexpressionOrderingConstraintsstestSimpleMultiDispatchstestInstanceMethodsstestSubclassDispatchstestArgNormalizationstestKwArgHandlingstestVarArgHandlings"test_NoApplicableMethods_is_raised(((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pys GenericTestsTs    ) ) )   )  cCs)dk}|idd|iddSdS(Ns combiners.txts optionflagsspackagesdispatch(sdoctests DocFileSuitesELLIPSIS(sdoctest((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pystest_combinersws cCsBttggi}tD]}|t|dq~SdS(Nstest(s TestSuitestest_combinerssappends_[1]s TestClassessts makeSuite(s_[1]st((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pys test_suite}s(.s__doc__sunittestsTestCases makeSuites TestSuitesoperatorssysstypess ClassTypes InstanceTypesmaxintsversionsdispatchs protocolssdispatch.predicatessdispatch.functionss InterfacesadvisesdeclareImplementationsprotocols.advicesgetMROsstrategys functionssdispatch.strategysobjectsVehicles LandVehicles WaterVehiclesWheeleds FourWheeleds TwoWheeleds GasPowereds HumanPoweredsBicyclesHummers Speedboats PaddleBoats RiverBoats TestGraphs CriteriaTestssExpressionTestssSimpleGenericss GenericTestss TestClassesstest_combinerss test_suite(&s GenericTestss TestClassess Speedboatsdispatchsmaxints HumanPoweredsVehiclesoperators GasPoweredsHummers TestSuites functionss CriteriaTestss WaterVehicles LandVehiclesstrategysTestCases TestGraphsversions InterfacesSimpleGenericssadvisesWheeleds RiverBoats makeSuitestest_combinerss FourWheeledsExpressionTestsssyss TwoWheeledsdeclareImplementationsgetMROs protocolssBicycles ClassTypes InstanceTypes test_suites PaddleBoat((s5build\bdist.win32\egg\dispatch\tests\test_dispatch.pys?sF )i  PK:84uudispatch/tests/doctest.pyc; ^Gc!@syeWnej oeefZnXyeWnej odZnXdZdddddddd d d d d ddddddddddddddddddd d!d"g!Zd#kZd#kZd#k Z d#k Z d#k Z d#k Z d#k Z d#kZd#kZd#kZd#kZd#kZd#kZd$klZeid%deed&hZd'ZedZedZedZedZedZeeBeBeBeBZed Z ed Z!ed Z"ed Z#e e!Be"Be#BZ$d(Z%d)Z&d*Z'd+Z(d,d-Z)d.d/Z*d0Z+d1efd2YZ,d3Z-d4Z.d5ei/fd6YZ0d7Z1dfd8YZ2dfd9YZ3dfd:YZ4dfd;YZ5dfd<YZ6dfd=YZ7de8fd>YZ9de8fd?YZ:de6fd@YZ;e<a=e<e<e<e<e<e>d&e<e?e?dA Z@e>e<e<e<e<e>d&e<e?e4dB ZAe?dCe<d&dDZBdfdEYZCd&aDdFZEdGeiFfdHYZGe<e<e<e<dIZHdJeGfdKYZIe>e<e<e4dLZJdMZKdNZLdOZMe?e<dPZNe?e<dQZOe?dRZPdSfdTYZQhdSeQ<dUdV<dWdX<dYdZ<d[d\<d]d^}|t|<|SdS(Ni(slensOPTIONFLAGS_BY_NAMEsflagsname(snamesflag((s/build\bdist.win32\egg\dispatch\tests\doctest.pysregister_optionflags s s...cCsOtidtdd|d djo$|d djo|djn SdS( sprefix, base -> true iff name prefix + "." + base is "private". Prefix may be an empty string, and base does not contain a period. Prefix is ignored (although functions you write conforming to this protocol may make use of it). Return true iff base begins with an (at least one) underscore, but does not both begin and end with (at least) two underscores. >>> is_private("a.b", "my_func") False >>> is_private("____", "_my_func") True >>> is_private("someclass", "__init__") False >>> is_private("sometypo", "__init_") True >>> is_private("x.y.z", "_") True >>> is_private("_x.y.z", "__") False >>> is_private("", "") # senseless but consistent False sVis_private is deprecated; it wasn't useful; examine DocTestFinder.find() lists insteads stackleveliis_s__iN(swarningsswarnsDeprecationWarningsbase(sprefixsbase((s/build\bdist.win32\egg\dispatch\tests\doctest.pys is_privates  cCs[d}xJtiD]?}|i|t}|tt|jo||i O}qqW|SdS(s Return the compiler-flags associated with the future features that have been imported into the given namespace (globs). iN( sflagss __future__sall_feature_namessfnamesglobssgetsNonesfeaturesgetattrs compiler_flag(sglobssfeaturesflagssfname((s/build\bdist.win32\egg\dispatch\tests\doctest.pys_extract_future_flagss icCsti|o|Snot|ttfo t|ttdgSn9|t jot i t i |idSn tddS(s Return the module specified by `module`. In particular: - If `module` is a module, then return module. - If `module` is a string, then import and return the module with that name. - If `module` is None, then return the calling module. The calling module is assumed to be the module of the stack frame at the given depth in the call stack. s*s__name__s"Expected a module, string, or NoneN(sinspectsismodulesmodules isinstancesstrsunicodes __import__sglobalsslocalssNonessyssmoduless _getframesdepths f_globalss TypeError(smodulesdepth((s/build\bdist.win32\egg\dispatch\tests\doctest.pys_normalize_modules   icCstid|d|SdS(s{ Add the given number of space characters to the beginning every non-blank line in `s`, and return the result. s (?m)^(?!$)s N(sressubsindentss(sssindent((s/build\bdist.win32\egg\dispatch\tests\doctest.pys_indentscCs?t}|\}}}ti|||d||iSdS(sz Return a string containing a traceback message for the given exc_info tuple (as returned by sys.exc_info()). sfileN( sStringIOsexcoutsexc_infosexc_typesexc_valsexc_tbs tracebacksprint_exceptionsgetvalue(sexc_infosexc_valsexc_typesexcoutsexc_tb((s/build\bdist.win32\egg\dispatch\tests\doctest.pys_exception_tracebacks  s _SpoofOutcBstZdZedZRS(NcCsWti|}|o|id o|d7}nt|do |`n|SdS(Ns s softspace(sStringIOsgetvaluesselfsresultsendswithshasattrs softspace(sselfsresult((s/build\bdist.win32\egg\dispatch\tests\doctest.pysgetvalues  cCs.ti||t|do |`ndS(Ns softspace(sStringIOstruncatesselfssizeshasattrs softspace(sselfssize((s/build\bdist.win32\egg\dispatch\tests\doctest.pystruncates(s__name__s __module__sgetvaluesNonestruncate(((s/build\bdist.win32\egg\dispatch\tests\doctest.pys _SpoofOuts cCsQ|itdjo||jSn|it}t|djptdt|f\}}|d}|o/|i |ot|}|d=qt Sn|d}|o3|i |o|t|8}|d=qt Sn||jot SnxH|D]@}|i|||}|djot Sn|t|7}qWtSdS(s_ Essentially the only subtle case: >>> _ellipsis_match('aa...aa', 'aaa') False iiiN(swantsfindsELLIPSIS_MARKERsgotssplitswsslensAssertionErrorsstartpossendpossws startswithsFalsesendswithsTrue(swantsgotswswssstartpossendpos((s/build\bdist.win32\egg\dispatch\tests\doctest.pys_ellipsis_match"s6       cCs'|i}|o d|SndSdS(s)Return a commented form of the given lines# s#N(slinesrstrip(sline((s/build\bdist.win32\egg\dispatch\tests\doctest.pys _comment_lineSs   s_OutputRedirectingPdbcBs tZdZdZdZRS(s A specialized version of the python debugger that redirects stdout to a given stream when interacting with the user. Stdout is *not* redirected when traced code is executed. cCs||_tii|dS(N(soutsselfs_OutputRedirectingPdb__outspdbsPdbs__init__(sselfsout((s/build\bdist.win32\egg\dispatch\tests\doctest.pys__init__as cGs=ti}|it_ztii||SWd|t_XdS(N( ssyssstdouts save_stdoutsselfs_OutputRedirectingPdb__outspdbsPdbstrace_dispatchsargs(sselfsargss save_stdout((s/build\bdist.win32\egg\dispatch\tests\doctest.pystrace_dispatches   (s__name__s __module__s__doc__s__init__strace_dispatch(((s/build\bdist.win32\egg\dispatch\tests\doctest.pys_OutputRedirectingPdb[s  cCsti| otd|n|ido tdnt|dotii |i d}n}|i djoXt tidjotiddjo!tii tidd}qti}ntd|d tii||i dSdS( NsExpected a module: %rs/s1Module-relative files may not have absolute pathss__file__is__main__ss+Can't resolve paths relative to the module s (it has no __file__)(sinspectsismodulesmodules TypeErrorspaths startswiths ValueErrorshasattrsosssplits__file__sbasedirs__name__slenssyssargvscurdirsjoin(smodulespathsbasedir((s/build\bdist.win32\egg\dispatch\tests\doctest.pys_module_relative_pathps *! cBs#tZdZeddedZRS(sn A single doctest example, consisting of source code and expected output. `Example` defines the following attributes: - source: A single Python statement, always ending with a newline. The constructor adds a newline if needed. - want: The expected output from running the source code (either from stdout, or a traceback in case of exception). `want` ends with a newline unless it's empty, in which case it's an empty string. The constructor adds a newline if needed. - exc_msg: The exception message generated by the example, if the example is expected to generate an exception; or `None` if it is not expected to generate an exception. This exception message is compared against the return value of `traceback.format_exception_only()`. `exc_msg` ends with a newline unless it's `None`. The constructor adds a newline if needed. - lineno: The line number within the DocTest string containing this Example where the Example begins. This line number is zero-based, with respect to the beginning of the DocTest. - indent: The example's indentation in the DocTest string. I.e., the number of space characters that preceed the example's first prompt. - options: A dictionary mapping from option flags to True or False, which is used to override default options for this example. Any option flags not contained in this dictionary are left at their default value (as specified by the DocTestRunner's optionflags). By default, no options are set. icCs|id o|d7}n|o|id o|d7}n|tj o|id o|d7}n||_||_||_||_|tjo h}n||_||_dS(Ns ( ssourcesendswithswantsexc_msgsNonesselfslinenosindentsoptions(sselfssourceswantsexc_msgslinenosindentsoptions((s/build\bdist.win32\egg\dispatch\tests\doctest.pys__init__s      (s__name__s __module__s__doc__sNones__init__(((s/build\bdist.win32\egg\dispatch\tests\doctest.pysExamples "cBs)tZdZdZdZdZRS(se A collection of doctest examples that should be run in a single namespace. Each `DocTest` defines the following attributes: - examples: the list of examples. - globs: The namespace (aka globals) that the examples should be run in. - name: A name identifying the DocTest (typically, the name of the object whose docstring this DocTest was extracted from). - filename: The name of the file that this DocTest was extracted from, or `None` if the filename is unknown. - lineno: The line number within filename where this DocTest begins, or `None` if the line number is unavailable. This line number is zero-based, with respect to the beginning of the file. - docstring: The string that the examples were extracted from, or `None` if the string is unavailable. cCs[t|t p td||_||_|i|_||_||_ ||_ dS(s Create a new DocTest containing the given examples. The DocTest's globals are initialized with a copy of `globs`. s8DocTest no longer accepts str; use DocTestParser insteadN( s isinstancesexampless basestringsAssertionErrorsselfs docstringsglobsscopysnamesfilenameslineno(sselfsexamplessglobssnamesfilenameslinenos docstring((s/build\bdist.win32\egg\dispatch\tests\doctest.pys__init__s    cCstt|idjo d}n4t|idjo d}ndt|i}d|i|i|i|fSdS(Nis no examplesis 1 examples %d exampless(slensselfsexamplessnamesfilenameslineno(sselfsexamples((s/build\bdist.win32\egg\dispatch\tests\doctest.pys__repr__s   cCs`t|t odSnt|i|i|it|f|i|i|it|fSdS(Ni( s isinstancesothersDocTestscmpsselfsnamesfilenameslinenosid(sselfsother((s/build\bdist.win32\egg\dispatch\tests\doctest.pys__cmp__s!(s__name__s __module__s__doc__s__init__s__repr__s__cmp__(((s/build\bdist.win32\egg\dispatch\tests\doctest.pysDocTests   cBstZdZeideieiBZeideieiBeiBZ eidi Z ddZ dZ ddZdZeid eiZd Zeid eiZd Zd ZdZRS(sD A class used to parse strings containing doctest examples. s # Source consists of a PS1 line followed by zero or more PS2 lines. (?P (?:^(?P [ ]*) >>> .*) # PS1 line (?:\n [ ]* \.\.\. .*)*) # PS2 lines \n? # Want consists of any non-blank lines that do not start with PS1. (?P (?:(?![ ]*$) # Not a blank line (?![ ]*>>>) # Not a line starting with PS1 .*$\n? # But any other line )*) s # Grab the traceback header. Different versions of Python have # said different things on the first traceback line. ^(?P Traceback\ \( (?: most\ recent\ call\ last | innermost\ last ) \) : ) \s* $ # toss trailing whitespace on the header. (?P .*?) # don't blink: absorb stuff until... ^ (?P \w+ .*) # a line *starts* with alphanum. s ^[ ]*(#.*)?$sc Cs|i}|i|}|djoAdigi}|idD]}|||qE~}ng} ddf\} } x|i i|D]}| i|| |i!| |id| |i7} |i||| \}} } }|i| oB| it|| |d| d|t|idd| n| |id|i|i7} |i} qW| i|| | SdS(s= Divide the given string into examples and intervening text, and return them as a list of alternating Examples and strings. Line numbers for the Examples are 0-based. The optional argument `name` is a name identifying this string, and is only used for error messages. is slinenosindentsoptionsN(sstrings expandtabssselfs _min_indents min_indentsjoinsappends_[1]ssplitslsoutputscharnoslinenos _EXAMPLE_REsfinditersmsstartscounts_parse_examplesnamessourcesoptionsswantsexc_msgs_IS_BLANK_OR_COMMENTsExampleslensgroupsend(sselfsstringsnames min_indentsexc_msgsmsls_[1]ssourceslinenoswantsoutputscharnosoptions((s/build\bdist.win32\egg\dispatch\tests\doctest.pysparse5s*  A!%cCs)t|i|||||||SdS(s" Extract all doctest examples from the given string, and collect them into a `DocTest` object. `globs`, `name`, `filename`, and `lineno` are attributes for the new `DocTest` object. See the documentation for `DocTest` for more information. N(sDocTestsselfs get_examplessstringsnamesglobssfilenameslineno(sselfsstringsglobssnamesfilenameslineno((s/build\bdist.win32\egg\dispatch\tests\doctest.pys get_doctest\scCsIgi}|i||D]$}t|to||qq~SdS(s Extract all doctest examples from the given string, and return them as a list of `Example` objects. Line numbers are 0-based, because it's most common in doctests that nothing interesting appears on the same line as opening triple-quote, and so the first interesting line is called "line 1" then. The optional argument `name` is a name identifying this string, and is only used for error messages. N( sappends_[1]sselfsparsesstringsnamesxs isinstancesExample(sselfsstringsnames_[1]sx((s/build\bdist.win32\egg\dispatch\tests\doctest.pys get_exampleshs cCst|id}|idid} |i| ||||i | dd|d||di gi }| D]} || |dqy~} |id} | id}t|djotid |d o |d =n|i |d|||t| di gi }|D]}|||q(~} |ii| }|o|id }nt}|i| ||} | | | |fSd S( s Given a regular expression match from `_EXAMPLE_RE` (`m`), return a pair `(source, want)`, where `source` is the matched example's source code (with prompts and indentation stripped); and `want` is the example's expected output (with indentation stripped). `name` is the string's name, and `lineno` is the line number where the example starts; both are used for error messages. sindentssources is s.iswants *$ismsgN(slensmsgroupsindentssplits source_linessselfs_check_prompt_blanksnameslinenos _check_prefixsjoinsappends_[1]sslssourceswants want_linessresmatchswls _EXCEPTION_REsexc_msgsNones _find_optionssoptions(sselfsmsnameslinenosindents want_linessexc_msgswls_[1]ssourceswantssls source_linessoptions((s/build\bdist.win32\egg\dispatch\tests\doctest.pys_parse_examplevs& "8* 4s#\s*doctest:\s*([^\n\'"]*)$c Csh}x|ii|D]}|ididdi}xs|D]k}|ddjp|dt jo!t d|d||fnt |d}|ddj||>> tests = DocTestFinder().find(_TestClass) >>> runner = DocTestRunner(verbose=False) >>> for test in tests: ... print runner.run(test) (0, 2) (0, 1) (0, 2) (0, 2) The `summarize` method prints a summary of all the test cases that have been run by the runner, and returns an aggregated `(f, t)` tuple: >>> runner.summarize(verbose=1) 4 items passed all tests: 2 tests in _TestClass 2 tests in _TestClass.__init__ 2 tests in _TestClass.get 1 tests in _TestClass.square 7 tests in 4 items. 7 passed and 0 failed. Test passed. (0, 7) The aggregated number of tried examples and failed examples is also available via the `tries` and `failures` attributes: >>> runner.tries 7 >>> runner.failures 0 The comparison between expected outputs and actual outputs is done by an `OutputChecker`. This comparison may be customized with a number of option flags; see the documentation for `testmod` for more information. If the option flags are insufficient, then the comparison may also be customized by passing a subclass of `OutputChecker` to the constructor. The test runner's display output can be controlled in two ways. First, an output function (`out) can be passed to `TestRunner.run`; this function will be called with strings that should be displayed. It defaults to `sys.stdout.write`. If capturing the output is not sufficient, then the display output can be also customized by subclassing DocTestRunner, and overriding the methods `report_start`, `report_success`, `report_unexpected_exception`, and `report_failure`. s*iFicCsy|pt|_|tjodtij}n||_||_ ||_ d|_ d|_ h|_ t|_dS(sc Create a new test runner. Optional keyword arg `checker` is the `OutputChecker` that should be used to compare the expected outputs and actual outputs of doctest examples. Optional keyword arg 'verbose' prints lots of stuff if true, only failures if false; by default, it's true iff '-v' is in sys.argv. Optional argument `optionflags` can be used to control how the test runner compares expected output to actual output, and how it displays failures. See the documentation for `testmod` for more information. s-viN(scheckers OutputCheckersselfs_checkersverbosesNonessyssargvs_verboses optionflagssoriginal_optionflagsstriessfailuress_name2fts _SpoofOuts_fakeout(sselfscheckersverboses optionflags((s/build\bdist.win32\egg\dispatch\tests\doctest.pys__init__Us       cCsc|ioU|io,|dt|idt|iq_|dt|idndS(s Report that the test runner is about to process the given example. (Only displays a message if verbose=True) sTrying: s Expecting: sExpecting nothing N(sselfs_verbosesexampleswantsouts_indentssource(sselfsoutstestsexample((s/build\bdist.win32\egg\dispatch\tests\doctest.pys report_startys   ,cCs|io|dndS(st Report that the given example ran successfully. (Only displays a message if verbose=True) sok N(sselfs_verbosesout(sselfsoutstestsexamplesgot((s/build\bdist.win32\egg\dispatch\tests\doctest.pysreport_successs cCs3||i|||ii|||idS(s7 Report that the given example failed. N( soutsselfs_failure_headerstestsexamples_checkersoutput_differencesgots optionflags(sselfsoutstestsexamplesgot((s/build\bdist.win32\egg\dispatch\tests\doctest.pysreport_failurescCs.||i||dtt|dS(sO Report that the given example raised an unexpected exception. sException raised: N(soutsselfs_failure_headerstestsexamples_indents_exception_tracebacksexc_info(sselfsoutstestsexamplesexc_info((s/build\bdist.win32\egg\dispatch\tests\doctest.pysreport_unexpected_exceptionscCs|ig}|iob|itj o |itj o|i|id}nd}|id|i||i fn"|id|id|i f|id|i }|it |di |SdS(Nis?sFile "%s", line %s, in %ssLine %s, in %ssFailed example:s ( sselfsDIVIDERsoutstestsfilenameslinenosNonesexamplesappendsnamessources_indentsjoin(sselfstestsexamplessourceslinenosout((s/build\bdist.win32\egg\dispatch\tests\doctest.pys_failure_headers   $!  cBsd}} |i} ed\} }}|i i }xUe |iD]D\}}|ie@o |dj}| |_|ioNxK|iiD]6\}}|o|i|O_q|i|M_qWn| d7} | o|i|||nd|i|f}y7e|i|d|d|iU|ii e!}Wn5e#j o n!e$i%}|ii nX|i&i'} |i&i)d|}|e!jo'||i+| |io | }qne$i%}e,i-|d d} | o| e/|7} n|i.e!jo |}n||i.| |io | }nz|ie0@oke1i2d|i.}e1i2d| }|o,|o%||i5d|i5d|io | }qn|| jo&| o|i6|||| qqD||jo0| o|i7|||| n|d7}qD||jo0| o|i8||||n|d7}qDe9pt:d |fqDW| |_|i;||| || fSd S( s Run the examples in `test`. Write the outcome of each example with one of the `DocTestRunner.report_*` methods, using the writer function `out`. `compileflags` is the set of compiler flags that should be used to execute examples. Return a tuple `(f, t)`, where `t` is the number of examples tried, and `f` is the number of examples that failed. The examples are run in the namespace `test.globs`. iiisssingleiis[^:]*:sunknown outcomeN(<sfailuresstriessselfs optionflagssoriginal_optionflagssrangesSUCCESSsFAILUREsBOOMs_checkers check_outputschecks enumeratestestsexampless examplenumsexamplesREPORT_ONLY_FIRST_FAILUREsquietsoptionssitemss optionflagsvals report_startsoutsnamesfilenamescompilessources compileflagssglobssdebuggers set_continuesNones exceptionsKeyboardInterruptssyssexc_infos_fakeoutsgetvaluesgotstruncatesoutcomeswants tracebacksformat_exception_onlysexc_msgs_exception_tracebacksIGNORE_EXCEPTION_DETAILsresmatchsm1sm2sgroupsreport_successsreport_failuresreport_unexpected_exceptionsFalsesAssertionErrors_DocTestRunner__record_outcome(sselfstests compileflagssoutschecksvalsfilenamesm1sm2sgotsoriginal_optionflagssSUCCESSsexc_msgstriessexc_infos exceptions optionflagsquietsFAILUREsBOOMs examplenumsfailuressoutcomesexample((s/build\bdist.win32\egg\dispatch\tests\doctest.pys__runs                )      cCsd|ii|iddf\}}||||f|i|i<|i |7_ |i |7_ dS(s{ Record the fact that the given DocTest (`test`) generated `f` failures out of `t` tried examples. iN( sselfs_name2ftsgetstestsnamesf2st2sfstsfailuresstries(sselfstestsfstsf2st2((s/build\bdist.win32\egg\dispatch\tests\doctest.pys__record_outcome(s $s3[\w\.]+)\[(?P\d+)\]>$cCs|ii|}|o|id|iijo3|iit |id}|i i t Sn8|iiidjo|i||Sn|i|SdS(Nsnames examplenumi(sselfs%_DocTestRunner__LINECACHE_FILENAME_REsmatchsfilenamesmsgroupstestsnamesexamplessintsexamplessources splitlinessTruessave_linecache_getliness func_codes co_argcountsmodule_globals(sselfsfilenamesmodule_globalssmsexample((s/build\bdist.win32\egg\dispatch\tests\doctest.pys__patched_linecache_getlines5s#cCs||_|tjot|i}nti}|tjo |i }n|i t_t i }t||_|ii|ii t _ ti|_|it_z|i|||SWd|t_|t _ |it_|o|iinXdS(sJ Run the examples in `test`, and display the results using the writer function `out`. The examples are run in the namespace `test.globs`. If `clear_globs` is true (the default), then this namespace will be cleared after the test runs, to help with garbage collection. If you would like to examine the namespace after the test completes, then use `clear_globs=False`. `compileflags` gives the set of flags that should be used by the Python compiler when running the examples. If not specified, then it will default to the set of future-import flags that apply to `globs`. The output of each example is checked using `DocTestRunner.check_output`, and the results are formatted by the `DocTestRunner.report_*` methods. N(stestsselfs compileflagssNones_extract_future_flagssglobsssyssstdouts save_stdoutsoutswrites_fakeoutspdbs set_tracessave_set_traces_OutputRedirectingPdbsdebuggersresets linecachesgetlinesssave_linecache_getliness*_DocTestRunner__patched_linecache_getliness_DocTestRunner__runs clear_globssclear(sselfstests compileflagssouts clear_globss save_stdoutssave_set_trace((s/build\bdist.win32\egg\dispatch\tests\doctest.pysrun?s,             c Cs7|tjo |i}ng} g}g}d}} x|i i D]} | \}\}}||jpt||7}| |7} |djo| i|qF|djo|i||fqF|i| qFW|o| o7t| GdGH| ix| D]} dG| GHqWn|oCt|GdGH|ix'|D]\} }d|| fGHqEWqln|oT|iGHt|GdGH|ix0|D]$\} \}}d||| fGHqWn|o3|GdGt|i Gd GH|| Gd G| Gd GHn| od G| Gd GHn|o dGHn| |fSdS(s Print a summary of all the test cases that have been run by this DocTestRunner, and return a tuple `(f, t)`, where `f` is the total number of failed examples, and `t` is the total number of tried examples. The optional `verbose` argument controls how detailed the summary is. If the verbosity is not specified, then the DocTestRunner's verbosity is used. isitems had no tests:s sitems passed all tests:s %3d tests in %ssitems had failures:s %3d of %3d in %sstests insitems.s passed andsfailed.s***Test Failed***s failures.s Test passed.N(sverbosesNonesselfs_verbosesnotestsspassedsfailedstotaltstotalfs_name2ftsitemssxsnamesfstsAssertionErrorsappendslenssortsthingscountsDIVIDER( sselfsverbosescountsfstotaltsnamesfailedstspassedsxstotalfsthingsnotests((s/build\bdist.win32\egg\dispatch\tests\doctest.pys summarizexs\             cCs|i}xu|iiD]d\}\}}||jo5d|dGH||\}}||}||}n||f||>> runner = DebugRunner(verbose=False) >>> test = DocTestParser().get_doctest('>>> raise KeyError\n42', ... {}, 'foo', 'foo.py', 0) >>> try: ... runner.run(test) ... except UnexpectedException, failure: ... pass >>> failure.test is test True >>> failure.example.want '42\n' >>> exc_info = failure.exc_info >>> raise exc_info[0], exc_info[1], exc_info[2] Traceback (most recent call last): ... KeyError We wrap the original exception to give the calling application access to the test and example information. If the output doesn't match, then a DocTestFailure is raised: >>> test = DocTestParser().get_doctest(''' ... >>> x = 1 ... >>> x ... 2 ... ''', {}, 'foo', 'foo.py', 0) >>> try: ... runner.run(test) ... except DocTestFailure, failure: ... pass DocTestFailure objects provide access to the test: >>> failure.test is test True As well as to the example: >>> failure.example.want '2\n' and the actual output: >>> failure.got '1\n' If a failure or error occurs, the globals are left intact: >>> del test.globs['__builtins__'] >>> test.globs {'x': 1} >>> test = DocTestParser().get_doctest(''' ... >>> x = 2 ... >>> raise KeyError ... ''', {}, 'foo', 'foo.py', 0) >>> runner.run(test) Traceback (most recent call last): ... UnexpectedException: >>> del test.globs['__builtins__'] >>> test.globs {'x': 2} But the globals are cleared if there is no error: >>> test = DocTestParser().get_doctest(''' ... >>> x = 2 ... ''', {}, 'foo', 'foo.py', 0) >>> runner.run(test) (0, 1) >>> test.globs {} cCs;ti||||t}|o|i i n|SdS(N( s DocTestRunnersrunsselfstests compileflagssoutsFalsesrs clear_globssglobssclear(sselfstests compileflagssouts clear_globssr((s/build\bdist.win32\egg\dispatch\tests\doctest.pysrunscCst|||dS(N(sUnexpectedExceptionstestsexamplesexc_info(sselfsoutstestsexamplesexc_info((s/build\bdist.win32\egg\dispatch\tests\doctest.pysreport_unexpected_exceptionscCst|||dS(N(sDocTestFailurestestsexamplesgot(sselfsoutstestsexamplesgot((s/build\bdist.win32\egg\dispatch\tests\doctest.pysreport_failures(s__name__s __module__s__doc__sNonesTruesrunsreport_unexpected_exceptionsreport_failure(((s/build\bdist.win32\egg\dispatch\tests\doctest.pys DebugRunnergs Y c CsS|tj otidtn|tjotiid}nt i | ot d|fn|tjo |i }ntd|d| } |otd|d|} ntd|d|} x3| i||d|d |D]} | i| qW|o| inttjo | anti| | i | i!fSd S( s m=None, name=None, globs=None, verbose=None, isprivate=None, report=True, optionflags=0, extraglobs=None, raise_on_error=False, exclude_empty=False Test examples in docstrings in functions and classes reachable from module m (or the current module if m is not supplied), starting with m.__doc__. Unless isprivate is specified, private names are not skipped. Also test examples reachable from dict m.__test__ if it exists and is not None. m.__test__ maps names to functions, classes and strings; function and class docstrings are tested even if the name is private; strings are tested directly, as if they were docstrings. Return (#failures, #tests). See doctest.__doc__ for an overview. Optional keyword arg "name" gives the name of the module; by default use m.__name__. Optional keyword arg "globs" gives a dict to be used as the globals when executing examples; by default, use m.__dict__. A copy of this dict is actually used for each docstring, so that each docstring's examples start with a clean slate. Optional keyword arg "extraglobs" gives a dictionary that should be merged into the globals that are used to execute examples. By default, no extra globals are used. This is new in 2.4. Optional keyword arg "verbose" prints lots of stuff if true, prints only failures if false; by default, it's true iff "-v" is in sys.argv. Optional keyword arg "report" prints a summary at the end when true, else prints nothing at the end. In verbose mode, the summary is detailed, else very brief (in fact, empty if all tests passed). Optional keyword arg "optionflags" or's together module constants, and defaults to 0. This is new in 2.3. Possible values (see the docs for details): DONT_ACCEPT_TRUE_FOR_1 DONT_ACCEPT_BLANKLINE NORMALIZE_WHITESPACE ELLIPSIS IGNORE_EXCEPTION_DETAIL REPORT_UDIFF REPORT_CDIFF REPORT_NDIFF REPORT_ONLY_FIRST_FAILURE Optional keyword arg "raise_on_error" raises an exception on the first unexpected exception or failure. This allows failures to be post-mortem debugged. Deprecated in Python 2.4: Optional keyword arg "isprivate" specifies a function used to determine whether a name is private. The default function is treat all functions as public. Optionally, "isprivate" can be set to doctest.is_private to skip over functions marked as private using the underscore naming convention; see its docs for details. Advanced tomfoolery: testmod runs methods of a local instance of class doctest.Tester, then merges the results into (or creates) global Tester instance doctest.master. Methods of doctest.master can be called directly too, if you want to do something unusual. Passing report=0 to testmod is especially useful then, to delay displaying a summary. Invoke doctest.master.summarize(verbose) when you're done fiddling. sPthe isprivate argument is deprecated; examine DocTestFinder.find() lists insteads__main__stestmod: module required; %rs _namefilters exclude_emptysverboses optionflagssglobss extraglobsN("s isprivatesNoneswarningsswarnsDeprecationWarningsmssyssmodulessgetsinspectsismodules TypeErrorsnames__name__s DocTestFinders exclude_emptysfindersraise_on_errors DebugRunnersverboses optionflagssrunners DocTestRunnersfindsglobss extraglobsstestsrunsreports summarizesmastersmergesfailuresstries( smsnamesglobssverboses isprivatesreports optionflagss extraglobssraise_on_errors exclude_emptysrunnerstestsfinder((s/build\bdist.win32\egg\dispatch\tests\doctest.pystestmods0H         c Cse|o| otdn|ot|}t||}n|tjoti i |}n|tjo h}n |i }|tj o|i|n| otd|d|} ntd|d|} t|i} | i| |||d} | i| |o| inttjo | anti| | i | i!fSdS(s Test examples in the given file. Return (#failures, #tests). Optional keyword arg "module_relative" specifies how filenames should be interpreted: - If "module_relative" is True (the default), then "filename" specifies a module-relative path. By default, this path is relative to the calling module's directory; but if the "package" argument is specified, then it is relative to that package. To ensure os-independence, "filename" should use "/" characters to separate path segments, and should not be an absolute path (i.e., it may not begin with "/"). - If "module_relative" is False, then "filename" specifies an os-specific path. The path may be absolute or relative (to the current working directory). Optional keyword arg "name" gives the name of the test; by default use the file's basename. Optional keyword argument "package" is a Python package or the name of a Python package whose directory should be used as the base directory for a module relative filename. If no package is specified, then the calling module's directory is used as the base directory for module relative filenames. It is an error to specify "package" if "module_relative" is False. Optional keyword arg "globs" gives a dict to be used as the globals when executing examples; by default, use {}. A copy of this dict is actually used for each docstring, so that each docstring's examples start with a clean slate. Optional keyword arg "extraglobs" gives a dictionary that should be merged into the globals that are used to execute examples. By default, no extra globals are used. Optional keyword arg "verbose" prints lots of stuff if true, prints only failures if false; by default, it's true iff "-v" is in sys.argv. Optional keyword arg "report" prints a summary at the end when true, else prints nothing at the end. In verbose mode, the summary is detailed, else very brief (in fact, empty if all tests passed). Optional keyword arg "optionflags" or's together module constants, and defaults to 0. Possible values (see the docs for details): DONT_ACCEPT_TRUE_FOR_1 DONT_ACCEPT_BLANKLINE NORMALIZE_WHITESPACE ELLIPSIS IGNORE_EXCEPTION_DETAIL REPORT_UDIFF REPORT_CDIFF REPORT_NDIFF REPORT_ONLY_FIRST_FAILURE Optional keyword arg "raise_on_error" raises an exception on the first unexpected exception or failure. This allows failures to be post-mortem debugged. Optional keyword arg "parser" specifies a DocTestParser (or subclass) that should be used to extract tests from the files. Advanced tomfoolery: testmod runs methods of a local instance of class doctest.Tester, then merges the results into (or creates) global Tester instance doctest.master. Methods of doctest.master can be called directly too, if you want to do something unusual. Passing report=0 to testmod is especially useful then, to delay displaying a summary. Invoke doctest.master.summarize(verbose) when you're done fiddling. s8Package may only be specified for module-relative paths.sverboses optionflagsiN("spackagesmodule_relatives ValueErrors_normalize_modules_module_relative_pathsfilenamesnamesNonesosspathsbasenamesglobsscopys extraglobssupdatesraise_on_errors DebugRunnersverboses optionflagssrunners DocTestRunnersopensreadsssparsers get_docteststestsrunsreports summarizesmastersmergesfailuresstries(sfilenamesmodule_relativesnamespackagesglobssverbosesreports optionflagss extraglobssraise_on_errorsparsersrunnerstestss((s/build\bdist.win32\egg\dispatch\tests\doctest.pystestfileKs4J          sNoNamec Csdtd|dt}td|d|}x3|i||d|D]}|i |d|qCWdS(sr Test examples in the given object's docstring (`f`), using `globs` as globals. Optional argument `name` is used in failure messages. If the optional argument `verbose` is true, then generate output even if there are no failures. `compileflags` gives the set of flags that should be used by the Python compiler when running the examples. If not specified, then it will default to the set of future-import flags that apply to `globs`. Optional keyword arg `optionflags` specifies options for the testing and output. See the documentation for `testmod` for more information. sverbosesrecurses optionflagssglobss compileflagsN(s DocTestFindersverbosesFalsesfinders DocTestRunners optionflagssrunnersfindsfsnamesglobsstestsruns compileflags( sfsglobssverbosesnames compileflagss optionflagssrunnerstestsfinder((s/build\bdist.win32\egg\dispatch\tests\doctest.pysrun_docstring_exampless cBsbtZeeeeddZdZeedZedZdZedZdZ RS( NicCstidtdd|tjo |tjotdn|tj oti| otd|fn|tjo |i }n||_||_ ||_ ||_ td||_td|d||_dS( NsCclass Tester is deprecated; use class doctest.DocTestRunner insteads stacklevelis*Tester.__init__: must specify mod or globss)Tester.__init__: mod must be a module; %rs _namefiltersverboses optionflags(swarningsswarnsDeprecationWarningsmodsNonesglobss TypeErrorsinspectsismodules__dict__sselfsverboses isprivates optionflagss DocTestFinders testfinders DocTestRunners testrunner(sselfsmodsglobssverboses isprivates optionflags((s/build\bdist.win32\egg\dispatch\tests\doctest.pys__init__s         cCsti||i|tt}|io dG|GHn|i i |\}}|io|GdG|GdG|GHn||fSdS(NsRunning stringsofsexamples failed in string( s DocTestParsers get_doctestsssselfsglobssnamesNonestestsverboses testrunnersrunsfst(sselfsssnamesfststest((s/build\bdist.win32\egg\dispatch\tests\doctest.pys runstrings!   c Csd}}|ii||d|d|i}x@|D]8} |i i | \}}||||f\}}q5W||fSdS(Nismodulesglobs(sfstsselfs testfindersfindsobjectsnamesmodulesglobsstestsstests testrunnersrunsf2st2( sselfsobjectsnamesmodulestestssfst2sf2ststest((s/build\bdist.win32\egg\dispatch\tests\doctest.pysrundocs cCsVdk}|i|}|ii||tjo t}n|i |||SdS(N( snewsmodulesnamesms__dict__supdatesdsNonesFalsesselfsrundoc(sselfsdsnamesmodulesmsnew((s/build\bdist.win32\egg\dispatch\tests\doctest.pysrundicts    cCs5dk}|i|}||_|i||SdS(N(snewsmodulesnamesmsds__test__sselfsrundoc(sselfsdsnamesnewsm((s/build\bdist.win32\egg\dispatch\tests\doctest.pys run__test__s  cCs|ii|SdS(N(sselfs testrunners summarizesverbose(sselfsverbose((s/build\bdist.win32\egg\dispatch\tests\doctest.pys summarizescCs|ii|idS(N(sselfs testrunnersmergesother(sselfsother((s/build\bdist.win32\egg\dispatch\tests\doctest.pysmerges( s__name__s __module__sNones__init__s runstringsrundocsrundicts run__test__s summarizesmerge(((s/build\bdist.win32\egg\dispatch\tests\doctest.pysTesters    cCs8|t@|jotd|nt}|a|SdS(sSets the unittest option flags. The old flag is returned so that a runner could restore the old value if it wished to: >>> old = _unittest_reportflags >>> set_unittest_reportflags(REPORT_NDIFF | ... REPORT_ONLY_FIRST_FAILURE) == old True >>> import doctest >>> doctest._unittest_reportflags == (REPORT_NDIFF | ... REPORT_ONLY_FIRST_FAILURE) True Only reporting flags can be set: >>> set_unittest_reportflags(ELLIPSIS) Traceback (most recent call last): ... ValueError: ('Only reporting flags allowed', 8) >>> set_unittest_reportflags(old) == (REPORT_NDIFF | ... REPORT_ONLY_FIRST_FAILURE) True sOnly reporting flags allowedN(sflagssREPORTING_FLAGSs ValueErrors_unittest_reportflagssold(sflagssold((s/build\bdist.win32\egg\dispatch\tests\doctest.pysset_unittest_reportflags!ss DocTestCasecBsktZdeeedZdZdZdZdZdZdZ d Z e Z d Z RS( NicCsAtii|||_||_||_ ||_ ||_ dS(N(sunittestsTestCases__init__sselfs optionflagss_dt_optionflagsscheckers _dt_checkerstests_dt_testssetUps _dt_setUpstearDowns _dt_tearDown(sselfstests optionflagsssetUpstearDownschecker((s/build\bdist.win32\egg\dispatch\tests\doctest.pys__init__Gs     cCs.|i}|itj o|i|ndS(N(sselfs_dt_teststests _dt_setUpsNone(sselfstest((s/build\bdist.win32\egg\dispatch\tests\doctest.pyssetUpQs cCs;|i}|itj o|i|n|iidS(N(sselfs_dt_teststests _dt_tearDownsNonesglobssclear(sselfstest((s/build\bdist.win32\egg\dispatch\tests\doctest.pystearDownWs cCs|i}ti}t}|i}|t @ o|t O}nt d|d|i dt}z5dd|_|i|d|idt\}}Wd|t_X|o"|i|i|indS(Ns optionflagsscheckersverboses-iFsouts clear_globs(sselfs_dt_teststestssyssstdoutsoldsStringIOsnews_dt_optionflagss optionflagssREPORTING_FLAGSs_unittest_reportflagss DocTestRunners _dt_checkersFalsesrunnersDIVIDERsrunswritesfailuresstriessfailureExceptionsformat_failuresgetvalue(sselfsoldsrunnerstriessfailuresstestsnews optionflags((s/build\bdist.win32\egg\dispatch\tests\doctest.pysrunTest_s       ( cCsp|i}|itjo d}nd|i}di|iidd}d|i|i |||fSdS(Nsunknown line numbers%ss.is:Failed doctest test for %s File "%s", line %s, in %s %s( sselfs_dt_teststestslinenosNonesjoinsnamessplitslnamesfilenameserr(sselfserrslnameslinenostest((s/build\bdist.win32\egg\dispatch\tests\doctest.pysformat_failurews    cCsI|itd|id|idt}|i|i|i dS(sRun the test case without results and without catching exceptions The unit test framework includes a debug method on test cases and test suites to support post-mortem debugging. The test code is run in such a way that errors are not caught. This way a caller can catch the errors and initiate post-mortem debugging. The DocTestCase provides a debug method that raises UnexpectedException errors if there is an unexepcted exception: >>> test = DocTestParser().get_doctest('>>> raise KeyError\n42', ... {}, 'foo', 'foo.py', 0) >>> case = DocTestCase(test) >>> try: ... case.debug() ... except UnexpectedException, failure: ... pass The UnexpectedException contains the test, the example, and the original exception: >>> failure.test is test True >>> failure.example.want '42\n' >>> exc_info = failure.exc_info >>> raise exc_info[0], exc_info[1], exc_info[2] Traceback (most recent call last): ... KeyError If the output doesn't match, then a DocTestFailure is raised: >>> test = DocTestParser().get_doctest(''' ... >>> x = 1 ... >>> x ... 2 ... ''', {}, 'foo', 'foo.py', 0) >>> case = DocTestCase(test) >>> try: ... case.debug() ... except DocTestFailure, failure: ... pass DocTestFailure objects provide access to the test: >>> failure.test is test True As well as to the example: >>> failure.example.want '2\n' and the actual output: >>> failure.got '1\n' s optionflagsscheckersverboseN( sselfssetUps DebugRunners_dt_optionflagss _dt_checkersFalsesrunnersruns_dt_teststearDown(sselfsrunner((s/build\bdist.win32\egg\dispatch\tests\doctest.pysdebugs @  cCs|iiSdS(N(sselfs_dt_testsname(sself((s/build\bdist.win32\egg\dispatch\tests\doctest.pysidscCs8|iiid}d|ddi|d fSdS(Ns.s%s (%s)i(sselfs_dt_testsnamessplitsjoin(sselfsname((s/build\bdist.win32\egg\dispatch\tests\doctest.pys__repr__scCsd|iiSdS(Ns Doctest: (sselfs_dt_testsname(sself((s/build\bdist.win32\egg\dispatch\tests\doctest.pysshortDescriptions( s__name__s __module__sNones__init__ssetUpstearDownsrunTestsformat_failuresdebugsids__repr__s__str__sshortDescription(((s/build\bdist.win32\egg\dispatch\tests\doctest.pys DocTestCaseEs    H  c Ks|tjo t}nt|}|i|d|d|}|tjo |i }n| ot |dn|i t i }x|D]}t|idjoqn|i o;|i}|dddfjo|d }n||_n|it||qW|Sd S( s Convert doctest tests for a module to a unittest test suite. This converts each documentation string in a module that contains doctest tests to a unittest test case. If any of the tests in a doc string fail, then the test case fails. An exception is raised showing the name of the file containing the test and a (sometimes approximate) line number. The `module` argument provides the module to be tested. The argument can be either a module or a module name. If no argument is given, the calling module is used. A number of options may be provided as keyword arguments: setUp A set-up function. This is called before running the tests in each file. The setUp function will be passed a DocTest object. The setUp function can access the test globals as the globs attribute of the test passed. tearDown A tear-down function. This is called after running the tests in each file. The tearDown function will be passed a DocTest object. The tearDown function can access the test globals as the globs attribute of the test passed. globs A dictionary containing initial global variables for the tests. optionflags A set of doctest option flags expressed as an integer. sglobss extraglobss has no testsiis.pycs.pyoiN(s test_findersNones DocTestFinders_normalize_modulesmodulesfindsglobss extraglobsstestss__dict__s ValueErrorssortsunittests TestSuitessuitestestslensexamplessfilenames__file__saddTests DocTestCasesoptions( smodulesglobss extraglobss test_findersoptionsstestsstestssuitesfilename((s/build\bdist.win32\egg\dispatch\tests\doctest.pys DocTestSuites,#          s DocFileCasecBs)tZdZdZeZdZRS(NcCs di|iiidSdS(Ns_s.(sjoinsselfs_dt_testsnamessplit(sself((s/build\bdist.win32\egg\dispatch\tests\doctest.pysid scCs|iiSdS(N(sselfs_dt_testsfilename(sself((s/build\bdist.win32\egg\dispatch\tests\doctest.pys__repr__ scCs!d|ii|ii|fSdS(Ns2Failed doctest test for %s File "%s", line 0 %s(sselfs_dt_testsnamesfilenameserr(sselfserr((s/build\bdist.win32\egg\dispatch\tests\doctest.pysformat_failure s(s__name__s __module__sids__repr__s__str__sformat_failure(((s/build\bdist.win32\egg\dispatch\tests\doctest.pys DocFileCase s  c Ks|tjo h}n|o| otdn|ot|}t||}ntii |}t |i }|i||||d}t||SdS(Ns8Package may only be specified for module-relative paths.i(sglobssNonespackagesmodule_relatives ValueErrors_normalize_modules_module_relative_pathspathsossbasenamesnamesopensreadsdocsparsers get_docteststests DocFileCasesoptions( spathsmodule_relativespackagesglobssparsersoptionssnamesdocstest((s/build\bdist.win32\egg\dispatch\tests\doctest.pys DocFileTest$ s   cOskti}|idtot|id|dA unittest suite for one or more doctest files. The path to each doctest file is given as a string; the interpretation of that string depends on the keyword argument "module_relative". A number of options may be provided as keyword arguments: module_relative If "module_relative" is True, then the given file paths are interpreted as os-independent module-relative paths. By default, these paths are relative to the calling module's directory; but if the "package" argument is specified, then they are relative to that package. To ensure os-independence, "filename" should use "/" characters to separate path segments, and may not be an absolute path (i.e., it may not begin with "/"). If "module_relative" is False, then the given file paths are interpreted as os-specific paths. These paths may be absolute or relative (to the current working directory). package A Python package or the name of a Python package whose directory should be used as the base directory for module relative paths. If "package" is not specified, then the calling module's directory is used as the base directory for module relative filenames. It is an error to specify "package" if "module_relative" is False. setUp A set-up function. This is called before running the tests in each file. The setUp function will be passed a DocTest object. The setUp function can access the test globals as the globs attribute of the test passed. tearDown A tear-down function. This is called after running the tests in each file. The tearDown function will be passed a DocTest object. The tearDown function can access the test globals as the globs attribute of the test passed. globs A dictionary containing initial global variables for the tests. optionflags A set of doctest option flags expressed as an integer. parser A DocTestParser (or subclass) that should be used to extract tests from the files. smodule_relativespackageN( sunittests TestSuitessuiteskwsgetsTrues_normalize_modulespathsspathsaddTests DocFileTest(spathsskwspathssuite((s/build\bdist.win32\egg\dispatch\tests\doctest.pys DocFileSuite: s4 cCsNg}xti|D]}t|tou|i|id |i }|oM|id|gi}|i dd D]}|d|q~~7}qq|gi}|i dd D]}|t |q~7}qWx'|o|ddjo|iqWx*|o|ddjo|idqWdi|SdS(scExtract script from text with examples. Converts text with examples to a Python script. Example input is converted to regular code. Example output and all other words are converted to comments: >>> text = ''' ... Here are examples of simple math. ... ... Python has super accurate integer addition ... ... >>> 2 + 2 ... 5 ... ... And very friendly error messages: ... ... >>> 1/0 ... To Infinity ... And ... Beyond ... ... You can use logic if you want: ... ... >>> if 0: ... ... blah ... ... blah ... ... ... ... Ho hum ... ''' >>> print script_from_examples(text) # Here are examples of simple math. # # Python has super accurate integer addition # 2 + 2 # Expected: ## 5 # # And very friendly error messages: # 1/0 # Expected: ## To Infinity ## And ## Beyond # # You can use logic if you want: # if 0: blah blah # # Ho hum is # Expected:s s## s#iN(soutputs DocTestParsersparsessspieces isinstancesExamplesappendssourceswants_[1]ssplitsls _comment_linespopsjoin(ssspiecesls_[1]swantsoutput((s/build\bdist.win32\egg\dispatch\tests\doctest.pysscript_from_examples s$8  DBcCst|}ti|}gi}|D]$}|i|jo||q,q,~}| ot |dn|d}t |i }|SdS(sExtract the test sources from a doctest docstring as a script. Provide the module (or dotted name of the module) containing the test to be debugged and the name (within the module) of the object with the doc string with tests to be debugged. snot found in testsiN(s_normalize_modulesmodules DocTestFindersfindstestssappends_[1]stsnamestests ValueErrorsscript_from_exampless docstringstestsrc(smodulesnamestestss_[1]stestsrcststest((s/build\bdist.win32\egg\dispatch\tests\doctest.pys testsource s ; cCs t|}t|||dS(s4Debug a single doctest docstring, in argument `src`'N(sscript_from_examplesssrcstestsrcs debug_scriptspmsglobs(ssrcspmsglobsstestsrc((s/build\bdist.win32\egg\dispatch\tests\doctest.pys debug_src s cCsdk}tidd}t|d}|i||iz|o|i }nh}|oHyt |||Wqt idGH|it idqXn|id|||Wdti|XdS(s7Debug a test script. `src` is the script, as a string.Ns.pys doctestdebugswiis execfile(%r)(spdbstempfilesmktemps srcfilenamesopensfswritessrcsclosesglobsscopyspmsexecfilessyssexc_infos post_mortemsrunsossremove(ssrcspmsglobssfs srcfilenamespdb((s/build\bdist.win32\egg\dispatch\tests\doctest.pys debug_script s&   cCs2t|}t||}t|||idS(sDebug a single doctest docstring. Provide the module (or dotted name of the module) containing the test to be debugged and the name (within the module) of the object with the docstring with tests to be debugged. N(s_normalize_modulesmodules testsourcesnamestestsrcs debug_scriptspms__dict__(smodulesnamespmstestsrc((s/build\bdist.win32\egg\dispatch\tests\doctest.pysdebug s s _TestClasscBs)tZdZdZdZdZRS(s A pointless class, for sanity-checking of docstring testing. Methods: square() get() >>> _TestClass(13).get() + _TestClass(-12).get() 1 >>> hex(_TestClass(13).square().get()) '0xa9' cCs ||_dS(sval -> _TestClass object with associated value val. >>> t = _TestClass(123) >>> print t.get() 123 N(svalsself(sselfsval((s/build\bdist.win32\egg\dispatch\tests\doctest.pys__init__! scCs|id|_|SdS(sosquare() -> square TestClass's associated value >>> _TestClass(13).square().get() 169 iN(sselfsval(sself((s/build\bdist.win32\egg\dispatch\tests\doctest.pyssquare+ scCs |iSdS(s}get() -> return TestClass's associated value. >>> x = _TestClass(-42) >>> print x.get() -42 N(sselfsval(sself((s/build\bdist.win32\egg\dispatch\tests\doctest.pysget5 s(s__name__s __module__s__doc__s__init__ssquaresget(((s/build\bdist.win32\egg\dispatch\tests\doctest.pys _TestClass s  sstrings Example of a string object, searched as-is. >>> x = 1; y = 2 >>> x + y, x * y (3, 2) sbool-int equivalences In 2.2, boolean expressions displayed 0 or 1. By default, we still accept them. This can be disabled by passing DONT_ACCEPT_TRUE_FOR_1 to the new optionflags argument. >>> 4 == 4 1 >>> 4 == 4 True >>> 4 > 4 0 >>> 4 > 4 False s blank liness Blank lines can be marked with : >>> print 'foo\n\nbar\n' foo bar sellipsiss If the ellipsis flag is used, then '...' can be used to elide substrings in the desired output: >>> print range(1000) #doctest: +ELLIPSIS [0, 1, 2, ..., 999] swhitespace normalizations| If the whitespace normalization flag is used, then differences in whitespace are ignored. >>> print range(30) #doctest: +NORMALIZE_WHITESPACE [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29] cCs ti}|itdS(N(sunittestsTextTestRunnersrsruns DocTestSuite(sr((s/build\bdist.win32\egg\dispatch\tests\doctest.pys_testq s s__main__(Ts basestrings NameErrorsstrsunicodes enumerates __docformat__s__all__s __future__ssyss tracebacksinspects linecachesossrestypessunittestsdifflibspdbstempfileswarningssStringIOsfilterwarningssDeprecationWarnings__name__sOPTIONFLAGS_BY_NAMEsregister_optionflagsDONT_ACCEPT_TRUE_FOR_1sDONT_ACCEPT_BLANKLINEsNORMALIZE_WHITESPACEsELLIPSISsIGNORE_EXCEPTION_DETAILsCOMPARISON_FLAGSs REPORT_UDIFFs REPORT_CDIFFs REPORT_NDIFFsREPORT_ONLY_FIRST_FAILUREsREPORTING_FLAGSsBLANKLINE_MARKERsELLIPSIS_MARKERs is_privates_extract_future_flagss_normalize_modules_indents_exception_tracebacks _SpoofOuts_ellipsis_matchs _comment_linesPdbs_OutputRedirectingPdbs_module_relative_pathsExamplesDocTests DocTestParsers DocTestFinders DocTestRunners OutputCheckers ExceptionsDocTestFailuresUnexpectedExceptions DebugRunnersNonesmastersTruesFalsestestmodstestfilesrun_docstring_examplessTesters_unittest_reportflagssset_unittest_reportflagssTestCases DocTestCases DocTestSuites DocFileCases DocFileTests DocFileSuitesscript_from_exampless testsources debug_srcs debug_scriptsdebugs _TestClasss__test__s_test(Fs_module_relative_paths __future__s OutputCheckersBLANKLINE_MARKERsunittestsNORMALIZE_WHITESPACEs __docformat__stestmods_normalize_modules REPORT_UDIFFsDONT_ACCEPT_TRUE_FOR_1s enumerates_OutputRedirectingPdbs_ellipsis_matchs basestringsIGNORE_EXCEPTION_DETAILs__all__sTesterstempfiles DocFileCases DocTestRunners DocFileTestsres is_privatesDocTestFailures DocTestCasesELLIPSISs_tests _comment_lines REPORT_CDIFFs testsourcesDocTestsDONT_ACCEPT_BLANKLINEs _SpoofOutswarningss DocFileSuitesrun_docstring_examplessREPORT_ONLY_FIRST_FAILUREsinspects _TestClasss debug_scriptssyssdebugsscript_from_exampless debug_srcs__test__s_extract_future_flagss_indentsExamplestypess DocTestSuitesregister_optionflagsOPTIONFLAGS_BY_NAMEs DocTestParsersStringIOsset_unittest_reportflagss REPORT_NDIFFs tracebacksdifflibs linecaches DocTestFinders DebugRunnersELLIPSIS_MARKERsREPORTING_FLAGSsCOMPARISON_FLAGSsUnexpectedExceptionsosspdbstestfiles_exception_traceback((s/build\bdist.win32\egg\dispatch\tests\doctest.pys? s(i. ?$                  1  $5<+n't*vA $? F P  ,<2  PK98OY Y EGG-INFO/PKG-INFOMetadata-Version: 1.0 Name: RuleDispatch Version: 0.5a1.dev-r2506 Summary: Rule-based Dispatching and Generic Functions Home-page: http://pypi.python.org/pypi/RuleDispatch Author: Phillip J. Eby Author-email: peak@eby-sarna.com License: PSF or ZPL Download-URL: http://peak.telecommunity.com/snapshots/ Description: RuleDispatch ============ RuleDispatch is a prototype implementation of the Chambers and Chen "efficient multiple and predicate dispatch" algorithm for Python. It lets you specify a function in terms of a collection of arbitrary rules, including Lisp-style "before/after/around" methods. Although it is used by various projects, including ``peak.security.rules`` and TurboGears, it is no longer being actively developed. It is expected to be replaced by the more extensible PEAK-Rules package, which is currently in development (with snapshot and SVN releases available in PyPI). Please note that if you are starting new development, you are almost certainly better off using PEAK-Rules instead. It is smaller, has a simpler API, and for certain use cases can be significantly faster than RuleDispatch. It was also developed from the ground up using TDD, which means that every single line of its code is tested. In contrast, the central core of RuleDispatch was developed many years ago using a hack, slash, and burn methodology, with only some functional tests and very few unit tests. The consequences of this can be seen in the number of RuleDispatch bugs that have occurred over the last few years that involve the core engine in some way. So, although I will continue to accept bug reports and apply fixes to RuleDispatch, it is absolutely a dead parrot, and there are no plans to update its documentation, tests, or anything else. Use it at your own risk. Python 2.5 Issues ----------------- RuleDispatch has not been updated for certain additions to the Python 2.5 grammar. It does not support any kind of loops, generator expressions or "y if x else z" conditional expressions in rules, and its behavior if you use them is undefined. Mailing List ------------ Please direct questions regarding this package to the PEAK mailing list; see http://www.eby-sarna.com/mailman/listinfo/PEAK/ for details. Platform: UNKNOWN PK98WEGG-INFO/SOURCES.txt.cvsignore README.txt TODO.txt setup.cfg setup.py ez_setup/README.txt ez_setup/__init__.py src/dispatch/_d_speedups.c src/RuleDispatch.egg-info/PKG-INFO src/RuleDispatch.egg-info/SOURCES.txt src/RuleDispatch.egg-info/dependency_links.txt src/RuleDispatch.egg-info/native_libs.txt src/RuleDispatch.egg-info/requires.txt src/RuleDispatch.egg-info/top_level.txt src/RuleDispatch.egg-info/zip-safe src/dispatch/__init__.py src/dispatch/_d_speedups.c src/dispatch/_d_speedups.pyx src/dispatch/ast_builder.py src/dispatch/combiners.py src/dispatch/combiners.txt src/dispatch/functions.py src/dispatch/interfaces.py src/dispatch/predicates.py src/dispatch/strategy.py src/dispatch/tests/__init__.py src/dispatch/tests/doctest.py src/dispatch/tests/test_dispatch.py src/dispatch/tests/test_parsing.pyPK982EGG-INFO/dependency_links.txt PK:8]NEGG-INFO/native_libs.txtdispatch/_d_speedups.pyd PK98h=9))EGG-INFO/requires.txtPyProtocols>=1.0a0dev-r2302 Extremes>=1.1PK98 EGG-INFO/top_level.txtdispatch PK͚\82EGG-INFO/zip-safe PKK\8I$$dispatch/ast_builder.pyPKK\8NnvIvI$dispatch/predicates.pyPKK\8fndispatch/__init__.pyPKK\83(hdispatch/interfaces.pyPKK\8OecKcK۟dispatch/functions.pyPKK\8L`qdispatch/combiners.pyPKK\8Eradispatch/strategy.pyPKK\8hhydispatch/combiners.txtPK:8YOdispatch/_d_speedups.pydPK:8d**ldispatch/ast_builder.pycPK:8=,ϗdispatch/predicates.pycPK:8ŏ'dispatch/__init__.pycPK:8T׳<<Adispatch/interfaces.pycPK:8pvDlDl~dispatch/functions.pycPK:8ng? ? 6dispatch/combiners.pycPK:8Qޛdispatch/strategy.pycPK:8Gdispatch/_d_speedups.pyPK:88))dispatch/_d_speedups.pycPKK\8W||?dispatch/tests/test_parsing.pyPKK\8  Ldispatch/tests/__init__.pyPKK\8>>YMdispatch/tests/test_dispatch.pyPKK\8fv dispatch/tests/doctest.pyPK:8ʳLLdispatch/tests/test_parsing.pycPK:8=Q|+dispatch/tests/__init__.pycPK:84Is00 .dispatch/tests/test_dispatch.pycPK:84uu,_ dispatch/tests/doctest.pycPK98OY Y  EGG-INFO/PKG-INFOPK98W EGG-INFO/SOURCES.txtPK982 EGG-INFO/dependency_links.txtPK:8]N EGG-INFO/native_libs.txtPK98h=9))j EGG-INFO/requires.txtPK98  EGG-INFO/top_level.txtPK͚\82 EGG-INFO/zip-safePK!!3