From pedronis at codespeak.net Tue Mar 1 00:50:44 2005 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Tue, 1 Mar 2005 00:50:44 +0100 (MET) Subject: [pypy-svn] r9533 - in pypy/dist: goal pypy/objspace Message-ID: <20050228235044.1959F27B4C@code1.codespeak.net> Author: pedronis Date: Tue Mar 1 00:50:43 2005 New Revision: 9533 Added: pypy/dist/goal/translate_pypy0.py (contents, props changed) pypy/dist/pypy/objspace/dummy.py (contents, props changed) Log: dummy object space to try to annotate only the interpreter, with corresponding driver (translate_pypy0). Right now the annotator starts quite happily, but then gets confused by the multiple inheritance impls of frames. Added: pypy/dist/goal/translate_pypy0.py ============================================================================== --- (empty file) +++ pypy/dist/goal/translate_pypy0.py Tue Mar 1 00:50:43 2005 @@ -0,0 +1,286 @@ +# +# +# +""" +Command-line options for translate_pypy: + + port Listen on the given port number for connexions + (see pypy/translator/tool/pygame/graphclient.py) + -text Don't start the Pygame viewer + -no-a Don't infer annotations, just translate everything + -no-c Don't generate the C code + -c Generate the C code, but don't compile it + -o Generate and compile the C code, but don't run it + -no-mark-some-objects + Do not mark functions that have SomeObject in their signature. + -tcc Equivalent to the envvar PYPY_CC='tcc -shared -o "%s.so" "%s.c"' + -- http://fabrice.bellard.free.fr/tcc/ + -no-d Disable recording of debugging information +""" +import autopath, sys, threading, pdb, os +import buildcache2 +from pypy.objspace.std.objspace import StdObjSpace, W_Object +from pypy.objspace.std.intobject import W_IntObject +from pypy.translator.translator import Translator +from pypy.annotation import model as annmodel +from pypy.tool.cache import Cache +from pypy.annotation.model import SomeObject +from pypy.tool.udir import udir + +from pypy.objspace import dummy +from pypy.interpreter.pycode import PyCode + +# XXX this tries to make compiling faster +from pypy.translator.tool import buildpyxmodule +buildpyxmodule.enable_fast_compilation() + +# __________ Entry point __________ + +def entry_point(code, w_loc): + code2 = PyCode(space) + code2 = code2._from_code(code) + code2.exec_code(space, space.wrap({}), w_loc) + +# __________ Main __________ + +def analyse(entry_point=entry_point): + global t, space + space = dummy.DummyObjSpace() + # call cache filling code + #buildcache2.buildcache(space) + # further call the entry_point once to trigger building remaining + # caches (as far as analyzing the entry_point is concerned) + + from pypy.interpreter import pycode + from pypy.interpreter import pyopcode + from pypy.interpreter import nestedscope + from pypy.interpreter import generator + + for comb in ((),(nestedscope.PyNestedScopeFrame,),(generator.GeneratorFrame,),(nestedscope.PyNestedScopeFrame,generator.GeneratorFrame)): + F = pyopcode.PyInterpFrame + for x in comb: + F = pycode.enhanceclass(F, x) + #print F.__mro__ + + t = Translator(entry_point, verbose=True, simplifying=True) + if listen_port: + run_async_server() + if not options['-no-a']: + a = t.annotate([object, dummy.W_Obj]) + a.simplify() + t.frozen = True # cannot freeze if we don't have annotations + if not options['-no-mark-some-objects']: + options['-no-mark-some-objects'] = True # Do not do this again + find_someobjects(t) + + +def find_someobjects(translator, quiet=False): + """Find all functions in that have SomeObject in their signature.""" + annotator = translator.annotator + if not annotator: + return # no annotations available + + translator.highlight_functions = {} + + def is_someobject(var): + try: + return annotator.binding(var).__class__ == SomeObject + except KeyError: + return False + + def short_binding(var): + try: + binding = annotator.binding(var) + except KeyError: + return "?" + if binding.is_constant(): + return 'const %s' % binding.__class__.__name__ + else: + return binding.__class__.__name__ + + header = True + items = [(graph.name, func, graph) + for func, graph in translator.flowgraphs.items()] + items.sort() + num = someobjnum = 0 + for graphname, func, graph in items: + unknown_input_args = len(filter(is_someobject, graph.getargs())) + unknown_return_value = is_someobject(graph.getreturnvar()) + if unknown_input_args or unknown_return_value: + someobjnum += 1 + translator.highlight_functions[func] = True + if not quiet: + if header: + header = False + print "=" * 70 + print "Functions that have SomeObject in their signature" + print "=" * 70 + print ("%(name)s(%(args)s) -> %(result)s\n" + "%(filename)s:%(lineno)s\n" + % {'name': graph.name, + 'filename': func.func_globals.get('__name__', '?'), + 'lineno': func.func_code.co_firstlineno, + 'args': ', '.join(map(short_binding, + graph.getargs())), + 'result': short_binding(graph.getreturnvar())}) + num += 1 + if not quiet: + print "=" * 70 + percent = int(num and (100.0*someobjnum / num) or 0) + print "somobjectness: %2d percent" % (percent) + print "(%d out of %d functions get or return SomeObjects" % ( + someobjnum, num) + print "=" * 70 + + +def update_usession_dir(stabledir = udir.dirpath('usession')): + from py import path + try: + if stabledir.check(dir=1): + for x in udir.visit(path.checker(file=1)): + target = stabledir.join(x.relto(udir)) + if target.check(): + target.remove() + else: + target.dirpath().ensure(dir=1) + try: + target.mklinkto(x) + except path.Invalid: + x.copy(target) + except path.Invalid: + print "ignored: couldn't link or copy to %s" % stabledir + +def run_in_thread(fn, args, cleanup=None, cleanup_args=()): + def _run_in_thread(): + fn(*args) + if cleanup is not None: + cleanup(*cleanup_args) + return threading.Thread(target=_run_in_thread, args=()) + +def run_async_server(): + from pypy.translator.tool import graphpage, graphserver + homepage = graphpage.TranslatorPage(t) + graphserver.run_server(homepage, port=listen_port, background=True) + options['-text'] = True + + +if __name__ == '__main__': + + options = {'-text': False, + '-no-c': False, + '-c': False, + '-o': False, + '-no-mark-some-objects': False, + '-no-a': False, + '-tcc': False, + '-no-d': False, + } + listen_port = None + for arg in sys.argv[1:]: + if arg in ('-h', '--help'): + print __doc__.strip() + sys.exit() + try: + listen_port = int(arg) + except ValueError: + assert arg in options, "unknown option %r" % (arg,) + options[arg] = True + if options['-tcc']: + os.environ['PYPY_CC'] = 'tcc -shared -o "%s.so" "%s.c"' + if options['-no-d']: + annmodel.DEBUG = False + + def about(x): + """ interactive debugging helper """ + from pypy.objspace.flow.model import Block, flatten + if isinstance(x, Block): + for func, graph in t.flowgraphs.items(): + if x in flatten(graph): + funcname = func.func_name + cls = getattr(func, 'class_', None) + if cls: + funcname = '%s.%s' % (cls.__name__, funcname) + print '%s is a %s in the graph of %s' % (x, + x.__class__.__name__, funcname) + print 'at %s:%d' % (func.func_globals.get('__name__', '?'), + func.func_code.co_firstlineno) + break + else: + print '%s is a %s at some unknown location' % (x, + x.__class__.__name__) + print 'containing the following operations:' + for op in x.operations: + print op + print '--end--' + return + print "don't know about", x + + def run_server(): + from pypy.translator.tool.graphpage import TranslatorPage + from pypy.translator.tool.pygame.graphclient import get_layout + from pypy.translator.tool.pygame.graphdisplay import GraphDisplay + import pygame + + if not options['-no-mark-some-objects']: + find_someobjects(t, quiet=True) + + display = GraphDisplay(get_layout(TranslatorPage(t))) + async_quit = display.async_quit + return display.run, async_quit, pygame.quit + + def debug(got_error): + if got_error: + import traceback + exc, val, tb = sys.exc_info() + print >> sys.stderr + traceback.print_exception(exc, val, tb) + print >> sys.stderr + + block = getattr(val, '__annotator_block', None) + if block: + print '-'*60 + about(block) + print '-'*60 + + print >> sys.stderr + func, args = pdb.post_mortem, (tb,) + else: + print '-'*60 + print 'Done.' + print + func, args = pdb.set_trace, () + if options['-text']: + func(*args) + else: + start, stop, cleanup = run_server() + debugger = run_in_thread(func, args, stop) + debugger.start() + start() + debugger.join() + cleanup() + + try: + analyse() + print '-'*60 + if options['-no-c']: + print 'Not generating C code.' + elif options['-c']: + print 'Generating C code without compiling it...' + filename = t.ccompile(really_compile=False) + update_usession_dir() + print 'Written %s.' % (filename,) + else: + print 'Generating and compiling C code...' + c_entry_point = t.ccompile() + update_usession_dir() + if not options['-o']: + print 'Running!' + w_result = c_entry_point() + print w_result + print w_result.intval + assert w_result.intval == 42 + except: + debug(True) + else: + debug(False) + Added: pypy/dist/pypy/objspace/dummy.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/objspace/dummy.py Tue Mar 1 00:50:43 2005 @@ -0,0 +1,119 @@ +from pypy.interpreter.baseobjspace import ObjSpace, W_Root +from pypy.interpreter.module import Module +from pypy.interpreter.error import OperationError + +class W_Obj(W_Root): + + def is_true(self): + return True + + def str_w(self, space): + raise OperatioError(space.w_TypeError,space.wrap("!")) + + def int_w(self, space): + raise OperatioError(space.w_TypeError,space.wrap("!")) + + def float_w(self, space): + raise OperatioError(space.w_TypeError,space.wrap("!")) + + def unwrap(self, space): + raise OperatioError(space.w_TypeError,space.wrap("!")) + +class W_Str(W_Obj): + def __init__(self, s): + self.s = s + + def is_true(self): + return self.s != "" + + def str_w(self, space): + return self.s + + def unwrap(self, space): + return self.s + +class W_Int(W_Obj): + def __init__(self, i): + self.i = i + + def is_true(self): + return self.i != 0 + + def int_w(self, space): + return self.i + + def unwrap(self, space): + return self.i + +class W_None(W_Obj): + + def unwrap(self, space): + return None + +class W_Special(W_Obj): + def __init__(self, spec): + self.spec = spec + + +class DummyObjSpace(ObjSpace): + + def __init__(self): + """NOT_RPYTHON""" + self.builtin = Module(self, self.wrap('__builtin__'), self.wrap({})) + def pick_builtin(w_globals): + return self.builtin + self.builtin.pick_builtin = pick_builtin + self.sys = Module(self, self.wrap('sys'), self.wrap({})) + self.sys.recursionlimit = 1000 + + self.w_None = W_None() + self.w_NotImplemented = W_Special(NotImplemented) + self.w_Ellpisis = W_Special(Ellipsis) + self.w_False = self.wrap(0) + self.w_True = self.wrap(1) + + for en in ObjSpace.ExceptionTable: + setattr(self, 'w_'+en, self.wrap(en)) + + for n, symbol, arity, ign in ObjSpace.MethodTable+[('newdict',"",1,[]), ('newtuple',"",1,[]), ('newslice',"",3,[]), ]: + source = ("""if 1: + def %s(self, %s): + return W_Obj() +""" % (n, ', '.join(["w_a%d" % i for i in range(arity)]))) + #print source + exec source + + del n, symbol, arity, ign, i + + def wrap(self, obj): + if obj is None: + return self.w_None + if isinstance(obj, str): + return W_Str(obj) + if isinstance(obj, int): + return W_Int(obj) + return W_Obj() + wrap._specialize_ = "argtypes" + + def call_args(self, w_obj, args): + return W_Obj() + + def is_true(self, w_obj): + return w_obj.is_true() + + def str_w(self, w_obj): + return w_obj.str_w(self) + + def int_w(self, w_obj): + return w_obj.int_w(self) + + def float_w(self, w_obj): + return w_obj.float_w(self) + + def unwrap(self, w_obj): + return w_obj.unwrap(self) + + +if __name__ == '__main__': + dummy_space = DummyObjSpace() + print dummy_space.eval("a+b",dummy_space.wrap({'a': 1,'b': 2}),dummy_space.wrap({})) From tismer at codespeak.net Tue Mar 1 10:34:17 2005 From: tismer at codespeak.net (tismer at codespeak.net) Date: Tue, 1 Mar 2005 10:34:17 +0100 (MET) Subject: [pypy-svn] r9534 - pypy/dist/pypy/translator Message-ID: <20050301093417.CA94927B40@code1.codespeak.net> Author: tismer Date: Tue Mar 1 10:34:17 2005 New Revision: 9534 Modified: pypy/dist/pypy/translator/geninterplevel.py Log: added support for the new SpecTag construct in framestate.py . This tag type triggers specialization on different values. We use this for goto labels, hopefully producing less and more efficient code on the second flow graph pass. As a side effect, initialization of locals should become obsolete. Modified: pypy/dist/pypy/translator/geninterplevel.py ============================================================================== --- pypy/dist/pypy/translator/geninterplevel.py (original) +++ pypy/dist/pypy/translator/geninterplevel.py Tue Mar 1 10:34:17 2005 @@ -10,17 +10,10 @@ that globals are constants, for instance. This definition is not exact and might change. -This module appears to be already quite usable. -But I need to ask how we want to integrate it. - -XXX open questions: -- do we want a moduleperapp-spaceoperation? -- do we want to auto-generate stuff? -- do we want to create code that is more similar to the app code? -- do we want to create specialized code for constants? -- do we want to use small tail-functions instead of goto? -- do we want to inline small functions? -- do we want to translate non-rpythonic code as well? +Integration of this module will be done half-automatically +using a simple caching mechanism. The generated files are +not meant to be checked into svn, although this currently +still happens. """ from __future__ import generators @@ -45,6 +38,8 @@ from pypy.tool.sourcetools import render_docstr +import pypy # __path__ +import py.path # ____________________________________________________________ def c_string(s): @@ -165,6 +160,8 @@ self.space = FlowObjSpace() # for introspection self.use_fast_call = True + self.specialize_goto = True + self._labeltable = {} # unique label names, reused per func self._space_arities = None @@ -279,6 +276,19 @@ res = [line + nonestr for line in res] return res + def mklabel(self, blocknum): + if self.specialize_goto: + lbname = self._labeltable.get(blocknum) + if not lbname: + self.initcode.append( + 'from pypy.objspace.flow.framestate import SpecTag') + lbname = self.uniquename("glabel_%d" % blocknum) + self._labeltable[blocknum] = lbname + self.initcode.append('m.%s = SpecTag()' % lbname) + return lbname + else: + return repr(blocknum) + def gen_link(self, link, localvars, blocknum, block, linklocalvars=None): "Generate the code to jump across the given Link." linklocalvars = linklocalvars or {} @@ -298,7 +308,7 @@ for line in self.large_assignment(left, right): yield line goto = blocknum[link.target] - yield 'goto = %d' % goto + yield 'goto = %s' % self.mklabel(goto) if goto <= blocknum[block]: yield 'continue' @@ -373,7 +383,7 @@ self.initcode.append('m.%s = space.wrap(%r)' % (name, value)) return name name = self.uniquename('g_object') - self.initcode.appendnew('_tup= space.newtuple([])\n' + self.initcode.appendnew('_tup = space.newtuple([])\n' 'm.%s = space.call(space.w_object, _tup)' % name) return name @@ -927,7 +937,17 @@ for name in g: pass # self.initcode.append('# REGISTER_GLOBAL(%s)' % (name,)) del g[:] - + + def rel_filename(self, name): + # try to find a name relative to pypy and unify. + # if not possible, stick with the original. + ref = py.path.local(pypy.__path__[0]) + rel = py.path.local(name).relto(ref) + if rel: + # make it os independent + return rel.replace('\\', '/') + return name # no success + def gen_rpyfunction(self, func): f = self.f @@ -935,7 +955,7 @@ print >> f, ("## filename %r\n" "## function %r\n" "## firstlineno %d") % ( - os.path.basename(func.func_code.co_filename), + self.rel_filename(func.func_code.co_filename), func.func_code.co_name, func.func_code.co_firstlineno) print >> f, "##SECTION##" @@ -1038,13 +1058,13 @@ print >> f, docstr fast_locals = [arg for arg in localnames if arg not in fast_set] - if fast_locals: + # if goto is specialized, the false detection of + # uninitialized variables goes away. + if fast_locals and not self.specialize_goto: print >> f for line in self.large_initialize(fast_locals): print >> f, " %s" % line print >> f - # generate an incref for each input argument - # skipped # print the body for line in body: @@ -1088,7 +1108,7 @@ for block in allblocks: blocknum[block] = len(blocknum)+1 - yield " goto = %d # startblock" % blocknum[start] + yield " goto = %s # startblock" % self.mklabel(blocknum[start]) yield " while True:" def render_block(block): @@ -1168,10 +1188,11 @@ for op in self.gen_link(exits[-1], localvars, blocknum, block): yield " %s" % op + cmpop = ('==', 'is') [self.specialize_goto] for block in allblocks: blockno = blocknum[block] yield "" - yield " if goto == %d:" % blockno + yield " if goto %s %s:" % (cmpop, self.mklabel(blockno)) for line in render_block(block): yield " %s" % line @@ -1531,4 +1552,4 @@ """ if __name__ == '__main__': - res = translate_as_module(testcode)#, tmpname='/tmp/look.py') + res = translate_as_module(testcode, tmpname='/tmp/look.py') From tismer at codespeak.net Tue Mar 1 10:35:09 2005 From: tismer at codespeak.net (tismer at codespeak.net) Date: Tue, 1 Mar 2005 10:35:09 +0100 (MET) Subject: [pypy-svn] r9535 - pypy/dist/pypy/module Message-ID: <20050301093509.26BEA27B40@code1.codespeak.net> Author: tismer Date: Tue Mar 1 10:35:08 2005 New Revision: 9535 Modified: pypy/dist/pypy/module/classobjinterp.py Log: after change of geninterplevel, regenerated this file (XXX should goout of svn) python translator/tool/tointerplevel.py --modname classobj --out module/classobjinterp.py lib/_classobj.py classobj instance purify Modified: pypy/dist/pypy/module/classobjinterp.py ============================================================================== --- pypy/dist/pypy/module/classobjinterp.py (original) +++ pypy/dist/pypy/module/classobjinterp.py Tue Mar 1 10:35:08 2005 @@ -1,13 +1,8 @@ #!/bin/env python # -*- coding: LATIN-1 -*- -from pypy.interpreter.error import OperationError -from pypy.interpreter.argument import Arguments -from pypy.interpreter import gateway - - ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function '_coerce' ## firstlineno 7 ##SECTION## @@ -21,55 +16,52 @@ f__coerce = _coerce def _coerce(space, w_left, w_right): - - w_0=w_3=w_4=w_5=w_6=w_7=v8=w_9=w_10=w_11=w_12=v13=w_etype=w_evalue=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: try: w_0 = space.coerce(w_left, w_right) w_3 = w_0 - goto = 5 + goto = glabel_5 except OperationError, e: if space.is_true(space.issubtype(e.w_type, space.w_Exception)): w_4, w_5, w_6 = e.w_type, e.w_value, e.w_type - goto = 2 + goto = glabel_2 else:raise # unhandled case, should not happen - if goto == 2: + if goto is glabel_2: w_7 = space.is_(w_6, space.w_TypeError) v8 = space.is_true(w_7) if v8 == True: w_3 = space.w_None - goto = 5 + goto = glabel_5 else: assert v8 == False w_9, w_10, w_11 = w_4, w_5, w_6 - goto = 3 + goto = glabel_3 - if goto == 3: + if goto is glabel_3: w_12 = space.issubtype(w_11, space.w_TypeError) v13 = space.is_true(w_12) if v13 == True: w_3 = space.w_None - goto = 5 + goto = glabel_5 else: assert v13 == False w_etype, w_evalue = w_9, w_10 - goto = 4 + goto = glabel_4 - if goto == 4: + if goto is glabel_4: raise OperationError(w_etype, w_evalue) - if goto == 5: + if goto is glabel_5: return w_3 fastf__coerce = _coerce ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function 'uid' ## firstlineno 18 ##SECTION## @@ -88,38 +80,35 @@ f_uid = uid def uid(space, w_o): - - w_v=w_2=v3=w_4=w_v_1=w_v_2=w_v_3=w_v_4=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_v = space.id(w_o) w_2 = space.lt(w_v, gi_0) v3 = space.is_true(w_2) if v3 == True: w_v_1 = w_v - goto = 2 + goto = glabel_2 else: assert v3 == False w_4 = w_v - goto = 3 + goto = glabel_3 - if goto == 2: + if goto is glabel_2: w_v_2 = space.inplace_add(w_v_1, glong_0x7fffffffL) w_v_3 = space.inplace_add(w_v_2, glong_0x7fffffffL) w_v_4 = space.inplace_add(w_v_3, gi_2) w_4 = w_v_4 - goto = 3 + goto = glabel_3 - if goto == 3: + if goto is glabel_3: return w_4 fastf_uid = uid ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function 'type_err' ## firstlineno 35 ##SECTION## @@ -136,28 +125,25 @@ f_type_err = type_err def type_err(space, w_arg, w_expected, w_v): - - w_0=w_2=w_3=w_6=w_7=w_8=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_0 = space.call_function(space.w_type, w_v) w_2 = space.getattr(w_0, gs___name__) w_3 = space.newtuple([w_arg, w_expected, w_2]) w_6 = space.mod(gs_argument__s_must_be__s__not__s, w_3) w_7 = space.call_function(space.w_TypeError, w_6) w_8 = w_7 - goto = 2 + goto = glabel_2 - if goto == 2: + if goto is glabel_2: return w_8 fastf_type_err = type_err ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function 'set_name' ## firstlineno 38 ##SECTION## @@ -175,40 +161,37 @@ f_set_name = set_name def set_name(space, w_cls, w_name): - - w_0=v2=w_etype=w_evalue=w_cls_1=w_name_1=w_6=w_7=w_8=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_0 = space.isinstance(w_name, space.w_str) v2 = space.is_true(w_0) if v2 == True: w_cls_1, w_name_1 = w_cls, w_name - goto = 2 + goto = glabel_2 else: assert v2 == False (w_etype, w_evalue) = (space.w_TypeError, gs___name___must_be_a_string_object) - goto = 3 + goto = glabel_3 - if goto == 2: + if goto is glabel_2: w_6 = space.getattr(gdescriptor_classobj__name, gs___set__) w_7 = space.call_function(w_6, w_cls_1, w_name_1) w_8 = space.w_None - goto = 4 + goto = glabel_4 - if goto == 3: + if goto is glabel_3: raise OperationError(w_etype, w_evalue) - if goto == 4: + if goto is glabel_4: return w_8 fastf_set_name = set_name ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function 'set_bases' ## firstlineno 43 ##SECTION## @@ -229,71 +212,66 @@ f_set_bases = set_bases def set_bases(space, w_cls, w_bases): - - w_0=v2=w_etype=w_evalue=w_cls_1=w_bases_1=w_6=w_cls_2=w_bases_2=None - w_7=w_b=w_cls_3=w_bases_3=w_9=w_b_1=w_10=v11=w_cls_4=w_bases_4=None - w_12=w_13=w_14=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_0 = space.isinstance(w_bases, space.w_tuple) v2 = space.is_true(w_0) if v2 == True: w_cls_1, w_bases_1 = w_cls, w_bases - goto = 2 + goto = glabel_2 else: assert v2 == False (w_etype, w_evalue) = (space.w_TypeError, gs___bases___must_be_a_tuple_object) - goto = 6 + goto = glabel_6 - if goto == 2: + if goto is glabel_2: w_6 = space.iter(w_bases_1) w_cls_2, w_bases_2, w_7 = w_cls_1, w_bases_1, w_6 - goto = 3 + goto = glabel_3 - if goto == 3: + if goto is glabel_3: try: w_b = space.next(w_7) w_cls_3, w_bases_3, w_9, w_b_1 = w_cls_2, w_bases_2, w_7, w_b - goto = 4 + goto = glabel_4 except OperationError, e: if space.is_true(space.issubtype(e.w_type, space.w_StopIteration)): w_cls_4, w_bases_4 = w_cls_2, w_bases_2 - goto = 5 + goto = glabel_5 else:raise # unhandled case, should not happen - if goto == 4: + if goto is glabel_4: w_10 = space.isinstance(w_b_1, gcls_classobj) v11 = space.is_true(w_10) if v11 == True: w_cls_2, w_bases_2, w_7 = w_cls_3, w_bases_3, w_9 - goto = 3 + goto = glabel_3 continue else: assert v11 == False (w_etype, w_evalue) = (space.w_TypeError, gs___bases___items_must_be_classes) - goto = 6 + goto = glabel_6 - if goto == 5: + if goto is glabel_5: w_12 = space.getattr(gdescriptor_classobj__bases, gs___set__) w_13 = space.call_function(w_12, w_cls_4, w_bases_4) w_14 = space.w_None - goto = 7 + goto = glabel_7 - if goto == 6: + if goto is glabel_6: raise OperationError(w_etype, w_evalue) - if goto == 7: + if goto is glabel_7: return w_14 fastf_set_bases = set_bases ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function 'set_dict' ## firstlineno 51 ##SECTION## @@ -311,39 +289,36 @@ f_set_dict = set_dict def set_dict(space, w_cls, w_dic): - - w_0=v2=w_etype=w_evalue=w_cls_1=w_dic_1=w_6=w_7=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_0 = space.isinstance(w_dic, space.w_dict) v2 = space.is_true(w_0) if v2 == True: w_cls_1, w_dic_1 = w_cls, w_dic - goto = 2 + goto = glabel_2 else: assert v2 == False (w_etype, w_evalue) = (space.w_TypeError, gs___dict___must_be_a_dictionary_ob) - goto = 3 + goto = glabel_3 - if goto == 2: + if goto is glabel_2: w_6 = space.call_function(gdescriptor_object___setattr__, w_cls_1, gs___dict__, w_dic_1) w_7 = space.w_None - goto = 4 + goto = glabel_4 - if goto == 3: + if goto is glabel_3: raise OperationError(w_etype, w_evalue) - if goto == 4: + if goto is glabel_4: return w_7 fastf_set_dict = set_dict ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function 'retrieve' ## firstlineno 56 ##SECTION## @@ -362,62 +337,58 @@ f_retrieve = retrieve def retrieve(space, w_obj, w_attr): - - w_dic=w_2=w_4=w_attr_1=w_5=w_6=w_7=w_8=v9=w_attr_2=w_12=w_13=None - w_14=w_15=v16=w_etype=w_evalue=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_dic = space.call_function(gdescriptor_object___getattribute__, w_obj, gs___dict__) try: w_2 = space.getitem(w_dic, w_attr) w_4 = w_2 - goto = 5 + goto = glabel_5 except OperationError, e: if space.is_true(space.issubtype(e.w_type, space.w_IndexError)): (w_attr_1, w_5, w_6, w_7) = (w_attr, space.w_IndexError, e.w_value, space.w_IndexError) - goto = 2 + goto = glabel_2 elif space.is_true(space.issubtype(e.w_type, space.w_KeyError)): (w_attr_1, w_5, w_6, w_7) = (w_attr, space.w_KeyError, e.w_value, space.w_KeyError) - goto = 2 + goto = glabel_2 else:raise # unhandled case, should not happen - if goto == 2: + if goto is glabel_2: w_8 = space.is_(w_7, space.w_KeyError) v9 = space.is_true(w_8) if v9 == True: w_etype, w_evalue = space.w_AttributeError, w_attr_1 - goto = 4 + goto = glabel_4 else: assert v9 == False w_attr_2, w_12, w_13, w_14 = w_attr_1, w_5, w_6, w_7 - goto = 3 + goto = glabel_3 - if goto == 3: + if goto is glabel_3: w_15 = space.issubtype(w_14, space.w_KeyError) v16 = space.is_true(w_15) if v16 == True: w_etype, w_evalue = space.w_AttributeError, w_attr_2 - goto = 4 + goto = glabel_4 else: assert v16 == False w_etype, w_evalue = w_12, w_13 - goto = 4 + goto = glabel_4 - if goto == 4: + if goto is glabel_4: raise OperationError(w_etype, w_evalue) - if goto == 5: + if goto is glabel_5: return w_4 fastf_retrieve = retrieve ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function 'lookup' ## firstlineno 63 ##SECTION## @@ -434,122 +405,115 @@ f_lookup = lookup def lookup(space, w_cls, w_attr): - - w_v=w_cls_1=w_v_1=w_6=w_7=w_cls_2=w_attr_1=w_3=w_4=w_5=w_8=v9=None - w_cls_4=w_attr_3=w_10=w_11=w_12=w_13=v14=w_etype=w_evalue=w_cls_5=None - w_attr_4=w_17=w_18=w_19=w_attr_5=w_20=w_b=w_attr_6=w_25=w_b_1=None - w_26=w_27=w_28=v29=w_attr_7=w_30=w_31=w_v_2=w_found=v33=w_v_3=None - w_found_1=w_34=w_cls_3=w_attr_2=w_21=w_22=w_23=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: try: w_v = fastf_retrieve(space, w_cls, w_attr) w_cls_1, w_v_1 = w_cls, w_v - goto = 2 + goto = glabel_2 except OperationError, e: if space.is_true(space.issubtype(e.w_type, space.w_Exception)): (w_cls_2, w_attr_1, w_3, w_4, w_5) = (w_cls, w_attr, e.w_type, e.w_value, e.w_type) - goto = 3 + goto = glabel_3 else:raise # unhandled case, should not happen - if goto == 2: + if goto is glabel_2: w_6 = space.newtuple([w_v_1, w_cls_1]) w_7 = w_6 - goto = 12 + goto = glabel_12 - if goto == 3: + if goto is glabel_3: w_8 = space.is_(w_5, space.w_AttributeError) v9 = space.is_true(w_8) if v9 == True: w_cls_3, w_attr_2 = w_cls_2, w_attr_1 - goto = 6 + goto = glabel_6 else: assert v9 == False (w_cls_4, w_attr_3, w_10, w_11, w_12) = (w_cls_2, w_attr_1, w_3, w_4, w_5) - goto = 4 + goto = glabel_4 - if goto == 4: + if goto is glabel_4: w_13 = space.issubtype(w_12, space.w_AttributeError) v14 = space.is_true(w_13) if v14 == True: w_cls_5, w_attr_4 = w_cls_4, w_attr_3 - goto = 5 + goto = glabel_5 else: assert v14 == False w_etype, w_evalue = w_10, w_11 - goto = 11 + goto = glabel_11 - if goto == 5: + if goto is glabel_5: w_17 = space.getattr(gdescriptor_classobj__bases, gs___get__) w_18 = space.call_function(w_17, w_cls_5) w_19 = space.iter(w_18) w_attr_5, w_20 = w_attr_4, w_19 - goto = 7 + goto = glabel_7 - if goto == 6: + if goto is glabel_6: w_21 = space.getattr(gdescriptor_classobj__bases, gs___get__) w_22 = space.call_function(w_21, w_cls_3) w_23 = space.iter(w_22) w_attr_5, w_20 = w_attr_2, w_23 - goto = 7 + goto = glabel_7 - if goto == 7: + if goto is glabel_7: try: w_b = space.next(w_20) w_attr_6, w_25, w_b_1 = w_attr_5, w_20, w_b - goto = 8 + goto = glabel_8 except OperationError, e: if space.is_true(space.issubtype(e.w_type, space.w_StopIteration)): w_7 = g2tuple_1 - goto = 12 + goto = glabel_12 else:raise # unhandled case, should not happen - if goto == 8: + if goto is glabel_8: w_26 = fastf_lookup(space, w_b_1, w_attr_6) w_27 = space.len(w_26) w_28 = space.eq(w_27, gi_2) v29 = space.is_true(w_28) if v29 == True: w_attr_7, w_30, w_31 = w_attr_6, w_25, w_26 - goto = 9 + goto = glabel_9 else: assert v29 == False w_etype, w_evalue = space.w_ValueError, space.w_None - goto = 11 + goto = glabel_11 - if goto == 9: + if goto is glabel_9: w_v_2 = space.getitem(w_31, gi_0) w_found = space.getitem(w_31, gi_1) v33 = space.is_true(w_found) if v33 == True: w_v_3, w_found_1 = w_v_2, w_found - goto = 10 + goto = glabel_10 else: assert v33 == False w_attr_5, w_20 = w_attr_7, w_30 - goto = 7 + goto = glabel_7 continue - if goto == 10: + if goto is glabel_10: w_34 = space.newtuple([w_v_3, w_found_1]) w_7 = w_34 - goto = 12 + goto = glabel_12 - if goto == 11: + if goto is glabel_11: raise OperationError(w_etype, w_evalue) - if goto == 12: + if goto is glabel_12: return w_7 fastf_lookup = lookup ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function 'get_class_module' ## firstlineno 75 ##SECTION## @@ -557,6 +521,8 @@ # global object gfunc_retrieve # global object gcls_Exception # global object gcls_AttributeError +# global object glabel_6 +# global object glabel_5 def get_class_module(space, __args__): funcname = "get_class_module" @@ -568,68 +534,64 @@ f_get_class_module = get_class_module def get_class_module(space, w_cls): - - w_mod=w_mod_1=w_10=v11=w_12=w_2=w_3=w_4=w_5=v6=w_7=w_8=w_9=w_13=None - v14=w_etype=w_evalue=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: try: w_mod = fastf_retrieve(space, w_cls, gs___module__) w_mod_1 = w_mod - goto = 3 + goto = glabel_3 except OperationError, e: if space.is_true(space.issubtype(e.w_type, space.w_Exception)): w_2, w_3, w_4 = e.w_type, e.w_value, e.w_type - goto = 2 + goto = glabel_2 else:raise # unhandled case, should not happen - if goto == 2: + if goto is glabel_2: w_5 = space.is_(w_4, space.w_AttributeError) v6 = space.is_true(w_5) if v6 == True: w_mod_1 = space.w_None - goto = 3 + goto = glabel_3 else: assert v6 == False w_7, w_8, w_9 = w_2, w_3, w_4 - goto = 4 + goto = glabel_4 - if goto == 3: + if goto is glabel_3: w_10 = space.isinstance(w_mod_1, space.w_str) v11 = space.is_true(w_10) if v11 == True: w_12 = w_mod_1 - goto = 6 + goto = glabel_6 else: assert v11 == False w_12 = gs__ - goto = 6 + goto = glabel_6 - if goto == 4: + if goto is glabel_4: w_13 = space.issubtype(w_9, space.w_AttributeError) v14 = space.is_true(w_13) if v14 == True: w_mod_1 = space.w_None - goto = 3 + goto = glabel_3 continue else: assert v14 == False w_etype, w_evalue = w_7, w_8 - goto = 5 + goto = glabel_5 - if goto == 5: + if goto is glabel_5: raise OperationError(w_etype, w_evalue) - if goto == 6: + if goto is glabel_6: return w_12 fastf_get_class_module = get_class_module ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function 'mro_lookup' ## firstlineno 84 ##SECTION## @@ -646,67 +608,63 @@ f_mro_lookup = mro_lookup def mro_lookup(space, w_v, w_name): - - w_0=w_mro=w_name_1=w_mro_1=w_5=w_name_2=w_6=w_x=w_name_3=w_8=None - w_x_1=w_9=w_10=v11=w_name_4=w_x_2=w_12=w_13=w_4=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_0 = space.call_function(space.w_type, w_v) try: w_mro = space.getattr(w_0, gs___mro__) w_name_1, w_mro_1 = w_name, w_mro - goto = 2 + goto = glabel_2 except OperationError, e: if space.is_true(space.issubtype(e.w_type, space.w_AttributeError)): w_4 = space.w_None - goto = 6 + goto = glabel_6 else:raise # unhandled case, should not happen - if goto == 2: + if goto is glabel_2: w_5 = space.iter(w_mro_1) w_name_2, w_6 = w_name_1, w_5 - goto = 3 + goto = glabel_3 - if goto == 3: + if goto is glabel_3: try: w_x = space.next(w_6) w_name_3, w_8, w_x_1 = w_name_2, w_6, w_x - goto = 4 + goto = glabel_4 except OperationError, e: if space.is_true(space.issubtype(e.w_type, space.w_StopIteration)): w_4 = space.w_None - goto = 6 + goto = glabel_6 else:raise # unhandled case, should not happen - if goto == 4: + if goto is glabel_4: w_9 = space.getattr(w_x_1, gs___dict__) w_10 = space.contains(w_9, w_name_3) v11 = space.is_true(w_10) if v11 == True: w_name_4, w_x_2 = w_name_3, w_x_1 - goto = 5 + goto = glabel_5 else: assert v11 == False w_name_2, w_6 = w_name_3, w_8 - goto = 3 + goto = glabel_3 continue - if goto == 5: + if goto is glabel_5: w_12 = space.getattr(w_x_2, gs___dict__) w_13 = space.getitem(w_12, w_name_4) w_4 = w_13 - goto = 6 + goto = glabel_6 - if goto == 6: + if goto is glabel_6: return w_4 fastf_mro_lookup = mro_lookup ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function '__new__' ## firstlineno 112 ##SECTION## @@ -714,20 +672,34 @@ # global object gfunc_type_err # global object gs_name # global object gs_string +# global object glabel_32 # global object g0tuple # global object gs_bases # global object gs_tuple # global object gs_dict # global object gs___doc__ +# global object glabel_25 +# global object glabel_27 # global object gs__getframe +# global object glabel_22 # global object gs_f_globals # global object gs_get # global object gs_OLD_STYLE_CLASSES_IMPL # global object g_object +# global object glabel_20 +# global object glabel_23 # global object gcls_OverflowError # global object gcls_FloatingPointError +# global object glabel_21 +# global object glabel_24 +# global object glabel_26 +# global object glabel_28 +# global object glabel_31 +# global object glabel_29 # global object gs_callable +# global object glabel_30 # global object gs_base_must_be_class +# global object glabel_33 def __new__(space, __args__): funcname = "__new__" @@ -739,372 +711,349 @@ f___new__ = __new__ def __new__(space, w_subtype, w_name, w_bases, w_dic): - - w_0=v2=w_name_2=w_5=w_6=w_etype=w_evalue=w_name_1=w_bases_1=w_dic_1=None - w_9=v10=w_name_3=w_bases_2=w_dic_2=w_11=v12=w_bases_4=w_13=w_14=None - w_name_4=w_bases_3=w_dic_3=w_15=v16=w_dic_5=w_17=w_18=w_name_5=None - w_bases_5=w_dic_4=w_19=w_name_6=w_bases_6=w_dic_6=w_30=w_name_11=None - w_bases_11=w_dic_11=w_66=w_name_24=w_bases_24=w_dic_24=w_67=w_b=None - w_name_25=w_bases_25=w_dic_25=w_69=w_b_1=w_72=v73=w_name_27=w_bases_27=None - w_dic_27=w_b_2=w_74=w_75=v76=w_name_28=w_bases_28=w_dic_28=w_b_3=None - w_77=w_78=w_79=w_name_26=w_bases_26=w_dic_26=w_new_class=w_81=None - w_82=w_83=w_84=w_85=w_name_12=w_bases_12=w_dic_12=w_31=w_32=w_33=None - w_34=v35=w_name_14=w_bases_14=w_dic_14=w_37=w_38=w_39=w_70=v71=None - w_name_13=w_bases_13=w_dic_13=w_i=w_42=w_name_15=w_bases_15=w_dic_15=None - w_i_1=w_43=w_g=w_name_17=w_bases_17=w_dic_17=w_i_2=w_g_1=w_48=None - w_name_18=w_bases_18=w_dic_18=w_i_3=w_g_2=w_49=w_50=w_name_19=None - w_bases_19=w_dic_19=w_i_4=w_g_3=w_51=w_52=v53=w_name_21=w_bases_21=None - w_dic_21=w_g_4=w_61=w_modname=w_63=v64=w_name_23=w_bases_23=w_dic_23=None - w_modname_1=w_65=w_name_20=w_bases_20=w_dic_20=w_i_5=w_i_6=w_name_16=None - w_bases_16=w_dic_16=w_44=w_45=w_46=w_59=v60=w_name_22=w_bases_22=None - w_dic_22=w_57=w_58=w_55=w_54=v56=w_name_7=w_bases_7=w_dic_7=w_20=None - w_21=w_22=w_23=v24=w_name_9=w_bases_9=w_dic_9=w_25=w_26=w_27=None - w_40=v41=w_name_10=w_bases_10=w_dic_10=w_28=w_name_8=w_bases_8=None - w_dic_8=w_29=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_0 = space.isinstance(w_name, space.w_str) v2 = space.is_true(w_0) if v2 == True: w_name_1, w_bases_1, w_dic_1 = w_name, w_bases, w_dic - goto = 3 + goto = glabel_3 else: assert v2 == False w_name_2 = w_name - goto = 2 + goto = glabel_2 - if goto == 2: + if goto is glabel_2: w_5 = fastf_type_err(space, gs_name, gs_string, w_name_2) w_6 = space.type(w_5) w_etype, w_evalue = w_6, w_5 - goto = 32 + goto = glabel_32 - if goto == 3: + if goto is glabel_3: w_9 = space.is_(w_bases_1, space.w_None) v10 = space.is_true(w_9) if v10 == True: w_name_3, w_bases_2, w_dic_2 = w_name_1, g0tuple, w_dic_1 - goto = 4 + goto = glabel_4 else: assert v10 == False w_name_3, w_bases_2, w_dic_2 = w_name_1, w_bases_1, w_dic_1 - goto = 4 + goto = glabel_4 - if goto == 4: + if goto is glabel_4: w_11 = space.isinstance(w_bases_2, space.w_tuple) v12 = space.is_true(w_11) if v12 == True: w_name_4, w_bases_3, w_dic_3 = w_name_3, w_bases_2, w_dic_2 - goto = 6 + goto = glabel_6 else: assert v12 == False w_bases_4 = w_bases_2 - goto = 5 + goto = glabel_5 - if goto == 5: + if goto is glabel_5: w_13 = fastf_type_err(space, gs_bases, gs_tuple, w_bases_4) w_14 = space.type(w_13) w_etype, w_evalue = w_14, w_13 - goto = 32 + goto = glabel_32 - if goto == 6: + if goto is glabel_6: w_15 = space.isinstance(w_dic_3, space.w_dict) v16 = space.is_true(w_15) if v16 == True: w_name_5, w_bases_5, w_dic_4 = w_name_4, w_bases_3, w_dic_3 - goto = 8 + goto = glabel_8 else: assert v16 == False w_dic_5 = w_dic_3 - goto = 7 + goto = glabel_7 - if goto == 7: + if goto is glabel_7: w_17 = fastf_type_err(space, gs_dict, gs_dict, w_dic_5) w_18 = space.type(w_17) w_etype, w_evalue = w_18, w_17 - goto = 32 + goto = glabel_32 - if goto == 8: + if goto is glabel_8: try: w_19 = space.getitem(w_dic_4, gs___doc__) w_name_6, w_bases_6, w_dic_6 = w_name_5, w_bases_5, w_dic_4 - goto = 12 + goto = glabel_12 except OperationError, e: if space.is_true(space.issubtype(e.w_type, space.w_IndexError)): (w_name_7, w_bases_7, w_dic_7, w_20, w_21, w_22) = (w_name_5, w_bases_5, w_dic_4, space.w_IndexError, e.w_value, space.w_IndexError) - goto = 9 + goto = glabel_9 elif space.is_true(space.issubtype(e.w_type, space.w_KeyError)): (w_name_7, w_bases_7, w_dic_7, w_20, w_21, w_22) = (w_name_5, w_bases_5, w_dic_4, space.w_KeyError, e.w_value, space.w_KeyError) - goto = 9 + goto = glabel_9 else:raise # unhandled case, should not happen - if goto == 9: + if goto is glabel_9: w_23 = space.is_(w_22, space.w_KeyError) v24 = space.is_true(w_23) if v24 == True: w_name_8, w_bases_8, w_dic_8 = w_name_7, w_bases_7, w_dic_7 - goto = 11 + goto = glabel_11 else: assert v24 == False (w_name_9, w_bases_9, w_dic_9, w_25, w_26, w_27) = (w_name_7, w_bases_7, w_dic_7, w_20, w_21, w_22) - goto = 14 + goto = glabel_14 - if goto == 10: + if goto is glabel_10: w_28 = space.setitem(w_dic_10, gs___doc__, space.w_None) w_name_6, w_bases_6, w_dic_6 = w_name_10, w_bases_10, w_dic_10 - goto = 12 + goto = glabel_12 - if goto == 11: + if goto is glabel_11: w_29 = space.setitem(w_dic_8, gs___doc__, space.w_None) w_name_6, w_bases_6, w_dic_6 = w_name_8, w_bases_8, w_dic_8 - goto = 12 + goto = glabel_12 - if goto == 12: + if goto is glabel_12: try: w_30 = space.getitem(w_dic_6, gs___module__) w_name_11, w_bases_11, w_dic_11 = w_name_6, w_bases_6, w_dic_6 - goto = 25 + goto = glabel_25 except OperationError, e: if space.is_true(space.issubtype(e.w_type, space.w_IndexError)): (w_name_12, w_bases_12, w_dic_12, w_31, w_32, w_33) = (w_name_6, w_bases_6, w_dic_6, space.w_IndexError, e.w_value, space.w_IndexError) - goto = 13 + goto = glabel_13 elif space.is_true(space.issubtype(e.w_type, space.w_KeyError)): (w_name_12, w_bases_12, w_dic_12, w_31, w_32, w_33) = (w_name_6, w_bases_6, w_dic_6, space.w_KeyError, e.w_value, space.w_KeyError) - goto = 13 + goto = glabel_13 else:raise # unhandled case, should not happen - if goto == 13: + if goto is glabel_13: w_34 = space.is_(w_33, space.w_KeyError) v35 = space.is_true(w_34) if v35 == True: (w_name_13, w_bases_13, w_dic_13, w_i) = (w_name_12, w_bases_12, w_dic_12, gi_0) - goto = 15 + goto = glabel_15 else: assert v35 == False (w_name_14, w_bases_14, w_dic_14, w_37, w_38, w_39) = (w_name_12, w_bases_12, w_dic_12, w_31, w_32, w_33) - goto = 27 + goto = glabel_27 - if goto == 14: + if goto is glabel_14: w_40 = space.issubtype(w_27, space.w_KeyError) v41 = space.is_true(w_40) if v41 == True: w_name_10, w_bases_10, w_dic_10 = w_name_9, w_bases_9, w_dic_9 - goto = 10 + goto = glabel_10 continue else: assert v41 == False w_etype, w_evalue = w_25, w_26 - goto = 32 + goto = glabel_32 - if goto == 15: + if goto is glabel_15: try: w_42 = space.call_function((space.sys.get(space.str_w(gs__getframe))), w_i) (w_name_15, w_bases_15, w_dic_15, w_i_1, w_43) = (w_name_13, w_bases_13, w_dic_13, w_i, w_42) - goto = 16 + goto = glabel_16 except OperationError, e: if space.is_true(space.issubtype(e.w_type, space.w_Exception)): (w_name_16, w_bases_16, w_dic_16, w_44, w_45, w_46) = (w_name_13, w_bases_13, w_dic_13, e.w_type, e.w_value, e.w_type) - goto = 22 + goto = glabel_22 else:raise # unhandled case, should not happen - if goto == 16: + if goto is glabel_16: try: w_g = space.getattr(w_43, gs_f_globals) (w_name_17, w_bases_17, w_dic_17, w_i_2, w_g_1) = (w_name_15, w_bases_15, w_dic_15, w_i_1, w_g) - goto = 17 + goto = glabel_17 except OperationError, e: if space.is_true(space.issubtype(e.w_type, space.w_AttributeError)): (w_name_16, w_bases_16, w_dic_16, w_44, w_45, w_46) = (w_name_15, w_bases_15, w_dic_15, space.w_AttributeError, e.w_value, space.w_AttributeError) - goto = 22 + goto = glabel_22 else:raise # unhandled case, should not happen - if goto == 17: + if goto is glabel_17: try: w_48 = space.getattr(w_g_1, gs_get) (w_name_18, w_bases_18, w_dic_18, w_i_3, w_g_2, w_49) = (w_name_17, w_bases_17, w_dic_17, w_i_2, w_g_1, w_48) - goto = 18 + goto = glabel_18 except OperationError, e: if space.is_true(space.issubtype(e.w_type, space.w_AttributeError)): (w_name_16, w_bases_16, w_dic_16, w_44, w_45, w_46) = (w_name_17, w_bases_17, w_dic_17, space.w_AttributeError, e.w_value, space.w_AttributeError) - goto = 22 + goto = glabel_22 else:raise # unhandled case, should not happen - if goto == 18: + if goto is glabel_18: try: w_50 = space.call_function(w_49, gs_OLD_STYLE_CLASSES_IMPL, space.w_None) (w_name_19, w_bases_19, w_dic_19, w_i_4, w_g_3, w_51) = (w_name_18, w_bases_18, w_dic_18, w_i_3, w_g_2, w_50) - goto = 19 + goto = glabel_19 except OperationError, e: if space.is_true(space.issubtype(e.w_type, space.w_Exception)): (w_name_16, w_bases_16, w_dic_16, w_44, w_45, w_46) = (w_name_18, w_bases_18, w_dic_18, e.w_type, e.w_value, e.w_type) - goto = 22 + goto = glabel_22 else:raise # unhandled case, should not happen - if goto == 19: + if goto is glabel_19: w_52 = space.is_(w_51, g_object) v53 = space.is_true(w_52) if v53 == True: (w_name_20, w_bases_20, w_dic_20, w_i_5) = (w_name_19, w_bases_19, w_dic_19, w_i_4) - goto = 20 + goto = glabel_20 else: assert v53 == False (w_name_21, w_bases_21, w_dic_21, w_g_4) = (w_name_19, w_bases_19, w_dic_19, w_g_3) - goto = 23 + goto = glabel_23 - if goto == 20: + if goto is glabel_20: try: w_i_6 = space.inplace_add(w_i_5, gi_1) (w_name_13, w_bases_13, w_dic_13, w_i) = (w_name_20, w_bases_20, w_dic_20, w_i_6) - goto = 15 + goto = glabel_15 continue except OperationError, e: if space.is_true(space.issubtype(e.w_type, space.w_OverflowError)): (w_name_16, w_bases_16, w_dic_16, w_44, w_45, w_46) = (w_name_20, w_bases_20, w_dic_20, space.w_OverflowError, e.w_value, space.w_OverflowError) - goto = 22 + goto = glabel_22 elif space.is_true(space.issubtype(e.w_type, space.w_FloatingPointError)): (w_name_16, w_bases_16, w_dic_16, w_44, w_45, w_46) = (w_name_20, w_bases_20, w_dic_20, space.w_FloatingPointError, e.w_value, space.w_FloatingPointError) - goto = 22 + goto = glabel_22 else:raise # unhandled case, should not happen - if goto == 21: + if goto is glabel_21: w_54 = space.issubtype(w_55, space.w_ValueError) v56 = space.is_true(w_54) if v56 == True: w_name_11, w_bases_11, w_dic_11 = w_name_22, w_bases_22, w_dic_22 - goto = 25 + goto = glabel_25 else: assert v56 == False w_etype, w_evalue = w_57, w_58 - goto = 32 + goto = glabel_32 - if goto == 22: + if goto is glabel_22: w_59 = space.is_(w_46, space.w_ValueError) v60 = space.is_true(w_59) if v60 == True: w_name_11, w_bases_11, w_dic_11 = w_name_16, w_bases_16, w_dic_16 - goto = 25 + goto = glabel_25 else: assert v60 == False (w_name_22, w_bases_22, w_dic_22, w_57, w_58, w_55) = (w_name_16, w_bases_16, w_dic_16, w_44, w_45, w_46) - goto = 21 + goto = glabel_21 continue - if goto == 23: + if goto is glabel_23: w_61 = space.getattr(w_g_4, gs_get) w_modname = space.call_function(w_61, gs___name__, space.w_None) w_63 = space.is_(w_modname, space.w_None) v64 = space.is_true(w_63) if v64 == True: w_name_11, w_bases_11, w_dic_11 = w_name_21, w_bases_21, w_dic_21 - goto = 25 + goto = glabel_25 else: assert v64 == False (w_name_23, w_bases_23, w_dic_23, w_modname_1) = (w_name_21, w_bases_21, w_dic_21, w_modname) - goto = 24 + goto = glabel_24 - if goto == 24: + if goto is glabel_24: w_65 = space.setitem(w_dic_23, gs___module__, w_modname_1) w_name_11, w_bases_11, w_dic_11 = w_name_23, w_bases_23, w_dic_23 - goto = 25 + goto = glabel_25 - if goto == 25: + if goto is glabel_25: w_66 = space.iter(w_bases_11) (w_name_24, w_bases_24, w_dic_24, w_67) = (w_name_11, w_bases_11, w_dic_11, w_66) - goto = 26 + goto = glabel_26 - if goto == 26: + if goto is glabel_26: try: w_b = space.next(w_67) (w_name_25, w_bases_25, w_dic_25, w_69, w_b_1) = (w_name_24, w_bases_24, w_dic_24, w_67, w_b) - goto = 28 + goto = glabel_28 except OperationError, e: if space.is_true(space.issubtype(e.w_type, space.w_StopIteration)): w_name_26, w_bases_26, w_dic_26 = w_name_24, w_bases_24, w_dic_24 - goto = 31 + goto = glabel_31 else:raise # unhandled case, should not happen - if goto == 27: + if goto is glabel_27: w_70 = space.issubtype(w_39, space.w_KeyError) v71 = space.is_true(w_70) if v71 == True: (w_name_13, w_bases_13, w_dic_13, w_i) = (w_name_14, w_bases_14, w_dic_14, gi_0) - goto = 15 + goto = glabel_15 continue else: assert v71 == False w_etype, w_evalue = w_37, w_38 - goto = 32 + goto = glabel_32 - if goto == 28: + if goto is glabel_28: w_72 = space.isinstance(w_b_1, gcls_classobj) v73 = space.is_true(w_72) if v73 == True: (w_name_24, w_bases_24, w_dic_24, w_67) = (w_name_25, w_bases_25, w_dic_25, w_69) - goto = 26 + goto = glabel_26 continue else: assert v73 == False (w_name_27, w_bases_27, w_dic_27, w_b_2) = (w_name_25, w_bases_25, w_dic_25, w_b_1) - goto = 29 + goto = glabel_29 - if goto == 29: + if goto is glabel_29: w_74 = space.call_function(space.w_type, w_b_2) w_75 = space.call_function((space.builtin.get(space.str_w(gs_callable))), w_74) v76 = space.is_true(w_75) if v76 == True: (w_name_28, w_bases_28, w_dic_28, w_b_3) = (w_name_27, w_bases_27, w_dic_27, w_b_2) - goto = 30 + goto = glabel_30 else: assert v76 == False w_etype, w_evalue = space.w_TypeError, gs_base_must_be_class - goto = 32 + goto = glabel_32 - if goto == 30: + if goto is glabel_30: w_77 = space.call_function(space.w_type, w_b_3) w_78 = space.call_function(w_77, w_name_28, w_bases_28, w_dic_28) w_79 = w_78 - goto = 33 + goto = glabel_33 - if goto == 31: + if goto is glabel_31: w_new_class = space.call_function(gbltinmethod___new__, gcls_classobj) w_81 = space.call_function(gdescriptor_object___setattr__, w_new_class, gs___dict__, w_dic_26) w_82 = space.getattr(gdescriptor_classobj__name, gs___set__) @@ -1112,25 +1061,27 @@ w_84 = space.getattr(gdescriptor_classobj__bases, gs___set__) w_85 = space.call_function(w_84, w_new_class, w_bases_26) w_79 = w_new_class - goto = 33 + goto = glabel_33 - if goto == 32: + if goto is glabel_32: raise OperationError(w_etype, w_evalue) - if goto == 33: + if goto is glabel_33: return w_79 fastf___new__ = __new__ ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function '__setattr__' ## firstlineno 162 ##SECTION## # global declarations # global object gfunc_set_name +# global object glabel_8 # global object gs___bases__ # global object gfunc_set_bases +# global object glabel_7 # global object gfunc_set_dict # global object gdescriptor_object___setattr__ @@ -1144,74 +1095,69 @@ f_classobj___setattr__ = __setattr__ def __setattr__(space, w_self, w_attr, w_value): - - w_0=v2=w_self_2=w_attr_1=w_value_2=w_7=v8=w_self_4=w_attr_2=w_value_4=None - w_10=v11=w_self_6=w_attr_3=w_value_6=w_13=w_6=w_self_5=w_value_5=None - w_12=w_self_3=w_value_3=w_9=w_self_1=w_value_1=w_5=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_0 = space.eq(w_attr, gs___name__) v2 = space.is_true(w_0) if v2 == True: w_self_1, w_value_1 = w_self, w_value - goto = 2 + goto = glabel_2 else: assert v2 == False w_self_2, w_attr_1, w_value_2 = w_self, w_attr, w_value - goto = 3 + goto = glabel_3 - if goto == 2: + if goto is glabel_2: w_5 = fastf_set_name(space, w_self_1, w_value_1) w_6 = space.w_None - goto = 8 + goto = glabel_8 - if goto == 3: + if goto is glabel_3: w_7 = space.eq(w_attr_1, gs___bases__) v8 = space.is_true(w_7) if v8 == True: w_self_3, w_value_3 = w_self_2, w_value_2 - goto = 4 + goto = glabel_4 else: assert v8 == False w_self_4, w_attr_2, w_value_4 = w_self_2, w_attr_1, w_value_2 - goto = 5 + goto = glabel_5 - if goto == 4: + if goto is glabel_4: w_9 = fastf_set_bases(space, w_self_3, w_value_3) w_6 = space.w_None - goto = 8 + goto = glabel_8 - if goto == 5: + if goto is glabel_5: w_10 = space.eq(w_attr_2, gs___dict__) v11 = space.is_true(w_10) if v11 == True: w_self_5, w_value_5 = w_self_4, w_value_4 - goto = 6 + goto = glabel_6 else: assert v11 == False w_self_6, w_attr_3, w_value_6 = w_self_4, w_attr_2, w_value_4 - goto = 7 + goto = glabel_7 - if goto == 6: + if goto is glabel_6: w_12 = fastf_set_dict(space, w_self_5, w_value_5) w_6 = space.w_None - goto = 8 + goto = glabel_8 - if goto == 7: + if goto is glabel_7: w_13 = space.call_function(gdescriptor_object___setattr__, w_self_6, w_attr_3, w_value_6) w_6 = space.w_None - goto = 8 + goto = glabel_8 - if goto == 8: + if goto is glabel_8: return w_6 fastf_classobj___setattr__ = __setattr__ ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function '__delattr__' ## firstlineno 172 ##SECTION## @@ -1229,50 +1175,52 @@ f_classobj___delattr__ = __delattr__ def __delattr__(space, w_self, w_attr): - - w_0=v2=w_self_2=w_attr_2=w_6=w_5=w_self_1=w_attr_1=w_4=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_0 = space.contains(g3tuple_2, w_attr) v2 = space.is_true(w_0) if v2 == True: w_self_1, w_attr_1 = w_self, w_attr - goto = 2 + goto = glabel_2 else: assert v2 == False w_self_2, w_attr_2 = w_self, w_attr - goto = 3 + goto = glabel_3 - if goto == 2: + if goto is glabel_2: w_4 = fastf_classobj___setattr__(space, w_self_1, w_attr_1, space.w_None) w_5 = space.w_None - goto = 4 + goto = glabel_4 - if goto == 3: + if goto is glabel_3: w_6 = space.call_function(gdescriptor_object___delattr__, w_self_2, w_attr_2) w_5 = space.w_None - goto = 4 + goto = glabel_4 - if goto == 4: + if goto is glabel_4: return w_5 fastf_classobj___delattr__ = __delattr__ ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function '__getattribute__' ## firstlineno 179 ##SECTION## # global declarations +# global object glabel_13 # global object gs___get__ # global object gi_1 +# global object glabel_10 +# global object glabel_9 # global object gfunc_lookup # global object gcls_ValueError +# global object glabel_12 # global object gs_class__s_has_no_attribute__s # global object gfunc_mro_lookup +# global object glabel_11 def __getattribute__(space, __args__): funcname = "__getattribute__" @@ -1284,126 +1232,119 @@ f_classobj___getattribute__ = __getattribute__ def __getattribute__(space, w_self, w_attr): - - w_0=v2=w_self_2=w_attr_1=w_6=v7=w_self_4=w_attr_2=w_14=v15=w_self_9=None - w_attr_5=w_18=w_19=w_20=v21=w_etype=w_evalue=w_self_5=w_attr_3=None - w_11=w_v=w_found=v13=w_self_7=w_attr_4=w_24=w_25=w_26=w_self_6=None - w_v_1=w_descr_get=w_28=v29=w_self_10=w_descr_get_1=w_v_2=w_30=None - w_5=w_self_8=w_16=w_17=w_self_3=w_8=w_9=w_self_1=w_4=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_0 = space.eq(w_attr, gs___dict__) v2 = space.is_true(w_0) if v2 == True: w_self_1 = w_self - goto = 2 + goto = glabel_2 else: assert v2 == False w_self_2, w_attr_1 = w_self, w_attr - goto = 3 + goto = glabel_3 - if goto == 2: + if goto is glabel_2: w_4 = space.call_function(gdescriptor_object___getattribute__, w_self_1, gs___dict__) w_5 = w_4 - goto = 13 + goto = glabel_13 - if goto == 3: + if goto is glabel_3: w_6 = space.eq(w_attr_1, gs___name__) v7 = space.is_true(w_6) if v7 == True: w_self_3 = w_self_2 - goto = 4 + goto = glabel_4 else: assert v7 == False w_self_4, w_attr_2 = w_self_2, w_attr_1 - goto = 6 + goto = glabel_6 - if goto == 4: + if goto is glabel_4: w_8 = space.getattr(gdescriptor_classobj__name, gs___get__) w_9 = space.call_function(w_8, w_self_3) w_5 = w_9 - goto = 13 + goto = glabel_13 - if goto == 5: + if goto is glabel_5: w_v = space.getitem(w_11, gi_0) w_found = space.getitem(w_11, gi_1) v13 = space.is_true(w_found) if v13 == True: w_self_6, w_v_1 = w_self_5, w_v - goto = 10 + goto = glabel_10 else: assert v13 == False w_self_7, w_attr_4 = w_self_5, w_attr_3 - goto = 9 + goto = glabel_9 - if goto == 6: + if goto is glabel_6: w_14 = space.eq(w_attr_2, gs___bases__) v15 = space.is_true(w_14) if v15 == True: w_self_8 = w_self_4 - goto = 7 + goto = glabel_7 else: assert v15 == False w_self_9, w_attr_5 = w_self_4, w_attr_2 - goto = 8 + goto = glabel_8 - if goto == 7: + if goto is glabel_7: w_16 = space.getattr(gdescriptor_classobj__bases, gs___get__) w_17 = space.call_function(w_16, w_self_8) w_5 = w_17 - goto = 13 + goto = glabel_13 - if goto == 8: + if goto is glabel_8: w_18 = fastf_lookup(space, w_self_9, w_attr_5) w_19 = space.len(w_18) w_20 = space.eq(w_19, gi_2) v21 = space.is_true(w_20) if v21 == True: w_self_5, w_attr_3, w_11 = w_self_9, w_attr_5, w_18 - goto = 5 + goto = glabel_5 continue else: assert v21 == False w_etype, w_evalue = space.w_ValueError, space.w_None - goto = 12 + goto = glabel_12 - if goto == 9: + if goto is glabel_9: w_24 = space.getattr(w_self_7, gs___name__) w_25 = space.newtuple([w_24, w_attr_4]) w_26 = space.mod(gs_class__s_has_no_attribute__s, w_25) w_etype, w_evalue = space.w_AttributeError, w_26 - goto = 12 + goto = glabel_12 - if goto == 10: + if goto is glabel_10: w_descr_get = fastf_mro_lookup(space, w_v_1, gs___get__) w_28 = space.is_(w_descr_get, space.w_None) v29 = space.is_true(w_28) if v29 == True: w_5 = w_v_1 - goto = 13 + goto = glabel_13 else: assert v29 == False w_self_10, w_descr_get_1, w_v_2 = w_self_6, w_descr_get, w_v_1 - goto = 11 + goto = glabel_11 - if goto == 11: + if goto is glabel_11: w_30 = space.call_function(w_descr_get_1, w_v_2, space.w_None, w_self_10) w_5 = w_30 - goto = 13 + goto = glabel_13 - if goto == 12: + if goto is glabel_12: raise OperationError(w_etype, w_evalue) - if goto == 13: + if goto is glabel_13: return w_5 fastf_classobj___getattribute__ = __getattribute__ ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function '__repr__' ## firstlineno 196 ##SECTION## @@ -1421,35 +1362,34 @@ f_classobj___repr__ = __repr__ def __repr__(space, w_self): - - w_mod=w_2=w_3=w_4=w_5=w_6=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_mod = fastf_get_class_module(space, w_self) w_2 = space.getattr(w_self, gs___name__) w_3 = fastf_uid(space, w_self) w_4 = space.newtuple([w_mod, w_2, w_3]) w_5 = space.mod(gs__class__s__s_at_0x_x_, w_4) w_6 = w_5 - goto = 2 + goto = glabel_2 - if goto == 2: + if goto is glabel_2: return w_6 fastf_classobj___repr__ = __repr__ ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function '__str__' ## firstlineno 200 ##SECTION## # global declarations # global object gfunc_get_class_module # global object gs__ +# global object glabel_3 # global object gs___name__ +# global object glabel_4 # global object gs__s__s def __str__(space, __args__): @@ -1462,43 +1402,40 @@ f_classobj___str__ = __str__ def __str__(space, w_self): - - w_mod=w_2=v3=w_self_2=w_mod_1=w_6=w_7=w_8=w_5=w_self_1=w_4=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_mod = fastf_get_class_module(space, w_self) w_2 = space.eq(w_mod, gs__) v3 = space.is_true(w_2) if v3 == True: w_self_1 = w_self - goto = 2 + goto = glabel_2 else: assert v3 == False w_self_2, w_mod_1 = w_self, w_mod - goto = 3 + goto = glabel_3 - if goto == 2: + if goto is glabel_2: w_4 = space.getattr(w_self_1, gs___name__) w_5 = w_4 - goto = 4 + goto = glabel_4 - if goto == 3: + if goto is glabel_3: w_6 = space.getattr(w_self_2, gs___name__) w_7 = space.newtuple([w_mod_1, w_6]) w_8 = space.mod(gs__s__s, w_7) w_5 = w_8 - goto = 4 + goto = glabel_4 - if goto == 4: + if goto is glabel_4: return w_5 fastf_classobj___str__ = __str__ ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function '__call__' ## firstlineno 207 ##SECTION## @@ -1519,14 +1456,10 @@ f_classobj___call__ = __call__ def __call__(space, w_self, w_args, w_kwds): - - w_inst=w_dic=w_2=w_3=w_init=v6=w_9=w_args_1=w_kwds_1=w_inst_1=None - w_init_1=w_ret=w_11=v12=w_13=w_etype=w_evalue=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_inst = space.call_function(gbltinmethod___new__, gcls_instance) w_dic = space.getattr(w_inst, gs___dict__) w_2 = space.getattr(gdescriptor_instance__class, gs___set__) @@ -1536,45 +1469,51 @@ if v6 == True: (w_args_1, w_kwds_1, w_inst_1, w_init_1) = (w_args, w_kwds, w_inst, w_init) - goto = 2 + goto = glabel_2 else: assert v6 == False w_9 = w_inst - goto = 5 + goto = glabel_5 - if goto == 2: + if goto is glabel_2: _args = Arguments.fromshape(space, (0, (), True, True), [w_args_1, w_kwds_1]) w_ret = space.call_args(w_init_1, _args) w_11 = space.is_(w_ret, space.w_None) v12 = space.is_true(w_11) if v12 == True: w_9 = w_inst_1 - goto = 5 + goto = glabel_5 else: assert v12 == False - goto = 3 + goto = glabel_3 - if goto == 3: + if goto is glabel_3: w_13 = space.call_function(space.w_TypeError, gs___init_____should_return_None) w_etype, w_evalue = space.w_TypeError, w_13 - goto = 4 + goto = glabel_4 - if goto == 4: + if goto is glabel_4: raise OperationError(w_etype, w_evalue) - if goto == 5: + if goto is glabel_5: return w_9 fastf_classobj___call__ = __call__ ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function 'instance_getattr1' ## firstlineno 228 ##SECTION## # global declarations +# global object glabel_19 # global object gs___class__ +# global object glabel_18 +# global object glabel_16 +# global object glabel_14 +# global object glabel_15 # global object gs__s_instance_has_no_attribute__s +# global object glabel_17 def instance_getattr1(space, __args__): funcname = "instance_getattr1" @@ -1586,92 +1525,79 @@ f_instance_getattr1 = instance_getattr1 def instance_getattr1(space, w_inst, w_name, w_exc): - - w_0=v2=w_inst_2=w_name_2=w_exc_1=w_7=v8=w_inst_4=w_name_3=w_exc_2=None - w_18=w_6=w_inst_7=w_name_6=w_exc_5=w_19=w_20=w_21=w_22=v23=w_inst_5=None - w_name_4=w_exc_3=w_14=w_16=w_12=w_11=v13=w_etype=w_evalue=w_inst_6=None - w_name_5=w_exc_4=w_24=w_cls=w_26=w_27=w_28=v29=w_inst_9=w_name_8=None - w_exc_7=w_cls_1=w_30=w_v_2=w_found_1=v40=w_name_11=w_exc_10=w_cls_6=None - v41=w_name_12=w_cls_7=w_43=w_44=w_45=w_inst_11=w_v_1=w_cls_4=None - w_descr_get=w_50=v51=w_inst_12=w_descr_get_1=w_v_3=w_cls_9=w_52=None - w_inst_8=w_name_7=w_exc_6=w_31=w_cls_2=w_32=w_33=w_34=v35=w_inst_10=None - w_name_9=w_exc_8=w_cls_3=w_36=w_v=w_found=v39=w_name_10=w_exc_9=None - w_cls_5=v42=w_name_13=w_cls_8=w_46=w_47=w_48=w_inst_3=w_9=w_10=None - w_inst_1=w_name_1=w_5=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_0 = space.eq(w_name, gs___dict__) v2 = space.is_true(w_0) if v2 == True: w_inst_1, w_name_1 = w_inst, w_name - goto = 2 + goto = glabel_2 else: assert v2 == False w_inst_2, w_name_2, w_exc_1 = w_inst, w_name, w_exc - goto = 3 + goto = glabel_3 - if goto == 2: + if goto is glabel_2: w_5 = space.call_function(gdescriptor_object___getattribute__, w_inst_1, w_name_1) w_6 = w_5 - goto = 19 + goto = glabel_19 - if goto == 3: + if goto is glabel_3: w_7 = space.eq(w_name_2, gs___class__) v8 = space.is_true(w_7) if v8 == True: w_inst_3 = w_inst_2 - goto = 4 + goto = glabel_4 else: assert v8 == False w_inst_4, w_name_3, w_exc_2 = w_inst_2, w_name_2, w_exc_1 - goto = 6 + goto = glabel_6 - if goto == 4: + if goto is glabel_4: w_9 = space.getattr(gdescriptor_instance__class, gs___get__) w_10 = space.call_function(w_9, w_inst_3) w_6 = w_10 - goto = 19 + goto = glabel_19 - if goto == 5: + if goto is glabel_5: w_11 = space.issubtype(w_12, space.w_AttributeError) v13 = space.is_true(w_11) if v13 == True: w_inst_6, w_name_5, w_exc_4 = w_inst_5, w_name_4, w_exc_3 - goto = 8 + goto = glabel_8 else: assert v13 == False w_etype, w_evalue = w_14, w_16 - goto = 18 + goto = glabel_18 - if goto == 6: + if goto is glabel_6: try: w_18 = fastf_retrieve(space, w_inst_4, w_name_3) w_6 = w_18 - goto = 19 + goto = glabel_19 except OperationError, e: if space.is_true(space.issubtype(e.w_type, space.w_Exception)): (w_inst_7, w_name_6, w_exc_5, w_19, w_20, w_21) = (w_inst_4, w_name_3, w_exc_2, e.w_type, e.w_value, e.w_type) - goto = 7 + goto = glabel_7 else:raise # unhandled case, should not happen - if goto == 7: + if goto is glabel_7: w_22 = space.is_(w_21, space.w_AttributeError) v23 = space.is_true(w_22) if v23 == True: w_inst_8, w_name_7, w_exc_6 = w_inst_7, w_name_6, w_exc_5 - goto = 9 + goto = glabel_9 else: assert v23 == False (w_inst_5, w_name_4, w_exc_3, w_14, w_16, w_12) = (w_inst_7, w_name_6, w_exc_5, w_19, w_20, w_21) - goto = 5 + goto = glabel_5 continue - if goto == 8: + if goto is glabel_8: w_24 = space.getattr(gdescriptor_instance__class, gs___get__) w_cls = space.call_function(w_24, w_inst_6) w_26 = fastf_lookup(space, w_cls, w_name_5) @@ -1681,13 +1607,13 @@ if v29 == True: (w_inst_9, w_name_8, w_exc_7, w_cls_1, w_30) = (w_inst_6, w_name_5, w_exc_4, w_cls, w_26) - goto = 11 + goto = glabel_11 else: assert v29 == False w_etype, w_evalue = space.w_ValueError, space.w_None - goto = 18 + goto = glabel_18 - if goto == 9: + if goto is glabel_9: w_31 = space.getattr(gdescriptor_instance__class, gs___get__) w_cls_2 = space.call_function(w_31, w_inst_8) w_32 = fastf_lookup(space, w_cls_2, w_name_7) @@ -1697,98 +1623,98 @@ if v35 == True: (w_inst_10, w_name_9, w_exc_8, w_cls_3, w_36) = (w_inst_8, w_name_7, w_exc_6, w_cls_2, w_32) - goto = 10 + goto = glabel_10 else: assert v35 == False w_etype, w_evalue = space.w_ValueError, space.w_None - goto = 18 + goto = glabel_18 - if goto == 10: + if goto is glabel_10: w_v = space.getitem(w_36, gi_0) w_found = space.getitem(w_36, gi_1) v39 = space.is_true(w_found) if v39 == True: w_inst_11, w_v_1, w_cls_4 = w_inst_10, w_v, w_cls_3 - goto = 16 + goto = glabel_16 else: assert v39 == False w_name_10, w_exc_9, w_cls_5 = w_name_9, w_exc_8, w_cls_3 - goto = 13 + goto = glabel_13 - if goto == 11: + if goto is glabel_11: w_v_2 = space.getitem(w_30, gi_0) w_found_1 = space.getitem(w_30, gi_1) v40 = space.is_true(w_found_1) if v40 == True: w_inst_11, w_v_1, w_cls_4 = w_inst_9, w_v_2, w_cls_1 - goto = 16 + goto = glabel_16 else: assert v40 == False w_name_11, w_exc_10, w_cls_6 = w_name_8, w_exc_7, w_cls_1 - goto = 12 + goto = glabel_12 - if goto == 12: + if goto is glabel_12: v41 = space.is_true(w_exc_10) if v41 == True: w_name_12, w_cls_7 = w_name_11, w_cls_6 - goto = 14 + goto = glabel_14 else: assert v41 == False w_6 = space.w_None - goto = 19 + goto = glabel_19 - if goto == 13: + if goto is glabel_13: v42 = space.is_true(w_exc_9) if v42 == True: w_name_13, w_cls_8 = w_name_10, w_cls_5 - goto = 15 + goto = glabel_15 else: assert v42 == False w_6 = space.w_None - goto = 19 + goto = glabel_19 - if goto == 14: + if goto is glabel_14: w_43 = space.getattr(w_cls_7, gs___name__) w_44 = space.newtuple([w_43, w_name_12]) w_45 = space.mod(gs__s_instance_has_no_attribute__s, w_44) w_etype, w_evalue = space.w_AttributeError, w_45 - goto = 18 + goto = glabel_18 - if goto == 15: + if goto is glabel_15: w_46 = space.getattr(w_cls_8, gs___name__) w_47 = space.newtuple([w_46, w_name_13]) w_48 = space.mod(gs__s_instance_has_no_attribute__s, w_47) w_etype, w_evalue = space.w_AttributeError, w_48 - goto = 18 + goto = glabel_18 - if goto == 16: + if goto is glabel_16: w_descr_get = fastf_mro_lookup(space, w_v_1, gs___get__) w_50 = space.is_(w_descr_get, space.w_None) v51 = space.is_true(w_50) if v51 == True: w_6 = w_v_1 - goto = 19 + goto = glabel_19 else: assert v51 == False (w_inst_12, w_descr_get_1, w_v_3, w_cls_9) = (w_inst_11, w_descr_get, w_v_1, w_cls_4) - goto = 17 + goto = glabel_17 - if goto == 17: + if goto is glabel_17: w_52 = space.call_function(w_descr_get_1, w_v_3, w_inst_12, w_cls_9) w_6 = w_52 - goto = 19 + goto = glabel_19 - if goto == 18: + if goto is glabel_18: raise OperationError(w_etype, w_evalue) - if goto == 19: + if goto is glabel_19: return w_6 fastf_instance_getattr1 = instance_getattr1 ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function '__getattribute__' ## firstlineno 252 ##SECTION## @@ -1805,97 +1731,90 @@ f_instance___getattribute__ = __getattribute__ def __getattribute__(space, w_self, w_name): - - w_0=w_3=w_self_1=w_name_1=w_4=w_5=w_6=w_7=w_8=w_9=v10=w_self_3=None - w_name_3=w_13=w_14=w_15=w_16=w_17=w_18=v19=w_etype=w_evalue=w_self_4=None - w_name_4=w_20=w_21=w_getattr=w_25=v26=w_name_5=w_getattr_1=w_29=None - w_self_2=w_name_2=w_11=w_12=w_getattr_2=w_27=v28=w_name_6=w_getattr_3=None - w_30=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: try: w_0 = space.call_function(gfunc_instance_getattr1, w_self, w_name) w_3 = w_0 - goto = 9 + goto = glabel_9 except OperationError, e: if space.is_true(space.issubtype(e.w_type, space.w_Exception)): (w_self_1, w_name_1, w_4, w_5, w_6, w_7, w_8) = (w_self, w_name, e.w_type, e.w_value, e.w_type, e.w_type, e.w_value) - goto = 2 + goto = glabel_2 else:raise # unhandled case, should not happen - if goto == 2: + if goto is glabel_2: w_9 = space.is_(w_6, space.w_AttributeError) v10 = space.is_true(w_9) if v10 == True: w_self_2, w_name_2, w_11, w_12 = w_self_1, w_name_1, w_7, w_8 - goto = 5 + goto = glabel_5 else: assert v10 == False (w_self_3, w_name_3, w_13, w_14, w_15, w_16, w_17) = (w_self_1, w_name_1, w_4, w_5, w_6, w_7, w_8) - goto = 3 + goto = glabel_3 - if goto == 3: + if goto is glabel_3: w_18 = space.issubtype(w_15, space.w_AttributeError) v19 = space.is_true(w_18) if v19 == True: w_self_4, w_name_4, w_20, w_21 = w_self_3, w_name_3, w_16, w_17 - goto = 4 + goto = glabel_4 else: assert v19 == False w_etype, w_evalue = w_13, w_14 - goto = 8 + goto = glabel_8 - if goto == 4: + if goto is glabel_4: _args = Arguments.fromshape(space, (2, ('exc',), False, False), [w_self_4, gs___getattr__, space.w_False]) w_getattr = space.call_args(gfunc_instance_getattr1, _args) w_25 = space.is_(w_getattr, space.w_None) v26 = space.is_true(w_25) if v26 == True: w_etype, w_evalue = w_20, w_21 - goto = 8 + goto = glabel_8 else: assert v26 == False w_name_5, w_getattr_1 = w_name_4, w_getattr - goto = 6 + goto = glabel_6 - if goto == 5: + if goto is glabel_5: _args = Arguments.fromshape(space, (2, ('exc',), False, False), [w_self_2, gs___getattr__, space.w_False]) w_getattr_2 = space.call_args(gfunc_instance_getattr1, _args) w_27 = space.is_(w_getattr_2, space.w_None) v28 = space.is_true(w_27) if v28 == True: w_etype, w_evalue = w_11, w_12 - goto = 8 + goto = glabel_8 else: assert v28 == False w_name_6, w_getattr_3 = w_name_2, w_getattr_2 - goto = 7 + goto = glabel_7 - if goto == 6: + if goto is glabel_6: w_29 = space.call_function(w_getattr_1, w_name_5) w_3 = w_29 - goto = 9 + goto = glabel_9 - if goto == 7: + if goto is glabel_7: w_30 = space.call_function(w_getattr_3, w_name_6) w_3 = w_30 - goto = 9 + goto = glabel_9 - if goto == 8: + if goto is glabel_8: raise OperationError(w_etype, w_evalue) - if goto == 9: + if goto is glabel_9: return w_3 fastf_instance___getattribute__ = __getattribute__ ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function '__new__' ## firstlineno 261 ##SECTION## @@ -1913,78 +1832,73 @@ f___new___1 = __new__ def __new__(space, w_typ, w_klass, w_dic): - - w_0=v2=w_4=w_etype=w_evalue=w_klass_1=w_dic_1=w_7=v8=w_klass_3=None - w_dic_2=w_9=v10=w_11=w_klass_4=w_dic_4=w_inst=w_13=w_14=w_15=None - w_16=w_klass_2=w_dic_3=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_0 = space.isinstance(w_klass, gcls_classobj) v2 = space.is_true(w_0) if v2 == True: w_klass_1, w_dic_1 = w_klass, w_dic - goto = 3 + goto = glabel_3 else: assert v2 == False - goto = 2 + goto = glabel_2 - if goto == 2: + if goto is glabel_2: w_4 = space.call_function(space.w_TypeError, gs_instance___first_arg_must_be_cla) w_etype, w_evalue = space.w_TypeError, w_4 - goto = 8 + goto = glabel_8 - if goto == 3: + if goto is glabel_3: w_7 = space.is_(w_dic_1, space.w_None) v8 = space.is_true(w_7) if v8 == True: w_klass_2 = w_klass_1 - goto = 4 + goto = glabel_4 else: assert v8 == False w_klass_3, w_dic_2 = w_klass_1, w_dic_1 - goto = 5 + goto = glabel_5 - if goto == 4: + if goto is glabel_4: w_dic_3 = space.newdict([]) w_klass_4, w_dic_4 = w_klass_2, w_dic_3 - goto = 7 + goto = glabel_7 - if goto == 5: + if goto is glabel_5: w_9 = space.isinstance(w_dic_2, space.w_dict) v10 = space.is_true(w_9) if v10 == True: w_klass_4, w_dic_4 = w_klass_3, w_dic_2 - goto = 7 + goto = glabel_7 else: assert v10 == False - goto = 6 + goto = glabel_6 - if goto == 6: + if goto is glabel_6: w_11 = space.call_function(space.w_TypeError, gs_instance___second_arg_must_be_di) w_etype, w_evalue = space.w_TypeError, w_11 - goto = 8 + goto = glabel_8 - if goto == 7: + if goto is glabel_7: w_inst = space.call_function(gbltinmethod___new__, gcls_instance) w_13 = space.getattr(gdescriptor_instance__class, gs___set__) w_14 = space.call_function(w_13, w_inst, w_klass_4) w_15 = space.call_function(gdescriptor_object___setattr__, w_inst, gs___dict__, w_dic_4) w_16 = w_inst - goto = 9 + goto = glabel_9 - if goto == 8: + if goto is glabel_8: raise OperationError(w_etype, w_evalue) - if goto == 9: + if goto is glabel_9: return w_16 fastf___new___1 = __new__ ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function '__setattr__' ## firstlineno 274 ##SECTION## @@ -2002,113 +1916,106 @@ f_instance___setattr__ = __setattr__ def __setattr__(space, w_self, w_name, w_value): - - w_0=v2=w_self_2=w_name_1=w_value_2=w_12=v13=w_self_5=w_name_2=None - w_value_5=w_setattr=w_20=v21=w_name_4=w_value_8=w_setattr_1=w_22=None - w_11=w_self_7=w_name_3=w_value_7=w_23=w_24=w_self_4=w_value_4=None - w_14=v15=w_16=w_etype=w_evalue=w_self_6=w_value_6=w_17=w_18=w_self_1=None - w_value_1=w_5=v6=w_7=w_self_3=w_value_3=w_10=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_0 = space.eq(w_name, gs___dict__) v2 = space.is_true(w_0) if v2 == True: w_self_1, w_value_1 = w_self, w_value - goto = 2 + goto = glabel_2 else: assert v2 == False w_self_2, w_name_1, w_value_2 = w_self, w_name, w_value - goto = 5 + goto = glabel_5 - if goto == 2: + if goto is glabel_2: w_5 = space.isinstance(w_value_1, space.w_dict) v6 = space.is_true(w_5) if v6 == True: w_self_3, w_value_3 = w_self_1, w_value_1 - goto = 4 + goto = glabel_4 else: assert v6 == False - goto = 3 + goto = glabel_3 - if goto == 3: + if goto is glabel_3: w_7 = space.call_function(space.w_TypeError, gs___dict___must_be_set_to_a_dictio) w_etype, w_evalue = space.w_TypeError, w_7 - goto = 12 + goto = glabel_12 - if goto == 4: + if goto is glabel_4: w_10 = space.call_function(gdescriptor_object___setattr__, w_self_3, gs___dict__, w_value_3) w_11 = space.w_None - goto = 13 + goto = glabel_13 - if goto == 5: + if goto is glabel_5: w_12 = space.eq(w_name_1, gs___class__) v13 = space.is_true(w_12) if v13 == True: w_self_4, w_value_4 = w_self_2, w_value_2 - goto = 6 + goto = glabel_6 else: assert v13 == False w_self_5, w_name_2, w_value_5 = w_self_2, w_name_1, w_value_2 - goto = 9 + goto = glabel_9 - if goto == 6: + if goto is glabel_6: w_14 = space.isinstance(w_value_4, gcls_classobj) v15 = space.is_true(w_14) if v15 == True: w_self_6, w_value_6 = w_self_4, w_value_4 - goto = 8 + goto = glabel_8 else: assert v15 == False - goto = 7 + goto = glabel_7 - if goto == 7: + if goto is glabel_7: w_16 = space.call_function(space.w_TypeError, gs___class___must_be_set_to_a_class) w_etype, w_evalue = space.w_TypeError, w_16 - goto = 12 + goto = glabel_12 - if goto == 8: + if goto is glabel_8: w_17 = space.getattr(gdescriptor_instance__class, gs___set__) w_18 = space.call_function(w_17, w_self_6, w_value_6) w_11 = space.w_None - goto = 13 + goto = glabel_13 - if goto == 9: + if goto is glabel_9: _args = Arguments.fromshape(space, (2, ('exc',), False, False), [w_self_5, gs___setattr__, space.w_False]) w_setattr = space.call_args(gfunc_instance_getattr1, _args) w_20 = space.is_(w_setattr, space.w_None) v21 = space.is_true(w_20) if v21 == True: w_self_7, w_name_3, w_value_7 = w_self_5, w_name_2, w_value_5 - goto = 11 + goto = glabel_11 else: assert v21 == False w_name_4, w_value_8, w_setattr_1 = w_name_2, w_value_5, w_setattr - goto = 10 + goto = glabel_10 - if goto == 10: + if goto is glabel_10: w_22 = space.call_function(w_setattr_1, w_name_4, w_value_8) w_11 = space.w_None - goto = 13 + goto = glabel_13 - if goto == 11: + if goto is glabel_11: w_23 = space.getattr(w_self_7, gs___dict__) w_24 = space.setitem(w_23, w_name_3, w_value_7) w_11 = space.w_None - goto = 13 + goto = glabel_13 - if goto == 12: + if goto is glabel_12: raise OperationError(w_etype, w_evalue) - if goto == 13: + if goto is glabel_13: return w_11 fastf_instance___setattr__ = __setattr__ ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function '__delattr__' ## firstlineno 290 ##SECTION## @@ -2126,131 +2033,123 @@ f_instance___delattr__ = __delattr__ def __delattr__(space, w_self, w_name): - - w_0=v2=w_self_2=w_name_2=w_delattr=w_7=v8=w_name_4=w_delattr_1=None - w_9=w_5=w_self_3=w_name_3=w_10=w_self_4=w_name_5=w_11=w_15=w_self_5=None - w_name_6=w_12=w_13=w_14=w_23=v24=w_self_6=w_name_7=w_19=w_21=None - w_17=w_16=v18=w_etype=w_evalue=w_self_7=w_name_8=w_25=w_26=w_27=None - w_28=w_29=w_self_8=w_name_9=w_30=w_31=w_32=w_33=w_34=w_self_1=None - w_name_1=w_4=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_0 = space.contains(g2tuple_2, w_name) v2 = space.is_true(w_0) if v2 == True: w_self_1, w_name_1 = w_self, w_name - goto = 2 + goto = glabel_2 else: assert v2 == False w_self_2, w_name_2 = w_self, w_name - goto = 3 + goto = glabel_3 - if goto == 2: + if goto is glabel_2: w_4 = fastf_instance___setattr__(space, w_self_1, w_name_1, space.w_None) w_5 = space.w_None - goto = 12 + goto = glabel_12 - if goto == 3: + if goto is glabel_3: _args = Arguments.fromshape(space, (2, ('exc',), False, False), [w_self_2, gs___delattr__, space.w_False]) w_delattr = space.call_args(gfunc_instance_getattr1, _args) w_7 = space.is_(w_delattr, space.w_None) v8 = space.is_true(w_7) if v8 == True: w_self_3, w_name_3 = w_self_2, w_name_2 - goto = 5 + goto = glabel_5 else: assert v8 == False w_name_4, w_delattr_1 = w_name_2, w_delattr - goto = 4 + goto = glabel_4 - if goto == 4: + if goto is glabel_4: w_9 = space.call_function(w_delattr_1, w_name_4) w_5 = space.w_None - goto = 12 + goto = glabel_12 - if goto == 5: + if goto is glabel_5: try: w_10 = space.getattr(w_self_3, gs___dict__) w_self_4, w_name_5, w_11 = w_self_3, w_name_3, w_10 - goto = 6 + goto = glabel_6 except OperationError, e: if space.is_true(space.issubtype(e.w_type, space.w_AttributeError)): (w_self_5, w_name_6, w_12, w_13, w_14) = (w_self_3, w_name_3, space.w_AttributeError, e.w_value, space.w_AttributeError) - goto = 8 + goto = glabel_8 else:raise # unhandled case, should not happen - if goto == 6: + if goto is glabel_6: try: w_15 = space.delitem(w_11, w_name_5) w_5 = space.w_None - goto = 12 + goto = glabel_12 except OperationError, e: if space.is_true(space.issubtype(e.w_type, space.w_IndexError)): (w_self_5, w_name_6, w_12, w_13, w_14) = (w_self_4, w_name_5, space.w_IndexError, e.w_value, space.w_IndexError) - goto = 8 + goto = glabel_8 elif space.is_true(space.issubtype(e.w_type, space.w_KeyError)): (w_self_5, w_name_6, w_12, w_13, w_14) = (w_self_4, w_name_5, space.w_KeyError, e.w_value, space.w_KeyError) - goto = 8 + goto = glabel_8 else:raise # unhandled case, should not happen - if goto == 7: + if goto is glabel_7: w_16 = space.issubtype(w_17, space.w_KeyError) v18 = space.is_true(w_16) if v18 == True: w_self_7, w_name_8 = w_self_6, w_name_7 - goto = 9 + goto = glabel_9 else: assert v18 == False w_etype, w_evalue = w_19, w_21 - goto = 11 + goto = glabel_11 - if goto == 8: + if goto is glabel_8: w_23 = space.is_(w_14, space.w_KeyError) v24 = space.is_true(w_23) if v24 == True: w_self_8, w_name_9 = w_self_5, w_name_6 - goto = 10 + goto = glabel_10 else: assert v24 == False (w_self_6, w_name_7, w_19, w_21, w_17) = (w_self_5, w_name_6, w_12, w_13, w_14) - goto = 7 + goto = glabel_7 continue - if goto == 9: + if goto is glabel_9: w_25 = space.getattr(w_self_7, gs___class__) w_26 = space.getattr(w_25, gs___name__) w_27 = space.newtuple([w_26, w_name_8]) w_28 = space.mod(gs__s_instance_has_no_attribute___s, w_27) w_29 = space.call_function(space.w_AttributeError, w_28) w_etype, w_evalue = space.w_AttributeError, w_29 - goto = 11 + goto = glabel_11 - if goto == 10: + if goto is glabel_10: w_30 = space.getattr(w_self_8, gs___class__) w_31 = space.getattr(w_30, gs___name__) w_32 = space.newtuple([w_31, w_name_9]) w_33 = space.mod(gs__s_instance_has_no_attribute___s, w_32) w_34 = space.call_function(space.w_AttributeError, w_33) w_etype, w_evalue = space.w_AttributeError, w_34 - goto = 11 + goto = glabel_11 - if goto == 11: + if goto is glabel_11: raise OperationError(w_etype, w_evalue) - if goto == 12: + if goto is glabel_12: return w_5 fastf_instance___delattr__ = __delattr__ ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function '__repr__' ## firstlineno 306 ##SECTION## @@ -2267,38 +2166,32 @@ f_instance___repr__ = __repr__ def __repr__(space, w_self): - - w_func=w_func_1=w_21=w_16=w_self_1=w_2=w_3=w_4=w_5=v6=w_self_3=None - w_7=w_8=w_9=w_22=v23=w_etype=w_evalue=w_self_4=w_klass=w_mod=None - w_12=w_13=w_14=w_15=w_self_2=w_klass_1=w_mod_1=w_17=w_18=w_19=None - w_20=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: try: w_func = space.call_function(gfunc_instance_getattr1, w_self, gs___repr__) w_func_1 = w_func - goto = 5 + goto = glabel_5 except OperationError, e: if space.is_true(space.issubtype(e.w_type, space.w_Exception)): w_self_1, w_2, w_3, w_4 = w_self, e.w_type, e.w_value, e.w_type - goto = 2 + goto = glabel_2 else:raise # unhandled case, should not happen - if goto == 2: + if goto is glabel_2: w_5 = space.is_(w_4, space.w_AttributeError) v6 = space.is_true(w_5) if v6 == True: w_self_2 = w_self_1 - goto = 4 + goto = glabel_4 else: assert v6 == False w_self_3, w_7, w_8, w_9 = w_self_1, w_2, w_3, w_4 - goto = 6 + goto = glabel_6 - if goto == 3: + if goto is glabel_3: w_klass = space.getattr(w_self_4, gs___class__) w_mod = fastf_get_class_module(space, w_klass) w_12 = space.getattr(w_klass, gs___name__) @@ -2306,9 +2199,9 @@ w_14 = space.newtuple([w_mod, w_12, w_13]) w_15 = space.mod(gs___s__s_instance_at_0x_x_, w_14) w_16 = w_15 - goto = 8 + goto = glabel_8 - if goto == 4: + if goto is glabel_4: w_klass_1 = space.getattr(w_self_2, gs___class__) w_mod_1 = fastf_get_class_module(space, w_klass_1) w_17 = space.getattr(w_klass_1, gs___name__) @@ -2316,35 +2209,35 @@ w_19 = space.newtuple([w_mod_1, w_17, w_18]) w_20 = space.mod(gs___s__s_instance_at_0x_x_, w_19) w_16 = w_20 - goto = 8 + goto = glabel_8 - if goto == 5: + if goto is glabel_5: w_21 = space.call_function(w_func_1, ) w_16 = w_21 - goto = 8 + goto = glabel_8 - if goto == 6: + if goto is glabel_6: w_22 = space.issubtype(w_9, space.w_AttributeError) v23 = space.is_true(w_22) if v23 == True: w_self_4 = w_self_3 - goto = 3 + goto = glabel_3 continue else: assert v23 == False w_etype, w_evalue = w_7, w_8 - goto = 7 + goto = glabel_7 - if goto == 7: + if goto is glabel_7: raise OperationError(w_etype, w_evalue) - if goto == 8: + if goto is glabel_8: return w_16 fastf_instance___repr__ = __repr__ ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function '__str__' ## firstlineno 315 ##SECTION## @@ -2358,73 +2251,68 @@ f_instance___str__ = __str__ def __str__(space, w_self): - - w_func=w_func_1=w_13=w_11=w_self_1=w_2=w_3=w_4=w_5=v6=w_self_3=None - w_7=w_8=w_9=w_14=v15=w_etype=w_evalue=w_self_4=w_10=w_self_2=None - w_12=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: try: w_func = space.call_function(gfunc_instance_getattr1, w_self, gs___str__) w_func_1 = w_func - goto = 5 + goto = glabel_5 except OperationError, e: if space.is_true(space.issubtype(e.w_type, space.w_Exception)): w_self_1, w_2, w_3, w_4 = w_self, e.w_type, e.w_value, e.w_type - goto = 2 + goto = glabel_2 else:raise # unhandled case, should not happen - if goto == 2: + if goto is glabel_2: w_5 = space.is_(w_4, space.w_AttributeError) v6 = space.is_true(w_5) if v6 == True: w_self_2 = w_self_1 - goto = 4 + goto = glabel_4 else: assert v6 == False w_self_3, w_7, w_8, w_9 = w_self_1, w_2, w_3, w_4 - goto = 6 + goto = glabel_6 - if goto == 3: + if goto is glabel_3: w_10 = fastf_instance___repr__(space, w_self_4) w_11 = w_10 - goto = 8 + goto = glabel_8 - if goto == 4: + if goto is glabel_4: w_12 = fastf_instance___repr__(space, w_self_2) w_11 = w_12 - goto = 8 + goto = glabel_8 - if goto == 5: + if goto is glabel_5: w_13 = space.call_function(w_func_1, ) w_11 = w_13 - goto = 8 + goto = glabel_8 - if goto == 6: + if goto is glabel_6: w_14 = space.issubtype(w_9, space.w_AttributeError) v15 = space.is_true(w_14) if v15 == True: w_self_4 = w_self_3 - goto = 3 + goto = glabel_3 continue else: assert v15 == False w_etype, w_evalue = w_7, w_8 - goto = 7 + goto = glabel_7 - if goto == 7: + if goto is glabel_7: raise OperationError(w_etype, w_evalue) - if goto == 8: + if goto is glabel_8: return w_11 fastf_instance___str__ = __str__ ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function '__hash__' ## firstlineno 322 ##SECTION## @@ -2442,102 +2330,97 @@ f_instance___hash__ = __hash__ def __hash__(space, w_self): - - w__eq=w__cmp=w__hash=v4=w_self_1=w__hash_1=w_5=v6=w_self_3=w__hash_3=None - w_7=v9=w_self_4=w__hash_4=v13=w_self_5=w_19=w_17=w__hash_5=w_ret=None - w_15=v16=w_18=w_etype=w_evalue=w_10=w_self_2=w__hash_2=v8=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w__eq = space.call_function(gfunc_instance_getattr1, w_self, gs___eq__, space.w_False) w__cmp = space.call_function(gfunc_instance_getattr1, w_self, gs___cmp__, space.w_False) w__hash = space.call_function(gfunc_instance_getattr1, w_self, gs___hash__, space.w_False) v4 = space.is_true(w__eq) if v4 == True: w_self_1, w__hash_1, w_5 = w_self, w__hash, w__eq - goto = 2 + goto = glabel_2 else: assert v4 == False w_self_1, w__hash_1, w_5 = w_self, w__hash, w__cmp - goto = 2 + goto = glabel_2 - if goto == 2: + if goto is glabel_2: v6 = space.is_true(w_5) if v6 == True: w_self_2, w__hash_2 = w_self_1, w__hash_1 - goto = 3 + goto = glabel_3 else: assert v6 == False w_self_3, w__hash_3, w_7 = w_self_1, w__hash_1, w_5 - goto = 4 + goto = glabel_4 - if goto == 3: + if goto is glabel_3: v8 = space.is_true(w__hash_2) if v8 == True: w_self_3, w__hash_3, w_7 = w_self_2, w__hash_2, space.w_False - goto = 4 + goto = glabel_4 else: assert v8 == False w_self_3, w__hash_3, w_7 = w_self_2, w__hash_2, space.w_True - goto = 4 + goto = glabel_4 - if goto == 4: + if goto is glabel_4: v9 = space.is_true(w_7) if v9 == True: - goto = 5 + goto = glabel_5 else: assert v9 == False w_self_4, w__hash_4 = w_self_3, w__hash_3 - goto = 6 + goto = glabel_6 - if goto == 5: + if goto is glabel_5: w_10 = space.call_function(space.w_TypeError, gs_unhashable_instance) w_etype, w_evalue = space.w_TypeError, w_10 - goto = 10 + goto = glabel_10 - if goto == 6: + if goto is glabel_6: v13 = space.is_true(w__hash_4) if v13 == True: w__hash_5 = w__hash_4 - goto = 7 + goto = glabel_7 else: assert v13 == False w_self_5 = w_self_4 - goto = 9 + goto = glabel_9 - if goto == 7: + if goto is glabel_7: w_ret = space.call_function(w__hash_5, ) w_15 = space.isinstance(w_ret, space.w_int) v16 = space.is_true(w_15) if v16 == True: w_17 = w_ret - goto = 11 + goto = glabel_11 else: assert v16 == False - goto = 8 + goto = glabel_8 - if goto == 8: + if goto is glabel_8: w_18 = space.call_function(space.w_TypeError, gs___hash_____should_return_an_int) w_etype, w_evalue = space.w_TypeError, w_18 - goto = 10 + goto = glabel_10 - if goto == 9: + if goto is glabel_9: w_19 = space.id(w_self_5) w_17 = w_19 - goto = 11 + goto = glabel_11 - if goto == 10: + if goto is glabel_10: raise OperationError(w_etype, w_evalue) - if goto == 11: + if goto is glabel_11: return w_17 fastf_instance___hash__ = __hash__ ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function '__len__' ## firstlineno 336 ##SECTION## @@ -2555,54 +2438,51 @@ f_instance___len__ = __len__ def __len__(space, w_self): - - w_0=w_ret=w_3=v4=w_11=w_etype=w_evalue=w_ret_1=w_5=v6=w_7=w_8=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_0 = space.call_function(gfunc_instance_getattr1, w_self, gs___len__) w_ret = space.call_function(w_0, ) w_3 = space.isinstance(w_ret, space.w_int) v4 = space.is_true(w_3) if v4 == True: w_ret_1 = w_ret - goto = 2 + goto = glabel_2 else: assert v4 == False - goto = 4 + goto = glabel_4 - if goto == 2: + if goto is glabel_2: w_5 = space.lt(w_ret_1, gi_0) v6 = space.is_true(w_5) if v6 == True: - goto = 3 + goto = glabel_3 else: assert v6 == False w_7 = w_ret_1 - goto = 6 + goto = glabel_6 - if goto == 3: + if goto is glabel_3: w_8 = space.call_function(space.w_ValueError, gs___len_____should_return____0) w_etype, w_evalue = space.w_ValueError, w_8 - goto = 5 + goto = glabel_5 - if goto == 4: + if goto is glabel_4: w_11 = space.call_function(space.w_TypeError, gs___len_____should_return_an_int) w_etype, w_evalue = space.w_TypeError, w_11 - goto = 5 + goto = glabel_5 - if goto == 5: + if goto is glabel_5: raise OperationError(w_etype, w_evalue) - if goto == 6: + if goto is glabel_6: return w_7 fastf_instance___len__ = __len__ ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function '__getitem__' ## firstlineno 345 ##SECTION## @@ -2619,72 +2499,67 @@ f_instance___getitem__ = __getitem__ def __getitem__(space, w_self, w_key): - - w_0=v2=w_self_2=w_key_2=w_4=v7=w_self_4=w_key_4=w_14=w_15=w_13=None - w_self_3=w_key_3=w_func=v9=w_key_5=w_func_1=w_10=w_11=w_12=w_self_1=None - w_key_1=w_5=w_6=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_0 = space.isinstance(w_key, space.w_slice) v2 = space.is_true(w_0) if v2 == True: w_self_1, w_key_1 = w_self, w_key - goto = 2 + goto = glabel_2 else: assert v2 == False w_self_2, w_key_2, w_4 = w_self, w_key, w_0 - goto = 3 + goto = glabel_3 - if goto == 2: + if goto is glabel_2: w_5 = space.getattr(w_key_1, gs_step) w_6 = space.is_(w_5, space.w_None) w_self_2, w_key_2, w_4 = w_self_1, w_key_1, w_6 - goto = 3 + goto = glabel_3 - if goto == 3: + if goto is glabel_3: v7 = space.is_true(w_4) if v7 == True: w_self_3, w_key_3 = w_self_2, w_key_2 - goto = 4 + goto = glabel_4 else: assert v7 == False w_self_4, w_key_4 = w_self_2, w_key_2 - goto = 6 + goto = glabel_6 - if goto == 4: + if goto is glabel_4: w_func = space.call_function(gfunc_instance_getattr1, w_self_3, gs___getslice__, space.w_False) v9 = space.is_true(w_func) if v9 == True: w_key_5, w_func_1 = w_key_3, w_func - goto = 5 + goto = glabel_5 else: assert v9 == False w_self_4, w_key_4 = w_self_3, w_key_3 - goto = 6 + goto = glabel_6 - if goto == 5: + if goto is glabel_5: w_10 = space.getattr(w_key_5, gs_start) w_11 = space.getattr(w_key_5, gs_stop) w_12 = space.call_function(w_func_1, w_10, w_11) w_13 = w_12 - goto = 7 + goto = glabel_7 - if goto == 6: + if goto is glabel_6: w_14 = space.call_function(gfunc_instance_getattr1, w_self_4, gs___getitem__) w_15 = space.call_function(w_14, w_key_4) w_13 = w_15 - goto = 7 + goto = glabel_7 - if goto == 7: + if goto is glabel_7: return w_13 fastf_instance___getitem__ = __getitem__ ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function '__setitem__' ## firstlineno 352 ##SECTION## @@ -2704,75 +2579,69 @@ f_instance___setitem__ = __setitem__ def __setitem__(space, w_self, w_key, w_value): - - w_0=v2=w_self_2=w_key_2=w_value_2=w_5=v8=w_self_4=w_key_4=w_value_4=None - w_14=w_15=w_16=w_self_3=w_key_3=w_value_3=w_func=v10=w_self_5=None - w_key_5=w_value_5=w_func_1=w_11=w_12=w_13=w_self_1=w_key_1=w_value_1=None - w_6=w_7=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_0 = space.isinstance(w_key, space.w_slice) v2 = space.is_true(w_0) if v2 == True: w_self_1, w_key_1, w_value_1 = w_self, w_key, w_value - goto = 2 + goto = glabel_2 else: assert v2 == False w_self_2, w_key_2, w_value_2, w_5 = w_self, w_key, w_value, w_0 - goto = 3 + goto = glabel_3 - if goto == 2: + if goto is glabel_2: w_6 = space.getattr(w_key_1, gs_step) w_7 = space.is_(w_6, space.w_None) (w_self_2, w_key_2, w_value_2, w_5) = (w_self_1, w_key_1, w_value_1, w_7) - goto = 3 + goto = glabel_3 - if goto == 3: + if goto is glabel_3: v8 = space.is_true(w_5) if v8 == True: w_self_3, w_key_3, w_value_3 = w_self_2, w_key_2, w_value_2 - goto = 4 + goto = glabel_4 else: assert v8 == False w_self_4, w_key_4, w_value_4 = w_self_2, w_key_2, w_value_2 - goto = 6 + goto = glabel_6 - if goto == 4: + if goto is glabel_4: w_func = space.call_function(gfunc_instance_getattr1, w_self_3, gs___setslice__, space.w_False) v10 = space.is_true(w_func) if v10 == True: (w_self_5, w_key_5, w_value_5, w_func_1) = (w_self_3, w_key_3, w_value_3, w_func) - goto = 5 + goto = glabel_5 else: assert v10 == False w_self_4, w_key_4, w_value_4 = w_self_3, w_key_3, w_value_3 - goto = 6 + goto = glabel_6 - if goto == 5: + if goto is glabel_5: w_11 = space.getattr(w_key_5, gs_start) w_12 = space.getattr(w_key_5, gs_stop) w_13 = space.call_function(w_func_1, w_11, w_12, w_value_5) w_self_4, w_key_4, w_value_4 = w_self_5, w_key_5, w_value_5 - goto = 6 + goto = glabel_6 - if goto == 6: + if goto is glabel_6: w_14 = space.call_function(gfunc_instance_getattr1, w_self_4, gs___setitem__) w_15 = space.call_function(w_14, w_key_4, w_value_4) w_16 = space.w_None - goto = 7 + goto = glabel_7 - if goto == 7: + if goto is glabel_7: return w_16 fastf_instance___setitem__ = __setitem__ ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function '__delitem__' ## firstlineno 359 ##SECTION## @@ -2789,72 +2658,67 @@ f_instance___delitem__ = __delitem__ def __delitem__(space, w_self, w_key): - - w_0=v2=w_self_2=w_key_2=w_4=v7=w_self_4=w_key_4=w_13=w_14=w_15=None - w_self_3=w_key_3=w_func=v9=w_self_5=w_key_5=w_func_1=w_10=w_11=None - w_12=w_self_1=w_key_1=w_5=w_6=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_0 = space.isinstance(w_key, space.w_slice) v2 = space.is_true(w_0) if v2 == True: w_self_1, w_key_1 = w_self, w_key - goto = 2 + goto = glabel_2 else: assert v2 == False w_self_2, w_key_2, w_4 = w_self, w_key, w_0 - goto = 3 + goto = glabel_3 - if goto == 2: + if goto is glabel_2: w_5 = space.getattr(w_key_1, gs_step) w_6 = space.is_(w_5, space.w_None) w_self_2, w_key_2, w_4 = w_self_1, w_key_1, w_6 - goto = 3 + goto = glabel_3 - if goto == 3: + if goto is glabel_3: v7 = space.is_true(w_4) if v7 == True: w_self_3, w_key_3 = w_self_2, w_key_2 - goto = 4 + goto = glabel_4 else: assert v7 == False w_self_4, w_key_4 = w_self_2, w_key_2 - goto = 6 + goto = glabel_6 - if goto == 4: + if goto is glabel_4: w_func = space.call_function(gfunc_instance_getattr1, w_self_3, gs___delslice__, space.w_False) v9 = space.is_true(w_func) if v9 == True: w_self_5, w_key_5, w_func_1 = w_self_3, w_key_3, w_func - goto = 5 + goto = glabel_5 else: assert v9 == False w_self_4, w_key_4 = w_self_3, w_key_3 - goto = 6 + goto = glabel_6 - if goto == 5: + if goto is glabel_5: w_10 = space.getattr(w_key_5, gs_start) w_11 = space.getattr(w_key_5, gs_stop) w_12 = space.call_function(w_func_1, w_10, w_11) w_self_4, w_key_4 = w_self_5, w_key_5 - goto = 6 + goto = glabel_6 - if goto == 6: + if goto is glabel_6: w_13 = space.call_function(gfunc_instance_getattr1, w_self_4, gs___delitem__) w_14 = space.call_function(w_13, w_key_4) w_15 = space.w_None - goto = 7 + goto = glabel_7 - if goto == 7: + if goto is glabel_7: return w_15 fastf_instance___delitem__ = __delitem__ ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function '__contains__' ## firstlineno 366 ##SECTION## @@ -2868,65 +2732,61 @@ f_instance___contains__ = __contains__ def __contains__(space, w_self, w_obj): - - w_func=v2=w_self_1=w_obj_2=w_7=w_obj_3=w_8=w_x=w_obj_4=w_10=w_x_1=None - w_11=v12=w_6=w_obj_1=w_func_1=w_4=w_5=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_func = space.call_function(gfunc_instance_getattr1, w_self, gs___contains__, space.w_False) v2 = space.is_true(w_func) if v2 == True: w_obj_1, w_func_1 = w_obj, w_func - goto = 2 + goto = glabel_2 else: assert v2 == False w_self_1, w_obj_2 = w_self, w_obj - goto = 3 + goto = glabel_3 - if goto == 2: + if goto is glabel_2: w_4 = space.call_function(w_func_1, w_obj_1) w_5 = space.call_function(space.w_bool, w_4) w_6 = w_5 - goto = 6 + goto = glabel_6 - if goto == 3: + if goto is glabel_3: w_7 = space.iter(w_self_1) w_obj_3, w_8 = w_obj_2, w_7 - goto = 4 + goto = glabel_4 - if goto == 4: + if goto is glabel_4: try: w_x = space.next(w_8) w_obj_4, w_10, w_x_1 = w_obj_3, w_8, w_x - goto = 5 + goto = glabel_5 except OperationError, e: if space.is_true(space.issubtype(e.w_type, space.w_StopIteration)): w_6 = space.w_False - goto = 6 + goto = glabel_6 else:raise # unhandled case, should not happen - if goto == 5: + if goto is glabel_5: w_11 = space.eq(w_x_1, w_obj_4) v12 = space.is_true(w_11) if v12 == True: w_6 = space.w_True - goto = 6 + goto = glabel_6 else: assert v12 == False w_obj_3, w_8 = w_obj_4, w_10 - goto = 4 + goto = glabel_4 continue - if goto == 6: + if goto is glabel_6: return w_6 fastf_instance___contains__ = __contains__ ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function '__abs__' ## firstlineno 381 ##SECTION## @@ -2940,25 +2800,22 @@ f_instance___abs__ = __abs__ def __abs__(space, w_self): - - w_0=w_2=w_3=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_0 = space.call_function(gfunc_instance_getattr1, w_self, gs___abs__) w_2 = space.call_function(w_0, ) w_3 = w_2 - goto = 2 + goto = glabel_2 - if goto == 2: + if goto is glabel_2: return w_3 fastf_instance___abs__ = __abs__ ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function '__float__' ## firstlineno 381 ##SECTION## @@ -2972,25 +2829,22 @@ f_instance___float__ = __float__ def __float__(space, w_self): - - w_0=w_2=w_3=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_0 = space.call_function(gfunc_instance_getattr1, w_self, gs___float__) w_2 = space.call_function(w_0, ) w_3 = w_2 - goto = 2 + goto = glabel_2 - if goto == 2: + if goto is glabel_2: return w_3 fastf_instance___float__ = __float__ ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function '__hex__' ## firstlineno 381 ##SECTION## @@ -3004,25 +2858,22 @@ f_instance___hex__ = __hex__ def __hex__(space, w_self): - - w_0=w_2=w_3=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_0 = space.call_function(gfunc_instance_getattr1, w_self, gs___hex__) w_2 = space.call_function(w_0, ) w_3 = w_2 - goto = 2 + goto = glabel_2 - if goto == 2: + if goto is glabel_2: return w_3 fastf_instance___hex__ = __hex__ ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function '__int__' ## firstlineno 381 ##SECTION## @@ -3036,25 +2887,22 @@ f_instance___int__ = __int__ def __int__(space, w_self): - - w_0=w_2=w_3=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_0 = space.call_function(gfunc_instance_getattr1, w_self, gs___int__) w_2 = space.call_function(w_0, ) w_3 = w_2 - goto = 2 + goto = glabel_2 - if goto == 2: + if goto is glabel_2: return w_3 fastf_instance___int__ = __int__ ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function '__invert__' ## firstlineno 381 ##SECTION## @@ -3068,25 +2916,22 @@ f_instance___invert__ = __invert__ def __invert__(space, w_self): - - w_0=w_2=w_3=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_0 = space.call_function(gfunc_instance_getattr1, w_self, gs___invert__) w_2 = space.call_function(w_0, ) w_3 = w_2 - goto = 2 + goto = glabel_2 - if goto == 2: + if goto is glabel_2: return w_3 fastf_instance___invert__ = __invert__ ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function '__long__' ## firstlineno 381 ##SECTION## @@ -3100,25 +2945,22 @@ f_instance___long__ = __long__ def __long__(space, w_self): - - w_0=w_2=w_3=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_0 = space.call_function(gfunc_instance_getattr1, w_self, gs___long__) w_2 = space.call_function(w_0, ) w_3 = w_2 - goto = 2 + goto = glabel_2 - if goto == 2: + if goto is glabel_2: return w_3 fastf_instance___long__ = __long__ ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function '__neg__' ## firstlineno 381 ##SECTION## @@ -3132,25 +2974,22 @@ f_instance___neg__ = __neg__ def __neg__(space, w_self): - - w_0=w_2=w_3=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_0 = space.call_function(gfunc_instance_getattr1, w_self, gs___neg__) w_2 = space.call_function(w_0, ) w_3 = w_2 - goto = 2 + goto = glabel_2 - if goto == 2: + if goto is glabel_2: return w_3 fastf_instance___neg__ = __neg__ ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function '__oct__' ## firstlineno 381 ##SECTION## @@ -3164,25 +3003,22 @@ f_instance___oct__ = __oct__ def __oct__(space, w_self): - - w_0=w_2=w_3=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_0 = space.call_function(gfunc_instance_getattr1, w_self, gs___oct__) w_2 = space.call_function(w_0, ) w_3 = w_2 - goto = 2 + goto = glabel_2 - if goto == 2: + if goto is glabel_2: return w_3 fastf_instance___oct__ = __oct__ ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function '__pos__' ## firstlineno 381 ##SECTION## @@ -3196,25 +3032,22 @@ f_instance___pos__ = __pos__ def __pos__(space, w_self): - - w_0=w_2=w_3=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_0 = space.call_function(gfunc_instance_getattr1, w_self, gs___pos__) w_2 = space.call_function(w_0, ) w_3 = w_2 - goto = 2 + goto = glabel_2 - if goto == 2: + if goto is glabel_2: return w_3 fastf_instance___pos__ = __pos__ ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function '__coerce__' ## firstlineno 387 ##SECTION## @@ -3228,35 +3061,32 @@ f_instance___coerce__ = __coerce__ def __coerce__(space, w_self, w_other): - - w_func=v2=w_4=w_other_1=w_func_1=w_5=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_func = space.call_function(gfunc_instance_getattr1, w_self, gs___coerce__, space.w_False) v2 = space.is_true(w_func) if v2 == True: w_other_1, w_func_1 = w_other, w_func - goto = 2 + goto = glabel_2 else: assert v2 == False w_4 = space.w_NotImplemented - goto = 3 + goto = glabel_3 - if goto == 2: + if goto is glabel_2: w_5 = space.call_function(w_func_1, w_other_1) w_4 = w_5 - goto = 3 + goto = glabel_3 - if goto == 3: + if goto is glabel_3: return w_4 fastf_instance___coerce__ = __coerce__ ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function '__add__' ## firstlineno 404 ##SECTION## @@ -3270,70 +3100,65 @@ f_instance___add__ = __add__ def __add__(space, w_self, w_other): - - w_coerced=w_3=v4=w_self_2=w_other_2=w_coerced_1=w_6=w_7=w_self_1=None - w_other_1=w_5=v8=w_self_4=w_other_4=w_13=w_11=w_self_3=w_other_3=None - w_func=v10=w_other_5=w_func_1=w_12=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_coerced = fastf__coerce(space, w_self, w_other) w_3 = space.is_(w_coerced, space.w_None) v4 = space.is_true(w_3) if v4 == True: w_self_1, w_other_1, w_5 = w_self, w_other, w_3 - goto = 3 + goto = glabel_3 else: assert v4 == False w_self_2, w_other_2, w_coerced_1 = w_self, w_other, w_coerced - goto = 2 + goto = glabel_2 - if goto == 2: + if goto is glabel_2: w_6 = space.getitem(w_coerced_1, gi_0) w_7 = space.is_(w_6, w_self_2) w_self_1, w_other_1, w_5 = w_self_2, w_other_2, w_7 - goto = 3 + goto = glabel_3 - if goto == 3: + if goto is glabel_3: v8 = space.is_true(w_5) if v8 == True: w_self_3, w_other_3 = w_self_1, w_other_1 - goto = 4 + goto = glabel_4 else: assert v8 == False w_self_4, w_other_4 = w_self_1, w_other_1 - goto = 6 + goto = glabel_6 - if goto == 4: + if goto is glabel_4: w_func = space.call_function(gfunc_instance_getattr1, w_self_3, gs___add__, space.w_False) v10 = space.is_true(w_func) if v10 == True: w_other_5, w_func_1 = w_other_3, w_func - goto = 5 + goto = glabel_5 else: assert v10 == False w_11 = space.w_NotImplemented - goto = 7 + goto = glabel_7 - if goto == 5: + if goto is glabel_5: w_12 = space.call_function(w_func_1, w_other_5) w_11 = w_12 - goto = 7 + goto = glabel_7 - if goto == 6: + if goto is glabel_6: w_13 = space.add(w_self_4, w_other_4) w_11 = w_13 - goto = 7 + goto = glabel_7 - if goto == 7: + if goto is glabel_7: return w_11 fastf_instance___add__ = __add__ ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function '__and__' ## firstlineno 404 ##SECTION## @@ -3347,70 +3172,65 @@ f_instance___and__ = __and__ def __and__(space, w_self, w_other): - - w_coerced=w_3=v4=w_self_2=w_other_2=w_coerced_1=w_6=w_7=w_self_1=None - w_other_1=w_5=v8=w_self_4=w_other_4=w_13=w_11=w_self_3=w_other_3=None - w_func=v10=w_other_5=w_func_1=w_12=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_coerced = fastf__coerce(space, w_self, w_other) w_3 = space.is_(w_coerced, space.w_None) v4 = space.is_true(w_3) if v4 == True: w_self_1, w_other_1, w_5 = w_self, w_other, w_3 - goto = 3 + goto = glabel_3 else: assert v4 == False w_self_2, w_other_2, w_coerced_1 = w_self, w_other, w_coerced - goto = 2 + goto = glabel_2 - if goto == 2: + if goto is glabel_2: w_6 = space.getitem(w_coerced_1, gi_0) w_7 = space.is_(w_6, w_self_2) w_self_1, w_other_1, w_5 = w_self_2, w_other_2, w_7 - goto = 3 + goto = glabel_3 - if goto == 3: + if goto is glabel_3: v8 = space.is_true(w_5) if v8 == True: w_self_3, w_other_3 = w_self_1, w_other_1 - goto = 4 + goto = glabel_4 else: assert v8 == False w_self_4, w_other_4 = w_self_1, w_other_1 - goto = 6 + goto = glabel_6 - if goto == 4: + if goto is glabel_4: w_func = space.call_function(gfunc_instance_getattr1, w_self_3, gs___and__, space.w_False) v10 = space.is_true(w_func) if v10 == True: w_other_5, w_func_1 = w_other_3, w_func - goto = 5 + goto = glabel_5 else: assert v10 == False w_11 = space.w_NotImplemented - goto = 7 + goto = glabel_7 - if goto == 5: + if goto is glabel_5: w_12 = space.call_function(w_func_1, w_other_5) w_11 = w_12 - goto = 7 + goto = glabel_7 - if goto == 6: + if goto is glabel_6: w_13 = space.and_(w_self_4, w_other_4) w_11 = w_13 - goto = 7 + goto = glabel_7 - if goto == 7: + if goto is glabel_7: return w_11 fastf_instance___and__ = __and__ ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function '__div__' ## firstlineno 404 ##SECTION## @@ -3424,70 +3244,65 @@ f_instance___div__ = __div__ def __div__(space, w_self, w_other): - - w_coerced=w_3=v4=w_self_2=w_other_2=w_coerced_1=w_6=w_7=w_self_1=None - w_other_1=w_5=v8=w_self_4=w_other_4=w_13=w_11=w_self_3=w_other_3=None - w_func=v10=w_other_5=w_func_1=w_12=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_coerced = fastf__coerce(space, w_self, w_other) w_3 = space.is_(w_coerced, space.w_None) v4 = space.is_true(w_3) if v4 == True: w_self_1, w_other_1, w_5 = w_self, w_other, w_3 - goto = 3 + goto = glabel_3 else: assert v4 == False w_self_2, w_other_2, w_coerced_1 = w_self, w_other, w_coerced - goto = 2 + goto = glabel_2 - if goto == 2: + if goto is glabel_2: w_6 = space.getitem(w_coerced_1, gi_0) w_7 = space.is_(w_6, w_self_2) w_self_1, w_other_1, w_5 = w_self_2, w_other_2, w_7 - goto = 3 + goto = glabel_3 - if goto == 3: + if goto is glabel_3: v8 = space.is_true(w_5) if v8 == True: w_self_3, w_other_3 = w_self_1, w_other_1 - goto = 4 + goto = glabel_4 else: assert v8 == False w_self_4, w_other_4 = w_self_1, w_other_1 - goto = 6 + goto = glabel_6 - if goto == 4: + if goto is glabel_4: w_func = space.call_function(gfunc_instance_getattr1, w_self_3, gs___div__, space.w_False) v10 = space.is_true(w_func) if v10 == True: w_other_5, w_func_1 = w_other_3, w_func - goto = 5 + goto = glabel_5 else: assert v10 == False w_11 = space.w_NotImplemented - goto = 7 + goto = glabel_7 - if goto == 5: + if goto is glabel_5: w_12 = space.call_function(w_func_1, w_other_5) w_11 = w_12 - goto = 7 + goto = glabel_7 - if goto == 6: + if goto is glabel_6: w_13 = space.div(w_self_4, w_other_4) w_11 = w_13 - goto = 7 + goto = glabel_7 - if goto == 7: + if goto is glabel_7: return w_11 fastf_instance___div__ = __div__ ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function '__divmod__' ## firstlineno 404 ##SECTION## @@ -3501,70 +3316,65 @@ f_instance___divmod__ = __divmod__ def __divmod__(space, w_self, w_other): - - w_coerced=w_3=v4=w_self_2=w_other_2=w_coerced_1=w_6=w_7=w_self_1=None - w_other_1=w_5=v8=w_self_4=w_other_4=w_13=w_11=w_self_3=w_other_3=None - w_func=v10=w_other_5=w_func_1=w_12=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_coerced = fastf__coerce(space, w_self, w_other) w_3 = space.is_(w_coerced, space.w_None) v4 = space.is_true(w_3) if v4 == True: w_self_1, w_other_1, w_5 = w_self, w_other, w_3 - goto = 3 + goto = glabel_3 else: assert v4 == False w_self_2, w_other_2, w_coerced_1 = w_self, w_other, w_coerced - goto = 2 + goto = glabel_2 - if goto == 2: + if goto is glabel_2: w_6 = space.getitem(w_coerced_1, gi_0) w_7 = space.is_(w_6, w_self_2) w_self_1, w_other_1, w_5 = w_self_2, w_other_2, w_7 - goto = 3 + goto = glabel_3 - if goto == 3: + if goto is glabel_3: v8 = space.is_true(w_5) if v8 == True: w_self_3, w_other_3 = w_self_1, w_other_1 - goto = 4 + goto = glabel_4 else: assert v8 == False w_self_4, w_other_4 = w_self_1, w_other_1 - goto = 6 + goto = glabel_6 - if goto == 4: + if goto is glabel_4: w_func = space.call_function(gfunc_instance_getattr1, w_self_3, gs___divmod__, space.w_False) v10 = space.is_true(w_func) if v10 == True: w_other_5, w_func_1 = w_other_3, w_func - goto = 5 + goto = glabel_5 else: assert v10 == False w_11 = space.w_NotImplemented - goto = 7 + goto = glabel_7 - if goto == 5: + if goto is glabel_5: w_12 = space.call_function(w_func_1, w_other_5) w_11 = w_12 - goto = 7 + goto = glabel_7 - if goto == 6: + if goto is glabel_6: w_13 = space.divmod(w_self_4, w_other_4) w_11 = w_13 - goto = 7 + goto = glabel_7 - if goto == 7: + if goto is glabel_7: return w_11 fastf_instance___divmod__ = __divmod__ ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function '__floordiv__' ## firstlineno 404 ##SECTION## @@ -3578,70 +3388,65 @@ f_instance___floordiv__ = __floordiv__ def __floordiv__(space, w_self, w_other): - - w_coerced=w_3=v4=w_self_2=w_other_2=w_coerced_1=w_6=w_7=w_self_1=None - w_other_1=w_5=v8=w_self_4=w_other_4=w_13=w_11=w_self_3=w_other_3=None - w_func=v10=w_other_5=w_func_1=w_12=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_coerced = fastf__coerce(space, w_self, w_other) w_3 = space.is_(w_coerced, space.w_None) v4 = space.is_true(w_3) if v4 == True: w_self_1, w_other_1, w_5 = w_self, w_other, w_3 - goto = 3 + goto = glabel_3 else: assert v4 == False w_self_2, w_other_2, w_coerced_1 = w_self, w_other, w_coerced - goto = 2 + goto = glabel_2 - if goto == 2: + if goto is glabel_2: w_6 = space.getitem(w_coerced_1, gi_0) w_7 = space.is_(w_6, w_self_2) w_self_1, w_other_1, w_5 = w_self_2, w_other_2, w_7 - goto = 3 + goto = glabel_3 - if goto == 3: + if goto is glabel_3: v8 = space.is_true(w_5) if v8 == True: w_self_3, w_other_3 = w_self_1, w_other_1 - goto = 4 + goto = glabel_4 else: assert v8 == False w_self_4, w_other_4 = w_self_1, w_other_1 - goto = 6 + goto = glabel_6 - if goto == 4: + if goto is glabel_4: w_func = space.call_function(gfunc_instance_getattr1, w_self_3, gs___floordiv__, space.w_False) v10 = space.is_true(w_func) if v10 == True: w_other_5, w_func_1 = w_other_3, w_func - goto = 5 + goto = glabel_5 else: assert v10 == False w_11 = space.w_NotImplemented - goto = 7 + goto = glabel_7 - if goto == 5: + if goto is glabel_5: w_12 = space.call_function(w_func_1, w_other_5) w_11 = w_12 - goto = 7 + goto = glabel_7 - if goto == 6: + if goto is glabel_6: w_13 = space.floordiv(w_self_4, w_other_4) w_11 = w_13 - goto = 7 + goto = glabel_7 - if goto == 7: + if goto is glabel_7: return w_11 fastf_instance___floordiv__ = __floordiv__ ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function '__lshift__' ## firstlineno 404 ##SECTION## @@ -3655,70 +3460,65 @@ f_instance___lshift__ = __lshift__ def __lshift__(space, w_self, w_other): - - w_coerced=w_3=v4=w_self_2=w_other_2=w_coerced_1=w_6=w_7=w_self_1=None - w_other_1=w_5=v8=w_self_4=w_other_4=w_13=w_11=w_self_3=w_other_3=None - w_func=v10=w_other_5=w_func_1=w_12=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_coerced = fastf__coerce(space, w_self, w_other) w_3 = space.is_(w_coerced, space.w_None) v4 = space.is_true(w_3) if v4 == True: w_self_1, w_other_1, w_5 = w_self, w_other, w_3 - goto = 3 + goto = glabel_3 else: assert v4 == False w_self_2, w_other_2, w_coerced_1 = w_self, w_other, w_coerced - goto = 2 + goto = glabel_2 - if goto == 2: + if goto is glabel_2: w_6 = space.getitem(w_coerced_1, gi_0) w_7 = space.is_(w_6, w_self_2) w_self_1, w_other_1, w_5 = w_self_2, w_other_2, w_7 - goto = 3 + goto = glabel_3 - if goto == 3: + if goto is glabel_3: v8 = space.is_true(w_5) if v8 == True: w_self_3, w_other_3 = w_self_1, w_other_1 - goto = 4 + goto = glabel_4 else: assert v8 == False w_self_4, w_other_4 = w_self_1, w_other_1 - goto = 6 + goto = glabel_6 - if goto == 4: + if goto is glabel_4: w_func = space.call_function(gfunc_instance_getattr1, w_self_3, gs___lshift__, space.w_False) v10 = space.is_true(w_func) if v10 == True: w_other_5, w_func_1 = w_other_3, w_func - goto = 5 + goto = glabel_5 else: assert v10 == False w_11 = space.w_NotImplemented - goto = 7 + goto = glabel_7 - if goto == 5: + if goto is glabel_5: w_12 = space.call_function(w_func_1, w_other_5) w_11 = w_12 - goto = 7 + goto = glabel_7 - if goto == 6: + if goto is glabel_6: w_13 = space.lshift(w_self_4, w_other_4) w_11 = w_13 - goto = 7 + goto = glabel_7 - if goto == 7: + if goto is glabel_7: return w_11 fastf_instance___lshift__ = __lshift__ ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function '__mod__' ## firstlineno 404 ##SECTION## @@ -3732,70 +3532,65 @@ f_instance___mod__ = __mod__ def __mod__(space, w_self, w_other): - - w_coerced=w_3=v4=w_self_2=w_other_2=w_coerced_1=w_6=w_7=w_self_1=None - w_other_1=w_5=v8=w_self_4=w_other_4=w_13=w_11=w_self_3=w_other_3=None - w_func=v10=w_other_5=w_func_1=w_12=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_coerced = fastf__coerce(space, w_self, w_other) w_3 = space.is_(w_coerced, space.w_None) v4 = space.is_true(w_3) if v4 == True: w_self_1, w_other_1, w_5 = w_self, w_other, w_3 - goto = 3 + goto = glabel_3 else: assert v4 == False w_self_2, w_other_2, w_coerced_1 = w_self, w_other, w_coerced - goto = 2 + goto = glabel_2 - if goto == 2: + if goto is glabel_2: w_6 = space.getitem(w_coerced_1, gi_0) w_7 = space.is_(w_6, w_self_2) w_self_1, w_other_1, w_5 = w_self_2, w_other_2, w_7 - goto = 3 + goto = glabel_3 - if goto == 3: + if goto is glabel_3: v8 = space.is_true(w_5) if v8 == True: w_self_3, w_other_3 = w_self_1, w_other_1 - goto = 4 + goto = glabel_4 else: assert v8 == False w_self_4, w_other_4 = w_self_1, w_other_1 - goto = 6 + goto = glabel_6 - if goto == 4: + if goto is glabel_4: w_func = space.call_function(gfunc_instance_getattr1, w_self_3, gs___mod__, space.w_False) v10 = space.is_true(w_func) if v10 == True: w_other_5, w_func_1 = w_other_3, w_func - goto = 5 + goto = glabel_5 else: assert v10 == False w_11 = space.w_NotImplemented - goto = 7 + goto = glabel_7 - if goto == 5: + if goto is glabel_5: w_12 = space.call_function(w_func_1, w_other_5) w_11 = w_12 - goto = 7 + goto = glabel_7 - if goto == 6: + if goto is glabel_6: w_13 = space.mod(w_self_4, w_other_4) w_11 = w_13 - goto = 7 + goto = glabel_7 - if goto == 7: + if goto is glabel_7: return w_11 fastf_instance___mod__ = __mod__ ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function '__mul__' ## firstlineno 404 ##SECTION## @@ -3809,70 +3604,65 @@ f_instance___mul__ = __mul__ def __mul__(space, w_self, w_other): - - w_coerced=w_3=v4=w_self_2=w_other_2=w_coerced_1=w_6=w_7=w_self_1=None - w_other_1=w_5=v8=w_self_4=w_other_4=w_13=w_11=w_self_3=w_other_3=None - w_func=v10=w_other_5=w_func_1=w_12=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_coerced = fastf__coerce(space, w_self, w_other) w_3 = space.is_(w_coerced, space.w_None) v4 = space.is_true(w_3) if v4 == True: w_self_1, w_other_1, w_5 = w_self, w_other, w_3 - goto = 3 + goto = glabel_3 else: assert v4 == False w_self_2, w_other_2, w_coerced_1 = w_self, w_other, w_coerced - goto = 2 + goto = glabel_2 - if goto == 2: + if goto is glabel_2: w_6 = space.getitem(w_coerced_1, gi_0) w_7 = space.is_(w_6, w_self_2) w_self_1, w_other_1, w_5 = w_self_2, w_other_2, w_7 - goto = 3 + goto = glabel_3 - if goto == 3: + if goto is glabel_3: v8 = space.is_true(w_5) if v8 == True: w_self_3, w_other_3 = w_self_1, w_other_1 - goto = 4 + goto = glabel_4 else: assert v8 == False w_self_4, w_other_4 = w_self_1, w_other_1 - goto = 6 + goto = glabel_6 - if goto == 4: + if goto is glabel_4: w_func = space.call_function(gfunc_instance_getattr1, w_self_3, gs___mul__, space.w_False) v10 = space.is_true(w_func) if v10 == True: w_other_5, w_func_1 = w_other_3, w_func - goto = 5 + goto = glabel_5 else: assert v10 == False w_11 = space.w_NotImplemented - goto = 7 + goto = glabel_7 - if goto == 5: + if goto is glabel_5: w_12 = space.call_function(w_func_1, w_other_5) w_11 = w_12 - goto = 7 + goto = glabel_7 - if goto == 6: + if goto is glabel_6: w_13 = space.mul(w_self_4, w_other_4) w_11 = w_13 - goto = 7 + goto = glabel_7 - if goto == 7: + if goto is glabel_7: return w_11 fastf_instance___mul__ = __mul__ ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function '__or__' ## firstlineno 404 ##SECTION## @@ -3886,70 +3676,65 @@ f_instance___or__ = __or__ def __or__(space, w_self, w_other): - - w_coerced=w_3=v4=w_self_2=w_other_2=w_coerced_1=w_6=w_7=w_self_1=None - w_other_1=w_5=v8=w_self_4=w_other_4=w_13=w_11=w_self_3=w_other_3=None - w_func=v10=w_other_5=w_func_1=w_12=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_coerced = fastf__coerce(space, w_self, w_other) w_3 = space.is_(w_coerced, space.w_None) v4 = space.is_true(w_3) if v4 == True: w_self_1, w_other_1, w_5 = w_self, w_other, w_3 - goto = 3 + goto = glabel_3 else: assert v4 == False w_self_2, w_other_2, w_coerced_1 = w_self, w_other, w_coerced - goto = 2 + goto = glabel_2 - if goto == 2: + if goto is glabel_2: w_6 = space.getitem(w_coerced_1, gi_0) w_7 = space.is_(w_6, w_self_2) w_self_1, w_other_1, w_5 = w_self_2, w_other_2, w_7 - goto = 3 + goto = glabel_3 - if goto == 3: + if goto is glabel_3: v8 = space.is_true(w_5) if v8 == True: w_self_3, w_other_3 = w_self_1, w_other_1 - goto = 4 + goto = glabel_4 else: assert v8 == False w_self_4, w_other_4 = w_self_1, w_other_1 - goto = 6 + goto = glabel_6 - if goto == 4: + if goto is glabel_4: w_func = space.call_function(gfunc_instance_getattr1, w_self_3, gs___or__, space.w_False) v10 = space.is_true(w_func) if v10 == True: w_other_5, w_func_1 = w_other_3, w_func - goto = 5 + goto = glabel_5 else: assert v10 == False w_11 = space.w_NotImplemented - goto = 7 + goto = glabel_7 - if goto == 5: + if goto is glabel_5: w_12 = space.call_function(w_func_1, w_other_5) w_11 = w_12 - goto = 7 + goto = glabel_7 - if goto == 6: + if goto is glabel_6: w_13 = space.or_(w_self_4, w_other_4) w_11 = w_13 - goto = 7 + goto = glabel_7 - if goto == 7: + if goto is glabel_7: return w_11 fastf_instance___or__ = __or__ ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function '__rshift__' ## firstlineno 404 ##SECTION## @@ -3963,70 +3748,65 @@ f_instance___rshift__ = __rshift__ def __rshift__(space, w_self, w_other): - - w_coerced=w_3=v4=w_self_2=w_other_2=w_coerced_1=w_6=w_7=w_self_1=None - w_other_1=w_5=v8=w_self_4=w_other_4=w_13=w_11=w_self_3=w_other_3=None - w_func=v10=w_other_5=w_func_1=w_12=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_coerced = fastf__coerce(space, w_self, w_other) w_3 = space.is_(w_coerced, space.w_None) v4 = space.is_true(w_3) if v4 == True: w_self_1, w_other_1, w_5 = w_self, w_other, w_3 - goto = 3 + goto = glabel_3 else: assert v4 == False w_self_2, w_other_2, w_coerced_1 = w_self, w_other, w_coerced - goto = 2 + goto = glabel_2 - if goto == 2: + if goto is glabel_2: w_6 = space.getitem(w_coerced_1, gi_0) w_7 = space.is_(w_6, w_self_2) w_self_1, w_other_1, w_5 = w_self_2, w_other_2, w_7 - goto = 3 + goto = glabel_3 - if goto == 3: + if goto is glabel_3: v8 = space.is_true(w_5) if v8 == True: w_self_3, w_other_3 = w_self_1, w_other_1 - goto = 4 + goto = glabel_4 else: assert v8 == False w_self_4, w_other_4 = w_self_1, w_other_1 - goto = 6 + goto = glabel_6 - if goto == 4: + if goto is glabel_4: w_func = space.call_function(gfunc_instance_getattr1, w_self_3, gs___rshift__, space.w_False) v10 = space.is_true(w_func) if v10 == True: w_other_5, w_func_1 = w_other_3, w_func - goto = 5 + goto = glabel_5 else: assert v10 == False w_11 = space.w_NotImplemented - goto = 7 + goto = glabel_7 - if goto == 5: + if goto is glabel_5: w_12 = space.call_function(w_func_1, w_other_5) w_11 = w_12 - goto = 7 + goto = glabel_7 - if goto == 6: + if goto is glabel_6: w_13 = space.rshift(w_self_4, w_other_4) w_11 = w_13 - goto = 7 + goto = glabel_7 - if goto == 7: + if goto is glabel_7: return w_11 fastf_instance___rshift__ = __rshift__ ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function '__sub__' ## firstlineno 404 ##SECTION## @@ -4040,70 +3820,65 @@ f_instance___sub__ = __sub__ def __sub__(space, w_self, w_other): - - w_coerced=w_3=v4=w_self_2=w_other_2=w_coerced_1=w_6=w_7=w_self_1=None - w_other_1=w_5=v8=w_self_4=w_other_4=w_13=w_11=w_self_3=w_other_3=None - w_func=v10=w_other_5=w_func_1=w_12=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_coerced = fastf__coerce(space, w_self, w_other) w_3 = space.is_(w_coerced, space.w_None) v4 = space.is_true(w_3) if v4 == True: w_self_1, w_other_1, w_5 = w_self, w_other, w_3 - goto = 3 + goto = glabel_3 else: assert v4 == False w_self_2, w_other_2, w_coerced_1 = w_self, w_other, w_coerced - goto = 2 + goto = glabel_2 - if goto == 2: + if goto is glabel_2: w_6 = space.getitem(w_coerced_1, gi_0) w_7 = space.is_(w_6, w_self_2) w_self_1, w_other_1, w_5 = w_self_2, w_other_2, w_7 - goto = 3 + goto = glabel_3 - if goto == 3: + if goto is glabel_3: v8 = space.is_true(w_5) if v8 == True: w_self_3, w_other_3 = w_self_1, w_other_1 - goto = 4 + goto = glabel_4 else: assert v8 == False w_self_4, w_other_4 = w_self_1, w_other_1 - goto = 6 + goto = glabel_6 - if goto == 4: + if goto is glabel_4: w_func = space.call_function(gfunc_instance_getattr1, w_self_3, gs___sub__, space.w_False) v10 = space.is_true(w_func) if v10 == True: w_other_5, w_func_1 = w_other_3, w_func - goto = 5 + goto = glabel_5 else: assert v10 == False w_11 = space.w_NotImplemented - goto = 7 + goto = glabel_7 - if goto == 5: + if goto is glabel_5: w_12 = space.call_function(w_func_1, w_other_5) w_11 = w_12 - goto = 7 + goto = glabel_7 - if goto == 6: + if goto is glabel_6: w_13 = space.sub(w_self_4, w_other_4) w_11 = w_13 - goto = 7 + goto = glabel_7 - if goto == 7: + if goto is glabel_7: return w_11 fastf_instance___sub__ = __sub__ ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function '__truediv__' ## firstlineno 404 ##SECTION## @@ -4117,70 +3892,65 @@ f_instance___truediv__ = __truediv__ def __truediv__(space, w_self, w_other): - - w_coerced=w_3=v4=w_self_2=w_other_2=w_coerced_1=w_6=w_7=w_self_1=None - w_other_1=w_5=v8=w_self_4=w_other_4=w_13=w_11=w_self_3=w_other_3=None - w_func=v10=w_other_5=w_func_1=w_12=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_coerced = fastf__coerce(space, w_self, w_other) w_3 = space.is_(w_coerced, space.w_None) v4 = space.is_true(w_3) if v4 == True: w_self_1, w_other_1, w_5 = w_self, w_other, w_3 - goto = 3 + goto = glabel_3 else: assert v4 == False w_self_2, w_other_2, w_coerced_1 = w_self, w_other, w_coerced - goto = 2 + goto = glabel_2 - if goto == 2: + if goto is glabel_2: w_6 = space.getitem(w_coerced_1, gi_0) w_7 = space.is_(w_6, w_self_2) w_self_1, w_other_1, w_5 = w_self_2, w_other_2, w_7 - goto = 3 + goto = glabel_3 - if goto == 3: + if goto is glabel_3: v8 = space.is_true(w_5) if v8 == True: w_self_3, w_other_3 = w_self_1, w_other_1 - goto = 4 + goto = glabel_4 else: assert v8 == False w_self_4, w_other_4 = w_self_1, w_other_1 - goto = 6 + goto = glabel_6 - if goto == 4: + if goto is glabel_4: w_func = space.call_function(gfunc_instance_getattr1, w_self_3, gs___truediv__, space.w_False) v10 = space.is_true(w_func) if v10 == True: w_other_5, w_func_1 = w_other_3, w_func - goto = 5 + goto = glabel_5 else: assert v10 == False w_11 = space.w_NotImplemented - goto = 7 + goto = glabel_7 - if goto == 5: + if goto is glabel_5: w_12 = space.call_function(w_func_1, w_other_5) w_11 = w_12 - goto = 7 + goto = glabel_7 - if goto == 6: + if goto is glabel_6: w_13 = space.truediv(w_self_4, w_other_4) w_11 = w_13 - goto = 7 + goto = glabel_7 - if goto == 7: + if goto is glabel_7: return w_11 fastf_instance___truediv__ = __truediv__ ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function '__xor__' ## firstlineno 404 ##SECTION## @@ -4197,70 +3967,65 @@ f_instance___xor__ = __xor__ def __xor__(space, w_self, w_other): - - w_coerced=w_3=v4=w_self_2=w_other_2=w_coerced_1=w_6=w_7=w_self_1=None - w_other_1=w_5=v8=w_self_4=w_other_4=w_13=w_11=w_self_3=w_other_3=None - w_func=v10=w_other_5=w_func_1=w_12=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_coerced = fastf__coerce(space, w_self, w_other) w_3 = space.is_(w_coerced, space.w_None) v4 = space.is_true(w_3) if v4 == True: w_self_1, w_other_1, w_5 = w_self, w_other, w_3 - goto = 3 + goto = glabel_3 else: assert v4 == False w_self_2, w_other_2, w_coerced_1 = w_self, w_other, w_coerced - goto = 2 + goto = glabel_2 - if goto == 2: + if goto is glabel_2: w_6 = space.getitem(w_coerced_1, gi_0) w_7 = space.is_(w_6, w_self_2) w_self_1, w_other_1, w_5 = w_self_2, w_other_2, w_7 - goto = 3 + goto = glabel_3 - if goto == 3: + if goto is glabel_3: v8 = space.is_true(w_5) if v8 == True: w_self_3, w_other_3 = w_self_1, w_other_1 - goto = 4 + goto = glabel_4 else: assert v8 == False w_self_4, w_other_4 = w_self_1, w_other_1 - goto = 6 + goto = glabel_6 - if goto == 4: + if goto is glabel_4: w_func = space.call_function(gfunc_instance_getattr1, w_self_3, gs___xor__, space.w_False) v10 = space.is_true(w_func) if v10 == True: w_other_5, w_func_1 = w_other_3, w_func - goto = 5 + goto = glabel_5 else: assert v10 == False w_11 = space.w_NotImplemented - goto = 7 + goto = glabel_7 - if goto == 5: + if goto is glabel_5: w_12 = space.call_function(w_func_1, w_other_5) w_11 = w_12 - goto = 7 + goto = glabel_7 - if goto == 6: + if goto is glabel_6: w_13 = space.xor(w_self_4, w_other_4) w_11 = w_13 - goto = 7 + goto = glabel_7 - if goto == 7: + if goto is glabel_7: return w_11 fastf_instance___xor__ = __xor__ ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function '__radd__' ## firstlineno 414 ##SECTION## @@ -4274,70 +4039,65 @@ f_instance___radd__ = __radd__ def __radd__(space, w_self, w_other): - - w_coerced=w_3=v4=w_self_2=w_other_2=w_coerced_1=w_6=w_7=w_self_1=None - w_other_1=w_5=v8=w_self_4=w_other_4=w_13=w_11=w_self_3=w_other_3=None - w_func=v10=w_other_5=w_func_1=w_12=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_coerced = fastf__coerce(space, w_self, w_other) w_3 = space.is_(w_coerced, space.w_None) v4 = space.is_true(w_3) if v4 == True: w_self_1, w_other_1, w_5 = w_self, w_other, w_3 - goto = 3 + goto = glabel_3 else: assert v4 == False w_self_2, w_other_2, w_coerced_1 = w_self, w_other, w_coerced - goto = 2 + goto = glabel_2 - if goto == 2: + if goto is glabel_2: w_6 = space.getitem(w_coerced_1, gi_0) w_7 = space.is_(w_6, w_self_2) w_self_1, w_other_1, w_5 = w_self_2, w_other_2, w_7 - goto = 3 + goto = glabel_3 - if goto == 3: + if goto is glabel_3: v8 = space.is_true(w_5) if v8 == True: w_self_3, w_other_3 = w_self_1, w_other_1 - goto = 4 + goto = glabel_4 else: assert v8 == False w_self_4, w_other_4 = w_self_1, w_other_1 - goto = 6 + goto = glabel_6 - if goto == 4: + if goto is glabel_4: w_func = space.call_function(gfunc_instance_getattr1, w_self_3, gs___radd__, space.w_False) v10 = space.is_true(w_func) if v10 == True: w_other_5, w_func_1 = w_other_3, w_func - goto = 5 + goto = glabel_5 else: assert v10 == False w_11 = space.w_NotImplemented - goto = 7 + goto = glabel_7 - if goto == 5: + if goto is glabel_5: w_12 = space.call_function(w_func_1, w_other_5) w_11 = w_12 - goto = 7 + goto = glabel_7 - if goto == 6: + if goto is glabel_6: w_13 = space.add(w_other_4, w_self_4) w_11 = w_13 - goto = 7 + goto = glabel_7 - if goto == 7: + if goto is glabel_7: return w_11 fastf_instance___radd__ = __radd__ ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function '__rand__' ## firstlineno 414 ##SECTION## @@ -4351,70 +4111,65 @@ f_instance___rand__ = __rand__ def __rand__(space, w_self, w_other): - - w_coerced=w_3=v4=w_self_2=w_other_2=w_coerced_1=w_6=w_7=w_self_1=None - w_other_1=w_5=v8=w_self_4=w_other_4=w_13=w_11=w_self_3=w_other_3=None - w_func=v10=w_other_5=w_func_1=w_12=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_coerced = fastf__coerce(space, w_self, w_other) w_3 = space.is_(w_coerced, space.w_None) v4 = space.is_true(w_3) if v4 == True: w_self_1, w_other_1, w_5 = w_self, w_other, w_3 - goto = 3 + goto = glabel_3 else: assert v4 == False w_self_2, w_other_2, w_coerced_1 = w_self, w_other, w_coerced - goto = 2 + goto = glabel_2 - if goto == 2: + if goto is glabel_2: w_6 = space.getitem(w_coerced_1, gi_0) w_7 = space.is_(w_6, w_self_2) w_self_1, w_other_1, w_5 = w_self_2, w_other_2, w_7 - goto = 3 + goto = glabel_3 - if goto == 3: + if goto is glabel_3: v8 = space.is_true(w_5) if v8 == True: w_self_3, w_other_3 = w_self_1, w_other_1 - goto = 4 + goto = glabel_4 else: assert v8 == False w_self_4, w_other_4 = w_self_1, w_other_1 - goto = 6 + goto = glabel_6 - if goto == 4: + if goto is glabel_4: w_func = space.call_function(gfunc_instance_getattr1, w_self_3, gs___rand__, space.w_False) v10 = space.is_true(w_func) if v10 == True: w_other_5, w_func_1 = w_other_3, w_func - goto = 5 + goto = glabel_5 else: assert v10 == False w_11 = space.w_NotImplemented - goto = 7 + goto = glabel_7 - if goto == 5: + if goto is glabel_5: w_12 = space.call_function(w_func_1, w_other_5) w_11 = w_12 - goto = 7 + goto = glabel_7 - if goto == 6: + if goto is glabel_6: w_13 = space.and_(w_other_4, w_self_4) w_11 = w_13 - goto = 7 + goto = glabel_7 - if goto == 7: + if goto is glabel_7: return w_11 fastf_instance___rand__ = __rand__ ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function '__rdiv__' ## firstlineno 414 ##SECTION## @@ -4428,70 +4183,65 @@ f_instance___rdiv__ = __rdiv__ def __rdiv__(space, w_self, w_other): - - w_coerced=w_3=v4=w_self_2=w_other_2=w_coerced_1=w_6=w_7=w_self_1=None - w_other_1=w_5=v8=w_self_4=w_other_4=w_13=w_11=w_self_3=w_other_3=None - w_func=v10=w_other_5=w_func_1=w_12=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_coerced = fastf__coerce(space, w_self, w_other) w_3 = space.is_(w_coerced, space.w_None) v4 = space.is_true(w_3) if v4 == True: w_self_1, w_other_1, w_5 = w_self, w_other, w_3 - goto = 3 + goto = glabel_3 else: assert v4 == False w_self_2, w_other_2, w_coerced_1 = w_self, w_other, w_coerced - goto = 2 + goto = glabel_2 - if goto == 2: + if goto is glabel_2: w_6 = space.getitem(w_coerced_1, gi_0) w_7 = space.is_(w_6, w_self_2) w_self_1, w_other_1, w_5 = w_self_2, w_other_2, w_7 - goto = 3 + goto = glabel_3 - if goto == 3: + if goto is glabel_3: v8 = space.is_true(w_5) if v8 == True: w_self_3, w_other_3 = w_self_1, w_other_1 - goto = 4 + goto = glabel_4 else: assert v8 == False w_self_4, w_other_4 = w_self_1, w_other_1 - goto = 6 + goto = glabel_6 - if goto == 4: + if goto is glabel_4: w_func = space.call_function(gfunc_instance_getattr1, w_self_3, gs___rdiv__, space.w_False) v10 = space.is_true(w_func) if v10 == True: w_other_5, w_func_1 = w_other_3, w_func - goto = 5 + goto = glabel_5 else: assert v10 == False w_11 = space.w_NotImplemented - goto = 7 + goto = glabel_7 - if goto == 5: + if goto is glabel_5: w_12 = space.call_function(w_func_1, w_other_5) w_11 = w_12 - goto = 7 + goto = glabel_7 - if goto == 6: + if goto is glabel_6: w_13 = space.div(w_other_4, w_self_4) w_11 = w_13 - goto = 7 + goto = glabel_7 - if goto == 7: + if goto is glabel_7: return w_11 fastf_instance___rdiv__ = __rdiv__ ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function '__rdivmod__' ## firstlineno 414 ##SECTION## @@ -4505,70 +4255,65 @@ f_instance___rdivmod__ = __rdivmod__ def __rdivmod__(space, w_self, w_other): - - w_coerced=w_3=v4=w_self_2=w_other_2=w_coerced_1=w_6=w_7=w_self_1=None - w_other_1=w_5=v8=w_self_4=w_other_4=w_13=w_11=w_self_3=w_other_3=None - w_func=v10=w_other_5=w_func_1=w_12=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_coerced = fastf__coerce(space, w_self, w_other) w_3 = space.is_(w_coerced, space.w_None) v4 = space.is_true(w_3) if v4 == True: w_self_1, w_other_1, w_5 = w_self, w_other, w_3 - goto = 3 + goto = glabel_3 else: assert v4 == False w_self_2, w_other_2, w_coerced_1 = w_self, w_other, w_coerced - goto = 2 + goto = glabel_2 - if goto == 2: + if goto is glabel_2: w_6 = space.getitem(w_coerced_1, gi_0) w_7 = space.is_(w_6, w_self_2) w_self_1, w_other_1, w_5 = w_self_2, w_other_2, w_7 - goto = 3 + goto = glabel_3 - if goto == 3: + if goto is glabel_3: v8 = space.is_true(w_5) if v8 == True: w_self_3, w_other_3 = w_self_1, w_other_1 - goto = 4 + goto = glabel_4 else: assert v8 == False w_self_4, w_other_4 = w_self_1, w_other_1 - goto = 6 + goto = glabel_6 - if goto == 4: + if goto is glabel_4: w_func = space.call_function(gfunc_instance_getattr1, w_self_3, gs___rdivmod__, space.w_False) v10 = space.is_true(w_func) if v10 == True: w_other_5, w_func_1 = w_other_3, w_func - goto = 5 + goto = glabel_5 else: assert v10 == False w_11 = space.w_NotImplemented - goto = 7 + goto = glabel_7 - if goto == 5: + if goto is glabel_5: w_12 = space.call_function(w_func_1, w_other_5) w_11 = w_12 - goto = 7 + goto = glabel_7 - if goto == 6: + if goto is glabel_6: w_13 = space.divmod(w_other_4, w_self_4) w_11 = w_13 - goto = 7 + goto = glabel_7 - if goto == 7: + if goto is glabel_7: return w_11 fastf_instance___rdivmod__ = __rdivmod__ ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function '__rfloordiv__' ## firstlineno 414 ##SECTION## @@ -4582,70 +4327,65 @@ f_instance___rfloordiv__ = __rfloordiv__ def __rfloordiv__(space, w_self, w_other): - - w_coerced=w_3=v4=w_self_2=w_other_2=w_coerced_1=w_6=w_7=w_self_1=None - w_other_1=w_5=v8=w_self_4=w_other_4=w_13=w_11=w_self_3=w_other_3=None - w_func=v10=w_other_5=w_func_1=w_12=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_coerced = fastf__coerce(space, w_self, w_other) w_3 = space.is_(w_coerced, space.w_None) v4 = space.is_true(w_3) if v4 == True: w_self_1, w_other_1, w_5 = w_self, w_other, w_3 - goto = 3 + goto = glabel_3 else: assert v4 == False w_self_2, w_other_2, w_coerced_1 = w_self, w_other, w_coerced - goto = 2 + goto = glabel_2 - if goto == 2: + if goto is glabel_2: w_6 = space.getitem(w_coerced_1, gi_0) w_7 = space.is_(w_6, w_self_2) w_self_1, w_other_1, w_5 = w_self_2, w_other_2, w_7 - goto = 3 + goto = glabel_3 - if goto == 3: + if goto is glabel_3: v8 = space.is_true(w_5) if v8 == True: w_self_3, w_other_3 = w_self_1, w_other_1 - goto = 4 + goto = glabel_4 else: assert v8 == False w_self_4, w_other_4 = w_self_1, w_other_1 - goto = 6 + goto = glabel_6 - if goto == 4: + if goto is glabel_4: w_func = space.call_function(gfunc_instance_getattr1, w_self_3, gs___rfloordiv__, space.w_False) v10 = space.is_true(w_func) if v10 == True: w_other_5, w_func_1 = w_other_3, w_func - goto = 5 + goto = glabel_5 else: assert v10 == False w_11 = space.w_NotImplemented - goto = 7 + goto = glabel_7 - if goto == 5: + if goto is glabel_5: w_12 = space.call_function(w_func_1, w_other_5) w_11 = w_12 - goto = 7 + goto = glabel_7 - if goto == 6: + if goto is glabel_6: w_13 = space.floordiv(w_other_4, w_self_4) w_11 = w_13 - goto = 7 + goto = glabel_7 - if goto == 7: + if goto is glabel_7: return w_11 fastf_instance___rfloordiv__ = __rfloordiv__ ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function '__rlshift__' ## firstlineno 414 ##SECTION## @@ -4659,70 +4399,65 @@ f_instance___rlshift__ = __rlshift__ def __rlshift__(space, w_self, w_other): - - w_coerced=w_3=v4=w_self_2=w_other_2=w_coerced_1=w_6=w_7=w_self_1=None - w_other_1=w_5=v8=w_self_4=w_other_4=w_13=w_11=w_self_3=w_other_3=None - w_func=v10=w_other_5=w_func_1=w_12=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_coerced = fastf__coerce(space, w_self, w_other) w_3 = space.is_(w_coerced, space.w_None) v4 = space.is_true(w_3) if v4 == True: w_self_1, w_other_1, w_5 = w_self, w_other, w_3 - goto = 3 + goto = glabel_3 else: assert v4 == False w_self_2, w_other_2, w_coerced_1 = w_self, w_other, w_coerced - goto = 2 + goto = glabel_2 - if goto == 2: + if goto is glabel_2: w_6 = space.getitem(w_coerced_1, gi_0) w_7 = space.is_(w_6, w_self_2) w_self_1, w_other_1, w_5 = w_self_2, w_other_2, w_7 - goto = 3 + goto = glabel_3 - if goto == 3: + if goto is glabel_3: v8 = space.is_true(w_5) if v8 == True: w_self_3, w_other_3 = w_self_1, w_other_1 - goto = 4 + goto = glabel_4 else: assert v8 == False w_self_4, w_other_4 = w_self_1, w_other_1 - goto = 6 + goto = glabel_6 - if goto == 4: + if goto is glabel_4: w_func = space.call_function(gfunc_instance_getattr1, w_self_3, gs___rlshift__, space.w_False) v10 = space.is_true(w_func) if v10 == True: w_other_5, w_func_1 = w_other_3, w_func - goto = 5 + goto = glabel_5 else: assert v10 == False w_11 = space.w_NotImplemented - goto = 7 + goto = glabel_7 - if goto == 5: + if goto is glabel_5: w_12 = space.call_function(w_func_1, w_other_5) w_11 = w_12 - goto = 7 + goto = glabel_7 - if goto == 6: + if goto is glabel_6: w_13 = space.lshift(w_other_4, w_self_4) w_11 = w_13 - goto = 7 + goto = glabel_7 - if goto == 7: + if goto is glabel_7: return w_11 fastf_instance___rlshift__ = __rlshift__ ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function '__rmod__' ## firstlineno 414 ##SECTION## @@ -4736,70 +4471,65 @@ f_instance___rmod__ = __rmod__ def __rmod__(space, w_self, w_other): - - w_coerced=w_3=v4=w_self_2=w_other_2=w_coerced_1=w_6=w_7=w_self_1=None - w_other_1=w_5=v8=w_self_4=w_other_4=w_13=w_11=w_self_3=w_other_3=None - w_func=v10=w_other_5=w_func_1=w_12=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_coerced = fastf__coerce(space, w_self, w_other) w_3 = space.is_(w_coerced, space.w_None) v4 = space.is_true(w_3) if v4 == True: w_self_1, w_other_1, w_5 = w_self, w_other, w_3 - goto = 3 + goto = glabel_3 else: assert v4 == False w_self_2, w_other_2, w_coerced_1 = w_self, w_other, w_coerced - goto = 2 + goto = glabel_2 - if goto == 2: + if goto is glabel_2: w_6 = space.getitem(w_coerced_1, gi_0) w_7 = space.is_(w_6, w_self_2) w_self_1, w_other_1, w_5 = w_self_2, w_other_2, w_7 - goto = 3 + goto = glabel_3 - if goto == 3: + if goto is glabel_3: v8 = space.is_true(w_5) if v8 == True: w_self_3, w_other_3 = w_self_1, w_other_1 - goto = 4 + goto = glabel_4 else: assert v8 == False w_self_4, w_other_4 = w_self_1, w_other_1 - goto = 6 + goto = glabel_6 - if goto == 4: + if goto is glabel_4: w_func = space.call_function(gfunc_instance_getattr1, w_self_3, gs___rmod__, space.w_False) v10 = space.is_true(w_func) if v10 == True: w_other_5, w_func_1 = w_other_3, w_func - goto = 5 + goto = glabel_5 else: assert v10 == False w_11 = space.w_NotImplemented - goto = 7 + goto = glabel_7 - if goto == 5: + if goto is glabel_5: w_12 = space.call_function(w_func_1, w_other_5) w_11 = w_12 - goto = 7 + goto = glabel_7 - if goto == 6: + if goto is glabel_6: w_13 = space.mod(w_other_4, w_self_4) w_11 = w_13 - goto = 7 + goto = glabel_7 - if goto == 7: + if goto is glabel_7: return w_11 fastf_instance___rmod__ = __rmod__ ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function '__rmul__' ## firstlineno 414 ##SECTION## @@ -4813,70 +4543,65 @@ f_instance___rmul__ = __rmul__ def __rmul__(space, w_self, w_other): - - w_coerced=w_3=v4=w_self_2=w_other_2=w_coerced_1=w_6=w_7=w_self_1=None - w_other_1=w_5=v8=w_self_4=w_other_4=w_13=w_11=w_self_3=w_other_3=None - w_func=v10=w_other_5=w_func_1=w_12=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_coerced = fastf__coerce(space, w_self, w_other) w_3 = space.is_(w_coerced, space.w_None) v4 = space.is_true(w_3) if v4 == True: w_self_1, w_other_1, w_5 = w_self, w_other, w_3 - goto = 3 + goto = glabel_3 else: assert v4 == False w_self_2, w_other_2, w_coerced_1 = w_self, w_other, w_coerced - goto = 2 + goto = glabel_2 - if goto == 2: + if goto is glabel_2: w_6 = space.getitem(w_coerced_1, gi_0) w_7 = space.is_(w_6, w_self_2) w_self_1, w_other_1, w_5 = w_self_2, w_other_2, w_7 - goto = 3 + goto = glabel_3 - if goto == 3: + if goto is glabel_3: v8 = space.is_true(w_5) if v8 == True: w_self_3, w_other_3 = w_self_1, w_other_1 - goto = 4 + goto = glabel_4 else: assert v8 == False w_self_4, w_other_4 = w_self_1, w_other_1 - goto = 6 + goto = glabel_6 - if goto == 4: + if goto is glabel_4: w_func = space.call_function(gfunc_instance_getattr1, w_self_3, gs___rmul__, space.w_False) v10 = space.is_true(w_func) if v10 == True: w_other_5, w_func_1 = w_other_3, w_func - goto = 5 + goto = glabel_5 else: assert v10 == False w_11 = space.w_NotImplemented - goto = 7 + goto = glabel_7 - if goto == 5: + if goto is glabel_5: w_12 = space.call_function(w_func_1, w_other_5) w_11 = w_12 - goto = 7 + goto = glabel_7 - if goto == 6: + if goto is glabel_6: w_13 = space.mul(w_other_4, w_self_4) w_11 = w_13 - goto = 7 + goto = glabel_7 - if goto == 7: + if goto is glabel_7: return w_11 fastf_instance___rmul__ = __rmul__ ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function '__ror__' ## firstlineno 414 ##SECTION## @@ -4890,70 +4615,65 @@ f_instance___ror__ = __ror__ def __ror__(space, w_self, w_other): - - w_coerced=w_3=v4=w_self_2=w_other_2=w_coerced_1=w_6=w_7=w_self_1=None - w_other_1=w_5=v8=w_self_4=w_other_4=w_13=w_11=w_self_3=w_other_3=None - w_func=v10=w_other_5=w_func_1=w_12=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_coerced = fastf__coerce(space, w_self, w_other) w_3 = space.is_(w_coerced, space.w_None) v4 = space.is_true(w_3) if v4 == True: w_self_1, w_other_1, w_5 = w_self, w_other, w_3 - goto = 3 + goto = glabel_3 else: assert v4 == False w_self_2, w_other_2, w_coerced_1 = w_self, w_other, w_coerced - goto = 2 + goto = glabel_2 - if goto == 2: + if goto is glabel_2: w_6 = space.getitem(w_coerced_1, gi_0) w_7 = space.is_(w_6, w_self_2) w_self_1, w_other_1, w_5 = w_self_2, w_other_2, w_7 - goto = 3 + goto = glabel_3 - if goto == 3: + if goto is glabel_3: v8 = space.is_true(w_5) if v8 == True: w_self_3, w_other_3 = w_self_1, w_other_1 - goto = 4 + goto = glabel_4 else: assert v8 == False w_self_4, w_other_4 = w_self_1, w_other_1 - goto = 6 + goto = glabel_6 - if goto == 4: + if goto is glabel_4: w_func = space.call_function(gfunc_instance_getattr1, w_self_3, gs___ror__, space.w_False) v10 = space.is_true(w_func) if v10 == True: w_other_5, w_func_1 = w_other_3, w_func - goto = 5 + goto = glabel_5 else: assert v10 == False w_11 = space.w_NotImplemented - goto = 7 + goto = glabel_7 - if goto == 5: + if goto is glabel_5: w_12 = space.call_function(w_func_1, w_other_5) w_11 = w_12 - goto = 7 + goto = glabel_7 - if goto == 6: + if goto is glabel_6: w_13 = space.or_(w_other_4, w_self_4) w_11 = w_13 - goto = 7 + goto = glabel_7 - if goto == 7: + if goto is glabel_7: return w_11 fastf_instance___ror__ = __ror__ ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function '__rrshift__' ## firstlineno 414 ##SECTION## @@ -4967,70 +4687,65 @@ f_instance___rrshift__ = __rrshift__ def __rrshift__(space, w_self, w_other): - - w_coerced=w_3=v4=w_self_2=w_other_2=w_coerced_1=w_6=w_7=w_self_1=None - w_other_1=w_5=v8=w_self_4=w_other_4=w_13=w_11=w_self_3=w_other_3=None - w_func=v10=w_other_5=w_func_1=w_12=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_coerced = fastf__coerce(space, w_self, w_other) w_3 = space.is_(w_coerced, space.w_None) v4 = space.is_true(w_3) if v4 == True: w_self_1, w_other_1, w_5 = w_self, w_other, w_3 - goto = 3 + goto = glabel_3 else: assert v4 == False w_self_2, w_other_2, w_coerced_1 = w_self, w_other, w_coerced - goto = 2 + goto = glabel_2 - if goto == 2: + if goto is glabel_2: w_6 = space.getitem(w_coerced_1, gi_0) w_7 = space.is_(w_6, w_self_2) w_self_1, w_other_1, w_5 = w_self_2, w_other_2, w_7 - goto = 3 + goto = glabel_3 - if goto == 3: + if goto is glabel_3: v8 = space.is_true(w_5) if v8 == True: w_self_3, w_other_3 = w_self_1, w_other_1 - goto = 4 + goto = glabel_4 else: assert v8 == False w_self_4, w_other_4 = w_self_1, w_other_1 - goto = 6 + goto = glabel_6 - if goto == 4: + if goto is glabel_4: w_func = space.call_function(gfunc_instance_getattr1, w_self_3, gs___rrshift__, space.w_False) v10 = space.is_true(w_func) if v10 == True: w_other_5, w_func_1 = w_other_3, w_func - goto = 5 + goto = glabel_5 else: assert v10 == False w_11 = space.w_NotImplemented - goto = 7 + goto = glabel_7 - if goto == 5: + if goto is glabel_5: w_12 = space.call_function(w_func_1, w_other_5) w_11 = w_12 - goto = 7 + goto = glabel_7 - if goto == 6: + if goto is glabel_6: w_13 = space.rshift(w_other_4, w_self_4) w_11 = w_13 - goto = 7 + goto = glabel_7 - if goto == 7: + if goto is glabel_7: return w_11 fastf_instance___rrshift__ = __rrshift__ ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function '__rsub__' ## firstlineno 414 ##SECTION## @@ -5044,70 +4759,65 @@ f_instance___rsub__ = __rsub__ def __rsub__(space, w_self, w_other): - - w_coerced=w_3=v4=w_self_2=w_other_2=w_coerced_1=w_6=w_7=w_self_1=None - w_other_1=w_5=v8=w_self_4=w_other_4=w_13=w_11=w_self_3=w_other_3=None - w_func=v10=w_other_5=w_func_1=w_12=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_coerced = fastf__coerce(space, w_self, w_other) w_3 = space.is_(w_coerced, space.w_None) v4 = space.is_true(w_3) if v4 == True: w_self_1, w_other_1, w_5 = w_self, w_other, w_3 - goto = 3 + goto = glabel_3 else: assert v4 == False w_self_2, w_other_2, w_coerced_1 = w_self, w_other, w_coerced - goto = 2 + goto = glabel_2 - if goto == 2: + if goto is glabel_2: w_6 = space.getitem(w_coerced_1, gi_0) w_7 = space.is_(w_6, w_self_2) w_self_1, w_other_1, w_5 = w_self_2, w_other_2, w_7 - goto = 3 + goto = glabel_3 - if goto == 3: + if goto is glabel_3: v8 = space.is_true(w_5) if v8 == True: w_self_3, w_other_3 = w_self_1, w_other_1 - goto = 4 + goto = glabel_4 else: assert v8 == False w_self_4, w_other_4 = w_self_1, w_other_1 - goto = 6 + goto = glabel_6 - if goto == 4: + if goto is glabel_4: w_func = space.call_function(gfunc_instance_getattr1, w_self_3, gs___rsub__, space.w_False) v10 = space.is_true(w_func) if v10 == True: w_other_5, w_func_1 = w_other_3, w_func - goto = 5 + goto = glabel_5 else: assert v10 == False w_11 = space.w_NotImplemented - goto = 7 + goto = glabel_7 - if goto == 5: + if goto is glabel_5: w_12 = space.call_function(w_func_1, w_other_5) w_11 = w_12 - goto = 7 + goto = glabel_7 - if goto == 6: + if goto is glabel_6: w_13 = space.sub(w_other_4, w_self_4) w_11 = w_13 - goto = 7 + goto = glabel_7 - if goto == 7: + if goto is glabel_7: return w_11 fastf_instance___rsub__ = __rsub__ ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function '__rtruediv__' ## firstlineno 414 ##SECTION## @@ -5121,70 +4831,65 @@ f_instance___rtruediv__ = __rtruediv__ def __rtruediv__(space, w_self, w_other): - - w_coerced=w_3=v4=w_self_2=w_other_2=w_coerced_1=w_6=w_7=w_self_1=None - w_other_1=w_5=v8=w_self_4=w_other_4=w_13=w_11=w_self_3=w_other_3=None - w_func=v10=w_other_5=w_func_1=w_12=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_coerced = fastf__coerce(space, w_self, w_other) w_3 = space.is_(w_coerced, space.w_None) v4 = space.is_true(w_3) if v4 == True: w_self_1, w_other_1, w_5 = w_self, w_other, w_3 - goto = 3 + goto = glabel_3 else: assert v4 == False w_self_2, w_other_2, w_coerced_1 = w_self, w_other, w_coerced - goto = 2 + goto = glabel_2 - if goto == 2: + if goto is glabel_2: w_6 = space.getitem(w_coerced_1, gi_0) w_7 = space.is_(w_6, w_self_2) w_self_1, w_other_1, w_5 = w_self_2, w_other_2, w_7 - goto = 3 + goto = glabel_3 - if goto == 3: + if goto is glabel_3: v8 = space.is_true(w_5) if v8 == True: w_self_3, w_other_3 = w_self_1, w_other_1 - goto = 4 + goto = glabel_4 else: assert v8 == False w_self_4, w_other_4 = w_self_1, w_other_1 - goto = 6 + goto = glabel_6 - if goto == 4: + if goto is glabel_4: w_func = space.call_function(gfunc_instance_getattr1, w_self_3, gs___rtruediv__, space.w_False) v10 = space.is_true(w_func) if v10 == True: w_other_5, w_func_1 = w_other_3, w_func - goto = 5 + goto = glabel_5 else: assert v10 == False w_11 = space.w_NotImplemented - goto = 7 + goto = glabel_7 - if goto == 5: + if goto is glabel_5: w_12 = space.call_function(w_func_1, w_other_5) w_11 = w_12 - goto = 7 + goto = glabel_7 - if goto == 6: + if goto is glabel_6: w_13 = space.truediv(w_other_4, w_self_4) w_11 = w_13 - goto = 7 + goto = glabel_7 - if goto == 7: + if goto is glabel_7: return w_11 fastf_instance___rtruediv__ = __rtruediv__ ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function '__rxor__' ## firstlineno 414 ##SECTION## @@ -5198,70 +4903,65 @@ f_instance___rxor__ = __rxor__ def __rxor__(space, w_self, w_other): - - w_coerced=w_3=v4=w_self_2=w_other_2=w_coerced_1=w_6=w_7=w_self_1=None - w_other_1=w_5=v8=w_self_4=w_other_4=w_13=w_11=w_self_3=w_other_3=None - w_func=v10=w_other_5=w_func_1=w_12=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_coerced = fastf__coerce(space, w_self, w_other) w_3 = space.is_(w_coerced, space.w_None) v4 = space.is_true(w_3) if v4 == True: w_self_1, w_other_1, w_5 = w_self, w_other, w_3 - goto = 3 + goto = glabel_3 else: assert v4 == False w_self_2, w_other_2, w_coerced_1 = w_self, w_other, w_coerced - goto = 2 + goto = glabel_2 - if goto == 2: + if goto is glabel_2: w_6 = space.getitem(w_coerced_1, gi_0) w_7 = space.is_(w_6, w_self_2) w_self_1, w_other_1, w_5 = w_self_2, w_other_2, w_7 - goto = 3 + goto = glabel_3 - if goto == 3: + if goto is glabel_3: v8 = space.is_true(w_5) if v8 == True: w_self_3, w_other_3 = w_self_1, w_other_1 - goto = 4 + goto = glabel_4 else: assert v8 == False w_self_4, w_other_4 = w_self_1, w_other_1 - goto = 6 + goto = glabel_6 - if goto == 4: + if goto is glabel_4: w_func = space.call_function(gfunc_instance_getattr1, w_self_3, gs___rxor__, space.w_False) v10 = space.is_true(w_func) if v10 == True: w_other_5, w_func_1 = w_other_3, w_func - goto = 5 + goto = glabel_5 else: assert v10 == False w_11 = space.w_NotImplemented - goto = 7 + goto = glabel_7 - if goto == 5: + if goto is glabel_5: w_12 = space.call_function(w_func_1, w_other_5) w_11 = w_12 - goto = 7 + goto = glabel_7 - if goto == 6: + if goto is glabel_6: w_13 = space.xor(w_other_4, w_self_4) w_11 = w_13 - goto = 7 + goto = glabel_7 - if goto == 7: + if goto is glabel_7: return w_11 fastf_instance___rxor__ = __rxor__ ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function '__iadd__' ## firstlineno 432 ##SECTION## @@ -5275,35 +4975,32 @@ f_instance___iadd__ = __iadd__ def __iadd__(space, w_self, w_other): - - w_func=v2=w_4=w_other_1=w_func_1=w_5=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_func = space.call_function(gfunc_instance_getattr1, w_self, gs___iadd__, space.w_False) v2 = space.is_true(w_func) if v2 == True: w_other_1, w_func_1 = w_other, w_func - goto = 2 + goto = glabel_2 else: assert v2 == False w_4 = space.w_NotImplemented - goto = 3 + goto = glabel_3 - if goto == 2: + if goto is glabel_2: w_5 = space.call_function(w_func_1, w_other_1) w_4 = w_5 - goto = 3 + goto = glabel_3 - if goto == 3: + if goto is glabel_3: return w_4 fastf_instance___iadd__ = __iadd__ ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function '__iand__' ## firstlineno 432 ##SECTION## @@ -5317,35 +5014,32 @@ f_instance___iand__ = __iand__ def __iand__(space, w_self, w_other): - - w_func=v2=w_4=w_other_1=w_func_1=w_5=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_func = space.call_function(gfunc_instance_getattr1, w_self, gs___iand__, space.w_False) v2 = space.is_true(w_func) if v2 == True: w_other_1, w_func_1 = w_other, w_func - goto = 2 + goto = glabel_2 else: assert v2 == False w_4 = space.w_NotImplemented - goto = 3 + goto = glabel_3 - if goto == 2: + if goto is glabel_2: w_5 = space.call_function(w_func_1, w_other_1) w_4 = w_5 - goto = 3 + goto = glabel_3 - if goto == 3: + if goto is glabel_3: return w_4 fastf_instance___iand__ = __iand__ ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function '__idiv__' ## firstlineno 432 ##SECTION## @@ -5359,35 +5053,32 @@ f_instance___idiv__ = __idiv__ def __idiv__(space, w_self, w_other): - - w_func=v2=w_4=w_other_1=w_func_1=w_5=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_func = space.call_function(gfunc_instance_getattr1, w_self, gs___idiv__, space.w_False) v2 = space.is_true(w_func) if v2 == True: w_other_1, w_func_1 = w_other, w_func - goto = 2 + goto = glabel_2 else: assert v2 == False w_4 = space.w_NotImplemented - goto = 3 + goto = glabel_3 - if goto == 2: + if goto is glabel_2: w_5 = space.call_function(w_func_1, w_other_1) w_4 = w_5 - goto = 3 + goto = glabel_3 - if goto == 3: + if goto is glabel_3: return w_4 fastf_instance___idiv__ = __idiv__ ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function '__ifloordiv__' ## firstlineno 432 ##SECTION## @@ -5401,35 +5092,32 @@ f_instance___ifloordiv__ = __ifloordiv__ def __ifloordiv__(space, w_self, w_other): - - w_func=v2=w_4=w_other_1=w_func_1=w_5=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_func = space.call_function(gfunc_instance_getattr1, w_self, gs___ifloordiv__, space.w_False) v2 = space.is_true(w_func) if v2 == True: w_other_1, w_func_1 = w_other, w_func - goto = 2 + goto = glabel_2 else: assert v2 == False w_4 = space.w_NotImplemented - goto = 3 + goto = glabel_3 - if goto == 2: + if goto is glabel_2: w_5 = space.call_function(w_func_1, w_other_1) w_4 = w_5 - goto = 3 + goto = glabel_3 - if goto == 3: + if goto is glabel_3: return w_4 fastf_instance___ifloordiv__ = __ifloordiv__ ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function '__ilshift__' ## firstlineno 432 ##SECTION## @@ -5443,35 +5131,32 @@ f_instance___ilshift__ = __ilshift__ def __ilshift__(space, w_self, w_other): - - w_func=v2=w_4=w_other_1=w_func_1=w_5=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_func = space.call_function(gfunc_instance_getattr1, w_self, gs___ilshift__, space.w_False) v2 = space.is_true(w_func) if v2 == True: w_other_1, w_func_1 = w_other, w_func - goto = 2 + goto = glabel_2 else: assert v2 == False w_4 = space.w_NotImplemented - goto = 3 + goto = glabel_3 - if goto == 2: + if goto is glabel_2: w_5 = space.call_function(w_func_1, w_other_1) w_4 = w_5 - goto = 3 + goto = glabel_3 - if goto == 3: + if goto is glabel_3: return w_4 fastf_instance___ilshift__ = __ilshift__ ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function '__imod__' ## firstlineno 432 ##SECTION## @@ -5485,35 +5170,32 @@ f_instance___imod__ = __imod__ def __imod__(space, w_self, w_other): - - w_func=v2=w_4=w_other_1=w_func_1=w_5=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_func = space.call_function(gfunc_instance_getattr1, w_self, gs___imod__, space.w_False) v2 = space.is_true(w_func) if v2 == True: w_other_1, w_func_1 = w_other, w_func - goto = 2 + goto = glabel_2 else: assert v2 == False w_4 = space.w_NotImplemented - goto = 3 + goto = glabel_3 - if goto == 2: + if goto is glabel_2: w_5 = space.call_function(w_func_1, w_other_1) w_4 = w_5 - goto = 3 + goto = glabel_3 - if goto == 3: + if goto is glabel_3: return w_4 fastf_instance___imod__ = __imod__ ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function '__imul__' ## firstlineno 432 ##SECTION## @@ -5527,35 +5209,32 @@ f_instance___imul__ = __imul__ def __imul__(space, w_self, w_other): - - w_func=v2=w_4=w_other_1=w_func_1=w_5=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_func = space.call_function(gfunc_instance_getattr1, w_self, gs___imul__, space.w_False) v2 = space.is_true(w_func) if v2 == True: w_other_1, w_func_1 = w_other, w_func - goto = 2 + goto = glabel_2 else: assert v2 == False w_4 = space.w_NotImplemented - goto = 3 + goto = glabel_3 - if goto == 2: + if goto is glabel_2: w_5 = space.call_function(w_func_1, w_other_1) w_4 = w_5 - goto = 3 + goto = glabel_3 - if goto == 3: + if goto is glabel_3: return w_4 fastf_instance___imul__ = __imul__ ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function '__ior__' ## firstlineno 432 ##SECTION## @@ -5569,35 +5248,32 @@ f_instance___ior__ = __ior__ def __ior__(space, w_self, w_other): - - w_func=v2=w_4=w_other_1=w_func_1=w_5=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_func = space.call_function(gfunc_instance_getattr1, w_self, gs___ior__, space.w_False) v2 = space.is_true(w_func) if v2 == True: w_other_1, w_func_1 = w_other, w_func - goto = 2 + goto = glabel_2 else: assert v2 == False w_4 = space.w_NotImplemented - goto = 3 + goto = glabel_3 - if goto == 2: + if goto is glabel_2: w_5 = space.call_function(w_func_1, w_other_1) w_4 = w_5 - goto = 3 + goto = glabel_3 - if goto == 3: + if goto is glabel_3: return w_4 fastf_instance___ior__ = __ior__ ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function '__ipow__' ## firstlineno 432 ##SECTION## @@ -5611,35 +5287,32 @@ f_instance___ipow__ = __ipow__ def __ipow__(space, w_self, w_other): - - w_func=v2=w_4=w_other_1=w_func_1=w_5=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_func = space.call_function(gfunc_instance_getattr1, w_self, gs___ipow__, space.w_False) v2 = space.is_true(w_func) if v2 == True: w_other_1, w_func_1 = w_other, w_func - goto = 2 + goto = glabel_2 else: assert v2 == False w_4 = space.w_NotImplemented - goto = 3 + goto = glabel_3 - if goto == 2: + if goto is glabel_2: w_5 = space.call_function(w_func_1, w_other_1) w_4 = w_5 - goto = 3 + goto = glabel_3 - if goto == 3: + if goto is glabel_3: return w_4 fastf_instance___ipow__ = __ipow__ ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function '__irshift__' ## firstlineno 432 ##SECTION## @@ -5653,35 +5326,32 @@ f_instance___irshift__ = __irshift__ def __irshift__(space, w_self, w_other): - - w_func=v2=w_4=w_other_1=w_func_1=w_5=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_func = space.call_function(gfunc_instance_getattr1, w_self, gs___irshift__, space.w_False) v2 = space.is_true(w_func) if v2 == True: w_other_1, w_func_1 = w_other, w_func - goto = 2 + goto = glabel_2 else: assert v2 == False w_4 = space.w_NotImplemented - goto = 3 + goto = glabel_3 - if goto == 2: + if goto is glabel_2: w_5 = space.call_function(w_func_1, w_other_1) w_4 = w_5 - goto = 3 + goto = glabel_3 - if goto == 3: + if goto is glabel_3: return w_4 fastf_instance___irshift__ = __irshift__ ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function '__isub__' ## firstlineno 432 ##SECTION## @@ -5695,35 +5365,32 @@ f_instance___isub__ = __isub__ def __isub__(space, w_self, w_other): - - w_func=v2=w_4=w_other_1=w_func_1=w_5=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_func = space.call_function(gfunc_instance_getattr1, w_self, gs___isub__, space.w_False) v2 = space.is_true(w_func) if v2 == True: w_other_1, w_func_1 = w_other, w_func - goto = 2 + goto = glabel_2 else: assert v2 == False w_4 = space.w_NotImplemented - goto = 3 + goto = glabel_3 - if goto == 2: + if goto is glabel_2: w_5 = space.call_function(w_func_1, w_other_1) w_4 = w_5 - goto = 3 + goto = glabel_3 - if goto == 3: + if goto is glabel_3: return w_4 fastf_instance___isub__ = __isub__ ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function '__itruediv__' ## firstlineno 432 ##SECTION## @@ -5737,35 +5404,32 @@ f_instance___itruediv__ = __itruediv__ def __itruediv__(space, w_self, w_other): - - w_func=v2=w_4=w_other_1=w_func_1=w_5=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_func = space.call_function(gfunc_instance_getattr1, w_self, gs___itruediv__, space.w_False) v2 = space.is_true(w_func) if v2 == True: w_other_1, w_func_1 = w_other, w_func - goto = 2 + goto = glabel_2 else: assert v2 == False w_4 = space.w_NotImplemented - goto = 3 + goto = glabel_3 - if goto == 2: + if goto is glabel_2: w_5 = space.call_function(w_func_1, w_other_1) w_4 = w_5 - goto = 3 + goto = glabel_3 - if goto == 3: + if goto is glabel_3: return w_4 fastf_instance___itruediv__ = __itruediv__ ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function '__ixor__' ## firstlineno 432 ##SECTION## @@ -5779,35 +5443,32 @@ f_instance___ixor__ = __ixor__ def __ixor__(space, w_self, w_other): - - w_func=v2=w_4=w_other_1=w_func_1=w_5=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_func = space.call_function(gfunc_instance_getattr1, w_self, gs___ixor__, space.w_False) v2 = space.is_true(w_func) if v2 == True: w_other_1, w_func_1 = w_other, w_func - goto = 2 + goto = glabel_2 else: assert v2 == False w_4 = space.w_NotImplemented - goto = 3 + goto = glabel_3 - if goto == 2: + if goto is glabel_2: w_5 = space.call_function(w_func_1, w_other_1) w_4 = w_5 - goto = 3 + goto = glabel_3 - if goto == 3: + if goto is glabel_3: return w_4 fastf_instance___ixor__ = __ixor__ ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function '__pow__' ## firstlineno 441 ##SECTION## @@ -5821,99 +5482,92 @@ f_instance___pow__ = __pow__ def __pow__(space, w_self, w_other, w_modulo): - - w_0=v2=w_self_2=w_other_2=w_modulo_1=w_func_2=v17=w_14=w_other_8=None - w_modulo_2=w_func_3=w_18=w_self_1=w_other_1=w_coerced=w_6=v7=None - w_self_4=w_other_4=w_coerced_1=w_9=w_10=w_self_3=w_other_3=w_8=None - v11=w_self_6=w_other_6=w_16=w_self_5=w_other_5=w_func=v13=w_other_7=None - w_func_1=w_15=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_0 = space.is_(w_modulo, space.w_None) v2 = space.is_true(w_0) if v2 == True: w_self_1, w_other_1 = w_self, w_other - goto = 2 + goto = glabel_2 else: assert v2 == False w_self_2, w_other_2, w_modulo_1 = w_self, w_other, w_modulo - goto = 8 + goto = glabel_8 - if goto == 2: + if goto is glabel_2: w_coerced = fastf__coerce(space, w_self_1, w_other_1) w_6 = space.is_(w_coerced, space.w_None) v7 = space.is_true(w_6) if v7 == True: w_self_3, w_other_3, w_8 = w_self_1, w_other_1, w_6 - goto = 4 + goto = glabel_4 else: assert v7 == False w_self_4, w_other_4, w_coerced_1 = w_self_1, w_other_1, w_coerced - goto = 3 + goto = glabel_3 - if goto == 3: + if goto is glabel_3: w_9 = space.getitem(w_coerced_1, gi_0) w_10 = space.is_(w_9, w_self_4) w_self_3, w_other_3, w_8 = w_self_4, w_other_4, w_10 - goto = 4 + goto = glabel_4 - if goto == 4: + if goto is glabel_4: v11 = space.is_true(w_8) if v11 == True: w_self_5, w_other_5 = w_self_3, w_other_3 - goto = 5 + goto = glabel_5 else: assert v11 == False w_self_6, w_other_6 = w_self_3, w_other_3 - goto = 7 + goto = glabel_7 - if goto == 5: + if goto is glabel_5: w_func = space.call_function(gfunc_instance_getattr1, w_self_5, gs___pow__, space.w_False) v13 = space.is_true(w_func) if v13 == True: w_other_7, w_func_1 = w_other_5, w_func - goto = 6 + goto = glabel_6 else: assert v13 == False w_14 = space.w_NotImplemented - goto = 10 + goto = glabel_10 - if goto == 6: + if goto is glabel_6: w_15 = space.call_function(w_func_1, w_other_7) w_14 = w_15 - goto = 10 + goto = glabel_10 - if goto == 7: + if goto is glabel_7: w_16 = space.pow(w_self_6, w_other_6, space.w_None) w_14 = w_16 - goto = 10 + goto = glabel_10 - if goto == 8: + if goto is glabel_8: w_func_2 = space.call_function(gfunc_instance_getattr1, w_self_2, gs___pow__, space.w_False) v17 = space.is_true(w_func_2) if v17 == True: w_other_8, w_modulo_2, w_func_3 = w_other_2, w_modulo_1, w_func_2 - goto = 9 + goto = glabel_9 else: assert v17 == False w_14 = space.w_NotImplemented - goto = 10 + goto = glabel_10 - if goto == 9: + if goto is glabel_9: w_18 = space.call_function(w_func_3, w_other_8, w_modulo_2) w_14 = w_18 - goto = 10 + goto = glabel_10 - if goto == 10: + if goto is glabel_10: return w_14 fastf_instance___pow__ = __pow__ ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function '__rpow__' ## firstlineno 459 ##SECTION## @@ -5927,99 +5581,92 @@ f_instance___rpow__ = __rpow__ def __rpow__(space, w_self, w_other, w_modulo): - - w_0=v2=w_self_2=w_other_2=w_modulo_1=w_func_2=v17=w_14=w_other_8=None - w_modulo_2=w_func_3=w_18=w_self_1=w_other_1=w_coerced=w_6=v7=None - w_self_4=w_other_4=w_coerced_1=w_9=w_10=w_self_3=w_other_3=w_8=None - v11=w_self_6=w_other_6=w_16=w_self_5=w_other_5=w_func=v13=w_other_7=None - w_func_1=w_15=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_0 = space.is_(w_modulo, space.w_None) v2 = space.is_true(w_0) if v2 == True: w_self_1, w_other_1 = w_self, w_other - goto = 2 + goto = glabel_2 else: assert v2 == False w_self_2, w_other_2, w_modulo_1 = w_self, w_other, w_modulo - goto = 8 + goto = glabel_8 - if goto == 2: + if goto is glabel_2: w_coerced = fastf__coerce(space, w_self_1, w_other_1) w_6 = space.is_(w_coerced, space.w_None) v7 = space.is_true(w_6) if v7 == True: w_self_3, w_other_3, w_8 = w_self_1, w_other_1, w_6 - goto = 4 + goto = glabel_4 else: assert v7 == False w_self_4, w_other_4, w_coerced_1 = w_self_1, w_other_1, w_coerced - goto = 3 + goto = glabel_3 - if goto == 3: + if goto is glabel_3: w_9 = space.getitem(w_coerced_1, gi_0) w_10 = space.is_(w_9, w_self_4) w_self_3, w_other_3, w_8 = w_self_4, w_other_4, w_10 - goto = 4 + goto = glabel_4 - if goto == 4: + if goto is glabel_4: v11 = space.is_true(w_8) if v11 == True: w_self_5, w_other_5 = w_self_3, w_other_3 - goto = 5 + goto = glabel_5 else: assert v11 == False w_self_6, w_other_6 = w_self_3, w_other_3 - goto = 7 + goto = glabel_7 - if goto == 5: + if goto is glabel_5: w_func = space.call_function(gfunc_instance_getattr1, w_self_5, gs___rpow__, space.w_False) v13 = space.is_true(w_func) if v13 == True: w_other_7, w_func_1 = w_other_5, w_func - goto = 6 + goto = glabel_6 else: assert v13 == False w_14 = space.w_NotImplemented - goto = 10 + goto = glabel_10 - if goto == 6: + if goto is glabel_6: w_15 = space.call_function(w_func_1, w_other_7) w_14 = w_15 - goto = 10 + goto = glabel_10 - if goto == 7: + if goto is glabel_7: w_16 = space.pow(w_other_6, w_self_6, space.w_None) w_14 = w_16 - goto = 10 + goto = glabel_10 - if goto == 8: + if goto is glabel_8: w_func_2 = space.call_function(gfunc_instance_getattr1, w_self_2, gs___rpow__, space.w_False) v17 = space.is_true(w_func_2) if v17 == True: w_other_8, w_modulo_2, w_func_3 = w_other_2, w_modulo_1, w_func_2 - goto = 9 + goto = glabel_9 else: assert v17 == False w_14 = space.w_NotImplemented - goto = 10 + goto = glabel_10 - if goto == 9: + if goto is glabel_9: w_18 = space.call_function(w_func_3, w_other_8, w_modulo_2) w_14 = w_18 - goto = 10 + goto = glabel_10 - if goto == 10: + if goto is glabel_10: return w_14 fastf_instance___rpow__ = __rpow__ ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function '__nonzero__' ## firstlineno 477 ##SECTION## @@ -6037,81 +5684,77 @@ f_instance___nonzero__ = __nonzero__ def __nonzero__(space, w_self): - - w_func=v2=w_self_1=w_func_2=v3=w_4=w_func_1=w_ret=w_6=v7=w_14=None - w_etype=w_evalue=w_ret_1=w_8=v9=w_ret_2=w_13=w_10=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_func = space.call_function(gfunc_instance_getattr1, w_self, gs___nonzero__, space.w_False) v2 = space.is_true(w_func) if v2 == True: w_func_1 = w_func - goto = 3 + goto = glabel_3 else: assert v2 == False w_self_1 = w_self - goto = 2 + goto = glabel_2 - if goto == 2: + if goto is glabel_2: w_func_2 = space.call_function(gfunc_instance_getattr1, w_self_1, gs___nonzero__, space.w_False) v3 = space.is_true(w_func_2) if v3 == True: w_func_1 = w_func_2 - goto = 3 + goto = glabel_3 else: assert v3 == False w_4 = space.w_True - goto = 9 + goto = glabel_9 - if goto == 3: + if goto is glabel_3: w_ret = space.call_function(w_func_1, ) w_6 = space.isinstance(w_ret, space.w_int) v7 = space.is_true(w_6) if v7 == True: w_ret_1 = w_ret - goto = 4 + goto = glabel_4 else: assert v7 == False - goto = 7 + goto = glabel_7 - if goto == 4: + if goto is glabel_4: w_8 = space.lt(w_ret_1, gi_0) v9 = space.is_true(w_8) if v9 == True: - goto = 5 + goto = glabel_5 else: assert v9 == False w_ret_2 = w_ret_1 - goto = 6 + goto = glabel_6 - if goto == 5: + if goto is glabel_5: w_10 = space.call_function(space.w_ValueError, gs___nonzero_____should_return____0) w_etype, w_evalue = space.w_ValueError, w_10 - goto = 8 + goto = glabel_8 - if goto == 6: + if goto is glabel_6: w_13 = space.gt(w_ret_2, gi_0) w_4 = w_13 - goto = 9 + goto = glabel_9 - if goto == 7: + if goto is glabel_7: w_14 = space.call_function(space.w_TypeError, gs___nonzero_____should_return_an_i) w_etype, w_evalue = space.w_TypeError, w_14 - goto = 8 + goto = glabel_8 - if goto == 8: + if goto is glabel_8: raise OperationError(w_etype, w_evalue) - if goto == 9: + if goto is glabel_9: return w_4 fastf_instance___nonzero__ = __nonzero__ ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function '__call__' ## firstlineno 492 ##SECTION## @@ -6128,47 +5771,43 @@ f_instance___call__ = __call__ def __call__(space, w_self, w_args, w_kwds): - - w_func=v2=w_self_1=w_5=w_6=w_7=w_etype=w_evalue=w_args_1=w_kwds_1=None - w_func_1=w_10=w_11=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_func = space.call_function(gfunc_instance_getattr1, w_self, gs___call__, space.w_False) v2 = space.is_true(w_func) if v2 == True: w_args_1, w_kwds_1, w_func_1 = w_args, w_kwds, w_func - goto = 3 + goto = glabel_3 else: assert v2 == False w_self_1 = w_self - goto = 2 + goto = glabel_2 - if goto == 2: + if goto is glabel_2: w_5 = space.getattr(w_self_1, gs___class__) w_6 = space.getattr(w_5, gs___name__) w_7 = space.mod(gs__s_instance_has_no___call___meth, w_6) w_etype, w_evalue = space.w_AttributeError, w_7 - goto = 4 + goto = glabel_4 - if goto == 3: + if goto is glabel_3: _args = Arguments.fromshape(space, (0, (), True, True), [w_args_1, w_kwds_1]) w_10 = space.call_args(w_func_1, _args) w_11 = w_10 - goto = 5 + goto = glabel_5 - if goto == 4: + if goto is glabel_4: raise OperationError(w_etype, w_evalue) - if goto == 5: + if goto is glabel_5: return w_11 fastf_instance___call__ = __call__ ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function '__eq__' ## firstlineno 503 ##SECTION## @@ -6182,68 +5821,64 @@ f_instance___eq__ = __eq__ def __eq__(space, w_self, w_other): - - w_0=w_other_1=w_3=w_7=w_8=w_4=w_5=w_6=w_16=v17=w_12=w_14=w_10=None - w_9=v11=w_etype=w_evalue=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: try: w_0 = space.call_function(gfunc_instance_getattr1, w_self, gs___eq__) w_other_1, w_3 = w_other, w_0 - goto = 2 + goto = glabel_2 except OperationError, e: if space.is_true(space.issubtype(e.w_type, space.w_Exception)): w_4, w_5, w_6 = e.w_type, e.w_value, e.w_type - goto = 4 + goto = glabel_4 else:raise # unhandled case, should not happen - if goto == 2: + if goto is glabel_2: try: w_7 = space.call_function(w_3, w_other_1) w_8 = w_7 - goto = 6 + goto = glabel_6 except OperationError, e: if space.is_true(space.issubtype(e.w_type, space.w_Exception)): w_4, w_5, w_6 = e.w_type, e.w_value, e.w_type - goto = 4 + goto = glabel_4 else:raise # unhandled case, should not happen - if goto == 3: + if goto is glabel_3: w_9 = space.issubtype(w_10, space.w_AttributeError) v11 = space.is_true(w_9) if v11 == True: w_8 = space.w_NotImplemented - goto = 6 + goto = glabel_6 else: assert v11 == False w_etype, w_evalue = w_12, w_14 - goto = 5 + goto = glabel_5 - if goto == 4: + if goto is glabel_4: w_16 = space.is_(w_6, space.w_AttributeError) v17 = space.is_true(w_16) if v17 == True: w_8 = space.w_NotImplemented - goto = 6 + goto = glabel_6 else: assert v17 == False w_12, w_14, w_10 = w_4, w_5, w_6 - goto = 3 + goto = glabel_3 continue - if goto == 5: + if goto is glabel_5: raise OperationError(w_etype, w_evalue) - if goto == 6: + if goto is glabel_6: return w_8 fastf_instance___eq__ = __eq__ ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function '__ge__' ## firstlineno 503 ##SECTION## @@ -6257,68 +5892,64 @@ f_instance___ge__ = __ge__ def __ge__(space, w_self, w_other): - - w_0=w_other_1=w_3=w_7=w_8=w_4=w_5=w_6=w_16=v17=w_12=w_14=w_10=None - w_9=v11=w_etype=w_evalue=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: try: w_0 = space.call_function(gfunc_instance_getattr1, w_self, gs___ge__) w_other_1, w_3 = w_other, w_0 - goto = 2 + goto = glabel_2 except OperationError, e: if space.is_true(space.issubtype(e.w_type, space.w_Exception)): w_4, w_5, w_6 = e.w_type, e.w_value, e.w_type - goto = 4 + goto = glabel_4 else:raise # unhandled case, should not happen - if goto == 2: + if goto is glabel_2: try: w_7 = space.call_function(w_3, w_other_1) w_8 = w_7 - goto = 6 + goto = glabel_6 except OperationError, e: if space.is_true(space.issubtype(e.w_type, space.w_Exception)): w_4, w_5, w_6 = e.w_type, e.w_value, e.w_type - goto = 4 + goto = glabel_4 else:raise # unhandled case, should not happen - if goto == 3: + if goto is glabel_3: w_9 = space.issubtype(w_10, space.w_AttributeError) v11 = space.is_true(w_9) if v11 == True: w_8 = space.w_NotImplemented - goto = 6 + goto = glabel_6 else: assert v11 == False w_etype, w_evalue = w_12, w_14 - goto = 5 + goto = glabel_5 - if goto == 4: + if goto is glabel_4: w_16 = space.is_(w_6, space.w_AttributeError) v17 = space.is_true(w_16) if v17 == True: w_8 = space.w_NotImplemented - goto = 6 + goto = glabel_6 else: assert v17 == False w_12, w_14, w_10 = w_4, w_5, w_6 - goto = 3 + goto = glabel_3 continue - if goto == 5: + if goto is glabel_5: raise OperationError(w_etype, w_evalue) - if goto == 6: + if goto is glabel_6: return w_8 fastf_instance___ge__ = __ge__ ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function '__gt__' ## firstlineno 503 ##SECTION## @@ -6332,68 +5963,64 @@ f_instance___gt__ = __gt__ def __gt__(space, w_self, w_other): - - w_0=w_other_1=w_3=w_7=w_8=w_4=w_5=w_6=w_16=v17=w_12=w_14=w_10=None - w_9=v11=w_etype=w_evalue=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: try: w_0 = space.call_function(gfunc_instance_getattr1, w_self, gs___gt__) w_other_1, w_3 = w_other, w_0 - goto = 2 + goto = glabel_2 except OperationError, e: if space.is_true(space.issubtype(e.w_type, space.w_Exception)): w_4, w_5, w_6 = e.w_type, e.w_value, e.w_type - goto = 4 + goto = glabel_4 else:raise # unhandled case, should not happen - if goto == 2: + if goto is glabel_2: try: w_7 = space.call_function(w_3, w_other_1) w_8 = w_7 - goto = 6 + goto = glabel_6 except OperationError, e: if space.is_true(space.issubtype(e.w_type, space.w_Exception)): w_4, w_5, w_6 = e.w_type, e.w_value, e.w_type - goto = 4 + goto = glabel_4 else:raise # unhandled case, should not happen - if goto == 3: + if goto is glabel_3: w_9 = space.issubtype(w_10, space.w_AttributeError) v11 = space.is_true(w_9) if v11 == True: w_8 = space.w_NotImplemented - goto = 6 + goto = glabel_6 else: assert v11 == False w_etype, w_evalue = w_12, w_14 - goto = 5 + goto = glabel_5 - if goto == 4: + if goto is glabel_4: w_16 = space.is_(w_6, space.w_AttributeError) v17 = space.is_true(w_16) if v17 == True: w_8 = space.w_NotImplemented - goto = 6 + goto = glabel_6 else: assert v17 == False w_12, w_14, w_10 = w_4, w_5, w_6 - goto = 3 + goto = glabel_3 continue - if goto == 5: + if goto is glabel_5: raise OperationError(w_etype, w_evalue) - if goto == 6: + if goto is glabel_6: return w_8 fastf_instance___gt__ = __gt__ ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function '__le__' ## firstlineno 503 ##SECTION## @@ -6407,68 +6034,64 @@ f_instance___le__ = __le__ def __le__(space, w_self, w_other): - - w_0=w_other_1=w_3=w_7=w_8=w_4=w_5=w_6=w_16=v17=w_12=w_14=w_10=None - w_9=v11=w_etype=w_evalue=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: try: w_0 = space.call_function(gfunc_instance_getattr1, w_self, gs___le__) w_other_1, w_3 = w_other, w_0 - goto = 2 + goto = glabel_2 except OperationError, e: if space.is_true(space.issubtype(e.w_type, space.w_Exception)): w_4, w_5, w_6 = e.w_type, e.w_value, e.w_type - goto = 4 + goto = glabel_4 else:raise # unhandled case, should not happen - if goto == 2: + if goto is glabel_2: try: w_7 = space.call_function(w_3, w_other_1) w_8 = w_7 - goto = 6 + goto = glabel_6 except OperationError, e: if space.is_true(space.issubtype(e.w_type, space.w_Exception)): w_4, w_5, w_6 = e.w_type, e.w_value, e.w_type - goto = 4 + goto = glabel_4 else:raise # unhandled case, should not happen - if goto == 3: + if goto is glabel_3: w_9 = space.issubtype(w_10, space.w_AttributeError) v11 = space.is_true(w_9) if v11 == True: w_8 = space.w_NotImplemented - goto = 6 + goto = glabel_6 else: assert v11 == False w_etype, w_evalue = w_12, w_14 - goto = 5 + goto = glabel_5 - if goto == 4: + if goto is glabel_4: w_16 = space.is_(w_6, space.w_AttributeError) v17 = space.is_true(w_16) if v17 == True: w_8 = space.w_NotImplemented - goto = 6 + goto = glabel_6 else: assert v17 == False w_12, w_14, w_10 = w_4, w_5, w_6 - goto = 3 + goto = glabel_3 continue - if goto == 5: + if goto is glabel_5: raise OperationError(w_etype, w_evalue) - if goto == 6: + if goto is glabel_6: return w_8 fastf_instance___le__ = __le__ ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function '__lt__' ## firstlineno 503 ##SECTION## @@ -6482,68 +6105,64 @@ f_instance___lt__ = __lt__ def __lt__(space, w_self, w_other): - - w_0=w_other_1=w_3=w_7=w_8=w_4=w_5=w_6=w_16=v17=w_12=w_14=w_10=None - w_9=v11=w_etype=w_evalue=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: try: w_0 = space.call_function(gfunc_instance_getattr1, w_self, gs___lt__) w_other_1, w_3 = w_other, w_0 - goto = 2 + goto = glabel_2 except OperationError, e: if space.is_true(space.issubtype(e.w_type, space.w_Exception)): w_4, w_5, w_6 = e.w_type, e.w_value, e.w_type - goto = 4 + goto = glabel_4 else:raise # unhandled case, should not happen - if goto == 2: + if goto is glabel_2: try: w_7 = space.call_function(w_3, w_other_1) w_8 = w_7 - goto = 6 + goto = glabel_6 except OperationError, e: if space.is_true(space.issubtype(e.w_type, space.w_Exception)): w_4, w_5, w_6 = e.w_type, e.w_value, e.w_type - goto = 4 + goto = glabel_4 else:raise # unhandled case, should not happen - if goto == 3: + if goto is glabel_3: w_9 = space.issubtype(w_10, space.w_AttributeError) v11 = space.is_true(w_9) if v11 == True: w_8 = space.w_NotImplemented - goto = 6 + goto = glabel_6 else: assert v11 == False w_etype, w_evalue = w_12, w_14 - goto = 5 + goto = glabel_5 - if goto == 4: + if goto is glabel_4: w_16 = space.is_(w_6, space.w_AttributeError) v17 = space.is_true(w_16) if v17 == True: w_8 = space.w_NotImplemented - goto = 6 + goto = glabel_6 else: assert v17 == False w_12, w_14, w_10 = w_4, w_5, w_6 - goto = 3 + goto = glabel_3 continue - if goto == 5: + if goto is glabel_5: raise OperationError(w_etype, w_evalue) - if goto == 6: + if goto is glabel_6: return w_8 fastf_instance___lt__ = __lt__ ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function '__ne__' ## firstlineno 503 ##SECTION## @@ -6557,68 +6176,64 @@ f_instance___ne__ = __ne__ def __ne__(space, w_self, w_other): - - w_0=w_other_1=w_3=w_7=w_8=w_4=w_5=w_6=w_16=v17=w_12=w_14=w_10=None - w_9=v11=w_etype=w_evalue=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: try: w_0 = space.call_function(gfunc_instance_getattr1, w_self, gs___ne__) w_other_1, w_3 = w_other, w_0 - goto = 2 + goto = glabel_2 except OperationError, e: if space.is_true(space.issubtype(e.w_type, space.w_Exception)): w_4, w_5, w_6 = e.w_type, e.w_value, e.w_type - goto = 4 + goto = glabel_4 else:raise # unhandled case, should not happen - if goto == 2: + if goto is glabel_2: try: w_7 = space.call_function(w_3, w_other_1) w_8 = w_7 - goto = 6 + goto = glabel_6 except OperationError, e: if space.is_true(space.issubtype(e.w_type, space.w_Exception)): w_4, w_5, w_6 = e.w_type, e.w_value, e.w_type - goto = 4 + goto = glabel_4 else:raise # unhandled case, should not happen - if goto == 3: + if goto is glabel_3: w_9 = space.issubtype(w_10, space.w_AttributeError) v11 = space.is_true(w_9) if v11 == True: w_8 = space.w_NotImplemented - goto = 6 + goto = glabel_6 else: assert v11 == False w_etype, w_evalue = w_12, w_14 - goto = 5 + goto = glabel_5 - if goto == 4: + if goto is glabel_4: w_16 = space.is_(w_6, space.w_AttributeError) v17 = space.is_true(w_16) if v17 == True: w_8 = space.w_NotImplemented - goto = 6 + goto = glabel_6 else: assert v17 == False w_12, w_14, w_10 = w_4, w_5, w_6 - goto = 3 + goto = glabel_3 continue - if goto == 5: + if goto is glabel_5: raise OperationError(w_etype, w_evalue) - if goto == 6: + if goto is glabel_6: return w_8 fastf_instance___ne__ = __ne__ ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function '__iter__' ## firstlineno 512 ##SECTION## @@ -6636,70 +6251,66 @@ f_instance___iter__ = __iter__ def __iter__(space, w_self): - - w_func=v2=w_self_1=w_func_2=v12=w_etype=w_evalue=w_self_2=w_13=None - w_6=w_func_1=w_ret=w_4=v5=w_ret_1=w_7=w_8=w_9=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_func = space.call_function(gfunc_instance_getattr1, w_self, gs___iter__, space.w_False) v2 = space.is_true(w_func) if v2 == True: w_func_1 = w_func - goto = 2 + goto = glabel_2 else: assert v2 == False w_self_1 = w_self - goto = 4 + goto = glabel_4 - if goto == 2: + if goto is glabel_2: w_ret = space.call_function(w_func_1, ) w_4 = fastf_mro_lookup(space, w_ret, gs_next) v5 = space.is_true(w_4) if v5 == True: w_6 = w_ret - goto = 7 + goto = glabel_7 else: assert v5 == False w_ret_1 = w_ret - goto = 3 + goto = glabel_3 - if goto == 3: + if goto is glabel_3: w_7 = space.call_function(space.w_type, w_ret_1) w_8 = space.getattr(w_7, gs___name__) w_9 = space.mod(gs___iter___returned_non_iterator_o, w_8) w_etype, w_evalue = space.w_TypeError, w_9 - goto = 6 + goto = glabel_6 - if goto == 4: + if goto is glabel_4: w_func_2 = space.call_function(gfunc_instance_getattr1, w_self_1, gs___getitem__, space.w_False) v12 = space.is_true(w_func_2) if v12 == True: w_self_2 = w_self_1 - goto = 5 + goto = glabel_5 else: assert v12 == False (w_etype, w_evalue) = (space.w_TypeError, gs_iteration_over_non_sequence) - goto = 6 + goto = glabel_6 - if goto == 5: + if goto is glabel_5: w_13 = space.call_function(space.builtin.get('_seqiter'), w_self_2) w_6 = w_13 - goto = 7 + goto = glabel_7 - if goto == 6: + if goto is glabel_6: raise OperationError(w_etype, w_evalue) - if goto == 7: + if goto is glabel_7: return w_6 fastf_instance___iter__ = __iter__ ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function 'next' ## firstlineno 527 ##SECTION## @@ -6716,39 +6327,36 @@ f_instance_next = next def next(space, w_self): - - w_func=v2=w_etype=w_evalue=w_func_1=w_5=w_6=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_func = space.call_function(gfunc_instance_getattr1, w_self, gs_next, space.w_False) v2 = space.is_true(w_func) if v2 == True: w_func_1 = w_func - goto = 2 + goto = glabel_2 else: assert v2 == False (w_etype, w_evalue) = (space.w_TypeError, gs_instance_has_no_next___method) - goto = 3 + goto = glabel_3 - if goto == 2: + if goto is glabel_2: w_5 = space.call_function(w_func_1, ) w_6 = w_5 - goto = 4 + goto = glabel_4 - if goto == 3: + if goto is glabel_3: raise OperationError(w_etype, w_evalue) - if goto == 4: + if goto is glabel_4: return w_6 fastf_instance_next = next ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function '__cmp__' ## firstlineno 533 ##SECTION## @@ -6766,190 +6374,182 @@ f_instance___cmp__ = __cmp__ def __cmp__(space, w_self, w_other): - - w_coerced=w_3=v4=w_coerced_1=w_v_1=w_w_1=w_7=v8=w_v_3=w_w_3=w_10=None - v11=w_w_2=w_v_2=w_9=v12=w_w=w_v=w_15=v16=w_w_6=w_v_6=w_28=v29=None - w_14=w_v_7=w_func_2=v30=w_v_8=w_func_3=w_res_3=w_31=v32=w_etype=None - w_evalue=w_res_4=w_33=v34=w_res_5=w_35=v36=w_w_5=w_v_5=w_func=None - v18=w_w_7=w_func_1=w_res=w_20=v21=w_res_1=w_24=v25=w_res_2=w_26=None - v27=w_w_4=w_v_4=w_13=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_coerced = fastf__coerce(space, w_self, w_other) w_3 = space.is_(w_coerced, space.w_None) v4 = space.is_true(w_3) if v4 == True: w_w, w_v = w_other, w_self - goto = 6 + goto = glabel_6 else: assert v4 == False w_coerced_1 = w_coerced - goto = 2 + goto = glabel_2 - if goto == 2: + if goto is glabel_2: w_v_1 = space.getitem(w_coerced_1, gi_0) w_w_1 = space.getitem(w_coerced_1, gi_1) w_7 = space.isinstance(w_v_1, gcls_instance) v8 = space.is_true(w_7) if v8 == True: w_w_2, w_v_2, w_9 = w_w_1, w_v_1, space.w_False - goto = 4 + goto = glabel_4 else: assert v8 == False w_v_3, w_w_3 = w_v_1, w_w_1 - goto = 3 + goto = glabel_3 - if goto == 3: + if goto is glabel_3: w_10 = space.isinstance(w_w_3, gcls_instance) v11 = space.is_true(w_10) if v11 == True: w_w_2, w_v_2, w_9 = w_w_3, w_v_3, space.w_False - goto = 4 + goto = glabel_4 else: assert v11 == False w_w_2, w_v_2, w_9 = w_w_3, w_v_3, space.w_True - goto = 4 + goto = glabel_4 - if goto == 4: + if goto is glabel_4: v12 = space.is_true(w_9) if v12 == True: w_w_4, w_v_4 = w_w_2, w_v_2 - goto = 5 + goto = glabel_5 else: assert v12 == False w_w, w_v = w_w_2, w_v_2 - goto = 6 + goto = glabel_6 - if goto == 5: + if goto is glabel_5: w_13 = space.cmp(w_v_4, w_w_4) w_14 = w_13 - goto = 17 + goto = glabel_17 - if goto == 6: + if goto is glabel_6: w_15 = space.isinstance(w_v, gcls_instance) v16 = space.is_true(w_15) if v16 == True: w_w_5, w_v_5 = w_w, w_v - goto = 7 + goto = glabel_7 else: assert v16 == False w_w_6, w_v_6 = w_w, w_v - goto = 11 + goto = glabel_11 - if goto == 7: + if goto is glabel_7: w_func = space.call_function(gfunc_instance_getattr1, w_v_5, gs___cmp__, space.w_False) v18 = space.is_true(w_func) if v18 == True: w_w_7, w_func_1 = w_w_5, w_func - goto = 8 + goto = glabel_8 else: assert v18 == False w_w_6, w_v_6 = w_w_5, w_v_5 - goto = 11 + goto = glabel_11 - if goto == 8: + if goto is glabel_8: w_res = space.call_function(w_func_1, w_w_7) w_20 = space.isinstance(w_res, space.w_int) v21 = space.is_true(w_20) if v21 == True: w_res_1 = w_res - goto = 9 + goto = glabel_9 else: assert v21 == False w_etype, w_evalue = space.w_TypeError, gs___cmp___must_return_int - goto = 16 + goto = glabel_16 - if goto == 9: + if goto is glabel_9: w_24 = space.gt(w_res_1, gi_0) v25 = space.is_true(w_24) if v25 == True: w_14 = gi_1 - goto = 17 + goto = glabel_17 else: assert v25 == False w_res_2 = w_res_1 - goto = 10 + goto = glabel_10 - if goto == 10: + if goto is glabel_10: w_26 = space.lt(w_res_2, gi_0) v27 = space.is_true(w_26) if v27 == True: w_14 = gi_minus_1 - goto = 17 + goto = glabel_17 else: assert v27 == False w_14 = gi_0 - goto = 17 + goto = glabel_17 - if goto == 11: + if goto is glabel_11: w_28 = space.isinstance(w_w_6, gcls_instance) v29 = space.is_true(w_28) if v29 == True: w_v_7 = w_v_6 - goto = 12 + goto = glabel_12 else: assert v29 == False w_14 = space.w_NotImplemented - goto = 17 + goto = glabel_17 - if goto == 12: + if goto is glabel_12: w_func_2 = space.call_function(gfunc_instance_getattr1, w_v_7, gs___cmp__, space.w_False) v30 = space.is_true(w_func_2) if v30 == True: w_v_8, w_func_3 = w_v_7, w_func_2 - goto = 13 + goto = glabel_13 else: assert v30 == False w_14 = space.w_NotImplemented - goto = 17 + goto = glabel_17 - if goto == 13: + if goto is glabel_13: w_res_3 = space.call_function(w_func_3, w_v_8) w_31 = space.isinstance(w_res_3, space.w_int) v32 = space.is_true(w_31) if v32 == True: w_res_4 = w_res_3 - goto = 14 + goto = glabel_14 else: assert v32 == False w_etype, w_evalue = space.w_TypeError, gs___cmp___must_return_int - goto = 16 + goto = glabel_16 - if goto == 14: + if goto is glabel_14: w_33 = space.gt(w_res_4, gi_0) v34 = space.is_true(w_33) if v34 == True: w_14 = gi_1 - goto = 17 + goto = glabel_17 else: assert v34 == False w_res_5 = w_res_4 - goto = 15 + goto = glabel_15 - if goto == 15: + if goto is glabel_15: w_35 = space.lt(w_res_5, gi_0) v36 = space.is_true(w_35) if v36 == True: w_14 = gi_minus_1 - goto = 17 + goto = glabel_17 else: assert v36 == False w_14 = gi_0 - goto = 17 + goto = glabel_17 - if goto == 16: + if goto is glabel_16: raise OperationError(w_etype, w_evalue) - if goto == 17: + if goto is glabel_17: return w_14 fastf_instance___cmp__ = __cmp__ ##SECTION## -## filename '_classobj.py' +## filename 'lib/_classobj.py' ## function 'purify' ## firstlineno 571 ##SECTION## @@ -6974,6 +6574,8 @@ # global object gs__class # global object gs_instance # global object gfunc_purify +# global object glabel_1 +# global object glabel_2 def purify(space, __args__): funcname = "purify" @@ -6985,22 +6587,19 @@ f_purify = purify def purify(space): - - w_0=w_1=w_2=w_3=w_4=w_5=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_0 = space.delattr(gcls_classobj, gs__name) w_1 = space.delattr(gcls_classobj, gs__bases) w_2 = space.delattr(gcls_classobj, gs___slots__) w_3 = space.delattr(gcls_instance, gs__class) w_4 = space.delattr(gcls_instance, gs___slots__) w_5 = space.w_None - goto = 2 + goto = glabel_2 - if goto == 2: + if goto is glabel_2: return w_5 fastf_purify = purify @@ -7174,6 +6773,7 @@ m.gs__classobj = space.wrap('_classobj') space.setitem(_dic, gs___module__, gs__classobj) m.gs___new__ = space.wrap('__new__') + from pypy.interpreter import gateway m.gfunc___new__ = space.wrap(gateway.interp2app(f___new__, unwrap_spec=[gateway.ObjSpace, gateway.Arguments])) m.gsm___new__ = space.wrap(gfunc___new__) space.setitem(_dic, gs___new__, gsm___new__) @@ -7201,6 +6801,9 @@ m.gcls_instance = space.call(space.w_type, _args) m.gfunc_purify = space.wrap(gateway.interp2app(f_purify, unwrap_spec=[gateway.ObjSpace, gateway.Arguments])) m.g3tuple = space.newtuple([gcls_classobj, gcls_instance, gfunc_purify]) + from pypy.objspace.flow.framestate import SpecTag + m.glabel_1 = SpecTag() + m.glabel_2 = SpecTag() del m.purify m.gs___abs__ = space.wrap('__abs__') m.gfunc_instance___abs__ = space.wrap(gateway.interp2app(f_instance___abs__, unwrap_spec=[gateway.ObjSpace, gateway.Arguments])) @@ -7435,16 +7038,24 @@ space.setattr(gcls_classobj, gs___str__, gfunc_classobj___str__) m.gfunc_get_class_module = space.wrap(gateway.interp2app(f_get_class_module, unwrap_spec=[gateway.ObjSpace, gateway.Arguments])) m.gs__ = space.wrap('?') + m.glabel_3 = SpecTag() m.gs___name__ = space.wrap('__name__') + m.glabel_4 = SpecTag() m.gs__s__s = space.wrap('%s.%s') del m.__str__ m.gfunc_retrieve = space.wrap(gateway.interp2app(f_retrieve, unwrap_spec=[gateway.ObjSpace, gateway.Arguments])) + from pypy.interpreter.error import OperationError + m.OperationError = OperationError + m.glabel_6 = SpecTag() + m.glabel_5 = SpecTag() del m.get_class_module m.gdescriptor_object___getattribute__ = space.getattr(space.w_object, gs___getattribute__) del m.retrieve m.gfunc_set_name = space.wrap(gateway.interp2app(f_set_name, unwrap_spec=[gateway.ObjSpace, gateway.Arguments])) + m.glabel_8 = SpecTag() m.gs___bases__ = space.wrap('__bases__') m.gfunc_set_bases = space.wrap(gateway.interp2app(f_set_bases, unwrap_spec=[gateway.ObjSpace, gateway.Arguments])) + m.glabel_7 = SpecTag() m.gfunc_set_dict = space.wrap(gateway.interp2app(f_set_dict, unwrap_spec=[gateway.ObjSpace, gateway.Arguments])) m.gdescriptor_object___setattr__ = space.getattr(space.w_object, gs___setattr__) del m.__setattr__ @@ -7465,11 +7076,16 @@ m.glong_0x7fffffffL = space.wrap(0x7fffffffL) # XXX implement long! m.gi_2 = space.newint(2) del m.uid + m.glabel_13 = SpecTag() m.gs___get__ = space.wrap('__get__') m.gi_1 = space.newint(1) + m.glabel_10 = SpecTag() + m.glabel_9 = SpecTag() m.gfunc_lookup = space.wrap(gateway.interp2app(f_lookup, unwrap_spec=[gateway.ObjSpace, gateway.Arguments])) + m.glabel_12 = SpecTag() m.gs_class__s_has_no_attribute__s = space.wrap('class %s has no attribute %s') m.gfunc_mro_lookup = space.wrap(gateway.interp2app(f_mro_lookup, unwrap_spec=[gateway.ObjSpace, gateway.Arguments])) + m.glabel_11 = SpecTag() del m.__getattribute__ m.gs___mro__ = space.wrap('__mro__') del m.mro_lookup @@ -7482,10 +7098,18 @@ m.gdescriptor_instance__class = space.getattr(gcls_instance, gs__class) m.gfunc_instance_getattr1 = space.wrap(gateway.interp2app(f_instance_getattr1, unwrap_spec=[gateway.ObjSpace, gateway.Arguments])) m.gs___init__ = space.wrap('__init__') + from pypy.interpreter.argument import Arguments + m.Arguments = Arguments m.gs___init_____should_return_None = space.wrap('__init__() should return None') del m.__call__ + m.glabel_19 = SpecTag() m.gs___class__ = space.wrap('__class__') + m.glabel_18 = SpecTag() + m.glabel_16 = SpecTag() + m.glabel_14 = SpecTag() + m.glabel_15 = SpecTag() m.gs__s_instance_has_no_attribute__s = space.wrap('%s instance has no attribute %s') + m.glabel_17 = SpecTag() del m.instance_getattr1 m.gs_instance_has_no_next___method = space.wrap('instance has no next() method') del m.next @@ -7586,19 +7210,33 @@ m.gfunc_type_err = space.wrap(gateway.interp2app(f_type_err, unwrap_spec=[gateway.ObjSpace, gateway.Arguments])) m.gs_name = space.wrap('name') m.gs_string = space.wrap('string') + m.glabel_32 = SpecTag() m.g0tuple = space.newtuple([]) m.gs_bases = space.wrap('bases') m.gs_tuple = space.wrap('tuple') m.gs_dict = space.wrap('dict') m.gs___doc__ = space.wrap('__doc__') + m.glabel_25 = SpecTag() + m.glabel_27 = SpecTag() m.gs__getframe = space.wrap('_getframe') + m.glabel_22 = SpecTag() m.gs_f_globals = space.wrap('f_globals') m.gs_get = space.wrap('get') m.gs_OLD_STYLE_CLASSES_IMPL = space.wrap('OLD_STYLE_CLASSES_IMPL') - _tup= space.newtuple([]) + _tup = space.newtuple([]) m.g_object = space.call(space.w_object, _tup) + m.glabel_20 = SpecTag() + m.glabel_23 = SpecTag() + m.glabel_21 = SpecTag() + m.glabel_24 = SpecTag() + m.glabel_26 = SpecTag() + m.glabel_28 = SpecTag() + m.glabel_31 = SpecTag() + m.glabel_29 = SpecTag() m.gs_callable = space.wrap('callable') + m.glabel_30 = SpecTag() m.gs_base_must_be_class = space.wrap('base must be class') + m.glabel_33 = SpecTag() m.gs_argument__s_must_be__s__not__s = space.wrap('argument %s must be %s, not %s') del m.type_err return g3tuple From tismer at codespeak.net Tue Mar 1 11:17:24 2005 From: tismer at codespeak.net (tismer at codespeak.net) Date: Tue, 1 Mar 2005 11:17:24 +0100 (MET) Subject: [pypy-svn] r9536 - pypy/dist/pypy/translator Message-ID: <20050301101724.E65B627B40@code1.codespeak.net> Author: tismer Date: Tue Mar 1 11:17:24 2005 New Revision: 9536 Modified: pypy/dist/pypy/translator/geninterplevel.py Log: disabled metaclass change in geninterplevel. This behavior is controlled by pypy's cmd line options. Modified: pypy/dist/pypy/translator/geninterplevel.py ============================================================================== --- pypy/dist/pypy/translator/geninterplevel.py (original) +++ pypy/dist/pypy/translator/geninterplevel.py Tue Mar 1 11:17:24 2005 @@ -637,11 +637,11 @@ # exception are defined on the space return 'space.w_%s' % cls.__name__ - # For the moment, use old-style classes exactly when the - # pypy source uses old-style classes, to avoid strange problems. if not isinstance(cls, type): assert type(cls) is type(Exception) - metaclass = 'space.w_classobj' + # do *not* change metaclass, but leave the + # decision to what PyPy thinks is correct. + # metaclass = 'space.w_classobj' basenames = [self.nameof(base) for base in cls.__bases__] def initclassobj(): From tismer at codespeak.net Tue Mar 1 11:19:45 2005 From: tismer at codespeak.net (tismer at codespeak.net) Date: Tue, 1 Mar 2005 11:19:45 +0100 (MET) Subject: [pypy-svn] r9537 - pypy/dist/pypy/module Message-ID: <20050301101945.2362327B38@code1.codespeak.net> Author: tismer Date: Tue Mar 1 11:19:44 2005 New Revision: 9537 Modified: pypy/dist/pypy/module/exceptionsinterp.py Log: exceptionsinterp generated, again, using python translator/tool/tointerplevel.py --modname exceptions --out module/exceptionsinterp.py lib/_exceptions.py file names in the source are now pypy-relative and using forward slashed. But these files are going to be moved into a cache, soon. Modified: pypy/dist/pypy/module/exceptionsinterp.py ============================================================================== --- pypy/dist/pypy/module/exceptionsinterp.py (original) +++ pypy/dist/pypy/module/exceptionsinterp.py Tue Mar 1 11:19:44 2005 @@ -1,11 +1,6 @@ #!/bin/env python # -*- coding: LATIN-1 -*- -from pypy.interpreter.error import OperationError -from pypy.interpreter.argument import Arguments -from pypy.interpreter import gateway - - """Python's standard exception class hierarchy. Before Python 1.5, the standard exceptions were all simple string objects. @@ -159,7 +154,7 @@ # global object gs_EOFError # global object gcls_EOFError # global object gs___file__ -# global object gs__Users_pedronis_PyPy_dist_pypy_l +# global object gs_D___pypy__dist__pypy__lib___exce # global object gs_TabError # global object gcls_TabError # global object gs_UnicodeEncodeError @@ -220,7 +215,7 @@ # global object gfunc_Exception___str__ ##SECTION## -## filename '_exceptions.py' +## filename 'lib/_exceptions.py' ## function '__getitem__' ## firstlineno 94 ##SECTION## @@ -234,25 +229,22 @@ f_Exception___getitem__ = __getitem__ def __getitem__(space, w_self, w_idx): - - w_0=w_2=w_4=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_0 = space.getattr(w_self, gs_args) w_2 = space.getitem(w_0, w_idx) w_4 = w_2 - goto = 2 + goto = glabel_2 - if goto == 2: + if goto is glabel_2: return w_4 fastf_Exception___getitem__ = __getitem__ ##SECTION## -## filename '_exceptions.py' +## filename 'lib/_exceptions.py' ## function '__init__' ## firstlineno 98 ##SECTION## @@ -266,31 +258,33 @@ f_Exception___init__ = __init__ def __init__(space, w_self, w_args): - - w_0=w_3=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_0 = space.setattr(w_self, gs_args, w_args) w_3 = space.w_None - goto = 2 + goto = glabel_2 - if goto == 2: + if goto is glabel_2: return w_3 fastf_Exception___init__ = __init__ ##SECTION## -## filename '_exceptions.py' +## filename 'lib/_exceptions.py' ## function '__str__' ## firstlineno 102 ##SECTION## # global declarations +# global object glabel_1 # global object gs_args # global object gi_0 +# global object glabel_5 +# global object glabel_2 # global object gi_1 +# global object glabel_3 +# global object glabel_4 def __str__(space, __args__): funcname = "__str__" @@ -302,55 +296,51 @@ f_Exception___str__ = __str__ def __str__(space, w_self): - - w_args=w_argc=w_3=v4=w_args_1=w_argc_1=w_6=v7=w_args_3=w_10=w_5=None - w_args_2=w_8=w_9=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_args = space.getattr(w_self, gs_args) w_argc = space.len(w_args) w_3 = space.eq(w_argc, gi_0) v4 = space.is_true(w_3) if v4 == True: w_5 = gs__emptystr_ - goto = 5 + goto = glabel_5 else: assert v4 == False w_args_1, w_argc_1 = w_args, w_argc - goto = 2 + goto = glabel_2 - if goto == 2: + if goto is glabel_2: w_6 = space.eq(w_argc_1, gi_1) v7 = space.is_true(w_6) if v7 == True: w_args_2 = w_args_1 - goto = 3 + goto = glabel_3 else: assert v7 == False w_args_3 = w_args_1 - goto = 4 + goto = glabel_4 - if goto == 3: + if goto is glabel_3: w_8 = space.getitem(w_args_2, gi_0) w_9 = space.call_function(space.w_str, w_8) w_5 = w_9 - goto = 5 + goto = glabel_5 - if goto == 4: + if goto is glabel_4: w_10 = space.call_function(space.w_str, w_args_3) w_5 = w_10 - goto = 5 + goto = glabel_5 - if goto == 5: + if goto is glabel_5: return w_5 fastf_Exception___str__ = __str__ ##SECTION## -## filename '_exceptions.py' +## filename 'lib/_exceptions.py' ## function '__init__' ## firstlineno 131 ##SECTION## @@ -369,27 +359,23 @@ f_UnicodeTranslateError___init__ = __init__ def __init__(space, w_self, w_args): - - w_argc=w_2=w_4=v5=w_6=w_self_1=w_args_1=w_7=w_8=w_9=w_10=w_11=None - w_12=w_13=w_14=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_argc = space.len(w_args) w_2 = space.setattr(w_self, gs_args, w_args) w_4 = space.eq(w_argc, gi_4) v5 = space.is_true(w_4) if v5 == True: w_self_1, w_args_1 = w_self, w_args - goto = 2 + goto = glabel_2 else: assert v5 == False w_6 = space.w_None - goto = 3 + goto = glabel_3 - if goto == 2: + if goto is glabel_2: w_7 = space.getitem(w_args_1, gi_0) w_8 = space.setattr(w_self_1, gs_object, w_7) w_9 = space.getitem(w_args_1, gi_1) @@ -399,15 +385,15 @@ w_13 = space.getitem(w_args_1, gi_3) w_14 = space.setattr(w_self_1, gs_reason, w_13) w_6 = space.w_None - goto = 3 + goto = glabel_3 - if goto == 3: + if goto is glabel_3: return w_6 fastf_UnicodeTranslateError___init__ = __init__ ##SECTION## -## filename '_exceptions.py' +## filename 'lib/_exceptions.py' ## function '__str__' ## firstlineno 141 ##SECTION## @@ -436,14 +422,10 @@ f_UnicodeTranslateError___str__ = __str__ def __str__(space, w_self): - - w_0=w_2=w_3=w_4=w_5=w_6=w_7=w_8=w_9=w_10=w_11=w_12=w_13=w_14=None - w_15=w_16=w_res=w_18=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_0 = space.call_function((space.builtin.get(space.str_w(gs_getattr))), w_self, gs_start, space.w_None) w_2 = space.call_function(space.w_str, w_0) w_3 = space.add(gs_start_, w_2) @@ -462,15 +444,15 @@ w_16 = space.newlist([w_3, w_6, w_9, w_12, w_15]) w_res = space.call_function(gbltinmethod_join, w_16) w_18 = w_res - goto = 2 + goto = glabel_2 - if goto == 2: + if goto is glabel_2: return w_18 fastf_UnicodeTranslateError___str__ = __str__ ##SECTION## -## filename '_exceptions.py' +## filename 'lib/_exceptions.py' ## function '__str__' ## firstlineno 159 ##SECTION## @@ -484,55 +466,51 @@ f_KeyError___str__ = __str__ def __str__(space, w_self): - - w_args=w_argc=w_3=v4=w_args_1=w_argc_1=w_6=v7=w_args_3=w_10=w_5=None - w_args_2=w_8=w_9=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_args = space.getattr(w_self, gs_args) w_argc = space.len(w_args) w_3 = space.eq(w_argc, gi_0) v4 = space.is_true(w_3) if v4 == True: w_5 = gs__emptystr_ - goto = 5 + goto = glabel_5 else: assert v4 == False w_args_1, w_argc_1 = w_args, w_argc - goto = 2 + goto = glabel_2 - if goto == 2: + if goto is glabel_2: w_6 = space.eq(w_argc_1, gi_1) v7 = space.is_true(w_6) if v7 == True: w_args_2 = w_args_1 - goto = 3 + goto = glabel_3 else: assert v7 == False w_args_3 = w_args_1 - goto = 4 + goto = glabel_4 - if goto == 3: + if goto is glabel_3: w_8 = space.getitem(w_args_2, gi_0) w_9 = space.repr(w_8) w_5 = w_9 - goto = 5 + goto = glabel_5 - if goto == 4: + if goto is glabel_4: w_10 = space.call_function(space.w_str, w_args_3) w_5 = w_10 - goto = 5 + goto = glabel_5 - if goto == 5: + if goto is glabel_5: return w_5 fastf_KeyError___str__ = __str__ ##SECTION## -## filename '_exceptions.py' +## filename 'lib/_exceptions.py' ## function '__init__' ## firstlineno 185 ##SECTION## @@ -546,16 +524,10 @@ f_EnvironmentError___init__ = __init__ def __init__(space, w_self, w_args): - - w_argc=w_2=w_4=w_5=w_6=w_7=v8=w_self_2=w_args_2=w_argc_2=w_9=None - v11=w_self_4=w_args_4=w_argc_4=w_16=v17=w_18=w_self_5=w_args_5=None - w_19=w_20=w_21=w_22=w_23=w_24=w_self_3=w_args_3=w_argc_3=w_12=None - w_13=w_14=w_15=w_self_1=w_args_1=w_argc_1=w_10=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_argc = space.len(w_args) w_2 = space.setattr(w_self, gs_args, w_args) w_4 = space.setattr(w_self, gs_errno, space.w_None) @@ -565,48 +537,48 @@ v8 = space.is_true(w_7) if v8 == True: w_self_1, w_args_1, w_argc_1 = w_self, w_args, w_argc - goto = 2 + goto = glabel_2 else: assert v8 == False w_self_2, w_args_2, w_argc_2, w_9 = w_self, w_args, w_argc, w_7 - goto = 3 + goto = glabel_3 - if goto == 2: + if goto is glabel_2: w_10 = space.le(w_argc_1, gi_3) (w_self_2, w_args_2, w_argc_2, w_9) = (w_self_1, w_args_1, w_argc_1, w_10) - goto = 3 + goto = glabel_3 - if goto == 3: + if goto is glabel_3: v11 = space.is_true(w_9) if v11 == True: w_self_3, w_args_3, w_argc_3 = w_self_2, w_args_2, w_argc_2 - goto = 4 + goto = glabel_4 else: assert v11 == False w_self_4, w_args_4, w_argc_4 = w_self_2, w_args_2, w_argc_2 - goto = 5 + goto = glabel_5 - if goto == 4: + if goto is glabel_4: w_12 = space.getitem(w_args_3, gi_0) w_13 = space.setattr(w_self_3, gs_errno, w_12) w_14 = space.getitem(w_args_3, gi_1) w_15 = space.setattr(w_self_3, gs_strerror, w_14) w_self_4, w_args_4, w_argc_4 = w_self_3, w_args_3, w_argc_3 - goto = 5 + goto = glabel_5 - if goto == 5: + if goto is glabel_5: w_16 = space.eq(w_argc_4, gi_3) v17 = space.is_true(w_16) if v17 == True: w_self_5, w_args_5 = w_self_4, w_args_4 - goto = 6 + goto = glabel_6 else: assert v17 == False w_18 = space.w_None - goto = 7 + goto = glabel_7 - if goto == 6: + if goto is glabel_6: w_19 = space.getitem(w_args_5, gi_2) w_20 = space.setattr(w_self_5, gs_filename, w_19) w_21 = space.getitem(w_args_5, gi_0) @@ -614,15 +586,15 @@ w_23 = space.newtuple([w_21, w_22]) w_24 = space.setattr(w_self_5, gs_args, w_23) w_18 = space.w_None - goto = 7 + goto = glabel_7 - if goto == 7: + if goto is glabel_7: return w_18 fastf_EnvironmentError___init__ = __init__ ##SECTION## -## filename '_exceptions.py' +## filename 'lib/_exceptions.py' ## function '__str__' ## firstlineno 199 ##SECTION## @@ -643,14 +615,10 @@ f_EnvironmentError___str__ = __str__ def __str__(space, w_self): - - w_0=w_2=w_3=w_4=w_5=w_6=w_7=w_8=w_9=w_10=w_11=w_12=w_13=w_res=None - w_15=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_0 = space.call_function((space.builtin.get(space.str_w(gs_getattr))), w_self, gs_errno, space.w_None) w_2 = space.call_function(space.w_str, w_0) w_3 = space.add(gs_errno_, w_2) @@ -666,15 +634,15 @@ w_13 = space.newlist([w_3, w_6, w_9, w_12]) w_res = space.call_function(gbltinmethod_join, w_13) w_15 = w_res - goto = 2 + goto = glabel_2 - if goto == 2: + if goto is glabel_2: return w_15 fastf_EnvironmentError___str__ = __str__ ##SECTION## -## filename '_exceptions.py' +## filename 'lib/_exceptions.py' ## function '__init__' ## firstlineno 219 ##SECTION## @@ -691,27 +659,23 @@ f_UnicodeEncodeError___init__ = __init__ def __init__(space, w_self, w_args): - - w_argc=w_2=w_4=v5=w_6=w_self_1=w_args_1=w_7=w_8=w_9=w_10=w_11=None - w_12=w_13=w_14=w_15=w_16=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_argc = space.len(w_args) w_2 = space.setattr(w_self, gs_args, w_args) w_4 = space.eq(w_argc, gi_5) v5 = space.is_true(w_4) if v5 == True: w_self_1, w_args_1 = w_self, w_args - goto = 2 + goto = glabel_2 else: assert v5 == False w_6 = space.w_None - goto = 3 + goto = glabel_3 - if goto == 2: + if goto is glabel_2: w_7 = space.getitem(w_args_1, gi_0) w_8 = space.setattr(w_self_1, gs_encoding, w_7) w_9 = space.getitem(w_args_1, gi_1) @@ -723,15 +687,15 @@ w_15 = space.getitem(w_args_1, gi_4) w_16 = space.setattr(w_self_1, gs_reason, w_15) w_6 = space.w_None - goto = 3 + goto = glabel_3 - if goto == 3: + if goto is glabel_3: return w_6 fastf_UnicodeEncodeError___init__ = __init__ ##SECTION## -## filename '_exceptions.py' +## filename 'lib/_exceptions.py' ## function '__str__' ## firstlineno 230 ##SECTION## @@ -749,14 +713,10 @@ f_UnicodeEncodeError___str__ = __str__ def __str__(space, w_self): - - w_0=w_2=w_3=w_4=w_5=w_6=w_7=w_8=w_9=w_10=w_11=w_12=w_13=w_14=None - w_15=w_16=w_17=w_18=w_19=w_res=w_21=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_0 = space.call_function((space.builtin.get(space.str_w(gs_getattr))), w_self, gs_object, space.w_None) w_2 = space.call_function(space.w_str, w_0) w_3 = space.add(gs_object_, w_2) @@ -778,15 +738,15 @@ w_19 = space.newlist([w_3, w_6, w_9, w_12, w_15, w_18]) w_res = space.call_function(gbltinmethod_join, w_19) w_21 = w_res - goto = 2 + goto = glabel_2 - if goto == 2: + if goto is glabel_2: return w_21 fastf_UnicodeEncodeError___str__ = __str__ ##SECTION## -## filename '_exceptions.py' +## filename 'lib/_exceptions.py' ## function '__init__' ## firstlineno 270 ##SECTION## @@ -800,45 +760,40 @@ f_SyntaxError___init__ = __init__ def __init__(space, w_self, w_args): - - w_argc=w_2=w_4=v5=w_self_2=w_args_2=w_argc_2=w_8=v9=w_10=w_self_3=None - w_args_3=w_11=w_12=w_13=w_14=w_15=w_16=w_17=w_18=w_19=w_20=w_21=None - w_22=w_self_1=w_args_1=w_argc_1=w_6=w_7=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_argc = space.len(w_args) w_2 = space.setattr(w_self, gs_args, w_args) w_4 = space.ge(w_argc, gi_1) v5 = space.is_true(w_4) if v5 == True: w_self_1, w_args_1, w_argc_1 = w_self, w_args, w_argc - goto = 2 + goto = glabel_2 else: assert v5 == False w_self_2, w_args_2, w_argc_2 = w_self, w_args, w_argc - goto = 3 + goto = glabel_3 - if goto == 2: + if goto is glabel_2: w_6 = space.getitem(w_args_1, gi_0) w_7 = space.setattr(w_self_1, gs_msg, w_6) w_self_2, w_args_2, w_argc_2 = w_self_1, w_args_1, w_argc_1 - goto = 3 + goto = glabel_3 - if goto == 3: + if goto is glabel_3: w_8 = space.eq(w_argc_2, gi_2) v9 = space.is_true(w_8) if v9 == True: w_self_3, w_args_3 = w_self_2, w_args_2 - goto = 4 + goto = glabel_4 else: assert v9 == False w_10 = space.w_None - goto = 5 + goto = glabel_5 - if goto == 4: + if goto is glabel_4: w_11 = space.getitem(w_args_3, gi_1) w_12 = space.getitem(w_11, gi_0) w_13 = space.setattr(w_self_3, gs_filename, w_12) @@ -852,15 +807,15 @@ w_21 = space.getitem(w_20, gi_3) w_22 = space.setattr(w_self_3, gs_text, w_21) w_10 = space.w_None - goto = 5 + goto = glabel_5 - if goto == 5: + if goto is glabel_5: return w_10 fastf_SyntaxError___init__ = __init__ ##SECTION## -## filename '_exceptions.py' +## filename 'lib/_exceptions.py' ## function '__str__' ## firstlineno 282 ##SECTION## @@ -874,33 +829,32 @@ f_SyntaxError___str__ = __str__ def __str__(space, w_self): - - w_0=w_2=w_3=w_4=w_res=w_6=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_0 = space.call_function((space.builtin.get(space.str_w(gs_getattr))), w_self, gs_args, space.w_None) w_2 = space.call_function(space.w_str, w_0) w_3 = space.add(gs_args_, w_2) w_4 = space.newlist([w_3]) w_res = space.call_function(gbltinmethod_join, w_4) w_6 = w_res - goto = 2 + goto = glabel_2 - if goto == 2: + if goto is glabel_2: return w_6 fastf_SyntaxError___str__ = __str__ ##SECTION## -## filename '_exceptions.py' +## filename 'lib/_exceptions.py' ## function '__init__' ## firstlineno 296 ##SECTION## -# global declaration +# global declarations # global object gs_code +# global object glabel_6 +# global object glabel_7 def __init__(space, __args__): funcname = "__init__" @@ -912,72 +866,67 @@ f_SystemExit___init__ = __init__ def __init__(space, w_self, w_args): - - w_argc=w_2=v3=w_self_2=w_args_2=w_argc_2=w_6=w_7=v8=w_self_4=None - w_args_4=w_argc_4=w_11=v12=w_13=w_self_5=w_args_5=w_14=w_self_3=None - w_args_3=w_argc_3=w_9=w_10=w_self_1=w_args_1=w_argc_1=w_5=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_argc = space.len(w_args) w_2 = space.eq(w_argc, gi_0) v3 = space.is_true(w_2) if v3 == True: w_self_1, w_args_1, w_argc_1 = w_self, w_args, w_argc - goto = 2 + goto = glabel_2 else: assert v3 == False w_self_2, w_args_2, w_argc_2 = w_self, w_args, w_argc - goto = 3 + goto = glabel_3 - if goto == 2: + if goto is glabel_2: w_5 = space.setattr(w_self_1, gs_code, space.w_None) w_self_2, w_args_2, w_argc_2 = w_self_1, w_args_1, w_argc_1 - goto = 3 + goto = glabel_3 - if goto == 3: + if goto is glabel_3: w_6 = space.setattr(w_self_2, gs_args, w_args_2) w_7 = space.eq(w_argc_2, gi_1) v8 = space.is_true(w_7) if v8 == True: w_self_3, w_args_3, w_argc_3 = w_self_2, w_args_2, w_argc_2 - goto = 4 + goto = glabel_4 else: assert v8 == False w_self_4, w_args_4, w_argc_4 = w_self_2, w_args_2, w_argc_2 - goto = 5 + goto = glabel_5 - if goto == 4: + if goto is glabel_4: w_9 = space.getitem(w_args_3, gi_0) w_10 = space.setattr(w_self_3, gs_code, w_9) w_self_4, w_args_4, w_argc_4 = w_self_3, w_args_3, w_argc_3 - goto = 5 + goto = glabel_5 - if goto == 5: + if goto is glabel_5: w_11 = space.ge(w_argc_4, gi_2) v12 = space.is_true(w_11) if v12 == True: w_self_5, w_args_5 = w_self_4, w_args_4 - goto = 6 + goto = glabel_6 else: assert v12 == False w_13 = space.w_None - goto = 7 + goto = glabel_7 - if goto == 6: + if goto is glabel_6: w_14 = space.setattr(w_self_5, gs_code, w_args_5) w_13 = space.w_None - goto = 7 + goto = glabel_7 - if goto == 7: + if goto is glabel_7: return w_13 fastf_SystemExit___init__ = __init__ ##SECTION## -## filename '_exceptions.py' +## filename 'lib/_exceptions.py' ## function '__init__' ## firstlineno 331 ##SECTION## @@ -991,27 +940,23 @@ f_UnicodeDecodeError___init__ = __init__ def __init__(space, w_self, w_args): - - w_argc=w_2=w_4=v5=w_6=w_self_1=w_args_1=w_7=w_8=w_9=w_10=w_11=None - w_12=w_13=w_14=w_15=w_16=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_argc = space.len(w_args) w_2 = space.setattr(w_self, gs_args, w_args) w_4 = space.eq(w_argc, gi_5) v5 = space.is_true(w_4) if v5 == True: w_self_1, w_args_1 = w_self, w_args - goto = 2 + goto = glabel_2 else: assert v5 == False w_6 = space.w_None - goto = 3 + goto = glabel_3 - if goto == 2: + if goto is glabel_2: w_7 = space.getitem(w_args_1, gi_0) w_8 = space.setattr(w_self_1, gs_encoding, w_7) w_9 = space.getitem(w_args_1, gi_1) @@ -1023,15 +968,15 @@ w_15 = space.getitem(w_args_1, gi_4) w_16 = space.setattr(w_self_1, gs_reason, w_15) w_6 = space.w_None - goto = 3 + goto = glabel_3 - if goto == 3: + if goto is glabel_3: return w_6 fastf_UnicodeDecodeError___init__ = __init__ ##SECTION## -## filename '_exceptions.py' +## filename 'lib/_exceptions.py' ## function '__str__' ## firstlineno 342 ##SECTION## @@ -1045,14 +990,10 @@ f_UnicodeDecodeError___str__ = __str__ def __str__(space, w_self): - - w_0=w_2=w_3=w_4=w_5=w_6=w_7=w_8=w_9=w_10=w_11=w_12=w_13=w_14=None - w_15=w_16=w_17=w_18=w_19=w_res=w_21=None - - goto = 1 # startblock + goto = glabel_1 # startblock while True: - if goto == 1: + if goto is glabel_1: w_0 = space.call_function((space.builtin.get(space.str_w(gs_getattr))), w_self, gs_object, space.w_None) w_2 = space.call_function(space.w_str, w_0) w_3 = space.add(gs_object_, w_2) @@ -1074,9 +1015,9 @@ w_19 = space.newlist([w_3, w_6, w_9, w_12, w_15, w_18]) w_res = space.call_function(gbltinmethod_join, w_19) w_21 = w_res - goto = 2 + goto = glabel_2 - if goto == 2: + if goto is glabel_2: return w_21 fastf_UnicodeDecodeError___str__ = __str__ @@ -1355,8 +1296,8 @@ space.setitem(g48dict, gs_EOFError, gcls_EOFError) space.setitem(g48dict, gs_StandardError, gcls_StandardError) m.gs___file__ = space.wrap('__file__') - m.gs__Users_pedronis_PyPy_dist_pypy_l = space.wrap('/Users/pedronis/PyPy/dist/pypy/lib/_exceptions.py') - space.setitem(g48dict, gs___file__, gs__Users_pedronis_PyPy_dist_pypy_l) + m.gs_D___pypy__dist__pypy__lib___exce = space.wrap('D:\\pypy\\dist\\pypy\\lib\\_exceptions.py') + space.setitem(g48dict, gs___file__, gs_D___pypy__dist__pypy__lib___exce) m.gs_TabError = space.wrap('TabError') _dic = space.newdict([]) space.setitem(_dic, gs___module__, gs__exceptions) @@ -1511,6 +1452,7 @@ m.gcls_WindowsError = space.call(space.w_type, _args) space.setitem(g48dict, gs_WindowsError, gcls_WindowsError) m.gs___init__ = space.wrap('__init__') + from pypy.interpreter import gateway m.gfunc_UnicodeDecodeError___init__ = space.wrap(gateway.interp2app(f_UnicodeDecodeError___init__, unwrap_spec=[gateway.ObjSpace, gateway.Arguments])) space.setattr(gcls_UnicodeDecodeError, gs___init__, gfunc_UnicodeDecodeError___init__) m.gs___str__ = space.wrap('__str__') @@ -1556,9 +1498,15 @@ space.setattr(gcls_Exception, gs___init__, gfunc_Exception___init__) m.gfunc_Exception___str__ = space.wrap(gateway.interp2app(f_Exception___str__, unwrap_spec=[gateway.ObjSpace, gateway.Arguments])) space.setattr(gcls_Exception, gs___str__, gfunc_Exception___str__) + from pypy.objspace.flow.framestate import SpecTag + m.glabel_1 = SpecTag() m.gs_args = space.wrap('args') m.gi_0 = space.newint(0) + m.glabel_5 = SpecTag() + m.glabel_2 = SpecTag() m.gi_1 = space.newint(1) + m.glabel_3 = SpecTag() + m.glabel_4 = SpecTag() del m.__str__ del m.__init__ del m.__getitem__ @@ -1579,6 +1527,8 @@ m.gi_2 = space.newint(2) m.gi_3 = space.newint(3) m.gs_code = space.wrap('code') + m.glabel_6 = SpecTag() + m.glabel_7 = SpecTag() m.gs_errno = space.wrap('errno') m.gs_errno_ = space.wrap('errno=') m.gs_strerror = space.wrap('strerror') From pedronis at codespeak.net Tue Mar 1 14:25:51 2005 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Tue, 1 Mar 2005 14:25:51 +0100 (MET) Subject: [pypy-svn] r9538 - pypy/dist/pypy/annotation Message-ID: <20050301132551.F3D2227B40@code1.codespeak.net> Author: pedronis Date: Tue Mar 1 14:25:51 2005 New Revision: 9538 Modified: pypy/dist/pypy/annotation/classdef.py Log: fix assertion Modified: pypy/dist/pypy/annotation/classdef.py ============================================================================== --- pypy/dist/pypy/annotation/classdef.py (original) +++ pypy/dist/pypy/annotation/classdef.py Tue Mar 1 14:25:51 2005 @@ -48,8 +48,8 @@ self.cls = cls self.subdefs = {} assert (len(cls.__bases__) <= 1 or - cls.__bases__[1:] == (object,), # for baseobjspace.Wrappable - "single inheritance only right now: %r" % (cls,)) + cls.__bases__[1:] == (object,) # for baseobjspace.Wrappable + ), "single inheritance only right now: %r" % (cls,) if cls.__bases__: base = cls.__bases__[0] else: From arigo at codespeak.net Tue Mar 1 14:54:19 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 1 Mar 2005 14:54:19 +0100 (MET) Subject: [pypy-svn] r9539 - pypy/dist/pypy/interpreter Message-ID: <20050301135419.533D827B40@code1.codespeak.net> Author: arigo Date: Tue Mar 1 14:54:19 2005 New Revision: 9539 Modified: pypy/dist/pypy/interpreter/generator.py Log: Cleaned up generator.py; moved the 'exhausted' flag to the GeneratorIterator class. Modified: pypy/dist/pypy/interpreter/generator.py ============================================================================== --- pypy/dist/pypy/interpreter/generator.py (original) +++ pypy/dist/pypy/interpreter/generator.py Tue Mar 1 14:54:19 2005 @@ -17,7 +17,6 @@ def run(self): "Build a generator-iterator." - self.exhausted = False return self.space.wrap(GeneratorIterator(self)) ### extra opcodes ### @@ -42,6 +41,7 @@ self.space = frame.space self.frame = frame self.running = False + self.exhausted = False def descr__iter__(self): return self.space.wrap(self) @@ -51,18 +51,15 @@ if self.running: raise OperationError(space.w_ValueError, space.wrap('generator already executing')) - if self.frame.exhausted: + if self.exhausted: raise OperationError(space.w_StopIteration, space.w_None) self.running = True try: try: return self.frame.resume() - except OperationError, e: - self.frame.exhausted = True - if e.match(self.space, self.space.w_StopIteration): - raise OperationError(space.w_StopIteration, space.w_None) - else: - raise + except OperationError: + self.exhausted = True + raise finally: self.running = False @@ -80,5 +77,4 @@ class SGeneratorReturn(ControlFlowException): """Signals a 'return' statement inside a generator.""" def emptystack(self, frame): - frame.exhausted = True raise OperationError(frame.space.w_StopIteration, frame.space.w_None) From pedronis at codespeak.net Tue Mar 1 15:36:58 2005 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Tue, 1 Mar 2005 15:36:58 +0100 (MET) Subject: [pypy-svn] r9545 - pypy/dist/pypy/interpreter Message-ID: <20050301143658.EAFE127B39@code1.codespeak.net> Author: pedronis Date: Tue Mar 1 15:36:58 2005 New Revision: 9545 Modified: pypy/dist/pypy/interpreter/pycode.py Log: don't use multiple inheritance for frame impls Modified: pypy/dist/pypy/interpreter/pycode.py ============================================================================== --- pypy/dist/pypy/interpreter/pycode.py (original) +++ pypy/dist/pypy/interpreter/pycode.py Tue Mar 1 15:36:58 2005 @@ -44,6 +44,28 @@ kwargname = None return argnames, varargname, kwargname + +NESTED = 1 +GENERATOR = 2 + +frame_classes = {} + +def frame_class(choose): + if frame_classes: + return frame_classes[choose] + else: + from pypy.interpreter.pyopcode import PyInterpFrame + from pypy.interpreter.nestedscope import PyNestedScopeFrame + from pypy.interpreter.generator import GeneratorFrame + + frame_classes[0] = PyInterpFrame + frame_classes[NESTED] = PyNestedScopeFrame + frame_classes[GENERATOR] = type('PyGeneratorFrame', (PyInterpFrame,), + GeneratorFrame.__dict__.copy()) + frame_classes[NESTED|GENERATOR] = type('PyNestedScopeGeneratorFrame', (PyNestedScopeFrame,), + GeneratorFrame.__dict__.copy()) + return frame_classes[choose] + class PyCode(eval.Code): "CPython-style code objects." @@ -117,13 +139,12 @@ def create_frame(self, space, w_globals, closure=None): "Create an empty PyFrame suitable for this code object." # select the appropriate kind of frame - from pypy.interpreter.pyopcode import PyInterpFrame as Frame + choose = 0 if self.co_cellvars or self.co_freevars: - from pypy.interpreter.nestedscope import PyNestedScopeFrame as F - Frame = enhanceclass(Frame, F) + choose |= NESTED if self.co_flags & CO_GENERATOR: - from pypy.interpreter.generator import GeneratorFrame as F - Frame = enhanceclass(Frame, F) + choose |= GENERATOR + Frame = frame_class(choose) return Frame(space, self, w_globals, closure) signature = cpython_code_signature @@ -224,17 +245,3 @@ code.co_cellvars = unpack_str_tuple(space, w_cellvars) return space.wrap(code) descr_code__new__.unwrap_spec = unwrap_spec - - -def _really_enhanceclass(key, stuff): - return type("Mixed", key, {}) - -def enhanceclass(baseclass, newclass, cache=Cache()): - # this is a bit too dynamic for RPython, but it looks nice - # and I assume that we can easily change it into a static - # pre-computed table - if issubclass(newclass, baseclass): - return newclass - else: - return cache.getorbuild((newclass, baseclass), - _really_enhanceclass, None) From pedronis at codespeak.net Tue Mar 1 17:40:17 2005 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Tue, 1 Mar 2005 17:40:17 +0100 (MET) Subject: [pypy-svn] r9549 - in pypy/dist/pypy: interpreter interpreter/test objspace/flow Message-ID: <20050301164017.B717627B3B@code1.codespeak.net> Author: pedronis Date: Tue Mar 1 17:40:17 2005 New Revision: 9549 Modified: pypy/dist/pypy/interpreter/eval.py pypy/dist/pypy/interpreter/nestedscope.py pypy/dist/pypy/interpreter/pyframe.py pypy/dist/pypy/interpreter/pyopcode.py pypy/dist/pypy/interpreter/test/test_eval.py pypy/dist/pypy/objspace/flow/framestate.py pypy/dist/pypy/objspace/flow/model.py Log: Use None for undefined local variables as natural. Change flow space accordingly. Modified: pypy/dist/pypy/interpreter/eval.py ============================================================================== --- pypy/dist/pypy/interpreter/eval.py (original) +++ pypy/dist/pypy/interpreter/eval.py Tue Mar 1 17:40:17 2005 @@ -49,11 +49,6 @@ def getdocstring(self): return None -class UndefinedClass(object): - pass -UNDEFINED = UndefinedClass() # marker for undefined local variables - - class Frame(Wrappable): """A frame is an environment supporting the execution of a code object. Abstract base class.""" @@ -114,7 +109,7 @@ self.w_locals = self.space.newdict([]) varnames = self.code.getvarnames() for name, w_value in zip(varnames, self.getfastscope()): - if w_value is not UNDEFINED: + if w_value is not None: w_name = self.space.wrap(name) self.space.setitem(self.w_locals, w_name, w_value) @@ -123,7 +118,7 @@ assert self.w_locals is not None varnames = self.code.getvarnames() - new_fastlocals_w = [UNDEFINED]*self.numlocals + new_fastlocals_w = [None]*self.numlocals for name, i in zip(varnames, range(self.numlocals)): w_name = self.space.wrap(varnames[i]) Modified: pypy/dist/pypy/interpreter/nestedscope.py ============================================================================== --- pypy/dist/pypy/interpreter/nestedscope.py (original) +++ pypy/dist/pypy/interpreter/nestedscope.py Tue Mar 1 17:40:17 2005 @@ -1,5 +1,4 @@ from pypy.interpreter.error import OperationError -from pypy.interpreter.eval import UNDEFINED from pypy.interpreter.pyopcode import PyInterpFrame from pypy.interpreter import function, pycode from pypy.interpreter.baseobjspace import Wrappable @@ -7,17 +6,17 @@ class Cell(Wrappable): "A simple container for a wrapped value." - def __init__(self, w_value=UNDEFINED): + def __init__(self, w_value=None): self.w_value = w_value def clone(self): return self.__class__(self.w_value) def empty(self): - return self.w_value is UNDEFINED + return self.w_value is None def get(self): - if self.w_value is UNDEFINED: + if self.w_value is None: raise ValueError, "get() from an empty cell" return self.w_value @@ -25,13 +24,13 @@ self.w_value = w_value def delete(self): - if self.w_value is UNDEFINED: + if self.w_value is None: raise ValueError, "delete() on an empty cell" - self.w_value = UNDEFINED + self.w_value = None def __repr__(self): """ representation for debugging purposes """ - if self.w_value is UNDEFINED: + if self.w_value is None: content = "" else: content = repr(self.w_value) Modified: pypy/dist/pypy/interpreter/pyframe.py ============================================================================== --- pypy/dist/pypy/interpreter/pyframe.py (original) +++ pypy/dist/pypy/interpreter/pyframe.py Tue Mar 1 17:40:17 2005 @@ -39,7 +39,7 @@ if code.dictscope_needed(): self.w_locals = space.newdict([]) # set to None by Frame.__init__ - self.fastlocals_w = [eval.UNDEFINED]*self.numlocals + self.fastlocals_w = [None]*self.numlocals def getfastscope(self): "Get the fast locals as a list." Modified: pypy/dist/pypy/interpreter/pyopcode.py ============================================================================== --- pypy/dist/pypy/interpreter/pyopcode.py (original) +++ pypy/dist/pypy/interpreter/pyopcode.py Tue Mar 1 17:40:17 2005 @@ -5,7 +5,6 @@ """ from pypy.interpreter.baseobjspace import OperationError, BaseWrappable -from pypy.interpreter.eval import UNDEFINED from pypy.interpreter import gateway, function from pypy.interpreter import pyframe, pytraceback from pypy.interpreter.miscutils import InitializedClass @@ -92,7 +91,7 @@ def LOAD_FAST(f, varindex): # access a local variable directly w_value = f.fastlocals_w[varindex] - if w_value is UNDEFINED: + if w_value is None: varname = f.getlocalvarname(varindex) message = "local variable '%s' referenced before assignment" % varname raise OperationError(f.space.w_UnboundLocalError, f.space.wrap(message)) @@ -466,11 +465,12 @@ f.valuestack.push(w_value) def DELETE_FAST(f, varindex): - if f.fastlocals_w[varindex] is UNDEFINED: + if f.fastlocals_w[varindex] is None: varname = f.getlocalvarname(varindex) message = "local variable '%s' referenced before assignment" % varname raise OperationError(f.space.w_UnboundLocalError, f.space.wrap(message)) - f.fastlocals_w[varindex] = UNDEFINED + f.fastlocals_w[varindex] = None + def BUILD_TUPLE(f, itemcount): items = [f.valuestack.pop() for i in range(itemcount)] Modified: pypy/dist/pypy/interpreter/test/test_eval.py ============================================================================== --- pypy/dist/pypy/interpreter/test/test_eval.py (original) +++ pypy/dist/pypy/interpreter/test/test_eval.py Tue Mar 1 17:40:17 2005 @@ -1,6 +1,6 @@ import autopath -from pypy.interpreter.eval import Frame, UNDEFINED +from pypy.interpreter.eval import Frame from pypy.interpreter.pycode import PyCode @@ -14,7 +14,7 @@ def __init__(self, space, code, numlocals): Frame.__init__(self, space, code, numlocals=numlocals) - self.fastlocals_w = [UNDEFINED] * self.numlocals + self.fastlocals_w = [None] * self.numlocals def setfastscope(self, scope_w): self.fastlocals_w = scope_w @@ -45,24 +45,24 @@ def sameList(self, l1, l2): assert len(l1) == len(l2) for w_1, w_2 in zip(l1, l2): - assert (w_1 is UNDEFINED) == (w_2 is UNDEFINED) - if w_1 is not UNDEFINED: + assert (w_1 is None) == (w_2 is None) + if w_1 is not None: assert self.space.eq_w(w_1, w_2) def test_locals2fast(self): w = self.space.wrap self.f.w_locals = self.space.newdict([]) self.f.locals2fast() - self.sameList(self.f.fastlocals_w, [UNDEFINED]*5) + self.sameList(self.f.fastlocals_w, [None]*5) self.f.w_locals = self.space.newdict([ (w('x'), w(5))]) self.f.locals2fast() - self.sameList(self.f.fastlocals_w, [w(5)] + [UNDEFINED]*4) + self.sameList(self.f.fastlocals_w, [w(5)] + [None]*4) self.f.w_locals = self.space.newdict([ (w('x'), w(5)), (w('args'), w(7))]) self.f.locals2fast() - self.sameList(self.f.fastlocals_w, [w(5), UNDEFINED, w(7), - UNDEFINED, UNDEFINED]) + self.sameList(self.f.fastlocals_w, [w(5), None, w(7), + None, None]) Modified: pypy/dist/pypy/objspace/flow/framestate.py ============================================================================== --- pypy/dist/pypy/objspace/flow/framestate.py (original) +++ pypy/dist/pypy/objspace/flow/framestate.py Tue Mar 1 17:40:17 2005 @@ -7,7 +7,13 @@ def __init__(self, state): if isinstance(state, PyFrame): - data = state.getfastscope() + state.valuestack.items + data = [] + for w in state.getfastscope(): + if w is None: + data.append(UNDEFINED) + else: + data.append(w) + data.extend(state.valuestack.items) if state.last_exception is None: data.append(Constant(None)) data.append(Constant(None)) @@ -35,7 +41,13 @@ fastlocals = len(frame.fastlocals_w) data = self.mergeable[:] recursively_unflatten(frame.space, data) - frame.setfastscope(data[:fastlocals]) + fastscope = [] + for w in data[:fastlocals]: + if w is UNDEFINED: + fastscope.append(None) + else: + fastscope.append(w) + frame.setfastscope(fastscope) frame.valuestack.items[:] = data[fastlocals:-2] if data[-2] == Constant(None): assert data[-1] == Constant(None) Modified: pypy/dist/pypy/objspace/flow/model.py ============================================================================== --- pypy/dist/pypy/objspace/flow/model.py (original) +++ pypy/dist/pypy/objspace/flow/model.py Tue Mar 1 17:40:17 2005 @@ -195,13 +195,14 @@ flags = '' return '(%s%s)' % (r, flags) -# hack! it is useful to have UNDEFINED be an instance of Constant too. -# PyFrame then automatically uses this Constant as a marker for -# non-initialized variables. -from pypy.interpreter.eval import UNDEFINED -UndefinedConstant = UNDEFINED.__class__ -UndefinedConstant.__bases__ += (Constant,) -Constant.__init__(UNDEFINED, None) +class UndefinedConstant(Constant): + def __init__(self): + Constant.__init__(self,object()) + + def __repr__(self): + return '(*undefined*)' + +UNDEFINED = UndefinedConstant() class SpaceOperation: def __init__(self, opname, args, result): From tismer at codespeak.net Tue Mar 1 17:43:17 2005 From: tismer at codespeak.net (tismer at codespeak.net) Date: Tue, 1 Mar 2005 17:43:17 +0100 (MET) Subject: [pypy-svn] r9550 - pypy/dist/pypy/translator Message-ID: <20050301164317.04BAC27B36@code1.codespeak.net> Author: tismer Date: Tue Mar 1 17:43:16 2005 New Revision: 9550 Modified: pypy/dist/pypy/translator/geninterplevel.py Log: repaired geninterp to ignore old-style classes, again. Still no support for pickled state. Modified: pypy/dist/pypy/translator/geninterplevel.py ============================================================================== --- pypy/dist/pypy/translator/geninterplevel.py (original) +++ pypy/dist/pypy/translator/geninterplevel.py Tue Mar 1 17:43:16 2005 @@ -536,8 +536,15 @@ self.latercode.append((gen, self.debugstack)) def nameof_instance(self, instance): - name = self.uniquename('ginst_' + instance.__class__.__name__) - cls = self.nameof(instance.__class__) + klass = instance.__class__ + name = self.uniquename('ginst_' + klass.__name__) + cls = self.nameof(klass) + if hasattr(klass, '__base__'): + base_class = builtin_base(instance) + base = self.nameof(base_class) + else: + base_class = None + base = cls def initinstance(): content = instance.__dict__.items() content.sort() @@ -550,23 +557,11 @@ print >> sys.stderr, "Problem while generating %s of %r" % ( name, instance) raise - if isinstance(instance, Exception): - # special-case for exception instances: wrap them directly - self.initcode.append('_ins = %s()\n' - 'm.%s = space.wrap(_ins)' % ( - instance.__class__.__name__, name)) - else: - if isinstance(instance.__class__, type): - self.initcode.append( - '_new = space.getattr(%s, %s)\n' - '_tup = space.newtuple([%s])\n' - 'm.%s = space.call(_new, _tup)' % ( - cls, self.nameof('__new__'), cls, name)) - else: - self.initcode.append( - '_tup = space.newtuple([%s])\n' - 'm.%s = space.call(space.w_instance, _tup)' % ( - cls, name)) + self.initcode.append( + '_new = space.getattr(%s, %s)\n' + '_tup = space.newtuple([%s])\n' + 'm.%s = space.call(_new, _tup)' % ( + cls, self.nameof('__new__'), cls, name)) self.later(initinstance()) return name From arigo at codespeak.net Tue Mar 1 17:48:04 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 1 Mar 2005 17:48:04 +0100 (MET) Subject: [pypy-svn] r9551 - pypy/dist/pypy/interpreter Message-ID: <20050301164804.62F8127B43@code1.codespeak.net> Author: arigo Date: Tue Mar 1 17:48:04 2005 New Revision: 9551 Modified: pypy/dist/pypy/interpreter/pycode.py Log: Frame subclasses creation is NOT_RPYTHON. Modified: pypy/dist/pypy/interpreter/pycode.py ============================================================================== --- pypy/dist/pypy/interpreter/pycode.py (original) +++ pypy/dist/pypy/interpreter/pycode.py Tue Mar 1 17:48:04 2005 @@ -50,21 +50,20 @@ frame_classes = {} -def frame_class(choose): - if frame_classes: - return frame_classes[choose] - else: - from pypy.interpreter.pyopcode import PyInterpFrame - from pypy.interpreter.nestedscope import PyNestedScopeFrame - from pypy.interpreter.generator import GeneratorFrame - - frame_classes[0] = PyInterpFrame - frame_classes[NESTED] = PyNestedScopeFrame - frame_classes[GENERATOR] = type('PyGeneratorFrame', (PyInterpFrame,), - GeneratorFrame.__dict__.copy()) - frame_classes[NESTED|GENERATOR] = type('PyNestedScopeGeneratorFrame', (PyNestedScopeFrame,), - GeneratorFrame.__dict__.copy()) - return frame_classes[choose] +def setup_frame_classes(): + "NOT_RPYTHON" + from pypy.interpreter.pyopcode import PyInterpFrame + from pypy.interpreter.nestedscope import PyNestedScopeFrame + from pypy.interpreter.generator import GeneratorFrame + + frame_classes[0] = PyInterpFrame + frame_classes[NESTED] = PyNestedScopeFrame + frame_classes[GENERATOR] = type('PyGeneratorFrame', + (PyInterpFrame,), + GeneratorFrame.__dict__.copy()) + frame_classes[NESTED|GENERATOR] = type('PyNestedScopeGeneratorFrame', + (PyNestedScopeFrame,), + GeneratorFrame.__dict__.copy()) class PyCode(eval.Code): "CPython-style code objects." @@ -139,12 +138,14 @@ def create_frame(self, space, w_globals, closure=None): "Create an empty PyFrame suitable for this code object." # select the appropriate kind of frame + if not frame_classes: + setup_frame_classes() # lazily choose = 0 if self.co_cellvars or self.co_freevars: choose |= NESTED if self.co_flags & CO_GENERATOR: choose |= GENERATOR - Frame = frame_class(choose) + Frame = frame_classes[choose] return Frame(space, self, w_globals, closure) signature = cpython_code_signature From arigo at codespeak.net Tue Mar 1 18:01:41 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 1 Mar 2005 18:01:41 +0100 (MET) Subject: [pypy-svn] r9554 - pypy/dist/pypy/module/test Message-ID: <20050301170141.768A427B45@code1.codespeak.net> Author: arigo Date: Tue Mar 1 18:01:41 2005 New Revision: 9554 Modified: pypy/dist/pypy/module/test/test_zip.py Log: Remove the test copied verbatim from CPython. The import line fails if whatever happens to be the current directory has a 'test' subpackage... More importantly, tests from CPython should be run directly now instead of copied into our own tests. Modified: pypy/dist/pypy/module/test/test_zip.py ============================================================================== --- pypy/dist/pypy/module/test/test_zip.py (original) +++ pypy/dist/pypy/module/test/test_zip.py Tue Mar 1 18:01:41 2005 @@ -36,105 +36,3 @@ def test_mixed_types(self): assert zip('hello', [1,2,3,4], (7,8,9,10)) == ( [('h', 1, 7), ('e', 2, 8), ('l', 3, 9), ('l', 4, 10)]) - - def test_from_cpython(self): - from test.test_support import TESTFN, unlink - class BasicIterClass: - def __init__(self, n): - self.n = n - self.i = 0 - def next(self): - res = self.i - if res >= self.n: - raise StopIteration - self.i = res + 1 - return res - - - class IteratingSequenceClass: - def __init__(self, n): - self.n = n - def __iter__(self): - return BasicIterClass(self.n) - - class SequenceClass: - def __init__(self, n): - self.n = n - def __getitem__(self, i): - if 0 <= i < self.n: - return i - else: - raise IndexError - - assert zip(*[(1, 2), 'ab']) == [(1, 'a'), (2, 'b')] - - raises(TypeError, zip, None) - raises(TypeError, zip, range(10), 42) - raises(TypeError, zip, range(10), zip) - - assert zip(IteratingSequenceClass(3)) == [(0,), (1,), (2,)] - assert zip(SequenceClass(3)) == [(0,), (1,), (2,)] - - d = {"one": 1, "two": 2, "three": 3} - assert d.items() == zip(d, d.itervalues()) - - # Generate all ints starting at constructor arg. - class IntsFrom: - def __init__(self, start): - self.i = start - - def __iter__(self): - return self - - def next(self): - i = self.i - self.i = i+1 - return i - - f = open(TESTFN, "w") - try: - f.write("a\n" "bbb\n" "cc\n") - finally: - f.close() - f = open(TESTFN, "r") - try: - assert (zip(IntsFrom(0), f, IntsFrom(-100)) == - [(0, "a\n", -100), - (1, "bbb\n", -99), - (2, "cc\n", -98)]) - finally: - f.close() - try: - unlink(TESTFN) - except OSError: - pass - - assert zip(xrange(5)) == [(i,) for i in range(5)] - - # Classes that lie about their lengths. - class NoGuessLen5: - def __getitem__(self, i): - if i >= 5: - raise IndexError - return i - - class Guess3Len5(NoGuessLen5): - def __len__(self): - return 3 - - class Guess30Len5(NoGuessLen5): - def __len__(self): - return 30 - - assert len(Guess3Len5()) == 3 - assert len(Guess30Len5()) == 30 - assert zip(NoGuessLen5()) == zip(range(5)) - assert zip(Guess3Len5()) == zip(range(5)) - assert zip(Guess30Len5()) == zip(range(5)) - - expected = [(i, i) for i in range(5)] - for x in NoGuessLen5(), Guess3Len5(), Guess30Len5(): - for y in NoGuessLen5(), Guess3Len5(), Guess30Len5(): - assert zip(x, y) == expected - - From tismer at codespeak.net Tue Mar 1 19:34:36 2005 From: tismer at codespeak.net (tismer at codespeak.net) Date: Tue, 1 Mar 2005 19:34:36 +0100 (MET) Subject: [pypy-svn] r9559 - pypy/dist/pypy/translator Message-ID: <20050301183436.412F827B3B@code1.codespeak.net> Author: tismer Date: Tue Mar 1 19:34:36 2005 New Revision: 9559 Modified: pypy/dist/pypy/translator/geninterplevel.py Log: shorter, more elegant, but slightly slower code for instance creation Modified: pypy/dist/pypy/translator/geninterplevel.py ============================================================================== --- pypy/dist/pypy/translator/geninterplevel.py (original) +++ pypy/dist/pypy/translator/geninterplevel.py Tue Mar 1 19:34:36 2005 @@ -557,11 +557,8 @@ print >> sys.stderr, "Problem while generating %s of %r" % ( name, instance) raise - self.initcode.append( - '_new = space.getattr(%s, %s)\n' - '_tup = space.newtuple([%s])\n' - 'm.%s = space.call(_new, _tup)' % ( - cls, self.nameof('__new__'), cls, name)) + self.initcode.append("m.%s = space.call_method(%s, '__new__', %s)" % ( + name, cls, cls)) self.later(initinstance()) return name From tismer at codespeak.net Tue Mar 1 19:42:57 2005 From: tismer at codespeak.net (tismer at codespeak.net) Date: Tue, 1 Mar 2005 19:42:57 +0100 (MET) Subject: [pypy-svn] r9561 - pypy/dist/pypy/translator Message-ID: <20050301184257.27B7827B3B@code1.codespeak.net> Author: tismer Date: Tue Mar 1 19:42:56 2005 New Revision: 9561 Modified: pypy/dist/pypy/translator/geninterplevel.py Log: removed some unused code Modified: pypy/dist/pypy/translator/geninterplevel.py ============================================================================== --- pypy/dist/pypy/translator/geninterplevel.py (original) +++ pypy/dist/pypy/translator/geninterplevel.py Tue Mar 1 19:42:56 2005 @@ -364,15 +364,6 @@ else: return self.uniquename('%s_%d' % (basename, n)) - def uniquelocalname(self, basename, seennames): - basename = basename.translate(C_IDENTIFIER) - n = seennames.get(basename, 0) - seennames[basename] = n+1 - if n == 0: - return basename - else: - return self.uniquelocalname('%s_%d' % (basename, n), seennames) - def nameof_NotImplementedType(self, value): return "space.w_NotImplemented" From tismer at codespeak.net Tue Mar 1 20:41:57 2005 From: tismer at codespeak.net (tismer at codespeak.net) Date: Tue, 1 Mar 2005 20:41:57 +0100 (MET) Subject: [pypy-svn] r9562 - pypy/dist/pypy/translator Message-ID: <20050301194157.37E1E27B3B@code1.codespeak.net> Author: tismer Date: Tue Mar 1 20:41:57 2005 New Revision: 9562 Modified: pypy/dist/pypy/translator/genc.py Log: generating shorter local names like in geninterp. Will extract common functions, later. Modified: pypy/dist/pypy/translator/genc.py ============================================================================== --- pypy/dist/pypy/translator/genc.py (original) +++ pypy/dist/pypy/translator/genc.py Tue Mar 1 20:41:57 2005 @@ -67,6 +67,7 @@ self.globaldecl = [] self.globalobjects = [] self.pendingfunctions = [] + self.currentfunc = None self.debugstack = () # linked list of nested nameof() self.gen_source() @@ -533,7 +534,8 @@ ## func.__name__) f = self.f - body = list(self.cfunction_body(func)) + localvars = {} + body = list(self.cfunction_body(func, localvars)) name_of_defaults = [self.nameof(x, debug=('Default argument of', func)) for x in (func.func_defaults or ())] self.gen_global_declarations() @@ -550,7 +552,7 @@ if isinstance(node, Block): localslst.extend(node.getvariables()) traverse(visit, graph) - localnames = [a.name for a in uniqueitems(localslst)] + localnames = [self.expr(a, localvars) for a in uniqueitems(localslst)] # collect all the arguments if func.func_code.co_flags & CO_VARARGS: @@ -561,7 +563,7 @@ positional_args = graph.getargs() min_number_of_args = len(positional_args) - len(name_of_defaults) - fast_args = [a.name for a in positional_args] + fast_args = [self.expr(a, localvars) for a in positional_args] if vararg is not None: fast_args.append(str(vararg)) fast_name = 'fast' + f_name @@ -654,7 +656,7 @@ # generate an incref for each input argument for v in positional_args: - print >> f, '\tPy_INCREF(%s);' % v.name + print >> f, '\tPy_INCREF(%s);' % self.expr(v, localvars) # print the body for line in body: @@ -675,7 +677,45 @@ del self.translator.flowgraphs[func] Variable.instances.clear() - def cfunction_body(self, func): + def expr(self, v, localnames, wrapped = False): + # this function is copied from geninterp just with a different default. + # the purpose is to generate short local names. + # This is intermediate. Common code will be extracted into a base class. + if isinstance(v, Variable): + n = v.name + if n.startswith("v") and n[1:].isdigit(): + ret = localnames.get(v.name) + if not ret: + if wrapped: + localnames[v.name] = ret = "w_%d" % len(localnames) + else: + localnames[v.name] = ret = "v%d" % len(localnames) + return ret + scorepos = n.rfind("_") + if scorepos >= 0 and n[scorepos+1:].isdigit(): + name = n[:scorepos] + # do individual numbering on named vars + thesenames = localnames.setdefault(name, {}) + ret = thesenames.get(v.name) + if not ret: + if wrapped: + fmt = "w_%s_%d" + else: + fmt = "%s_%d" + # don't use zero + if len(thesenames) == 0: + fmt = fmt[:-3] + thesenames[v.name] = ret = fmt % name + else: + thesenames[v.name] = ret = fmt % (name, len(thesenames)) + return ret + elif isinstance(v, Constant): + return self.nameof(v.value, + debug=('Constant in the graph of', self.currentfunc)) + else: + raise TypeError, "expr(%r)" % (v,) + + def cfunction_body(self, func, localvars): graph = self.translator.getflowgraph(func) remove_direct_loops(graph) checkgraph(graph) @@ -683,32 +723,23 @@ blocknum = {} allblocks = [] - def expr(v): - if isinstance(v, Variable): - return v.name - elif isinstance(v, Constant): - return self.nameof(v.value, - debug=('Constant in the graph of',func)) - else: - raise TypeError, "expr(%r)" % (v,) - def gen_link(link, linklocalvars=None): "Generate the code to jump across the given Link." has_ref = {} linklocalvars = linklocalvars or {} for v in to_release: - linklocalvars[v] = v.name + linklocalvars[v] = self.expr(v, localvars) has_ref = linklocalvars.copy() for a1, a2 in zip(link.args, link.target.inputargs): if a1 in linklocalvars: src = linklocalvars[a1] else: - src = expr(a1) - line = 'MOVE(%s, %s)' % (src, a2.name) + src = self.expr(a1, localvars) + line = 'MOVE(%s, %s)' % (src, self.expr(a2, localvars)) if a1 in has_ref: del has_ref[a1] else: - line += '\tPy_INCREF(%s);' % a2.name + line += '\tPy_INCREF(%s);' % self.expr(a2, localvars) yield line for v in has_ref: yield 'Py_DECREF(%s);' % linklocalvars[v] @@ -727,8 +758,8 @@ yield 'block%d:' % blocknum[block] to_release = list(block.inputargs) for op in block.operations: - lst = [expr(v) for v in op.args] - lst.append(op.result.name) + lst = [self.expr(v, localvars) for v in op.args] + lst.append(self.expr(op.result, localvars)) lst.append('err%d_%d' % (blocknum[block], len(to_release))) macro = 'OP_%s' % op.opname.upper() meth = getattr(self, macro, None) @@ -742,13 +773,13 @@ if len(block.exits) == 0: if len(block.inputargs) == 2: # exc_cls, exc_value # exceptional return block - exc_cls = expr(block.inputargs[0]) - exc_value = expr(block.inputargs[1]) + exc_cls = self.expr(block.inputargs[0], localvars) + exc_value = self.expr(block.inputargs[1], localvars) yield 'PyErr_Restore(%s, %s, NULL);' % (exc_cls, exc_value) yield 'FUNCTION_RETURN(NULL)' else: # regular return block - retval = expr(block.inputargs[0]) + retval = self.expr(block.inputargs[0], localvars) yield 'FUNCTION_RETURN(%s)' % retval continue elif block.exitswitch is None: @@ -791,13 +822,13 @@ # block ending in a switch on a value for link in block.exits[:-1]: yield 'if (EQ_%s(%s)) {' % (link.exitcase, - block.exitswitch.name) + self.expr(block.exitswitch, localvars)) for op in gen_link(link): yield '\t' + op yield '}' link = block.exits[-1] yield 'assert(EQ_%s(%s));' % (link.exitcase, - block.exitswitch.name) + self.expr(block.exitswitch, localvars)) for op in gen_link(block.exits[-1]): yield op yield '' @@ -805,7 +836,7 @@ while to_release: v = to_release.pop() if err_reachable: - yield 'ERR_DECREF(%s)' % v.name + yield 'ERR_DECREF(%s)' % self.expr(v, localvars) yield 'err%d_%d:' % (blocknum[block], len(to_release)) err_reachable = True if err_reachable: From tismer at codespeak.net Tue Mar 1 20:44:13 2005 From: tismer at codespeak.net (tismer at codespeak.net) Date: Tue, 1 Mar 2005 20:44:13 +0100 (MET) Subject: [pypy-svn] r9563 - pypy/dist/pypy/translator Message-ID: <20050301194413.0031227B3B@code1.codespeak.net> Author: tismer Date: Tue Mar 1 20:44:13 2005 New Revision: 9563 Modified: pypy/dist/pypy/translator/geninterplevel.py Log: small renamings, after sharing code with genc.py Modified: pypy/dist/pypy/translator/geninterplevel.py ============================================================================== --- pypy/dist/pypy/translator/geninterplevel.py (original) +++ pypy/dist/pypy/translator/geninterplevel.py Tue Mar 1 20:44:13 2005 @@ -942,8 +942,8 @@ func.func_code.co_name, func.func_code.co_firstlineno) print >> f, "##SECTION##" - locals = {} - body = list(self.rpyfunction_body(func, locals)) + localvars = {} + body = list(self.rpyfunction_body(func, localvars)) name_of_defaults = [self.nameof(x, debug=('Default argument of', func)) for x in (func.func_defaults or ())] self.gen_global_declarations() @@ -961,7 +961,7 @@ if isinstance(node, Block): localslst.extend(node.getvariables()) traverse(visit, graph) - localnames = [self.expr(a, locals) for a in uniqueitems(localslst)] + localnames = [self.expr(a, localvars) for a in uniqueitems(localslst)] # collect all the arguments vararg = varkw = None @@ -978,11 +978,11 @@ varargname = func.func_code.co_varnames[p] positional_args = all_args[:p] - fast_args = [self.expr(a, locals) for a in positional_args] + fast_args = [self.expr(a, localvars) for a in positional_args] if vararg is not None: - fast_args.append(self.expr(vararg, locals)) + fast_args.append(self.expr(vararg, localvars)) if varkw is not None: - fast_args.append(self.expr(varkw, locals)) + fast_args.append(self.expr(varkw, localvars)) fast_name = 'fast' + f_name fast_set = dict(zip(fast_args, fast_args)) From tismer at codespeak.net Tue Mar 1 20:48:43 2005 From: tismer at codespeak.net (tismer at codespeak.net) Date: Tue, 1 Mar 2005 20:48:43 +0100 (MET) Subject: [pypy-svn] r9564 - pypy/dist/pypy/translator Message-ID: <20050301194843.C303F27B3B@code1.codespeak.net> Author: tismer Date: Tue Mar 1 20:48:43 2005 New Revision: 9564 Modified: pypy/dist/pypy/translator/genc.py Log: some omission... Modified: pypy/dist/pypy/translator/genc.py ============================================================================== --- pypy/dist/pypy/translator/genc.py (original) +++ pypy/dist/pypy/translator/genc.py Tue Mar 1 20:48:43 2005 @@ -633,7 +633,7 @@ '"%s:%s"' % (fmt, func.__name__), 'kwlist', ] - lst += ['&' + a.name for a in positional_args] + lst += ['&' + self.expr(a, localvars) for a in positional_args] print >> f, '\tif (!PyArg_ParseTupleAndKeywords(%s))' % ', '.join(lst), print >> f, tail From tismer at codespeak.net Tue Mar 1 21:07:53 2005 From: tismer at codespeak.net (tismer at codespeak.net) Date: Tue, 1 Mar 2005 21:07:53 +0100 (MET) Subject: [pypy-svn] r9566 - pypy/dist/pypy/translator Message-ID: <20050301200753.6F15B27B3B@code1.codespeak.net> Author: tismer Date: Tue Mar 1 21:07:53 2005 New Revision: 9566 Modified: pypy/dist/pypy/translator/genc.py Log: yet another omission. Too bad that I cannot compile as fast as tcc under Windows. Modified: pypy/dist/pypy/translator/genc.py ============================================================================== --- pypy/dist/pypy/translator/genc.py (original) +++ pypy/dist/pypy/translator/genc.py Tue Mar 1 21:07:53 2005 @@ -624,7 +624,7 @@ tail = '\n\t\tFUNCTION_RETURN(NULL)' for i in range(len(name_of_defaults)): print >> f, '\t%s = %s;' % ( - positional_args[min_number_of_args+i], + self.expr(positional_args[min_number_of_args+i], localvars), name_of_defaults[i]) fmt = 'O'*min_number_of_args if min_number_of_args < len(positional_args): From tismer at codespeak.net Tue Mar 1 21:23:42 2005 From: tismer at codespeak.net (tismer at codespeak.net) Date: Tue, 1 Mar 2005 21:23:42 +0100 (MET) Subject: [pypy-svn] r9567 - pypy/dist/pypy/translator Message-ID: <20050301202342.91D2627B3B@code1.codespeak.net> Author: tismer Date: Tue Mar 1 21:23:42 2005 New Revision: 9567 Modified: pypy/dist/pypy/translator/genc.py Log: hmm, my naming games produce new problems by clashing with reserved names. oh-oh Modified: pypy/dist/pypy/translator/genc.py ============================================================================== --- pypy/dist/pypy/translator/genc.py (original) +++ pypy/dist/pypy/translator/genc.py Tue Mar 1 21:23:42 2005 @@ -61,6 +61,12 @@ 'Py_False = False', 'Py_True = True', ] + # just a few predefined names which cannot be reused. + # I think this should come from some external file, + # if we want to be complete + self.reserved_names = {} + for each in 'typedef static void'.split(): + self.reserved_names[each] = 1 self.latercode = [] # list of generators generating extra lines # for later in initxxx() -- for recursive # objects @@ -703,7 +709,7 @@ else: fmt = "%s_%d" # don't use zero - if len(thesenames) == 0: + if len(thesenames) == 0 and v.name not in self.reserved_names: fmt = fmt[:-3] thesenames[v.name] = ret = fmt % name else: From tismer at codespeak.net Tue Mar 1 21:33:35 2005 From: tismer at codespeak.net (tismer at codespeak.net) Date: Tue, 1 Mar 2005 21:33:35 +0100 (MET) Subject: [pypy-svn] r9568 - pypy/dist/pypy/translator Message-ID: <20050301203335.1783627B3B@code1.codespeak.net> Author: tismer Date: Tue Mar 1 21:33:34 2005 New Revision: 9568 Modified: pypy/dist/pypy/translator/geninterplevel.py Log: adjusting the classes a bit Modified: pypy/dist/pypy/translator/geninterplevel.py ============================================================================== --- pypy/dist/pypy/translator/geninterplevel.py (original) +++ pypy/dist/pypy/translator/geninterplevel.py Tue Mar 1 21:33:34 2005 @@ -146,6 +146,9 @@ self.latercode = u() # list of generators generating extra lines # for later in initxxx() -- for recursive # objects + # this can stay empty, because we cannot have used a reserved + # name as a variable in the same language. But see genc.py + self.reserved_names = {} self.globaldecl = [] self.globalobjects = [] self.pendingfunctions = [] @@ -188,7 +191,7 @@ else: fmt = "%s_%d" # don't use zero - if len(thesenames) == 0: + if len(thesenames) == 0 and v.name not in self.reserved_names: fmt = fmt[:-3] thesenames[v.name] = ret = fmt % name else: From tismer at codespeak.net Tue Mar 1 21:33:46 2005 From: tismer at codespeak.net (tismer at codespeak.net) Date: Tue, 1 Mar 2005 21:33:46 +0100 (MET) Subject: [pypy-svn] r9569 - pypy/dist/pypy/translator Message-ID: <20050301203346.EB0D827B41@code1.codespeak.net> Author: tismer Date: Tue Mar 1 21:33:46 2005 New Revision: 9569 Modified: pypy/dist/pypy/translator/genc.py Log: last? small glitch Modified: pypy/dist/pypy/translator/genc.py ============================================================================== --- pypy/dist/pypy/translator/genc.py (original) +++ pypy/dist/pypy/translator/genc.py Tue Mar 1 21:33:46 2005 @@ -709,7 +709,7 @@ else: fmt = "%s_%d" # don't use zero - if len(thesenames) == 0 and v.name not in self.reserved_names: + if len(thesenames) == 0 and name not in self.reserved_names: fmt = fmt[:-3] thesenames[v.name] = ret = fmt % name else: From tismer at codespeak.net Tue Mar 1 21:39:45 2005 From: tismer at codespeak.net (tismer at codespeak.net) Date: Tue, 1 Mar 2005 21:39:45 +0100 (MET) Subject: [pypy-svn] r9570 - pypy/dist/pypy/translator Message-ID: <20050301203945.0B39027B41@code1.codespeak.net> Author: tismer Date: Tue Mar 1 21:39:44 2005 New Revision: 9570 Modified: pypy/dist/pypy/translator/genc.py Log: yet another small name collision glitch Modified: pypy/dist/pypy/translator/genc.py ============================================================================== --- pypy/dist/pypy/translator/genc.py (original) +++ pypy/dist/pypy/translator/genc.py Tue Mar 1 21:39:44 2005 @@ -65,7 +65,7 @@ # I think this should come from some external file, # if we want to be complete self.reserved_names = {} - for each in 'typedef static void'.split(): + for each in 'typedef static void const'.split(): self.reserved_names[each] = 1 self.latercode = [] # list of generators generating extra lines # for later in initxxx() -- for recursive From tismer at codespeak.net Tue Mar 1 22:25:36 2005 From: tismer at codespeak.net (tismer at codespeak.net) Date: Tue, 1 Mar 2005 22:25:36 +0100 (MET) Subject: [pypy-svn] r9571 - pypy/dist/pypy/translator Message-ID: <20050301212536.DC43E27B3B@code1.codespeak.net> Author: tismer Date: Tue Mar 1 22:25:36 2005 New Revision: 9571 Modified: pypy/dist/pypy/translator/genc.py Log: there seems to be another name clashingproblem. I disabled the feature for the moment, everything works like before. Modified: pypy/dist/pypy/translator/genc.py ============================================================================== --- pypy/dist/pypy/translator/genc.py (original) +++ pypy/dist/pypy/translator/genc.py Tue Mar 1 22:25:36 2005 @@ -689,6 +689,9 @@ # This is intermediate. Common code will be extracted into a base class. if isinstance(v, Variable): n = v.name + # there is a problem at the moment. + # use the name as is until this is solved + return v.name if n.startswith("v") and n[1:].isdigit(): ret = localnames.get(v.name) if not ret: From pedronis at codespeak.net Tue Mar 1 22:48:13 2005 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Tue, 1 Mar 2005 22:48:13 +0100 (MET) Subject: [pypy-svn] r9572 - in pypy/dist/pypy/translator: . test Message-ID: <20050301214813.B6C7727B3B@code1.codespeak.net> Author: pedronis Date: Tue Mar 1 22:48:13 2005 New Revision: 9572 Modified: pypy/dist/pypy/translator/annrpython.py pypy/dist/pypy/translator/test/snippet.py pypy/dist/pypy/translator/test/test_annrpython.py Log: failing test that exemplifies how translate_pypy0 right now after a while get stuck. currentdef() cares about freshness (checks revision), so contains usages (e.g. inst setattr one) cannot ignore revision otherwise fresher SomeInstances will not be propagated to where currentdef because of a stale SomeInstance blocked inference. Modified: pypy/dist/pypy/translator/annrpython.py ============================================================================== --- pypy/dist/pypy/translator/annrpython.py (original) +++ pypy/dist/pypy/translator/annrpython.py Tue Mar 1 22:48:13 2005 @@ -82,7 +82,7 @@ self.addpendingblock(func, flowgraph.startblock, inputcells) # recursively proceed until no more pending block is left self.complete() - return self.binding(flowgraph.getreturnvar()) + return self.binding(flowgraph.getreturnvar(), extquery=True) def gettype(self, variable): """Return the known type of a control flow graph variable, @@ -155,10 +155,16 @@ print "++-" * 20 - def binding(self, arg): + def binding(self, arg, extquery=False): "Gives the SomeValue corresponding to the given Variable or Constant." if isinstance(arg, Variable): - return self.bindings[arg] + try: + return self.bindings[arg] + except KeyError: + if extquery: + return None + else: + raise elif isinstance(arg, UndefinedConstant): # undefined local variables return annmodel.SomeImpossibleValue() elif isinstance(arg, Constant): Modified: pypy/dist/pypy/translator/test/snippet.py ============================================================================== --- pypy/dist/pypy/translator/test/snippet.py (original) +++ pypy/dist/pypy/translator/test/snippet.py Tue Mar 1 22:48:13 2005 @@ -892,3 +892,24 @@ def one_thing2(): return thing2 + +# propagation of fresh instances through attributes + +class Stk: + def __init__(self): + self.itms = [] + + def push(self, v): + self.itms.append(v) + +class EC: + + def __init__(self): + self.stk = Stk() + + def enter(self, f): + self.stk.push(f) + +def propagation_of_fresh_instances_through_attrs(x): + e = EC() + e.enter(x) Modified: pypy/dist/pypy/translator/test/test_annrpython.py ============================================================================== --- pypy/dist/pypy/translator/test/test_annrpython.py (original) +++ pypy/dist/pypy/translator/test/test_annrpython.py Tue Mar 1 22:48:13 2005 @@ -526,6 +526,11 @@ assert isinstance(a.binding(g_flowgraph.getreturnvar()), annmodel.SomeString) + def test_propagation_of_fresh_instances_through_attrs(self): + a = RPythonAnnotator() + s = a.build_types(snippet.propagation_of_fresh_instances_through_attrs, [int]) + assert s is not None + def g(n): return [0,1,2,n] From pedronis at codespeak.net Wed Mar 2 01:49:46 2005 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Wed, 2 Mar 2005 01:49:46 +0100 (MET) Subject: [pypy-svn] r9576 - pypy/dist/goal Message-ID: <20050302004946.40DE527B3B@code1.codespeak.net> Author: pedronis Date: Wed Mar 2 01:49:46 2005 New Revision: 9576 Modified: pypy/dist/goal/translate_pypy0.py Log: update this goal setup Modified: pypy/dist/goal/translate_pypy0.py ============================================================================== --- pypy/dist/goal/translate_pypy0.py (original) +++ pypy/dist/goal/translate_pypy0.py Wed Mar 2 01:49:46 2005 @@ -52,15 +52,8 @@ # caches (as far as analyzing the entry_point is concerned) from pypy.interpreter import pycode - from pypy.interpreter import pyopcode - from pypy.interpreter import nestedscope - from pypy.interpreter import generator - - for comb in ((),(nestedscope.PyNestedScopeFrame,),(generator.GeneratorFrame,),(nestedscope.PyNestedScopeFrame,generator.GeneratorFrame)): - F = pyopcode.PyInterpFrame - for x in comb: - F = pycode.enhanceclass(F, x) - #print F.__mro__ + + pycode.setup_frame_classes() t = Translator(entry_point, verbose=True, simplifying=True) if listen_port: From pedronis at codespeak.net Wed Mar 2 14:33:52 2005 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Wed, 2 Mar 2005 14:33:52 +0100 (MET) Subject: [pypy-svn] r9580 - in pypy/dist/pypy: annotation objspace/flow translator translator/tool Message-ID: <20050302133352.0595B27B40@code1.codespeak.net> Author: pedronis Date: Wed Mar 2 14:33:52 2005 New Revision: 9580 Modified: pypy/dist/pypy/annotation/factory.py pypy/dist/pypy/annotation/unaryop.py pypy/dist/pypy/objspace/flow/model.py pypy/dist/pypy/translator/annrpython.py pypy/dist/pypy/translator/tool/make_dot.py Log: attach more info to BlockedInference exceptions more uniform printing of flow positions put @xxx info also the graphs, to ease finding blocked inference blocks in them Modified: pypy/dist/pypy/annotation/factory.py ============================================================================== --- pypy/dist/pypy/annotation/factory.py (original) +++ pypy/dist/pypy/annotation/factory.py Wed Mar 2 14:33:52 2005 @@ -15,14 +15,25 @@ """This exception signals the type inference engine that the situation is currently blocked, and that it should try to progress elsewhere.""" - def __init__(self): + def __init__(self, info=None): try: + self.annotator = getbookkeeper().annotator self.break_at = getbookkeeper().position_key except AttributeError: self.break_at = None + self.info = info def __repr__(self): - return "" %(self.break_at,) + if self.info: + info = "[%s]" % self.info + else: + info = "" + if not self.break_at: + break_at = "?" + else: + break_at = self.annotator.whereami(self.break_at) + return "" %(break_at, info) + __str__ = __repr__ Modified: pypy/dist/pypy/annotation/unaryop.py ============================================================================== --- pypy/dist/pypy/annotation/unaryop.py (original) +++ pypy/dist/pypy/annotation/unaryop.py Wed Mar 2 14:33:52 2005 @@ -162,15 +162,18 @@ def currentdef(ins): if ins.revision != ins.classdef.revision: - #print ins.revision, ins.classdef.revision - raise BlockedInference + raise BlockedInference(info="stale inst of %s" % ins.classdef.cls) return ins.classdef def getattr(ins, s_attr): if s_attr.is_constant() and isinstance(s_attr.const, str): attr = s_attr.const #print 'getattr:', ins, attr, ins.classdef.revision - s_result = ins.currentdef().find_attribute(attr).getvalue() + try: + s_result = ins.currentdef().find_attribute(attr).getvalue() + except BlockedInference, blocked: + blocked.info = "%s .%s" % (blocked.info, attr) + raise blocked # we call this because it might raise BlockedInference if # the above line caused generalization. ins.currentdef() @@ -180,7 +183,11 @@ def setattr(ins, s_attr, s_value): if s_attr.is_constant() and isinstance(s_attr.const, str): attr = s_attr.const - clsdef = ins.currentdef().locate_attribute(attr) + try: + clsdef = ins.currentdef().locate_attribute(attr) + except BlockedInference, blocked: + blocked.info = "%s .%s" % (blocked.info, attr) + raise blocked attrdef = clsdef.attrs[attr] attrdef.readonly = False Modified: pypy/dist/pypy/objspace/flow/model.py ============================================================================== --- pypy/dist/pypy/objspace/flow/model.py (original) +++ pypy/dist/pypy/objspace/flow/model.py Wed Mar 2 14:33:52 2005 @@ -69,6 +69,12 @@ self.exc_handler = False # block at the start of exception handling code + def at(self): + if self.operations: + return "@%d" % self.operations[0].offset + else: + return "" + def __str__(self): if self.operations: txt = "block@%d" % self.operations[0].offset Modified: pypy/dist/pypy/translator/annrpython.py ============================================================================== --- pypy/dist/pypy/translator/annrpython.py (original) +++ pypy/dist/pypy/translator/annrpython.py Wed Mar 2 14:33:52 2005 @@ -143,7 +143,7 @@ import traceback print '-+' * 30 print 'BLOCKED block at:', - print self.why_not_annotated[block][1].break_at + print self.whereami(self.why_not_annotated[block][1].break_at) print 'because of:' traceback.print_exception(*self.why_not_annotated[block]) print '-+' * 30 @@ -185,11 +185,11 @@ cause_history.append(self.binding_caused_by[arg]) self.bindings[arg] = s_value if annmodel.DEBUG: - #if arg in self.return_bindings: - # ansi_print("%s -> %s" % (self.whereami((self.return_bindings[arg], - # None, None)), - # s_value), - # esc="1") # bold + if arg in self.return_bindings: + ansi_print("%s -> %s" % (self.whereami((self.return_bindings[arg], + None, None)), + s_value), + esc="1") # bold if arg in self.return_bindings and s_value == annmodel.SomeObject(): ansi_print("*** WARNING: %s result degenerated to SomeObject" % @@ -333,7 +333,15 @@ else: name = 'UNKNOWN' firstlineno = -1 - return "(%s:%d) %s" % (mod, firstlineno, name) + blk = "" + if block: + at = block.at() + if at: + blk = " block"+at + opid="" + if i is not None: + opid = " op=%d" % i + return "(%s:%d) %s%s%s" % (mod, firstlineno, name, blk, opid) def flowin(self, fn, block): #print 'Flowing', block, [self.binding(a) for a in block.inputargs] @@ -422,7 +430,7 @@ if resultcell is None: resultcell = annmodel.SomeImpossibleValue() # no return value elif resultcell == annmodel.SomeImpossibleValue(): - raise BlockedInference # the operation cannot succeed + raise BlockedInference(info=op) # the operation cannot succeed assert isinstance(resultcell, annmodel.SomeObject) assert isinstance(op.result, Variable) self.setbinding(op.result, resultcell) # bind resultcell to op.result Modified: pypy/dist/pypy/translator/tool/make_dot.py ============================================================================== --- pypy/dist/pypy/translator/tool/make_dot.py (original) +++ pypy/dist/pypy/translator/tool/make_dot.py Wed Mar 2 14:33:52 2005 @@ -141,7 +141,7 @@ eh = 'EH' else: eh = '' - data = "%s(%s %s)\\ninputargs: %s\\n\\n" % (name, block.__class__.__name__, eh, iargs) + data = "%s%s(%s %s)\\ninputargs: %s\\n\\n" % (name, block.at(), block.__class__.__name__, eh, iargs) if block.operations and self.func: maxoffs = max([op.offset for op in block.operations]) if maxoffs >= 0: From pedronis at codespeak.net Wed Mar 2 16:10:44 2005 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Wed, 2 Mar 2005 16:10:44 +0100 (MET) Subject: [pypy-svn] r9584 - in pypy/dist/pypy/annotation: . test Message-ID: <20050302151044.77F3827B47@code1.codespeak.net> Author: pedronis Date: Wed Mar 2 16:10:44 2005 New Revision: 9584 Modified: pypy/dist/pypy/annotation/model.py pypy/dist/pypy/annotation/test/test_model.py pypy/dist/pypy/annotation/unaryop.py Log: try at a more precise contains, consider revisions too. this makes the failing test pass. But it exposes to the possibility of infinite cycles of rev increments, I have an example that shows that. To solve that we likely need a contains that can separate cases where only revs are involved, from other possibilities. And be more careful about triggering rev increments. Modified: pypy/dist/pypy/annotation/model.py ============================================================================== --- pypy/dist/pypy/annotation/model.py (original) +++ pypy/dist/pypy/annotation/model.py Wed Mar 2 16:10:44 2005 @@ -63,10 +63,23 @@ def fmt_knowntype(self, t): return t.__name__ - - def contains(self, other): - return self == other or pair(self, other).union() == self + def contains(self, other): + if self == other: + return True + if self.__class__ == other.__class__: + return self.hom_contains(other) + s_union = pair(self, other).union() + if s_union.__class__ != self.__class__: + return False + if s_union == self: + return True + return self.hom_contains(s_union) + + # default hom_contains, hom_contains can assume self.__class__ == other.__class__ + def hom_contains(self, other): + return pair(self, other).union() == self + def is_constant(self): return hasattr(self, 'const') @@ -128,6 +141,9 @@ self.factories = factories self.s_item = s_item # general enough for any element + def hom_contains(self, other): + return self.s_item.contains(other.s_item) + class SomeSlice(SomeObject): knowntype = slice @@ -136,6 +152,11 @@ self.stop = stop self.step = step + def hom_contains(self, other): + return (self.start.contains(other.start) and + self.stop.contains(other.stop) and + self.step.contains(other.step)) + class SomeTuple(SomeObject): "Stands for a tuple of known length." @@ -148,6 +169,17 @@ else: self.const = tuple([i.const for i in items]) + def hom_contains(self, other): + self_items = self.items + other_items = other.items + if len(self.items) != len(self.items): + return False + for i1, i2 in zip(self_items, other_items): + if not i1.contains(i2): + return False + return True + + class SomeDict(SomeObject): "Stands for a dict." @@ -157,6 +189,9 @@ self.s_key = s_key self.s_value = s_value + def hom_contains(self, other): + return self.s_key.contains(other.s_key) and self.s_value.contains(other.s_value) + class SomeIterator(SomeObject): "Stands for an iterator returning objects of a known type." @@ -164,6 +199,8 @@ def __init__(self, s_item=SomeObject()): self.s_item = s_item + def hom_contains(self, other): + return self.s_item.contains(other.s_item) class SomeInstance(SomeObject): "Stands for an instance of a (user-defined) class." @@ -176,6 +213,11 @@ def fmt_classdef(self, cd): return cd.cls.__name__ + def hom_contains(self, other): + if self.classdef is other.classdef: + return self.revision >= other.revision + return self.classdef.commonbase(other.classdef) is self.classdef + def new_or_old_class(c): if hasattr(c, '__class__'): return c.__class__ @@ -239,6 +281,9 @@ self.analyser = analyser self.s_self = s_self + def hom_contains(self, other): + return self.analyser == other.analyser and (not self.s_self or self.s_self.contains(other.s_self)) + class SomeImpossibleValue(SomeObject): """The empty set. Instances are placeholders for objects that Modified: pypy/dist/pypy/annotation/test/test_model.py ============================================================================== --- pypy/dist/pypy/annotation/test/test_model.py (original) +++ pypy/dist/pypy/annotation/test/test_model.py Wed Mar 2 16:10:44 2005 @@ -9,10 +9,12 @@ s4 = SomeList({}, SomeTuple([SomeInteger(nonneg=True), SomeString()])) s5 = SomeList({}, SomeTuple([SomeInteger(nonneg=False), SomeString()])) s6 = SomeImpossibleValue() -slist = [s1,s2,s3,s4,s5,s6] +s7 = SomeInteger(nonneg=True) +s7.const = 7 +slist = [s1,s2,s3,s4,s5,s6, s7] def test_equality(): - assert s1 != s2 != s3 != s4 != s5 != s6 + assert s1 != s2 != s3 != s4 != s5 != s6 != s7 assert s1 == SomeObject() assert s2 == SomeInteger(nonneg=True) assert s3 == SomeInteger(nonneg=False) @@ -20,23 +22,26 @@ assert s5 == SomeList({}, SomeTuple([SomeInteger(nonneg=False), SomeString()])) assert s6 == SomeImpossibleValue() + def test_contains(): assert ([(s,t) for s in slist for t in slist if s.contains(t)] == - [(s1,s1), (s1,s2), (s1,s3), (s1,s4), (s1,s5), (s1,s6), - (s2,s2), (s2,s6), - (s3,s2), (s3,s3), (s3,s6), + [(s1,s1), (s1,s2), (s1,s3), (s1,s4), (s1,s5), (s1,s6), (s1,s7), + (s2,s2), (s2,s6), (s2,s7), + (s3,s2), (s3,s3), (s3,s6), (s3,s7), (s4,s4), (s4,s6), (s5,s4), (s5,s5), (s5,s6), - (s6,s6)]) + (s6,s6), + (s7,s6), (s7, s7)]) def test_union(): assert ([unionof(s,t) for s in slist for t in slist] == - [s1, s1, s1, s1, s1, s1, - s1, s2, s3, s1, s1, s2, - s1, s3, s3, s1, s1, s3, - s1, s1, s1, s4, s5, s4, - s1, s1, s1, s5, s5, s5, - s1, s2, s3, s4, s5, s6]) + [s1, s1, s1, s1, s1, s1, s1, + s1, s2, s3, s1, s1, s2, s2, + s1, s3, s3, s1, s1, s3, s3, + s1, s1, s1, s4, s5, s4, s1, + s1, s1, s1, s5, s5, s5, s1, + s1, s2, s3, s4, s5, s6, s7, + s1, s2, s3, s1, s1, s7, s7]) def test_commonbase_simple(): class A0: Modified: pypy/dist/pypy/annotation/unaryop.py ============================================================================== --- pypy/dist/pypy/annotation/unaryop.py (original) +++ pypy/dist/pypy/annotation/unaryop.py Wed Mar 2 16:10:44 2005 @@ -199,13 +199,13 @@ raise BlockedInference return - def contains(self, other): - # override the default contains() to ignore revision numbers - if self == other: - return True - s_union = pair(self, other).union() - return (isinstance(s_union, SomeInstance) and - s_union.classdef is self.classdef) + #def contains(self, other): + # # override the default contains() to ignore revision numbers + # if self == other: + # return True + # s_union = pair(self, other).union() + # return (isinstance(s_union, SomeInstance) and + # s_union.classdef is self.classdef) class __extend__(SomeBuiltin): From arigo at codespeak.net Wed Mar 2 19:00:30 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Wed, 2 Mar 2005 19:00:30 +0100 (MET) Subject: [pypy-svn] r9589 - in pypy/dist/pypy: objspace/flow translator Message-ID: <20050302180030.CEF1E27B40@code1.codespeak.net> Author: arigo Date: Wed Mar 2 19:00:30 2005 New Revision: 9589 Modified: pypy/dist/pypy/objspace/flow/framestate.py pypy/dist/pypy/objspace/flow/model.py pypy/dist/pypy/objspace/flow/objspace.py pypy/dist/pypy/translator/annrpython.py pypy/dist/pypy/translator/gencl.py pypy/dist/pypy/translator/genpyrex.py Log: Cleaned up the UndefinedConstant subclass of Constant. Replaced it with Constant(undefined_value). This is a follow-up on the removal of UNDEFINED in the interpreter. Modified: pypy/dist/pypy/objspace/flow/framestate.py ============================================================================== --- pypy/dist/pypy/objspace/flow/framestate.py (original) +++ pypy/dist/pypy/objspace/flow/framestate.py Wed Mar 2 19:00:30 2005 @@ -10,7 +10,7 @@ data = [] for w in state.getfastscope(): if w is None: - data.append(UNDEFINED) + data.append(Constant(undefined_value)) else: data.append(w) data.extend(state.valuestack.items) @@ -43,7 +43,7 @@ recursively_unflatten(frame.space, data) fastscope = [] for w in data[:fastlocals]: - if w is UNDEFINED: + if isinstance(w, Constant) and w.value is undefined_value: fastscope.append(None) else: fastscope.append(w) Modified: pypy/dist/pypy/objspace/flow/model.py ============================================================================== --- pypy/dist/pypy/objspace/flow/model.py (original) +++ pypy/dist/pypy/objspace/flow/model.py Wed Mar 2 19:00:30 2005 @@ -201,15 +201,6 @@ flags = '' return '(%s%s)' % (r, flags) -class UndefinedConstant(Constant): - def __init__(self): - Constant.__init__(self,object()) - - def __repr__(self): - return '(*undefined*)' - -UNDEFINED = UndefinedConstant() - class SpaceOperation: def __init__(self, opname, args, result): self.opname = opname # operation name @@ -232,14 +223,14 @@ def __repr__(self): return "%r = %s(%s)" % (self.result, self.opname, ", ".join(map(repr, self.args))) -class Atom: - "NOT_RPYTHON" +class Atom(object): def __init__(self, name): self.name = name def __repr__(self): return self.name last_exception = Atom('last_exception') last_exc_value = Atom('last_exc_value') +undefined_value= Atom('*undefined*') # if Block().exitswitch == Constant(last_exception), it means that we are # interested in catching the exception that the *last operation* of the # block could raise. The exitcases of the links are None for no exception Modified: pypy/dist/pypy/objspace/flow/objspace.py ============================================================================== --- pypy/dist/pypy/objspace/flow/objspace.py (original) +++ pypy/dist/pypy/objspace/flow/objspace.py Wed Mar 2 19:00:30 2005 @@ -108,7 +108,7 @@ return self.do_operation('newslice', w_start, w_stop, w_step) def wrap(self, obj): - if isinstance(obj, (Variable, Constant)) and obj is not UNDEFINED: + if isinstance(obj, (Variable, Constant)): raise TypeError("already wrapped: " + repr(obj)) # method-wrapper have ill-defined comparison and introspection # to appear in a flow graph Modified: pypy/dist/pypy/translator/annrpython.py ============================================================================== --- pypy/dist/pypy/translator/annrpython.py (original) +++ pypy/dist/pypy/translator/annrpython.py Wed Mar 2 19:00:30 2005 @@ -6,7 +6,7 @@ from pypy.annotation.model import pair from pypy.annotation.factory import ListFactory, DictFactory, BlockedInference from pypy.annotation.bookkeeper import Bookkeeper -from pypy.objspace.flow.model import Variable, Constant, UndefinedConstant +from pypy.objspace.flow.model import Variable, Constant, undefined_value from pypy.objspace.flow.model import SpaceOperation, FunctionGraph from pypy.objspace.flow.model import last_exception, last_exc_value @@ -165,9 +165,9 @@ return None else: raise - elif isinstance(arg, UndefinedConstant): # undefined local variables - return annmodel.SomeImpossibleValue() elif isinstance(arg, Constant): + if arg.value is undefined_value: # undefined local variables + return annmodel.SomeImpossibleValue() assert not arg.value is last_exception and not arg.value is last_exc_value return self.bookkeeper.immutablevalue(arg.value) else: Modified: pypy/dist/pypy/translator/gencl.py ============================================================================== --- pypy/dist/pypy/translator/gencl.py (original) +++ pypy/dist/pypy/translator/gencl.py Wed Mar 2 19:00:30 2005 @@ -298,7 +298,7 @@ target = link.target.inputargs print "(psetq", # parallel assignment for s, t in zip(source, target): - if s != t and not isinstance(s, UndefinedConstant): + if s != t and s != Constant(undefined_value): print self.str(t), self.str(s), print ")" self.emit_jump(link.target) Modified: pypy/dist/pypy/translator/genpyrex.py ============================================================================== --- pypy/dist/pypy/translator/genpyrex.py (original) +++ pypy/dist/pypy/translator/genpyrex.py Wed Mar 2 19:00:30 2005 @@ -4,7 +4,7 @@ """ from pypy.interpreter.baseobjspace import ObjSpace from pypy.interpreter.argument import Arguments -from pypy.objspace.flow.model import Variable, Constant, UndefinedConstant +from pypy.objspace.flow.model import Variable, Constant, undefined_value from pypy.objspace.flow.model import mkentrymap, last_exception from pypy.translator.annrpython import RPythonAnnotator from pypy.annotation.model import SomePBC @@ -403,10 +403,10 @@ sourceargs = link.args targetargs = block.inputargs assert len(sourceargs) == len(targetargs) - # get rid of identity-assignments and assignments of UndefinedConstant + # get rid of identity-assignments and assignments of undefined_value sargs, targs = [], [] for s,t in zip(sourceargs, targetargs): - if s != t and not isinstance(s, UndefinedConstant): + if s != t and s != Constant(undefined_value): sargs.append(s) targs.append(t) if sargs: From pedronis at codespeak.net Wed Mar 2 19:40:07 2005 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Wed, 2 Mar 2005 19:40:07 +0100 (MET) Subject: [pypy-svn] r9590 - in pypy/dist/pypy: annotation annotation/test translator/test Message-ID: <20050302184007.95BF027B42@code1.codespeak.net> Author: pedronis Date: Wed Mar 2 19:40:07 2005 New Revision: 9590 Modified: pypy/dist/pypy/annotation/classdef.py pypy/dist/pypy/annotation/model.py pypy/dist/pypy/annotation/test/test_model.py pypy/dist/pypy/annotation/unaryop.py pypy/dist/pypy/translator/test/snippet.py pypy/dist/pypy/translator/test/test_annrpython.py Log: don't bump classdef revision number if only a fresher revision in an attribute is involved, notice that we still reflow even in this case. contains logic modified to let caller distinguish this situation, RevDiff (a false value) is returned if the only reason for a false contains relationship is rev numbers. without these changes the new test analysing make_eo would recurse infinititely. Modified: pypy/dist/pypy/annotation/classdef.py ============================================================================== --- pypy/dist/pypy/annotation/classdef.py (original) +++ pypy/dist/pypy/annotation/classdef.py Wed Mar 2 19:40:07 2005 @@ -4,7 +4,7 @@ from __future__ import generators from types import FunctionType -from pypy.annotation.model import SomeImpossibleValue, unionof +from pypy.annotation.model import SomeImpossibleValue, unionof, RevDiff class Attribute: @@ -118,12 +118,25 @@ def _generalize_attr(self, attr, s_value): # first remove the attribute from subclasses -- including us! subclass_attrs = [] + was_here = attr in self.attrs for subdef in self.getallsubdefs(): if attr in subdef.attrs: subclass_attrs.append(subdef.attrs[attr]) del subdef.attrs[attr] - # bump the revision number of this class and all subclasses - subdef.revision += 1 + + bump = True + # don't bump if the only cause is rev diff discrepancies + if was_here and len(subclass_attrs) == 1 and s_value is not None: + old_attr = subclass_attrs[0] + wasgeneralenough = old_attr.s_value.contains(s_value) + assert not wasgeneralenough + if wasgeneralenough is RevDiff: + bump = False + + if bump: + # bump the revision number of this class and all subclasses + for subdef in self.getallsubdefs(): + subdef.revision += 1 # do the generalization newattr = Attribute(attr, self.bookkeeper) @@ -140,11 +153,16 @@ def generalize_attr(self, attr, s_value=None): # if the attribute exists in a superclass, generalize there. + found = 0 for clsdef in self.getmro(): if attr in clsdef.attrs: - clsdef._generalize_attr(attr, s_value) - else: + if found == 0: + clsdef._generalize_attr(attr, s_value) + found += 1 + if found == 0: self._generalize_attr(attr, s_value) + else: + assert found == 1, "generalization itself should prevent this" def about_attribute(self, name): for cdef in self.getmro(): Modified: pypy/dist/pypy/annotation/model.py ============================================================================== --- pypy/dist/pypy/annotation/model.py (original) +++ pypy/dist/pypy/annotation/model.py Wed Mar 2 19:40:07 2005 @@ -39,6 +39,31 @@ DEBUG = True # set to False to disable recording of debugging information +# weak false, for contains in the case of SomeInstance revision differences + +class _RevDiff(object): + def __nonzero__(self): + return False + + def __repr__(self): + return "RevDiff" + +RevDiff = _RevDiff() + +# False contains_and RevDiff = False +# RevDiff contains_and False = False +# RevDiff contains_and True = RevDiff +# True contains_and RevDiff = RevDiff + +def contains_and(*args): + if False in args: + return False + if RevDiff in args: + return RevDiff + assert args == (True,) * len(args) + return True + + class SomeObject: """The set of all objects. Each instance stands for an arbitrary object about which nothing is known.""" @@ -77,6 +102,7 @@ return self.hom_contains(s_union) # default hom_contains, hom_contains can assume self.__class__ == other.__class__ + # IMPORTANT: use contains_and or equivalent in here def hom_contains(self, other): return pair(self, other).union() == self @@ -153,9 +179,9 @@ self.step = step def hom_contains(self, other): - return (self.start.contains(other.start) and - self.stop.contains(other.stop) and - self.step.contains(other.step)) + return contains_and(self.start.contains(other.start), + self.stop.contains(other.stop), + self.step.contains(other.step)) class SomeTuple(SomeObject): @@ -174,11 +200,7 @@ other_items = other.items if len(self.items) != len(self.items): return False - for i1, i2 in zip(self_items, other_items): - if not i1.contains(i2): - return False - return True - + return contains_and(*[i1.contains(i2) for i1,i2 in zip(self_items, other_items)]) class SomeDict(SomeObject): @@ -190,7 +212,8 @@ self.s_value = s_value def hom_contains(self, other): - return self.s_key.contains(other.s_key) and self.s_value.contains(other.s_value) + return contains_and(self.s_key.contains(other.s_key), + self.s_value.contains(other.s_value)) class SomeIterator(SomeObject): @@ -215,7 +238,10 @@ def hom_contains(self, other): if self.classdef is other.classdef: - return self.revision >= other.revision + if self.revision >= other.revision: + return True + else: + return RevDiff return self.classdef.commonbase(other.classdef) is self.classdef def new_or_old_class(c): @@ -282,7 +308,11 @@ self.s_self = s_self def hom_contains(self, other): - return self.analyser == other.analyser and (not self.s_self or self.s_self.contains(other.s_self)) + if self.analyser != other.analyser: + return False + if self.s_self is None: + return other.s_self is None + return self.s_self.contains(other.s_self) class SomeImpossibleValue(SomeObject): Modified: pypy/dist/pypy/annotation/test/test_model.py ============================================================================== --- pypy/dist/pypy/annotation/test/test_model.py (original) +++ pypy/dist/pypy/annotation/test/test_model.py Wed Mar 2 19:40:07 2005 @@ -31,7 +31,108 @@ (s4,s4), (s4,s6), (s5,s4), (s5,s5), (s5,s6), (s6,s6), - (s7,s6), (s7, s7)]) + (s7,s6), (s7,s7)]) + + +def test_contains_more(): + from pypy.annotation import bookkeeper + bk = bookkeeper.Bookkeeper(None) + class C: + pass + C_classdef = bk.getclassdef(C) + si1 = SomeInstance(C_classdef) + C_classdef.revision += 1 + si2 = SomeInstance(C_classdef) + + assert s1.contains(si1) + assert si1.contains(si1) + assert si1.contains(s6) + + assert si2.contains(si1) + assert not si1.contains(si2) + assert si1.contains(si2) is RevDiff + + # dicts + + sd1 = SomeDict({}, SomeString(), s1) + sd6 = SomeDict({}, SomeString(), s6) + sdi1 = SomeDict({}, SomeString(), si1) + sdi2 = SomeDict({}, SomeString(), si2) + sdi3 = SomeDict({}, SomeInteger(), si1) + + assert sd1.contains(sdi1) + assert sdi1.contains(sdi1) + assert sdi1.contains(sd6) + + assert sdi2.contains(sdi1) + assert not sdi1.contains(sdi2) + assert sdi1.contains(sdi2) is RevDiff + + assert not sdi1.contains(sdi3) + assert sdi1.contains(sdi3) is False + assert not sdi3.contains(sdi1) + assert sdi3.contains(sdi1) is False + + sdx = SomeDict({}, si1, SomeString()) + sdy = SomeDict({}, si2, SomeString()) + + assert sdy.contains(sdx) + assert not sdx.contains(sdy) + assert sdx.contains(sdy) is RevDiff + + sdz = SomeDict({}, si1, SomeInteger()) + + assert not sdz.contains(sdx) + assert not sdx.contains(sdz) + assert sdz.contains(sdx) is False + assert sdx.contains(sdz) is False + + # tuples + + st1 = SomeTuple((SomeString(), s1)) + st6 = SomeTuple((SomeString(), s6)) + sti1 = SomeTuple((SomeString(), si1)) + sti2 = SomeTuple((SomeString(), si2)) + sti3 = SomeTuple((SomeInteger(), si1)) + + assert st1.contains(sti1) + assert sti1.contains(sti1) + assert sti1.contains(st6) + + assert sti2.contains(sti1) + assert not sti1.contains(sti2) + assert sti1.contains(sti2) is RevDiff + + assert not sti1.contains(sti3) + assert sti1.contains(sti3) is False + assert not sti3.contains(sti1) + assert sti3.contains(sti1) is False + + stx = SomeTuple((si1, SomeString())) + sty = SomeTuple((si2, SomeString())) + + assert sty.contains(stx) + assert not stx.contains(sty) + assert stx.contains(sty) is RevDiff + + stz = SomeTuple((si1, SomeInteger())) + + assert not stz.contains(stx) + assert not stx.contains(stz) + assert stz.contains(stx) is False + assert stx.contains(stz) is False + + C_classdef.revision += 1 + si3 = SomeInstance(C_classdef) + + sti12 = SomeTuple((si1,si2)) + sti23 = SomeTuple((si2,si3)) + + assert sti23.contains(sti12) + assert not sti12.contains(sti23) + assert sti12.contains(sti23) is RevDiff + + def test_union(): assert ([unionof(s,t) for s in slist for t in slist] == Modified: pypy/dist/pypy/annotation/unaryop.py ============================================================================== --- pypy/dist/pypy/annotation/unaryop.py (original) +++ pypy/dist/pypy/annotation/unaryop.py Wed Mar 2 19:40:07 2005 @@ -194,6 +194,7 @@ # if the attrdef is new, this must fail if attrdef.getvalue().contains(s_value): return + # create or update the attribute in clsdef clsdef.generalize_attr(attr, s_value) raise BlockedInference Modified: pypy/dist/pypy/translator/test/snippet.py ============================================================================== --- pypy/dist/pypy/translator/test/snippet.py (original) +++ pypy/dist/pypy/translator/test/snippet.py Wed Mar 2 19:40:07 2005 @@ -913,3 +913,46 @@ def propagation_of_fresh_instances_through_attrs(x): e = EC() e.enter(x) + +# same involving recursion + + +class R: + def __init__(self, n): + if n>0: + self.r = R(n-1) + else: + self.r = None + self.n = n + if self.r: + self.m = self.r.n + else: + self.m = -1 + +def make_r(n): + return R(n) + +class B: + pass + +class Even(B): + def __init__(self,n): + if n > 0: + self.x = [Odd(n-1)] + self.y = self.x[0].x + else: + self.x = [] + self.y = [] + +class Odd(B): + def __init__(self,n): + self.x = [Even(n-1)] + self.y = self.x[0].x + +def make_eo(n): + if n%2 == 0: + return Even(n) + else: + return Odd(n) + + Modified: pypy/dist/pypy/translator/test/test_annrpython.py ============================================================================== --- pypy/dist/pypy/translator/test/test_annrpython.py (original) +++ pypy/dist/pypy/translator/test/test_annrpython.py Wed Mar 2 19:40:07 2005 @@ -530,7 +530,29 @@ a = RPythonAnnotator() s = a.build_types(snippet.propagation_of_fresh_instances_through_attrs, [int]) assert s is not None + + def test_propagation_of_fresh_instances_through_attrs_rec_0(self): + a = RPythonAnnotator() + s = a.build_types(snippet.make_r, [int]) + assert s.knowntype == snippet.R + Rdef = a.getuserclasses()[snippet.R] + assert Rdef.attrs['r'].s_value.knowntype == snippet.R + assert Rdef.attrs['n'].s_value.knowntype == int + assert Rdef.attrs['m'].s_value.knowntype == int + + def test_propagation_of_fresh_instances_through_attrs_rec_eo(self): + a = RPythonAnnotator() + s = a.build_types(snippet.make_eo, [int]) + assert s.knowntype == snippet.B + Even_def = a.getuserclasses()[snippet.Even] + Odd_def = a.getuserclasses()[snippet.Odd] + assert Even_def.attrs['x'].s_value.s_item.knowntype == snippet.Odd + assert Even_def.attrs['y'].s_value.s_item.knowntype == snippet.Even + assert Odd_def.attrs['x'].s_value.s_item.knowntype == snippet.Even + assert Odd_def.attrs['y'].s_value.s_item.knowntype == snippet.Odd + + def g(n): return [0,1,2,n] From tismer at codespeak.net Thu Mar 3 00:16:29 2005 From: tismer at codespeak.net (tismer at codespeak.net) Date: Thu, 3 Mar 2005 00:16:29 +0100 (MET) Subject: [pypy-svn] r9591 - pypy/dist/pypy/translator Message-ID: <20050302231629.CFC4527B36@code1.codespeak.net> Author: tismer Date: Thu Mar 3 00:16:29 2005 New Revision: 9591 Added: pypy/dist/pypy/translator/gensupp.py Log: start of a generic support module for genxxx Added: pypy/dist/pypy/translator/gensupp.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/gensupp.py Thu Mar 3 00:16:29 2005 @@ -0,0 +1,159 @@ +""" +Some support for genxxx implementations of source generators. +Another name could be genEric, but well... +""" + +from __future__ import generators + +import sys + +from pypy.objspace.flow.model import Block +from pypy.objspace.flow.model import traverse + +# ordering the blocks of a graph by source position + +def ordered_blocks(graph): + # collect all blocks + allblocks = [] + def visit(block): + if isinstance(block, Block): + # first we order by offset in the code string + if block.operations: + ofs = block.operations[0].offset + else: + ofs = sys.maxint + # then we order by input variable name or value + if block.inputargs: + txt = str(block.inputargs[0]) + else: + txt = "dummy" + allblocks.append((ofs, txt, block)) + traverse(visit, graph) + allblocks.sort() + #for ofs, txt, block in allblocks: + # print ofs, txt, block + return [block for ofs, txt, block in allblocks] + +# a unique list, similar to a list. +# append1 appends an object only if it is not there,already. + +class UniqueList(list): + def __init__(self, *args, **kwds): + list.__init__(self, *args, **kwds) + self.dic = {} + + def append1(self, arg): + try: + self.dic[arg] + except KeyError: + self.dic[arg] = 1 + list.append(self, arg) + except TypeError: # not hashable + if arg not in self: + list.append(self, arg) + +def builtin_base(obj): + typ = type(obj) + while typ.__module__ != '__builtin__': + typ = typ.__base__ + return typ + +def c_string(s): + return '"%s"' % (s.replace('\\', '\\\\').replace('"', '\"'),) + +def uniquemodulename(name, SEEN={}): + # never reuse the same module name within a Python session! + i = 0 + while True: + i += 1 + result = '%s_%d' % (name, i) + if result not in SEEN: + SEEN[result] = True + return result + +# a translation table suitable for str.translate() to remove +# non-C characters from an identifier +C_IDENTIFIER = ''.join([(('0' <= chr(i) <= '9' or + 'a' <= chr(i) <= 'z' or + 'A' <= chr(i) <= 'Z') and chr(i) or '_') + for i in range(256)]) + +# a name manager knows about all global and local names in the +# program and keeps them disjoint. It provides ways to generate +# shorter local names with and without wrapping prefixes, +# while always keeping all globals visible. + +class NameManager(object): + def __init__(self): + self.seennames = {} + self.scope = 0 + self.scopelist = [] + + def make_reserved_names(self, txt): + """add names to list of known names. If one exists already, + then we raise an exception. This function should be called + before generating any new names.""" + for name in txt.split(): + if name in self.seennames: + raise NameError, "%s has already been seen!" + self.seennames[name] = 1 + + def uniquename(self, basename): + basename = basename.translate(C_IDENTIFIER) + n = self.seennames.get(basename, 0) + self.seennames[basename] = n+1 + if basename in ('v', 'w_'): + if n == 0: + return '%s%d' % (basename, n) + else: + return self.uniquename('%s%d' % (basename, n)) + if n == 0: + return basename + else: + return self.uniquename('%s_%d' % (basename, n)) + + def localScope(self, parent=None): + ret = _LocalScope(self, parent) + while ret.scope >= len(self.scopelist): + self.scopelist.append({}) + return ret + +class _LocalScope(object): + """track local names without hiding globals or nested locals""" + def __init__(self, glob, parent): + self.glob = glob + if not parent: + parent = glob + self.parent = parent + self.mapping = {} + self.usednames = {} + self.scope = parent.scope + 1 + + def uniquename(self, basename): + basename = basename.translate(C_IDENTIFIER) + glob = self.glob + p = self.usednames.get(basename, 0) + self.usednames[basename] = p+1 + namesbyscope = glob.scopelist[self.scope] + namelist = namesbyscope.setdefault(basename, []) + if p == len(namelist): + namelist.append(glob.uniquename(basename)) + return namelist[p] + + def localname(self, name, wrapped=False): + """modify and mangle local names""" + if name in self.mapping: + return self.mapping[name] + scorepos = name.rfind("_") + if name.startswith("v") and name[1:].isdigit(): + basename = ('v', 'w_') [wrapped] + elif scorepos >= 0 and name[scorepos+1:].isdigit(): + basename = name[:scorepos] + if wrapped: + basename = "w_" + basename + else: + basename = name + ret = self.uniquename(basename) + self.mapping[name] = ret + return ret + From tismer at codespeak.net Thu Mar 3 00:19:34 2005 From: tismer at codespeak.net (tismer at codespeak.net) Date: Thu, 3 Mar 2005 00:19:34 +0100 (MET) Subject: [pypy-svn] r9592 - pypy/dist/pypy/translator Message-ID: <20050302231934.88F8D27B44@code1.codespeak.net> Author: tismer Date: Thu Mar 3 00:19:34 2005 New Revision: 9592 Modified: pypy/dist/pypy/translator/genc.py pypy/dist/pypy/translator/geninterplevel.py pypy/dist/pypy/translator/translator.py Log: we seem to produce quite nice and short names now Modified: pypy/dist/pypy/translator/genc.py ============================================================================== --- pypy/dist/pypy/translator/genc.py (original) +++ pypy/dist/pypy/translator/genc.py Thu Mar 3 00:19:34 2005 @@ -13,34 +13,18 @@ from pypy.annotation import model as annmodel from types import FunctionType, CodeType, InstanceType, ClassType +from pypy.translator.gensupp import ordered_blocks, UniqueList, builtin_base, \ + c_string, uniquemodulename, C_IDENTIFIER, NameManager + from pypy.objspace.std.restricted_int import r_int, r_uint # ____________________________________________________________ -def c_string(s): - return '"%s"' % (s.replace('\\', '\\\\').replace('"', '\"'),) - -def uniquemodulename(name, SEEN={}): - # never reuse the same module name within a Python session! - i = 0 - while True: - i += 1 - result = '%s_%d' % (name, i) - if result not in SEEN: - SEEN[result] = True - return result - #def go_figure_out_this_name(source): # # ahem # return 'PyRun_String("%s", Py_eval_input, PyEval_GetGlobals(), NULL)' % ( # source, ) -def builtin_base(obj): - typ = type(obj) - while typ.__module__ != '__builtin__': - typ = typ.__base__ - return typ - class GenC: MODNAMES = {} @@ -61,15 +45,19 @@ 'Py_False = False', 'Py_True = True', ] - # just a few predefined names which cannot be reused. - # I think this should come from some external file, - # if we want to be complete - self.reserved_names = {} - for each in 'typedef static void const'.split(): - self.reserved_names[each] = 1 + self.latercode = [] # list of generators generating extra lines # for later in initxxx() -- for recursive # objects + self.namespace= NameManager() + # just a few predefined names which cannot be reused. + # I think this should come from some external file, + # if we want to be complete + self.namespace.make_reserved_names('typedef static void const') + # these names are used in function headers, + # therefore pseudo-preserved in scope 1: + self.namespace.make_reserved_names('self args kwds') + self.globaldecl = [] self.globalobjects = [] self.pendingfunctions = [] @@ -107,15 +95,10 @@ return name def uniquename(self, basename): - basename = basename.translate(C_IDENTIFIER) - n = self.seennames.get(basename, 0) - self.seennames[basename] = n+1 - if n == 0: - self.globalobjects.append(basename) - self.globaldecl.append('static PyObject *%s;' % (basename,)) - return basename - else: - return self.uniquename('%s_%d' % (basename, n)) + name = self.namespace.uniquename(basename) + self.globalobjects.append(basename) + self.globaldecl.append('static PyObject *%s;' % (basename,)) + return name def initcode_python(self, name, pyexpr): # generate init code that will evaluate the given Python expression @@ -540,8 +523,8 @@ ## func.__name__) f = self.f - localvars = {} - body = list(self.cfunction_body(func, localvars)) + localscope = self.namespace.localScope() + body = list(self.cfunction_body(func, localscope)) name_of_defaults = [self.nameof(x, debug=('Default argument of', func)) for x in (func.func_defaults or ())] self.gen_global_declarations() @@ -558,7 +541,7 @@ if isinstance(node, Block): localslst.extend(node.getvariables()) traverse(visit, graph) - localnames = [self.expr(a, localvars) for a in uniqueitems(localslst)] + localnames = [self.expr(a, localscope) for a in uniqueitems(localslst)] # collect all the arguments if func.func_code.co_flags & CO_VARARGS: @@ -569,9 +552,10 @@ positional_args = graph.getargs() min_number_of_args = len(positional_args) - len(name_of_defaults) - fast_args = [self.expr(a, localvars) for a in positional_args] + fast_args = [self.expr(a, localscope) for a in positional_args] if vararg is not None: - fast_args.append(str(vararg)) + vararg = self.expr(vararg, localscope) + fast_args.append(vararg) fast_name = 'fast' + f_name fast_set = dict(zip(fast_args, fast_args)) @@ -630,7 +614,7 @@ tail = '\n\t\tFUNCTION_RETURN(NULL)' for i in range(len(name_of_defaults)): print >> f, '\t%s = %s;' % ( - self.expr(positional_args[min_number_of_args+i], localvars), + self.expr(positional_args[min_number_of_args+i], localscope), name_of_defaults[i]) fmt = 'O'*min_number_of_args if min_number_of_args < len(positional_args): @@ -639,7 +623,7 @@ '"%s:%s"' % (fmt, func.__name__), 'kwlist', ] - lst += ['&' + self.expr(a, localvars) for a in positional_args] + lst += ['&' + self.expr(a, localscope) for a in positional_args] print >> f, '\tif (!PyArg_ParseTupleAndKeywords(%s))' % ', '.join(lst), print >> f, tail @@ -662,7 +646,7 @@ # generate an incref for each input argument for v in positional_args: - print >> f, '\tPy_INCREF(%s);' % self.expr(v, localvars) + print >> f, '\tPy_INCREF(%s);' % self.expr(v, localscope) # print the body for line in body: @@ -683,48 +667,16 @@ del self.translator.flowgraphs[func] Variable.instances.clear() - def expr(self, v, localnames, wrapped = False): - # this function is copied from geninterp just with a different default. - # the purpose is to generate short local names. - # This is intermediate. Common code will be extracted into a base class. + def expr(self, v, localscope): if isinstance(v, Variable): - n = v.name - # there is a problem at the moment. - # use the name as is until this is solved - return v.name - if n.startswith("v") and n[1:].isdigit(): - ret = localnames.get(v.name) - if not ret: - if wrapped: - localnames[v.name] = ret = "w_%d" % len(localnames) - else: - localnames[v.name] = ret = "v%d" % len(localnames) - return ret - scorepos = n.rfind("_") - if scorepos >= 0 and n[scorepos+1:].isdigit(): - name = n[:scorepos] - # do individual numbering on named vars - thesenames = localnames.setdefault(name, {}) - ret = thesenames.get(v.name) - if not ret: - if wrapped: - fmt = "w_%s_%d" - else: - fmt = "%s_%d" - # don't use zero - if len(thesenames) == 0 and name not in self.reserved_names: - fmt = fmt[:-3] - thesenames[v.name] = ret = fmt % name - else: - thesenames[v.name] = ret = fmt % (name, len(thesenames)) - return ret + return localscope.localname(v.name) elif isinstance(v, Constant): return self.nameof(v.value, debug=('Constant in the graph of', self.currentfunc)) else: raise TypeError, "expr(%r)" % (v,) - def cfunction_body(self, func, localvars): + def cfunction_body(self, func, localscope): graph = self.translator.getflowgraph(func) remove_direct_loops(graph) checkgraph(graph) @@ -737,18 +689,18 @@ has_ref = {} linklocalvars = linklocalvars or {} for v in to_release: - linklocalvars[v] = self.expr(v, localvars) + linklocalvars[v] = self.expr(v, localscope) has_ref = linklocalvars.copy() for a1, a2 in zip(link.args, link.target.inputargs): if a1 in linklocalvars: src = linklocalvars[a1] else: - src = self.expr(a1, localvars) - line = 'MOVE(%s, %s)' % (src, self.expr(a2, localvars)) + src = self.expr(a1, localscope) + line = 'MOVE(%s, %s)' % (src, self.expr(a2, localscope)) if a1 in has_ref: del has_ref[a1] else: - line += '\tPy_INCREF(%s);' % self.expr(a2, localvars) + line += '\tPy_INCREF(%s);' % self.expr(a2, localscope) yield line for v in has_ref: yield 'Py_DECREF(%s);' % linklocalvars[v] @@ -767,8 +719,8 @@ yield 'block%d:' % blocknum[block] to_release = list(block.inputargs) for op in block.operations: - lst = [self.expr(v, localvars) for v in op.args] - lst.append(self.expr(op.result, localvars)) + lst = [self.expr(v, localscope) for v in op.args] + lst.append(self.expr(op.result, localscope)) lst.append('err%d_%d' % (blocknum[block], len(to_release))) macro = 'OP_%s' % op.opname.upper() meth = getattr(self, macro, None) @@ -782,13 +734,13 @@ if len(block.exits) == 0: if len(block.inputargs) == 2: # exc_cls, exc_value # exceptional return block - exc_cls = self.expr(block.inputargs[0], localvars) - exc_value = self.expr(block.inputargs[1], localvars) + exc_cls = self.expr(block.inputargs[0], localscope) + exc_value = self.expr(block.inputargs[1], localscope) yield 'PyErr_Restore(%s, %s, NULL);' % (exc_cls, exc_value) yield 'FUNCTION_RETURN(NULL)' else: # regular return block - retval = self.expr(block.inputargs[0], localvars) + retval = self.expr(block.inputargs[0], localscope) yield 'FUNCTION_RETURN(%s)' % retval continue elif block.exitswitch is None: @@ -831,13 +783,13 @@ # block ending in a switch on a value for link in block.exits[:-1]: yield 'if (EQ_%s(%s)) {' % (link.exitcase, - self.expr(block.exitswitch, localvars)) + self.expr(block.exitswitch, localscope)) for op in gen_link(link): yield '\t' + op yield '}' link = block.exits[-1] yield 'assert(EQ_%s(%s));' % (link.exitcase, - self.expr(block.exitswitch, localvars)) + self.expr(block.exitswitch, localscope)) for op in gen_link(block.exits[-1]): yield op yield '' @@ -845,7 +797,7 @@ while to_release: v = to_release.pop() if err_reachable: - yield 'ERR_DECREF(%s)' % self.expr(v, localvars) + yield 'ERR_DECREF(%s)' % self.expr(v, localscope) yield 'err%d_%d:' % (blocknum[block], len(to_release)) err_reachable = True if err_reachable: @@ -924,9 +876,3 @@ else: return ('%s %s' % (type, name)).rstrip() -# a translation table suitable for str.translate() to remove -# non-C characters from an identifier -C_IDENTIFIER = ''.join([(('0' <= chr(i) <= '9' or - 'a' <= chr(i) <= 'z' or - 'A' <= chr(i) <= 'Z') and chr(i) or '_') - for i in range(256)]) Modified: pypy/dist/pypy/translator/geninterplevel.py ============================================================================== --- pypy/dist/pypy/translator/geninterplevel.py (original) +++ pypy/dist/pypy/translator/geninterplevel.py Thu Mar 3 00:19:34 2005 @@ -38,81 +38,25 @@ from pypy.tool.sourcetools import render_docstr +from pypy.translator.gensupp import ordered_blocks, UniqueList, builtin_base, \ + c_string, uniquemodulename, C_IDENTIFIER, NameManager + import pypy # __path__ import py.path # ____________________________________________________________ -def c_string(s): - return '"%s"' % (s.replace('\\', '\\\\').replace('"', '\"'),) - -def uniquemodulename(name, SEEN={}): - # never reuse the same module name within a Python session! - i = 0 - while True: - i += 1 - result = '%s_%d' % (name, i) - if result not in SEEN: - SEEN[result] = True - return result - -def ordered_blocks(graph): - # collect all blocks - allblocks = [] - def visit(block): - if isinstance(block, Block): - # first we order by offset in the code string - if block.operations: - ofs = block.operations[0].offset - else: - ofs = sys.maxint - # then we order by input variable name or value - if block.inputargs: - txt = str(block.inputargs[0]) - else: - txt = "dummy" - allblocks.append((ofs, txt, block)) - traverse(visit, graph) - allblocks.sort() - #for ofs, txt, block in allblocks: - # print ofs, txt, block - return [block for ofs, txt, block in allblocks] - -class UniqueList(list): - def __init__(self, *args, **kwds): - list.__init__(self, *args, **kwds) - self.dic = {} - - def append(self, arg): - try: - self.dic[arg] - except KeyError: - self.dic[arg] = 1 - list.append(self, arg) - except TypeError: # not hashable - if arg not in self: - list.append(self, arg) - def appendnew(self, arg): - "always append" - list.append(self, arg) - def eval_helper(self, typename, expr): name = self.uniquename("gtype_%s" % typename) bltinsname = self.nameof('__builtins__') - self.initcode.append( + self.initcode.append1( 'def eval_helper(expr):\n' ' import types\n' ' dic = space.newdict([(%s, space.w_builtins)])\n' ' space.exec_("import types", dic, dic)\n' ' return space.eval(expr, dic, dic)' % bltinsname) - self.initcode.append('m.%s = eval_helper(%r)' % (name, expr)) + self.initcode.append1('m.%s = eval_helper(%r)' % (name, expr)) return name -def builtin_base(obj): - typ = type(obj) - while typ.__module__ != '__builtin__': - typ = typ.__base__ - return typ - class GenRpy: def __init__(self, translator, entrypoint=None, modname=None, moddict=None): self.translator = translator @@ -124,12 +68,12 @@ self.moddict = moddict # the dict if we translate a module def late_OperationError(): - self.initcode.append( + self.initcode.append1( 'from pypy.interpreter.error import OperationError\n' 'm.OperationError = OperationError') return 'OperationError' def late_Arguments(): - self.initcode.append( + self.initcode.append1( 'from pypy.interpreter.argument import Arguments\n' 'm.Arguments = Arguments') return 'Arguments' @@ -140,15 +84,13 @@ Constant(OperationError).key: late_OperationError, Constant(Arguments).key: late_Arguments, } - self.seennames = {} u = UniqueList self.initcode = u() # list of lines for the module's initxxx() self.latercode = u() # list of generators generating extra lines # for later in initxxx() -- for recursive # objects - # this can stay empty, because we cannot have used a reserved - # name as a variable in the same language. But see genc.py - self.reserved_names = {} + self.namespace = NameManager() + self.namespace.make_reserved_names('__doc__ __args__ space goto') self.globaldecl = [] self.globalobjects = [] self.pendingfunctions = [] @@ -168,46 +110,20 @@ self._space_arities = None - def expr(self, v, localnames, wrapped = True): + def expr(self, v, localscope, wrapped = True): if isinstance(v, Variable): - n = v.name - if n.startswith("v") and n[1:].isdigit(): - ret = localnames.get(v.name) - if not ret: - if wrapped: - localnames[v.name] = ret = "w_%d" % len(localnames) - else: - localnames[v.name] = ret = "v%d" % len(localnames) - return ret - scorepos = n.rfind("_") - if scorepos >= 0 and n[scorepos+1:].isdigit(): - name = n[:scorepos] - # do individual numbering on named vars - thesenames = localnames.setdefault(name, {}) - ret = thesenames.get(v.name) - if not ret: - if wrapped: - fmt = "w_%s_%d" - else: - fmt = "%s_%d" - # don't use zero - if len(thesenames) == 0 and v.name not in self.reserved_names: - fmt = fmt[:-3] - thesenames[v.name] = ret = fmt % name - else: - thesenames[v.name] = ret = fmt % (name, len(thesenames)) - return ret + return localscope.localname(v.name, wrapped) elif isinstance(v, Constant): return self.nameof(v.value, debug=('Constant in the graph of', self.currentfunc)) else: raise TypeError, "expr(%r)" % (v,) - def arglist(self, args, localnames): - res = [self.expr(arg, localnames) for arg in args] + def arglist(self, args, localscope): + res = [self.expr(arg, localscope) for arg in args] return ", ".join(res) - def oper(self, op, localnames): + def oper(self, op, localscope): if op.opname == "simple_call": v = op.args[0] space_shortcut = self.try_space_shortcut_for_builtin(v, len(op.args)-1) @@ -216,7 +132,7 @@ exv = space_shortcut fmt = "%(res)s = %(func)s(%(args)s)" else: - exv = self.expr(v, localnames) + exv = self.expr(v, localscope) # default for a spacecall: fmt = "%(res)s = space.call_function(%(func)s, %(args)s)" # see if we can optimize for a fast call. @@ -228,22 +144,22 @@ func.func_defaults is None): fmt = "%(res)s = fastf_%(func)s(space, %(args)s)" exv = exv[6:] - return fmt % {"res" : self.expr(op.result, localnames), + return fmt % {"res" : self.expr(op.result, localscope), "func": exv, - "args": self.arglist(op.args[1:], localnames) } + "args": self.arglist(op.args[1:], localscope) } if op.opname == "call_args": v = op.args[0] - exv = self.expr(v, localnames) + exv = self.expr(v, localscope) self.nameof(Arguments) # trigger init fmt = ( "_args = Arguments.fromshape(space, %(shape)s, [%(data_w)s])\n" "%(res)s = space.call_args(%(func)s, _args)") assert isinstance(op.args[1], Constant) shape = op.args[1].value - return fmt % {"res": self.expr(op.result, localnames), + return fmt % {"res": self.expr(op.result, localscope), "func": exv, "shape": repr(shape), - "data_w": self.arglist(op.args[2:], localnames) } + "data_w": self.arglist(op.args[2:], localscope) } if op.opname in self.has_listarg: fmt = "%s = %s([%s])" else: @@ -251,8 +167,8 @@ # special case is_true wrapped = op.opname != "is_true" oper = "space.%s" % op.opname - return fmt % (self.expr(op.result, localnames, wrapped), oper, - self.arglist(op.args, localnames)) + return fmt % (self.expr(op.result, localscope, wrapped), oper, + self.arglist(op.args, localscope)) def large_assignment(self, left, right, margin=65): expr = "(%s) = (%s)" % (", ".join(left), ", ".join(right)) @@ -283,16 +199,16 @@ if self.specialize_goto: lbname = self._labeltable.get(blocknum) if not lbname: - self.initcode.append( + self.initcode.append1( 'from pypy.objspace.flow.framestate import SpecTag') lbname = self.uniquename("glabel_%d" % blocknum) self._labeltable[blocknum] = lbname - self.initcode.append('m.%s = SpecTag()' % lbname) + self.initcode.append1('m.%s = SpecTag()' % lbname) return lbname else: return repr(blocknum) - def gen_link(self, link, localvars, blocknum, block, linklocalvars=None): + def gen_link(self, link, localscope, blocknum, block, linklocalvars=None): "Generate the code to jump across the given Link." linklocalvars = linklocalvars or {} left, right = [], [] @@ -300,8 +216,8 @@ if a1 in linklocalvars: src = linklocalvars[a1] else: - src = self.expr(a1, localvars) - left.append(self.expr(a2, localvars)) + src = self.expr(a1, localscope) + left.append(self.expr(a2, localscope)) right.append(src) if left: # anything at all? txt = "%s = %s" % (", ".join(left), ", ".join(right)) @@ -357,15 +273,10 @@ return name def uniquename(self, basename): - basename = basename.translate(C_IDENTIFIER) - n = self.seennames.get(basename, 0) - self.seennames[basename] = n+1 - if n == 0: - self.globalobjects.append(basename) - self.globaldecl.append('# global object %s' % (basename,)) - return basename - else: - return self.uniquename('%s_%d' % (basename, n)) + name = self.namespace.uniquename(basename) + self.globalobjects.append(name) + self.globaldecl.append('# global object %s' % (name,)) + return name def nameof_NotImplementedType(self, value): return "space.w_NotImplemented" @@ -374,10 +285,10 @@ if type(value) is not object: # try to just wrap it? name = self.uniquename('g_%sinst_%r' % (type(value).__name__, value)) - self.initcode.append('m.%s = space.wrap(%r)' % (name, value)) + self.initcode.append1('m.%s = space.wrap(%r)' % (name, value)) return name name = self.uniquename('g_object') - self.initcode.appendnew('_tup = space.newtuple([])\n' + self.initcode.append('_tup = space.newtuple([])\n' 'm.%s = space.call(space.w_object, _tup)' % name) return name @@ -389,8 +300,8 @@ value.__file__.endswith('.pyo')), \ "%r is not a builtin module (probably :)"%value name = self.uniquename('mod_%s' % value.__name__) - self.initcode.append('import %s as _tmp' % value.__name__) - self.initcode.append('m.%s = space.wrap(_tmp)' % (name)) + self.initcode.append1('import %s as _tmp' % value.__name__) + self.initcode.append1('m.%s = space.wrap(_tmp)' % (name)) return name @@ -402,7 +313,7 @@ # the prefixbefore the initial '_' for easy postprocessing name = 'gi_minus_%d' % abs(value) name = self.uniquename(name) - self.initcode.append('m.%s = space.newint(%d)' % (name, value)) + self.initcode.append1('m.%s = space.newint(%d)' % (name, value)) return name def nameof_long(self, value): @@ -421,7 +332,7 @@ # the prefix before the initial '_' name = 'glong_minus_%d' % abs(value) name = self.uniquename(name) - self.initcode.append('m.%s = space.wrap(%s) # XXX implement long!' % (name, s)) + self.initcode.append1('m.%s = space.wrap(%s) # XXX implement long!' % (name, s)) return name def nameof_float(self, value): @@ -429,7 +340,7 @@ name = (name.replace('-', 'minus') .replace('.', 'dot')) name = self.uniquename(name) - self.initcode.append('m.%s = space.newfloat(%r)' % (name, value)) + self.initcode.append1('m.%s = space.newfloat(%r)' % (name, value)) return name def nameof_str(self, value): @@ -442,9 +353,9 @@ if not namestr: namestr = "_emptystr_" name = self.uniquename('gs_' + namestr[:32]) - # self.initcode.append('m.%s = space.newstring(%r)' % (name, value)) + # self.initcode.append1('m.%s = space.newstring(%r)' % (name, value)) # ick! very unhandy - self.initcode.append('m.%s = space.wrap(%r)' % (name, value)) + self.initcode.append1('m.%s = space.wrap(%r)' % (name, value)) return name def skipped_function(self, func): @@ -452,7 +363,7 @@ # that raises an exception when called. name = self.uniquename('gskippedfunc_' + func.__name__) self.globaldecl.append('# global decl %s' % (name, )) - self.initcode.append('# build func %s' % name) + self.initcode.append1('# build func %s' % name) return name def skipped_class(self, cls): @@ -460,7 +371,7 @@ # that raises an exception when called. name = self.uniquename('gskippedclass_' + cls.__name__) self.globaldecl.append('# global decl %s' % (name, )) - self.initcode.append('# build class %s' % name) + self.initcode.append1('# build class %s' % name) return name def trans_funcname(self, s): @@ -486,8 +397,8 @@ name = self.uniquename('gfunc_' + self.trans_funcname( namehint + func.__name__)) f_name = 'f_' + name[6:] - self.initcode.append('from pypy.interpreter import gateway') - self.initcode.append('m.%s = space.wrap(gateway.interp2app(%s, unwrap_spec=[gateway.ObjSpace, gateway.Arguments]))' % (name, f_name)) + self.initcode.append1('from pypy.interpreter import gateway') + self.initcode.append1('m.%s = space.wrap(gateway.interp2app(%s, unwrap_spec=[gateway.ObjSpace, gateway.Arguments]))' % (name, f_name)) self.pendingfunctions.append(func) return name @@ -496,7 +407,7 @@ func = sm.__get__(42.5) name = self.uniquename('gsm_' + func.__name__) functionname = self.nameof(func) - self.initcode.append('m.%s = space.wrap(%s)' % (name, functionname)) + self.initcode.append1('m.%s = space.wrap(%s)' % (name, functionname)) return name def nameof_instancemethod(self, meth): @@ -509,7 +420,7 @@ typ = self.nameof(meth.im_class) name = self.uniquename('gmeth_' + meth.im_func.__name__) funcname = self.nameof(meth.im_func.__name__) - self.initcode.append( + self.initcode.append1( '%s = space.getattr(%s, %s)' % (name, ob, funcname)) return name @@ -527,7 +438,7 @@ return False def later(self, gen): - self.latercode.append((gen, self.debugstack)) + self.latercode.append1((gen, self.debugstack)) def nameof_instance(self, instance): klass = instance.__class__ @@ -551,7 +462,7 @@ print >> sys.stderr, "Problem while generating %s of %r" % ( name, instance) raise - self.initcode.append("m.%s = space.call_method(%s, '__new__', %s)" % ( + self.initcode.append1("m.%s = space.call_method(%s, '__new__', %s)" % ( name, cls, cls)) self.later(initinstance()) return name @@ -588,7 +499,7 @@ else: raise Exception, '%r not found in any built-in module' % (func,) if modname == '__builtin__': - #self.initcode.append('m.%s = space.getattr(space.w_builtin, %s)'% ( + #self.initcode.append1('m.%s = space.getattr(space.w_builtin, %s)'% ( # name, self.nameof(func.__name__))) # be lazy return "(space.builtin.get(space.str_w(%s)))" % self.nameof(func.__name__) @@ -599,12 +510,12 @@ print ("WARNING: accessing builtin modules different from sys or __builtin__" " is likely producing non-sense: %s %s" % (module.__name__, func.__name__)) name = self.uniquename('gbltin_' + func.__name__) - self.initcode.append('m.%s = space.getattr(%s, %s)' % ( + self.initcode.append1('m.%s = space.getattr(%s, %s)' % ( name, self.nameof(module), self.nameof(func.__name__))) else: # builtin (bound) method name = self.uniquename('gbltinmethod_' + func.__name__) - self.initcode.append('m.%s = space.getattr(%s, %s)' % ( + self.initcode.append1('m.%s = space.getattr(%s, %s)' % ( name, self.nameof(func.__self__), self.nameof(func.__name__))) return name @@ -654,22 +565,22 @@ name, self.nameof(key), self.nameof(value)) baseargs = ", ".join(basenames) - self.initcode.appendnew('_dic = space.newdict([])') + self.initcode.append('_dic = space.newdict([])') for key, value in cls.__dict__.items(): if key.startswith('__'): if key in ['__module__', '__metaclass__', '__slots__','__new__']: keyname = self.nameof(key) valname = self.nameof(value) - self.initcode.appendnew("space.setitem(_dic, %s, %s)" % ( + self.initcode.append("space.setitem(_dic, %s, %s)" % ( keyname, valname)) if cls.__doc__ is not None: sdoc = self.nameof("__doc__") docstr = render_docstr(cls, "_doc = space.wrap(", ")") - self.initcode.append((docstr,)) # not splitted - self.initcode.appendnew("space.setitem(_dic, %s, _doc)" % ( + self.initcode.append1((docstr,)) # not splitted + self.initcode.append("space.setitem(_dic, %s, _doc)" % ( self.nameof("__doc__"),)) - self.initcode.append('_bases = space.newtuple([%(bases)s])\n' + self.initcode.append1('_bases = space.newtuple([%(bases)s])\n' '_args = space.newtuple([%(name)s, _bases, _dic])\n' 'm.%(klass)s = space.call(%(meta)s, _args)' % {"bases": baseargs, @@ -743,7 +654,7 @@ name = self.uniquename('g%dtuple' % len(tup)) args = [self.nameof(x) for x in tup] args = ', '.join(args) - self.initcode.append('m.%s = space.newtuple([%s])' % (name, args)) + self.initcode.append1('m.%s = space.newtuple([%s])' % (name, args)) return name def nameof_list(self, lis): @@ -753,8 +664,8 @@ item = self.nameof(lis[i]) yield 'space.setitem(%s, %s, %s);' % ( name, self.nameof(i), item) - self.initcode.append('m.%s = space.newlist([space.w_None])' % (name,)) - self.initcode.append('m.%s = space.mul(%s, %s)' % (name, name, self.nameof(len(lis)))) + self.initcode.append1('m.%s = space.newlist([space.w_None])' % (name,)) + self.initcode.append1('m.%s = space.mul(%s, %s)' % (name, name, self.nameof(len(lis)))) self.later(initlist()) return name @@ -767,7 +678,7 @@ for k in dic: yield ('space.setitem(%s, %s, %s)'%( name, self.nameof(k), self.nameof(dic[k]))) - self.initcode.append('m.%s = space.newdict([])' % (name,)) + self.initcode.append1('m.%s = space.newdict([])' % (name,)) self.later(initdict()) return name @@ -778,7 +689,7 @@ md.__objclass__.__name__, md.__name__)) cls = self.nameof(md.__objclass__) # do I need to take the dict and then getitem??? - self.initcode.append('m.%s = space.getattr(%s, %s)' % + self.initcode.append1('m.%s = space.getattr(%s, %s)' % (name, cls, self.nameof(md.__name__))) return name nameof_getset_descriptor = nameof_member_descriptor @@ -864,8 +775,7 @@ # make sure it is not rendered again key = Constant(doc).key self.rpynames[key] = "__doc__" - self.seennames["__doc__"] = 1 - self.initcode.append("m.__doc__ = space.wrap(m.__doc__)") + self.initcode.append1("m.__doc__ = space.wrap(m.__doc__)") # function implementations while self.pendingfunctions or self.latercode: if self.pendingfunctions: @@ -877,7 +787,7 @@ gen, self.debugstack = self.latercode.pop() #self.initcode.extend(gen) -- eats TypeError! bad CPython! for line in gen: - self.initcode.append(line) + self.initcode.append1(line) self.debugstack = () self.gen_global_declarations() @@ -921,7 +831,7 @@ del g[:] g = self.globalobjects for name in g: - pass # self.initcode.append('# REGISTER_GLOBAL(%s)' % (name,)) + pass # self.initcode.append1('# REGISTER_GLOBAL(%s)' % (name,)) del g[:] def rel_filename(self, name): @@ -945,8 +855,8 @@ func.func_code.co_name, func.func_code.co_firstlineno) print >> f, "##SECTION##" - localvars = {} - body = list(self.rpyfunction_body(func, localvars)) + localscope = self.namespace.localScope() + body = list(self.rpyfunction_body(func, localscope)) name_of_defaults = [self.nameof(x, debug=('Default argument of', func)) for x in (func.func_defaults or ())] self.gen_global_declarations() @@ -964,7 +874,7 @@ if isinstance(node, Block): localslst.extend(node.getvariables()) traverse(visit, graph) - localnames = [self.expr(a, localvars) for a in uniqueitems(localslst)] + localnames = [self.expr(a, localscope) for a in uniqueitems(localslst)] # collect all the arguments vararg = varkw = None @@ -981,11 +891,13 @@ varargname = func.func_code.co_varnames[p] positional_args = all_args[:p] - fast_args = [self.expr(a, localvars) for a in positional_args] + fast_args = [self.expr(a, localscope) for a in positional_args] if vararg is not None: - fast_args.append(self.expr(vararg, localvars)) + vararg = self.expr(vararg, localscope) + fast_args.append(vararg) if varkw is not None: - fast_args.append(self.expr(varkw, localvars)) + varkw = self.expr(varkw, localscope) + fast_args.append(varkw) fast_name = 'fast' + f_name fast_set = dict(zip(fast_args, fast_args)) @@ -1004,7 +916,7 @@ if dic.get(name): yield 'del %s # hiding a builtin!' % name else: - self.initcode.append('del m.%s' % (name,)) + self.initcode.append1('del m.%s' % (name,)) print >> f, 'def %s(space, __args__):' % (name,) if docstr is not None: @@ -1067,7 +979,7 @@ del self.translator.flowgraphs[func] Variable.instances.clear() - def rpyfunction_body(self, func, localvars): + def rpyfunction_body(self, func, localscope): try: graph = self.translator.getflowgraph(func) except Exception, e: @@ -1102,37 +1014,37 @@ regular_op = len(block.operations) - catch_exception # render all but maybe the last op for op in block.operations[:regular_op]: - for line in self.oper(op, localvars).split("\n"): + for line in self.oper(op, localscope).split("\n"): yield "%s" % line # render the last op if it is exception handled for op in block.operations[regular_op:]: yield "try:" - for line in self.oper(op, localvars).split("\n"): + for line in self.oper(op, localscope).split("\n"): yield " %s" % line if len(block.exits) == 0: if len(block.inputargs) == 2: # exc_cls, exc_value # exceptional return block - exc_cls = self.expr(block.inputargs[0], localvars) - exc_val = self.expr(block.inputargs[1], localvars) + exc_cls = self.expr(block.inputargs[0], localscope) + exc_val = self.expr(block.inputargs[1], localscope) self.nameof(OperationError) # trigger init yield "raise OperationError(%s, %s)" % (exc_cls, exc_val) else: # regular return block - retval = self.expr(block.inputargs[0], localvars) + retval = self.expr(block.inputargs[0], localscope) yield "return %s" % retval return elif block.exitswitch is None: # single-exit block assert len(block.exits) == 1 - for op in self.gen_link(block.exits[0], localvars, blocknum, block): + for op in self.gen_link(block.exits[0], localscope, blocknum, block): yield "%s" % op elif catch_exception: # block catching the exceptions raised by its last operation # we handle the non-exceptional case first link = block.exits[0] assert link.exitcase is None - for op in self.gen_link(link, localvars, blocknum, block): + for op in self.gen_link(link, localscope, blocknum, block): yield " %s" % op # we must catch the exception raised by the last operation, # which goes to the last err%d_%d label written above. @@ -1146,7 +1058,7 @@ yield " %s space.is_true(space.issubtype(e.w_type, %s)):" % (q, self.nameof(link.exitcase)) q = "elif" - for op in self.gen_link(link, localvars, blocknum, block, { + for op in self.gen_link(link, localscope, blocknum, block, { Constant(last_exception): 'e.w_type', Constant(last_exc_value): 'e.w_value'}): yield " %s" % op @@ -1161,17 +1073,17 @@ q = "if" for link in exits[:-1]: yield "%s %s == %s:" % (q, self.expr(block.exitswitch, - localvars), + localscope), link.exitcase) - for op in self.gen_link(link, localvars, blocknum, block): + for op in self.gen_link(link, localscope, blocknum, block): yield " %s" % op q = "elif" link = exits[-1] yield "else:" yield " assert %s == %s" % (self.expr(block.exitswitch, - localvars), + localscope), link.exitcase) - for op in self.gen_link(exits[-1], localvars, blocknum, block): + for op in self.gen_link(exits[-1], localscope, blocknum, block): yield " %s" % op cmpop = ('==', 'is') [self.specialize_goto] @@ -1214,13 +1126,6 @@ print ret ''' -# a translation table suitable for str.translate() to remove -# non-C characters from an identifier -C_IDENTIFIER = ''.join([(('0' <= chr(i) <= '9' or - 'a' <= chr(i) <= 'z' or - 'A' <= chr(i) <= 'Z') and chr(i) or '_') - for i in range(256)]) - # _____________________________________________________________________ ## this should go into some test file Modified: pypy/dist/pypy/translator/translator.py ============================================================================== --- pypy/dist/pypy/translator/translator.py (original) +++ pypy/dist/pypy/translator/translator.py Thu Mar 3 00:19:34 2005 @@ -37,7 +37,8 @@ from pypy.translator.simplify import simplify_graph from pypy.translator.genpyrex import GenPyrex from pypy.translator.gencl import GenCL -from pypy.translator.genc import GenC, uniquemodulename +from pypy.translator.genc import GenC +from pypy.translator.gensupp import uniquemodulename from pypy.translator.tool.buildpyxmodule import make_module_from_pyxstring from pypy.translator.tool.buildpyxmodule import make_module_from_c from pypy.objspace.flow import FlowObjSpace From tismer at codespeak.net Thu Mar 3 00:22:04 2005 From: tismer at codespeak.net (tismer at codespeak.net) Date: Thu, 3 Mar 2005 00:22:04 +0100 (MET) Subject: [pypy-svn] r9593 - pypy/dist/pypy/translator Message-ID: <20050302232204.B949D27B44@code1.codespeak.net> Author: tismer Date: Thu Mar 3 00:22:04 2005 New Revision: 9593 Modified: pypy/dist/pypy/translator/gensupp.py (contents, props changed) Log: eol style Modified: pypy/dist/pypy/translator/gensupp.py ============================================================================== --- pypy/dist/pypy/translator/gensupp.py (original) +++ pypy/dist/pypy/translator/gensupp.py Thu Mar 3 00:22:04 2005 @@ -1,159 +1,159 @@ -""" -Some support for genxxx implementations of source generators. -Another name could be genEric, but well... -""" - -from __future__ import generators - -import sys - -from pypy.objspace.flow.model import Block -from pypy.objspace.flow.model import traverse - -# ordering the blocks of a graph by source position - -def ordered_blocks(graph): - # collect all blocks - allblocks = [] - def visit(block): - if isinstance(block, Block): - # first we order by offset in the code string - if block.operations: - ofs = block.operations[0].offset - else: - ofs = sys.maxint - # then we order by input variable name or value - if block.inputargs: - txt = str(block.inputargs[0]) - else: - txt = "dummy" - allblocks.append((ofs, txt, block)) - traverse(visit, graph) - allblocks.sort() - #for ofs, txt, block in allblocks: - # print ofs, txt, block - return [block for ofs, txt, block in allblocks] - -# a unique list, similar to a list. -# append1 appends an object only if it is not there,already. - -class UniqueList(list): - def __init__(self, *args, **kwds): - list.__init__(self, *args, **kwds) - self.dic = {} - - def append1(self, arg): - try: - self.dic[arg] - except KeyError: - self.dic[arg] = 1 - list.append(self, arg) - except TypeError: # not hashable - if arg not in self: - list.append(self, arg) - -def builtin_base(obj): - typ = type(obj) - while typ.__module__ != '__builtin__': - typ = typ.__base__ - return typ - -def c_string(s): - return '"%s"' % (s.replace('\\', '\\\\').replace('"', '\"'),) - -def uniquemodulename(name, SEEN={}): - # never reuse the same module name within a Python session! - i = 0 - while True: - i += 1 - result = '%s_%d' % (name, i) - if result not in SEEN: - SEEN[result] = True - return result - -# a translation table suitable for str.translate() to remove -# non-C characters from an identifier -C_IDENTIFIER = ''.join([(('0' <= chr(i) <= '9' or - 'a' <= chr(i) <= 'z' or - 'A' <= chr(i) <= 'Z') and chr(i) or '_') - for i in range(256)]) - -# a name manager knows about all global and local names in the -# program and keeps them disjoint. It provides ways to generate -# shorter local names with and without wrapping prefixes, -# while always keeping all globals visible. - -class NameManager(object): - def __init__(self): - self.seennames = {} - self.scope = 0 - self.scopelist = [] - - def make_reserved_names(self, txt): - """add names to list of known names. If one exists already, - then we raise an exception. This function should be called - before generating any new names.""" - for name in txt.split(): - if name in self.seennames: - raise NameError, "%s has already been seen!" - self.seennames[name] = 1 - - def uniquename(self, basename): - basename = basename.translate(C_IDENTIFIER) - n = self.seennames.get(basename, 0) - self.seennames[basename] = n+1 - if basename in ('v', 'w_'): - if n == 0: - return '%s%d' % (basename, n) - else: - return self.uniquename('%s%d' % (basename, n)) - if n == 0: - return basename - else: - return self.uniquename('%s_%d' % (basename, n)) - - def localScope(self, parent=None): - ret = _LocalScope(self, parent) - while ret.scope >= len(self.scopelist): - self.scopelist.append({}) - return ret - -class _LocalScope(object): - """track local names without hiding globals or nested locals""" - def __init__(self, glob, parent): - self.glob = glob - if not parent: - parent = glob - self.parent = parent - self.mapping = {} - self.usednames = {} - self.scope = parent.scope + 1 - - def uniquename(self, basename): - basename = basename.translate(C_IDENTIFIER) - glob = self.glob - p = self.usednames.get(basename, 0) - self.usednames[basename] = p+1 - namesbyscope = glob.scopelist[self.scope] - namelist = namesbyscope.setdefault(basename, []) - if p == len(namelist): - namelist.append(glob.uniquename(basename)) - return namelist[p] - - def localname(self, name, wrapped=False): - """modify and mangle local names""" - if name in self.mapping: - return self.mapping[name] - scorepos = name.rfind("_") - if name.startswith("v") and name[1:].isdigit(): - basename = ('v', 'w_') [wrapped] - elif scorepos >= 0 and name[scorepos+1:].isdigit(): - basename = name[:scorepos] - if wrapped: - basename = "w_" + basename - else: - basename = name - ret = self.uniquename(basename) - self.mapping[name] = ret - return ret - +""" +Some support for genxxx implementations of source generators. +Another name could be genEric, but well... +""" + +from __future__ import generators + +import sys + +from pypy.objspace.flow.model import Block +from pypy.objspace.flow.model import traverse + +# ordering the blocks of a graph by source position + +def ordered_blocks(graph): + # collect all blocks + allblocks = [] + def visit(block): + if isinstance(block, Block): + # first we order by offset in the code string + if block.operations: + ofs = block.operations[0].offset + else: + ofs = sys.maxint + # then we order by input variable name or value + if block.inputargs: + txt = str(block.inputargs[0]) + else: + txt = "dummy" + allblocks.append((ofs, txt, block)) + traverse(visit, graph) + allblocks.sort() + #for ofs, txt, block in allblocks: + # print ofs, txt, block + return [block for ofs, txt, block in allblocks] + +# a unique list, similar to a list. +# append1 appends an object only if it is not there,already. + +class UniqueList(list): + def __init__(self, *args, **kwds): + list.__init__(self, *args, **kwds) + self.dic = {} + + def append1(self, arg): + try: + self.dic[arg] + except KeyError: + self.dic[arg] = 1 + list.append(self, arg) + except TypeError: # not hashable + if arg not in self: + list.append(self, arg) + +def builtin_base(obj): + typ = type(obj) + while typ.__module__ != '__builtin__': + typ = typ.__base__ + return typ + +def c_string(s): + return '"%s"' % (s.replace('\\', '\\\\').replace('"', '\"'),) + +def uniquemodulename(name, SEEN={}): + # never reuse the same module name within a Python session! + i = 0 + while True: + i += 1 + result = '%s_%d' % (name, i) + if result not in SEEN: + SEEN[result] = True + return result + +# a translation table suitable for str.translate() to remove +# non-C characters from an identifier +C_IDENTIFIER = ''.join([(('0' <= chr(i) <= '9' or + 'a' <= chr(i) <= 'z' or + 'A' <= chr(i) <= 'Z') and chr(i) or '_') + for i in range(256)]) + +# a name manager knows about all global and local names in the +# program and keeps them disjoint. It provides ways to generate +# shorter local names with and without wrapping prefixes, +# while always keeping all globals visible. + +class NameManager(object): + def __init__(self): + self.seennames = {} + self.scope = 0 + self.scopelist = [] + + def make_reserved_names(self, txt): + """add names to list of known names. If one exists already, + then we raise an exception. This function should be called + before generating any new names.""" + for name in txt.split(): + if name in self.seennames: + raise NameError, "%s has already been seen!" + self.seennames[name] = 1 + + def uniquename(self, basename): + basename = basename.translate(C_IDENTIFIER) + n = self.seennames.get(basename, 0) + self.seennames[basename] = n+1 + if basename in ('v', 'w_'): + if n == 0: + return '%s%d' % (basename, n) + else: + return self.uniquename('%s%d' % (basename, n)) + if n == 0: + return basename + else: + return self.uniquename('%s_%d' % (basename, n)) + + def localScope(self, parent=None): + ret = _LocalScope(self, parent) + while ret.scope >= len(self.scopelist): + self.scopelist.append({}) + return ret + +class _LocalScope(object): + """track local names without hiding globals or nested locals""" + def __init__(self, glob, parent): + self.glob = glob + if not parent: + parent = glob + self.parent = parent + self.mapping = {} + self.usednames = {} + self.scope = parent.scope + 1 + + def uniquename(self, basename): + basename = basename.translate(C_IDENTIFIER) + glob = self.glob + p = self.usednames.get(basename, 0) + self.usednames[basename] = p+1 + namesbyscope = glob.scopelist[self.scope] + namelist = namesbyscope.setdefault(basename, []) + if p == len(namelist): + namelist.append(glob.uniquename(basename)) + return namelist[p] + + def localname(self, name, wrapped=False): + """modify and mangle local names""" + if name in self.mapping: + return self.mapping[name] + scorepos = name.rfind("_") + if name.startswith("v") and name[1:].isdigit(): + basename = ('v', 'w_') [wrapped] + elif scorepos >= 0 and name[scorepos+1:].isdigit(): + basename = name[:scorepos] + if wrapped: + basename = "w_" + basename + else: + basename = name + ret = self.uniquename(basename) + self.mapping[name] = ret + return ret + From tismer at codespeak.net Thu Mar 3 00:36:38 2005 From: tismer at codespeak.net (tismer at codespeak.net) Date: Thu, 3 Mar 2005 00:36:38 +0100 (MET) Subject: [pypy-svn] r9594 - pypy/dist/pypy/translator Message-ID: <20050302233638.ECF5627B37@code1.codespeak.net> Author: tismer Date: Thu Mar 3 00:36:38 2005 New Revision: 9594 Modified: pypy/dist/pypy/translator/genc.py Log: modulo a small bug... Modified: pypy/dist/pypy/translator/genc.py ============================================================================== --- pypy/dist/pypy/translator/genc.py (original) +++ pypy/dist/pypy/translator/genc.py Thu Mar 3 00:36:38 2005 @@ -96,8 +96,8 @@ def uniquename(self, basename): name = self.namespace.uniquename(basename) - self.globalobjects.append(basename) - self.globaldecl.append('static PyObject *%s;' % (basename,)) + self.globalobjects.append(name) + self.globaldecl.append('static PyObject *%s;' % (name,)) return name def initcode_python(self, name, pyexpr): From arigo at codespeak.net Thu Mar 3 10:50:47 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 3 Mar 2005 10:50:47 +0100 (MET) Subject: [pypy-svn] r9595 - pypy/dist/pypy/translator Message-ID: <20050303095047.CD92427B41@code1.codespeak.net> Author: arigo Date: Thu Mar 3 10:50:47 2005 New Revision: 9595 Modified: pypy/dist/pypy/translator/genc.py Log: The complete list of all C99 keywords. Modified: pypy/dist/pypy/translator/genc.py ============================================================================== --- pypy/dist/pypy/translator/genc.py (original) +++ pypy/dist/pypy/translator/genc.py Thu Mar 3 10:50:47 2005 @@ -50,10 +50,19 @@ # for later in initxxx() -- for recursive # objects self.namespace= NameManager() - # just a few predefined names which cannot be reused. - # I think this should come from some external file, - # if we want to be complete - self.namespace.make_reserved_names('typedef static void const') + # keywords cannot be reused. This is the C99 draft's list. + self.namespace.make_reserved_names(''' + auto enum restrict unsigned + break extern return void + case float short volatile + char for signed while + const goto sizeof _Bool + continue if static _Complex + default inline struct _Imaginary + do int switch + double long typedef + else register union + ''') # these names are used in function headers, # therefore pseudo-preserved in scope 1: self.namespace.make_reserved_names('self args kwds') From pedronis at codespeak.net Thu Mar 3 16:52:33 2005 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Thu, 3 Mar 2005 16:52:33 +0100 (MET) Subject: [pypy-svn] r9603 - in pypy/dist/pypy: annotation translator/test Message-ID: <20050303155233.5B9A727B48@code1.codespeak.net> Author: pedronis Date: Thu Mar 3 16:52:33 2005 New Revision: 9603 Modified: pypy/dist/pypy/annotation/classdef.py pypy/dist/pypy/annotation/model.py pypy/dist/pypy/translator/test/snippet.py pypy/dist/pypy/translator/test/test_annrpython.py Log: use structural comparison to decide when not to bump rev numbers. Modified: pypy/dist/pypy/annotation/classdef.py ============================================================================== --- pypy/dist/pypy/annotation/classdef.py (original) +++ pypy/dist/pypy/annotation/classdef.py Thu Mar 3 16:52:33 2005 @@ -6,6 +6,7 @@ from types import FunctionType from pypy.annotation.model import SomeImpossibleValue, unionof, RevDiff +notyet = object() class Attribute: # readonly-ness @@ -20,8 +21,11 @@ self.s_value = SomeImpossibleValue() self.readonly = True + self.flat = notyet + def getvalue(self): while self.sources: + self.flat = notyet source, classdef = self.sources.popitem() s_value = self.bookkeeper.immutablevalue( source.__dict__[self.name]) @@ -35,6 +39,13 @@ self.sources.update(other.sources) self.s_value = unionof(self.s_value, other.s_value) self.readonly = self.readonly and other.readonly + self.flat = notyet + + def structure(self): + s_value = self.getvalue() + if self.flat is notyet: + self.flat = s_value.structure() + return self.flat class ClassDef: @@ -125,13 +136,19 @@ del subdef.attrs[attr] bump = True + attach_flat = None # don't bump if the only cause is rev diff discrepancies if was_here and len(subclass_attrs) == 1 and s_value is not None: old_attr = subclass_attrs[0] wasgeneralenough = old_attr.s_value.contains(s_value) assert not wasgeneralenough if wasgeneralenough is RevDiff: - bump = False + s_value_struct = s_value.structure() + if not old_attr.flat is notyet: + old_attr_struct = old_attr.structure() + if s_value_struct == old_attr_struct: + bump = False + attach_flat = s_value_struct if bump: # bump the revision number of this class and all subclasses @@ -147,6 +164,9 @@ newattr.merge(subattr) self.attrs[attr] = newattr + if attach_flat is not None: + newattr.flat = attach_flat + # reflow from all factories for position in self.getallinstantiations(): self.bookkeeper.annotator.reflowfromposition(position) Modified: pypy/dist/pypy/annotation/model.py ============================================================================== --- pypy/dist/pypy/annotation/model.py (original) +++ pypy/dist/pypy/annotation/model.py Thu Mar 3 16:52:33 2005 @@ -134,6 +134,23 @@ del set_caused_by_merge + # structural expansion + + def structure(self, memo=None): + if self.is_constant(): + return self.const + if memo is None: + memo = {} + return self._structure(memo) + + def _structure(self, memo): + return self + +class struct(tuple): + def __new__(cls, *args): + return tuple.__new__(cls,args) + + class SomeInteger(SomeObject): "Stands for an object which is known to be an integer." knowntype = int @@ -170,6 +187,9 @@ def hom_contains(self, other): return self.s_item.contains(other.s_item) + def _structure(self, memo): + return struct(list, self.s_item.structure(memo)) + class SomeSlice(SomeObject): knowntype = slice @@ -183,6 +203,14 @@ self.stop.contains(other.stop), self.step.contains(other.step)) + def _structure(self, memo): + return struct(slice, + self.start.structure(memo), + self.stop.structure(memo), + self.step.structure(memo), + ) + + class SomeTuple(SomeObject): "Stands for a tuple of known length." @@ -202,6 +230,10 @@ return False return contains_and(*[i1.contains(i2) for i1,i2 in zip(self_items, other_items)]) + def _structure(self, memo): + return struct(tuple,*[ i.structure(memo) for i in self.items]) + + class SomeDict(SomeObject): "Stands for a dict." @@ -216,6 +248,12 @@ self.s_value.contains(other.s_value)) + def _structure(self, memo): + return struct(dict, + self.s_key.structure(memo), + self.s_value.structure(memo)) + + class SomeIterator(SomeObject): "Stands for an iterator returning objects of a known type." knowntype = type(iter([])) # arbitrarily chose seqiter as the type @@ -225,6 +263,10 @@ def hom_contains(self, other): return self.s_item.contains(other.s_item) + def _structure(self, memo): + return struct(iter, + self.s_item.structure(memo)) + class SomeInstance(SomeObject): "Stands for an instance of a (user-defined) class." def __init__(self, classdef): @@ -244,6 +286,27 @@ return RevDiff return self.classdef.commonbase(other.classdef) is self.classdef + def _classdef_structure(self, classdef, memo): + if classdef is None: + return None + if classdef in memo or classdef.cls.__module__ == '__builtin__': + return struct(classdef) + attr_names = classdef.attrs.keys() + attr_names.sort() + attrs = classdef.attrs + parts = [classdef] + memo[classdef] = None + parts.append(self._classdef_structure(classdef.basedef, memo)) + for name in attr_names: + a = attrs[name] + parts.append((name, a.getvalue().structure(memo))) + strct = struct(*parts) + return strct + + def _structure(self, memo): # xxx try later an approach that can cache classef expansions + return self._classdef_structure(self.classdef, memo) + + def new_or_old_class(c): if hasattr(c, '__class__'): return c.__class__ @@ -314,6 +377,15 @@ return other.s_self is None return self.s_self.contains(other.s_self) + def _structure(self, memo): + if self.s_self: + return struct(len, + self.analyser, + self.s_self.structure(memo)) + else: + return struct(len, + self.analyser) + class SomeImpossibleValue(SomeObject): """The empty set. Instances are placeholders for objects that Modified: pypy/dist/pypy/translator/test/snippet.py ============================================================================== --- pypy/dist/pypy/translator/test/snippet.py (original) +++ pypy/dist/pypy/translator/test/snippet.py Thu Mar 3 16:52:33 2005 @@ -956,3 +956,32 @@ return Odd(n) +# shows that we care about the expanded structure in front of changes to attributes involving only +# instances rev numbers + +class Box: + pass + +class Box2: + pass + +class Box3(Box2): + pass + +def flow_rev_numbers(n): + bx3 = Box3() + bx3.x = 1 + bx = Box() + bx.bx3 = bx3 + if n >0: + z = bx.bx3.x + if n >0: + bx2 = Box2() + bx2.x = 3 + return z + raise Exception + + + + + Modified: pypy/dist/pypy/translator/test/test_annrpython.py ============================================================================== --- pypy/dist/pypy/translator/test/test_annrpython.py (original) +++ pypy/dist/pypy/translator/test/test_annrpython.py Thu Mar 3 16:52:33 2005 @@ -552,6 +552,11 @@ assert Odd_def.attrs['x'].s_value.s_item.knowntype == snippet.Even assert Odd_def.attrs['y'].s_value.s_item.knowntype == snippet.Odd + def test_flow_rev_numbers(self): + a = RPythonAnnotator() + s = a.build_types(snippet.flow_rev_numbers, []) + assert s.knowntype == int + assert not s.is_constant() # ! def g(n): From pedronis at codespeak.net Thu Mar 3 17:10:58 2005 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Thu, 3 Mar 2005 17:10:58 +0100 (MET) Subject: [pypy-svn] r9606 - pypy/dist/pypy/annotation Message-ID: <20050303161058.1B2AC27B53@code1.codespeak.net> Author: pedronis Date: Thu Mar 3 17:10:57 2005 New Revision: 9606 Modified: pypy/dist/pypy/annotation/classdef.py pypy/dist/pypy/annotation/unaryop.py Log: don't block the setattr block if we did not increment the rev number, we may never get there again in that case. Modified: pypy/dist/pypy/annotation/classdef.py ============================================================================== --- pypy/dist/pypy/annotation/classdef.py (original) +++ pypy/dist/pypy/annotation/classdef.py Thu Mar 3 17:10:57 2005 @@ -170,19 +170,22 @@ # reflow from all factories for position in self.getallinstantiations(): self.bookkeeper.annotator.reflowfromposition(position) + return bump def generalize_attr(self, attr, s_value=None): # if the attribute exists in a superclass, generalize there. found = 0 + r = False for clsdef in self.getmro(): if attr in clsdef.attrs: if found == 0: - clsdef._generalize_attr(attr, s_value) + r = clsdef._generalize_attr(attr, s_value) found += 1 if found == 0: - self._generalize_attr(attr, s_value) + return self._generalize_attr(attr, s_value) else: assert found == 1, "generalization itself should prevent this" + return r def about_attribute(self, name): for cdef in self.getmro(): Modified: pypy/dist/pypy/annotation/unaryop.py ============================================================================== --- pypy/dist/pypy/annotation/unaryop.py (original) +++ pypy/dist/pypy/annotation/unaryop.py Thu Mar 3 17:10:57 2005 @@ -196,8 +196,8 @@ return # create or update the attribute in clsdef - clsdef.generalize_attr(attr, s_value) - raise BlockedInference + if clsdef.generalize_attr(attr, s_value): # block only if we bumped a rev number + raise BlockedInference return #def contains(self, other): From pedronis at codespeak.net Thu Mar 3 18:06:34 2005 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Thu, 3 Mar 2005 18:06:34 +0100 (MET) Subject: [pypy-svn] r9611 - pypy/dist/pypy/annotation Message-ID: <20050303170634.5133C27B4C@code1.codespeak.net> Author: pedronis Date: Thu Mar 3 18:06:34 2005 New Revision: 9611 Modified: pypy/dist/pypy/annotation/classdef.py Log: update comment Modified: pypy/dist/pypy/annotation/classdef.py ============================================================================== --- pypy/dist/pypy/annotation/classdef.py (original) +++ pypy/dist/pypy/annotation/classdef.py Thu Mar 3 18:06:34 2005 @@ -138,6 +138,7 @@ bump = True attach_flat = None # don't bump if the only cause is rev diff discrepancies + # and they don't imply any change in our expanded type structure if was_here and len(subclass_attrs) == 1 and s_value is not None: old_attr = subclass_attrs[0] wasgeneralenough = old_attr.s_value.contains(s_value) From pedronis at codespeak.net Thu Mar 3 19:25:41 2005 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Thu, 3 Mar 2005 19:25:41 +0100 (MET) Subject: [pypy-svn] r9614 - pypy/dist/pypy/annotation Message-ID: <20050303182541.A163727B45@code1.codespeak.net> Author: pedronis Date: Thu Mar 3 19:25:41 2005 New Revision: 9614 Modified: pypy/dist/pypy/annotation/unaryop.py Log: remove commented out code, now all contains logic is directly in the classes in model Modified: pypy/dist/pypy/annotation/unaryop.py ============================================================================== --- pypy/dist/pypy/annotation/unaryop.py (original) +++ pypy/dist/pypy/annotation/unaryop.py Thu Mar 3 19:25:41 2005 @@ -200,14 +200,6 @@ raise BlockedInference return - #def contains(self, other): - # # override the default contains() to ignore revision numbers - # if self == other: - # return True - # s_union = pair(self, other).union() - # return (isinstance(s_union, SomeInstance) and - # s_union.classdef is self.classdef) - class __extend__(SomeBuiltin): def simple_call(bltn, *args): From arigo at codespeak.net Fri Mar 4 14:09:50 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 4 Mar 2005 14:09:50 +0100 (MET) Subject: [pypy-svn] r9624 - pypy/branch/annotation-no-rev-num Message-ID: <20050304130950.C3E3F27B61@code1.codespeak.net> Author: arigo Date: Fri Mar 4 14:09:50 2005 New Revision: 9624 Added: pypy/branch/annotation-no-rev-num/ - copied from r9580, pypy/dist/pypy/annotation/ Modified: pypy/branch/annotation-no-rev-num/bookkeeper.py pypy/branch/annotation-no-rev-num/classdef.py pypy/branch/annotation-no-rev-num/model.py pypy/branch/annotation-no-rev-num/unaryop.py Log: A branch to play with revision-number-less annotations. Actually now I wonder why I made a branch, before it took 10 minutes to make it work... Modified: pypy/branch/annotation-no-rev-num/bookkeeper.py ============================================================================== --- pypy/dist/pypy/annotation/bookkeeper.py (original) +++ pypy/branch/annotation-no-rev-num/bookkeeper.py Fri Mar 4 14:09:50 2005 @@ -42,9 +42,6 @@ del getthreadlocals().bookkeeper del self.position_key - def is_in_an_operation(self): - return hasattr(self, 'position_key') - def getfactory(self, factorycls): """Get the Factory associated with the current position, or build it if it doesn't exist yet.""" @@ -146,12 +143,6 @@ elif isinstance(t, (type, ClassType)) and \ t.__module__ != '__builtin__': classdef = self.getclassdef(t) - if self.is_in_an_operation(): - # woha! instantiating a "mutable" SomeXxx like - # SomeInstance is always dangerous, because we need to - # allow reflowing from the current operation if/when - # the classdef later changes. - classdef.instantiation_locations[self.position_key] = True return SomeInstance(classdef) else: o = SomeObject() @@ -173,7 +164,6 @@ "unsupported specialization type '%s'"%(x,) classdef = self.getclassdef(cls) - classdef.instantiation_locations[self.position_key] = True s_instance = SomeInstance(classdef) # flow into __init__() if the class has got one init = getattr(cls, '__init__', None) Modified: pypy/branch/annotation-no-rev-num/classdef.py ============================================================================== --- pypy/dist/pypy/annotation/classdef.py (original) +++ pypy/branch/annotation-no-rev-num/classdef.py Fri Mar 4 14:09:50 2005 @@ -19,6 +19,7 @@ # XXX a SomeImpossibleValue() constant? later!! self.s_value = SomeImpossibleValue() self.readonly = True + self.read_locations = {} def getvalue(self): while self.sources: @@ -35,6 +36,7 @@ self.sources.update(other.sources) self.s_value = unionof(self.s_value, other.s_value) self.readonly = self.readonly and other.readonly + self.read_locations.update(other.read_locations) class ClassDef: @@ -43,8 +45,7 @@ def __init__(self, cls, bookkeeper): self.bookkeeper = bookkeeper self.attrs = {} # {name: Attribute} - self.revision = 0 # which increases the revision number - self.instantiation_locations = {} + #self.instantiation_locations = {} self.cls = cls self.subdefs = {} assert (len(cls.__bases__) <= 1 or @@ -109,11 +110,11 @@ pending.append(sub) seen[sub] = True - def getallinstantiations(self): - locations = {} - for clsdef in self.getallsubdefs(): - locations.update(clsdef.instantiation_locations) - return locations +## def getallinstantiations(self): +## locations = {} +## for clsdef in self.getallsubdefs(): +## locations.update(clsdef.instantiation_locations) +## return locations def _generalize_attr(self, attr, s_value): # first remove the attribute from subclasses -- including us! @@ -122,8 +123,6 @@ if attr in subdef.attrs: subclass_attrs.append(subdef.attrs[attr]) del subdef.attrs[attr] - # bump the revision number of this class and all subclasses - subdef.revision += 1 # do the generalization newattr = Attribute(attr, self.bookkeeper) @@ -135,7 +134,7 @@ self.attrs[attr] = newattr # reflow from all factories - for position in self.getallinstantiations(): + for position in newattr.read_locations: self.bookkeeper.annotator.reflowfromposition(position) def generalize_attr(self, attr, s_value=None): Modified: pypy/branch/annotation-no-rev-num/model.py ============================================================================== --- pypy/dist/pypy/annotation/model.py (original) +++ pypy/branch/annotation-no-rev-num/model.py Fri Mar 4 14:09:50 2005 @@ -170,7 +170,6 @@ def __init__(self, classdef): self.classdef = classdef self.knowntype = classdef.cls - self.revision = classdef.revision def fmt_knowntype(self, kt): return None def fmt_classdef(self, cd): Modified: pypy/branch/annotation-no-rev-num/unaryop.py ============================================================================== --- pypy/dist/pypy/annotation/unaryop.py (original) +++ pypy/branch/annotation-no-rev-num/unaryop.py Fri Mar 4 14:09:50 2005 @@ -160,34 +160,20 @@ class __extend__(SomeInstance): - def currentdef(ins): - if ins.revision != ins.classdef.revision: - raise BlockedInference(info="stale inst of %s" % ins.classdef.cls) - return ins.classdef - def getattr(ins, s_attr): if s_attr.is_constant() and isinstance(s_attr.const, str): attr = s_attr.const - #print 'getattr:', ins, attr, ins.classdef.revision - try: - s_result = ins.currentdef().find_attribute(attr).getvalue() - except BlockedInference, blocked: - blocked.info = "%s .%s" % (blocked.info, attr) - raise blocked - # we call this because it might raise BlockedInference if - # the above line caused generalization. - ins.currentdef() - return s_result + attrdef = ins.classdef.find_attribute(attr) + position = getbookkeeper().position_key + attrdef.read_locations[position] = True + return attrdef.getvalue() return SomeObject() def setattr(ins, s_attr, s_value): if s_attr.is_constant() and isinstance(s_attr.const, str): attr = s_attr.const - try: - clsdef = ins.currentdef().locate_attribute(attr) - except BlockedInference, blocked: - blocked.info = "%s .%s" % (blocked.info, attr) - raise blocked + # find the (possibly parent) class where this attr is defined + clsdef = ins.classdef.locate_attribute(attr) attrdef = clsdef.attrs[attr] attrdef.readonly = False @@ -196,16 +182,6 @@ return # create or update the attribute in clsdef clsdef.generalize_attr(attr, s_value) - raise BlockedInference - return - - def contains(self, other): - # override the default contains() to ignore revision numbers - if self == other: - return True - s_union = pair(self, other).union() - return (isinstance(s_union, SomeInstance) and - s_union.classdef is self.classdef) class __extend__(SomeBuiltin): @@ -251,10 +227,7 @@ results = [] for func, classdef in pbc.prebuiltinstances.items(): if isclassdef(classdef): - # create s_self and record the creation in the factory s_self = SomeInstance(classdef) - classdef.instantiation_locations[ - bookkeeper.position_key] = True args1 = args.prepend(s_self) else: args1 = args From arigo at codespeak.net Fri Mar 4 14:35:19 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 4 Mar 2005 14:35:19 +0100 (MET) Subject: [pypy-svn] r9625 - in pypy: branch/annotation-no-rev-num dist/pypy/objspace Message-ID: <20050304133519.9627F27B5C@code1.codespeak.net> Author: arigo Date: Fri Mar 4 14:35:19 2005 New Revision: 9625 Modified: pypy/branch/annotation-no-rev-num/classdef.py pypy/dist/pypy/objspace/descroperation.py Log: naive support for _mixin_ multiple inheritance Modified: pypy/branch/annotation-no-rev-num/classdef.py ============================================================================== --- pypy/branch/annotation-no-rev-num/classdef.py (original) +++ pypy/branch/annotation-no-rev-num/classdef.py Fri Mar 4 14:35:19 2005 @@ -48,19 +48,28 @@ #self.instantiation_locations = {} self.cls = cls self.subdefs = {} - assert (len(cls.__bases__) <= 1 or - cls.__bases__[1:] == (object,) # for baseobjspace.Wrappable - ), "single inheritance only right now: %r" % (cls,) - if cls.__bases__: - base = cls.__bases__[0] - else: - base = object + base = object + mixeddict = {} + baselist = list(cls.__bases__) + baselist.reverse() + for b1 in baselist: + if b1 is object: + continue + if getattr(b1, '_mixin_', False): + assert b1.__bases__ == () or b1.__bases__ == (object,), ( + "mixin class %r should have no base" % (b1,)) + mixeddict.update(b1.__dict__) + else: + assert base is object, ("multiple inheritance only supported " + "with _mixin_: %r" % (cls,)) + base = b1 + mixeddict.update(cls.__dict__) self.basedef = bookkeeper.getclassdef(base) if self.basedef: self.basedef.subdefs[cls] = self # collect the (supposed constant) class attributes - for name, value in cls.__dict__.items(): + for name, value in mixeddict.items(): # ignore some special attributes if name.startswith('_') and not isinstance(value, FunctionType): continue Modified: pypy/dist/pypy/objspace/descroperation.py ============================================================================== --- pypy/dist/pypy/objspace/descroperation.py (original) +++ pypy/dist/pypy/objspace/descroperation.py Fri Mar 4 14:35:19 2005 @@ -55,6 +55,7 @@ pass # XXX some strange checking maybe class DescrOperation: + _mixin_ = True def getdict(space, w_obj): return w_obj.getdict() From arigo at codespeak.net Fri Mar 4 14:35:19 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 4 Mar 2005 14:35:19 +0100 (MET) Subject: [pypy-svn] r9625 - in pypy: branch/annotation-no-rev-num dist/pypy/objspace Message-ID: <20050304133519.A614C27B5D@code1.codespeak.net> Author: arigo Date: Fri Mar 4 14:35:19 2005 New Revision: 9625 Modified: pypy/branch/annotation-no-rev-num/classdef.py pypy/dist/pypy/objspace/descroperation.py Log: naive support for _mixin_ multiple inheritance Modified: pypy/branch/annotation-no-rev-num/classdef.py ============================================================================== --- pypy/branch/annotation-no-rev-num/classdef.py (original) +++ pypy/branch/annotation-no-rev-num/classdef.py Fri Mar 4 14:35:19 2005 @@ -48,19 +48,28 @@ #self.instantiation_locations = {} self.cls = cls self.subdefs = {} - assert (len(cls.__bases__) <= 1 or - cls.__bases__[1:] == (object,) # for baseobjspace.Wrappable - ), "single inheritance only right now: %r" % (cls,) - if cls.__bases__: - base = cls.__bases__[0] - else: - base = object + base = object + mixeddict = {} + baselist = list(cls.__bases__) + baselist.reverse() + for b1 in baselist: + if b1 is object: + continue + if getattr(b1, '_mixin_', False): + assert b1.__bases__ == () or b1.__bases__ == (object,), ( + "mixin class %r should have no base" % (b1,)) + mixeddict.update(b1.__dict__) + else: + assert base is object, ("multiple inheritance only supported " + "with _mixin_: %r" % (cls,)) + base = b1 + mixeddict.update(cls.__dict__) self.basedef = bookkeeper.getclassdef(base) if self.basedef: self.basedef.subdefs[cls] = self # collect the (supposed constant) class attributes - for name, value in cls.__dict__.items(): + for name, value in mixeddict.items(): # ignore some special attributes if name.startswith('_') and not isinstance(value, FunctionType): continue Modified: pypy/dist/pypy/objspace/descroperation.py ============================================================================== --- pypy/dist/pypy/objspace/descroperation.py (original) +++ pypy/dist/pypy/objspace/descroperation.py Fri Mar 4 14:35:19 2005 @@ -55,6 +55,7 @@ pass # XXX some strange checking maybe class DescrOperation: + _mixin_ = True def getdict(space, w_obj): return w_obj.getdict() From arigo at codespeak.net Fri Mar 4 14:48:18 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 4 Mar 2005 14:48:18 +0100 (MET) Subject: [pypy-svn] r9626 - pypy/branch/annotation-no-rev-num Message-ID: <20050304134818.5CD2327B5F@code1.codespeak.net> Author: arigo Date: Fri Mar 4 14:48:18 2005 New Revision: 9626 Modified: pypy/branch/annotation-no-rev-num/classdef.py Log: Mixins bug fix. Modified: pypy/branch/annotation-no-rev-num/classdef.py ============================================================================== --- pypy/branch/annotation-no-rev-num/classdef.py (original) +++ pypy/branch/annotation-no-rev-num/classdef.py Fri Mar 4 14:48:18 2005 @@ -50,6 +50,7 @@ self.subdefs = {} base = object mixeddict = {} + sources = {} baselist = list(cls.__bases__) baselist.reverse() for b1 in baselist: @@ -59,6 +60,8 @@ assert b1.__bases__ == () or b1.__bases__ == (object,), ( "mixin class %r should have no base" % (b1,)) mixeddict.update(b1.__dict__) + for name in b1.__dict__: + sources[name] = b1 else: assert base is object, ("multiple inheritance only supported " "with _mixin_: %r" % (cls,)) @@ -75,7 +78,7 @@ continue if isinstance(value, FunctionType): value.class_ = cls # remember that this is really a method - self.add_source_for_attribute(name, cls, self) + self.add_source_for_attribute(name, sources.get(name, cls), self) def add_source_for_attribute(self, attr, source, clsdef=None): self.find_attribute(attr).sources[source] = clsdef From arigo at codespeak.net Fri Mar 4 14:52:28 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 4 Mar 2005 14:52:28 +0100 (MET) Subject: [pypy-svn] r9627 - pypy/dist/goal Message-ID: <20050304135228.B22C927B62@code1.codespeak.net> Author: arigo Date: Fri Mar 4 14:52:28 2005 New Revision: 9627 Added: pypy/dist/goal/translate_pypy1.py - copied, changed from r9623, pypy/dist/goal/translate_pypy.py Log: A modified version of the goal, which calls the 'mul' multimethod directly, instead of going through DescrOperation. This allows the annotation to "drag in" only a small part of PyPy, so it terminates (successfully!) in only 15-20 seconds. Copied: pypy/dist/goal/translate_pypy1.py (from r9623, pypy/dist/goal/translate_pypy.py) ============================================================================== --- pypy/dist/goal/translate_pypy.py (original) +++ pypy/dist/goal/translate_pypy1.py Fri Mar 4 14:52:28 2005 @@ -21,6 +21,7 @@ import buildcache2 from pypy.objspace.std.objspace import StdObjSpace, W_Object from pypy.objspace.std.intobject import W_IntObject +from pypy.objspace.std import stdtypedef from pypy.translator.translator import Translator from pypy.annotation import model as annmodel from pypy.tool.cache import Cache @@ -36,17 +37,29 @@ def entry_point(): w_a = W_IntObject(space, -6) w_b = W_IntObject(space, -7) - return space.mul(w_a, w_b) + return mmentrypoint(space, w_a, w_b) # __________ Main __________ def analyse(entry_point=entry_point): - global t, space + global t, space, mmentrypoint # disable translation of the whole of classobjinterp.py StdObjSpace.setup_old_style_classes = lambda self: None space = StdObjSpace() # call cache filling code - buildcache2.buildcache(space) + buildcache2.buildcache(space) + + # ------------------------------------------------------------ + name = 'mul' + mm = space.MM.mul + exprargs, expr, miniglobals, fallback = ( + mm.install_not_sliced(space.model.typeorder, baked_perform_call=False)) + func = stdtypedef.make_perform_trampoline('__mm_'+name, + exprargs, expr, miniglobals, + mm) + mmentrypoint = func + # ------------------------------------------------------------ + # further call the entry_point once to trigger building remaining # caches (as far as analyzing the entry_point is concerned) entry_point() From arigo at codespeak.net Fri Mar 4 14:53:12 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 4 Mar 2005 14:53:12 +0100 (MET) Subject: [pypy-svn] r9628 - pypy/dist/pypy/annotation Message-ID: <20050304135312.16C0A27B72@code1.codespeak.net> Author: arigo Date: Fri Mar 4 14:53:11 2005 New Revision: 9628 Removed: pypy/dist/pypy/annotation/ Log: The branch looks like a good idea. Merging... From arigo at codespeak.net Fri Mar 4 14:53:32 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 4 Mar 2005 14:53:32 +0100 (MET) Subject: [pypy-svn] r9629 - in pypy: branch/annotation-no-rev-num dist/pypy/annotation Message-ID: <20050304135332.B6BCC27B7A@code1.codespeak.net> Author: arigo Date: Fri Mar 4 14:53:32 2005 New Revision: 9629 Added: pypy/dist/pypy/annotation/ - copied from r9628, pypy/branch/annotation-no-rev-num/ Removed: pypy/branch/annotation-no-rev-num/ Log: Merged. From arigo at codespeak.net Fri Mar 4 14:53:32 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 4 Mar 2005 14:53:32 +0100 (MET) Subject: [pypy-svn] r9629 - in pypy: branch/annotation-no-rev-num dist/pypy/annotation Message-ID: <20050304135332.E3BD127B7A@code1.codespeak.net> Author: arigo Date: Fri Mar 4 14:53:32 2005 New Revision: 9629 Added: pypy/dist/pypy/annotation/ - copied from r9628, pypy/branch/annotation-no-rev-num/ Removed: pypy/branch/annotation-no-rev-num/ Log: Merged. From arigo at codespeak.net Fri Mar 4 15:09:02 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 4 Mar 2005 15:09:02 +0100 (MET) Subject: [pypy-svn] r9631 - in pypy/dist/pypy/interpreter: . test Message-ID: <20050304140902.EAA8A27B6E@code1.codespeak.net> Author: arigo Date: Fri Mar 4 15:09:02 2005 New Revision: 9631 Modified: pypy/dist/pypy/interpreter/function.py pypy/dist/pypy/interpreter/test/test_function.py Log: The attribute f.__module__ was broken. Added a test. Modified: pypy/dist/pypy/interpreter/function.py ============================================================================== --- pypy/dist/pypy/interpreter/function.py (original) +++ pypy/dist/pypy/interpreter/function.py Fri Mar 4 15:09:02 2005 @@ -104,11 +104,11 @@ self.w_module = space.w_None return self.w_module - def fset___module__(space, w_self, w_module ): + def fset___module__(space, w_self, w_module): self = space.interpclass_w(w_self) - self.w_module = space.w_module + self.w_module = w_module - def fdel___module__(space, w_self, w_module ): + def fdel___module__(space, w_self): self = space.interpclass_w(w_self) self.w_module = space.w_None Modified: pypy/dist/pypy/interpreter/test/test_function.py ============================================================================== --- pypy/dist/pypy/interpreter/test/test_function.py (original) +++ pypy/dist/pypy/interpreter/test/test_function.py Fri Mar 4 15:09:02 2005 @@ -8,6 +8,7 @@ class AppTestFunctionIntrospection: def test_attributes(self): + globals()['__name__'] = 'mymodulename' def f(): pass assert hasattr(f, 'func_code') assert f.func_defaults == None @@ -16,6 +17,7 @@ #self.assertEquals(f.func_closure, None) XXX assert f.func_doc == None assert f.func_name == 'f' + assert f.__module__ == 'mymodulename' def test_code_is_ok(self): def f(): pass @@ -46,6 +48,13 @@ del f.func_doc assert f.func_doc == None + def test_write_module(self): + def f(): "hello" + f.__module__ = 'ab.c' + assert f.__module__ == 'ab.c' + del f.__module__ + assert f.__module__ is None + class AppTestFunction: def test_simple_call(self): def func(arg1, arg2): From arigo at codespeak.net Fri Mar 4 15:36:13 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 4 Mar 2005 15:36:13 +0100 (MET) Subject: [pypy-svn] r9633 - pypy/dist/pypy/annotation Message-ID: <20050304143613.7AACB27B80@code1.codespeak.net> Author: arigo Date: Fri Mar 4 15:36:13 2005 New Revision: 9633 Modified: pypy/dist/pypy/annotation/builtin.py Log: (Dummy) annotations for some more builtins. Modified: pypy/dist/pypy/annotation/builtin.py ============================================================================== --- pypy/dist/pypy/annotation/builtin.py (original) +++ pypy/dist/pypy/annotation/builtin.py Fri Mar 4 15:36:13 2005 @@ -3,7 +3,7 @@ """ import types -import sys +import sys, math from pypy.tool.ansi_print import ansi_print from pypy.annotation.model import SomeInteger, SomeObject, SomeChar, SomeBool from pypy.annotation.model import SomeList, SomeString, SomeTuple, SomeSlice @@ -48,9 +48,15 @@ def builtin_hex(o): return SomeString() +def builtin_oct(o): + return SomeString() + def builtin_abs(o): return o.__class__() +def builtin_divmod(o1, o2): + return SomeTuple([SomeObject(), SomeObject()]) # XXX + def builtin_unicode(s_obj): return SomeString() @@ -188,6 +194,12 @@ def count(s_obj): return SomeInteger() +def math_fmod(x, y): + return SomeObject() + +def math_floor(x): + return SomeObject() + # collect all functions import __builtin__ BUILTIN_ANALYZERS = {} @@ -200,3 +212,5 @@ BUILTIN_ANALYZERS[pypy.objspace.std.restricted_int.r_uint] = restricted_uint BUILTIN_ANALYZERS[Exception.__init__.im_func] = exception_init BUILTIN_ANALYZERS[sys.getrefcount] = count +BUILTIN_ANALYZERS[math.fmod] = math_fmod +BUILTIN_ANALYZERS[math.floor] = math_floor From pedronis at codespeak.net Fri Mar 4 19:46:04 2005 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Fri, 4 Mar 2005 19:46:04 +0100 (MET) Subject: [pypy-svn] r9644 - pypy/dist/pypy/annotation Message-ID: <20050304184604.A7F1327B95@code1.codespeak.net> Author: pedronis Date: Fri Mar 4 19:46:04 2005 New Revision: 9644 Modified: pypy/dist/pypy/annotation/bookkeeper.py Log: long-winded comment Modified: pypy/dist/pypy/annotation/bookkeeper.py ============================================================================== --- pypy/dist/pypy/annotation/bookkeeper.py (original) +++ pypy/dist/pypy/annotation/bookkeeper.py Fri Mar 4 19:46:04 2005 @@ -251,7 +251,12 @@ except KeyError: if isinstance(thing, FunctionType): # XXX XXX XXX HAAAAAAAAAAAACK + # xxx we need a way to let know subsequent phases (the generator) about the specialized function + # the caller flowgraph as it is doesn't. + # This line just avoids that the flowgraph of the original function, which is what will be considered + # and compiled for now will be computed during generation itself self.annotator.translator.getflowgraph(thing) + # thing = func_with_new_name(thing, name or thing.func_name) elif isinstance(thing, (type, ClassType)): assert not "not working yet" From tismer at codespeak.net Fri Mar 4 20:15:55 2005 From: tismer at codespeak.net (tismer at codespeak.net) Date: Fri, 4 Mar 2005 20:15:55 +0100 (MET) Subject: [pypy-svn] r9648 - pypy/dist/pypy/translator Message-ID: <20050304191555.984DC27B96@code1.codespeak.net> Author: tismer Date: Fri Mar 4 20:15:55 2005 New Revision: 9648 Modified: pypy/dist/pypy/translator/genc.h pypy/dist/pypy/translator/genc.py Log: made the goal compile under windows, again. First, the init code gets zlib compressed. This is a nice code reduction, the source code gets below 12 MB. But for windows, the size limit of string constants appears to be some 2040, so I broke the string into 1K chunks and modified the C code to collect these into a temp string. Modified: pypy/dist/pypy/translator/genc.h ============================================================================== --- pypy/dist/pypy/translator/genc.h (original) +++ pypy/dist/pypy/translator/genc.h Fri Mar 4 20:15:55 2005 @@ -278,7 +278,7 @@ PyType_Ready(&PyGenCFunction_Type); \ if (setup_globalfunctions(globalfunctiondefs) < 0) \ return; \ - if (setup_initcode(frozen_initcode, sizeof(frozen_initcode)) < 0) \ + if (setup_initcode(frozen_initcode, FROZEN_INITCODE_SIZE) < 0) \ return; \ if (setup_globalobjects(globalobjectdefs) < 0) \ return; @@ -342,14 +342,29 @@ return 0; } -static int setup_initcode(char* frozendata, int len) +static int setup_initcode(char* frozendata[], int len) { PyObject* co; PyObject* globals; PyObject* res; - co = PyMarshal_ReadObjectFromString(frozendata, len); + char *buffer, *bufp; + int chunk, count = 0; + + buffer = PyMem_NEW(char, len); + if (buffer == NULL) + return -1; + bufp = buffer; + while (count < len) { + chunk = len-count < 1024 ? len-count : 1024; + memcpy(bufp, *frozendata, chunk); + bufp += chunk; + count += chunk; + ++frozendata; + } + co = PyMarshal_ReadObjectFromString(buffer, len); if (co == NULL) return -1; + PyMem_DEL(buffer); if (!PyCode_Check(co)) { PyErr_SetString(PyExc_TypeError, "uh?"); return -1; Modified: pypy/dist/pypy/translator/genc.py ============================================================================== --- pypy/dist/pypy/translator/genc.py (original) +++ pypy/dist/pypy/translator/genc.py Fri Mar 4 20:15:55 2005 @@ -3,7 +3,7 @@ """ from __future__ import generators -import autopath, os, sys, __builtin__, marshal +import autopath, os, sys, __builtin__, marshal, zlib from pypy.objspace.flow.model import Variable, Constant, SpaceOperation from pypy.objspace.flow.model import FunctionGraph, Block, Link from pypy.objspace.flow.model import last_exception, last_exc_value @@ -493,9 +493,12 @@ if c in '\\"': return '\\' + c if ' ' <= c < '\x7F': return c return '\\%03o' % ord(c) - for i in range(0, len(bytecode), 20): - print >> f, ''.join([char_repr(c) for c in bytecode[i:i+20]])+'\\' + for i in range(0, len(bytecode), 32): + print >> f, ''.join([char_repr(c) for c in bytecode[i:i+32]])+'\\' + if (i+32) % 1024 == 0: + print >> f, self.C_FROZEN_BETWEEN print >> f, self.C_FROZEN_END + print >> f, "#define FROZEN_INITCODE_SIZE %d" % len(bytecode) # the footer proper: the module init function */ print >> f, self.C_FOOTER % info @@ -523,8 +526,14 @@ del self.initcode[:] co = compile(source, self.modname, 'exec') del source + small = zlib.compress(marshal.dumps(co)) + source = """if 1: + import zlib, marshal + exec marshal.loads(zlib.decompress(%r))""" % small + co = compile(source, self.modname, 'exec') + del source return marshal.dumps(co) - + def gen_cfunction(self, func): ## print 'gen_cfunction (%s:%d) %s' % ( ## func.func_globals.get('__name__', '?'), @@ -831,9 +840,11 @@ C_FROZEN_BEGIN = ''' /* Frozen Python bytecode: the initialization code */ -static char frozen_initcode[] = "\\''' +static char *frozen_initcode[] = {"\\''' + + C_FROZEN_BETWEEN = '''", "\\''' - C_FROZEN_END = '''";\n''' + C_FROZEN_END = '''"};\n''' C_FOOTER = C_SEP + ''' From arigo at codespeak.net Sat Mar 5 10:54:36 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 5 Mar 2005 10:54:36 +0100 (MET) Subject: [pypy-svn] r9653 - pypy/dist/pypy/translator Message-ID: <20050305095436.9CC9E27B4C@code1.codespeak.net> Author: arigo Date: Sat Mar 5 10:54:36 2005 New Revision: 9653 Modified: pypy/dist/pypy/translator/simplify.py Log: Flow graph simplification: When the same variable is passed multiple times into the next block, pass it only once. This enables further optimizations by the annotator, which otherwise doesn't realize that tests performed on one of the copies of the variable also affect the other. Modified: pypy/dist/pypy/translator/simplify.py ============================================================================== --- pypy/dist/pypy/translator/simplify.py (original) +++ pypy/dist/pypy/translator/simplify.py Sat Mar 5 10:54:36 2005 @@ -16,6 +16,7 @@ remove_implicit_exceptions(graph) join_blocks(graph) transform_dead_op_vars(graph) + remove_identical_vars(graph) checkgraph(graph) # ____________________________________________________________ @@ -219,3 +220,45 @@ for i in range(len(block.inputargs)-1, -1, -1): if block.inputargs[i] not in read_vars: del block.inputargs[i] + +def remove_identical_vars(graph): + """When the same variable is passed multiple times into the next block, + pass it only once. This enables further optimizations by the annotator, + which otherwise doesn't realize that tests performed on one of the copies + of the variable also affect the other.""" + + entrymap = mkentrymap(graph) + consider_blocks = entrymap + + while consider_blocks: + blocklist = consider_blocks.keys() + consider_blocks = {} + for block in blocklist: + if not block.exits: + continue + links = entrymap[block] + entryargs = {} + for i in range(len(block.inputargs)): + # list of possible vars that can arrive in i'th position + key = tuple([link.args[i] for link in links]) + if key not in entryargs: + entryargs[key] = i + else: + j = entryargs[key] + # positions i and j receive exactly the same input vars, + # we can remove the argument i and replace it with the j. + argi = block.inputargs[i] + if not isinstance(argi, Variable): continue + argj = block.inputargs[j] + block.renamevariables({argi: argj}) + assert block.inputargs[i] == block.inputargs[j] == argj + del block.inputargs[i] + for link in links: + assert link.args[i] == link.args[j] + del link.args[i] + # mark this block and all the following ones as subject to + # possible further optimization + consider_blocks[block] = True + for link in block.exits: + consider_blocks[link.target] = True + break From arigo at codespeak.net Sat Mar 5 13:51:33 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 5 Mar 2005 13:51:33 +0100 (MET) Subject: [pypy-svn] r9655 - pypy/dist/pypy/objspace/flow Message-ID: <20050305125133.03E7427B4C@code1.codespeak.net> Author: arigo Date: Sat Mar 5 13:51:33 2005 New Revision: 9655 Modified: pypy/dist/pypy/objspace/flow/flowcontext.py pypy/dist/pypy/objspace/flow/objspace.py pypy/dist/pypy/objspace/flow/specialcase.py Log: Partial clean-up of the flow object space. Instead of a set of 'crnt_*' attributes, the FlowExecutionContext now has a 'recorder' attribute pointing to a Recorder. The standard BlockRecorder records operations into a block; the main alternate one is Replayer (which was ReplayList). Modified: pypy/dist/pypy/objspace/flow/flowcontext.py ============================================================================== --- pypy/dist/pypy/objspace/flow/flowcontext.py (original) +++ pypy/dist/pypy/objspace/flow/flowcontext.py Sat Mar 5 13:51:33 2005 @@ -16,12 +16,11 @@ Block.__init__(self, framestate.getvariables()) self.framestate = framestate - def patchframe(self, frame, executioncontext): + def patchframe(self, frame): if self.dead: raise ExitFrame(None) self.framestate.restoreframe(frame) - executioncontext.crnt_block = self - executioncontext.crnt_ops = self.operations + return BlockRecorder(self) class EggBlock(Block): @@ -31,30 +30,123 @@ self.prevblock = prevblock self.booloutcome = booloutcome - def patchframe(self, frame, executioncontext): + def patchframe(self, frame): parentblocks = [] block = self while isinstance(block, EggBlock): block = block.prevblock parentblocks.append(block) # parentblocks = [Egg, Egg, ..., Egg, Spam] not including self - block.patchframe(frame, executioncontext) - replaylist = self.operations + block.patchframe(frame) + recorder = BlockRecorder(self) prevblock = self for block in parentblocks: - replaylist = ReplayList(block.operations, - prevblock, prevblock.booloutcome, - replaylist) + recorder = Replayer(block, prevblock.booloutcome, recorder) prevblock = block - executioncontext.crnt_ops = replaylist + return recorder -class ReplayList: +# ____________________________________________________________ + +class Recorder: + + def append(self, operation): + raise NotImplementedError + + def bytecode_trace(self, ec, frame): + pass + + def guessbool(self, ec, w_condition, **kwds): + raise AssertionError, "cannot guessbool(%s)" % (w_condition,) + + +class BlockRecorder(Recorder): + # Records all generated operations into a block. + + def __init__(self, block): + self.crnt_block = block + + def append(self, operation): + self.crnt_block.operations.append(operation) + + def bytecode_trace(self, ec, frame): + assert frame is ec.crnt_frame, "seeing an unexpected frame!" + next_instr = frame.next_instr + ec.crnt_offset = next_instr # save offset for opcode + varnames = frame.code.getvarnames() + for name, w_value in zip(varnames, frame.getfastscope()): + if isinstance(w_value, Variable): + w_value.rename(name) + if next_instr in ec.joinpoints: + currentstate = FrameState(frame) + # can 'currentstate' be merged with one of the blocks that + # already exist for this bytecode position? + for block in ec.joinpoints[next_instr]: + newstate = block.framestate.union(currentstate) + if newstate is not None: + # yes + finished = newstate == block.framestate + break + else: + # no + newstate = currentstate.copy() + finished = False + block = None + + if finished: + newblock = block + else: + newblock = SpamBlock(newstate) + # unconditionally link the current block to the newblock + outputargs = currentstate.getoutputargs(newstate) + self.crnt_block.closeblock(Link(outputargs, newblock)) + # phew + if finished: + raise ExitFrame(None) + if block is not None and block.exits: + # to simplify the graph, we patch the old block to point + # directly at the new block which is its generalization + block.dead = True + block.operations = () + block.exitswitch = None + outputargs = block.framestate.getoutputargs(newstate) + block.recloseblock(Link(outputargs, newblock)) + ec.recorder = newblock.patchframe(frame) + ec.joinpoints[next_instr].insert(0, newblock) + + def guessbool(self, ec, w_condition, cases=[False,True], + replace_last_variable_except_in_first_case = None): + block = self.crnt_block + vars = vars2 = block.getvariables() + links = [] + for case in cases: + egg = EggBlock(vars2, block, case) + ec.pendingblocks.append(egg) + link = Link(vars, egg, case) + links.append(link) + if replace_last_variable_except_in_first_case is not None: + assert block.operations[-1].result is vars[-1] + vars = vars[:-1] + vars.extend(replace_last_variable_except_in_first_case) + vars2 = vars2[:-1] + while len(vars2) < len(vars): + vars2.append(Variable()) + replace_last_variable_except_in_first_case = None + block.exitswitch = w_condition + block.closeblock(*links) + # forked the graph. Note that False comes before True by default + # in the exits tuple so that (just in case we need it) we + # actually have block.exits[False] = elseLink and + # block.exits[True] = ifLink. + raise ExitFrame(None) + + +class Replayer(Recorder): - def __init__(self, listtoreplay, nextblock, booloutcome, nextreplaylist): - self.listtoreplay = listtoreplay - self.nextblock = nextblock + def __init__(self, block, booloutcome, nextreplayer): + self.crnt_block = block + self.listtoreplay = block.operations self.booloutcome = booloutcome - self.nextreplaylist = nextreplaylist + self.nextreplayer = nextreplayer self.index = 0 def append(self, operation): @@ -67,16 +159,22 @@ [str(s) for s in self.listtoreplay[self.index:]])) self.index += 1 - def finished(self): - return self.index == len(self.listtoreplay) + def guessbool(self, ec, w_condition, **kwds): + assert self.index == len(self.listtoreplay) + ec.recorder = self.nextreplayer + return self.booloutcome + -class ConcreteNoOp: +class ConcreteNoOp(Recorder): # In "concrete mode", no SpaceOperations between Variables are allowed. # Concrete mode is used to precompute lazily-initialized caches, # when we don't want this precomputation to show up on the flow graph. def append(self, operation): raise AssertionError, "concrete mode: cannot perform %s" % operation +# ____________________________________________________________ + + class FlowExecutionContext(ExecutionContext): def __init__(self, space, code, globals, constargs={}, closure=None, @@ -109,91 +207,15 @@ def create_frame(self): # create an empty frame suitable for the code object # while ignoring any operation like the creation of the locals dict - self.crnt_ops = [] + self.recorder = [] return self.code.create_frame(self.space, self.w_globals, self.closure) def bytecode_trace(self, frame): - if not isinstance(self.crnt_ops, list): - return - assert frame is self.crnt_frame, "seeing an unexpected frame!" - next_instr = frame.next_instr - self.crnt_offset = next_instr # save offset for opcode - varnames = frame.code.getvarnames() - for name, w_value in zip(varnames, frame.getfastscope()): - if isinstance(w_value, Variable): - w_value.rename(name) - if next_instr in self.joinpoints: - currentstate = FrameState(frame) - # can 'currentstate' be merged with one of the blocks that - # already exist for this bytecode position? - for block in self.joinpoints[next_instr]: - newstate = block.framestate.union(currentstate) - if newstate is not None: - # yes - finished = newstate == block.framestate - break - else: - # no - newstate = currentstate.copy() - finished = False - block = None - - if finished: - newblock = block - else: - newblock = SpamBlock(newstate) - # unconditionally link the current block to the newblock - outputargs = currentstate.getoutputargs(newstate) - self.crnt_block.closeblock(Link(outputargs, newblock)) - # phew - if finished: - raise ExitFrame(None) - if block is not None and block.exits: - # to simplify the graph, we patch the old block to point - # directly at the new block which is its generalization - block.dead = True - block.operations = () - block.exitswitch = None - outputargs = block.framestate.getoutputargs(newstate) - block.recloseblock(Link(outputargs, newblock)) - newblock.patchframe(frame, self) - self.joinpoints[next_instr].insert(0, newblock) + self.recorder.bytecode_trace(self, frame) - def guessbool(self, w_condition, cases=[False,True], - replace_last_variable_except_in_first_case = None): - if isinstance(self.crnt_ops, list): - block = self.crnt_block - vars = vars2 = block.getvariables() - links = [] - for case in cases: - egg = EggBlock(vars2, block, case) - self.pendingblocks.append(egg) - link = Link(vars, egg, case) - links.append(link) - if replace_last_variable_except_in_first_case is not None: - assert block.operations[-1].result is vars[-1] - vars = vars[:-1] - vars.extend(replace_last_variable_except_in_first_case) - vars2 = vars2[:-1] - while len(vars2) < len(vars): - vars2.append(Variable()) - replace_last_variable_except_in_first_case = None - block.exitswitch = w_condition - block.closeblock(*links) - # forked the graph. Note that False comes before True by default - # in the exits tuple so that (just in case we need it) we - # actually have block.exits[False] = elseLink and - # block.exits[True] = ifLink. - raise ExitFrame(None) - if isinstance(self.crnt_ops, ReplayList): - replaylist = self.crnt_ops - assert replaylist.finished() - self.crnt_block = replaylist.nextblock - self.crnt_ops = replaylist.nextreplaylist - return replaylist.booloutcome - raise AssertionError, "concrete mode: cannot guessbool(%s)" % ( - w_condition,) + def guessbool(self, w_condition, **kwds): + return self.recorder.guessbool(self, w_condition, **kwds) def guessexception(self, *classes): outcome = self.guessbool(Constant(last_exception, last_exception=True), @@ -204,7 +226,7 @@ if outcome is None: w_exc_cls, w_exc_value = None, None else: - w_exc_cls, w_exc_value = self.crnt_block.inputargs[-2:] + w_exc_cls, w_exc_value = self.recorder.crnt_block.inputargs[-2:] return outcome, w_exc_cls, w_exc_value def build_flow(self): @@ -213,7 +235,7 @@ block = self.pendingblocks.pop(0) frame = self.create_frame() try: - block.patchframe(frame, self) + self.recorder = block.patchframe(frame) except ExitFrame: continue # restarting a dead SpamBlock try: @@ -229,11 +251,12 @@ self.space.unwrap(e.w_value))) except OperationError, e: link = Link([e.w_type, e.w_value], self.graph.exceptblock) - self.crnt_block.closeblock(link) + self.recorder.crnt_block.closeblock(link) else: if w_result is not None: link = Link([w_result], self.graph.returnblock) - self.crnt_block.closeblock(link) + self.recorder.crnt_block.closeblock(link) + del self.recorder self.fixeggblocks() def fixeggblocks(self): Modified: pypy/dist/pypy/objspace/flow/objspace.py ============================================================================== --- pypy/dist/pypy/objspace/flow/objspace.py (original) +++ pypy/dist/pypy/objspace/flow/objspace.py Sat Mar 5 13:51:33 2005 @@ -62,13 +62,13 @@ # "concrete mode". In this mode, only Constants are allowed # and no SpaceOperation is recorded. def my_builder(key, stuff): - previous_ops = self.executioncontext.crnt_ops - self.executioncontext.crnt_ops = flowcontext.ConcreteNoOp() + previous_recorder = self.executioncontext.recorder + self.executioncontext.recorder = flowcontext.ConcreteNoOp() self.concrete_mode += 1 try: return builder(key, stuff) finally: - self.executioncontext.crnt_ops = previous_ops + self.executioncontext.recorder = previous_recorder self.concrete_mode -= 1 return super(FlowObjSpace, self).loadfromcache(key, my_builder, cache) @@ -163,7 +163,7 @@ specialcase.setup(self) def exception_match(self, w_exc_type, w_check_class): - self.executioncontext.crnt_block.exc_handler = True + self.executioncontext.recorder.crnt_block.exc_handler = True return ObjSpace.exception_match(self, w_exc_type, w_check_class) @@ -243,7 +243,7 @@ spaceop = SpaceOperation(name, args_w, Variable()) if hasattr(self, 'executioncontext'): # not here during bootstrapping spaceop.offset = self.executioncontext.crnt_offset - self.executioncontext.crnt_ops.append(spaceop) + self.executioncontext.recorder.append(spaceop) return spaceop.result def is_true(self, w_obj): Modified: pypy/dist/pypy/objspace/flow/specialcase.py ============================================================================== --- pypy/dist/pypy/objspace/flow/specialcase.py (original) +++ pypy/dist/pypy/objspace/flow/specialcase.py Sat Mar 5 13:51:33 2005 @@ -55,8 +55,9 @@ # Normally, Instance should have been created by the previous operation # which should be a simple_call(, ...). # Fetch the out of there. (This doesn't work while replaying) - if space.executioncontext.crnt_ops: - spaceop = space.executioncontext.crnt_ops[-1] + operations = space.executioncontext.recorder.crnt_block.operations + if operations: + spaceop = operations[-1] if (spaceop.opname == 'simple_call' and spaceop.result is w_arg1): w_type = spaceop.args[0] From arigo at codespeak.net Sat Mar 5 15:27:01 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 5 Mar 2005 15:27:01 +0100 (MET) Subject: [pypy-svn] r9657 - in pypy/dist/pypy/objspace/flow: . test Message-ID: <20050305142701.2548B27B4C@code1.codespeak.net> Author: arigo Date: Sat Mar 5 15:27:00 2005 New Revision: 9657 Modified: pypy/dist/pypy/objspace/flow/flowcontext.py pypy/dist/pypy/objspace/flow/framestate.py pypy/dist/pypy/objspace/flow/test/test_objspace.py Log: Dynamic merge point creation, just before any generated operation. This enables a kind of automatic specialization in code where several constants can enter. Modified: pypy/dist/pypy/objspace/flow/flowcontext.py ============================================================================== --- pypy/dist/pypy/objspace/flow/flowcontext.py (original) +++ pypy/dist/pypy/objspace/flow/flowcontext.py Sat Mar 5 15:27:00 2005 @@ -1,5 +1,4 @@ from pypy.interpreter.executioncontext import ExecutionContext -from pypy.interpreter.pyframe import ExitFrame from pypy.interpreter.error import OperationError from pypy.objspace.flow.model import * from pypy.objspace.flow.framestate import FrameState @@ -8,6 +7,12 @@ class OperationThatShouldNotBePropagatedError(OperationError): pass +class StopFlowing(Exception): + pass + +class MergeBlock(Exception): + pass + class SpamBlock(Block): dead = False @@ -18,7 +23,7 @@ def patchframe(self, frame): if self.dead: - raise ExitFrame(None) + raise StopFlowing self.framestate.restoreframe(frame) return BlockRecorder(self) @@ -64,54 +69,34 @@ def __init__(self, block): self.crnt_block = block + # saved state at the join point most recently seen + self.last_join_point = None + self.progress = False def append(self, operation): + if self.last_join_point is not None: + # don't add more operations if we already crossed a join point + raise MergeBlock(self.crnt_block, self.last_join_point) self.crnt_block.operations.append(operation) def bytecode_trace(self, ec, frame): assert frame is ec.crnt_frame, "seeing an unexpected frame!" next_instr = frame.next_instr - ec.crnt_offset = next_instr # save offset for opcode - varnames = frame.code.getvarnames() - for name, w_value in zip(varnames, frame.getfastscope()): - if isinstance(w_value, Variable): - w_value.rename(name) - if next_instr in ec.joinpoints: - currentstate = FrameState(frame) - # can 'currentstate' be merged with one of the blocks that - # already exist for this bytecode position? - for block in ec.joinpoints[next_instr]: - newstate = block.framestate.union(currentstate) - if newstate is not None: - # yes - finished = newstate == block.framestate - break - else: - # no - newstate = currentstate.copy() - finished = False - block = None - - if finished: - newblock = block - else: - newblock = SpamBlock(newstate) - # unconditionally link the current block to the newblock - outputargs = currentstate.getoutputargs(newstate) - self.crnt_block.closeblock(Link(outputargs, newblock)) - # phew - if finished: - raise ExitFrame(None) - if block is not None and block.exits: - # to simplify the graph, we patch the old block to point - # directly at the new block which is its generalization - block.dead = True - block.operations = () - block.exitswitch = None - outputargs = block.framestate.getoutputargs(newstate) - block.recloseblock(Link(outputargs, newblock)) - ec.recorder = newblock.patchframe(frame) - ec.joinpoints[next_instr].insert(0, newblock) + if self.crnt_block.operations or isinstance(self.crnt_block, EggBlock): + # if we have already produced at least one operation or a branch, + # make a join point as early as possible (but not before we + # actually try to generate more operations) + self.last_join_point = FrameState(frame) + else: + ec.crnt_offset = next_instr # save offset for opcode + varnames = frame.code.getvarnames() + for name, w_value in zip(varnames, frame.getfastscope()): + if isinstance(w_value, Variable): + w_value.rename(name) + # record passage over already-existing join points + if self.progress and next_instr in ec.joinpoints: + self.last_join_point = FrameState(frame) + self.progress = True def guessbool(self, ec, w_condition, cases=[False,True], replace_last_variable_except_in_first_case = None): @@ -137,7 +122,7 @@ # in the exits tuple so that (just in case we need it) we # actually have block.exits[False] = elseLink and # block.exits[True] = ifLink. - raise ExitFrame(None) + raise StopFlowing class Replayer(Recorder): @@ -198,8 +183,8 @@ arg_list[position] = Constant(value) frame.setfastscope(arg_list) self.joinpoints = {} - for joinpoint in code.getjoinpoints(): - self.joinpoints[joinpoint] = [] # list of blocks + #for joinpoint in code.getjoinpoints(): + # self.joinpoints[joinpoint] = [] # list of blocks initialblock = SpamBlock(FrameState(frame).copy()) self.pendingblocks = [initialblock] self.graph = FunctionGraph(name or code.co_name, initialblock) @@ -236,7 +221,7 @@ frame = self.create_frame() try: self.recorder = block.patchframe(frame) - except ExitFrame: + except StopFlowing: continue # restarting a dead SpamBlock try: self.crnt_frame = frame @@ -244,18 +229,29 @@ w_result = frame.resume() finally: self.crnt_frame = None + except OperationThatShouldNotBePropagatedError, e: raise Exception( 'found an operation that always raises %s: %s' % ( self.space.unwrap(e.w_type).__name__, self.space.unwrap(e.w_value))) + except OperationError, e: link = Link([e.w_type, e.w_value], self.graph.exceptblock) self.recorder.crnt_block.closeblock(link) + + except StopFlowing: + pass + + except MergeBlock, e: + block, currentstate = e.args + self.mergeblock(block, currentstate) + else: - if w_result is not None: - link = Link([w_result], self.graph.returnblock) - self.recorder.crnt_block.closeblock(link) + assert w_result is not None + link = Link([w_result], self.graph.returnblock) + self.recorder.crnt_block.closeblock(link) + del self.recorder self.fixeggblocks() @@ -270,3 +266,40 @@ mapping[a] = Variable(a) node.renamevariables(mapping) traverse(fixegg, self.graph) + + def mergeblock(self, currentblock, currentstate): + next_instr = currentstate.next_instr + # can 'currentstate' be merged with one of the blocks that + # already exist for this bytecode position? + candidates = self.joinpoints.setdefault(next_instr, []) + for block in candidates: + newstate = block.framestate.union(currentstate) + if newstate is not None: + # yes + finished = newstate == block.framestate + break + else: + # no + newstate = currentstate.copy() + finished = False + block = None + + if finished: + newblock = block + else: + newblock = SpamBlock(newstate) + # unconditionally link the current block to the newblock + outputargs = currentstate.getoutputargs(newstate) + currentblock.closeblock(Link(outputargs, newblock)) + # phew + if not finished: + if block is not None and block.exits: + # to simplify the graph, we patch the old block to point + # directly at the new block which is its generalization + block.dead = True + block.operations = () + block.exitswitch = None + outputargs = block.framestate.getoutputargs(newstate) + block.recloseblock(Link(outputargs, newblock)) + candidates.insert(0, newblock) + self.pendingblocks.append(newblock) Modified: pypy/dist/pypy/objspace/flow/framestate.py ============================================================================== --- pypy/dist/pypy/objspace/flow/framestate.py (original) +++ pypy/dist/pypy/objspace/flow/framestate.py Sat Mar 5 15:27:00 2005 @@ -32,6 +32,7 @@ else: raise TypeError("can't get framestate for %r" % state.__class__.__name__) + self.next_instr = self.nonmergeable[1] for w1 in self.mergeable: assert isinstance(w1, (Variable, Constant)), ( '%r found in frame state' % w1) Modified: pypy/dist/pypy/objspace/flow/test/test_objspace.py ============================================================================== --- pypy/dist/pypy/objspace/flow/test/test_objspace.py (original) +++ pypy/dist/pypy/objspace/flow/test/test_objspace.py Sat Mar 5 15:27:00 2005 @@ -1,5 +1,5 @@ import autopath -from pypy.objspace.flow.model import Constant +from pypy.objspace.flow.model import Constant, Block, traverse from pypy.interpreter.argument import Arguments @@ -338,6 +338,8 @@ def test_specialcases(self): x = self.codetest(self.specialcases) + from pypy.translator.simplify import join_blocks + join_blocks(x) assert len(x.startblock.operations) == 13 for op in x.startblock.operations: assert op.opname in ['lt', 'le', 'eq', 'ne', @@ -346,6 +348,23 @@ assert op.args[0].value == 2 assert op.args[1].value == 3 + #__________________________________________________________ + def jump_target_specialization(x): + if x: + n = 5 + else: + n = 6 + return n*2 + + def test_jump_target_specialization(self): + x = self.codetest(self.jump_target_specialization) + self.show(x) + def visitor(node): + if isinstance(node, Block): + for op in node.operations: + assert op.opname != 'mul', "mul should have disappeared" + traverse(visitor, x) + DATA = {'x': 5, 'y': 6} From arigo at codespeak.net Sat Mar 5 15:40:43 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 5 Mar 2005 15:40:43 +0100 (MET) Subject: [pypy-svn] r9658 - pypy/dist/pypy/translator Message-ID: <20050305144043.0489E27B4C@code1.codespeak.net> Author: arigo Date: Sat Mar 5 15:40:43 2005 New Revision: 9658 Modified: pypy/dist/pypy/translator/geninterplevel.py Log: There is no point in using the flow space's SpecTag hints any more. It works just as well without. Modified: pypy/dist/pypy/translator/geninterplevel.py ============================================================================== --- pypy/dist/pypy/translator/geninterplevel.py (original) +++ pypy/dist/pypy/translator/geninterplevel.py Sat Mar 5 15:40:43 2005 @@ -105,7 +105,7 @@ self.space = FlowObjSpace() # for introspection self.use_fast_call = True - self.specialize_goto = True + self.specialize_goto = False self._labeltable = {} # unique label names, reused per func self._space_arities = None @@ -956,13 +956,13 @@ print >> f, docstr fast_locals = [arg for arg in localnames if arg not in fast_set] - # if goto is specialized, the false detection of - # uninitialized variables goes away. - if fast_locals and not self.specialize_goto: - print >> f - for line in self.large_initialize(fast_locals): - print >> f, " %s" % line - print >> f +## # if goto is specialized, the false detection of +## # uninitialized variables goes away. +## if fast_locals and not self.specialize_goto: +## print >> f +## for line in self.large_initialize(fast_locals): +## print >> f, " %s" % line +## print >> f # print the body for line in body: From arigo at codespeak.net Sat Mar 5 16:28:29 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 5 Mar 2005 16:28:29 +0100 (MET) Subject: [pypy-svn] r9659 - pypy/dist/pypy/annotation Message-ID: <20050305152829.923A127B4C@code1.codespeak.net> Author: arigo Date: Sat Mar 5 16:28:29 2005 New Revision: 9659 Modified: pypy/dist/pypy/annotation/classdef.py Log: Quick fix for the annotator discovering new classes... Modified: pypy/dist/pypy/annotation/classdef.py ============================================================================== --- pypy/dist/pypy/annotation/classdef.py (original) +++ pypy/dist/pypy/annotation/classdef.py Sat Mar 5 16:28:29 2005 @@ -81,7 +81,10 @@ self.add_source_for_attribute(name, sources.get(name, cls), self) def add_source_for_attribute(self, attr, source, clsdef=None): - self.find_attribute(attr).sources[source] = clsdef + attrdef = self.find_attribute(attr) + attrdef.sources[source] = clsdef + for position in attrdef.read_locations: + self.bookkeeper.annotator.reflowfromposition(position) def locate_attribute(self, attr): for cdef in self.getmro(): From arigo at codespeak.net Sat Mar 5 16:28:40 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 5 Mar 2005 16:28:40 +0100 (MET) Subject: [pypy-svn] r9660 - pypy/dist/pypy/objspace/flow Message-ID: <20050305152840.EA80B27B4C@code1.codespeak.net> Author: arigo Date: Sat Mar 5 16:28:40 2005 New Revision: 9660 Modified: pypy/dist/pypy/objspace/flow/flowcontext.py Log: Memory saver. Modified: pypy/dist/pypy/objspace/flow/flowcontext.py ============================================================================== --- pypy/dist/pypy/objspace/flow/flowcontext.py (original) +++ pypy/dist/pypy/objspace/flow/flowcontext.py Sat Mar 5 16:28:40 2005 @@ -265,6 +265,8 @@ for a in node.inputargs: mapping[a] = Variable(a) node.renamevariables(mapping) + elif isinstance(node, SpamBlock): + del node.framestate # memory saver traverse(fixegg, self.graph) def mergeblock(self, currentblock, currentstate): From arigo at codespeak.net Sat Mar 5 16:51:51 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 5 Mar 2005 16:51:51 +0100 (MET) Subject: [pypy-svn] r9661 - pypy/dist/pypy/translator/test Message-ID: <20050305155151.BCC4B27B4C@code1.codespeak.net> Author: arigo Date: Sat Mar 5 16:51:51 2005 New Revision: 9661 Modified: pypy/dist/pypy/translator/test/snippet.py pypy/dist/pypy/translator/test/test_annrpython.py Log: A test to verify that method calls are precise. Modified: pypy/dist/pypy/translator/test/snippet.py ============================================================================== --- pypy/dist/pypy/translator/test/snippet.py (original) +++ pypy/dist/pypy/translator/test/snippet.py Sat Mar 5 16:51:51 2005 @@ -465,6 +465,21 @@ i = MI_D() return i.a + i.b + i.c + i.d +class CBase(object): + pass +class CSub1(CBase): + def m(self): + self.x = 42 + return self +class CSub2(CBase): + def m(self): + self.x = 'world' + return self + +def methodcall_is_precise(): + return (CSub1().m(), CSub2().m()) + + def flow_type_info(i): if isinstance(i, int): a = i + 1 Modified: pypy/dist/pypy/translator/test/test_annrpython.py ============================================================================== --- pypy/dist/pypy/translator/test/test_annrpython.py (original) +++ pypy/dist/pypy/translator/test/test_annrpython.py Sat Mar 5 16:51:51 2005 @@ -558,6 +558,19 @@ assert s.knowntype == int assert not s.is_constant() # ! + def test_methodcall_is_precise(self): + a = RPythonAnnotator() + s = a.build_types(snippet.methodcall_is_precise, []) + classes = a.bookkeeper.userclasses + assert s == annmodel.SomeTuple([ + annmodel.SomeInstance(classes[snippet.CSub1]), + annmodel.SomeInstance(classes[snippet.CSub2])]) + assert 'x' not in classes[snippet.CBase].attrs + assert (classes[snippet.CSub1].attrs['x'].s_value == + a.bookkeeper.immutablevalue(42)) + assert (classes[snippet.CSub2].attrs['x'].s_value == + a.bookkeeper.immutablevalue('world')) + def g(n): return [0,1,2,n] From arigo at codespeak.net Sat Mar 5 16:56:07 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 5 Mar 2005 16:56:07 +0100 (MET) Subject: [pypy-svn] r9662 - pypy/dist/pypy/translator/test Message-ID: <20050305155607.AB47E27B4C@code1.codespeak.net> Author: arigo Date: Sat Mar 5 16:56:07 2005 New Revision: 9662 Modified: pypy/dist/pypy/translator/test/snippet.py pypy/dist/pypy/translator/test/test_annrpython.py Log: Sorry, this is how I meant the test to be. Modified: pypy/dist/pypy/translator/test/snippet.py ============================================================================== --- pypy/dist/pypy/translator/test/snippet.py (original) +++ pypy/dist/pypy/translator/test/snippet.py Sat Mar 5 16:56:07 2005 @@ -470,14 +470,16 @@ class CSub1(CBase): def m(self): self.x = 42 - return self class CSub2(CBase): def m(self): self.x = 'world' - return self -def methodcall_is_precise(): - return (CSub1().m(), CSub2().m()) +def methodcall_is_precise(cond): + if cond: + x = CSub1() + else: + x = CSub2() + x.m() def flow_type_info(i): Modified: pypy/dist/pypy/translator/test/test_annrpython.py ============================================================================== --- pypy/dist/pypy/translator/test/test_annrpython.py (original) +++ pypy/dist/pypy/translator/test/test_annrpython.py Sat Mar 5 16:56:07 2005 @@ -562,9 +562,6 @@ a = RPythonAnnotator() s = a.build_types(snippet.methodcall_is_precise, []) classes = a.bookkeeper.userclasses - assert s == annmodel.SomeTuple([ - annmodel.SomeInstance(classes[snippet.CSub1]), - annmodel.SomeInstance(classes[snippet.CSub2])]) assert 'x' not in classes[snippet.CBase].attrs assert (classes[snippet.CSub1].attrs['x'].s_value == a.bookkeeper.immutablevalue(42)) From arigo at codespeak.net Sat Mar 5 17:18:54 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 5 Mar 2005 17:18:54 +0100 (MET) Subject: [pypy-svn] r9663 - pypy/dist/pypy/translator/test Message-ID: <20050305161854.CF97C27B4C@code1.codespeak.net> Author: arigo Date: Sat Mar 5 17:18:54 2005 New Revision: 9663 Modified: pypy/dist/pypy/translator/test/snippet.py pypy/dist/pypy/translator/test/test_annrpython.py Log: Yet another try at what I really want to check. Modified: pypy/dist/pypy/translator/test/snippet.py ============================================================================== --- pypy/dist/pypy/translator/test/snippet.py (original) +++ pypy/dist/pypy/translator/test/snippet.py Sat Mar 5 17:18:54 2005 @@ -470,9 +470,11 @@ class CSub1(CBase): def m(self): self.x = 42 + return self.x class CSub2(CBase): def m(self): self.x = 'world' + return self.x def methodcall_is_precise(cond): if cond: @@ -480,6 +482,7 @@ else: x = CSub2() x.m() + return CSub1().m() def flow_type_info(i): Modified: pypy/dist/pypy/translator/test/test_annrpython.py ============================================================================== --- pypy/dist/pypy/translator/test/test_annrpython.py (original) +++ pypy/dist/pypy/translator/test/test_annrpython.py Sat Mar 5 17:18:54 2005 @@ -567,6 +567,7 @@ a.bookkeeper.immutablevalue(42)) assert (classes[snippet.CSub2].attrs['x'].s_value == a.bookkeeper.immutablevalue('world')) + assert s == a.bookkeeper.immutablevalue(42) def g(n): From arigo at codespeak.net Sat Mar 5 17:29:08 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 5 Mar 2005 17:29:08 +0100 (MET) Subject: [pypy-svn] r9664 - pypy/dist/pypy/annotation Message-ID: <20050305162908.929FA27B4C@code1.codespeak.net> Author: arigo Date: Sat Mar 5 17:29:08 2005 New Revision: 9664 Modified: pypy/dist/pypy/annotation/classdef.py pypy/dist/pypy/annotation/unaryop.py Log: More precise calls to methods. Modified: pypy/dist/pypy/annotation/classdef.py ============================================================================== --- pypy/dist/pypy/annotation/classdef.py (original) +++ pypy/dist/pypy/annotation/classdef.py Sat Mar 5 17:29:08 2005 @@ -157,6 +157,7 @@ for clsdef in self.getmro(): if attr in clsdef.attrs: clsdef._generalize_attr(attr, s_value) + break else: self._generalize_attr(attr, s_value) Modified: pypy/dist/pypy/annotation/unaryop.py ============================================================================== --- pypy/dist/pypy/annotation/unaryop.py (original) +++ pypy/dist/pypy/annotation/unaryop.py Sat Mar 5 17:29:08 2005 @@ -166,7 +166,22 @@ attrdef = ins.classdef.find_attribute(attr) position = getbookkeeper().position_key attrdef.read_locations[position] = True - return attrdef.getvalue() + s_result = attrdef.getvalue() + # hack: if s_result is a set of methods, discard the ones + # that can't possibly apply to an instance of ins.classdef. + if isinstance(s_result, SomePBC): + d = {} + for func, value in s_result.prebuiltinstances.items(): + if (isclassdef(value) and + value not in ins.classdef.getmro() and + ins.classdef not in value.getmro()): + continue + d[func] = value + if d: + s_result = SomePBC(d) + else: + s_result = SomeImpossibleValue() + return s_result return SomeObject() def setattr(ins, s_attr, s_value): From pedronis at codespeak.net Sat Mar 5 17:37:48 2005 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Sat, 5 Mar 2005 17:37:48 +0100 (MET) Subject: [pypy-svn] r9665 - pypy/dist/pypy/translator Message-ID: <20050305163748.B0EC327B4C@code1.codespeak.net> Author: pedronis Date: Sat Mar 5 17:37:48 2005 New Revision: 9665 Modified: pypy/dist/pypy/translator/translator.py Log: make simplfying (which is needed by exception handling annotation) the default Modified: pypy/dist/pypy/translator/translator.py ============================================================================== --- pypy/dist/pypy/translator/translator.py (original) +++ pypy/dist/pypy/translator/translator.py Sat Mar 5 17:37:48 2005 @@ -46,7 +46,7 @@ class Translator: - def __init__(self, func=None, verbose=False, simplifying=False, builtins_can_raise_exceptions=False): + def __init__(self, func=None, verbose=False, simplifying=True, builtins_can_raise_exceptions=False): self.entrypoint = func self.verbose = verbose self.simplifying = simplifying From pedronis at codespeak.net Sat Mar 5 17:39:03 2005 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Sat, 5 Mar 2005 17:39:03 +0100 (MET) Subject: [pypy-svn] r9666 - pypy/dist/pypy/translator/tool/pygame Message-ID: <20050305163903.361DE27B4C@code1.codespeak.net> Author: pedronis Date: Sat Mar 5 17:39:03 2005 New Revision: 9666 Modified: pypy/dist/pypy/translator/tool/pygame/graphdisplay.py Log: allow to use the space-bar and not only the clicks to follow word links Modified: pypy/dist/pypy/translator/tool/pygame/graphdisplay.py ============================================================================== --- pypy/dist/pypy/translator/tool/pygame/graphdisplay.py (original) +++ pypy/dist/pypy/translator/tool/pygame/graphdisplay.py Sat Mar 5 17:39:03 2005 @@ -99,6 +99,7 @@ 'shift up' : ('fast_pan', (0, -1)), 'shift down' : ('fast_pan', (0, 1)), 'help': 'help', + 'space': 'hit', } HELP_MSG = """ @@ -112,6 +113,8 @@ Arrows Scroll Shift+Arrows Scroll faster + Space Follow word link + Backspace Go back in history Meta Left Go back in history Meta Right Go forward in history @@ -276,6 +279,18 @@ if text != old_text: draw(prompt + text) + def hit(self): + word = self.highlight_word + if word is not None: + if word in self.layout.links: + self.setstatusbar('loading...') + self.redraw_now() + newlayout = self.layout.followlink(word) + if newlayout is not None: + self.setlayout(newlayout) + return + self.setstatusbar('') + def search(self): searchstr = self.input('Find: ') if not searchstr: From arigo at codespeak.net Sat Mar 5 17:44:11 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 5 Mar 2005 17:44:11 +0100 (MET) Subject: [pypy-svn] r9667 - pypy/dist/pypy/annotation Message-ID: <20050305164411.017BF27B4C@code1.codespeak.net> Author: arigo Date: Sat Mar 5 17:44:11 2005 New Revision: 9667 Modified: pypy/dist/pypy/annotation/classdef.py pypy/dist/pypy/annotation/unaryop.py Log: Fix confusing debugging helper Modified: pypy/dist/pypy/annotation/classdef.py ============================================================================== --- pypy/dist/pypy/annotation/classdef.py (original) +++ pypy/dist/pypy/annotation/classdef.py Sat Mar 5 17:44:11 2005 @@ -77,7 +77,8 @@ if name.startswith('_') and not isinstance(value, FunctionType): continue if isinstance(value, FunctionType): - value.class_ = cls # remember that this is really a method + if not hasattr(value, 'class_'): + value.class_ = cls # remember that this is really a method self.add_source_for_attribute(name, sources.get(name, cls), self) def add_source_for_attribute(self, attr, source, clsdef=None): Modified: pypy/dist/pypy/annotation/unaryop.py ============================================================================== --- pypy/dist/pypy/annotation/unaryop.py (original) +++ pypy/dist/pypy/annotation/unaryop.py Sat Mar 5 17:44:11 2005 @@ -169,6 +169,7 @@ s_result = attrdef.getvalue() # hack: if s_result is a set of methods, discard the ones # that can't possibly apply to an instance of ins.classdef. + # XXX do it more nicely if isinstance(s_result, SomePBC): d = {} for func, value in s_result.prebuiltinstances.items(): From pedronis at codespeak.net Sat Mar 5 20:14:54 2005 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Sat, 5 Mar 2005 20:14:54 +0100 (MET) Subject: [pypy-svn] r9669 - in pypy/dist/pypy: annotation translator/test Message-ID: <20050305191454.3204627B4C@code1.codespeak.net> Author: pedronis Date: Sat Mar 5 20:14:53 2005 New Revision: 9669 Modified: pypy/dist/pypy/annotation/bookkeeper.py pypy/dist/pypy/annotation/classdef.py pypy/dist/pypy/translator/test/snippet.py pypy/dist/pypy/translator/test/test_annrpython.py Log: first cut at activating support for specialized classes. Notice the code to make the original class appear totally abstract. + test Modified: pypy/dist/pypy/annotation/bookkeeper.py ============================================================================== --- pypy/dist/pypy/annotation/bookkeeper.py (original) +++ pypy/dist/pypy/annotation/bookkeeper.py Sat Mar 5 20:14:53 2005 @@ -12,6 +12,8 @@ from pypy.interpreter.pycode import cpython_code_signature from pypy.interpreter.argument import ArgErr +import inspect, new + class Bookkeeper: """The log of choices that have been made while analysing the operations. It ensures that the same 'choice objects' will be returned if we ask @@ -259,8 +261,26 @@ # thing = func_with_new_name(thing, name or thing.func_name) elif isinstance(thing, (type, ClassType)): - assert not "not working yet" - thing = type(thing)(name or thing.__name__, (thing,)) + superclasses = iter(inspect.getmro(thing)) + superclasses.next() # skip thing itself + for cls in superclasses: + assert not hasattr(cls, "_specialize_"), "for now specialization only for leaf classes" + + newdict = {} + for attrname,val in thing.__dict__.iteritems(): + if attrname == '_specialize_': # don't copy the marker + continue + if isinstance(val, FunctionType): + fname = val.func_name + if name: + fname = "%s_for_%s" % (fname, name) + newval = func_with_new_name(val, fname) + # xxx more special cases + else: + newval = val + newdict[attrname] = newval + + thing = type(thing)(name or thing.__name__, (thing,), newdict) else: raise Exception, "specializing %r?? why??"%thing self.cachespecializations[key] = thing Modified: pypy/dist/pypy/annotation/classdef.py ============================================================================== --- pypy/dist/pypy/annotation/classdef.py (original) +++ pypy/dist/pypy/annotation/classdef.py Sat Mar 5 20:14:53 2005 @@ -66,7 +66,10 @@ assert base is object, ("multiple inheritance only supported " "with _mixin_: %r" % (cls,)) base = b1 - mixeddict.update(cls.__dict__) + if '_specialize_' not in cls.__dict__: # otherwise make the original specialized class appear empty + mixeddict.update(cls.__dict__) + else: + assert not mixeddict, " _specialize_ + mixins not both supported right now" self.basedef = bookkeeper.getclassdef(base) if self.basedef: self.basedef.subdefs[cls] = self Modified: pypy/dist/pypy/translator/test/snippet.py ============================================================================== --- pypy/dist/pypy/translator/test/snippet.py (original) +++ pypy/dist/pypy/translator/test/snippet.py Sat Mar 5 20:14:53 2005 @@ -1002,6 +1002,30 @@ raise Exception +# class specialization +class PolyStk: + _specialize_ = 'location' + + def __init__(self): + self.itms = [] + + def push(self, v): + self.itms.append(v) + + def top(self): + return self.itms[-1] + + +def class_spec(): + istk = PolyStk() + istk.push(1) + sstk = PolyStk() + sstk.push("a") + istk.push(2) + sstk.push("b") + if not isinstance(istk, PolyStk): + return "confused" + return istk.top(), sstk.top() Modified: pypy/dist/pypy/translator/test/test_annrpython.py ============================================================================== --- pypy/dist/pypy/translator/test/test_annrpython.py (original) +++ pypy/dist/pypy/translator/test/test_annrpython.py Sat Mar 5 20:14:53 2005 @@ -569,6 +569,11 @@ a.bookkeeper.immutablevalue('world')) assert s == a.bookkeeper.immutablevalue(42) + def test_class_spec(self): + a = RPythonAnnotator() + s = a.build_types(snippet.class_spec, []) + assert s.items[0].knowntype == int + assert s.items[1].knowntype == str def g(n): return [0,1,2,n] From pedronis at codespeak.net Sun Mar 6 00:29:15 2005 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Sun, 6 Mar 2005 00:29:15 +0100 (MET) Subject: [pypy-svn] r9670 - pypy/dist/pypy/annotation Message-ID: <20050305232915.C797A27B44@code1.codespeak.net> Author: pedronis Date: Sun Mar 6 00:29:15 2005 New Revision: 9670 Modified: pypy/dist/pypy/annotation/classdef.py pypy/dist/pypy/annotation/unaryop.py Log: reorg of SomeInstance getattr logic for methods Modified: pypy/dist/pypy/annotation/classdef.py ============================================================================== --- pypy/dist/pypy/annotation/classdef.py (original) +++ pypy/dist/pypy/annotation/classdef.py Sun Mar 6 00:29:15 2005 @@ -4,7 +4,7 @@ from __future__ import generators from types import FunctionType -from pypy.annotation.model import SomeImpossibleValue, unionof +from pypy.annotation.model import SomeImpossibleValue, SomePBC, unionof class Attribute: @@ -119,6 +119,9 @@ yield self self = self.basedef + def issubclass(self, otherclsdef): + return issubclass(self.cls, otherclsdef.cls) + def getallsubdefs(self): pending = [self] seen = {} @@ -175,6 +178,18 @@ return None return None + def matching(self, pbc): + d = {} + for func, value in pbc.prebuiltinstances.items(): + if isclassdef(value): + if not value.issubclass(self) and not self.issubclass(value): + continue + d[func] = value + if d: + return SomePBC(d) + else: + return SomeImpossibleValue() + def isclassdef(x): return isinstance(x, ClassDef) Modified: pypy/dist/pypy/annotation/unaryop.py ============================================================================== --- pypy/dist/pypy/annotation/unaryop.py (original) +++ pypy/dist/pypy/annotation/unaryop.py Sun Mar 6 00:29:15 2005 @@ -171,17 +171,7 @@ # that can't possibly apply to an instance of ins.classdef. # XXX do it more nicely if isinstance(s_result, SomePBC): - d = {} - for func, value in s_result.prebuiltinstances.items(): - if (isclassdef(value) and - value not in ins.classdef.getmro() and - ins.classdef not in value.getmro()): - continue - d[func] = value - if d: - s_result = SomePBC(d) - else: - s_result = SomeImpossibleValue() + s_result = ins.classdef.matching(s_result) return s_result return SomeObject() From pedronis at codespeak.net Sun Mar 6 01:02:24 2005 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Sun, 6 Mar 2005 01:02:24 +0100 (MET) Subject: [pypy-svn] r9671 - pypy/dist/pypy/annotation Message-ID: <20050306000224.E202427B44@code1.codespeak.net> Author: pedronis Date: Sun Mar 6 01:02:24 2005 New Revision: 9671 Modified: pypy/dist/pypy/annotation/classdef.py Log: try to be more precise with SomeInstance.getattr and methods, this avoids having to fake an empty dict for specialized classes. Modified: pypy/dist/pypy/annotation/classdef.py ============================================================================== --- pypy/dist/pypy/annotation/classdef.py (original) +++ pypy/dist/pypy/annotation/classdef.py Sun Mar 6 01:02:24 2005 @@ -66,10 +66,8 @@ assert base is object, ("multiple inheritance only supported " "with _mixin_: %r" % (cls,)) base = b1 - if '_specialize_' not in cls.__dict__: # otherwise make the original specialized class appear empty - mixeddict.update(cls.__dict__) - else: - assert not mixeddict, " _specialize_ + mixins not both supported right now" + mixeddict.update(cls.__dict__) + self.basedef = bookkeeper.getclassdef(base) if self.basedef: self.basedef.subdefs[cls] = self @@ -180,16 +178,28 @@ def matching(self, pbc): d = {} + uplookup = None + upfunc = None for func, value in pbc.prebuiltinstances.items(): if isclassdef(value): - if not value.issubclass(self) and not self.issubclass(value): + if value is not self and value.issubclass(self): + pass # subclasses methods are always candidates + elif self.issubclass(value): # upward consider only the best match + if uplookup is None or value.issubclass(uplookup): + uplookup = value + upfunc = func continue + # for clsdef1 >= clsdef2 + # clsdef1.matching(pbc) includes clsdef2.matching(pbc) + else: + continue # not matching d[func] = value + if uplookup is not None: + d[upfunc] = uplookup if d: return SomePBC(d) else: return SomeImpossibleValue() - def isclassdef(x): return isinstance(x, ClassDef) From arigo at codespeak.net Sun Mar 6 19:31:35 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sun, 6 Mar 2005 19:31:35 +0100 (MET) Subject: [pypy-svn] r9675 - in pypy/dist/pypy/objspace/flow: . test Message-ID: <20050306183135.6D24B27B47@code1.codespeak.net> Author: arigo Date: Sun Mar 6 19:31:35 2005 New Revision: 9675 Modified: pypy/dist/pypy/objspace/flow/flowcontext.py pypy/dist/pypy/objspace/flow/test/test_model.py pypy/dist/pypy/objspace/flow/test/test_objspace.py Log: Removed a case where the flow objspace would repeat some operations: near the beginning of the function. Cleaned up the tests, which were too precise about the shape and generally not precise enough about what's really in the graph. Modified: pypy/dist/pypy/objspace/flow/flowcontext.py ============================================================================== --- pypy/dist/pypy/objspace/flow/flowcontext.py (original) +++ pypy/dist/pypy/objspace/flow/flowcontext.py Sun Mar 6 19:31:35 2005 @@ -71,32 +71,33 @@ self.crnt_block = block # saved state at the join point most recently seen self.last_join_point = None - self.progress = False + self.enterspamblock = isinstance(block, SpamBlock) def append(self, operation): if self.last_join_point is not None: - # don't add more operations if we already crossed a join point + # only add operations corresponding to the first bytecode raise MergeBlock(self.crnt_block, self.last_join_point) self.crnt_block.operations.append(operation) def bytecode_trace(self, ec, frame): assert frame is ec.crnt_frame, "seeing an unexpected frame!" - next_instr = frame.next_instr - if self.crnt_block.operations or isinstance(self.crnt_block, EggBlock): - # if we have already produced at least one operation or a branch, - # make a join point as early as possible (but not before we - # actually try to generate more operations) - self.last_join_point = FrameState(frame) - else: - ec.crnt_offset = next_instr # save offset for opcode + ec.crnt_offset = frame.next_instr # save offset for opcode + if self.enterspamblock: + # If we have a SpamBlock, the first call to bytecode_trace() + # occurs as soon as frame.resume() starts, before interpretation + # really begins. varnames = frame.code.getvarnames() for name, w_value in zip(varnames, frame.getfastscope()): if isinstance(w_value, Variable): w_value.rename(name) - # record passage over already-existing join points - if self.progress and next_instr in ec.joinpoints: - self.last_join_point = FrameState(frame) - self.progress = True + self.enterspamblock = False + else: + # At this point, we progress to the next bytecode. When this + # occurs, we no longer allow any more operations to be recorded in + # the same block. We will continue, to figure out where the next + # such operation *would* appear, and we make a join point just + # before. + self.last_join_point = FrameState(frame) def guessbool(self, ec, w_condition, cases=[False,True], replace_last_variable_except_in_first_case = None): @@ -259,14 +260,27 @@ # EggBlocks reuse the variables of their previous block, # which is deemed not acceptable for simplicity of the operations # that will be performed later on the flow graph. - def fixegg(node): - if isinstance(node, EggBlock): - mapping = {} - for a in node.inputargs: - mapping[a] = Variable(a) - node.renamevariables(mapping) - elif isinstance(node, SpamBlock): - del node.framestate # memory saver + def fixegg(link): + if isinstance(link, Link): + block = link.target + if isinstance(block, EggBlock): + if (not block.operations and len(block.exits) == 1 and + link.args == block.inputargs): # not renamed + # if the variables are not renamed across this link + # (common case for EggBlocks) then it's easy enough to + # get rid of the empty EggBlock. + link2 = block.exits[0] + link.args = list(link2.args) + link.target = link2.target + assert link2.exitcase is None + fixegg(link) + else: + mapping = {} + for a in block.inputargs: + mapping[a] = Variable(a) + block.renamevariables(mapping) + elif isinstance(link, SpamBlock): + del link.framestate # memory saver traverse(fixegg, self.graph) def mergeblock(self, currentblock, currentstate): Modified: pypy/dist/pypy/objspace/flow/test/test_model.py ============================================================================== --- pypy/dist/pypy/objspace/flow/test/test_model.py (original) +++ pypy/dist/pypy/objspace/flow/test/test_model.py Sun Mar 6 19:31:35 2005 @@ -24,9 +24,7 @@ def test_simplefunc(self): graph = self.getflow(self.simplefunc) - l = flatten(graph) - #print l - assert len(l) == 4 + assert all_operations(graph) == {'add': 1} def test_class(self): graph = self.getflow(self.simplefunc) @@ -45,32 +43,32 @@ v = MyVisitor() traverse(v, graph) - assert len(v.blocks) == 2 - assert len(v.links) == 1 + #assert len(v.blocks) == 2 + #assert len(v.links) == 1 assert v.graph == graph assert v.links[0] == graph.startblock.exits[0] - def test_partial_class(self): - graph = self.getflow(self.simplefunc) +## def test_partial_class(self): +## graph = self.getflow(self.simplefunc) - class MyVisitor: - def __init__(self): - self.blocks = [] - self.links = [] - - def visit_FunctionGraph(self, graph): - self.graph = graph - def visit_Block(self, block): - self.blocks.append(block) - def visit(self, link): - self.links.append(link) - - v = MyVisitor() - traverse(v, graph) - assert len(v.blocks) == 2 - assert len(v.links) == 1 - assert v.graph == graph - assert v.links[0] == graph.startblock.exits[0] +## class MyVisitor: +## def __init__(self): +## self.blocks = [] +## self.links = [] + +## def visit_FunctionGraph(self, graph): +## self.graph = graph +## def visit_Block(self, block): +## self.blocks.append(block) +## def visit(self, link): +## self.links.append(link) + +## v = MyVisitor() +## traverse(v, graph) +## assert len(v.blocks) == 2 +## assert len(v.links) == 1 +## assert v.graph == graph +## assert v.links[0] == graph.startblock.exits[0] def loop(x): x = abs(x) @@ -78,6 +76,18 @@ x = x - 1 def test_loop(self): - graph = self.getflow(self.simplefunc) - l = flatten(graph) - assert len(l) == 4 + graph = self.getflow(self.loop) + assert all_operations(graph) == {'simple_call': 1, + 'is_true': 1, + 'sub': 1} + + +def all_operations(graph): + result = {} + def visit(node): + if isinstance(node, Block): + for op in node.operations: + result.setdefault(op.opname, 0) + result[op.opname] += 1 + traverse(visit, graph) + return result Modified: pypy/dist/pypy/objspace/flow/test/test_objspace.py ============================================================================== --- pypy/dist/pypy/objspace/flow/test/test_objspace.py (original) +++ pypy/dist/pypy/objspace/flow/test/test_objspace.py Sun Mar 6 19:31:35 2005 @@ -1,6 +1,7 @@ import autopath from pypy.objspace.flow.model import Constant, Block, traverse from pypy.interpreter.argument import Arguments +from pypy.translator.simplify import simplify_graph objspacename = 'flow' @@ -256,6 +257,7 @@ def test_raise3(self): x = self.codetest(self.raise3) self.show(x) + simplify_graph(x) assert len(x.startblock.operations) == 1 assert x.startblock.operations[0].opname == 'simple_call' assert list(x.startblock.operations[0].args) == [ From pedronis at codespeak.net Thu Mar 10 14:02:36 2005 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Thu, 10 Mar 2005 14:02:36 +0100 (MET) Subject: [pypy-svn] r9724 - pypy/dist/pypy/tool Message-ID: <20050310130236.3A2A127B3E@code1.codespeak.net> Author: pedronis Date: Thu Mar 10 14:02:36 2005 New Revision: 9724 Added: pypy/dist/pypy/tool/delta.css (contents, props changed) pypy/dist/pypy/tool/delta.js (contents, props changed) pypy/dist/pypy/tool/delta.py (contents, props changed) Log: tool to generate summary pages about implementation status of (builtin) modules, classes and types. We propably need to pick a canonical set of modules we really care about, and then publish the results consistently. Added: pypy/dist/pypy/tool/delta.css ============================================================================== --- (empty file) +++ pypy/dist/pypy/tool/delta.css Thu Mar 10 14:02:36 2005 @@ -0,0 +1,17 @@ +body { font-family: arial, helvetica, sans-serif; } + +.title {font-size: 2em; font-weight: bolder } + +.even { background: #d0d0d0; } +.odd { background: white; } + +table { border-spacing: 0pt } + +a { color: inherit; } +a:hover { background: yellow } +a:visited:hover { background: inherit } + +.missing { color: red } +.faked { color: red; font-style: italic } +.somemissing { color: maroon } +.only_in { font-style: italic } \ No newline at end of file Added: pypy/dist/pypy/tool/delta.js ============================================================================== --- (empty file) +++ pypy/dist/pypy/tool/delta.js Thu Mar 10 14:02:36 2005 @@ -0,0 +1,15 @@ + + +toggle_list = ['alpha', 'grandmissing', 'incompleteness']; +TABLE_HIDE = "display: none" +TABLE_SHOW = "display: table" + +function toggle(on) { + for (i in toggle_list) { + x = toggle_list[i]; + if (x!=on) { + document.getElementById(x).setAttribute("style", TABLE_HIDE); + } + }; + document.getElementById(on).setAttribute("style", TABLE_SHOW); +} \ No newline at end of file Added: pypy/dist/pypy/tool/delta.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/tool/delta.py Thu Mar 10 14:02:36 2005 @@ -0,0 +1,712 @@ +import autopath +from pypy.interpreter.error import OperationError + +from py.xml import html + +class html_plus(html): + __tagspec__ = html.__tagspec__.copy() + + __tagspec__['button'] = 1 + __tagspec__['script'] = 1 + +html = html_plus + +import os, sys +from sets import Set + +W = 125 +H = 12 + +RED = "#ff0000" +WHITE = "#ffffff" +BLACK = "#000000" +GREY = "#808080" + +def incompleteness_bar(DIR, incompleteness): + from PIL import Image, ImageDraw, ImageColor + + red = ImageColor.getrgb(RED) + white = ImageColor.getrgb(WHITE) + black = ImageColor.getrgb(BLACK) + grey = ImageColor.getrgb(GREY) + + if incompleteness == -1.0: + inc = -1 + name = "bar_none.png" + else: + inc = round((W-1) * incompleteness) + if inc == 0 and incompleteness != 0: + inc == 1 + name = "bar_%d.png" % inc + + imgfname = os.path.join(DIR,'images',name) + + if not os.path.exists(imgfname): + img = Image.new("RGB",(W,H), red) + draw = ImageDraw.Draw(img) + + if inc == -1: + draw.rectangle([0,0,W-1,H-1], outline=black, fill=white) + else: + if W-1-inc != 0: + draw.rectangle([0,0,W-1-inc,H-1],outline=grey, fill=grey) + + IMGDIR = os.path.join(DIR,'images') + + if not os.path.isdir(IMGDIR): + os.mkdir(IMGDIR) + + img.save(imgfname,optimize=True) + + return html.img(src=os.path.join('images', name),alt="incompleteness=%.2f" % incompleteness) + + +NOTFOUND = object() + +class Explore: + + def __init__(self, label): + self.label = label + self.type_names = {} + + def get_module(self, name): + pass + + def names(self, obj): + if obj is NOTFOUND: + return [] + return self.donames(obj) + + + def donames(self, obj): + pass + + def findattr(self, obj, name): + if obj is NOTFOUND: + return NOTFOUND + return self.dofindattr(obj, name) + + def dofindattr(self, obj, name): + pass + + def get_kind(self, obj): + if obj is NOTFOUND: + return '-' + if self.is_class(obj): + return 'C' + elif self.findattr(obj, '__call__') is not NOTFOUND: + return '()' + else: + return '_' + + def is_class(self, obj): + if obj is NOTFOUND: + return False + return self.dois_class(obj) + + def is_faked(self, obj): + return False + + def get_mro(self, obj): + if obj is NOTFOUND: + return [] + return self.doget_mro(obj) + + def doget_mro(self, obj): + pass + + #def get_type(self, obj): + # pass + # + #def assign_class_name(obj, name): + # if obj in self.type_names: + # return + # self.type_names[obj] = name + # + #def get_lazy_class_name(obj): + # return lambda: self.type_names[obj] + + +class HostExplore(Explore): + + def __init__(self): + import sys + Explore.__init__(self, "CPython %s" % sys.version) + + def get_module(self, name): + try: + return __import__(name,{},{},['*']) + except ImportError: + return NOTFOUND + + def donames(self, obj): + return obj.__dict__.keys() + + def dofindattr(self, obj, name): + return getattr(obj, name, NOTFOUND) + + def dois_class(self, obj): + import types + return type(obj) in (type, types.ClassType) + + def doget_mro(self, obj): + import inspect + return inspect.getmro(obj) + + #def get_type(self, obj): + # return type(obj) + + +def abstract_mro(obj, get_bases, acc=None): + if acc is None: + acc = [] + if obj in acc: + return acc + acc.append(obj) + for base in get_bases(obj): + abstract_mro(base, get_bases, acc) + return acc + +class ObjSpaceExplore(Explore): + + def __init__(self, space): + Explore.__init__(self, "PyPy/%s" % space.__class__.__name__) + self.space = space + + def get_module(self, name): + space = self.space + w = space.wrap + try: + return space.builtin.call('__import__', w(name),w({}),w({}),w(['*'])) + except OperationError: + return NOTFOUND + + def donames(self, obj): + space = self.space + return space.unwrap(space.call_method(space.getattr(obj, space.wrap('__dict__')), 'keys')) + + def dofindattr(self, obj, name): + space = self.space + try: + return space.getattr(obj, space.wrap(name)) + except OperationError: + return NOTFOUND + + def is_faked(self, obj): + if hasattr(obj, 'instancetypedef'): + return hasattr(obj.instancetypedef, 'fakedcpytype') + else: + return self.is_faked(self.space.type(obj)) + + def dois_class(self, obj): + #space = self.space + #w_t = space.type(obj) + #if space.is_w(w_t, space.w_type) or space.is_w(w_t, space.w_classobj): + # return True + return self.findattr(obj, '__bases__') is not NOTFOUND + + def doget_mro(self, obj): + space = self.space + try: + return space.unpackiterable(space.getattr(obj, space.wrap('__mro__'))) + except OperationError: + def get_bases(obj): + return space.unpackiterable(space.getattr(obj, space.wrap('__bases__'))) + + return abstract_mro(obj, get_bases) + + #def get_type(self, obj): + # return type(obj) + + +class Status: + def __init__(self, msg, detail_missing, class_, incompleteness): + self.msg = msg + self.detail_missing = detail_missing + self.class_ = class_ + self.incompleteness = incompleteness + +class Entry: + + def __init__(self, name): + self.name = name + self.shortname = name + self.status = 'PRESENT' + + def __repr__(self): + return "<%s %s>" % (self.__class__.__name__, self.name) + + def __str__(self): + return self.name + + def set_status(self, obj1, obj2, expl1): + if obj1 is NOTFOUND: + assert obj2 is not NOTFOUND, "whoopsy %s" % self.name + self.status = 'MISSING' + self.specifically = 'missing' + elif expl1.is_faked(obj1): + assert obj2 is not NOTFOUND, "whoopsy %s" % self.name + self.status = 'MISSING' + self.specifically = 'faked' + elif obj2 is NOTFOUND: + self.status = expl1 + + def only_in(self, parent): + if parent is not None and parent.status != 'PRESENT': + return "" + return 'only in %s' % self.status.label + + def status_wrt(self, parent=None): + detail_missing = 0 + incompleteness = 0.0 + if self.status == 'MISSING': + class_= msg = self.specifically + detail_missing = 1 + incompleteness = 1.0 + elif self.status == 'PRESENT': + msg = '' + class_ = None + else: + msg = self.only_in(parent) + if msg: + class_ = "only_in" + else: + class_ = None + incompleteness = -1.0 + return Status(msg, detail_missing, class_, incompleteness) + + def attach(self, parent, annot=None, name=None): + if self.status == 'MISSING': + parent.total += 1 + parent.missing += 1 + elif self.status == 'PRESENT': + parent.total += 1 + + if annot is None: + parent.add_row(self, [], name=name, parent=parent) + else: + parent.add_row(self, [annot], name=name, parent=parent) + + def grandadd(self, parent): + if self.status == 'MISSING': + parent.grandtotal += 1 + parent.grandmissing += 1 + elif self.status == 'PRESENT': + parent.grandtotal += 1 + + def handle(self): + return self.shortname, # 1-tuple! + + def link(self, name): + h = self.handle() + if len(h) == 1: + h = h[0] + if name is None: + return h + if name.endswith(h): + return name + return "%s [%s]" % (name, h) + else: + h, dest = h + if name is None: + return html.a(h, href=dest) + if name.endswith(h): + return html.a(name, href=dest) + return html.span(name, " [", + html.a(h, href=dest), "]") + + + +reports = [] + +class Report(Entry): + + notes = None + + def __init__(self, name, title=None, fname=None, notes=None): + if title is None: + title = name + Entry.__init__(self, name) + + self.title = title + + self.rows = [] + + reports.append(self) + + self.total = 0 + self.missing = 0 + + self.grandtotal = 0 + self.grandmissing = 0 + + self._fname = fname + + if notes is not None: + self.notes = notes + + def add_row(self, entry, rest, name=None, parent=None): + self.rows.append((name, entry, rest, parent)) + + def missing_stats(self, missing, total): + return "%s/%s missing (%.1f%%)" % (missing, total, float(missing)/total*100) + + def status_wrt(self, parent=None): + detail_missing = 0 + incompleteness = 0.0 + + if self.status == 'MISSING': + msg = "%s (%s)" % (self.specifically, self.total) + detail_missing = self.total + if self.grandtotal: + msg = "%s or in detail (%s)" % (msg, self.grandtotal) + detail_missing = self.grandtotal + return Status(msg, detail_missing, class_=self.specifically, incompleteness=1.0) + elif self.status == 'PRESENT': + if self.missing == 0 and self.grandmissing == 0: + return Status(msg="complete", detail_missing=detail_missing, class_=None, + incompleteness=incompleteness) + if self.missing == 0: + msg = "all present but" + incompleteness = 1.0 + else: + msg = self.missing_stats(self.missing, self.total) + detail_missing = self.missing + incompleteness = float(self.missing) / self.total + + if self.grandtotal: + msg = "%s in detail %s" % (msg, + self.missing_stats(self.grandmissing, self.grandtotal)) + detail_missing = self.grandmissing + incompleteness = (incompleteness + float(self.grandmissing)/self.grandtotal)/2 + return Status(msg, detail_missing, class_='somemissing', + incompleteness=incompleteness) + else: + msg = self.only_in(parent) + if msg: + class_ = "only_in" + else: + class_ = None + return Status(msg, detail_missing=0, class_=class_, + incompleteness=-1.0) + + def fname(self): + fname = self._fname + if fname is None: + fname = self.name + return fname+'.html' + + def handle(self): + return self.shortname, self.fname() + + def fill_table(self, dir, tbl, rows): + def set_class(class_): + if class_ is None: + return {} + else: + return {'class': class_} + + i = 0 + for name, entry, rest, st in rows: + tr_class = i%2 == 0 and "even" or "odd" + rest = rest + [st.msg, incompleteness_bar(dir, st.incompleteness)] + tbl.append(html.tr( + html.td(entry.link(name), **set_class(st.class_)), + *map(html.td,rest), **{'class': tr_class}) + ) + i += 1 + + def html(self, dir): + title = self.title + + def set_class(class_): + if class_ is None: + return {} + else: + return {'class': class_} + + if self.notes is not None: + notes = html.p(self.notes) + else: + notes = html.p() + + st = self.status_wrt() + + msg = st.msg + class_ = st.class_ + bar = incompleteness_bar(dir, st.incompleteness) + + HEADER = ''' +''' + + HIDE = 'display: none' + SHOW = 'display: table' + + alpha_table = html.table(id="alpha", style=SHOW) + grandmissing_table = html.table(id="grandmissing", style=HIDE) + incompleteness_table = html.table(id="incompleteness", style=HIDE) + + toggle = html.p("sort:", + html.button("alphabetical", type="button", onclick="toggle('alpha')"),'|', + html.button("incompleteness", type="button", onclick="toggle('incompleteness')"),'|', + html.button("# overall missing", type="button", onclick="toggle('grandmissing')")) + + page = html.html( + html.head(html.title(title), + html.link(href="delta.css", rel="stylesheet", type="text/css"), + html.script(type="text/javascript",src="delta.js")), + html.body(self.navig(), + html.p(msg, bar, **set_class(class_)), + toggle, + alpha_table, + grandmissing_table, + incompleteness_table, + notes), xmlns="http://www.w3.org/1999/xhtml") + + rows = [] + for name, entry, rest, parent in self.rows: + st = entry.status_wrt(parent) + rows.append((name, entry, rest, st)) + + self.fill_table(dir, alpha_table, rows) + + rows.sort(lambda (name1, ent1, r1, st1),(name2, ent2, r2, st2): -cmp(st1.detail_missing, st2.detail_missing)) + self.fill_table(dir, grandmissing_table, rows) + + rows.sort(lambda (name1, ent1, r1, st1),(name2, ent2, r2, st2): -cmp(st1.incompleteness, st2.incompleteness)) + self.fill_table(dir, incompleteness_table, rows) + + f = open(os.path.join(dir, self.fname()),'w') + + f.write(HEADER+unicode(page).encode("utf8")) + + f.close() + + def navig(self): + return html.h1(self.title) + +class ClassReport(Report): + + def navig(self): + return html.p(html.span(self.title,**{'class': 'title'}), + "|",mods_report.link(None),"|",cls_report.link(None)) + + def grandadd(self, parent): + if self.status == 'MISSING': + parent.grandtotal += self.total + parent.grandmissing += self.missing + elif self.status == 'PRESENT': + parent.grandtotal += self.total + +class ModuleReport(Report): + + def navig(self): + return html.p(html.span(self.title,**{'class': 'title'}), + "|",mods_report.link(None),"|",cls_report.link(None)) + + notes = ("(): callable, C: type/class; detail counts module functions, attrs and " + "contained class/type methods and attrs") + + def grandadd(self, parent): + if self.status == 'MISSING': + parent.grandtotal += self.grandtotal + parent.grandmissing += self.grandmissing + elif self.status == 'PRESENT': + parent.grandtotal += self.grandtotal + + +def delta(expl1, expl2, modnames): + + rep = Report('Modules', fname="modules-index", + notes = "detail counts module functions, attrs and " + "contained class/type methods and attrs") + def navig(): + return html.p(html.span('Modules',**{'class': 'title'}), + "|",cls_report.link(None)) + + rep.navig = navig + + for modname in modnames: + + mod1 = expl1.get_module(modname) + mod2 = expl2.get_module(modname) + + mod_rep = mod_delta(modname, expl1, mod1, expl2, mod2) + + mod_rep.attach(rep) + mod_rep.grandadd(rep) + + return rep + + +def mod_delta(modname, expl1, mod1, expl2, mod2): + print "; mod %s" % modname + rep = ModuleReport(modname) + + rep.set_status(mod1, mod2, expl1) + + names = Set() + + names.update(expl1.names(mod1)) + names.update(expl2.names(mod2)) + + names = list(names) + names.sort() + + for name in names: + obj1 = expl1.findattr(mod1, name) + obj2 = expl2.findattr(mod2, name) + + if expl1.is_class(obj1) or expl2.is_class(obj2): + entry = cls_delta("%s.%s" % (modname, name), expl1, obj1, expl2, obj2) + else: + entry = Entry(name) + entry.set_status(obj1, obj2, expl1) + + kind1 = expl1.get_kind(obj1) + kind2 = expl2.get_kind(obj2) + + if kind1 == '-': + kindinf = kind2 + elif kind2 == '-': + kindinf = kind1 + else: + if kind1 == kind2: + kindinf = kind1 + else: + if kind1 == '_': kind1 = '?' + if kind2 == '_': kind2 = '?' + kindinf = "%s/%s" % (kind1, kind2) + + if kindinf == '_': + kindinf = '' + + entry.attach(rep, kindinf, name=name) + entry.grandadd(rep) + + return rep + + +cls_delta_cache = {} + +def cls_delta(clsname, expl1, cls1, expl2, cls2): + cache = cls_delta_cache + print "; cls %s" % clsname + try: + rep = cache[(cls1, cls2)] + return rep + except KeyError: + pass + + rep = ClassReport(clsname) + rep.shortname = clsname.split('.')[1] + rep.set_status(cls1, cls2, expl1) + + cls1_is_not_a_class = False + + if not expl1.is_class(cls1): + if cls1 is not NOTFOUND: + cls1 = NOTFOUND + cls1_is_not_a_class = True + + if not expl2.is_class(cls2): + cls2 = NOTFOUND + assert not cls1_is_not_a_class + + names = Set() + + for cls in expl1.get_mro(cls1): + names.update(expl1.names(cls)) + + for cls in expl2.get_mro(cls2): + names.update(expl2.names(cls)) + + names = list(names) + names.sort() + + for name in names: + obj1 = expl1.findattr(cls1, name) + obj2 = expl2.findattr(cls2, name) + + if obj1 is NOTFOUND and obj2 is NOTFOUND: + continue # spurious :( + + entry = Entry(name) + if cls1_is_not_a_class: + entry.status = expl2 + else: + entry.set_status(obj1, obj2, expl1) + + entry.attach(rep) + + cache[(cls1, cls2)] = rep + + return rep + +def cls_delta_rep(): + reps = cls_delta_cache.values() + cls_rep = Report('Types/Classes', fname="types-index", + notes = "detail counts class/type methods and attrs") + + def navig(): + return html.p(mods_report.link(None), + "|",html.span('Types/Classes',**{'class': 'title'})) + + cls_rep.navig = navig + + + reps.sort(lambda rep1,rep2: cmp(rep1.name, rep2.name)) + + for rep in reps: + cls_rep.add_row(rep, [], name=rep.name) + cls_rep.total += 1 + cls_rep.missing += rep.status == 'MISSING' + rep.grandadd(cls_rep) + + return cls_rep + +#__________________________________________ + +host_explore = HostExplore() + +os_layer = [] +for modname in ['posix', 'nt', 'os2', 'mac', 'ce', 'riscos']: + if host_explore.get_module(modname) is not NOTFOUND: + os_layer.append(modname) + + +TO_CHECK = list(Set(['types', '__builtin__', 'sys']).union(Set(sys.builtin_module_names)). + union(Set([ + 'math', '_codecs', 'array', + '_random', '_sre', 'time', '_socket', 'errno', + 'marshal', 'binascii', 'parser']+os_layer))) +TO_CHECK.remove('__main__') +TO_CHECK.remove('xxsubtype') +TO_CHECK.sort() + + +if __name__ == '__main__': + if len(sys.argv) == 1: + print "usage: delta.py " + print "Then copy delta.css, delta.js to dest-dir if they are not already there" + sys.exit(0) + + DIR = sys.argv[1] + + + from pypy.objspace.std.objspace import StdObjSpace + + space = StdObjSpace() + + mods_report = delta(ObjSpaceExplore(space), host_explore, TO_CHECK) + cls_report = cls_delta_rep() + + reports.insert(1,reports.pop()) + + reports.reverse() + + if not os.path.isdir(DIR): + os.mkdir(DIR) + + for rep in reports: + rep.html(DIR) From pedronis at codespeak.net Thu Mar 10 14:10:55 2005 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Thu, 10 Mar 2005 14:10:55 +0100 (MET) Subject: [pypy-svn] r9726 - pypy/dist/pypy/tool Message-ID: <20050310131055.939D727B43@code1.codespeak.net> Author: pedronis Date: Thu Mar 10 14:10:55 2005 New Revision: 9726 Modified: pypy/dist/pypy/tool/delta.py Log: dev time stuff, not needed anymore for pure html generation Modified: pypy/dist/pypy/tool/delta.py ============================================================================== --- pypy/dist/pypy/tool/delta.py (original) +++ pypy/dist/pypy/tool/delta.py Thu Mar 10 14:10:55 2005 @@ -701,10 +701,6 @@ mods_report = delta(ObjSpaceExplore(space), host_explore, TO_CHECK) cls_report = cls_delta_rep() - reports.insert(1,reports.pop()) - - reports.reverse() - if not os.path.isdir(DIR): os.mkdir(DIR) From pedronis at codespeak.net Thu Mar 10 16:00:10 2005 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Thu, 10 Mar 2005 16:00:10 +0100 (MET) Subject: [pypy-svn] r9727 - in pypy/dist/pypy: annotation interpreter Message-ID: <20050310150010.E1C2827B3D@code1.codespeak.net> Author: pedronis Date: Thu Mar 10 16:00:10 2005 New Revision: 9727 Modified: pypy/dist/pypy/annotation/binaryop.py pypy/dist/pypy/interpreter/pycode.py Log: added sanity check and workaround to problems when to subclasses of a class contain an identical function but is not correct to consider this to belong to a superclass because unrelated subclasses could obviously don't have it. we either need to manually avoid this problem or make the pbc representation more complicated. Modified: pypy/dist/pypy/annotation/binaryop.py ============================================================================== --- pypy/dist/pypy/annotation/binaryop.py (original) +++ pypy/dist/pypy/annotation/binaryop.py Thu Mar 10 16:00:10 2005 @@ -283,7 +283,7 @@ return SomeBuiltin(bltn1.analyser, s_self) class __extend__(pairtype(SomePBC, SomePBC)): - def union((pbc1, pbc2)): + def union((pbc1, pbc2)): if len(pbc2.prebuiltinstances) > len(pbc1.prebuiltinstances): pbc1, pbc2 = pbc2, pbc1 d = pbc1.prebuiltinstances.copy() @@ -294,7 +294,15 @@ "union failed for %r with classdefs %r and %r" % (x, classdef, d[x])) if isclassdef(classdef): + classdef2 = classdef classdef = classdef.commonbase(d[x]) + for cand in classdef.getmro(): + if x in cand.__dict__.values(): + break + else: + assert False, ("confused pbc union trying unwarranted" + "moving up of method %s from pair %s %s" % + (x, d[x], classdef2)) d[x] = classdef result = SomePBC(d) return result Modified: pypy/dist/pypy/interpreter/pycode.py ============================================================================== --- pypy/dist/pypy/interpreter/pycode.py (original) +++ pypy/dist/pypy/interpreter/pycode.py Thu Mar 10 16:00:10 2005 @@ -56,14 +56,25 @@ from pypy.interpreter.nestedscope import PyNestedScopeFrame from pypy.interpreter.generator import GeneratorFrame + def fresh_GeneratorFrame_methods(): + import types + from pypy.tool.hack import func_with_new_name + dic = GeneratorFrame.__dict__.copy() + for n in dic: + x = dic[n] + if isinstance(x, types.FunctionType): + dic[n] = func_with_new_name(x, x.__name__) + print dic + return dic + frame_classes[0] = PyInterpFrame frame_classes[NESTED] = PyNestedScopeFrame frame_classes[GENERATOR] = type('PyGeneratorFrame', (PyInterpFrame,), - GeneratorFrame.__dict__.copy()) + fresh_GeneratorFrame_methods()) frame_classes[NESTED|GENERATOR] = type('PyNestedScopeGeneratorFrame', (PyNestedScopeFrame,), - GeneratorFrame.__dict__.copy()) + fresh_GeneratorFrame_methods()) class PyCode(eval.Code): "CPython-style code objects." From pedronis at codespeak.net Thu Mar 10 16:12:21 2005 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Thu, 10 Mar 2005 16:12:21 +0100 (MET) Subject: [pypy-svn] r9728 - pypy/dist/pypy/interpreter Message-ID: <20050310151221.0484327B3D@code1.codespeak.net> Author: pedronis Date: Thu Mar 10 16:12:21 2005 New Revision: 9728 Modified: pypy/dist/pypy/interpreter/pycode.py Log: oops Modified: pypy/dist/pypy/interpreter/pycode.py ============================================================================== --- pypy/dist/pypy/interpreter/pycode.py (original) +++ pypy/dist/pypy/interpreter/pycode.py Thu Mar 10 16:12:21 2005 @@ -64,7 +64,6 @@ x = dic[n] if isinstance(x, types.FunctionType): dic[n] = func_with_new_name(x, x.__name__) - print dic return dic frame_classes[0] = PyInterpFrame From pedronis at codespeak.net Thu Mar 10 17:29:17 2005 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Thu, 10 Mar 2005 17:29:17 +0100 (MET) Subject: [pypy-svn] r9729 - pypy/dist/pypy/interpreter Message-ID: <20050310162917.AC0D227B3D@code1.codespeak.net> Author: pedronis Date: Thu Mar 10 17:29:17 2005 New Revision: 9729 Modified: pypy/dist/pypy/interpreter/pyframe.py Log: make the annotator happy Modified: pypy/dist/pypy/interpreter/pyframe.py ============================================================================== --- pypy/dist/pypy/interpreter/pyframe.py (original) +++ pypy/dist/pypy/interpreter/pyframe.py Thu Mar 10 17:29:17 2005 @@ -61,6 +61,7 @@ def eval(self, executioncontext): "Interpreter main loop!" try: + last_instr = -1 while True: try: try: From hpk at codespeak.net Fri Mar 11 09:06:26 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Fri, 11 Mar 2005 09:06:26 +0100 (MET) Subject: [pypy-svn] r9731 - pypy/dist/pypy/tool Message-ID: <20050311080626.CF67D27B3D@code1.codespeak.net> Author: hpk Date: Fri Mar 11 09:06:26 2005 New Revision: 9731 Modified: pypy/dist/pypy/tool/delta.py Log: use unicode() method to produce nicer (indented) html Modified: pypy/dist/pypy/tool/delta.py ============================================================================== --- pypy/dist/pypy/tool/delta.py (original) +++ pypy/dist/pypy/tool/delta.py Fri Mar 11 09:06:26 2005 @@ -478,7 +478,7 @@ f = open(os.path.join(dir, self.fname()),'w') - f.write(HEADER+unicode(page).encode("utf8")) + f.write(HEADER+page.unicode().encode("utf8")) f.close() From hpk at codespeak.net Fri Mar 11 09:13:47 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Fri, 11 Mar 2005 09:13:47 +0100 (MET) Subject: [pypy-svn] r9732 - pypy/dist/pypy/tool Message-ID: <20050311081347.3897027B41@code1.codespeak.net> Author: hpk Date: Fri Mar 11 09:13:47 2005 New Revision: 9732 Modified: pypy/dist/pypy/tool/delta.py Log: added a small helper that gets the svn revision number from the current pypy package. This is not integrated into the html output yet. Modified: pypy/dist/pypy/tool/delta.py ============================================================================== --- pypy/dist/pypy/tool/delta.py (original) +++ pypy/dist/pypy/tool/delta.py Fri Mar 11 09:13:47 2005 @@ -684,6 +684,16 @@ TO_CHECK.remove('xxsubtype') TO_CHECK.sort() +def getpypyrevision(cache=[]): + try: + return cache[0] + except IndexError: + import pypy + import py + pypydir = py.path.svnwc(pypy.__file__).dirpath() + rev = pypydir.info().rev + cache.append(rev) + return rev if __name__ == '__main__': if len(sys.argv) == 1: From pedronis at codespeak.net Fri Mar 11 15:43:37 2005 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Fri, 11 Mar 2005 15:43:37 +0100 (MET) Subject: [pypy-svn] r9733 - pypy/dist/pypy/objspace Message-ID: <20050311144337.0318C27B41@code1.codespeak.net> Author: pedronis Date: Fri Mar 11 15:43:37 2005 New Revision: 9733 Modified: pypy/dist/pypy/objspace/dummy.py Log: fix typos in dummy objspace Modified: pypy/dist/pypy/objspace/dummy.py ============================================================================== --- pypy/dist/pypy/objspace/dummy.py (original) +++ pypy/dist/pypy/objspace/dummy.py Fri Mar 11 15:43:37 2005 @@ -8,16 +8,16 @@ return True def str_w(self, space): - raise OperatioError(space.w_TypeError,space.wrap("!")) + raise OperationError(space.w_TypeError,space.wrap("!")) def int_w(self, space): - raise OperatioError(space.w_TypeError,space.wrap("!")) + raise OperationError(space.w_TypeError,space.wrap("!")) def float_w(self, space): - raise OperatioError(space.w_TypeError,space.wrap("!")) + raise OperationError(space.w_TypeError,space.wrap("!")) def unwrap(self, space): - raise OperatioError(space.w_TypeError,space.wrap("!")) + raise OperationError(space.w_TypeError,space.wrap("!")) class W_Str(W_Obj): def __init__(self, s): From pedronis at codespeak.net Fri Mar 11 15:47:18 2005 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Fri, 11 Mar 2005 15:47:18 +0100 (MET) Subject: [pypy-svn] r9734 - pypy/dist/pypy/annotation Message-ID: <20050311144718.4928127B41@code1.codespeak.net> Author: pedronis Date: Fri Mar 11 15:47:18 2005 New Revision: 9734 Modified: pypy/dist/pypy/annotation/binaryop.py pypy/dist/pypy/annotation/classdef.py pypy/dist/pypy/annotation/unaryop.py Log: oops, correct the sanity check start of support for lshift, invert naive support for MI with Exception Modified: pypy/dist/pypy/annotation/binaryop.py ============================================================================== --- pypy/dist/pypy/annotation/binaryop.py (original) +++ pypy/dist/pypy/annotation/binaryop.py Fri Mar 11 15:47:18 2005 @@ -24,7 +24,9 @@ 'getitem', 'setitem', 'inplace_add', 'inplace_sub', 'lt', 'le', 'eq', 'ne', 'gt', 'ge', 'is_', - 'union', 'issubtype']) + 'union', 'issubtype', + 'lshift', + ]) for opname in BINARY_OPERATIONS: missing_operation(pairtype(SomeObject, SomeObject), opname) @@ -130,6 +132,10 @@ return SomeInteger(nonneg = int1.nonneg or int1.nonneg, unsigned = int1.unsigned or int2.unsigned) + def lshift((int1, int2)): + if int1.unsigned: + return SomeInteger(unsigned=True) + return SomeInteger() class __extend__(pairtype(SomeBool, SomeBool)): @@ -295,14 +301,15 @@ (x, classdef, d[x])) if isclassdef(classdef): classdef2 = classdef - classdef = classdef.commonbase(d[x]) - for cand in classdef.getmro(): - if x in cand.__dict__.values(): - break - else: - assert False, ("confused pbc union trying unwarranted" - "moving up of method %s from pair %s %s" % - (x, d[x], classdef2)) + if classdef != d[x]: + classdef = classdef.commonbase(d[x]) + for cand in classdef.getmro(): + if x in cand.cls.__dict__.values(): + break + else: + assert False, ("confused pbc union trying unwarranted" + "moving up of method %s from pair %s %s" % + (x, d[x], classdef2)) d[x] = classdef result = SomePBC(d) return result Modified: pypy/dist/pypy/annotation/classdef.py ============================================================================== --- pypy/dist/pypy/annotation/classdef.py (original) +++ pypy/dist/pypy/annotation/classdef.py Fri Mar 11 15:47:18 2005 @@ -53,6 +53,10 @@ sources = {} baselist = list(cls.__bases__) baselist.reverse() + if Exception in baselist and len(baselist)>1: # special-case + baselist.remove(Exception) + mixeddict['__init__'] = Exception.__init__.im_func + for b1 in baselist: if b1 is object: continue Modified: pypy/dist/pypy/annotation/unaryop.py ============================================================================== --- pypy/dist/pypy/annotation/unaryop.py (original) +++ pypy/dist/pypy/annotation/unaryop.py Fri Mar 11 15:47:18 2005 @@ -22,7 +22,7 @@ UNARY_OPERATIONS = set(['len', 'is_true', 'getattr', 'setattr', 'simple_call', 'call_args', - 'iter', 'next']) + 'iter', 'next', 'invert']) for opname in UNARY_OPERATIONS: missing_operation(SomeObject, opname) @@ -79,6 +79,13 @@ (getbookkeeper().whereami(), obj, args), esc="31") # RED return SomeObject() +class __extend__(SomeInteger): + + def invert(self): + if self.unsigned: + return SomeInteger(unsigned=True) + return SomeInteger() + class __extend__(SomeBool): def is_true(self): From pedronis at codespeak.net Fri Mar 11 15:54:27 2005 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Fri, 11 Mar 2005 15:54:27 +0100 (MET) Subject: [pypy-svn] r9735 - pypy/dist/pypy/interpreter Message-ID: <20050311145427.0144327B41@code1.codespeak.net> Author: pedronis Date: Fri Mar 11 15:54:27 2005 New Revision: 9735 Modified: pypy/dist/pypy/interpreter/miscutils.py pypy/dist/pypy/interpreter/pyopcode.py Log: make the interpreter code more annotator friendly. - use different table with functions with different signature, - use closures for generic binary/unary opcode impls to avoid getattr(.,SomeString()) problem - fix bug discovered by the annotator in INPLACE_POWER (inplace_pow has arity 2) - Stack is used polymorphically, specialize Modified: pypy/dist/pypy/interpreter/miscutils.py ============================================================================== --- pypy/dist/pypy/interpreter/miscutils.py (original) +++ pypy/dist/pypy/interpreter/miscutils.py Fri Mar 11 15:54:27 2005 @@ -8,6 +8,8 @@ class Stack: """Utility class implementing a stack.""" + _specialize_ = 'location' # polymorphic + def __init__(self): self.items = [] Modified: pypy/dist/pypy/interpreter/pyopcode.py ============================================================================== --- pypy/dist/pypy/interpreter/pyopcode.py (original) +++ pypy/dist/pypy/interpreter/pyopcode.py Fri Mar 11 15:54:27 2005 @@ -9,47 +9,50 @@ from pypy.interpreter import pyframe, pytraceback from pypy.interpreter.miscutils import InitializedClass from pypy.interpreter.argument import Arguments +from pypy.tool import hack - -class unaryoperation: - def __init__(self, operationname): - self.operationname = operationname - - def __call__(self, f): - operation = getattr(f.space, self.operationname) +def unaryoperation(operationname): + """NOT_RPYTHON""" + def opimpl(f): + operation = getattr(f.space, operationname) w_1 = f.valuestack.pop() w_result = operation(w_1) f.valuestack.push(w_result) -class binaryoperation: - def __init__(self, operationname): - self.operationname = operationname - def __call__(self, f): - operation = getattr(f.space, self.operationname) + return hack.func_with_new_name(opimpl, "opcode_impl_for_%s" % operationname) + +def binaryoperation(operationname): + """NOT_RPYTHON""" + def opimpl(f): + operation = getattr(f.space, operationname) w_2 = f.valuestack.pop() w_1 = f.valuestack.pop() w_result = operation(w_1, w_2) f.valuestack.push(w_result) + return hack.func_with_new_name(opimpl, "opcode_impl_for_%s" % operationname) + class PyInterpFrame(pyframe.PyFrame): """A PyFrame that knows about interpretation of standard Python opcodes minus the ones related to nested scopes.""" ### opcode dispatch ### - - # 'dispatch_table' is a class attribute: a list of functions. - # Currently, it is always created by setup_dispatch_table in pyopcode.py + + # 'opcode_has_arg' is a class attribute: list of True/False whether opcode takes arg + # 'dispatch_table_no_arg: list of functions/None + # 'dispatch_table_w_arg: list of functions/None + # Currently, they are always setup in pyopcode.py # but it could be a custom table. def dispatch(self): opcode = self.nextop() - fn = self.dispatch_table[opcode] - if fn.has_arg: + if self.opcode_has_arg[opcode]: + fn = self.dispatch_table_w_arg[opcode] oparg = self.nextarg() fn(self, oparg) - else: + fn = self.dispatch_table_no_arg[opcode] fn(self) def nextop(self): @@ -180,7 +183,7 @@ def INPLACE_POWER(f): w_2 = f.valuestack.pop() w_1 = f.valuestack.pop() - w_result = f.space.inplace_pow(w_1, w_2, f.space.w_None) + w_result = f.space.inplace_pow(w_1, w_2) f.valuestack.push(w_result) INPLACE_MULTIPLY = binaryoperation("inplace_mul") @@ -681,9 +684,9 @@ def EXTENDED_ARG(f, oparg): opcode = f.nextop() oparg = oparg<<16 | f.nextarg() - fn = f.dispatch_table[opcode] - if not fn.has_arg: - raise pyframe.BytecodeCorruption + fn = f.dispatch_table_w_arg[opcode] + if fn is None: + raise pyframe.BytecodeCorruption fn(f, oparg) def MISSING_OPCODE(f, oparg=None): @@ -691,26 +694,38 @@ ### dispatch_table ### - # 'dispatch_table' is a class attribute: a list of functions - # it is created by 'cls.setup_dispatch_table()'. + # 'opcode_has_arg' is a class attribute: list of True/False whether opcode takes arg + # 'dispatch_table_no_arg: list of functions/None + # 'dispatch_table_w_arg: list of functions/None __metaclass__ = InitializedClass def __initclass__(cls): "NOT_RPYTHON" # create the 'cls.dispatch_table' attribute import dis - dispatch_table = [] + opcode_has_arg = [] + dispatch_table_no_arg = [] + dispatch_table_w_arg = [] missing_opcode = cls.MISSING_OPCODE for i in range(256): opname = dis.opname[i].replace('+', '_') fn = getattr(cls, opname, missing_opcode) fn = getattr(fn, 'im_func',fn) - fn.has_arg = i >= dis.HAVE_ARGUMENT + has_arg = i >= dis.HAVE_ARGUMENT #if fn is missing_opcode and not opname.startswith('<') and i>0: # import warnings # warnings.warn("* Warning, missing opcode %s" % opname) - dispatch_table.append(fn) - cls.dispatch_table = dispatch_table + opcode_has_arg.append(has_arg) + if has_arg: + dispatch_table_w_arg.append(fn) + dispatch_table_no_arg.append(None) + else: + dispatch_table_no_arg.append(fn) + dispatch_table_w_arg.append(None) + + cls.opcode_has_arg = opcode_has_arg + cls.dispatch_table_no_arg = dispatch_table_no_arg + cls.dispatch_table_w_arg = dispatch_table_w_arg ### helpers written at the application-level ### From pedronis at codespeak.net Fri Mar 11 18:01:06 2005 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Fri, 11 Mar 2005 18:01:06 +0100 (MET) Subject: [pypy-svn] r9742 - in pypy/dist/pypy: annotation translator/test Message-ID: <20050311170106.6820C27B56@code1.codespeak.net> Author: pedronis Date: Fri Mar 11 18:01:06 2005 New Revision: 9742 Modified: pypy/dist/pypy/annotation/unaryop.py pypy/dist/pypy/translator/test/snippet.py pypy/dist/pypy/translator/test/test_annrpython.py Log: - some more tests involving exception handling code annotation - annotation for type op to pass all of them Modified: pypy/dist/pypy/annotation/unaryop.py ============================================================================== --- pypy/dist/pypy/annotation/unaryop.py (original) +++ pypy/dist/pypy/annotation/unaryop.py Fri Mar 11 18:01:06 2005 @@ -22,13 +22,28 @@ UNARY_OPERATIONS = set(['len', 'is_true', 'getattr', 'setattr', 'simple_call', 'call_args', - 'iter', 'next', 'invert']) + 'iter', 'next', 'invert', 'type']) for opname in UNARY_OPERATIONS: missing_operation(SomeObject, opname) class __extend__(SomeObject): + + def type(obj): + if obj.is_constant(): + r = immutablevalue(obj.knowntype) + else: + r = SomeObject() + bk = getbookkeeper() + fn, block, i = bk.position_key + annotator = bk.annotator + op = block.operations[i] + assert op.opname == "type" + assert len(op.args) == 1 + assert annotator.binding(op.args[0]) == obj + r.is_type_of = [op.args[0]] + return r def len(obj): return SomeInteger(nonneg=True) Modified: pypy/dist/pypy/translator/test/snippet.py ============================================================================== --- pypy/dist/pypy/translator/test/snippet.py (original) +++ pypy/dist/pypy/translator/test/snippet.py Fri Mar 11 18:01:06 2005 @@ -721,6 +721,40 @@ except Exc, e: return e return Exc() + + +def witness(x): + pass + +def exception_deduction_with_raise1(x): + try: + exception_deduction0(2) + if x: + raise Exc() + except Exc, e: + witness(e) + return e + return Exc() + +def exception_deduction_with_raise2(x): + try: + exception_deduction0(2) + if x: + raise Exc + except Exc, e: + witness(e) + return e + return Exc() + +def exception_deduction_with_raise3(x): + try: + exception_deduction0(2) + if x: + raise Exc, Exc() + except Exc, e: + witness(e) + return e + return Exc() def slice_union(x): if x: Modified: pypy/dist/pypy/translator/test/test_annrpython.py ============================================================================== --- pypy/dist/pypy/translator/test/test_annrpython.py (original) +++ pypy/dist/pypy/translator/test/test_annrpython.py Fri Mar 11 18:01:06 2005 @@ -575,6 +575,26 @@ assert s.items[0].knowntype == int assert s.items[1].knowntype == str + def test_exception_deduction_with_raise1(self): + a = RPythonAnnotator() + s = a.build_types(snippet.exception_deduction_with_raise1, [bool]) + assert isinstance(s, annmodel.SomeInstance) + assert s.knowntype is snippet.Exc + + + def test_exception_deduction_with_raise2(self): + a = RPythonAnnotator() + s = a.build_types(snippet.exception_deduction_with_raise2, [bool]) + assert isinstance(s, annmodel.SomeInstance) + assert s.knowntype is snippet.Exc + + def test_exception_deduction_with_raise3(self): + a = RPythonAnnotator() + s = a.build_types(snippet.exception_deduction_with_raise3, [bool]) + assert isinstance(s, annmodel.SomeInstance) + assert s.knowntype is snippet.Exc + + def g(n): return [0,1,2,n] From pedronis at codespeak.net Fri Mar 11 18:12:10 2005 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Fri, 11 Mar 2005 18:12:10 +0100 (MET) Subject: [pypy-svn] r9747 - pypy/dist/pypy/objspace Message-ID: <20050311171210.0AEA227B60@code1.codespeak.net> Author: pedronis Date: Fri Mar 11 18:12:09 2005 New Revision: 9747 Modified: pypy/dist/pypy/objspace/dummy.py Log: added missing new list Modified: pypy/dist/pypy/objspace/dummy.py ============================================================================== --- pypy/dist/pypy/objspace/dummy.py (original) +++ pypy/dist/pypy/objspace/dummy.py Fri Mar 11 18:12:09 2005 @@ -75,7 +75,8 @@ for en in ObjSpace.ExceptionTable: setattr(self, 'w_'+en, self.wrap(en)) - for n, symbol, arity, ign in ObjSpace.MethodTable+[('newdict',"",1,[]), ('newtuple',"",1,[]), ('newslice',"",3,[]), ]: + for n, symbol, arity, ign in ObjSpace.MethodTable+[('newdict',"",1,[]), ('newlist',"",1,[]), + ('newtuple',"",1,[]), ('newslice',"",3,[]), ]: source = ("""if 1: def %s(self, %s): return W_Obj() From pedronis at codespeak.net Fri Mar 11 19:28:52 2005 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Fri, 11 Mar 2005 19:28:52 +0100 (MET) Subject: [pypy-svn] r9748 - pypy/dist/pypy/objspace Message-ID: <20050311182852.9374027B5F@code1.codespeak.net> Author: pedronis Date: Fri Mar 11 19:28:52 2005 New Revision: 9748 Modified: pypy/dist/pypy/objspace/dummy.py Log: make dummy space more realistic: space ops can return interpreter objects Modified: pypy/dist/pypy/objspace/dummy.py ============================================================================== --- pypy/dist/pypy/objspace/dummy.py (original) +++ pypy/dist/pypy/objspace/dummy.py Fri Mar 11 19:28:52 2005 @@ -1,7 +1,9 @@ -from pypy.interpreter.baseobjspace import ObjSpace, W_Root +from pypy.interpreter.baseobjspace import ObjSpace, W_Root, BaseWrappable from pypy.interpreter.module import Module from pypy.interpreter.error import OperationError +from pypy.tool.cache import Cache + class W_Obj(W_Root): def is_true(self): @@ -75,11 +77,13 @@ for en in ObjSpace.ExceptionTable: setattr(self, 'w_'+en, self.wrap(en)) + self._gatewaycache = Cache() + for n, symbol, arity, ign in ObjSpace.MethodTable+[('newdict',"",1,[]), ('newlist',"",1,[]), ('newtuple',"",1,[]), ('newslice',"",3,[]), ]: source = ("""if 1: def %s(self, %s): - return W_Obj() + return W_Root() """ % (n, ', '.join(["w_a%d" % i for i in range(arity)]))) #print source exec source @@ -93,26 +97,39 @@ return W_Str(obj) if isinstance(obj, int): return W_Int(obj) - return W_Obj() + return W_Root() wrap._specialize_ = "argtypes" def call_args(self, w_obj, args): - return W_Obj() + return W_Root() def is_true(self, w_obj): - return w_obj.is_true() + if isinstance(w_obj, W_Obj): + return w_obj.is_true() + return True def str_w(self, w_obj): + if not isinstance(w_obj, W_Obj): + w_obj = self.w_None + return w_obj.str_w(self) def int_w(self, w_obj): + if not isinstance(w_obj, W_Obj): + w_obj = self.w_None + return w_obj.int_w(self) def float_w(self, w_obj): + if not isinstance(w_obj, W_Obj): + w_obj = self.w_None + return w_obj.float_w(self) - + def unwrap(self, w_obj): - return w_obj.unwrap(self) + if isinstance(w_obj, BaseWrappable): + return w_obj + return w_obj.unwrap() if __name__ == '__main__': From pedronis at codespeak.net Fri Mar 11 19:31:30 2005 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Fri, 11 Mar 2005 19:31:30 +0100 (MET) Subject: [pypy-svn] r9749 - pypy/dist/pypy/interpreter Message-ID: <20050311183130.2231C27B61@code1.codespeak.net> Author: pedronis Date: Fri Mar 11 19:31:29 2005 New Revision: 9749 Modified: pypy/dist/pypy/interpreter/pyopcode.py Log: sanity checks and assertion for lost PyCode types Modified: pypy/dist/pypy/interpreter/pyopcode.py ============================================================================== --- pypy/dist/pypy/interpreter/pyopcode.py (original) +++ pypy/dist/pypy/interpreter/pyopcode.py Fri Mar 11 19:31:29 2005 @@ -9,6 +9,7 @@ from pypy.interpreter import pyframe, pytraceback from pypy.interpreter.miscutils import InitializedClass from pypy.interpreter.argument import Arguments +from pypy.interpreter.pycode import PyCode from pypy.tool import hack def unaryoperation(operationname): @@ -357,6 +358,7 @@ if plain: w_locals = f.getdictscope() pycode = f.space.interpclass_w(w_prog) + assert isinstance(pycode, PyCode) pycode.exec_code(f.space, w_globals, w_locals) if plain: f.setdictscope(w_locals) @@ -655,7 +657,8 @@ def MAKE_FUNCTION(f, numdefaults): w_codeobj = f.valuestack.pop() - codeobj = f.space.interpclass_w(w_codeobj) + codeobj = f.space.interpclass_w(w_codeobj) + assert isinstance(codeobj, PyCode) defaultarguments = [f.valuestack.pop() for i in range(numdefaults)] defaultarguments.reverse() fn = function.Function(f.space, codeobj, f.w_globals, defaultarguments) From pedronis at codespeak.net Fri Mar 11 19:39:33 2005 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Fri, 11 Mar 2005 19:39:33 +0100 (MET) Subject: [pypy-svn] r9750 - in pypy/dist: goal pypy/annotation Message-ID: <20050311183933.D8BAF27B61@code1.codespeak.net> Author: pedronis Date: Fri Mar 11 19:39:33 2005 New Revision: 9750 Modified: pypy/dist/goal/translate_pypy0.py pypy/dist/pypy/annotation/builtin.py Log: * dummy annotation for sys.exc_info. This is just a hack. In reality we should hide is usage from the translator * cheat in translate_pypy0 to deal with the app-level helpers * added code so that we can even try to run the result Right now translate_pypy0 manages to go through annotating the touched interp code with a few remaining problems, it can even start to run a compiled result but then chokes on a problem with Stack instances. We specialize Stack so that could be related. Modified: pypy/dist/goal/translate_pypy0.py ============================================================================== --- pypy/dist/goal/translate_pypy0.py (original) +++ pypy/dist/goal/translate_pypy0.py Fri Mar 11 19:39:33 2005 @@ -55,6 +55,11 @@ pycode.setup_frame_classes() + from pypy.interpreter import pyopcode + + # cheat + space._gatewaycache.content[pyopcode.app] = space.newdict([]) + t = Translator(entry_point, verbose=True, simplifying=True) if listen_port: run_async_server() @@ -268,10 +273,8 @@ update_usession_dir() if not options['-o']: print 'Running!' - w_result = c_entry_point() + w_result = c_entry_point(compile("a+b","","eval"),dummy.W_Obj()) print w_result - print w_result.intval - assert w_result.intval == 42 except: debug(True) else: Modified: pypy/dist/pypy/annotation/builtin.py ============================================================================== --- pypy/dist/pypy/annotation/builtin.py (original) +++ pypy/dist/pypy/annotation/builtin.py Fri Mar 11 19:39:33 2005 @@ -200,6 +200,9 @@ def math_floor(x): return SomeObject() +def exc_info(): # XXX + return SomeTuple((immutablevalue(None),)*3) + # collect all functions import __builtin__ BUILTIN_ANALYZERS = {} @@ -214,3 +217,4 @@ BUILTIN_ANALYZERS[sys.getrefcount] = count BUILTIN_ANALYZERS[math.fmod] = math_fmod BUILTIN_ANALYZERS[math.floor] = math_floor +BUILTIN_ANALYZERS[sys.exc_info] = exc_info # xxx From pedronis at codespeak.net Fri Mar 11 23:16:32 2005 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Fri, 11 Mar 2005 23:16:32 +0100 (MET) Subject: [pypy-svn] r9751 - pypy/dist/pypy/tool Message-ID: <20050311221632.20C0B27B71@code1.codespeak.net> Author: pedronis Date: Fri Mar 11 23:16:31 2005 New Revision: 9751 Modified: pypy/dist/pypy/tool/delta.css pypy/dist/pypy/tool/delta.js pypy/dist/pypy/tool/delta.py Log: fixes for IE, tried with Mac IE5 Modified: pypy/dist/pypy/tool/delta.css ============================================================================== --- pypy/dist/pypy/tool/delta.css (original) +++ pypy/dist/pypy/tool/delta.css Fri Mar 11 23:16:31 2005 @@ -14,4 +14,4 @@ .missing { color: red } .faked { color: red; font-style: italic } .somemissing { color: maroon } -.only_in { font-style: italic } \ No newline at end of file +.only_in { font-style: italic } Modified: pypy/dist/pypy/tool/delta.js ============================================================================== --- pypy/dist/pypy/tool/delta.js (original) +++ pypy/dist/pypy/tool/delta.js Fri Mar 11 23:16:31 2005 @@ -1,15 +1,16 @@ toggle_list = ['alpha', 'grandmissing', 'incompleteness']; -TABLE_HIDE = "display: none" -TABLE_SHOW = "display: table" +ALPHA = 'alpha' +GRANDMISSING = 'grandmissing' +INCOMPLETENESS = 'incompleteness' function toggle(on) { for (i in toggle_list) { x = toggle_list[i]; if (x!=on) { - document.getElementById(x).setAttribute("style", TABLE_HIDE); + document.getElementById(x).style.display='none'; } }; - document.getElementById(on).setAttribute("style", TABLE_SHOW); -} \ No newline at end of file + document.getElementById(on).style.display=''; +} Modified: pypy/dist/pypy/tool/delta.py ============================================================================== --- pypy/dist/pypy/tool/delta.py (original) +++ pypy/dist/pypy/tool/delta.py Fri Mar 11 23:16:31 2005 @@ -447,14 +447,14 @@ incompleteness_table = html.table(id="incompleteness", style=HIDE) toggle = html.p("sort:", - html.button("alphabetical", type="button", onclick="toggle('alpha')"),'|', - html.button("incompleteness", type="button", onclick="toggle('incompleteness')"),'|', - html.button("# overall missing", type="button", onclick="toggle('grandmissing')")) + html.button("alphabetical", type="button", onclick="toggle(ALPHA)"),'|', + html.button("incompleteness", type="button", onclick="toggle(INCOMPLETENESS)"),'|', + html.button("# overall missing", type="button", onclick="toggle(GRANDMISSING)")) page = html.html( html.head(html.title(title), html.link(href="delta.css", rel="stylesheet", type="text/css"), - html.script(type="text/javascript",src="delta.js")), + html.script(' ',type="text/javascript",src="delta.js")), html.body(self.navig(), html.p(msg, bar, **set_class(class_)), toggle, From arigo at codespeak.net Sat Mar 12 22:01:53 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 12 Mar 2005 22:01:53 +0100 (MET) Subject: [pypy-svn] r9752 - in pypy/dist/pypy: annotation interpreter tool translator/test Message-ID: <20050312210153.6FC3E27B44@code1.codespeak.net> Author: arigo Date: Sat Mar 12 22:01:53 2005 New Revision: 9752 Modified: pypy/dist/pypy/annotation/bookkeeper.py pypy/dist/pypy/annotation/model.py pypy/dist/pypy/annotation/unaryop.py pypy/dist/pypy/interpreter/gateway.py pypy/dist/pypy/interpreter/lazymodule.py pypy/dist/pypy/tool/cache.py pypy/dist/pypy/translator/test/test_annrpython.py Log: Added the _freeze_() protocol to help the annotator decide if something is a pre-built constant or a SomeInstance (i.e. holds mutable state). The method _freeze_() is also a good place for the objects to perform last-minute initialization, e.g. for LazyModule objects. Added a test for _freeze_(). New method bookkeeper.warning() for all warning-issuing situations of the annotator. Modified: pypy/dist/pypy/annotation/bookkeeper.py ============================================================================== --- pypy/dist/pypy/annotation/bookkeeper.py (original) +++ pypy/dist/pypy/annotation/bookkeeper.py Sat Mar 12 22:01:53 2005 @@ -4,6 +4,7 @@ from types import FunctionType, ClassType, MethodType from types import BuiltinMethodType +from pypy.tool.ansi_print import ansi_print from pypy.annotation.model import * from pypy.annotation.classdef import ClassDef from pypy.interpreter.miscutils import getthreadlocals @@ -29,6 +30,7 @@ self.userclasseslist = []# userclasses.keys() in creation order self.cachespecializations = {} self.pbccache = {} + self.pbctypes = {} # import ordering hack global BUILTIN_ANALYZERS from pypy.annotation.builtin import BUILTIN_ANALYZERS @@ -64,6 +66,9 @@ try: return self.userclasses[cls] except KeyError: + if cls in self.pbctypes: + self.warning("%r gets a ClassDef, but is the type of some PBC" + % (cls,)) cdef = ClassDef(cls, self) self.userclasses[cls] = cdef self.userclasseslist.append(cdef) @@ -94,9 +99,8 @@ elif callable(x) or isinstance(x, staticmethod): # XXX # maybe 'x' is a method bound to a not-yet-frozen cache? # fun fun fun. - if (hasattr(x, 'im_self') and isinstance(x.im_self, Cache) - and not x.im_self.frozen): - x.im_self.freeze() + if hasattr(x, 'im_self') and hasattr(x.im_self, '_freeze_'): + x.im_self._freeze_() if hasattr(x, '__self__') and x.__self__ is not None: s_self = self.immutablevalue(x.__self__) try: @@ -107,9 +111,18 @@ return self.getpbc(x) elif hasattr(x, '__class__') \ and x.__class__.__module__ != '__builtin__': - if isinstance(x, Cache) and not x.frozen: - x.freeze() - return self.getpbc(x) + # user-defined classes can define a method _freeze_(), which + # is called when a prebuilt instance is found. If the method + # returns True, the instance is considered immutable and becomes + # a SomePBC(). Otherwise it's just SomeInstance(). + frozen = hasattr(x, '_freeze_') and x._freeze_() + if frozen: + return self.getpbc(x) + else: + clsdef = self.getclassdef(x.__class__) + for attr in x.__dict__: + clsdef.add_source_for_attribute(attr, x) + return SomeInstance(clsdef) elif x is None: return self.getpbc(None) else: @@ -124,15 +137,22 @@ return self.pbccache[x] except KeyError: result = SomePBC({x: True}) # pre-built inst - clsdef = self.getclassdef(new_or_old_class(x)) - for attr in getattr(x, '__dict__', {}): - clsdef.add_source_for_attribute(attr, x) + #clsdef = self.getclassdef(new_or_old_class(x)) + #for attr in getattr(x, '__dict__', {}): + # clsdef.add_source_for_attribute(attr, x) self.pbccache[x] = result + cls = new_or_old_class(x) + if cls not in self.pbctypes: + self.pbctypes[cls] = True + if cls in self.userclasses: + self.warning("making some PBC of type %r, which has " + "already got a ClassDef" % (cls,)) return result def valueoftype(self, t): """The most precise SomeValue instance that contains all objects of type t.""" + assert isinstance(t, (type, ClassType)) if t is bool: return SomeBool() elif t is int: @@ -142,8 +162,7 @@ elif t is list: return SomeList(factories={}) # can't do dict, tuple - elif isinstance(t, (type, ClassType)) and \ - t.__module__ != '__builtin__': + elif t.__module__ != '__builtin__': classdef = self.getclassdef(t) return SomeInstance(classdef) else: @@ -246,6 +265,13 @@ def whereami(self): return self.annotator.whereami(self.position_key) + def warning(self, msg): + try: + pos = self.whereami() + except AttributeError: + pos = '?' + ansi_print("*** WARNING: [%s] %s" % (pos, msg), esc="31") # RED + def specialize_by_key(self, thing, key, name=None): key = thing, key try: Modified: pypy/dist/pypy/annotation/model.py ============================================================================== --- pypy/dist/pypy/annotation/model.py (original) +++ pypy/dist/pypy/annotation/model.py Sat Mar 12 22:01:53 2005 @@ -32,7 +32,6 @@ import pypy from pypy.annotation.pairtype import pair, extendabletype from pypy.objspace.flow.model import Constant -from pypy.tool.cache import Cache import inspect Modified: pypy/dist/pypy/annotation/unaryop.py ============================================================================== --- pypy/dist/pypy/annotation/unaryop.py (original) +++ pypy/dist/pypy/annotation/unaryop.py Sat Mar 12 22:01:53 2005 @@ -3,7 +3,6 @@ """ from types import FunctionType -from pypy.tool.ansi_print import ansi_print from pypy.interpreter.argument import Arguments from pypy.annotation.pairtype import pair from pypy.annotation.model import SomeObject, SomeInteger, SomeBool @@ -90,8 +89,7 @@ def call(obj, args): #raise Exception, "cannot follow call_args%r" % ((obj, args),) - ansi_print("*** WARNING: [%s] cannot follow call(%r, %r)" % - (getbookkeeper().whereami(), obj, args), esc="31") # RED + getbookkeeper().warning("cannot follow call(%r, %r)" % (obj, args)) return SomeObject() class __extend__(SomeInteger): @@ -238,17 +236,14 @@ for c in pbc.prebuiltinstances: if hasattr(c, attr): # force the attribute to be considered on the class - classdef = bookkeeper.getclassdef(new_or_old_class(c)) - classdef.find_attribute(attr).getvalue() + ##classdef = bookkeeper.getclassdef(new_or_old_class(c)) + ##classdef.find_attribute(attr).getvalue() # but only return the more precise result getattr(c, attr) actuals.append(immutablevalue(getattr(c, attr))) return unionof(*actuals) def setattr(pbc, s_attr, s_value): - #raise Exception, "oops!" - ansi_print("*** WARNING: [%s] setattr not wanted on %r" % - (getbookkeeper().whereami(), pbc), esc="31") # RED - pass + getbookkeeper().warning("setattr not wanted on %r" % (pbc,)) def call(pbc, args): bookkeeper = getbookkeeper() @@ -269,9 +264,9 @@ d = {} for func, value in pbc.prebuiltinstances.items(): if isinstance(func, FunctionType): - if isclassdef(value): - print ("!!! rebinding an already bound" - " method %r with %r" % (func, value)) + if isclassdef(value): + getbookkeeper().warning("rebinding an already bound " + "method %r with %r" % (func, value)) d[func] = classdef elif isinstance(func, staticmethod): d[func.__get__(43)] = value Modified: pypy/dist/pypy/interpreter/gateway.py ============================================================================== --- pypy/dist/pypy/interpreter/gateway.py (original) +++ pypy/dist/pypy/interpreter/gateway.py Sat Mar 12 22:01:53 2005 @@ -522,6 +522,9 @@ appcaller.get_function = get_function return appcaller + def _freeze_(self): + return True # hint for the annotator: applevel instances are constants + ## XXX experimental code using geninterplevel class applevelinterp(applevel): Modified: pypy/dist/pypy/interpreter/lazymodule.py ============================================================================== --- pypy/dist/pypy/interpreter/lazymodule.py (original) +++ pypy/dist/pypy/interpreter/lazymodule.py Sat Mar 12 22:01:53 2005 @@ -54,6 +54,12 @@ self.lazy = False return self.w_dict + def _freeze_(self): + self.getdict() + # hint for the annotator: Modules can hold state, so they are + # not constant + return False + def buildloaders(cls): """ NOT_RPYTHON """ if not hasattr(cls, 'loaders'): Modified: pypy/dist/pypy/tool/cache.py ============================================================================== --- pypy/dist/pypy/tool/cache.py (original) +++ pypy/dist/pypy/tool/cache.py Sat Mar 12 22:01:53 2005 @@ -32,4 +32,10 @@ getorbuild._specialize_ = "location" def freeze(self): - del self.frozen + try: + del self.frozen + except AttributeError: + pass + return True + + _freeze_ = freeze Modified: pypy/dist/pypy/translator/test/test_annrpython.py ============================================================================== --- pypy/dist/pypy/translator/test/test_annrpython.py (original) +++ pypy/dist/pypy/translator/test/test_annrpython.py Sat Mar 12 22:01:53 2005 @@ -594,6 +594,25 @@ assert isinstance(s, annmodel.SomeInstance) assert s.knowntype is snippet.Exc + def test_freeze_protocol(self): + class Stuff: + def __init__(self, flag): + self.called = False + self.flag = flag + def _freeze_(self): + self.called = True + return self.flag + myobj = Stuff(True) + a = RPythonAnnotator() + s = a.build_types(lambda: myobj, []) + assert myobj.called + assert s == annmodel.SomePBC({myobj: True}) + myobj = Stuff(False) + a = RPythonAnnotator() + s = a.build_types(lambda: myobj, []) + assert myobj.called + assert s == annmodel.SomeInstance(a.bookkeeper.getclassdef(Stuff)) + def g(n): return [0,1,2,n] From hpk at codespeak.net Sat Mar 12 22:24:56 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sat, 12 Mar 2005 22:24:56 +0100 (MET) Subject: [pypy-svn] r9753 - in pypy/dist/pypy/objspace: . std Message-ID: <20050312212456.7BD3527B44@code1.codespeak.net> Author: hpk Date: Sat Mar 12 22:24:56 2005 New Revision: 9753 Modified: pypy/dist/pypy/objspace/descroperation.py pypy/dist/pypy/objspace/std/objspace.py Log: substitute the use of space._compare_nesting with space.get_ec_state_dict()['...'] ... make the space become a SomePBC again (with the new _freeze_() protocol). Modified: pypy/dist/pypy/objspace/descroperation.py ============================================================================== --- pypy/dist/pypy/objspace/descroperation.py (original) +++ pypy/dist/pypy/objspace/descroperation.py Sat Mar 12 22:24:56 2005 @@ -283,8 +283,6 @@ _NESTING_LIMIT = 20 - _compare_nesting = 0 - def cmp(space, w_v, w_w): # Icky implementation trying to mimic python 2.3 semantics. @@ -294,10 +292,14 @@ w_vt = space.type(w_v) token = None _inprogress_dict = None + + # um + statedict = space.get_ec_state_dict() + _compare_nesting = statedict.get('_compare_nesting', 0) + 1 + statedict['_compare_nesting'] = _compare_nesting try: # Try to do some magic to compare cyclic constructs. - space._compare_nesting += 1 - if (space._compare_nesting > space._NESTING_LIMIT and + if (_compare_nesting > space._NESTING_LIMIT and (space.lookup(w_v, '__getitem__') is not None) and not (space.is_w(w_vt, space.w_str) or space.is_w(w_vt, space.w_tuple))): @@ -308,7 +310,7 @@ t = (iv, iw, -1) else: t = (iw, iv, -1) - _inprogress_dict = space.get_ec_state_dict().setdefault('cmp_state', {}) + _inprogress_dict = statedict.setdefault('cmp_state', {}) if t in _inprogress_dict: # If we are allready trying to compare the arguments # presume they are equal @@ -338,7 +340,7 @@ except: pass finally: - space._compare_nesting -= 1 + statedict['_compare_nesting'] -= 1 def coerce(space, w_obj1, w_obj2): w_typ1 = space.type(w_obj1) @@ -474,10 +476,14 @@ token = None _inprogress_dict = None + + # um + statedict = space.get_ec_state_dict() + _compare_nesting = statedict.get('_compare_nesting', 0) + 1 + statedict['_compare_nesting'] = _compare_nesting try: # Try to do some magic to compare cyclic constructs. - space._compare_nesting += 1 - if (space._compare_nesting > space._NESTING_LIMIT and + if (_compare_nesting > space._NESTING_LIMIT and (space.lookup(w_obj1, '__getitem__') is not None) and not (space.is_w(w_typ1, space.w_str) or space.is_w(w_typ1, space.w_tuple))): @@ -520,6 +526,7 @@ res = space.int_w(w_res) return space.wrap(op(res, 0)) finally: + statedict['_compare_nesting'] -= 1 if token is not None: try: del _inprogress_dict[token] Modified: pypy/dist/pypy/objspace/std/objspace.py ============================================================================== --- pypy/dist/pypy/objspace/std/objspace.py (original) +++ pypy/dist/pypy/objspace/std/objspace.py Sat Mar 12 22:24:56 2005 @@ -26,6 +26,9 @@ PACKAGE_PATH = 'objspace.std' + def _freeze_(self): + return True + def initialize(self): "NOT_RPYTHON: only for initializing the space." self._typecache = Cache() From pedronis at codespeak.net Sun Mar 13 02:13:47 2005 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Sun, 13 Mar 2005 02:13:47 +0100 (MET) Subject: [pypy-svn] r9754 - in pypy/dist/pypy: annotation objspace objspace/flow objspace/flow/test translator/test Message-ID: <20050313011347.4210127B44@code1.codespeak.net> Author: pedronis Date: Sun Mar 13 02:13:47 2005 New Revision: 9754 Modified: pypy/dist/pypy/annotation/bookkeeper.py pypy/dist/pypy/objspace/dummy.py pypy/dist/pypy/objspace/flow/objspace.py pypy/dist/pypy/objspace/flow/test/test_objspace.py pypy/dist/pypy/translator/test/test_annrpython.py Log: possible _freeze_ handling in flowspace + tests test_circular_mutable_getattr fix _freeze_ adaption for dummy Modified: pypy/dist/pypy/annotation/bookkeeper.py ============================================================================== --- pypy/dist/pypy/annotation/bookkeeper.py (original) +++ pypy/dist/pypy/annotation/bookkeeper.py Sun Mar 13 02:13:47 2005 @@ -31,6 +31,7 @@ self.cachespecializations = {} self.pbccache = {} self.pbctypes = {} + self.seen_mutable = {} # import ordering hack global BUILTIN_ANALYZERS from pypy.annotation.builtin import BUILTIN_ANALYZERS @@ -120,8 +121,12 @@ return self.getpbc(x) else: clsdef = self.getclassdef(x.__class__) - for attr in x.__dict__: - clsdef.add_source_for_attribute(attr, x) + + if x not in self.seen_mutable: # avoid circular reflowing, + # see for example test_circular_mutable_getattr + for attr in x.__dict__: + clsdef.add_source_for_attribute(attr, x) # can trigger reflowing + self.seen_mutable[x] = True return SomeInstance(clsdef) elif x is None: return self.getpbc(None) Modified: pypy/dist/pypy/objspace/dummy.py ============================================================================== --- pypy/dist/pypy/objspace/dummy.py (original) +++ pypy/dist/pypy/objspace/dummy.py Sun Mar 13 02:13:47 2005 @@ -56,15 +56,19 @@ def __init__(self, spec): self.spec = spec +class BuiltinModule(Module): + def __init__(self, space): + Module.__init__(self, space, space.wrap('__builtin__'), space.wrap({})) + def pick_builtin(self, w_globals): + return self + class DummyObjSpace(ObjSpace): def __init__(self): """NOT_RPYTHON""" - self.builtin = Module(self, self.wrap('__builtin__'), self.wrap({})) - def pick_builtin(w_globals): - return self.builtin - self.builtin.pick_builtin = pick_builtin + self.builtin = BuiltinModule(self) + self.sys = Module(self, self.wrap('sys'), self.wrap({})) self.sys.recursionlimit = 1000 @@ -131,6 +135,8 @@ return w_obj return w_obj.unwrap() + def _freeze_(self): + return True if __name__ == '__main__': dummy_space = DummyObjSpace() Modified: pypy/dist/pypy/objspace/flow/objspace.py ============================================================================== --- pypy/dist/pypy/objspace/flow/objspace.py (original) +++ pypy/dist/pypy/objspace/flow/objspace.py Sun Mar 13 02:13:47 2005 @@ -148,6 +148,23 @@ else: raise TypeError("not wrapped: " + repr(w_obj)) + def unwrap_for_computation(self, w_obj): + obj = self.unwrap(w_obj) + to_check = obj + if hasattr(to_check, 'im_self'): + to_check = to_check.im_self + if (not isinstance(to_check, (type, types.ClassType)) and # classes/types are assumed immutable + hasattr(to_check, '__class__') and to_check.__class__.__module__ != '__builtin__'): + frozen = hasattr(to_check, '_freeze_') and to_check._freeze_() + if not frozen: + if self.concrete_mode: + # xxx do we want some warning? notice that some stuff is harmless + # like setitem(dict, 'n', mutable) + pass + else: # cannot count on it not mutating at runtime! + raise UnwrapException + return obj + def interpclass_w(self, w_obj): obj = self.unwrap(w_obj) if isinstance(obj, BaseWrappable): @@ -248,7 +265,7 @@ def is_true(self, w_obj): try: - obj = self.unwrap(w_obj) + obj = self.unwrap_for_computation(w_obj) except UnwrapException: pass else: @@ -398,7 +415,7 @@ args = [] for w_arg in args_w: try: - arg = self.unwrap(w_arg) + arg = self.unwrap_for_computation(w_arg) except UnwrapException: break else: Modified: pypy/dist/pypy/objspace/flow/test/test_objspace.py ============================================================================== --- pypy/dist/pypy/objspace/flow/test/test_objspace.py (original) +++ pypy/dist/pypy/objspace/flow/test/test_objspace.py Sun Mar 13 02:13:47 2005 @@ -1,5 +1,5 @@ import autopath -from pypy.objspace.flow.model import Constant, Block, traverse +from pypy.objspace.flow.model import Constant, Block, Link, Variable, traverse from pypy.interpreter.argument import Arguments from pypy.translator.simplify import simplify_graph @@ -367,6 +367,88 @@ assert op.opname != 'mul', "mul should have disappeared" traverse(visitor, x) + #__________________________________________________________ + def test_unfrozen_user_class1(self): + class C: + def __nonzero__(self): + return True + c = C() + def f(): + if c: + return 1 + else: + return 2 + graph = self.codetest(f) + + results = [] + def visit(link): + if isinstance(link, Link): + if link.target == graph.returnblock: + results.extend(link.args) + traverse(visit, graph) + assert len(results) == 2 + + def test_unfrozen_user_class2(self): + class C: + def __add__(self, other): + return 4 + c = C() + d = C() + def f(): + return c+d + graph = self.codetest(f) + + results = [] + def visit(link): + if isinstance(link, Link): + if link.target == graph.returnblock: + results.extend(link.args) + traverse(visit, graph) + assert not isinstance(results[0], Constant) + + def test_frozen_user_class1(self): + class C: + def __nonzero__(self): + return True + def _freeze_(self): + return True + c = C() + def f(): + if c: + return 1 + else: + return 2 + + graph = self.codetest(f) + + results = [] + def visit(link): + if isinstance(link, Link): + if link.target == graph.returnblock: + results.extend(link.args) + traverse(visit, graph) + assert len(results) == 1 + + def test_frozen_user_class2(self): + class C: + def __add__(self, other): + return 4 + def _freeze_(self): + return True + c = C() + d = C() + def f(): + return c+d + graph = self.codetest(f) + + results = [] + def visit(link): + if isinstance(link, Link): + if link.target == graph.returnblock: + results.extend(link.args) + traverse(visit, graph) + assert results == [Constant(4)] + DATA = {'x': 5, 'y': 6} Modified: pypy/dist/pypy/translator/test/test_annrpython.py ============================================================================== --- pypy/dist/pypy/translator/test/test_annrpython.py (original) +++ pypy/dist/pypy/translator/test/test_annrpython.py Sun Mar 13 02:13:47 2005 @@ -613,6 +613,16 @@ assert myobj.called assert s == annmodel.SomeInstance(a.bookkeeper.getclassdef(Stuff)) + def test_circular_mutable_getattr(self): + class C: + pass + c = C() + c.x = c + def f(): + return c.x + a = RPythonAnnotator() + s = a.build_types(f, []) + assert s.knowntype == C def g(n): return [0,1,2,n] From pedronis at codespeak.net Mon Mar 14 14:03:36 2005 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Mon, 14 Mar 2005 14:03:36 +0100 (MET) Subject: [pypy-svn] r9758 - in pypy/dist/pypy: annotation objspace/flow translator/test Message-ID: <20050314130336.D233927B5C@code1.codespeak.net> Author: pedronis Date: Mon Mar 14 14:03:36 2005 New Revision: 9758 Modified: pypy/dist/pypy/annotation/unaryop.py pypy/dist/pypy/objspace/flow/specialcase.py pypy/dist/pypy/translator/test/test_annrpython.py Log: - annotation for list.extend - comment about never used code Modified: pypy/dist/pypy/annotation/unaryop.py ============================================================================== --- pypy/dist/pypy/annotation/unaryop.py (original) +++ pypy/dist/pypy/annotation/unaryop.py Mon Mar 14 14:03:36 2005 @@ -118,6 +118,9 @@ def method_append(lst, s_value): pair(lst, SomeInteger()).setitem(s_value) + def method_extend(lst, s_iterable): + pair(lst, SomeInteger()).setitem(s_iterable.iter()) + def method_reverse(lst): pass Modified: pypy/dist/pypy/objspace/flow/specialcase.py ============================================================================== --- pypy/dist/pypy/objspace/flow/specialcase.py (original) +++ pypy/dist/pypy/objspace/flow/specialcase.py Mon Mar 14 14:03:36 2005 @@ -55,6 +55,10 @@ # Normally, Instance should have been created by the previous operation # which should be a simple_call(, ...). # Fetch the out of there. (This doesn't work while replaying) + # XXX this case is likely not triggered anymore, because the instance creation op + # is walled off in a different block by the surrounding it with exception + # handling logic that is always put in place for calls. + # We may want to make this more clever! operations = space.executioncontext.recorder.crnt_block.operations if operations: spaceop = operations[-1] Modified: pypy/dist/pypy/translator/test/test_annrpython.py ============================================================================== --- pypy/dist/pypy/translator/test/test_annrpython.py (original) +++ pypy/dist/pypy/translator/test/test_annrpython.py Mon Mar 14 14:03:36 2005 @@ -369,7 +369,8 @@ # the annotator (it doesn't check that they operate property, though) for example, methname, s_example in [ ('', 'join', annmodel.SomeString()), - ([], 'append', annmodel.SomeList({})), + ([], 'append', annmodel.SomeList({})), + ([], 'extend', annmodel.SomeList({})), ([], 'reverse', annmodel.SomeList({})), ([], 'insert', annmodel.SomeList({})), ([], 'pop', annmodel.SomeList({})), From arigo at codespeak.net Mon Mar 14 14:24:56 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 14 Mar 2005 14:24:56 +0100 (MET) Subject: [pypy-svn] r9759 - pypy/dist/pypy/annotation Message-ID: <20050314132456.D7EC827B5C@code1.codespeak.net> Author: arigo Date: Mon Mar 14 14:24:56 2005 New Revision: 9759 Modified: pypy/dist/pypy/annotation/unaryop.py Log: Fix list.extend() annotation. Modified: pypy/dist/pypy/annotation/unaryop.py ============================================================================== --- pypy/dist/pypy/annotation/unaryop.py (original) +++ pypy/dist/pypy/annotation/unaryop.py Mon Mar 14 14:24:56 2005 @@ -119,7 +119,8 @@ pair(lst, SomeInteger()).setitem(s_value) def method_extend(lst, s_iterable): - pair(lst, SomeInteger()).setitem(s_iterable.iter()) + s_iter = s_iterable.iter() + pair(lst, SomeInteger()).setitem(s_iter.next()) def method_reverse(lst): pass From pedronis at codespeak.net Mon Mar 14 16:04:50 2005 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Mon, 14 Mar 2005 16:04:50 +0100 (MET) Subject: [pypy-svn] r9762 - pypy/dist/pypy/interpreter Message-ID: <20050314150450.2A90227B72@code1.codespeak.net> Author: pedronis Date: Mon Mar 14 16:04:49 2005 New Revision: 9762 Modified: pypy/dist/pypy/interpreter/pyframe.py Log: - the flow space does not normalize exceptions - SApplicationException.args[1] seems not used, and the 1-tuple and 2-tuple cases resulted in SomeObject Modified: pypy/dist/pypy/interpreter/pyframe.py ============================================================================== --- pypy/dist/pypy/interpreter/pyframe.py (original) +++ pypy/dist/pypy/interpreter/pyframe.py Mon Mar 14 16:04:49 2005 @@ -76,15 +76,15 @@ # into OperationErrors except KeyboardInterrupt: import sys; tb = sys.exc_info()[2] - raise OperationError, (self.space.w_KeyboardInterrupt, + raise OperationError, OperationError(self.space.w_KeyboardInterrupt, self.space.w_None), tb except MemoryError: import sys; tb = sys.exc_info()[2] - raise OperationError, (self.space.w_MemoryError, + raise OperationError, OperationError(self.space.w_MemoryError, self.space.w_None), tb except RuntimeError, e: import sys; tb = sys.exc_info()[2] - raise OperationError, (self.space.w_RuntimeError, + raise OperationError, OperationError(self.space.w_RuntimeError, self.space.wrap("internal error: " + str(e))), tb except OperationError, e: @@ -95,7 +95,7 @@ # exception import sys tb = sys.exc_info()[2] - raise SApplicationException(e, tb) + raise SApplicationException(e) except ControlFlowException, ctlflowexc: # we have a reason to change the control flow From pedronis at codespeak.net Mon Mar 14 16:05:30 2005 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Mon, 14 Mar 2005 16:05:30 +0100 (MET) Subject: [pypy-svn] r9763 - pypy/dist/pypy/annotation Message-ID: <20050314150530.1E46427B72@code1.codespeak.net> Author: pedronis Date: Mon Mar 14 16:05:29 2005 New Revision: 9763 Modified: pypy/dist/pypy/annotation/binaryop.py Log: let mix lists and None for now Modified: pypy/dist/pypy/annotation/binaryop.py ============================================================================== --- pypy/dist/pypy/annotation/binaryop.py (original) +++ pypy/dist/pypy/annotation/binaryop.py Mon Mar 14 16:05:29 2005 @@ -340,6 +340,18 @@ def union((pbc, ins)): return pair(ins, pbc).union() +# let mix lists and None for now +class __extend__(pairtype(SomeList, SomePBC)): + def union((lst, pbc)): + if pbc.isNone(): + return lst + return SomeObject() + +class __extend__(pairtype(SomePBC, SomeList )): + def union((pbc, lst)): + return pair(lst, pbc).union() + + class __extend__(pairtype(SomeObject, SomePBC)): def issubtype((obj, pbc)): s = SomeBool() From pedronis at codespeak.net Mon Mar 14 16:06:05 2005 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Mon, 14 Mar 2005 16:06:05 +0100 (MET) Subject: [pypy-svn] r9764 - pypy/dist/pypy/interpreter Message-ID: <20050314150605.AD1A827B72@code1.codespeak.net> Author: pedronis Date: Mon Mar 14 16:06:05 2005 New Revision: 9764 Modified: pypy/dist/pypy/interpreter/gateway.py Log: a list is expected Modified: pypy/dist/pypy/interpreter/gateway.py ============================================================================== --- pypy/dist/pypy/interpreter/gateway.py (original) +++ pypy/dist/pypy/interpreter/gateway.py Mon Mar 14 16:06:05 2005 @@ -512,7 +512,7 @@ def interphook(self, name): "NOT_RPYTHON" def appcaller(space, *args_w): - args = Arguments(space, args_w) + args = Arguments(space, list(args_w)) w_func = self.wget(space, name) return space.call_args(w_func, args) def get_function(space): From pedronis at codespeak.net Mon Mar 14 16:52:54 2005 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Mon, 14 Mar 2005 16:52:54 +0100 (MET) Subject: [pypy-svn] r9765 - pypy/dist/pypy/interpreter Message-ID: <20050314155254.6504B27B85@code1.codespeak.net> Author: pedronis Date: Mon Mar 14 16:52:54 2005 New Revision: 9765 Modified: pypy/dist/pypy/interpreter/baseobjspace.py Log: don't mix int values and None Modified: pypy/dist/pypy/interpreter/baseobjspace.py ============================================================================== --- pypy/dist/pypy/interpreter/baseobjspace.py (original) +++ pypy/dist/pypy/interpreter/baseobjspace.py Mon Mar 14 16:52:54 2005 @@ -138,7 +138,7 @@ return w_obj return None - def unpackiterable(self, w_iterable, expected_length=None): + def unpackiterable(self, w_iterable, expected_length=-1): """Unpack an iterable object into a real (interpreter-level) list. Raise a real ValueError if the length is wrong.""" w_iterator = self.iter(w_iterable) @@ -150,10 +150,10 @@ if not e.match(self, self.w_StopIteration): raise break # done - if expected_length is not None and len(items) == expected_length: + if expected_length != -1 and len(items) == expected_length: raise ValueError, "too many values to unpack" items.append(w_item) - if expected_length is not None and len(items) < expected_length: + if expected_length != -1 and len(items) < expected_length: i = len(items) if i == 1: plural = "" From pedronis at codespeak.net Mon Mar 14 17:12:11 2005 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Mon, 14 Mar 2005 17:12:11 +0100 (MET) Subject: [pypy-svn] r9766 - pypy/dist/pypy/interpreter Message-ID: <20050314161211.4360827B85@code1.codespeak.net> Author: pedronis Date: Mon Mar 14 17:12:11 2005 New Revision: 9766 Modified: pypy/dist/pypy/interpreter/nestedscope.py Log: wrap the string for OperationError Modified: pypy/dist/pypy/interpreter/nestedscope.py ============================================================================== --- pypy/dist/pypy/interpreter/nestedscope.py (original) +++ pypy/dist/pypy/interpreter/nestedscope.py Mon Mar 14 17:12:11 2005 @@ -55,8 +55,8 @@ if closure is None: if nfreevars: raise OperationError(space.w_TypeError, - "directly executed code object " - "may not contain free variables") + space.wrap("directly executed code object " + "may not contain free variables")) closure = [] else: if len(closure) != nfreevars: From arigo at codespeak.net Mon Mar 14 18:26:08 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 14 Mar 2005 18:26:08 +0100 (MET) Subject: [pypy-svn] r9768 - pypy/dist/pypy/documentation Message-ID: <20050314172608.A933727B85@code1.codespeak.net> Author: arigo Date: Mon Mar 14 18:26:08 2005 New Revision: 9768 Modified: pypy/dist/pypy/documentation/annotation.txt Log: Deleted all the old stuff about annotations, and started to write something up-to-date. Modified: pypy/dist/pypy/documentation/annotation.txt ============================================================================== --- pypy/dist/pypy/documentation/annotation.txt (original) +++ pypy/dist/pypy/documentation/annotation.txt Mon Mar 14 18:26:08 2005 @@ -1,369 +1,160 @@ The annotation pass =================== -We describe below how a control flow graph can be "annotated" -to discover the types of the objects. This annotation pass is -done after control flow graphs are built by the FlowObjSpace, -but before these graphs are translated into low-level code +(INCOMPLETE DRAFT) + +We describe below how a control flow graph can be "annotated" to +discover the types of the objects. This annotation pass is a form of +type inference. It is done after control flow graphs are built by the +FlowObjSpace, but before these graphs are translated into low-level code (e.g. C/Lisp/Pyrex). -**THIS IS OUT OF DATE** (not to mention insane!) -I guess we should document the new world sometime.. +Model +----- + +The major goal of the annotator is to "annotate" each variable that +appears in a flow graph. An "annotation" describes all the possible +Python objects that this variable could contain at run-time, based on a +whole-program analysis of all the flow graphs --- one per function. + +An "annotation" is an instance of ``SomeObject``. There are subclasses +that are meant to represent specific families of objects. Note that +these classes are all meant to be instantiated; the classes ``SomeXxx`` +themselves are not the annotations. + +Here is an overview (see ``pypy.annotation.model``): + +* ``SomeObject`` is the base class. An instance ``SomeObject()`` + represents any Python object. It is used for the case where we don't + have enough information to be more precise. In practice, the presence + of ``SomeObject()`` means that we have to make the annotated source code + simpler or the annotator smarter. + +* ``SomeInteger()`` represents any integer. + ``SomeInteger(nonneg=True)`` represent a non-negative integer (``>=0``). -An example: the factorial -------------------------- +* ``SomeString()`` represents any string; ``SomeChar()`` a string of + length 1. -Say we want to make the control flow graph and type inference -on the following program:: - - def f(n): - if n >= 2: - return n * f(n-1) - else: - return 1 - -The flow objspace gives us the following graph (after the -simplification that turns ``call`` into ``simple_call``):: - - StartBlock(v1): - v2 = ge(v1, 2) - exitswitch(v2) - link "True" to Block2(v1) - link "False" to Block3 - - Block2(v3): - v4 = sub(v3, 1) - v7 = simple_call(f, v4) - v8 = mul(v3, v7) - jump to ReturnBlock(v8) - - Block3: - v9 = 1 - jump to ReturnBlock(v9) - - ReturnBlock(retval): - (empty, just returns retval) - -Suppose that we know that ``f`` takes an ``int`` argument. -We start type inference on the first block:: - - Analyse(StartBlock): - v1 ----> SV1 type(SV1)=int - v2 ----> SV2 type(SV2)=bool - -The notation is as follows. Everything at the right of the arrows -lives in a "big heap" of objects and annotations; a object is like a -CPython ``PyObject`` object structure in the heap, althought it can -here be unknown (SV1, SV2, SV3...). Annotations give some information -about the unknown heap objects. The arrows represent binding from -variables to objects. ``SV`` means ``SomeValue``. - -After StartBlock, we proceed to the type inference of its exits; -first Block2:: - - Analyse(Block2): - v3 ------------> SV1 # copied from StartBlock - v4 ------------> SV4 type(SV4)=int - v7 ------------> impossiblevalue - -It fails at the simple_call to f, because we don't know yet anything -about the return value of f. We suspend the analysis of Block2 and -resume at some other non-blocked point -- in this case, the other exit -from the StackBlock, which is jumping to Block3:: - - Analyse(Block3): - v9 --------> SV31 # const(SV31)=1, type(SV31)=int - -The object SV31 is the constant object 1. -Then we proceed to ReturnBlock:: - - Analyse(ReturnBlock): - retval --------> SV31 - -And we are done. We can now try to resume the suspended analysis of -Block2 -- in practice it is easier to just restart it:: - - Analyse(Block2): - v3 ------------> SV1 # copied from StartBlock - v4 ------------> SV4 type(SV4)=int - v7 ------------> SV31 # because that's the retval of f - v8 ------------> SV8 type(SV8)=int - -And now is the second branch into ReturnBlock. We must combine the -annotations coming from the two branches:: - - Intersection(ReturnBlock): - previous annotations for retval ----> SV31 type(SV31)=int const(SV31)=1 - new annotations for retval ---------> SV8 type(SV8)=int - intersection of both is retval -----> SV10 type(SV10)=int - -We invalidate the analysis of the blocks that depend on this new result, -namely ReturnBlock, which in turn invalidates the analysis of Block2 -which depended on the return value. Then we can restart it once more:: - - Analyse(Block2): - v3 ------------> SV1 # with type(SV1)=int - v4 ------------> SV4 type(SV4)=int - v7 ------------> SV10 # with type(SV10)=int - v8 ------------> SV11 type(SV11)=int - -Again, we must redo the intersection of the two branches -that enter ReturnBlock:: - - Intersection(ReturnBlock): - previous annotations for retval -------> SV10 type(SV10)=int - new annotations for retval ------------> SV11 type(SV11)=int - intersection doesn't change any more. - -Now the annotations are stable, and we are done. In the final version -summarized below, all the objects that are used in the variables and -in retval are properly annotated:: - - Bindings: - v1 ------> SV1 - v2 ------> SV2 - v3 ------> SV1 - v4 ------> SV4 - v7 ------> SV10 - v8 ------> SV11 - v9 ------> SV31 - retval --> SV10 - - Annotations: - type(SV1)=int - type(SV2)=bool - type(SV4)=int - type(SV10)=int - type(SV11)=int - -The bindings are implemented as a dictionary, and the annotations as -an AnnotationSet instance. More about it below. - - -Whole-program analysis ----------------------- - -A program of more than one function is analysed in exactly the same way, -starting from an entry point and following calls. We have a cache of all -the flowgraphs that the flow objspace produced, and a list of pending blocks -that we have to type-analyse. When the analysis of a block temporarily -fails (as above for the first recursive call to ``f``) we move the block -back into the pending list. There is only one heap of annotations for the -whole program, so that we can track where the objects come from and go -through the whole program. (This makes separate compilation very difficult, -I guess.) - - -Empty lists and mutable objects -------------------------------- - -Nothing special is required for empty lists. Let's try:: - - def g(a, n): - a.append(n) - - def f(): - b = [] - g(b, 5) - g(b, 6) - -As above, after simplification:: - - F_StartBlock(): - v1 = newlist() - v2 = simple_call(g, v1, 5) - v3 = simple_call(g, v1, 6) - - Analyse(F_StartBlock): - v1 -------> SV1 type(SV1)=list len(SV1)=0 listitems(SV1)=impossiblevalue - v2 -------> impossiblevalue - -The annotations about ``SV1`` mean that it is an empty list. When trying -to get any item out of it, the result is ``impossiblevalue``, because if we -try to execute code like ``c=b[0]`` then obviously it is impossible for -``c`` to contain any value. It is important not to confuse the two extreme -values: ``impossiblevalue`` means that no value can ever be found there -during actual execution, and corresponds to a ``SVx`` about which all -annotations are still possible. During the annotation pass, annotations -about a ``SVx`` can only *decrease*: we can later remove annotations that -we find to be incorrect, but we don't add new annotations. Thus an -``impossiblevalue`` is a value with potentially all annotations at first. -The other extreme is a ``SVx`` with no annotation at all; it represents -an object about which we know nothing at all -- and about which nothing -will be known later either: it means that we have inferred that many -different objects could be found at that point during execution. -Typically it shows a problem, e.g. that type inference failed to figure -out what object type can appear at that point. - -Let's come back to the example. The type analysis above fails at ``v2`` -because of the calls to ``g``, but it triggers the analysis of ``g`` with -the input arguments' annotations:: - - G_StartBlock(v4, v5): - v6 = getattr(v4, 'append') - v7 = simple_call(v6, v5) - - Analyse(G_StartBlock): - v4 -------> SV1 # from the call above - v5 -------> SV35 const(SV35)=5 type(SV35)=int - v6 -------> SV6 im_self(SV6)=SV1 im_func(SV6)=list_append - v7 -------> SV30 const(SV30)=None - -And most importantly the call to list_append corrects the annotations about -``SV1``. The annotation ``len(SV1)=0`` is deleted, and ``listitems(SV1)`` -is generalized from ``impossiblevalue`` to ``SV35`` -- this is done by -the same intersection process as above: we already know that -``listitems(SV1)`` can be ``impossiblevalue``, and now we figure out that -it could also be ``SV35``, so we take the intersection of the annotations -that apply to both ``impossiblevalue`` and ``SV35``. The result in this -case is just ``SV35``. - -Note that killing annotations like ``len(SV1)=0`` invalidates the inference -in any block that explicitely depends on it. Such blocks are marked as -"to be redone". (There isn't any such block in the present example.) - -Only after this can the analysis of ``F_StartBlock`` proceed, and -now we know that v1 points to the list ``SV1`` with the correct annotations: -unknown length, all items are ``5``. - -In the above example I also show a second call to ``g(b, 6)``, which -triggers an intersection on the input argument types of ``g`` which was -previously thought to be used with ``5`` only:: - - Intersection(G_StartBlock): - previous annotations for v5 -----> SV35 const(SV35)=5 type(SV35)=int - new annotations for v5 ----------> SV36 const(SV36)=6 type(SV36)=int - intersection of both is v5 ------> SV5 type(SV5)=int - -And so this time the list ``SV1`` is updated with:: - - listitems(SV1)=SV5 - -and now we know that we have a list of integers. - -Note that during this whole process the same list is represented by ``SV1``. -This is important, so that any code anywhere that could modify the list -can kill invalid annotations about it. Intersection must be clever about -mutable objects: we have seen above an example where ``retval`` could map -to ``SV10`` or ``SV11``, and the intersection said it was fine because they -had the same annotations. It would not be fine if ``SV10`` and ``SV11`` -could be of a mutable type. In this case we must force ``SV10==SV11`` for -the whole program. In other words the representation choosen for a list -depends on all the places where this list could go, and these places -themselves use a representation that depends on all the lists that could -come at this point. All these places and lists will use a common, -most general representation. - - -Polymorphism and mixed flowing/inference ----------------------------------------- - -(This paragraph is just an idea, it is not implemented.) - -We might eventually mix type inference and control flow generation a bit -more than described above. The annotations could influence the generation -of the graph. - -The most interesting influence would be to occasionally prevent two -FrameStates from being merged. This would result in a bigger control flow -graph in which several basic blocks can contain the operations about the -same bytecode positions, with different annotations. In particular, a -quite interesting idea is to disallow two states to be merged if the -resulting intersection of annotations is too poor -- say if it would make -genpyrex.py use the fall-back generic object type, which is not available -to other genxxx.py. - -The result is that we will automatically generate several specialized -version of the RPython code when it is meant to be polymorphic. For -example, in a function such as:: - - def push(stack, item): - stack.append(item) - -the different entry points, specifying quite different type annotations -for ``item``, are all unmergeable, as merging them would result in -insufficently many annotations left. By contrast, in the factorial -example above, all merges are fine because they conserve at least the -``type(X)=int`` annotation. +* ``SomeTuple([s1,s2,..,sn])`` represents a tuple of length ``n``. The + elements in this tuple are themselves constrained by the given list of + annotations. For example, ``SomeTuple([SomeInteger(), SomeString()])`` + represents a tuple with two items: an integer and a string. +There are more complex subclasses of ``SomeObject`` that we describe in +more details below. -SomeValue +All the ``SomeXxx`` instances can optionally have a ``const`` attribute, +which means that we know exactly which Python object the Variable will +contain. + +All the ``SomeXxx`` instances are supposed to be immutable. The +annotator manages a dictionary mapping Variables (which appear in flow +graphs) to ``SomeXxx`` instances; if it needs to revise its belief about +what a Variable can contain, it does so by updating this dictionary, not +the ``SomeXxx`` instance. + + +Annotator --------- -An abstract Python object in the heap is represented by an -instance of ``pypy.annotation.model.SomeValue``. All these SomeValue() -instances print as SV0, SV1, SV2... for debugging, but we only -use their identity internally. - -A SomeValue() alone represents an object about which nothing -is known. To collect information about such an object we use an -instance of ``pypy.annotation.annset.AnnotationSet``. An -annotation is like an attribute of a SomeValue(); for example, to -say that an object SV5 is known to be an integer, then we set the -annotation ``SV5.type = int``. However, for various good and bad -reasons, the annotation is not actually stored as an attribute, -but managed by the AnnotationSet(). The allowed "attributes", -i.e. the various annotations that exist, are in -``pypy.annotation.model.ANN``. Thus for the above example we -set the annotation ``ANN.type`` of SV5 to ``int``. This is what -we wrote in the above examples ``type(SV5) = int``. - -Note that unlike previous attempts an annotation is now always -a "name" (ANN.type) with just two arguments: the subject (SV5) and -the associated value (int). Just like with attributes, there are -never more than one associated value per subject and attribute name. -But unlike attributes, all annotations have a default value: -``mostgeneralvalue``, which is a SomeValue() about which nothing -is known. The only differences between the ``mostgeneralvalue`` -and a normal SomeValue() with no annotations are that AnnotationSet -will complain if you try to set annotations to ``mostgeneralvalue``; -and for convenience reasons ``mostgeneralvalue`` is false in a -boolean context. - - -AnnotationSet and ANN ---------------------- - -AnnotationSet has two main methods: ``get(name, subject)`` to -read the current annotation ``name`` about ``subject``, and -``set(name, subject, value)`` to set it. - -The meaning of ``value`` depends on the annotation. In some -cases it is a usual Python object (int, 3, True...). In other -cases it is specifically a SomeValue() instance, on which we -can recursively have partial information only. Here are -a few common annotations: - -* ``ANN.type``: the ``value`` is the type (int, list, ...). - -* ``ANN.len``: the ``value`` is the length of the object - (if known and constant, of course). - -* ``ANN.const``: we know that the ``subject`` is a constant - object; the ``value`` of ``ANN.const`` is precisely this - constant. - -* ``ANN.listitems``: the ``value`` is another SomeValue() - which stands for any item of the list. Thus the - annotations about this sub-SomeValue() tell what is known - in general about all the items in the list. - -* ``ANN.tupleitem[index]``: this is a family of annotations. - This is one of the reasons why we don't just use attributes - to store annotations: the whole expression ``ANN.tupleitem[0]`` - would be the attribute name. The expression ``ANN.tupleitem[1]`` - would be a different attribute name, and so on. Annotation-wise, - ``ANN.tupleitem[i]`` has a ``value`` which is a SomeValue() - describing what is known about the item ``i`` of a tuple. - -* ``ANN.immutable``: the ``value`` is always ``True``, unless - the annotation is not set, in which case it automatically - defaults to ``mostgeneralvalue`` (which is considered as false - in a boolean context for convenient checking). When - ``ANN.immutable`` is set, it means that the subject is known to - be of an immutable type (int, float, tuple...). This influences - the intersection algorithm. +The annotator itself (``pypy.translator.annrpython``) works by +propagating the annotations forward in the flow graphs, starting at some +entry point function, possibly with explicitely provided annotations +about the entry point's input arguments. It considers each operation in +the flow graph in turn. Each operation takes a few input arguments +(Variables and Constants) and produce a single result (a Variable). +Depending on the input argument's annotations, an annotation about the +operation result is produced. The exact rules to do this are provided +by the whole ``pypy.annotation`` subdirectory, which defines all the +cases in detail according to the R-Python semantics. For example, if +the operation is 'v3=add(v1,v2)' and the Variables v1 and v2 are +annotated with ``SomeInteger()``, then v3 also receives the annotation +``SomeInteger()``. So for example the function:: + + def f(n): + return n+1 + +corresponds to the flow graph:: + + start ----------. + | + V + +-------------------+ + | v2 = add(v1, 1) | + +-------------------+ + | + `---> return block + +If the annotator is told that v1 is ``SomeInteger()``, then it will +deduce that v2 (and hence the function's return value) is +``SomeInteger()``. + +This step-by-step annotation phase proceeds through all the operations +in a block, and then along the links between the blocks of the flow +graph. If there are loops in the flow graph, then the links will close +back to already-seen blocks, as in:: + + def g(n): + i = 0 + while n: + i = i + n + n = n - 1 + +whose flow graph is:: + + start -----. ,-----------------. + | n1 0 | m3 j3 | + V v | + +-------------------+ | + | input: n2 i2 | | + | v2 = is_true(n2) | | + +-------------------+ | + | | | + |ifFalse |ifTrue | + return <---' | n2 i2 | + V | + +--------------------+ | + | input: n3 i3 | | + | j3 = add(i3, n3) | | + | m3 = sub(n3, 1) |---' + +--------------------+ + +Be sure to follow the variable renaming that occurs systematically +across each link in a flow graph. In the above example the Variables +have been given names similar to the name of the original variables in +the source code (the FlowObjSpace tries to do this too) but keep in mind +that all Variables are different: n1, n2, i2, v2, n3, i3, j3, m3. + +Assume that we call the annotator with an input annotation of +``SomeInteger()`` for n1. Following the links from the start, the +annotator will first believe that the Variable i2, whose value comes +from the constant 0 of the first link, must always be zero. It will +thus use the annotation ``SomeInteger(const=0)`` for i2. Then it will +propagate the annotations through both blocks, and find that v2 is +``SomeBool()`` and all other variables are ``SomeInteger()``. In +particular, the annotation of j3 is different from the annotation of the +Variable i2 into which it is copied (via the back-link). More +precisely, j3 is ``SomeInteger()`` but i2 is the more specific +``SomeInteger(const=0)``. This means that the assumption that i2 must +always be zero is found to be wrong. At this point, the annotation of +i2 is *generalized* to include both the existing and the new annotation. +(This is the purpose of ``pypy.annotation.model.unionof()``). Then +these more general annotations must again be propagated forward. + +This process of successive generalizations continues until the +annotations stabilize. In the above example, it is sufficient to +re-analyse the first block once, but in general it can take several +iterations to reach a fixpoint. Annotations may also be propagated from +one flow graph to another and back repeatedly, across ``call`` +operations. The overall model should ensure that this process +eventually terminates under reasonable conditions. Note that as long as +the process is not finished, the annotations given to the Variables are +wrong, in the sense that they are too specific; at run-time, the +Variables will possibly contain Python objects outside the set defined +by the annotation, and the annotator doesn't know it yet. + + +XXX write more -The interection algorithm is implemented in the ``merge()`` method -of AnnotationSet. From arigo at codespeak.net Tue Mar 15 16:14:25 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 15 Mar 2005 16:14:25 +0100 (MET) Subject: [pypy-svn] r9797 - pypy/dist/pypy/translator Message-ID: <20050315151425.4A6D727B9A@code1.codespeak.net> Author: arigo Date: Tue Mar 15 16:14:25 2005 New Revision: 9797 Modified: pypy/dist/pypy/translator/genpyrex.py Log: 'is_perfect_number__-4854089c' is not a valid identifier... we have to use uid() instead of id(). Modified: pypy/dist/pypy/translator/genpyrex.py ============================================================================== --- pypy/dist/pypy/translator/genpyrex.py (original) +++ pypy/dist/pypy/translator/genpyrex.py Tue Mar 15 16:14:25 2005 @@ -9,6 +9,7 @@ from pypy.translator.annrpython import RPythonAnnotator from pypy.annotation.model import SomePBC from pypy.annotation.classdef import isclassdef +from pypy.tool.uid import uid import inspect class Op: @@ -289,7 +290,7 @@ name = cls.__name__ if issubclass(cls,Exception): return name - return '%s__%x' % (name, id(cls))#self._hackname(cls) + return '%s__%x' % (name, uid(cls))#self._hackname(cls) def getfunctionname(self,func): # NB. the purpose of the cache is not performance, but to ensure that @@ -300,7 +301,7 @@ return self.namecache[func] except KeyError: assert inspect.isfunction(func) or inspect.ismethod(func) - name = '%s__%x' % (func.__name__, id(func))#self._hackname(func) + name = '%s__%x' % (func.__name__, uid(func))#self._hackname(func) self.namecache[func] = name return name From arigo at codespeak.net Tue Mar 15 17:59:24 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 15 Mar 2005 17:59:24 +0100 (MET) Subject: [pypy-svn] r9812 - pypy/dist/pypy/documentation Message-ID: <20050315165924.A2B4327BAA@code1.codespeak.net> Author: arigo Date: Tue Mar 15 17:59:24 2005 New Revision: 9812 Modified: pypy/dist/pypy/documentation/annotation.txt Log: More (terse) documentation about annotations. Modified: pypy/dist/pypy/documentation/annotation.txt ============================================================================== --- pypy/dist/pypy/documentation/annotation.txt (original) +++ pypy/dist/pypy/documentation/annotation.txt Tue Mar 15 17:59:24 2005 @@ -10,6 +10,7 @@ (e.g. C/Lisp/Pyrex). +----- Model ----- @@ -56,6 +57,7 @@ the ``SomeXxx`` instance. +--------- Annotator --------- @@ -156,5 +158,149 @@ by the annotation, and the annotator doesn't know it yet. -XXX write more +---------------------------------- +Description of the available types +---------------------------------- + +The reference and the details for the annotation model is found in the +module ``pypy.annotation.model``. We describe below the issues related +to the various kinds of annotations. + + +Simple Types +++++++++++++ + +``SomeInteger``, ``SomeBool``, ``SomeString``, ``SomeChar`` all stands +for the obvious corresponding set of immutable Python objects. + + +Tuples +++++++ + +``SomeTuple`` only considers tuples of known length. We don't try to +handle tuples of varying length (the program should use lists instead). + + +Lists and Dictionaries +++++++++++++++++++++++ + +``SomeList`` stands for a list of homogenous type (i.e. all the elements +of the list are represented by a single common ``SomeXxx`` annotation). + +``SomeDict`` stands for a homogenous dictionary (i.e. all keys have the +same ``SomeXxx`` annotation, and so have all values). + +These types are mutable, which requires special support for the +annotator. The problem is that in code like:: + + lst = [42] + update_list(lst) + value = lst[0] + +the annotation given to ``value`` depends on the order in which the +annotator progresses. As ``lst`` is originally considered as a list of +``SomeInteger(const=42)``, it is possible that ``value`` becomes +``SomeInteger(const=42)`` as well if the analysis of ``update_list()`` +is not completed by the time the third operation is first considered. +To solve this problem, each ``SomeList`` or ``SomeDict`` is linked to a +set of so-called *factories*. Each creation point, i.e. each 'newlist' +or 'newdict' operation, gets its associated factory. The factory +remembers what kind of object it really needs to build. For example, in +code like:: + + lst = [42] + lst.append(43) + +the factory associated with the first line originally builds a list +whose items are all constants equal to 42; when the ``append(43)`` call +is then found, the factory is updated to build a more general list of +integers, and the annotator restarts its analysis from the factory +position. Our model is not sensitive to timing: it doesn't know that +the same list object may contain different items at different times. It +only computes how general the items in the list must be to cover all +cases. + +For initially empty lists, as created by ``lst = []``, we build a list +whose items have the annotation ``SomeImpossibleValue``. This is an +annotation that denotes that no Python object at all can possibly appear +here at run-time. It is the least general annotation. The rationale is +that:: + + lst = [] + oups = lst[0] + +will give the variable ``oups`` the annotation ``SomeImpossibleValue``, +which is reasonable given that no concrete Python object can ever be put +in ``oups`` at run-time. In a more usual example:: + + lst = [] + lst.append(42) + +the list is first built with ``SomeImpossibleValue`` items, and then the +factory is generalized to produce a list of ``SomeInteger(const=42)``. +With this "impossible object" trick we don't have to do anything special +about empty lists. + + +User-defined Classes and Instances +++++++++++++++++++++++++++++++++++ + +``SomeInstance`` stands for an instance of the given class or any +subclass of it. For each user-defined class seen by the annotator, we +maintain a ClassDef (``pypy.annotation.classdef``) describing the +attributes of the instances of the class; essentially, a ClassDef gives +the set of all class-level and instance-level attributes, and for each +one, a corresponding ``SomeXxx`` annotation. + +Instance-level attributes are discovered progressively as the annotation +progresses. Assignments like:: + + inst.attr = value + +update the ClassDef of the given instance to record that the given +attribute exists and can be as general as the given value. + +For every attribute, the ClassDef also records all the positions where +the attribute is *read*. If, at some later time, we discover an +assignment that forces the annotation about the attribute to be +generalized, then all the places that read the attribute so far are +marked as invalid and the annotator will have to restart its analysis +from there. + +The distinction between instance-level and class-level attributes is +thin; class-level attributes are essentially considered as initial +values for instance-level attributes. Methods are not special in this +respect, expect that they are bound to the instance (i.e. ``self = +SomeInstance(cls)``) when considered as the initial value for the +instance. + +The inheritance rules are as follows: the union of two ``SomeInstance`` +annotations is the ``SomeInstance`` of the most precise common base +class. If an attribute is considered (i.e. read or written) through a +``SomeInstance`` of a parent class, then we assume that all subclasses +also have the same attribute, and that the same annotation applies to +them all (so code like ``return self.x`` in a method of a parent class +forces the parent class and all its subclasses to have an attribute +``x``, whose annotation is general enough to contain all the values that +all the subclasses might want to store in ``x``). However, distinct +subclasses can have attributes of the same names with different, +unrelated annotations if they are not used in a general way through the +parent class. + + +Prebuilt Constants +++++++++++++++++++ + +(to be completed) + + +Built-in functions and methods +++++++++++++++++++++++++++++++ + +(to be completed) + + +Others +++++++ +(to be completed) From pedronis at codespeak.net Tue Mar 15 19:27:20 2005 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Tue, 15 Mar 2005 19:27:20 +0100 (MET) Subject: [pypy-svn] r9816 - pypy/dist/pypy/tool Message-ID: <20050315182720.63AC627B8D@code1.codespeak.net> Author: pedronis Date: Tue Mar 15 19:27:20 2005 New Revision: 9816 Modified: pypy/dist/pypy/tool/delta.py Log: - fixes - more verbosity about what we are exactly counting, swap incompleteness bar and text/numbers summary Modified: pypy/dist/pypy/tool/delta.py ============================================================================== --- pypy/dist/pypy/tool/delta.py (original) +++ pypy/dist/pypy/tool/delta.py Tue Mar 15 19:27:20 2005 @@ -189,7 +189,7 @@ space = self.space try: return space.getattr(obj, space.wrap(name)) - except OperationError: + except OperationError, e: return NOTFOUND def is_faked(self, obj): @@ -220,11 +220,15 @@ class Status: - def __init__(self, msg, detail_missing, class_, incompleteness): + def __init__(self, msg, detail_missing, class_, incompleteness, shortmsg = None): self.msg = msg self.detail_missing = detail_missing self.class_ = class_ self.incompleteness = incompleteness + if shortmsg is None: + self.shortmsg = msg + else: + self.shortmsg = shortmsg class Entry: @@ -244,8 +248,7 @@ assert obj2 is not NOTFOUND, "whoopsy %s" % self.name self.status = 'MISSING' self.specifically = 'missing' - elif expl1.is_faked(obj1): - assert obj2 is not NOTFOUND, "whoopsy %s" % self.name + elif expl1.is_faked(obj1) and obj2 is not NOTFOUND: self.status = 'MISSING' self.specifically = 'faked' elif obj2 is NOTFOUND: @@ -321,9 +324,13 @@ class Report(Entry): + useshort = False + notes = None + + descr = granddescr = "" - def __init__(self, name, title=None, fname=None, notes=None): + def __init__(self, name, title=None, fname=None, **kwds): if title is None: title = name Entry.__init__(self, name) @@ -342,45 +349,53 @@ self._fname = fname - if notes is not None: - self.notes = notes + self.__dict__.update(kwds) + def add_row(self, entry, rest, name=None, parent=None): self.rows.append((name, entry, rest, parent)) - def missing_stats(self, missing, total): - return "%s/%s missing (%.1f%%)" % (missing, total, float(missing)/total*100) + def missing_stats(self, missing, total, descr): + return "%s/%s %s missing (%.1f%%)" % (missing, total, descr, float(missing)/total*100) def status_wrt(self, parent=None): detail_missing = 0 incompleteness = 0.0 if self.status == 'MISSING': - msg = "%s (%s)" % (self.specifically, self.total) + count = "%s %s" % (self.total, self.descr) + shortmsg = "%s (%s)" % (self.specifically, count) detail_missing = self.total if self.grandtotal: - msg = "%s or in detail (%s)" % (msg, self.grandtotal) + count = "%s or in detail %s %s" % (count, self.granddescr, self.grandtotal) detail_missing = self.grandtotal - return Status(msg, detail_missing, class_=self.specifically, incompleteness=1.0) + msg = "%s (%s)" % (self.specifically, count) + return Status(msg, detail_missing, class_=self.specifically, incompleteness=1.0, + shortmsg = shortmsg) elif self.status == 'PRESENT': if self.missing == 0 and self.grandmissing == 0: return Status(msg="complete", detail_missing=detail_missing, class_=None, incompleteness=incompleteness) + disj = "or " if self.missing == 0: msg = "all present but" incompleteness = 1.0 + disj = "" else: - msg = self.missing_stats(self.missing, self.total) + msg = self.missing_stats(self.missing, self.total, self.descr) detail_missing = self.missing incompleteness = float(self.missing) / self.total + + shortmsg = msg if self.grandtotal: - msg = "%s in detail %s" % (msg, - self.missing_stats(self.grandmissing, self.grandtotal)) + msg = "%s %sin detail %s" % (msg, disj, + self.missing_stats(self.grandmissing, self.grandtotal, + self.granddescr)) detail_missing = self.grandmissing incompleteness = (incompleteness + float(self.grandmissing)/self.grandtotal)/2 return Status(msg, detail_missing, class_='somemissing', - incompleteness=incompleteness) + incompleteness=incompleteness, shortmsg = shortmsg) else: msg = self.only_in(parent) if msg: @@ -409,7 +424,11 @@ i = 0 for name, entry, rest, st in rows: tr_class = i%2 == 0 and "even" or "odd" - rest = rest + [st.msg, incompleteness_bar(dir, st.incompleteness)] + if self.useshort: + msg = st.shortmsg + else: + msg = st.msg + rest = rest + [incompleteness_bar(dir, st.incompleteness), msg] tbl.append(html.tr( html.td(entry.link(name), **set_class(st.class_)), *map(html.td,rest), **{'class': tr_class}) @@ -436,7 +455,7 @@ class_ = st.class_ bar = incompleteness_bar(dir, st.incompleteness) - HEADER = ''' + HEADER = ''' ''' HIDE = 'display: none' @@ -487,25 +506,27 @@ class ClassReport(Report): + descr = "methods+attrs" + def navig(self): return html.p(html.span(self.title,**{'class': 'title'}), "|",mods_report.link(None),"|",cls_report.link(None)) def grandadd(self, parent): - if self.status == 'MISSING': - parent.grandtotal += self.total - parent.grandmissing += self.missing - elif self.status == 'PRESENT': - parent.grandtotal += self.total + parent.grandtotal += self.total + parent.grandmissing += self.missing class ModuleReport(Report): + descr = "module funcs+types+etc" + + granddescr = "module funcs+others and contained types/classes methods+attrs" + def navig(self): return html.p(html.span(self.title,**{'class': 'title'}), "|",mods_report.link(None),"|",cls_report.link(None)) - notes = ("(): callable, C: type/class; detail counts module functions, attrs and " - "contained class/type methods and attrs") + notes = ("(): callable, C: type/class") def grandadd(self, parent): if self.status == 'MISSING': @@ -518,8 +539,9 @@ def delta(expl1, expl2, modnames): rep = Report('Modules', fname="modules-index", - notes = "detail counts module functions, attrs and " - "contained class/type methods and attrs") + descr = "modules", + granddescr = "of all modules funcs+others and contained types/classes methods+attrs", + useshort = True) def navig(): return html.p(html.span('Modules',**{'class': 'title'}), "|",cls_report.link(None)) @@ -646,7 +668,9 @@ def cls_delta_rep(): reps = cls_delta_cache.values() cls_rep = Report('Types/Classes', fname="types-index", - notes = "detail counts class/type methods and attrs") + descr = "types/classes", + granddescr = "of all types/classes methods+attrs" + ) def navig(): return html.p(mods_report.link(None), @@ -669,19 +693,41 @@ host_explore = HostExplore() + +basic = ['__builtin__', 'types', 'sys'] + os_layer = [] -for modname in ['posix', 'nt', 'os2', 'mac', 'ce', 'riscos']: +for modname in ['posix', 'nt', 'os2', 'mac', 'ce', 'riscos', 'errno', '_socket', 'select', 'thread']: if host_explore.get_module(modname) is not NOTFOUND: os_layer.append(modname) - -TO_CHECK = list(Set(['types', '__builtin__', 'sys']).union(Set(sys.builtin_module_names)). - union(Set([ - 'math', '_codecs', 'array', - '_random', '_sre', 'time', '_socket', 'errno', - 'marshal', 'binascii', 'parser']+os_layer))) -TO_CHECK.remove('__main__') -TO_CHECK.remove('xxsubtype') +mods = """ +_codecs +_random +_sre +_weakref +array +binascii +cPickle +cStringIO +struct +datetime +gc +itertools +math +cmath +md5 +operator +parser +sha +unicodedata +zipimport +time +""".split() + +TO_CHECK = (basic + + os_layer + + mods) TO_CHECK.sort() def getpypyrevision(cache=[]): From mwh at codespeak.net Thu Mar 17 10:43:33 2005 From: mwh at codespeak.net (mwh at codespeak.net) Date: Thu, 17 Mar 2005 10:43:33 +0100 (MET) Subject: [pypy-svn] r9845 - pypy/funding/negotiations Message-ID: <20050317094333.B46E527B61@code1.codespeak.net> Author: mwh Date: Thu Mar 17 10:43:33 2005 New Revision: 9845 Added: pypy/funding/negotiations/part_b_2004_12_11.pdf (contents, props changed) pypy/funding/negotiations/pypy-association-agreement.pdf (contents, props changed) pypy/funding/negotiations/pypy-consortium-contract.pdf (contents, props changed) Log: add pdf versions of part b of the proposal, the consortium contract and the association agreement. Added: pypy/funding/negotiations/part_b_2004_12_11.pdf ============================================================================== Binary file. No diff available. Added: pypy/funding/negotiations/pypy-association-agreement.pdf ============================================================================== Binary file. No diff available. Added: pypy/funding/negotiations/pypy-consortium-contract.pdf ============================================================================== Binary file. No diff available. From mwh at codespeak.net Thu Mar 17 10:56:01 2005 From: mwh at codespeak.net (mwh at codespeak.net) Date: Thu, 17 Mar 2005 10:56:01 +0100 (MET) Subject: [pypy-svn] r9846 - in pypy/funding: . negotiations Message-ID: <20050317095601.414D627B61@code1.codespeak.net> Author: mwh Date: Thu Mar 17 10:56:00 2005 New Revision: 9846 Removed: pypy/funding/B0.0_preamble.txt pypy/funding/B0.1_summary.txt pypy/funding/B1.0_objectives.txt pypy/funding/B2.relevance_to_IST.txt pypy/funding/B3.impact.txt pypy/funding/B4.resources.txt pypy/funding/B5.0_manage_bea.txt pypy/funding/B6.0_detailed_implementation.txt pypy/funding/B6.4_gantt.txt pypy/funding/B6.5_workpackage_list.txt pypy/funding/B6.6_deliverables_list.txt pypy/funding/B6.7.wp01_management.txt pypy/funding/B6.7.wp02_maintenance.txt pypy/funding/B6.7.wp03_synchronisation.txt pypy/funding/B6.7.wp04_core.txt pypy/funding/B6.7.wp05_translation.txt pypy/funding/B6.7.wp06_core_optimisations.txt pypy/funding/B6.7.wp07_translator_optimisations.txt pypy/funding/B6.7.wp08_dynamic_optimisation.txt pypy/funding/B6.7.wp09_search_and_logic.txt pypy/funding/B6.7.wp10_aspects_and_contracts.txt pypy/funding/B6.7.wp11_embed_in_hardware.txt pypy/funding/B6.7.wp12_validations.txt pypy/funding/B6.7.wp13_integration_config.txt pypy/funding/B6.7.wp14_documentation.txt pypy/funding/B7.0_other_issues.txt pypy/funding/negotiations/part_b_2004_04_02.pdf pypy/funding/negotiations/part_b_2004_04_02.sxw pypy/funding/negotiations/part_b_2004_07_22.sxw pypy/funding/negotiations/part_b_2004_07_22_individual.sxw pypy/funding/negotiations/part_b_2004_07_29.pdf pypy/funding/negotiations/part_b_2004_07_29.sxw Log: svn rm some obsolete stuff. If I've deleted too much, sorry -- but you should have responded to my mail to pypy-funding :) Deleted: /pypy/funding/B0.0_preamble.txt ============================================================================== --- /pypy/funding/B0.0_preamble.txt Thu Mar 17 10:56:00 2005 +++ (empty file) @@ -1,90 +0,0 @@ -:DELETE:BEGIN - -Annex 2 - Proposal Part B -IST Priority - ? 2nd call - Guide for Proposers ? Specific Targeted Research -Projects ? June 2003 - -Instructions for preparing proposal Part B for -Specific targeted research projects in the IST Priority - -In addition to the detailed technical information provided in Part B, -a proposal must also contain a Part A, containing basic information on -the proposal and the consortium making the proposal1. The forms for -Part A are provided elsewhere in this Guide. Incomplete proposals are -not eligible and will not be evaluated - - -Specific targeted research projects will aim at improving European -competitiveness. They will be sharply focused and will take either of -the following two forms, or a combination of the two: - -(a) a research and technological development project designed to gain - new knowledge either to improve considerably or to develop new products, - processes or services or to meet other needs of society and community - policies; - -(b) a demonstration project designed to prove the viability of new - technologies offering potential economic advantage but which cannot - be commercialised directly. - -Proposers should particularly note that only research, demonstration and -project management activities are funded in STREPs. Training activities -cannot be included among the eligible costs of projects. - -Information which fully details what a STREP comprises and how such a -project should be implemented can be found at -http://www.cordis.lu/fp6/instrument-strp/. Proposers should study this -information thoroughly before commencing the preparation of their proposal - -Part B. - -*** Front page -- PAGE 1 *** - - PYPY - - A flexible, modular, self-hosting, next-generation - specialising compiler for the Open Source Programming - Language Python - - -Proposal Part B - -Date of preparation: October 2003 - - A Specific Targeted Research Project for: IST-2002-2.3.2.3 - Open - development platforms for software and services - -:DELETE:END - -**List of participants** - -================ ============================================= ======================= -Participant no. Participant name Participant short name -================ ============================================= ======================= -1 (coordinator) DFKI DFKI ----------------- --------------------------------------------- ----------------------- -2 University of Southampton USH ----------------- --------------------------------------------- ----------------------- -5 AB Strakt Strakt ----------------- --------------------------------------------- ----------------------- -6 Logilab Logilab ----------------- --------------------------------------------- ----------------------- -7 ChangeMaker ChangeMaker -================ ============================================= ======================= - -:DELETE:BEGIN - -following table must be edited to have no borders. - -:DELETE:END - -==================================== ========================== -**Coordinator name** Alastair Burt ------------------------------------- -------------------------- -**Coordinator organisation name** DFKI ------------------------------------- -------------------------- -**Coordinator email** burt at dfki.de ------------------------------------- -------------------------- -**Coordinator fax** +49 681 302 2235 -==================================== ========================== - Deleted: /pypy/funding/B0.1_summary.txt ============================================================================== --- /pypy/funding/B0.1_summary.txt Thu Mar 17 10:56:00 2005 +++ (empty file) @@ -1,59 +0,0 @@ - -**Proposal full title:** - - 'PyPy: Researching a highly flexible and modular language platform - and implementing it by leveraging the Open Source Python Language - and Community' - -**Proposal acronym:** - - The proposal acronym is PyPy. - -**Strategic Objectives:** - - This proposal directly addresses the Strategic Objective - IST-2002-2.3.2.3 - 'Open development platforms for software and - services' of the Second Call of the Information Society - Technologies Workprogramme. - - Our primary Technical objective is to build an open run-time environment - for the Open Source Programming language Python. This will - facilitate the development and production of networked and distributed - software systems and services, and embedded software. - - Our primary Scientific objective is to investigate novel - techniques (based on Aspect-Oriented-Programming code generation - and abstract interpretation) for the implementation of practical - dynamic languages, breaking the compromise between flexibility, - simplicity and performance trade-offs and expanding the range - (small-to-large) of directly supportable runtime platforms. - - Our primary Methological objective is to showcase a novel - software engineering process, Sprint Driven Development. This is - an Agile methodology, providing a dynamic and adaptive - environment, suitable for co-operative and distributed - development. - - - - -**Proposal abstract:** - -.. include:: abstract.asc - - - - - - - - - - - - - - - - - Deleted: /pypy/funding/B1.0_objectives.txt ============================================================================== --- /pypy/funding/B1.0_objectives.txt Thu Mar 17 10:56:00 2005 +++ (empty file) @@ -1,469 +0,0 @@ -Scientific and Technological Objectives of the Project and State of the Art -=============================================================================== - - -Problem to be Solved ---------------------------- - -Current language implementations are static and hard to modify by -the programmers that use them ("language users"). -Even the implementations of Open Source dynamic languages have -non-flexible designs crafted by a small group of developers. -(This has always been a 'given'. The language designer, or designers, -make certain trade-offs in their language implementation, and the -language users are stuck with what was decided, even if it does not -suit their particular needs.) - -With a new flexible architecture, it is now possible to give -application developers more flexibility and configurability in their -preferred language. This is especially the case for the rising number of -specialized runtime environments where small memory footprints, -concurrency or real-time features are essential. - -Very-high-level languages (VHLL) offer a highly productive development -tool. However, whole-program static compilation is often not -suitable, so that VHLL are usually implemented by introducing a -bytecode and interpretation level, resulting in a loss of performance. -This is in contrast to lower-level languages such as C, which offer -better performance but greatly decrease productivity. - -The architectures of current interpreter implementations are a -compromise between initial simplicity, Unix-style portability and -performance in a single code base. The resulting monolithic (C) code -bases are inflexible and expensive to evolve. Early design decisions -concerning aspects such as memory management, object model and layout, -security, multi-threading model are deeply tangled in the code and -cannot be reverted, experimented with or adapted to specific runtime -environments. - -In the long run, user pressure tends to shape interpreters towards -performance at the expense of other aspects (simplicity, flexibility), -possibly culminating in the introduction of a native 'Just-In-Time' (JIT) -compiler, adding a significant amount of code and complexity and further -impairing the flexibility. [S03]_ - -Consequently, application developers are often left with bad choices - -not only regarding productivity versus performance, but also involving the -hard-wired characteristics built into the languages. They would prefer -to adapt and configure a VHLL to suit their needs while at the same -time developing on top of a customized but standard language offering both -productivity and performance. - -Quantified Specific Objective ------------------------------------ - -The aim of the PyPy project is to research and implement an interpreter -and runtime environment for the Python language, built on a unique -architecture enabling both productivity and performance. The main -building block is the concept of an Object Space which cleanly -encapsulates computational operations on objects, separated from the -bytecode interpreter. A number of features, most of which are hard to -implement as application-level libraries, can become part of the -language in a manageable and language-user-configurable way if they are -implemented modularly as Object Spaces. For example: - -* choice of memory and threading model -* choice of speed vs. memory trade-offs -* pluggable adaptive implementations of various VHLL types, e.g. dictionaries -* distributed/parallel execution (SMP or Networked) -* orthogonal persistence -* pervasive security support -* logic and aspect-oriented programming - -The second key idea to reach this level of flexibility -is to write the interpreter and Object Spaces in a -VHLL language (Python itself) and recover performance with a separate -translation process producing specialized efficient low-level code. The -translation is not one-shot: it can be repeated and tailored to weave -different aspects into releases with different trade-offs and features, -giving the user of the language a real choice. - -The PyPy project plans to deliver a compliant language implementation -passing all unit-tests of the current reference C-implementation that are -relevant to the new one. At least 90% of existing unit tests will be directly -applicable. [*]_ Moreover, we will be able to add techniques such as JIT compilation -without making the interpreter more complex. Not only will we thus -produce a more easily-understood optimising compiler, of particular -interest to educators, but we will also get speed increases of -2-10 times over the reference C-implementation. We expect algorithmic code to -run at least at 50% of the speed of pure, optimized C code. - - -.. [*] The reference C-implementation contains some tests that depend on - implementation details. The exact line between a language feature and an - implementation detail might at times be hard to draw precisely, but in any - case only concerns a minority of the tests (less than 10%). - -Current State of The Art ------------------------------- - -Interpreter Modularity -++++++++++++++++++++++++ - -Haskell monadic modular interpreters [LHJ95]_ [H98]_ are a -researched attempt at achieving modularity for interpreters. They have -not been tried on something as large as Python but in the context of -Domain-Specific Languages (DSLs). However, the approach is hard -for programmers accustomed to more conventional Object-Oriented (OO) -Programming to grasp, and requires sophisticated partial evaluation to remove the -monadic overhead. On the positive side, monad transformers are powerful enough -to modularize continuation passing, exceptions and other control flow aspects. - -Some of the kind of modularity we are interested in for interpreters - -subsetting, choice among implementation of basics aspects (memory -management,...), feature selection - has some similarity with recent research -on OS modularity and software composition, e.g. the Flux Group OSKit project -and their composition tool Knit [RFSLE00]_. - -In its basics, the approach of writing a language interpreter in the -language itself (a subset thereof) and then producing a running -low-level code version through a translation process has already been -taken e.g. for the Scheme (Scheme 48) [K97]_ and the Smalltalk -(Squeak) [IKM97]_ languages. These approaches are typically based on -translation from high-level source code (or parsed source code) into -C. It would be possible within this current state of the art to obtain -an interpreter comparable with the current C -Python implementation in functionality; but note -that our approach already differs in three respects (as explained in more -details in the section *Beyond the State of the Art*): what we will translate is a dynamically loaded -and initialized program state instead of the static source code; the translator -works by abstract interpretation (also known as symbolic interpretation), -which makes it independent from the actual source or bytecode; and we will -put the key modularity and flexibility concerns into the translator. - -We plan to exploit the gained flexibility of the translator much further. -It will enable separation on concerns between the translator, the -core interpreter, and the Object Spaces, in the spirit of Aspect -Oriented Programming (AOP) as developed in [KLM97]_. AOP separate cross-cutting -aspects into separate components. This approach has however never been used on -interpreters for large practical languages. - - -Compilation and Optimisation -++++++++++++++++++++++++++++ - -JIT compilers have been reasonably well studied; an account of their -history is given in [A03]_ . But actually writing a JIT compiler for a -given language is generally a major task [WAU99]_ . For example the -recent Jalapeno Java VM [AFGHS00]_ and its compilers, although being in -written in Java, are a complex architecture, requiring fine tuning, -using runtime sampling to assess at runtime the dynamic call graph to -drive inlining. - -Different techniques to ease this path have been recently explored: - -* To implement a dynamic language in a flexible way, it can be written - on top of another one, e.g. as a dynamic translator that produces - bytecodes for an existing virtual machine. If the virtual machine is - already equipped with state-of-the-art JIT compilation, it is - possible to leverage its benefits to the new language. This path is - not only much shorter than designing a complete custom JIT compiler, - but it is also easier to maintain and evolve. This idea is explored - in [WAU99]_ with experimental Java and Smalltalk implementations , built on top of - the Self virtual machine. As pointed out in - that paper, some source language features may not match any of the - target virtual machine features. When this issue arises, we are left - with the hard problem of refactoring an efficient JIT compiler-based - virtual machine. - -* Using a completely different approach, to make it easier to derive a JIT - compiler from an existing C interpreter, DynamoRIO instruments the - execution of compiled programs and optimizes them dynamically. It - has been extended with specific support for interpreters. With - minimal amounts of changes in the source of an interpreter, it can - significantly reduce the processor-time interpretative overhead - [S03]_ . While this offers a highly competitive gain/effort - ratio, performance does not reach the levels of a hand-crafted JIT compiler. - -The current Python C implementation (CPython) is a straight-forward bytecode -interpreter. Psyco [R03]_ is an extension to it implementing a highly -experimental [APJ03]_ specializing JIT compiler based on abstract -interpretation. In its current incarnation it is also a delicate hand-crafted -piece of code, which is hard to maintain and not flexible. But this should not -inherently be the case. Moreover it would likely benefit from integration -with type-feedback techniques such as those developed for Self [HCU91]_ [HU94]_. - -Language Extensions -+++++++++++++++++++ - -The family of languages based around logic and constraint programming has -proved very useful for knowledge representation and optimisation -problems. The key features of these languages are the use of a *logic -variable*, which allows the matching of data through unification or -constraint processing, and non-deterministic control structures. Work -initiated at the DFKI has examined ways to combine these constructs with -those from other languages [Sch02]_. A key concept here is *encapsulated -search*, which hives off these features from the more mainstream -programming constructs. - -Several people have looked at Python as a programming language for -Artificial Intelligence. Logilab initiated a project to implement -constraint programming in Python [Log]_, and one of most popular text books -in Artificial Intelligence has Python code for the examples -[RN02]_. Moreover, the main inventor of the world wide web developed the -first inference engine for the semantic web in Python [Cwm]_. However, none of -these projects has realised code that can be used in production -environments. It is simply too slow. - -Beyond State of The Art ------------------------------ - -Theoretical concepts -++++++++++++++++++++ - -* We present a novel interpreter architecture based on the separation - between Bytecode interpretation and **Object Spaces.** The former, i.e. - the interpreter's main dispatch loop, handles control flow and supporting - data structures (frame stack, bytecode objects...), while each individual - operation on objects is dispatched to the Object Space. In effect, - an Object Space explicitly captures the notion of "object library". - -* Object Spaces simultaneously capture the notion of "abstract domains": - indeed, building on this architecture, **abstract interpretation** based - on the *same* Bytecode interpreter with a different Object Space gives - us unprecedented power and simplicity for all kind of source analysis - tools. In particular, this is a new way to efficiently close the gap - between a Very High-Level Language (VHLL) and low-level code, including - for advanced JIT compilers. - -* Many aspects of the interpreter are not fixed in all their details within - the interpreter source: they are **translation aspects,** i.e. they are - weaved into the low-level translation of our VHLL source by the process of - translating it into a low-level equivalent. This allows low-level aspects - like multithreading, memory management, and continuation management to be - kept orthogonal from the rest of the source. - - -Interpreter Modularity -++++++++++++++++++++++ - -Object Spaces, in contrast to monadic interpreters, will allow -customization with OO techniques. They encapsulate the object -operation semantics, creation and global state of all objects. -As mentioned above, monad transformers have been used to -modularize continuation passing, exceptions and other control flow -aspects; the theoretical solution we provide offers a more practical -and scalable approach to the modularization of these aspects. - -In contrast to the related work previously cited, -we don't expect to encode a fixed single interpreter in all its details in a -subset of our VHLL (Python). We plan to exploit the flexibility and abstraction -gained by using the VHLL and -- most importantly -- the indirectness of -translation in order to "weave" aspects such as continuation passing, memory -management, object layout, threading model etc. at translation time. - -Many of these aspects are really cross-cutting concerns in the -original Aspect Oriented Programming (AOP) sense. E.g. we expect to -code addition between Python integers in a high-level way independent -of memory management and of boxing issues. In -general our approach relates to the seminal AOP ideas of [KLM97]_: -the subset of Python in which we express the core -interpreter and Object Spaces is the *component language* in the -terminology of the paper, while the translator is a *weaver* written -with the full dynamism of Python. - -In summary, we will explore for each feature and extension how to best -implement it by separation of concerns: either in OO-customized Object -Spaces, or in the core or in modules to be translated, or as a pluggable -behaviour of the translation itself. - -Compilation and Optimisation -++++++++++++++++++++++++++++ - -The front-end of the translator itself will be innovative in that it is -based on abstract (symbolic) interpretation. The translation of code -from our Python subset (in particular the source of PyPy itself) will -thus be driven by PyPy's own Python interpreter, made symbolic by -plugging a custom Object Space. This turns the Object Space operations -into the semantics units of translation as well, leveraging the coherence -of our architecture and gaining independence from surface issues including -the details of the syntax or of the bytecode itself. -Moreover, we can use the full dynamism of Python at system definition time, -i.e. when PyPy loads, until we reach a "stable-and-ready" state that the -translator can freeze into a snapshot containing exactly the features and -modules that we need. In previous work, the translator generally operated -on the static source code. - -During the translation process, weaving custom aspects will be done mainly -as intermediate stages, while the customizable back-end generates low-level -code in various styles as needed. For example, it can be in continuation -passing style (CPS), or it can target altogether -different runtime environments like Java -- providing a cheap way to -regenerate a replacement for Jython, the Python interpreter written in Java, -without the burden of having to maintain it synchronized with CPython. - -Another key innovative aspect of our project is to generate the JIT -compiler instead of writing it manually. Indeed, although Psyco was -hand-written, large parts have a one-to-one correspondence to whole -sections of the CPython interpreter. This is uncommon for JIT compilers, but -Psyco's good results give ample proof-of-concept. (This property can be -explicitly related to the DynamoRIO project cited above, which -instruments the interpreter itself.) The one-to-one correspondence -between parts of CPython and Psyco is as follows: to each expression in -the source of CPython corresponds a more complex expression in Psyco, -which does instrumentation and optimisations. Our plan is thus to -generate automatically as much of the JIT as possible, by changing the -translator to generate instrumenting/optimizing C instructions instead -of (or in addition to) the normal C instructions that would be the -direct translation. - - -Language Extensions -+++++++++++++++++++ - -Within PyPy, we will be the first to provide usable constraint programming -techniques within a popular VHLL. We will take advantage of the -light-weight multithreading that we will introduce to Python to handle the -constraint processing efficiently and we will examine the use of object -spaces to develop implementations of Python that are specialised for search -tasks. Doing this in a modular way through the use of object spaces, -represents a novel feature of the project. - -The DFKI has a variety of expertise with the semantic web and plays an -active role in several W3C working groups. The work of PyPy will dovetail -with the work being carried out within the DIRECT-INFO EU project, where -the DFKI is supporting a media analysis application by integrating semantic -web constructs into the Python-based Zope application server. It is -expected that efficient search integrated into the application server -framework will lead to many novel applications. - - -Distribution -++++++++++++ - -We expect to develop automatic interpreter build tools that allow -choices about aspects, modifications and extensions to be made by the -language user, and that enable advanced programmers to develop and -integrate their own aspects and extensions to the language. - -We believe that ours is a practical and scalable approach to interpreter -modularity, applicable to any language, from general to domain-specific ones. -The PyPy implementation should quickly reach the large user base of the -current, industrial-strength Python, and could eventually form the foundation -of the "next generation" Python implementation commonly referred to as -Python3000. The efforts will be focused on actively reaching out non-Python -communities, based on: - -* the build tools to generate customized versions of Python, attractive to - a larger industrial base which is currently outside the scope of VHLLs - for reasons like performance, configurability, or end-user device resources; - -* the framework of PyPy's source code, reusable to implement other - general or domain-specific languages; - -* the theoretical approach and solutions that we publish. - ----------------------------------------------- - -**References** - -.. [A03] John Aycock, "A Brief History of - Just-In-Time", ACM Computing Surveys 35, 2 (June 2003), pp. 97-113. - -.. file = jit-history.pdf - - -.. [AFGHS00] Matthew Arnold, Stephen J. Fink, David Grove, Michael Hind, and Peter F. Sweeney, - "Adaptive Optimization in the Jalapeno JVM", In Conference on Object-Oriented Programming and Systems, pp. 47-65, 2000. - http://citeseer.nj.nec.com/arnold00adaptive.html - - -.. [APJ03] John Aycock and David Pereira and Georges Jodoin, - "UCPy: Reverse-Engineering Python", PyCon DC 2003, 9pp. - http://pages.cpsc.ucalgary.ca/~aycock/papers/ucpy.pdf - -.. file = ucpy-reverse-engineering-python.pdf - - -.. [Cwm] http://www.w3.org/2000/10/swap/doc/cwm - - -.. [H98] Paul Hudak. "Modular Domain Specific Languages and Tools". ICSR 98. - 1998. http://haskell.org/frp/dsl.ps - -.. file = dsl.ps.gz - - -.. [HCU91] Urs H?lzle, Craig Chambers, and David Ungar, - "Optimizing Dynamically-Typed Object-Oriented Languages with Polymorphic - Inline Caches", ECOOP'91 Conference Proceedings, Geneva, 1991. Published - as Springer Verlag Lecture Notes in Computer Science 512, Springer Verlag, - Berlin, 1991. - http://self.sunlabs.com/papers/ecoop91.ps.Z - -.. file = hlzle91optimizing.ps.gz - - -.. [HU94] Urs H?lzle, David Ungar, - "Reconciling Responsiveness with Performance in Pure Object-Oriented - Languages", PLDI '94 and OOPSLA '94 - http://www.cs.ucsb.edu/oocsb/papers/toplas96.pdf/reconciling-responsiveness-with-performance.pdf - -.. file = reconciling-responsiveness-with-performance.pdf - - -.. [IKM97] Dan Ingalls, Ted Kaehler, John Maloney, Scott Wallace, and - Alan Kay. "Back to the future: The story of Squeak, A practical - Smalltalk written in itself." In Proceedings OOPSLA'97, pages - 318--326, November 1997. - ftp://st.cs.uiuc.edu/Smalltalk/Squeak/docs/OOPSLA.Squeak.html - -.. file = OOPSLA.Squeak.htm - - -.. [K97] Richard Kelsey, "Pre-Scheme: A Scheme Dialect for Systems - Programming".1997. http://citeseer.nj.nec.com/kelsey97prescheme.html - -.. file = kelsey97prescheme.pdf - - -.. [KLM97] Gregor Kiczales and John Lamping and - Anurag Menhdhekar and Chris Maeda and Cristina Lopes and Jean-Marc - Loingtier and John Irwin, "Aspect-Oriented Programming", ECOOP'97 - http://www2.parc.com/csl/groups/sda/publications/papers/Kiczales-ECOOP97/for-web.pdf - -.. file = kiczales97aspectoriented.pdf - - -.. [LHJ95] Sheng Liang, Paul Hudak and Mark Jones. "Monad Transformers - and Modular Interpreters". 22nd ACM Symposium on Principles of Programming - Languages (POPL'95). January 1995. - http://java.sun.com/people/sl/papers/popl95.ps.gz - -.. file = popl95.ps.gz - - -.. [Log] http://www.logilab.org/projects/constraint - -.. [RN02] Russell, Stuart, and Norvig, Peter, "AI: A Modern Approach", - Prentice-Hall, 2002, http://aima.cs.berkeley.edu/python/readme.html - -.. [R03] Armin Rigo, http://psyco.sourceforge.net - -.. file = psycoguide.ps.gz - - -.. [RFSLE00] Alastair Reid, Matthew Flatt, Leigh Stoller, Jay Lepreau, and Eric Eide, - "Knit: Component Composition for Systems Software", - in Proceedings of the Fourth Symposium on Operating Systems Design and Implementation OSDI'2000, 2000. - http://www.cs.utah.edu/flux/papers/knit-osdi00.pdf - - -.. [S03] Gregory Sullivan et. al., "Dynamic Native Optimization of Native - Interpreters". IVME 03. 2003. http://www.ai.mit.edu/~gregs/dynamorio.html - -.. file = ivme03.pdf - - -.. [Sch02] Christian Schulte, "Programming Constraint Services". Volume - 2302 of Lecture Notes in Artificial Intelligence, Springer-Verlag, 2002 - -.. [WAU99] Mario Wolczko, Ole Agesen, David Ungar, "Towards a - Universal Implementation Substrate for Object-Oriented - Languages",OOPSLA 99 workshop on Simplicity, Performance and - Portability in Virtual Machine Design, OOPSLA '99, Denver, CO, Nov - 2, 1999. - http://research.sun.com/research/kanban/oopsla-vm-wkshp.pdf - -.. file = oopsla-vm-wkshp.pdf - Deleted: /pypy/funding/B2.relevance_to_IST.txt ============================================================================== --- /pypy/funding/B2.relevance_to_IST.txt Thu Mar 17 10:56:00 2005 +++ (empty file) @@ -1,179 +0,0 @@ -.. include:: crossreferences.asc - -Relevance to the Objectives of the IST Priority ------------------------------------------------ - -Supporting Participation -++++++++++++++++++++++++ - -The PyPy project will connect expert researchers, programmers -and users at all levels at all times. On the social level we will explore -and refine new cooperative ways of researching and implementing advanced -highly involved technologies. Building on the large communication network of -opensource programmers we will explore and refine agile methodologies. -We believe that our new **fluid networked way of rapid software development -presents a new paradigm how people can work together**. - -This is an efficient countermeasure to the perceived European "weak culture -of transferring and exploiting university research results" (SWOT table from -'IST Advisory Group: Software technologies, embedded systems and distributed -systems: A European strategy towards an Ambient Intelligent environment'). - - -Python as a Language "For Everybody" -++++++++++++++++++++++++++++++++++++ - -The European industry, as well as many developers, are not interested in -yet another new language. Instead our project will produce an -extremely flexible and performing development platform around the -Python programming language. Much anecdotal, and some empirical, -evidence suggests that Python is one of the easiest programming -languages to learn and is one of the languages in which one can code -up a given algorithm the fastest. For these reasons, it is -**particularly popular among those people whose main competence lies -beyond computer science and for whom programming is a secondary -activity**, that is to say almost everyone in the information -industry. Using Python itself to develop an innovative Python -implementation will allow many people to understand the platform and -reuse it in their context. Understanding, teaching and adapting our -Python implementation will be much easier than almost any other -language implementation. - - -A Development Platform Suited for Tomorrow's European industry -++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - -The EU is interested in **software technologies that are reliable, -pervasive, interoperable and can be adapted to accommodate new -applications and services**. This is exactly the focus of our project. -With some unique approaches to building a highly performing and -productive development platform we will further innovation and -interoperability. - -We will build an extensible Python implementation that can be adapted -and configured for almost all runtime environments. It will go far -beyond the state of the Art in computer languages, and produce a -runtime system which is much better suited for the development and -deployment of networked, embedded, and mobile devices than any -existing language available today. In doing so it will be compliant -with the Python language specification requiring no re-training for -the tens of thousands of European Python programmers. To dramatically -expand the scope of an already very productive development environment -can only have a positive effect on European competitiveness. - - -PyPy Builds on the Most Successful Language Designed in Europe -++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - -Python is the most widely used European-designed computer language. -Its development started in 1990, at CWI, Centrum voor Wiskunde en -Informatica, the National Research Institute for Mathematics and -Computer Science in the Netherlands. This project will strengthen European leadership -in the area of innovative language design, and increase world-wide -awareness of this fact. We can even do our bit to reverse the -brain-drain, as talented European language designers will no longer -have to move to North America to be involved in language projects -which have more than academic interest. - -We believe that PyPy presents a **unique opportunity to bring -considerable market- and mind share with respect to development tools -and environments back to Europe**. The many individuals and companies -involved with the project are deeply entangled with the opensource -community and businesses. Python and PyPy in particular provide a -viable alternative to American closed source language monopolies, -while increasing innovation and competitiveness in European businesses -and industry and thus contributing to the greater well-being of all -European citizens. - -Working with the strong Open Source community to overcome the -European weakness with development platforms obviously builds on the -strategies as outlined in the SWOT-analysis by the IST workgroup. - - -Solving 'trust and Confidence' Problems -+++++++++++++++++++++++++++++++++++++++ - -The IST thematic priority will contribute directly to realizing -European policies for the knowledge society as agreed at the Lisbon -Council of 2000, the Stockholm Council of 2001, the Seville Council of -2002, and as reflected in the e-Europe Action Plan. - -A main target of IST in FP6 is:: - - solving 'trust and confidence' problems so as to improve - dependability of technologies, infrastructures and applications. - -PyPy will contribute to this goal because it is build on the strength -of the Open Source community. Open Source programs are more widely trusted -than proprietary alternatives because they are more transparent, accessible -and customizable. Especially in large Open Source projects all parts of -the program are under permanent scrutiny of many interested developers. -Because we are deeply connected with the large Python community we are -confident that PyPy can take full advantage of this open culture. - -Moreover, Python is an extremely readable language. Readability was and -remains one of its main design goals. This makes maintaining Python programs -substantially easier than similar program in less readable languages. It is the -maintainability of computer programs which most directly effects their -actual and perceived reliability and encourages intelligent usage. - -In our view development platforms should not be proprietary but should -**empower the user** to get involved and provide appropriate extensions -suiting commercial and research needs. Thus rather than 'trusting the -manufacturer because you have no choice' you can 'trust yourself'. -This second form of trust is far more durable and useful. - - -Strengthening Social Cohesion -+++++++++++++++++++++++++++++ - -Social cohesion is strengthened when technological advances are no -longer the exclusive domain of a technological or commercial elite, -but readily accessible by all members of society. The best way to -achieve such a goal is to have the participation of all members of -society in the design and implementation of new technological advances. -In the field of software, this means more than simply providing programs -which are easy to use -- it also means providing languages which are -easier for people for whom programming is a secondary activity. - -- enabling sustainable growth and improving competitiveness both of - large and small businesses as well as the efficiency and transparency - of governments. - -Governments have been embracing Open Source for some time now. -To the extent that they will demand programs developed in an -Open Source Language, for reasons of transparency, reliability, and -national security they will benefit from the existence of PyPy as an -Open Source language choice. - -Participation of SME's in High-Level Research -+++++++++++++++++++++++++++++++++++++++++++++ - -The consortium will closely interact with the Python Business Forum -(of which some members are part), an international trade -association of SMEs who develop using the Python programming language, and -other SME partners. -Since SMEs are the main engines for innovation, growth, and competitiveness -in the IT sector, supporting these SMEs, and improving the language they -use to develop can have a direct positive effect on European competitiveness. -Moreover, synergies can be developed between the SMEs and academia, and SMEs -and large industrial players. Disseminating knowledge to SMEs is a -primary goal of this proposal, and a major focus of our efforts. They will be -poised to fully exploit the new language implementation because they are -among its developers, and the beneficiaries of a focused effort in -knowledge dissemination. - -Contribution to EC Policies -++++++++++++++++++++++++++++ - -There will be transfer of knowledge from research to industry through -the participation of software developing SMEs. Thus the SMEs in the -project will benefit from the cutting-edge, high level research results. -Since the SMEs are in a hurry to commercialise products which use this -research, the academics will see that their research is not wasted -- -locked into tiny languages which have little effect outside of the -academic community. A specialising Just-in-Time Compiler for Python, -designed for the use of networked and embedded systems will have -immediate effect in reinforcing European dominance in this demanding -competitive field, and thus contribute to the employment of people -in desirable jobs in a rapidly growing commercial sector. Deleted: /pypy/funding/B3.impact.txt ============================================================================== --- /pypy/funding/B3.impact.txt Thu Mar 17 10:56:00 2005 +++ (empty file) @@ -1,549 +0,0 @@ -.. include:: crossreferences.asc - -Potential Impact ---------------------------------------------------------------------------- - -The successful execution of the PyPy project will deliver a highly productive -and flexible implementation of an Object-Oriented, Open Source Very-High-Level -programming language (VHLL). - -This will impact software development in several important ways. - - - The cost of software development will diminish. - - - The time to market will be reduced. - - - The cost of software maintenance will be reduced. - - - The barriers to marketing a product will be lowered. - - -The development methods of the PyPy project will prove that using Sprints, -pair programming and test-driven development results in : - - - Broader understanding of the code base among developers - - - Rapid developments from ideas to working code - - - Sustainable project progress through unit testing - -The cost of software development is essentially labor costs, time to -market, and costs of software tools. Having a (free) flexible VHLL means -problems are solved closer to the abstraction level at which they are -formulated, thereby -improving the productivity of the individual programmer. Higher productivity, -obviously, will decrease labor costs and time to market. - -However, the greater impact we expect to have is to produce a version of the -language which, being superior to anything which -has gone before, will be extremely widely used. To that end, our first -target group is the existing community of Python/Jython programmers. -See the section on Exploitation where this is discussed at length. - -Contributions to Standards -+++++++++++++++++++++++++++ - -There are currently two implementations of Python in common use. The -first one, which we will call CPython, (what the world -knows as Python), is a C implementation of the Python Programming -language which compiles to its own virtual machine. The second one is -Jython, a pure-Python implementation which compiles to the Java -virtual machine. There is no ANSI standard (or similar standard) for Python. -Right now the de-facto standard for the programming language is -'whatever CPython does'. This is far from ideal, and questions arise, -especially from the developers of Jython as to which CPython language -behaviors are essential to the Python language itself, and which are -mere accidents of this particular implementation. - -For example, the garbage-collection behavior of CPython is implemented -by reference-counting, which ensures that an object is finalized as soon as -the last reference to it goes away. That would be extremely -inconvenient (close to impossible) to implement on standard Java -Virtual Machines, which have a deliberately under-specified garbage -collector (it can collect anything it pleases whenever it pleases...). -In this case, the Jython designers had to obtain an explicit ruling -from Guido van Rossum, Python's designer -- who ruled that the -behavior of CPython was 'accidental' in this case, and not intrinsic -to the Python language specification. - -Guido van Rossum has expressed interest in giving PyPy the status of -'implementation standard' (executable specification) of the Python -programming language. PyPy's Object Space flexibility will be crucial -in distinguishing "accidental" from "designed-in" characteristics. - -Here is the relevant mail from Guido van Rossum:: - - Having participated in one PyPy Sprint, I am very happy with this - project, and hope to see it going forward. The PyPy team includes - some of the best minds in the Python community. - - Unlike Perl or Tcl, Python is not a "one-implementation" language, and - consequently the formal language specification should have priority - over the behavior of a particular implementation. The PyPy project - will reinforce this idea, and can be useful in sorting out ambiguities - in the specification. It is even possible that PyPy will eventually - serve as an "executable specification" for the language, and the - behavior of one of PyPy's object spaces will be deemed the correct - one. - - --Guido van Rossum (home page: http://www.python.org/~guido/) - -In order to do this we will have to submit a PEP. A PEP - Python -Enhancement Proposal - is a design document providing information to the -Python community, or describing a new feature for Python. The PEP process -is designed for Community involvement and participation. - -There are two kinds of PEPs. A Standards Track PEP describes a new -feature or implementation for Python. An Informational PEP describes a -Python design issue, or provides general guidelines or information to -the Python community, but does not propose a new feature. If we -proposed to make PyPy the reference standard of the Python language, -we would, obviously, have to submit a Standards Track PEP. - -The complete details of how to write a PEP are themselves an -Informational PEP -- PEP #1 [PEP1]_ in fact. - -After circulating through the community, PEPs are reviewed by Guido -van Rossum, the language author, and his chosen consultants, who may -accept or reject a PEP or send it back to the author(s) for revision. -Thus the expression of interest from Guido van Rossum is of extreme -significance. It is very likely, if all the goals described in the -project are completed, that PyPy will become the standard reference -implementation of the Python language. In other words, our problems -are technical, and not political. The political will is already there -to make PyPy the reference language. We merely need to create it. - -Strategic impact -+++++++++++++++++ - -PyPy will have a significant strategic impact throughout the IT -sector. It produces immensely useful, practical results which shall -be immediately exploited by Python developers world-wide. While it -addresses issues which have hitherto mostly remained the special -province of academia, and significantly enhances the State-of-the-Art, -it is not a project that will only satisfy intellectual curiosity. - -We intend to make a new reference version of the Python Programming -Language, which is faster, more flexible, more extensible, and which -gives more control to the individual programmer as to how it is -deployed. For instance, you will be able to build a Python -interpreter customized for a very small amount of available memory. -Or one with speed enhancements only possible because there is a huge -amount of memory available. Or a PyPy interpreter which will be -executed on several machines but offer a single distributed computation -space and balances the load by moving execution threads around. We can -produce Object Spaces which implement Logic Programming, Aspect Oriented -Programming and Design By Contract, hot new topics in computer science -research which are rarely seen in industry because existing popular -languages do not support them. - -An implementation of the language with substantial improvements will -have an immediate direct effect on European competitiveness. Moreover, -the planned improvements directly target the handheld, mobile, and -embedded device sectors, where Europe is the acknowledged world -leader. People working in such industries have long desired a high -level language with a very small footprint. The new innovative -concept of Object Spaces, pioneered by PyPy makes possible the -construction of tiny Object Spaces, suitable for running on the -smallest devices. Indeed, it will be possible for application -programmers to configure Python runtime environments to suit their -particular hardware characteristics -- for instance, a version that -runs in a minimal amount of memory, or a version that can exploit a -huge amount of memory to achieve the highest performance speed. - -Python with greater speed will seamlessly improve the offerings of -those European companies who already develop using Python. Moreover, -many companies resist using Python because of speed concerns. If -execution speed, rather than development speed is of paramount -importance, then Python is currently not a very good language -choice. A faster Python would be appealing to such companies, perhaps -appealing enough to motivate them to switch development languages. -Already many companies are using Python for their scripting needs, -indicating that the speed factor is very significant. - -Strategic Impact of Open Source -================================ - -Open Source has now reached an installed application base sufficient to -become widely recognized as a viable business standard, especially in -Europe. This is in part because the proprietary alternatives are -intellectual properties of large USA based companies, but also due to -a growing awareness of the other benefits that Open Source can provide. -The European Union, -comprising heterogeneous distinct regions with different availability -of economic resources, is well positioned to take advantage of the Open -Source momentum. One reason that Open Source is becoming so appealing is due -to its equal suitability for projects based on diverse capital budgets. - -Python is an easy to learn, easy to use, Open Source programming -language. It is readily accessible to a broad user base, estimated at -175,000 programmers world-wide, employed in education, -government and commercial enterprises of all sizes. This -project aims at building upon the inherent strengths of Python to -ensure its longevity in the commercial and research marketplaces. This -will maximize the return of the existing and future capital investment -in this technology and ensure Python's widespread acceptance as one of -the most cost-effective technology platforms available. - -Potential Impact on the Balance of Trade -======================================== -One of the greatest threats to European competitiveness -is its dependence upon proprietary closed source software, mostly made -in the United States. This is not only an issue of money being -spent in the United States is money that is not being spent here, -although that affect matters as well. There are two more serious -risks. - -The first is a threat in the present. Any company which writes its -software in a proprietary, closed source language is dependent upon its -software provider. If you have a bug, you must wait for them to fix it. -If this bug is not a high priority for them, you can wait a long time. If -you have access to the source you always have the option of fixing it -yourself, or hiring somebody else to do that. But this is not the greatest -of your worries. The second threat is that you are at constant risk of -having your software provider discontinue support for your platform. This -is a real threat, not a theoretical one. In 2002, Microsoft announced that -it would no longer be supporting Visual Basic 6.0 after the year 2005. All -Visual Basic Developers have been told to convert their code to run under -Microsoft's new .NET framework. Before that, in 2001, Microsoft suddenly -stopped supporting its Visual J++ language platform, meant to be a direct -competitor for Java, after settling a lawsuit with Sun Microsystems. No -migration path was specified. Microsoft is making these decisions because -they make business sense for Microsoft, regardless of the effects on -European software developers. - -Right now Python is the sixth most popular programming language in the -world. Java and Visual Basic (VB), ranked 1 and 2, are closed source -proprietary American products. The number one reason that is cited by -Java users as to 'why they don't use Python' is that it is too slow. -PyPy will fix this. The Visual Basic programmers are in a more -interesting position. Microsoft, in its wisdom, has decided to end -support of their current platform, Visual Basic 6.0. After the year -2005, these programmers will have to move to Microsoft's .NET. They're -understandably unhappy, and tempted to move, not to .NET, but to an Open -Source language, just so that they can have control over their own destiny -and indicate their displeasure with Microsoft at the same time. - -This is a tremendous opportunity for us. Every Java and VB user that -switches to Python does not pay license fees to Sun or Microsoft and -helps the European balance of Trade. - -Of course, all the PBF members are predicting that an improved Python -will improve their sales, both domestic and foreign. The dominance of -the PBF by European companies means this can only improve Europe's -trade balance. - -European Dimension -=================== - -PyPy is an extremely high-profile project, as is only right since we -intend to utilize the estimated 175,000 Python users as our user-base. -Consequently, it is essential that we have the full support of the -International Python community. Our success in that regard was more -fully spoken about in B3.1, International Standards, but suffice to -say that the only possible dimensions for this project is 'Europe -Wide' or 'World Wide'. We could not find the expertise needed in a -single country, and nor could we attain international acceptance -without involving the top members of the Python community. Working at -a smaller (single-country) scale would only 'fork the project' -- make -a local version which is of limited use, while the main line project -continued to develop in another direction. At best we would have a -ghetto. At worst, we would have two hostile camps slinging insults at -each other over which 'was the real Python'. - -We have avoided all of these problems by carefully making the PyPy project -sufficiently international, by discussing this proposal for nearly a year at -international conferences, and by inviting non-European Python -luminaries to our week-long intensive code-writing meetings called -'Sprints'. By producing a prototype in four coding Sprints (spread out -over half a year) held in locations in Hildesheim, Germany; -Gothenburg, Sweden; Louvain-La-Neuve, Belgium; and Berlin, Germany, -while discussing the project on mailing lists and on our -website, we have made certain that we have the proper dimension for -our project to succeed, and become the new reference language for -Python. - -Innovation Related Activities -++++++++++++++++++++++++++++++ - -This is an Open Source Project. Thus complicated issues involving -intellectual property do not arise. The knowledge produced -by this project, every deliverable, is listed at Dissemination Level -Public (PU). We are utterly committed to transparency and open dissemination, -and as such will have all of our code available for nightly downloads, -our papers freely available on the PyPy websites, and freely available -for other people to link to. All Consortium members will have signed -a consortium agreement, asserting that all code producing during the -PyPy STREP will be released under the MIT Open Source License, approved -by both the Open Source Initiative and the Free Software Foundation. -The MIT license is here: - -:: - - The MIT License - - Copyright (c) - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation - files (the "Software"), to deal in the Software without - restriction, including without limitation the rights to use, - copy, modify, merge, publish, distribute, sublicense, and/or - sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - DEALINGS IN THE SOFTWARE. - -This license is concise and clearly permits any person obtaining our -product to use it without limitation. The open, clear language removes -any chance of a licensing controversy. It allows commercial entities -and the project partners in particular to incorporate code and results -into commercial or non-commercial projects. - -The consortium did consider using the GPL license for protection from a -commercial takeover. We regognise that there is some risk that the -results of our project would be subject to an 'embrace and extend' -strategy or another form of hostile takeover, especially if the project -is a great success. - -However, the 'critical mass' which makes such a scenario -likely is dependent upon our achieving widespread adoption both within and -outside the present Python community. Before we can get any adoption -outside the Python community, we have to win the hearts of people on the -inside. These people - especially the portal figures - have a strong -preference for MIT license models and lack enthusiasm for the GPL. - -Also, such a takeover attempt is not guranteed to be successful and the Python -world is probably more resilient to such tries than most other -communities, since it is more strongly integrated and collaboratively -focused than other comparable groups. - -Management of Intellectual Property -==================================== - -Management of the primary PyPy intellectual property, source code, -consists of posting the license on -the website, or wherever source code is available, and periodically -running a program, especially before software releases, to check that -the license is properly refered to from each file. - -The only other intellectual properties which we will produce are -scientific papers, talks, workshops, and the like. They will all be freely -available. Copyright shall rest in the authors, unless somebody -gives a paper to one of the scientific journals that keeps all -copyright to itself. In either case, no management is necessary. - -The current version of Python is licensed under the Python Software -License. Our project will in no way conflict with this license. This is -authoritative. Tim Peters, a member of the PyPy project, is also director of -the Python Software Foundation, and responsible for the Intellectual Property -of the existing Python language. - -Dissemination -++++++++++++++ - -To successfully disseminate knowledge from the PyPy project, the project -needs to have good steadfast routines for documenting and interacting with -the project stakeholders. The project management team (project manager and -assisting project manager) will be responsible for overseeing -dissemination tasks and activities. - -Dissemination will consist of, but not be limited to - -* The key activities in the project and the development process are the - "Sprints". These are open forums to which we actively invite members from - both commercial and research oriented organizations to actively - participate - -* since PyPy as a project has goal of a high transparency (see B5), - documentation and information as well as project member contact information - will be easy to locate for external interested potential stakeholders - -* the PyPy project will gather on a regular basis, during Sprints, knowledge - about the the development process and results. Every six months, the project - will go through a project review workshop in which specific emphasis will be - put on knowledge gathering and dissemination strategies - -* a PyPy newsletter will be produced for external organizations/commercial - enterprises that will be sent out after each Sprint, keeping them - updated on project process and development progress. The assistant - project manager will be responsible for this. - -* to ensure that interested external parties will be able to use knowledge - acquired in the PyPy project we will host two workshops during the - project, one after 6 months and the first review workshop and one at the - end of the project in which we actively work with interested parties to - analyze potential usage of PyPy process and prototype.We will also host - 4 domain specific workshops for SME:s within community, industrial stakeholders - within embedded software community and game developing companies to ensure a - thorough dissemination of possibilities of PyPy usage - -We will also partake in the following official events, forum, conferences -to spread information about the ongoing project, its unique process and -technological impact and thus reaching out to software developers within -the Python community as well as practitioners of other software languages: - -EuroPython/EuroZope (European Python Conference), -ACM/IFIP/USENIX International Middleware Conference, -OSCON (Open Source Convention), -OOPSLA (Object-Oriented programming, systems, languages and applications) -PyCon (Python Developers conference), -FOSDEM (Free and Open Source Developer European Meeting), -ECOOP (European Conference for Object Oriented Programming) - -More conferences will be added once the project gets started. - -Exploitation -+++++++++++++ - -Our first goal in exploitation will be to make PyPy the reference Python -language. Our market, then is all existing Python programmers. -*Just how many are we?* - -It is always difficult to measure how many people are using a -programming language. Python is generally ranked the sixth most popular -computer language in the world. Only Java, Visual Basic, C, C++, and Perl are -believed to have more users. - -The Python FAQ, available at the Python language home site of -python.org says:: - - 2.1. How many people are using Python? - - Certainly thousands, and quite probably tens of thousands of users. - More are seeing the light each day. The comp.lang.python newsgroup is - very active, but overall there is no accurate estimate of the number - of subscribers or Python users. Jacek Artymiak has created a Python - Users Counter; you can see the current count by visiting - http://www.wszechnica.safenet.pl/cgi-bin/checkpythonuserscounter.py - - Jacek's counter has more than 43,000 registered users. - -Googling for 'python programming' gives 3,020,000 hits. ('Python' gives -ten million, but many of those Pythons are probably actual reptiles.) - -Compared to the most common languages these days, C, C++, Java and -Visual Basic, there is certainly less 'market penetration', -and in some niches, languages such as PHP, Perl and SQL are popular, -but Python is vastly bigger than the more obscure languages such -as Haskell, OCaml, Smalltalk, ADA, Ruby etc. - -Some statistics from python.org may be relevant. There were 47,751 -Python 2.3 downloads in the first 10 days of September 2003. These are the -**bleeding edge** developers, who were interested in the new release of -Python first made available at the end of August. At the other end of -the spectrum, there are many more who wait for Python to become -available as a Red Hat, or Debian package, or simply use the version -of Python that came installed with their machine when they bought it. - -For what it's worth, there are about 600,000 web visitors a month to -python.org. About one third of them are using the documentation, -which is a fairly good indicator that they are trying to use the -language. Number of unique IP addresses per month is about 350,000 at -this point, and has been rising steadily from about 250,000 this time -last year. - -Converting this into an actual estimate of number of users is difficult, -because: - -1) One user may use multiple machines (e.g. home & work & cafe) -2) Many sites use a firewall that hides the actual IP (and thus combines - multiple users into one) -3) Not all Python users go to python.org every month (or at least not - the Documentation page), because they have already downloaded the - documentation for local browsing. - -A conservative estimate would be that there are at least 175,000 active -Python users in the world. At least half of them are in Europe, if -O'Reilly's sales statistics for their popular books *Learning Python*, -*Python in a Nutshell* and *The Python Cookbook* are to be considered -relevant. Another piece of data, sales statistics of *The Essential -Jython* targeted at users of the Python version that compiles to -the Java Virtual Machine indicate that there are at least 10 thousand -Jython users worldwide. - -175,000. That's a lot of Python users. Greatly improving the language -which they all use will have an enormous impact. Since the PyPy development -team is in constant contact with the Python community, and its -world-wide leadership, there is no friction or political resistance to -PyPy. The individual members of the consortium are among the most -well-known and well-respected members of the Python community. We -have taken special care to include prominent stakeholders in the -existing language from the very beginning, and have constantly invited -members of the community to a series of development Sprints whereby we -produced a prototype which served as a proof-of-concept. We have also -budgeted for extensive communication and dissemination with this -community. Thus when we deliver a working product, they will be ready -to adopt it. - -Beyond this, there are the users of other languages. There are -something like 12 million programmers world-wide and roughly 50% of -those use Visual Basic (according to International Data Corp). In -March 2002, Borland said Java had about 1.5 million developers. How -do we go about getting them to use PyPy? - -First of all, we must give them something that they find useful, and -useful enough to switch. While Python users might be satisfied at -getting a faster language, the users of other languages, who will need -to make a greater effort in switching need a greater reason to switch. -Fortunately, this is the technical goal of the project. - -The current State-of-the-Art, both in Python and in programming languages -in general, does not best serve the new needs of the creators of -embedded, networked and distributed software sectors. They need a -more flexible language which is easier to reduce to its 'bare-bones' -for embedding, and which can dynamically reconfigure itself and -optimize execution speed at the interpreter level. Consequently, the -PyPy project is a collaboration between academic researchers and SME -software and service providers. The former have the skill and vision -to produce a new run-time language architecture for the twenty-first -century and the latter wish to deploy PyPy in their innovative new -business ventures. - -Furthermore, an important aspect of the current proposal is that we -will make use of the new opportunities that the Object Spaces give us -to extend the reach of the Python to areas where programmers currently -have to resort to other languages. In particular, we will bring the -Stackless version of Python into the mainstream. This allows Python to -handle thousands of threads inexpensively, making simulation software -easy to program. The makers of computer games have already shown -interest in this, and have funded its early development. The Stackless -Python implementation also supports mobility of running code, allowing -it to migrate from one machine to another. Other programming areas -addressed by the project by building on Object Spaces are Aspect -Oriented Programming, Design by Contract, and Constraint Solving. All -these will significantly increase the attractiveness of Python as a -programming language, and we will work with people in the Python -community who are interested in simulation, software engineering, and -the semantic web to ensure that they can take full advantage of the -new platform we are offering. - -Here is a selection of endorsements of the project from stakeholders, -members of the Python Business Forum. - -.. include:: endorsements.asc - -The results of the PyPy project are also expected to be utilized by -established industrial users. We have expressions of interest from -*Bang and Olufsen*, the Danish manufacturer of high-end stereo -equipment, *The IBM Zurich Research Lab*, *Vodaphone* and *Ericsson* the mobile industrialists, -*Siemens*, the German conglomerate, and *Axis* the Swedish-based -multinational market leader in in-house developed chip technology for -network video and print servers. - - -**References** - - -.. [PEP1] http://www.python.org/peps/pep-0001.html - - Deleted: /pypy/funding/B4.resources.txt ============================================================================== --- /pypy/funding/B4.resources.txt Thu Mar 17 10:56:00 2005 +++ (empty file) @@ -1,655 +0,0 @@ -The Consortium and Project Resources -===================================== - -Description of the Partners ---------------------------- - -DFKI -++++ - -:: - - Role: Project Coordinator & Technical Partner - Country: Germany - Contact: Alastair Burt - -Founded in 1988, the DFKI (http://www.dfki.de/) today is a -contract research institute in the field of innovative software -technology based on Artificial Intelligence (AI). The DFKI focuses -on the complete cycle of innovation - from world-class basic -research and technology development through leading-edge demonstrator -and prototypes to product functions and commercialization. - -Based in Kaiserslautern and Saarbr?cken, the German Research Center -for Artificial Intelligence ranks among the important "Centers of -Excellence" worldwide. - -An important element of DFKI's mission is to move innovations as -quickly as possible from the lab into the marketplace. A tenet of -the DFKI is that the best way to meets its technology transfer goals -is to maintain a varied portfolio of research projects at the -forefront of science. - - -Key Personnel -~~~~~~~~~~~~~ - -**Alastair Burt**, a researcher at the German Research Center for Artificial -Intelligence (German Research Center for Artificial Intelligence). He -studied Psychology at the University of Stirling, Scotland and Computing at -Imperial College London. In 1990 he joined the Multiagent System Research -Group at German Research Center for Artificial Intelligence GmbH in -Saarbr?cken in the department of Deduction and Multiagent Systems headed by -Prof. H. J. Siekmann. Since then he has has been involved with wide variety -of research projects centered around the application of multi agent -systems, including participation in several EC projects and taking -responsibility for their coordination. In particular, he was coordinator of -the ASWAD project that developed a Free Software workflow tool for public -administrations across Europe, an innovative use of the Zope and Python -platform. - -University of Southampton -+++++++++++++++++++++++++ - -:: - - Role: Technical Partner - Country: United Kingdom - Contact: Michael Leuschel - -The University of Southampton (http://www.soton.ac.uk) is one of the -leading universities in the UK for high-quality research across a wide -range of disciplines. - -In the most recent Research Assessment Exercise (RAE) carried out by -the Higher Education Funding Council for England the University -achieved spectacular results - gaining the 5 or 5* status for 24 of -its 34 units of assessment (5* being the top rating). The University -was placed ninth in the country for the quality of its research. The -University of Southampton competes internationally as an elite -research intensive institution. - -Key Personnel -~~~~~~~~~~~~~ - -**Armin Rigo** was born in 1976 in Lausanne, Switzerland. He is a -researcher at the University of Southampton (UK). He studied -Mathematics at the University of Lausanne and obtained his Ph.D. in -Logic and Set Theory at the Free University of Brussels. He is the -main author of several commercial, open source and research programs -and contributed to a number of them, most notably in the fields of -computer graphics and 3D modelling, education, and programming -languages. He recently developed in the Psyco project novel techniques -for efficient interpretation of dynamic programming languages. He is -also a member and contributor of the TUNES Project for a Free -Reflective Computing System. - -**Michael Hudson** was born in 1978 in the United Kingdom. He holds a -first class degree in Mathematics from the University of Cambridge and -took the Certificate of Advanced Study in Mathematics at the same -institution. He is currently studying for a PhD in Algebra at the -University of Bristol, but should join USH upon graduation. He has -been a member of the wider Python community since 1998 and has had -commit rights to the Python core since August 2001. He was release -manager for the 2.2.1 release and made many contributions of code over -the years. He is the chairman of the EuroPython Society and is a -member of the Python Software Foundation (PSF). - -AB Strakt -+++++++++ - -:: - - Role: Project Management & Technical Partner - Country: Sweden - Contact: Jacob Hall?n - -AB Strakt (http://www.strakt.com) is a software product developing -company located in G?teborg, Sweden. The main product of the company -is CAPS, a platform for constructing collaborative workflow -systems. On top of this platform the company has built a number of -applications; helpdesk, project management, customer relations -management and procurement. All products are built in Python. Strakt -is involved in the development of several OpenSource projects, which -in one way or another play a role in the company's software -development. The main development platform is Linux. The company has -13 full time employees, and 6 part time employees. The company was formed in -January 2001. - -Key Personnel -~~~~~~~~~~~~~ - -**Jacob Hall?n**, born 1958, comes to his position as co-founder and CTO -of AB Strakt from being a Technical Manager and international -standards expert at the LIBRIS Department of the Royal Library. He was -the LIBRIS representative in the EU funded ONE-2 project. Before this, -he was the CEO of NetGuide Scandinavia AB, one of the first internet -services companies in Sweden. Mr Hall?n has also been a Computer -Science and Programming teacher and an army officer. Throughout his -career he has managed many projects which varied from 1200 participant -conventions down to 3 person development tasks. He has also done -electronics development and microcontroller programming, winning two -innovation awards in the process. Mr Hall?n is also chairman of the Python -Business Forum. - -**Tim Peters**: Over 20 years top-tier industrial experience in -programming language implementation and high-performance -computing. 1979-1988, Cray Research: Compiler development, Group -leader--common back-end optimisation group. 1988- 1994, Kendall -Square Research (KSR), Compiler and Library development, Architecture -and FPU design. 1994-2000, Dragon Systems: Developed core speech -recognition system for portable devices; scalable, large-scale -telephone speech recognition; and award-winning PhoneQuery Toolkit -product. 2000 to present: Zope Corporation: Development--Core -technologies underlying Zope's leading content management framework; -Python core. Python: first port of Python to 64- bit platform (KSR-1); -POSIX pthreads support; algorithmic and optimisation expertise; -elected Director of Python Software Foundation (PSF) since its -inception. - -**Samuele Pedroni**: Born 1974 in Switzerland. Dipl. Math. ETH Zurich -(1999) His thesis was awarded by the ETH Polya Fond. Between 1999-2001 -he worked as teaching/published research assistant at the Institute of -Theor. CS of the ETHZ. He was designer on the state-of-the-art -genetic programming framework for Java JRGP, becoming involved in -Jython (the industry-strength Java re-implementation of Python). He is -now a main developer of Jython, working on internals, compilers and -Java integration, and was author of Jython Essentials (O'Reilly, -2002). He is also involved on the ongoing design of Python. For his -contributions to Python/Jython he was nominated and accepted as a member of the -Python Software Foundation. He brings to the project his know-how on languages, -re-implementation/design of Python, reflection, lookup and dispatch -optimisation. - -**Laura Creighton**: Co-founder and lead investor of AB Strakt, Treasurer -of the PBF. Studied Physics (csc minor) at the University of Toronto, -and later instructed there in Physics and Computer Science, while -simultaneously working for the Canadian Armed Forces, teaching -programming to non-programmers, and assisting with research in Human -Factors Engineering and Learning Techniques. Moving to the US, she -consulted for software companies and government institutions, taught -Unix, project management, and interpersonal relations, and wrote a -geophysical simulation system. She brings strong connections in -financial and government sectors, and was an Open Source advocate -before the term was coined. Her passions: programming, empowerment of -ordinary citizens, and the Open Society. - -Logilab -+++++++ - -:: - - Role: Technical Partner - Country: France - Contact: Nicolas Chauvat - -Logilab (http://www.logilab.fr/) specializes in the use of Python for advanced -computing, artificial intelligence and knowledge manipulation. Logilab works -for large public and private entities in France and Europe, including -Commissariat ? l'Energie Atomique, Electricit? De France, SNECMA, etc. -Logilab was involved in two IST projects before, ASWAD (free software -workflows for public administration) and KIDDANET (web filtering for kids -based on machine learning techniques). The company has currently seven -full-time employees and is expected to reach the size of ten by the end of -2003. - -For over three years, Logilab has been dedicating resources to high-profile -projects such as intelligent agents, natural language processing and -semantic web applications. Logilab has also been contributing libraries to -the Python languages, namely XML processing, logic and aspect-oriented -programming and static checking. Since Logilab has been committed -to free software from its creation in 2000, most of these projects are -available under a free software license from the Logilab.org website. - - -Key Personnel -~~~~~~~~~~~~~ - -**Nicolas Chauvat**: He completed his studies of engineering (spec. Robotics) -at Ecole Centrale Paris and computer science (Artificial Intelligence) at -Universit? Paris 6. Worked as a researcher in industrial and academic -laboratories in France and in the USA before founding Logilab in year 2000. -Research work concerned the modelisation of complex distributed electronic -systems as agent communities and human-agent interaction based on -context-awareness capabilities. President and CEO of Logilab. Python user -since 1997. Secretary of the Python Business Forum. Chairman of the -"EuroPython Science Track". - -Changemaker -+++++++++++ - -:: - - Role: Project Management - Country: Sweden - Contact: Beatrice D?ring - -Change Maker (http://www.changemaker.nu) is an education and -consultancy firm and we offer services in the areas of -project management, leadership, team building and change management. We -supply courses, workshops and seminars to corporations, schools and -other organisations. - -We offer support for applications and process management to small -companies in receiving financial support from the European Union -program V?xtkraft M?l 3. - -We also tailor educational concepts for the national Qualified -Education committee (KY), aiming at making the process of evaluating -the needs for recruiting personnel easier. Examples are companies -working with interactive media and games development. - -We deliver project management and quality evaluation for larger -educational projects. - -Some customers: - -Blekinge Tekniska H?gskola, Socialh?gskolan, Arvika -N?ringslivscentrum, Elmo Leather, Learning Tree International, FSO, -Semcon, Lundsbergs Internatskola,Galaxenis - - -Key Personnel -~~~~~~~~~~~~~ - -**Beatrice D?ring** studied teaching/pedagogy at the University of -Karlstad in Sweden. She was recruited into the IT-industry to work as -a project manager for large scale education projects for the company -NetGuide Scandinavia, Gothenburg. Since 1998 she has been working -with education and development project management and management of -education and consultant departments, implementing Open Source -strategies and Agile development methods. Beatrice also teaches -project management, leadership and communication courses for Learning -Tree International. - -Krekel -++++++ - -:: - - Role: Technical Partner - Country: Germany - Contact: Holger Krekel - -Key Personnel -~~~~~~~~~~~~~ - -**Holger Krekel**, born 1969 in Frankfurt a.M., began in 1985 to work as a -lead programmer producing games for Electronic Arts. He went to -university, gave courses in Prolog, C, Assembler, mathematics and -assisted in numerical computing. He got his degree "magna cum -laude". He consulted for Volkswagen, large German banks and the -chairman of the EU-founded CEN/ISSS workshop who contracted him to -prototype integration of OpenSource software. He implemented an -open-source transaction service on top of TAO/CORBA and published -several articles about Free projects. In 2001 he joined the Python -community, published an interactive tool, took part in Zope3 -development and some of the first coding Sprints in Europe and became -one of the initiators of the PyPy project. - -Martelli -++++++++ - -:: - - Role: Technical Partner - Country: Italy - Contact: Alessandro Martelli - -Key Personnel -~~~~~~~~~~~~~ - -**Alex Martelli**: Best-selling author of *Python in a -Nutshell*. Co-editor of *Python Cookbook*. ActiveState 2002 -*Activators' Choice* award winner. PSF member, Python language developer, PBF -board member. Consultant to AB Strakt, developing the CAPS -framework. Also consults for other firms on Python and O-O design, -teaching, coding, feasibility studies, interfacing. 1989-2002, Cad.Lab -(think3, Inc): innovative component architecture for web-enabling -existing GUI- oriented apps; Event Manager, interfacing, proprietary -protocols. Taught Computer Programming and Numerical Analysis, Ferrara -University. 1981-1989, IBM Research: 3 Outstanding Technical -Achievement awards, voice recognition, image processing. *Laurea* -1980, Electronic Engineering, Bologna University, 100/100 magna cum -laude. - -**Anna Ravenscroft**: Started programming with Python in 2002, presenting -papers on teaching Python, serving as track chair at EuroPython and -OSCON, writing and technical-editing books and articles. Before 2002, -Instruction Administrator for a public transport company, managing -projects, teaching, developing course material, creating -websites. Earlier, Office Manager for a small training company, -creating and editing training documents and administering the firm's -NT LAN. Up to 1994, Distribution Coordinator for a large Financial -Services company, providing field communications and training for a -sales force of 7500. In the 1980's, served as Psychological -Operations Specialist in the US Army, receiving an Honors Degree in -Russian. Education: Liberal Arts, Univ. of MN. - -Tismer -++++++ - -:: - - Role: Technical Partner - Country: Germany - Contact: Christian Tismer - -Key Personnel -~~~~~~~~~~~~~ - -**Christian Tismer**: Born 1956 in Jena, Germany, studied Math, Physics -and Informatics at the Free University of Berlin, diploma on Adaptive -Huffman Coding. He has been working for Pharmaceutic Research -companies for more than 10 years, doing statistical evaluations, EEG -and EMG recording, signal analysis, networking, report generation and -automation. He wrote his first multitasking system in 1985 for DOS, -continuous 32 channel EEG recording and visualisation on a 286 -machine. Later, he worked on Netscape plugins, document automation, -Web and database applications. Converted to Python in 1997, founded -Python Starship, became Python core developer. He translates Python -books into German, is the author of the Stackless Python extension to -be merged into PyPy, and is one of the founders of the PyPy project. - -Sub-Contracting ---------------- - -Some pure accounting and auditing tasks will be subcontracted. No core -technical functions or project management will be handed to non-partners. - -Quality of Partnership, Involvement of Users and SMEs ------------------------------------------------------ - -Roles -+++++ - -While all the partners except Changemaker have staff with Python -programming skills that will enable them to fulfill their responsibilities -in the various tasks of the project, each partner brings -unique skills or functions, without which the project is not complete. - -**DFKI** -has previous experience of being a project coordinator in EU projects, -ensuring smooth communication between the project and the FP6 project -officer. - -**University of Southampton** -is the employer of Armin Rigo, who is the lead architect of the whole -project as well as the author of Psyco, the blueprint for how to do -optimisation in PyPy. - -**Strakt** -brings management knowhow and entrepreneurial skills to the project as -well as showcasing how to apply the results of the project in a major -business application. - -Strakt will also bring Tim Peters and Samuele Pedroni to the project. -Tim Peters been a core developer of the Python language, what we call -CPython, from its inception. Apart from being an outstanding programmer, -Tim has intimate knowledge about all the details of the Python language -definition. As Director of the Python Software foundation, Tim Peters is -also responsible for the Intellectual Property of the existing Python -language. - -Samuele Pedroni is currently the main developer of Jython (the -industry-strength Java re-implementation of Python), working on -internals, compilers and Java integration. A member of the Python -Software Foundation, he brings to the project his know-how on -languages, re-implementation/design of Python, reflection, lookup and -dispatch optimisation. - -With 13 full time and 6 part time employees, Strakt is an SME -representative. Strakt is particularly interested in this project -because it is doubtful that its Framework system, CAPS, can scale from -several hundred thousand to several million concurrent users unless -one of two things happen. Either parts of CAPS are rewritten in C, -which is faster, or Python itself becomes faster. The second -alternative is much to be preferred. Participation will also enhance -Strakt's ability to attract the best Python programmers, and add to -it's reputation in the Open Source community. Strakt's financial -backer and board of Directors enthuthiastically endorse participation -in this project as a brilliant strategic move. - -**Changemaker** -adds rare project management skills by managing not only the project, but -the learning processes of the project participants as well as the group -dynamics between the different members. We intend to document and -disseminate the management of change throughout the project. Changemaker -is also the contact point for Axis Communications, who will receive a -specific report on how to integrate PyPy in an embedded device. - -**Logilab** -focuses on constraints and aspect oriented programming and will verify -that PyPy is both extensible with specialised language features and -embeddable in small-sized devices with dedicated hardware. - -With 7 full time employees, Logilab is an SME representative. - -**Holger Krekel** -will have a focus on development, packaging and -dissemination tools. He will also be a main contributor in matters of -systems architecture. - -**Christian Tismer** -is the developer of Stackless Python, which is the -blueprint for how we intend to implement persistent threads. - -**Alex Martelli** -is a prolific writer and popular speaker as well as a Python -programmer. Alex is uniquely suited for widely disseminating the progress -and the results of the project. - -Ability to Deliver -++++++++++++++++++ - -DFKI, Logilab, and University of Southampton have -already successfully participated in EU projects, so their ability to -deliver on another project should not be in doubt. - -Strakt, Tismer and Martelli have all recently produced substantial -products, which show their capability to handle large undertakings. - -Krekel has demonstrated his ability to deliver results during the -prototype phase that has preceded this application. - -Changemaker has a number of documented successful projects. Further -details can be found under B 5.1. - -A special circumstance is that several of the project participants -have already collaborated in developing a proof of concept for -PyPy. This means that the ability to collaborate and to deliver -results has already been tested under circumstances that are very -similar to what they will be during the project. - -Moreover, this project will be run in as transparent a fashion as -possible. Our code will be avaliable every night from our repository. -Our mailing list discussions will be available on a publically -readable archive, and any person is free to join our mailing lists. -Our Internet-Relay-Chat conversations, when important, will be -logged and archived. You can watch us create our documents, our -code, and our deliverables, day to day, as it happens. Meetings -in person will be summarised, and they will be posted. This is -*life in a fish bowl*, as transparent a process as you can see. - -This is important because the reason most projects fail to deliver -is because somebody was having a problem, and was too embarassed or -afraid to look bad in front of others to admit the problem until it -was too late to do anything about it. It is secrecy, and not lack of -competance that causes most of the problem. We will avoid this. -Our EU project leader will be able to monitor our progress on a daily -basis and will always be able to know what we are up to, and how -we think it is going. He or she will be free to participate in our -Sprints, and join our mailing lists, talk to us via IRC - whatever -level of involvement is desired. - -Resources to be Mobilised -------------------------- -In any project there are three crucial resources to be mobilised. - -The first is equipment. The PyPy project needs very little. We -would like to purchase a projector, for use in displaying code -at Sprints. We would also like to purchase a portable printable -whiteboard. We draw a lot at Sprints, and would like to be able to -give every attendee a copy of the diagrams we made at the touch -of a button for use at home in between Sprints. Each of these -will cost somewhere between 1 and 2 thousand euros. - -The second is Finance. We don't need to mobilise outside financial -contributions, though we have some excellent connections. AB Strakt, -Krekel, Martelli and Tismer have already arranged for bank -guarantees, should they be required by the Commission. AB -Strakt uses KPMG as its standard auditor, and a KPMG recommended -bookkeeper who is familiar with EU project funding for its daily -business practices. Everybody else has already been involved in -successful EU projects, and will simply continue their usual -behaviour. - -And the third, and most important resource to be mobilised, -is people. This is where this -Consortium really shines. Not only have we already attracted some of -the top people in the Python community in this project, we also have a -plan to continue to attract the interest, support, and constructive -criticism of the very best. The Open Source movement is **all about -community**. This fact is often overlooked by people who are -discovering Open Source for the first time, who mistakenly believe that it -is **all about licensing**. Successful Open Source projects are based on -sharing and trust, process rather than product, and key people. The -same is true of Agile development methods, as defined by the Agile -Alliance. - -We are pioneers of a software development method, Sprint Driven -Development, which promises to mobilise people in a unique and -special way. We outline *what* we do in Section 5 -- Project -Management. Here we would only like to speak briefly of *one -reason why we do this*. - -One of the classics of software management is Fred Brooks -*The Mythical Man Month*. - -In it he asserts the then-controversial, and now well-established -claim: **Adding people to a late software project makes it later**. -This is because the communications cost of *bringing a new person up -to speed* outweighs the benefits you can get by putting them on the -project. And some projects are just too large -- the burden of simply -letting the left hand know what the right hand is doing is crippling. - -Sprint Driven Development is an attempt to make a development -model which refutes this claim. What would you get if you didn't -have to *bring people up to speed* because *they were already -aware of the project*? If you published everything you were doing -and made constant efforts to communicate where you were, and why -you were doing things to the base of programmers you might -*someday* like to have on your project, then when time came to -add people to the late project (or just because the project -reached a point where there *was* comparatively more work that -could be shared among programmers) they would already be mostly -ready to go. - -You could not do that in a proprietary environment. You **can** do this -in the Open Source Software community. A for-profit company cannot -afford to have very many people just sitting around, preparing, -absorbing knowledge, in case they might be needed somewhere. -Commercial software companies pay their people to write code. But -outside the company is the competition. Sharing is thus frowned upon. - -But there are three groups who function this way, all the time. They -are always sitting around learning things. The first group are -students, and teachers. The second are those people in industries -which have an off-season -- tax preparers and fishermen both fit this -pattern. And the third are software consultants, both small and those -in large IT consulting firms. Learning things is called *keeping -current* and is essential to maintaining competitiveness as a software -consultant. I will call these people **seasonal workers** though the -term is not quite accurate. The important thing is that you can -mobilise them for short projects. And the Open Source community *has* -mobilised them quite effectively. - -Sprinting is more than just an effort to maximise creativity by putting all -your creative people in a room and letting them bounce ideas off each other -and write code to test theories. (Though it is that, too, and that is very -important.) Sprinting is also an way to constantly involve the community -and disseminate knowledge, especially the more difficult **know-how**, as -opposed to **know-that** which one can read in books, papers, mailing lists -and websites. It keeps people *in the loop* -- ready to contribute should -it be necessary -- especially when combined with the sort of supplementary -materials we intend to produce. (**Know-that** is obviously good as well, -but, -it is **know-how** that is must be developed when bringing a new person up to speed in a -project.) - -As part of this project, we intend to document our creative process in -the hope that it will be picked up throughout the Open Source community -as an effective way to work, and one that is compatible with the EU's -Funding Programmes. Right now there is considerable desire on the part -of Open Source developers to become involved with EU projects, but too -little experience. The process seems cumbersome, and overweildy for -those people who are used to more Agile methods. There is great interest -in finding an acceptable way to respond to calls and provide enough -accountability to suit the EC, while enough flexibility to suit the -Agile developers. We believe we have found such a way, and are very -anxious to prove it so, and then spread the message so that other -Agile developers can benefit from our experience. - -STREP Project Effort Form -------------------------- - -Full duration of project: 24 months - -+---------------------+--------------+--------------+--------------+--------------+--------------+--------------+ -| |DFKI |USH |Strakt |Logilab |CM |Total | -+---------------------+--------------+--------------+--------------+--------------+--------------+--------------+ -|Research and | | | | | | | -|Innovation | | | | | | | -+---------------------+--------------+--------------+--------------+--------------+--------------+--------------+ -|WP2: Infrastructure | 8| | | | | 8| -|and Tools | | | | | | | -+---------------------+--------------+--------------+--------------+--------------+--------------+--------------+ -|WP3: Synchronisation | 6| 3| | | | 9| -|with Standard Python | | | | | | | -+---------------------+--------------+--------------+--------------+--------------+--------------+--------------+ -|WP4: PyPy Core | 12| | 6| 5| | 23| -+---------------------+--------------+--------------+--------------+--------------+--------------+--------------+ -|WP5: PyPy Translation| 6| 8| 15| | | 29| -+---------------------+--------------+--------------+--------------+--------------+--------------+--------------+ -|WP6: Core | 1| 12| | | | 13| -|Optimisations | | | | | | | -+---------------------+--------------+--------------+--------------+--------------+--------------+--------------+ -|WP7: Translator | 15| 3| | | | 18| -|Optimisations | | | | | | | -+---------------------+--------------+--------------+--------------+--------------+--------------+--------------+ -|WP8: Dynamic | 2| 6| 17| | | 25| -|Optimisations | | | | | | | -+---------------------+--------------+--------------+--------------+--------------+--------------+--------------+ -|WP9: Search and Logic| 10| | | 9| | 19| -+---------------------+--------------+--------------+--------------+--------------+--------------+--------------+ -|WP10: Aspects and | 3| | | 9| | 12| -|Contracts | | | | | | | -+---------------------+--------------+--------------+--------------+--------------+--------------+--------------+ -|WP11: Specialised | | | | 5| 1| 6| -|Hardware | | | | | | | -+---------------------+--------------+--------------+--------------+--------------+--------------+--------------+ -|WP12: Security, | | 3| 10| | | 13| -|Distribution and | | | | | | | -|Persistence | | | | | | | -+---------------------+--------------+--------------+--------------+--------------+--------------+--------------+ -|WP13: Integration and| 8| | | 4| | 12| -|Configuration | | | | | | | -+---------------------+--------------+--------------+--------------+--------------+--------------+--------------+ -|WP14: Documentaion | 12| | | | 11| 23| -|and Dissemination | | | | | | | -+---------------------+--------------+--------------+--------------+--------------+--------------+--------------+ -| | | | | | | | -+---------------------+--------------+--------------+--------------+--------------+--------------+--------------+ -|Total Research and | 83| 35| 48| 32| 12| 210| -|Innovation | | | | | | | -+---------------------+--------------+--------------+--------------+--------------+--------------+--------------+ -|Management | | | | | | | -+---------------------+--------------+--------------+--------------+--------------+--------------+--------------+ -|WP1: Coordination and| 4| | 4| | 4| 12| -|Management | | | | | | | -+---------------------+--------------+--------------+--------------+--------------+--------------+--------------+ -| | | | | | | | -+---------------------+--------------+--------------+--------------+--------------+--------------+--------------+ -|Total | 87| 35| 52| 32| 16| 222| -+---------------------+--------------+--------------+--------------+--------------+--------------+--------------+ - Deleted: /pypy/funding/B5.0_manage_bea.txt ============================================================================== --- /pypy/funding/B5.0_manage_bea.txt Thu Mar 17 10:56:00 2005 +++ (empty file) @@ -1,578 +0,0 @@ -Project Management -================== - -PyPy as a project will be implementing an agile development -lifecycle.This choice of development method will have effects on the -way the project will be structured and managed. - -The project will have a structured project plan as is showed in this -proposal (workpackages, Gantt-chart, deliverables, quality control -etc). It also means that the project process, once the project get -started, will work from a evaluate-feedback-change perspective, or so -called "learning loops" in which project management will continuously -follow up on the initial project plan but also evaluate process, -team effectiveness, communication climate. From these learning loops -change, when necessary, will be applied throughout the process. - -To illustrate the focus on development process as well as project focus: - - -.. image:: sprintprocess.gif - - -Both the project and the development process are based around critical -workshops, so called "sprints" that will take place on a six week cycle -throughout the project (24 months). Around these sprints input and output to -stakeholders will be structured. The arrows above symbolize the evaluation- -feedback-change system that will be implemented. - -This method will affect the role of the project management, management -structure, role of coordinator, project meetings, quality control and -communication in the project in what we have experienced to be a very -constructive way. - -Our reasons for choosing this development and project method are several: - -- This project has a history of 6 months in which the team successfully - implemented sprints and agile development methods - -- In this project, team members from at least 5 different countries - will work continuously in separate places. Sprints will be the main - forum in which the team members meet up and work together in real - life - -- The sprints will be open for non team members to participate in the - development process, thus allowing for an open and feedback driven - process - -- The sprints will be the forum in which knowledge will be shared and - the transparency within the project organisation will be measured - -We will during the project focus on evaluating and documenting our -project method and share knowledge and experience in that area as -well. It is our goal that the overall deliverables from this project -will be a functioning PyPy as well as an effective project method for -agile development/Open Source projects. Our goal is also to disseminate -this knowledge to the developer communities inside and outside the Open -Source movement as well as to commercial and academic organisations. - -On the following pages we will describe in more detail how this choice -of method will influence the way this project will be managed. - -Coordination and Management Team --------------------------------- - -The PyPy project will have a management and coordination structure that is -based upon three resources, Jacob Hall?n as project manager, Beatrice -D?ring as assisting project manager, and Alastair Burt as coordinator. - -The role of the project manager is to: - -- manage the project and its scope of time, budget and deliverables -- lead the work of the management board and report to the management board -- execute decisions made in the management board -- report to the project coordinator -- support the project coordinator concerning the relations to the EU -- manage the sprints -- manage tracking of quality assurance of the technical development - -The role of the assistant project manager is to: - -- report to the project manager -- participate in reports to management board and project coordinator -- manage project administration (reports, documentation,etc) -- manage routines and tracking of sprints, quality assurance of project -- process, resource allocation -- manage contact with external partners -- manage the day-to-day operations of the project (ex. executing -- decisions made by management board) -- manage the knowledge process and actively spread information to the -- stakeholders regarding methods used and knowledge acquired - -The reasons for having a structure based on a project manager and -assisting project manager are: - - both the development and the project process will receive due attention - in that the persons chosen have expert skills in these different areas - - the project will not be exposed to the risk that a single project - manager would mean - - a project of this size with team and stakeholders distributed in several - countries needs more project management resources - -The responsibilities of the project coordinator will include: - -- to manage negotiations regarding proposal -- to manage ongoing dialogue with the EU project office during the project -- to appoint a project manager -- to be a representative on the management board -- to participate in the project review workshops -- to submit reports regarding project review workshops -- to participate in project evaluation and submit report of this to the EU - project office -- handle financial tasks and payments between the project and the EU - project office - -The project coordinator will be able to use the project management team -for support in the tasks mentioned above. - -The skills and experience of the combined management and coordination team are -as follows: - -Large Scale Projects -+++++++++++++++++++++ - -**Jacob Hall?n** has been working since 1994 with large scale development -projects. He was a consultant for, and later employee of, the LIBRIS -Department of the Royal Library of Sweden (http://www.libris.kb.se) in -the role of Technical Project Manager, with main focus on being -systems architect for the national bibliography system and -interlibrary loan system. Participated in international -standardisation groups for search systems (Z39.50) and interlibrary -loans. - -He was also the initiator of the international standardisation effort -for library services information. Participated as the Royal Library -representative in ONE-2, an EU funded project under the Telematics for -Libraries project (http://www.one-2.org) - -Since 2001, Jacob has been involved in founding AB Strakt -(http://www.strakt.com), a company developing workflow and document -handling systems. There he has worked in roles as developer, project -manager, CTO and CEO. The company has grown from 3 employees to having -13 full time employees and 6 part time employees so far. - -Connected to his work at AB Strakt, Jacob has also been active as -co-founder and chairman of the Python Business Forum, an international -trade organisation for companies that use Python as their main tool of -business. The PBF has approximately 50 member organisations. He is -also the project leader for the EuroPython 2004 conference, to be held -in G?teborg, Sweden 9-11 June 2004. - -**Beatrice D?ring** has experience in large scale education projects -involving working with consortia of three companies servicing a -stakeholder group of about 30 recruiting companies. These large -education projects was part of a national program to solve shortages -of skilled IT-personnel during the years 1998- 2000. 200 students -participated in the projects and the projects met their deliverables -in that over 80% of the student were employed after the education. The -project team consisted of 7 persons working full time. As a project -manager, Beatrice was responsible for meeting project goals, meeting -profit margins, leading the team and creating strategies for -stakeholder participation in the projects. She was also responsible -for reporting and documenting the project to the client. - -Since 2000 she has been involved in similar assignments, one recently -finished for University of Blekinge in which the education was -directed towards recruiting companies in the game development -industry. She has also worked as project manager for several -development projects during the time 1998-2002. - -She has also developed project methods for the companies and teams -shes been working with and have also been working with quality -assurance of development projects. Her current company, Change Maker -is also working with supporting smaller companies in the application -process for the EU Framework 3 (V?xtkraft M?l 3) and has a experience -of working with similar EU-funded projects since 1997. - -Financial Tracking in Projects -+++++++++++++++++++++++++++++++ - -**Jacob Hall?n** has a widespread experience of founding and managing -companies as well as being project manager for large scale -projects. He has also developed several accounting programs. When -being the CEO of NetGuide Scandinavia AB, the company was under -budgetary squeeze in its early days, generating a lot of experience in -tight cost control and progress tracking. The management was -successful and the company grew to 35 employees under his leadership. - -The large scale education projects that **Beatrice** managed had a -profit margin of 20% which was met. The total budget for these projects -was SEK 20 million. She has also recently been involved in the -prestudy, budgeting and start of a 6 year long education project in -Arvika, Sweden with a total budget of 18 million SEK. - -During her time as a manager for the education and consultant -department in NetGuide Scandinavia (1999-2002) she had budget and -result responsibility. - -Leadership Skills -++++++++++++++++++ - -**Jacob Hall?n** has experienced leadership challenges in different -situations. In his role as an officer in the reserve of the Swedish -army he has been deputy rifle platoon leader in the Swedish UN forces -in Cyprus, duty officer with responsibility for the battalion safety -and security in Lebanon and instructor/platoon leader for training raw -recruits. He has been a teacher at the Chalmers University of -Technology, for Informator and for LearningTree International, all of -which include being a leader for your students. At NetGuide -Scandinavia his leadership was mostly focused on leading the company, -initially with 4 people. A number that grew to 35 in the subsequent 3 -years. - -At LIBRIS he assisted the project leader for the SEK 20 million -modernisation project in getting consensus among the approximately 30 -members of the consortium on what sort of changes should be required, -wanted or tolerated in the new system. - -At AB Strakt, Jacob Hall?n started out managing the company but -changed his role to Chief Technical Officer, after successfully -recruiting a suitable CEO as replacement. Jacob enjoys managing -technical processes more than general corporate management. - -**Beatrice D?ring** has experience from leadership situations in projects -as well as in line organisations since 1998. During four years she was -a part of a management team of five people, leading teams of 5 to 14 -people. As a leader, Beatrice was responsible for coaching, motivating -and developing her personnel. - -Beatrice employs strategies of empowerment, active listening combined -with creating and maintaining an open communication climate based on -honesty and trust the achieve goals together with her team. Beatrice -have been teaching management oriented courses (leadership, project -management, communication, conflict resolving) for Learning Tree -International since 2000 in both Sweden and USA. - -Coordination in EU Projects -+++++++++++++++++++++++++++ - -**Alastair Burt**, DFKI, has participated in several European projects, was -the coordinator of the EU-funded ASWAD free software project, and is in the -coordinating team of the EUTIST-AMI cluster. The DFKI itself has over a -decade of experience of working with the EU's financial and reporting -procedures. - -Management Structure --------------------- - -The management structure will be as follows: - -.. image:: projectstructure_pypy.gif - - -Representatives in the management board: - -- Alastair Burt, DFKI -- Holger Krekel -- Jacob Hall?n, AB Strakt -- Nicolas Chauvat, Logilab - -Responsibilities of the management board includes: - -- manage resources -- manage quality assurance for the project and the technical process -- track cost, timeline, tasks, budget -- manage technical implementation plan and progress -- manage compliance with legal and ethical obligations - -The operative management of these responsibilities will be delegated to -the project management team and the technical board. In the management -board, decisions that cannot be made by consensus and open discussions -will be solved by voting (each partner have a vote, in case of tie - the -project manager will have a casting vote) - -Representatives in the technical board: - -- Armin Rigo, University of Southampton -- Samuele Pedroni, AB Strakt -- Holger Krekel -- Christian Tismer - -Further representatives on the Technical Board will be selected at the -outset of the project. They will be appointed by a vote of everyone who has -commit rights to the source repository and used them to contribute source code. -Guido van Rossum, the author of Python will act as an advisor to the -Technical Board. - -The responsibilities of the technical board are: - -- make recommendations on technical strategic issues to be decided in the - management board -- manage the quality assurance of the technical development process - - this task is delegated to the technical board from the management board -- manage technical implementation plan and progress - this task - is delegated to the technical board from the management board - -These responsibilities are reported to the management board through the -technical director who is a representative on the management board. -In the technical board, decisions that cannot be made by consensus and -open discussions will be solved by voting (each representative have a -vote, in case of tie - the technical director will have a casting vote) - - -Since the PyPy project is implementing agile/Open Source methods -("Sprints") the goal is to have a proactive team of developers and project -managers. -This means that the project will be ruled by one primary management -strategy - to delegate as much responsibility to the developer team and -the persons responsible for each individual workpackage. This rule _will_ -guide all planning and decision-making in the two boards. - - -Project Meetings ----------------- - -Management Board will meet at the start of the project and two times -per year or on an ad hoc basis as requested. The meetings will -normally be scheduled to rotate between countries of the EU and mainly -the principal contractors home base. The project manager is -responsible for the invite and agenda as well as managing the -meetings. Objectives on these meeting are tracking progress regarding -workpackages, budget, timescale and strategies for involving -stakeholders as in partners or new partners. Agenda and -discussions/decisions on these meeting will be documented and put up -in the internal project web. - -Team Meetings -+++++++++++++ - -The project team will meet at the "sprints" which take place on a six -week cycle ( see below). During the sprints, there will be time -allotted to discuss and evaluate the project process, track progress, -discuss resource allocation, new team members. The project manager is -responsible for the invite and agenda as well as managing the -meetings.Agenda and discussions/decisions on these meeting will be -documented and put up in the internal project web. - -Project Review Workshops ("learning loops") -+++++++++++++++++++++++++++++++++++++++++++ - -Every six months, as preparation for the Management Board meetings and -project reviews from the EU project office, the project management -team invites the team to an evaluation workshop, lasting for a day, in -which product as well as process is being reviewed. Risk assessment is -also an important part of this workshop. This meeting could result in -proposed changes that will then be reported to the Management Board -for decision. The project manager is responsible for the invite and -agenda as well as managing the meetings.Agenda and -discussions/decisions on these meeting will be documented and put up -in the internal project web. - - -"Sprint" Meetings are the Key to PyPy's Technical Development -+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - -Key to PyPy's technical development and research are so called -"Sprints". These publically announced one-week meetings serve as an -intense working forum to rapidly discuss and implement key PyPy ideas -with agile methodologies and take place on a six week cycle. -The goals for each "Sprint" will be decided by the development team -in cooperation with the project management team. The project manager -is responsible for the handling of logistics before, during and after -the sprints (invite, location, preparation etc). Agenda and -discussions/decisions on these sprints will be documented and put up -in the internal project web. - -During the "Sprints", developers usually pair up and write -unit-tests to test the to-be-implemented features before actually -adding them. The unit-test-first approach helps to understand the -planned feature. Additionally, the discussion in a pair makes sure -that obviously wrong paths of development are avoided. If something -seems too hard to test or to pin down explicitly this is taken as an -indication of an underlying design problem. - -Note that more traditional approaches usually follow a model where -developers work alone and only meet to talk. Instead with -sprint-driven development talking and actually implementing resulting -ideas ensures a more focused approach with fast feedback cycles. -While the free software community is successful especially because of -it's open communication model sprints are an accelerator to this -process. While coding in pairs developers educate each other which -leads to a broader common understanding of the project. During a -sprint multiple pairs want to work in parallel which adds pressure on -design decisions so that independent development of components of the -system is possible. Thus sprints not only deepen the communication and -understanding among researchers and developers but they imply a -working process which enhances the software design in multiple -ways. - -The sprints are also the forum in which interested developers can -participate in the development process. This is a fast and effective way -of introducing new project members into the team, its methodologies, -climate and tasks. - -With a very-high-level-language like Python rapid development in -coding-sprints becomes especially effective. A VHLL-language generally -allows to focus on ideas rather than on low- level language -details. In combination with pervasive test-driven development this -eases high-quality rapid evolution towards the intended -goals. Obviously, the PyPy developers are very experienced with Python -and bigger applications in general. Thus the full potential of agile -methodologies is unveiled during PyPy sprints. In less than five weeks -worth of development (during four sprints) the group produced a -working prototype which is a big success not only in the eyes of its -developers. - -Technical Decisions -+++++++++++++++++++ - -Major design or technical decisions are usually reached through -consensus during the sprints. If a conflict cannot be resolved there -then the technical board gets the final say. -However, it is expected that design -and implementation choices will usually be determined by consensual -agreement or by informal votes on the development mailing list. This -is common practice within the Python and many others free software -communities. Also, the PyPy developers and researchers will construct -few if any formal hierarchies between them. Constantly working -together with agile methodologies and the visibility of each -individual contribution help enforce high-quality program code and -good design decisions. - -Quality Control of Technical Development ----------------------------------------- - -The PyPy project will ensure quality by a variety of means. On the -grand scale, the involvement of excellent researchers ensures that the -general direction takes care of latest insights in language -research. Moreover, we will publish our research results on -conferences and to scientific and free software communities. This -forms the basis to maintain a high- quality general technical -direction. - -The developers deploy agile methodologies like unit-test-driven -development and pair-programming. By the end of the project we expect -to have produced more than 3000 unit-tests testing every aspect of the -runtime system. The presence of such tests also allows to rapidly -change parts of the implementation without fear of breaking -functionality elsewhere. We also plan to release our runtime system -often and thus gather additional feedback from early adopters, -developers and researchers. - -To support the open development we base all of our documents, source -code and website information on a version control system. In -combination with a notification on all changes this ensures that all -interested parties can review and react to developments. - -The PyPy developers have produced a working prototype within four -one-week sprints and a little development in between. The code and -design quality of the project is already widely accepted. There are -now 400 unit-tests. As a consequence, Guido van Rossum, the inventor -and maintainer of today's Python, listed is as the number one project -he would like to succeed. He previously attended one of our sprints -and got deeply involved with our architecture and source code which he -immediately found intuitive to work with. Thus we believe that our -choices for technical quality management are fit to meet highest -standards. - -Additional Quality Procedures -+++++++++++++++++++++++++++++ - -The project manager will circulate a draft Quality Management plan for -the project prior to first Project Meeting and and then present it for -approval at the first Meeting. It should complement the prescribed -quality approach with respect to the following aspects: - -- Document procedures, standards and control -- Issue control for documents -- Reporting procedures, frequency and format -- Communication procedures -- Corrective actions -- Exception control -- Conflict resolution -- Meeting draft agenda -- Format of meeting minutes -- Tracking system for actions -- Risk assessment -- Evaluation routines -- Specific responsibilities within the project - -Communication and Reporting ---------------------------- - -The project process will be reported as follows: - -- Monthly written status reports to the Management Board/Technical - Board by the project management team. These reports will be - posted on the internal project web for the entire team to access. - -- Project review report to the EU project office. These reports are - the result of the project review workshops (every 6th month) and - are produced by the project management team. These reports will - be posted on the internal project web for the entire team to - access. - -- Project evaluation report. At the end of the project, an - evaluation report will be produced in which both product, process - and deliverables will be evaluated. This report will be presented - to stakeholders (consortium companies and partners) and the EU - project office. - -Transparency concerning information and decision-making is vital for the -PyPy project: - -- all discussions, protocols, reports, reviews and product/project - information will be accessible to all people participating in the - project -- information of the kind mentioned above will not be altered to suit - different target groups in the project - this minimizes the risk for - information to be filtered - -The technical development of PyPy is driven by open continuous -discussion. Many of the involved decisions are made and verified -during one-week working meetings, so called "sprints". Members from -the larger Python software community are publicly invited and have the -chance to interact and work with the PyPy developers or become one -themselves. Mailing lists, chat-sessions, Wikis and notification of -program changes provide a constant flow of information between PyPy -project members and the wider community. Additionally, groups of -developers can start interactive "screen" sessions which allows -sharing their workspace and implement and communicate -efficiently. Therefore conflicts out of missing or conflicting -information or due to misunderstandings will be minimized. - -Each sprint meeting is planned for by all developers. The sprint goals -are usually agreed upon before the meeting starts. This is also -important to allow new developers or contributors to join specific -efforts. Sprint results are subsequently published to email and -web-channels to gather feedback and educate others about changes. - -We will present multiple reports and scientific papers on major -conferences such as EuroPython (Python's European community -conference), FOSDEM (Free and Open Source Developer European Meeting), -OSCON (Open Source Convention), PyCon (Python developer -conference) and to domain specific audiences such as embedded device -developers.In a later phase of the project the PEP (Python Enhancement -Proposals) procedures may be implemented. This is the standard -procedure for applying changes to the C-implementation of Python as of -today. It forces an author to clearly state the benefits of the -proposed Enhancement and provides an rationale. However, such a formal -method will only by required when the project reaches the point where -users begin to rely on aspects of our implementation. - -Management of Knowledge and Intellectual Property --------------------------------------------------- - -Every contributor is fully responsible for not introducing program code -which might infringe third party copyright or patents for that matter. -Every contributor agrees to license his contributions under a MIT-style -license approved by the Open Source Initiative and the Free Software -Foundation. See section 3. - -The public availability of PyPy's source code at all times on the basis -on such an open and commercially exploitable license stipulates exchange -of ideas, contribution to the project and reusability all parts of PyPy from -the start. - -In return, this provides the developers with fast feedback and -improvements with respect to their current developments. At the heart of -a free software community lies open communication, the free flow of -information and organizing shared interests. The PyPy project is already -fully involved and based on these principles. We also believe that for -a language runtime system like PyPy a free license is of vital -importance to reach wide deployment and recognition. Such a license is -also a necessity to allow PyPy to become a reference implementation of -the Python language specification. - -Consortium Agreement --------------------- - -In the case that the proposal is accepted by the EU, the coordinator and -the project management team will draw up a consortium agreement that -formalises the license policy outlined above. As all technical deliverables -will be fully public, for general modification and reuse, all partners, and -indeed the rest of the world, are free to exploit the results as they -choose. - Deleted: /pypy/funding/B6.0_detailed_implementation.txt ============================================================================== --- /pypy/funding/B6.0_detailed_implementation.txt Thu Mar 17 10:56:00 2005 +++ (empty file) @@ -1,638 +0,0 @@ -.. include:: crossreferences.asc - -Detailed Implementation Plan -============================= - - -:DELETE:BEGIN - -B6.1 - -:DELETE:END - -Workplan Introduction -~~~~~~~~~~~~~~~~~~~~~ - - -The PyPy project can be divided into three phases: - -- Phase 1: Building a Novel Language Research Tool. The core - functionality of PyPy itself must first be developed, using our novel - and flexible approach of Object Spaces. - -- Phase 2: High Performance. This code base can be used as an - research/integration platform of choice, targeting especially performance. - -- Phase 3: Validation & Flexibility. Specific applications can be - implemented and disseminated. - -Phase 1 is a prerequisite for Phases 2 and 3; Phases 2 and 3 are reasonably -independent from each other. - -Beyond phase-specific tasks, several project-long infrastructure tasks are of -paramount importance. In particular, coordination is assured by the project -coordinator in workpackage WP01_, with the help of the management and -technical boards, as described in section B5. This workpackage involves -collecting and monitoring monthly status reports, reporting to the EU, -organising sprints, and maintaining an internal web site in collaboration with -the maintenance workpackage. - - - -:DELETE:BEGIN - -B6.2 - -:DELETE:END - -Research and Technological Aspects and Options -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - -Phase 1 -------- - -The first phase will provide a novel architecture for research of a VHLL language. -It is to be compatible with the language specification of Python and -consists of the following major parts: - -- A *bytecode compiler,* which inputs Python source code and outputs an internal - intermediate representation, the *bytecode*. - -- A *bytecode interpreter,* which interprets bytecodes and manages the - supporting internal structures (frames, exception tracebacks...). It - considers objects as black boxes and delegates all individual operations on - them to a library of built-in types, the *Object Space.* - -- An *Object Space,* which captures the semantics of the various types - and objects of the language. - -This subdivision is common among interpreter implementations, although we -place special emphasis on the library of built-in types and its separation -from the bytecode interpreter. The implementation will closely follow the -current reference C implementation (CPython). It is thus expected to be -relatively straightforward, varying from CPython only in a few design -decisions (mainly with respect to the Object Space separation of concerns), -and changing strictly nothing in the Python language itself. - -This task is done in workpackage WP04_. After the initial development, WP04_ -will switch its focus to reimplementing the many extension modules written in -C that are either standard or widely-used in CPython. (The Python Standard -Library is already mostly written in Python, so that the problem only concerns -C-coded extension modules.) For each extension module, two strategies can be -followed: either the module is rewritten as a (regular) Python module, or -it is written as an extension module of the PyPy interpreter (i.e. in Python -too, but at the level of the interpreter.) - -The result of WP04_ up to this point will still only be able to run on top of -another Python implementation, such as CPython. Despite this limitation, it -will still present some advantages over the existing CPython implementation, -in terms of education (being a much more compact, modular and readable piece -of code than CPython) and in terms of flexibility (as a basis into which -experimenters can plug in alternate Object Spaces, alternate interpreters, or -alternate compilers) -- more about this below. - -At this point, to make PyPy stand-alone (and running at a reasonable speed), -we must ensure that key areas of the source have been restricted to be written -in a subset of the Python language, a sublanguage (RPython) in which -staticness restrictions are enforced. This sublanguage is suitable for -analysis and translation into a lower-level language. The sublanguage's -precise definition is a trade-off between the amount of dynamic power desired -to write PyPy and the amount of effort we put in the translation tools. - -Note that translation is not a one-shot process; the only source code for PyPy -will be in Python or RPython, and translation can be repeated freely as part -of a compilation process. - -We are giving translation an innovative emphasis (and thus a whole -workpackage, WP05_) in the project. It is not only an RPython-to-C -translator; it is a source-to-source transformer, and as such an -essential part of our flexibility goals. Numerous aspects that used to -be design decisions influencing the whole source code of the current -CPython have by now become merely customizable behaviour of the -translator. Indeed, instead of hard-coding such design decisions, we -will keep the PyPy source as simple as possible, and "plug-in" the -required knowledge into the translator. For example, the high-level -source need not be concerned about memory management issues (garbage -collection, reference counting...); this aspect can be "weaved" into -the low-level code by the translator. This point is essential for the -separation of concerns. Weaving aspects will be done mainly as -intermediate stages, for example as transformations on the -intermediate representation used by the translator, allowing control -over orthogonality issues between aspects. This whole approach has -deep advantages over the classic monolithic one, ranging from -education (the main source base is not encumbered by details) to raw -performance (choice of appropriate low-level models based on -real-world context-dependent measures and comparisons). Also note this -architecture's extreme adaptability: instead of generating C code, it -is straightforward to target other runtime environments like Java or -.NET. By contrast, today's costs of maintaining several evolving -implementations (CPython, Jython for Java...) are very high. - -The translation process itself requires some kind of analysis of the RPython -code. Among the various ways to perform this analysis we will most probably -choose the one based on *abstract interpretation,* as opposed to source-level -or bytecode-level analysis: - -.. image:: translation.png - -The basic idea is to write an alternative "abstract" Object Space which, -instead of actually performing any operation between objects, records these -operations and traces the control flow. The "abstract" Object Space will be -plugged into the existing bytecode interpreter; these two components, -together, will then function as an abstract (or symbolic) interpreter in the -usual sense of the word. The net result is that we can actually analyse -RPython source code without writing any code specific to the language, -given that we already have a bytecode interpreter which is flexible enough to -accommodate a non-standard Object Space. In other words, the combination of -PyPy and an "abstract" Object Space performs as the front-end of the -translator, and can be used to translate (for example) the regular PyPy -interpreter and its standard Object Space. Note the two different roles played -by the bytecode interpreter in the diagram above. - -Another important advantage of this approach is that, instead of operating on -static source code, it works on the result of loading and initializing the -code into the existing CPython interpreter. (Python, unlike more static -languages, allows arbitrary computations to be performed while loading -modules, e.g. initializing caches or selecting components according to -external parameters.) We are thus not restricted to RPython at initialization -time, which is important in order to achieve the configurability goals. - - -Phase 2 -------- - -The completion of the first translated stand-alone PyPy interpreter is where -the project could potentially branch into a large number of directions. -Numerous exciting applications can be foreseen; we will examine some of them -in more details in Phase 3. - -Phase 2 is concerned about research, and integration of research, based on the -extreme flexibility afforded by the PyPy platform. - - -Performance -+++++++++++ - -Part of Phase 2 focuses essentially on performance issues, which are important -in helping to establish the real-world success of a language implementation, -and may open the language to a wide range of applications for which it was -previously thought to be unsuitable. - -The flexibility in PyPy allows a number of design decisions to be easily -reconsidered; better yet, it allows different design decisions to coexist. -Indeed, most "hard" issues in interpreters have no obvious best solution; they -are all depend in complicated ways on the specific details of the runtime -environment and on the particular application considered and its possibly -evolving context. PyPy will provide a good platform to experiment with, and -compare empirically, several different possible approaches for many of these -issues. For example: - -- The language's core object types can have several implementations with - different trade-offs. To experiment with this, we will write a collection - of alternatives in the "standard" Object Space implementation and heuristics - to select between them. This kind of research effort is common, but PyPy can - provide a good platform for real-world comparisons, and to help isolate - which particular choices have which effects in an otherwise unchanged - environment. Such data is notoriously hard to obtain in monolithic - interpreters. This is the focus of WP06_. - -- Similarly, as described above, pervasive design decisions can be - experimented with by tailoring the translator. This is the focus of WP07_. - -We will in particular investigate in detail two specific ways to customize the -translator: - -- Generating Continuation Passing Style (CPS) low-level code. This makes the - advanced notion of continuation available for the programmer; but -- most - importantly in our case -- it allows the development, with the help of an - appropriate runtime system, to support massive parallelism. Indeed, in - almost any OS, native threads are not appropriate for massive usage. - Applications (e.g. web servers handling thousands of connections) have to - somehow emulate parallelism explicitly. Soft-threads are an ideal target for - language integration. This work (also part of WP07_) consists of exploiting - this idea, which has been first tried for Python in the Stackless project. - -- Generating a JIT compiler. Existing work in the Psyco project has shown that - it would actually be possible to generate the most part of a JIT compiler instead of - having to write it from scratch. The basic idea is again abstract - interpretation: instead of actually performing any operation between two - objects, we *generate* machine code that can perform the required operation. - Again, no change to the bytecode interpreter is needed; all we need is to - turn individual operation orders into processor instructions, together with a - supporting runtime systems. This is defined by WP08_. - -In dynamic languages, the truth behind JIT compiling is a bit more involved -than the above paragraph suggests. All the "standard" operations in Python, -including intuitively simple ones, are in fact relatively complex because -they depend heavily on the runtime type of the objects involved. This complex -code is already written in detail in the "standard" Object Space. Thus the JIT -compiler will work by abstract interpretation of RPython code, i.e. abstract -interpretation of the interpreter itself (as opposed to user application -code). This is similar to the ideas behind the translator, which operates on -the RPython source (i.e. the bytecode interpreter and the standard Object -Space). We plan to write the dynamic part of the JIT as a plug-in to the -translator: instead of generating C code that is the direct translation of -PyPy, we will generate C code (with the translator) that itself generates -machine code (by directly emitting it as bytes into memory). This extra -indirection has large benefits: the operations the JIT need to be manually taught -about for the generation of machine code are only the ones allowed in RPython. -In other words, we only need to design a JIT supporting the low-level operations -of RPython; still, the translated piece of C code that we obtain is a JIT-enabled -version of PyPy that supports the whole of the Python language. - - -Other Research Aspects -++++++++++++++++++++++ - -The other part of Phase 2 focuses on non-performance-oriented research-level -aspects. These are the extensions enabled by the flexible modularization -(bytecode compiler, bytecode interpreter, Object Spaces, and translator) -enabled in Phase 1. For example, it would be possible to write an interpreter -for a completely different language using the same framework, -leveraging the translator and thus obtaining an efficient JIT-enabled -implementation with little effort. - -This is actually strongly considered as an implementation strategy for the -Prolog language in a current EU-funded project:: - - We could replace with a reasonable amount of effort the core Python - interpreter in PyPy with an experimental Prolog interpreter. This - would both prove the versatility of the PyPy platform and give performance - results possibly far beyond the state of the art. This is a reasonable - assumption because the long history of Prolog is quite focused on - static (compile-time) optimisations. - - --Armin Rigo, for ASAP, Southampton team (Advanced Specialization and - Analysis for Pervasive Computing), EU IST FET Programme Project Number - IST-2001-38059. - -In the context of the PyPy project, we will not replace the interpreter -altogether, but experiment with extensions: - -- based on feedback from the Python community, we will experiment with the - proposed language extensions that are deemed worthy by the CPython - developers. Numerous PEPs (Python Extension Proposals), for example, need an - experimental implementation for testing before they can be accepted or - rejected for integration into CPython; not only is PyPy a good platform to - test them on, but also, playing this sandbox role will ensure PyPy remains - synchronised with the development of CPython. (The role of WP03_ is to keep - track of the ongoing development of the Python language and its CPython - implementation; as a part of this task, we will also look for existing - solutions to automate the "passive" part of this effort at least partially.) - -- WP09_ involves the research and development of techniques inspired from - logic programming. An inference engine already exists in the python-logic - libraries. Successful integration of these concepts, far from regular - imperative programming, would provide a validation of the level of - flexibility we achieved in Phase 1. Similarly, WP10_ will experiment with - OO concepts not originally present in Python, like aspect-oriented - programming and design-by-contract. - -Phase 3 -------- - -The third phase of the project is to implement selected key applications of -the flexibility we have enabled so far. - -Let us stress again that Phase 3 is not meant to run only after Phase 2, but -partly in parallel with it. The core flexibility on top of which we will be -building is provided by the PyPy interpreter as described in Phase 1. - -The applications we have selected can be categorized as follows: - -- Language-level object models; - -- Language-level extensions; - -- Interpreter adaptations. - -Phase 3 is also when we expect third parties to build on top of our platform. - - -Language-Level Object Models -++++++++++++++++++++++++++++ - -This is the topic of WP12_. We will integrate with the language itself three -middleware features: security, transparent distribution, and persistence. - -**Security** is an important and difficult aspect that requires knowledge and -support at a wide number of levels to be effective. Programming languages can -help contribute to security at their level. Different object security models -are possible: - -- The language can be artificially restricted, with dangerous operations taken - out and thus impossible to achieve by interpreted programs. In effect, this - amount to building a carefully stripped-down interpreter. - -- Access to some objects can be denied to only some (untrusted) parts of the - interpreted program; or access can go though proxies performing some kind of - access checks. This is a more flexible solution, but it is more difficult to - implement efficiently. Explicit checks for each access consume time. In PyPy - this could be implemented as an Object Space checking and delegating - operations to another Object Space. - -For comparison, CPython used to implement security-by-absence-of-reference: -untrusted parts of a program could supposedly not obtain a reference to a -dangerous object. This model, called "RExec", has been recognized as fragile -and hard to maintain. It has been removed from CPython. - -In PyPy, one or both of the alternatives previously described can be -practically implemented. - -**Transparent distribution** of objects over a network is another middleware -feature that would benefit from being implemented at the language level. This -is a vast subject which has been studied extensively. There are several -implementations already available in Python, with varying degrees of -transparency. None however can be fully transparent by definition of the -language itself, which allows introspection -- a program using introspection -features could thus defeat the delicate mechanisms introduced by a network -distribution library. Moreover, such libraries typically impose additional -constrains, e.g. are only able to move objects over a network if they are of a -class inheriting from a particular class. - -We will study which of these implementations is best suited for being moved -into the interpreter itself. These include transparent interfaces to remote -objects (like CORBA, Java RMI...), transparent distribution of objects, and -transparent distribution of processes themselves. For example, a foreseen -solution for the CORBA model would be to design a Proxy Object Space that -delegates operations to a remote CORBA object server over the network, thus -hiding the complexities of the underlying protocols. We will also study -approaches enabling transparent distributed execution, i.e. in which the -Object Space may decide to move, rather objects or operations, a whole -algorithm's bytecode. Such totally-transparent distributed execution would -support applications such as fault tolerance (e.g. perform a computation on -two machines and compare the results). - -**Persistence** is related to distribution; it is essentially a way to move -objects transparently between the persistent storage and the main memory. This -subject has been studied extensively, and there are several implementations -already available. - -We are considering at this point ZODB, the Zope Database engine, and -PyPerSyst, which are quite complete. Their respective developers have -already expressed high interest in PyPy. Indeed, they would benefit -from better language integration; they currently put non-natural -constrains on the programmer in terms of what he is allowed to do for -persistence to actually work transparently. Typically, it is not -possible for a library to detect changes such as adding elements to -lists, so that list objects cannot be automatically marked as "dirty" -(as needed to ensure they will transparently be saved when -necessary). This requires language support, and more specifically an -extension or proxy Object Space. - - -Language-Level Extensions -+++++++++++++++++++++++++ - -WP09_ and WP10_ are language-level extensions in the sense that they -introduce new features usually present as libraries directly into the -interpreter itself. - -A major goal of the PyPy project is to enable people to carry out more of -their programming tasks in Python without having to resort to other -programming languages. We will therefore exploit the architecture and the -optimisations of the -PyPy implementation and the constructs for constraints and search to -enhance the object model, thus offering in Python what can currently only -be found in some other object-oriented languages. In particular: - -WP10_ will offer the ability to compose program functionality with aspects -and to design object-oriented programs through contract. For example, today -to add aspects like logging or design-by-contract to functions you have to -add a wrapper or another layer on top of existing definitions, a process -which is clumsy and fragile and thus impractical. Instead it would be -preferable to be able to hook into the internals of an interpreter and -extend its behaviour, e.g. the method invocation mechanisms. Specifically, -WP10_ will experiment with having first-class hooks for checking arguments -and return values, or supporting efficiently "around/after and before" -behaviours like the similar concepts in the Common Lisp Object System. - -WP09_ will explore the integration of logic programming techniques. For -example, today to use a constraint solver like the one from the -python-logic libraries, one has to resort to an unfamiliar custom syntax. -These libraries would be much more useful if they were better integrated -with the language. WP09_ will specifically experiment with rewriting parts -of the python-logic libraries in RPython for integration and performance, -and enhance the syntax to support them, with the goal of supporting -Semantic Web and knowledge representation applications. - - -Interpreter Adaptations -+++++++++++++++++++++++ - -The PyPy interpreter as developed in Phases 1 and 2 will be particularly -suitable to be adapted to extremely diverse runtime environments, from -embedded devices to number-crunching machines. - -In WP11_ we propose to study to specific case of embedded devices, which -are often limited in processor speed and memory size. This either -limits the power of software that is implemented for these platforms, or -enforces use of low-level approaches like C/C++ or Java. PyPy is -especially suited to support such platforms, since it can produce -effective and compact code, while retaining the abstraction and -ease-of-use of a Very-High-Level Language. Based on the specific needs -of these devices, we will experiment with memory- or battery-efficient -implementations of all the customizable aspects described in Phase 2. -Additionally, results from WP13_ and feedback from one or more selected -industrial partners will be used to verify the applicability of Python's -flexible architecture for embedded devices in particular. - - -Integration and Configuration -+++++++++++++++++++++++++++++ - -It is expected that most of the applications described above will still be -relatively experimental when the project ends. It is also expected that the -extreme flexibility will lead to the deployment of a potentially large number -of different configurations of PyPy. Thus our essential goal, beyond validating -our techniques and showing what can be done and how it benefits from -integration with the language, is to make this knowledge available and -easy-to-use for contributors and third-parties. - -To fulfill the technical aspect of this goal, we will not only release a range -of different versions of PyPy with different trade-offs and including more or -less of the features developed in Phase 3, but we will also build a complete -toolchain to allow programmers to choose from the available features, various -implementations, and runtime restrictions and build a custom PyPy version. -This is the objective of WP13_. - - -Documentation and Dissemination -------------------------------- - -The documentation aspect of the dissemination goal is handled by one of the -few workpackages that run for the whole duration of the project. - -Each sprint, as well as the regular progress of non-sprint development, will -produce technical novelties, some of which may afford immediate use and -adoption of the novel technologies being developed. We expect all developers -and participants to openly report to and discuss with their appropriate -communities. Reports and summaries will be posted to the relevant mailing -lists as well as archived on both the PyPy (and the Python Business Forum) -website for universal availability. WP14_ is to support this process at all -levels. - -Moreover, WP14_ will produce a joint report about agile methodologies -employed by the project. In particular, any "lessons learned" about Sprint -Driven development will be analysed in cooperation with all participants, -the technical and management board. - -Python community members will be encouraged to keep current and get involved -with the project, while community involvement and feedback on technical -developments will affect design and implementation decisions. Feedback and -suggestions will be gathered on the website and mailing lists and used by the -appropriate project areas to further enhance the project's development -efforts, in true Open Source spirit. - -In addition to supporting the communication process, WP14_ will on occasion -present longer, detailed reports to the Commission, and to scientific -committees advising the Commission on technical issues. Technical papers and -talks will be submitted to scientific conferences which deal with the subject -matters covered by the project. When the advancement of the project warrants -it, WP14_ will also publish "popularization" articles and tutorial materials -to help other practitioners of software development to make practical use of -the project's results. Diagrams and schematics will be provided to illustrate -fundamental concepts, as appropriate to the audience and the subject matter. - -To ensure stakeholder participation and feedback that goes beyond the -python community, WP14_ also consists of arranging workshops ( 6 in total) -to disseminate the ongoing process- and development progress.The majority -of the workshops are going to target important stakeholder groups and will -primarily focus on disseminating PyPy results from an implementation -perspective, customized for the target groups different needs. - -Maintenance ------------ - -PyPy's own development needs an infrastructure that must continuously be kept -up-to-date and further developed. The role of WP02_ is decisive in choosing -and adopting modern development environments. The main source repository is -placed under control of Subversion, a Concurrent Versioning System. This -workpackage also includes maintaining and possibly redesigning frameworks for -unit-testing -- unit-tests are essential in the development process in -sprints. The website makes heavy use of collaborative tools like Wiki pages, a -content management system, and issue trackers. - -Other tasks include: - -- Subversion maintenance (e.g. notification hooks and pre/post-commit - restrictions); - -- providing access over http/https and ssh server; - -- building extensions for automatic document extraction; - -- maintenance or setup of mailing lists; - -- implementing a search facility over all content; - -- maintaining or extending the issue tracker; - -- maintaining and enhancing the website infrastructure; - -- performing backups for all relevant information/code; - -- setting up a mirror repository which is kept up-to-date and which can be - used read-only in case of failure of the main repository; - -- taking care of regular repository backups, designing a strict backup policy - suitable for the project, and adhering to it. - - -:DELETE:BEGIN - -B6.3 - -:DELETE:END - -Risks in the Project and Steps to Minimise Them -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - -The success of the whole project depends on the success of Phase 1. When the -corresponding milestone is reached -- a complete Python interpreter in Python -and a translator for it -- the project will branch. Phase 2 and Phase 3 -workpackages are not tightly interconnected. So we will examine project risks -with our main focus on Phase 1. - - -Phase 1 -------- - -The initial design decisions have already been discussed during the young -history of the project and its first four sprints, and a basic working -prototype has already been written, as a proof of concept. We thus take for -granted that the risks associated with the following decisions are almost -non-existent at this point: - -- writing a Python interpreter in Python is not only possible -- it is - markedly faster and easier to do than in a low level language like C. - -- following some of the basic design decisions of CPython (the internals of - whom most of us are intimately familiar with) leads to fast development and - good results. - -- pluggable Object Spaces do work. Several proof-of-concept Object Spaces have - been successfully tried. - -- Object Spaces are a remarkably suitable abstraction for abstract/symbolic - interpretation. Control flow of simple functions has been derived using an - Object Space. - -Moreover, simple type analysis and generation of low-level code from a -low-level representation is common in a variety of contexts, so we don't -expect any particular problem from that issue either. - -As a fall-back solution, we are aware of the more common way to do the -translator analysis: if the abstract Object Space should fail to scale as -expected, we will revert to classic bytecode-based analysis, adapting tools -that are already available for this task. We will, however, pursue the -abstract interpretation solution as far as possible, because it leads to more -language-independence and particularly to a single place where all knowledge -about the details of the actual bytecode needs to be represented. - - -Phase 2 -------- - -Phase 2 is mainly research-oriented. It is by definition more difficult to -predict the involved risks, and fall-back strategies if risks materialize, -for this Phase than for the others. - -However, a risk-mitigating factor is that the performance goals of Phase 2 are -backed by the existing and working prototypes Stackless and Psyco, whose -authors are among the PyPy members. Further, it is also important to note that -the described performance goals, while very interesting and important in order -to widen the application area of the language, are not essential to the other -applications we have planned. Phase 1 (including translation) already produces -a level of performance that can reasonably be expected to be comparable to the -existing CPython interpreter. - - -Phase 3 -------- - -Phase 3 consists of a number of independent applications. Consequently, a -failure in one of them would almost certainly not influence the others. Of -course, appropriate effort has nevertheless been taken to avoid failure in -each of the mentioned applications: all of them are to some extent already -existing as middleware libraries, and people fluent in the corresponding -domains generally appreciate the advantages a better language integration -would bring. - -The project concludes with an Integration and Configuration workpackage; -should one of the previous applications fail, the final configurable tool will -still be able to integrate the others. The only risk involved there would -involve difficulties (technical or others) to integrate the work done by the -various partners. As a fall-back solution we may have to keep some successful -but hard to integrate applications out of the mainstream full-featured release -or even configuration tool. It is a tendency inherent in open source projects -to sometimes fork, in order to explore alternative possibilities, and later, -when consensus is reached, merge again. We will try to minimize the -corresponding risk (of divergence, i.e., a fork not followed by a later -merge), but we also think that it is inherently very low, as long as the -different applications are kept as non-overlapping as possible. This risk -minimization strategy in application-structuring is already reflected in -the work-packages presented for Phase 3. - Deleted: /pypy/funding/B6.4_gantt.txt ============================================================================== --- /pypy/funding/B6.4_gantt.txt Thu Mar 17 10:56:00 2005 +++ (empty file) @@ -1,5 +0,0 @@ -PRoject Planning and Time Table (Gantt chart) ------------------------------------------------ - -.. image:: project_gantt.png - :scale: 70 Deleted: /pypy/funding/B6.5_workpackage_list.txt ============================================================================== --- /pypy/funding/B6.5_workpackage_list.txt Thu Mar 17 10:56:00 2005 +++ (empty file) @@ -1,45 +0,0 @@ -.. include:: crossreferences.asc - -Workpackage List -==================== - -.. |wpn| replace:: Work-package No -.. |lcn| replace:: Lead contractor No -.. |pm| replace:: Person-months -.. |sm| replace:: Start month -.. |em| replace:: End month -.. |dn| replace:: Deliverable No - - -===== ==================================================== ===== ==== ==== ==== ==== ======== -|wpn| Workpackage title |lcn| |pm| |sm| |em| |dn| delete -===== ==================================================== ===== ==== ==== ==== ==== ======== -WP01_ Coordination and Management 1 12 0 24 DFKI ------ ---------------------------------------------------- ----- ---- ---- ---- ---- -------- -WP02_ Infrastructure and Tools 1 8 0 24 Krekel ------ ---------------------------------------------------- ----- ---- ---- ---- ---- -------- -WP03_ Synchronisation with Standard Python 2 9 0 24 USH ------ ---------------------------------------------------- ----- ---- ---- ---- ---- -------- -WP04_ The PyPy Core 5 22 0 9 Strakt ------ ---------------------------------------------------- ----- ---- ---- ---- ---- -------- -WP05_ The PyPy Translation 2 28 0 9 USH ------ ---------------------------------------------------- ----- ---- ---- ---- ---- -------- -WP06_ Core Optimisations 2 12 9 24 USH ------ ---------------------------------------------------- ----- ---- ---- ---- ---- -------- -WP07_ Translator Optimisations 1 16 9 18 Tismer ------ ---------------------------------------------------- ----- ---- ---- ---- ---- -------- -WP08_ Dynamic Optimisations 5 25 9 18 Strakt ------ ---------------------------------------------------- ----- ---- ---- ---- ---- -------- -WP09_ Extend Language with Search and Logic 1 19 9 24 DFKI ------ ---------------------------------------------------- ----- ---- ---- ---- ---- -------- -WP10_ Extend Language with Aspects and Contracts 6 12 9 24 Logilab ------ ---------------------------------------------------- ----- ---- ---- ---- ---- -------- -WP11_ Embed in Specialized Hardware 7 6 9 24 ChangeMaker ------ ---------------------------------------------------- ----- ---- ---- ---- ---- -------- -WP12_ Implement Security, Distribution and Persistence 5 13 18 24 Strakt ------ ---------------------------------------------------- ----- ---- ---- ---- ---- -------- -WP13_ Integration and Configuration 1 12 18 24 Krekel ------ ---------------------------------------------------- ----- ---- ---- ---- ---- -------- -WP14_ Project Documentation and Dissemination 7 23 0 24 ChangeMaker -===== ==================================================== ===== ==== ==== ==== ==== ======== - Deleted: /pypy/funding/B6.6_deliverables_list.txt ============================================================================== --- /pypy/funding/B6.6_deliverables_list.txt Thu Mar 17 10:56:00 2005 +++ (empty file) @@ -1,169 +0,0 @@ -.. include:: crossreferences.asc - -Deliverables List -==================== - -.. |dn| replace:: Deliverable No -.. |dd| replace:: Deliverable Date -.. |na| replace:: Nature -.. |dl| replace:: Dissemination Level - - -===== ===================================================== ===== ==== ==== -|dn| Deliverable sortformtitle |dd| |na| |dl| -===== ===================================================== ===== ==== ==== -D01.1 Create QA plan for the project 1 O PU ------ ----------------------------------------------------- ----- ---- ---- -D01.2 Collection and monitoring of reports 24 O PU ------ ----------------------------------------------------- ----- ---- ---- -D01.3 Report to EU 24 O PU ------ ----------------------------------------------------- ----- ---- ---- -D01.4 Organise meetings 24 O PU ------ ----------------------------------------------------- ----- ---- ---- -D01.5 Organize sprints 24 O PU ------ ----------------------------------------------------- ----- ---- ---- -D01.6 Create and maintain internal web site 24 O PU ------ ----------------------------------------------------- ----- ---- ---- -D01.7 Newsletter for external stakeholders 24 O PU ------ ----------------------------------------------------- ----- ---- ---- -D02.1 Configuring, installation of all development tools 24 O PU ------ ----------------------------------------------------- ----- ---- ---- -D02.2 A release scheme for PyPy versions 24 O PU ------ ----------------------------------------------------- ----- ---- ---- -D02.3 Http-server to present runtime/introspection 24 P PU ------ ----------------------------------------------------- ----- ---- ---- -D02.4 Several website revisions 24 O PU ------ ----------------------------------------------------- ----- ---- ---- -D02.5 Automated (unit-)testing framework 24 P PU ------ ----------------------------------------------------- ----- ---- ---- -D03.1 A PyPy that supports a subset of the CPython API 24 P PU ------ ----------------------------------------------------- ----- ---- ---- -D03.2 Report on supporting full C-extensions compatibility 24 R PU ------ ----------------------------------------------------- ----- ---- ---- -D03.3 A guide describing the porting of C extensions 24 R PU ------ ----------------------------------------------------- ----- ---- ---- -D04.1 Partial Python Implementation on top of CPython 6 P PU ------ ----------------------------------------------------- ----- ---- ---- -D04.2 Complete Python Implementation on top of CPython 9 P PU ------ ----------------------------------------------------- ----- ---- ---- -D04.3 Report about the parser and bytecode compiler 10 R PU ------ ----------------------------------------------------- ----- ---- ---- -D04.4 Release PyPy as a research tool 9 P PU ------ ----------------------------------------------------- ----- ---- ---- -D05.1 Publish on translating a very-high-level description 9 R PU ------ ----------------------------------------------------- ----- ---- ---- -D05.2 A compiled, self-contained version of PyPy 9 P PU ------ ----------------------------------------------------- ----- ---- ---- -D05.3 Publish on implementation with translation aspects 10 R PU ------ ----------------------------------------------------- ----- ---- ---- -D05.4 Publish on encapsulating low level language aspects 10 R PU ------ ----------------------------------------------------- ----- ---- ---- -D06.1 Integrate the first core optimisation results 18 P PU ------ ----------------------------------------------------- ----- ---- ---- -D06.2 Publication of statistics for core objects 24 R PU ------ ----------------------------------------------------- ----- ---- ---- -D06.3 Publication of novel heuristic techniques 24 R PU ------ ----------------------------------------------------- ----- ---- ---- -D07.1 Support for massive parallelism 18 P PU ------ ----------------------------------------------------- ----- ---- ---- -D07.2 Publish optimisation results 19 R PU ------ ----------------------------------------------------- ----- ---- ---- -D07.3 Report about practical usages 18 R PU ------ ----------------------------------------------------- ----- ---- ---- -D07.4 Report on approaches for translator aspects 19 R PU ------ ----------------------------------------------------- ----- ---- ---- -D08.1 A processor back-end supporting Intel(tm) i386 18 P PU ------ ----------------------------------------------------- ----- ---- ---- -D08.2 A processor back-end supporting PowerPC 18 P PU ------ ----------------------------------------------------- ----- ---- ---- -D08.3 A Just-In-Time compiler for PyPy 18 P PU ------ ----------------------------------------------------- ----- ---- ---- -D08.4 Publish a report about the new JIT architecture 19 R PU ------ ----------------------------------------------------- ----- ---- ---- -D08.5 Publish a research report comparing JIT techniques 19 R PU ------ ----------------------------------------------------- ----- ---- ---- -D09.1 Initial constraint satisfaction and inference engine 18 P PU ------ ----------------------------------------------------- ----- ---- ---- -D09.2 Improved constraint satisfaction and inference engine 24 P PU ------ ----------------------------------------------------- ----- ---- ---- -D09.3 Assessment of benefits 24 R PU ------ ----------------------------------------------------- ----- ---- ---- -D10.1 Aspect-oriented programming capabilities in PyPy 24 P PU ------ ----------------------------------------------------- ----- ---- ---- -D10.2 Design-by-contract capabilities 24 P PU ------ ----------------------------------------------------- ----- ---- ---- -D10.3 Advanced static checking capabilities 24 P PU ------ ----------------------------------------------------- ----- ---- ---- -D11.1 Written report to Axis Communication 21 R PU ------ ----------------------------------------------------- ----- ---- ---- -D11.2 Documented feedback from Axis Communication 24 R PU ------ ----------------------------------------------------- ----- ---- ---- -D12.1 Prototype supporting control of individual operations 24 P PU ------ ----------------------------------------------------- ----- ---- ---- -D12.2 Prototype supporting transparent remote proxying 24 P PU ------ ----------------------------------------------------- ----- ---- ---- -D12.3 Prototype supporting orthogonal persistence 24 P PU ------ ----------------------------------------------------- ----- ---- ---- -D12.4 Report on novel directions in middleware features 24 R PU ------ ----------------------------------------------------- ----- ---- ---- -D13.1 A release with all optimisation and runtime features 24 P PU ------ ----------------------------------------------------- ----- ---- ---- -D13.2 A build- and configuration tool 24 P PU ------ ----------------------------------------------------- ----- ---- ---- -D13.3 A publication about PyPy code base and customization 24 R PU ------ ----------------------------------------------------- ----- ---- ---- -D14.1 Report about Milestone/Phase 1 10 R PU ------ ----------------------------------------------------- ----- ---- ---- -D14.2 Tutorials and a guide through the PyPy source code 15 R PU ------ ----------------------------------------------------- ----- ---- ---- -D14.3 Report about Milestone/Phase 2 19 R PU ------ ----------------------------------------------------- ----- ---- ---- -D14.4 Report about Milestone/Phase 3 25 R PU ------ ----------------------------------------------------- ----- ---- ---- -D14.5 Documentation of the development process 24 R PU ------ ----------------------------------------------------- ----- ---- ---- -D14.6 Organize four domain specific Workshops 24 O PU ------ ----------------------------------------------------- ----- ---- ---- -D14.7 Arrange two nondomain specific workshops 24 O PU ------ ----------------------------------------------------- ----- ---- ---- -D14.8 Participation of PyPy members in conferences 24 O PU -===== ===================================================== ===== ==== ==== - -:DELETE:BEGIN - -Deliverable numbers in order of delivery dates: D1 ? Dn - -Month in which the deliverables will be available. Month 0 marking the start of the project, -and all delivery dates being relative to this start date. - -Please indicate the nature of the deliverable using one of the following codes: - - R = Report - - P = Prototype - - D = Demonstrator - - O = Other - -Please indicate the dissemination level using one of the following codes: - - PU = Public - - PP = Restricted to other programme participants (including the Commission Services). - - RE = Restricted to a group specified by the consortium (including the Commission Services). - - CO = Confidential, only for members of the consortium (including the Commission Services). - -:DELETE:END - -Workpackage description -=========================== - -:DELETE:BEGIN - -Here the working packages start. -Just leave this header in. - -:DELETE:END Deleted: /pypy/funding/B6.7.wp01_management.txt ============================================================================== --- /pypy/funding/B6.7.wp01_management.txt Thu Mar 17 10:56:00 2005 +++ (empty file) @@ -1,60 +0,0 @@ -.. include:: crossreferences.asc - -.. |title| replace:: Coordination and Management -.. |wp| replace:: WP01 -.. |start| replace:: 0 -.. |p1| replace:: CM -.. |m1| replace:: 4 -.. |p2| replace:: DFKI -.. |m2| replace:: 4 -.. |p3| replace:: STRAKT -.. |m3| replace:: 4 -.. |p4| replace:: |e| -.. |m4| replace:: |e| -.. |p5| replace:: |e| -.. |m5| replace:: |e| -.. |p6| replace:: |e| -.. |m6| replace:: |e| - -.. include:: wp-toptable.asc - -.. include:: wp-tablebegin.asc - -**Objectives** - -Coordination and Management of the PyPy Project. - -.. include:: wp-tableend.asc -.. include:: wp-tablebegin.asc - -**Description of work** - -- collection and monitoring of monthly status reports, -- reporting to the EU project office -- organising project meetings and sprints -- maintaining contents and structure of the project web site. - The website will make heavy - use of collaborative tools like Wiki pages, a content management system, - and issue trackers. - -.. include:: wp-tableend.asc -.. include:: wp-tablebegin.asc - -**Deliverables** - -- D01.1 Create QA plan for the project -- D01.2 Collection and monitoring of reports (monthly, sprints, review workshop, evaluation) -- D01.3 Report to EU -- D01.4 Organise project meetings -- D01.5 Organize sprints -- D01.6 Create and maintain internal web site -- D01.7 Create and maintain newsletter covering ongoing project process for external stakeholders - -.. include:: wp-tableend.asc -.. include:: wp-tablebegin.asc - -**Milestones and Expected Result** - -A succesful and measurable delivery of every workpackage within the project scope. - -.. include:: wp-tableend.asc Deleted: /pypy/funding/B6.7.wp02_maintenance.txt ============================================================================== --- /pypy/funding/B6.7.wp02_maintenance.txt Thu Mar 17 10:56:00 2005 +++ (empty file) @@ -1,90 +0,0 @@ -.. include:: crossreferences.asc - -.. |title| replace:: Infrastructure and Tools -.. |wp| replace:: WP02 -.. |start| replace:: 0 -.. |p1| replace:: DFKI -.. |m1| replace:: 8 -.. |p2| replace:: |e| -.. |m2| replace:: |e| -.. |p3| replace:: |e| -.. |m3| replace:: |e| -.. |p4| replace:: |e| -.. |m4| replace:: |e| -.. |p5| replace:: |e| -.. |m5| replace:: |e| -.. |p6| replace:: |e| -.. |m6| replace:: |e| - -.. include:: wp-toptable.asc - -.. include:: wp-tablebegin.asc - -**Objectives** - -Supporting the PyPy project by producing and enhancing the tools for version -control of source code, communication, dissemination and distribution of information. -Collaborate with community to implement a powerful development environment -for the various needs of the PyPy STREP. - -.. include:: wp-tableend.asc -.. include:: wp-tablebegin.asc - -**Description of work** - -Support the development process with reusing and furthering -existing or developing new debugging opensource tools. - -- maintain the Subversion repository including notification - hooks and pre/post-commit restrictions. - -- provide access over http/https and ssh to the repository. - -- setup support for releasing different versions of PyPy - -- build extensions for automatic document extraction - -- maintain/setup mailing lists - -- implement a search facility over all content - -- maintain/extend issuetracker - -- maintain and enhance website infrastructure - -- perform backups for all relevant information and sourcecode - -- setup a mirror repository which is kept up-to-date and which - can be used readonly in case of failure of the main repository. - -- Take care of regular repository backups. Design a strict backup - policy suitable for the project, and adhere to it. - -- setup and maintain mailing lists for development, consortium - and community communication. - -- help with automated testing - -.. include:: wp-tableend.asc -.. include:: wp-tablebegin.asc - -**Deliverables** - -- D02.1 configuring, installation of all development tools (subversion, apache2, mailman, backup, roundup, ...) - -- D02.2 introduce and document a release scheme for PyPy versions - -- D02.3 http-server to present runtime/introspection information aiding debugging and understanding of PyPy internals - -- D02.4 several website revisions - -- D02.5 release automated (unit-)testing framework with html/pdf reports - -.. include:: wp-tableend.asc -.. include:: wp-tablebegin.asc - -**Milestones and Expected Result** - -Provide advanced infrastructure to support goals and objectives of the project. - -.. include:: wp-tableend.asc Deleted: /pypy/funding/B6.7.wp03_synchronisation.txt ============================================================================== --- /pypy/funding/B6.7.wp03_synchronisation.txt Thu Mar 17 10:56:00 2005 +++ (empty file) @@ -1,71 +0,0 @@ -.. include:: crossreferences.asc - -.. |title| replace:: Synchronisation with Standard Python -.. |wp| replace:: WP03 -.. |start| replace:: 0 -.. |p1| replace:: USH -.. |m1| replace:: 3 -.. |p2| replace:: DFKI -.. |m2| replace:: 6 -.. |p3| replace:: |e| -.. |m3| replace:: |e| -.. |p4| replace:: |e| -.. |m4| replace:: |e| -.. |p5| replace:: |e| -.. |m5| replace:: |e| -.. |p6| replace:: |e| -.. |m6| replace:: |e| - -.. include:: wp-toptable.asc - -.. include:: wp-tablebegin.asc - -**Objectives** - -Keeping PyPy in sync with potential changes to Standard Python. -Support a subset of the CPython API for compatibility with -extension modules. Facilitate porting of extension modules to PyPy. -Collaborate strongly with CPython developer communities. - -.. include:: wp-tableend.asc -.. include:: wp-tablebegin.asc - -**Description of work** - -**Task 1** - -Monitor the development of Standard Python for its ongoing changes. -Check the relevance of the changes concerning the structure of -PyPy. Collaborate with CPython developer communities. -Embed the relevant changes with proper testing, notifying the other -concurrent tasks of these changes. -Investigate tools which could partially automate -integration of simple changes. - -**Task 2** - -Investigate different solutions to address compatibility with -existing C extensions. Collaborate with CPython developer communities. -Support a subset of the CPython API. Facilitate porting of -more involved extensions. -Investigate adjusting existing interface generators (in particular SWIG, used e.g -by wxPython, subversion bindings and other popular extensions) to target PyPy. - -.. include:: wp-tableend.asc -.. include:: wp-tablebegin.asc - -**Deliverables** - -- D03.1 A version of PyPy that supports a subset of the CPython API -- D03.2 A report on the feasibility of supporting full C-extensions compatibility -- D03.3 A guide describing the porting of C extensions to PyPy - -.. include:: wp-tableend.asc -.. include:: wp-tablebegin.asc - -**Milestones and Expected Result** - -PyPy is kept in sync with potential changes to Standard Python throughout -the duration of the project. - -.. include:: wp-tableend.asc Deleted: /pypy/funding/B6.7.wp04_core.txt ============================================================================== --- /pypy/funding/B6.7.wp04_core.txt Thu Mar 17 10:56:00 2005 +++ (empty file) @@ -1,122 +0,0 @@ -.. include:: crossreferences.asc - -.. |title| replace:: The PyPy Core -.. |wp| replace:: WP04 -.. |start| replace:: 0 -.. |p1| replace:: Strakt -.. |m1| replace:: 6 -.. |p2| replace:: DFKI -.. |m2| replace:: 12 -.. |p3| replace:: Logilab -.. |m3| replace:: 5 -.. |p4| replace:: |e| -.. |m4| replace:: |e| -.. |p5| replace:: |e| -.. |m5| replace:: |e| -.. |p6| replace:: |e| -.. |m6| replace:: |e| - -.. include:: wp-toptable.asc - -.. include:: wp-tablebegin.asc - -**Objectives** - -Building a complete Python interpreter written in Python, -using a subset of Python that avoids dynamic features -which would impair the objectives of WP05_ (RPython). -Collaborate with CPython core developers. - -.. include:: wp-tableend.asc -.. include:: wp-tablebegin.asc - -**Description of work** - -**Task 1** - -Implement an interpreter that is able to accept the complete -Python language specification, built according to the general -modularity goals described in the body of the text. -This task specifically includes research and implementation -work leading to: - -- the Object Space interface. - -- a bytecode interpreter, accepting the standard CPython - bytecode format. - -- a "standard" object space implementing the core Python - objects' normal semantics. - -This task excludes the standard extension modules and the -parser and bytecode compiler, which for the purpose of -testing are borrowed from the underlying CPython interpreter -on top of which our interpreter runs. Collaborate strongly -with CPython core developers via the python-dev mailing list. - -**Task 2** - -Port the standard Python "builtin" library: - -- types (there are some 100 of them); - -- built-in functions; - -- built-in modules; - -- other built-in objects, e.g. exception classes. - -Research and decide on a case-by-case basis how to implement -each one within PyPy in a simple and efficient way. The common -options are to either re-implement them inside the interpreter -where appropriate, or to provide a pure Python replacement -(which in some cases already exists and can be borrowed). - -**Task 3** - -Complete the interpreter with a Python source parser and bytecode -compiler. Collaborate with various core developers involved -with new parsing and compiling techniques. - -- Implement a Python parser and bytecode compiler in Python by - leveraging existing research and implementation work. Reuse - code and ideas from ongoing open source projects. - -- Design a flexible way to insert the compiler into the - code base, easing future experimentation with the syntax. - -- More generally, research and provide bridges between the interpreter - source and the code it interprets, allowing the interpreter to delegate - some of its "core" work to regular, interpreted, pure Python code. - Decide when it is appropriate to make this regular code visible to - language users (e.g. as modules, modifiable at run-time). - -.. include:: wp-tableend.asc -.. include:: wp-tablebegin.asc - -**Deliverables** - -- D04.1 First partial Python Implementation running on top of CPython -- D04.2 Complete Python implementation running on top of CPython -- D04.3 Report about the parser and bytecode compiler implementation -- D04.4 Release PyPy as a research tool for experimental language - enhancements - -.. include:: wp-tableend.asc -.. include:: wp-tablebegin.asc - -**Milestones and Expected Result** - -- A partial Python implementation that passes 90% of the official - Python test suite for core language features, i.e. not depending on - library-level C extension modules (the C part of the "standard - library"). - -- Providing a substitute for the many existing C modules will be an - ongoing effort neccessarily involving the wider python communities. - By the end of Phases 2 and 3 of the project we expect to have the most - commonly used modules reimplemented in a flexible framework or - if - technically not feasible - matched with equivalent functionality in - PyPy. - -.. include:: wp-tableend.asc Deleted: /pypy/funding/B6.7.wp05_translation.txt ============================================================================== --- /pypy/funding/B6.7.wp05_translation.txt Thu Mar 17 10:56:00 2005 +++ (empty file) @@ -1,115 +0,0 @@ -.. include:: crossreferences.asc - -.. |title| replace:: The PyPy Translation -.. |wp| replace:: WP05 -.. |start| replace:: 0 -.. |p1| replace:: STRAKT -.. |m1| replace:: 15 -.. |p2| replace:: DFKI -.. |m2| replace:: 6 -.. |p3| replace:: USH -.. |m3| replace:: 8 -.. |p4| replace:: |e| -.. |m4| replace:: |e| -.. |p5| replace:: |e| -.. |m5| replace:: |e| -.. |p6| replace:: |e| -.. |m6| replace:: |e| - -.. include:: wp-toptable.asc - -.. include:: wp-tablebegin.asc - -**Objectives** - -Analysis and translation of the PyPy core (WP04_) into -efficient low-level code (C, Pyrex, Java, others). -Providing a Runtime Library for the translated versions -of PyPy. - -.. include:: wp-tableend.asc -.. include:: wp-tablebegin.asc - -**Description of work** - -**Task 1** - -At the core of this task lies the research and -implementation of full "abstract interpretation" by reusing -the unmodified PyPy interpreter with a special object space. - -- Create a code analysis tool for a subset of the Python - language (RPython). - -- Coordinate the definition of RPython with WP04_, being the - implementation language for most of the core. - -- Experiment with different ways of doing Abstract Interpretation. - Look for an Abstract Domain suitable for type inference. - Compare with published algorithms for type inference. - Select and implement the most appropriate solution in our - context. - -**Task 2** - -Produce a tool chain, capable of extracting the RPython -bytecode from the core, translating it into low-level -code (with C being the primary target) and compiling it. - -- Create a build process for statically generating and running - a low-level PyPy interpreter and object space. The LLVM (Low level virtual Machine) - project is a candidate for collaboration in this context. - -- Provide hooks into internals to alter translation aspects. - -- Research/experiment with a Java backend. - -**Task 3** - -In order to give a working environment to the translated RPython -program, build the low-level-specific runtime components of PyPy. -For the C PyPy runtime, important parts can be directly re-used from CPython. -However, certain aspects such as memory management and threading models -are to be implemented in a modular way. - -- Implement a minimal C-runtime for the translated PyPy, - collaborate for with CPython core developers. - -- Integrate Memory Management, threadings models, and other aspects in a - modular way into both the C-runtime and the statically generated PyPy low - level code. For memory management improve and build on top of solutions from other open - source language projects. - -.. include:: wp-tableend.asc -.. include:: wp-tablebegin.asc - -**Deliverables** - -- D05.1 Publish a report about translating a very-high-level description - of a language into low level code by building on "abstract interpretation" and - PyPy's separation of the interpreter and the object space in particular. -- D05.2 Release a compiled, self-contained modular static version of PyPy. -- D05.3 Publish solutions and open challenges regarding the implementation of - memory management/threading models as translation aspects. -- D05.4 Publish an overview paper about the success of encapsulating low level - language aspects as well defined parts of the translation phase. - -.. include:: wp-tableend.asc -.. include:: wp-tablebegin.asc - -**Milestones and Expected Result** - -- M1 Complete implementation of the Python language, conforming to the - language definition and passing all language compliancy [*]_ tests of - the official Python test suite. - -- Research Results on encapsulating low level language aspects as parts - of a translation from very-high-level into low-level code. - -.. [*] Some of the the many hundred CPython language tests actually test - implementation details like e.g. memory management. The exact line - between a language feature and an implementation detail is at times - hard to draw. In case of doubt the original CPython developers will - be consulted for clarification. - -.. include:: wp-tableend.asc Deleted: /pypy/funding/B6.7.wp06_core_optimisations.txt ============================================================================== --- /pypy/funding/B6.7.wp06_core_optimisations.txt Thu Mar 17 10:56:00 2005 +++ (empty file) @@ -1,79 +0,0 @@ -.. include:: crossreferences.asc - -.. |title| replace:: Core Optimisations -.. |wp| replace:: WP06 -.. |start| replace:: 9 -.. |p1| replace:: USH -.. |m1| replace:: 12 -.. |p2| replace:: DFKI -.. |m2| replace:: 1 -.. |p3| replace:: |e| -.. |m3| replace:: |e| -.. |p4| replace:: |e| -.. |m4| replace:: |e| -.. |p5| replace:: |e| -.. |m5| replace:: |e| -.. |p6| replace:: |e| -.. |m6| replace:: |e| - -.. include:: wp-toptable.asc - -.. include:: wp-tablebegin.asc - -**Objectives** - -Building upon the efficiency and flexibility of the code base -developed in WP04_, investigate and compare alternative designs and -implementations. - -.. include:: wp-tableend.asc -.. include:: wp-tablebegin.asc - -**Description of work** - -**Task 1** - -Provide alternative implementations of the core objects, -such as dictionaries, strings and integers, with different -trade-offs (speed, size, limitations). Collect existing -techniques from the literature and research new ones. - -Identify other performance-critical parts of the PyPy source -and provide alternative implementations (new or from the -literature). - -**Task 2** - -Run performance tests on the above, comparing the different -implementation decisions for a range of platforms and -applications. -Categorize into overall improvement, platform, and application dependency. -Produce and publish reports on the results. - -**Task 3** - -Merge the results back into the optimisation effort. -Where necessary, define heuristics to select implementations -and to switch between them, depending on evolving runtime conditions. -Collect existing heuristics from the literature and research new ones. -Report on the results and submit as publications. - -.. include:: wp-tableend.asc -.. include:: wp-tablebegin.asc - -**Deliverables** - -- D06.1 Integrate the first core optimisation results into the PyPy core - at the end of phase 2 -- D06.2 Publication and analysis of performance statistics for different - implementations of core objects -- D06.3 Publication of novel heuristic techniques - -.. include:: wp-tableend.asc -.. include:: wp-tablebegin.asc - -**Milestones and Expected Result** - -- Measurably better performance for non-trivial programs. - -.. include:: wp-tableend.asc Deleted: /pypy/funding/B6.7.wp07_translator_optimisations.txt ============================================================================== --- /pypy/funding/B6.7.wp07_translator_optimisations.txt Thu Mar 17 10:56:00 2005 +++ (empty file) @@ -1,92 +0,0 @@ -.. include:: crossreferences.asc - -.. |title| replace:: Translator Optimisations -.. |wp| replace:: WP07 -.. |start| replace:: 9 -.. |p1| replace:: DFKI -.. |m1| replace:: 15 -.. |p2| replace:: USH -.. |m2| replace:: 3 -.. |p3| replace:: |e| -.. |m3| replace:: |e| -.. |p4| replace:: |e| -.. |m4| replace:: |e| -.. |p5| replace:: |e| -.. |m5| replace:: |e| -.. |p6| replace:: |e| -.. |m6| replace:: |e| - -.. include:: wp-toptable.asc - -.. include:: wp-tablebegin.asc - -**Objectives** - -Identification and Implementation of Optimisations -through modifications of the Translator. -Enable Massive Parallelism in a Single Thread. -Provide support for soft-real-time parallelism. -Allow Pickling of a Running Program. - -.. include:: wp-tableend.asc -.. include:: wp-tablebegin.asc - -**Description of work** - -**Task 1** - -Implement memory-efficient massive parallelism complementing -the threads based on C stack switching provided by OSes or -semi-OS-independent libraries. - -- Enhance the translator to support continuation passing - style by integrating technology from the Stackless project. - -- Implement the necessary runtime system to support - massive parallelism Minimize the resource footprint of - each "microthread". - -- To complement explicit (application-defined) scheduling, - implement a pre-emptive scheduler at the bytecode level, - with priorities, distributing "microthreads" to one or a - small number of OS threads. - -- Implement pickling a running program or a selected microthread - (i.e. serializing continuations). - -**Task 2** - -Use PyPy as a research tool for general optimisations. - -- Study approaches concerning code size vs. speed trade-offs. - -- Implement and compare different object layout and memory management - strategies. Implement schemes of pointer tagging. - -- Enhance multimethod dispatching and other places where hand-crafted - optimisations can help the translator. - -- Create reports and merge the results back into the optimisation effort. - As of general interest, submit the reports as publication. - -.. include:: wp-tableend.asc -.. include:: wp-tablebegin.asc - -**Deliverables** - -- D07.1 Release a version of PyPy that supports automatic or explicitly - scheduled massive parallelism -- D07.2 Publish optimisation results -- D07.3 Report about practical usages of massive parallelism and program pickling -- D07.4 Report on approaches for memory management, object implementations - and other translator aspects for high performance PyPy - -.. include:: wp-tableend.asc -.. include:: wp-tablebegin.asc - -**Milestones and Expected Result** - -- M2 High performance PyPy, together with WP08_. Outperform the - state-of-the art (Psyco, Stackless). - -.. include:: wp-tableend.asc Deleted: /pypy/funding/B6.7.wp08_dynamic_optimisation.txt ============================================================================== --- /pypy/funding/B6.7.wp08_dynamic_optimisation.txt Thu Mar 17 10:56:00 2005 +++ (empty file) @@ -1,93 +0,0 @@ -.. include:: crossreferences.asc - -.. |title| replace:: Dynamic Optimisations -.. |wp| replace:: WP08 -.. |start| replace:: 9 -.. |p1| replace:: STRAKT -.. |m1| replace:: 17 -.. |p2| replace:: USH -.. |m2| replace:: 6 -.. |p3| replace:: DFKI -.. |m3| replace:: 2 -.. |p4| replace:: |e| -.. |m4| replace:: |e| -.. |p5| replace:: |e| -.. |m5| replace:: |e| -.. |p6| replace:: |e| -.. |m6| replace:: |e| - -.. include:: wp-toptable.asc - -.. include:: wp-tablebegin.asc - -**Objectives** - -Enhance PyPy to dynamically adapt to its run-time environment and -to the characteristics of the running program. Dramatically -increase speed by enabling Just-In-Time compilation and -specialization. Address multiple processor architectures. - -.. include:: wp-tableend.asc -.. include:: wp-tablebegin.asc - -**Description of work** - -**Task 1** - -Make a Just-In-Time compiler for the PyPy framework. - -- Apply and enhance techniques from the Psyco project. - Combine them with the static type inference techniques implemented - in WP05_. - -- Leverage the static translator to generate instrumenting and - self-specializing code for all the parts of the PyPy interpreter - and standard Object Space that support possibly time-critical - application code. - -- Implement the run-time management environment to support the JIT - compiler (in-memory machine code and supporting data structures, - profiling and statistics collection, etc). - -**Task 2** - -Make the JIT compiler flexible and portable. - -- Enable dynamic foreign function calls. Allow language users to - use them in their applications. Collaborate strongly with - core developers from the ctypes and SWIG open source projects. - -- Design and implement a back-end component for dynamically emitting - machine code for multiple processor architectures. - -**Task 3** - -Research optimisation heuristics for the Just-In-Time compiler. - -- Research by comparing existing and novel techniques for JIT - compilers heuristics, management issues, etc. - -- Coordinate with WP06_. - -.. include:: wp-tableend.asc -.. include:: wp-tablebegin.asc - -**Deliverables** - -- D08.1 A processor back-end supporting Intel(tm) i386 -- D08.2 A processor back-end supporting PowerPC -- D08.3 Release A Just-In-Time compiler for PyPy -- D08.4 Publish a report about the new JIT architecture, its perfomance and how its - techniques can be applied to languages other than Python/PyPy -- D08.5 Publish a research report comparing JIT techniques - -.. include:: wp-tableend.asc -.. include:: wp-tablebegin.asc - -**Milestones and Expected Result** - -- M2 High performance PyPy, together with WP07_. Outperform the - state-of-the art (Psyco, Stackless). Verify the expectation - of reaching half the speed of C for purely algorithmic code. - -.. include:: wp-tableend.asc Deleted: /pypy/funding/B6.7.wp09_search_and_logic.txt ============================================================================== --- /pypy/funding/B6.7.wp09_search_and_logic.txt Thu Mar 17 10:56:00 2005 +++ (empty file) @@ -1,80 +0,0 @@ -.. include:: crossreferences.asc - -.. |title| replace:: Extend Language with Search and Logic -.. |wp| replace:: WP09 -.. |start| replace:: 9 -.. |p1| replace:: DFKI -.. |m1| replace:: 10 -.. |p2| replace:: Logilab -.. |m2| replace:: 9 -.. |p3| replace:: |e| -.. |m3| replace:: |e| -.. |p4| replace:: |e| -.. |m4| replace:: |e| -.. |p5| replace:: |e| -.. |m5| replace:: |e| -.. |p6| replace:: |e| -.. |m6| replace:: |e| - -.. include:: wp-toptable.asc - -.. include:: wp-tablebegin.asc - -**Objectives** - -Leveraging PyPy flexibility implement language-integrated constraint -satisfaction algorithms and inference engine to allow logic -programming for Semantic Web applications developed at Logilab and DFKI. - -.. include:: wp-tableend.asc -.. include:: wp-tablebegin.asc - -**Description of work** - -**Task 1** - -Using the flexible architecture provided by the PyPy interpreter, we -will first reimplement the current python-logic libraries available -from Logilab to better integrate with the language and gain important -execution speed-ups. - -**Task 2** - -We will investigate alternative implementation techniques to improve the -efficiency of the search component. These will build on ideas from -constraint languages such as Oz/Mozart and, where appropriate, will take -advantage of the new avenues for implementation opened up by the object -space architecture. - -**Task 3** - -This logic programming enabled Python interpreter will then be used to -support frameworks for Semantic Web applications that are on-going at -Logilab and DFKI and which are related to RDF-based approaches to -knowledge representation. - -.. include:: wp-tableend.asc -.. include:: wp-tablebegin.asc - -**Deliverables** - -- D09.1 Initial implementation of constraint satisfaction engine and - inference engine based on Logilab's library. - -- D09.2 Improved implementation of constraint satisfaction engine and - inference engine in PyPy. Benchhmarks will be provided, to measure - performance improvements. - -- D09.3 Assessment of benefits obtained from using PyPy over current tools - to further develop Semantic Web projects at Logilab and DFKI, accompanied - by appropriate code examples. - -.. include:: wp-tableend.asc -.. include:: wp-tablebegin.asc - -**Milestones and Expected Result** - -- Python interpreter exhibiting logic-programming features, such as - inference and constraint satisfaction. - -.. include:: wp-tableend.asc Deleted: /pypy/funding/B6.7.wp10_aspects_and_contracts.txt ============================================================================== --- /pypy/funding/B6.7.wp10_aspects_and_contracts.txt Thu Mar 17 10:56:00 2005 +++ (empty file) @@ -1,101 +0,0 @@ -.. include:: crossreferences.asc - -.. |title| replace:: Extend Language with Aspects and Contracts -.. |wp| replace:: WP10 -.. |start| replace:: 9 -.. |p1| replace:: Logilab -.. |m1| replace:: 9 -.. |p2| replace:: DFKI -.. |m2| replace:: 3 -.. |p3| replace:: |e| -.. |m3| replace:: |e| -.. |p4| replace:: |e| -.. |m4| replace:: |e| -.. |p5| replace:: |e| -.. |m5| replace:: |e| -.. |p6| replace:: |e| -.. |m6| replace:: |e| - -.. include:: wp-toptable.asc - -.. include:: wp-tablebegin.asc - -**Objectives** - -Leveraging PyPy flexibility implement aspect-oriented programming, -design-by-contract and advanced static checking capabilities. - -.. include:: wp-tableend.asc -.. include:: wp-tablebegin.asc - -**Description of work** - - -**Task 1** - -Using the flexible architecture provided by the PyPy interpreter, -we will first reimplement the current aspect-oriented libraries -available from Logilab, to better integrate with the language -and greatly simplify the design and enhance the performance. - -Aspect-Oriented Programming is a technique that improves on -Object-Oriented Programming by facilitating the division of -concerns in the implementation of classes. Some behaviors -may be made into aspects that are later weaved with the existing -implementation of classes for which one wants to add the aspect's -behavior. An example would be a Logger aspect weaved with a -class to provide logging functionnality without the class -having any knowledge of logging. - -Logilab already published an implementation of aspects for Python, -but it is limited by the language in the sense that weaving code consists -of wrapping methods instead of actually producing new code or -modifying existing code. This adds overhead and other constraints -that would be removed with a PyPy-based implementation. Once the -equivalent of Logilab's aspect library will be implemented in PyPy, -further progress will be made using articles and research tools from -wwww.aosd.net, the aspect-oriented software development community and -research portal. - -**Task 2** - -Implement design-by-contract using the aspect-enabled interpreter. - -Design-by-contract, as first exhibited by the Eiffel object-oriented -programming language, can be implemented as a specific aspect as -was done by Logilab in its aspect library. A PyPy-based implementation -would allow for further experiments in terms of syntax improvements -on the contract definition, but also better performance. - -**Task 3** - -Implement advanced static checking and code correctness checking capabilities, -thus furthering the work done with the pychecker and pylint tools. - -Static checking tools for Python already exist, but still have difficulties -at the moment when it comes to type checking and inference. The implementation -of static checking in PyPy will benefit from PyPy's runtime optimisation -mechanism based for part on type inference, but also from articles describing -the implementation of type checking and type inference for other languages -and from existing implementations of pychecker and Logilab's pylint tools. - -.. include:: wp-tableend.asc -.. include:: wp-tablebegin.asc - -**Deliverables** - -- D10.1 Implementation of aspect-oriented programming capabilities in PyPy - -- D10.2 Implementation of design-by-contract in PyPy - -- D10.3 Implementation of advanced static checking capabilities - -.. include:: wp-tableend.asc -.. include:: wp-tablebegin.asc - -**Milestones and Expected Result** - -- Python interpreter exhibiting aspect-oriented programming, - design-by-contract and advanced static checking capabilities. - -.. include:: wp-tableend.asc Deleted: /pypy/funding/B6.7.wp11_embed_in_hardware.txt ============================================================================== --- /pypy/funding/B6.7.wp11_embed_in_hardware.txt Thu Mar 17 10:56:00 2005 +++ (empty file) @@ -1,63 +0,0 @@ -.. include:: crossreferences.asc - -.. |title| replace:: Embed in Specialized Hardware -.. |wp| replace:: WP11 -.. |start| replace:: 9 -.. |p1| replace:: Logilab -.. |m1| replace:: 5 -.. |p2| replace:: CM -.. |m2| replace:: 1 -.. |p3| replace:: |e| -.. |m3| replace:: |e| -.. |p4| replace:: |e| -.. |m4| replace:: |e| -.. |p5| replace:: |e| -.. |m5| replace:: |e| -.. |p6| replace:: |e| -.. |m6| replace:: |e| - -.. include:: wp-toptable.asc - -.. include:: wp-tablebegin.asc - -**Objectives** - -Axis Communications (http://www.axis.com/) of Lund, Sweden have shown an interest in -how PyPy could be implemented on their hardware and have specifically asked for information -regarding this part of the PyPy project (WP13).Axis is a -world leading company in printer servers and network video products. -Change Maker, who have an ongoing relation with the company will be an -interface between Axis. - -The objective is to write a specific report targeting embedded software companies with the results from WP13_ -(usage of PyPy custom version and the build- and configuration tool).This report will showcase -usage with Axis hardware as an example. - -.. include:: wp-tableend.asc -.. include:: wp-tablebegin.asc - -**Description of work** - -**Task 1** - -Write report to Axis showcasing usage of PyPy custom version. -Report and analyse feedback from Axis regarding content of report. -Communicate to Axis all reports and build tools developed in WP13_. - -.. include:: wp-tableend.asc -.. include:: wp-tablebegin.asc - -**Deliverables** - -- D11.1 Written report to Axis Communication -- D11.2 Documented feedback from Axis Communication - -.. include:: wp-tableend.asc -.. include:: wp-tablebegin.asc - -**Milestones and Expected Result** - -- Dissemination and feedback on the PyPy custom version and the build- and configuration tool - from Axis Communication, a target stakeholder within the embedded sector. - -.. include:: wp-tableend.asc Deleted: /pypy/funding/B6.7.wp12_validations.txt ============================================================================== --- /pypy/funding/B6.7.wp12_validations.txt Thu Mar 17 10:56:00 2005 +++ (empty file) @@ -1,87 +0,0 @@ -.. include:: crossreferences.asc - -.. |title| replace:: Implement Security, Distribution and Persistence -.. |wp| replace:: WP12 -.. |start| replace:: 18 -.. |p1| replace:: STRAKT -.. |m1| replace:: 10 -.. |p2| replace:: USH -.. |m2| replace:: 3 -.. |p3| replace:: |e| -.. |m3| replace:: |e| -.. |p4| replace:: |e| -.. |m4| replace:: |e| -.. |p5| replace:: |e| -.. |m5| replace:: |e| -.. |p6| replace:: |e| -.. |m6| replace:: |e| - -.. include:: wp-toptable.asc - -.. include:: wp-tablebegin.asc - -**Objectives** - -Research and validate the flexibility and accessibility of PyPy by building -experimental prototypes of key middleware features into the language itself, -namely, security, remote execution, and orthogonal persistence. -Publish reports outlining the novel future directions opened up by the PyPy -architecture, building on the experimental support provided. - -.. include:: wp-tableend.asc -.. include:: wp-tablebegin.asc - -**Description of work** - -**Task 1** - -Build an experimental prototype on security by controlling the individual -operations performed by a non-trusted program. -Coordinate with WP14_ and consult with researchers from the IBM Zurich -Research Lab in particular as to which level of control is needed. -Report on the novel future directions. - -**Task 2** - -Build support for transparent remote proxying at the language level. -Look up existing libraries. Typical libraries like the Zope Enterprise -Objects (ZEO) or CORBA/Java RMI models require programs to be aware of -the remote execution model; by contrast, experimentally build the support -for an equivalent functionality directly into the language. Collaborate -with existing open source projects. Report on the novel future directions. - -**Task 3** - -Build persistence at the language level by implementing an -orthogonally persistent object space for Python programs. -Look up existing libraries. Persistence is never fully orthogonal without -advanced language support, as witnessed by libraries like the Zope Database -(ZODB); we will build an experimental object space that can provide full -orthogonally. Collaborate with ZODB and PyPersyst developer communitiies. -Report on the novel future directions. - -.. include:: wp-tableend.asc -.. include:: wp-tablebegin.asc - -**Deliverables** - -- D12.1 An experimental prototype supporting security through control of - individual operations at the language level. - -- D12.2 An experimental prototype supporting transparent remote proxying - at the language level. - -- D12.3 An experimental prototype supporting orthogonal persistence - at the language level. - -- D12.4 Publish a report outlining the novel future directions opened up by - the PyPy architecture in middleware features. - -.. include:: wp-tableend.asc -.. include:: wp-tablebegin.asc - -**Milestones and Expected Result** - -- M3 Validation of the flexibility of PyPy with respect to key middleware requirements - -.. include:: wp-tableend.asc Deleted: /pypy/funding/B6.7.wp13_integration_config.txt ============================================================================== --- /pypy/funding/B6.7.wp13_integration_config.txt Thu Mar 17 10:56:00 2005 +++ (empty file) @@ -1,75 +0,0 @@ -.. include:: crossreferences.asc - -.. |title| replace:: Integration and Configuration -.. |wp| replace:: WP13 -.. |start| replace:: 18 -.. |p1| replace:: DFKI -.. |m1| replace:: 8 -.. |p2| replace:: Logilab -.. |m2| replace:: 4 -.. |p3| replace:: |e| -.. |m3| replace:: |e| -.. |p4| replace:: |e| -.. |m4| replace:: |e| -.. |p5| replace:: |e| -.. |m5| replace:: |e| -.. |p6| replace:: |e| -.. |m6| replace:: |e| - -.. include:: wp-toptable.asc - -.. include:: wp-tablebegin.asc - -**Objectives** - -Integrate research and the source code from wp06_, wp07_, wp08_, wp09_ and wp10_. -Analyse remaining problems. Develop tools that will allow to chose from available -features and runtime restrictions to build a custom PyPy version. - -.. include:: wp-tableend.asc -.. include:: wp-tablebegin.asc - -**Description of work** - -**Task 1** - -Analyse and integrate all results from the results of other workpackages. - -- Provide a consistent and combined code base for translation aspects, - the JIT-compiler and language extensions - -- assert benefits and open problems regarding interaction between - the different translation and language extension aspects. - -- write a report about the combined PyPy code base. - -**Task 2** - -Implement user interfaces to select features and runtime restrictions. - -- Provide a way to automatically build a PyPy custom version for different - memory, performance and extension requirements. - -- Research and select defaults for environments with large and with - small amounts of system resources. - -.. include:: wp-tableend.asc -.. include:: wp-tablebegin.asc - -**Deliverables** - -- D13.1 A release of PyPy with all available optimisation and runtime features -- D13.2 A build- and configuration tool that allows to build custom PyPy versions suitable for specialized environments like small or very large computing devices -- D13.3 A publication about the combined PyPy code base and its - customization possibilities. - -.. include:: wp-tableend.asc -.. include:: wp-tablebegin.asc - -**Milestones and Expected Result** - -- A stable release of PyPy enabling a wide range of language users to - experiment and develop using it as a flexible and highly-optimizable - Python implementation. - -.. include:: wp-tableend.asc Deleted: /pypy/funding/B6.7.wp14_documentation.txt ============================================================================== --- /pypy/funding/B6.7.wp14_documentation.txt Thu Mar 17 10:56:00 2005 +++ (empty file) @@ -1,124 +0,0 @@ -.. include:: crossreferences.asc - -.. |title| replace:: Documentation and Dissemination -.. |wp| replace:: WP14 -.. |start| replace:: 0 -.. |p1| replace:: CM -.. |m1| replace:: 11 -.. |p2| replace:: DFKI -.. |m2| replace:: 12 -.. |p3| replace:: |e| -.. |m3| replace:: |e| -.. |p4| replace:: |e| -.. |m4| replace:: |e| -.. |p5| replace:: |e| -.. |m5| replace:: |e| -.. |p6| replace:: |e| -.. |m6| replace:: |e| - -.. include:: wp-toptable.asc - -.. include:: wp-tablebegin.asc - -**Objectives** - -Providing ongoing documentation throughout the whole project. -Supporting the dissemination process at all levels. Analysis of "Sprint -driven development" and the agile development methods of the project. -Report to the Commission in collaboration with the PyPy consortium. - -.. include:: wp-tableend.asc -.. include:: wp-tablebegin.asc - -**Description of work** - -**Task 1** - -Support the dissemination process at all levels. - -- Write, disseminate and archive reports about each development sprint and - produce newsletter - -- Gathering feedback from participants, present a detailed joint report - about agile methodologies employed by the project. - -- Ensure that all reports and publications that are being produced as part of - workpackages 1-14 are effectively disseminated to - python and non-python communities. - -**Task 2** - -Provide longer, detailed reports to the commission and scientific committees -advising the Commission on technical and agile development issues. - -**Task 3** - -When the advancement of the project warrants it, publish "popularization" -articles and tutorial materials to help other practitioners of software -development to make practical use of the project's results. - -- Diagrams and schematics will be provided to illustrate fundamental - concepts, as appropriate to the audience and the subject matter. - -- Tutorials will be published on the web site and disseminated to - various communities - -- Utilizing tools from WP02_ a guide through the source code of PyPy - will be provided. - -**Task 4** - -Prepare and organize workshops with special interested groups at all -levels (the PyPy interpreter, the build toolchain to create custom -interpreters, third-party language extensions or alternate languages, -and theoretical aspects). Take part in conferences. -Interact with various python and non-python communities. - -- For example, Reseachers at the IBM Zurich Resarch lab have shown - interest in our work and volunteered to discuss and peer-review our - published results. We plan to present our security findings during a - joint workshop and solicit non-confidential input from the research - group on Identity Management and Privacy (Dr. Matthias Schunter). - -- Generally reach out to companies and research groups inside and - outside the python community by organizing workshops to disseminate - project results and gather feedback with respect to our novel language - architecture. 2 specific workshops will be arranged in this manner - (during phase 1 and at the end of phase 3). - -- organize Workshops during the course of the PyPy STREP to allow for - adaptation of detail planning on specific feedback issues from - specific target groups (industrial companies, game developing - companies and SME:s). - -.. include:: wp-tableend.asc -.. include:: wp-tablebegin.asc - -**Deliverables** - -- D14.1 Report about Milestone/Phase 1 -- D14.2 Tutorials and a guide through the PyPy source code -- D14.3 Report about Milestone/Phase 2 -- D14.4 Report about Milestone/Phase 3 -- D14.5 Documentation of the development process and "Sprint driven development" in particular -- D14.6 Organize four domain specific Workshops during phase 3 with various business and research - communities. Reports about these workshops. -- D14.7 Arrange two nondomain specific workshops disseminating development process - and results (during phase 1 and phase 3) -- D14.8 Participation of PyPy researchers and developers in conferences - throughout the project process. - -.. include:: wp-tableend.asc -.. include:: wp-tablebegin.asc - -**Milestones and Expected Result** - -Good documentation and dissemination to multiple business and research -communities through promotion, workshops and conference. -Useful feedback on the practical flexibility of our language research efforts. - -A better understanding how research and development can be accelerated -through agile methodologies and "Sprint Driven Development" and how the -PyPy project achieved its goals. - -.. include:: wp-tableend.asc Deleted: /pypy/funding/B7.0_other_issues.txt ============================================================================== --- /pypy/funding/B7.0_other_issues.txt Thu Mar 17 10:56:00 2005 +++ (empty file) @@ -1,290 +0,0 @@ -Other Issues -============ -Ethical Considerations ----------------------- -A. Proposers are requested to fill in the following table - -Does your proposed research raise sensitive ethical questions related to: - -+--------------------------------------------------------------------+------+ -| Human beings | No. | -+--------------------------------------------------------------------+------+ -| Human biological samples | No. | -+--------------------------------------------------------------------+------+ -| Personal data (whether identified by name or not) | No. | -+--------------------------------------------------------------------+------+ -| Genetic information | No. | -+--------------------------------------------------------------------+------+ -| Animals | No. | -+--------------------------------------------------------------------+------+ - - -B. Proposers are requested to confirm that the proposed research does not - involve: - -+--------------------------------------------------------------------+------+ -| Research activity aimed at human cloning for reproductive purposes| No. | -+--------------------------------------------------------------------+------+ -| Research activity intended to modify the genetic heritage of human| | -| beings which could make such changes heritable. | No. | -+--------------------------------------------------------------------+------+ -| Research activity intended to create human embryos solely for the | | -| purpose of research or for the purpose of stem cell procurement | | -| including by means of somatic cell nuclear transfer; | No. | -+--------------------------------------------------------------------+------+ -| Research involving the use of human embryos or embryonic stem | | -| cells with the exception of banked or isolated human embryonic | | -| stem cells in culture | No. | -+--------------------------------------------------------------------+------+ -|Confirmation : the proposed research involves none of the issues | | -|listed in section B | YES.| -+--------------------------------------------------------------------+------+ - -There are however, other ethical issues which reflect the philosophy -of the Open Source Community. We believe that it is unethical to -withold the source of fundamental tools upon with other people rely. -When a tool that is critical to your business or your daily life -fails, it becomes vital for you to get it fixed. Either you can fix -it yourself, or you can pay somebody else to fix it for you. If that -vital tool is proprietary, then you are immediately stuck in a Market -situation. If the only people who can fix the tool work for high -wages in a country with a high standard of living, then all their -dependent customers who live in poorer conditions are at a -disadvantage, often an unsurmountable one. For lack of the financial -resources to pay for needed fixes, small businesses fail or produce -software that performs poorly in the marketplace, riddled with bugs -that cannot be addressed. This, in turn, prevents those poorer -companies from attaining success. They are marginalised, all -unintentionally, by the normal workings of the Market. They become -a second-tier 'user' of the product, dependent on their software -provider to 'do the right thing', even though 'the right thing' -may vary enormously from region to region. - -Thus, when you deny people the option of being able to 'do it yourself' you -contribute to the forces in society which produce wealth-based social -differentiation and segregation. 'The rich get richer and the poor -get poorer'. A compiler is an extremely fundamental tool which one uses -to create any sort of software which one can think of. This is precisely -the sort of tool that must be freely available to the rich as well as -the poor, in all its entirity. The poorer nations will then be in a -non-dependent situation. As they use their imaginations and creativity -and labour to increase their own personal standard of living and that -of the communities where they live, they will have one fewer thing to -worry about -- what will I do if my compiler has a bug? - -Gender Issues -------------- - -Women are chronically (and increasingly) underrepresented in the computer -field; particularly among designers of software and products. - -Studies [1]_ [2]_ have shown several factors involved in this gender gap, among -them: - - - Lack of experience with computers leading to avoidance of CS as a field of study or employment. - - Interest in "computing for a purpose" rather than "programming for programming sake" - - Focus on usability and usefulness - -PyPy addresses these concerns in the following ways: - - Allowing the creation of mobile devices which are easily - programmed will increase women's successful experiences with - computers, thus increasing their comfort level and likelihood of - pursuing education and careers in computers. The ease of - creating programs due to PyPy's simple but powerful language will - allow women to incorporate programming in pursuit of their - interests. The user-friendly, interactive interfaces available - will attract more women into programming and designing software. - - As more women bring their viewpoints to the design-process, - better products in terms of meeting the needs of a broader number - of people will be created and increase the appeal of the products - among women, which in turn will encourage women to use and - familiarize themselves with the new technologies. - - Furthermore, the increase in economic and educational - opportunities afforded in the CS fields must not be - ignored. Studies have shown that, while women who do enter CS - enter with less experience, they demonstrate no less ability than - their male counterparts. By breaking down the barriers to entry - noted above, PyPy will help lessen the gender gap, - technologically, socially and economically. - -As an example of the benificial effects that Python already has on -introducing women to the field of programming, the Georgia Institute -of Technology teaches a course for non-Computer Science majors which -focuses on media, rather than the traditional math-oriented -model. This is the Abstract of the paper [3]_ describing the course: - - Computing may well become considered an essential part of a - liberal education, but introductory programming courses will not - look like the way that they do today. Current CS1 course are - failing dramatically. We are developing a new course, to be - taught starting in Spring 2003, which uses com- putation for - communication as a guiding principle. Students learn to program - by writing Python programs for manipu- lating sound, images, and - movies. This paper describes the course development and the - tools developed for the course. - -While only 3 out of 14 expected participants in the project are -female, this merely reflects the poor state of gender equality in the -field of programming. Indeed, the ratio in this project is actually -more than twice of what is normal. - -.. [1] Becoming a computer scientist: a report by the ACM committee on the status of women in computing science. - Authors: Pearl, Amy; Pollack, Martha E.; Riskin, Eve; Thomas, Becky; Wolf, Elizabeth; Wu, Alice. - Journal: Communications of the ACM, Nov. 1990, v33, n11, p47-58. - -.. [2] Unlocking the Clubhouse: Women in Computing - Allan Fisher and Jane Margolis, PIs - School of Computer Science - Carnegie Mellon University - MIT Press, 2002, ISBN 0262133989. - -.. [3] http://coweb.cc.gatech.edu/mediaComp-plan/uploads/37/ITICSE-mediacomp2.pdf - -Safety Issues ----------------- - -Nobody who uses a computer can avoid noticing how viruses, unsolicited -email and computer attacks have made life difficult for computer -users. While PyPy is unable to solve such problems, it may mitigate -them. There are 3 factors that affect this: - -1. The ease of writing Python programs give the developers more time - to consider security implications. - -2. Python as a language has built in checks against buffer overflows - and other classic problems that make traditional languages like C - and C++ prone to attacks. By improving Python performance, a larger - set of programs will be immune to such exploits. - -3. PyPy provides the tools for adding specialised security features to - the language, in the form of new Object Spaces. This allows - applications where security is paramount to add checks and - partitioning that will significantly strengthen the defenses. As - far as we know, no other language has this feature. - -Other Policy Related Issues ---------------------------- - -As we mentioned before, one of the greatest threats to European -competitiveness is its dependence upon proprietary closed source -software, mostly made in the United States. The short-term threat of -dependedence upon your supplier was already discussed in section 3. - -There is another threat, which is more insidious, and more long term. -**A good workman knows his tools**. This is much more than the -theoretical knowledge of how his tools ought to work, according to -principles learned in school. The way car mechanics know how cars -work is distinctly different from what you would know if you had -attended classes on 'the principles of the internal combustion -engine'. - -Right now, in Europe, we don't have enough of the software equivalents -of car-mechanics. And most of them live in academia, where they know -the intimate details of languages that never get used in industrial -applications. They are the Formula-One race car mechanics of the -software world. While race car mechanics do serve a useful purpose, -we have a much greater need for people who know how to repair the -family car. - -It is not as if there is a shortage of people who would be interested -in learning such things, if the source were made available. Many -people have taken this step by learning how CPython does its stuff. -But still there is a barrier. If you want to know how CPython does -things, you need to learn C. C is a notoriously difficult language to -learn. - -But let us quote an article posted to the Python-in-Education -mailing list in its entirity:: - - Date: Sun, 14 Sep 2003 11:52:05 -0400 - From: Arthur - To: edu-sig at python.org - Subject: [Edu-sig] re : If the PyPy Project ... - - List-Id: Python in education - - Terry - - - >Since I presume the goal of PyPy is to implement *Python* in Python, - >wouldn't the implementation language be rather insignificant to an - >end-user such as an educator? Why would it be "better" than CPython? - - For whatever reason, the complex built_in and the cmath module, implemented - in Python, are part of the early PyPy codebase. As I had been spending some - time in the complex realm with PyGeo - a simple version of the complex - realm, as these things go - Laura's post gave me the impetus to try to - plugin the PyPy implementations. - - Only got stuck on the typing issue. My code tests for - instance(object,complex). The PyPy complexobject, unadorned, is a class - - and fails the test. But that leads me into a deeper look at some of the - PyPy codebase, trying to understand a little bit of how this kind of issue - are to be dealt with. Not that I got there, yet - but I did seem to have an - avenue to explore I would not have with CPython - as someone who doesn't C, - and has no intention of trying, seriously, to do so. - - As someone living within the limits of having Python as my only real - language, I think that PyPy should open things up for me considerably. It - will make Python, I believe, a more attractive educational language, because - it will make someone with a strong foundation in Python - as the language of - choice - a more self-sufficient programmer. - - Presumably - the point is - there will be less cases where the right - approach would be an extension module in C or C++, and a sense of - fundamental compromise should one not be equipped to go there. Many - thousands of folks - using VB and the like - already do involved, - highly performing real world applications and make nice livings doing - so, without being equipped to do C. I am thinking that PyPy would put - Python more squarely in that "space". - - Is any of this so, or just hope? - - Art - -Here is somebody who is hoping we can give him a language he can -understand and use without learning C. He is the author of PyGeo, a -dynamic geometry laboratory and toolkit, commonly used by elementary -and high school teachers. This is where the future lies. Python is -already an excellent teaching language. PyPy will be a better one. - -Thus PyPy comes full circle, and back to Python's original heritage, -as a language that was designed to be 'easy to use' for -non-programmers. In the appendix, a proposal *Computer Programming -For Everybody*, written in 1999 by Guido van Rossum, Python's creator, -is as relevant now as when it was written. To summarise: - -Python's predecessor, ABC, was designed at CWI in the early eighties -as a teaching language. Its motto was "stamp out Basic" -- the main -competition in languages for non-experts at the time. ABC's designers -had a lot of experience teaching traditional programming languages -like ALGOL to novices. They discovered that students were often so -overwhelmed by the incidental details of using a computer language -they never managed to focus on good program and algorithm design. - -ABC's designers therefore set out to design a language that would take -care of all the incidentals, leaving the student more time to learn -about programming, and not the chore of 'how to use a computer'. They -proposed both a new language design and new terminology that deviated -radically from what was (and still is) current among computer -scientists and programmers. This proved to be a barrier towards -widespread adoption. ABC was too different. People actually wanted a -language which was more like other languages, not one that simply -didn't relate to what programmers would be doing the rest of their -lives. Thus ABC remained a teaching language, and nothing more. - -About a decade later, Python grew out of this frustration. It shares -ABC's focus on elegance of expression, fundamentals of programming, -and taking away incidentals, but adds the modern tools that programmers -have come to expect, such as object-orientation, and a large and -powerful standard library. - -The PyPy project, being a focused STREP, does not intend to address -the problem of 'Computer Literacy' and 'Computer Programming For -Everybody'. But we believe that these problems would make an -excellent candidate for a Python-related Specific Supporting Action, -and we would make every effort to aid and assist such an action should -the Commission call for it. - Deleted: /pypy/funding/negotiations/part_b_2004_04_02.pdf ============================================================================== Binary file. No diff available. Deleted: /pypy/funding/negotiations/part_b_2004_04_02.sxw ============================================================================== Binary file. No diff available. Deleted: /pypy/funding/negotiations/part_b_2004_07_22.sxw ============================================================================== Binary file. No diff available. Deleted: /pypy/funding/negotiations/part_b_2004_07_22_individual.sxw ============================================================================== Binary file. No diff available. Deleted: /pypy/funding/negotiations/part_b_2004_07_29.pdf ============================================================================== Binary file. No diff available. Deleted: /pypy/funding/negotiations/part_b_2004_07_29.sxw ============================================================================== Binary file. No diff available. From arigo at codespeak.net Thu Mar 17 12:30:54 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 17 Mar 2005 12:30:54 +0100 (MET) Subject: [pypy-svn] r9848 - pypy/dist/pypy/translator Message-ID: <20050317113054.9FA6127B61@code1.codespeak.net> Author: arigo Date: Thu Mar 17 12:30:54 2005 New Revision: 9848 Added: pypy/dist/pypy/translator/genc_funcdef.py - copied, changed from r9754, pypy/dist/pypy/translator/genc.py Modified: pypy/dist/pypy/translator/genc.h pypy/dist/pypy/translator/genc.py Log: Split genc.py in two files, genc.py and genc_funcdef.py. The latter contains a FunctionDef class whose instances care about a single function. It's slightly less messy now. As a first application, we generate direct C-to-C calls instead of OP_SIMPLE_CALL() when possible. This allows most function to be compiled into a single C function, instead of a C function plus a CPython-API-compatible wrapper. Modified: pypy/dist/pypy/translator/genc.h ============================================================================== --- pypy/dist/pypy/translator/genc.h (original) +++ pypy/dist/pypy/translator/genc.h Thu Mar 17 12:30:54 2005 @@ -16,10 +16,7 @@ static PyObject *this_module_globals; -/* Set this if you want call trace frames to be built */ -#if 0 -#define USE_CALL_TRACE -#endif +/* Set genc_funcdef.USE_CALL_TRACE if you want call trace frames to be built */ #if 0 #define OBNOXIOUS_PRINT_STATEMENTS @@ -177,10 +174,8 @@ #if defined(USE_CALL_TRACE) -#define TRACE_CALL __f, __tstate, -#define TRACE_ARGS PyFrameObject *__f, PyThreadState *__tstate, -#define TRACE_CALL_VOID __f, __tstate -#define TRACE_ARGS_VOID PyFrameObject *__f, PyThreadState *__tstate +#define TRACE_CALL __f, __tstate +#define TRACE_ARGS PyFrameObject *__f, PyThreadState *__tstate #define FAIL(err) { __f->f_lineno = __f->f_code->co_firstlineno = __LINE__; goto err; } @@ -198,19 +193,10 @@ #else /* !defined(USE_CALL_TRACE) */ -#define TRACE_CALL /* nothing */ -#define TRACE_ARGS /* nothing */ -#define TRACE_CALL_VOID /* nothing */ -#define TRACE_ARGS_VOID void - #define FAIL(err) { goto err; } -#define FUNCTION_HEAD(signature, self, args, names, file, line) - #define ERR_DECREF(arg) { Py_DECREF(arg); } -#define FUNCTION_CHECK() - #define FUNCTION_RETURN(rval) return rval; #endif /* defined(USE_CALL_TRACE) */ Modified: pypy/dist/pypy/translator/genc.py ============================================================================== --- pypy/dist/pypy/translator/genc.py (original) +++ pypy/dist/pypy/translator/genc.py Thu Mar 17 12:30:54 2005 @@ -4,20 +4,16 @@ """ from __future__ import generators import autopath, os, sys, __builtin__, marshal, zlib -from pypy.objspace.flow.model import Variable, Constant, SpaceOperation -from pypy.objspace.flow.model import FunctionGraph, Block, Link -from pypy.objspace.flow.model import last_exception, last_exc_value -from pypy.objspace.flow.model import traverse, uniqueitems, checkgraph -from pypy.translator.simplify import remove_direct_loops -from pypy.interpreter.pycode import CO_VARARGS -from pypy.annotation import model as annmodel +from pypy.objspace.flow.model import Variable, Constant from types import FunctionType, CodeType, InstanceType, ClassType -from pypy.translator.gensupp import ordered_blocks, UniqueList, builtin_base, \ - c_string, uniquemodulename, C_IDENTIFIER, NameManager +from pypy.translator.gensupp import builtin_base, uniquemodulename +from pypy.translator.gensupp import NameManager from pypy.objspace.std.restricted_int import r_int, r_uint +from pypy.translator.genc_funcdef import FunctionDef, USE_CALL_TRACE + # ____________________________________________________________ #def go_figure_out_this_name(source): @@ -70,7 +66,8 @@ self.globaldecl = [] self.globalobjects = [] self.pendingfunctions = [] - self.currentfunc = None + self.funcdefs = {} + self.allfuncdefs = [] self.debugstack = () # linked list of nested nameof() self.gen_source() @@ -179,6 +176,14 @@ self.initcode.append(' raise NotImplementedError') return name + def getfuncdef(self, func): + if func not in self.funcdefs: + funcdef = FunctionDef(func, self) + self.funcdefs[func] = funcdef + self.allfuncdefs.append(funcdef) + self.pendingfunctions.append(funcdef) + return self.funcdefs[func] + def nameof_function(self, func, progress=['-\x08', '\\\x08', '|\x08', '/\x08']): printable_name = '(%s:%d) %s' % ( @@ -197,9 +202,8 @@ p = progress.pop(0) sys.stderr.write(p) progress.append(p) - name = self.uniquename('gfunc_' + func.__name__) - self.pendingfunctions.append(func) - return name + funcdef = self.getfuncdef(func) + return funcdef.get_globalobject() def nameof_staticmethod(self, sm): # XXX XXX XXXX @@ -455,12 +459,14 @@ 'entrypoint': self.nameof(self.translator.functions[0]), } # header + if USE_CALL_TRACE: + print >> f, '#define USE_CALL_TRACE' print >> f, self.C_HEADER # function implementations while self.pendingfunctions: - func = self.pendingfunctions.pop() - self.gen_cfunction(func) + funcdef = self.pendingfunctions.pop() + self.gen_cfunction(funcdef) # collect more of the latercode after each function while self.latercode: gen, self.debugstack = self.latercode.pop() @@ -470,7 +476,12 @@ self.debugstack = () self.gen_global_declarations() - # after all the functions: global object table + # after all the ff_xxx() functions we generate the pyff_xxx() wrappers + for funcdef in self.allfuncdefs: + if funcdef.wrapper_name is not None: + funcdef.gen_wrapper(f) + + # global object table print >> f, self.C_OBJECT_TABLE for name in self.globalobjects: if not name.startswith('gfunc_'): @@ -479,11 +490,13 @@ # global function table print >> f, self.C_FUNCTION_TABLE - for name in self.globalobjects: - if name.startswith('gfunc_'): - print >> f, ('\t{&%s, {"%s", (PyCFunction)f_%s, ' + for funcdef in self.allfuncdefs: + if funcdef.globalobject_name is not None: + print >> f, ('\t{&%s, {"%s", (PyCFunction)%s, ' 'METH_VARARGS|METH_KEYWORDS}},' % ( - name, name[6:], name[6:])) + funcdef.globalobject_name, + funcdef.base_name, + funcdef.wrapper_name)) print >> f, self.C_TABLE_END # frozen init bytecode @@ -534,293 +547,25 @@ del source return marshal.dumps(co) - def gen_cfunction(self, func): + def gen_cfunction(self, funcdef): ## print 'gen_cfunction (%s:%d) %s' % ( ## func.func_globals.get('__name__', '?'), ## func.func_code.co_firstlineno, ## func.__name__) - f = self.f - localscope = self.namespace.localScope() - body = list(self.cfunction_body(func, localscope)) - name_of_defaults = [self.nameof(x, debug=('Default argument of', func)) - for x in (func.func_defaults or ())] - self.gen_global_declarations() - - # print header - cname = self.nameof(func) - assert cname.startswith('gfunc_') - f_name = 'f_' + cname[6:] - - # collect all the local variables - graph = self.translator.getflowgraph(func) - localslst = [] - def visit(node): - if isinstance(node, Block): - localslst.extend(node.getvariables()) - traverse(visit, graph) - localnames = [self.expr(a, localscope) for a in uniqueitems(localslst)] - - # collect all the arguments - if func.func_code.co_flags & CO_VARARGS: - vararg = graph.getargs()[-1] - positional_args = graph.getargs()[:-1] - else: - vararg = None - positional_args = graph.getargs() - min_number_of_args = len(positional_args) - len(name_of_defaults) - - fast_args = [self.expr(a, localscope) for a in positional_args] - if vararg is not None: - vararg = self.expr(vararg, localscope) - fast_args.append(vararg) - fast_name = 'fast' + f_name - - fast_set = dict(zip(fast_args, fast_args)) - - declare_fast_args = [('PyObject *' + a) for a in fast_args] - if declare_fast_args: - declare_fast_args = 'TRACE_ARGS ' + ', '.join(declare_fast_args) - else: - declare_fast_args = 'TRACE_ARGS_VOID' - fast_function_header = ('static PyObject *\n' - '%s(%s)' % (fast_name, declare_fast_args)) - - print >> f, fast_function_header + ';' # forward - print >> f - - print >> f, 'static PyObject *' - print >> f, '%s(PyObject* self, PyObject* args, PyObject* kwds)' % ( - f_name,) - print >> f, '{' - print >> f, '\tFUNCTION_HEAD(%s, %s, args, %s, __FILE__, __LINE__ - 2)' % ( - c_string('%s(%s)' % (cname, ', '.join(name_of_defaults))), - cname, - '(%s)' % (', '.join(map(c_string, name_of_defaults) + ['NULL']),), - ) - - kwlist = ['"%s"' % name for name in - func.func_code.co_varnames[:func.func_code.co_argcount]] - kwlist.append('0') - print >> f, '\tstatic char* kwlist[] = {%s};' % (', '.join(kwlist),) - - if fast_args: - print >> f, '\tPyObject *%s;' % (', *'.join(fast_args)) - print >> f - - print >> f, '\tFUNCTION_CHECK()' - - # argument unpacking - if vararg is not None: - print >> f, '\t%s = PyTuple_GetSlice(args, %d, INT_MAX);' % ( - vararg, len(positional_args)) - print >> f, '\tif (%s == NULL)' % (vararg,) - print >> f, '\t\tFUNCTION_RETURN(NULL)' - print >> f, '\targs = PyTuple_GetSlice(args, 0, %d);' % ( - len(positional_args),) - print >> f, '\tif (args == NULL) {' - print >> f, '\t\tERR_DECREF(%s)' % (vararg,) - print >> f, '\t\tFUNCTION_RETURN(NULL)' - print >> f, '\t}' - tail = """{ -\t\tERR_DECREF(args) -\t\tERR_DECREF(%s) -\t\tFUNCTION_RETURN(NULL); -\t} -\tPy_DECREF(args);""" % vararg - else: - tail = '\n\t\tFUNCTION_RETURN(NULL)' - for i in range(len(name_of_defaults)): - print >> f, '\t%s = %s;' % ( - self.expr(positional_args[min_number_of_args+i], localscope), - name_of_defaults[i]) - fmt = 'O'*min_number_of_args - if min_number_of_args < len(positional_args): - fmt += '|' + 'O'*(len(positional_args)-min_number_of_args) - lst = ['args', 'kwds', - '"%s:%s"' % (fmt, func.__name__), - 'kwlist', - ] - lst += ['&' + self.expr(a, localscope) for a in positional_args] - print >> f, '\tif (!PyArg_ParseTupleAndKeywords(%s))' % ', '.join(lst), - print >> f, tail - - call_fast_args = list(fast_args) - if call_fast_args: - call_fast_args = 'TRACE_CALL ' + ', '.join(call_fast_args) - else: - call_fast_args = 'TRACE_CALL_VOID' - print >> f, '\treturn %s(%s);' % (fast_name, call_fast_args) - print >> f, '}' - print >> f - - print >> f, fast_function_header - print >> f, '{' - - fast_locals = [arg for arg in localnames if arg not in fast_set] - if fast_locals: - print >> f, '\tPyObject *%s;' % (', *'.join(fast_locals),) - print >> f - - # generate an incref for each input argument - for v in positional_args: - print >> f, '\tPy_INCREF(%s);' % self.expr(v, localscope) - - # print the body - for line in body: - if line.endswith(':'): - if line.startswith('err'): - fmt = '\t%s' - else: - fmt = ' %s\n' - elif line: - fmt = '\t%s\n' - else: - fmt = '%s\n' - f.write(fmt % line) - print >> f, '}' + # compute the whole body + body = list(funcdef.cfunction_body()) + + # generate the source now + self.gen_global_declarations() #.. before the body where they are needed + funcdef.gen_cfunction(self.f, body) + # this is only to keep the RAM consumption under control + funcdef.clear() if not self.translator.frozen: - # this is only to keep the RAM consumption under control - del self.translator.flowgraphs[func] + del self.translator.flowgraphs[funcdef.func] Variable.instances.clear() - def expr(self, v, localscope): - if isinstance(v, Variable): - return localscope.localname(v.name) - elif isinstance(v, Constant): - return self.nameof(v.value, - debug=('Constant in the graph of', self.currentfunc)) - else: - raise TypeError, "expr(%r)" % (v,) - - def cfunction_body(self, func, localscope): - graph = self.translator.getflowgraph(func) - remove_direct_loops(graph) - checkgraph(graph) - - blocknum = {} - allblocks = [] - - def gen_link(link, linklocalvars=None): - "Generate the code to jump across the given Link." - has_ref = {} - linklocalvars = linklocalvars or {} - for v in to_release: - linklocalvars[v] = self.expr(v, localscope) - has_ref = linklocalvars.copy() - for a1, a2 in zip(link.args, link.target.inputargs): - if a1 in linklocalvars: - src = linklocalvars[a1] - else: - src = self.expr(a1, localscope) - line = 'MOVE(%s, %s)' % (src, self.expr(a2, localscope)) - if a1 in has_ref: - del has_ref[a1] - else: - line += '\tPy_INCREF(%s);' % self.expr(a2, localscope) - yield line - for v in has_ref: - yield 'Py_DECREF(%s);' % linklocalvars[v] - yield 'goto block%d;' % blocknum[link.target] - - # collect all blocks - def visit(block): - if isinstance(block, Block): - allblocks.append(block) - blocknum[block] = len(blocknum) - traverse(visit, graph) - - # generate the body of each block - for block in allblocks: - yield '' - yield 'block%d:' % blocknum[block] - to_release = list(block.inputargs) - for op in block.operations: - lst = [self.expr(v, localscope) for v in op.args] - lst.append(self.expr(op.result, localscope)) - lst.append('err%d_%d' % (blocknum[block], len(to_release))) - macro = 'OP_%s' % op.opname.upper() - meth = getattr(self, macro, None) - if meth: - yield meth(lst[:-2], lst[-2], lst[-1]) - else: - yield '%s(%s)' % (macro, ', '.join(lst)) - to_release.append(op.result) - - err_reachable = False - if len(block.exits) == 0: - if len(block.inputargs) == 2: # exc_cls, exc_value - # exceptional return block - exc_cls = self.expr(block.inputargs[0], localscope) - exc_value = self.expr(block.inputargs[1], localscope) - yield 'PyErr_Restore(%s, %s, NULL);' % (exc_cls, exc_value) - yield 'FUNCTION_RETURN(NULL)' - else: - # regular return block - retval = self.expr(block.inputargs[0], localscope) - yield 'FUNCTION_RETURN(%s)' % retval - continue - elif block.exitswitch is None: - # single-exit block - assert len(block.exits) == 1 - for op in gen_link(block.exits[0]): - yield op - yield '' - elif block.exitswitch == Constant(last_exception): - # block catching the exceptions raised by its last operation - # we handle the non-exceptional case first - link = block.exits[0] - assert link.exitcase is None - for op in gen_link(link): - yield op - # we must catch the exception raised by the last operation, - # which goes to the last err%d_%d label written above. - yield '' - to_release.pop() # skip default error handling for this label - yield 'err%d_%d:' % (blocknum[block], len(to_release)) - yield '' - for link in block.exits[1:]: - assert issubclass(link.exitcase, Exception) - yield 'if (PyErr_ExceptionMatches(%s)) {' % ( - self.nameof(link.exitcase),) - yield '\tPyObject *exc_cls, *exc_value, *exc_tb;' - yield '\tPyErr_Fetch(&exc_cls, &exc_value, &exc_tb);' - yield '\tif (exc_value == NULL) {' - yield '\t\texc_value = Py_None;' - yield '\t\tPy_INCREF(Py_None);' - yield '\t}' - yield '\tPy_XDECREF(exc_tb);' - for op in gen_link(link, { - Constant(last_exception): 'exc_cls', - Constant(last_exc_value): 'exc_value'}): - yield '\t' + op - yield '}' - err_reachable = True - else: - # block ending in a switch on a value - for link in block.exits[:-1]: - yield 'if (EQ_%s(%s)) {' % (link.exitcase, - self.expr(block.exitswitch, localscope)) - for op in gen_link(link): - yield '\t' + op - yield '}' - link = block.exits[-1] - yield 'assert(EQ_%s(%s));' % (link.exitcase, - self.expr(block.exitswitch, localscope)) - for op in gen_link(block.exits[-1]): - yield op - yield '' - - while to_release: - v = to_release.pop() - if err_reachable: - yield 'ERR_DECREF(%s)' % self.expr(v, localscope) - yield 'err%d_%d:' % (blocknum[block], len(to_release)) - err_reachable = True - if err_reachable: - yield 'FUNCTION_RETURN(NULL)' - # ____________________________________________________________ C_HEADER = '#include "genc.h"\n' @@ -853,46 +598,3 @@ \tSETUP_MODULE(%(modname)s) \tPyModule_AddObject(m, "%(entrypointname)s", %(entrypoint)s); }''' - - # the C preprocessor cannot handle operations taking a variable number - # of arguments, so here are Python methods that do it - - def OP_NEWLIST(self, args, r, err): - if len(args) == 0: - return 'OP_NEWLIST0(%s, %s)' % (r, err) - else: - args.insert(0, '%d' % len(args)) - return 'OP_NEWLIST((%s), %s, %s)' % (', '.join(args), r, err) - - def OP_NEWDICT(self, args, r, err): - if len(args) == 0: - return 'OP_NEWDICT0(%s, %s)' % (r, err) - else: - assert len(args) % 2 == 0 - args.insert(0, '%d' % (len(args)//2)) - return 'OP_NEWDICT((%s), %s, %s)' % (', '.join(args), r, err) - - def OP_NEWTUPLE(self, args, r, err): - args.insert(0, '%d' % len(args)) - return 'OP_NEWTUPLE((%s), %s, %s)' % (', '.join(args), r, err) - - def OP_SIMPLE_CALL(self, args, r, err): - args.append('NULL') - return 'OP_SIMPLE_CALL((%s), %s, %s)' % (', '.join(args), r, err) - - def OP_CALL_ARGS(self, args, r, err): - return 'OP_CALL_ARGS((%s), %s, %s)' % (', '.join(args), r, err) - -# ____________________________________________________________ - -def cdecl(type, name): - # Utility to generate a typed name declaration in C syntax. - # For local variables, struct fields, function declarations, etc. - # For complex C types, the 'type' can contain a '@' character that - # specifies where the 'name' should be inserted; for example, an - # array of 10 ints has a type of "int @[10]". - if '@' in type: - return type.replace('@', name) - else: - return ('%s %s' % (type, name)).rstrip() - Copied: pypy/dist/pypy/translator/genc_funcdef.py (from r9754, pypy/dist/pypy/translator/genc.py) ============================================================================== --- pypy/dist/pypy/translator/genc.py (original) +++ pypy/dist/pypy/translator/genc_funcdef.py Thu Mar 17 12:30:54 2005 @@ -1,565 +1,56 @@ -""" -Generate a C source file from the flowmodel. - -""" from __future__ import generators -import autopath, os, sys, __builtin__, marshal, zlib -from pypy.objspace.flow.model import Variable, Constant, SpaceOperation -from pypy.objspace.flow.model import FunctionGraph, Block, Link -from pypy.objspace.flow.model import last_exception, last_exc_value +from pypy.objspace.flow.model import Variable, Constant from pypy.objspace.flow.model import traverse, uniqueitems, checkgraph +from pypy.objspace.flow.model import Block, Link +from pypy.objspace.flow.model import last_exception, last_exc_value from pypy.translator.simplify import remove_direct_loops from pypy.interpreter.pycode import CO_VARARGS -from pypy.annotation import model as annmodel -from types import FunctionType, CodeType, InstanceType, ClassType +from types import FunctionType -from pypy.translator.gensupp import ordered_blocks, UniqueList, builtin_base, \ - c_string, uniquemodulename, C_IDENTIFIER, NameManager +from pypy.translator.gensupp import c_string -from pypy.objspace.std.restricted_int import r_int, r_uint -# ____________________________________________________________ +# Set this if you want call trace frames to be built +USE_CALL_TRACE = False -#def go_figure_out_this_name(source): -# # ahem -# return 'PyRun_String("%s", Py_eval_input, PyEval_GetGlobals(), NULL)' % ( -# source, ) - -class GenC: - MODNAMES = {} - - def __init__(self, f, translator, modname=None, f2=None): - self.f = f - self.f2 = f2 - self.translator = translator - self.modname = (modname or - uniquemodulename(translator.functions[0].__name__)) - self.cnames = {Constant(None).key: 'Py_None', - Constant(False).key: 'Py_False', - Constant(True).key: 'Py_True', - } - self.seennames = {} - self.initcode = [ # list of lines for the module's initxxx() - 'import new, types, sys', - 'Py_None = None', - 'Py_False = False', - 'Py_True = True', - ] - - self.latercode = [] # list of generators generating extra lines - # for later in initxxx() -- for recursive - # objects - self.namespace= NameManager() - # keywords cannot be reused. This is the C99 draft's list. - self.namespace.make_reserved_names(''' - auto enum restrict unsigned - break extern return void - case float short volatile - char for signed while - const goto sizeof _Bool - continue if static _Complex - default inline struct _Imaginary - do int switch - double long typedef - else register union - ''') - # these names are used in function headers, - # therefore pseudo-preserved in scope 1: - self.namespace.make_reserved_names('self args kwds') - - self.globaldecl = [] - self.globalobjects = [] - self.pendingfunctions = [] - self.currentfunc = None - self.debugstack = () # linked list of nested nameof() - self.gen_source() - - def nameof(self, obj, debug=None): - key = Constant(obj).key - try: - return self.cnames[key] - except KeyError: - if debug: - stackentry = debug, obj - else: - stackentry = obj - self.debugstack = (self.debugstack, stackentry) - obj_builtin_base = builtin_base(obj) - if obj_builtin_base in (object, int, long) and type(obj) is not obj_builtin_base: - # assume it's a user defined thingy - name = self.nameof_instance(obj) - else: - for cls in type(obj).__mro__: - meth = getattr(self, - 'nameof_' + cls.__name__.replace(' ', ''), - None) - if meth: - break - else: - raise Exception, "nameof(%r)" % (obj,) - name = meth(obj) - self.debugstack, x = self.debugstack - assert x is stackentry - self.cnames[key] = name - return name - - def uniquename(self, basename): - name = self.namespace.uniquename(basename) - self.globalobjects.append(name) - self.globaldecl.append('static PyObject *%s;' % (name,)) - return name - - def initcode_python(self, name, pyexpr): - # generate init code that will evaluate the given Python expression - #self.initcode.append("print 'setting up', %r" % name) - self.initcode.append("%s = %s" % (name, pyexpr)) - - def nameof_object(self, value): - if type(value) is not object: - raise Exception, "nameof(%r)" % (value,) - name = self.uniquename('g_object') - self.initcode_python(name, "object()") - return name - - def nameof_module(self, value): - assert value is os or not hasattr(value, "__file__") or \ - not (value.__file__.endswith('.pyc') or - value.__file__.endswith('.py') or - value.__file__.endswith('.pyo')), \ - "%r is not a builtin module (probably :)"%value - name = self.uniquename('mod%s'%value.__name__) - self.initcode_python(name, "__import__(%r)" % (value.__name__,)) - return name - - def nameof_int(self, value): - if value >= 0: - name = 'gint_%d' % value - else: - name = 'gint_minus%d' % abs(value) - name = self.uniquename(name) - self.initcode_python(name, repr(value)) - return name - - def nameof_long(self, value): - if value >= 0: - name = 'glong%d' % value - else: - name = 'glong_minus%d' % abs(value) - name = self.uniquename(name) - self.initcode_python(name, repr(value)) - return name - - def nameof_float(self, value): - name = 'gfloat_%s' % value - name = (name.replace('-', 'minus') - .replace('.', 'dot')) - name = self.uniquename(name) - self.initcode_python(name, repr(value)) - return name - - def nameof_str(self, value): - name = self.uniquename('gstr_' + value[:32]) -## if [c for c in value if c<' ' or c>'~' or c=='"' or c=='\\']: -## # non-printable string -## s = 'chr_%s' % name -## self.globaldecl.append('static char %s[] = { %s };' % ( -## s, ', '.join(['%d' % ord(c) for c in value]))) -## else: -## # printable string -## s = '"%s"' % value - self.initcode_python(name, repr(value)) - return name - - def skipped_function(self, func): - # debugging only! Generates a placeholder for missing functions - # that raises an exception when called. - name = self.uniquename('gskippedfunc_' + func.__name__) - self.initcode.append('def %s(*a,**k):' % name) - self.initcode.append(' raise NotImplementedError') - return name - - def nameof_function(self, func, progress=['-\x08', '\\\x08', - '|\x08', '/\x08']): - printable_name = '(%s:%d) %s' % ( - func.func_globals.get('__name__', '?'), - func.func_code.co_firstlineno, - func.__name__) - if self.translator.frozen: - if func not in self.translator.flowgraphs: - print "NOT GENERATING", printable_name - return self.skipped_function(func) - else: - if (func.func_doc and - func.func_doc.lstrip().startswith('NOT_RPYTHON')): - print "skipped", printable_name - return self.skipped_function(func) - p = progress.pop(0) - sys.stderr.write(p) - progress.append(p) - name = self.uniquename('gfunc_' + func.__name__) - self.pendingfunctions.append(func) - return name - - def nameof_staticmethod(self, sm): - # XXX XXX XXXX - func = sm.__get__(42.5) - name = self.uniquename('gsm_' + func.__name__) - functionname = self.nameof(func) - self.initcode_python(name, 'staticmethod(%s)' % functionname) - return name - - def nameof_instancemethod(self, meth): - if meth.im_self is None: - # no error checking here - return self.nameof(meth.im_func) - else: - ob = self.nameof(meth.im_self) - func = self.nameof(meth.im_func) - typ = self.nameof(meth.im_class) - name = self.uniquename('gmeth_'+meth.im_func.__name__) - self.initcode_python(name, 'new.instancemethod(%s, %s, %s)' % ( - func, ob, typ)) - return name - - def should_translate_attr(self, pbc, attr): - ann = self.translator.annotator - if ann is None: - ignore = getattr(pbc.__class__, 'NOT_RPYTHON_ATTRIBUTES', []) - if attr in ignore: - return False - else: - return "probably" # True - classdef = ann.getuserclasses().get(pbc.__class__) - if classdef and classdef.about_attribute(attr) is not None: - return True - return False - - def later(self, gen): - self.latercode.append((gen, self.debugstack)) - - def nameof_instance(self, instance): - klass = instance.__class__ - name = self.uniquename('ginst_' + klass.__name__) - cls = self.nameof(klass) - if hasattr(klass, '__base__'): - base_class = builtin_base(instance) - base = self.nameof(base_class) - else: - base_class = None - base = cls - def initinstance(): - content = instance.__dict__.items() - content.sort() - for key, value in content: - if self.should_translate_attr(instance, key): - line = '%s.%s = %s' % (name, key, self.nameof(value)) - yield line - if hasattr(instance,'__reduce_ex__'): - import copy_reg - reduced = instance.__reduce_ex__() - assert reduced[0] is copy_reg._reconstructor,"not clever enough" - assert reduced[1][1] is base_class, "not clever enough for %r vs. %r" % (base_class, reduced) - state = reduced[1][2] - else: - state = None - self.initcode.append('if isinstance(%s, type):' % cls) - if state is not None: - self.initcode.append(' %s = %s.__new__(%s, %r)' % (name, base, cls, state)) - else: - self.initcode.append(' %s = %s.__new__(%s)' % (name, base, cls)) - self.initcode.append('else:') - self.initcode.append(' %s = new.instance(%s)' % (name, cls)) - self.later(initinstance()) - return name - - def nameof_builtin_function_or_method(self, func): - if func.__self__ is None: - # builtin function - # where does it come from? Python2.2 doesn't have func.__module__ - for modname, module in sys.modules.items(): - if hasattr(module, '__file__'): - if (module.__file__.endswith('.py') or - module.__file__.endswith('.pyc') or - module.__file__.endswith('.pyo')): - continue # skip non-builtin modules - if func is getattr(module, func.__name__, None): - break - else: - raise Exception, '%r not found in any built-in module' % (func,) - name = self.uniquename('gbltin_' + func.__name__) - if modname == '__builtin__': - self.initcode_python(name, func.__name__) - else: - modname = self.nameof(module) - self.initcode_python(name, '%s.%s' % (modname, func.__name__)) - else: - # builtin (bound) method - name = self.uniquename('gbltinmethod_' + func.__name__) - selfname = self.nameof(func.__self__) - self.initcode_python(name, '%s.%s' % (selfname, func.__name__)) - return name - - def nameof_classobj(self, cls): - if cls.__doc__ and cls.__doc__.lstrip().startswith('NOT_RPYTHON'): - raise Exception, "%r should never be reached" % (cls,) - - metaclass = "type" - if issubclass(cls, Exception): - if cls.__module__ == 'exceptions': - name = self.uniquename('gexc_' + cls.__name__) - self.initcode_python(name, cls.__name__) - return name - #else: - # # exceptions must be old-style classes (grr!) - # metaclass = "&PyClass_Type" - # For the moment, use old-style classes exactly when the - # pypy source uses old-style classes, to avoid strange problems. - if not isinstance(cls, type): - assert type(cls) is ClassType - metaclass = "types.ClassType" - - name = self.uniquename('gcls_' + cls.__name__) - basenames = [self.nameof(base) for base in cls.__bases__] - def initclassobj(): - content = cls.__dict__.items() - content.sort() - for key, value in content: - if key.startswith('__'): - if key in ['__module__', '__doc__', '__dict__', - '__weakref__', '__repr__', '__metaclass__']: - continue - # XXX some __NAMES__ are important... nicer solution sought - #raise Exception, "unexpected name %r in class %s"%(key, cls) - if isinstance(value, staticmethod) and value.__get__(1) not in self.translator.flowgraphs and self.translator.frozen: - print value - continue - if isinstance(value, classmethod) and value.__get__(cls).__doc__.lstrip().startswith("NOT_RPYTHON"): - continue - if isinstance(value, FunctionType) and value not in self.translator.flowgraphs and self.translator.frozen: - print value - continue - - yield '%s.%s = %s' % (name, key, self.nameof(value)) - - baseargs = ", ".join(basenames) - if baseargs: - baseargs = '(%s)' % baseargs - self.initcode.append('class %s%s:' % (name, baseargs)) - self.initcode.append(' __metaclass__ = %s' % metaclass) - self.later(initclassobj()) - return name - - nameof_class = nameof_classobj # for Python 2.2 - - typename_mapping = { - InstanceType: 'types.InstanceType', - type(None): 'type(None)', - CodeType: 'types.CodeType', - type(sys): 'type(new)', - - r_int: 'int', # XXX - r_uint: 'int', # XXX - - # XXX more hacks - # type 'builtin_function_or_method': - type(len): 'type(len)', - # type 'method_descriptor': - type(list.append): 'type(list.append)', - # type 'wrapper_descriptor': - type(type(None).__repr__): 'type(type(None).__repr__)', - # type 'getset_descriptor': - type(type.__dict__['__dict__']): "type(type.__dict__['__dict__'])", - # type 'member_descriptor': - type(type.__dict__['__basicsize__']): "type(type.__dict__['__basicsize__'])", - } - - def nameof_type(self, cls): - if cls.__module__ != '__builtin__': - return self.nameof_classobj(cls) # user-defined type - name = self.uniquename('gtype_%s' % cls.__name__) - if getattr(__builtin__, cls.__name__, None) is cls: - expr = cls.__name__ # type available from __builtin__ - else: - expr = self.typename_mapping[cls] - self.initcode_python(name, expr) - return name - - def nameof_tuple(self, tup): - name = self.uniquename('g%dtuple' % len(tup)) - args = [self.nameof(x) for x in tup] - args = ', '.join(args) - if args: - args += ',' - self.initcode_python(name, '(%s)' % args) - return name - - def nameof_list(self, lis): - name = self.uniquename('g%dlist' % len(lis)) - def initlist(): - for i in range(len(lis)): - item = self.nameof(lis[i]) - yield '%s.append(%s)' % (name, item) - self.initcode_python(name, '[]') - self.later(initlist()) - return name - - def nameof_dict(self, dic): - assert dic is not __builtins__ - assert '__builtins__' not in dic, 'Seems to be the globals of %s' % ( - dic.get('__name__', '?'),) - name = self.uniquename('g%ddict' % len(dic)) - def initdict(): - for k in dic: - if type(k) is str: - yield '%s[%r] = %s' % (name, k, self.nameof(dic[k])) - else: - yield '%s[%s] = %s' % (name, self.nameof(k), - self.nameof(dic[k])) - self.initcode_python(name, '{}') - self.later(initdict()) - return name - - # strange prebuilt instances below, don't look too closely - # XXX oh well. - def nameof_member_descriptor(self, md): - name = self.uniquename('gdescriptor_%s_%s' % ( - md.__objclass__.__name__, md.__name__)) - cls = self.nameof(md.__objclass__) - self.initcode_python(name, '%s.__dict__[%r]' % (cls, md.__name__)) - return name - nameof_getset_descriptor = nameof_member_descriptor - nameof_method_descriptor = nameof_member_descriptor - nameof_wrapper_descriptor = nameof_member_descriptor - - def nameof_file(self, fil): - if fil is sys.stdin: - name = self.uniquename("gsys_stdin") - self.initcode_python(name, "sys.stdin") - return name - if fil is sys.stdout: - name = self.uniquename("gsys_stdout") - self.initcode_python(name, "sys.stdout") - return name - if fil is sys.stderr: - name = self.uniquename("gsys_stderr") - self.initcode_python(name, "sys.stderr") - return name - raise Exception, 'Cannot translate an already-open file: %r' % (fil,) - - def gen_source(self): - f = self.f - info = { - 'modname': self.modname, - 'entrypointname': self.translator.functions[0].__name__, - 'entrypoint': self.nameof(self.translator.functions[0]), - } - # header - print >> f, self.C_HEADER - - # function implementations - while self.pendingfunctions: - func = self.pendingfunctions.pop() - self.gen_cfunction(func) - # collect more of the latercode after each function - while self.latercode: - gen, self.debugstack = self.latercode.pop() - #self.initcode.extend(gen) -- eats TypeError! bad CPython! - for line in gen: - self.initcode.append(line) - self.debugstack = () - self.gen_global_declarations() - - # after all the functions: global object table - print >> f, self.C_OBJECT_TABLE - for name in self.globalobjects: - if not name.startswith('gfunc_'): - print >> f, '\t{&%s, "%s"},' % (name, name) - print >> f, self.C_TABLE_END - - # global function table - print >> f, self.C_FUNCTION_TABLE - for name in self.globalobjects: - if name.startswith('gfunc_'): - print >> f, ('\t{&%s, {"%s", (PyCFunction)f_%s, ' - 'METH_VARARGS|METH_KEYWORDS}},' % ( - name, name[6:], name[6:])) - print >> f, self.C_TABLE_END - - # frozen init bytecode - print >> f, self.C_FROZEN_BEGIN - bytecode = self.getfrozenbytecode() - def char_repr(c): - if c in '\\"': return '\\' + c - if ' ' <= c < '\x7F': return c - return '\\%03o' % ord(c) - for i in range(0, len(bytecode), 32): - print >> f, ''.join([char_repr(c) for c in bytecode[i:i+32]])+'\\' - if (i+32) % 1024 == 0: - print >> f, self.C_FROZEN_BETWEEN - print >> f, self.C_FROZEN_END - print >> f, "#define FROZEN_INITCODE_SIZE %d" % len(bytecode) - - # the footer proper: the module init function */ - print >> f, self.C_FOOTER % info - - def gen_global_declarations(self): - g = self.globaldecl - if g: - f = self.f - print >> f, '/* global declaration%s */' % ('s'*(len(g)>1)) - for line in g: - print >> f, line - print >> f - del g[:] - if self.f2 is not None: - for line in self.initcode: - print >> self.f2, line - del self.initcode[:] - - def getfrozenbytecode(self): - if self.f2 is not None: - self.f2.seek(0) - self.initcode.insert(0, self.f2.read()) - self.initcode.append('') - source = '\n'.join(self.initcode) - del self.initcode[:] - co = compile(source, self.modname, 'exec') - del source - small = zlib.compress(marshal.dumps(co)) - source = """if 1: - import zlib, marshal - exec marshal.loads(zlib.decompress(%r))""" % small - co = compile(source, self.modname, 'exec') - del source - return marshal.dumps(co) - - def gen_cfunction(self, func): -## print 'gen_cfunction (%s:%d) %s' % ( -## func.func_globals.get('__name__', '?'), -## func.func_code.co_firstlineno, -## func.__name__) - - f = self.f - localscope = self.namespace.localScope() - body = list(self.cfunction_body(func, localscope)) - name_of_defaults = [self.nameof(x, debug=('Default argument of', func)) - for x in (func.func_defaults or ())] - self.gen_global_declarations() +class FunctionDef: + """ + Collects information about a function which we have to generate. + The operations of each function are collected in a C function + with signature: - # print header - cname = self.nameof(func) - assert cname.startswith('gfunc_') - f_name = 'f_' + cname[6:] + static PyObject *fn_xxx(PyObject *arg1, PyObject *arg2, etc); + + If needed, another wrapper function is created with a signature + suitable for the built-in function type of CPython: + + static PyObject *pyfn_xxx(PyObject *self, PyObject *args); + + The built-in function object, if needed, is put in the global + variable named gfn_xxx. + """ + + def __init__(self, func, genc): + self.func = func + self.genc = genc + + # get the function name + namespace = genc.namespace + self.fast_name = namespace.uniquename('fn_' + func.__name__) # fn_xxx + self.base_name = self.fast_name[3:] # xxx + self.wrapper_name = None # pyfn_xxx + self.globalobject_name = None # gfunc_xxx + self.localscope = namespace.localScope() + self.graph = graph = genc.translator.getflowgraph(func) # collect all the local variables - graph = self.translator.getflowgraph(func) localslst = [] def visit(node): if isinstance(node, Block): localslst.extend(node.getvariables()) traverse(visit, graph) - localnames = [self.expr(a, localscope) for a in uniqueitems(localslst)] + self.localnames = [self.expr(a) for a in uniqueitems(localslst)] # collect all the arguments if func.func_code.co_flags & CO_VARARGS: @@ -568,47 +59,89 @@ else: vararg = None positional_args = graph.getargs() - min_number_of_args = len(positional_args) - len(name_of_defaults) - fast_args = [self.expr(a, localscope) for a in positional_args] + fast_args = [self.expr(a) for a in positional_args] if vararg is not None: - vararg = self.expr(vararg, localscope) + vararg = self.expr(vararg) fast_args.append(vararg) - fast_name = 'fast' + f_name - - fast_set = dict(zip(fast_args, fast_args)) declare_fast_args = [('PyObject *' + a) for a in fast_args] - if declare_fast_args: - declare_fast_args = 'TRACE_ARGS ' + ', '.join(declare_fast_args) - else: - declare_fast_args = 'TRACE_ARGS_VOID' + if USE_CALL_TRACE: + declare_fast_args.insert(0, 'TRACE_ARGS') + declare_fast_args = ', '.join(declare_fast_args) or 'void' fast_function_header = ('static PyObject *\n' - '%s(%s)' % (fast_name, declare_fast_args)) + '%s(%s)' % (self.fast_name, declare_fast_args)) - print >> f, fast_function_header + ';' # forward - print >> f + name_of_defaults = [self.genc.nameof(x, debug=('Default argument of', + self)) + for x in (func.func_defaults or ())] + + # store misc. information + self.fast_function_header = fast_function_header + self.fast_args = fast_args + self.fast_set = dict(zip(fast_args, fast_args)) + self.vararg = vararg + self.positional_args = positional_args + self.name_of_defaults = name_of_defaults + + # generate the forward header + self.genc.globaldecl.append(fast_function_header + '; /* forward */') + + + def get_globalobject(self): + if self.globalobject_name is None: + self.wrapper_name = 'py' + self.fast_name + self.globalobject_name = self.genc.uniquename('gfunc_' + + self.base_name) + return self.globalobject_name + + def clear(self): + del self.localscope + del self.localnames + del self.fast_set + del self.graph + + def expr(self, v): + if isinstance(v, Variable): + return self.localscope.localname(v.name) + elif isinstance(v, Constant): + return self.genc.nameof(v.value, + debug=('Constant in the graph of', self)) + else: + raise TypeError, "expr(%r)" % (v,) + # ____________________________________________________________ + + def gen_wrapper(self, f): + func = self.func + f_name = self.wrapper_name + positional_args = self.positional_args + vararg = self.vararg + name_of_defaults = self.name_of_defaults + + min_number_of_args = len(self.positional_args) - len(name_of_defaults) print >> f, 'static PyObject *' print >> f, '%s(PyObject* self, PyObject* args, PyObject* kwds)' % ( f_name,) print >> f, '{' - print >> f, '\tFUNCTION_HEAD(%s, %s, args, %s, __FILE__, __LINE__ - 2)' % ( - c_string('%s(%s)' % (cname, ', '.join(name_of_defaults))), - cname, - '(%s)' % (', '.join(map(c_string, name_of_defaults) + ['NULL']),), - ) + if USE_CALL_TRACE: + print >> f, '\tFUNCTION_HEAD(%s, %s, args, %s, __FILE__, __LINE__ - 2)' % ( + c_string('%s(%s)' % (self.base_name, ', '.join(name_of_defaults))), + self.globalobject_name, + '(%s)' % (', '.join(map(c_string, name_of_defaults) + ['NULL']),), + ) kwlist = ['"%s"' % name for name in func.func_code.co_varnames[:func.func_code.co_argcount]] kwlist.append('0') print >> f, '\tstatic char* kwlist[] = {%s};' % (', '.join(kwlist),) - if fast_args: - print >> f, '\tPyObject *%s;' % (', *'.join(fast_args)) + if self.fast_args: + print >> f, '\tPyObject *%s;' % (', *'.join(self.fast_args)) print >> f - print >> f, '\tFUNCTION_CHECK()' + if USE_CALL_TRACE: + print >> f, '\tFUNCTION_CHECK()' # argument unpacking if vararg is not None: @@ -632,7 +165,7 @@ tail = '\n\t\tFUNCTION_RETURN(NULL)' for i in range(len(name_of_defaults)): print >> f, '\t%s = %s;' % ( - self.expr(positional_args[min_number_of_args+i], localscope), + self.fast_args[min_number_of_args+i], name_of_defaults[i]) fmt = 'O'*min_number_of_args if min_number_of_args < len(positional_args): @@ -641,30 +174,33 @@ '"%s:%s"' % (fmt, func.__name__), 'kwlist', ] - lst += ['&' + self.expr(a, localscope) for a in positional_args] + lst += ['&' + a for a in self.fast_args] print >> f, '\tif (!PyArg_ParseTupleAndKeywords(%s))' % ', '.join(lst), print >> f, tail - call_fast_args = list(fast_args) - if call_fast_args: - call_fast_args = 'TRACE_CALL ' + ', '.join(call_fast_args) - else: - call_fast_args = 'TRACE_CALL_VOID' - print >> f, '\treturn %s(%s);' % (fast_name, call_fast_args) + call_fast_args = list(self.fast_args) + if USE_CALL_TRACE: + call_fast_args.insert(0, 'TRACE_CALL') + call_fast_args = ', '.join(call_fast_args) + print >> f, '\treturn %s(%s);' % (self.fast_name, call_fast_args) print >> f, '}' print >> f - print >> f, fast_function_header + # ____________________________________________________________ + + def gen_cfunction(self, f, body): + print >> f, self.fast_function_header print >> f, '{' - fast_locals = [arg for arg in localnames if arg not in fast_set] + fast_locals = [arg for arg in self.localnames + if arg not in self.fast_set] if fast_locals: print >> f, '\tPyObject *%s;' % (', *'.join(fast_locals),) print >> f # generate an incref for each input argument - for v in positional_args: - print >> f, '\tPy_INCREF(%s);' % self.expr(v, localscope) + for v in self.positional_args: + print >> f, '\tPy_INCREF(%s);' % self.expr(v) # print the body for line in body: @@ -679,23 +215,12 @@ fmt = '%s\n' f.write(fmt % line) print >> f, '}' + print >> f - if not self.translator.frozen: - # this is only to keep the RAM consumption under control - del self.translator.flowgraphs[func] - Variable.instances.clear() + # ____________________________________________________________ - def expr(self, v, localscope): - if isinstance(v, Variable): - return localscope.localname(v.name) - elif isinstance(v, Constant): - return self.nameof(v.value, - debug=('Constant in the graph of', self.currentfunc)) - else: - raise TypeError, "expr(%r)" % (v,) - - def cfunction_body(self, func, localscope): - graph = self.translator.getflowgraph(func) + def cfunction_body(self): + graph = self.graph remove_direct_loops(graph) checkgraph(graph) @@ -707,18 +232,18 @@ has_ref = {} linklocalvars = linklocalvars or {} for v in to_release: - linklocalvars[v] = self.expr(v, localscope) + linklocalvars[v] = self.expr(v) has_ref = linklocalvars.copy() for a1, a2 in zip(link.args, link.target.inputargs): if a1 in linklocalvars: src = linklocalvars[a1] else: - src = self.expr(a1, localscope) - line = 'MOVE(%s, %s)' % (src, self.expr(a2, localscope)) + src = self.expr(a1) + line = 'MOVE(%s, %s)' % (src, self.expr(a2)) if a1 in has_ref: del has_ref[a1] else: - line += '\tPy_INCREF(%s);' % self.expr(a2, localscope) + line += '\tPy_INCREF(%s);' % self.expr(a2) yield line for v in has_ref: yield 'Py_DECREF(%s);' % linklocalvars[v] @@ -737,14 +262,15 @@ yield 'block%d:' % blocknum[block] to_release = list(block.inputargs) for op in block.operations: - lst = [self.expr(v, localscope) for v in op.args] - lst.append(self.expr(op.result, localscope)) - lst.append('err%d_%d' % (blocknum[block], len(to_release))) + args = [lazy(self.expr, v) for v in op.args] + res = self.expr(op.result) + err = 'err%d_%d' % (blocknum[block], len(to_release)) macro = 'OP_%s' % op.opname.upper() - meth = getattr(self, macro, None) + meth = getattr(self, macro, None) if meth: - yield meth(lst[:-2], lst[-2], lst[-1]) + yield meth(args, res, err) else: + lst = [arg.compute() for arg in args] + [res, err] yield '%s(%s)' % (macro, ', '.join(lst)) to_release.append(op.result) @@ -752,13 +278,13 @@ if len(block.exits) == 0: if len(block.inputargs) == 2: # exc_cls, exc_value # exceptional return block - exc_cls = self.expr(block.inputargs[0], localscope) - exc_value = self.expr(block.inputargs[1], localscope) + exc_cls = self.expr(block.inputargs[0]) + exc_value = self.expr(block.inputargs[1]) yield 'PyErr_Restore(%s, %s, NULL);' % (exc_cls, exc_value) yield 'FUNCTION_RETURN(NULL)' else: # regular return block - retval = self.expr(block.inputargs[0], localscope) + retval = self.expr(block.inputargs[0]) yield 'FUNCTION_RETURN(%s)' % retval continue elif block.exitswitch is None: @@ -783,7 +309,7 @@ for link in block.exits[1:]: assert issubclass(link.exitcase, Exception) yield 'if (PyErr_ExceptionMatches(%s)) {' % ( - self.nameof(link.exitcase),) + self.genc.nameof(link.exitcase),) yield '\tPyObject *exc_cls, *exc_value, *exc_tb;' yield '\tPyErr_Fetch(&exc_cls, &exc_value, &exc_tb);' yield '\tif (exc_value == NULL) {' @@ -801,13 +327,13 @@ # block ending in a switch on a value for link in block.exits[:-1]: yield 'if (EQ_%s(%s)) {' % (link.exitcase, - self.expr(block.exitswitch, localscope)) + self.expr(block.exitswitch)) for op in gen_link(link): yield '\t' + op yield '}' link = block.exits[-1] yield 'assert(EQ_%s(%s));' % (link.exitcase, - self.expr(block.exitswitch, localscope)) + self.expr(block.exitswitch)) for op in gen_link(block.exits[-1]): yield op yield '' @@ -815,49 +341,19 @@ while to_release: v = to_release.pop() if err_reachable: - yield 'ERR_DECREF(%s)' % self.expr(v, localscope) + yield 'ERR_DECREF(%s)' % self.expr(v) yield 'err%d_%d:' % (blocknum[block], len(to_release)) err_reachable = True if err_reachable: yield 'FUNCTION_RETURN(NULL)' -# ____________________________________________________________ - - C_HEADER = '#include "genc.h"\n' - - C_SEP = "/************************************************************/" - - C_OBJECT_TABLE = C_SEP + ''' - -/* Table of global objects */ -static globalobjectdef_t globalobjectdefs[] = {''' - - C_FUNCTION_TABLE = ''' -/* Table of functions */ -static globalfunctiondef_t globalfunctiondefs[] = {''' - - C_TABLE_END = '\t{ NULL }\t/* Sentinel */\n};' - - C_FROZEN_BEGIN = ''' -/* Frozen Python bytecode: the initialization code */ -static char *frozen_initcode[] = {"\\''' - - C_FROZEN_BETWEEN = '''", "\\''' - - C_FROZEN_END = '''"};\n''' - - C_FOOTER = C_SEP + ''' - -MODULE_INITFUNC(%(modname)s) -{ -\tSETUP_MODULE(%(modname)s) -\tPyModule_AddObject(m, "%(entrypointname)s", %(entrypoint)s); -}''' + # ____________________________________________________________ # the C preprocessor cannot handle operations taking a variable number # of arguments, so here are Python methods that do it def OP_NEWLIST(self, args, r, err): + args = [arg.compute() for arg in args] if len(args) == 0: return 'OP_NEWLIST0(%s, %s)' % (r, err) else: @@ -865,6 +361,7 @@ return 'OP_NEWLIST((%s), %s, %s)' % (', '.join(args), r, err) def OP_NEWDICT(self, args, r, err): + args = [arg.compute() for arg in args] if len(args) == 0: return 'OP_NEWDICT0(%s, %s)' % (r, err) else: @@ -873,26 +370,36 @@ return 'OP_NEWDICT((%s), %s, %s)' % (', '.join(args), r, err) def OP_NEWTUPLE(self, args, r, err): + args = [arg.compute() for arg in args] args.insert(0, '%d' % len(args)) return 'OP_NEWTUPLE((%s), %s, %s)' % (', '.join(args), r, err) - def OP_SIMPLE_CALL(self, args, r, err): + def OP_SIMPLE_CALL(self, target_args, r, err): + # try to use the shortcut: a direct call to + # the ff_xxx() function, using its C signature. + target = target_args[0].args[0] + args = [arg.compute() for arg in target_args[1:]] + if (isinstance(target, Constant) and + isinstance(target.value, FunctionType) and not USE_CALL_TRACE): + funcdef = self.genc.getfuncdef(target.value) + if len(funcdef.positional_args) == len(args) and not funcdef.vararg: + return 'if (!(%s=%s(%s))) FAIL(%s);' % ( + r, funcdef.fast_name, ', '.join(args), err) + # fall-back + args.insert(0, target_args[0].compute()) args.append('NULL') return 'OP_SIMPLE_CALL((%s), %s, %s)' % (', '.join(args), r, err) def OP_CALL_ARGS(self, args, r, err): + args = [arg.compute() for arg in args] return 'OP_CALL_ARGS((%s), %s, %s)' % (', '.join(args), r, err) # ____________________________________________________________ -def cdecl(type, name): - # Utility to generate a typed name declaration in C syntax. - # For local variables, struct fields, function declarations, etc. - # For complex C types, the 'type' can contain a '@' character that - # specifies where the 'name' should be inserted; for example, an - # array of 10 ints has a type of "int @[10]". - if '@' in type: - return type.replace('@', name) - else: - return ('%s %s' % (type, name)).rstrip() - +class lazy: + def __init__(self, fn, *args, **kwds): + self.fn = fn + self.args = args + self.kwds = kwds + def compute(self): + return self.fn(*self.args, **self.kwds) From hpk at codespeak.net Thu Mar 17 13:52:15 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Thu, 17 Mar 2005 13:52:15 +0100 (MET) Subject: [pypy-svn] r9852 - pypy/funding Message-ID: <20050317125215.DD28527B61@code1.codespeak.net> Author: hpk Date: Thu Mar 17 13:52:15 2005 New Revision: 9852 Added: pypy/funding/B0.0_preamble.txt - copied unchanged from r9845, pypy/funding/B0.0_preamble.txt pypy/funding/B0.1_summary.txt - copied unchanged from r9845, pypy/funding/B0.1_summary.txt pypy/funding/B1.0_objectives.txt - copied unchanged from r9845, pypy/funding/B1.0_objectives.txt pypy/funding/B2.relevance_to_IST.txt - copied unchanged from r9845, pypy/funding/B2.relevance_to_IST.txt pypy/funding/B3.impact.txt - copied unchanged from r9845, pypy/funding/B3.impact.txt pypy/funding/B4.resources.txt - copied unchanged from r9845, pypy/funding/B4.resources.txt pypy/funding/B5.0_manage_bea.txt - copied unchanged from r9845, pypy/funding/B5.0_manage_bea.txt pypy/funding/B6.0_detailed_implementation.txt - copied unchanged from r9845, pypy/funding/B6.0_detailed_implementation.txt pypy/funding/B6.4_gantt.txt - copied unchanged from r9845, pypy/funding/B6.4_gantt.txt pypy/funding/B6.5_workpackage_list.txt - copied unchanged from r9845, pypy/funding/B6.5_workpackage_list.txt pypy/funding/B6.6_deliverables_list.txt - copied unchanged from r9845, pypy/funding/B6.6_deliverables_list.txt pypy/funding/B6.7.wp01_management.txt - copied unchanged from r9845, pypy/funding/B6.7.wp01_management.txt pypy/funding/B6.7.wp02_maintenance.txt - copied unchanged from r9845, pypy/funding/B6.7.wp02_maintenance.txt pypy/funding/B6.7.wp03_synchronisation.txt - copied unchanged from r9845, pypy/funding/B6.7.wp03_synchronisation.txt pypy/funding/B6.7.wp04_core.txt - copied unchanged from r9845, pypy/funding/B6.7.wp04_core.txt pypy/funding/B6.7.wp05_translation.txt - copied unchanged from r9845, pypy/funding/B6.7.wp05_translation.txt pypy/funding/B6.7.wp06_core_optimisations.txt - copied unchanged from r9845, pypy/funding/B6.7.wp06_core_optimisations.txt pypy/funding/B6.7.wp07_translator_optimisations.txt - copied unchanged from r9845, pypy/funding/B6.7.wp07_translator_optimisations.txt pypy/funding/B6.7.wp08_dynamic_optimisation.txt - copied unchanged from r9845, pypy/funding/B6.7.wp08_dynamic_optimisation.txt pypy/funding/B6.7.wp09_search_and_logic.txt - copied unchanged from r9845, pypy/funding/B6.7.wp09_search_and_logic.txt pypy/funding/B6.7.wp10_aspects_and_contracts.txt - copied unchanged from r9845, pypy/funding/B6.7.wp10_aspects_and_contracts.txt pypy/funding/B6.7.wp11_embed_in_hardware.txt - copied unchanged from r9845, pypy/funding/B6.7.wp11_embed_in_hardware.txt pypy/funding/B6.7.wp12_validations.txt - copied unchanged from r9845, pypy/funding/B6.7.wp12_validations.txt pypy/funding/B6.7.wp13_integration_config.txt - copied unchanged from r9845, pypy/funding/B6.7.wp13_integration_config.txt pypy/funding/B6.7.wp14_documentation.txt - copied unchanged from r9845, pypy/funding/B6.7.wp14_documentation.txt pypy/funding/B7.0_other_issues.txt - copied unchanged from r9845, pypy/funding/B7.0_other_issues.txt Log: resurrect the text files from the (still messy) funding directory. They are used for web links so they can't just go away. When we finally remove them we want to redirect all the links to the new place but this requires some coding and testing first ... From arigo at codespeak.net Thu Mar 17 18:22:13 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 17 Mar 2005 18:22:13 +0100 (MET) Subject: [pypy-svn] r9865 - pypy/dist/pypy/documentation Message-ID: <20050317172213.BE5EA27BA8@code1.codespeak.net> Author: arigo Date: Thu Mar 17 18:22:13 2005 New Revision: 9865 Modified: pypy/dist/pypy/documentation/architecture.txt Log: Pasted the introduction from http://www.python.org/pycon/dc2004/papers/27/. Thanks houcj for the pointer. Modified: pypy/dist/pypy/documentation/architecture.txt ============================================================================== --- pypy/dist/pypy/documentation/architecture.txt (original) +++ pypy/dist/pypy/documentation/architecture.txt Thu Mar 17 18:22:13 2005 @@ -1,8 +1,45 @@ -Overview on PyPy's current architecture (Dec. 2003) +Overview on PyPy's current architecture (Mar. 2004) =================================================== -Introduction and higher level picture +PyPy - an implementation of Python in Python +-------------------------------------------- + +It has become a tradition in the development of computer languages to +implement each language in itself. This serves many purposes. By doing so, +you demonstrate the versatility of the language, and its applicability for +large projects. A compiler/interpreter is close to as complex as software +ever gets. + +The PyPy project aims to do this for Python and has made some significant +progress. In a number of one week sprints, each attracting approximately +10 developers each, we made an almost complete implementation of Python in +Python. Currently it is rather slow, benchmarking at a factor 4000 times +slower than regular Python (henceforth referred to as CPython). + +In the next step of the project, we will generate C code from the source +of PyPy, thereby reducing the speed penalty. + +Later in the project, we will introduce optimisation (following the ideas +of Psyco) that should make PyPy run faster than CPython. + +An important aspect of implementing Python in Python is the high level of +abstraction and compactness of the language. This yields an implementation +that is easier to understand than the one done in C. + +Another carrying idea in PyPy is to build the implementation in the form +of a number of independent modules with clearly defined API's. This eases +reuse and allows experimenting with multiple implementations of specific +features. + +Our rather complete and 2.3-compliant interpreter is about 22000 lines of +code, with another 7000 lines of unit tests (we also pass a number of +CPython's own tests). If we include the tools, the parts related to code +analysis and generation, and the standard library modules ported from C, +PyPy is now 55000 lines of code and 20000 lines of tests. + + +Higher level picture ------------------------------------- The various parts of PyPy have always been under more or less heavy From arigo at codespeak.net Thu Mar 17 19:44:04 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 17 Mar 2005 19:44:04 +0100 (MET) Subject: [pypy-svn] r9867 - pypy/dist/pypy/translator Message-ID: <20050317184404.3AA8B27BA7@code1.codespeak.net> Author: arigo Date: Thu Mar 17 19:44:03 2005 New Revision: 9867 Modified: pypy/dist/pypy/translator/genc.py pypy/dist/pypy/translator/genc_funcdef.py Log: Restored support for skipped (not R-Python) functions. Modified: pypy/dist/pypy/translator/genc.py ============================================================================== --- pypy/dist/pypy/translator/genc.py (original) +++ pypy/dist/pypy/translator/genc.py Thu Mar 17 19:44:03 2005 @@ -171,6 +171,15 @@ def skipped_function(self, func): # debugging only! Generates a placeholder for missing functions # that raises an exception when called. + if self.translator.frozen: + warning = 'NOT GENERATING' + else: + warning = 'skipped' + printable_name = '(%s:%d) %s' % ( + func.func_globals.get('__name__', '?'), + func.func_code.co_firstlineno, + func.__name__) + print warning, printable_name name = self.uniquename('gskippedfunc_' + func.__name__) self.initcode.append('def %s(*a,**k):' % name) self.initcode.append(' raise NotImplementedError') @@ -178,6 +187,13 @@ def getfuncdef(self, func): if func not in self.funcdefs: + if self.translator.frozen: + if func not in self.translator.flowgraphs: + return None + else: + if (func.func_doc and + func.func_doc.lstrip().startswith('NOT_RPYTHON')): + return None funcdef = FunctionDef(func, self) self.funcdefs[func] = funcdef self.allfuncdefs.append(funcdef) @@ -186,23 +202,13 @@ def nameof_function(self, func, progress=['-\x08', '\\\x08', '|\x08', '/\x08']): - printable_name = '(%s:%d) %s' % ( - func.func_globals.get('__name__', '?'), - func.func_code.co_firstlineno, - func.__name__) - if self.translator.frozen: - if func not in self.translator.flowgraphs: - print "NOT GENERATING", printable_name - return self.skipped_function(func) - else: - if (func.func_doc and - func.func_doc.lstrip().startswith('NOT_RPYTHON')): - print "skipped", printable_name - return self.skipped_function(func) + funcdef = self.getfuncdef(func) + if funcdef is None: + return self.skipped_function(func) + if not self.translator.frozen: p = progress.pop(0) sys.stderr.write(p) progress.append(p) - funcdef = self.getfuncdef(func) return funcdef.get_globalobject() def nameof_staticmethod(self, sm): Modified: pypy/dist/pypy/translator/genc_funcdef.py ============================================================================== --- pypy/dist/pypy/translator/genc_funcdef.py (original) +++ pypy/dist/pypy/translator/genc_funcdef.py Thu Mar 17 19:44:03 2005 @@ -374,19 +374,31 @@ args.insert(0, '%d' % len(args)) return 'OP_NEWTUPLE((%s), %s, %s)' % (', '.join(args), r, err) - def OP_SIMPLE_CALL(self, target_args, r, err): - # try to use the shortcut: a direct call to - # the ff_xxx() function, using its C signature. - target = target_args[0].args[0] - args = [arg.compute() for arg in target_args[1:]] - if (isinstance(target, Constant) and - isinstance(target.value, FunctionType) and not USE_CALL_TRACE): - funcdef = self.genc.getfuncdef(target.value) - if len(funcdef.positional_args) == len(args) and not funcdef.vararg: - return 'if (!(%s=%s(%s))) FAIL(%s);' % ( - r, funcdef.fast_name, ', '.join(args), err) + def fast_simple_call(self, args, r, err): + # try to generate a SIMPLE_CALL using a shortcut: + # a direct call to the ff_xxx() function, using its C signature. + if USE_CALL_TRACE: + return None + target = args[0].args[0] + args = [arg.compute() for arg in args[1:]] + if not isinstance(target, Constant): + return None + if not isinstance(target.value, FunctionType): + return None + funcdef = self.genc.getfuncdef(target.value) + if funcdef is None: + return None + if len(funcdef.positional_args) != len(args) or funcdef.vararg: + return None + return 'if (!(%s=%s(%s))) FAIL(%s);' % ( + r, funcdef.fast_name, ', '.join(args), err) + + def OP_SIMPLE_CALL(self, args, r, err): + result = self.fast_simple_call(args, r, err) + if result is not None: + return result # fall-back - args.insert(0, target_args[0].compute()) + args = [arg.compute() for arg in args] args.append('NULL') return 'OP_SIMPLE_CALL((%s), %s, %s)' % (', '.join(args), r, err) From arigo at codespeak.net Thu Mar 17 19:53:33 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 17 Mar 2005 19:53:33 +0100 (MET) Subject: [pypy-svn] r9868 - pypy/dist/pypy/translator Message-ID: <20050317185333.E0EB427BA7@code1.codespeak.net> Author: arigo Date: Thu Mar 17 19:53:33 2005 New Revision: 9868 Modified: pypy/dist/pypy/translator/simplify.py Log: Exhaustive list of operations that can't have side-effects in R-Python. Modified: pypy/dist/pypy/translator/simplify.py ============================================================================== --- pypy/dist/pypy/translator/simplify.py (original) +++ pypy/dist/pypy/translator/simplify.py Thu Mar 17 19:53:33 2005 @@ -128,15 +128,22 @@ traverse(visit, graph) return transform_dead_op_vars_in_blocks(blocks) +# the set of operations that can safely be removed +# (they have no side effects, at least in R-Python) +CanRemove = {} +for _op in ''' + newtuple newlist newdict newslice is_true + is_ id type issubtype repr str len hash getattr getitem + pos neg nonzero abs hex oct round ord invert add sub mul + truediv floordiv div mod divmod pow lshift rshift and_ or_ + xor int float long lt le eq ne gt ge cmp coerce contains + iter get '''.split(): + CanRemove[_op] = True +del _op + def transform_dead_op_vars_in_blocks(blocks): """Remove dead operations and variables that are passed over a link but not used in the target block. Input is a set of blocks""" - # the set of operations that can safely be removed (no side effects) - CanRemove = {'newtuple': True, - 'newlist': True, - 'newdict': True, - 'is_': True, - 'is_true': True} read_vars = {} # set of variables really used variable_flow = {} # map {Var: list-of-Vars-it-depends-on} From arigo at codespeak.net Sat Mar 19 13:59:21 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 19 Mar 2005 13:59:21 +0100 (MET) Subject: [pypy-svn] r9891 - pypy/dist/pypy/objspace/flow Message-ID: <20050319125921.22E2427B71@code1.codespeak.net> Author: arigo Date: Sat Mar 19 13:59:20 2005 New Revision: 9891 Modified: pypy/dist/pypy/objspace/flow/framestate.py Log: Fix the flow space's SpecTag, broken by the recent changes. Modified: pypy/dist/pypy/objspace/flow/framestate.py ============================================================================== --- pypy/dist/pypy/objspace/flow/framestate.py (original) +++ pypy/dist/pypy/objspace/flow/framestate.py Sat Mar 19 13:59:20 2005 @@ -148,6 +148,8 @@ class SpecTag(object): def __repr__(self): return 'SpecTag(%d)' % id(self) + def _freeze_(self): + return True # ____________________________________________________________ # From hpk at codespeak.net Sat Mar 19 17:23:25 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sat, 19 Mar 2005 17:23:25 +0100 (MET) Subject: [pypy-svn] r9893 - pypy/dist/pypy/objspace Message-ID: <20050319162325.D640927B58@code1.codespeak.net> Author: hpk Date: Sat Mar 19 17:23:25 2005 New Revision: 9893 Removed: pypy/dist/pypy/objspace/trivial.py Log: good bye! Deleted: /pypy/dist/pypy/objspace/trivial.py ============================================================================== --- /pypy/dist/pypy/objspace/trivial.py Sat Mar 19 17:23:25 2005 +++ (empty file) @@ -1,391 +0,0 @@ -# -# Trivial object space for testing -# Does not perform any wrapping and (more importantly) does not -# correctly wrap the exceptions. -# - -from pypy.interpreter import gateway -from pypy.interpreter.baseobjspace import * -from pypy.objspace.descroperation import DescrOperation, Object -from pypy.interpreter.argument import Arguments -import types, sys -import __builtin__ as cpy_builtin - -class CPyWrapper(object): - def getdictvalue(self, space, name): - return self.__dict__.get(name, None) - -class TrivialObjSpace(ObjSpace, DescrOperation): - - def clone_exception_hierarchy(self): - def __init__(self, *args): - self.args = args - def __str__(self): - l = len(self.args) - if l == 0: - return '' - elif l == 1: - return str(self.args[0]) - else: - return str(self.args) - import exceptions - - # to create types, we should call the standard type object; - # but being able to do that depends on the existence of some - # of the exceptions... - - self.w_Exception = type('Exception', (), - {'__init__':__init__, '__str__': __str__, - 'originalex': Exception}) - - done = {'Exception': self.w_Exception} - - # some of the complexity of the following is due to the fact - # that we need to create the tree root first, but the only - # connections we have go in the inconvenient direction... - - for k in dir(exceptions): - if k not in done: - v = getattr(exceptions, k) - if not isinstance(v, type(Exception)): - continue - if not issubclass(v, Exception): - continue - stack = [k] - while stack: - next = stack[-1] - if next not in done: - v = getattr(exceptions, next) - b = v.__bases__[0] - if b.__name__ not in done: - stack.append(b.__name__) - continue - else: - base = done[b.__name__] - newtype = type(next, (base,), {}) - setattr(self, 'w_' + next, newtype) - newtype.originalex = v - done[next] = newtype - stack.pop() - else: - stack.pop() - return done - - def initialize(self): - from pypy.interpreter.typedef import TypeDef, GetSetProperty - - self.object_typedef = TypeDef('object', - __getattribute__ = gateway.interp2app(Object.descr__getattribute__.im_func), - __setattr__ = gateway.interp2app(Object.descr__setattr__.im_func), - __delattr__ = gateway.interp2app(Object.descr__delattr__.im_func), - __str__ = gateway.interp2app(lambda space, w_x: space.repr(w_x)), - __repr__ = gateway.interp2app(lambda space, w_x: repr(w_x)), - __class__ = GetSetProperty(self.__class__.type), - __init__ = gateway.interp2app(Object.descr__init__.im_func), - __dict__ = GetSetProperty(self.__class__.getdict_or_complain), - ) - # make a wrapped None object - none_typedef = TypeDef('NoneType', - __nonzero__ = gateway.interp2app(lambda space, w_None: - space.w_False), - __repr__ = gateway.interp2app(lambda space, w_None: - space.wrap('None'))) - nonewrapperclass = self.hackwrapperclass(none_typedef) - self.w_None = CPyWrapper.__new__(nonewrapperclass) - instancedict = CPyWrapper.__dict__['__dict__'].__get__(self.w_None) - instancedict['__internalpypyobject__'] = None - - self.w_True = True - self.w_False = False - self.w_NotImplemented = NotImplemented - self.w_Ellipsis = Ellipsis - - self.w_classobj = types.ClassType - self.w_instance = types.InstanceType - - newstuff = {"False": self.w_False, - "True" : self.w_True, - "NotImplemented" : self.w_NotImplemented, - "None" : self.w_None, - "Ellipsis" : self.w_Ellipsis, - "buffer": buffer, - #"xrange": xrange, - "slice": slice, - } - for n, c in cpy_builtin.__dict__.iteritems(): - if n in ['xrange', # we define this in builtin_app - 'staticmethod', - 'classmethod', - 'property', - ]: - continue - if isinstance(c, types.TypeType): - setattr(self, 'w_' + c.__name__, c) - newstuff[c.__name__] = c - newstuff.update(self.clone_exception_hierarchy()) - self.make_builtins() - # XXX Do we need the following still? - #for name, value in newstuff.items(): - # self.builtin.w_dict[name] = value - - # general stuff - def wrap(self, x): - if isinstance(x, BaseWrappable): - x = x.__spacebind__(self) - wrapperclass = self.hackwrapperclass(x.typedef) - instance = CPyWrapper.__new__(wrapperclass) - instancedict = CPyWrapper.__dict__['__dict__'].__get__(instance) - instancedict['__internalpypyobject__'] = x - return instance - elif x is None: - return self.w_None - else: - # optional check for double-wrapping - if isinstance(x, CPyWrapper): - raise TypeError, "wrapping an already-wrapped object" - # grumble grumble grumble recursive wrapping grumble - if isinstance(x, tuple): - return tuple([self.wrap(y) for y in x]) - return x - - def int_w(self, w): - if type(w) is int: - return w - if type(w) is long: - if -sys.maxint-1 <= w <= sys.maxint: - return int(w) - raise OperationError(self.w_OverflowError, - self.wrap("long int too large to convert to int")) - - raise OperationError(self.w_TypeError, - self.wrap("expected integer")) - - def str_w(self, w): - if type(w) is not str: - raise OperationError(self.w_TypeError, - self.wrap("expected string")) - return w - - def float_w(self, w): - if type(w) not in (int,long,float): - raise OperationError(self.w_TypeError, - self.wrap("expected float")) - return float(w) - - def unwrap(self, w): - if isinstance(w, CPyWrapper): - instancedict = CPyWrapper.__dict__['__dict__'].__get__(w) - return instancedict['__internalpypyobject__'] - else: - return w - - def interpclass_w(self, w): - w = self.unwrap(w) - if isinstance(w, BaseWrappable): - return w - return None - - def getdict(self, w_obj): - if isinstance(w_obj, CPyWrapper): - obj = self.unwrap(w_obj) - return obj.getdict() - else: - try: - return w_obj.__dict__ - except: - self.reraise() - - def getdict_or_complain(self, w_obj): - result = self.getdict(w_obj) - if result is None: - raise OperationError(self.w_AttributeError, - self.wrap('no __dict__')) - return result - - def allocate_instance(self, cls, w_subtype): - raise NotImplementedError("cannot manually instantiate built-in types") - - def hackwrapperclass(self, typedef): - try: - return typedef.trivialwrapperclass - except AttributeError: - from pypy.interpreter.gateway import interp2app - - # make the base first - if typedef.base: - bases = (self.hackwrapperclass(typedef.base),) - else: - bases = (CPyWrapper,) - # make the class dict with descriptors redirecting to the ones - # in rawdict - descrdict = {'__internalpypytypedef__': typedef} - for descrname, descr in typedef.rawdict.items(): - if isinstance(descr, interp2app): - def make_stuff(descr=descr, descrname=descrname, space=self): - def stuff(w_obj, *args, **kwds): - fn = descr.get_function(space) - args = Arguments(space, list(args), kwds) - try: - return space.call_args(space.wrap(fn), - args.prepend(w_obj)) - except OperationError, e: - if not hasattr(e.w_type, 'originalex'): - raise # XXX - # XXX normalize ... - #if isinstance(e.w_value, e.w_type): - raise e.w_type.originalex(repr(e.w_value)) # e.w_value) - return stuff - descrdict[descrname] = make_stuff() - else: - # more generally, defining a property - def fget(w_obj, descr=descr, space=self): - w_descr = space.wrap(descr) - return space.get(w_descr, w_obj) - def fset(w_obj, w_value, descr=descr, space=self): - w_descr = space.wrap(descr) - return space.set(w_descr, w_obj, w_value) - def fdel(w_obj, descr=descr, space=self): - w_descr = space.wrap(descr) - return space.delete(w_descr, w_obj) - descrdict[descrname] = property(fget, fset, fdel) - cls = type('CPyWrapped '+typedef.name, bases, descrdict) - typedef.trivialwrapperclass = cls - return cls - - def is_(self, w_obj1, w_obj2): - return self.unwrap(w_obj1) is self.unwrap(w_obj2) - - def id(self, w_obj): - return id(self.unwrap(w_obj)) - - def unpacktuple(self, w_tuple, expected_length=None): - assert isinstance(w_tuple, tuple) - if expected_length is not None and expected_length != len(w_tuple): - raise ValueError, "got a tuple of length %d instead of %d" % ( - len(w_tuple), expected_length) - return list(w_tuple) - - def reraise(self): - #import traceback - #traceback.print_exc() - #ec = self.getexecutioncontext() # .framestack.items[-1] - #ec.print_detailed_traceback(self) - etype, evalue, etb = sys.exc_info() - if etype is OperationError: - raise etype, evalue, etb # just re-raise it - name = etype.__name__ - if hasattr(self, 'w_' + name): - nt = getattr(self, 'w_' + name) - nv = object.__new__(nt) - if isinstance(evalue, etype): - nv.args = evalue.args - else: - print [etype, evalue, nt, nv], - print '!!!!!!!!' - nv.args = (evalue,) - else: - nt = etype - nv = evalue - raise OperationError, OperationError(nt, nv), etb - - # from the built-ins - def issubtype(self, w_x, w_y): - try: - return issubclass(w_x, w_y) - except: - self.reraise() - - def newtuple(self, args_w): - return tuple(args_w) - - def newlist(self, args_w): - return list(args_w) - - def newdict(self, items_w): - try: - return dict(items_w) - except: - self.reraise() - - def newslice(self, *args_w): - try: - return slice(*args_w) - except: - self.reraise() - - def is_true(self, w_obj): - return not not w_obj - - def not_(self, w_obj): - return not w_obj - - def type(self, w_x): - return type(w_x) - - def ord(self, w_x): - try: - return ord(w_x) - except: - self.reraise() - - def round(self, w_x): - try: - return round(w_x) - except: - self.reraise() - - def iter(self, w_obj): - if isinstance(w_obj, str) and not hasattr(w_obj, '__iter__'): - return iter(w_obj) # str.__iter__ is missing in CPython - else: - return DescrOperation.iter(self, w_obj) - - def newstring(self, asciilist): - try: - return ''.join([chr(ascii) for ascii in asciilist]) - except: - self.reraise() - - def newseqiter(self, w_obj): - try: - return iter(w_obj) - except: - self.reraise() - - def lookup(space, w_obj, name): - assert not isinstance(w_obj, BaseWrappable) - if isinstance(w_obj, CPyWrapper): - typedef = type(w_obj).__internalpypytypedef__ - while typedef is not None: - if name in typedef.rawdict: - return space.wrap(typedef.rawdict[name]) - typedef = typedef.base - if name in space.object_typedef.rawdict: - return space.wrap(space.object_typedef.rawdict[name]) - return None - else: - for cls in w_obj.__class__.__mro__: - if name in cls.__dict__: - return cls.__dict__[name] - return None - - def get_and_call_args(self, w_descr, w_obj, args): - if isinstance(w_descr, CPyWrapper): - return DescrOperation.get_and_call_args(self, w_descr, w_obj, args) - else: - try: - obj = self.unwrap(w_obj) - if hasattr(w_descr, '__get__'): - obj = w_descr.__get__(obj, type(obj)) - args_w, kwds_w = args.unpack() - return obj(*args_w, **kwds_w) - except: - #import traceback; traceback.print_exc() - self.reraise() - - -for m in ObjSpace.MethodTable: - if not hasattr(TrivialObjSpace, m[0]): - print 'XXX there is no', m[0], 'in TrivialObjSpace' - -Space = TrivialObjSpace From amcintyre at codespeak.net Sat Mar 19 18:02:11 2005 From: amcintyre at codespeak.net (amcintyre at codespeak.net) Date: Sat, 19 Mar 2005 18:02:11 +0100 (MET) Subject: [pypy-svn] r9894 - pypy/dist/pypy/lib Message-ID: <20050319170211.1D88A27B58@code1.codespeak.net> Author: amcintyre Date: Sat Mar 19 18:02:10 2005 New Revision: 9894 Modified: pypy/dist/pypy/lib/struct.py Log: Moved import after docstring. Modified: pypy/dist/pypy/lib/struct.py ============================================================================== --- pypy/dist/pypy/lib/struct.py (original) +++ pypy/dist/pypy/lib/struct.py Sat Mar 19 18:02:10 2005 @@ -1,5 +1,3 @@ -import math,sys - """Functions to convert between Python values and C structs. Python strings are used to hold the data representing the C struct and also as format strings to describe the layout of data in the C struct. @@ -36,6 +34,8 @@ The variable struct.error is an exception raised on errors.""" +import math,sys + # TODO: XXX Find a way to get information on native sizes and alignments class StructError(Exception): pass From amcintyre at codespeak.net Sat Mar 19 18:11:19 2005 From: amcintyre at codespeak.net (amcintyre at codespeak.net) Date: Sat, 19 Mar 2005 18:11:19 +0100 (MET) Subject: [pypy-svn] r9895 - pypy/dist/pypy/lib Message-ID: <20050319171119.3354927B58@code1.codespeak.net> Author: amcintyre Date: Sat Mar 19 18:11:19 2005 New Revision: 9895 Modified: pypy/dist/pypy/lib/cmath.py Log: Added e and pi (from math). Modified: pypy/dist/pypy/lib/cmath.py ============================================================================== --- pypy/dist/pypy/lib/cmath.py (original) +++ pypy/dist/pypy/lib/cmath.py Sat Mar 19 18:11:19 2005 @@ -6,9 +6,7 @@ # much code borrowed from mathmodule.c import math - -M_PI = 3.141592653589793239 - +from math import e, pi # constants From amcintyre at codespeak.net Sat Mar 19 18:14:51 2005 From: amcintyre at codespeak.net (amcintyre at codespeak.net) Date: Sat, 19 Mar 2005 18:14:51 +0100 (MET) Subject: [pypy-svn] r9896 - pypy/dist/pypy/lib Message-ID: <20050319171451.484EA27B58@code1.codespeak.net> Author: amcintyre Date: Sat Mar 19 18:14:51 2005 New Revision: 9896 Modified: pypy/dist/pypy/lib/md5.py Log: Renamed MD5 class to MD5Type. Modified: pypy/dist/pypy/lib/md5.py ============================================================================== --- pypy/dist/pypy/lib/md5.py (original) +++ pypy/dist/pypy/lib/md5.py Sat Mar 19 18:14:51 2005 @@ -148,7 +148,7 @@ return res & 0xffffffffL -class MD5: +class MD5Type: "An implementation of the MD5 hash function in pure Python." def __init__(self): @@ -417,7 +417,7 @@ If arg is present, the method call update(arg) is made. """ - md5 = MD5() + md5 = MD5Type() if arg: md5.update(arg) From ac at codespeak.net Sat Mar 19 18:47:59 2005 From: ac at codespeak.net (ac at codespeak.net) Date: Sat, 19 Mar 2005 18:47:59 +0100 (MET) Subject: [pypy-svn] r9897 - pypy/dist/pypy/lib Message-ID: <20050319174759.7281E27B66@code1.codespeak.net> Author: ac Date: Sat Mar 19 18:47:59 2005 New Revision: 9897 Modified: pypy/dist/pypy/lib/operator.py Log: Add missing attributes. Modified: pypy/dist/pypy/lib/operator.py ============================================================================== --- pypy/dist/pypy/lib/operator.py (original) +++ pypy/dist/pypy/lib/operator.py Sat Mar 19 18:47:59 2005 @@ -1,3 +1,8 @@ +'''Operator interface. + +This module exports a set of operators as functions. E.g. operator.add(x,y) is +equivalent to x+y. +''' import __builtin__ def abs(obj,): @@ -14,7 +19,10 @@ __and__ = and_ def concat(obj1, obj2): 'concat(a, b) -- Same as a + b, for a and b sequences.' - return obj1 + obj2 # XXX should we be stricter? + return obj1 + obj2 # XXX cPython only works on types with sequence api + # we support any with __add__ +__concat__ = concat + def contains(obj1,obj2): 'contains(a, b) -- Same as b in a (note reversed operands).' return obj2 in obj1 @@ -129,7 +137,9 @@ __neg__ = neg def not_(obj,): 'not_(a) -- Same as not a.' - return not obj + return not obj +__not__ = not_ + def or_(a, b): 'or_(a, b) -- Same as a | b.' return a | b @@ -146,7 +156,10 @@ 'repeat(a, b) -- Return a * b, where a is a sequence, and b is an integer.' if not isinstance(num, (int, long)): raise TypeError, 'an integer is required' - return obj * num # XXX should we be stricter? + return obj * num # XXX cPython only supports objects with the sequence + # protocol. We support any with a __mul__ +__repeat__ = repeat + def rshift(a, b): 'rshift(a, b) -- Same as a >> b.' return a >> b From amcintyre at codespeak.net Sat Mar 19 19:16:13 2005 From: amcintyre at codespeak.net (amcintyre at codespeak.net) Date: Sat, 19 Mar 2005 19:16:13 +0100 (MET) Subject: [pypy-svn] r9898 - pypy/dist/pypy/lib Message-ID: <20050319181613.6357827B66@code1.codespeak.net> Author: amcintyre Date: Sat Mar 19 19:16:13 2005 New Revision: 9898 Modified: pypy/dist/pypy/lib/types.py Log: Uncommented DictProxyType Modified: pypy/dist/pypy/lib/types.py ============================================================================== --- pypy/dist/pypy/lib/types.py (original) +++ pypy/dist/pypy/lib/types.py Sat Mar 19 19:16:13 2005 @@ -111,7 +111,7 @@ SliceType = type(slice(0)) EllipsisType = type(Ellipsis) -#DictProxyType = type(TypeType.__dict__) +DictProxyType = type(TypeType.__dict__) try: NotImplementedType = type(NotImplemented) except NameError: From amcintyre at codespeak.net Sat Mar 19 19:20:09 2005 From: amcintyre at codespeak.net (amcintyre at codespeak.net) Date: Sat, 19 Mar 2005 19:20:09 +0100 (MET) Subject: [pypy-svn] r9899 - in pypy/dist/pypy: lib lib/test2 module/builtin Message-ID: <20050319182009.8799927B72@code1.codespeak.net> Author: amcintyre Date: Sat Mar 19 19:20:09 2005 New Revision: 9899 Modified: pypy/dist/pypy/lib/cmath.py pypy/dist/pypy/lib/test2/test_complexobject.py pypy/dist/pypy/module/builtin/app_complex.py Log: Added test case for complex() with (complex, real), (complex, complex), (real, complex) arguments. Converted from unittest to py.test Modified lib/cmath.py and module/builtin/app_complex.py to match CPython behavior. Modified: pypy/dist/pypy/lib/cmath.py ============================================================================== --- pypy/dist/pypy/lib/cmath.py (original) +++ pypy/dist/pypy/lib/cmath.py Sat Mar 19 19:20:09 2005 @@ -18,6 +18,7 @@ # internal function not available from Python def _prodi(x): + x = complex(x, 0) real = -x.imag imag = x.real return complex(real, imag) @@ -84,7 +85,8 @@ """cos(x) Return the cosine of x.""" - + + x = complex(x, 0) real = math.cos(x.real) * math.cosh(x.imag) imag = -math.sin(x.real) * math.sinh(x.imag) return complex(real, imag) @@ -94,7 +96,8 @@ """cosh(x) Return the hyperbolic cosine of x.""" - + + x = complex(x, 0) real = math.cos(x.imag) * math.cosh(x.real) imag = math.sin(x.imag) * math.sinh(x.real) return complex(real, imag) @@ -104,7 +107,8 @@ """exp(x) Return the exponential value e**x.""" - + + x = complex(x, 0) l = math.exp(x.real) real = l * math.cos(x.imag) imag = l * math.sin(x.imag) @@ -116,6 +120,7 @@ Return the natural logarithm of x.""" + x = complex(x, 0) l = math.hypot(x.real,x.imag) imag = math.atan2(x.imag, x.real) real = math.log(l) @@ -127,6 +132,7 @@ Return the base-10 logarithm of x.""" + x = complex(x, 0) l = math.hypot(x.real, x.imag) imag = math.atan2(x.imag, x.real)/math.log(10.) real = math.log10(l) @@ -138,6 +144,7 @@ Return the sine of x.""" + x = complex(x, 0) real = math.sin(x.real) * math.cosh(x.imag) imag = math.cos(x.real) * math.sinh(x.imag) return complex(real, imag) @@ -148,6 +155,7 @@ Return the hyperbolic sine of x.""" + x = complex(x, 0) real = math.cos(x.imag) * math.sinh(x.real) imag = math.sin(x.imag) * math.cosh(x.real) return complex(real, imag) @@ -158,6 +166,7 @@ Return the square root of x.""" + x = complex(x, 0) if x.real == 0. and x.imag == 0.: real, imag = 0, 0 else: @@ -180,6 +189,7 @@ Return the tangent of x.""" + x = complex(x, 0) sr = math.sin(x.real) cr = math.cos(x.real) shi = math.sinh(x.imag) @@ -199,6 +209,7 @@ Return the hyperbolic tangent of x.""" + x = complex(x, 0) si = math.sin(x.imag) ci = math.cos(x.imag) shr = math.sinh(x.real) Modified: pypy/dist/pypy/lib/test2/test_complexobject.py ============================================================================== --- pypy/dist/pypy/lib/test2/test_complexobject.py (original) +++ pypy/dist/pypy/lib/test2/test_complexobject.py Sat Mar 19 19:20:09 2005 @@ -24,14 +24,16 @@ import cmath import sys import types -import unittest +#import unittest -from pypy.tool import testit +#from pypy.tool import testit #from pypy.appspace.complexobject import complex as pycomplex -from pypy.module.test.applevel_in_cpython import applevel_in_cpython -our_own_builtin = applevel_in_cpython('__builtin__') -pycomplex = our_own_builtin.complex + +#from pypy.module.test.applevel_in_cpython import applevel_in_cpython +#our_own_builtin = applevel_in_cpython('__builtin__') +#pycomplex = our_own_builtin.complex +from pypy.module.builtin.app_complex import complex as pycomplex try: unicode @@ -79,11 +81,10 @@ -class TestComplex(unittest.TestCase): +class TestComplex: def assertAEqual(self, a, b): - if not equal(a, b): - raise self.failureException, '%s ~== %s'%(a, b) + assert equal(a, b) def test_wrongInit1(self): "Compare wrong init. with CPython." @@ -189,8 +190,8 @@ self.assertAEqual(abs(zc), abs(zp)) self.assertAEqual(zc, zp) #self.assertEqual(zc.conjugate(), zp.conjugate()) XXX - self.assertEqual(str(zc), str(zp)) - self.assertEqual(hash(zc), hash(zp)) + assert str(zc) == str(zp) + assert hash(zc) == hash(zp) # this fails on python2.3 and is depreacted anyway @@ -250,6 +251,17 @@ pc = z0c**z0c.real pp = z0p**z0p.real self.assertAEqual(pc, pp) - -if __name__ == "__main__": - testit.main() + + def test_complex(self): + "Compare complex() with CPython (with complex arguments)" + ours = pycomplex(pycomplex(1,10), 100) + cpy = complex(complex(1,10), 100) + self.assertAEqual(ours, cpy) + + ours = pycomplex(pycomplex(1,10), pycomplex(100,1000)) + cpy = complex(complex(1,10), complex(100,1000)) + self.assertAEqual(ours, cpy) + + ours = pycomplex(10, pycomplex(100,1000)) + cpy = complex(10, complex(100,1000)) + self.assertAEqual(ours, cpy) Modified: pypy/dist/pypy/module/builtin/app_complex.py ============================================================================== --- pypy/dist/pypy/module/builtin/app_complex.py (original) +++ pypy/dist/pypy/module/builtin/app_complex.py Sat Mar 19 19:20:09 2005 @@ -13,24 +13,29 @@ # XXX this class is not well tested def __init__(self, real=0.0, imag=None): - if isinstance(real, str) and imag is not None: - msg = "complex() can't take second arg if first is a string" - raise TypeError, msg + if isinstance(real, str): + if imag is not None: + msg = "complex() can't take second arg if first is a string" + raise TypeError, msg + re, im = self._makeComplexFromString(real) + elif isinstance(real, complex): + re = real.real + im = real.imag + else: + re = float(real) + im = 0.0 if isinstance(imag, str): msg = "complex() second arg can't be a string" raise TypeError, msg + elif isinstance(imag, complex): + re -= imag.imag + im += imag.real + elif imag is not None: + im += float(imag) - if isinstance(real, str): - real, imag = self._makeComplexFromString(real) - self.__dict__['real'] = real - self.__dict__['imag'] = imag - else: - if imag is None: - imag = 0. - self.__dict__['real'] = float(real) - self.__dict__['imag'] = float(imag) - + self.__dict__['real'] = re + self.__dict__['imag'] = im def __setattr__(self, name, value): if name in ('real', 'imag'): From tismer at codespeak.net Sat Mar 19 19:20:53 2005 From: tismer at codespeak.net (tismer at codespeak.net) Date: Sat, 19 Mar 2005 19:20:53 +0100 (MET) Subject: [pypy-svn] r9900 - pypy/dist/pypy/lib Message-ID: <20050319182053.07E8727B72@code1.codespeak.net> Author: tismer Date: Sat Mar 19 19:20:52 2005 New Revision: 9900 Added: pypy/dist/pypy/lib/cPickle.py Log: did a whole implementation of cPickle in a minute :-) Added: pypy/dist/pypy/lib/cPickle.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/lib/cPickle.py Sat Mar 19 19:20:52 2005 @@ -0,0 +1,5 @@ +# +# One-liner implementation of cPickle +# + +from pickle import * From briandorsey at codespeak.net Sat Mar 19 19:28:57 2005 From: briandorsey at codespeak.net (briandorsey at codespeak.net) Date: Sat, 19 Mar 2005 19:28:57 +0100 (MET) Subject: [pypy-svn] r9901 - in pypy/dist/pypy/objspace/std: . test Message-ID: <20050319182857.2B38327B72@code1.codespeak.net> Author: briandorsey Date: Sat Mar 19 19:28:57 2005 New Revision: 9901 Modified: pypy/dist/pypy/objspace/std/stringobject.py pypy/dist/pypy/objspace/std/test/test_stringobject.py Log: Fixed off by one error in string.split with a maxsplit. Modified: pypy/dist/pypy/objspace/std/stringobject.py ============================================================================== --- pypy/dist/pypy/objspace/std/stringobject.py (original) +++ pypy/dist/pypy/objspace/std/stringobject.py Sat Mar 19 19:28:57 2005 @@ -306,8 +306,6 @@ #next = value.find(by, start) #of course we cannot use #the find method, if next < 0: - res.append(value[start:]) - start = len(value) + 1 break res.append(value[start:next]) start = next + bylen @@ -316,8 +314,7 @@ if maxsplit > -1: splitcount = splitcount - 1 - if start < len(value): - res.append(value[start:]) + res.append(value[start:]) for i in range(len(res)): res[i] = W_StringObject(w_self.space, res[i]) Modified: pypy/dist/pypy/objspace/std/test/test_stringobject.py ============================================================================== --- pypy/dist/pypy/objspace/std/test/test_stringobject.py (original) +++ pypy/dist/pypy/objspace/std/test/test_stringobject.py Sat Mar 19 19:28:57 2005 @@ -121,7 +121,11 @@ def test_split(self): assert "".split() == [] + assert " ".split() == [] assert "a".split() == ['a'] + assert "a".split("a", 1) == ['', ''] + assert " ".split(" ", 1) == ['', ''] + assert "aa".split("a", 2) == ['', '', ''] assert " a ".split() == ['a'] assert "a b c".split() == ['a','b','c'] assert 'this is the split function'.split() == ['this', 'is', 'the', 'split', 'function'] From amcintyre at codespeak.net Sat Mar 19 19:29:49 2005 From: amcintyre at codespeak.net (amcintyre at codespeak.net) Date: Sat, 19 Mar 2005 19:29:49 +0100 (MET) Subject: [pypy-svn] r9902 - pypy/dist/lib-python-2.3.4/test Message-ID: <20050319182949.7F62527B72@code1.codespeak.net> Author: amcintyre Date: Sat Mar 19 19:29:49 2005 New Revision: 9902 Modified: pypy/dist/lib-python-2.3.4/test/conftest.py Log: Added test_cmath.py to working unit tests. Modified: pypy/dist/lib-python-2.3.4/test/conftest.py ============================================================================== --- pypy/dist/lib-python-2.3.4/test/conftest.py (original) +++ pypy/dist/lib-python-2.3.4/test/conftest.py Sat Mar 19 19:29:49 2005 @@ -30,6 +30,7 @@ 'test_bisect.py', 'test_builtin.py', 'test_call', +'test_cmath.py', 'test_codeop.py', 'test_commands.py', 'test_compare.py', From briandorsey at codespeak.net Sat Mar 19 19:43:04 2005 From: briandorsey at codespeak.net (briandorsey at codespeak.net) Date: Sat, 19 Mar 2005 19:43:04 +0100 (MET) Subject: [pypy-svn] r9904 - pypy/dist/lib-python-2.3.4/test Message-ID: <20050319184304.0EE6D27B7A@code1.codespeak.net> Author: briandorsey Date: Sat Mar 19 19:43:03 2005 New Revision: 9904 Modified: pypy/dist/lib-python-2.3.4/test/conftest.py Log: Added new passing tests, fixed missing '.py' for test_call.py Modified: pypy/dist/lib-python-2.3.4/test/conftest.py ============================================================================== --- pypy/dist/lib-python-2.3.4/test/conftest.py (original) +++ pypy/dist/lib-python-2.3.4/test/conftest.py Sat Mar 19 19:43:03 2005 @@ -29,7 +29,8 @@ 'test_binop.py', 'test_bisect.py', 'test_builtin.py', -'test_call', +'test_call.py', +'test_cgi.py', 'test_cmath.py', 'test_codeop.py', 'test_commands.py', @@ -41,6 +42,7 @@ 'test_operator.py', 'test_pprint.py', 'test_sgmllib.py', +'test_string.py', 'test_sys.py', 'test_textwrap.py', 'test_urlparse.py', From jacob at codespeak.net Sat Mar 19 21:53:24 2005 From: jacob at codespeak.net (jacob at codespeak.net) Date: Sat, 19 Mar 2005 21:53:24 +0100 (MET) Subject: [pypy-svn] r9905 - pypy/funding/negotiations Message-ID: <20050319205324.9738027BAA@code1.codespeak.net> Author: jacob Date: Sat Mar 19 21:53:24 2005 New Revision: 9905 Modified: pypy/funding/negotiations/pypy-association-agreement.sxw Log: Update after Ms Saxena's comments. Modified: pypy/funding/negotiations/pypy-association-agreement.sxw ============================================================================== Binary files. No diff available. From lutz_p at codespeak.net Sat Mar 19 22:13:08 2005 From: lutz_p at codespeak.net (lutz_p at codespeak.net) Date: Sat, 19 Mar 2005 22:13:08 +0100 (MET) Subject: [pypy-svn] r9906 - pypy/dist/pypy/module/sys2 Message-ID: <20050319211308.B878127BB2@code1.codespeak.net> Author: lutz_p Date: Sat Mar 19 22:13:08 2005 New Revision: 9906 Modified: pypy/dist/pypy/module/sys2/state.py Log: Removed marshal from the list of faked modules since Samuele and me got it working. Lutz Modified: pypy/dist/pypy/module/sys2/state.py ============================================================================== --- pypy/dist/pypy/module/sys2/state.py (original) +++ pypy/dist/pypy/module/sys2/state.py Sat Mar 19 22:13:08 2005 @@ -27,7 +27,7 @@ for fn in ['posix', 'nt', 'os2', 'mac', 'ce', 'riscos', 'math', '_codecs', 'array', '_random', '_sre', 'time', '_socket', 'errno', - 'marshal', 'binascii', 'parser']: + 'binascii', 'parser']: if fn not in builtin_modules: try: builtin_modules[fn] = hack_cpython_module(fn) From lutz_p at codespeak.net Sat Mar 19 22:28:09 2005 From: lutz_p at codespeak.net (lutz_p at codespeak.net) Date: Sat, 19 Mar 2005 22:28:09 +0100 (MET) Subject: [pypy-svn] r9907 - pypy/dist/pypy/lib Message-ID: <20050319212809.1EC5427BB1@code1.codespeak.net> Author: lutz_p Date: Sat Mar 19 22:28:08 2005 New Revision: 9907 Added: pypy/dist/pypy/lib/marshal.py Log: the marshal module is now in library source is taken from the jython cvs repository but the code originally came from the CPython base. There was an obscure bug due to bit shifting when the Unmarshaller reconstructs long values from the pickled state in Unmarshaller.r_long and Unmarshaller.r_long64. Unit test is now passing. Samuele & Lutz Added: pypy/dist/pypy/lib/marshal.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/lib/marshal.py Sat Mar 19 22:28:08 2005 @@ -0,0 +1,326 @@ +"""Marshal module written in Python. + +This doesn't marshal code objects, but supports everything else. +Performance or careful error checking is not an issue. + +""" + +import StringIO +import string +from types import * +try: + import new +except ImportError: + new = None + +TYPE_NULL = '0' +TYPE_NONE = 'N' +TYPE_ELLIPSIS = '.' +TYPE_INT = 'i' +TYPE_INT64 = 'I' +TYPE_FLOAT = 'f' +TYPE_COMPLEX = 'x' +TYPE_LONG = 'l' +TYPE_STRING = 's' +TYPE_TUPLE = '(' +TYPE_LIST = '[' +TYPE_DICT = '{' +TYPE_CODE = 'c' +TYPE_UNKNOWN = '?' + + +class Marshaller: + + dispatch = {} + + def __init__(self, f): + self.f = f + + def dump(self, x): + self.dispatch[type(x)](self, x) + + def w_long64(self, x): + self.w_long(x) + self.w_long(x>>32) + + def w_long(self, x): + write = self.f.write + write(chr((x) & 0xff)) + write(chr((x>> 8) & 0xff)) + write(chr((x>>16) & 0xff)) + write(chr((x>>24) & 0xff)) + + def w_short(self, x): + write = self.f.write + write(chr((x) & 0xff)) + write(chr((x>> 8) & 0xff)) + + def dump_none(self, x): + self.f.write(TYPE_NONE) + dispatch[NoneType] = dump_none + + def dump_ellipsis(self, x): + self.f.write(TYPE_ELLIPSIS) + try: + dispatch[EllipsisType] = dump_ellipsis + except NameError: + pass + + def dump_int(self, x): + y = x>>31 + if y and y != -1: + self.f.write(TYPE_INT64) + self.w_long64(x) + else: + self.f.write(TYPE_INT) + self.w_long(x) + dispatch[IntType] = dump_int + + def dump_long(self, x): + self.f.write(TYPE_LONG) + sign = 1 + if x < 0: + sign = -1 + x = -x + digits = [] + while x: + digits.append(x & 0x7FFF) + x = x>>15 + self.w_long(len(digits) * sign) + for d in digits: + self.w_short(d) + dispatch[LongType] = dump_long + + def dump_float(self, x): + write = self.f.write + write(TYPE_FLOAT) + s = `x` + write(chr(len(s))) + write(s) + dispatch[FloatType] = dump_float + + def dump_complex(self, x): + write = self.f.write + write(TYPE_COMPLEX) + s = `x.real` + write(chr(len(s))) + write(s) + s = `x.imag` + write(chr(len(s))) + write(s) + try: + dispatch[ComplexType] = dump_complex + except NameError: + pass + + def dump_string(self, x): + self.f.write(TYPE_STRING) + self.w_long(len(x)) + self.f.write(x) + dispatch[StringType] = dump_string + + def dump_tuple(self, x): + self.f.write(TYPE_TUPLE) + self.w_long(len(x)) + for item in x: + self.dump(item) + dispatch[TupleType] = dump_tuple + + def dump_list(self, x): + self.f.write(TYPE_LIST) + self.w_long(len(x)) + for item in x: + self.dump(item) + dispatch[ListType] = dump_list + + def dump_dict(self, x): + self.f.write(TYPE_DICT) + for key, value in x.items(): + self.dump(key) + self.dump(value) + self.f.write(TYPE_NULL) + dispatch[DictionaryType] = dump_dict + + def dump_code(self, x): + self.f.write(TYPE_CODE) + self.w_short(x.co_argcount) + self.w_short(x.co_nlocals) + self.w_short(x.co_stacksize) + self.w_short(x.co_flags) + self.dump(x.co_code) + self.dump(x.co_consts) + self.dump(x.co_names) + self.dump(x.co_varnames) + self.dump(x.co_filename) + self.dump(x.co_name) + self.w_short(x.co_firstlineno) + self.dump(x.co_lnotab) + try: + dispatch[CodeType] = dump_code + except NameError: + pass + + +class NULL: + pass + +class Unmarshaller: + + dispatch = {} + + def __init__(self, f): + self.f = f + + def load(self): + c = self.f.read(1) + if not c: + raise EOFError + return self.dispatch[c](self) + + def r_short(self): + read = self.f.read + lo = ord(read(1)) + hi = ord(read(1)) + x = lo | (hi<<8) + if x & 0x8000: + x = x - 0x10000 + return x + + def r_long(self): + read = self.f.read + a = ord(read(1)) + b = ord(read(1)) + c = ord(read(1)) + d = ord(read(1)) + x = a | (b<<8) | (c<<16) | (d<<24) + if d & 0x80 and x > 0: + x = -((1L<<32) - x) + return x + + def r_long64(self): + read = self.f.read + a = ord(read(1)) + b = ord(read(1)) + c = ord(read(1)) + d = ord(read(1)) + e = long(ord(read(1))) + f = long(ord(read(1))) + g = long(ord(read(1))) + h = long(ord(read(1))) + x = a | (b<<8) | (c<<16) | (d<<24) + x = x | (e<<32) | (f<<40) | (g<<48) | (h<<56) + if h & 0x80 and x > 0: + x = -((1L<<64) - x) + return x + + def load_null(self): + return NULL + dispatch[TYPE_NULL] = load_null + + def load_none(self): + return None + dispatch[TYPE_NONE] = load_none + + def load_ellipsis(self): + return EllipsisType + dispatch[TYPE_ELLIPSIS] = load_ellipsis + + def load_int(self): + return self.r_long() + dispatch[TYPE_INT] = load_int + + def load_int64(self): + return self.r_long64() + dispatch[TYPE_INT64] = load_int64 + + def load_long(self): + size = self.r_long() + sign = 1 + if size < 0: + sign = -1 + size = -size + x = 0L + for i in range(size): + d = self.r_short() + x = x | (d<<(i*15L)) + return x * sign + dispatch[TYPE_LONG] = load_long + + def load_float(self): + n = ord(self.f.read(1)) + s = self.f.read(n) + return string.atof(s) + dispatch[TYPE_FLOAT] = load_float + + def load_complex(self): + n = ord(self.f.read(1)) + s = self.f.read(n) + real = float(s) + n = ord(self.f.read(1)) + s = self.f.read(n) + imag = float(s) + return complex(real, imag) + dispatch[TYPE_COMPLEX] = load_complex + + def load_string(self): + n = self.r_long() + return self.f.read(n) + dispatch[TYPE_STRING] = load_string + + def load_tuple(self): + return tuple(self.load_list()) + dispatch[TYPE_TUPLE] = load_tuple + + def load_list(self): + n = self.r_long() + list = [] + for i in range(n): + list.append(self.load()) + return list + dispatch[TYPE_LIST] = load_list + + def load_dict(self): + d = {} + while 1: + key = self.load() + if key is NULL: + break + value = self.load() + d[key] = value + return d + dispatch[TYPE_DICT] = load_dict + + def load_code(self): + argcount = self.r_short() + nlocals = self.r_short() + stacksize = self.r_short() + flags = self.r_short() + code = self.load() + consts = self.load() + names = self.load() + varnames = self.load() + filename = self.load() + name = self.load() + firstlineno = self.r_short() + lnotab = self.load() + if not new: + raise RuntimeError, "can't unmarshal code objects; no 'new' module" + return new.code(argcount, nlocals, stacksize, flags, code, consts, + names, varnames, filename, name, firstlineno, lnotab) + dispatch[TYPE_CODE] = load_code + + +def dump(x, f): + Marshaller(f).dump(x) + +def load(f): + return Unmarshaller(f).load() + +def dumps(x): + f = StringIO.StringIO() + dump(x, f) + return f.getvalue() + +def loads(s): + f = StringIO.StringIO(s) + return load(f) From hpk at codespeak.net Sat Mar 19 23:17:15 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sat, 19 Mar 2005 23:17:15 +0100 (MET) Subject: [pypy-svn] r9908 - pypy/dist/lib-python-2.3.4/test Message-ID: <20050319221715.3F4C427BB7@code1.codespeak.net> Author: hpk Date: Sat Mar 19 23:17:15 2005 New Revision: 9908 Modified: pypy/dist/lib-python-2.3.4/test/conftest.py Log: actually do compare output from "output-tests" with the expected output from the output directory. Modified: pypy/dist/lib-python-2.3.4/test/conftest.py ============================================================================== --- pypy/dist/lib-python-2.3.4/test/conftest.py (original) +++ pypy/dist/lib-python-2.3.4/test/conftest.py Sat Mar 19 23:17:15 2005 @@ -7,6 +7,8 @@ from pypy.interpreter.module import Module as PyPyModule from pypy.interpreter.main import run_string, run_file +from regrtest import reportdiff + # # PyPy's command line extra options (these are added # to py.test's standard options) @@ -30,7 +32,6 @@ 'test_bisect.py', 'test_builtin.py', 'test_call.py', -'test_cgi.py', 'test_cmath.py', 'test_codeop.py', 'test_commands.py', @@ -49,7 +50,7 @@ ) working_outputtests = ( - # well + 'test_cgi.py', ) # sanity check for when the above lists become long @@ -124,11 +125,24 @@ def run(self, driver): space = gettestobjspace('std') try: - run_file(str(self.fspath), space=space) + oldsysout = sys.stdout + sys.stdout = capturesysout = py.std.cStringIO.StringIO() + try: + print self.fspath.purebasename + run_file(str(self.fspath), space=space) + finally: + sys.stdout = oldsysout except OperationError, e: raise self.Failed( excinfo=pytestsupport.AppExceptionInfo(space, e)) - + else: + # we want to compare outputs + result = capturesysout.getvalue() + expected = self.outputpath.read(mode='r') + if result != expected: + reportdiff(expected, result) + assert 0, "expected and real output of running test differ" + class UnittestModule(py.test.collect.Module): def __init__(self, fspath): super(UnittestModule, self).__init__(fspath) @@ -192,4 +206,3 @@ def execute(self): self.space.call_function(self.w_method) - From arigo at codespeak.net Sun Mar 20 00:48:31 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sun, 20 Mar 2005 00:48:31 +0100 (MET) Subject: [pypy-svn] r9909 - in pypy/dist: lib-python-2.3.4/test pypy/module/builtin Message-ID: <20050319234831.CBD2827BBA@code1.codespeak.net> Author: arigo Date: Sun Mar 20 00:48:31 2005 New Revision: 9909 Modified: pypy/dist/lib-python-2.3.4/test/conftest.py pypy/dist/pypy/module/builtin/app_inspect.py Log: Dark cases for isinstance(). Modified: pypy/dist/lib-python-2.3.4/test/conftest.py ============================================================================== --- pypy/dist/lib-python-2.3.4/test/conftest.py (original) +++ pypy/dist/lib-python-2.3.4/test/conftest.py Sun Mar 20 00:48:31 2005 @@ -40,6 +40,7 @@ 'test_heapq.py', 'test_htmllib.py', 'test_htmlparser.py', +'test_isinstance.py', 'test_operator.py', 'test_pprint.py', 'test_sgmllib.py', Modified: pypy/dist/pypy/module/builtin/app_inspect.py ============================================================================== --- pypy/dist/pypy/module/builtin/app_inspect.py (original) +++ pypy/dist/pypy/module/builtin/app_inspect.py Sun Mar 20 00:48:31 2005 @@ -17,12 +17,12 @@ def _recursive_issubclass(cls, klass_or_tuple): if cls is klass_or_tuple: return True - for base in cls.__bases__: + for base in getattr(cls, '__bases__', ()): if _recursive_issubclass(base, klass_or_tuple): return True return False -def issubclass(cls, klass_or_tuple): +def _issubclass(cls, klass_or_tuple, check_cls): if _issubtype(type(klass_or_tuple), tuple): for klass in klass_or_tuple: if issubclass(cls, klass): @@ -31,12 +31,14 @@ try: return _issubtype(cls, klass_or_tuple) except TypeError: - if not hasattr(cls, '__bases__'): + if check_cls and not hasattr(cls, '__bases__'): raise TypeError, "arg 1 must be a class or type" if not hasattr(klass_or_tuple, '__bases__'): raise TypeError, "arg 2 must be a class or type or a tuple thereof" return _recursive_issubclass(cls, klass_or_tuple) +def issubclass(cls, klass_or_tuple): + return _issubclass(cls, klass_or_tuple, True) def isinstance(obj, klass_or_tuple): if issubclass(type(obj), klass_or_tuple): @@ -46,7 +48,8 @@ except AttributeError: return False else: - return objcls is not type(obj) and issubclass(objcls, klass_or_tuple) + return (objcls is not type(obj) and + _issubclass(objcls, klass_or_tuple, False)) def vars(*obj): From tismer at codespeak.net Sun Mar 20 01:11:29 2005 From: tismer at codespeak.net (tismer at codespeak.net) Date: Sun, 20 Mar 2005 01:11:29 +0100 (MET) Subject: [pypy-svn] r9910 - pypy/dist/pypy/objspace/std/test Message-ID: <20050320001129.E87A227BBD@code1.codespeak.net> Author: tismer Date: Sun Mar 20 01:11:29 2005 New Revision: 9910 Modified: pypy/dist/pypy/objspace/std/test/test_stringobject.py Log: added test for str.decode Modified: pypy/dist/pypy/objspace/std/test/test_stringobject.py ============================================================================== --- pypy/dist/pypy/objspace/std/test/test_stringobject.py (original) +++ pypy/dist/pypy/objspace/std/test/test_stringobject.py Sun Mar 20 01:11:29 2005 @@ -516,3 +516,8 @@ assert 'ab' in 'abc' assert not 'd' in 'abc' raises(TypeError, 'a'.__contains__, 1) + + def test_decode(self): + assert 'hello'.decode('rot-13') == 'uryyb' + assert 'hello'.decode('string-escape') == 'hello' + \ No newline at end of file From hpk at codespeak.net Sun Mar 20 01:11:54 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sun, 20 Mar 2005 01:11:54 +0100 (MET) Subject: [pypy-svn] r9911 - pypy/dist/pypy/interpreter Message-ID: <20050320001154.49A6327BBD@code1.codespeak.net> Author: hpk Date: Sun Mar 20 01:11:54 2005 New Revision: 9911 Modified: pypy/dist/pypy/interpreter/gateway.py pypy/dist/pypy/interpreter/lazymodule.py Log: allow applevel to directly understand that source code comes from a specific file (improves error/py.test output) Modified: pypy/dist/pypy/interpreter/gateway.py ============================================================================== --- pypy/dist/pypy/interpreter/gateway.py (original) +++ pypy/dist/pypy/interpreter/gateway.py Sun Mar 20 01:11:54 2005 @@ -487,9 +487,12 @@ NOT_RPYTHON_ATTRIBUTES = ['code'] - def __init__(self, source): + def __init__(self, source, filename=None): "NOT_RPYTHON" - self.code = py.code.Source(source).compile() + if filename is None: + self.code = py.code.Source(source).compile() + else: + self.code = compile(source, filename, 'exec') def getwdict(self, space): return space.loadfromcache(self, applevel._builddict, Modified: pypy/dist/pypy/interpreter/lazymodule.py ============================================================================== --- pypy/dist/pypy/interpreter/lazymodule.py (original) +++ pypy/dist/pypy/interpreter/lazymodule.py Sun Mar 20 01:11:54 2005 @@ -112,4 +112,7 @@ def buildapplevelfrommodule(mod, _): """ NOT_RPYTHON """ source = inspect.getsource(mod) - return gateway.applevel(source) + fn = mod.__file__ + if fn.endswith('.pyc'): + fn = fn[:-1] + return gateway.applevel(source, filename=fn) From tismer at codespeak.net Sun Mar 20 01:13:45 2005 From: tismer at codespeak.net (tismer at codespeak.net) Date: Sun, 20 Mar 2005 01:13:45 +0100 (MET) Subject: [pypy-svn] r9912 - pypy/dist/pypy/objspace/std Message-ID: <20050320001345.20B4727BBD@code1.codespeak.net> Author: tismer Date: Sun Mar 20 01:13:44 2005 New Revision: 9912 Modified: pypy/dist/pypy/objspace/std/stringobject.py Log: fixed str.decode with "string-escape", must not be done via unicode Modified: pypy/dist/pypy/objspace/std/stringobject.py ============================================================================== --- pypy/dist/pypy/objspace/std/stringobject.py (original) +++ pypy/dist/pypy/objspace/std/stringobject.py Sun Mar 20 01:13:44 2005 @@ -945,7 +945,9 @@ "of length %d found"%(len(w_str._value),))) return space.wrap(ord(u_str)) -app = gateway.applevel(r''' +app = gateway.applevel(r''' + import codecs + def str_translate__String_ANY_ANY(s, table, deletechars=''): """charfilter - unicode handling is not implemented @@ -996,9 +998,9 @@ if encoding is None and errors is None: return unicode(str) elif errors is None: - return unicode(str, encoding) + return codecs.getdecoder(encoding)(str)[0] else: - return unicode(str, encoding, errors) + return codecs.getdecoder(encoding)(str, errors)[0] ''') str_translate__String_ANY_ANY = app.interphook('str_translate__String_ANY_ANY') From tismer at codespeak.net Sun Mar 20 01:15:55 2005 From: tismer at codespeak.net (tismer at codespeak.net) Date: Sun, 20 Mar 2005 01:15:55 +0100 (MET) Subject: [pypy-svn] r9913 - pypy/dist/pypy/interpreter Message-ID: <20050320001555.A603727BBD@code1.codespeak.net> Author: tismer Date: Sun Mar 20 01:15:55 2005 New Revision: 9913 Modified: pypy/dist/pypy/interpreter/executioncontext.py pypy/dist/pypy/interpreter/interactive.py Log: corrected handling of __main__ in interactive mode. Will have to check whether executioncontext is needed there as a property, also w_globals is questionable. Modified: pypy/dist/pypy/interpreter/executioncontext.py ============================================================================== --- pypy/dist/pypy/interpreter/executioncontext.py (original) +++ pypy/dist/pypy/interpreter/executioncontext.py Sun Mar 20 01:15:55 2005 @@ -32,6 +32,7 @@ except IndexError: return self.space.builtin + # XXX this one should probably be dropped in favor of a module def make_standard_w_globals(self): "Create a new empty 'globals' dictionary." w_key = self.space.wrap("__builtins__") Modified: pypy/dist/pypy/interpreter/interactive.py ============================================================================== --- pypy/dist/pypy/interpreter/interactive.py (original) +++ pypy/dist/pypy/interpreter/interactive.py Sun Mar 20 01:15:55 2005 @@ -1,7 +1,7 @@ import autopath from pypy.interpreter import error -from pypy.interpreter import executioncontext, baseobjspace +from pypy.interpreter import executioncontext, baseobjspace, module import sys import code import time @@ -13,10 +13,16 @@ self.space = objspace self.verbose = verbose self.ec = executioncontext.ExecutionContext(self.space) - self.w_globals = self.ec.make_standard_w_globals() - self.space.setitem(self.w_globals, - self.space.wrap("__name__"), - self.space.wrap("__main__")) + + space=self.space + w_main = space.wrap('__main__') + mainmodule = module.Module(space, w_main) + w_modules = space.sys.get('modules') + space.setitem(w_modules, w_main, mainmodule) + + self.w_globals = mainmodule.w_dict + space.setitem(self.w_globals, space.wrap('__builtins__'), space.builtin) + # XXX check: do we need self.ec, self.w_globals? def interact(self, banner=None): if banner is None: From arigo at codespeak.net Sun Mar 20 01:17:42 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sun, 20 Mar 2005 01:17:42 +0100 (MET) Subject: [pypy-svn] r9914 - pypy/dist/pypy/module/builtin Message-ID: <20050320001742.1F83A27BBD@code1.codespeak.net> Author: arigo Date: Sun Mar 20 01:17:41 2005 New Revision: 9914 Added: pypy/dist/pypy/module/builtin/app_buffer.py (contents, props changed) Modified: pypy/dist/pypy/module/builtin/__init__.py pypy/dist/pypy/module/builtin/app_misc.py Log: A limited implementation of buffer(). Modified: pypy/dist/pypy/module/builtin/__init__.py ============================================================================== --- pypy/dist/pypy/module/builtin/__init__.py (original) +++ pypy/dist/pypy/module/builtin/__init__.py Sun Mar 20 01:17:41 2005 @@ -51,7 +51,7 @@ 'intern' : 'app_misc.intern', 'unichr' : 'app_misc.unichr', - 'buffer' : 'app_misc.buffer', + 'buffer' : 'app_buffer.buffer', 'reload' : 'app_misc.reload', } Added: pypy/dist/pypy/module/builtin/app_buffer.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/module/builtin/app_buffer.py Sun Mar 20 01:17:41 2005 @@ -0,0 +1,46 @@ +# Might probably be deprecated in Python at some point. + +class buffer(object): + """buffer(object [, offset[, size]]) + +Create a new buffer object which references the given object. +The buffer will reference a slice of the target object from the +start of the object (or at the specified offset). The slice will +extend to the end of the target object (or with the specified size). +""" + + def __init__(self, object, offset=0, size=None): + if isinstance(object, str): + pass + elif isinstance(object, buffer): + object = object.buf + else: + # XXX check for more types + raise TypeError, "buffer object expected" + if size is None: + self.buf = object[offset:] + else: + self.buf = object[offset:offset+size] + + def __str__(self): + return self.buf + + def __add__(self, other): + return self.buf + buffer(other).buf + + def __mul__(self, count): + return self.buf * count + + __rmul__ = __mul__ + + def __cmp__(self, other): + return cmp(self.buf, buffer(other).buf) + + def __getitem__(self, index_or_slice): + return self.buf[index_or_slice] + + def __hash__(self): + return hash(self.buf) + + def __len__(self): + return len(self.buf) Modified: pypy/dist/pypy/module/builtin/app_misc.py ============================================================================== --- pypy/dist/pypy/module/builtin/app_misc.py (original) +++ pypy/dist/pypy/module/builtin/app_misc.py Sun Mar 20 01:17:41 2005 @@ -18,11 +18,6 @@ return unicode('\\U%08x' %(code), 'unicode-escape') -class buffer(object): - def __init__(self, object, offset=None, size=None): - raise NotImplementedError, "XXX nobody needs this anyway" - - def reload(module): import imp, sys, errno From tismer at codespeak.net Sun Mar 20 01:21:51 2005 From: tismer at codespeak.net (tismer at codespeak.net) Date: Sun, 20 Mar 2005 01:21:51 +0100 (MET) Subject: [pypy-svn] r9915 - pypy/dist/pypy/objspace/std Message-ID: <20050320002151.33A9D27BBD@code1.codespeak.net> Author: tismer Date: Sun Mar 20 01:21:51 2005 New Revision: 9915 Modified: pypy/dist/pypy/objspace/std/objecttype.py Log: added __hash__, __reduce_ex__ and __reduce__ (as an alias) to object. We did not care about double-redirecting __reduce__, btw. See typeobject.c, this is most probably just for backward c-level compatibility. Modified: pypy/dist/pypy/objspace/std/objecttype.py ============================================================================== --- pypy/dist/pypy/objspace/std/objecttype.py (original) +++ pypy/dist/pypy/objspace/std/objecttype.py Sun Mar 20 01:21:51 2005 @@ -35,9 +35,97 @@ w_obj.__init__(space) return w_obj +def descr__hash__(space, w_obj): + return space.id(w_obj) + def descr__init__(space, w_obj, __args__): pass +def descr__reduce_ex__(space, w_obj, __args__): + funcname = "__reduce_ex__" + signature = ['proto'], None, None + defaults_w = [space.wrap(0)] + w_proto, = __args__.parse(funcname, signature, defaults_w) + + # we intentionally avoid to ask for __reduce__ here + # XXX check for integerness of proto ? + + if space.is_true(space.ge(w_proto, space.wrap(2))): + return reduce_2(space, w_obj) + + return reduce_1(space, w_obj, w_proto) + +app = gateway.applevel(r''' +def reduce_1(obj, proto): + import copy_reg + return copy_reg._reduce_ex(obj, proto) + +def reduce_2(obj): + cls = obj.__class__ + + try: + getnewargs = obj.__getnewargs__ + except AttributeError: + args = () + else: + args = getnewargs() + if not isinstance(args, tuple): + raise TypeError, "__getnewargs__ should return a tuple" + + try: + getstate = obj.__getstate__ + except AttributeError: + state = getattr(obj, "__dict__", None) + names = slotnames(cls) # not checking for list + if names is not None: + slots = {} + for name in names: + try: + value = getattr(obj, name) + except AttributeError: + pass + else: + slots[name] = value + if slots: + state = state, slots + else: + state = getstate() + + if isinstance(obj, list): + listitems = iter(obj) + else: + listitems = None + + if isinstance(obj, dict): + dictitems = obj.iteritems() + else: + dictitems = None + + import copy_reg + newobj = copy_reg.__newobj__ + + args2 = (cls,) + args + return newobj, args2, state, listitems, dictitems + +def slotnames(cls): + if not isinstance(cls, type): + return None + + try: + return cls.__dict__["__slotnames__"] + except KeyError: + pass + + import copy_reg + slotnames = copy_reg._slotnames(cls) + if not isinstance(slotnames, list) and slotnames is not None: + raise TypeError, "copy_reg._slotnames didn't return a list or None" + return slotnames +''') + +reduce_1 = app.interphook('reduce_1') +reduce_2 = app.interphook('reduce_2') + # ____________________________________________________________ object_typedef = StdTypeDef("object", @@ -49,6 +137,11 @@ __class__ = GetSetProperty(descr__class__), __new__ = newmethod(descr__new__, unwrap_spec = [gateway.ObjSpace,gateway.W_Root,gateway.Arguments]), + __hash__ = gateway.interp2app(descr__hash__), + __reduce_ex__ = gateway.interp2app(descr__reduce_ex__, + unwrap_spec=[gateway.ObjSpace,gateway.W_Root,gateway.Arguments]), + __reduce__ = gateway.interp2app(descr__reduce_ex__, + unwrap_spec=[gateway.ObjSpace,gateway.W_Root,gateway.Arguments]), __init__ = gateway.interp2app(descr__init__, unwrap_spec=[gateway.ObjSpace,gateway.W_Root,gateway.Arguments]), ) From arigo at codespeak.net Sun Mar 20 01:49:25 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sun, 20 Mar 2005 01:49:25 +0100 (MET) Subject: [pypy-svn] r9916 - pypy/dist/lib-python-2.3.4/test Message-ID: <20050320004925.37F1727B4F@code1.codespeak.net> Author: arigo Date: Sun Mar 20 01:49:25 2005 New Revision: 9916 Modified: pypy/dist/lib-python-2.3.4/test/conftest.py Log: more passing CPython tests. Modified: pypy/dist/lib-python-2.3.4/test/conftest.py ============================================================================== --- pypy/dist/lib-python-2.3.4/test/conftest.py (original) +++ pypy/dist/lib-python-2.3.4/test/conftest.py Sun Mar 20 01:49:25 2005 @@ -37,7 +37,10 @@ 'test_commands.py', 'test_compare.py', 'test_compile.py', +'test_dis.py', +'test_hash.py', 'test_heapq.py', +'test_hexoct.py', 'test_htmllib.py', 'test_htmlparser.py', 'test_isinstance.py', From pedronis at codespeak.net Sun Mar 20 02:04:07 2005 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Sun, 20 Mar 2005 02:04:07 +0100 (MET) Subject: [pypy-svn] r9917 - pypy/dist/pypy/lib Message-ID: <20050320010407.4318327B53@code1.codespeak.net> Author: pedronis Date: Sun Mar 20 02:04:07 2005 New Revision: 9917 Modified: pypy/dist/pypy/lib/marshal.py Log: marshal for bools Modified: pypy/dist/pypy/lib/marshal.py ============================================================================== --- pypy/dist/pypy/lib/marshal.py (original) +++ pypy/dist/pypy/lib/marshal.py Sun Mar 20 02:04:07 2005 @@ -27,7 +27,8 @@ TYPE_DICT = '{' TYPE_CODE = 'c' TYPE_UNKNOWN = '?' - +FALSE_CODE = 'F' +TRUE_CODE = 'T' class Marshaller: @@ -57,14 +58,22 @@ def dump_none(self, x): self.f.write(TYPE_NONE) - dispatch[NoneType] = dump_none + dispatch[NoneType] = dump_none + + def dump_bool(self, x): + if x: + self.f.write(TRUE_CODE) + else: + self.f.write(FALSE_CODE) + dispatch[bool] = dump_bool def dump_ellipsis(self, x): self.f.write(TYPE_ELLIPSIS) - try: - dispatch[EllipsisType] = dump_ellipsis - except NameError: - pass + + try: + dispatch[EllipsisType] = dump_ellipsis + except NameError: + pass def dump_int(self, x): y = x>>31 @@ -221,6 +230,14 @@ return None dispatch[TYPE_NONE] = load_none + def load_true(self): + return True + dispatch[TRUE_CODE] = load_true + + def load_false(self): + return False + dispatch[FALSE_CODE] = load_false + def load_ellipsis(self): return EllipsisType dispatch[TYPE_ELLIPSIS] = load_ellipsis From arigo at codespeak.net Sun Mar 20 15:51:53 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sun, 20 Mar 2005 15:51:53 +0100 (MET) Subject: [pypy-svn] r9918 - in pypy/dist/pypy: interpreter objspace/std Message-ID: <20050320145153.76F7827B58@code1.codespeak.net> Author: arigo Date: Sun Mar 20 15:51:53 2005 New Revision: 9918 Modified: pypy/dist/pypy/interpreter/typedef.py pypy/dist/pypy/objspace/std/booltype.py pypy/dist/pypy/objspace/std/typeobject.py Log: Prevent 'bool' from being subclassed. Modified: pypy/dist/pypy/interpreter/typedef.py ============================================================================== --- pypy/dist/pypy/interpreter/typedef.py (original) +++ pypy/dist/pypy/interpreter/typedef.py Sun Mar 20 15:51:53 2005 @@ -16,6 +16,7 @@ self.base = __base self.hasdict = '__dict__' in rawdict or (__base and __base.hasdict) self.rawdict = rawdict + self.acceptable_as_base_class = True unique_interplevel_subclass_cache = Cache() Modified: pypy/dist/pypy/objspace/std/booltype.py ============================================================================== --- pypy/dist/pypy/objspace/std/booltype.py (original) +++ pypy/dist/pypy/objspace/std/booltype.py Sun Mar 20 15:51:53 2005 @@ -15,3 +15,4 @@ bool_typedef = StdTypeDef("bool", int_typedef, __new__ = newmethod(descr__new__), ) +bool_typedef.acceptable_as_base_class = False Modified: pypy/dist/pypy/objspace/std/typeobject.py ============================================================================== --- pypy/dist/pypy/objspace/std/typeobject.py (original) +++ pypy/dist/pypy/objspace/std/typeobject.py Sun Mar 20 15:51:53 2005 @@ -34,6 +34,11 @@ raise OperationError(space.w_TypeError, space.wrap("instance layout conflicts in " "multiple inheritance")) + if not instancetypedef.acceptable_as_base_class: + raise OperationError(space.w_TypeError, + space.wrap("type '%s' is not an " + "acceptable base class" % + instancetypedef.name)) w_self.instancetypedef = instancetypedef w_self.hasdict = False hasoldstylebase = False From tismer at codespeak.net Sun Mar 20 16:18:05 2005 From: tismer at codespeak.net (tismer at codespeak.net) Date: Sun, 20 Mar 2005 16:18:05 +0100 (MET) Subject: [pypy-svn] r9919 - pypy/dist/pypy/lib/test2 Message-ID: <20050320151805.EF6B627B56@code1.codespeak.net> Author: tismer Date: Sun Mar 20 16:18:05 2005 New Revision: 9919 Added: pypy/dist/pypy/lib/test2/test_obj.py Log: tests for __hash__, __reduce__ to come Added: pypy/dist/pypy/lib/test2/test_obj.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/lib/test2/test_obj.py Sun Mar 20 16:18:05 2005 @@ -0,0 +1,23 @@ +# -*- coding: iso-8859-1 -*- +import unittest, test.test_support +import sys, cStringIO + +class ObjectTest(unittest.TestCase): + + def test_hash_builtin(self): + o = object() + self.assertEquals(hash(o), id(o)) + + def test_hash_method(self): + o = object() + self.assertEquals(hash(o), o.__hash__()) + + def test_hash_list(self): + l = range(5) + self.assertRaises(TypeError, hash, l) + +def test_main(): + test.test_support.run_unittest(ObjectTest) + +if __name__ == "__main__": + test_main() From tismer at codespeak.net Sun Mar 20 16:23:18 2005 From: tismer at codespeak.net (tismer at codespeak.net) Date: Sun, 20 Mar 2005 16:23:18 +0100 (MET) Subject: [pypy-svn] r9920 - pypy/dist/pypy/objspace/std Message-ID: <20050320152318.2F94D27B56@code1.codespeak.net> Author: tismer Date: Sun Mar 20 16:23:18 2005 New Revision: 9920 Modified: pypy/dist/pypy/objspace/std/objecttype.py Log: fixing the wrapping level Modified: pypy/dist/pypy/objspace/std/objecttype.py ============================================================================== --- pypy/dist/pypy/objspace/std/objecttype.py (original) +++ pypy/dist/pypy/objspace/std/objecttype.py Sun Mar 20 16:23:18 2005 @@ -41,18 +41,13 @@ def descr__init__(space, w_obj, __args__): pass -def descr__reduce_ex__(space, w_obj, __args__): - funcname = "__reduce_ex__" - signature = ['proto'], None, None - defaults_w = [space.wrap(0)] - w_proto, = __args__.parse(funcname, signature, defaults_w) - +def descr__reduce_ex__(space, w_obj, proto=0): # we intentionally avoid to ask for __reduce__ here # XXX check for integerness of proto ? - if space.is_true(space.ge(w_proto, space.wrap(2))): + if proto >= 2: return reduce_2(space, w_obj) - + w_proto = space.wrap(proto) return reduce_1(space, w_obj, w_proto) app = gateway.applevel(r''' @@ -139,9 +134,9 @@ unwrap_spec = [gateway.ObjSpace,gateway.W_Root,gateway.Arguments]), __hash__ = gateway.interp2app(descr__hash__), __reduce_ex__ = gateway.interp2app(descr__reduce_ex__, - unwrap_spec=[gateway.ObjSpace,gateway.W_Root,gateway.Arguments]), + unwrap_spec=[gateway.ObjSpace,gateway.W_Root,int]), __reduce__ = gateway.interp2app(descr__reduce_ex__, - unwrap_spec=[gateway.ObjSpace,gateway.W_Root,gateway.Arguments]), + unwrap_spec=[gateway.ObjSpace,gateway.W_Root,int]), __init__ = gateway.interp2app(descr__init__, unwrap_spec=[gateway.ObjSpace,gateway.W_Root,gateway.Arguments]), ) From alex at codespeak.net Sun Mar 20 16:34:41 2005 From: alex at codespeak.net (alex at codespeak.net) Date: Sun, 20 Mar 2005 16:34:41 +0100 (MET) Subject: [pypy-svn] r9921 - pypy/dist/pypy/lib/test2 Message-ID: <20050320153441.909CA27B56@code1.codespeak.net> Author: alex Date: Sun Mar 20 16:34:41 2005 New Revision: 9921 Modified: pypy/dist/pypy/lib/test2/test_obj.py Log: test pickle (plain) on user class Modified: pypy/dist/pypy/lib/test2/test_obj.py ============================================================================== --- pypy/dist/pypy/lib/test2/test_obj.py (original) +++ pypy/dist/pypy/lib/test2/test_obj.py Sun Mar 20 16:34:41 2005 @@ -1,23 +1,36 @@ -# -*- coding: iso-8859-1 -*- -import unittest, test.test_support -import sys, cStringIO - -class ObjectTest(unittest.TestCase): - - def test_hash_builtin(self): - o = object() - self.assertEquals(hash(o), id(o)) - - def test_hash_method(self): - o = object() - self.assertEquals(hash(o), o.__hash__()) - - def test_hash_list(self): - l = range(5) - self.assertRaises(TypeError, hash, l) - -def test_main(): - test.test_support.run_unittest(ObjectTest) - -if __name__ == "__main__": - test_main() +# -*- coding: iso-8859-1 -*- +import unittest, test.test_support +import sys, cStringIO, pickle + +class Picklable(object): + def __init__(self): + self.a = 5 + def __eq__(self, other): + return self.a == other.a + +class ObjectTest(unittest.TestCase): + + def test_hash_builtin(self): + o = object() + self.assertEquals(hash(o), id(o)) + + def test_hash_method(self): + o = object() + self.assertEquals(hash(o), o.__hash__()) + + def test_hash_list(self): + l = range(5) + self.assertRaises(TypeError, hash, l) + + def test_pickle_plain(self): + x = Picklable() + for proto in range(pickle.HIGHEST_PROTOCOL + 1): + s = pickle.dumps(x, proto) + y = pickle.loads(s) + self.assertEqual(x, y) + +def test_main(): + test.test_support.run_unittest(ObjectTest) + +if __name__ == "__main__": + test_main() From alex at codespeak.net Sun Mar 20 16:37:42 2005 From: alex at codespeak.net (alex at codespeak.net) Date: Sun, 20 Mar 2005 16:37:42 +0100 (MET) Subject: [pypy-svn] r9922 - pypy/dist/pypy/lib/test2 Message-ID: <20050320153742.21F8C27B56@code1.codespeak.net> Author: alex Date: Sun Mar 20 16:37:41 2005 New Revision: 9922 Modified: pypy/dist/pypy/lib/test2/test_obj.py Log: fixed tabs Modified: pypy/dist/pypy/lib/test2/test_obj.py ============================================================================== --- pypy/dist/pypy/lib/test2/test_obj.py (original) +++ pypy/dist/pypy/lib/test2/test_obj.py Sun Mar 20 16:37:41 2005 @@ -4,9 +4,10 @@ class Picklable(object): def __init__(self): - self.a = 5 + self.a = 5 def __eq__(self, other): - return self.a == other.a + return self.a == other.a + class ObjectTest(unittest.TestCase): @@ -23,11 +24,11 @@ self.assertRaises(TypeError, hash, l) def test_pickle_plain(self): - x = Picklable() - for proto in range(pickle.HIGHEST_PROTOCOL + 1): - s = pickle.dumps(x, proto) - y = pickle.loads(s) - self.assertEqual(x, y) + x = Picklable() + for proto in range(pickle.HIGHEST_PROTOCOL + 1): + s = pickle.dumps(x, proto) + y = pickle.loads(s) + self.assertEqual(x, y) def test_main(): test.test_support.run_unittest(ObjectTest) From tismer at codespeak.net Sun Mar 20 16:40:27 2005 From: tismer at codespeak.net (tismer at codespeak.net) Date: Sun, 20 Mar 2005 16:40:27 +0100 (MET) Subject: [pypy-svn] r9923 - pypy/dist/pypy/lib/test2 Message-ID: <20050320154027.EDDFF27B56@code1.codespeak.net> Author: tismer Date: Sun Mar 20 16:40:27 2005 New Revision: 9923 Modified: pypy/dist/pypy/lib/test2/test_obj.py (props changed) Log: fixeol From arigo at codespeak.net Sun Mar 20 16:44:03 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sun, 20 Mar 2005 16:44:03 +0100 (MET) Subject: [pypy-svn] r9925 - in pypy/dist/pypy/objspace/std: . test Message-ID: <20050320154403.826CC27B56@code1.codespeak.net> Author: arigo Date: Sun Mar 20 16:44:03 2005 New Revision: 9925 Modified: pypy/dist/pypy/objspace/std/restricted_int.py pypy/dist/pypy/objspace/std/stringobject.py pypy/dist/pypy/objspace/std/test/test_stringobject.py Log: - str.startswith(), str.endswith() must return booleans. - implement str.__hash__(). Modified: pypy/dist/pypy/objspace/std/restricted_int.py ============================================================================== --- pypy/dist/pypy/objspace/std/restricted_int.py (original) +++ pypy/dist/pypy/objspace/std/restricted_int.py Sun Mar 20 16:44:03 2005 @@ -147,6 +147,15 @@ LONG_BIT = _bits+1 LONG_MASK = _Ltest*2-1 +LONG_TEST = _Ltest + +def intmask(n): + if isinstance(n, int): + return n + n &= LONG_MASK + if n >= LONG_TEST: + n -= 2*LONG_TEST + return int(n) del _bits, _itest, _Ltest Modified: pypy/dist/pypy/objspace/std/stringobject.py ============================================================================== --- pypy/dist/pypy/objspace/std/stringobject.py (original) +++ pypy/dist/pypy/objspace/std/stringobject.py Sun Mar 20 16:44:03 2005 @@ -77,6 +77,7 @@ from pypy.objspace.std.objspace import * from pypy.interpreter import gateway from pypy.objspace.std.intobject import W_IntObject +from pypy.objspace.std.restricted_int import intmask from pypy.objspace.std.sliceobject import W_SliceObject from pypy.objspace.std import slicetype from pypy.objspace.std.listobject import W_ListObject @@ -638,7 +639,7 @@ else: found = 1 - return W_IntObject(space, found) + return space.newbool(found) def str_startswith__String_String_ANY(space, w_self, w_prefix, w_start): @@ -654,7 +655,7 @@ else: found = 1 - return W_IntObject(space, found) + return space.newbool(found) def _tabindent(u_token, u_tabsize): @@ -752,7 +753,17 @@ def hash__String(space, w_str): w_hash = w_str.w_hash if w_hash is None: - w_hash = W_IntObject(space, hash(w_str._value)) + s = w_str._value + try: + x = ord(s[0]) << 7 + except IndexError: + x = 0 + else: + for c in s: + x = (1000003*x) ^ ord(c) + x ^= len(s) + # unlike CPython, there is no reason to avoid to return -1 + w_hash = W_IntObject(space, intmask(x)) w_str.w_hash = w_hash return w_hash Modified: pypy/dist/pypy/objspace/std/test/test_stringobject.py ============================================================================== --- pypy/dist/pypy/objspace/std/test/test_stringobject.py (original) +++ pypy/dist/pypy/objspace/std/test/test_stringobject.py Sun Mar 20 16:44:03 2005 @@ -268,31 +268,31 @@ assert 'aaa'.count('a', 0, -10) == 0 def test_startswith(self): - assert 'ab'.startswith('ab') == 1 - assert 'ab'.startswith('a') == 1 - assert 'ab'.startswith('') == 1 - assert 'x'.startswith('a') == 0 - assert 'x'.startswith('x') == 1 - assert ''.startswith('') == 1 - assert ''.startswith('a') == 0 - assert 'x'.startswith('xx') == 0 - assert 'y'.startswith('xx') == 0 + assert 'ab'.startswith('ab') is True + assert 'ab'.startswith('a') is True + assert 'ab'.startswith('') is True + assert 'x'.startswith('a') is False + assert 'x'.startswith('x') is True + assert ''.startswith('') is True + assert ''.startswith('a') is False + assert 'x'.startswith('xx') is False + assert 'y'.startswith('xx') is False def test_startswith_more(self): - assert 'ab'.startswith('a', 0) == 1 - assert 'ab'.startswith('a', 1) == 0 - assert 'ab'.startswith('b', 1) == 1 + assert 'ab'.startswith('a', 0) is True + assert 'ab'.startswith('a', 1) is False + assert 'ab'.startswith('b', 1) is True def test_endswith(self): - assert 'ab'.endswith('ab') == 1 - assert 'ab'.endswith('b') == 1 - assert 'ab'.endswith('') == 1 - assert 'x'.endswith('a') == 0 - assert 'x'.endswith('x') == 1 - assert ''.endswith('') == 1 - assert ''.endswith('a') == 0 - assert 'x'.endswith('xx') == 0 - assert 'y'.endswith('xx') == 0 + assert 'ab'.endswith('ab') is True + assert 'ab'.endswith('b') is True + assert 'ab'.endswith('') is True + assert 'x'.endswith('a') is False + assert 'x'.endswith('x') is True + assert ''.endswith('') is True + assert ''.endswith('a') is False + assert 'x'.endswith('xx') is False + assert 'y'.endswith('xx') is False def test_expandtabs(self): assert 'abc\rab\tdef\ng\thi'.expandtabs() == 'abc\rab def\ng hi' @@ -520,4 +520,10 @@ def test_decode(self): assert 'hello'.decode('rot-13') == 'uryyb' assert 'hello'.decode('string-escape') == 'hello' - \ No newline at end of file + + def test_hash(self): + # check that we have the same hash as CPython for at least 31 bits + # (but don't go checking CPython's special case -1) + assert hash('') == 0 + assert hash('hello') & 0x7fffffff == 0x347697fd + assert hash('hello world!') & 0x7fffffff == 0x2f0bb411 From alex at codespeak.net Sun Mar 20 16:45:35 2005 From: alex at codespeak.net (alex at codespeak.net) Date: Sun, 20 Mar 2005 16:45:35 +0100 (MET) Subject: [pypy-svn] r9926 - pypy/dist/pypy/lib/test2 Message-ID: <20050320154535.1F68427B56@code1.codespeak.net> Author: alex Date: Sun Mar 20 16:45:34 2005 New Revision: 9926 Modified: pypy/dist/pypy/lib/test2/test_obj.py Log: add test for pickling object w/__reduce__ returning a 2-tuple Modified: pypy/dist/pypy/lib/test2/test_obj.py ============================================================================== --- pypy/dist/pypy/lib/test2/test_obj.py (original) +++ pypy/dist/pypy/lib/test2/test_obj.py Sun Mar 20 16:45:34 2005 @@ -3,11 +3,16 @@ import sys, cStringIO, pickle class Picklable(object): - def __init__(self): - self.a = 5 + def __init__(self, a=5): + self.a = a def __eq__(self, other): return self.a == other.a - + def __str__(self): + return '%s(%r)' % (self.__class__.__name__, self.a) + +class PicklableSpecial2(Picklable): + def __reduce__(self): + return self.__class__, (self.a,) class ObjectTest(unittest.TestCase): @@ -23,13 +28,18 @@ l = range(5) self.assertRaises(TypeError, hash, l) - def test_pickle_plain(self): - x = Picklable() + def _pickle_some(self, x): for proto in range(pickle.HIGHEST_PROTOCOL + 1): s = pickle.dumps(x, proto) y = pickle.loads(s) self.assertEqual(x, y) + def test_pickle_plain(self): + self._pickle_some(Picklable()) + + def test_pickle_special2(self): + self._pickle_some(PicklableSpecial2()) + def test_main(): test.test_support.run_unittest(ObjectTest) From hpk at codespeak.net Sun Mar 20 16:48:53 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sun, 20 Mar 2005 16:48:53 +0100 (MET) Subject: [pypy-svn] r9927 - in pypy/dist/pypy: documentation documentation/revreport tool Message-ID: <20050320154853.3F7B027B56@code1.codespeak.net> Author: hpk Date: Sun Mar 20 16:48:53 2005 New Revision: 9927 Added: pypy/dist/pypy/documentation/__init__.py (contents, props changed) pypy/dist/pypy/documentation/revreport/ (props changed) pypy/dist/pypy/documentation/revreport/__init__.py (contents, props changed) pypy/dist/pypy/documentation/revreport/autopath.py - copied unchanged from r9902, pypy/dist/pypy/tool/autopath.py pypy/dist/pypy/documentation/revreport/delta.css - copied unchanged from r9902, pypy/dist/pypy/tool/delta.css pypy/dist/pypy/documentation/revreport/delta.js - copied unchanged from r9902, pypy/dist/pypy/tool/delta.js pypy/dist/pypy/documentation/revreport/delta.py - copied, changed from r9902, pypy/dist/pypy/tool/delta.py Removed: pypy/dist/pypy/tool/delta.css pypy/dist/pypy/tool/delta.js pypy/dist/pypy/tool/delta.py Log: move Samuele's deltareport tool to pypy/documentation/revreport where we should put all "revision" related reports (including nightly tests and other stuff at some point) Added: pypy/dist/pypy/documentation/__init__.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/documentation/__init__.py Sun Mar 20 16:48:53 2005 @@ -0,0 +1 @@ +# Added: pypy/dist/pypy/documentation/revreport/__init__.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/documentation/revreport/__init__.py Sun Mar 20 16:48:53 2005 @@ -0,0 +1 @@ +# Copied: pypy/dist/pypy/documentation/revreport/delta.py (from r9902, pypy/dist/pypy/tool/delta.py) ============================================================================== --- pypy/dist/pypy/tool/delta.py (original) +++ pypy/dist/pypy/documentation/revreport/delta.py Sun Mar 20 16:48:53 2005 @@ -2,14 +2,7 @@ from pypy.interpreter.error import OperationError from py.xml import html - -class html_plus(html): - __tagspec__ = html.__tagspec__.copy() - - __tagspec__['button'] = 1 - __tagspec__['script'] = 1 - -html = html_plus +import py import os, sys from sets import Set @@ -21,6 +14,7 @@ WHITE = "#ffffff" BLACK = "#000000" GREY = "#808080" +GREEN = "#00ff00" def incompleteness_bar(DIR, incompleteness): from PIL import Image, ImageDraw, ImageColor @@ -29,6 +23,7 @@ white = ImageColor.getrgb(WHITE) black = ImageColor.getrgb(BLACK) grey = ImageColor.getrgb(GREY) + green = ImageColor.getrgb(GREEN) if incompleteness == -1.0: inc = -1 @@ -39,27 +34,21 @@ inc == 1 name = "bar_%d.png" % inc - imgfname = os.path.join(DIR,'images',name) - - if not os.path.exists(imgfname): - img = Image.new("RGB",(W,H), red) + IMGDIR = DIR.join('images') + IMGDIR.ensure(dir=1) + imgfname = IMGDIR.join(name) + if not imgfname.check(): + img = Image.new("RGB", (W,H), red) draw = ImageDraw.Draw(img) if inc == -1: draw.rectangle([0,0,W-1,H-1], outline=black, fill=white) else: if W-1-inc != 0: - draw.rectangle([0,0,W-1-inc,H-1],outline=grey, fill=grey) - - IMGDIR = os.path.join(DIR,'images') - - if not os.path.isdir(IMGDIR): - os.mkdir(IMGDIR) - - img.save(imgfname,optimize=True) - - return html.img(src=os.path.join('images', name),alt="incompleteness=%.2f" % incompleteness) - + draw.rectangle([0,0,W-1-inc,H-1], outline=black, fill=green) + img.save(str(imgfname),optimize=True) + return html.img(src='images/%s' % name, + alt="incompleteness=%.2f" % incompleteness) NOTFOUND = object() @@ -220,7 +209,8 @@ class Status: - def __init__(self, msg, detail_missing, class_, incompleteness, shortmsg = None): + def __init__(self, msg, detail_missing, class_, + incompleteness, shortmsg = None): self.msg = msg self.detail_missing = detail_missing self.class_ = class_ @@ -325,9 +315,7 @@ class Report(Entry): useshort = False - notes = None - descr = granddescr = "" def __init__(self, name, title=None, fname=None, **kwds): @@ -415,12 +403,6 @@ return self.shortname, self.fname() def fill_table(self, dir, tbl, rows): - def set_class(class_): - if class_ is None: - return {} - else: - return {'class': class_} - i = 0 for name, entry, rest, st in rows: tr_class = i%2 == 0 and "even" or "odd" @@ -430,20 +412,15 @@ msg = st.msg rest = rest + [incompleteness_bar(dir, st.incompleteness), msg] tbl.append(html.tr( - html.td(entry.link(name), **set_class(st.class_)), - *map(html.td,rest), **{'class': tr_class}) - ) + html.td(entry.link(name), class_=st.class_), + class_=tr_class, + *map(html.td,rest)) + ) i += 1 def html(self, dir): title = self.title - def set_class(class_): - if class_ is None: - return {} - else: - return {'class': class_} - if self.notes is not None: notes = html.p(self.notes) else: @@ -466,21 +443,28 @@ incompleteness_table = html.table(id="incompleteness", style=HIDE) toggle = html.p("sort:", - html.button("alphabetical", type="button", onclick="toggle(ALPHA)"),'|', - html.button("incompleteness", type="button", onclick="toggle(INCOMPLETENESS)"),'|', - html.button("# overall missing", type="button", onclick="toggle(GRANDMISSING)")) + html.button("alphabetical", + type="button", onclick="toggle(ALPHA)"), + '|', + html.button("incompleteness", + type="button", onclick="toggle(INCOMPLETENESS)"), + '|', + html.button("# overall missing", + type="button", onclick="toggle(GRANDMISSING)")) page = html.html( html.head(html.title(title), - html.link(href="delta.css", rel="stylesheet", type="text/css"), - html.script(' ',type="text/javascript",src="delta.js")), + html.link(href="delta.css", rel="stylesheet", + type="text/css"), + html.script(' ',type="text/javascript", src="delta.js")), html.body(self.navig(), - html.p(msg, bar, **set_class(class_)), + html.p(msg, bar, class_=class_), toggle, alpha_table, grandmissing_table, incompleteness_table, - notes), xmlns="http://www.w3.org/1999/xhtml") + notes), + xmlns="http://www.w3.org/1999/xhtml") rows = [] for name, entry, rest, parent in self.rows: @@ -489,17 +473,17 @@ self.fill_table(dir, alpha_table, rows) - rows.sort(lambda (name1, ent1, r1, st1),(name2, ent2, r2, st2): -cmp(st1.detail_missing, st2.detail_missing)) + rows.sort(lambda (name1, ent1, r1, st1), (name2, ent2, r2, st2): + -cmp(st1.detail_missing, st2.detail_missing)) self.fill_table(dir, grandmissing_table, rows) - rows.sort(lambda (name1, ent1, r1, st1),(name2, ent2, r2, st2): -cmp(st1.incompleteness, st2.incompleteness)) + rows.sort(lambda (name1, ent1, r1, st1),(name2, ent2, r2, st2): + -cmp(st1.incompleteness, st2.incompleteness)) self.fill_table(dir, incompleteness_table, rows) - f = open(os.path.join(dir, self.fname()),'w') - - f.write(HEADER+page.unicode().encode("utf8")) - - f.close() + f = dir.join(self.fname()).write( + HEADER+page.unicode().encode("utf8") + ) def navig(self): return html.h1(self.title) @@ -747,18 +731,14 @@ print "Then copy delta.css, delta.js to dest-dir if they are not already there" sys.exit(0) - DIR = sys.argv[1] - + DIR = py.path.local(sys.argv[1]) from pypy.objspace.std.objspace import StdObjSpace - space = StdObjSpace() mods_report = delta(ObjSpaceExplore(space), host_explore, TO_CHECK) cls_report = cls_delta_rep() - if not os.path.isdir(DIR): - os.mkdir(DIR) - + DIR.ensure(dir=1) for rep in reports: rep.html(DIR) Deleted: /pypy/dist/pypy/tool/delta.css ============================================================================== --- /pypy/dist/pypy/tool/delta.css Sun Mar 20 16:48:53 2005 +++ (empty file) @@ -1,17 +0,0 @@ -body { font-family: arial, helvetica, sans-serif; } - -.title {font-size: 2em; font-weight: bolder } - -.even { background: #d0d0d0; } -.odd { background: white; } - -table { border-spacing: 0pt } - -a { color: inherit; } -a:hover { background: yellow } -a:visited:hover { background: inherit } - -.missing { color: red } -.faked { color: red; font-style: italic } -.somemissing { color: maroon } -.only_in { font-style: italic } Deleted: /pypy/dist/pypy/tool/delta.js ============================================================================== --- /pypy/dist/pypy/tool/delta.js Sun Mar 20 16:48:53 2005 +++ (empty file) @@ -1,16 +0,0 @@ - - -toggle_list = ['alpha', 'grandmissing', 'incompleteness']; -ALPHA = 'alpha' -GRANDMISSING = 'grandmissing' -INCOMPLETENESS = 'incompleteness' - -function toggle(on) { - for (i in toggle_list) { - x = toggle_list[i]; - if (x!=on) { - document.getElementById(x).style.display='none'; - } - }; - document.getElementById(on).style.display=''; -} Deleted: /pypy/dist/pypy/tool/delta.py ============================================================================== --- /pypy/dist/pypy/tool/delta.py Sun Mar 20 16:48:53 2005 +++ (empty file) @@ -1,764 +0,0 @@ -import autopath -from pypy.interpreter.error import OperationError - -from py.xml import html - -class html_plus(html): - __tagspec__ = html.__tagspec__.copy() - - __tagspec__['button'] = 1 - __tagspec__['script'] = 1 - -html = html_plus - -import os, sys -from sets import Set - -W = 125 -H = 12 - -RED = "#ff0000" -WHITE = "#ffffff" -BLACK = "#000000" -GREY = "#808080" - -def incompleteness_bar(DIR, incompleteness): - from PIL import Image, ImageDraw, ImageColor - - red = ImageColor.getrgb(RED) - white = ImageColor.getrgb(WHITE) - black = ImageColor.getrgb(BLACK) - grey = ImageColor.getrgb(GREY) - - if incompleteness == -1.0: - inc = -1 - name = "bar_none.png" - else: - inc = round((W-1) * incompleteness) - if inc == 0 and incompleteness != 0: - inc == 1 - name = "bar_%d.png" % inc - - imgfname = os.path.join(DIR,'images',name) - - if not os.path.exists(imgfname): - img = Image.new("RGB",(W,H), red) - draw = ImageDraw.Draw(img) - - if inc == -1: - draw.rectangle([0,0,W-1,H-1], outline=black, fill=white) - else: - if W-1-inc != 0: - draw.rectangle([0,0,W-1-inc,H-1],outline=grey, fill=grey) - - IMGDIR = os.path.join(DIR,'images') - - if not os.path.isdir(IMGDIR): - os.mkdir(IMGDIR) - - img.save(imgfname,optimize=True) - - return html.img(src=os.path.join('images', name),alt="incompleteness=%.2f" % incompleteness) - - -NOTFOUND = object() - -class Explore: - - def __init__(self, label): - self.label = label - self.type_names = {} - - def get_module(self, name): - pass - - def names(self, obj): - if obj is NOTFOUND: - return [] - return self.donames(obj) - - - def donames(self, obj): - pass - - def findattr(self, obj, name): - if obj is NOTFOUND: - return NOTFOUND - return self.dofindattr(obj, name) - - def dofindattr(self, obj, name): - pass - - def get_kind(self, obj): - if obj is NOTFOUND: - return '-' - if self.is_class(obj): - return 'C' - elif self.findattr(obj, '__call__') is not NOTFOUND: - return '()' - else: - return '_' - - def is_class(self, obj): - if obj is NOTFOUND: - return False - return self.dois_class(obj) - - def is_faked(self, obj): - return False - - def get_mro(self, obj): - if obj is NOTFOUND: - return [] - return self.doget_mro(obj) - - def doget_mro(self, obj): - pass - - #def get_type(self, obj): - # pass - # - #def assign_class_name(obj, name): - # if obj in self.type_names: - # return - # self.type_names[obj] = name - # - #def get_lazy_class_name(obj): - # return lambda: self.type_names[obj] - - -class HostExplore(Explore): - - def __init__(self): - import sys - Explore.__init__(self, "CPython %s" % sys.version) - - def get_module(self, name): - try: - return __import__(name,{},{},['*']) - except ImportError: - return NOTFOUND - - def donames(self, obj): - return obj.__dict__.keys() - - def dofindattr(self, obj, name): - return getattr(obj, name, NOTFOUND) - - def dois_class(self, obj): - import types - return type(obj) in (type, types.ClassType) - - def doget_mro(self, obj): - import inspect - return inspect.getmro(obj) - - #def get_type(self, obj): - # return type(obj) - - -def abstract_mro(obj, get_bases, acc=None): - if acc is None: - acc = [] - if obj in acc: - return acc - acc.append(obj) - for base in get_bases(obj): - abstract_mro(base, get_bases, acc) - return acc - -class ObjSpaceExplore(Explore): - - def __init__(self, space): - Explore.__init__(self, "PyPy/%s" % space.__class__.__name__) - self.space = space - - def get_module(self, name): - space = self.space - w = space.wrap - try: - return space.builtin.call('__import__', w(name),w({}),w({}),w(['*'])) - except OperationError: - return NOTFOUND - - def donames(self, obj): - space = self.space - return space.unwrap(space.call_method(space.getattr(obj, space.wrap('__dict__')), 'keys')) - - def dofindattr(self, obj, name): - space = self.space - try: - return space.getattr(obj, space.wrap(name)) - except OperationError, e: - return NOTFOUND - - def is_faked(self, obj): - if hasattr(obj, 'instancetypedef'): - return hasattr(obj.instancetypedef, 'fakedcpytype') - else: - return self.is_faked(self.space.type(obj)) - - def dois_class(self, obj): - #space = self.space - #w_t = space.type(obj) - #if space.is_w(w_t, space.w_type) or space.is_w(w_t, space.w_classobj): - # return True - return self.findattr(obj, '__bases__') is not NOTFOUND - - def doget_mro(self, obj): - space = self.space - try: - return space.unpackiterable(space.getattr(obj, space.wrap('__mro__'))) - except OperationError: - def get_bases(obj): - return space.unpackiterable(space.getattr(obj, space.wrap('__bases__'))) - - return abstract_mro(obj, get_bases) - - #def get_type(self, obj): - # return type(obj) - - -class Status: - def __init__(self, msg, detail_missing, class_, incompleteness, shortmsg = None): - self.msg = msg - self.detail_missing = detail_missing - self.class_ = class_ - self.incompleteness = incompleteness - if shortmsg is None: - self.shortmsg = msg - else: - self.shortmsg = shortmsg - -class Entry: - - def __init__(self, name): - self.name = name - self.shortname = name - self.status = 'PRESENT' - - def __repr__(self): - return "<%s %s>" % (self.__class__.__name__, self.name) - - def __str__(self): - return self.name - - def set_status(self, obj1, obj2, expl1): - if obj1 is NOTFOUND: - assert obj2 is not NOTFOUND, "whoopsy %s" % self.name - self.status = 'MISSING' - self.specifically = 'missing' - elif expl1.is_faked(obj1) and obj2 is not NOTFOUND: - self.status = 'MISSING' - self.specifically = 'faked' - elif obj2 is NOTFOUND: - self.status = expl1 - - def only_in(self, parent): - if parent is not None and parent.status != 'PRESENT': - return "" - return 'only in %s' % self.status.label - - def status_wrt(self, parent=None): - detail_missing = 0 - incompleteness = 0.0 - if self.status == 'MISSING': - class_= msg = self.specifically - detail_missing = 1 - incompleteness = 1.0 - elif self.status == 'PRESENT': - msg = '' - class_ = None - else: - msg = self.only_in(parent) - if msg: - class_ = "only_in" - else: - class_ = None - incompleteness = -1.0 - return Status(msg, detail_missing, class_, incompleteness) - - def attach(self, parent, annot=None, name=None): - if self.status == 'MISSING': - parent.total += 1 - parent.missing += 1 - elif self.status == 'PRESENT': - parent.total += 1 - - if annot is None: - parent.add_row(self, [], name=name, parent=parent) - else: - parent.add_row(self, [annot], name=name, parent=parent) - - def grandadd(self, parent): - if self.status == 'MISSING': - parent.grandtotal += 1 - parent.grandmissing += 1 - elif self.status == 'PRESENT': - parent.grandtotal += 1 - - def handle(self): - return self.shortname, # 1-tuple! - - def link(self, name): - h = self.handle() - if len(h) == 1: - h = h[0] - if name is None: - return h - if name.endswith(h): - return name - return "%s [%s]" % (name, h) - else: - h, dest = h - if name is None: - return html.a(h, href=dest) - if name.endswith(h): - return html.a(name, href=dest) - return html.span(name, " [", - html.a(h, href=dest), "]") - - - -reports = [] - -class Report(Entry): - - useshort = False - - notes = None - - descr = granddescr = "" - - def __init__(self, name, title=None, fname=None, **kwds): - if title is None: - title = name - Entry.__init__(self, name) - - self.title = title - - self.rows = [] - - reports.append(self) - - self.total = 0 - self.missing = 0 - - self.grandtotal = 0 - self.grandmissing = 0 - - self._fname = fname - - self.__dict__.update(kwds) - - - def add_row(self, entry, rest, name=None, parent=None): - self.rows.append((name, entry, rest, parent)) - - def missing_stats(self, missing, total, descr): - return "%s/%s %s missing (%.1f%%)" % (missing, total, descr, float(missing)/total*100) - - def status_wrt(self, parent=None): - detail_missing = 0 - incompleteness = 0.0 - - if self.status == 'MISSING': - count = "%s %s" % (self.total, self.descr) - shortmsg = "%s (%s)" % (self.specifically, count) - detail_missing = self.total - if self.grandtotal: - count = "%s or in detail %s %s" % (count, self.granddescr, self.grandtotal) - detail_missing = self.grandtotal - msg = "%s (%s)" % (self.specifically, count) - return Status(msg, detail_missing, class_=self.specifically, incompleteness=1.0, - shortmsg = shortmsg) - elif self.status == 'PRESENT': - if self.missing == 0 and self.grandmissing == 0: - return Status(msg="complete", detail_missing=detail_missing, class_=None, - incompleteness=incompleteness) - disj = "or " - if self.missing == 0: - msg = "all present but" - incompleteness = 1.0 - disj = "" - else: - msg = self.missing_stats(self.missing, self.total, self.descr) - detail_missing = self.missing - incompleteness = float(self.missing) / self.total - - shortmsg = msg - - if self.grandtotal: - msg = "%s %sin detail %s" % (msg, disj, - self.missing_stats(self.grandmissing, self.grandtotal, - self.granddescr)) - detail_missing = self.grandmissing - incompleteness = (incompleteness + float(self.grandmissing)/self.grandtotal)/2 - return Status(msg, detail_missing, class_='somemissing', - incompleteness=incompleteness, shortmsg = shortmsg) - else: - msg = self.only_in(parent) - if msg: - class_ = "only_in" - else: - class_ = None - return Status(msg, detail_missing=0, class_=class_, - incompleteness=-1.0) - - def fname(self): - fname = self._fname - if fname is None: - fname = self.name - return fname+'.html' - - def handle(self): - return self.shortname, self.fname() - - def fill_table(self, dir, tbl, rows): - def set_class(class_): - if class_ is None: - return {} - else: - return {'class': class_} - - i = 0 - for name, entry, rest, st in rows: - tr_class = i%2 == 0 and "even" or "odd" - if self.useshort: - msg = st.shortmsg - else: - msg = st.msg - rest = rest + [incompleteness_bar(dir, st.incompleteness), msg] - tbl.append(html.tr( - html.td(entry.link(name), **set_class(st.class_)), - *map(html.td,rest), **{'class': tr_class}) - ) - i += 1 - - def html(self, dir): - title = self.title - - def set_class(class_): - if class_ is None: - return {} - else: - return {'class': class_} - - if self.notes is not None: - notes = html.p(self.notes) - else: - notes = html.p() - - st = self.status_wrt() - - msg = st.msg - class_ = st.class_ - bar = incompleteness_bar(dir, st.incompleteness) - - HEADER = ''' -''' - - HIDE = 'display: none' - SHOW = 'display: table' - - alpha_table = html.table(id="alpha", style=SHOW) - grandmissing_table = html.table(id="grandmissing", style=HIDE) - incompleteness_table = html.table(id="incompleteness", style=HIDE) - - toggle = html.p("sort:", - html.button("alphabetical", type="button", onclick="toggle(ALPHA)"),'|', - html.button("incompleteness", type="button", onclick="toggle(INCOMPLETENESS)"),'|', - html.button("# overall missing", type="button", onclick="toggle(GRANDMISSING)")) - - page = html.html( - html.head(html.title(title), - html.link(href="delta.css", rel="stylesheet", type="text/css"), - html.script(' ',type="text/javascript",src="delta.js")), - html.body(self.navig(), - html.p(msg, bar, **set_class(class_)), - toggle, - alpha_table, - grandmissing_table, - incompleteness_table, - notes), xmlns="http://www.w3.org/1999/xhtml") - - rows = [] - for name, entry, rest, parent in self.rows: - st = entry.status_wrt(parent) - rows.append((name, entry, rest, st)) - - self.fill_table(dir, alpha_table, rows) - - rows.sort(lambda (name1, ent1, r1, st1),(name2, ent2, r2, st2): -cmp(st1.detail_missing, st2.detail_missing)) - self.fill_table(dir, grandmissing_table, rows) - - rows.sort(lambda (name1, ent1, r1, st1),(name2, ent2, r2, st2): -cmp(st1.incompleteness, st2.incompleteness)) - self.fill_table(dir, incompleteness_table, rows) - - f = open(os.path.join(dir, self.fname()),'w') - - f.write(HEADER+page.unicode().encode("utf8")) - - f.close() - - def navig(self): - return html.h1(self.title) - -class ClassReport(Report): - - descr = "methods+attrs" - - def navig(self): - return html.p(html.span(self.title,**{'class': 'title'}), - "|",mods_report.link(None),"|",cls_report.link(None)) - - def grandadd(self, parent): - parent.grandtotal += self.total - parent.grandmissing += self.missing - -class ModuleReport(Report): - - descr = "module funcs+types+etc" - - granddescr = "module funcs+others and contained types/classes methods+attrs" - - def navig(self): - return html.p(html.span(self.title,**{'class': 'title'}), - "|",mods_report.link(None),"|",cls_report.link(None)) - - notes = ("(): callable, C: type/class") - - def grandadd(self, parent): - if self.status == 'MISSING': - parent.grandtotal += self.grandtotal - parent.grandmissing += self.grandmissing - elif self.status == 'PRESENT': - parent.grandtotal += self.grandtotal - - -def delta(expl1, expl2, modnames): - - rep = Report('Modules', fname="modules-index", - descr = "modules", - granddescr = "of all modules funcs+others and contained types/classes methods+attrs", - useshort = True) - def navig(): - return html.p(html.span('Modules',**{'class': 'title'}), - "|",cls_report.link(None)) - - rep.navig = navig - - for modname in modnames: - - mod1 = expl1.get_module(modname) - mod2 = expl2.get_module(modname) - - mod_rep = mod_delta(modname, expl1, mod1, expl2, mod2) - - mod_rep.attach(rep) - mod_rep.grandadd(rep) - - return rep - - -def mod_delta(modname, expl1, mod1, expl2, mod2): - print "; mod %s" % modname - rep = ModuleReport(modname) - - rep.set_status(mod1, mod2, expl1) - - names = Set() - - names.update(expl1.names(mod1)) - names.update(expl2.names(mod2)) - - names = list(names) - names.sort() - - for name in names: - obj1 = expl1.findattr(mod1, name) - obj2 = expl2.findattr(mod2, name) - - if expl1.is_class(obj1) or expl2.is_class(obj2): - entry = cls_delta("%s.%s" % (modname, name), expl1, obj1, expl2, obj2) - else: - entry = Entry(name) - entry.set_status(obj1, obj2, expl1) - - kind1 = expl1.get_kind(obj1) - kind2 = expl2.get_kind(obj2) - - if kind1 == '-': - kindinf = kind2 - elif kind2 == '-': - kindinf = kind1 - else: - if kind1 == kind2: - kindinf = kind1 - else: - if kind1 == '_': kind1 = '?' - if kind2 == '_': kind2 = '?' - kindinf = "%s/%s" % (kind1, kind2) - - if kindinf == '_': - kindinf = '' - - entry.attach(rep, kindinf, name=name) - entry.grandadd(rep) - - return rep - - -cls_delta_cache = {} - -def cls_delta(clsname, expl1, cls1, expl2, cls2): - cache = cls_delta_cache - print "; cls %s" % clsname - try: - rep = cache[(cls1, cls2)] - return rep - except KeyError: - pass - - rep = ClassReport(clsname) - rep.shortname = clsname.split('.')[1] - rep.set_status(cls1, cls2, expl1) - - cls1_is_not_a_class = False - - if not expl1.is_class(cls1): - if cls1 is not NOTFOUND: - cls1 = NOTFOUND - cls1_is_not_a_class = True - - if not expl2.is_class(cls2): - cls2 = NOTFOUND - assert not cls1_is_not_a_class - - names = Set() - - for cls in expl1.get_mro(cls1): - names.update(expl1.names(cls)) - - for cls in expl2.get_mro(cls2): - names.update(expl2.names(cls)) - - names = list(names) - names.sort() - - for name in names: - obj1 = expl1.findattr(cls1, name) - obj2 = expl2.findattr(cls2, name) - - if obj1 is NOTFOUND and obj2 is NOTFOUND: - continue # spurious :( - - entry = Entry(name) - if cls1_is_not_a_class: - entry.status = expl2 - else: - entry.set_status(obj1, obj2, expl1) - - entry.attach(rep) - - cache[(cls1, cls2)] = rep - - return rep - -def cls_delta_rep(): - reps = cls_delta_cache.values() - cls_rep = Report('Types/Classes', fname="types-index", - descr = "types/classes", - granddescr = "of all types/classes methods+attrs" - ) - - def navig(): - return html.p(mods_report.link(None), - "|",html.span('Types/Classes',**{'class': 'title'})) - - cls_rep.navig = navig - - - reps.sort(lambda rep1,rep2: cmp(rep1.name, rep2.name)) - - for rep in reps: - cls_rep.add_row(rep, [], name=rep.name) - cls_rep.total += 1 - cls_rep.missing += rep.status == 'MISSING' - rep.grandadd(cls_rep) - - return cls_rep - -#__________________________________________ - -host_explore = HostExplore() - - -basic = ['__builtin__', 'types', 'sys'] - -os_layer = [] -for modname in ['posix', 'nt', 'os2', 'mac', 'ce', 'riscos', 'errno', '_socket', 'select', 'thread']: - if host_explore.get_module(modname) is not NOTFOUND: - os_layer.append(modname) - -mods = """ -_codecs -_random -_sre -_weakref -array -binascii -cPickle -cStringIO -struct -datetime -gc -itertools -math -cmath -md5 -operator -parser -sha -unicodedata -zipimport -time -""".split() - -TO_CHECK = (basic + - os_layer + - mods) -TO_CHECK.sort() - -def getpypyrevision(cache=[]): - try: - return cache[0] - except IndexError: - import pypy - import py - pypydir = py.path.svnwc(pypy.__file__).dirpath() - rev = pypydir.info().rev - cache.append(rev) - return rev - -if __name__ == '__main__': - if len(sys.argv) == 1: - print "usage: delta.py " - print "Then copy delta.css, delta.js to dest-dir if they are not already there" - sys.exit(0) - - DIR = sys.argv[1] - - - from pypy.objspace.std.objspace import StdObjSpace - - space = StdObjSpace() - - mods_report = delta(ObjSpaceExplore(space), host_explore, TO_CHECK) - cls_report = cls_delta_rep() - - if not os.path.isdir(DIR): - os.mkdir(DIR) - - for rep in reports: - rep.html(DIR) From tismer at codespeak.net Sun Mar 20 16:49:28 2005 From: tismer at codespeak.net (tismer at codespeak.net) Date: Sun, 20 Mar 2005 16:49:28 +0100 (MET) Subject: [pypy-svn] r9928 - pypy/dist/pypy/lib/test2 Message-ID: <20050320154928.612F627B56@code1.codespeak.net> Author: tismer Date: Sun Mar 20 16:49:28 2005 New Revision: 9928 Added: pypy/dist/pypy/lib/test2/test_pickle.py (contents, props changed) Modified: pypy/dist/pypy/lib/test2/test_obj.py Log: splitted test_obj into two Modified: pypy/dist/pypy/lib/test2/test_obj.py ============================================================================== --- pypy/dist/pypy/lib/test2/test_obj.py (original) +++ pypy/dist/pypy/lib/test2/test_obj.py Sun Mar 20 16:49:28 2005 @@ -1,18 +1,5 @@ # -*- coding: iso-8859-1 -*- import unittest, test.test_support -import sys, cStringIO, pickle - -class Picklable(object): - def __init__(self, a=5): - self.a = a - def __eq__(self, other): - return self.a == other.a - def __str__(self): - return '%s(%r)' % (self.__class__.__name__, self.a) - -class PicklableSpecial2(Picklable): - def __reduce__(self): - return self.__class__, (self.a,) class ObjectTest(unittest.TestCase): @@ -28,18 +15,6 @@ l = range(5) self.assertRaises(TypeError, hash, l) - def _pickle_some(self, x): - for proto in range(pickle.HIGHEST_PROTOCOL + 1): - s = pickle.dumps(x, proto) - y = pickle.loads(s) - self.assertEqual(x, y) - - def test_pickle_plain(self): - self._pickle_some(Picklable()) - - def test_pickle_special2(self): - self._pickle_some(PicklableSpecial2()) - def test_main(): test.test_support.run_unittest(ObjectTest) Added: pypy/dist/pypy/lib/test2/test_pickle.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/lib/test2/test_pickle.py Sun Mar 20 16:49:28 2005 @@ -0,0 +1,35 @@ +# -*- coding: iso-8859-1 -*- +import unittest, test.test_support +import pickle + +class Picklable(object): + def __init__(self, a=5): + self.a = a + def __eq__(self, other): + return self.a == other.a + def __str__(self): + return '%s(%r)' % (self.__class__.__name__, self.a) + +class PicklableSpecial2(Picklable): + def __reduce__(self): + return self.__class__, (self.a,) + +class PickleTest(unittest.TestCase): + + def _pickle_some(self, x): + for proto in range(pickle.HIGHEST_PROTOCOL + 1): + s = pickle.dumps(x, proto) + y = pickle.loads(s) + self.assertEqual(x, y) + + def test_pickle_plain(self): + self._pickle_some(Picklable()) + + def test_pickle_special2(self): + self._pickle_some(PicklableSpecial2()) + +def test_main(): + test.test_support.run_unittest(PickleTest) + +if __name__ == "__main__": + test_main() From arigo at codespeak.net Sun Mar 20 16:51:17 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sun, 20 Mar 2005 16:51:17 +0100 (MET) Subject: [pypy-svn] r9929 - in pypy/dist/pypy/objspace/std: . test Message-ID: <20050320155117.177DB27B56@code1.codespeak.net> Author: arigo Date: Sun Mar 20 16:51:16 2005 New Revision: 9929 Modified: pypy/dist/pypy/objspace/std/test/test_tupleobject.py pypy/dist/pypy/objspace/std/tupleobject.py Log: tuple.__hash__(). Modified: pypy/dist/pypy/objspace/std/test/test_tupleobject.py ============================================================================== --- pypy/dist/pypy/objspace/std/test/test_tupleobject.py (original) +++ pypy/dist/pypy/objspace/std/test/test_tupleobject.py Sun Mar 20 16:51:16 2005 @@ -233,3 +233,12 @@ self.space.w_True) assert self.space.eq_w(self.space.le(w_tuple4, w_tuple3), self.space.w_True) + + +class AppTestW_TupleObject: + + def test_hash(self): + # check that hash behaves as in 2.4 for at least 31 bits + assert hash(()) & 0x7fffffff == 0x35d373 + assert hash((12,)) & 0x7fffffff == 0x1cca0557 + assert hash((12,34)) & 0x7fffffff == 0x153e2a41 Modified: pypy/dist/pypy/objspace/std/tupleobject.py ============================================================================== --- pypy/dist/pypy/objspace/std/tupleobject.py (original) +++ pypy/dist/pypy/objspace/std/tupleobject.py Sun Mar 20 16:51:16 2005 @@ -1,5 +1,6 @@ from pypy.objspace.std.objspace import * from pypy.objspace.std.intobject import W_IntObject +from pypy.objspace.std.restricted_int import intmask from pypy.objspace.std.sliceobject import W_SliceObject from pypy.objspace.std import slicetype from pypy.interpreter import gateway @@ -122,7 +123,16 @@ repr__Tuple = app.interphook('repr__Tuple') def hash__Tuple(space, w_tuple): - # silly-ish, but _correct_, while lacking it would be WRONG - return space.len(w_tuple) + # this is the CPython 2.4 algorithm (changed from 2.3) + mult = 1000003 + x = 0x345678 + z = len(w_tuple.wrappeditems) + for w_item in w_tuple.wrappeditems: + y = space.int_w(space.hash(w_item)) + x = (x ^ y) * mult + z -= 1 + mult += 82520 + z + z + x += 97531 + return space.wrap(intmask(x)) register_all(vars()) From arigo at codespeak.net Sun Mar 20 16:52:28 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sun, 20 Mar 2005 16:52:28 +0100 (MET) Subject: [pypy-svn] r9930 - pypy/dist/pypy/objspace/std Message-ID: <20050320155228.1F54327B56@code1.codespeak.net> Author: arigo Date: Sun Mar 20 16:52:27 2005 New Revision: 9930 Modified: pypy/dist/pypy/objspace/std/sliceobject.py Log: typo Modified: pypy/dist/pypy/objspace/std/sliceobject.py ============================================================================== --- pypy/dist/pypy/objspace/std/sliceobject.py (original) +++ pypy/dist/pypy/objspace/std/sliceobject.py Sun Mar 20 16:52:27 2005 @@ -43,7 +43,7 @@ return space.w_False def hash__Slice(space, w_slice): - """space are not hashables but they must have a __hash__ method""" + """slices are not hashables but they must have a __hash__ method""" raise OperationError(space.w_TypeError, space.wrap("unhashable type")) From hpk at codespeak.net Sun Mar 20 17:18:40 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sun, 20 Mar 2005 17:18:40 +0100 (MET) Subject: [pypy-svn] r9931 - pypy/dist/lib-python-2.3.4/test Message-ID: <20050320161840.DA4CD27B55@code1.codespeak.net> Author: hpk Date: Sun Mar 20 17:18:40 2005 New Revision: 9931 Modified: pypy/dist/lib-python-2.3.4/test/conftest.py Log: call test_main() if it exists in order to hack out the list of classes that are to be tested. Modified: pypy/dist/lib-python-2.3.4/test/conftest.py ============================================================================== --- pypy/dist/lib-python-2.3.4/test/conftest.py (original) +++ pypy/dist/lib-python-2.3.4/test/conftest.py Sun Mar 20 17:18:40 2005 @@ -95,18 +95,30 @@ ...] """ #print "entering list_testmethods" - l = [] - for clsname, cls in mod.__dict__.items(): - if hasattr(cls, '__bases__') and \ - issubclass(cls, testcaseclass): - instance = cls() - #print "checking", instance - methods = [] - for methodname in dir(cls): - if methodname.startswith('test_'): - name = clsname + '.' + methodname - methods.append((name, getattr(instance, methodname))) - l.append((instance.setUp, instance.tearDown, methods)) + classlist = [] + if callable(getattr(mod, 'test_main', None)): + def hack_run_unittest(*classes): + classlist.extend(list(classes)) + mod.test_support.run_unittest = hack_run_unittest + mod.test_main() + mod.test_support.run_unittest = None + else: + # we try to find out fitting tests ourselves + for clsname, cls in mod.__dict__.items(): + if hasattr(cls, '__bases__') and \ + issubclass(cls, testcaseclass): + classlist.append(cls) + l = [] + for cls in classlist: + clsname = cls.__name__ + instance = cls() + #print "checking", instance + methods = [] + for methodname in dir(cls): + if methodname.startswith('test_'): + name = clsname + '.' + methodname + methods.append((name, getattr(instance, methodname))) + l.append((instance.setUp, instance.tearDown, methods)) return l list_testmethods = app2interp_temp(app_list_testmethods) From alex at codespeak.net Sun Mar 20 17:31:54 2005 From: alex at codespeak.net (alex at codespeak.net) Date: Sun, 20 Mar 2005 17:31:54 +0100 (MET) Subject: [pypy-svn] r9932 - pypy/dist/pypy/objspace/std Message-ID: <20050320163154.2881127B55@code1.codespeak.net> Author: alex Date: Sun Mar 20 17:31:53 2005 New Revision: 9932 Modified: pypy/dist/pypy/objspace/std/objecttype.py Log: __reduce__ (not working properly yet) Modified: pypy/dist/pypy/objspace/std/objecttype.py ============================================================================== --- pypy/dist/pypy/objspace/std/objecttype.py (original) +++ pypy/dist/pypy/objspace/std/objecttype.py Sun Mar 20 17:31:53 2005 @@ -42,9 +42,17 @@ pass def descr__reduce_ex__(space, w_obj, proto=0): - # we intentionally avoid to ask for __reduce__ here - # XXX check for integerness of proto ? - + w_st_reduce = space.wrap('__reduce__') + try: w_reduce = space.getattr(w_obj, w_st_reduce) + except OperationError: pass + else: + w_cls = space.getattr(w_obj, space.wrap('__class__')) + w_cls_reduce = space.getattr(w_cls, w_st_reduce) + w_objtype = space.w_object + w_obj_reduce = space.getattr(w_objtype, space.wrap('__dict__')) + override = space.is_true(space.ne(w_cls_reduce, w_obj_reduce)) + if override: + return space.call(w_reduce, space.newtuple([])) if proto >= 2: return reduce_2(space, w_obj) w_proto = space.wrap(proto) From arigo at codespeak.net Sun Mar 20 17:50:39 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sun, 20 Mar 2005 17:50:39 +0100 (MET) Subject: [pypy-svn] r9933 - pypy/dist/pypy/interpreter Message-ID: <20050320165039.EFFEB27B55@code1.codespeak.net> Author: arigo Date: Sun Mar 20 17:50:39 2005 New Revision: 9933 Modified: pypy/dist/pypy/interpreter/argument.py Log: Minor fixes in */** calls error messages. Modified: pypy/dist/pypy/interpreter/argument.py ============================================================================== --- pypy/dist/pypy/interpreter/argument.py (original) +++ pypy/dist/pypy/interpreter/argument.py Sun Mar 20 17:50:39 2005 @@ -264,13 +264,13 @@ argnames, varargname, kwargname = signature args_w, kwds_w = args.unpack() nargs = len(args_w) + if kwargname is not None: + msg2 = "non-keyword " + else: + msg2 = "" + nargs += len(kwds_w) n = len(argnames) if n == 0: - if kwargname is not None: - msg2 = "non-keyword " - else: - msg2 = "" - nargs += len(kwds_w) msg = "%s() takes no %sargument (%d given)" % ( fnname, msg2, @@ -284,10 +284,8 @@ else: msg1 = "at least" n -= defcount - if kwargname is not None: - msg2 = "non-keyword " - else: - msg2 = "" + if not kwds_w: # msg "f() takes at least X non-keyword args" + msg2 = "" # is confusing if no kwd arg actually provided if n == 1: plural = "" else: From hpk at codespeak.net Sun Mar 20 17:53:25 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sun, 20 Mar 2005 17:53:25 +0100 (MET) Subject: [pypy-svn] r9934 - in pypy/dist/pypy: . lib/test2 Message-ID: <20050320165325.8FFEE27B56@code1.codespeak.net> Author: hpk Date: Sun Mar 20 17:53:25 2005 New Revision: 9934 Modified: pypy/dist/pypy/TODO pypy/dist/pypy/lib/test2/conftest.py Log: we want multiple instances of object spaces at some point Modified: pypy/dist/pypy/TODO ============================================================================== --- pypy/dist/pypy/TODO (original) +++ pypy/dist/pypy/TODO Sun Mar 20 17:53:25 2005 @@ -5,6 +5,10 @@ compiler, a number of C modules, and some types -- as printed when running py.py: "faking ". +* re-allow more than one instance of StdObjSpace + (probably requiring geninterp to generate less global + init-code) + * not all of CPython's exceptions use the same __init__! * refactor the cmdline-entrypoints to PyPy aka py.py main.py Modified: pypy/dist/pypy/lib/test2/conftest.py ============================================================================== --- pypy/dist/pypy/lib/test2/conftest.py (original) +++ pypy/dist/pypy/lib/test2/conftest.py Sun Mar 20 17:53:25 2005 @@ -1,5 +1,20 @@ +import autopath import py +import pypy +from pypy.conftest import gettestobjspace + +lib = py.path.local(pypy.__file__).dirpath() +lib = lib.dirpath('lib-python-2.3.4', 'test') +assert lib.check(dir=1) +conftest = lib.join('conftest.py').getpymodule() + +class Module(conftest.Module): + pass + +class Directory(conftest.Module): + pass + +#class Directory(py.test.collect.Directory): +# def __iter__(self): +# return iter([]) -class Directory(py.test.collect.Directory): - def __iter__(self): - return iter([]) From hpk at codespeak.net Sun Mar 20 17:59:45 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sun, 20 Mar 2005 17:59:45 +0100 (MET) Subject: [pypy-svn] r9935 - in pypy/dist: lib-python-2.3.4/test pypy/lib/test2 Message-ID: <20050320165945.03A0D27B58@code1.codespeak.net> Author: hpk Date: Sun Mar 20 17:59:45 2005 New Revision: 9935 Modified: pypy/dist/lib-python-2.3.4/test/conftest.py pypy/dist/pypy/lib/test2/conftest.py Log: fix test hacking for lib-python and exclude tests in pypy/lib/test2 by default Modified: pypy/dist/lib-python-2.3.4/test/conftest.py ============================================================================== --- pypy/dist/lib-python-2.3.4/test/conftest.py (original) +++ pypy/dist/lib-python-2.3.4/test/conftest.py Sun Mar 20 17:59:45 2005 @@ -97,11 +97,15 @@ #print "entering list_testmethods" classlist = [] if callable(getattr(mod, 'test_main', None)): + from test import test_support # humpf def hack_run_unittest(*classes): classlist.extend(list(classes)) - mod.test_support.run_unittest = hack_run_unittest + test_support.run_unittest = hack_run_unittest mod.test_main() - mod.test_support.run_unittest = None + assert classlist, ("found %s.test_main() but it returned no " + "test classes" % mod.__name__) + test_support.run_unittest = None # nobody should really + # call it anymore else: # we try to find out fitting tests ourselves for clsname, cls in mod.__dict__.items(): @@ -128,6 +132,7 @@ # ok this is an output test return OutputTestItem(fspath, output) content = fspath.read() + # XXX not exactly clean: if content.find('unittest') != -1: # we can try to run ... return UnittestModule(fspath) Modified: pypy/dist/pypy/lib/test2/conftest.py ============================================================================== --- pypy/dist/pypy/lib/test2/conftest.py (original) +++ pypy/dist/pypy/lib/test2/conftest.py Sun Mar 20 17:59:45 2005 @@ -8,13 +8,10 @@ assert lib.check(dir=1) conftest = lib.join('conftest.py').getpymodule() -class Module(conftest.Module): - pass +def Module(fspath): + return conftest.Module(fspath) -class Directory(conftest.Module): - pass - -#class Directory(py.test.collect.Directory): -# def __iter__(self): -# return iter([]) +class Directory(conftest.Directory): + def __iter__(self): + return iter([]) From jacob at codespeak.net Sun Mar 20 18:12:19 2005 From: jacob at codespeak.net (jacob at codespeak.net) Date: Sun, 20 Mar 2005 18:12:19 +0100 (MET) Subject: [pypy-svn] r9936 - in pypy/dist/pypy/lib: . test2 Message-ID: <20050320171219.1FB7227B5D@code1.codespeak.net> Author: jacob Date: Sun Mar 20 18:12:18 2005 New Revision: 9936 Added: pypy/dist/pypy/lib/datetime.py pypy/dist/pypy/lib/test2/test_datetime.py Log: Python implementation of datetime. Originally from the CPython CVS sandbox. Added: pypy/dist/pypy/lib/datetime.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/lib/datetime.py Sun Mar 20 18:12:18 2005 @@ -0,0 +1,2003 @@ +"""Concrete date/time and related types -- prototype implemented in Python. + +See http://www.zope.org/Members/fdrake/DateTimeWiki/FrontPage + +See also http://dir.yahoo.com/Reference/calendars/ + +For a primer on DST, including many current DST rules, see +http://webexhibits.org/daylightsaving/ + +For more about DST than you ever wanted to know, see +ftp://elsie.nci.nih.gov/pub/ + +Sources for time zone and DST data: http://www.twinsun.com/tz/tz-link.htm + +This was originally copied from the sandbox of the CPython CVS repository. +Thanks to Tim Peters for suggesting using it. +""" + +import time as _time +import math as _math + +MINYEAR = 1 +MAXYEAR = 9999 + +# Utility functions, adapted from Python's Demo/classes/Dates.py, which +# also assumes the current Gregorian calendar indefinitely extended in +# both directions. Difference: Dates.py calls January 1 of year 0 day +# number 1. The code here calls January 1 of year 1 day number 1. This is +# to match the definition of the "proleptic Gregorian" calendar in Dershowitz +# and Reingold's "Calendrical Calculations", where it's the base calendar +# for all computations. See the book for algorithms for converting between +# proleptic Gregorian ordinals and many other calendar systems. + +_DAYS_IN_MONTH = [None, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] + +_DAYS_BEFORE_MONTH = [None] +dbm = 0 +for dim in _DAYS_IN_MONTH[1:]: + _DAYS_BEFORE_MONTH.append(dbm) + dbm += dim +del dbm, dim + +def _is_leap(year): + "year -> 1 if leap year, else 0." + return year % 4 == 0 and (year % 100 != 0 or year % 400 == 0) + +def _days_in_year(year): + "year -> number of days in year (366 if a leap year, else 365)." + return 365 + _is_leap(year) + +def _days_before_year(year): + "year -> number of days before January 1st of year." + y = year - 1 + return y*365 + y//4 - y//100 + y//400 + +def _days_in_month(year, month): + "year, month -> number of days in that month in that year." + assert 1 <= month <= 12, month + if month == 2 and _is_leap(year): + return 29 + return _DAYS_IN_MONTH[month] + +def _days_before_month(year, month): + "year, month -> number of days in year preceeding first day of month." + if not 1 <= month <= 12: + raise ValueError('month must be in 1..12', month) + return _DAYS_BEFORE_MONTH[month] + (month > 2 and _is_leap(year)) + +def _ymd2ord(year, month, day): + "year, month, day -> ordinal, considering 01-Jan-0001 as day 1." + if not 1 <= month <= 12: + raise ValueError('month must be in 1..12', month) + dim = _days_in_month(year, month) + if not 1 <= day <= dim: + raise ValueError('day must be in 1..%d' % dim, day) + return (_days_before_year(year) + + _days_before_month(year, month) + + day) + +_DI400Y = _days_before_year(401) # number of days in 400 years +_DI100Y = _days_before_year(101) # " " " " 100 " +_DI4Y = _days_before_year(5) # " " " " 4 " + +# A 4-year cycle has an extra leap day over what we'd get from pasting +# together 4 single years. +assert _DI4Y == 4 * 365 + 1 + +# Similarly, a 400-year cycle has an extra leap day over what we'd get from +# pasting together 4 100-year cycles. +assert _DI400Y == 4 * _DI100Y + 1 + +# OTOH, a 100-year cycle has one fewer leap day than we'd get from +# pasting together 25 4-year cycles. +assert _DI100Y == 25 * _DI4Y - 1 + +def _ord2ymd(n): + "ordinal -> (year, month, day), considering 01-Jan-0001 as day 1." + + # n is a 1-based index, starting at 1-Jan-1. The pattern of leap years + # repeats exactly every 400 years. The basic strategy is to find the + # closest 400-year boundary at or before n, then work with the offset + # from that boundary to n. Life is much clearer if we subtract 1 from + # n first -- then the values of n at 400-year boundaries are exactly + # those divisible by _DI400Y: + # + # D M Y n n-1 + # -- --- ---- ---------- ---------------- + # 31 Dec -400 -_DI400Y -_DI400Y -1 + # 1 Jan -399 -_DI400Y +1 -_DI400Y 400-year boundary + # ... + # 30 Dec 000 -1 -2 + # 31 Dec 000 0 -1 + # 1 Jan 001 1 0 400-year boundary + # 2 Jan 001 2 1 + # 3 Jan 001 3 2 + # ... + # 31 Dec 400 _DI400Y _DI400Y -1 + # 1 Jan 401 _DI400Y +1 _DI400Y 400-year boundary + n -= 1 + n400, n = divmod(n, _DI400Y) + year = n400 * 400 + 1 # ..., -399, 1, 401, ... + + # Now n is the (non-negative) offset, in days, from January 1 of year, to + # the desired date. Now compute how many 100-year cycles precede n. + # Note that it's possible for n100 to equal 4! In that case 4 full + # 100-year cycles precede the desired day, which implies the desired + # day is December 31 at the end of a 400-year cycle. + n100, n = divmod(n, _DI100Y) + + # Now compute how many 4-year cycles precede it. + n4, n = divmod(n, _DI4Y) + + # And now how many single years. Again n1 can be 4, and again meaning + # that the desired day is December 31 at the end of the 4-year cycle. + n1, n = divmod(n, 365) + + year += n100 * 100 + n4 * 4 + n1 + if n1 == 4 or n100 == 4: + assert n == 0 + return year-1, 12, 31 + + # Now the year is correct, and n is the offset from January 1. We find + # the month via an estimate that's either exact or one too large. + leapyear = n1 == 3 and (n4 != 24 or n100 == 3) + assert leapyear == _is_leap(year) + month = (n + 50) >> 5 + preceding = _DAYS_BEFORE_MONTH[month] + (month > 2 and leapyear) + if preceding > n: # estimate is too large + month -= 1 + preceding -= _DAYS_IN_MONTH[month] + (month == 2 and leapyear) + n -= preceding + assert 0 <= n < _days_in_month(year, month) + + # Now the year and month are correct, and n is the offset from the + # start of that month: we're done! + return year, month, n+1 + +# Month and day names. For localized versions, see the calendar module. +_MONTHNAMES = [None, "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"] +_DAYNAMES = [None, "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"] + + +def _build_struct_time(y, m, d, hh, mm, ss, dstflag): + wday = (_ymd2ord(y, m, d) + 6) % 7 + dnum = _days_before_month(y, m) + d + return _time.struct_time((y, m, d, hh, mm, ss, wday, dnum, dstflag)) + +def _format_time(hh, mm, ss, us): + # Skip trailing microseconds when us==0. + result = "%02d:%02d:%02d" % (hh, mm, ss) + if us: + result += ".%06d" % us + return result + +# Correctly substitute for %z and %Z escapes in strftime formats. +def _wrap_strftime(object, format, timetuple): + year = timetuple[0] + if year < 1900: + raise ValueError("year=%d is before 1900; the datetime strftime() " + "methods require year >= 1900" % year) + # Don't call _utcoffset() or tzname() unless actually needed. + zreplace = None # the string to use for %z + Zreplace = None # the string to use for %Z + + # Scan format for %z and %Z escapes, replacing as needed. + newformat = [] + push = newformat.append + i, n = 0, len(format) + while i < n: + ch = format[i] + i += 1 + if ch == '%': + if i < n: + ch = format[i] + i += 1 + if ch == 'z': + if zreplace is None: + zreplace = "" + if hasattr(object, "_utcoffset"): + offset = object._utcoffset() + if offset is not None: + sign = '+' + if offset < 0: + offset = -offset + sign = '-' + h, m = divmod(offset, 60) + zreplace = '%c%02d%02d' % (sign, h, m) + assert '%' not in zreplace + newformat.append(zreplace) + elif ch == 'Z': + if Zreplace is None: + Zreplace = "" + if hasattr(object, "tzname"): + s = object.tzname() + if s is not None: + # strftime is going to have at this: escape % + Zreplace = s.replace('%', '%%') + newformat.append(Zreplace) + else: + push('%') + push(ch) + else: + push('%') + else: + push(ch) + newformat = "".join(newformat) + return _time.strftime(newformat, timetuple) + +def _call_tzinfo_method(tzinfo, methname, tzinfoarg): + if tzinfo is None: + return None + return getattr(tzinfo, methname)(tzinfoarg) + +# Just raise TypeError if the arg isn't None or a string. +def _check_tzname(name): + if name is not None and not isinstance(name, str): + raise TypeError("tzinfo.tzname() must return None or string, " + "not '%s'" % type(name)) + +# name is the offset-producing method, "utcoffset" or "dst". +# offset is what it returned. +# If offset isn't None or timedelta, raises TypeError. +# If offset is None, returns None. +# Else offset is checked for being in range, and a whole # of minutes. +# If it is, its integer value is returned. Else ValueError is raised. +def _check_utc_offset(name, offset): + assert name in ("utcoffset", "dst") + if offset is None: + return None + if not isinstance(offset, timedelta): + raise TypeError("tzinfo.%s() must return None " + "or timedelta, not '%s'" % (name, type(offset))) + days = offset.days + if days < -1 or days > 0: + offset = 1440 # trigger out-of-range + else: + seconds = days * 86400 + offset.seconds + minutes, seconds = divmod(seconds, 60) + if seconds or offset.microseconds: + raise ValueError("tzinfo.%s() must return a whole number " + "of minutes" % name) + offset = minutes + if -1440 < offset < 1440: + return offset + raise ValueError("%s()=%d, must be in -1439..1439" % (name, offset)) + +def _check_date_fields(year, month, day): + if not MINYEAR <= year <= MAXYEAR: + raise ValueError('year must be in %d..%d' % (MINYEAR, MAXYEAR), year) + if not 1 <= month <= 12: + raise ValueError('month must be in 1..12', month) + dim = _days_in_month(year, month) + if not 1 <= day <= dim: + raise ValueError('day must be in 1..%d' % dim, day) + +def _check_time_fields(hour, minute, second, microsecond): + if not 0 <= hour <= 23: + raise ValueError('hour must be in 0..23', hour) + if not 0 <= minute <= 59: + raise ValueError('minute must be in 0..59', minute) + if not 0 <= second <= 59: + raise ValueError('second must be in 0..59', second) + if not 0 <= microsecond <= 999999: + raise ValueError('microsecond must be in 0..999999', microsecond) + +def _check_tzinfo_arg(tz): + if tz is not None and not isinstance(tz, tzinfo): + raise TypeError("tzinfo argument must be None or of a tzinfo subclass") + + +# Notes on comparison: In general, datetime module comparison operators raise +# TypeError when they don't know how to do a comparison themself. If they +# returned NotImplemented instead, comparison could (silently) fall back to +# the default compare-objects-by-comparing-their-memory-addresses strategy, +# and that's not helpful. There are two exceptions: +# +# 1. For date and datetime, if the other object has a "timetuple" attr, +# NotImplemented is returned. This is a hook to allow other kinds of +# datetime-like objects a chance to intercept the comparison. +# +# 2. Else __eq__ and __ne__ return False and True, respectively. This is +# so opertaions like +# +# x == y +# x != y +# x in sequence +# x not in sequence +# dict[x] = y +# +# don't raise annoying TypeErrors just because a datetime object +# is part of a heterogeneous collection. If there's no known way to +# compare X to a datetime, saying they're not equal is reasonable. + +def _cmperror(x, y): + raise TypeError("can't compare '%s' to '%s'" % ( + type(x).__name__, type(y).__name__)) + +# This is a start at a struct tm workalike. Goals: +# +# + Works the same way across platforms. +# + Handles all the fields datetime needs handled, without 1970-2038 glitches. +# +# Note: I suspect it's best if this flavor of tm does *not* try to +# second-guess timezones or DST. Instead fold whatever adjustments you want +# into the minutes argument (and the constructor will normalize). + +_ORD1970 = _ymd2ord(1970, 1, 1) # base ordinal for UNIX epoch + +class tmxxx: + + ordinal = None + + def __init__(self, year, month, day, hour=0, minute=0, second=0, + microsecond=0): + # Normalize all the inputs, and store the normalized values. + if not 0 <= microsecond <= 999999: + carry, microsecond = divmod(microsecond, 1000000) + second += carry + if not 0 <= second <= 59: + carry, second = divmod(second, 60) + minute += carry + if not 0 <= minute <= 59: + carry, minute = divmod(minute, 60) + hour += carry + if not 0 <= hour <= 23: + carry, hour = divmod(hour, 24) + day += carry + + # That was easy. Now it gets muddy: the proper range for day + # can't be determined without knowing the correct month and year, + # but if day is, e.g., plus or minus a million, the current month + # and year values make no sense (and may also be out of bounds + # themselves). + # Saying 12 months == 1 year should be non-controversial. + if not 1 <= month <= 12: + carry, month = divmod(month-1, 12) + year += carry + month += 1 + assert 1 <= month <= 12 + + # Now only day can be out of bounds (year may also be out of bounds + # for a datetime object, but we don't care about that here). + # If day is out of bounds, what to do is arguable, but at least the + # method here is principled and explainable. + dim = _days_in_month(year, month) + if not 1 <= day <= dim: + # Move day-1 days from the first of the month. First try to + # get off cheap if we're only one day out of range (adjustments + # for timezone alone can't be worse than that). + if day == 0: # move back a day + month -= 1 + if month > 0: + day = _days_in_month(year, month) + else: + year, month, day = year-1, 12, 31 + elif day == dim + 1: # move forward a day + month += 1 + day = 1 + if month > 12: + month = 1 + year += 1 + else: + self.ordinal = _ymd2ord(year, month, 1) + (day - 1) + year, month, day = _ord2ymd(self.ordinal) + + self.year, self.month, self.day = year, month, day + self.hour, self.minute, self.second = hour, minute, second + self.microsecond = microsecond + + def toordinal(self): + """Return proleptic Gregorian ordinal for the year, month and day. + + January 1 of year 1 is day 1. Only the year, month and day values + contribute to the result. + """ + if self.ordinal is None: + self.ordinal = _ymd2ord(self.year, self.month, self.day) + return self.ordinal + + def time(self): + "Return Unixish timestamp, as a float (assuming UTC)." + days = self.toordinal() - _ORD1970 # convert to UNIX epoch + seconds = ((days * 24. + self.hour)*60. + self.minute)*60. + return seconds + self.second + self.microsecond / 1e6 + + def ctime(self): + "Return ctime() style string." + weekday = self.toordinal() % 7 or 7 + return "%s %s %2d %02d:%02d:%02d %04d" % ( + _DAYNAMES[weekday], + _MONTHNAMES[self.month], + self.day, + self.hour, self.minute, self.second, + self.year) + +class timedelta(object): + """Represent the difference between two datetime objects. + + Supported operators: + + - add, subtract timedelta + - unary plus, minus, abs + - compare to timedelta + - multiply, divide by int/long + + In addition, datetime supports subtraction of two datetime objects + returning a timedelta, and addition or subtraction of a datetime + and a timedelta giving a datetime. + + Representation: (days, seconds, microseconds). Why? Because I + felt like it. + """ + + def __new__(cls, days=0, seconds=0, microseconds=0, + # XXX The following should only be used as keyword args: + milliseconds=0, minutes=0, hours=0, weeks=0): + # Doing this efficiently and accurately in C is going to be difficult + # and error-prone, due to ubiquitous overflow possibilities, and that + # C double doesn't have enough bits of precision to represent + # microseconds over 10K years faithfully. The code here tries to make + # explicit where go-fast assumptions can be relied on, in order to + # guide the C implementation; it's way more convoluted than speed- + # ignoring auto-overflow-to-long idiomatic Python could be. + + # XXX Check that all inputs are ints, longs or floats. + + # Final values, all integer. + # s and us fit in 32-bit signed ints; d isn't bounded. + d = s = us = 0 + + # Normalize everything to days, seconds, microseconds. + days += weeks*7 + seconds += minutes*60 + hours*3600 + microseconds += milliseconds*1000 + + # Get rid of all fractions, and normalize s and us. + # Take a deep breath . + if isinstance(days, float): + dayfrac, days = _math.modf(days) + daysecondsfrac, daysecondswhole = _math.modf(dayfrac * (24.*3600.)) + assert daysecondswhole == int(daysecondswhole) # can't overflow + s = int(daysecondswhole) + assert days == long(days) + d = long(days) + else: + daysecondsfrac = 0.0 + d = days + assert isinstance(daysecondsfrac, float) + assert abs(daysecondsfrac) <= 1.0 + assert isinstance(d, (int, long)) + assert abs(s) <= 24 * 3600 + # days isn't referenced again before redefinition + + if isinstance(seconds, float): + secondsfrac, seconds = _math.modf(seconds) + assert seconds == long(seconds) + seconds = long(seconds) + secondsfrac += daysecondsfrac + assert abs(secondsfrac) <= 2.0 + else: + secondsfrac = daysecondsfrac + # daysecondsfrac isn't referenced again + assert isinstance(secondsfrac, float) + assert abs(secondsfrac) <= 2.0 + + assert isinstance(seconds, (int, long)) + days, seconds = divmod(seconds, 24*3600) + d += days + s += int(seconds) # can't overflow + assert isinstance(s, int) + assert abs(s) <= 2 * 24 * 3600 + # seconds isn't referenced again before redefinition + + usdouble = secondsfrac * 1e6 + assert abs(usdouble) < 2.1e6 # exact value not critical + # secondsfrac isn't referenced again + + if isinstance(microseconds, float): + microseconds += usdouble + microseconds = round(microseconds) + seconds, microseconds = divmod(microseconds, 1e6) + assert microseconds == int(microseconds) + assert seconds == long(seconds) + days, seconds = divmod(seconds, 24.*3600.) + assert days == long(days) + assert seconds == int(seconds) + d += long(days) + s += int(seconds) # can't overflow + assert isinstance(s, int) + assert abs(s) <= 3 * 24 * 3600 + else: + seconds, microseconds = divmod(microseconds, 1000000) + days, seconds = divmod(seconds, 24*3600) + d += days + s += int(seconds) # can't overflow + assert isinstance(s, int) + assert abs(s) <= 3 * 24 * 3600 + microseconds = float(microseconds) + microseconds += usdouble + microseconds = round(microseconds) + assert abs(s) <= 3 * 24 * 3600 + assert abs(microseconds) < 3.1e6 + + # Just a little bit of carrying possible for microseconds and seconds. + assert isinstance(microseconds, float) + assert int(microseconds) == microseconds + us = int(microseconds) + seconds, us = divmod(us, 1000000) + s += seconds # cant't overflow + assert isinstance(s, int) + days, s = divmod(s, 24*3600) + d += days + + assert isinstance(d, (int, long)) + assert isinstance(s, int) and 0 <= s < 24*3600 + assert isinstance(us, int) and 0 <= us < 1000000 + + self = object.__new__(cls) + + self.__days = d + self.__seconds = s + self.__microseconds = us + if abs(d) > 999999999: + raise OverflowError("timedelta # of days is too large: %d" % d) + + return self + + def __repr__(self): + if self.__microseconds: + return "%s(%d, %d, %d)" % ('datetime.' + self.__class__.__name__, + self.__days, + self.__seconds, + self.__microseconds) + if self.__seconds: + return "%s(%d, %d)" % ('datetime.' + self.__class__.__name__, + self.__days, + self.__seconds) + return "%s(%d)" % ('datetime.' + self.__class__.__name__, self.__days) + + def __str__(self): + mm, ss = divmod(self.__seconds, 60) + hh, mm = divmod(mm, 60) + s = "%d:%02d:%02d" % (hh, mm, ss) + if self.__days: + def plural(n): + return n, abs(n) != 1 and "s" or "" + s = ("%d day%s, " % plural(self.__days)) + s + if self.__microseconds: + s = s + ".%06d" % self.__microseconds + return s + + days = property(lambda self: self.__days, doc="days") + seconds = property(lambda self: self.__seconds, doc="seconds") + microseconds = property(lambda self: self.__microseconds, + doc="microseconds") + + def __add__(self, other): + if isinstance(other, timedelta): + return self.__class__(self.__days + other.__days, + self.__seconds + other.__seconds, + self.__microseconds + other.__microseconds) + return NotImplemented + + __radd__ = __add__ + + def __sub__(self, other): + if isinstance(other, timedelta): + return self + -other + return NotImplemented + + def __rsub__(self, other): + if isinstance(other, timedelta): + return -self + other + return NotImplemented + + def __neg__(self): + return self.__class__(-self.__days, + -self.__seconds, + -self.__microseconds) + + def __pos__(self): + return self + + def __abs__(self): + if self.__days < 0: + return -self + else: + return self + + def __mul__(self, other): + if isinstance(other, (int, long)): + return self.__class__(self.__days * other, + self.__seconds * other, + self.__microseconds * other) + return NotImplemented + + __rmul__ = __mul__ + + def __div__(self, other): + if isinstance(other, (int, long)): + usec = ((self.__days * (24*3600L) + self.__seconds) * 1000000 + + self.__microseconds) + return self.__class__(0, 0, usec // other) + return NotImplemented + + __floordiv__ = __div__ + + # Comparisons. + + def __eq__(self, other): + if isinstance(other, timedelta): + return self.__cmp(other) == 0 + else: + return False + + def __ne__(self, other): + if isinstance(other, timedelta): + return self.__cmp(other) != 0 + else: + return True + + def __le__(self, other): + if isinstance(other, timedelta): + return self.__cmp(other) <= 0 + else: + _cmperror(self, other) + + def __lt__(self, other): + if isinstance(other, timedelta): + return self.__cmp(other) < 0 + else: + _cmperror(self, other) + + def __ge__(self, other): + if isinstance(other, timedelta): + return self.__cmp(other) >= 0 + else: + _cmperror(self, other) + + def __gt__(self, other): + if isinstance(other, timedelta): + return self.__cmp(other) > 0 + else: + _cmperror(self, other) + + def __cmp(self, other): + assert isinstance(other, timedelta) + return cmp(self.__getstate(), other.__getstate()) + + def __hash__(self): + return hash(self.__getstate()) + + def __nonzero__(self): + return (self.__days != 0 or + self.__seconds != 0 or + self.__microseconds != 0) + + # Pickle support. + + __safe_for_unpickling__ = True # For Python 2.2 + + def __getstate(self): + return (self.__days, self.__seconds, self.__microseconds) + + def __reduce__(self): + return (self.__class__, self.__getstate()) + +timedelta.min = timedelta(-999999999) +timedelta.max = timedelta(days=999999999, hours=23, minutes=59, seconds=59, + microseconds=999999) +timedelta.resolution = timedelta(microseconds=1) + +class date(object): + """Concrete date type. + + Constructors: + + __new__() + fromtimestamp() + today() + fromordinal() + + Operators: + + __repr__, __str__ + __cmp__, __hash__ + __add__, __radd__, __sub__ (add/radd only with timedelta arg) + + Methods: + + timetuple() + toordinal() + weekday() + isoweekday(), isocalendar(), isoformat() + ctime() + strftime() + + Properties (readonly): + year, month, day + """ + + def __new__(cls, year, month=None, day=None): + """Constructor. + + Arguments: + + year, month, day (required, base 1) + """ + if isinstance(year, str): + # Pickle support + self = object.__new__(cls) + self.__setstate((year,)) + return self + _check_date_fields(year, month, day) + self = object.__new__(cls) + self.__year = year + self.__month = month + self.__day = day + return self + + # Additional constructors + + def fromtimestamp(cls, t): + "Construct a date from a POSIX timestamp (like time.time())." + y, m, d, hh, mm, ss, weekday, jday, dst = _time.localtime(t) + return cls(y, m, d) + fromtimestamp = classmethod(fromtimestamp) + + def today(cls): + "Construct a date from time.time()." + t = _time.time() + return cls.fromtimestamp(t) + today = classmethod(today) + + def fromordinal(cls, n): + """Contruct a date from a proleptic Gregorian ordinal. + + January 1 of year 1 is day 1. Only the year, month and day are + non-zero in the result. + """ + y, m, d = _ord2ymd(n) + return cls(y, m, d) + fromordinal = classmethod(fromordinal) + + # Conversions to string + + def __repr__(self): + "Convert to formal string, for repr()." + return "%s(%d, %d, %d)" % ('datetime.' + self.__class__.__name__, + self.__year, + self.__month, + self.__day) + # XXX These shouldn't depend on time.localtime(), because that + # clips the usable dates to [1970 .. 2038). At least ctime() is + # easily done without using strftime() -- that's better too because + # strftime("%c", ...) is locale specific. + + def ctime(self): + "Format a la ctime()." + return tmxxx(self.__year, self.__month, self.__day).ctime() + + def strftime(self, fmt): + "Format using strftime()." + return _wrap_strftime(self, fmt, self.timetuple()) + + def isoformat(self): + """Return the date formatted according to ISO. + + This is 'YYYY-MM-DD'. + + References: + - http://www.w3.org/TR/NOTE-datetime + - http://www.cl.cam.ac.uk/~mgk25/iso-time.html + """ + return "%04d-%02d-%02d" % (self.__year, self.__month, self.__day) + + __str__ = isoformat + + # Read-only field accessors + year = property(lambda self: self.__year, + doc="year (%d-%d)" % (MINYEAR, MAXYEAR)) + month = property(lambda self: self.__month, doc="month (1-12)") + day = property(lambda self: self.__day, doc="day (1-31)") + + # Standard conversions, __cmp__, __hash__ (and helpers) + + def timetuple(self): + "Return local time tuple compatible with time.localtime()." + return _build_struct_time(self.__year, self.__month, self.__day, + 0, 0, 0, -1) + + def toordinal(self): + """Return proleptic Gregorian ordinal for the year, month and day. + + January 1 of year 1 is day 1. Only the year, month and day values + contribute to the result. + """ + return _ymd2ord(self.__year, self.__month, self.__day) + + def replace(self, year=None, month=None, day=None): + """Return a new date with new values for the specified fields.""" + if year is None: + year = self.__year + if month is None: + month = self.__month + if day is None: + day = self.__day + _check_date_fields(year, month, day) + return date(year, month, day) + + # Comparisons. + + def __eq__(self, other): + if isinstance(other, date): + return self.__cmp(other) == 0 + elif hasattr(other, "timetuple"): + return NotImplemented + else: + return False + + def __ne__(self, other): + if isinstance(other, date): + return self.__cmp(other) != 0 + elif hasattr(other, "timetuple"): + return NotImplemented + else: + return True + + def __le__(self, other): + if isinstance(other, date): + return self.__cmp(other) <= 0 + elif hasattr(other, "timetuple"): + return NotImplemented + else: + _cmperror(self, other) + + def __lt__(self, other): + if isinstance(other, date): + return self.__cmp(other) < 0 + elif hasattr(other, "timetuple"): + return NotImplemented + else: + _cmperror(self, other) + + def __ge__(self, other): + if isinstance(other, date): + return self.__cmp(other) >= 0 + elif hasattr(other, "timetuple"): + return NotImplemented + else: + _cmperror(self, other) + + def __gt__(self, other): + if isinstance(other, date): + return self.__cmp(other) > 0 + elif hasattr(other, "timetuple"): + return NotImplemented + else: + _cmperror(self, other) + + def __cmp(self, other): + assert isinstance(other, date) + y, m, d = self.__year, self.__month, self.__day + y2, m2, d2 = other.__year, other.__month, other.__day + return cmp((y, m, d), (y2, m2, d2)) + + def __hash__(self): + "Hash." + return hash(self.__getstate()) + + # Computations + + def _checkOverflow(self, year): + if not MINYEAR <= year <= MAXYEAR: + raise OverflowError("date +/-: result year %d not in %d..%d" % + (year, MINYEAR, MAXYEAR)) + + def __add__(self, other): + "Add a date to a timedelta." + if isinstance(other, timedelta): + t = tmxxx(self.__year, + self.__month, + self.__day + other.days) + self._checkOverflow(t.year) + result = self.__class__(t.year, t.month, t.day) + return result + raise TypeError + # XXX Should be 'return NotImplemented', but there's a bug in 2.2... + + __radd__ = __add__ + + def __sub__(self, other): + """Subtract two dates, or a date and a timedelta.""" + if isinstance(other, timedelta): + return self + timedelta(-other.days) + if isinstance(other, date): + days1 = self.toordinal() + days2 = other.toordinal() + return timedelta(days1 - days2) + return NotImplemented + + def weekday(self): + "Return day of the week, where Monday == 0 ... Sunday == 6." + return (self.toordinal() + 6) % 7 + + # Day-of-the-week and week-of-the-year, according to ISO + + def isoweekday(self): + "Return day of the week, where Monday == 1 ... Sunday == 7." + # 1-Jan-0001 is a Monday + return self.toordinal() % 7 or 7 + + def isocalendar(self): + """Return a 3-tuple containing ISO year, week number, and weekday. + + The first ISO week of the year is the (Mon-Sun) week + containing the year's first Thursday; everything else derives + from that. + + The first week is 1; Monday is 1 ... Sunday is 7. + + ISO calendar algorithm taken from + http://www.phys.uu.nl/~vgent/calendar/isocalendar.htm + """ + year = self.__year + week1monday = _isoweek1monday(year) + today = _ymd2ord(self.__year, self.__month, self.__day) + # Internally, week and day have origin 0 + week, day = divmod(today - week1monday, 7) + if week < 0: + year -= 1 + week1monday = _isoweek1monday(year) + week, day = divmod(today - week1monday, 7) + elif week >= 52: + if today >= _isoweek1monday(year+1): + year += 1 + week = 0 + return year, week+1, day+1 + + # Pickle support. + + __safe_for_unpickling__ = True # For Python 2.2 + + def __getstate(self): + yhi, ylo = divmod(self.__year, 256) + return ("%c%c%c%c" % (yhi, ylo, self.__month, self.__day), ) + + def __setstate(self, t): + assert isinstance(t, tuple) and len(t) == 1, `t` + string = t[0] + assert len(string) == 4 + yhi, ylo, self.__month, self.__day = map(ord, string) + self.__year = yhi * 256 + ylo + + def __reduce__(self): + return (self.__class__, self.__getstate()) + +_date_class = date # so functions w/ args named "date" can get at the class + +date.min = date(1, 1, 1) +date.max = date(9999, 12, 31) +date.resolution = timedelta(days=1) + +class tzinfo(object): + """Abstract base class for time zone info classes. + + Subclasses must override the name(), utcoffset() and dst() methods. + """ + + def tzname(self, dt): + "datetime -> string name of time zone." + raise NotImplementedError("tzinfo subclass must override tzname()") + + def utcoffset(self, dt): + "datetime -> minutes east of UTC (negative for west of UTC)" + raise NotImplementedError("tzinfo subclass must override utcoffset()") + + def dst(self, dt): + """datetime -> DST offset in minutes east of UTC. + + Return 0 if DST not in effect. utcoffset() must include the DST + offset. + """ + raise NotImplementedError("tzinfo subclass must override dst()") + + def fromutc(self, dt): + "datetime in UTC -> datetime in local time." + + if not isinstance(dt, datetime): + raise TypeError("fromutc() requires a datetime argument") + if dt.tzinfo is not self: + raise ValueError("dt.tzinfo is not self") + + dtoff = dt.utcoffset() + if dtoff is None: + raise ValueError("fromutc() requires a non-None utcoffset() " + "result") + + # See the long comment block at the end of this file for an + # explanation of this algorithm. + dtdst = dt.dst() + if dtdst is None: + raise ValueError("fromutc() requires a non-None dst() result") + delta = dtoff - dtdst + if delta: + dt += delta + dtdst = dt.dst() + if dtdst is None: + raise ValueError("fromutc(): dt.dst gave inconsistent " + "results; cannot convert") + if dtdst: + return dt + dtdst + else: + return dt + + # Pickle support. + + __safe_for_unpickling__ = True # For Python 2.2 + + def __reduce__(self): + getinitargs = getattr(self, "__getinitargs__", None) + if getinitargs: + args = getinitargs() + else: + args = () + getstate = getattr(self, "__getstate__", None) + if getstate: + state = getstate() + else: + state = getattr(self, "__dict__", None) or None + if state is None: + return (self.__class__, args) + else: + return (self.__class__, args, state) + +_tzinfo_class = tzinfo # so functions w/ args named "tinfo" can get at it + +class time(object): + """Time with time zone. + + Constructors: + + __new__() + + Operators: + + __repr__, __str__ + __cmp__, __hash__ + + Methods: + + strftime() + isoformat() + utcoffset() + tzname() + dst() + + Properties (readonly): + hour, minute, second, microsecond, tzinfo + """ + + def __new__(cls, hour=0, minute=0, second=0, microsecond=0, tzinfo=None): + """Constructor. + + Arguments: + + hour, minute (required) + second, microsecond (default to zero) + tzinfo (default to None) + """ + self = object.__new__(cls) + if isinstance(hour, str): + # Pickle support + self.__setstate((hour, minute or None)) + return self + _check_tzinfo_arg(tzinfo) + _check_time_fields(hour, minute, second, microsecond) + self.__hour = hour + self.__minute = minute + self.__second = second + self.__microsecond = microsecond + self._tzinfo = tzinfo + return self + + # Read-only field accessors + hour = property(lambda self: self.__hour, doc="hour (0-23)") + minute = property(lambda self: self.__minute, doc="minute (0-59)") + second = property(lambda self: self.__second, doc="second (0-59)") + microsecond = property(lambda self: self.__microsecond, + doc="microsecond (0-999999)") + tzinfo = property(lambda self: self._tzinfo, doc="timezone info object") + + # Standard conversions, __hash__ (and helpers) + + # Comparisons. + + def __eq__(self, other): + if isinstance(other, time): + return self.__cmp(other) == 0 + else: + return False + + def __ne__(self, other): + if isinstance(other, time): + return self.__cmp(other) != 0 + else: + return True + + def __le__(self, other): + if isinstance(other, time): + return self.__cmp(other) <= 0 + else: + _cmperror(self, other) + + def __lt__(self, other): + if isinstance(other, time): + return self.__cmp(other) < 0 + else: + _cmperror(self, other) + + def __ge__(self, other): + if isinstance(other, time): + return self.__cmp(other) >= 0 + else: + _cmperror(self, other) + + def __gt__(self, other): + if isinstance(other, time): + return self.__cmp(other) > 0 + else: + _cmperror(self, other) + + def __cmp(self, other): + assert isinstance(other, time) + mytz = self._tzinfo + ottz = other._tzinfo + myoff = otoff = None + + if mytz is ottz: + base_compare = True + else: + myoff = self._utcoffset() + otoff = other._utcoffset() + base_compare = myoff == otoff + + if base_compare: + return cmp((self.__hour, self.__minute, self.__second, + self.__microsecond), + (other.__hour, other.__minute, other.__second, + other.__microsecond)) + if myoff is None or otoff is None: + # XXX Buggy in 2.2.2. + raise TypeError("cannot compare naive and aware times") + myhhmm = self.__hour * 60 + self.__minute - myoff + othhmm = other.__hour * 60 + other.__minute - otoff + return cmp((myhhmm, self.__second, self.__microsecond), + (othhmm, other.__second, other.__microsecond)) + + def __hash__(self): + """Hash.""" + tzoff = self._utcoffset() + if not tzoff: # zero or None + return hash(self.__getstate()[0]) + h, m = divmod(self.hour * 60 + self.minute - tzoff, 60) + if 0 <= h < 24: + return hash(time(h, m, self.second, self.microsecond)) + return hash((h, m, self.second, self.microsecond)) + + # Conversion to string + + def _tzstr(self, sep=":"): + """Return formatted timezone offset (+xx:xx) or None.""" + off = self._utcoffset() + if off is not None: + if off < 0: + sign = "-" + off = -off + else: + sign = "+" + hh, mm = divmod(off, 60) + assert 0 <= hh < 24 + off = "%s%02d%s%02d" % (sign, hh, sep, mm) + return off + + def __repr__(self): + """Convert to formal string, for repr().""" + if self.__microsecond != 0: + s = ", %d, %d" % (self.__second, self.__microsecond) + elif self.__second != 0: + s = ", %d" % self.__second + else: + s = "" + s= "%s(%d, %d%s)" % ('datetime.' + self.__class__.__name__, + self.__hour, self.__minute, s) + if self._tzinfo is not None: + assert s[-1:] == ")" + s = s[:-1] + ", tzinfo=%r" % self._tzinfo + ")" + return s + + def isoformat(self): + """Return the time formatted according to ISO. + + This is 'HH:MM:SS.mmmmmm+zz:zz', or 'HH:MM:SS+zz:zz' if + self.microsecond == 0. + """ + s = _format_time(self.__hour, self.__minute, self.__second, + self.__microsecond) + tz = self._tzstr() + if tz: + s += tz + return s + + __str__ = isoformat + + def strftime(self, fmt): + """Format using strftime(). The date part of the timestamp passed + to underlying strftime should not be used. + """ + # The year must be >= 1900 else Python's strftime implementation + # can raise a bogus exception. + timetuple = (1900, 1, 1, + self.__hour, self.__minute, self.__second, + 0, 1, -1) + return _wrap_strftime(self, fmt, timetuple) + + # Timezone functions + + def utcoffset(self): + """Return the timezone offset in minutes east of UTC (negative west of + UTC).""" + offset = _call_tzinfo_method(self._tzinfo, "utcoffset", None) + offset = _check_utc_offset("utcoffset", offset) + if offset is not None: + offset = timedelta(minutes=offset) + return offset + + # Return an integer (or None) instead of a timedelta (or None). + def _utcoffset(self): + offset = _call_tzinfo_method(self._tzinfo, "utcoffset", None) + offset = _check_utc_offset("utcoffset", offset) + return offset + + def tzname(self): + """Return the timezone name. + + Note that the name is 100% informational -- there's no requirement that + it mean anything in particular. For example, "GMT", "UTC", "-500", + "-5:00", "EDT", "US/Eastern", "America/New York" are all valid replies. + """ + name = _call_tzinfo_method(self._tzinfo, "tzname", None) + _check_tzname(name) + return name + + def dst(self): + """Return 0 if DST is not in effect, or the DST offset (in minutes + eastward) if DST is in effect. + + This is purely informational; the DST offset has already been added to + the UTC offset returned by utcoffset() if applicable, so there's no + need to consult dst() unless you're interested in displaying the DST + info. + """ + offset = _call_tzinfo_method(self._tzinfo, "dst", None) + offset = _check_utc_offset("dst", offset) + if offset is not None: + offset = timedelta(minutes=offset) + return offset + + def replace(self, hour=None, minute=None, second=None, microsecond=None, + tzinfo=True): + """Return a new time with new values for the specified fields.""" + if hour is None: + hour = self.hour + if minute is None: + minute = self.minute + if second is None: + second = self.second + if microsecond is None: + microsecond = self.microsecond + if tzinfo is True: + tzinfo = self.tzinfo + _check_time_fields(hour, minute, second, microsecond) + _check_tzinfo_arg(tzinfo) + return time(hour, minute, second, microsecond, tzinfo) + + # Return an integer (or None) instead of a timedelta (or None). + def _dst(self): + offset = _call_tzinfo_method(self._tzinfo, "dst", None) + offset = _check_utc_offset("dst", offset) + return offset + + def __nonzero__(self): + if self.second or self.microsecond: + return 1 + offset = self._utcoffset() or 0 + return self.hour * 60 + self.minute - offset != 0 + + # Pickle support. + + __safe_for_unpickling__ = True # For Python 2.2 + + def __getstate(self): + us2, us3 = divmod(self.__microsecond, 256) + us1, us2 = divmod(us2, 256) + basestate = ("%c" * 6) % (self.__hour, self.__minute, self.__second, + us1, us2, us3) + if self._tzinfo is None: + return (basestate,) + else: + return (basestate, self._tzinfo) + + def __setstate(self, state): + assert isinstance(state, tuple) + assert 1 <= len(state) <= 2 + string = state[0] + assert len(string) == 6 + self.__hour, self.__minute, self.__second, us1, us2, us3 = \ + map(ord, string) + self.__microsecond = (((us1 << 8) | us2) << 8) | us3 + if len(state) == 1: + self._tzinfo = None + else: + self._tzinfo = state[1] + + def __reduce__(self): + return (self.__class__, self.__getstate()) + +_time_class = time # so functions w/ args named "time" can get at the class + +time.min = time(0, 0, 0) +time.max = time(23, 59, 59, 999999) +time.resolution = timedelta(microseconds=1) + +class datetime(date): + + # XXX needs docstrings + # See http://www.zope.org/Members/fdrake/DateTimeWiki/TimeZoneInfo + + def __new__(cls, year, month=None, day=None, hour=0, minute=0, second=0, + microsecond=0, tzinfo=None): + if isinstance(year, str): + # Pickle support + self = date.__new__(cls, year[:4]) + self.__setstate((year, month)) + return self + _check_tzinfo_arg(tzinfo) + _check_time_fields(hour, minute, second, microsecond) + self = date.__new__(cls, year, month, day) + # XXX This duplicates __year, __month, __day for convenience :-( + self.__year = year + self.__month = month + self.__day = day + self.__hour = hour + self.__minute = minute + self.__second = second + self.__microsecond = microsecond + self._tzinfo = tzinfo + return self + + # Read-only field accessors + hour = property(lambda self: self.__hour, doc="hour (0-23)") + minute = property(lambda self: self.__minute, doc="minute (0-59)") + second = property(lambda self: self.__second, doc="second (0-59)") + microsecond = property(lambda self: self.__microsecond, + doc="microsecond (0-999999)") + tzinfo = property(lambda self: self._tzinfo, doc="timezone info object") + + def fromtimestamp(cls, t, tz=None): + """Construct a datetime from a POSIX timestamp (like time.time()). + + A timezone info object may be passed in as well. + """ + + _check_tzinfo_arg(tz) + if tz is None: + converter = _time.localtime + else: + converter = _time.gmtime + y, m, d, hh, mm, ss, weekday, jday, dst = converter(t) + us = int((t % 1.0) * 1000000) + ss = min(ss, 59) # clamp out leap seconds if the platform has them + result = cls(y, m, d, hh, mm, ss, us, tz) + if tz is not None: + result = tz.fromutc(result) + return result + fromtimestamp = classmethod(fromtimestamp) + + def utcfromtimestamp(cls, t): + "Construct a UTC datetime from a POSIX timestamp (like time.time())." + y, m, d, hh, mm, ss, weekday, jday, dst = _time.gmtime(t) + us = int((t % 1.0) * 1000000) + ss = min(ss, 59) # clamp out leap seconds if the platform has them + return cls(y, m, d, hh, mm, ss, us) + utcfromtimestamp = classmethod(utcfromtimestamp) + + # XXX This is supposed to do better than we *can* do by using time.time(), + # XXX if the platform supports a more accurate way. The C implementation + # XXX uses gettimeofday on platforms that have it, but that isn't + # XXX available from Python. So now() may return different results + # XXX across the implementations. + def now(cls, tz=None): + "Construct a datetime from time.time() and optional time zone info." + t = _time.time() + return cls.fromtimestamp(t, tz) + now = classmethod(now) + + def utcnow(cls): + "Construct a UTC datetime from time.time()." + t = _time.time() + return cls.utcfromtimestamp(t) + utcnow = classmethod(utcnow) + + def combine(cls, date, time): + "Construct a datetime from a given date and a given time." + if not isinstance(date, _date_class): + raise TypeError("date argument must be a date instance") + if not isinstance(time, _time_class): + raise TypeError("time argument must be a time instance") + return cls(date.year, date.month, date.day, + time.hour, time.minute, time.second, time.microsecond, + time.tzinfo) + combine = classmethod(combine) + + def timetuple(self): + "Return local time tuple compatible with time.localtime()." + dst = self._dst() + if dst is None: + dst = -1 + elif dst: + dst = 1 + return _build_struct_time(self.year, self.month, self.day, + self.hour, self.minute, self.second, + dst) + + def utctimetuple(self): + "Return UTC time tuple compatible with time.gmtime()." + y, m, d = self.year, self.month, self.day + hh, mm, ss = self.hour, self.minute, self.second + offset = self._utcoffset() + if offset: # neither None nor 0 + tm = tmxxx(y, m, d, hh, mm - offset) + y, m, d = tm.year, tm.month, tm.day + hh, mm = tm.hour, tm.minute + return _build_struct_time(y, m, d, hh, mm, ss, 0) + + def date(self): + "Return the date part." + return date(self.__year, self.__month, self.__day) + + def time(self): + "Return the time part, with tzinfo None." + return time(self.hour, self.minute, self.second, self.microsecond) + + def timetz(self): + "Return the time part, with same tzinfo." + return time(self.hour, self.minute, self.second, self.microsecond, + self._tzinfo) + + def replace(self, year=None, month=None, day=None, hour=None, + minute=None, second=None, microsecond=None, tzinfo=True): + """Return a new datetime with new values for the specified fields.""" + if year is None: + year = self.year + if month is None: + month = self.month + if day is None: + day = self.day + if hour is None: + hour = self.hour + if minute is None: + minute = self.minute + if second is None: + second = self.second + if microsecond is None: + microsecond = self.microsecond + if tzinfo is True: + tzinfo = self.tzinfo + _check_date_fields(year, month, day) + _check_time_fields(hour, minute, second, microsecond) + _check_tzinfo_arg(tzinfo) + return datetime(year, month, day, hour, minute, second, + microsecond, tzinfo) + + def astimezone(self, tz): + if not isinstance(tz, tzinfo): + raise TypeError("tz argument must be an instance of tzinfo") + + mytz = self.tzinfo + if mytz is None: + raise ValueError("astimezone() requires an aware datetime") + + if tz is mytz: + return self + + # Convert self to UTC, and attach the new time zone object. + myoffset = self.utcoffset() + if myoffset is None: + raise ValuError("astimezone() requires an aware datetime") + utc = (self - myoffset).replace(tzinfo=tz) + + # Convert from UTC to tz's local time. + return tz.fromutc(utc) + + # Ways to produce a string. + + def ctime(self): + "Format a la ctime()." + t = tmxxx(self.__year, self.__month, self.__day, self.__hour, + self.__minute, self.__second) + return t.ctime() + + def isoformat(self, sep='T'): + """Return the time formatted according to ISO. + + This is 'YYYY-MM-DD HH:MM:SS.mmmmmm', or 'YYYY-MM-DD HH:MM:SS' if + self.microsecond == 0. + + If self.tzinfo is not None, the UTC offset is also attached, giving + 'YYYY-MM-DD HH:MM:SS.mmmmmm+HH:MM' or 'YYYY-MM-DD HH:MM:SS+HH:MM'. + + Optional argument sep specifies the separator between date and + time, default 'T'. + """ + s = ("%04d-%02d-%02d%c" % (self.__year, self.__month, self.__day, + sep) + + _format_time(self.__hour, self.__minute, self.__second, + self.__microsecond)) + off = self._utcoffset() + if off is not None: + if off < 0: + sign = "-" + off = -off + else: + sign = "+" + hh, mm = divmod(off, 60) + s += "%s%02d:%02d" % (sign, hh, mm) + return s + + def __repr__(self): + "Convert to formal string, for repr()." + L = [self.__year, self.__month, self.__day, # These are never zero + self.__hour, self.__minute, self.__second, self.__microsecond] + while L[-1] == 0: + del L[-1] + s = ", ".join(map(str, L)) + s = "%s(%s)" % ('datetime.' + self.__class__.__name__, s) + if self._tzinfo is not None: + assert s[-1:] == ")" + s = s[:-1] + ", tzinfo=%r" % self._tzinfo + ")" + return s + + def __str__(self): + "Convert to string, for str()." + return self.isoformat(sep=' ') + + def utcoffset(self): + """Return the timezone offset in minutes east of UTC (negative west of + UTC).""" + offset = _call_tzinfo_method(self._tzinfo, "utcoffset", self) + offset = _check_utc_offset("utcoffset", offset) + if offset is not None: + offset = timedelta(minutes=offset) + return offset + + # Return an integer (or None) instead of a timedelta (or None). + def _utcoffset(self): + offset = _call_tzinfo_method(self._tzinfo, "utcoffset", self) + offset = _check_utc_offset("utcoffset", offset) + return offset + + def tzname(self): + """Return the timezone name. + + Note that the name is 100% informational -- there's no requirement that + it mean anything in particular. For example, "GMT", "UTC", "-500", + "-5:00", "EDT", "US/Eastern", "America/New York" are all valid replies. + """ + name = _call_tzinfo_method(self._tzinfo, "tzname", self) + _check_tzname(name) + return name + + def dst(self): + """Return 0 if DST is not in effect, or the DST offset (in minutes + eastward) if DST is in effect. + + This is purely informational; the DST offset has already been added to + the UTC offset returned by utcoffset() if applicable, so there's no + need to consult dst() unless you're interested in displaying the DST + info. + """ + offset = _call_tzinfo_method(self._tzinfo, "dst", self) + offset = _check_utc_offset("dst", offset) + if offset is not None: + offset = timedelta(minutes=offset) + return offset + + # Return an integer (or None) instead of a timedelta (or None).1573 + def _dst(self): + offset = _call_tzinfo_method(self._tzinfo, "dst", self) + offset = _check_utc_offset("dst", offset) + return offset + + # Comparisons. + + def __eq__(self, other): + if isinstance(other, datetime): + return self.__cmp(other) == 0 + elif hasattr(other, "timetuple"): + return NotImplemented + else: + return False + + def __ne__(self, other): + if isinstance(other, datetime): + return self.__cmp(other) != 0 + elif hasattr(other, "timetuple"): + return NotImplemented + else: + return True + + def __le__(self, other): + if isinstance(other, datetime): + return self.__cmp(other) <= 0 + elif hasattr(other, "timetuple"): + return NotImplemented + else: + _cmperror(self, other) + + def __lt__(self, other): + if isinstance(other, datetime): + return self.__cmp(other) < 0 + elif hasattr(other, "timetuple"): + return NotImplemented + else: + _cmperror(self, other) + + def __ge__(self, other): + if isinstance(other, datetime): + return self.__cmp(other) >= 0 + elif hasattr(other, "timetuple"): + return NotImplemented + else: + _cmperror(self, other) + + def __gt__(self, other): + if isinstance(other, datetime): + return self.__cmp(other) > 0 + elif hasattr(other, "timetuple"): + return NotImplemented + else: + _cmperror(self, other) + + def __cmp(self, other): + assert isinstance(other, datetime) + mytz = self._tzinfo + ottz = other._tzinfo + myoff = otoff = None + + if mytz is ottz: + base_compare = True + else: + if mytz is not None: + myoff = self._utcoffset() + if ottz is not None: + otoff = other._utcoffset() + base_compare = myoff == otoff + + if base_compare: + return cmp((self.__year, self.__month, self.__day, + self.__hour, self.__minute, self.__second, + self.__microsecond), + (other.__year, other.__month, other.__day, + other.__hour, other.__minute, other.__second, + other.__microsecond)) + if myoff is None or otoff is None: + # XXX Buggy in 2.2.2. + raise TypeError("cannot compare naive and aware datetimes") + # XXX What follows could be done more efficiently... + diff = self - other # this will take offsets into account + if diff.days < 0: + return -1 + return diff and 1 or 0 + + def __add__(self, other): + "Add a datetime and a timedelta." + if not isinstance(other, timedelta): + return NotImplemented + t = tmxxx(self.__year, + self.__month, + self.__day + other.days, + self.__hour, + self.__minute, + self.__second + other.seconds, + self.__microsecond + other.microseconds) + self._checkOverflow(t.year) + result = self.__class__(t.year, t.month, t.day, + t.hour, t.minute, t.second, + t.microsecond, tzinfo=self._tzinfo) + return result + + __radd__ = __add__ + + def __sub__(self, other): + "Subtract two datetimes, or a datetime and a timedelta." + if not isinstance(other, datetime): + if isinstance(other, timedelta): + return self + -other + return NotImplemented + + days1 = self.toordinal() + days2 = other.toordinal() + secs1 = self.__second + self.__minute * 60 + self.__hour * 3600 + secs2 = other.__second + other.__minute * 60 + other.__hour * 3600 + base = timedelta(days1 - days2, + secs1 - secs2, + self.__microsecond - other.__microsecond) + if self._tzinfo is other._tzinfo: + return base + myoff = self._utcoffset() + otoff = other._utcoffset() + if myoff == otoff: + return base + if myoff is None or otoff is None: + raise TypeError, "cannot mix naive and timezone-aware time" + return base + timedelta(minutes = otoff-myoff) + + def __hash__(self): + tzoff = self._utcoffset() + if tzoff is None: + return hash(self.__getstate()[0]) + days = _ymd2ord(self.year, self.month, self.day) + seconds = self.hour * 3600 + (self.minute - tzoff) * 60 + self.second + return hash(timedelta(days, seconds, self.microsecond)) + + # Pickle support. + + __safe_for_unpickling__ = True # For Python 2.2 + + def __getstate(self): + yhi, ylo = divmod(self.__year, 256) + us2, us3 = divmod(self.__microsecond, 256) + us1, us2 = divmod(us2, 256) + basestate = ("%c" * 10) % (yhi, ylo, self.__month, self.__day, + self.__hour, self.__minute, self.__second, + us1, us2, us3) + if self._tzinfo is None: + return (basestate,) + else: + return (basestate, self._tzinfo) + + def __setstate(self, state): + assert isinstance(state, tuple) + assert 1 <= len(state) <= 2 + string = state[0] + assert len(string) == 10 + (yhi, ylo, self.__month, self.__day, self.__hour, + self.__minute, self.__second, us1, us2, us3) = map(ord, string) + self.__year = yhi * 256 + ylo + self.__microsecond = (((us1 << 8) | us2) << 8) | us3 + if len(state) == 1: + self._tzinfo = None + else: + self._tzinfo = state[1] + + def __reduce__(self): + return (self.__class__, self.__getstate()) + + +datetime.min = datetime(1, 1, 1) +datetime.max = datetime(9999, 12, 31, 23, 59, 59, 999999) +datetime.resolution = timedelta(microseconds=1) + + +def _isoweek1monday(year): + # Helper to calculate the day number of the Monday starting week 1 + # XXX This could be done more efficiently + THURSDAY = 3 + firstday = _ymd2ord(year, 1, 1) + firstweekday = (firstday + 6) % 7 # See weekday() above + week1monday = firstday - firstweekday + if firstweekday > THURSDAY: + week1monday += 7 + return week1monday + +""" +Some time zone algebra. For a datetime x, let + x.n = x stripped of its timezone -- its naive time. + x.o = x.utcoffset(), and assuming that doesn't raise an exception or + return None + x.d = x.dst(), and assuming that doesn't raise an exception or + return None + x.s = x's standard offset, x.o - x.d + +Now some derived rules, where k is a duration (timedelta). + +1. x.o = x.s + x.d + This follows from the definition of x.s. + +2. If x and y have the same tzinfo member, x.s = y.s. + This is actually a requirement, an assumption we need to make about + sane tzinfo classes. + +3. The naive UTC time corresponding to x is x.n - x.o. + This is again a requirement for a sane tzinfo class. + +4. (x+k).s = x.s + This follows from #2, and that datimetimetz+timedelta preserves tzinfo. + +5. (x+k).n = x.n + k + Again follows from how arithmetic is defined. + +Now we can explain tz.fromutc(x). Let's assume it's an interesting case +(meaning that the various tzinfo methods exist, and don't blow up or return +None when called). + +The function wants to return a datetime y with timezone tz, equivalent to x. +x is already in UTC. + +By #3, we want + + y.n - y.o = x.n [1] + +The algorithm starts by attaching tz to x.n, and calling that y. So +x.n = y.n at the start. Then it wants to add a duration k to y, so that [1] +becomes true; in effect, we want to solve [2] for k: + + (y+k).n - (y+k).o = x.n [2] + +By #1, this is the same as + + (y+k).n - ((y+k).s + (y+k).d) = x.n [3] + +By #5, (y+k).n = y.n + k, which equals x.n + k because x.n=y.n at the start. +Substituting that into [3], + + x.n + k - (y+k).s - (y+k).d = x.n; the x.n terms cancel, leaving + k - (y+k).s - (y+k).d = 0; rearranging, + k = (y+k).s - (y+k).d; by #4, (y+k).s == y.s, so + k = y.s - (y+k).d + +On the RHS, (y+k).d can't be computed directly, but y.s can be, and we +approximate k by ignoring the (y+k).d term at first. Note that k can't be +very large, since all offset-returning methods return a duration of magnitude +less than 24 hours. For that reason, if y is firmly in std time, (y+k).d must +be 0, so ignoring it has no consequence then. + +In any case, the new value is + + z = y + y.s [4] + +It's helpful to step back at look at [4] from a higher level: it's simply +mapping from UTC to tz's standard time. + +At this point, if + + z.n - z.o = x.n [5] + +we have an equivalent time, and are almost done. The insecurity here is +at the start of daylight time. Picture US Eastern for concreteness. The wall +time jumps from 1:59 to 3:00, and wall hours of the form 2:MM don't make good +sense then. The docs ask that an Eastern tzinfo class consider such a time to +be EDT (because it's "after 2"), which is a redundant spelling of 1:MM EST +on the day DST starts. We want to return the 1:MM EST spelling because that's +the only spelling that makes sense on the local wall clock. + +In fact, if [5] holds at this point, we do have the standard-time spelling, +but that takes a bit of proof. We first prove a stronger result. What's the +difference between the LHS and RHS of [5]? Let + + diff = x.n - (z.n - z.o) [6] + +Now + z.n = by [4] + (y + y.s).n = by #5 + y.n + y.s = since y.n = x.n + x.n + y.s = since z and y are have the same tzinfo member, + y.s = z.s by #2 + x.n + z.s + +Plugging that back into [6] gives + + diff = + x.n - ((x.n + z.s) - z.o) = expanding + x.n - x.n - z.s + z.o = cancelling + - z.s + z.o = by #2 + z.d + +So diff = z.d. + +If [5] is true now, diff = 0, so z.d = 0 too, and we have the standard-time +spelling we wanted in the endcase described above. We're done. Contrarily, +if z.d = 0, then we have a UTC equivalent, and are also done. + +If [5] is not true now, diff = z.d != 0, and z.d is the offset we need to +add to z (in effect, z is in tz's standard time, and we need to shift the +local clock into tz's daylight time). + +Let + + z' = z + z.d = z + diff [7] + +and we can again ask whether + + z'.n - z'.o = x.n [8] + +If so, we're done. If not, the tzinfo class is insane, according to the +assumptions we've made. This also requires a bit of proof. As before, let's +compute the difference between the LHS and RHS of [8] (and skipping some of +the justifications for the kinds of substitutions we've done several times +already): + + diff' = x.n - (z'.n - z'.o) = replacing z'.n via [7] + x.n - (z.n + diff - z'.o) = replacing diff via [6] + x.n - (z.n + x.n - (z.n - z.o) - z'.o) = + x.n - z.n - x.n + z.n - z.o + z'.o = cancel x.n + - z.n + z.n - z.o + z'.o = cancel z.n + - z.o + z'.o = #1 twice + -z.s - z.d + z'.s + z'.d = z and z' have same tzinfo + z'.d - z.d + +So z' is UTC-equivalent to x iff z'.d = z.d at this point. If they are equal, +we've found the UTC-equivalent so are done. In fact, we stop with [7] and +return z', not bothering to compute z'.d. + +How could z.d and z'd differ? z' = z + z.d [7], so merely moving z' by +a dst() offset, and starting *from* a time already in DST (we know z.d != 0), +would have to change the result dst() returns: we start in DST, and moving +a little further into it takes us out of DST. + +There isn't a sane case where this can happen. The closest it gets is at +the end of DST, where there's an hour in UTC with no spelling in a hybrid +tzinfo class. In US Eastern, that's 5:MM UTC = 0:MM EST = 1:MM EDT. During +that hour, on an Eastern clock 1:MM is taken as being in standard time (6:MM +UTC) because the docs insist on that, but 0:MM is taken as being in daylight +time (4:MM UTC). There is no local time mapping to 5:MM UTC. The local +clock jumps from 1:59 back to 1:00 again, and repeats the 1:MM hour in +standard time. Since that's what the local clock *does*, we want to map both +UTC hours 5:MM and 6:MM to 1:MM Eastern. The result is ambiguous +in local time, but so it goes -- it's the way the local clock works. + +When x = 5:MM UTC is the input to this algorithm, x.o=0, y.o=-5 and y.d=0, +so z=0:MM. z.d=60 (minutes) then, so [5] doesn't hold and we keep going. +z' = z + z.d = 1:MM then, and z'.d=0, and z'.d - z.d = -60 != 0 so [8] +(correctly) concludes that z' is not UTC-equivalent to x. + +Because we know z.d said z was in daylight time (else [5] would have held and +we would have stopped then), and we know z.d != z'.d (else [8] would have held +and we we have stopped then), and there are only 2 possible values dst() can +return in Eastern, it follows that z'.d must be 0 (which it is in the example, +but the reasoning doesn't depend on the example -- it depends on there being +two possible dst() outcomes, one zero and the other non-zero). Therefore +z' must be in standard time, and is the spelling we want in this case. + +Note again that z' is not UTC-equivalent as far as the hybrid tzinfo class is +concerned (because it takes z' as being in standard time rather than the +daylight time we intend here), but returning it gives the real-life "local +clock repeats an hour" behavior when mapping the "unspellable" UTC hour into +tz. + +When the input is 6:MM, z=1:MM and z.d=0, and we stop at once, again with +the 1:MM standard time spelling we want. + +So how can this break? One of the assumptions must be violated. Two +possibilities: + +1) [2] effectively says that y.s is invariant across all y belong to a given + time zone. This isn't true if, for political reasons or continental drift, + a region decides to change its base offset from UTC. + +2) There may be versions of "double daylight" time where the tail end of + the analysis gives up a step too early. I haven't thought about that + enough to say. + +In any case, it's clear that the default fromutc() is strong enough to handle +"almost all" time zones: so long as the standard offset is invariant, it +doesn't matter if daylight time transition points change from year to year, or +if daylight time is skipped in some years; it doesn't matter how large or +small dst() may get within its bounds; and it doesn't even matter if some +perverse time zone returns a negative dst()). So a breaking case must be +pretty bizarre, and a tzinfo subclass can override fromutc() if it is. +""" + Added: pypy/dist/pypy/lib/test2/test_datetime.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/lib/test2/test_datetime.py Sun Mar 20 18:12:18 2005 @@ -0,0 +1,2903 @@ +"""Test date/time type. + +This is a py.test conversion of the test cases in the CVS sandbox of +CPython. +""" + +import sys +import pickle +import cPickle + +from datetime import MINYEAR, MAXYEAR +from datetime import timedelta +from datetime import tzinfo +from datetime import time +from datetime import date, datetime + + +# Before Python 2.3, proto=2 was taken as a synonym for proto=1. +pickle_choices = [(pickler, unpickler, proto) + for pickler in pickle, cPickle + for unpickler in pickle, cPickle + for proto in range(3)] +assert len(pickle_choices) == 2*2*3 + +# An arbitrary collection of objects of non-datetime types, for testing +# mixed-type comparisons. +OTHERSTUFF = (10, 10L, 34.5, "abc", {}, [], ()) + + +############################################################################# +# module tests + +class TestModule(object): + + def test_constants(self): + import datetime + assert datetime.MINYEAR == 1 + assert datetime.MAXYEAR == 9999 + +############################################################################# +# tzinfo tests + +class FixedOffset(tzinfo): + def __init__(self, offset, name, dstoffset=42): + if isinstance(offset, int): + offset = timedelta(minutes=offset) + if isinstance(dstoffset, int): + dstoffset = timedelta(minutes=dstoffset) + self.__offset = offset + self.__name = name + self.__dstoffset = dstoffset + def __repr__(self): + return self.__name.lower() + def utcoffset(self, dt): + return self.__offset + def tzname(self, dt): + return self.__name + def dst(self, dt): + return self.__dstoffset + +class PicklableFixedOffset(FixedOffset): + def __init__(self, offset=None, name=None, dstoffset=None): + FixedOffset.__init__(self, offset, name, dstoffset) + +class TestTZInfo(object): + + def test_non_abstractness(self): + # In order to allow subclasses to get pickled, the C implementation + # wasn't able to get away with having __init__ raise + # NotImplementedError. + useless = tzinfo() + dt = datetime.max + raises(NotImplementedError, useless.tzname, dt) + raises(NotImplementedError, useless.utcoffset, dt) + raises(NotImplementedError, useless.dst, dt) + + def test_subclass_must_override(self): + class NotEnough(tzinfo): + def __init__(self, offset, name): + self.__offset = offset + self.__name = name + assert issubclass(NotEnough, tzinfo) + ne = NotEnough(3, "NotByALongShot") + assert isinstance(ne, tzinfo) + + dt = datetime.now() + raises(NotImplementedError, ne.tzname, dt) + raises(NotImplementedError, ne.utcoffset, dt) + raises(NotImplementedError, ne.dst, dt) + + def test_normal(self): + fo = FixedOffset(3, "Three") + assert isinstance(fo, tzinfo) + for dt in datetime.now(), None: + assert fo.utcoffset(dt) == timedelta(minutes=3) + assert fo.tzname(dt) == "Three" + assert fo.dst(dt) == timedelta(minutes=42) + + def test_pickling_base(self): + # There's no point to pickling tzinfo objects on their own (they + # carry no data), but they need to be picklable anyway else + # concrete subclasses can't be pickled. + orig = tzinfo.__new__(tzinfo) + assert type(orig) is tzinfo + for pickler, unpickler, proto in pickle_choices: + green = pickler.dumps(orig, proto) + derived = unpickler.loads(green) + assert type(derived) is tzinfo + + def test_pickling_subclass(self): + # Make sure we can pickle/unpickle an instance of a subclass. + offset = timedelta(minutes=-300) + orig = PicklableFixedOffset(offset, 'cookie') + assert isinstance(orig, tzinfo) + assert type(orig) is PicklableFixedOffset + assert orig.utcoffset(None) == offset + assert orig.tzname(None) == 'cookie' + for pickler, unpickler, proto in pickle_choices: + green = pickler.dumps(orig, proto) + derived = unpickler.loads(green) + assert isinstance(derived, tzinfo) + assert type(derived) is PicklableFixedOffset + assert derived.utcoffset(None) == offset + assert derived.tzname(None) == 'cookie' + +############################################################################# +# Base clase for testing a particular aspect of timedelta, time, date and +# datetime comparisons. + +class HarmlessMixedComparison(object): + # Test that __eq__ and __ne__ don't complain for mixed-type comparisons. + + # Subclasses must define 'theclass', and theclass(1, 1, 1) must be a + # legit constructor. + + def test_harmless_mixed_comparison(self): + me = self.theclass(1, 1, 1) + + assert not me == () + assert me != () + assert not () == me + assert () != me + + assert me in [1, 20L, [], me] + assert not me not in [1, 20L, [], me] + + assert [] in [me, 1, 20L, []] + assert not [] not in [me, 1, 20L, []] + + def test_harmful_mixed_comparison(self): + me = self.theclass(1, 1, 1) + + raises(TypeError, lambda: me < ()) + raises(TypeError, lambda: me <= ()) + raises(TypeError, lambda: me > ()) + raises(TypeError, lambda: me >= ()) + + raises(TypeError, lambda: () < me) + raises(TypeError, lambda: () <= me) + raises(TypeError, lambda: () > me) + raises(TypeError, lambda: () >= me) + + raises(TypeError, cmp, (), me) + raises(TypeError, cmp, me, ()) + +############################################################################# +# timedelta tests + +class TestTimeDelta(HarmlessMixedComparison): + + theclass = timedelta + + def test_constructor(self): + td = timedelta + + # Check keyword args to constructor + assert td() == td(weeks=0, days=0, hours=0, minutes=0, seconds=0, + milliseconds=0, microseconds=0) + assert td(1) == td(days=1) + assert td(0, 1) == td(seconds=1) + assert td(0, 0, 1) == td(microseconds=1) + assert td(weeks=1) == td(days=7) + assert td(days=1) == td(hours=24) + assert td(hours=1) == td(minutes=60) + assert td(minutes=1) == td(seconds=60) + assert td(seconds=1) == td(milliseconds=1000) + assert td(milliseconds=1) == td(microseconds=1000) + + # Check float args to constructor + assert td(weeks=1.0/7) == td(days=1) + assert td(days=1.0/24) == td(hours=1) + assert td(hours=1.0/60) == td(minutes=1) + assert td(minutes=1.0/60) == td(seconds=1) + assert td(seconds=0.001) == td(milliseconds=1) + assert td(milliseconds=0.001) == td(microseconds=1) + + def test_computations(self): + td = timedelta + + a = td(7) # One week + b = td(0, 60) # One minute + c = td(0, 0, 1000) # One millisecond + assert a+b+c == td(7, 60, 1000) + assert a-b == td(6, 24*3600 - 60) + assert -a == td(-7) + assert +a == td(7) + assert -b == td(-1, 24*3600 - 60) + assert -c == td(-1, 24*3600 - 1, 999000) + assert abs(a) == a + assert abs(-a) == a + assert td(6, 24*3600) == a + assert td(0, 0, 60*1000000) == b + assert a*10 == td(70) + assert a*10 == 10*a + assert a*10L == 10*a + assert b*10 == td(0, 600) + assert 10*b == td(0, 600) + assert b*10L == td(0, 600) + assert c*10 == td(0, 0, 10000) + assert 10*c == td(0, 0, 10000) + assert c*10L == td(0, 0, 10000) + assert a*-1 == -a + assert b*-2 == -b-b + assert c*-2 == -c+-c + assert b*(60*24) == (b*60)*24 + assert b*(60*24) == (60*b)*24 + assert c*1000 == td(0, 1) + assert 1000*c == td(0, 1) + assert a//7 == td(1) + assert b//10 == td(0, 6) + assert c//1000 == td(0, 0, 1) + assert a//10 == td(0, 7*24*360) + assert a//3600000 == td(0, 0, 7*24*1000) + + def test_disallowed_computations(self): + a = timedelta(42) + + # Add/sub ints, longs, floats should be illegal + for i in 1, 1L, 1.0: + raises(TypeError, lambda: a+i) + raises(TypeError, lambda: a-i) + raises(TypeError, lambda: i+a) + raises(TypeError, lambda: i-a) + + # Mul/div by float isn't supported. + x = 2.3 + raises(TypeError, lambda: a*x) + raises(TypeError, lambda: x*a) + raises(TypeError, lambda: a/x) + raises(TypeError, lambda: x/a) + raises(TypeError, lambda: a // x) + raises(TypeError, lambda: x // a) + + # Divison of int by timedelta doesn't make sense. + # Division by zero doesn't make sense. + for zero in 0, 0L: + raises(TypeError, lambda: zero // a) + raises(ZeroDivisionError, lambda: a // zero) + + def test_basic_attributes(self): + days, seconds, us = 1, 7, 31 + td = timedelta(days, seconds, us) + assert td.days == days + assert td.seconds == seconds + assert td.microseconds == us + + def test_carries(self): + t1 = timedelta(days=100, + weeks=-7, + hours=-24*(100-49), + minutes=-3, + seconds=12, + microseconds=(3*60 - 12) * 1e6 + 1) + t2 = timedelta(microseconds=1) + assert t1 == t2 + + def test_hash_equality(self): + t1 = timedelta(days=100, + weeks=-7, + hours=-24*(100-49), + minutes=-3, + seconds=12, + microseconds=(3*60 - 12) * 1000000) + t2 = timedelta() + assert hash(t1) == hash(t2) + + t1 += timedelta(weeks=7) + t2 += timedelta(days=7*7) + assert t1 == t2 + assert hash(t1) == hash(t2) + + d = {t1: 1} + d[t2] = 2 + assert len(d) == 1 + assert d[t1] == 2 + + def test_pickling(self): + args = 12, 34, 56 + orig = timedelta(*args) + for pickler, unpickler, proto in pickle_choices: + green = pickler.dumps(orig, proto) + derived = unpickler.loads(green) + assert orig == derived + + def test_compare(self): + t1 = timedelta(2, 3, 4) + t2 = timedelta(2, 3, 4) + assert t1 == t2 + assert t1 <= t2 + assert t1 >= t2 + assert not t1 != t2 + assert not t1 < t2 + assert not t1 > t2 + assert cmp(t1, t2) == 0 + assert cmp(t2, t1) == 0 + + for args in (3, 3, 3), (2, 4, 4), (2, 3, 5): + t2 = timedelta(*args) # this is larger than t1 + assert t1 < t2 + assert t2 > t1 + assert t1 <= t2 + assert t2 >= t1 + assert t1 != t2 + assert t2 != t1 + assert not t1 == t2 + assert not t2 == t1 + assert not t1 > t2 + assert not t2 < t1 + assert not t1 >= t2 + assert not t2 <= t1 + assert cmp(t1, t2) == -1 + assert cmp(t2, t1) == 1 + + for badarg in OTHERSTUFF: + assert (t1 == badarg) == False + assert (t1 != badarg) == True + assert (badarg == t1) == False + assert (badarg != t1) == True + + raises(TypeError, lambda: t1 <= badarg) + raises(TypeError, lambda: t1 < badarg) + raises(TypeError, lambda: t1 > badarg) + raises(TypeError, lambda: t1 >= badarg) + raises(TypeError, lambda: badarg <= t1) + raises(TypeError, lambda: badarg < t1) + raises(TypeError, lambda: badarg > t1) + raises(TypeError, lambda: badarg >= t1) + + def test_str(self): + td = timedelta + + assert str(td(1)) == "1 day, 0:00:00" + assert str(td(-1)) == "-1 day, 0:00:00" + assert str(td(2)) == "2 days, 0:00:00" + assert str(td(-2)) == "-2 days, 0:00:00" + + assert str(td(hours=12, minutes=58, seconds=59)) == "12:58:59" + assert str(td(hours=2, minutes=3, seconds=4)) == "2:03:04" + assert str(td(weeks=-30, hours=23, minutes=12, seconds=34)) == ( + "-210 days, 23:12:34") + + assert str(td(milliseconds=1)) == "0:00:00.001000" + assert str(td(microseconds=3)) == "0:00:00.000003" + + assert str(td(days=999999999, hours=23, minutes=59, seconds=59, + microseconds=999999)) == ( + "999999999 days, 23:59:59.999999") + + def test_roundtrip(self): + for td in (timedelta(days=999999999, hours=23, minutes=59, + seconds=59, microseconds=999999), + timedelta(days=-999999999), + timedelta(days=1, seconds=2, microseconds=3)): + + # Verify td -> string -> td identity. + s = repr(td) + assert s.startswith('datetime.') + s = s[9:] + td2 = eval(s) + assert td == td2 + + # Verify identity via reconstructing from pieces. + td2 = timedelta(td.days, td.seconds, td.microseconds) + assert td == td2 + + def test_resolution_info(self): + assert isinstance(timedelta.min, timedelta) + assert isinstance(timedelta.max, timedelta) + assert isinstance(timedelta.resolution, timedelta) + assert timedelta.max > timedelta.min + assert timedelta.min == timedelta(-999999999) + assert timedelta.max == timedelta(999999999, 24*3600-1, 1e6-1) + assert timedelta.resolution == timedelta(0, 0, 1) + + def test_overflow(self): + tiny = timedelta.resolution + + td = timedelta.min + tiny + td -= tiny # no problem + raises(OverflowError, td.__sub__, tiny) + raises(OverflowError, td.__add__, -tiny) + + td = timedelta.max - tiny + td += tiny # no problem + raises(OverflowError, td.__add__, tiny) + raises(OverflowError, td.__sub__, -tiny) + + raises(OverflowError, lambda: -timedelta.max) + + def test_microsecond_rounding(self): + td = timedelta + + # Single-field rounding. + assert td(milliseconds=0.4/1000) == td(0) # rounds to 0 + assert td(milliseconds=-0.4/1000) == td(0) # rounds to 0 + assert td(milliseconds=0.6/1000) == td(microseconds=1) + assert td(milliseconds=-0.6/1000) == td(microseconds=-1) + + # Rounding due to contributions from more than one field. + us_per_hour = 3600e6 + us_per_day = us_per_hour * 24 + assert td(days=.4/us_per_day) == td(0) + assert td(hours=.2/us_per_hour) == td(0) + assert td(days=.4/us_per_day, hours=.2/us_per_hour) == td(microseconds=1) + + assert td(days=-.4/us_per_day) == td(0) + assert td(hours=-.2/us_per_hour) == td(0) + assert td(days=-.4/us_per_day, hours=-.2/us_per_hour) == td(microseconds=-1) + + def test_massive_normalization(self): + td = timedelta(microseconds=-1) + assert (td.days, td.seconds, td.microseconds) == ( + (-1, 24*3600-1, 999999)) + + def test_bool(self): + assert timedelta(1) + assert timedelta(0, 1) + assert timedelta(0, 0, 1) + assert timedelta(microseconds=1) + assert not timedelta(0) + +############################################################################# +# date tests + +class TestDateOnly(object): + # Tests here won't pass if also run on datetime objects, so don't + # subclass this to test datetimes too. + + def test_delta_non_days_ignored(self): + dt = date(2000, 1, 2) + delta = timedelta(days=1, hours=2, minutes=3, seconds=4, + microseconds=5) + days = timedelta(delta.days) + assert days == timedelta(1) + + dt2 = dt + delta + assert dt2 == dt + days + + dt2 = delta + dt + assert dt2 == dt + days + + dt2 = dt - delta + assert dt2 == dt - days + + delta = -delta + days = timedelta(delta.days) + assert days == timedelta(-2) + + dt2 = dt + delta + assert dt2 == dt + days + + dt2 = delta + dt + assert dt2 == dt + days + + dt2 = dt - delta + assert dt2 == dt - days + +class TestDate(HarmlessMixedComparison): + # Tests here should pass for both dates and datetimes, except for a + # few tests that TestDateTime overrides. + + theclass = date + + def test_basic_attributes(self): + dt = self.theclass(2002, 3, 1) + assert dt.year == 2002 + assert dt.month == 3 + assert dt.day == 1 + + def test_roundtrip(self): + for dt in (self.theclass(1, 2, 3), + self.theclass.today()): + # Verify dt -> string -> date identity. + s = repr(dt) + assert s.startswith('datetime.') + s = s[9:] + dt2 = eval(s) + assert dt == dt2 + + # Verify identity via reconstructing from pieces. + dt2 = self.theclass(dt.year, dt.month, dt.day) + assert dt == dt2 + + def test_ordinal_conversions(self): + # Check some fixed values. + for y, m, d, n in [(1, 1, 1, 1), # calendar origin + (1, 12, 31, 365), + (2, 1, 1, 366), + # first example from "Calendrical Calculations" + (1945, 11, 12, 710347)]: + d = self.theclass(y, m, d) + assert n == d.toordinal() + fromord = self.theclass.fromordinal(n) + assert d == fromord + if hasattr(fromord, "hour"): + # if we're checking something fancier than a date, verify + # the extra fields have been zeroed out + assert fromord.hour == 0 + assert fromord.minute == 0 + assert fromord.second == 0 + assert fromord.microsecond == 0 + + # Check first and last days of year spottily across the whole + # range of years supported. + for year in xrange(MINYEAR, MAXYEAR+1, 7): + # Verify (year, 1, 1) -> ordinal -> y, m, d is identity. + d = self.theclass(year, 1, 1) + n = d.toordinal() + d2 = self.theclass.fromordinal(n) + assert d == d2 + # Verify that moving back a day gets to the end of year-1. + if year > 1: + d = self.theclass.fromordinal(n-1) + d2 = self.theclass(year-1, 12, 31) + assert d == d2 + assert d2.toordinal() == n-1 + + # Test every day in a leap-year and a non-leap year. + dim = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] + for year, isleap in (2000, True), (2002, False): + n = self.theclass(year, 1, 1).toordinal() + for month, maxday in zip(range(1, 13), dim): + if month == 2 and isleap: + maxday += 1 + for day in range(1, maxday+1): + d = self.theclass(year, month, day) + assert d.toordinal() == n + assert d == self.theclass.fromordinal(n) + n += 1 + + def test_extreme_ordinals(self): + a = self.theclass.min + a = self.theclass(a.year, a.month, a.day) # get rid of time parts + aord = a.toordinal() + b = a.fromordinal(aord) + assert a == b + + raises(ValueError, lambda: a.fromordinal(aord - 1)) + + b = a + timedelta(days=1) + assert b.toordinal() == aord + 1 + assert b == self.theclass.fromordinal(aord + 1) + + a = self.theclass.max + a = self.theclass(a.year, a.month, a.day) # get rid of time parts + aord = a.toordinal() + b = a.fromordinal(aord) + assert a == b + + raises(ValueError, lambda: a.fromordinal(aord + 1)) + + b = a - timedelta(days=1) + assert b.toordinal() == aord - 1 + assert b == self.theclass.fromordinal(aord - 1) + + def test_bad_constructor_arguments(self): + # bad years + self.theclass(MINYEAR, 1, 1) # no exception + self.theclass(MAXYEAR, 1, 1) # no exception + raises(ValueError, self.theclass, MINYEAR-1, 1, 1) + raises(ValueError, self.theclass, MAXYEAR+1, 1, 1) + # bad months + self.theclass(2000, 1, 1) # no exception + self.theclass(2000, 12, 1) # no exception + raises(ValueError, self.theclass, 2000, 0, 1) + raises(ValueError, self.theclass, 2000, 13, 1) + # bad days + self.theclass(2000, 2, 29) # no exception + self.theclass(2004, 2, 29) # no exception + self.theclass(2400, 2, 29) # no exception + raises(ValueError, self.theclass, 2000, 2, 30) + raises(ValueError, self.theclass, 2001, 2, 29) + raises(ValueError, self.theclass, 2100, 2, 29) + raises(ValueError, self.theclass, 1900, 2, 29) + raises(ValueError, self.theclass, 2000, 1, 0) + raises(ValueError, self.theclass, 2000, 1, 32) + + def test_hash_equality(self): + d = self.theclass(2000, 12, 31) + # same thing + e = self.theclass(2000, 12, 31) + assert d == e + assert hash(d) == hash(e) + + dic = {d: 1} + dic[e] = 2 + assert len(dic) == 1 + assert dic[d] == 2 + assert dic[e] == 2 + + d = self.theclass(2001, 1, 1) + # same thing + e = self.theclass(2001, 1, 1) + assert d == e + assert hash(d) == hash(e) + + dic = {d: 1} + dic[e] = 2 + assert len(dic) == 1 + assert dic[d] == 2 + assert dic[e] == 2 + + def test_computations(self): + a = self.theclass(2002, 1, 31) + b = self.theclass(1956, 1, 31) + + diff = a-b + assert diff.days == 46*365 + len(range(1956, 2002, 4)) + assert diff.seconds == 0 + assert diff.microseconds == 0 + + day = timedelta(1) + week = timedelta(7) + a = self.theclass(2002, 3, 2) + assert a + day == self.theclass(2002, 3, 3) + assert day + a == self.theclass(2002, 3, 3) + assert a - day == self.theclass(2002, 3, 1) + assert -day + a == self.theclass(2002, 3, 1) + assert a + week == self.theclass(2002, 3, 9) + assert a - week == self.theclass(2002, 2, 23) + assert a + 52*week == self.theclass(2003, 3, 1) + assert a - 52*week == self.theclass(2001, 3, 3) + assert (a + week) - a == week + assert (a + day) - a == day + assert (a - week) - a == -week + assert (a - day) - a == -day + assert a - (a + week) == -week + assert a - (a + day) == -day + assert a - (a - week) == week + assert a - (a - day) == day + + # Add/sub ints, longs, floats should be illegal + for i in 1, 1L, 1.0: + raises(TypeError, lambda: a+i) + raises(TypeError, lambda: a-i) + raises(TypeError, lambda: i+a) + raises(TypeError, lambda: i-a) + + # delta - date is senseless. + raises(TypeError, lambda: day - a) + # mixing date and (delta or date) via * or // is senseless + raises(TypeError, lambda: day * a) + raises(TypeError, lambda: a * day) + raises(TypeError, lambda: day // a) + raises(TypeError, lambda: a // day) + raises(TypeError, lambda: a * a) + raises(TypeError, lambda: a // a) + # date + date is senseless + raises(TypeError, lambda: a + a) + + def test_overflow(self): + tiny = self.theclass.resolution + + dt = self.theclass.min + tiny + dt -= tiny # no problem + raises(OverflowError, dt.__sub__, tiny) + raises(OverflowError, dt.__add__, -tiny) + + dt = self.theclass.max - tiny + dt += tiny # no problem + raises(OverflowError, dt.__add__, tiny) + raises(OverflowError, dt.__sub__, -tiny) + + def test_fromtimestamp(self): + import time + + # Try an arbitrary fixed value. + year, month, day = 1999, 9, 19 + ts = time.mktime((year, month, day, 0, 0, 0, 0, 0, -1)) + d = self.theclass.fromtimestamp(ts) + assert d.year == year + assert d.month == month + assert d.day == day + + def test_today(self): + import time + + # We claim that today() is like fromtimestamp(time.time()), so + # prove it. + for dummy in range(3): + today = self.theclass.today() + ts = time.time() + todayagain = self.theclass.fromtimestamp(ts) + if today == todayagain: + break + # There are several legit reasons that could fail: + # 1. It recently became midnight, between the today() and the + # time() calls. + # 2. The platform time() has such fine resolution that we'll + # never get the same value twice. + # 3. The platform time() has poor resolution, and we just + # happened to call today() right before a resolution quantum + # boundary. + # 4. The system clock got fiddled between calls. + # In any case, wait a little while and try again. + time.sleep(0.1) + + # It worked or it didn't. If it didn't, assume it's reason #2, and + # let the test pass if they're within half a second of each other. + assert (today == todayagain or + abs(todayagain - today) < timedelta(seconds=0.5)) + + def test_weekday(self): + for i in range(7): + # March 4, 2002 is a Monday + assert self.theclass(2002, 3, 4+i).weekday() == i + assert self.theclass(2002, 3, 4+i).isoweekday() == i+1 + # January 2, 1956 is a Monday + assert self.theclass(1956, 1, 2+i).weekday() == i + assert self.theclass(1956, 1, 2+i).isoweekday() == i+1 + + def test_isocalendar(self): + # Check examples from + # http://www.phys.uu.nl/~vgent/calendar/isocalendar.htm + for i in range(7): + d = self.theclass(2003, 12, 22+i) + assert d.isocalendar() == (2003, 52, i+1) + d = self.theclass(2003, 12, 29) + timedelta(i) + assert d.isocalendar() == (2004, 1, i+1) + d = self.theclass(2004, 1, 5+i) + assert d.isocalendar() == (2004, 2, i+1) + d = self.theclass(2009, 12, 21+i) + assert d.isocalendar() == (2009, 52, i+1) + d = self.theclass(2009, 12, 28) + timedelta(i) + assert d.isocalendar() == (2009, 53, i+1) + d = self.theclass(2010, 1, 4+i) + assert d.isocalendar() == (2010, 1, i+1) + + def test_iso_long_years(self): + # Calculate long ISO years and compare to table from + # http://www.phys.uu.nl/~vgent/calendar/isocalendar.htm + ISO_LONG_YEARS_TABLE = """ + 4 32 60 88 + 9 37 65 93 + 15 43 71 99 + 20 48 76 + 26 54 82 + + 105 133 161 189 + 111 139 167 195 + 116 144 172 + 122 150 178 + 128 156 184 + + 201 229 257 285 + 207 235 263 291 + 212 240 268 296 + 218 246 274 + 224 252 280 + + 303 331 359 387 + 308 336 364 392 + 314 342 370 398 + 320 348 376 + 325 353 381 + """ + iso_long_years = map(int, ISO_LONG_YEARS_TABLE.split()) + iso_long_years.sort() + L = [] + for i in range(400): + d = self.theclass(2000+i, 12, 31) + d1 = self.theclass(1600+i, 12, 31) + assert d.isocalendar()[1:] == d1.isocalendar()[1:] + if d.isocalendar()[1] == 53: + L.append(i) + assert L == iso_long_years + + def test_isoformat(self): + t = self.theclass(2, 3, 2) + assert t.isoformat() == "0002-03-02" + + def test_ctime(self): + t = self.theclass(2002, 3, 2) + assert t.ctime() == "Sat Mar 2 00:00:00 2002" + + def test_strftime(self): + t = self.theclass(2005, 3, 2) + assert t.strftime("m:%m d:%d y:%y") == "m:03 d:02 y:05" + + raises(TypeError, t.strftime) # needs an arg + raises(TypeError, t.strftime, "one", "two") # too many args + raises(TypeError, t.strftime, 42) # arg wrong type + + # A naive object replaces %z and %Z w/ empty strings. + assert t.strftime("'%z' '%Z'") == "'' ''" + + def test_resolution_info(self): + assert isinstance(self.theclass.min, self.theclass) + assert isinstance(self.theclass.max, self.theclass) + assert isinstance(self.theclass.resolution, timedelta) + assert self.theclass.max > self.theclass.min + + def test_extreme_timedelta(self): + big = self.theclass.max - self.theclass.min + # 3652058 days, 23 hours, 59 minutes, 59 seconds, 999999 microseconds + n = (big.days*24*3600 + big.seconds)*1000000 + big.microseconds + # n == 315537897599999999 ~= 2**58.13 + justasbig = timedelta(0, 0, n) + assert big == justasbig + assert self.theclass.min + big == self.theclass.max + assert self.theclass.max - big == self.theclass.min + + def test_timetuple(self): + for i in range(7): + # January 2, 1956 is a Monday (0) + d = self.theclass(1956, 1, 2+i) + t = d.timetuple() + assert t == (1956, 1, 2+i, 0, 0, 0, i, 2+i, -1) + # February 1, 1956 is a Wednesday (2) + d = self.theclass(1956, 2, 1+i) + t = d.timetuple() + assert t == (1956, 2, 1+i, 0, 0, 0, (2+i)%7, 32+i, -1) + # March 1, 1956 is a Thursday (3), and is the 31+29+1 = 61st day + # of the year. + d = self.theclass(1956, 3, 1+i) + t = d.timetuple() + assert t == (1956, 3, 1+i, 0, 0, 0, (3+i)%7, 61+i, -1) + assert t.tm_year == 1956 + assert t.tm_mon == 3 + assert t.tm_mday == 1+i + assert t.tm_hour == 0 + assert t.tm_min == 0 + assert t.tm_sec == 0 + assert t.tm_wday == (3+i)%7 + assert t.tm_yday == 61+i + assert t.tm_isdst == -1 + + def test_pickling(self): + args = 6, 7, 23 + orig = self.theclass(*args) + for pickler, unpickler, proto in pickle_choices: + green = pickler.dumps(orig, proto) + derived = unpickler.loads(green) + assert orig == derived + + def test_compare(self): + t1 = self.theclass(2, 3, 4) + t2 = self.theclass(2, 3, 4) + assert t1 == t2 + assert t1 <= t2 + assert t1 >= t2 + assert not t1 != t2 + assert not t1 < t2 + assert not t1 > t2 + assert cmp(t1, t2) == 0 + assert cmp(t2, t1) == 0 + + for args in (3, 3, 3), (2, 4, 4), (2, 3, 5): + t2 = self.theclass(*args) # this is larger than t1 + assert t1 < t2 + assert t2 > t1 + assert t1 <= t2 + assert t2 >= t1 + assert t1 != t2 + assert t2 != t1 + assert not t1 == t2 + assert not t2 == t1 + assert not t1 > t2 + assert not t2 < t1 + assert not t1 >= t2 + assert not t2 <= t1 + assert cmp(t1, t2) == -1 + assert cmp(t2, t1) == 1 + + for badarg in OTHERSTUFF: + assert (t1 == badarg) == False + assert (t1 != badarg) == True + assert (badarg == t1) == False + assert (badarg != t1) == True + + raises(TypeError, lambda: t1 < badarg) + raises(TypeError, lambda: t1 > badarg) + raises(TypeError, lambda: t1 >= badarg) + raises(TypeError, lambda: badarg <= t1) + raises(TypeError, lambda: badarg < t1) + raises(TypeError, lambda: badarg > t1) + raises(TypeError, lambda: badarg >= t1) + + def test_mixed_compare(self): + our = self.theclass(2000, 4, 5) + raises(TypeError, cmp, our, 1) + raises(TypeError, cmp, 1, our) + + class AnotherDateTimeClass(object): + def __cmp__(self, other): + # Return "equal" so calling this can't be confused with + # compare-by-address (which never says "equal" for distinct + # objects). + return 0 + + # This still errors, because date and datetime comparison raise + # TypeError instead of NotImplemented when they don't know what to + # do, in order to stop comparison from falling back to the default + # compare-by-address. + their = AnotherDateTimeClass() + raises(TypeError, cmp, our, their) + # Oops: The next stab raises TypeError in the C implementation, + # but not in the Python implementation of datetime. The difference + # is due to that the Python implementation defines __cmp__ but + # the C implementation defines tp_richcompare. This is more pain + # to fix than it's worth, so commenting out the test. + # self.assertEqual(cmp(their, our), 0) + + # But date and datetime comparison return NotImplemented instead if the + # other object has a timetuple attr. This gives the other object a + # chance to do the comparison. + class Comparable(AnotherDateTimeClass): + def timetuple(self): + return () + + their = Comparable() + assert cmp(our, their) == 0 + assert cmp(their, our) == 0 + assert our == their + assert their == our + + def test_bool(self): + # All dates are considered true. + assert self.theclass.min + assert self.theclass.max + + def test_srftime_out_of_range(self): + # For nasty technical reasons, we can't handle years before 1900. + cls = self.theclass + assert cls(1900, 1, 1).strftime("%Y") == "1900" + for y in 1, 49, 51, 99, 100, 1000, 1899: + raises(ValueError, cls(y, 1, 1).strftime, "%Y") + + def test_replace(self): + cls = self.theclass + args = [1, 2, 3] + base = cls(*args) + assert base == base.replace() + + i = 0 + for name, newval in (("year", 2), + ("month", 3), + ("day", 4)): + newargs = args[:] + newargs[i] = newval + expected = cls(*newargs) + got = base.replace(**{name: newval}) + assert expected == got + i += 1 + + # Out of bounds. + base = cls(2000, 2, 29) + raises(ValueError, base.replace, year=2001) + +############################################################################# +# datetime tests + +class TestDateTime(TestDate): + + theclass = datetime + + def test_basic_attributes(self): + dt = self.theclass(2002, 3, 1, 12, 0) + assert dt.year == 2002 + assert dt.month == 3 + assert dt.day == 1 + assert dt.hour == 12 + assert dt.minute == 0 + assert dt.second == 0 + assert dt.microsecond == 0 + + def test_basic_attributes_nonzero(self): + # Make sure all attributes are non-zero so bugs in + # bit-shifting access show up. + dt = self.theclass(2002, 3, 1, 12, 59, 59, 8000) + assert dt.year == 2002 + assert dt.month == 3 + assert dt.day == 1 + assert dt.hour == 12 + assert dt.minute == 59 + assert dt.second == 59 + assert dt.microsecond == 8000 + + def test_roundtrip(self): + for dt in (self.theclass(1, 2, 3, 4, 5, 6, 7), + self.theclass.now()): + # Verify dt -> string -> datetime identity. + s = repr(dt) + assert s.startswith('datetime.') + s = s[9:] + dt2 = eval(s) + assert dt == dt2 + + # Verify identity via reconstructing from pieces. + dt2 = self.theclass(dt.year, dt.month, dt.day, + dt.hour, dt.minute, dt.second, + dt.microsecond) + assert dt == dt2 + + def test_isoformat(self): + t = self.theclass(2, 3, 2, 4, 5, 1, 123) + assert t.isoformat() == "0002-03-02T04:05:01.000123" + assert t.isoformat('T') == "0002-03-02T04:05:01.000123" + assert t.isoformat(' ') == "0002-03-02 04:05:01.000123" + # str is ISO format with the separator forced to a blank. + assert str(t) == "0002-03-02 04:05:01.000123" + + t = self.theclass(2, 3, 2) + assert t.isoformat() == "0002-03-02T00:00:00" + assert t.isoformat('T') == "0002-03-02T00:00:00" + assert t.isoformat(' ') == "0002-03-02 00:00:00" + # str is ISO format with the separator forced to a blank. + assert str(t) == "0002-03-02 00:00:00" + + def test_more_ctime(self): + # Test fields that TestDate doesn't touch. + import time + + t = self.theclass(2002, 3, 2, 18, 3, 5, 123) + assert t.ctime() == "Sat Mar 2 18:03:05 2002" + # Oops! The next line fails on Win2K under MSVC 6, so it's commented + # out. The difference is that t.ctime() produces " 2" for the day, + # but platform ctime() produces "02" for the day. According to + # C99, t.ctime() is correct here. + # self.assertEqual(t.ctime(), time.ctime(time.mktime(t.timetuple()))) + + # So test a case where that difference doesn't matter. + t = self.theclass(2002, 3, 22, 18, 3, 5, 123) + assert t.ctime() == time.ctime(time.mktime(t.timetuple())) + + def test_tz_independent_comparing(self): + dt1 = self.theclass(2002, 3, 1, 9, 0, 0) + dt2 = self.theclass(2002, 3, 1, 10, 0, 0) + dt3 = self.theclass(2002, 3, 1, 9, 0, 0) + assert dt1 == dt3 + assert dt2 > dt3 + + # Make sure comparison doesn't forget microseconds, and isn't done + # via comparing a float timestamp (an IEEE double doesn't have enough + # precision to span microsecond resolution across years 1 thru 9999, + # so comparing via timestamp necessarily calls some distinct values + # equal). + dt1 = self.theclass(MAXYEAR, 12, 31, 23, 59, 59, 999998) + us = timedelta(microseconds=1) + dt2 = dt1 + us + assert dt2 - dt1 == us + assert dt1 < dt2 + + def test_bad_constructor_arguments(self): + # bad years + self.theclass(MINYEAR, 1, 1) # no exception + self.theclass(MAXYEAR, 1, 1) # no exception + raises(ValueError, self.theclass, MINYEAR-1, 1, 1) + raises(ValueError, self.theclass, MAXYEAR+1, 1, 1) + # bad months + self.theclass(2000, 1, 1) # no exception + self.theclass(2000, 12, 1) # no exception + raises(ValueError, self.theclass, 2000, 0, 1) + raises(ValueError, self.theclass, 2000, 13, 1) + # bad days + self.theclass(2000, 2, 29) # no exception + self.theclass(2004, 2, 29) # no exception + self.theclass(2400, 2, 29) # no exception + raises(ValueError, self.theclass, 2000, 2, 30) + raises(ValueError, self.theclass, 2001, 2, 29) + raises(ValueError, self.theclass, 2100, 2, 29) + raises(ValueError, self.theclass, 1900, 2, 29) + raises(ValueError, self.theclass, 2000, 1, 0) + raises(ValueError, self.theclass, 2000, 1, 32) + # bad hours + self.theclass(2000, 1, 31, 0) # no exception + self.theclass(2000, 1, 31, 23) # no exception + raises(ValueError, self.theclass, 2000, 1, 31, -1) + raises(ValueError, self.theclass, 2000, 1, 31, 24) + # bad minutes + self.theclass(2000, 1, 31, 23, 0) # no exception + self.theclass(2000, 1, 31, 23, 59) # no exception + raises(ValueError, self.theclass, 2000, 1, 31, 23, -1) + raises(ValueError, self.theclass, 2000, 1, 31, 23, 60) + # bad seconds + self.theclass(2000, 1, 31, 23, 59, 0) # no exception + self.theclass(2000, 1, 31, 23, 59, 59) # no exception + raises(ValueError, self.theclass, 2000, 1, 31, 23, 59, -1) + raises(ValueError, self.theclass, 2000, 1, 31, 23, 59, 60) + # bad microseconds + self.theclass(2000, 1, 31, 23, 59, 59, 0) # no exception + self.theclass(2000, 1, 31, 23, 59, 59, 999999) # no exception + raises(ValueError, self.theclass, + 2000, 1, 31, 23, 59, 59, -1) + raises(ValueError, self.theclass, + 2000, 1, 31, 23, 59, 59, + 1000000) + + def test_hash_equality(self): + d = self.theclass(2000, 12, 31, 23, 30, 17) + e = self.theclass(2000, 12, 31, 23, 30, 17) + assert d == e + assert hash(d) == hash(e) + + dic = {d: 1} + dic[e] = 2 + assert len(dic) == 1 + assert dic[d] == 2 + assert dic[e] == 2 + + d = self.theclass(2001, 1, 1, 0, 5, 17) + e = self.theclass(2001, 1, 1, 0, 5, 17) + assert d == e + assert hash(d) == hash(e) + + dic = {d: 1} + dic[e] = 2 + assert len(dic) == 1 + assert dic[d] == 2 + assert dic[e] == 2 + + def test_computations(self): + a = self.theclass(2002, 1, 31) + b = self.theclass(1956, 1, 31) + diff = a-b + assert diff.days == 46*365 + len(range(1956, 2002, 4)) + assert diff.seconds == 0 + assert diff.microseconds == 0 + a = self.theclass(2002, 3, 2, 17, 6) + millisec = timedelta(0, 0, 1000) + hour = timedelta(0, 3600) + day = timedelta(1) + week = timedelta(7) + assert a + hour == self.theclass(2002, 3, 2, 18, 6) + assert hour + a == self.theclass(2002, 3, 2, 18, 6) + assert a + 10*hour == self.theclass(2002, 3, 3, 3, 6) + assert a - hour == self.theclass(2002, 3, 2, 16, 6) + assert -hour + a == self.theclass(2002, 3, 2, 16, 6) + assert a - hour == a + -hour + assert a - 20*hour == self.theclass(2002, 3, 1, 21, 6) + assert a + day == self.theclass(2002, 3, 3, 17, 6) + assert a - day == self.theclass(2002, 3, 1, 17, 6) + assert a + week == self.theclass(2002, 3, 9, 17, 6) + assert a - week == self.theclass(2002, 2, 23, 17, 6) + assert a + 52*week == self.theclass(2003, 3, 1, 17, 6) + assert a - 52*week == self.theclass(2001, 3, 3, 17, 6) + assert (a + week) - a == week + assert (a + day) - a == day + assert (a + hour) - a == hour + assert (a + millisec) - a == millisec + assert (a - week) - a == -week + assert (a - day) - a == -day + assert (a - hour) - a == -hour + assert (a - millisec) - a == -millisec + assert a - (a + week) == -week + assert a - (a + day) == -day + assert a - (a + hour) == -hour + assert a - (a + millisec) == -millisec + assert a - (a - week) == week + assert a - (a - day) == day + assert a - (a - hour) == hour + assert a - (a - millisec) == millisec + assert a + (week + day + hour + millisec) == ( + self.theclass(2002, 3, 10, 18, 6, 0, 1000)) + assert a + (week + day + hour + millisec) == ( + (((a + week) + day) + hour) + millisec) + assert a - (week + day + hour + millisec) == ( + self.theclass(2002, 2, 22, 16, 5, 59, 999000)) + assert a - (week + day + hour + millisec) == ( + (((a - week) - day) - hour) - millisec) + # Add/sub ints, longs, floats should be illegal + for i in 1, 1L, 1.0: + raises(TypeError, lambda: a+i) + raises(TypeError, lambda: a-i) + raises(TypeError, lambda: i+a) + raises(TypeError, lambda: i-a) + + # delta - datetime is senseless. + raises(TypeError, lambda: day - a) + # mixing datetime and (delta or datetime) via * or // is senseless + raises(TypeError, lambda: day * a) + raises(TypeError, lambda: a * day) + raises(TypeError, lambda: day // a) + raises(TypeError, lambda: a // day) + raises(TypeError, lambda: a * a) + raises(TypeError, lambda: a // a) + # datetime + datetime is senseless + raises(TypeError, lambda: a + a) + + def test_pickling(self): + args = 6, 7, 23, 20, 59, 1, 64**2 + orig = self.theclass(*args) + for pickler, unpickler, proto in pickle_choices: + green = pickler.dumps(orig, proto) + derived = unpickler.loads(green) + assert orig == derived + + def test_more_pickling(self): + a = self.theclass(2003, 2, 7, 16, 48, 37, 444116) + s = pickle.dumps(a) + b = pickle.loads(s) + assert b.year == 2003 + assert b.month == 2 + assert b.day == 7 + + def test_more_compare(self): + # The test_compare() inherited from TestDate covers the error cases. + # We just want to test lexicographic ordering on the members datetime + # has that date lacks. + args = [2000, 11, 29, 20, 58, 16, 999998] + t1 = self.theclass(*args) + t2 = self.theclass(*args) + assert t1 == t2 + assert t1 <= t2 + assert t1 >= t2 + assert not t1 != t2 + assert not t1 < t2 + assert not t1 > t2 + assert cmp(t1, t2) == 0 + assert cmp(t2, t1) == 0 + + for i in range(len(args)): + newargs = args[:] + newargs[i] = args[i] + 1 + t2 = self.theclass(*newargs) # this is larger than t1 + assert t1 < t2 + assert t2 > t1 + assert t1 <= t2 + assert t2 >= t1 + assert t1 != t2 + assert t2 != t1 + assert not t1 == t2 + assert not t2 == t1 + assert not t1 > t2 + assert not t2 < t1 + assert not t1 >= t2 + assert not t2 <= t1 + assert cmp(t1, t2) == -1 + assert cmp(t2, t1) == 1 + + + # A helper for timestamp constructor tests. + def verify_field_equality(self, expected, got): + assert expected.tm_year == got.year + assert expected.tm_mon == got.month + assert expected.tm_mday == got.day + assert expected.tm_hour == got.hour + assert expected.tm_min == got.minute + assert expected.tm_sec == got.second + + def test_fromtimestamp(self): + import time + + ts = time.time() + expected = time.localtime(ts) + got = self.theclass.fromtimestamp(ts) + self.verify_field_equality(expected, got) + + def test_utcfromtimestamp(self): + import time + + ts = time.time() + expected = time.gmtime(ts) + got = self.theclass.utcfromtimestamp(ts) + self.verify_field_equality(expected, got) + + def test_utcnow(self): + import time + + # Call it a success if utcnow() and utcfromtimestamp() are within + # a second of each other. + tolerance = timedelta(seconds=1) + for dummy in range(3): + from_now = self.theclass.utcnow() + from_timestamp = self.theclass.utcfromtimestamp(time.time()) + if abs(from_timestamp - from_now) <= tolerance: + break + # Else try again a few times. + assert abs(from_timestamp - from_now) <= tolerance + + def test_more_timetuple(self): + # This tests fields beyond those tested by the TestDate.test_timetuple. + t = self.theclass(2004, 12, 31, 6, 22, 33) + assert t.timetuple() == (2004, 12, 31, 6, 22, 33, 4, 366, -1) + assert t.timetuple() == ( + (t.year, t.month, t.day, + t.hour, t.minute, t.second, + t.weekday(), + t.toordinal() - date(t.year, 1, 1).toordinal() + 1, + -1)) + tt = t.timetuple() + assert tt.tm_year == t.year + assert tt.tm_mon == t.month + assert tt.tm_mday == t.day + assert tt.tm_hour == t.hour + assert tt.tm_min == t.minute + assert tt.tm_sec == t.second + assert tt.tm_wday == t.weekday() + assert tt.tm_yday == ( t.toordinal() - + date(t.year, 1, 1).toordinal() + 1) + assert tt.tm_isdst == -1 + + def test_more_strftime(self): + # This tests fields beyond those tested by the TestDate.test_strftime. + t = self.theclass(2004, 12, 31, 6, 22, 33) + assert t.strftime("%m %d %y %S %M %H %j") == ( + "12 31 04 33 22 06 366") + + def test_extract(self): + dt = self.theclass(2002, 3, 4, 18, 45, 3, 1234) + assert dt.date() == date(2002, 3, 4) + assert dt.time() == time(18, 45, 3, 1234) + + def test_combine(self): + d = date(2002, 3, 4) + t = time(18, 45, 3, 1234) + expected = self.theclass(2002, 3, 4, 18, 45, 3, 1234) + combine = self.theclass.combine + dt = combine(d, t) + assert dt == expected + + dt = combine(time=t, date=d) + assert dt == expected + + assert d == dt.date() + assert t == dt.time() + assert dt == combine(dt.date(), dt.time()) + + raises(TypeError, combine) # need an arg + raises(TypeError, combine, d) # need two args + raises(TypeError, combine, t, d) # args reversed + raises(TypeError, combine, d, t, 1) # too many args + raises(TypeError, combine, "date", "time") # wrong types + + def test_replace(self): + cls = self.theclass + args = [1, 2, 3, 4, 5, 6, 7] + base = cls(*args) + assert base == base.replace() + + i = 0 + for name, newval in (("year", 2), + ("month", 3), + ("day", 4), + ("hour", 5), + ("minute", 6), + ("second", 7), + ("microsecond", 8)): + newargs = args[:] + newargs[i] = newval + expected = cls(*newargs) + got = base.replace(**{name: newval}) + assert expected == got + i += 1 + + # Out of bounds. + base = cls(2000, 2, 29) + raises(ValueError, base.replace, year=2001) + + def test_astimezone(self): + # Pretty boring! The TZ test is more interesting here. astimezone() + # simply can't be applied to a naive object. + dt = self.theclass.now() + f = FixedOffset(44, "") + raises(TypeError, dt.astimezone) # not enough args + raises(TypeError, dt.astimezone, f, f) # too many args + raises(TypeError, dt.astimezone, dt) # arg wrong type + raises(ValueError, dt.astimezone, f) # naive + raises(ValueError, dt.astimezone, tz=f) # naive + + class Bogus(tzinfo): + def utcoffset(self, dt): return None + def dst(self, dt): return timedelta(0) + bog = Bogus() + raises(ValueError, dt.astimezone, bog) # naive + + class AlsoBogus(tzinfo): + def utcoffset(self, dt): return timedelta(0) + def dst(self, dt): return None + alsobog = AlsoBogus() + raises(ValueError, dt.astimezone, alsobog) # also naive + +class TestTime(HarmlessMixedComparison): + + theclass = time + + def test_basic_attributes(self): + t = self.theclass(12, 0) + assert t.hour == 12 + assert t.minute == 0 + assert t.second == 0 + assert t.microsecond == 0 + + def test_basic_attributes_nonzero(self): + # Make sure all attributes are non-zero so bugs in + # bit-shifting access show up. + t = self.theclass(12, 59, 59, 8000) + assert t.hour == 12 + assert t.minute == 59 + assert t.second == 59 + assert t.microsecond == 8000 + + def test_roundtrip(self): + t = self.theclass(1, 2, 3, 4) + + # Verify t -> string -> time identity. + s = repr(t) + assert s.startswith('datetime.') + s = s[9:] + t2 = eval(s) + assert t == t2 + + # Verify identity via reconstructing from pieces. + t2 = self.theclass(t.hour, t.minute, t.second, + t.microsecond) + assert t == t2 + + def test_comparing(self): + args = [1, 2, 3, 4] + t1 = self.theclass(*args) + t2 = self.theclass(*args) + assert t1 == t2 + assert t1 <= t2 + assert t1 >= t2 + assert not t1 != t2 + assert not t1 < t2 + assert not t1 > t2 + assert cmp(t1, t2) == 0 + assert cmp(t2, t1) == 0 + + for i in range(len(args)): + newargs = args[:] + newargs[i] = args[i] + 1 + t2 = self.theclass(*newargs) # this is larger than t1 + assert t1 < t2 + assert t2 > t1 + assert t1 <= t2 + assert t2 >= t1 + assert t1 != t2 + assert t2 != t1 + assert not t1 == t2 + assert not t2 == t1 + assert not t1 > t2 + assert not t2 < t1 + assert not t1 >= t2 + assert not t2 <= t1 + assert cmp(t1, t2) == -1 + assert cmp(t2, t1) == 1 + + for badarg in OTHERSTUFF: + assert (t1 == badarg) == False + assert (t1 != badarg) == True + assert (badarg == t1) == False + assert (badarg != t1) == True + + raises(TypeError, lambda: t1 <= badarg) + raises(TypeError, lambda: t1 < badarg) + raises(TypeError, lambda: t1 > badarg) + raises(TypeError, lambda: t1 >= badarg) + raises(TypeError, lambda: badarg <= t1) + raises(TypeError, lambda: badarg < t1) + raises(TypeError, lambda: badarg > t1) + raises(TypeError, lambda: badarg >= t1) + + def test_bad_constructor_arguments(self): + # bad hours + self.theclass(0, 0) # no exception + self.theclass(23, 0) # no exception + raises(ValueError, self.theclass, -1, 0) + raises(ValueError, self.theclass, 24, 0) + # bad minutes + self.theclass(23, 0) # no exception + self.theclass(23, 59) # no exception + raises(ValueError, self.theclass, 23, -1) + raises(ValueError, self.theclass, 23, 60) + # bad seconds + self.theclass(23, 59, 0) # no exception + self.theclass(23, 59, 59) # no exception + raises(ValueError, self.theclass, 23, 59, -1) + raises(ValueError, self.theclass, 23, 59, 60) + # bad microseconds + self.theclass(23, 59, 59, 0) # no exception + self.theclass(23, 59, 59, 999999) # no exception + raises(ValueError, self.theclass, 23, 59, 59, -1) + raises(ValueError, self.theclass, 23, 59, 59, 1000000) + + def test_hash_equality(self): + d = self.theclass(23, 30, 17) + e = self.theclass(23, 30, 17) + assert d == e + assert hash(d) == hash(e) + + dic = {d: 1} + dic[e] = 2 + assert len(dic) == 1 + assert dic[d] == 2 + assert dic[e] == 2 + + d = self.theclass(0, 5, 17) + e = self.theclass(0, 5, 17) + assert d == e + assert hash(d) == hash(e) + + dic = {d: 1} + dic[e] = 2 + assert len(dic) == 1 + assert dic[d] == 2 + assert dic[e] == 2 + + def test_isoformat(self): + t = self.theclass(4, 5, 1, 123) + assert t.isoformat() == "04:05:01.000123" + assert t.isoformat() == str(t) + + t = self.theclass() + assert t.isoformat() == "00:00:00" + assert t.isoformat() == str(t) + + t = self.theclass(microsecond=1) + assert t.isoformat() == "00:00:00.000001" + assert t.isoformat() == str(t) + + t = self.theclass(microsecond=10) + assert t.isoformat() == "00:00:00.000010" + assert t.isoformat() == str(t) + + t = self.theclass(microsecond=100) + assert t.isoformat() == "00:00:00.000100" + assert t.isoformat() == str(t) + + t = self.theclass(microsecond=1000) + assert t.isoformat() == "00:00:00.001000" + assert t.isoformat() == str(t) + + t = self.theclass(microsecond=10000) + assert t.isoformat() == "00:00:00.010000" + assert t.isoformat() == str(t) + + t = self.theclass(microsecond=100000) + assert t.isoformat() == "00:00:00.100000" + assert t.isoformat() == str(t) + + def test_strftime(self): + t = self.theclass(1, 2, 3, 4) + assert t.strftime('%H %M %S') == "01 02 03" + # A naive object replaces %z and %Z with empty strings. + assert t.strftime("'%z' '%Z'") == "'' ''" + + def test_str(self): + assert str(self.theclass(1, 2, 3, 4)) == "01:02:03.000004" + assert str(self.theclass(10, 2, 3, 4000)) == "10:02:03.004000" + assert str(self.theclass(0, 2, 3, 400000)) == "00:02:03.400000" + assert str(self.theclass(12, 2, 3, 0)) == "12:02:03" + assert str(self.theclass(23, 15, 0, 0)) == "23:15:00" + + def test_repr(self): + name = 'datetime.' + self.theclass.__name__ + assert repr(self.theclass(1, 2, 3, 4)) == ( + "%s(1, 2, 3, 4)" % name) + assert repr(self.theclass(10, 2, 3, 4000)) == ( + "%s(10, 2, 3, 4000)" % name) + assert repr(self.theclass(0, 2, 3, 400000)) == ( + "%s(0, 2, 3, 400000)" % name) + assert repr(self.theclass(12, 2, 3, 0)) == ( + "%s(12, 2, 3)" % name) + assert repr(self.theclass(23, 15, 0, 0)) == ( + "%s(23, 15)" % name) + + def test_resolution_info(self): + assert isinstance(self.theclass.min, self.theclass) + assert isinstance(self.theclass.max, self.theclass) + assert isinstance(self.theclass.resolution, timedelta) + assert self.theclass.max > self.theclass.min + + def test_pickling(self): + args = 20, 59, 16, 64**2 + orig = self.theclass(*args) + for pickler, unpickler, proto in pickle_choices: + green = pickler.dumps(orig, proto) + derived = unpickler.loads(green) + assert orig == derived + + def test_bool(self): + cls = self.theclass + assert cls(1) + assert cls(0, 1) + assert cls(0, 0, 1) + assert cls(0, 0, 0, 1) + assert not cls(0) + assert not cls() + + def test_replace(self): + cls = self.theclass + args = [1, 2, 3, 4] + base = cls(*args) + assert base == base.replace() + + i = 0 + for name, newval in (("hour", 5), + ("minute", 6), + ("second", 7), + ("microsecond", 8)): + newargs = args[:] + newargs[i] = newval + expected = cls(*newargs) + got = base.replace(**{name: newval}) + assert expected == got + i += 1 + + # Out of bounds. + base = cls(1) + raises(ValueError, base.replace, hour=24) + raises(ValueError, base.replace, minute=-1) + raises(ValueError, base.replace, second=100) + raises(ValueError, base.replace, microsecond=1000000) + +# A mixin for classes with a tzinfo= argument. Subclasses must define +# theclass as a class atribute, and theclass(1, 1, 1, tzinfo=whatever) +# must be legit (which is true for time and datetime). +class TZInfoBase(object): + + def test_argument_passing(self): + cls = self.theclass + # A datetime passes itself on, a time passes None. + class introspective(tzinfo): + def tzname(self, dt): return dt and "real" or "none" + def utcoffset(self, dt): + return timedelta(minutes = dt and 42 or -42) + dst = utcoffset + + obj = cls(1, 2, 3, tzinfo=introspective()) + + expected = cls is time and "none" or "real" + assert obj.tzname() == expected + + expected = timedelta(minutes=(cls is time and -42 or 42)) + assert obj.utcoffset() == expected + assert obj.dst() == expected + + def test_bad_tzinfo_classes(self): + cls = self.theclass + raises(TypeError, cls, 1, 1, 1, tzinfo=12) + + class NiceTry(object): + def __init__(self): pass + def utcoffset(self, dt): pass + raises(TypeError, cls, 1, 1, 1, tzinfo=NiceTry) + + class BetterTry(tzinfo): + def __init__(self): pass + def utcoffset(self, dt): pass + b = BetterTry() + t = cls(1, 1, 1, tzinfo=b) + assert t.tzinfo is b + + def test_utc_offset_out_of_bounds(self): + class Edgy(tzinfo): + def __init__(self, offset): + self.offset = timedelta(minutes=offset) + def utcoffset(self, dt): + return self.offset + + cls = self.theclass + for offset, legit in ((-1440, False), + (-1439, True), + (1439, True), + (1440, False)): + if cls is time: + t = cls(1, 2, 3, tzinfo=Edgy(offset)) + elif cls is datetime: + t = cls(6, 6, 6, 1, 2, 3, tzinfo=Edgy(offset)) + else: + assert 0, "impossible" + if legit: + aofs = abs(offset) + h, m = divmod(aofs, 60) + tag = "%c%02d:%02d" % (offset < 0 and '-' or '+', h, m) + if isinstance(t, datetime): + t = t.timetz() + assert str(t) == "01:02:03" + tag + else: + raises(ValueError, str, t) + + def test_tzinfo_classes(self): + cls = self.theclass + class C1(tzinfo): + def utcoffset(self, dt): return None + def dst(self, dt): return None + def tzname(self, dt): return None + for t in (cls(1, 1, 1), + cls(1, 1, 1, tzinfo=None), + cls(1, 1, 1, tzinfo=C1())): + assert t.utcoffset() is None + assert t.dst() is None + assert t.tzname() is None + + class C3(tzinfo): + def utcoffset(self, dt): return timedelta(minutes=-1439) + def dst(self, dt): return timedelta(minutes=1439) + def tzname(self, dt): return "aname" + t = cls(1, 1, 1, tzinfo=C3()) + assert t.utcoffset() == timedelta(minutes=-1439) + assert t.dst() == timedelta(minutes=1439) + assert t.tzname() == "aname" + + # Wrong types. + class C4(tzinfo): + def utcoffset(self, dt): return "aname" + def dst(self, dt): return 7 + def tzname(self, dt): return 0 + t = cls(1, 1, 1, tzinfo=C4()) + raises(TypeError, t.utcoffset) + raises(TypeError, t.dst) + raises(TypeError, t.tzname) + + # Offset out of range. + class C6(tzinfo): + def utcoffset(self, dt): return timedelta(hours=-24) + def dst(self, dt): return timedelta(hours=24) + t = cls(1, 1, 1, tzinfo=C6()) + raises(ValueError, t.utcoffset) + raises(ValueError, t.dst) + + # Not a whole number of minutes. + class C7(tzinfo): + def utcoffset(self, dt): return timedelta(seconds=61) + def dst(self, dt): return timedelta(microseconds=-81) + t = cls(1, 1, 1, tzinfo=C7()) + raises(ValueError, t.utcoffset) + raises(ValueError, t.dst) + + def test_aware_compare(self): + cls = self.theclass + + # Ensure that utcoffset() gets ignored if the comparands have + # the same tzinfo member. + class OperandDependentOffset(tzinfo): + def utcoffset(self, t): + if t.minute < 10: + # d0 and d1 equal after adjustment + return timedelta(minutes=t.minute) + else: + # d2 off in the weeds + return timedelta(minutes=59) + + base = cls(8, 9, 10, tzinfo=OperandDependentOffset()) + d0 = base.replace(minute=3) + d1 = base.replace(minute=9) + d2 = base.replace(minute=11) + for x in d0, d1, d2: + for y in d0, d1, d2: + got = cmp(x, y) + expected = cmp(x.minute, y.minute) + assert got == expected + + # However, if they're different members, uctoffset is not ignored. + # Note that a time can't actually have an operand-depedent offset, + # though (and time.utcoffset() passes None to tzinfo.utcoffset()), + # so skip this test for time. + if cls is not time: + d0 = base.replace(minute=3, tzinfo=OperandDependentOffset()) + d1 = base.replace(minute=9, tzinfo=OperandDependentOffset()) + d2 = base.replace(minute=11, tzinfo=OperandDependentOffset()) + for x in d0, d1, d2: + for y in d0, d1, d2: + got = cmp(x, y) + if (x is d0 or x is d1) and (y is d0 or y is d1): + expected = 0 + elif x is y is d2: + expected = 0 + elif x is d2: + expected = -1 + else: + assert y is d2 + expected = 1 + assert got == expected + + +# Testing time objects with a non-None tzinfo. +class TestTimeTZ(TestTime, TZInfoBase): + theclass = time + + def test_empty(self): + t = self.theclass() + assert t.hour == 0 + assert t.minute == 0 + assert t.second == 0 + assert t.microsecond == 0 + assert t.tzinfo is None + + def test_zones(self): + est = FixedOffset(-300, "EST", 1) + utc = FixedOffset(0, "UTC", -2) + met = FixedOffset(60, "MET", 3) + t1 = time( 7, 47, tzinfo=est) + t2 = time(12, 47, tzinfo=utc) + t3 = time(13, 47, tzinfo=met) + t4 = time(microsecond=40) + t5 = time(microsecond=40, tzinfo=utc) + + assert t1.tzinfo == est + assert t2.tzinfo == utc + assert t3.tzinfo == met + assert t4.tzinfo is None + assert t5.tzinfo == utc + + assert t1.utcoffset() == timedelta(minutes=-300) + assert t2.utcoffset() == timedelta(minutes=0) + assert t3.utcoffset() == timedelta(minutes=60) + assert t4.utcoffset() is None + raises(TypeError, t1.utcoffset, "no args") + + assert t1.tzname() == "EST" + assert t2.tzname() == "UTC" + assert t3.tzname() == "MET" + assert t4.tzname() is None + raises(TypeError, t1.tzname, "no args") + + assert t1.dst() == timedelta(minutes=1) + assert t2.dst() == timedelta(minutes=-2) + assert t3.dst() == timedelta(minutes=3) + assert t4.dst() is None + raises(TypeError, t1.dst, "no args") + + assert hash(t1) == hash(t2) + assert hash(t1) == hash(t3) + assert hash(t2) == hash(t3) + + assert t1 == t2 + assert t1 == t3 + assert t2 == t3 + raises(TypeError, lambda: t4 == t5) # mixed tz-aware & naive + raises(TypeError, lambda: t4 < t5) # mixed tz-aware & naive + raises(TypeError, lambda: t5 < t4) # mixed tz-aware & naive + + assert str(t1) == "07:47:00-05:00" + assert str(t2) == "12:47:00+00:00" + assert str(t3) == "13:47:00+01:00" + assert str(t4) == "00:00:00.000040" + assert str(t5) == "00:00:00.000040+00:00" + + assert t1.isoformat() == "07:47:00-05:00" + assert t2.isoformat() == "12:47:00+00:00" + assert t3.isoformat() == "13:47:00+01:00" + assert t4.isoformat() == "00:00:00.000040" + assert t5.isoformat() == "00:00:00.000040+00:00" + + d = 'datetime.time' + assert repr(t1) == d + "(7, 47, tzinfo=est)" + assert repr(t2) == d + "(12, 47, tzinfo=utc)" + assert repr(t3) == d + "(13, 47, tzinfo=met)" + assert repr(t4) == d + "(0, 0, 0, 40)" + assert repr(t5) == d + "(0, 0, 0, 40, tzinfo=utc)" + + assert t1.strftime("%H:%M:%S %%Z=%Z %%z=%z") == ( + "07:47:00 %Z=EST %z=-0500") + assert t2.strftime("%H:%M:%S %Z %z") == "12:47:00 UTC +0000" + assert t3.strftime("%H:%M:%S %Z %z") == "13:47:00 MET +0100" + + yuck = FixedOffset(-1439, "%z %Z %%z%%Z") + t1 = time(23, 59, tzinfo=yuck) + assert t1.strftime("%H:%M %%Z='%Z' %%z='%z'") == ( + "23:59 %Z='%z %Z %%z%%Z' %z='-2359'") + + # Check that an invalid tzname result raises an exception. + class Badtzname(tzinfo): + def tzname(self, dt): return 42 + t = time(2, 3, 4, tzinfo=Badtzname()) + assert t.strftime("%H:%M:%S") == "02:03:04" + raises(TypeError, t.strftime, "%Z") + + def test_hash_edge_cases(self): + # Offsets that overflow a basic time. + t1 = self.theclass(0, 1, 2, 3, tzinfo=FixedOffset(1439, "")) + t2 = self.theclass(0, 0, 2, 3, tzinfo=FixedOffset(1438, "")) + assert hash(t1) == hash(t2) + + t1 = self.theclass(23, 58, 6, 100, tzinfo=FixedOffset(-1000, "")) + t2 = self.theclass(23, 48, 6, 100, tzinfo=FixedOffset(-1010, "")) + assert hash(t1) == hash(t2) + + def test_pickling(self): + # Try one without a tzinfo. + args = 20, 59, 16, 64**2 + orig = self.theclass(*args) + for pickler, unpickler, proto in pickle_choices: + green = pickler.dumps(orig, proto) + derived = unpickler.loads(green) + assert orig == derived + + # Try one with a tzinfo. + tinfo = PicklableFixedOffset(-300, 'cookie') + orig = self.theclass(5, 6, 7, tzinfo=tinfo) + for pickler, unpickler, proto in pickle_choices: + green = pickler.dumps(orig, proto) + derived = unpickler.loads(green) + assert orig == derived + assert isinstance(derived.tzinfo, PicklableFixedOffset) + assert derived.utcoffset() == timedelta(minutes=-300) + assert derived.tzname() == 'cookie' + + def test_more_bool(self): + # Test cases with non-None tzinfo. + cls = self.theclass + + t = cls(0, tzinfo=FixedOffset(-300, "")) + assert t + + t = cls(5, tzinfo=FixedOffset(-300, "")) + assert t + + t = cls(5, tzinfo=FixedOffset(300, "")) + assert not t + + t = cls(23, 59, tzinfo=FixedOffset(23*60 + 59, "")) + assert not t + + # Mostly ensuring this doesn't overflow internally. + t = cls(0, tzinfo=FixedOffset(23*60 + 59, "")) + assert t + + # But this should yield a value error -- the utcoffset is bogus. + t = cls(0, tzinfo=FixedOffset(24*60, "")) + raises(ValueError, lambda: bool(t)) + + # Likewise. + t = cls(0, tzinfo=FixedOffset(-24*60, "")) + raises(ValueError, lambda: bool(t)) + + def test_replace(self): + cls = self.theclass + z100 = FixedOffset(100, "+100") + zm200 = FixedOffset(timedelta(minutes=-200), "-200") + args = [1, 2, 3, 4, z100] + base = cls(*args) + assert base == base.replace() + + i = 0 + for name, newval in (("hour", 5), + ("minute", 6), + ("second", 7), + ("microsecond", 8), + ("tzinfo", zm200)): + newargs = args[:] + newargs[i] = newval + expected = cls(*newargs) + got = base.replace(**{name: newval}) + assert expected == got + i += 1 + + # Ensure we can get rid of a tzinfo. + assert base.tzname() == "+100" + base2 = base.replace(tzinfo=None) + assert base2.tzinfo is None + assert base2.tzname() is None + + # Ensure we can add one. + base3 = base2.replace(tzinfo=z100) + assert base == base3 + assert base.tzinfo is base3.tzinfo + + # Out of bounds. + base = cls(1) + raises(ValueError, base.replace, hour=24) + raises(ValueError, base.replace, minute=-1) + raises(ValueError, base.replace, second=100) + raises(ValueError, base.replace, microsecond=1000000) + + def test_mixed_compare(self): + t1 = time(1, 2, 3) + t2 = time(1, 2, 3) + assert t1 == t2 + t2 = t2.replace(tzinfo=None) + assert t1 == t2 + t2 = t2.replace(tzinfo=FixedOffset(None, "")) + assert t1 == t2 + t2 = t2.replace(tzinfo=FixedOffset(0, "")) + raises(TypeError, lambda: t1 == t2) + + # In time w/ identical tzinfo objects, utcoffset is ignored. + class Varies(tzinfo): + def __init__(self): + self.offset = timedelta(minutes=22) + def utcoffset(self, t): + self.offset += timedelta(minutes=1) + return self.offset + + v = Varies() + t1 = t2.replace(tzinfo=v) + t2 = t2.replace(tzinfo=v) + assert t1.utcoffset() == timedelta(minutes=23) + assert t2.utcoffset() == timedelta(minutes=24) + assert t1 == t2 + + # But if they're not identical, it isn't ignored. + t2 = t2.replace(tzinfo=Varies()) + assert t1 < t2 # t1's offset counter still going up + + +# Testing datetime objects with a non-None tzinfo. + +class TestDateTimeTZ(TestDateTime, TZInfoBase): + theclass = datetime + + def test_trivial(self): + dt = self.theclass(1, 2, 3, 4, 5, 6, 7) + assert dt.year == 1 + assert dt.month == 2 + assert dt.day == 3 + assert dt.hour == 4 + assert dt.minute == 5 + assert dt.second == 6 + assert dt.microsecond == 7 + assert dt.tzinfo == None + + def test_even_more_compare(self): + # The test_compare() and test_more_compare() inherited from TestDate + # and TestDateTime covered non-tzinfo cases. + + # Smallest possible after UTC adjustment. + t1 = self.theclass(1, 1, 1, tzinfo=FixedOffset(1439, "")) + # Largest possible after UTC adjustment. + t2 = self.theclass(MAXYEAR, 12, 31, 23, 59, 59, 999999, + tzinfo=FixedOffset(-1439, "")) + + # Make sure those compare correctly, and w/o overflow. + assert t1 < t2 + assert t1 != t2 + assert t2 > t1 + + assert t1 == t1 + assert t2 == t2 + + # Equal afer adjustment. + t1 = self.theclass(1, 12, 31, 23, 59, tzinfo=FixedOffset(1, "")) + t2 = self.theclass(2, 1, 1, 3, 13, tzinfo=FixedOffset(3*60+13+2, "")) + assert t1 == t2 + + # Change t1 not to subtract a minute, and t1 should be larger. + t1 = self.theclass(1, 12, 31, 23, 59, tzinfo=FixedOffset(0, "")) + assert t1 > t2 + + # Change t1 to subtract 2 minutes, and t1 should be smaller. + t1 = self.theclass(1, 12, 31, 23, 59, tzinfo=FixedOffset(2, "")) + assert t1 < t2 + + # Back to the original t1, but make seconds resolve it. + t1 = self.theclass(1, 12, 31, 23, 59, tzinfo=FixedOffset(1, ""), + second=1) + assert t1 > t2 + + # Likewise, but make microseconds resolve it. + t1 = self.theclass(1, 12, 31, 23, 59, tzinfo=FixedOffset(1, ""), + microsecond=1) + assert t1 > t2 + + # Make t2 naive and it should fail. + t2 = self.theclass.min + raises(TypeError, lambda: t1 == t2) + assert t2 == t2 + + # It's also naive if it has tzinfo but tzinfo.utcoffset() is None. + class Naive(tzinfo): + def utcoffset(self, dt): return None + t2 = self.theclass(5, 6, 7, tzinfo=Naive()) + raises(TypeError, lambda: t1 == t2) + assert t2 == t2 + + # OTOH, it's OK to compare two of these mixing the two ways of being + # naive. + t1 = self.theclass(5, 6, 7) + assert t1 == t2 + + # Try a bogus uctoffset. + class Bogus(tzinfo): + def utcoffset(self, dt): + return timedelta(minutes=1440) # out of bounds + t1 = self.theclass(2, 2, 2, tzinfo=Bogus()) + t2 = self.theclass(2, 2, 2, tzinfo=FixedOffset(0, "")) + raises(ValueError, lambda: t1 == t2) + + def test_pickling(self): + # Try one without a tzinfo. + args = 6, 7, 23, 20, 59, 1, 64**2 + orig = self.theclass(*args) + for pickler, unpickler, proto in pickle_choices: + green = pickler.dumps(orig, proto) + derived = unpickler.loads(green) + assert orig == derived + + # Try one with a tzinfo. + tinfo = PicklableFixedOffset(-300, 'cookie') + orig = self.theclass(*args, **{'tzinfo': tinfo}) + derived = self.theclass(1, 1, 1, tzinfo=FixedOffset(0, "", 0)) + for pickler, unpickler, proto in pickle_choices: + green = pickler.dumps(orig, proto) + derived = unpickler.loads(green) + assert orig == derived + assert isinstance(derived.tzinfo, + PicklableFixedOffset) + assert derived.utcoffset() == timedelta(minutes=-300) + assert derived.tzname() == 'cookie' + + def test_extreme_hashes(self): + # If an attempt is made to hash these via subtracting the offset + # then hashing a datetime object, OverflowError results. The + # Python implementation used to blow up here. + t = self.theclass(1, 1, 1, tzinfo=FixedOffset(1439, "")) + hash(t) + t = self.theclass(MAXYEAR, 12, 31, 23, 59, 59, 999999, + tzinfo=FixedOffset(-1439, "")) + hash(t) + + # OTOH, an OOB offset should blow up. + t = self.theclass(5, 5, 5, tzinfo=FixedOffset(-1440, "")) + raises(ValueError, hash, t) + + def test_zones(self): + est = FixedOffset(-300, "EST") + utc = FixedOffset(0, "UTC") + met = FixedOffset(60, "MET") + t1 = datetime(2002, 3, 19, 7, 47, tzinfo=est) + t2 = datetime(2002, 3, 19, 12, 47, tzinfo=utc) + t3 = datetime(2002, 3, 19, 13, 47, tzinfo=met) + assert t1.tzinfo == est + assert t2.tzinfo == utc + assert t3.tzinfo == met + assert t1.utcoffset() == timedelta(minutes=-300) + assert t2.utcoffset() == timedelta(minutes=0) + assert t3.utcoffset() == timedelta(minutes=60) + assert t1.tzname() == "EST" + assert t2.tzname() == "UTC" + assert t3.tzname() == "MET" + assert hash(t1) == hash(t2) + assert hash(t1) == hash(t3) + assert hash(t2) == hash(t3) + assert t1 == t2 + assert t1 == t3 + assert t2 == t3 + assert str(t1) == "2002-03-19 07:47:00-05:00" + assert str(t2) == "2002-03-19 12:47:00+00:00" + assert str(t3) == "2002-03-19 13:47:00+01:00" + d = 'datetime.datetime(2002, 3, 19, ' + assert repr(t1) == d + "7, 47, tzinfo=est)" + assert repr(t2) == d + "12, 47, tzinfo=utc)" + assert repr(t3) == d + "13, 47, tzinfo=met)" + + def test_combine(self): + met = FixedOffset(60, "MET") + d = date(2002, 3, 4) + tz = time(18, 45, 3, 1234, tzinfo=met) + dt = datetime.combine(d, tz) + assert dt == datetime(2002, 3, 4, 18, 45, 3, 1234, + tzinfo=met) + + def test_extract(self): + met = FixedOffset(60, "MET") + dt = self.theclass(2002, 3, 4, 18, 45, 3, 1234, tzinfo=met) + assert dt.date() == date(2002, 3, 4) + assert dt.time() == time(18, 45, 3, 1234) + assert dt.timetz() == time(18, 45, 3, 1234, tzinfo=met) + + def test_tz_aware_arithmetic(self): + import random + + now = self.theclass.now() + tz55 = FixedOffset(-330, "west 5:30") + timeaware = now.time().replace(tzinfo=tz55) + nowaware = self.theclass.combine(now.date(), timeaware) + assert nowaware.tzinfo is tz55 + assert nowaware.timetz() == timeaware + + # Can't mix aware and non-aware. + raises(TypeError, lambda: now - nowaware) + raises(TypeError, lambda: nowaware - now) + + # And adding datetime's doesn't make sense, aware or not. + raises(TypeError, lambda: now + nowaware) + raises(TypeError, lambda: nowaware + now) + raises(TypeError, lambda: nowaware + nowaware) + + # Subtracting should yield 0. + assert now - now == timedelta(0) + assert nowaware - nowaware == timedelta(0) + + # Adding a delta should preserve tzinfo. + delta = timedelta(weeks=1, minutes=12, microseconds=5678) + nowawareplus = nowaware + delta + assert nowaware.tzinfo is tz55 + nowawareplus2 = delta + nowaware + assert nowawareplus2.tzinfo is tz55 + assert nowawareplus == nowawareplus2 + + # that - delta should be what we started with, and that - what we + # started with should be delta. + diff = nowawareplus - delta + assert diff.tzinfo is tz55 + assert nowaware == diff + raises(TypeError, lambda: delta - nowawareplus) + assert nowawareplus - nowaware == delta + + # Make up a random timezone. + tzr = FixedOffset(random.randrange(-1439, 1440), "randomtimezone") + # Attach it to nowawareplus. + nowawareplus = nowawareplus.replace(tzinfo=tzr) + assert nowawareplus.tzinfo is tzr + # Make sure the difference takes the timezone adjustments into account. + got = nowaware - nowawareplus + # Expected: (nowaware base - nowaware offset) - + # (nowawareplus base - nowawareplus offset) = + # (nowaware base - nowawareplus base) + + # (nowawareplus offset - nowaware offset) = + # -delta + nowawareplus offset - nowaware offset + expected = nowawareplus.utcoffset() - nowaware.utcoffset() - delta + assert got == expected + + # Try max possible difference. + min = self.theclass(1, 1, 1, tzinfo=FixedOffset(1439, "min")) + max = self.theclass(MAXYEAR, 12, 31, 23, 59, 59, 999999, + tzinfo=FixedOffset(-1439, "max")) + maxdiff = max - min + assert maxdiff == ( self.theclass.max - self.theclass.min + + timedelta(minutes=2*1439)) + + def test_tzinfo_now(self): + meth = self.theclass.now + # Ensure it doesn't require tzinfo (i.e., that this doesn't blow up). + base = meth() + # Try with and without naming the keyword. + off42 = FixedOffset(42, "42") + another = meth(off42) + again = meth(tz=off42) + assert another.tzinfo is again.tzinfo + assert another.utcoffset() == timedelta(minutes=42) + # Bad argument with and w/o naming the keyword. + raises(TypeError, meth, 16) + raises(TypeError, meth, tzinfo=16) + # Bad keyword name. + raises(TypeError, meth, tinfo=off42) + # Too many args. + raises(TypeError, meth, off42, off42) + + # We don't know which time zone we're in, and don't have a tzinfo + # class to represent it, so seeing whether a tz argument actually + # does a conversion is tricky. + weirdtz = FixedOffset(timedelta(hours=15, minutes=58), "weirdtz", 0) + utc = FixedOffset(0, "utc", 0) + for dummy in range(3): + now = datetime.now(weirdtz) + assert now.tzinfo is weirdtz + utcnow = datetime.utcnow().replace(tzinfo=utc) + now2 = utcnow.astimezone(weirdtz) + if abs(now - now2) < timedelta(seconds=30): + break + # Else the code is broken, or more than 30 seconds passed between + # calls; assuming the latter, just try again. + else: + # Three strikes and we're out. + raise AssertionError, "utcnow(), now(tz), or astimezone() may be broken" + + def test_tzinfo_fromtimestamp(self): + import time + meth = self.theclass.fromtimestamp + ts = time.time() + # Ensure it doesn't require tzinfo (i.e., that this doesn't blow up). + base = meth(ts) + # Try with and without naming the keyword. + off42 = FixedOffset(42, "42") + another = meth(ts, off42) + again = meth(ts, tz=off42) + assert another.tzinfo is again.tzinfo + assert another.utcoffset() == timedelta(minutes=42) + # Bad argument with and w/o naming the keyword. + raises(TypeError, meth, ts, 16) + raises(TypeError, meth, ts, tzinfo=16) + # Bad keyword name. + raises(TypeError, meth, ts, tinfo=off42) + # Too many args. + raises(TypeError, meth, ts, off42, off42) + # Too few args. + raises(TypeError, meth) + + # Try to make sure tz= actually does some conversion. + timestamp = 1000000000 + utcdatetime = datetime.utcfromtimestamp(timestamp) + # In POSIX (epoch 1970), that's 2001-09-09 01:46:40 UTC, give or take. + # But on some flavor of Mac, it's nowhere near that. So we can't have + # any idea here what time that actually is, we can only test that + # relative changes match. + utcoffset = timedelta(hours=-15, minutes=39) # arbitrary, but not zero + tz = FixedOffset(utcoffset, "tz", 0) + expected = utcdatetime + utcoffset + got = datetime.fromtimestamp(timestamp, tz) + assert expected == got.replace(tzinfo=None) + + def test_tzinfo_utcnow(self): + meth = self.theclass.utcnow + # Ensure it doesn't require tzinfo (i.e., that this doesn't blow up). + base = meth() + # Try with and without naming the keyword; for whatever reason, + # utcnow() doesn't accept a tzinfo argument. + off42 = FixedOffset(42, "42") + raises(TypeError, meth, off42) + raises(TypeError, meth, tzinfo=off42) + + def test_tzinfo_utcfromtimestamp(self): + import time + meth = self.theclass.utcfromtimestamp + ts = time.time() + # Ensure it doesn't require tzinfo (i.e., that this doesn't blow up). + base = meth(ts) + # Try with and without naming the keyword; for whatever reason, + # utcfromtimestamp() doesn't accept a tzinfo argument. + off42 = FixedOffset(42, "42") + raises(TypeError, meth, ts, off42) + raises(TypeError, meth, ts, tzinfo=off42) + + def test_tzinfo_timetuple(self): + # TestDateTime tested most of this. datetime adds a twist to the + # DST flag. + class DST(tzinfo): + def __init__(self, dstvalue): + if isinstance(dstvalue, int): + dstvalue = timedelta(minutes=dstvalue) + self.dstvalue = dstvalue + def dst(self, dt): + return self.dstvalue + + cls = self.theclass + for dstvalue, flag in (-33, 1), (33, 1), (0, 0), (None, -1): + d = cls(1, 1, 1, 10, 20, 30, 40, tzinfo=DST(dstvalue)) + t = d.timetuple() + assert 1 == t.tm_year + assert 1 == t.tm_mon + assert 1 == t.tm_mday + assert 10 == t.tm_hour + assert 20 == t.tm_min + assert 30 == t.tm_sec + assert 0 == t.tm_wday + assert 1 == t.tm_yday + assert flag == t.tm_isdst + + # dst() returns wrong type. + raises(TypeError, cls(1, 1, 1, tzinfo=DST("x")).timetuple) + + # dst() at the edge. + assert cls(1,1,1, tzinfo=DST(1439)).timetuple().tm_isdst == 1 + assert cls(1,1,1, tzinfo=DST(-1439)).timetuple().tm_isdst == 1 + + # dst() out of range. + raises(ValueError, cls(1,1,1, tzinfo=DST(1440)).timetuple) + raises(ValueError, cls(1,1,1, tzinfo=DST(-1440)).timetuple) + + def test_utctimetuple(self): + class DST(tzinfo): + def __init__(self, dstvalue): + if isinstance(dstvalue, int): + dstvalue = timedelta(minutes=dstvalue) + self.dstvalue = dstvalue + def dst(self, dt): + return self.dstvalue + + cls = self.theclass + # This can't work: DST didn't implement utcoffset. + raises(NotImplementedError, + cls(1, 1, 1, tzinfo=DST(0)).utcoffset) + + class UOFS(DST): + def __init__(self, uofs, dofs=None): + DST.__init__(self, dofs) + self.uofs = timedelta(minutes=uofs) + def utcoffset(self, dt): + return self.uofs + + # Ensure tm_isdst is 0 regardless of what dst() says: DST is never + # in effect for a UTC time. + for dstvalue in -33, 33, 0, None: + d = cls(1, 2, 3, 10, 20, 30, 40, tzinfo=UOFS(-53, dstvalue)) + t = d.utctimetuple() + assert d.year == t.tm_year + assert d.month == t.tm_mon + assert d.day == t.tm_mday + assert 11 == t.tm_hour # 20mm + 53mm = 1hn + 13mm + assert 13 == t.tm_min + assert d.second == t.tm_sec + assert d.weekday() == t.tm_wday + assert d.toordinal() - date(1, 1, 1).toordinal() + 1 == ( + t.tm_yday) + assert 0 == t.tm_isdst + + # At the edges, UTC adjustment can normalize into years out-of-range + # for a datetime object. Ensure that a correct timetuple is + # created anyway. + tiny = cls(MINYEAR, 1, 1, 0, 0, 37, tzinfo=UOFS(1439)) + # That goes back 1 minute less than a full day. + t = tiny.utctimetuple() + assert t.tm_year == MINYEAR-1 + assert t.tm_mon == 12 + assert t.tm_mday == 31 + assert t.tm_hour == 0 + assert t.tm_min == 1 + assert t.tm_sec == 37 + assert t.tm_yday == 366 # "year 0" is a leap year + assert t.tm_isdst == 0 + + huge = cls(MAXYEAR, 12, 31, 23, 59, 37, 999999, tzinfo=UOFS(-1439)) + # That goes forward 1 minute less than a full day. + t = huge.utctimetuple() + assert t.tm_year == MAXYEAR+1 + assert t.tm_mon == 1 + assert t.tm_mday == 1 + assert t.tm_hour == 23 + assert t.tm_min == 58 + assert t.tm_sec == 37 + assert t.tm_yday == 1 + assert t.tm_isdst == 0 + + def test_tzinfo_isoformat(self): + zero = FixedOffset(0, "+00:00") + plus = FixedOffset(220, "+03:40") + minus = FixedOffset(-231, "-03:51") + unknown = FixedOffset(None, "") + + cls = self.theclass + datestr = '0001-02-03' + for ofs in None, zero, plus, minus, unknown: + for us in 0, 987001: + d = cls(1, 2, 3, 4, 5, 59, us, tzinfo=ofs) + timestr = '04:05:59' + (us and '.987001' or '') + ofsstr = ofs is not None and d.tzname() or '' + tailstr = timestr + ofsstr + iso = d.isoformat() + assert iso == datestr + 'T' + tailstr + assert iso == d.isoformat('T') + assert d.isoformat('k') == datestr + 'k' + tailstr + assert str(d) == datestr + ' ' + tailstr + + def test_replace(self): + cls = self.theclass + z100 = FixedOffset(100, "+100") + zm200 = FixedOffset(timedelta(minutes=-200), "-200") + args = [1, 2, 3, 4, 5, 6, 7, z100] + base = cls(*args) + assert base == base.replace() + + i = 0 + for name, newval in (("year", 2), + ("month", 3), + ("day", 4), + ("hour", 5), + ("minute", 6), + ("second", 7), + ("microsecond", 8), + ("tzinfo", zm200)): + newargs = args[:] + newargs[i] = newval + expected = cls(*newargs) + got = base.replace(**{name: newval}) + assert expected == got + i += 1 + + # Ensure we can get rid of a tzinfo. + assert base.tzname() == "+100" + base2 = base.replace(tzinfo=None) + assert base2.tzinfo is None + assert base2.tzname() is None + + # Ensure we can add one. + base3 = base2.replace(tzinfo=z100) + assert base == base3 + assert base.tzinfo is base3.tzinfo + + # Out of bounds. + base = cls(2000, 2, 29) + raises(ValueError, base.replace, year=2001) + + def test_more_astimezone(self): + # The inherited test_astimezone covered some trivial and error cases. + fnone = FixedOffset(None, "None") + f44m = FixedOffset(44, "44") + fm5h = FixedOffset(-timedelta(hours=5), "m300") + + dt = self.theclass.now(tz=f44m) + assert dt.tzinfo is f44m + # Replacing with degenerate tzinfo raises an exception. + raises(ValueError, dt.astimezone, fnone) + # Ditto with None tz. + raises(TypeError, dt.astimezone, None) + # Replacing with same tzinfo makes no change. + x = dt.astimezone(dt.tzinfo) + assert x.tzinfo is f44m + assert x.date() == dt.date() + assert x.time() == dt.time() + + # Replacing with different tzinfo does adjust. + got = dt.astimezone(fm5h) + assert got.tzinfo is fm5h + assert got.utcoffset() == timedelta(hours=-5) + expected = dt - dt.utcoffset() # in effect, convert to UTC + expected += fm5h.utcoffset(dt) # and from there to local time + expected = expected.replace(tzinfo=fm5h) # and attach new tzinfo + assert got.date() == expected.date() + assert got.time() == expected.time() + assert got.timetz() == expected.timetz() + assert got.tzinfo is expected.tzinfo + assert got == expected + + def test_aware_subtract(self): + cls = self.theclass + + # Ensure that utcoffset() is ignored when the operands have the + # same tzinfo member. + class OperandDependentOffset(tzinfo): + def utcoffset(self, t): + if t.minute < 10: + # d0 and d1 equal after adjustment + return timedelta(minutes=t.minute) + else: + # d2 off in the weeds + return timedelta(minutes=59) + + base = cls(8, 9, 10, 11, 12, 13, 14, tzinfo=OperandDependentOffset()) + d0 = base.replace(minute=3) + d1 = base.replace(minute=9) + d2 = base.replace(minute=11) + for x in d0, d1, d2: + for y in d0, d1, d2: + got = x - y + expected = timedelta(minutes=x.minute - y.minute) + assert got == expected + + # OTOH, if the tzinfo members are distinct, utcoffsets aren't + # ignored. + base = cls(8, 9, 10, 11, 12, 13, 14) + d0 = base.replace(minute=3, tzinfo=OperandDependentOffset()) + d1 = base.replace(minute=9, tzinfo=OperandDependentOffset()) + d2 = base.replace(minute=11, tzinfo=OperandDependentOffset()) + for x in d0, d1, d2: + for y in d0, d1, d2: + got = x - y + if (x is d0 or x is d1) and (y is d0 or y is d1): + expected = timedelta(0) + elif x is y is d2: + expected = timedelta(0) + elif x is d2: + expected = timedelta(minutes=(11-59)-0) + else: + assert y is d2 + expected = timedelta(minutes=0-(11-59)) + assert got == expected + + def test_mixed_compare(self): + t1 = datetime(1, 2, 3, 4, 5, 6, 7) + t2 = datetime(1, 2, 3, 4, 5, 6, 7) + assert t1 == t2 + t2 = t2.replace(tzinfo=None) + assert t1 == t2 + t2 = t2.replace(tzinfo=FixedOffset(None, "")) + assert t1 == t2 + t2 = t2.replace(tzinfo=FixedOffset(0, "")) + raises(TypeError, lambda: t1 == t2) + + # In datetime w/ identical tzinfo objects, utcoffset is ignored. + class Varies(tzinfo): + def __init__(self): + self.offset = timedelta(minutes=22) + def utcoffset(self, t): + self.offset += timedelta(minutes=1) + return self.offset + + v = Varies() + t1 = t2.replace(tzinfo=v) + t2 = t2.replace(tzinfo=v) + assert t1.utcoffset() == timedelta(minutes=23) + assert t2.utcoffset() == timedelta(minutes=24) + assert t1 == t2 + + # But if they're not identical, it isn't ignored. + t2 = t2.replace(tzinfo=Varies()) + assert t1 < t2 # t1's offset counter still going up + +# Pain to set up DST-aware tzinfo classes. + +def first_sunday_on_or_after(dt): + days_to_go = 6 - dt.weekday() + if days_to_go: + dt += timedelta(days_to_go) + return dt + +ZERO = timedelta(0) +HOUR = timedelta(hours=1) +DAY = timedelta(days=1) +# In the US, DST starts at 2am (standard time) on the first Sunday in April. +DSTSTART = datetime(1, 4, 1, 2) +# and ends at 2am (DST time; 1am standard time) on the last Sunday of Oct, +# which is the first Sunday on or after Oct 25. Because we view 1:MM as +# being standard time on that day, there is no spelling in local time of +# the last hour of DST (that's 1:MM DST, but 1:MM is taken as standard time). +DSTEND = datetime(1, 10, 25, 1) + +class USTimeZone(tzinfo): + + def __init__(self, hours, reprname, stdname, dstname): + self.stdoffset = timedelta(hours=hours) + self.reprname = reprname + self.stdname = stdname + self.dstname = dstname + + def __repr__(self): + return self.reprname + + def tzname(self, dt): + if self.dst(dt): + return self.dstname + else: + return self.stdname + + def utcoffset(self, dt): + return self.stdoffset + self.dst(dt) + + def dst(self, dt): + if dt is None or dt.tzinfo is None: + # An exception instead may be sensible here, in one or more of + # the cases. + return ZERO + assert dt.tzinfo is self + + # Find first Sunday in April. + start = first_sunday_on_or_after(DSTSTART.replace(year=dt.year)) + assert start.weekday() == 6 and start.month == 4 and start.day <= 7 + + # Find last Sunday in October. + end = first_sunday_on_or_after(DSTEND.replace(year=dt.year)) + assert end.weekday() == 6 and end.month == 10 and end.day >= 25 + + # Can't compare naive to aware objects, so strip the timezone from + # dt first. + if start <= dt.replace(tzinfo=None) < end: + return HOUR + else: + return ZERO + +Eastern = USTimeZone(-5, "Eastern", "EST", "EDT") +Central = USTimeZone(-6, "Central", "CST", "CDT") +Mountain = USTimeZone(-7, "Mountain", "MST", "MDT") +Pacific = USTimeZone(-8, "Pacific", "PST", "PDT") +utc_real = FixedOffset(0, "UTC", 0) +# For better test coverage, we want another flavor of UTC that's west of +# the Eastern and Pacific timezones. +utc_fake = FixedOffset(-12*60, "UTCfake", 0) + +class TestTimezoneConversions(object): + # The DST switch times for 2002, in std time. + dston = datetime(2002, 4, 7, 2) + dstoff = datetime(2002, 10, 27, 1) + + theclass = datetime + + # Check a time that's inside DST. + def checkinside(self, dt, tz, utc, dston, dstoff): + assert dt.dst() == HOUR + + # Conversion to our own timezone is always an identity. + assert dt.astimezone(tz) == dt + + asutc = dt.astimezone(utc) + there_and_back = asutc.astimezone(tz) + + # Conversion to UTC and back isn't always an identity here, + # because there are redundant spellings (in local time) of + # UTC time when DST begins: the clock jumps from 1:59:59 + # to 3:00:00, and a local time of 2:MM:SS doesn't really + # make sense then. The classes above treat 2:MM:SS as + # daylight time then (it's "after 2am"), really an alias + # for 1:MM:SS standard time. The latter form is what + # conversion back from UTC produces. + if dt.date() == dston.date() and dt.hour == 2: + # We're in the redundant hour, and coming back from + # UTC gives the 1:MM:SS standard-time spelling. + assert there_and_back + HOUR == dt + # Although during was considered to be in daylight + # time, there_and_back is not. + assert there_and_back.dst() == ZERO + # They're the same times in UTC. + assert there_and_back.astimezone(utc) == ( + dt.astimezone(utc)) + else: + # We're not in the redundant hour. + assert dt == there_and_back + + # Because we have a redundant spelling when DST begins, there is + # (unforunately) an hour when DST ends that can't be spelled at all in + # local time. When DST ends, the clock jumps from 1:59 back to 1:00 + # again. The hour 1:MM DST has no spelling then: 1:MM is taken to be + # standard time. 1:MM DST == 0:MM EST, but 0:MM is taken to be + # daylight time. The hour 1:MM daylight == 0:MM standard can't be + # expressed in local time. Nevertheless, we want conversion back + # from UTC to mimic the local clock's "repeat an hour" behavior. + nexthour_utc = asutc + HOUR + nexthour_tz = nexthour_utc.astimezone(tz) + if dt.date() == dstoff.date() and dt.hour == 0: + # We're in the hour before the last DST hour. The last DST hour + # is ineffable. We want the conversion back to repeat 1:MM. + assert nexthour_tz == dt.replace(hour=1) + nexthour_utc += HOUR + nexthour_tz = nexthour_utc.astimezone(tz) + assert nexthour_tz == dt.replace(hour=1) + else: + assert nexthour_tz - dt == HOUR + + # Check a time that's outside DST. + def checkoutside(self, dt, tz, utc): + assert dt.dst() == ZERO + + # Conversion to our own timezone is always an identity. + assert dt.astimezone(tz) == dt + + # Converting to UTC and back is an identity too. + asutc = dt.astimezone(utc) + there_and_back = asutc.astimezone(tz) + assert dt == there_and_back + + def convert_between_tz_and_utc(self, tz, utc): + dston = self.dston.replace(tzinfo=tz) + # Because 1:MM on the day DST ends is taken as being standard time, + # there is no spelling in tz for the last hour of daylight time. + # For purposes of the test, the last hour of DST is 0:MM, which is + # taken as being daylight time (and 1:MM is taken as being standard + # time). + dstoff = self.dstoff.replace(tzinfo=tz) + for delta in (timedelta(weeks=13), + DAY, + HOUR, + timedelta(minutes=1), + timedelta(microseconds=1)): + + self.checkinside(dston, tz, utc, dston, dstoff) + for during in dston + delta, dstoff - delta: + self.checkinside(during, tz, utc, dston, dstoff) + + self.checkoutside(dstoff, tz, utc) + for outside in dston - delta, dstoff + delta: + self.checkoutside(outside, tz, utc) + + def test_easy(self): + # Despite the name of this test, the endcases are excruciating. + self.convert_between_tz_and_utc(Eastern, utc_real) + self.convert_between_tz_and_utc(Pacific, utc_real) + self.convert_between_tz_and_utc(Eastern, utc_fake) + self.convert_between_tz_and_utc(Pacific, utc_fake) + # The next is really dancing near the edge. It works because + # Pacific and Eastern are far enough apart that their "problem + # hours" don't overlap. + self.convert_between_tz_and_utc(Eastern, Pacific) + self.convert_between_tz_and_utc(Pacific, Eastern) + # OTOH, these fail! Don't enable them. The difficulty is that + # the edge case tests assume that every hour is representable in + # the "utc" class. This is always true for a fixed-offset tzinfo + # class (lke utc_real and utc_fake), but not for Eastern or Central. + # For these adjacent DST-aware time zones, the range of time offsets + # tested ends up creating hours in the one that aren't representable + # in the other. For the same reason, we would see failures in the + # Eastern vs Pacific tests too if we added 3*HOUR to the list of + # offset deltas in convert_between_tz_and_utc(). + # + # self.convert_between_tz_and_utc(Eastern, Central) # can't work + # self.convert_between_tz_and_utc(Central, Eastern) # can't work + + def test_tricky(self): + # 22:00 on day before daylight starts. + fourback = self.dston - timedelta(hours=4) + ninewest = FixedOffset(-9*60, "-0900", 0) + fourback = fourback.replace(tzinfo=ninewest) + # 22:00-0900 is 7:00 UTC == 2:00 EST == 3:00 DST. Since it's "after + # 2", we should get the 3 spelling. + # If we plug 22:00 the day before into Eastern, it "looks like std + # time", so its offset is returned as -5, and -5 - -9 = 4. Adding 4 + # to 22:00 lands on 2:00, which makes no sense in local time (the + # local clock jumps from 1 to 3). The point here is to make sure we + # get the 3 spelling. + expected = self.dston.replace(hour=3) + got = fourback.astimezone(Eastern).replace(tzinfo=None) + assert expected == got + + # Similar, but map to 6:00 UTC == 1:00 EST == 2:00 DST. In that + # case we want the 1:00 spelling. + sixutc = self.dston.replace(hour=6, tzinfo=utc_real) + # Now 6:00 "looks like daylight", so the offset wrt Eastern is -4, + # and adding -4-0 == -4 gives the 2:00 spelling. We want the 1:00 EST + # spelling. + expected = self.dston.replace(hour=1) + got = sixutc.astimezone(Eastern).replace(tzinfo=None) + assert expected == got + + # Now on the day DST ends, we want "repeat an hour" behavior. + # UTC 4:MM 5:MM 6:MM 7:MM checking these + # EST 23:MM 0:MM 1:MM 2:MM + # EDT 0:MM 1:MM 2:MM 3:MM + # wall 0:MM 1:MM 1:MM 2:MM against these + for utc in utc_real, utc_fake: + for tz in Eastern, Pacific: + first_std_hour = self.dstoff - timedelta(hours=2) # 23:MM + # Convert that to UTC. + first_std_hour -= tz.utcoffset(None) + # Adjust for possibly fake UTC. + asutc = first_std_hour + utc.utcoffset(None) + # First UTC hour to convert; this is 4:00 when utc=utc_real & + # tz=Eastern. + asutcbase = asutc.replace(tzinfo=utc) + for tzhour in (0, 1, 1, 2): + expectedbase = self.dstoff.replace(hour=tzhour) + for minute in 0, 30, 59: + expected = expectedbase.replace(minute=minute) + asutc = asutcbase.replace(minute=minute) + astz = asutc.astimezone(tz) + assert astz.replace(tzinfo=None) == expected + asutcbase += HOUR + + + def test_bogus_dst(self): + class ok(tzinfo): + def utcoffset(self, dt): return HOUR + def dst(self, dt): return HOUR + + now = self.theclass.now().replace(tzinfo=utc_real) + # Doesn't blow up. + now.astimezone(ok()) + + # Does blow up. + class notok(ok): + def dst(self, dt): return None + raises(ValueError, now.astimezone, notok()) + + def test_fromutc(self): + raises(TypeError, Eastern.fromutc) # not enough args + now = datetime.utcnow().replace(tzinfo=utc_real) + raises(ValueError, Eastern.fromutc, now) # wrong tzinfo + now = now.replace(tzinfo=Eastern) # insert correct tzinfo + enow = Eastern.fromutc(now) # doesn't blow up + assert enow.tzinfo == Eastern # has right tzinfo member + raises(TypeError, Eastern.fromutc, now, now) # too many args + raises(TypeError, Eastern.fromutc, date.today()) # wrong type + + # Always converts UTC to standard time. + class FauxUSTimeZone(USTimeZone): + def fromutc(self, dt): + return dt + self.stdoffset + FEastern = FauxUSTimeZone(-5, "FEastern", "FEST", "FEDT") + + # UTC 4:MM 5:MM 6:MM 7:MM 8:MM 9:MM + # EST 23:MM 0:MM 1:MM 2:MM 3:MM 4:MM + # EDT 0:MM 1:MM 2:MM 3:MM 4:MM 5:MM + + # Check around DST start. + start = self.dston.replace(hour=4, tzinfo=Eastern) + fstart = start.replace(tzinfo=FEastern) + for wall in 23, 0, 1, 3, 4, 5: + expected = start.replace(hour=wall) + if wall == 23: + expected -= timedelta(days=1) + got = Eastern.fromutc(start) + assert expected == got + + expected = fstart + FEastern.stdoffset + got = FEastern.fromutc(fstart) + assert expected == got + + # Ensure astimezone() calls fromutc() too. + got = fstart.replace(tzinfo=utc_real).astimezone(FEastern) + assert expected == got + + start += HOUR + fstart += HOUR + + # Check around DST end. + start = self.dstoff.replace(hour=4, tzinfo=Eastern) + fstart = start.replace(tzinfo=FEastern) + for wall in 0, 1, 1, 2, 3, 4: + expected = start.replace(hour=wall) + got = Eastern.fromutc(start) + assert expected == got + + expected = fstart + FEastern.stdoffset + got = FEastern.fromutc(fstart) + assert expected == got + + # Ensure astimezone() calls fromutc() too. + got = fstart.replace(tzinfo=utc_real).astimezone(FEastern) + assert expected == got + + start += HOUR + fstart += HOUR + From ac at codespeak.net Sun Mar 20 18:13:18 2005 From: ac at codespeak.net (ac at codespeak.net) Date: Sun, 20 Mar 2005 18:13:18 +0100 (MET) Subject: [pypy-svn] r9937 - in pypy/dist: lib-python-2.3.4/test pypy/interpreter pypy/module/sys2 pypy/objspace Message-ID: <20050320171318.D328027B61@code1.codespeak.net> Author: ac Date: Sun Mar 20 18:13:18 2005 New Revision: 9937 Modified: pypy/dist/lib-python-2.3.4/test/test_scope.py pypy/dist/pypy/interpreter/eval.py pypy/dist/pypy/interpreter/executioncontext.py pypy/dist/pypy/interpreter/pyframe.py pypy/dist/pypy/interpreter/typedef.py pypy/dist/pypy/module/sys2/__init__.py pypy/dist/pypy/module/sys2/vm.py pypy/dist/pypy/objspace/trace.py Log: Preliminary work on sys.settrace() functionality. Stay tuned for more checkins. Modified: pypy/dist/lib-python-2.3.4/test/test_scope.py ============================================================================== --- pypy/dist/lib-python-2.3.4/test/test_scope.py (original) +++ pypy/dist/lib-python-2.3.4/test/test_scope.py Sun Mar 20 18:13:18 2005 @@ -437,6 +437,7 @@ d = f(2)(4) verify(d.has_key('h')) del d['h'] +print d verify(d == {'x': 2, 'y': 7, 'w': 6}) print "19. var is bound and free in class" Modified: pypy/dist/pypy/interpreter/eval.py ============================================================================== --- pypy/dist/pypy/interpreter/eval.py (original) +++ pypy/dist/pypy/interpreter/eval.py Sun Mar 20 18:13:18 2005 @@ -65,12 +65,7 @@ def resume(self): "Resume the execution of the frame from its current state." executioncontext = self.space.getexecutioncontext() - previous = executioncontext.enter(self) - try: - result = self.eval(executioncontext) - finally: - executioncontext.leave(previous) - return result + return self.eval(executioncontext) # running a frame is usually the same as resuming it from its # initial state, but not for generator frames Modified: pypy/dist/pypy/interpreter/executioncontext.py ============================================================================== --- pypy/dist/pypy/interpreter/executioncontext.py (original) +++ pypy/dist/pypy/interpreter/executioncontext.py Sun Mar 20 18:13:18 2005 @@ -10,7 +10,9 @@ self.space = space self.framestack = Stack() self.stateDict = {} - + self.w_tracefunc = None + self.is_tracing = 0 + def enter(self, frame): if self.framestack.depth() > self.space.sys.recursionlimit: raise OperationError(self.space.w_RuntimeError, @@ -18,10 +20,17 @@ locals = getthreadlocals() previous_ec = locals.executioncontext locals.executioncontext = self + if self.framestack.empty(): + frame.f_back = None + else: + frame.f_back = self.framestack.top() self.framestack.push(frame) + self.call_trace(frame, 'call', self.space.w_None) return previous_ec - def leave(self, previous_ec): + def leave(self, previous_ec, w_retval=None): + if w_retval is not None: + self.call_trace(self.framestack.top(), 'return', w_retval) self.framestack.pop() locals = getthreadlocals() locals.executioncontext = previous_ec @@ -46,6 +55,8 @@ def exception_trace(self, operationerr): "Trace function called upon OperationError." operationerr.record_interpreter_traceback() + self.call_trace(self.framestack.top(), 'exception', + self.sys_exc_info()) #operationerr.print_detailed_traceback(self.space) def sys_exc_info(self): @@ -62,3 +73,32 @@ Similar to cpython's PyThreadState_GetDict. """ return self.stateDict + + def settrace(self, w_func): + """Set the global trace function.""" + if self.space.is_(w_func, self.space.w_None): + self.w_tracefunc = None + else: + self.w_tracefunc = w_func + + def call_trace(self, frame, event, w_arg): + if event == 'call': + w_callback = self.w_tracefunc + else: + w_callback = frame.w_f_trace + if self.is_tracing or w_callback is None: + return + self.is_tracing += 1 + try: + try: + w_result = self.space.call(w_callback, self.space.wrap(frame), self.space.wrap(event), w_arg) + if self.space.is_(w_result, self.space.w_None): + frame.w_f_trace = None + else: + frame.w_f_trace = w_result + except: + self.settrace(self.space.w_None) + frame.w_f_trace = None + finally: + self.is_traceing -= 1 + Modified: pypy/dist/pypy/interpreter/pyframe.py ============================================================================== --- pypy/dist/pypy/interpreter/pyframe.py (original) +++ pypy/dist/pypy/interpreter/pyframe.py Sun Mar 20 18:13:18 2005 @@ -40,7 +40,10 @@ self.w_locals = space.newdict([]) # set to None by Frame.__init__ self.fastlocals_w = [None]*self.numlocals - + self.w_f_trace = None + self.last_instr = -1 + self.f_back = None + def getfastscope(self): "Get the fast locals as a list." return self.fastlocals_w @@ -60,8 +63,9 @@ def eval(self, executioncontext): "Interpreter main loop!" + previous = executioncontext.enter(self) try: - last_instr = -1 + self.last_instr = -1 while True: try: try: @@ -70,7 +74,7 @@ # fetch and dispatch the next opcode # dispatch() is abstract, see pyopcode. executioncontext.bytecode_trace(self) - last_instr = self.next_instr + self.last_instr = self.next_instr self.dispatch() # catch asynchronous exceptions and turn them # into OperationErrors @@ -89,7 +93,7 @@ except OperationError, e: pytraceback.record_application_traceback( - self.space, e, self, last_instr) + self.space, e, self, self.last_instr) executioncontext.exception_trace(e) # convert an OperationError into a control flow # exception @@ -100,13 +104,17 @@ except ControlFlowException, ctlflowexc: # we have a reason to change the control flow # (typically unroll the stack) - ctlflowexc.action(self, last_instr, executioncontext) + ctlflowexc.action(self, self.last_instr, executioncontext) except ExitFrame, e: # leave that frame w_exitvalue = e.args[0] + executioncontext.leave(previous, w_exitvalue) return w_exitvalue - + except: + executioncontext.leave(previous) + raise + ### exception stack ### def clean_exceptionstack(self): @@ -138,7 +146,22 @@ self = space.interpclass_w(w_self) return self.builtin.getdict() + def fget_f_back(space, w_self): + self = space.interpclass_w(w_self) + return self.space.wrap(self.f_back) + def fget_f_lasti(space, w_self): + self = space.interpclass_w(w_self) + return self.space.wrap(self.last_instr) + + def fget_f_trace(space, w_self): + self = space.interpclass_w(w_self) + return self.w_f_trace + + def fset_f_trace(space, w_self, w_trace): + self = space.interpclass_w(w_self) + self.w_f_trace = w_trace + ### Frame Blocks ### class FrameBlock: Modified: pypy/dist/pypy/interpreter/typedef.py ============================================================================== --- pypy/dist/pypy/interpreter/typedef.py (original) +++ pypy/dist/pypy/interpreter/typedef.py Sun Mar 20 18:13:18 2005 @@ -325,6 +325,9 @@ PyFrame.typedef = TypeDef('frame', f_builtins = GetSetProperty(PyFrame.fget_f_builtins), f_lineno = GetSetProperty(PyFrame.fget_f_lineno), + f_back = GetSetProperty(PyFrame.fget_f_back), + f_lasti = GetSetProperty(PyFrame.fget_f_lasti), + f_trace = GetSetProperty(PyFrame.fget_f_trace, PyFrame.fset_f_trace), **Frame.typedef.rawdict) Module.typedef = TypeDef("module", Modified: pypy/dist/pypy/module/sys2/__init__.py ============================================================================== --- pypy/dist/pypy/module/sys2/__init__.py (original) +++ pypy/dist/pypy/module/sys2/__init__.py Sun Mar 20 18:13:18 2005 @@ -42,7 +42,9 @@ 'getcheckinterval' : 'vm.getcheckinterval', 'exc_info' : 'vm.exc_info', 'exc_clear' : 'vm.exc_clear', - + 'settrace' : 'vm.settrace', + 'setprofile' : 'vm.setprofile', + 'executable' : 'space.wrap("py.py")', 'copyright' : 'space.wrap("MIT-License")', 'api_version' : 'space.wrap(1012)', Modified: pypy/dist/pypy/module/sys2/vm.py ============================================================================== --- pypy/dist/pypy/module/sys2/vm.py (original) +++ pypy/dist/pypy/module/sys2/vm.py Sun Mar 20 18:13:18 2005 @@ -93,3 +93,17 @@ # value of 6 to get results comparable to cpythons. /Arre return space.wrap(sys.getrefcount(w_obj) - 6) +def settrace(space, w_func): + """settrace(function) + +Set the global debug tracing function. It will be called on each +function call. See the debugger chapter in the library manual. +""" + +def setprofile(space, w_func): + """setprofile(function) + +Set the profiling function. It will be called on each function call +and return. See the profiler chapter in the library manual. +""" + Modified: pypy/dist/pypy/objspace/trace.py ============================================================================== --- pypy/dist/pypy/objspace/trace.py (original) +++ pypy/dist/pypy/objspace/trace.py Sun Mar 20 18:13:18 2005 @@ -103,11 +103,11 @@ self.result.append(EnterFrame(frame)) return self.ec.enter(frame) - def leave(self, previous_ec): + def leave(self, previous_ec, w_exitval=None): """ called just after evaluating of a frame is suspended/finished. """ frame = self.ec.framestack.top() self.result.append(LeaveFrame(frame)) - return self.ec.leave(previous_ec) + return self.ec.leave(previous_ec, w_exitval) def bytecode_trace(self, frame): """ called just before execution of a bytecode. """ From alex at codespeak.net Sun Mar 20 18:18:36 2005 From: alex at codespeak.net (alex at codespeak.net) Date: Sun, 20 Mar 2005 18:18:36 +0100 (MET) Subject: [pypy-svn] r9938 - pypy/dist/pypy/objspace/std Message-ID: <20050320171836.11A1E27B66@code1.codespeak.net> Author: alex Date: Sun Mar 20 18:18:35 2005 New Revision: 9938 Modified: pypy/dist/pypy/objspace/std/objecttype.py Log: implemented override of __reduce_ex__ by __reduce__ Modified: pypy/dist/pypy/objspace/std/objecttype.py ============================================================================== --- pypy/dist/pypy/objspace/std/objecttype.py (original) +++ pypy/dist/pypy/objspace/std/objecttype.py Sun Mar 20 18:18:35 2005 @@ -47,10 +47,13 @@ except OperationError: pass else: w_cls = space.getattr(w_obj, space.wrap('__class__')) - w_cls_reduce = space.getattr(w_cls, w_st_reduce) + w_cls_reduce_meth = space.getattr(w_cls, w_st_reduce) + w_cls_reduce = space.getattr(w_cls_reduce_meth, space.wrap('im_func')) w_objtype = space.w_object - w_obj_reduce = space.getattr(w_objtype, space.wrap('__dict__')) + w_obj_dict = space.getattr(w_objtype, space.wrap('__dict__')) + w_obj_reduce = space.getitem(w_obj_dict, w_st_reduce) override = space.is_true(space.ne(w_cls_reduce, w_obj_reduce)) + # print 'OVR', override, w_cls_reduce, w_obj_reduce if override: return space.call(w_reduce, space.newtuple([])) if proto >= 2: From tismer at codespeak.net Sun Mar 20 18:34:18 2005 From: tismer at codespeak.net (tismer at codespeak.net) Date: Sun, 20 Mar 2005 18:34:18 +0100 (MET) Subject: [pypy-svn] r9939 - pypy/dist/pypy/lib/test2 Message-ID: <20050320173418.3D60B27B72@code1.codespeak.net> Author: tismer Date: Sun Mar 20 18:34:18 2005 New Revision: 9939 Modified: pypy/dist/pypy/lib/test2/test_pickle.py Log: completed pickle tests. The full functionality should be checked with the standard test_pickle, but be aware that it computes long. Modified: pypy/dist/pypy/lib/test2/test_pickle.py ============================================================================== --- pypy/dist/pypy/lib/test2/test_pickle.py (original) +++ pypy/dist/pypy/lib/test2/test_pickle.py Sun Mar 20 18:34:18 2005 @@ -3,17 +3,30 @@ import pickle class Picklable(object): - def __init__(self, a=5): + def __init__(self, a=555): self.a = a def __eq__(self, other): return self.a == other.a def __str__(self): return '%s(%r)' % (self.__class__.__name__, self.a) + __repr__ = __str__ class PicklableSpecial2(Picklable): def __reduce__(self): return self.__class__, (self.a,) +class PicklableSpecial3(Picklable): + def __reduce__(self): + return self.__class__, (), self.a + def __setstate__(self, a): + self.a = a + +class PicklableSpecial4(Picklable): + def __reduce_ex__(self, proto): + return self.__class__, (), self.a + def __setstate__(self, a): + self.a = a + class PickleTest(unittest.TestCase): def _pickle_some(self, x): @@ -23,10 +36,16 @@ self.assertEqual(x, y) def test_pickle_plain(self): - self._pickle_some(Picklable()) + self._pickle_some(Picklable(5)) def test_pickle_special2(self): - self._pickle_some(PicklableSpecial2()) + self._pickle_some(PicklableSpecial2(66)) + + def test_pickle_special3(self): + self._pickle_some(PicklableSpecial3(7)) + + def test_pickle_special4(self): + self._pickle_some(PicklableSpecial4(17)) def test_main(): test.test_support.run_unittest(PickleTest) From tismer at codespeak.net Sun Mar 20 18:48:29 2005 From: tismer at codespeak.net (tismer at codespeak.net) Date: Sun, 20 Mar 2005 18:48:29 +0100 (MET) Subject: [pypy-svn] r9940 - pypy/dist/pypy/objspace/std Message-ID: <20050320174829.C0ED527B7A@code1.codespeak.net> Author: tismer Date: Sun Mar 20 18:48:29 2005 New Revision: 9940 Modified: pypy/dist/pypy/objspace/std/dictproxytype.py Log: dictproxy claimed that __cmp__ exists, but it doesn't Modified: pypy/dist/pypy/objspace/std/dictproxytype.py ============================================================================== --- pypy/dist/pypy/objspace/std/dictproxytype.py (original) +++ pypy/dist/pypy/objspace/std/dictproxytype.py Sun Mar 20 18:48:29 2005 @@ -30,7 +30,8 @@ __contains__ = _proxymethod('__contains__'), __str__ = _proxymethod('__str__'), __iter__ = _proxymethod('__iter__'), - __cmp__ = _proxymethod('__cmp__'), + #__cmp__ = _proxymethod('__cmp__'), + # you cannot have it here if it is not in dict __lt__ = _proxymethod('__lt__'), __le__ = _proxymethod('__le__'), __eq__ = _proxymethod('__eq__'), From arigo at codespeak.net Sun Mar 20 18:54:23 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sun, 20 Mar 2005 18:54:23 +0100 (MET) Subject: [pypy-svn] r9941 - pypy/dist/pypy/interpreter Message-ID: <20050320175423.11D9827B82@code1.codespeak.net> Author: arigo Date: Sun Mar 20 18:54:22 2005 New Revision: 9941 Modified: pypy/dist/pypy/interpreter/argument.py Log: Another small fix to the argument parsing error messages. Modified: pypy/dist/pypy/interpreter/argument.py ============================================================================== --- pypy/dist/pypy/interpreter/argument.py (original) +++ pypy/dist/pypy/interpreter/argument.py Sun Mar 20 18:54:22 2005 @@ -181,6 +181,7 @@ raise ArgErrMultipleValues(name) remainingkwds_w = kwds_w.copy() + not_enough = False if input_argcount < co_argcount: # not enough args, fill in kwargs or defaults if exists def_first = co_argcount - len(defaults_w) @@ -192,8 +193,11 @@ elif i >= def_first: scope_w.append(defaults_w[i-def_first]) else: - raise ArgErrCount(signature, defaults_w, False) - + # error: not enough arguments. Don't signal it immediately + # because it might be related to a problem with */** or + # keyword arguments, will be checked for below. + not_enough = True + # collect extra positional arguments into the *vararg if varargname is not None: if self.w_stararg is None: # common case @@ -211,6 +215,9 @@ scope_w.append(w_kwds) elif remainingkwds_w: raise ArgErrUnknownKwds(remainingkwds_w) + + if not_enough: + raise ArgErrCount(signature, defaults_w, False) return scope_w ### Argument <-> list of w_objects together with "shape" information From briandorsey at codespeak.net Sun Mar 20 19:20:56 2005 From: briandorsey at codespeak.net (briandorsey at codespeak.net) Date: Sun, 20 Mar 2005 19:20:56 +0100 (MET) Subject: [pypy-svn] r9942 - pypy/dist/lib-python-2.3.4/test Message-ID: <20050320182056.9F90F27B85@code1.codespeak.net> Author: briandorsey Date: Sun Mar 20 19:20:56 2005 New Revision: 9942 Modified: pypy/dist/lib-python-2.3.4/test/conftest.py Log: Supply sys.argv when py.test is running unittest testcases in lib-python-2.3.4 dir. Modified: pypy/dist/lib-python-2.3.4/test/conftest.py ============================================================================== --- pypy/dist/lib-python-2.3.4/test/conftest.py (original) +++ pypy/dist/lib-python-2.3.4/test/conftest.py Sun Mar 20 19:20:56 2005 @@ -33,7 +33,7 @@ 'test_builtin.py', 'test_call.py', 'test_cmath.py', -'test_codeop.py', +# 'test_codeop.py', # Commented out due to strange iteraction with py.test 'test_commands.py', 'test_compare.py', 'test_compile.py', @@ -201,7 +201,8 @@ class AppTestCaseMethod(py.test.Item): def __init__(self, fspath, space, w_name, w_method, w_setup, w_teardown): self.space = space - self.name = name = space.str_w(w_name) + self.name = name = space.str_w(w_name) + self.modulepath = fspath extpy = py.path.extpy(fspath, name) super(AppTestCaseMethod, self).__init__(extpy) self.w_method = w_method @@ -210,7 +211,11 @@ def run(self, driver): space = self.space - try: + try: + filename = str(self.modulepath) + w_argv = space.sys.get('argv') + space.setitem(w_argv, space.newslice(None, None, None), + space.newlist([space.wrap(filename)])) space.call_function(self.w_setup) try: try: From jacob at codespeak.net Sun Mar 20 19:24:18 2005 From: jacob at codespeak.net (jacob at codespeak.net) Date: Sun, 20 Mar 2005 19:24:18 +0100 (MET) Subject: [pypy-svn] r9943 - in pypy/dist/pypy/lib: . test2 Message-ID: <20050320182418.F33F027B96@code1.codespeak.net> Author: jacob Date: Sun Mar 20 19:24:18 2005 New Revision: 9943 Modified: pypy/dist/pypy/lib/md5.py pypy/dist/pypy/lib/sha.py pypy/dist/pypy/lib/test2/test_datetime.py Log: Fixed missing and badly named variables in interfaces. Modified: pypy/dist/pypy/lib/md5.py ============================================================================== --- pypy/dist/pypy/lib/md5.py (original) +++ pypy/dist/pypy/lib/md5.py Sun Mar 20 19:24:18 2005 @@ -412,16 +412,16 @@ digest_size = 16 def new(arg=None): - """Return a new md5 object. + """Return a new md5 crypto object. If arg is present, the method call update(arg) is made. """ - md5 = MD5Type() + crypto = MD5Type() if arg: - md5.update(arg) + crypto.update(arg) - return md5 + return crypto def md5(arg=None): Modified: pypy/dist/pypy/lib/sha.py ============================================================================== --- pypy/dist/pypy/lib/sha.py (original) +++ pypy/dist/pypy/lib/sha.py Sun Mar 20 19:24:18 2005 @@ -111,7 +111,7 @@ 0xCA62C1D6L # (60 <= t <= 79) ] -class MD5: +class sha: "An implementation of the MD5 hash function in pure Python." def __init__(self): @@ -326,16 +326,20 @@ # for consistency with the md5 module of the standard library. # ====================================================================== -digest_size = 16 +# These are mandatory variables in the module. They have constant values +# in the SHA standard. + +digest_size = digestsize = 20 +blocksize = 1 def new(arg=None): - """Return a new md5 object. + """Return a new sha crypto object. If arg is present, the method call update(arg) is made. """ - md5 = MD5() + crypto = sha() if arg: - md5.update(arg) + crypto.update(arg) - return md5 + return crypto Modified: pypy/dist/pypy/lib/test2/test_datetime.py ============================================================================== --- pypy/dist/pypy/lib/test2/test_datetime.py (original) +++ pypy/dist/pypy/lib/test2/test_datetime.py Sun Mar 20 19:24:18 2005 @@ -3,16 +3,17 @@ This is a py.test conversion of the test cases in the CVS sandbox of CPython. """ +import autopath import sys import pickle import cPickle -from datetime import MINYEAR, MAXYEAR -from datetime import timedelta -from datetime import tzinfo -from datetime import time -from datetime import date, datetime +from pypy.appspace.datetime import MINYEAR, MAXYEAR +from pypy.appspace.datetime import timedelta +from pypy.appspace.datetime import tzinfo +from pypy.appspace.datetime import time +from pypy.appspace.datetime import date, datetime # Before Python 2.3, proto=2 was taken as a synonym for proto=1. @@ -33,7 +34,7 @@ class TestModule(object): def test_constants(self): - import datetime + from pypy.appspace import datetime assert datetime.MINYEAR == 1 assert datetime.MAXYEAR == 9999 From arigo at codespeak.net Sun Mar 20 19:25:12 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sun, 20 Mar 2005 19:25:12 +0100 (MET) Subject: [pypy-svn] r9944 - pypy/dist/lib-python-2.3.4/test Message-ID: <20050320182512.D98E027B9A@code1.codespeak.net> Author: arigo Date: Sun Mar 20 19:25:12 2005 New Revision: 9944 Removed: pypy/dist/lib-python-2.3.4/test/test_scope.py Log: removed file modified by error Deleted: /pypy/dist/lib-python-2.3.4/test/test_scope.py ============================================================================== --- /pypy/dist/lib-python-2.3.4/test/test_scope.py Sun Mar 20 19:25:12 2005 +++ (empty file) @@ -1,525 +0,0 @@ -from test.test_support import verify, TestFailed, check_syntax - -import warnings -warnings.filterwarnings("ignore", r"import \*", SyntaxWarning, "") - -print "1. simple nesting" - -def make_adder(x): - def adder(y): - return x + y - return adder - -inc = make_adder(1) -plus10 = make_adder(10) - -verify(inc(1) == 2) -verify(plus10(-2) == 8) - -print "2. extra nesting" - -def make_adder2(x): - def extra(): # check freevars passing through non-use scopes - def adder(y): - return x + y - return adder - return extra() - -inc = make_adder2(1) -plus10 = make_adder2(10) - -verify(inc(1) == 2) -verify(plus10(-2) == 8) - -print "3. simple nesting + rebinding" - -def make_adder3(x): - def adder(y): - return x + y - x = x + 1 # check tracking of assignment to x in defining scope - return adder - -inc = make_adder3(0) -plus10 = make_adder3(9) - -verify(inc(1) == 2) -verify(plus10(-2) == 8) - -print "4. nesting with global but no free" - -def make_adder4(): # XXX add exta level of indirection - def nest(): - def nest(): - def adder(y): - return global_x + y # check that plain old globals work - return adder - return nest() - return nest() - -global_x = 1 -adder = make_adder4() -verify(adder(1) == 2) - -global_x = 10 -verify(adder(-2) == 8) - -print "5. nesting through class" - -def make_adder5(x): - class Adder: - def __call__(self, y): - return x + y - return Adder() - -inc = make_adder5(1) -plus10 = make_adder5(10) - -verify(inc(1) == 2) -verify(plus10(-2) == 8) - -print "6. nesting plus free ref to global" - -def make_adder6(x): - global global_nest_x - def adder(y): - return global_nest_x + y - global_nest_x = x - return adder - -inc = make_adder6(1) -plus10 = make_adder6(10) - -verify(inc(1) == 11) # there's only one global -verify(plus10(-2) == 8) - -print "7. nearest enclosing scope" - -def f(x): - def g(y): - x = 42 # check that this masks binding in f() - def h(z): - return x + z - return h - return g(2) - -test_func = f(10) -verify(test_func(5) == 47) - -print "8. mixed freevars and cellvars" - -def identity(x): - return x - -def f(x, y, z): - def g(a, b, c): - a = a + x # 3 - def h(): - # z * (4 + 9) - # 3 * 13 - return identity(z * (b + y)) - y = c + z # 9 - return h - return g - -g = f(1, 2, 3) -h = g(2, 4, 6) -verify(h() == 39) - -print "9. free variable in method" - -def test(): - method_and_var = "var" - class Test: - def method_and_var(self): - return "method" - def test(self): - return method_and_var - def actual_global(self): - return str("global") - def str(self): - return str(self) - return Test() - -t = test() -verify(t.test() == "var") -verify(t.method_and_var() == "method") -verify(t.actual_global() == "global") - -method_and_var = "var" -class Test: - # this class is not nested, so the rules are different - def method_and_var(self): - return "method" - def test(self): - return method_and_var - def actual_global(self): - return str("global") - def str(self): - return str(self) - -t = Test() -verify(t.test() == "var") -verify(t.method_and_var() == "method") -verify(t.actual_global() == "global") - -print "10. recursion" - -def f(x): - def fact(n): - if n == 0: - return 1 - else: - return n * fact(n - 1) - if x >= 0: - return fact(x) - else: - raise ValueError, "x must be >= 0" - -verify(f(6) == 720) - - -print "11. unoptimized namespaces" - -check_syntax("""\ -def unoptimized_clash1(strip): - def f(s): - from string import * - return strip(s) # ambiguity: free or local - return f -""") - -check_syntax("""\ -def unoptimized_clash2(): - from string import * - def f(s): - return strip(s) # ambiguity: global or local - return f -""") - -check_syntax("""\ -def unoptimized_clash2(): - from string import * - def g(): - def f(s): - return strip(s) # ambiguity: global or local - return f -""") - -# XXX could allow this for exec with const argument, but what's the point -check_syntax("""\ -def error(y): - exec "a = 1" - def f(x): - return x + y - return f -""") - -check_syntax("""\ -def f(x): - def g(): - return x - del x # can't del name -""") - -check_syntax("""\ -def f(): - def g(): - from string import * - return strip # global or local? -""") - -# and verify a few cases that should work - -exec """ -def noproblem1(): - from string import * - f = lambda x:x - -def noproblem2(): - from string import * - def f(x): - return x + 1 - -def noproblem3(): - from string import * - def f(x): - global y - y = x -""" - -print "12. lambdas" - -f1 = lambda x: lambda y: x + y -inc = f1(1) -plus10 = f1(10) -verify(inc(1) == 2) -verify(plus10(5) == 15) - -f2 = lambda x: (lambda : lambda y: x + y)() -inc = f2(1) -plus10 = f2(10) -verify(inc(1) == 2) -verify(plus10(5) == 15) - -f3 = lambda x: lambda y: global_x + y -global_x = 1 -inc = f3(None) -verify(inc(2) == 3) - -f8 = lambda x, y, z: lambda a, b, c: lambda : z * (b + y) -g = f8(1, 2, 3) -h = g(2, 4, 6) -verify(h() == 18) - -print "13. UnboundLocal" - -def errorInOuter(): - print y - def inner(): - return y - y = 1 - -def errorInInner(): - def inner(): - return y - inner() - y = 1 - -try: - errorInOuter() -except UnboundLocalError: - pass -else: - raise TestFailed - -try: - errorInInner() -except NameError: - pass -else: - raise TestFailed - -print "14. complex definitions" - -def makeReturner(*lst): - def returner(): - return lst - return returner - -verify(makeReturner(1,2,3)() == (1,2,3)) - -def makeReturner2(**kwargs): - def returner(): - return kwargs - return returner - -verify(makeReturner2(a=11)()['a'] == 11) - -def makeAddPair((a, b)): - def addPair((c, d)): - return (a + c, b + d) - return addPair - -verify(makeAddPair((1, 2))((100, 200)) == (101,202)) - -print "15. scope of global statements" -# Examples posted by Samuele Pedroni to python-dev on 3/1/2001 - -# I -x = 7 -def f(): - x = 1 - def g(): - global x - def i(): - def h(): - return x - return h() - return i() - return g() -verify(f() == 7) -verify(x == 7) - -# II -x = 7 -def f(): - x = 1 - def g(): - x = 2 - def i(): - def h(): - return x - return h() - return i() - return g() -verify(f() == 2) -verify(x == 7) - -# III -x = 7 -def f(): - x = 1 - def g(): - global x - x = 2 - def i(): - def h(): - return x - return h() - return i() - return g() -verify(f() == 2) -verify(x == 2) - -# IV -x = 7 -def f(): - x = 3 - def g(): - global x - x = 2 - def i(): - def h(): - return x - return h() - return i() - return g() -verify(f() == 2) -verify(x == 2) - -print "16. check leaks" - -class Foo: - count = 0 - - def __init__(self): - Foo.count += 1 - - def __del__(self): - Foo.count -= 1 - -def f1(): - x = Foo() - def f2(): - return x - f2() - -for i in range(100): - f1() - -verify(Foo.count == 0) - -print "17. class and global" - -def test(x): - class Foo: - global x - def __call__(self, y): - return x + y - return Foo() - -x = 0 -verify(test(6)(2) == 8) -x = -1 -verify(test(3)(2) == 5) - -print "18. verify that locals() works" - -def f(x): - def g(y): - def h(z): - return y + z - w = x + y - y += 3 - return locals() - return g - -d = f(2)(4) -verify(d.has_key('h')) -del d['h'] -print d -verify(d == {'x': 2, 'y': 7, 'w': 6}) - -print "19. var is bound and free in class" - -def f(x): - class C: - def m(self): - return x - a = x - return C - -inst = f(3)() -verify(inst.a == inst.m()) - -print "20. interaction with trace function" - -import sys -def tracer(a,b,c): - return tracer - -def adaptgetter(name, klass, getter): - kind, des = getter - if kind == 1: # AV happens when stepping from this line to next - if des == "": - des = "_%s__%s" % (klass.__name__, name) - return lambda obj: getattr(obj, des) - -class TestClass: - pass - -sys.settrace(tracer) -adaptgetter("foo", TestClass, (1, "")) -sys.settrace(None) - -try: sys.settrace() -except TypeError: pass -else: raise TestFailed, 'sys.settrace() did not raise TypeError' - -print "20. eval and exec with free variables" - -def f(x): - return lambda: x + 1 - -g = f(3) -try: - eval(g.func_code) -except TypeError: - pass -else: - print "eval() should have failed, because code contained free vars" - -try: - exec g.func_code -except TypeError: - pass -else: - print "exec should have failed, because code contained free vars" - -print "21. list comprehension with local variables" - -try: - print bad -except NameError: - pass -else: - print "bad should not be defined" - -def x(): - [bad for s in 'a b' for bad in s.split()] - -x() -try: - print bad -except NameError: - pass - -print "22. eval with free variables" - -def f(x): - def g(): - x - eval("x + 1") - return g - -f(4)() From arigo at codespeak.net Sun Mar 20 19:25:43 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sun, 20 Mar 2005 19:25:43 +0100 (MET) Subject: [pypy-svn] r9945 - pypy/dist/lib-python-2.3.4/test Message-ID: <20050320182543.0756A27B9C@code1.codespeak.net> Author: arigo Date: Sun Mar 20 19:25:42 2005 New Revision: 9945 Added: pypy/dist/lib-python-2.3.4/test/test_scope.py - copied unchanged from r9936, pypy/dist/lib-python-2.3.4/test/test_scope.py Log: reinserted the previous version of test_scope. From arigo at codespeak.net Sun Mar 20 19:38:07 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sun, 20 Mar 2005 19:38:07 +0100 (MET) Subject: [pypy-svn] r9946 - pypy/dist/pypy/interpreter Message-ID: <20050320183807.CEA8727BAA@code1.codespeak.net> Author: arigo Date: Sun Mar 20 19:38:07 2005 New Revision: 9946 Modified: pypy/dist/pypy/interpreter/argument.py Log: argument parsing tweaks going on Modified: pypy/dist/pypy/interpreter/argument.py ============================================================================== --- pypy/dist/pypy/interpreter/argument.py (original) +++ pypy/dist/pypy/interpreter/argument.py Sun Mar 20 19:38:07 2005 @@ -271,7 +271,7 @@ argnames, varargname, kwargname = signature args_w, kwds_w = args.unpack() nargs = len(args_w) - if kwargname is not None: + if kwargname is not None or (kwds_w and defaults_w): msg2 = "non-keyword " else: msg2 = "" From hpk at codespeak.net Sun Mar 20 19:50:29 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sun, 20 Mar 2005 19:50:29 +0100 (MET) Subject: [pypy-svn] r9947 - in pypy/dist: lib-python-2.3.4/test pypy pypy/lib/test2 Message-ID: <20050320185029.869F627BB1@code1.codespeak.net> Author: hpk Date: Sun Mar 20 19:50:29 2005 New Revision: 9947 Modified: pypy/dist/lib-python-2.3.4/test/conftest.py pypy/dist/pypy/conftest.py pypy/dist/pypy/lib/test2/conftest.py Log: let tests in pypy/lib/test2 run against CPython by default add an option --allpypy that will let the test2 tests run against PyPy (not yet fully enabled) Modified: pypy/dist/lib-python-2.3.4/test/conftest.py ============================================================================== --- pypy/dist/lib-python-2.3.4/test/conftest.py (original) +++ pypy/dist/lib-python-2.3.4/test/conftest.py Sun Mar 20 19:50:29 2005 @@ -7,7 +7,7 @@ from pypy.interpreter.module import Module as PyPyModule from pypy.interpreter.main import run_string, run_file -from regrtest import reportdiff +from test.regrtest import reportdiff # # PyPy's command line extra options (these are added @@ -125,7 +125,7 @@ l.append((instance.setUp, instance.tearDown, methods)) return l list_testmethods = app2interp_temp(app_list_testmethods) - + def Module(fspath): output = fspath.dirpath('output', fspath.purebasename) if output.check(file=1): @@ -135,7 +135,7 @@ # XXX not exactly clean: if content.find('unittest') != -1: # we can try to run ... - return UnittestModule(fspath) + return AppUnittestModule(fspath) class OutputTestItem(py.test.Item): def __init__(self, fspath, output): @@ -164,9 +164,9 @@ reportdiff(expected, result) assert 0, "expected and real output of running test differ" -class UnittestModule(py.test.collect.Module): +class AppUnittestModule(py.test.collect.Module): def __init__(self, fspath): - super(UnittestModule, self).__init__(fspath) + super(AppUnittestModule, self).__init__(fspath) def _prepare(self): if hasattr(self, 'space'): Modified: pypy/dist/pypy/conftest.py ============================================================================== --- pypy/dist/pypy/conftest.py (original) +++ pypy/dist/pypy/conftest.py Sun Mar 20 19:50:29 2005 @@ -14,9 +14,10 @@ help="object space to run tests on."), Option('--oldstyle', action="store_true",dest="oldstyle", default=False, help="enable oldstyle classes as default metaclass (std objspace only)"), + Option('--allpypy', action="store_true",dest="allpypy", default=False, + help="run everything possible on top of PyPy."), ]) - def getobjspace(name=None, _spacecache={}): """ helper for instantiating and caching space's for testing. """ Modified: pypy/dist/pypy/lib/test2/conftest.py ============================================================================== --- pypy/dist/pypy/lib/test2/conftest.py (original) +++ pypy/dist/pypy/lib/test2/conftest.py Sun Mar 20 19:50:29 2005 @@ -1,17 +1,78 @@ import autopath +import sys import py import pypy from pypy.conftest import gettestobjspace -lib = py.path.local(pypy.__file__).dirpath() -lib = lib.dirpath('lib-python-2.3.4', 'test') -assert lib.check(dir=1) -conftest = lib.join('conftest.py').getpymodule() +ModuleType = type(sys) + +def make_cpy_module(dottedname, filepath, force=False): + try: + if force: + raise KeyError + return sys.modules[dottedname] + except KeyError: + mod = ModuleType(dottedname) + execfile(str(filepath), mod.__dict__) + sys.modules[dottedname] = mod + return mod + +libtest = py.path.local(pypy.__file__).dirpath() +libtest = libtest.dirpath('lib-python-2.3.4', 'test') +assert libtest.check(dir=1) +#conftest = make_cpy_module('234conftest', libtest.join('conftest.py')) +conftest = libtest.join('conftest.py').getpymodule() +conftest.__file__ = str(conftest.__file__) # keep out the py's importhook def Module(fspath): - return conftest.Module(fspath) + if py.test.config.option.allpypy: + return conftest.Module(fspath) + return UnittestModuleOnCPython(fspath) class Directory(conftest.Directory): def __iter__(self): return iter([]) +class UnittestModuleOnCPython(py.test.collect.Module): + def _prepare(self): + mod = make_cpy_module('unittest', libtest.join('pypy_unittest.py'), force=True) + sys.modules['unittest'] = mod + mod.raises = py.test.raises + self.TestCase = mod.TestCase + + def __iter__(self): + self._prepare() + try: + iterable = self._cache + except AttributeError: + iterable = self._cache = list(self._iter()) + for x in iterable: + yield x + + def _iter(self): + name = self.fspath.purebasename + mod = make_cpy_module(name, self.fspath) + tlist = conftest.app_list_testmethods(mod, self.TestCase) + for (setup, teardown, methods) in tlist: + for name, method in methods: + yield CpyTestCaseMethod(self.fspath, name, method, + setup, teardown) + +class CpyTestCaseMethod(py.test.Item): + def __init__(self, fspath, name, method, setup, teardown): + self.name = name + extpy = py.path.extpy(fspath, name) + super(CpyTestCaseMethod, self).__init__(extpy) + self.method = method + self.setup = setup + self.teardown = teardown + + def run(self, driver): + self.setup() + try: + self.execute() + finally: + self.teardown() + + def execute(self): + return self.method() From ac at codespeak.net Sun Mar 20 20:40:49 2005 From: ac at codespeak.net (ac at codespeak.net) Date: Sun, 20 Mar 2005 20:40:49 +0100 (MET) Subject: [pypy-svn] r9948 - in pypy/dist/pypy: interpreter module/sys2 objspace Message-ID: <20050320194049.8995B27B95@code1.codespeak.net> Author: ac Date: Sun Mar 20 20:40:49 2005 New Revision: 9948 Modified: pypy/dist/pypy/interpreter/eval.py pypy/dist/pypy/interpreter/executioncontext.py pypy/dist/pypy/interpreter/pyframe.py pypy/dist/pypy/module/sys2/vm.py pypy/dist/pypy/objspace/trace.py Log: A closer to working settrace functionality. Modified: pypy/dist/pypy/interpreter/eval.py ============================================================================== --- pypy/dist/pypy/interpreter/eval.py (original) +++ pypy/dist/pypy/interpreter/eval.py Sun Mar 20 20:40:49 2005 @@ -65,7 +65,12 @@ def resume(self): "Resume the execution of the frame from its current state." executioncontext = self.space.getexecutioncontext() - return self.eval(executioncontext) + previous = executioncontext.enter(self) + try: + result = self.eval(executioncontext) + finally: + executioncontext.leave(previous) + return result # running a frame is usually the same as resuming it from its # initial state, but not for generator frames Modified: pypy/dist/pypy/interpreter/executioncontext.py ============================================================================== --- pypy/dist/pypy/interpreter/executioncontext.py (original) +++ pypy/dist/pypy/interpreter/executioncontext.py Sun Mar 20 20:40:49 2005 @@ -25,12 +25,9 @@ else: frame.f_back = self.framestack.top() self.framestack.push(frame) - self.call_trace(frame, 'call', self.space.w_None) return previous_ec - - def leave(self, previous_ec, w_retval=None): - if w_retval is not None: - self.call_trace(self.framestack.top(), 'return', w_retval) + + def leave(self, previous_ec): self.framestack.pop() locals = getthreadlocals() locals.executioncontext = previous_ec @@ -49,14 +46,24 @@ w_globals = self.space.newdict([(w_key, w_value)]) return w_globals + def call_trace(self, frame): + "Trace the call of a function" + self._trace(frame, 'call', self.space.w_None) + + def return_trace(self, frame, w_retval): + "Trace the return from a function" + self._trace(self.framestack.top(), 'return', w_retval) + def bytecode_trace(self, frame): "Trace function called before each bytecode." def exception_trace(self, operationerr): "Trace function called upon OperationError." operationerr.record_interpreter_traceback() - self.call_trace(self.framestack.top(), 'exception', - self.sys_exc_info()) + exc_info = self.sys_exc_info() + frame = self.framestack.top() + self._trace(self.framestack.top(), 'exception', + exc_info) #operationerr.print_detailed_traceback(self.space) def sys_exc_info(self): @@ -76,12 +83,12 @@ def settrace(self, w_func): """Set the global trace function.""" - if self.space.is_(w_func, self.space.w_None): + if self.space.is_true(self.space.is_(w_func, self.space.w_None)): self.w_tracefunc = None else: self.w_tracefunc = w_func - def call_trace(self, frame, event, w_arg): + def _trace(self, frame, event, w_arg): if event == 'call': w_callback = self.w_tracefunc else: @@ -91,14 +98,14 @@ self.is_tracing += 1 try: try: - w_result = self.space.call(w_callback, self.space.wrap(frame), self.space.wrap(event), w_arg) - if self.space.is_(w_result, self.space.w_None): + w_result = self.space.call_function(w_callback, self.space.wrap(frame), self.space.wrap(event), w_arg) + if self.space.is_true(self.space.is_(w_result, self.space.w_None)): frame.w_f_trace = None else: frame.w_f_trace = w_result except: self.settrace(self.space.w_None) frame.w_f_trace = None + raise finally: - self.is_traceing -= 1 - + self.is_tracing -= 1 Modified: pypy/dist/pypy/interpreter/pyframe.py ============================================================================== --- pypy/dist/pypy/interpreter/pyframe.py (original) +++ pypy/dist/pypy/interpreter/pyframe.py Sun Mar 20 20:40:49 2005 @@ -63,8 +63,8 @@ def eval(self, executioncontext): "Interpreter main loop!" - previous = executioncontext.enter(self) try: + executioncontext.call_trace(self) self.last_instr = -1 while True: try: @@ -109,11 +109,8 @@ except ExitFrame, e: # leave that frame w_exitvalue = e.args[0] - executioncontext.leave(previous, w_exitvalue) + executioncontext.return_trace(self, w_exitvalue) return w_exitvalue - except: - executioncontext.leave(previous) - raise ### exception stack ### Modified: pypy/dist/pypy/module/sys2/vm.py ============================================================================== --- pypy/dist/pypy/module/sys2/vm.py (original) +++ pypy/dist/pypy/module/sys2/vm.py Sun Mar 20 20:40:49 2005 @@ -99,7 +99,8 @@ Set the global debug tracing function. It will be called on each function call. See the debugger chapter in the library manual. """ - + space.getexecutioncontext().settrace(w_func) + def setprofile(space, w_func): """setprofile(function) Modified: pypy/dist/pypy/objspace/trace.py ============================================================================== --- pypy/dist/pypy/objspace/trace.py (original) +++ pypy/dist/pypy/objspace/trace.py Sun Mar 20 20:40:49 2005 @@ -103,11 +103,11 @@ self.result.append(EnterFrame(frame)) return self.ec.enter(frame) - def leave(self, previous_ec, w_exitval=None): + def leave(self, previous_ec): """ called just after evaluating of a frame is suspended/finished. """ frame = self.ec.framestack.top() self.result.append(LeaveFrame(frame)) - return self.ec.leave(previous_ec, w_exitval) + return self.ec.leave(previous_ec) def bytecode_trace(self, frame): """ called just before execution of a bytecode. """ From hpk at codespeak.net Sun Mar 20 20:57:45 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sun, 20 Mar 2005 20:57:45 +0100 (MET) Subject: [pypy-svn] r9949 - pypy/dist/pypy/documentation/revreport Message-ID: <20050320195745.A50D027B4F@code1.codespeak.net> Author: hpk Date: Sun Mar 20 20:57:45 2005 New Revision: 9949 Modified: pypy/dist/pypy/documentation/revreport/ (props changed) Log: ignore revdata if any From briandorsey at codespeak.net Sun Mar 20 21:07:35 2005 From: briandorsey at codespeak.net (briandorsey at codespeak.net) Date: Sun, 20 Mar 2005 21:07:35 +0100 (MET) Subject: [pypy-svn] r9950 - in pypy/dist/pypy/module: sys2 test Message-ID: <20050320200735.1522827B72@code1.codespeak.net> Author: briandorsey Date: Sun Mar 20 21:07:34 2005 New Revision: 9950 Modified: pypy/dist/pypy/module/sys2/__init__.py pypy/dist/pypy/module/test/test_sysmodule.py Log: Added sys.__stdin__ and sys.__stdout__ to sys2. Modified: pypy/dist/pypy/module/sys2/__init__.py ============================================================================== --- pypy/dist/pypy/module/sys2/__init__.py (original) +++ pypy/dist/pypy/module/sys2/__init__.py Sun Mar 20 21:07:34 2005 @@ -22,7 +22,9 @@ 'maxunicode' : 'space.wrap(sys.maxunicode)', 'maxint' : 'space.wrap(sys.maxint)', 'stdin' : 'space.wrap(sys.stdin)', + '__stdin__' : 'space.wrap(sys.stdin)', 'stdout' : 'space.wrap(sys.stdout)', + '__stdout__' : 'space.wrap(sys.stdout)', 'stderr' : 'space.wrap(sys.stderr)', 'pypy_objspaceclass' : 'space.wrap(space.__class__.__name__)', Modified: pypy/dist/pypy/module/test/test_sysmodule.py ============================================================================== --- pypy/dist/pypy/module/test/test_sysmodule.py (original) +++ pypy/dist/pypy/module/test/test_sysmodule.py Sun Mar 20 21:07:34 2005 @@ -9,8 +9,13 @@ b.cStringIO = cStringIO b.sys = sys +def test_stdin_exists(space): + space.sys.get('stdin') + space.sys.get('__stdin__') + def test_stdout_exists(space): - assert space.sys.get('stdout') + space.sys.get('stdout') + space.sys.get('__stdout__') class AppTestAppSysTests: def test_path_exists(self): From tismer at codespeak.net Sun Mar 20 22:08:05 2005 From: tismer at codespeak.net (tismer at codespeak.net) Date: Sun, 20 Mar 2005 22:08:05 +0100 (MET) Subject: [pypy-svn] r9951 - pypy/dist/pypy/objspace/std Message-ID: <20050320210805.1688A27B4B@code1.codespeak.net> Author: tismer Date: Sun Mar 20 22:08:04 2005 New Revision: 9951 Modified: pypy/dist/pypy/objspace/std/typeobject.py pypy/dist/pypy/objspace/std/typetype.py Log: some progress in pickling derived types. Added supportfor type.__flags__ as needed in copy_reg. Still a problem with unpickling of the otherwise perfect pickle string. Modified: pypy/dist/pypy/objspace/std/typeobject.py ============================================================================== --- pypy/dist/pypy/objspace/std/typeobject.py (original) +++ pypy/dist/pypy/objspace/std/typeobject.py Sun Mar 20 22:08:04 2005 @@ -5,6 +5,8 @@ from pypy.objspace.std.stdtypedef import std_dict_descr, issubtypedef, Member from pypy.objspace.std.objecttype import object_typedef +from copy_reg import _HEAPTYPE # XXX is it clean to do this? + class W_TypeObject(W_Object): from pypy.objspace.std.typetype import type_typedef as typedef @@ -22,7 +24,9 @@ if overridetypedef is not None: w_self.instancetypedef = overridetypedef w_self.hasdict = overridetypedef.hasdict + w_self.w__flags__ = space.wrap(0) # not a heaptype else: + w_self.w__flags__ = space.wrap(_HEAPTYPE) # find the most specific typedef instancetypedef = object_typedef for w_base in bases_w: Modified: pypy/dist/pypy/objspace/std/typetype.py ============================================================================== --- pypy/dist/pypy/objspace/std/typetype.py (original) +++ pypy/dist/pypy/objspace/std/typetype.py Sun Mar 20 22:08:04 2005 @@ -89,6 +89,8 @@ else: return w_result +def descr__flags(space, w_type): + return w_type.w__flags__ # ____________________________________________________________ type_typedef = StdTypeDef("type", @@ -100,4 +102,5 @@ __dict__ = GetSetProperty(descr_get_dictproxy), __doc__ = GetSetProperty(descr__doc), mro = gateway.interp2app(descr_mro), + __flags__ = GetSetProperty(descr__flags), ) From hpk at codespeak.net Sun Mar 20 22:13:13 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sun, 20 Mar 2005 22:13:13 +0100 (MET) Subject: [pypy-svn] r9952 - pypy/dist/pypy Message-ID: <20050320211313.9766327B4B@code1.codespeak.net> Author: hpk Date: Sun Mar 20 22:13:13 2005 New Revision: 9952 Modified: pypy/dist/pypy/conftest.py Log: set rootdir (for nicer py.test --session mode) Modified: pypy/dist/pypy/conftest.py ============================================================================== --- pypy/dist/pypy/conftest.py (original) +++ pypy/dist/pypy/conftest.py Sun Mar 20 22:13:13 2005 @@ -3,6 +3,8 @@ from pypy.interpreter.error import OperationError from pypy.tool import pytestsupport +rootdir = py.magic.autopath().dirpath() + # # PyPy's command line extra options (these are added # to py.test's standard options) From briandorsey at codespeak.net Sun Mar 20 22:15:04 2005 From: briandorsey at codespeak.net (briandorsey at codespeak.net) Date: Sun, 20 Mar 2005 22:15:04 +0100 (MET) Subject: [pypy-svn] r9953 - in pypy/dist/pypy/tool: . test Message-ID: <20050320211504.E83AA27B4B@code1.codespeak.net> Author: briandorsey Date: Sun Mar 20 22:15:04 2005 New Revision: 9953 Modified: pypy/dist/pypy/tool/pytestsupport.py pypy/dist/pypy/tool/test/test_pytestsupport.py Log: Disable py.test assertion magic if a message is explicitly passed to 'assert' at the application level. (eg: assert False, "this fails") Modified: pypy/dist/pypy/tool/pytestsupport.py ============================================================================== --- pypy/dist/pypy/tool/pytestsupport.py (original) +++ pypy/dist/pypy/tool/pytestsupport.py Sun Mar 20 22:15:04 2005 @@ -88,19 +88,24 @@ if frame.code.co_name == 'normalize_exception': frame = framestack.top(1) - runner = AppFrame(frame) - try: - source = runner.statement - source = str(source).strip() - except py.error.ENOENT: - source = None - if source and not py.test.config.option.nomagic: - msg = exprinfo.interpret(source, runner, should_fail=True) - space.setattr(w_self, space.wrap('args'), - space.newtuple([space.wrap(msg)])) - w_msg = space.wrap(msg) + # if the assertion provided a message, don't do magic + args_w, kwargs_w = __args__.unpack() + if args_w: + w_msg = args_w[0] else: - w_msg = space.w_None + runner = AppFrame(frame) + try: + source = runner.statement + source = str(source).strip() + except py.error.ENOENT: + source = None + if source and not py.test.config.option.nomagic: + msg = exprinfo.interpret(source, runner, should_fail=True) + space.setattr(w_self, space.wrap('args'), + space.newtuple([space.wrap(msg)])) + w_msg = space.wrap(msg) + else: + w_msg = space.w_None space.setattr(w_self, space.wrap('msg'), w_msg) # build a new AssertionError class to replace the original one. Modified: pypy/dist/pypy/tool/test/test_pytestsupport.py ============================================================================== --- pypy/dist/pypy/tool/test/test_pytestsupport.py (original) +++ pypy/dist/pypy/tool/test/test_pytestsupport.py Sun Mar 20 22:15:04 2005 @@ -46,4 +46,11 @@ else: raise AssertionError, "app level AssertionError mixup!" +def app_test_exception_with_message(): + try: + assert 0, "Failed" + except AssertionError, e: + assert e.msg == "Failed" + + From rxe at codespeak.net Sun Mar 20 23:04:42 2005 From: rxe at codespeak.net (rxe at codespeak.net) Date: Sun, 20 Mar 2005 23:04:42 +0100 (MET) Subject: [pypy-svn] r9955 - pypy/dist/pypy/interpreter Message-ID: <20050320220442.11B7B27B4F@code1.codespeak.net> Author: rxe Date: Sun Mar 20 23:04:41 2005 New Revision: 9955 Modified: pypy/dist/pypy/interpreter/executioncontext.py pypy/dist/pypy/interpreter/pyframe.py Log: Updates for getting sys.settrace() working. Modified: pypy/dist/pypy/interpreter/executioncontext.py ============================================================================== --- pypy/dist/pypy/interpreter/executioncontext.py (original) +++ pypy/dist/pypy/interpreter/executioncontext.py Sun Mar 20 23:04:41 2005 @@ -1,3 +1,4 @@ +import sys from pypy.interpreter.miscutils import getthreadlocals, Stack from pypy.interpreter.error import OperationError @@ -56,6 +57,49 @@ def bytecode_trace(self, frame): "Trace function called before each bytecode." + if self.is_tracing or frame.w_f_trace is None: + return + + if frame.instr_lb <= frame.last_instr < frame.instr_ub: + return + + code = getattr(frame, 'code') + + size = len(code.co_lnotab) / 2 + addr = 0 + line = code.co_firstlineno + p = iter(code.co_lnotab) + + while size > 0: + c = ord(p.next()) + if (addr + c) > frame.last_instr: + break + addr += c + if c: + frame.instr_lb = addr + + c = ord(p.next()) + line += c + size -= 1 + + if addr == frame.last_instr: + frame.f_lineno = line + self._trace(frame, 'line', self.space.w_None) + + if size > 0: + size -= 1 + while size >= 0: + + c = ord(p.next()) + addr += c + if c: + break + + frame.instr_ub = addr + else: + frame.instr_ub = sys.maxint + + def exception_trace(self, operationerr): "Trace function called upon OperationError." Modified: pypy/dist/pypy/interpreter/pyframe.py ============================================================================== --- pypy/dist/pypy/interpreter/pyframe.py (original) +++ pypy/dist/pypy/interpreter/pyframe.py Sun Mar 20 23:04:41 2005 @@ -43,6 +43,11 @@ self.w_f_trace = None self.last_instr = -1 self.f_back = None + self.f_lineno = self.code.co_firstlineno + + # For tracing + self.instr_lb = 0 + self.instr_ub = -1 def getfastscope(self): "Get the fast locals as a list." @@ -73,8 +78,8 @@ while True: # fetch and dispatch the next opcode # dispatch() is abstract, see pyopcode. - executioncontext.bytecode_trace(self) self.last_instr = self.next_instr + executioncontext.bytecode_trace(self) self.dispatch() # catch asynchronous exceptions and turn them # into OperationErrors @@ -129,7 +134,23 @@ def fget_f_lineno(space, w_self): "Returns the line number of the instruction currently being executed." self = space.interpclass_w(w_self) - return space.wrap(self.get_last_lineno()) + if self.w_f_trace is None: + return space.wrap(self.get_last_lineno()) + else: + return space.wrap(self.f_lineno) + +## def fset_f_lineno(space, w_self, w_f_lineo): +## "Returns the line number of the instruction currently being executed." +## f_lineo = space.int_w(w_f_lineo) + +## self = space.interpclass_w(w_self) +## if self.self.w_f_trace is None: +## raise OperationError(self.space.w_ValueError, space.wrap("f_lineo can only be set by a trace function.")) + +## if f_lineo < self.code.co_firstlineno: +## raise OperationError(self.space.w_ValueError, space.wrap("line %d comes before the current code." % f_lineo)) + +## self.f_lineno = f_lineo def get_last_lineno(self): "Returns the line number of the instruction currently being executed." From hpk at codespeak.net Sun Mar 20 23:05:49 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sun, 20 Mar 2005 23:05:49 +0100 (MET) Subject: [pypy-svn] r9956 - pypy/dist/pypy/documentation/revreport Message-ID: <20050320220549.808A727B4F@code1.codespeak.net> Author: hpk Date: Sun Mar 20 23:05:49 2005 New Revision: 9956 Added: pypy/dist/pypy/documentation/revreport/revreport.py Modified: pypy/dist/pypy/documentation/revreport/delta.py Log: improved reports to have an index page you should run 'revreport.py' to generate a local set of html pages or otherwise go to http://codespeak.net/pypy/rev/current to see the current version of the "revision report" Modified: pypy/dist/pypy/documentation/revreport/delta.py ============================================================================== --- pypy/dist/pypy/documentation/revreport/delta.py (original) +++ pypy/dist/pypy/documentation/revreport/delta.py Sun Mar 20 23:05:49 2005 @@ -1,5 +1,6 @@ import autopath from pypy.interpreter.error import OperationError +from pypy.tool.pypyrev import pypyrev from py.xml import html import py @@ -313,6 +314,8 @@ reports = [] class Report(Entry): + HEADER = ''' +''' useshort = False notes = None @@ -324,22 +327,15 @@ Entry.__init__(self, name) self.title = title - self.rows = [] - reports.append(self) - self.total = 0 self.missing = 0 - self.grandtotal = 0 self.grandmissing = 0 - self._fname = fname - self.__dict__.update(kwds) - def add_row(self, entry, rest, name=None, parent=None): self.rows.append((name, entry, rest, parent)) @@ -432,8 +428,6 @@ class_ = st.class_ bar = incompleteness_bar(dir, st.incompleteness) - HEADER = ''' -''' HIDE = 'display: none' SHOW = 'display: table' @@ -481,8 +475,8 @@ -cmp(st1.incompleteness, st2.incompleteness)) self.fill_table(dir, incompleteness_table, rows) - f = dir.join(self.fname()).write( - HEADER+page.unicode().encode("utf8") + dir.join(self.fname()).write( + self.HEADER+page.unicode().encode("utf8") ) def navig(self): @@ -493,8 +487,11 @@ descr = "methods+attrs" def navig(self): - return html.p(html.span(self.title,**{'class': 'title'}), - "|",mods_report.link(None),"|",cls_report.link(None)) + return html.p(html.span(self.title, class_='title'), + "|", mods_report.link(None),"|", + cls_report.link(None), '|', + index_report.link(None), + ) def grandadd(self, parent): parent.grandtotal += self.total @@ -507,8 +504,11 @@ granddescr = "module funcs+others and contained types/classes methods+attrs" def navig(self): - return html.p(html.span(self.title,**{'class': 'title'}), - "|",mods_report.link(None),"|",cls_report.link(None)) + return html.p(html.span(self.title, class_='title'), + "|", mods_report.link(None), + "|", cls_report.link(None), + "|", index_report.link(None), + ) notes = ("(): callable, C: type/class") @@ -519,6 +519,47 @@ elif self.status == 'PRESENT': parent.grandtotal += self.grandtotal +class IndexReport(Report): + + def __init__(self, name, rev): + Report.__init__(self, name) + self.shortname = "PyPy rev %d" % rev + + def html(self, DIR): + rev = pypyrev() + title = "PyPy - rev %s - Deltareport Overview" % rev + body = html.body(html.h2(title)) + + page = html.html( + html.head( + html.title(title), + html.link(href="delta.css", rel="stylesheet", type="text/css"), + ), + body, + xmlns="http://www.w3.org/1999/xhtml") + + def percent(incomplete): + return 100 * (1-incomplete) + mod_incomplete = mods_report.status_wrt().incompleteness + modimg = incompleteness_bar(DIR, mod_incomplete) + modlink = mods_report.link(None) + modlink.append(modimg) + modlink.append(" %.2f %%" % (percent(mod_incomplete),)) + body.append(html.div(modlink)) + + cls_incomplete = cls_report.status_wrt().incompleteness + clsimg = incompleteness_bar(DIR, cls_incomplete) + clslink = cls_report.link(None) + clslink.append(clsimg) + clslink.append(" %.2f %%" % (percent(cls_incomplete),)) + body.append(html.div(clslink)) + + body.append(html.h2("Quantitative PyPy CPython-Compliance: %.2f %%" % + percent((cls_incomplete+mod_incomplete)/2))) + + DIR.join(self.fname()).write( + self.HEADER+page.unicode().encode("utf8") + ) def delta(expl1, expl2, modnames): @@ -527,8 +568,10 @@ granddescr = "of all modules funcs+others and contained types/classes methods+attrs", useshort = True) def navig(): - return html.p(html.span('Modules',**{'class': 'title'}), - "|",cls_report.link(None)) + return html.p(html.span('Modules', class_='title'), + "|", cls_report.link(None), + "|", index_report.link(None), + ) rep.navig = navig @@ -658,7 +701,8 @@ def navig(): return html.p(mods_report.link(None), - "|",html.span('Types/Classes',**{'class': 'title'})) + "|",html.span('Types/Classes', class_="title"), + "|", index_report.link(None)) cls_rep.navig = navig @@ -714,16 +758,19 @@ mods) TO_CHECK.sort() -def getpypyrevision(cache=[]): - try: - return cache[0] - except IndexError: - import pypy - import py - pypydir = py.path.svnwc(pypy.__file__).dirpath() - rev = pypydir.info().rev - cache.append(rev) - return rev +def genreport(DIR): + from pypy.objspace.std.objspace import StdObjSpace + space = StdObjSpace() + + global cls_report, mods_report, index_report + mods_report = delta(ObjSpaceExplore(space), host_explore, TO_CHECK) + cls_report = cls_delta_rep() + rev = pypyrev() + index_report = IndexReport('index', rev) + + DIR.ensure(dir=1) + for rep in reports: + rep.html(DIR) if __name__ == '__main__': if len(sys.argv) == 1: @@ -732,13 +779,5 @@ sys.exit(0) DIR = py.path.local(sys.argv[1]) + genreport(DIR) - from pypy.objspace.std.objspace import StdObjSpace - space = StdObjSpace() - - mods_report = delta(ObjSpaceExplore(space), host_explore, TO_CHECK) - cls_report = cls_delta_rep() - - DIR.ensure(dir=1) - for rep in reports: - rep.html(DIR) Added: pypy/dist/pypy/documentation/revreport/revreport.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/documentation/revreport/revreport.py Sun Mar 20 23:05:49 2005 @@ -0,0 +1,38 @@ + +import os, sys +import autopath +import py +from pypy.documentation.revreport import delta +from pypy.tool.pypyrev import pypyrev + +BASE = py.path.local(delta.__file__).dirpath() +DEST = BASE.join('revdata') + +assert DEST.dirpath().check() + +if __name__ == '__main__': + rev = pypyrev() + revdir = DEST.ensure(str(rev), dir=1) + BASE.join('delta.css').copy(revdir) + BASE.join('delta.js').copy(revdir) + delta.genreport(revdir) + + print "generated into", revdir + + l = [] + for x in DEST.listdir(): + try: + x = int(x.basename) + except (TypeError, ValueError): + pass + else: + l.append(x) + latest = DEST.join(str(max(l))) + assert latest.check() + current = DEST.join('current') + if current.check(): + current.remove() + if sys.platform == 'win32': + latest.copy(current) + else: + current.mksymlinkto(latest) From ac at codespeak.net Sun Mar 20 23:09:17 2005 From: ac at codespeak.net (ac at codespeak.net) Date: Sun, 20 Mar 2005 23:09:17 +0100 (MET) Subject: [pypy-svn] r9957 - pypy/dist/lib-python-2.3.4/test Message-ID: <20050320220917.7745A27B4F@code1.codespeak.net> Author: ac Date: Sun Mar 20 23:09:17 2005 New Revision: 9957 Modified: pypy/dist/lib-python-2.3.4/test/pypy_unittest.py Log: Make sure we get the message in calls to fail(). Modified: pypy/dist/lib-python-2.3.4/test/pypy_unittest.py ============================================================================== --- pypy/dist/lib-python-2.3.4/test/pypy_unittest.py (original) +++ pypy/dist/lib-python-2.3.4/test/pypy_unittest.py Sun Mar 20 23:09:17 2005 @@ -37,7 +37,7 @@ assert not expr, msg def fail(self, msg): - assert False, msg + raise AssertionError(msg) def assertRaises(self, exc, call, *args, **kwargs): raises(exc, call, *args, **kwargs) From hpk at codespeak.net Sun Mar 20 23:21:12 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sun, 20 Mar 2005 23:21:12 +0100 (MET) Subject: [pypy-svn] r9960 - pypy/dist/pypy/tool Message-ID: <20050320222112.C153627B5B@code1.codespeak.net> Author: hpk Date: Sun Mar 20 23:21:12 2005 New Revision: 9960 Removed: pypy/dist/pypy/tool/bltinchecker.py Log: obsolete checker (using very old API, not worth to fix) Deleted: /pypy/dist/pypy/tool/bltinchecker.py ============================================================================== --- /pypy/dist/pypy/tool/bltinchecker.py Sun Mar 20 23:21:12 2005 +++ (empty file) @@ -1,80 +0,0 @@ -#python imports -try: - import readline - import rlcompleter - have_readline = True - -except: - have_readline = False - -import __builtin__ as cpy_builtin - -#pypy imports -import autopath -from pypy.objspace.std import Space -from pypy.interpreter.baseobjspace import OperationError - -def found_missing(name, attrs, w_obj, space): - #we cannot do a dir on a pypy wrapped object - found_attrs = [] - missing_attrs = [] - - for a in attrs: - try: - try: - w_name = space.wrap(a) - t = space.getattr(w_obj, w_name) - found_attrs.append(a) - except OperationError: #over-broad? - missing_attrs.append(a) - - except: #something horrible happened - print 'In builtin: ', name, 'Blew Up Trying to get attr: ', repr(a) - missing_attrs.append(a) - - return found_attrs, missing_attrs - -def check_for_attrs(name, space): - try: - cpy_attrs = dir(getattr(cpy_builtin, name)) - except AttributeError: - print "AttributeError: CPython module __builtin__ has no attribute '%s'" % name - return [], [] - - try: - w_obj = space.getitem(space.w_builtins, space.wrap(name)) - except OperationError: - print "AttributeError: PyPy space %s builtins has no attribute '%s'" % (space, name) - return [], cpy_attrs - - return found_missing(name, cpy_attrs, w_obj, space) - - -def print_report(names, space): - - for n in names: - found, missing = check_for_attrs(n, space) - print - print "For the Builtin Function or Type: '%s'" % n - print - print 'Found Attributes: \t', found - print - print 'Missing Attributes: \t', missing - print - print '-------------------------' - -if __name__ == '__main__': - - from pypy.tool import option - from pypy.tool import test - args = option.process_options(option.get_standard_options(), - option.Options) - - - # Create objspace... - objspace = option.objspace() - - #names = dir(cpy_builtin) - names = ['abs', 'xxx', 'unicode', 'enumerate', 'int'] - - print_report(names, objspace) From hpk at codespeak.net Sun Mar 20 23:51:53 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sun, 20 Mar 2005 23:51:53 +0100 (MET) Subject: [pypy-svn] r9963 - pypy/dist/pypy/tool Message-ID: <20050320225153.8CF5127B5B@code1.codespeak.net> Author: hpk Date: Sun Mar 20 23:51:53 2005 New Revision: 9963 Added: pypy/dist/pypy/tool/pypyrev.py Log: this provides a possibility to find out the revision number of the current 'pypy' package in use. Added: pypy/dist/pypy/tool/pypyrev.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/tool/pypyrev.py Sun Mar 20 23:51:53 2005 @@ -0,0 +1,15 @@ + +import pypy +import py + +def pypyrev(cache=[]): + """ return subversion revision number for current pypy package. + """ + try: + return cache[0] + except IndexError: + pypydir = py.path.svnwc(pypy.__file__).dirpath() + rev = pypydir.info().rev + cache.append(rev) + return rev + From hpk at codespeak.net Mon Mar 21 00:08:47 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Mon, 21 Mar 2005 00:08:47 +0100 (MET) Subject: [pypy-svn] r9964 - pypy/dist/pypy/lib Message-ID: <20050320230847.C4CC927B5B@code1.codespeak.net> Author: hpk Date: Mon Mar 21 00:08:47 2005 New Revision: 9964 Removed: pypy/dist/pypy/lib/_types.py Log: this was not used, was it? it cannot be used then anymore ... Deleted: /pypy/dist/pypy/lib/_types.py ============================================================================== --- /pypy/dist/pypy/lib/_types.py Mon Mar 21 00:08:47 2005 +++ (empty file) @@ -1,551 +0,0 @@ -""" -Definition of the standard Python types. -""" - -# XXX we can't do this import yet -from sys import pypy -import __builtin__ -import _types - -__all__ = ['BooleanType', 'BufferType', 'BuiltinFunctionType', - 'BuiltinMethodType', 'ClassType', 'CodeType', 'ComplexType', - 'DictProxyType', 'DictType', 'DictionaryType', 'EllipsisType', - 'FileType', 'FloatType', 'FrameType', 'FunctionType', - 'GeneratorType', 'InstanceType', 'IntType', 'LambdaType', - 'ListType', 'LongType', 'MethodType', 'ModuleType', 'NoneType', - 'NotImplementedType', 'ObjectType', 'SliceType', 'StringType', - 'TracebackType', 'TupleType', 'TypeType', 'UnboundMethodType', - 'UnicodeType', 'XRangeType'] - - -def _register(factory, cls, in_builtin=True, synonym=True): - """ - Register factory as type cls. - - If in_builtin is a true value (which is the default), also - register the type as a built-in. If the value of in_builtin - is a string, use this name as the type name in the __builtin__ - module. - - If synonym is true (which is the default), also register the - type in this very module under its synonym. If synonym is a - string, use this string, else uppercase the class name and - append the string "Type". - """ - pypy.registertype(factory, cls) - if in_builtin: - if isinstance(in_builtin, str): - typename = in_builtin - else: - typename = cls.__name__ - setattr(__builtin__, typename, cls) - if synonym: - if isinstance(synonym, str): - typename = synonym - else: - typename = cls.__name__.title() + 'Type' - setattr(_types, typename, cls) - - -class object: - - def __new__(cls): - if cls is object: - return pypy.ObjectFactory() - else: - return pypy.UserObjectFactory(cls, pypy.ObjectFactory) - - def __repr__(self): - return '<%s object at 0x%x>' % (type(self).__name__, id(self)) - -_register(pypy.ObjectFactory, object) - - -class bool(int): - - def __new__(cls, *args): - if cls is bool: - return pypy.BoolObjectFactory(args) - else: - return pypy.UserObjectFactory(cls, pypy.BoolObjectFactory, args) - - def __repr__(self): - return str(self) - -_register(pypy.BoolObjectFactory, bool, synonym='BooleanType') - - -class buffer(object): - - def __new__(cls, *args): - if cls is buffer: - return pypy.BufferObjectFactory(args) - else: - return pypy.UserObjectFactory(cls, pypy.BufferObjectFactory, args) - - def __repr__(self): - return str(self) - -_register(pypy.BufferObjectFactory, buffer) - - -class builtin_function_or_method(object): - - def __new__(cls, *args): - if cls is builtin_function_or_method: - return pypy.Builtin_Function_Or_MethodObjectFactory(args) - else: - return pypy.UserObjectFactory(cls, - pypy.Builtin_Function_Or_MethodObjectFactory, args) - - def __repr__(self): - return str(self) - -_register(pypy.Builtin_Function_Or_MethodObjectFactory, - builtin_function_or_method, in_builtin=False, - synonym='BuiltinFunctionType') - -setattr(_types, 'BuiltinMethodType', builtin_function_or_method) - - -class classobj(object): - - def __new__(cls, *args): - if cls is classobj: - return pypy.ClassobjObjectFactory(args) - else: - return pypy.UserObjectFactory(cls, pypy.ClassobjObjectFactory, args) - - def __repr__(self): - return str(self) - -_register(pypy.ClassobjObjectFactory, classobj, in_builtin=False, - synonym='ClassType') - - -class code(object): - - def __new__(cls, *args): - if cls is code: - return pypy.CodeObjectFactory(args) - else: - return pypy.UserObjectFactory(cls, pypy.CodeObjectFactory, args) - - def __repr__(self): - return str(self) - -_register(pypy.CodeObjectFactory, code, in_builtin=False) - - -class complex(object): - - def __new__(cls, *args): - if cls is complex: - return pypy.ComplexObjectFactory(args) - else: - return pypy.UserObjectFactory(cls, pypy.ComplexObjectFactory, args) - - def __repr__(self): - return str(self) - -_register(pypy.ComplexObjectFactory, complex) - - -class dictproxy(object): - - def __new__(cls, *args): - if cls is dictproxy: - return pypy.DictproxyObjectFactory(args) - else: - return pypy.UserObjectFactory(cls, pypy.DictproxyObjectFactory, - args) - - def __repr__(self): - return str(self) - -_register(pypy.DictproxyObjectFactory, dictproxy, in_builtin=False, - synonym='DictProxyType') - - -class dict(object): - - def __new__(cls, *args): - if cls is dict: - return pypy.DictObjectFactory(args) - else: - return pypy.UserObjectFactory(cls, pypy.DictObjectFactory, args) - - def __repr__(self): - return str(self) - -# add to dict all and only those methods that used to be defined in -# objspace/std/dicttype.py, but get the implementations from the -# excellent code in UserDict.DictMixin instead (no inheritance for -# two reasons: we could not control what methods we get, and we do -# not want DictMixin among user-visible __bases__). -import UserDict -for attribute in ('update popitem get setdefault pop' - 'iteritems iterkeys itervalues').split(): - setattr(dict, attribute, UserDict.DictMixin.__dict__[attribute]) - -_register(pypy.DictObjectFactory, dict) - -setattr(_types, 'DictionaryType', dict) - - -class ellipsis(object): - - def __new__(cls, *args): - if cls is ellipsis: - return pypy.EllipsisObjectFactory(args) - else: - return pypy.UserObjectFactory(cls, pypy.EllipsisObjectFactory, args) - - def __repr__(self): - return str(self) - -_register(pypy.EllipsisObjectFactory, ellipsis, in_builtin=False) - - -class file(object): - - def __new__(cls, *args): - if cls is file: - return pypy.FileObjectFactory(args) - else: - return pypy.UserObjectFactory(cls, pypy.FileObjectFactory, args) - - def __repr__(self): - return str(self) - -_register(pypy.FileObjectFactory, file, in_builtin='open') - - -# XXX: for float as for all other classes, __new__ defers to a suitable -# factory from pypy; in floattype.py, the implementation of __new__ was -# quite differently, but we think that was not needed -- remove this -# comment once this is definitively established. -# NB: other rich implementations of __new__ from old *type.py modules -# not reproduced here: int, slice, str, tuple, type -class float(object): - - def __new__(cls, *args): - if cls is float: - return pypy.FloatObjectFactory(args) - else: - return pypy.UserObjectFactory(cls, pypy.FloatObjectFactory, args) - - def __repr__(self): - return str(self) - -_register(pypy.FloatObjectFactory, float) - - -class frame(object): - - def __new__(cls, *args): - if cls is frame: - return pypy.FrameObjectFactory(args) - else: - return pypy.UserObjectFactory(cls, pypy.FrameObjectFactory, args) - - def __repr__(self): - return str(self) - -_register(pypy.FrameObjectFactory, frame, in_builtin=False) - - -class function(object): - - def __new__(cls, *args): - if cls is function: - return pypy.FunctionObjectFactory(args) - else: - return pypy.UserObjectFactory(cls, pypy.FunctionObjectFactory, args) - - def __repr__(self): - return str(self) - - # XXX find out details for builtin properties - func_code = pypy.builtin_property('fix') - func_globals = pypy.builtin_property('me') - -_register(pypy.FunctionObjectFactory, function, in_builtin=False) - - -class generator(object): - - def __new__(cls, *args): - if cls is generator: - return pypy.GeneratorObjectFactory(args) - else: - return pypy.UserObjectFactory(cls, pypy.GeneratorObjectFactory, args) - - def __repr__(self): - return str(self) - -_register(pypy.GeneratorObjectFactory, generator, in_builtin=False) - - -class instance(object): - - def __new__(cls, *args): - if cls is instance: - return pypy.InstanceObjectFactory(args) - else: - return pypy.UserObjectFactory(cls, pypy.InstanceObjectFactory, args) - - def __repr__(self): - return str(self) - -_register(pypy.InstanceObjectFactory, instance, in_builtin=False) - - -class int(object): - - def __new__(cls, *args): - if cls is int: - return pypy.IntObjectFactory(args) - else: - return pypy.UserObjectFactory(cls, pypy.IntObjectFactory, args) - - def __repr__(self): - return str(self) - -_register(pypy.IntObjectFactory, int) - -setattr(_types, 'LambdaType', function) - - -class list(object): - - def __new__(cls, *args): - if cls is list: - return pypy.ListObjectFactory(args) - else: - return pypy.UserObjectFactory(cls, pypy.ListObjectFactory, args) - - def __repr__(self): - return str(self) - -_register(pypy.ListObjectFactory, list) - - -class long(object): - - def __new__(cls, *args): - if cls is long: - return pypy.LongObjectFactory(args) - else: - return pypy.UserObjectFactory(cls, pypy.LongObjectFactory, args) - - def __repr__(self): - return str(self) - -_register(pypy.LongObjectFactory, long) - - -class instancemethod(object): - - def __new__(cls, *args): - if cls is instancemethod: - return pypy.InstancemethodObjectFactory(args) - else: - return pypy.UserObjectFactory(cls, - pypy.InstancemethodObjectFactory, args) - - def __repr__(self): - return str(self) - -_register(pypy.InstancemethodObjectFactory, instancemethod, in_builtin=False, - synonym='MethodType') - - -class module(object): - - def __new__(cls, *args): - if cls is module: - return pypy.ModuleObjectFactory(args) - else: - return pypy.UserObjectFactory(cls, pypy.ModuleObjectFactory, args) - - def __repr__(self): - return str(self) - -_register(pypy.ModuleObjectFactory, module, in_builtin=False) - - -class NoneType(object): - - def __new__(cls, *args): - if cls is NoneType: - return pypy.NonetypeObjectFactory(args) - else: - return pypy.UserObjectFactory(cls, pypy.NonetypeObjectFactory, args) - - def __repr__(self): - return str(self) - -_register(pypy.NonetypeObjectFactory, NoneType, in_builtin=False, - synonym='NoneType') - - -class NotImplementedType(object): - - def __new__(cls, *args): - if cls is NotImplementedType: - return pypy.NotimplementedtypeObjectFactory(args) - else: - return pypy.UserObjectFactory(cls, - pypy.NotimplementedtypeObjectFactory, args) - - def __repr__(self): - return str(self) - -_register(pypy.NotimplementedtypeObjectFactory, NotImplementedType, - in_builtin=False, synonym='NotImplementedType') - - -class slice(object): - - def __new__(cls, *args): - if cls is slice: - return pypy.SliceObjectFactory(args) - else: - return pypy.UserObjectFactory(cls, pypy.SliceObjectFactory, args) - - def __repr__(self): - return str(self) - - def indices(self, length): - step = self.step - if step is None: - step = 1 - elif step == 0: - raise ValueError, "slice step cannot be zero" - if step < 0: - defstart = length - 1 - defstop = -1 - else: - defstart = 0 - defstop = length - - start = self.start - if start is None: - start = defstart - else: - if start < 0: - start += length - if start < 0: - if step < 0: - start = -1 - else: - start = 0 - elif start >= length: - if step < 0: - start = length - 1 - else: - start = length - - stop = self.stop - if stop is None: - stop = defstop - else: - if stop < 0: - stop += length - if stop < 0: - stop = -1 - elif stop > length: - stop = length - - return start, stop, step - -_register(pypy.SliceObjectFactory, slice) - - -class str(object): - - def __new__(cls, *args): - if cls is str: - return pypy.StrObjectFactory(args) - else: - return pypy.UserObjectFactory(cls, pypy.StrObjectFactory, args) - - def __repr__(self): - return str(self) - -_register(pypy.StrObjectFactory, str, synonym='StringType') - - -class traceback(object): - - def __new__(cls, *args): - if cls is traceback: - return pypy.TracebackObjectFactory(args) - else: - return pypy.UserObjectFactory(cls, pypy.TracebackObjectFactory, - args) - - def __repr__(self): - return str(self) - -_register(pypy.TracebackObjectFactory, traceback, in_builtin=False) - - -class tuple(object): - - def __new__(cls, *args): - if cls is tuple: - return pypy.TupleObjectFactory(args) - else: - return pypy.UserObjectFactory(cls, pypy.TupleObjectFactory, args) - - def __repr__(self): - return str(self) - -_register(pypy.TupleObjectFactory, tuple) - - -class type(object): - - def __new__(cls, *args): - if cls is type: - return pypy.TypeObjectFactory(args) - else: - return pypy.UserObjectFactory(cls, pypy.TypeObjectFactory, args) - - def __repr__(self): - return str(self) - -_register(pypy.TypeObjectFactory, type) - -setattr(_types, 'UnboundMethodType', instancemethod) - - -class unicode(object): - - def __new__(cls, *args): - if cls is unicode: - return pypy.UnicodeObjectFactory(args) - else: - return pypy.UserObjectFactory(cls, pypy.UnicodeObjectFactory, args) - - def __repr__(self): - return str(self) - -_register(pypy.UnicodeObjectFactory, unicode) - - -class xrange(object): - - def __new__(cls, *args): - if cls is xrange: - return pypy.XrangeObjectFactory(args) - else: - return pypy.UserObjectFactory(cls, pypy.XrangeObjectFactory, args) - - def __repr__(self): - return str(self) - -_register(pypy.XrangeObjectFactory, xrange, synonym='XRangeType') - From tismer at codespeak.net Mon Mar 21 00:09:15 2005 From: tismer at codespeak.net (tismer at codespeak.net) Date: Mon, 21 Mar 2005 00:09:15 +0100 (MET) Subject: [pypy-svn] r9965 - pypy/dist/pypy/objspace/std Message-ID: <20050320230915.E2E2B27B5C@code1.codespeak.net> Author: tismer Date: Mon Mar 21 00:09:15 2005 New Revision: 9965 Modified: pypy/dist/pypy/objspace/std/unicodeobject.py Log: added error handling for the non unrealistic case that a string cannot be converted to unicode during "contains" Modified: pypy/dist/pypy/objspace/std/unicodeobject.py ============================================================================== --- pypy/dist/pypy/objspace/std/unicodeobject.py (original) +++ pypy/dist/pypy/objspace/std/unicodeobject.py Mon Mar 21 00:09:15 2005 @@ -97,7 +97,10 @@ return space.wrap(space.unwrap(w_left) + space.unwrap(w_right)) def contains__String_Unicode(space, w_left, w_right): - return space.wrap(space.unwrap(w_right) in space.unwrap(w_left)) + try: + return space.wrap(space.unwrap(w_right) in space.unwrap(w_left)) + except: + wrap_exception(space) def contains__Unicode_Unicode(space, w_left, w_right): return space.wrap(space.unwrap(w_right) in space.unwrap(w_left)) From tismer at codespeak.net Mon Mar 21 00:10:35 2005 From: tismer at codespeak.net (tismer at codespeak.net) Date: Mon, 21 Mar 2005 00:10:35 +0100 (MET) Subject: [pypy-svn] r9966 - pypy/dist/pypy/objspace/std Message-ID: <20050320231035.5C8F127B60@code1.codespeak.net> Author: tismer Date: Mon Mar 21 00:10:35 2005 New Revision: 9966 Modified: pypy/dist/pypy/objspace/std/stringobject.py Log: made contains__String_ANY more specific by turning it into contains__String_String, because lifting would introduce unicode, which is a *very* bad idea, especially for binary stuff... Modified: pypy/dist/pypy/objspace/std/stringobject.py ============================================================================== --- pypy/dist/pypy/objspace/std/stringobject.py (original) +++ pypy/dist/pypy/objspace/std/stringobject.py Mon Mar 21 00:10:35 2005 @@ -973,7 +973,7 @@ L = [ table[ord(s[i])] for i in range(len(s)) if s[i] not in deletechars ] return ''.join(L) - def contains__String_ANY(self, sub): + def contains__String_String(self, sub): return self.find(sub) >= 0 def repr__String(s): @@ -1017,7 +1017,7 @@ str_translate__String_ANY_ANY = app.interphook('str_translate__String_ANY_ANY') str_decode__String_ANY_ANY = app.interphook('str_decode__String_ANY_ANY') mod__String_ANY = app.interphook('mod__String_ANY') -contains__String_ANY = app.interphook('contains__String_ANY') +contains__String_String = app.interphook('contains__String_String') repr__String = app.interphook('repr__String') # register all methods From hpk at codespeak.net Mon Mar 21 00:12:44 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Mon, 21 Mar 2005 00:12:44 +0100 (MET) Subject: [pypy-svn] r9967 - pypy/dist/pypy/interpreter Message-ID: <20050320231244.D6D4927B62@code1.codespeak.net> Author: hpk Date: Mon Mar 21 00:12:44 2005 New Revision: 9967 Modified: pypy/dist/pypy/interpreter/baseobjspace.py Log: don't put e.g. NoneType into builtin Modified: pypy/dist/pypy/interpreter/baseobjspace.py ============================================================================== --- pypy/dist/pypy/interpreter/baseobjspace.py (original) +++ pypy/dist/pypy/interpreter/baseobjspace.py Mon Mar 21 00:12:44 2005 @@ -73,7 +73,7 @@ # initialize with "bootstrap types" from objspace (e.g. w_None) for name, value in self.__dict__.items(): - if name.startswith('w_'): + if name.startswith('w_') and not name.endswith('Type'): name = name[2:] #print "setitem: space instance %-20s into builtins" % name self.setitem(self.builtin.w_dict, self.wrap(name), value) From briandorsey at codespeak.net Mon Mar 21 00:26:27 2005 From: briandorsey at codespeak.net (briandorsey at codespeak.net) Date: Mon, 21 Mar 2005 00:26:27 +0100 (MET) Subject: [pypy-svn] r9969 - pypy/dist/pypy/lib/test2 Message-ID: <20050320232627.CBD0B27B56@code1.codespeak.net> Author: briandorsey Date: Mon Mar 21 00:26:27 2005 New Revision: 9969 Added: pypy/dist/pypy/lib/test2/test_optparse.py - copied, changed from r9954, pypy/dist/lib-python-2.3.4/test/test_optparse.py Log: Small change in test_optparse.py - one test relied on the order of dict keys. Copied: pypy/dist/pypy/lib/test2/test_optparse.py (from r9954, pypy/dist/lib-python-2.3.4/test/test_optparse.py) ============================================================================== --- pypy/dist/lib-python-2.3.4/test/test_optparse.py (original) +++ pypy/dist/pypy/lib/test2/test_optparse.py Mon Mar 21 00:26:27 2005 @@ -164,8 +164,9 @@ "must start with --, followed by non-dash", ["---"]) + # this test originally relied on the order of dict keys. def test_attr_invalid(self): - self.assertOptionError("invalid keyword arguments: foo, bar", + self.assertOptionError("invalid keyword arguments:", ["-b"], {'foo': None, 'bar': None}) def test_action_invalid(self): From pedronis at codespeak.net Mon Mar 21 00:39:32 2005 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Mon, 21 Mar 2005 00:39:32 +0100 (MET) Subject: [pypy-svn] r9970 - pypy/dist/pypy/objspace/std Message-ID: <20050320233932.3A0E127B72@code1.codespeak.net> Author: pedronis Date: Mon Mar 21 00:39:32 2005 New Revision: 9970 Modified: pypy/dist/pypy/objspace/std/stringobject.py Log: define string contains at interp-level Modified: pypy/dist/pypy/objspace/std/stringobject.py ============================================================================== --- pypy/dist/pypy/objspace/std/stringobject.py (original) +++ pypy/dist/pypy/objspace/std/stringobject.py Mon Mar 21 00:39:32 2005 @@ -404,6 +404,10 @@ return (self, sub, start, end) +def contains__String_String(space, w_self, w_sub): + self = w_self._value + sub = w_sub._value + return space.newbool(_find(self, sub, 0, len(self), 1) >= 0) def str_find__String_String_ANY_ANY(space, w_self, w_sub, w_start, w_end): @@ -973,9 +977,6 @@ L = [ table[ord(s[i])] for i in range(len(s)) if s[i] not in deletechars ] return ''.join(L) - def contains__String_String(self, sub): - return self.find(sub) >= 0 - def repr__String(s): quote = "'" if quote in s and '"' not in s: @@ -1017,7 +1018,6 @@ str_translate__String_ANY_ANY = app.interphook('str_translate__String_ANY_ANY') str_decode__String_ANY_ANY = app.interphook('str_decode__String_ANY_ANY') mod__String_ANY = app.interphook('mod__String_ANY') -contains__String_String = app.interphook('contains__String_String') repr__String = app.interphook('repr__String') # register all methods From hpk at codespeak.net Mon Mar 21 00:48:44 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Mon, 21 Mar 2005 00:48:44 +0100 (MET) Subject: [pypy-svn] r9971 - pypy/dist/pypy/documentation/revreport Message-ID: <20050320234844.61D4427B7D@code1.codespeak.net> Author: hpk Date: Mon Mar 21 00:48:44 2005 New Revision: 9971 Modified: pypy/dist/pypy/documentation/revreport/revreport.py Log: be a bit more careful about printing stdout/stderr on non-ttys Modified: pypy/dist/pypy/documentation/revreport/revreport.py ============================================================================== --- pypy/dist/pypy/documentation/revreport/revreport.py (original) +++ pypy/dist/pypy/documentation/revreport/revreport.py Mon Mar 21 00:48:44 2005 @@ -4,21 +4,14 @@ import py from pypy.documentation.revreport import delta from pypy.tool.pypyrev import pypyrev +from py.__impl__.test.tool.outerrcapture import SimpleOutErrCapture BASE = py.path.local(delta.__file__).dirpath() DEST = BASE.join('revdata') assert DEST.dirpath().check() -if __name__ == '__main__': - rev = pypyrev() - revdir = DEST.ensure(str(rev), dir=1) - BASE.join('delta.css').copy(revdir) - BASE.join('delta.js').copy(revdir) - delta.genreport(revdir) - - print "generated into", revdir - +def updatecurrent(): l = [] for x in DEST.listdir(): try: @@ -36,3 +29,27 @@ latest.copy(current) else: current.mksymlinkto(latest) + +if __name__ == '__main__': + rev = pypyrev() + revdir = DEST.ensure(str(rev), dir=1) + BASE.join('delta.css').copy(revdir) + BASE.join('delta.js').copy(revdir) + + if py.std.sys.stdout.isatty(): + delta.genreport(revdir) + else: + capture = SimpleOutErrCapture() + try: + delta.genreport(revdir) + except: + out, err = capture.done() + print "stdout", out + print "stderr", err + raise + else: + out, err = capture.done() + print "stdout" + print out + print "generated into", revdir + updatecurrent() From tismer at codespeak.net Mon Mar 21 00:53:01 2005 From: tismer at codespeak.net (tismer at codespeak.net) Date: Mon, 21 Mar 2005 00:53:01 +0100 (MET) Subject: [pypy-svn] r9972 - pypy/dist/pypy/lib Message-ID: <20050320235301.47CEB27B84@code1.codespeak.net> Author: tismer Date: Mon Mar 21 00:53:01 2005 New Revision: 9972 Modified: pypy/dist/pypy/lib/struct.py Log: 0.0 did not work correctly. test_struct is incomplete and out of date, we are working on it. Modified: pypy/dist/pypy/lib/struct.py ============================================================================== --- pypy/dist/pypy/lib/struct.py (original) +++ pypy/dist/pypy/lib/struct.py Mon Mar 21 00:53:01 2005 @@ -34,7 +34,7 @@ The variable struct.error is an exception raised on errors.""" -import math,sys +import math, sys # TODO: XXX Find a way to get information on native sizes and alignments class StructError(Exception): @@ -60,6 +60,8 @@ bytes = [ord(b) for b in data[index:index+size]] if len(bytes) != size: raise StructError,"Not enough data to unpack" + if min(bytes) == 0: + return 0.0 if le == 'big': bytes.reverse() if size == 4: @@ -126,13 +128,15 @@ # TODO: XXX Implement checks for floats return True -def pack_float(number,size,le): +def pack_float(number, size, le): if number < 0: - sign=1 + sign = 1 number *= -1 + elif number == 0.0: + return "\x00" * size else: - sign =0 + sign = 0 if size == 4: bias = 127 exp = 8 @@ -142,7 +146,7 @@ exp = 11 prec = 52 - man,e = math.frexp(number) + man, e = math.frexp(number) if 0.5 <= man and man < 1.0: man *= 2 e -= 1 From hpk at codespeak.net Mon Mar 21 00:57:28 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Mon, 21 Mar 2005 00:57:28 +0100 (MET) Subject: [pypy-svn] r9973 - pypy/dist/pypy/documentation Message-ID: <20050320235728.6C0B527B92@code1.codespeak.net> Author: hpk Date: Mon Mar 21 00:57:28 2005 New Revision: 9973 Modified: pypy/dist/pypy/documentation/index.txt Log: let the doc index page point to the "revision report" Modified: pypy/dist/pypy/documentation/index.txt ============================================================================== --- pypy/dist/pypy/documentation/index.txt (original) +++ pypy/dist/pypy/documentation/index.txt Mon Mar 21 00:57:28 2005 @@ -15,6 +15,10 @@ provides some hands-on instructions for getting started, including a two-liner to run PyPy on your computer. + * current `revision report`_ which shows status information + about ongoing pypy development + +.. _`revision report`: http://codespeak.net/pypy/rev/current Before doing pypy coding, you might also take a look at these developer-specific instructions: From ac at codespeak.net Mon Mar 21 01:02:05 2005 From: ac at codespeak.net (ac at codespeak.net) Date: Mon, 21 Mar 2005 01:02:05 +0100 (MET) Subject: [pypy-svn] r9974 - pypy/dist/pypy/interpreter Message-ID: <20050321000205.C69A727B96@code1.codespeak.net> Author: ac Date: Mon Mar 21 01:02:05 2005 New Revision: 9974 Modified: pypy/dist/pypy/interpreter/executioncontext.py pypy/dist/pypy/interpreter/pyframe.py Log: Working settrace() except for assigning to frame.f_lineno. Modified: pypy/dist/pypy/interpreter/executioncontext.py ============================================================================== --- pypy/dist/pypy/interpreter/executioncontext.py (original) +++ pypy/dist/pypy/interpreter/executioncontext.py Mon Mar 21 01:02:05 2005 @@ -59,42 +59,56 @@ "Trace function called before each bytecode." if self.is_tracing or frame.w_f_trace is None: return - + code = getattr(frame, 'code') + doTrace = code.co_name == 'arigo_example XXX' + if doTrace: + print frame.instr_lb, frame.last_instr, frame.instr_ub + if not hasattr(self, 'dumpedLineno'): + self.dumpedLineno = None + l = 0 + a = 0 + for i in range(0, len(code.co_lnotab),2): + print 'Line %3d: %3d'%(l, a) + a += ord(code.co_lnotab[i]) + l += ord(code.co_lnotab[i+1]) + print 'Line %3d: %3d'%(l, a) if frame.instr_lb <= frame.last_instr < frame.instr_ub: return - code = getattr(frame, 'code') - size = len(code.co_lnotab) / 2 addr = 0 line = code.co_firstlineno - p = iter(code.co_lnotab) - + p = 0 + lineno = code.co_lnotab while size > 0: - c = ord(p.next()) + c = ord(lineno[p]) if (addr + c) > frame.last_instr: break addr += c if c: frame.instr_lb = addr - c = ord(p.next()) - line += c + line += ord(lineno[p + 1]) + p += 2 size -= 1 - + if addr == frame.last_instr: frame.f_lineno = line + if doTrace: + print 'At line', line - code.co_firstlineno, 'addr', addr self._trace(frame, 'line', self.space.w_None) + elif doTrace: + print 'Skipping line', line - code.co_firstlineno, 'addr', addr if size > 0: - size -= 1 - while size >= 0: - - c = ord(p.next()) - addr += c - if c: + while True: + size -= 1 + if size < 0: break - + addr += ord(lineno[p]) + if ord(lineno[p + 1]): + break + p += 2 frame.instr_ub = addr else: frame.instr_ub = sys.maxint @@ -139,6 +153,10 @@ w_callback = frame.w_f_trace if self.is_tracing or w_callback is None: return + # To get better results when running test_trace.py + #if frame.code.co_filename.find('/lib-python-2.3.4/') <0: + # print 'Skipping', event, frame.code.co_name + # return self.is_tracing += 1 try: try: Modified: pypy/dist/pypy/interpreter/pyframe.py ============================================================================== --- pypy/dist/pypy/interpreter/pyframe.py (original) +++ pypy/dist/pypy/interpreter/pyframe.py Mon Mar 21 01:02:05 2005 @@ -178,8 +178,11 @@ def fset_f_trace(space, w_self, w_trace): self = space.interpclass_w(w_self) - self.w_f_trace = w_trace - + if space.is_true(space.is_(w_trace, space.w_None)): + self.w_f_trace = None + else: + self.w_f_trace = w_trace + self.f_lineno = self.get_last_lineno() ### Frame Blocks ### class FrameBlock: From hpk at codespeak.net Mon Mar 21 01:09:45 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Mon, 21 Mar 2005 01:09:45 +0100 (MET) Subject: [pypy-svn] r9975 - in pypy/dist/pypy/documentation: . revreport Message-ID: <20050321000945.30F5C27B85@code1.codespeak.net> Author: hpk Date: Mon Mar 21 01:09:45 2005 New Revision: 9975 Modified: pypy/dist/pypy/documentation/architecture.txt pypy/dist/pypy/documentation/index.txt pypy/dist/pypy/documentation/revreport/revreport.py Log: fix documentation, make the index page nicer try to improve revreports Modified: pypy/dist/pypy/documentation/architecture.txt ============================================================================== --- pypy/dist/pypy/documentation/architecture.txt (original) +++ pypy/dist/pypy/documentation/architecture.txt Mon Mar 21 01:09:45 2005 @@ -1,4 +1,4 @@ -Overview on PyPy's current architecture (Mar. 2004) +Overview on PyPy's current architecture (Mar. 2005) =================================================== Modified: pypy/dist/pypy/documentation/index.txt ============================================================================== --- pypy/dist/pypy/documentation/index.txt (original) +++ pypy/dist/pypy/documentation/index.txt Mon Mar 21 01:09:45 2005 @@ -2,44 +2,39 @@ PyPy - a Python_ implementation written in Python ================================================= -recently-modified_ .. _Python: http://www.python.org/dev/doc/maint24/ref/ref.html Here are some good entry points into PyPy's world: - * architecture_: - a technical overview of PyPy's current architecture + * PyPy's current architecture_ - * howtopypy_: - provides some hands-on instructions for getting started, - including a two-liner to run PyPy on your computer. + * howtopypy_ provides some hands-on instructions for getting started, + including a two-liner to run PyPy on your computer. - * current `revision report`_ which shows status information + * the current `revision report`_ shows status information about ongoing pypy development + * go to recently-modified_ for an overview on which documentation + changed recently + .. _`revision report`: http://codespeak.net/pypy/rev/current Before doing pypy coding, you might also take a look at these developer-specific instructions: - * coding-style_: - covers pypy coding conventions + * coding-style_ covers pypy coding conventions + + * optionaltool_ describes some optional tools used in pypy development + + * wrapping_ is a description of the crucial distinction between + application-level and interpreter-level objects (without understanding + this you might have difficulties understanding PyPy's source code). - * optionaltool_: - there are some optional tools we use for pypy. + * oscon2003-paper_ is a paper we presented at Oscon 2003 describing + what the pypy project is about and why you should care - * wrapping_: - a description of the crucial distinction between application-level and - interpreter-level objects (without understanding this you might - have difficulties understanding PyPy's source code). - - * oscon2003-paper_: - presentation to OSCON on what pypy is about and why you should care - - * testdesign_: - pypy is a test-driven development project. Read here to find out - more about how we're doing testing. + * testdesign_ describes a bit of PyPy's testing approaches Further reading / related projects ---------------------------------- Modified: pypy/dist/pypy/documentation/revreport/revreport.py ============================================================================== --- pypy/dist/pypy/documentation/revreport/revreport.py (original) +++ pypy/dist/pypy/documentation/revreport/revreport.py Mon Mar 21 01:09:45 2005 @@ -36,7 +36,7 @@ BASE.join('delta.css').copy(revdir) BASE.join('delta.js').copy(revdir) - if py.std.sys.stdout.isatty(): + if 1 or py.std.sys.stdout.isatty(): delta.genreport(revdir) else: capture = SimpleOutErrCapture() From arigo at codespeak.net Mon Mar 21 01:18:41 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 21 Mar 2005 01:18:41 +0100 (MET) Subject: [pypy-svn] r9977 - pypy/dist/pypy/interpreter Message-ID: <20050321001841.1EFEB27BA2@code1.codespeak.net> Author: arigo Date: Mon Mar 21 01:18:40 2005 New Revision: 9977 Modified: pypy/dist/pypy/interpreter/interactive.py Log: Handle "SystemExit().code" and set sys.last_{type, value, traceback}. Modified: pypy/dist/pypy/interpreter/interactive.py ============================================================================== --- pypy/dist/pypy/interpreter/interactive.py (original) +++ pypy/dist/pypy/interpreter/interactive.py Mon Mar 21 01:18:40 2005 @@ -66,10 +66,29 @@ pycode.exec_code(self.space, self.w_globals, self.w_globals) except error.OperationError, operationerr: space = self.space - if operationerr.match(space, space.w_SystemExit): - # XXX fetch the exit code from somewhere inside the w_SystemExit - raise SystemExit - # XXX insert exception info into the application-level sys.last_xxx + try: + if operationerr.match(space, space.w_SystemExit): + w_exitcode = space.getattr(operationerr.w_value, + space.wrap('code')) + if space.is_w(w_exitcode, space.w_None): + exitcode = 0 + else: + try: + exitcode = space.int_w(w_exitcode) + except error.OperationError: + # not an integer: print it to stderr + msg = space.str_w(space.str(w_exitcode)) + print >> sys.stderr, msg + exitcode = 1 + raise SystemExit(exitcode) + space.setitem(space.sys.w_dict, space.wrap('last_type'), + operationerr.w_type) + space.setitem(space.sys.w_dict, space.wrap('last_value'), + operationerr.w_value) + space.setitem(space.sys.w_dict, space.wrap('last_traceback'), + space.wrap(operationerr.application_traceback)) + except error.OperationError, operationerr: + pass # let the code below print any error we get above if self.verbose: operationerr.print_detailed_traceback(space) else: From hpk at codespeak.net Mon Mar 21 01:21:15 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Mon, 21 Mar 2005 01:21:15 +0100 (MET) Subject: [pypy-svn] r9978 - pypy/dist/pypy/documentation/revreport Message-ID: <20050321002115.DA14327BA7@code1.codespeak.net> Author: hpk Date: Mon Mar 21 01:21:15 2005 New Revision: 9978 Modified: pypy/dist/pypy/documentation/revreport/revreport.py Log: another try to get the revreports work nicely in non-tty situations Modified: pypy/dist/pypy/documentation/revreport/revreport.py ============================================================================== --- pypy/dist/pypy/documentation/revreport/revreport.py (original) +++ pypy/dist/pypy/documentation/revreport/revreport.py Mon Mar 21 01:21:15 2005 @@ -36,19 +36,19 @@ BASE.join('delta.css').copy(revdir) BASE.join('delta.js').copy(revdir) - if 1 or py.std.sys.stdout.isatty(): + if py.std.sys.stdout.isatty(): delta.genreport(revdir) else: capture = SimpleOutErrCapture() try: delta.genreport(revdir) except: - out, err = capture.done() + out, err = capture.reset() print "stdout", out print "stderr", err raise else: - out, err = capture.done() + out, err = capture.reset() print "stdout" print out print "generated into", revdir From tismer at codespeak.net Mon Mar 21 02:18:34 2005 From: tismer at codespeak.net (tismer at codespeak.net) Date: Mon, 21 Mar 2005 02:18:34 +0100 (MET) Subject: [pypy-svn] r9979 - pypy/dist/pypy/objspace/std/test Message-ID: <20050321011834.2FD1827BBA@code1.codespeak.net> Author: tismer Date: Mon Mar 21 02:18:34 2005 New Revision: 9979 Modified: pypy/dist/pypy/objspace/std/test/test_userobject.py Log: added test for userobject's base really being the subclassed type Modified: pypy/dist/pypy/objspace/std/test/test_userobject.py ============================================================================== --- pypy/dist/pypy/objspace/std/test/test_userobject.py (original) +++ pypy/dist/pypy/objspace/std/test/test_userobject.py Mon Mar 21 02:18:34 2005 @@ -35,6 +35,7 @@ raise else: assert isinstance(stuff, base) + assert subclass.__base__ is base def test_subclasstuple(self): class subclass(tuple): pass From arigo at codespeak.net Mon Mar 21 02:29:58 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 21 Mar 2005 02:29:58 +0100 (MET) Subject: [pypy-svn] r9980 - pypy/dist/pypy/objspace/std Message-ID: <20050321012958.90F3627BBF@code1.codespeak.net> Author: arigo Date: Mon Mar 21 02:29:58 2005 New Revision: 9980 Modified: pypy/dist/pypy/objspace/std/typeobject.py pypy/dist/pypy/objspace/std/typetype.py Log: Fix the __base__ attribute of types. Modified: pypy/dist/pypy/objspace/std/typeobject.py ============================================================================== --- pypy/dist/pypy/objspace/std/typeobject.py (original) +++ pypy/dist/pypy/objspace/std/typeobject.py Mon Mar 21 02:29:58 2005 @@ -20,11 +20,14 @@ w_self.dict_w = dict_w w_self.ensure_static__new__() w_self.nslots = 0 + w_self.w_bestbase = None if overridetypedef is not None: w_self.instancetypedef = overridetypedef w_self.hasdict = overridetypedef.hasdict w_self.w__flags__ = space.wrap(0) # not a heaptype + if overridetypedef.base is not None: + w_self.w_bestbase = space.gettypeobject(overridetypedef.base) else: w_self.w__flags__ = space.wrap(_HEAPTYPE) # find the most specific typedef @@ -33,7 +36,9 @@ if not space.is_true(space.isinstance(w_base, space.w_type)): continue if issubtypedef(w_base.instancetypedef, instancetypedef): - instancetypedef = w_base.instancetypedef + if instancetypedef is not w_base.instancetypedef: + instancetypedef = w_base.instancetypedef + w_self.w_bestbase = w_base elif not issubtypedef(instancetypedef, w_base.instancetypedef): raise OperationError(space.w_TypeError, space.wrap("instance layout conflicts in " @@ -64,6 +69,7 @@ w_self.hasdict = w_self.hasdict or w_base.hasdict if w_most_derived_base_with_slots: nslots = w_most_derived_base_with_slots.nslots + self.w_bestbase = w_most_derived_base_with_slots else: nslots = 0 Modified: pypy/dist/pypy/objspace/std/typetype.py ============================================================================== --- pypy/dist/pypy/objspace/std/typetype.py (original) +++ pypy/dist/pypy/objspace/std/typetype.py Mon Mar 21 02:29:58 2005 @@ -73,13 +73,12 @@ def descr__base(space, w_type): w_type = _check(space, w_type) - if w_type is space.w_object: - return space.w_None - b = w_type.instancetypedef.base - if b is not None: - return space.gettypeobject(b) - else: + if w_type.w_bestbase is not None: + return w_type.w_bestbase + elif w_type is not space.w_object: return space.w_object + else: + return space.w_None def descr__doc(space, w_type): w_type = _check(space, w_type) From tismer at codespeak.net Mon Mar 21 04:23:05 2005 From: tismer at codespeak.net (tismer at codespeak.net) Date: Mon, 21 Mar 2005 04:23:05 +0100 (MET) Subject: [pypy-svn] r9981 - pypy/dist/pypy/module/builtin Message-ID: <20050321032305.9808B27B9C@code1.codespeak.net> Author: tismer Date: Mon Mar 21 04:23:05 2005 New Revision: 9981 Modified: pypy/dist/pypy/module/builtin/app_complex.py Log: augmented complex a little to become subclassable for test_pickle. For that reason, it could not inheritfrom object, or it would not grow a __base__other than object. Do we want to special-case this in typeobject? Modified: pypy/dist/pypy/module/builtin/app_complex.py ============================================================================== --- pypy/dist/pypy/module/builtin/app_complex.py (original) +++ pypy/dist/pypy/module/builtin/app_complex.py Mon Mar 21 04:23:05 2005 @@ -2,7 +2,15 @@ Plain Python definition of the 'complex' type. """ -class complex(object): +# XXX this has been object before, +# but we need something different, or +# the __base__ will never become different from object. +# note that this is real Python behavior :-) + +# XXX would be eventually try tospecial-case this +# in typeobject to be handled as a base class? + +class complex(float): """complex(real[, imag]) -> complex number Create a complex number from a real part and an optional imaginary part. @@ -12,6 +20,14 @@ # XXX this class is not well tested + # provide __new__to prevend the default which has no parameters + def __new__(typ, *args, **kwds): + ret = float.__new__(typ) + return ret + + def __reduce__(self): + return self.__class__, (), self.__dict__ + def __init__(self, real=0.0, imag=None): if isinstance(real, str): if imag is not None: @@ -40,8 +56,9 @@ def __setattr__(self, name, value): if name in ('real', 'imag'): raise AttributeError, "readonly attribute" - else: + elif self.__class__ is complex: raise AttributeError, "'complex' object has no attribute %s" % name + self.__dict__[name] = value def _makeComplexFromString(self, string): import re From rxe at codespeak.net Mon Mar 21 15:36:55 2005 From: rxe at codespeak.net (rxe at codespeak.net) Date: Mon, 21 Mar 2005 15:36:55 +0100 (MET) Subject: [pypy-svn] r9985 - pypy/dist/pypy/interpreter Message-ID: <20050321143655.302D127BDF@code1.codespeak.net> Author: rxe Date: Mon Mar 21 15:36:55 2005 New Revision: 9985 Modified: pypy/dist/pypy/interpreter/executioncontext.py pypy/dist/pypy/interpreter/gateway.py pypy/dist/pypy/interpreter/miscutils.py pypy/dist/pypy/interpreter/pycode.py Log: Added applevel to code objects, to identity code which will be translated wasy (such as exception code) to hide these unexpectedly appearing in settrace() when running in CPython. Modified: pypy/dist/pypy/interpreter/executioncontext.py ============================================================================== --- pypy/dist/pypy/interpreter/executioncontext.py (original) +++ pypy/dist/pypy/interpreter/executioncontext.py Mon Mar 21 15:36:55 2005 @@ -21,10 +21,14 @@ locals = getthreadlocals() previous_ec = locals.executioncontext locals.executioncontext = self - if self.framestack.empty(): - frame.f_back = None + + for ff in self.framestack: + if not frame.code.getapplevel(): + frame.f_back = ff + break else: - frame.f_back = self.framestack.top() + frame.f_back = None + self.framestack.push(frame) return previous_ec @@ -147,6 +151,9 @@ self.w_tracefunc = w_func def _trace(self, frame, event, w_arg): + if frame.code.getapplevel(): + return + if event == 'call': w_callback = self.w_tracefunc else: Modified: pypy/dist/pypy/interpreter/gateway.py ============================================================================== --- pypy/dist/pypy/interpreter/gateway.py (original) +++ pypy/dist/pypy/interpreter/gateway.py Mon Mar 21 15:36:55 2005 @@ -493,7 +493,7 @@ self.code = py.code.Source(source).compile() else: self.code = compile(source, filename, 'exec') - + def getwdict(self, space): return space.loadfromcache(self, applevel._builddict, space._gatewaycache) @@ -504,8 +504,11 @@ def _builddict(self, space): "NOT_RPYTHON" + + from pypy.interpreter.pycode import PyCode + code = PyCode(space)._from_code(self.code, applevel=True) w_glob = space.newdict([]) - space.exec_(self.code, w_glob, w_glob) + space.exec_(code, w_glob, w_glob) return w_glob def wget(self, space, name): Modified: pypy/dist/pypy/interpreter/miscutils.py ============================================================================== --- pypy/dist/pypy/interpreter/miscutils.py (original) +++ pypy/dist/pypy/interpreter/miscutils.py Mon Mar 21 15:36:55 2005 @@ -42,6 +42,10 @@ def empty(self): return not self.items + def __iter__(self): + # Walk the stack backwards + for ii in self.items[::-1]: + yield ii class InitializedClass(type): """NOT_RPYTHON. A meta-class that allows a class to initialize itself (or Modified: pypy/dist/pypy/interpreter/pycode.py ============================================================================== --- pypy/dist/pypy/interpreter/pycode.py (original) +++ pypy/dist/pypy/interpreter/pycode.py Mon Mar 21 15:36:55 2005 @@ -96,13 +96,15 @@ #self.co_name (in base class)# string: name, for reference self.co_firstlineno = 0 # first source line number self.co_lnotab = "" # string: encoding addr<->lineno mapping + self.applevel = False - def _from_code(self, code): + def _from_code(self, code, applevel=False): """ Initialize the code object from a real (CPython) one. This is just a hack, until we have our own compile. At the moment, we just fake this. This method is called by our compile builtin function. """ + self.applevel = applevel import types assert isinstance(code, types.CodeType) # simply try to suck in all attributes we know of @@ -140,7 +142,7 @@ newconsts_w = [] for const in code.co_consts: if isinstance(const, types.CodeType): - const = PyCode(space)._from_code(const) + const = PyCode(space)._from_code(const, applevel=applevel) newconsts_w.append(space.wrap(const)) self.co_consts_w = newconsts_w return self @@ -160,6 +162,9 @@ signature = cpython_code_signature + def getapplevel(self): + return self.applevel + def getvarnames(self): return self.co_varnames From hpk at codespeak.net Mon Mar 21 15:47:55 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Mon, 21 Mar 2005 15:47:55 +0100 (MET) Subject: [pypy-svn] r9986 - pypy/dist/pypy/lib/test2 Message-ID: <20050321144755.883F727BE6@code1.codespeak.net> Author: hpk Date: Mon Mar 21 15:47:55 2005 New Revision: 9986 Removed: pypy/dist/pypy/lib/test2/test_sys.py Log: original 2.3.4 test_sys.py passes, removing our hacked version Deleted: /pypy/dist/pypy/lib/test2/test_sys.py ============================================================================== --- /pypy/dist/pypy/lib/test2/test_sys.py Mon Mar 21 15:47:55 2005 +++ (empty file) @@ -1,256 +0,0 @@ -# -*- coding: iso-8859-1 -*- -import unittest, test.test_support -import sys, cStringIO - -class SysModuleTest(unittest.TestCase): - - def test_original_displayhook(self): - import __builtin__ - savestdout = sys.stdout - out = cStringIO.StringIO() - sys.stdout = out - - dh = sys.__displayhook__ - - self.assertRaises(TypeError, dh) - if hasattr(__builtin__, "_"): - del __builtin__._ - - dh(None) - self.assertEqual(out.getvalue(), "") - self.assert_(not hasattr(__builtin__, "_")) - dh(42) - self.assertEqual(out.getvalue(), "42\n") - self.assertEqual(__builtin__._, 42) - - del sys.stdout - self.assertRaises(RuntimeError, dh, 42) - - sys.stdout = savestdout - - def test_lost_displayhook(self): - olddisplayhook = sys.displayhook - del sys.displayhook - code = compile("42", "", "single") - self.assertRaises(RuntimeError, eval, code) - sys.displayhook = olddisplayhook - - def test_custom_displayhook(self): - olddisplayhook = sys.displayhook - def baddisplayhook(obj): - raise ValueError - sys.displayhook = baddisplayhook - code = compile("42", "", "single") - self.assertRaises(ValueError, eval, code) - sys.displayhook = olddisplayhook - - def test_original_excepthook(self): - savestderr = sys.stderr - err = cStringIO.StringIO() - sys.stderr = err - - eh = sys.__excepthook__ - - self.assertRaises(TypeError, eh) - try: - raise ValueError(42) - except ValueError, exc: - eh(*sys.exc_info()) - - sys.stderr = savestderr - self.assert_(err.getvalue().endswith("ValueError: 42\n")) - - # FIXME: testing the code for a lost or replaced excepthook in - # Python/pythonrun.c::PyErr_PrintEx() is tricky. - - def test_exc_clear(self): - self.assertRaises(TypeError, sys.exc_clear, 42) - - # Verify that exc_info is present and matches exc, then clear it, and - # check that it worked. - def clear_check(exc): - typ, value, traceback = sys.exc_info() - self.assert_(typ is not None) - self.assert_(value is exc) - self.assert_(traceback is not None) - - sys.exc_clear() - - typ, value, traceback = sys.exc_info() - self.assert_(typ is None) - self.assert_(value is None) - self.assert_(traceback is None) - - def clear(): - try: - raise ValueError, 42 - except ValueError, exc: - clear_check(exc) - - # Raise an exception and check that it can be cleared - clear() - - # Verify that a frame currently handling an exception is - # unaffected by calling exc_clear in a nested frame. - try: - raise ValueError, 13 - except ValueError, exc: - typ1, value1, traceback1 = sys.exc_info() - clear() - typ2, value2, traceback2 = sys.exc_info() - - self.assert_(typ1 is typ2) - self.assert_(value1 is exc) - self.assert_(value1 is value2) - self.assert_(traceback1 is traceback2) - - # Check that an exception can be cleared outside of an except block - clear_check(exc) - - def test_exit(self): - self.assertRaises(TypeError, sys.exit, 42, 42) - - # call without argument - try: - sys.exit(0) - except SystemExit, exc: - self.assertEquals(exc.code, 0) - except: - self.fail("wrong exception") - else: - self.fail("no exception") - - # call with tuple argument with one entry - # entry will be unpacked - try: - sys.exit(42) - except SystemExit, exc: - self.assertEquals(exc.code, 42) - except: - self.fail("wrong exception") - else: - self.fail("no exception") - - # call with integer argument - try: - sys.exit((42,)) - except SystemExit, exc: - self.assertEquals(exc.code, 42) - except: - self.fail("wrong exception") - else: - self.fail("no exception") - - # call with string argument - try: - sys.exit("exit") - except SystemExit, exc: - self.assertEquals(exc.code, "exit") - except: - self.fail("wrong exception") - else: - self.fail("no exception") - - # call with tuple argument with two entries - try: - sys.exit((17, 23)) - except SystemExit, exc: - self.assertEquals(exc.code, (17, 23)) - except: - self.fail("wrong exception") - else: - self.fail("no exception") - - def test_getdefaultencoding(self): - if test.test_support.have_unicode: - self.assertRaises(TypeError, sys.getdefaultencoding, 42) - # can't check more than the type, as the user might have changed it - self.assert_(isinstance(sys.getdefaultencoding(), str)) - - # testing sys.settrace() is done in test_trace.py - # testing sys.setprofile() is done in test_profile.py - - def test_setcheckinterval(self): - self.assertRaises(TypeError, sys.setcheckinterval) - orig = sys.getcheckinterval() - for n in 0, 100, 120, orig: # orig last to restore starting state - sys.setcheckinterval(n) - self.assertEquals(sys.getcheckinterval(), n) - - def test_recursionlimit(self): - self.assertRaises(TypeError, sys.getrecursionlimit, 42) - oldlimit = sys.getrecursionlimit() - self.assertRaises(TypeError, sys.setrecursionlimit) - self.assertRaises(ValueError, sys.setrecursionlimit, -42) - sys.setrecursionlimit(10000) - self.assertEqual(sys.getrecursionlimit(), 10000) - sys.setrecursionlimit(oldlimit) - - def test_getwindowsversion(self): - if hasattr(sys, "getwindowsversion"): - v = sys.getwindowsversion() - self.assert_(isinstance(v, tuple)) - self.assertEqual(len(v), 5) - self.assert_(isinstance(v[0], int)) - self.assert_(isinstance(v[1], int)) - self.assert_(isinstance(v[2], int)) - self.assert_(isinstance(v[3], int)) - self.assert_(isinstance(v[4], str)) - - def test_dlopenflags(self): - if hasattr(sys, "setdlopenflags"): - self.assert_(hasattr(sys, "getdlopenflags")) - self.assertRaises(TypeError, sys.getdlopenflags, 42) - oldflags = sys.getdlopenflags() - self.assertRaises(TypeError, sys.setdlopenflags) - sys.setdlopenflags(oldflags+1) - self.assertEqual(sys.getdlopenflags(), oldflags+1) - sys.setdlopenflags(oldflags) - - def test_refcount(self): - if hasattr(sys, 'getrefcount'): - self.assertRaises(TypeError, sys.getrefcount) - c = sys.getrefcount(None) - n = None - self.assertEqual(sys.getrefcount(None), c+1) - del n - self.assertEqual(sys.getrefcount(None), c) - if hasattr(sys, "gettotalrefcount"): - self.assert_(isinstance(sys.gettotalrefcount(), int)) - - def test_getframe(self): - self.assertRaises(TypeError, sys._getframe, 42, 42) - self.assertRaises(ValueError, sys._getframe, 2000000000) - self.assert_( - SysModuleTest.test_getframe.im_func.func_code \ - is sys._getframe().f_code - ) - - def test_attributes(self): - self.assert_(isinstance(sys.api_version, int)) - self.assert_(isinstance(sys.argv, list)) - self.assert_(sys.byteorder in ("little", "big")) - self.assert_(isinstance(sys.builtin_module_names, tuple)) - self.assert_(isinstance(sys.copyright, basestring)) - self.assert_(isinstance(sys.exec_prefix, basestring)) - self.assert_(isinstance(sys.executable, basestring)) - self.assert_(isinstance(sys.hexversion, int)) - self.assert_(isinstance(sys.maxint, int)) - self.assert_(isinstance(sys.maxunicode, int)) - self.assert_(isinstance(sys.platform, basestring)) - self.assert_(isinstance(sys.prefix, basestring)) - self.assert_(isinstance(sys.version, basestring)) - vi = sys.version_info - self.assert_(isinstance(vi, tuple)) - self.assertEqual(len(vi), 5) - self.assert_(isinstance(vi[0], int)) - self.assert_(isinstance(vi[1], int)) - self.assert_(isinstance(vi[2], int)) - self.assert_(vi[3] in ("alpha", "beta", "candidate", "final")) - self.assert_(isinstance(vi[4], int)) - -def test_main(): - test.test_support.run_unittest(SysModuleTest) - -if __name__ == "__main__": - test_main() From hpk at codespeak.net Mon Mar 21 15:50:52 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Mon, 21 Mar 2005 15:50:52 +0100 (MET) Subject: [pypy-svn] r9987 - pypy/dist/pypy/objspace/std Message-ID: <20050321145052.BB19A27BEA@code1.codespeak.net> Author: hpk Date: Mon Mar 21 15:50:52 2005 New Revision: 9987 Modified: pypy/dist/pypy/objspace/std/typeobject.py Log: fix typo unconvererd by test_builtin.py Modified: pypy/dist/pypy/objspace/std/typeobject.py ============================================================================== --- pypy/dist/pypy/objspace/std/typeobject.py (original) +++ pypy/dist/pypy/objspace/std/typeobject.py Mon Mar 21 15:50:52 2005 @@ -69,7 +69,7 @@ w_self.hasdict = w_self.hasdict or w_base.hasdict if w_most_derived_base_with_slots: nslots = w_most_derived_base_with_slots.nslots - self.w_bestbase = w_most_derived_base_with_slots + w_self.w_bestbase = w_most_derived_base_with_slots else: nslots = 0 From hpk at codespeak.net Mon Mar 21 15:54:25 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Mon, 21 Mar 2005 15:54:25 +0100 (MET) Subject: [pypy-svn] r9988 - pypy/dist/pypy/lib/test2 Message-ID: <20050321145425.605B527BF0@code1.codespeak.net> Author: hpk Date: Mon Mar 21 15:54:25 2005 New Revision: 9988 Removed: pypy/dist/pypy/lib/test2/builtin_functions_test.py Log: the original test_builtin.py regrtest works these days ... Deleted: /pypy/dist/pypy/lib/test2/builtin_functions_test.py ============================================================================== --- /pypy/dist/pypy/lib/test2/builtin_functions_test.py Mon Mar 21 15:54:25 2005 +++ (empty file) @@ -1,1234 +0,0 @@ -# Python test set -- built-in functions -import autopath -from pypy.interpreter.gateway import app2interp_temp - -def app_init_globals(): - ''' support functionality for these tests ''' - import __builtin__ as b - - from sets import Set - from support_tests import fcmp, have_unicode, TESTFN, unlink - - if not have_unicode: - b.basestring = str - - import sys, cStringIO - - class Squares: - - def __init__(self, max): - self.max = max - self.sofar = [] - - def __len__(self): return len(self.sofar) - - def __getitem__(self, i): - if not 0 <= i < self.max: raise IndexError - n = len(self.sofar) - while n <= i: - self.sofar.append(n*n) - n += 1 - return self.sofar[i] - - class StrSquares: - - def __init__(self, max): - self.max = max - self.sofar = [] - - def __len__(self): - return len(self.sofar) - - def __getitem__(self, i): - if not 0 <= i < self.max: - raise IndexError - n = len(self.sofar) - while n <= i: - self.sofar.append(str(n*n)) - n += 1 - return self.sofar[i] - - class BitBucket: - def write(self, line): - pass - - L = [ - ('0', 0), - ('1', 1), - ('9', 9), - ('10', 10), - ('99', 99), - ('100', 100), - ('314', 314), - (' 314', 314), - ('314 ', 314), - (' \t\t 314 \t\t ', 314), - (`sys.maxint`, sys.maxint), - (' 1x', ValueError), - (' 1 ', 1), - (' 1\02 ', ValueError), - ('', ValueError), - (' ', ValueError), - (' \t\t ', ValueError) - ] - if have_unicode: - L += [ - (unicode('0'), 0), - (unicode('1'), 1), - (unicode('9'), 9), - (unicode('10'), 10), - (unicode('99'), 99), - (unicode('100'), 100), - (unicode('314'), 314), - (unicode(' 314'), 314), - (unicode('\u0663\u0661\u0664 ','raw-unicode-escape'), 314), - (unicode(' \t\t 314 \t\t '), 314), - (unicode(' 1x'), ValueError), - (unicode(' 1 '), 1), - (unicode(' 1\02 '), ValueError), - (unicode(''), ValueError), - (unicode(' '), ValueError), - (unicode(' \t\t '), ValueError), - (unichr(0x200), ValueError), - ] - b.Set = Set - b.fcmp = fcmp - b.have_unicode = have_unicode - b.TESTFN = TESTFN - b.unlink = unlink - b.sys = sys - b.cStringIO = cStringIO - b.Squares = Squares - b.StrSquares = StrSquares - b.BitBucket = BitBucket - b.L = L - - -class AppTestBuiltin: - objspacename = 'std' - - full_test = 1 - - def setup_class(cls): - app2interp_temp(app_init_globals)(cls.space) - - # we use "if 1:" to keep all method definitions indented, making - # it maximally easy to edit this file to pick and choose which - # ones to run (running everything takes 4 minutes or so...) - if 1: - def test_import(self): - __import__('sys') - __import__('time') - __import__('string') - raises(ImportError, __import__, 'spamspam') - raises(TypeError, __import__, 1, 2, 3, 4) - - def test_abs(self): - # int - assert abs(0) == 0 - assert abs(1234) == 1234 - assert abs(-1234) == 1234 - # float - assert abs(0.0) == 0.0 - assert abs(3.14) == 3.14 - assert abs(-3.14) == 3.14 - # long - assert abs(0L) == 0L - assert abs(1234L) == 1234L - assert abs(-1234L) == 1234L - # str - raises(TypeError, abs, 'a') - - def test_apply(self): - def f0(*args): - assert args == () - def f1(a1): - assert a1 == 1 - def f2(a1, a2): - assert a1 == 1 - assert a2 == 2 - def f3(a1, a2, a3): - assert a1 == 1 - assert a2 == 2 - assert a3 == 3 - apply(f0, ()) - apply(f1, (1,)) - apply(f2, (1, 2)) - apply(f3, (1, 2, 3)) - - # A PyCFunction that takes only positional parameters should allow - # an empty keyword dictionary to pass without a complaint, but - # raise a TypeError if the dictionary is non-empty. - apply(id, (1,), {}) - raises(TypeError, apply, id, (1,), {"foo": 1}) - raises(TypeError, apply) - raises(TypeError, apply, id, 42) - raises(TypeError, apply, id, (42,), 42) - - def test_callable(self): - assert callable(len) - def f(): pass - assert callable(f) - class C: - def meth(self): pass - assert callable(C) - x = C() - assert callable(x.meth) - assert not callable(x) - class D(C): - def __call__(self): pass - y = D() - assert callable(y) - y() - - def test_chr(self): - assert chr(32) == ' ' - assert chr(65) == 'A' - assert chr(97) == 'a' - assert chr(0xff) == '\xff' - raises(ValueError, chr, 256) - raises(TypeError, chr) - - def test_cmp(self): - assert cmp(-1, 1) == -1 - assert cmp(1, -1) == 1 - assert cmp(1, 1) == 0 - ''' TODO XXX Circular objects not handled yet - # verify that circular objects are handled - a = []; a.append(a) - b = []; b.append(b) - from UserList import UserList - c = UserList(); c.append(c) - assert cmp(a, b) == 0 - assert cmp(b, c) == 0 - assert cmp(c, a) == 0 - assert cmp(a, c) == 0 - # okay, now break the cycles - a.pop(); b.pop(); c.pop() - ''' - raises(TypeError, cmp) - - ''' TODO: XXX Coerce is not implemented - def test_coerce(self): - assert not fcmp(coerce(1, 1.1), (1.0, 1.1)) - assert coerce(1, 1L) == (1L, 1L) - assert not fcmp(coerce(1L, 1.1), (1.0, 1.1)) - raises(TypeError, coerce) - class BadNumber: - def __coerce__(self, other): - raise ValueError - raises(ValueError, coerce, 42, BadNumber()) - raises(OverflowError, coerce, 0.5, int("12345" * 1000)) - ''' - - def test_compile(self): - compile('print 1\n', '', 'exec') - bom = '\xef\xbb\xbf' - compile(bom + 'print 1\n', '', 'exec') - raises(TypeError, compile) - raises(ValueError, compile, - 'print 42\n', '', 'badmode') - raises(ValueError, compile, - 'print 42\n', '', 'single', 0xff) - if have_unicode: - compile(unicode('print u"\xc3\xa5"\n', 'utf8'), '', 'exec') - - def test_delattr(self): - import sys - sys.spam = 1 - delattr(sys, 'spam') - raises(TypeError, delattr) - - def test_dir(self): - x = 1 - assert 'x' in dir() - import sys - assert 'modules' in dir(sys) - raises(TypeError, dir, 42, 42) - - def test_divmod(self): - assert divmod(12, 7) == (1, 5) - assert divmod(-12, 7) == (-2, 2) - assert divmod(12, -7) == (-2, -2) - assert divmod(-12, -7) == (1, -5) - - assert divmod(12L, 7L) == (1L, 5L) - assert divmod(-12L, 7L) == (-2L, 2L) - assert divmod(12L, -7L) == (-2L, -2L) - assert divmod(-12L, -7L) == (1L, -5L) - - assert divmod(12, 7L) == (1, 5L) - assert divmod(-12, 7L) == (-2, 2L) - assert divmod(12L, -7) == (-2L, -2) - assert divmod(-12L, -7) == (1L, -5) - - assert not fcmp(divmod(3.25, 1.0), (3.0, 0.25)) - assert not fcmp(divmod(-3.25, 1.0), (-4.0, 0.75)) - assert not fcmp(divmod(3.25, -1.0), (-4.0, -0.75)) - assert not fcmp(divmod(-3.25, -1.0), (3.0, -0.25)) - - raises(TypeError, divmod) - - ''' XXX TODO No eval() support yet - def test_eval(self): - assert eval('1+1') == 2 - assert eval(' 1+1\n') == 2 - globals = {'a': 1, 'b': 2} - locals = {'b': 200, 'c': 300} - assert eval('a', globals) == 1 - assert eval('a', globals, locals) == 1 - assert eval('b', globals, locals) == 200 - assert eval('c', globals, locals) == 300 - if have_unicode: - assert eval(unicode('1+1')) == 2 - assert eval(unicode(' 1+1\n')) == 2 - globals = {'a': 1, 'b': 2} - locals = {'b': 200, 'c': 300} - if have_unicode: - assert eval(unicode('a'), globals) == 1 - assert eval(unicode('a'), globals, locals) == 1 - assert eval(unicode('b'), globals, locals) == 200 - assert eval(unicode('c'), globals, locals) == 300 - bom = '\xef\xbb\xbf' - assert eval(bom + 'a', globals, locals) == 1 - assert eval(unicode('u"\xc3\xa5"', 'utf8'), globals) == ( - unicode('\xc3\xa5', 'utf8')) - raises(TypeError, eval) - raises(TypeError, eval, ()) - - '\'' XXX TODO: Figure out later - # Done outside of the method test_z to get the correct scope - z = 0 - f = open(TESTFN, 'w') - f.write('z = z+1\n') - f.write('z = z*2\n') - f.close() - execfile(TESTFN) - - def test_execfile(self): - globals = {'a': 1, 'b': 2} - locals = {'b': 200, 'c': 300} - - assert self.__class__.z == 2 - globals['z'] = 0 - execfile(TESTFN, globals) - assert globals['z'] == 2 - locals['z'] = 0 - execfile(TESTFN, globals, locals) - assert locals['z'] == 2 - unlink(TESTFN) - raises(TypeError, execfile) - import os - raises(IOError, execfile, os.curdir) - raises(IOError, execfile, "I_dont_exist") - '\'' - ''' - - ''' XXX TODO: filter does NOT rely on __getitem__, but rather on - __iter__; it appears to me that the following two tests, - therefore, pass in CPython only because of the accident that - in that implementation str does not define __iter__ (while - list and tuple do, in 2.3). Probably best to substitute - most of these tests with more appropriate ones! - ''' - def test_filter(self): - assert filter(lambda c: 'a' <= c <= 'z', 'Hello World') == ( - 'elloorld') - assert (filter(None, [1, 'hello', [], [3], '', None, 9, 0]) - ) == [1, 'hello', [3], 9] - assert filter(lambda x: x > 0, [1, -3, 9, 0, 2]) == ( - [1, 9, 2]) - assert filter(None, Squares(10)) == ( - [1, 4, 9, 16, 25, 36, 49, 64, 81]) - assert filter(lambda x: x%2, Squares(10)) == ( - [1, 9, 25, 49, 81]) - def identity(item): - return 1 - filter(identity, Squares(5)) - raises(TypeError, filter) - ''' XXX rest of test disabled as above explained - class BadSeq(object): - def __getitem__(self, index): - if index<4: - return 42 - raise ValueError - raises(ValueError, filter, lambda x: x, BadSeq()) - def badfunc(): - pass - raises(TypeError, filter, badfunc, range(5)) - - # test bltinmodule.c::filtertuple() - assert filter(None, (1, 2)) == (1, 2) - assert filter(lambda x: x>=3, (1, 2, 3, 4)) == (3, 4) - raises(TypeError, filter, 42, (1, 2)) - - # test bltinmodule.c::filterstring() - assert filter(None, "12") == "12" - assert filter(lambda x: x>="3", "1234") == "34" - raises(TypeError, filter, 42, "12") - class badstr(str): - def __getitem__(self, index): - raise ValueError - raises(ValueError, filter, - lambda x: x >="3", badstr("1234")) - - class badstr2(str): - def __getitem__(self, index): - return 42 - raises(TypeError, filter, - lambda x: x >=42, badstr2("1234")) - - class weirdstr(str): - def __getitem__(self, index): - return weirdstr(2*str.__getitem__(self, index)) - assert filter(lambda x: x>="33", weirdstr("1234")) == ( - "3344") - - class shiftstr(str): - def __getitem__(self, index): - return chr(ord(str.__getitem__(self, index))+1) - assert filter(lambda x: x>="3", shiftstr("1234")) == "345" - - if have_unicode: - # test bltinmodule.c::filterunicode() - assert filter(None, unicode("12")) == unicode("12") - assert filter(lambda x: x>="3", unicode("1234")) == ( - unicode("34")) - raises(TypeError, filter, 42, unicode("12")) - raises(ValueError, filter, lambda x: x >="3", - badstr(unicode("1234"))) - - class badunicode(unicode): - def __getitem__(self, index): - return 42 - raises(TypeError, filter, lambda x: x >=42, - badunicode("1234")) - - class weirdunicode(unicode): - def __getitem__(self, index): - return weirdunicode(2*unicode.__getitem__(self, index)) - assert ( - filter(lambda x: x>=unicode("33"), weirdunicode("1234"))) == ( - unicode("3344")) - - class shiftunicode(unicode): - def __getitem__(self, index): - return unichr(ord(unicode.__getitem__(self, index))+1) - assert ( - filter(lambda x: x>=unicode("3"), shiftunicode("1234"))) == ( - unicode("345") - ) - - def test_filter_subclasses(self): - # test that filter() never returns tuple, str or unicode subclasses - # and that the result always goes through __getitem__ - funcs = (None, bool, lambda x: True) - class tuple2(tuple): - def __getitem__(self, index): - return 2*tuple.__getitem__(self, index) - class str2(str): - def __getitem__(self, index): - return 2*str.__getitem__(self, index) - inputs = { - tuple2: {(): (), (1, 2, 3): (2, 4, 6)}, - str2: {"": "", "123": "112233"} - } - if have_unicode: - class unicode2(unicode): - def __getitem__(self, index): - return 2*unicode.__getitem__(self, index) - inputs[unicode2] = { - unicode(): unicode(), - unicode("123"): unicode("112233") - } - - for (cls, inps) in inputs.iteritems(): - for (inp, exp) in inps.iteritems(): - # make sure the output goes through __getitem__ - # even if func is None - assert ( - filter(funcs[0], cls(inp))) == ( - filter(funcs[1], cls(inp)) - ) - for func in funcs: - outp = filter(func, cls(inp)) - assert outp == exp - assert not isinstance(outp, cls) - ''' - - def test_float(self): - assert float(3.14) == 3.14 - assert float(314) == 314.0 - assert float(314L) == 314.0 - assert float(" 3.14 ") == 3.14 - if have_unicode: - assert float(unicode(" 3.14 ")) == 3.14 - assert float(unicode( - " \u0663.\u0661\u0664 ",'raw-unicode-escape')) == 3.14 - - def test_getattr(self): - import sys - assert getattr(sys, 'stdout') is sys.stdout - raises(TypeError, getattr, sys, 1) - raises(TypeError, getattr, sys, 1, "foo") - raises(TypeError, getattr) - if have_unicode: - raises(UnicodeError, getattr, sys, - unichr(sys.maxunicode)) - - def test_hasattr(self): - import sys - assert hasattr(sys, 'stdout') - raises(TypeError, hasattr, sys, 1) - raises(TypeError, hasattr) - if have_unicode: - raises(UnicodeError, hasattr, sys, - unichr(sys.maxunicode)) - - def test_hash(self): - hash(None) - assert hash(1) == hash(1L) - assert hash(1) == hash(1.0) - hash('spam') - if have_unicode: - assert hash('spam') == hash(unicode('spam')) - hash((0,1,2,3)) - def f(): pass - raises(TypeError, hash, []) - raises(TypeError, hash, {}) - - def test_hex(self): - assert hex(16) == '0x10' - assert hex(16L) == '0x10L' - assert len(hex(-1)) == len(hex(sys.maxint)) - assert hex(-16) in ('0xfffffff0', '0xfffffffffffffff0') - assert hex(-16L) == '-0x10L' - raises(TypeError, hex, {}) - - def test_id(self): - id(None) - id(1) - id(1L) - id(1.0) - id('spam') - id((0,1,2,3)) - id([0,1,2,3]) - id({'spam': 1, 'eggs': 2, 'ham': 3}) - - # Test input() later, together with raw_input - - def test_int(self): - assert int(314) == 314 - assert int(3.14) == 3 - assert int(314L) == 314 - # Check that conversion from float truncates towards zero - assert int(-3.14) == -3 - assert int(3.9) == 3 - assert int(-3.9) == -3 - assert int(3.5) == 3 - assert int(-3.5) == -3 - # Different base: - assert int("10",16) == 16L - if have_unicode: - assert int(unicode("10"),16) == 16L - # Test conversion from strings and various anomalies - for s, v in L: - for sign in "", "+", "-": - for prefix in "", " ", "\t", " \t\t ": - ss = prefix + sign + s - vv = v - if sign == "-" and v is not ValueError: - vv = -v - try: - assert int(ss) == vv - except v: - pass - - s = `-1-sys.maxint` - assert int(s)+1 == -sys.maxint - # should return long - ''' XXX TODO: Longs not well supported yet - int(s[1:]) - - # should return long - x = int(1e100) - assert isinstance(x, long) - x = int(-1e100) - assert isinstance(x, long) - ''' - - # SF bug 434186: 0x80000000/2 != 0x80000000>>1. - # Worked by accident in Windows release build, but failed in - # debug build. Failed in all Linux builds. - x = -1-sys.maxint - assert x >> 1 == x//2 - - raises(ValueError, int, '123\0') - raises(ValueError, int, '53', 40) - - ''' XXX TODO: Longs not supported yet - x = int('1' * 600) - assert isinstance(x, long) - - if have_unicode: - x = int(unichr(0x661) * 600) - assert isinstance(x, long) - - raises(TypeError, int, 1, 12) - ''' - - assert int('0123', 0) == 83 - - def test_intern(self): - raises(TypeError, intern) - s = "never interned before" - assert intern(s) is s - s2 = s.swapcase().swapcase() - assert intern(s2) is s - - def test_iter(self): - raises(TypeError, iter) - raises(TypeError, iter, 42, 42) - lists = [("1", "2"), ["1", "2"], "12"] - if have_unicode: - lists.append(unicode("12")) - for l in lists: - i = iter(l) - assert i.next() == '1' - assert i.next() == '2' - raises(StopIteration, i.next) - - def test_isinstance(self): - class C: - pass - class D(C): - pass - class E: - pass - c = C() - d = D() - e = E() - assert isinstance(c, C) - assert isinstance(d, C) - assert not isinstance(e, C) - assert not isinstance(c, D) - assert not isinstance('foo', E) - raises(TypeError, isinstance, E, 'foo') - raises(TypeError, isinstance) - - def test_issubclass(self): - class C: - pass - class D(C): - pass - class E: - pass - c = C() - d = D() - e = E() - assert issubclass(D, C) - assert issubclass(C, C) - assert not issubclass(C, D) - raises(TypeError, issubclass, 'foo', E) - raises(TypeError, issubclass, E, 'foo') - raises(TypeError, issubclass) - - def test_len(self): - assert len('123') == 3 - assert len(()) == 0 - assert len((1, 2, 3, 4)) == 4 - assert len([1, 2, 3, 4]) == 4 - assert len({}) == 0 - assert len({'a':1, 'b': 2}) == 2 - class BadSeq: - def __len__(self): - raise ValueError - raises(ValueError, len, BadSeq()) - - if 1: - - def test_list(self): - assert list([]) == [] - l0_3 = [0, 1, 2, 3] - l0_3_bis = list(l0_3) - assert l0_3 == l0_3_bis - assert l0_3 is not l0_3_bis - assert list(()) == [] - assert list((0, 1, 2, 3)) == [0, 1, 2, 3] - assert list('') == [] - assert list('spam') == ['s', 'p', 'a', 'm'] - - ''' XXX TODO: disabled for now -- far too slow! - if sys.maxint == 0x7fffffff: - # This test can currently only work on 32-bit machines. - # XXX If/when PySequence_Length() returns a ssize_t, it should be - # XXX re-enabled. - # Verify clearing of bug #556025. - # This assumes that the max data size (sys.maxint) == max - # address size this also assumes that the address size is at - # least 4 bytes with 8 byte addresses, the bug is not well - # tested - # - # Note: This test is expected to SEGV under Cygwin 1.3.12 or - # earlier due to a newlib bug. See the following mailing list - # thread for the details: - - # http://sources.redhat.com/ml/newlib/2002/msg00369.html - raises(MemoryError, list, xrange(sys.maxint // 2)) - ''' - - ''' XXX TODO: disabled for now -- long not yet well supported - def test_long(self): - assert long(314) == 314L - assert long(3.14) == 3L - assert long(314L) == 314L - # Check that conversion from float truncates towards zero - assert long(-3.14) == -3L - assert long(3.9) == 3L - assert long(-3.9) == -3L - assert long(3.5) == 3L - assert long(-3.5) == -3L - assert long("-3") == -3L - if have_unicode: - assert long(unicode("-3")) == -3L - # Different base: - assert long("10",16) == 16L - if have_unicode: - assert long(unicode("10"),16) == 16L - # Check conversions from string (same test set as for int(), and then some) - LL = [ - ('1' + '0'*20, 10L**20), - ('1' + '0'*100, 10L**100) - ] - L2 = L[:] - if have_unicode: - L2 += [ - (unicode('1') + unicode('0')*20, 10L**20), - (unicode('1') + unicode('0')*100, 10L**100), - ] - for s, v in L2 + LL: - for sign in "", "+", "-": - for prefix in "", " ", "\t", " \t\t ": - ss = prefix + sign + s - vv = v - if sign == "-" and v is not ValueError: - vv = -v - try: - assert long(ss) == long(vv) - except v: - pass - - raises(ValueError, long, '123\0') - raises(ValueError, long, '53', 40) - raises(TypeError, long, 1, 12) - ''' - - def test_map(self): - assert ( - map(None, 'hello world')) == ( - ['h','e','l','l','o',' ','w','o','r','l','d'] - ) - assert ( - map(None, 'abcd', 'efg')) == ( - [('a', 'e'), ('b', 'f'), ('c', 'g'), ('d', None)] - ) - assert ( - map(None, range(10))) == ( - [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] - ) - assert ( - map(lambda x: x*x, range(1,4))) == ( - [1, 4, 9] - ) - try: - from math import sqrt - except ImportError: - def sqrt(x): - return pow(x, 0.5) - assert ( - map(lambda x: map(sqrt,x), [[16, 4], [81, 9]])) == ( - [[4.0, 2.0], [9.0, 3.0]] - ) - assert ( - map(lambda x, y: x+y, [1,3,2], [9,1,4])) == ( - [10, 4, 6] - ) - - def plus(*v): - accu = 0 - for i in v: accu = accu + i - return accu - assert ( - map(plus, [1, 3, 7])) == ( - [1, 3, 7] - ) - assert ( - map(plus, [1, 3, 7], [4, 9, 2])) == ( - [1+4, 3+9, 7+2] - ) - assert ( - map(plus, [1, 3, 7], [4, 9, 2], [1, 1, 0])) == ( - [1+4+1, 3+9+1, 7+2+0] - ) - assert ( - map(None, Squares(10))) == ( - [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] - ) - assert ( - map(int, Squares(10))) == ( - [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] - ) - assert ( - map(None, Squares(3), Squares(2))) == ( - [(0,0), (1,1), (4,None)] - ) - assert ( - map(max, Squares(3), Squares(2))) == ( - [0, 1, 4] - ) - raises(TypeError, map) - raises(TypeError, map, lambda x: x, 42) - assert map(None, [42]) == [42] - class BadSeq: - def __getitem__(self, index): - raise ValueError - raises(ValueError, map, lambda x: x, BadSeq()) - - def test_max(self): - assert max('123123') == '3' - assert max(1, 2, 3) == 3 - assert max((1, 2, 3, 1, 2, 3)) == 3 - assert max([1, 2, 3, 1, 2, 3]) == 3 - - assert max(1, 2L, 3.0) == 3.0 - assert max(1L, 2.0, 3) == 3 - assert max(1.0, 2, 3L) == 3L - - def test_min(self): - assert min('123123') == '1' - assert min(1, 2, 3) == 1 - assert min((1, 2, 3, 1, 2, 3)) == 1 - assert min([1, 2, 3, 1, 2, 3]) == 1 - - assert min(1, 2L, 3.0) == 1 - assert min(1L, 2.0, 3) == 1L - assert min(1.0, 2, 3L) == 1.0 - - raises(TypeError, min) - raises(TypeError, min, 42) - raises(ValueError, min, ()) - class BadSeq: - def __getitem__(self, index): - raise ValueError - raises(ValueError, min, BadSeq()) - ''' XXX TODO: some weird bug in pypy here -- fix later - class BadNumber: - def __cmp__(self, other): - raise ValueError - raises(ValueError, min, (42, BadNumber())) - ''' - - def test_oct(self): - assert oct(100) == '0144' - assert oct(100L) == '0144L' - assert oct(-100) in ('037777777634', '01777777777777777777634') - assert oct(-100L) == '-0144L' - raises(TypeError, oct, ()) - - - def test_open(self): - def write_testfile(): - # NB the first 4 lines are also used to test input and raw_input, below - fp = open(TESTFN, 'w') - try: - fp.write('1+1\n') - fp.write('1+1\n') - fp.write('The quick brown fox jumps over the lazy dog') - fp.write('.\n') - fp.write('Dear John\n') - fp.write('XXX'*100) - fp.write('YYY'*100) - finally: - fp.close() - write_testfile() - fp = open(TESTFN, 'r') - try: - assert fp.readline(4) == '1+1\n' - assert fp.readline(4) == '1+1\n' - assert fp.readline() == 'The quick brown fox jumps over the lazy dog.\n' - assert fp.readline(4) == 'Dear' - assert fp.readline(100) == ' John\n' - assert fp.read(300) == 'XXX'*100 - assert fp.read(1000) == 'YYY'*100 - finally: - fp.close() - unlink(TESTFN) - - def test_ord(self): - assert ord(' ') == 32 - assert ord('A') == 65 - assert ord('a') == 97 - raises(TypeError, ord, 42) - if have_unicode: - assert ord(unichr(sys.maxunicode)) == sys.maxunicode - raises(TypeError, ord, unicode("12")) - - def test_pow(self): - assert pow(0,0) == 1 - assert pow(0,1) == 0 - assert pow(1,0) == 1 - assert pow(1,1) == 1 - - assert pow(2,0) == 1 - assert pow(2,10) == 1024 - assert pow(2,20) == 1024*1024 - assert pow(2,30) == 1024*1024*1024 - - assert pow(-2,0) == 1 - assert pow(-2,1) == -2 - assert pow(-2,2) == 4 - assert pow(-2,3) == -8 - - assert pow(0L,0) == 1 - assert pow(0L,1) == 0 - assert pow(1L,0) == 1 - assert pow(1L,1) == 1 - - assert pow(2L,0) == 1 - assert pow(2L,10) == 1024 - assert pow(2L,20) == 1024*1024 - assert pow(2L,30) == 1024*1024*1024 - - assert pow(-2L,0) == 1 - assert pow(-2L,1) == -2 - assert pow(-2L,2) == 4 - assert pow(-2L,3) == -8 - - assert round(pow(0.,0) - 1., 7) == 0 - assert round(pow(0.,1) - 0., 7) == 0 - assert round(pow(1.,0) - 1., 7) == 0 - assert round(pow(1.,1) - 1., 7) == 0 - - assert round(pow(2.,0) - 1., 7) == 0 - assert round(pow(2.,10) - 1024., 7) == 0 - assert round(pow(2.,20) - 1024.*1024., 7) == 0 - assert round(pow(2.,30) - 1024.*1024.*1024., 7) == 0 - - assert round(pow(-2.,0) - 1., 7) == 0 - assert round(pow(-2.,1) - -2., 7) == 0 - assert round(pow(-2.,2) - 4., 7) == 0 - assert round(pow(-2.,3) - -8., 7) == 0 - - for x in 2, 2L, 2.0: - for y in 10, 10L, 10.0: - for z in 1000, 1000L, 1000.0: - if isinstance(x, float) or \ - isinstance(y, float) or \ - isinstance(z, float): - raises(TypeError, pow, x, y, z) - else: - assert round(pow(x, y, z) - 24.0, 7) == 0 - - raises(TypeError, pow, -1, -2, 3) - raises(ValueError, pow, 1, 2, 0) - raises(TypeError, pow, -1L, -2L, 3L) - raises(ValueError, pow, 1L, 2L, 0L) - raises(ValueError, pow, -342.43, 0.234) - - raises(TypeError, pow) - - def test_range(self): - assert range(3) == [0, 1, 2] - assert range(1, 5) == [1, 2, 3, 4] - assert range(0) == [] - assert range(-3) == [] - assert range(1, 10, 3) == [1, 4, 7] - assert range(5, -5, -3) == [5, 2, -1, -4] - - # Now test range() with longs - assert range(-2**100) == [] - assert range(0, -2**100) == [] - assert range(0, 2**100, -1) == [] - assert range(0, 2**100, -1) == [] - - a = long(10 * sys.maxint) - b = long(100 * sys.maxint) - c = long(50 * sys.maxint) - - assert range(a, a+2) == [a, a+1] - assert range(a+2, a, -1L) == [a+2, a+1] - assert range(a+4, a, -2) == [a+4, a+2] - - seq = range(a, b, c) - assert a in seq - assert b not in seq - assert len(seq) == 2 - - seq = range(b, a, -c) - assert b in seq - assert a not in seq - assert len(seq) == 2 - - seq = range(-a, -b, -c) - assert -a in seq - assert -b not in seq - assert len(seq) == 2 - - raises(TypeError, range) - raises(TypeError, range, 1, 2, 3, 4) - raises(ValueError, range, 1, 2, 0) - - # Reject floats when it would require PyLongs to represent. - # (smaller floats still accepted, but deprecated) - raises(TypeError, range, 1e100, 1e101, 1e101) - - raises(TypeError, range, 0, "spam") - raises(TypeError, range, 0, 42, "spam") - - raises(OverflowError, range, -sys.maxint, sys.maxint) - raises(OverflowError, range, 0, 2*sys.maxint) - - ''' XXX TODO: input and raw_input not supported yet - def test_input_and_raw_input(self): - self.write_testfile() - fp = open(TESTFN, 'r') - savestdin = sys.stdin - savestdout = sys.stdout # Eats the echo - try: - sys.stdin = fp - sys.stdout = BitBucket() - assert input() == 2 - assert input('testing\n') == 2 - assert raw_input() == 'The quick brown fox jumps over the lazy dog.' - assert raw_input('testing\n') == 'Dear John' - sys.stdin = cStringIO.StringIO("NULL\0") - raises(TypeError, input, 42, 42) - sys.stdin = cStringIO.StringIO(" 'whitespace'") - assert input() == 'whitespace' - sys.stdin = cStringIO.StringIO() - raises(EOFError, input) - del sys.stdout - raises(RuntimeError, input, 'prompt') - del sys.stdin - raises(RuntimeError, input, 'prompt') - finally: - sys.stdin = savestdin - sys.stdout = savestdout - fp.close() - unlink(TESTFN) - ''' - - def test_reduce(self): - assert reduce(lambda x, y: x+y, ['a', 'b', 'c'], '') == 'abc' - assert ( - reduce(lambda x, y: x+y, [['a', 'c'], [], ['d', 'w']], [])) == ( - ['a','c','d','w'] - ) - assert reduce(lambda x, y: x*y, range(2,8), 1) == 5040 - assert ( - reduce(lambda x, y: x*y, range(2,21), 1L)) == ( - 2432902008176640000L - ) - assert reduce(lambda x, y: x+y, Squares(10)) == 285 - assert reduce(lambda x, y: x+y, Squares(10), 0) == 285 - assert reduce(lambda x, y: x+y, Squares(0), 0) == 0 - raises(TypeError, reduce) - raises(TypeError, reduce, 42, 42) - raises(TypeError, reduce, 42, 42, 42) - assert reduce(42, "1") == "1" # func is never called with one item - assert reduce(42, "", "1") == "1" # func is never called with one item - raises(TypeError, reduce, 42, (42, 42)) - - class BadSeq: - def __getitem__(self, index): - raise ValueError - raises(ValueError, reduce, 42, BadSeq()) - - ''' XXX TODO: we don't have reload yet - def test_reload(self): - import sys - reload(sys) - import string - reload(string) - ## import sys - ## raises(ImportError, reload, sys) - ''' - - def test_repr(self): - assert repr('') == '\'\'' - assert repr(0) == '0' - assert repr(0L) == '0L' - assert repr(()) == '()' - assert repr([]) == '[]' - assert repr({}) == '{}' - ''' XXX TODO: we don't yet support "circular" objects! - a = [] - a.append(a) - assert repr(a) == '[[...]]' - a = {} - a[0] = a - assert repr(a) == '{0: {...}}' - ''' - - def test_round(self): - assert round(0.0) == 0.0 - assert round(1.0) == 1.0 - assert round(10.0) == 10.0 - assert round(1000000000.0) == 1000000000.0 - assert round(1e20) == 1e20 - - assert round(-1.0) == -1.0 - assert round(-10.0) == -10.0 - assert round(-1000000000.0) == -1000000000.0 - assert round(-1e20) == -1e20 - - assert round(0.1) == 0.0 - assert round(1.1) == 1.0 - assert round(10.1) == 10.0 - assert round(1000000000.1) == 1000000000.0 - - assert round(-1.1) == -1.0 - assert round(-10.1) == -10.0 - assert round(-1000000000.1) == -1000000000.0 - - assert round(0.9) == 1.0 - assert round(9.9) == 10.0 - assert round(999999999.9) == 1000000000.0 - - assert round(-0.9) == -1.0 - assert round(-9.9) == -10.0 - assert round(-999999999.9) == -1000000000.0 - - assert round(-8.0, -1) == -10.0 - - raises(TypeError, round) - - def test_setattr(self): - setattr(sys, 'spam', 1) - assert sys.spam == 1 - raises(TypeError, setattr, sys, 1, 'spam') - raises(TypeError, setattr) - - def test_str(self): - assert str('') == '' - assert str(0) == '0' - assert str(0L) == '0' - assert str(()) == '()' - assert str([]) == '[]' - assert str({}) == '{}' - ''' XXX TODO: we don't yet support "circular" objects! - a = [] - a.append(a) - assert str(a) == '[[...]]' - a = {} - a[0] = a - assert str(a) == '{0: {...}}' - ''' - - def test_sum(self): - assert sum([]) == 0 - assert sum(range(2,8)) == 27 - assert sum(iter(range(2,8))) == 27 - assert sum(Squares(10)) == 285 - assert sum(iter(Squares(10))) == 285 - assert sum([[1], [2], [3]], []) == [1, 2, 3] - - raises(TypeError, sum) - raises(TypeError, sum, 42) - raises(TypeError, sum, ['a', 'b', 'c']) - raises(TypeError, sum, ['a', 'b', 'c'], '') - raises(TypeError, sum, [[1], [2], [3]]) - raises(TypeError, sum, [{2:3}]) - raises(TypeError, sum, [{2:3}]*2, {2:3}) - - class BadSeq: - def __getitem__(self, index): - raise ValueError - raises(ValueError, sum, BadSeq()) - - def test_tuple(self): - assert tuple(()) == () - t0_3 = (0, 1, 2, 3) - t0_3_bis = tuple(t0_3) - ''' XXX TODO: tuples are immutable -- returns same object in CPython ''' - #self.assert_(t0_3 is t0_3_bis) - assert t0_3 == t0_3_bis - assert tuple([]) == () - assert tuple([0, 1, 2, 3]) == (0, 1, 2, 3) - assert tuple('') == () - assert tuple('spam') == ('s', 'p', 'a', 'm') - - def test_type(self): - assert type('') == type('123') - assert type('') != type(()) - - def test_unichr(self): - if have_unicode: - assert unichr(32) == unicode(' ') - assert unichr(65) == unicode('A') - assert unichr(97) == unicode('a') - assert ( - unichr(sys.maxunicode)) == ( - unicode('\\U%08x' % (sys.maxunicode), 'unicode-escape') - ) - raises(ValueError, unichr, sys.maxunicode+1) - raises(TypeError, unichr) - - def test_vars(self): - def get_vars_f0(): - return vars() - def get_vars_f2(): - get_vars_f0() - a = 1 - b = 2 - return vars() - assert Set(vars()) == Set(dir()) - import sys - assert Set(vars(sys)) == Set(dir(sys)) - assert get_vars_f0() == {} - assert get_vars_f2() == {'a': 1, 'b': 2} - raises(TypeError, vars, 42, 42) - raises(TypeError, vars, 42) - - def test_zip(self): - a = (1, 2, 3) - b = (4, 5, 6) - t = [(1, 4), (2, 5), (3, 6)] - assert zip(a, b) == t - b = [4, 5, 6] - assert zip(a, b) == t - b = (4, 5, 6, 7) - assert zip(a, b) == t - class I: - def __getitem__(self, i): - if i < 0 or i > 2: raise IndexError - return i + 4 - assert zip(a, I()) == t - raises(TypeError, zip) - raises(TypeError, zip, None) - class G: - pass - raises(TypeError, zip, a, G()) - - # Make sure zip doesn't try to allocate a billion elements for the - # result list when one of its arguments doesn't say how long it is. - # A MemoryError is the most likely failure mode. - class SequenceWithoutALength: - def __getitem__(self, i): - if i == 5: - raise IndexError - else: - return i - s = SequenceWithoutALength() - assert ( - zip(s, xrange(2**30))) == ( - [(x,x) for x in s] - ) - - class BadSeq: - def __getitem__(self, i): - if i == 5: - raise ValueError - else: - return i - raises(ValueError, zip, BadSeq(), BadSeq()) From hpk at codespeak.net Mon Mar 21 16:34:40 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Mon, 21 Mar 2005 16:34:40 +0100 (MET) Subject: [pypy-svn] r9989 - pypy/dist/pypy/lib/test2 Message-ID: <20050321153440.3A8BB27BF5@code1.codespeak.net> Author: hpk Date: Mon Mar 21 16:34:40 2005 New Revision: 9989 Removed: pypy/dist/pypy/lib/test2/test_sha.py Log: remove hacked version Deleted: /pypy/dist/pypy/lib/test2/test_sha.py ============================================================================== --- /pypy/dist/pypy/lib/test2/test_sha.py Mon Mar 21 16:34:40 2005 +++ (empty file) @@ -1,25 +0,0 @@ -# Testing sha module (NIST's Secure Hash Algorithm) - -# use the three examples from Federal Information Processing Standards -# Publication 180-1, Secure Hash Standard, 1995 April 17 -# http://www.itl.nist.gov/div897/pubs/fip180-1.htm - -import autopath -from pypy.appspace import sha - -class TestSHA: - def check(self, data, digest): - computed = sha.new(data).hexdigest() - assert computed == digest - - def test_case_1(self): - self.check("abc", - "a9993e364706816aba3e25717850c26c9cd0d89d") - - def test_case_2(self): - self.check("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", - "84983e441c3bd26ebaae4aa1f95129e5e54670f1") - - def disabled_too_slow_test_case_3(self): - self.check("a" * 1000000, - "34aa973cd4c4daa4f61eeb2bdbad27316534016f") From hpk at codespeak.net Mon Mar 21 16:38:32 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Mon, 21 Mar 2005 16:38:32 +0100 (MET) Subject: [pypy-svn] r9990 - pypy/dist/pypy/lib/test2 Message-ID: <20050321153832.F281827BFD@code1.codespeak.net> Author: hpk Date: Mon Mar 21 16:38:32 2005 New Revision: 9990 Added: pypy/dist/pypy/lib/test2/test_sha.py - copied, changed from r9983, pypy/dist/lib-python-2.3.4/test/test_sha.py Log: re-add test_sha.py and skip the too-long running "a" * 1000000 test Copied: pypy/dist/pypy/lib/test2/test_sha.py (from r9983, pypy/dist/lib-python-2.3.4/test/test_sha.py) ============================================================================== --- pypy/dist/lib-python-2.3.4/test/test_sha.py (original) +++ pypy/dist/pypy/lib/test2/test_sha.py Mon Mar 21 16:38:32 2005 @@ -22,7 +22,7 @@ self.check("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", "84983e441c3bd26ebaae4aa1f95129e5e54670f1") - def test_case_3(self): + def too_slow_test_case_3(self): self.check("a" * 1000000, "34aa973cd4c4daa4f61eeb2bdbad27316534016f") From hpk at codespeak.net Mon Mar 21 16:39:02 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Mon, 21 Mar 2005 16:39:02 +0100 (MET) Subject: [pypy-svn] r9991 - pypy/dist/pypy/lib/test2 Message-ID: <20050321153902.4C93827C01@code1.codespeak.net> Author: hpk Date: Mon Mar 21 16:39:02 2005 New Revision: 9991 Removed: pypy/dist/pypy/lib/test2/test_struct.py Log: remove old test_struct hacks to start off cleanly again Deleted: /pypy/dist/pypy/lib/test2/test_struct.py ============================================================================== --- /pypy/dist/pypy/lib/test2/test_struct.py Mon Mar 21 16:39:02 2005 +++ (empty file) @@ -1,439 +0,0 @@ -import autopath -from pypy.appspace.test.support_tests import TestFailed, verbose, verify -from pypy.appspace import struct -import sys - -ISBIGENDIAN = sys.byteorder == "big" -del sys -verify((struct.pack('=i', 1)[0] == chr(0)) == ISBIGENDIAN, - "bigendian determination appears wrong") - -def string_reverse(s): - chars = list(s) - chars.reverse() - return "".join(chars) - -def bigendian_to_native(value): - if ISBIGENDIAN: - return value - else: - return string_reverse(value) - -def simple_err(func, *args): - try: - func(*args) - except struct.error: - pass - else: - raise TestFailed, "%s%s did not raise struct.error" % ( - func.__name__, args) - -def any_err(func, *args): - try: - func(*args) - except (struct.error, OverflowError, TypeError): - pass - else: - raise TestFailed, "%s%s did not raise error" % ( - func.__name__, args) - - -simple_err(struct.calcsize, 'Z') - -sz = struct.calcsize('i') -if sz * 3 != struct.calcsize('iii'): - raise TestFailed, 'inconsistent sizes' - -fmt = 'cbxxxxxxhhhhiillffd' -fmt3 = '3c3b18x12h6i6l6f3d' -sz = struct.calcsize(fmt) -sz3 = struct.calcsize(fmt3) -if sz * 3 != sz3: - raise TestFailed, 'inconsistent sizes (3*%r -> 3*%d = %d, %r -> %d)' % ( - fmt, sz, 3*sz, fmt3, sz3) - -simple_err(struct.pack, 'iii', 3) -simple_err(struct.pack, 'i', 3, 3, 3) -simple_err(struct.pack, 'i', 'foo') -simple_err(struct.pack, 'P', 'foo') -simple_err(struct.unpack, 'd', 'flap') -s = struct.pack('ii', 1, 2) -simple_err(struct.unpack, 'iii', s) -simple_err(struct.unpack, 'i', s) - -c = 'a' -b = 0 -h = 255 -i = 65535 -l = 65536 -f = 3.1415 -d = 3.1415 - -for prefix in ('', '@', '<', '>', '=', '!'): - for format in ('xcbhilfd', 'xcBHILfd'): - format = prefix + format - if verbose: - print "trying:", format - s = struct.pack(format, c, b, h, i, l, f, d) - cp, bp, hp, ip, lp, fp, dp = struct.unpack(format, s) - if (cp != c or bp != b or hp != h or ip != i or lp != l or - int(100 * fp) != int(100 * f) or int(100 * dp) != int(100 * d)): - # ^^^ calculate only to two decimal places - raise TestFailed, "unpack/pack not transitive (%s, %s)" % ( - str(format), str((cp, bp, hp, ip, lp, fp, dp))) - -# Test some of the new features in detail - -# (format, argument, big-endian result, little-endian result, asymmetric) -tests = [ - ('c', 'a', 'a', 'a', 0), - ('xc', 'a', '\0a', '\0a', 0), - ('cx', 'a', 'a\0', 'a\0', 0), - ('s', 'a', 'a', 'a', 0), - ('0s', 'helloworld', '', '', 1), - ('1s', 'helloworld', 'h', 'h', 1), - ('9s', 'helloworld', 'helloworl', 'helloworl', 1), - ('10s', 'helloworld', 'helloworld', 'helloworld', 0), - ('11s', 'helloworld', 'helloworld\0', 'helloworld\0', 1), - ('20s', 'helloworld', 'helloworld'+10*'\0', 'helloworld'+10*'\0', 1), - ('b', 7, '\7', '\7', 0), - ('b', -7, '\371', '\371', 0), - ('B', 7, '\7', '\7', 0), - ('B', 249, '\371', '\371', 0), - ('h', 700, '\002\274', '\274\002', 0), - ('h', -700, '\375D', 'D\375', 0), - ('H', 700, '\002\274', '\274\002', 0), - ('H', 0x10000-700, '\375D', 'D\375', 0), - ('i', 70000000, '\004,\035\200', '\200\035,\004', 0), - ('i', -70000000, '\373\323\342\200', '\200\342\323\373', 0), - ('I', 70000000L, '\004,\035\200', '\200\035,\004', 0), - ('I', 0x100000000L-70000000, '\373\323\342\200', '\200\342\323\373', 0), - ('l', 70000000, '\004,\035\200', '\200\035,\004', 0), - ('l', -70000000, '\373\323\342\200', '\200\342\323\373', 0), - ('L', 70000000L, '\004,\035\200', '\200\035,\004', 0), - ('L', 0x100000000L-70000000, '\373\323\342\200', '\200\342\323\373', 0), - ('f', 2.0, '@\000\000\000', '\000\000\000@', 0), - ('d', 2.0, '@\000\000\000\000\000\000\000','\000\000\000\000\000\000\000@', 0), - ('f', -2.0, '\300\000\000\000', '\000\000\000\300', 0), - ('d', -2.0, '\300\000\000\000\000\000\000\000','\000\000\000\000\000\000\000\300', 0), -] - -for fmt, arg, big, lil, asy in tests: - if verbose: - print "%r %r %r %r" % (fmt, arg, big, lil) - for (xfmt, exp) in [('>'+fmt, big), ('!'+fmt, big), ('<'+fmt, lil), - ('='+fmt, ISBIGENDIAN and big or lil)]: - res = struct.pack(xfmt, arg) - if res != exp: - raise TestFailed, "pack(%r, %r) -> %r # expected %r" % ( - fmt, arg, res, exp) - n = struct.calcsize(xfmt) - if n != len(res): - raise TestFailed, "calcsize(%r) -> %d # expected %d" % ( - xfmt, n, len(res)) - rev = struct.unpack(xfmt, res)[0] - if rev != arg and not asy: - raise TestFailed, "unpack(%r, %r) -> (%r,) # expected (%r,)" % ( - fmt, res, rev, arg) - -########################################################################### -# Simple native q/Q tests. - -has_native_qQ = 1 -try: - struct.pack("q", 5) -except struct.error: - has_native_qQ = 0 - -if verbose: - print "Platform has native q/Q?", has_native_qQ and "Yes." or "No." - -any_err(struct.pack, "Q", -1) # can't pack -1 as unsigned regardless -simple_err(struct.pack, "q", "a") # can't pack string as 'q' regardless -simple_err(struct.pack, "Q", "a") # ditto, but 'Q' - -def test_native_qQ(): - bytes = struct.calcsize('q') - # The expected values here are in big-endian format, primarily because - # I'm on a little-endian machine and so this is the clearest way (for - # me) to force the code to get exercised. - for format, input, expected in ( - ('q', -1, '\xff' * bytes), - ('q', 0, '\x00' * bytes), - ('Q', 0, '\x00' * bytes), - ('q', 1L, '\x00' * (bytes-1) + '\x01'), - ('Q', (1L << (8*bytes))-1, '\xff' * bytes), - ('q', (1L << (8*bytes-1))-1, '\x7f' + '\xff' * (bytes - 1))): - got = struct.pack(format, input) - native_expected = bigendian_to_native(expected) - verify(got == native_expected, - "%r-pack of %r gave %r, not %r" % - (format, input, got, native_expected)) - retrieved = struct.unpack(format, got)[0] - verify(retrieved == input, - "%r-unpack of %r gave %r, not %r" % - (format, got, retrieved, input)) - -if has_native_qQ: - test_native_qQ() - -########################################################################### -# Standard integer tests (bBhHiIlLqQ). - -import binascii - -class IntTester: - - # XXX Most std integer modes fail to test for out-of-range. - # The "i" and "l" codes appear to range-check OK on 32-bit boxes, but - # fail to check correctly on some 64-bit ones (Tru64 Unix + Compaq C - # reported by Mark Favas). - BUGGY_RANGE_CHECK = "bBhHiIlL" - - def __init__(self, formatpair, bytesize): - assert len(formatpair) == 2 - self.formatpair = formatpair - for direction in "<>!=": - for code in formatpair: - format = direction + code - verify(struct.calcsize(format) == bytesize) - self.bytesize = bytesize - self.bitsize = bytesize * 8 - self.signed_code, self.unsigned_code = formatpair - self.unsigned_min = 0 - self.unsigned_max = 2L**self.bitsize - 1 - self.signed_min = -(2L**(self.bitsize-1)) - self.signed_max = 2L**(self.bitsize-1) - 1 - - def test_one(self, x, pack=struct.pack, - unpack=struct.unpack, - unhexlify=binascii.unhexlify): - if verbose: - print "trying std", self.formatpair, "on", x, "==", hex(x) - - # Try signed. - code = self.signed_code - if self.signed_min <= x <= self.signed_max: - # Try big -endian. - expected = long(x) - if x < 0: - expected += 1L << self.bitsize - assert expected > 0 - expected = hex(expected)[2:-1] # chop "0x" and trailing 'L' - if len(expected) & 1: - expected = "0" + expected - expected = unhexlify(expected) - expected = "\x00" * (self.bytesize - len(expected)) + expected - - # Pack work? - format = ">" + code - got = pack(format, x) - verify(got == expected, - "'%s'-pack of %r gave %r, not %r" % - (format, x, got, expected)) - - # Unpack work? - retrieved = unpack(format, got)[0] - verify(x == retrieved, - "'%s'-unpack of %r gave %r, not %r" % - (format, got, retrieved, x)) - - # Adding any byte should cause a "too big" error. - any_err(unpack, format, '\x01' + got) - - # Try little-endian. - format = "<" + code - expected = string_reverse(expected) - - # Pack work? - got = pack(format, x) - verify(got == expected, - "'%s'-pack of %r gave %r, not %r" % - (format, x, got, expected)) - - # Unpack work? - retrieved = unpack(format, got)[0] - verify(x == retrieved, - "'%s'-unpack of %r gave %r, not %r" % - (format, got, retrieved, x)) - - # Adding any byte should cause a "too big" error. - any_err(unpack, format, '\x01' + got) - - else: - # x is out of range -- verify pack realizes that. - if code in self.BUGGY_RANGE_CHECK: - if verbose: - print "Skipping buggy range check for code", code - else: - any_err(pack, ">" + code, x) - any_err(pack, "<" + code, x) - - # Much the same for unsigned. - code = self.unsigned_code - if self.unsigned_min <= x <= self.unsigned_max: - # Try big-endian. - format = ">" + code - expected = long(x) - expected = hex(expected)[2:-1] # chop "0x" and trailing 'L' - if len(expected) & 1: - expected = "0" + expected - expected = unhexlify(expected) - expected = "\x00" * (self.bytesize - len(expected)) + expected - - # Pack work? - got = pack(format, x) - verify(got == expected, - "'%s'-pack of %r gave %r, not %r" % - (format, x, got, expected)) - - # Unpack work? - retrieved = unpack(format, got)[0] - verify(x == retrieved, - "'%s'-unpack of %r gave %r, not %r" % - (format, got, retrieved, x)) - - # Adding any byte should cause a "too big" error. - any_err(unpack, format, '\x01' + got) - - # Try little-endian. - format = "<" + code - expected = string_reverse(expected) - - # Pack work? - got = pack(format, x) - verify(got == expected, - "'%s'-pack of %r gave %r, not %r" % - (format, x, got, expected)) - - # Unpack work? - retrieved = unpack(format, got)[0] - verify(x == retrieved, - "'%s'-unpack of %r gave %r, not %r" % - (format, got, retrieved, x)) - - # Adding any byte should cause a "too big" error. - any_err(unpack, format, '\x01' + got) - - else: - # x is out of range -- verify pack realizes that. - if code in self.BUGGY_RANGE_CHECK: - if verbose: - print "Skipping buggy range check for code", code - else: - any_err(pack, ">" + code, x) - any_err(pack, "<" + code, x) - - def run(self): - from random import randrange - - # Create all interesting powers of 2. - values = [] - for exp in range(self.bitsize + 3): - values.append(1L << exp) - - # Add some random values. - for i in range(self.bitsize): - val = 0L - for j in range(self.bytesize): - val = (val << 8) | randrange(256) - values.append(val) - - # Try all those, and their negations, and +-1 from them. Note - # that this tests all power-of-2 boundaries in range, and a few out - # of range, plus +-(2**n +- 1). - for base in values: - for val in -base, base: - for incr in -1, 0, 1: - x = val + incr - try: - x = int(x) - except OverflowError: - pass - self.test_one(x) - - # Some error cases. - for direction in "<>": - for code in self.formatpair: - for badobject in "a string", 3+42j, randrange: - any_err(struct.pack, direction + code, badobject) - -for args in [("bB", 1), - ("hH", 2), - ("iI", 4), - ("lL", 4), - ("qQ", 8)]: - t = IntTester(*args) - t.run() - - -########################################################################### -# The p ("Pascal string") code. - -def test_p_code(): - for code, input, expected, expectedback in [ - ('p','abc', '\x00', ''), - ('1p', 'abc', '\x00', ''), - ('2p', 'abc', '\x01a', 'a'), - ('3p', 'abc', '\x02ab', 'ab'), - ('4p', 'abc', '\x03abc', 'abc'), - ('5p', 'abc', '\x03abc\x00', 'abc'), - ('6p', 'abc', '\x03abc\x00\x00', 'abc'), - ('1000p', 'x'*1000, '\xff' + 'x'*999, 'x'*255)]: - got = struct.pack(code, input) - if got != expected: - raise TestFailed("pack(%r, %r) == %r but expected %r" % - (code, input, got, expected)) - (got,) = struct.unpack(code, got) - if got != expectedback: - raise TestFailed("unpack(%r, %r) == %r but expected %r" % - (code, input, got, expectedback)) - -test_p_code() - - -########################################################################### -# SF bug 705836. "f" had a severe rounding bug, where a carry -# from the low-order discarded bits could propagate into the exponent -# field, causing the result to be wrong by a factor of 2. - -def test_705836(): - import math - - for base in range(1, 33): - # smaller <- largest representable float less than base. - delta = 0.5 - while base - delta / 2.0 != base: - delta /= 2.0 - smaller = base - delta - # Packing this rounds away a solid string of trailing 1 bits. - packed = struct.pack("f", smaller) - verify(bigpacked == string_reverse(packed), - ">f pack should be byte-reversal of f", bigpacked)[0] - verify(base == unpacked) - - # Largest finite IEEE single. - big = (1 << 24) - 1 - big = math.ldexp(big, 127 - 23) - packed = struct.pack(">f", big) - unpacked = struct.unpack(">f", packed)[0] - verify(big == unpacked) - - # The same, but tack on a 1 bit so it rounds up to infinity. - big = (1 << 25) - 1 - big = math.ldexp(big, 127 - 24) - try: - packed = struct.pack(">f", big) - except OverflowError: - pass - else: - TestFailed("expected OverflowError") - -test_705836() From tismer at codespeak.net Mon Mar 21 17:00:58 2005 From: tismer at codespeak.net (tismer at codespeak.net) Date: Mon, 21 Mar 2005 17:00:58 +0100 (MET) Subject: [pypy-svn] r9992 - pypy/dist/pypy/lib Message-ID: <20050321160058.0D80F27C09@code1.codespeak.net> Author: tismer Date: Mon Mar 21 17:00:57 2005 New Revision: 9992 Modified: pypy/dist/pypy/lib/struct.py Log: special-cased 0.0 which is represented as zero string Modified: pypy/dist/pypy/lib/struct.py ============================================================================== --- pypy/dist/pypy/lib/struct.py (original) +++ pypy/dist/pypy/lib/struct.py Mon Mar 21 17:00:57 2005 @@ -60,7 +60,7 @@ bytes = [ord(b) for b in data[index:index+size]] if len(bytes) != size: raise StructError,"Not enough data to unpack" - if min(bytes) == 0: + if max(bytes) == 0: return 0.0 if le == 'big': bytes.reverse() From tismer at codespeak.net Mon Mar 21 17:01:32 2005 From: tismer at codespeak.net (tismer at codespeak.net) Date: Mon, 21 Mar 2005 17:01:32 +0100 (MET) Subject: [pypy-svn] r9993 - pypy/dist/pypy/objspace/std Message-ID: <20050321160132.80CBC27C0A@code1.codespeak.net> Author: tismer Date: Mon Mar 21 17:01:31 2005 New Revision: 9993 Modified: pypy/dist/pypy/objspace/std/stringobject.py Log: corrected string cast from derived string to pure Modified: pypy/dist/pypy/objspace/std/stringobject.py ============================================================================== --- pypy/dist/pypy/objspace/std/stringobject.py (original) +++ pypy/dist/pypy/objspace/std/stringobject.py Mon Mar 21 17:01:31 2005 @@ -944,8 +944,9 @@ return space.wrap(len(w_str._value)) def str__String(space, w_str): - return w_str - + if type(w_str) is W_StringObject: + return w_str + return W_StringObject(space, w_str._value) def iter__String(space, w_list): from pypy.objspace.std import iterobject From hpk at codespeak.net Mon Mar 21 17:07:01 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Mon, 21 Mar 2005 17:07:01 +0100 (MET) Subject: [pypy-svn] r9994 - pypy/dist/pypy/lib/test2 Message-ID: <20050321160701.419FF27C0F@code1.codespeak.net> Author: hpk Date: Mon Mar 21 17:07:01 2005 New Revision: 9994 Added: pypy/dist/pypy/lib/test2/test_struct.py - copied, changed from r9983, pypy/dist/lib-python-2.3.4/test/test_struct.py Log: re-add shallowly modified test_struct.py the only change really is that we cut down on the number of tests because running them via pypy/cpython is just too slow Copied: pypy/dist/pypy/lib/test2/test_struct.py (from r9983, pypy/dist/lib-python-2.3.4/test/test_struct.py) ============================================================================== --- pypy/dist/lib-python-2.3.4/test/test_struct.py (original) +++ pypy/dist/pypy/lib/test2/test_struct.py Mon Mar 21 17:07:01 2005 @@ -328,16 +328,26 @@ from random import randrange # Create all interesting powers of 2. - values = [] + allvalues = [] for exp in range(self.bitsize + 3): - values.append(1L << exp) + allvalues.append(1L << exp) + + # reduce the number of values again + values = [] + i = 1 + while i <= len(allvalues): + values.append(allvalues[i-1]) + i *= 2 # Add some random values. - for i in range(self.bitsize): - val = 0L - for j in range(self.bytesize): - val = (val << 8) | randrange(256) - values.append(val) + # + # XXX doesn't seem like good practice to run with random values + # + #for i in range(self.bitsize): + # val = 0L + # for j in range(self.bytesize): + # val = (val << 8) | randrange(256) + # values.append(val) # Try all those, and their negations, and +-1 from them. Note # that this tests all power-of-2 boundaries in range, and a few out From hpk at codespeak.net Mon Mar 21 17:13:34 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Mon, 21 Mar 2005 17:13:34 +0100 (MET) Subject: [pypy-svn] r9995 - in pypy/dist/pypy/lib: . test2 Message-ID: <20050321161334.DD0A727BFE@code1.codespeak.net> Author: hpk Date: Mon Mar 21 17:13:34 2005 New Revision: 9995 Modified: pypy/dist/pypy/lib/datetime.py (props changed) pypy/dist/pypy/lib/marshal.py (props changed) pypy/dist/pypy/lib/test2/test_datetime.py (props changed) Log: fixeol From lutz_p at codespeak.net Mon Mar 21 17:17:03 2005 From: lutz_p at codespeak.net (lutz_p at codespeak.net) Date: Mon, 21 Mar 2005 17:17:03 +0100 (MET) Subject: [pypy-svn] r9996 - in pypy/dist/pypy/lib: . test2 Message-ID: <20050321161703.A58F927BFF@code1.codespeak.net> Author: lutz_p Date: Mon Mar 21 17:17:03 2005 New Revision: 9996 Modified: pypy/dist/pypy/lib/cPickle.py (contents, props changed) pypy/dist/pypy/lib/test2/test_class.py (contents, props changed) Log: Fixed messed up EOL with the fixeol script as requested from Holger Modified: pypy/dist/pypy/lib/cPickle.py ============================================================================== --- pypy/dist/pypy/lib/cPickle.py (original) +++ pypy/dist/pypy/lib/cPickle.py Mon Mar 21 17:17:03 2005 @@ -1,5 +1,5 @@ -# -# One-liner implementation of cPickle -# - -from pickle import * +# +# One-liner implementation of cPickle +# + +from pickle import * Modified: pypy/dist/pypy/lib/test2/test_class.py ============================================================================== --- pypy/dist/pypy/lib/test2/test_class.py (original) +++ pypy/dist/pypy/lib/test2/test_class.py Mon Mar 21 17:17:03 2005 @@ -1,336 +1,336 @@ -"Test the functionality of Python classes implementing operators." - -from test.test_support import TestFailed - -# HACK BEGIN - -# After this implementation is complete and -# incorporated into the core after translation, -# this test file should really vanish! - -import pypy, os, new -prefix = os.path.dirname(pypy.__file__) -libdir = os.path.join(prefix, "lib") -fname = "_classobj.py" -fpath = os.path.join(libdir, fname) -mod = new.module("_classobj") -mod.__file__ = fpath -execfile(fpath, mod.__dict__) - -__metaclass__ = mod.classobj - -# HACK END - -testmeths = [ - -# Binary operations - "add", - "radd", - "sub", - "rsub", - "mul", - "rmul", - "div", - "rdiv", - "mod", - "rmod", - "divmod", - "rdivmod", - "pow", - "rpow", - "rshift", - "rrshift", - "lshift", - "rlshift", - "and", - "rand", - "or", - "ror", - "xor", - "rxor", - -# List/dict operations - "contains", - "getitem", - "getslice", - "setitem", - "setslice", - "delitem", - "delslice", - -# Unary operations - "neg", - "pos", - "abs", - "int", - "long", - "float", - "oct", - "hex", - -# generic operations - "init", - ] - -# These need to return something other than None -# "coerce", -# "hash", -# "str", -# "repr", - -# These are separate because they can influence the test of other methods. -# "getattr", -# "setattr", -# "delattr", - -class AllTests: - def __coerce__(self, *args): - print "__coerce__:", args - return (self,) + args - - def __hash__(self, *args): - print "__hash__:", args - return hash(id(self)) - - def __str__(self, *args): - print "__str__:", args - return "AllTests" - - def __repr__(self, *args): - print "__repr__:", args - return "AllTests" - - def __cmp__(self, *args): - print "__cmp__:", args - return 0 - - def __del__(self, *args): - print "__del__:", args - -# Synthesize AllTests methods from the names in testmeths. - -method_template = """\ -def __%(method)s__(self, *args): - print "__%(method)s__:", args -""" - -for method in testmeths: - exec method_template % locals() in AllTests.__dict__ - -del method, method_template - -# this also tests __init__ of course. -testme = AllTests() - -# Binary operations - -testme + 1 -1 + testme - -testme - 1 -1 - testme - -testme * 1 -1 * testme - -if 1/2 == 0: - testme / 1 - 1 / testme -else: - # True division is in effect, so "/" doesn't map to __div__ etc; but - # the canned expected-output file requires that __div__ etc get called. - testme.__coerce__(1) - testme.__div__(1) - testme.__coerce__(1) - testme.__rdiv__(1) - -testme % 1 -1 % testme - -divmod(testme,1) -divmod(1, testme) - -testme ** 1 -1 ** testme - -testme >> 1 -1 >> testme - -testme << 1 -1 << testme - -testme & 1 -1 & testme - -testme | 1 -1 | testme - -testme ^ 1 -1 ^ testme - - -# List/dict operations - -1 in testme - -testme[1] -testme[1] = 1 -del testme[1] - -testme[:42] -testme[:42] = "The Answer" -del testme[:42] - -testme[2:1024:10] -testme[2:1024:10] = "A lot" -del testme[2:1024:10] - -testme[:42, ..., :24:, 24, 100] -testme[:42, ..., :24:, 24, 100] = "Strange" -del testme[:42, ..., :24:, 24, 100] - - -# Now remove the slice hooks to see if converting normal slices to slice -# object works. - -del AllTests.__getslice__ -del AllTests.__setslice__ -del AllTests.__delslice__ - -import sys -if sys.platform[:4] != 'java': - testme[:42] - testme[:42] = "The Answer" - del testme[:42] -else: - # This works under Jython, but the actual slice values are - # different. - print "__getitem__: (slice(0, 42, None),)" - print "__setitem__: (slice(0, 42, None), 'The Answer')" - print "__delitem__: (slice(0, 42, None),)" - -# Unary operations - --testme -+testme -abs(testme) -if sys.platform[:4] != 'java': - int(testme) - long(testme) - float(testme) - oct(testme) - hex(testme) -else: - # Jython enforced that these methods return - # a value of the expected type. - print "__int__: ()" - print "__long__: ()" - print "__float__: ()" - print "__oct__: ()" - print "__hex__: ()" - - -# And the rest... - -hash(testme) -repr(testme) -str(testme) - -testme == 1 -testme < 1 -testme > 1 -testme <> 1 -testme != 1 -1 == testme -1 < testme -1 > testme -1 <> testme -1 != testme - -# This test has to be last (duh.) - -del testme -if sys.platform[:4] == 'java': - import java - java.lang.System.gc() - -# Interfering tests - -class ExtraTests: - def __getattr__(self, *args): - print "__getattr__:", args - return "SomeVal" - - def __setattr__(self, *args): - print "__setattr__:", args - - def __delattr__(self, *args): - print "__delattr__:", args - -testme = ExtraTests() -testme.spam -testme.eggs = "spam, spam, spam and ham" -del testme.cardinal - - -# Test correct errors from hash() on objects with comparisons but no __hash__ - -class C0: - pass - -hash(C0()) # This should work; the next two should raise TypeError - -class C1: - def __cmp__(self, other): return 0 - -try: hash(C1()) -except TypeError: pass -else: raise TestFailed, "hash(C1()) should raise an exception" - -class C2: - def __eq__(self, other): return 1 - -try: hash(C2()) -except TypeError: pass -else: raise TestFailed, "hash(C2()) should raise an exception" - - -# Test for SF bug 532646 - -class A: - pass -A.__call__ = A() -a = A() -try: - a() # This should not segfault -except RuntimeError: - pass -else: - raise TestFailed, "how could this not have overflowed the stack?" - - -# Tests for exceptions raised in instance_getattr2(). - -def booh(self): - raise AttributeError, "booh" - -class A: - a = property(booh) -try: - A().a # Raised AttributeError: A instance has no attribute 'a' -except AttributeError, x: - if str(x) is not "booh": - print "attribute error for A().a got masked:", str(x) - -class E: - __eq__ = property(booh) -E() == E() # In debug mode, caused a C-level assert() to fail - -class I: - __init__ = property(booh) -try: - I() # In debug mode, printed XXX undetected error and raises AttributeError -except AttributeError, x: - pass -else: - print "attribute error for I.__init__ got masked" +"Test the functionality of Python classes implementing operators." + +from test.test_support import TestFailed + +# HACK BEGIN + +# After this implementation is complete and +# incorporated into the core after translation, +# this test file should really vanish! + +import pypy, os, new +prefix = os.path.dirname(pypy.__file__) +libdir = os.path.join(prefix, "lib") +fname = "_classobj.py" +fpath = os.path.join(libdir, fname) +mod = new.module("_classobj") +mod.__file__ = fpath +execfile(fpath, mod.__dict__) + +__metaclass__ = mod.classobj + +# HACK END + +testmeths = [ + +# Binary operations + "add", + "radd", + "sub", + "rsub", + "mul", + "rmul", + "div", + "rdiv", + "mod", + "rmod", + "divmod", + "rdivmod", + "pow", + "rpow", + "rshift", + "rrshift", + "lshift", + "rlshift", + "and", + "rand", + "or", + "ror", + "xor", + "rxor", + +# List/dict operations + "contains", + "getitem", + "getslice", + "setitem", + "setslice", + "delitem", + "delslice", + +# Unary operations + "neg", + "pos", + "abs", + "int", + "long", + "float", + "oct", + "hex", + +# generic operations + "init", + ] + +# These need to return something other than None +# "coerce", +# "hash", +# "str", +# "repr", + +# These are separate because they can influence the test of other methods. +# "getattr", +# "setattr", +# "delattr", + +class AllTests: + def __coerce__(self, *args): + print "__coerce__:", args + return (self,) + args + + def __hash__(self, *args): + print "__hash__:", args + return hash(id(self)) + + def __str__(self, *args): + print "__str__:", args + return "AllTests" + + def __repr__(self, *args): + print "__repr__:", args + return "AllTests" + + def __cmp__(self, *args): + print "__cmp__:", args + return 0 + + def __del__(self, *args): + print "__del__:", args + +# Synthesize AllTests methods from the names in testmeths. + +method_template = """\ +def __%(method)s__(self, *args): + print "__%(method)s__:", args +""" + +for method in testmeths: + exec method_template % locals() in AllTests.__dict__ + +del method, method_template + +# this also tests __init__ of course. +testme = AllTests() + +# Binary operations + +testme + 1 +1 + testme + +testme - 1 +1 - testme + +testme * 1 +1 * testme + +if 1/2 == 0: + testme / 1 + 1 / testme +else: + # True division is in effect, so "/" doesn't map to __div__ etc; but + # the canned expected-output file requires that __div__ etc get called. + testme.__coerce__(1) + testme.__div__(1) + testme.__coerce__(1) + testme.__rdiv__(1) + +testme % 1 +1 % testme + +divmod(testme,1) +divmod(1, testme) + +testme ** 1 +1 ** testme + +testme >> 1 +1 >> testme + +testme << 1 +1 << testme + +testme & 1 +1 & testme + +testme | 1 +1 | testme + +testme ^ 1 +1 ^ testme + + +# List/dict operations + +1 in testme + +testme[1] +testme[1] = 1 +del testme[1] + +testme[:42] +testme[:42] = "The Answer" +del testme[:42] + +testme[2:1024:10] +testme[2:1024:10] = "A lot" +del testme[2:1024:10] + +testme[:42, ..., :24:, 24, 100] +testme[:42, ..., :24:, 24, 100] = "Strange" +del testme[:42, ..., :24:, 24, 100] + + +# Now remove the slice hooks to see if converting normal slices to slice +# object works. + +del AllTests.__getslice__ +del AllTests.__setslice__ +del AllTests.__delslice__ + +import sys +if sys.platform[:4] != 'java': + testme[:42] + testme[:42] = "The Answer" + del testme[:42] +else: + # This works under Jython, but the actual slice values are + # different. + print "__getitem__: (slice(0, 42, None),)" + print "__setitem__: (slice(0, 42, None), 'The Answer')" + print "__delitem__: (slice(0, 42, None),)" + +# Unary operations + +-testme ++testme +abs(testme) +if sys.platform[:4] != 'java': + int(testme) + long(testme) + float(testme) + oct(testme) + hex(testme) +else: + # Jython enforced that these methods return + # a value of the expected type. + print "__int__: ()" + print "__long__: ()" + print "__float__: ()" + print "__oct__: ()" + print "__hex__: ()" + + +# And the rest... + +hash(testme) +repr(testme) +str(testme) + +testme == 1 +testme < 1 +testme > 1 +testme <> 1 +testme != 1 +1 == testme +1 < testme +1 > testme +1 <> testme +1 != testme + +# This test has to be last (duh.) + +del testme +if sys.platform[:4] == 'java': + import java + java.lang.System.gc() + +# Interfering tests + +class ExtraTests: + def __getattr__(self, *args): + print "__getattr__:", args + return "SomeVal" + + def __setattr__(self, *args): + print "__setattr__:", args + + def __delattr__(self, *args): + print "__delattr__:", args + +testme = ExtraTests() +testme.spam +testme.eggs = "spam, spam, spam and ham" +del testme.cardinal + + +# Test correct errors from hash() on objects with comparisons but no __hash__ + +class C0: + pass + +hash(C0()) # This should work; the next two should raise TypeError + +class C1: + def __cmp__(self, other): return 0 + +try: hash(C1()) +except TypeError: pass +else: raise TestFailed, "hash(C1()) should raise an exception" + +class C2: + def __eq__(self, other): return 1 + +try: hash(C2()) +except TypeError: pass +else: raise TestFailed, "hash(C2()) should raise an exception" + + +# Test for SF bug 532646 + +class A: + pass +A.__call__ = A() +a = A() +try: + a() # This should not segfault +except RuntimeError: + pass +else: + raise TestFailed, "how could this not have overflowed the stack?" + + +# Tests for exceptions raised in instance_getattr2(). + +def booh(self): + raise AttributeError, "booh" + +class A: + a = property(booh) +try: + A().a # Raised AttributeError: A instance has no attribute 'a' +except AttributeError, x: + if str(x) is not "booh": + print "attribute error for A().a got masked:", str(x) + +class E: + __eq__ = property(booh) +E() == E() # In debug mode, caused a C-level assert() to fail + +class I: + __init__ = property(booh) +try: + I() # In debug mode, printed XXX undetected error and raises AttributeError +except AttributeError, x: + pass +else: + print "attribute error for I.__init__ got masked" From hpk at codespeak.net Mon Mar 21 17:25:53 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Mon, 21 Mar 2005 17:25:53 +0100 (MET) Subject: [pypy-svn] r9997 - in pypy/dist/pypy/module: builtin test Message-ID: <20050321162553.805B927C02@code1.codespeak.net> Author: hpk Date: Mon Mar 21 17:25:53 2005 New Revision: 9997 Modified: pypy/dist/pypy/module/builtin/app_io.py pypy/dist/pypy/module/test/test_builtin.py Log: execfile() needs to work with both dos/unix lineending-styles Modified: pypy/dist/pypy/module/builtin/app_io.py ============================================================================== --- pypy/dist/pypy/module/builtin/app_io.py (original) +++ pypy/dist/pypy/module/builtin/app_io.py Mon Mar 21 17:25:53 2005 @@ -12,7 +12,7 @@ loc = caller.f_locals elif loc is None: loc = glob - f = file(filename) + f = file(filename, 'rU') try: source = f.read() finally: Modified: pypy/dist/pypy/module/test/test_builtin.py ============================================================================== --- pypy/dist/pypy/module/test/test_builtin.py (original) +++ pypy/dist/pypy/module/test/test_builtin.py Mon Mar 21 17:25:53 2005 @@ -397,3 +397,32 @@ space.wrap(fn), w_dict, space.w_None) w_value = space.getitem(w_dict, space.wrap('i')) assert self.space.eq_w(w_value, space.wrap(42)) + + def test_execfile_different_lineendings(self): + space = self.space + from pypy.tool.udir import udir + d = udir.ensure('lineending', dir=1) + dos = d.join('dos.py') + f = dos.open('wb') + f.write("x=3\r\n\r\ny=4\r\n") + f.close() + space.appexec([space.wrap(str(dos))], """ + (filename): + d = {} + execfile(filename, d) + assert d['x'] == 3 + assert d['y'] == 4 + """) + + unix = d.join('unix.py') + f = unix.open('wb') + f.write("x=5\n\ny=6\n") + f.close() + + space.appexec([space.wrap(str(unix))], """ + (filename): + d = {} + execfile(filename, d) + assert d['x'] == 5 + assert d['y'] == 6 + """) From hpk at codespeak.net Mon Mar 21 17:28:34 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Mon, 21 Mar 2005 17:28:34 +0100 (MET) Subject: [pypy-svn] r9998 - pypy/dist/pypy/lib/test2 Message-ID: <20050321162834.C63D627C0E@code1.codespeak.net> Author: hpk Date: Mon Mar 21 17:28:34 2005 New Revision: 9998 Added: pypy/dist/pypy/lib/test2/test_pickle_extra.py - copied unchanged from r9997, pypy/dist/pypy/lib/test2/test_pickle.py Removed: pypy/dist/pypy/lib/test2/test_pickle.py Log: this are really extra tests in addition to the standard regrtest Deleted: /pypy/dist/pypy/lib/test2/test_pickle.py ============================================================================== --- /pypy/dist/pypy/lib/test2/test_pickle.py Mon Mar 21 17:28:34 2005 +++ (empty file) @@ -1,54 +0,0 @@ -# -*- coding: iso-8859-1 -*- -import unittest, test.test_support -import pickle - -class Picklable(object): - def __init__(self, a=555): - self.a = a - def __eq__(self, other): - return self.a == other.a - def __str__(self): - return '%s(%r)' % (self.__class__.__name__, self.a) - __repr__ = __str__ - -class PicklableSpecial2(Picklable): - def __reduce__(self): - return self.__class__, (self.a,) - -class PicklableSpecial3(Picklable): - def __reduce__(self): - return self.__class__, (), self.a - def __setstate__(self, a): - self.a = a - -class PicklableSpecial4(Picklable): - def __reduce_ex__(self, proto): - return self.__class__, (), self.a - def __setstate__(self, a): - self.a = a - -class PickleTest(unittest.TestCase): - - def _pickle_some(self, x): - for proto in range(pickle.HIGHEST_PROTOCOL + 1): - s = pickle.dumps(x, proto) - y = pickle.loads(s) - self.assertEqual(x, y) - - def test_pickle_plain(self): - self._pickle_some(Picklable(5)) - - def test_pickle_special2(self): - self._pickle_some(PicklableSpecial2(66)) - - def test_pickle_special3(self): - self._pickle_some(PicklableSpecial3(7)) - - def test_pickle_special4(self): - self._pickle_some(PicklableSpecial4(17)) - -def test_main(): - test.test_support.run_unittest(PickleTest) - -if __name__ == "__main__": - test_main() From hpk at codespeak.net Mon Mar 21 17:34:51 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Mon, 21 Mar 2005 17:34:51 +0100 (MET) Subject: [pypy-svn] r9999 - in pypy/dist/pypy: lib/test2 objspace/std Message-ID: <20050321163451.C20F727C10@code1.codespeak.net> Author: hpk Date: Mon Mar 21 17:34:51 2005 New Revision: 9999 Added: pypy/dist/pypy/objspace/std/test_obj.py - copied, changed from r9997, pypy/dist/pypy/lib/test2/test_obj.py Removed: pypy/dist/pypy/lib/test2/test_obj.py Log: move this "extra" test of some hash functionality to the standard object space instead of our hacked pypy/lib Deleted: /pypy/dist/pypy/lib/test2/test_obj.py ============================================================================== --- /pypy/dist/pypy/lib/test2/test_obj.py Mon Mar 21 17:34:51 2005 +++ (empty file) @@ -1,22 +0,0 @@ -# -*- coding: iso-8859-1 -*- -import unittest, test.test_support - -class ObjectTest(unittest.TestCase): - - def test_hash_builtin(self): - o = object() - self.assertEquals(hash(o), id(o)) - - def test_hash_method(self): - o = object() - self.assertEquals(hash(o), o.__hash__()) - - def test_hash_list(self): - l = range(5) - self.assertRaises(TypeError, hash, l) - -def test_main(): - test.test_support.run_unittest(ObjectTest) - -if __name__ == "__main__": - test_main() Copied: pypy/dist/pypy/objspace/std/test_obj.py (from r9997, pypy/dist/pypy/lib/test2/test_obj.py) ============================================================================== --- pypy/dist/pypy/lib/test2/test_obj.py (original) +++ pypy/dist/pypy/objspace/std/test_obj.py Mon Mar 21 17:34:51 2005 @@ -1,22 +1,14 @@ # -*- coding: iso-8859-1 -*- -import unittest, test.test_support - -class ObjectTest(unittest.TestCase): +class AppTestObject: def test_hash_builtin(self): o = object() - self.assertEquals(hash(o), id(o)) + assert hash(o) == id(o) def test_hash_method(self): o = object() - self.assertEquals(hash(o), o.__hash__()) + assert hash(o) == o.__hash__() def test_hash_list(self): l = range(5) - self.assertRaises(TypeError, hash, l) - -def test_main(): - test.test_support.run_unittest(ObjectTest) - -if __name__ == "__main__": - test_main() + raises(TypeError, hash, l) From jacob at codespeak.net Mon Mar 21 17:41:28 2005 From: jacob at codespeak.net (jacob at codespeak.net) Date: Mon, 21 Mar 2005 17:41:28 +0100 (MET) Subject: [pypy-svn] r10000 - pypy/dist/pypy/lib Message-ID: <20050321164128.E811627C13@code1.codespeak.net> Author: jacob Date: Mon Mar 21 17:41:28 2005 New Revision: 10000 Added: pypy/dist/pypy/lib/binascii.py Log: First revsion. Onlu supports uu-encode/decode. Added: pypy/dist/pypy/lib/binascii.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/lib/binascii.py Mon Mar 21 17:41:28 2005 @@ -0,0 +1,64 @@ +class Error(Exception): + pass + +class Incomplete(Exception): + pass + +def a2b_uu(s): + length = ord(s[0]) - 0x20 + a = quadruplets(s[1:]) + ''' + for A, B, C, D in a: + print chr((A - 0x20) << 2 | (((B - 0x20) >> 4) & 0x3)) + print chr(((B - 0x20) & 0xF) << 4 | (((C - 0x20) >> 2) & 0xF)) + print chr(((C - 0x20) & 0x3) << 6 | ((D - 0x20) & 0x3F)) + ''' + + result = [''.join( + [chr((A - 0x20) << 2 | (((B - 0x20) >> 4) & 0x3)), + chr(((B - 0x20) & 0xF) << 4 | (((C - 0x20) >> 2) & 0xF)), + chr(((C - 0x20) & 0x3) << 6 | ((D - 0x20) & 0x3F)) + ]) for A, B, C, D in a] + return ''.join(result)[:length] + +def quadruplets(s): + while s: + try: + a, b, c, d = s[0], s[1], s[2], s[3] + except IndexError: + s += '\0\0\0' + yield ord(s[0]), ord(s[1]), ord(s[2]), ord(s[3]) + return + s = s[4:] + yield ord(a), ord(b), ord(c), ord(d) + +def b2a_uu(s): + length = len(s) + if length > 45: + raise Error, 'At most 45 bytes at once' + + a = triples(s) + result = [''.join( + [chr(0x20 + (( A >> 2 ) & 0x3F)), + chr(0x20 + (((A << 4) | ((B >> 4) & 0xF)) & 0x3F)), + chr(0x20 + (((B << 2) | ((C >> 6) & 0x3)) & 0x3F)), + chr(0x20 + (( C ) & 0x3F))]) for A, B, C in a] + return chr(ord(' ') + (length & 077)) + ''.join(result) + '\\n' + +def triples(s): + while s: + try: + a, b, c = s[0], s[1], s[2] + except IndexError: + s += '\0\0' + yield ord(s[0]), ord(s[1]), ord(s[2]) + return + s = s[3:] + yield ord(a), ord(b), ord(c) + +print b2a_uu('1234567') +print b2a_uu('123456789012345678901234567890123456789012345') +#print b2a_uu('1234567890123456789012345678901234567890123456') +print '"%s"' % a2b_uu(b2a_uu('1234567')) +print '"%s"' % a2b_uu(b2a_uu('123456789012345678901234567890123456789012345')) + From hpk at codespeak.net Mon Mar 21 17:44:45 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Mon, 21 Mar 2005 17:44:45 +0100 (MET) Subject: [pypy-svn] r10001 - pypy/dist/pypy/lib/test2 Message-ID: <20050321164445.2AECC27C06@code1.codespeak.net> Author: hpk Date: Mon Mar 21 17:44:44 2005 New Revision: 10001 Removed: pypy/dist/pypy/lib/test2/test_md5.py Log: original md5 regrtest passes nice enough Deleted: /pypy/dist/pypy/lib/test2/test_md5.py ============================================================================== --- /pypy/dist/pypy/lib/test2/test_md5.py Mon Mar 21 17:44:44 2005 +++ (empty file) @@ -1,249 +0,0 @@ -"""A test script to compare MD5 implementations. - -A note about performance: the pure Python MD5 takes roughly -160 sec. per MB of data on a 233 MHz Intel Pentium CPU. -""" - -import autopath -import string, unittest -import md5 # CPython's implementation in C. -# since appspace is gone, we cannot test this way any longer: -#from pypy.appspace import md5 as pymd5 # The pure Python implementation. -# instead, we fake a module. -# XXX think of a better wayto do this -import os, new -# fake import of the python module which we cannot see -import pypy -fname = os.path.join(pypy.__path__[0], 'lib', 'md5.py') -pymd5 = new.module('pymd5') -exec file(fname).read() in pymd5.__dict__ - -# Helpers... - -def formatHex(str): - "Print a string's HEX code in groups of two digits." - - d = map(None, str) - d = map(ord, d) - d = map(lambda x:"%02x" % x, d) - return string.join(d, " ") - - -def format(str): - "Print a string as-is in groups of two characters." - - s = '' - for i in range(0, len(str)-1, 2): - s = s + "%03s" % str[i:i+2] - return s[1:] - - -def printDiff(message, d1, d2, expectedResult=None): - "Print different outputs for same message." - - print "Message: '%s'" % message - print "Message length: %d" % len(message) - if expectedResult: - print "%-48s (expected)" % format(expectedResult) - print "%-48s (Std. lib. MD5)" % formatHex(d1) - print "%-48s (Pure Python MD5)" % formatHex(d2) - print - - -# The real comparison function. - -def compareImp(message): - """Compare two MD5 implementations, C vs. pure Python module. - - For equal digests this returns None, otherwise it returns - a tuple of both digests. - """ - - # Use Python's standard library MD5 compiled C module. - m1 = md5.md5() - m1.update(message) - d1 = m1.digest() - d1h = m1.hexdigest() - - # Use MD5 module in pure Python. - m2 = pymd5.md5() - m2.update(message) - d2 = m2.digest() - d2h = m2.hexdigest() - - # Return None if equal or the different digests if not equal. - if d1 == d2 and d1h == d2h: - return - else: - return d1, d2 - - -class MD5CompareTestCase(unittest.TestCase): - "Compare pure Python MD5 against Python's std. lib. version." - - def test1(self): - "Test cases with known digest result." - - cases = ( - ("", - "d41d8cd98f00b204e9800998ecf8427e"), - ("a", - "0cc175b9c0f1b6a831c399e269772661"), - ("abc", - "900150983cd24fb0d6963f7d28e17f72"), - ("message digest", - "f96b697d7cb7938d525a2f31aaf161d0"), - ("abcdefghijklmnopqrstuvwxyz", - "c3fcd3d76192e4007dfb496cca67e13b"), - ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", - "d174ab98d277d9f5a5611c2c9f419d9f"), - ("1234567890"*8, - "57edf4a22be3c955ac49da2e2107b67a"), - ) - - for i in xrange(len(cases)): - res = compareImp(cases[i][0]) - try: - assert res == None - except AssertionError, details: - d1, d2 = res - message, expectedResult = cases[i][0], None - if len(cases[i]) == 2: - expectedResult = cases[i][1] - printDiff(message, d1, d2, expectedResult) - - - def test2(self): - "Test cases without known digest result." - - cases = ( - "123", - "1234", - "12345", - "123456", - "1234567", - "12345678", - "123456789 123456789 123456789 ", - "123456789 123456789 ", - "123456789 123456789 1", - "123456789 123456789 12", - "123456789 123456789 123", - "123456789 123456789 1234", - "123456789 123456789 123456789 1", - "123456789 123456789 123456789 12", - "123456789 123456789 123456789 123", - "123456789 123456789 123456789 1234", - "123456789 123456789 123456789 12345", - "123456789 123456789 123456789 123456", - "123456789 123456789 123456789 1234567", - "123456789 123456789 123456789 12345678", - ) - - for i in xrange(len(cases)): - res = compareImp(cases[i][0]) - try: - assert res == None - except AssertionError, details: - d1, d2 = res - message = cases[i][0] - printDiff(message, d1, d2) - - - def test3(self): - "Test cases with long messages (can take a while)." - - cases = ( - (2**10*'a',), - (2**10*'abcd',), -## (2**20*'a',), ## 1 MB, takes about 160 sec. on a 233 Mhz Pentium. - ) - - for i in xrange(len(cases)): - res = compareImp(cases[i][0]) - try: - assert res == None - except AssertionError, details: - d1, d2 = res - message = cases[i][0] - printDiff(message, d1, d2) - - - def test4(self): - "Test cases with increasingly growing message lengths." - - i = 0 - while i < 2**5: - message = i * 'a' - res = compareImp(message) - try: - assert res == None - except AssertionError, details: - d1, d2 = res - printDiff(message, d1, d2) - i = i + 1 - - - def test5(self): - "Test updating cloned objects." - - cases = ( - "123", - "1234", - "12345", - "123456", - "1234567", - "12345678", - "123456789 123456789 123456789 ", - "123456789 123456789 ", - "123456789 123456789 1", - "123456789 123456789 12", - "123456789 123456789 123", - "123456789 123456789 1234", - "123456789 123456789 123456789 1", - "123456789 123456789 123456789 12", - "123456789 123456789 123456789 123", - "123456789 123456789 123456789 1234", - "123456789 123456789 123456789 12345", - "123456789 123456789 123456789 123456", - "123456789 123456789 123456789 1234567", - "123456789 123456789 123456789 12345678", - ) - - # Load both with same prefix. - prefix1 = 2**10 * 'a' - - m1 = md5.md5() - m1.update(prefix1) - m1c = m1.copy() - - m2 = pymd5.md5() - m2.update(prefix1) - m2c = m2.copy() - - # Update and compare... - for i in xrange(len(cases)): - message = cases[i][0] - - m1c.update(message) - d1 = m1c.hexdigest() - - m2c.update(message) - d2 = m2c.hexdigest() - - assert d1 == d2 - - -def makeSuite(): - suite = unittest.TestSuite() - - suite.addTest(MD5CompareTestCase('test1')) - suite.addTest(MD5CompareTestCase('test2')) - suite.addTest(MD5CompareTestCase('test3')) - suite.addTest(MD5CompareTestCase('test4')) - suite.addTest(MD5CompareTestCase('test5')) - - return suite - - -if __name__ == "__main__": - unittest.TextTestRunner().run(makeSuite()) From hpk at codespeak.net Mon Mar 21 18:01:11 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Mon, 21 Mar 2005 18:01:11 +0100 (MET) Subject: [pypy-svn] r10002 - pypy/dist/pypy/lib Message-ID: <20050321170111.2E02527BF2@code1.codespeak.net> Author: hpk Date: Mon Mar 21 18:01:11 2005 New Revision: 10002 Modified: pypy/dist/pypy/lib/itertools.py Log: use the function version of islice (which is still wrong, alex is going to fix it ...) Modified: pypy/dist/pypy/lib/itertools.py ============================================================================== --- pypy/dist/pypy/lib/itertools.py (original) +++ pypy/dist/pypy/lib/itertools.py Mon Mar 21 18:01:11 2005 @@ -339,7 +339,7 @@ -class islice: +def islice(iterable, *args): """Make an iterator that returns selected elements from the iterable. If start is non-zero, then elements from the iterable are skipped until start is reached. Afterward, elements are @@ -351,63 +351,17 @@ step. Can be used to extract related fields from data where the internal structure has been flattened (for example, a multi-line report may list a name field on every third line). - - Equivalent to : - - def islice(iterable, *args): - s = slice(*args) - next, stop, step = s.start or 0, s.stop, s.step or 1 - for cnt, element in enumerate(iterable): - if cnt < next: - continue - if stop is not None and cnt >= stop: - break - yield element - next += step - """ - def __init__(self, iterable, arg, *other_args): - if len(other_args) > 2 : - raise TypeError("islice() takes at most 4 arguments, got %s" % - (2 + len(other_args))) - self._enum = enumerate(iterable) - start, stop, step = 0, -1, 1 - # We must do the same checks that in the CPython implementation - # Only one arg passed means it's the "stop" one - if not other_args: - stop = arg - else: - start = arg - try: - stop, step = other_args - except ValueError: # <=> No step specified - stop = other_args[0] - if not isinstance(start, int): - raise ValueError("Start argument must be an integer") - if stop is not None and not isinstance(stop, int): - raise ValueError("Stop argument must be an integer or None") - if start < 0 or (stop is not None and stop < -1): - raise ValueError("Indices for islice() must be non-negative integers.") - if step < 1: - raise ValueError("Step must be one or larger for islice()") - s = slice(start, stop, step) - self._next, self._stop, self._step = start, stop, step - # self._next, self._stop, self._step = s.start or 0, s.stop, s.step or 1 - - - def __iter__(self): - return self - - def next(self): - while True: - index, element = self._enum.next() - if self._stop is not None and index >= self._stop: - raise StopIteration() - if index < self._next: - continue - self._next += self._step - return element - - + """ + s = slice(*args) + next, stop, step = s.start or 0, s.stop, s.step or 1 + cnt = 0 + for element in enumerate(iterable): + if cnt < next: + continue + if stop is not None and cnt >= stop: + break + yield element + next += step class izip: """Make an iterator that aggregates elements from each of the From alex at codespeak.net Mon Mar 21 18:14:04 2005 From: alex at codespeak.net (alex at codespeak.net) Date: Mon, 21 Mar 2005 18:14:04 +0100 (MET) Subject: [pypy-svn] r10003 - pypy/dist/pypy/lib Message-ID: <20050321171404.076FE27C00@code1.codespeak.net> Author: alex Date: Mon Mar 21 18:14:03 2005 New Revision: 10003 Modified: pypy/dist/pypy/lib/itertools.py Log: fixed islice implementation (now simpler) Modified: pypy/dist/pypy/lib/itertools.py ============================================================================== --- pypy/dist/pypy/lib/itertools.py (original) +++ pypy/dist/pypy/lib/itertools.py Mon Mar 21 18:14:03 2005 @@ -353,15 +353,20 @@ report may list a name field on every third line). """ s = slice(*args) - next, stop, step = s.start or 0, s.stop, s.step or 1 + start, stop, step = s.start or 0, s.stop, s.step or 1 + next = iter(iterable).next cnt = 0 - for element in enumerate(iterable): - if cnt < next: - continue - if stop is not None and cnt >= stop: - break - yield element - next += step + while cnt < start: + next() + cnt += 1 + while stop is None or cnt < stop: + yield next() + cnt += 1 + skip = step - 1 + while skip: + next() + cnt += 1 + skip -= 1 class izip: """Make an iterator that aggregates elements from each of the From arigo at codespeak.net Mon Mar 21 18:29:44 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 21 Mar 2005 18:29:44 +0100 (MET) Subject: [pypy-svn] r10004 - in pypy/dist/pypy: interpreter objspace tool Message-ID: <20050321172944.C377927BF7@code1.codespeak.net> Author: arigo Date: Mon Mar 21 18:29:44 2005 New Revision: 10004 Added: pypy/dist/pypy/objspace/proxy.py - copied, changed from r9991, pypy/dist/pypy/objspace/trace.py pypy/dist/pypy/objspace/thunk.py Modified: pypy/dist/pypy/interpreter/interactive.py pypy/dist/pypy/tool/option.py Log: Replaced py.py -T and -S options with -o . Implemented a simple "thunk object space". See example usage in the docstring. Modified: pypy/dist/pypy/interpreter/interactive.py ============================================================================== --- pypy/dist/pypy/interpreter/interactive.py (original) +++ pypy/dist/pypy/interpreter/interactive.py Mon Mar 21 18:29:44 2005 @@ -31,7 +31,7 @@ # self.space.__class__.__name__) elapsed = time.time() - self.space._starttime banner = "PyPy in %s on top of Python %s (startupttime: %.2f secs)" % ( - self.space.__class__.__name__, sys.version.split()[0], elapsed) + self.space.__repr__(), sys.version.split()[0], elapsed) code.InteractiveConsole.interact(self, banner) def raw_input(self, prompt=""): Copied: pypy/dist/pypy/objspace/proxy.py (from r9991, pypy/dist/pypy/objspace/trace.py) ============================================================================== --- pypy/dist/pypy/objspace/trace.py (original) +++ pypy/dist/pypy/objspace/proxy.py Mon Mar 21 18:29:44 2005 @@ -1,216 +1,32 @@ -""" - Trace object space traces operations and bytecode execution - in frames. -""" - -from __future__ import generators -from pypy.tool import pydis +import py from pypy.interpreter.baseobjspace import ObjSpace # __________________________________________________________________________ -# -# Tracing Events -# __________________________________________________________________________ -# - -class ExecBytecode(object): - """ bytecode trace. """ - def __init__(self, frame): - self.frame = frame - self.code = frame.code - self.index = frame.next_instr - -class EnterFrame(object): - def __init__(self, frame): - self.frame = frame - -class LeaveFrame(object): - def __init__(self, frame): - self.frame = frame - -class CallInfo(object): - """ encapsulates a function call with its arguments. """ - def __init__(self, name, func, args, kwargs): - self.name = name - self.func = func - self.args = args - self.kwargs = kwargs - -class CallBegin(object): - def __init__(self, callinfo): - self.callinfo = callinfo - -class CallFinished(object): - def __init__(self, callinfo, res): - self.callinfo = callinfo - self.res = res - -class CallException(object): - def __init__(self, callinfo, e): - self.callinfo = callinfo - self.ex = e - -class TraceResult(object): - """ this is the state of tracing-in-progress. """ - def __init__(self, tracespace): - self.events = [] - self.tracespace = tracespace - - def append(self, arg): - self.events.append(arg) - - def getdisresult(self, frame, _cache = {}): - """ return (possibly cached) pydis result for the given frame. """ - try: - return _cache[id(frame.code)] - except KeyError: - res = _cache[id(frame.code)] = pydis.pydis(frame.code) - assert res is not None - return res - - def getbytecodes(self): - for event in self.events: - if isinstance(event, ExecBytecode): - disres = self.getdisresult(event.frame) - yield disres.getbytecode(event.index) - - def getoperations(self): - for event in self.events: - if isinstance(event, (CallBegin, CallFinished, CallException)): - yield event - - def getevents(self): - for event in self.events: - yield event - -# __________________________________________________________________________ -# -# Tracer Proxy objects -# __________________________________________________________________________ -# - -class ExecutionContextTracer(object): - def __init__(self, result, ec): - self.ec = ec - self.result = result - - def __getattr__(self, name): - """ generically pass through everything else ... """ - return getattr(self.ec, name) - - def enter(self, frame): - """ called just before (continuing to) evaluating a frame. """ - self.result.append(EnterFrame(frame)) - return self.ec.enter(frame) - - def leave(self, previous_ec): - """ called just after evaluating of a frame is suspended/finished. """ - frame = self.ec.framestack.top() - self.result.append(LeaveFrame(frame)) - return self.ec.leave(previous_ec) - - def bytecode_trace(self, frame): - """ called just before execution of a bytecode. """ - self.result.append(ExecBytecode(frame)) - -class CallableTracer(object): - def __init__(self, result, name, func): - self.result = result - self.name = name - self.func = func - - def __call__(self, *args, **kwargs): - callinfo = CallInfo(self.name, self.func, args, kwargs) - self.result.append(CallBegin(callinfo)) - - try: - res = self.func(*args, **kwargs) - except Exception, e: - self.result.append(CallException(callinfo, e)) - raise - else: - self.result.append(CallFinished(callinfo, res)) - return res - - def __getattr__(self, name): - """ generically pass through everything we don't intercept. """ - return getattr(self.func, name) - - def __str__(self): - return "%s - CallableTracer(%s)" % (self.name, self.func) - __repr__ = __str__ +def get_operations(): + return [r[0] for r in ObjSpace.MethodTable] + ObjSpace.IrregularOpTable -# __________________________________________________________________________ -# -# Tracer factory -# __________________________________________________________________________ -# +def create_proxy_space(proxyname, proxymaker, operations=None, space=None): + """ Will create a proxy object space if no space supplied. Otherwise + will patch the supplied space.""" -operations = None -def get_operations(): - global operations - if operations is None: - operations = dict([(r[0], r[0]) for r in ObjSpace.MethodTable]) - for name in ObjSpace.IrregularOpTable+ ["get_and_call_function"]: - operations[name] = name - - return operations - -def create_trace_space(space = None, operations = None): - """ Will create a trace object space if no space supplied. Otherwise - will turn the supplied into a tracable space by extending its class.""" - - # Don't trace an already tracable space - if hasattr(space, "__pypytrace__"): - return space - if space is None: - # make up a TrivialObjSpace by default - # ultimately, remove this hack and fix the -P option of tests - from pypy.objspace import trivial - space = trivial.TrivialObjSpace() + # make up a StdObjSpace by default + from pypy.objspace import std + space = std.Space() if operations is None: operations = get_operations() - class Trace(space.__class__): - - def __getattribute__(self, name): - obj = super(Trace, self).__getattribute__(name) - if name in operations: - assert callable(obj) - obj = CallableTracer(self._result, name, obj) - return obj - - def __pypytrace__(self): - pass - - def settrace(self): - self._result = TraceResult(self) - - def getresult(self): - return self._result - - def getexecutioncontext(self): - ec = super(Trace, self).getexecutioncontext() - assert not isinstance(ec, ExecutionContextTracer) - return ExecutionContextTracer(self._result, ec) - - def reset_trace(self): - """ Returns the class to it's original form. """ - space.__class__ = space.__oldclass__ - del space.__oldclass__ + for name in operations: + parentfn = getattr(space, name) + proxy = proxymaker(space, name, parentfn) + if proxy: + setattr(space, name, proxy) - if hasattr(self, "_result"): - del self._result + prevrepr = space.__repr__() + space.__repr__ = lambda: '%s(%s)' % (proxyname, prevrepr) - trace_clz = type("Trace" + space.__class__.__name__, (Trace,), {}) - space.__oldclass__, space.__class__ = space.__class__, trace_clz - - # XXX Ensure space's sys & builtin are fully loaded? - space.settrace() return space -# ______________________________________________________________________ -# End of trace.py +# __________________________________________________________________________ Added: pypy/dist/pypy/objspace/thunk.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/objspace/thunk.py Mon Mar 21 18:29:44 2005 @@ -0,0 +1,66 @@ +"""Example usage: + + $ python interpreter/py.py -o thunk + >>> def f(): + ... print 'computing...' + ... return 6*7 + ... + >>> x = thunk(f) + >>> x + computing... + 42 + >>> x + 42 + >>> y = thunk(f) + >>> type(y) + computing... + +""" + +from proxy import create_proxy_space +from pypy.interpreter import gateway +from pypy.interpreter.baseobjspace import W_Root + +# __________________________________________________________________________ + +class Thunk(W_Root, object): + def __init__(w_self, space, w_callable): + w_self.space = space + w_self.w_callable = w_callable + w_self.w_value = None + +def force(w_self): + while isinstance(w_self, Thunk): + if w_self.w_value is None: + w_self.w_value = w_self.space.call_function(w_self.w_callable) + w_self.w_callable = None + w_self = w_self.w_value + return w_self + +def thunk(space, w_callable): + return Thunk(space, w_callable) +app_thunk = gateway.interp2app(thunk) + +# __________________________________________________________________________ + +operation_args_that_dont_force = { + ('setattr', 2): True, + ('setitem', 2): True, + } + +def proxymaker(space, opname, parentfn): + def proxy(*args): + newargs = [] + for i in range(len(args)): + a = args[i] + if (opname, i) not in operation_args_that_dont_force: + a = force(a) + newargs.append(a) + return parentfn(*newargs) + return proxy + +def Space(): + space = create_proxy_space('thunk', proxymaker) + space.setitem(space.builtin.w_dict, space.wrap('thunk'), + space.wrap(app_thunk)) + return space Modified: pypy/dist/pypy/tool/option.py ============================================================================== --- pypy/dist/pypy/tool/option.py (original) +++ pypy/dist/pypy/tool/option.py Mon Mar 21 18:29:44 2005 @@ -14,21 +14,17 @@ def get_standard_options(): options = [] - def objspace_callback(option, opt, value, parser, space): - parser.values.spaces.append(space) + def objspace_callback(option, opt, value, parser): + parser.values.spaces.append(value) options.append(make_option( - '-S', action="callback", - callback=objspace_callback, callback_args=("std",), - help="run in std object space")) + '-o', '--objspace', action="callback", + callback=objspace_callback, type="string", + help="object space to run PyPy on.")) options.append(make_option( '--oldstyle', action="store_true",dest="oldstyle", help="enable oldstyle classes as default metaclass (std objspace only)")) options.append(make_option( - '-T', action="callback", - callback=objspace_callback, callback_args=("trivial",), - help="run in trivial object space")) - options.append(make_option( '-w', action="store_true", dest="showwarning", help="enable warnings (disabled by default)")) options.append(make_option( From tismer at codespeak.net Mon Mar 21 18:37:30 2005 From: tismer at codespeak.net (tismer at codespeak.net) Date: Mon, 21 Mar 2005 18:37:30 +0100 (MET) Subject: [pypy-svn] r10005 - pypy/dist/pypy/translator/tool Message-ID: <20050321173730.EEEE727C12@code1.codespeak.net> Author: tismer Date: Mon Mar 21 18:37:30 2005 New Revision: 10005 Modified: pypy/dist/pypy/translator/tool/buildpyxmodule.py Log: fixed imports. This case should be tested, because it only occours if we try to skip a test due to missing compiler. Modified: pypy/dist/pypy/translator/tool/buildpyxmodule.py ============================================================================== --- pypy/dist/pypy/translator/tool/buildpyxmodule.py (original) +++ pypy/dist/pypy/translator/tool/buildpyxmodule.py Mon Mar 21 18:37:30 2005 @@ -1,6 +1,7 @@ import autopath from pypy.tool.udir import udir +import py from py.process import cmdexec from py import path from pypy.translator.genpyrex import GenPyrex From tismer at codespeak.net Mon Mar 21 18:38:42 2005 From: tismer at codespeak.net (tismer at codespeak.net) Date: Mon, 21 Mar 2005 18:38:42 +0100 (MET) Subject: [pypy-svn] r10006 - pypy/dist/pypy/objspace/std Message-ID: <20050321173842.6946A27C14@code1.codespeak.net> Author: tismer Date: Mon Mar 21 18:38:42 2005 New Revision: 10006 Modified: pypy/dist/pypy/objspace/std/fake.py Log: changed fake to be more careful about getattribute. Bug found by test_pickle, which seems to be the most valuable test around :-) Modified: pypy/dist/pypy/objspace/std/fake.py ============================================================================== --- pypy/dist/pypy/objspace/std/fake.py (original) +++ pypy/dist/pypy/objspace/std/fake.py Mon Mar 21 18:38:42 2005 @@ -56,8 +56,9 @@ kw[meth_name] = __builtin__.eval("lambda m,*args,**kwds: m.%s(*args,**kwds)" % meth_name) else: for s, v in cpy_type.__dict__.items(): - if cpy_type is not unicode or s not in ['__add__', '__contains__']: - kw[s] = v + if not (cpy_type is unicode and s in ['__add__', '__contains__']): + if s != '__getattribute__' or cpy_type is type(sys): + kw[s] = v def fake__new__(space, w_type, args_w): args = [space.unwrap(w_arg) for w_arg in args_w] From arigo at codespeak.net Mon Mar 21 18:44:30 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 21 Mar 2005 18:44:30 +0100 (MET) Subject: [pypy-svn] r10007 - in pypy/dist/pypy/objspace: . test Message-ID: <20050321174430.3E97327C17@code1.codespeak.net> Author: arigo Date: Mon Mar 21 18:44:30 2005 New Revision: 10007 Added: pypy/dist/pypy/objspace/test/test_thunkobjspace.py (contents, props changed) Modified: pypy/dist/pypy/objspace/thunk.py Log: fixeol, typo, test for thunkobjspace. Added: pypy/dist/pypy/objspace/test/test_thunkobjspace.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/objspace/test/test_thunkobjspace.py Mon Mar 21 18:44:30 2005 @@ -0,0 +1,35 @@ + +class AppTest_Thunk: + + objspacename = 'thunk' + + def test_simple(self): + computed = [] + def f(): + computed.append(True) + return 6*7 + x = thunk(f) + assert computed == [] + t = type(x) + assert t is int + assert computed == [True] + t = type(x) + assert t is int + assert computed == [True] + + def test_setitem(self): + computed = [] + def f(): + computed.append(True) + return 6*7 + x = thunk(f) + d = {5: x} + d[6] = x + d[7] = [] + d[7].append(x) + assert computed == [] + y = d[5], d[6], d.values(), d.items() + assert computed == [] + d[7][0] += 1 + assert computed == [True] + assert d[7] == [43] Modified: pypy/dist/pypy/objspace/thunk.py ============================================================================== --- pypy/dist/pypy/objspace/thunk.py (original) +++ pypy/dist/pypy/objspace/thunk.py Mon Mar 21 18:44:30 2005 @@ -23,14 +23,14 @@ # __________________________________________________________________________ -class Thunk(W_Root, object): +class W_Thunk(W_Root, object): def __init__(w_self, space, w_callable): w_self.space = space w_self.w_callable = w_callable w_self.w_value = None def force(w_self): - while isinstance(w_self, Thunk): + while isinstance(w_self, W_Thunk): if w_self.w_value is None: w_self.w_value = w_self.space.call_function(w_self.w_callable) w_self.w_callable = None @@ -38,7 +38,7 @@ return w_self def thunk(space, w_callable): - return Thunk(space, w_callable) + return W_Thunk(space, w_callable) app_thunk = gateway.interp2app(thunk) # __________________________________________________________________________ From alex at codespeak.net Mon Mar 21 18:54:27 2005 From: alex at codespeak.net (alex at codespeak.net) Date: Mon, 21 Mar 2005 18:54:27 +0100 (MET) Subject: [pypy-svn] r10008 - pypy/dist/pypy/lib Message-ID: <20050321175427.5452B27C18@code1.codespeak.net> Author: alex Date: Mon Mar 21 18:54:27 2005 New Revision: 10008 Modified: pypy/dist/pypy/lib/itertools.py Log: redid islice as a class so it can raise early in case of problems Modified: pypy/dist/pypy/lib/itertools.py ============================================================================== --- pypy/dist/pypy/lib/itertools.py (original) +++ pypy/dist/pypy/lib/itertools.py Mon Mar 21 18:54:27 2005 @@ -339,7 +339,7 @@ -def islice(iterable, *args): +class islice: """Make an iterator that returns selected elements from the iterable. If start is non-zero, then elements from the iterable are skipped until start is reached. Afterward, elements are @@ -352,21 +352,24 @@ internal structure has been flattened (for example, a multi-line report may list a name field on every third line). """ - s = slice(*args) - start, stop, step = s.start or 0, s.stop, s.step or 1 - next = iter(iterable).next - cnt = 0 - while cnt < start: - next() - cnt += 1 - while stop is None or cnt < stop: - yield next() - cnt += 1 - skip = step - 1 - while skip: - next() - cnt += 1 - skip -= 1 + def __init__(self, iterable, *args): + s = slice(*args) + self.start, self.stop, self.step = s.start or 0, s.stop, s.step or 1 + self.donext = iter(iterable).next + + def __iter__(self): + cnt = 0 + while cnt < self.start: + self.donext() + cnt += 1 + while self.stop is None or cnt < self.stop: + yield self.donext() + cnt += 1 + skip = self.step - 1 + while skip: + self.donext() + cnt += 1 + skip -= 1 class izip: """Make an iterator that aggregates elements from each of the From arigo at codespeak.net Mon Mar 21 18:57:11 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 21 Mar 2005 18:57:11 +0100 (MET) Subject: [pypy-svn] r10009 - in pypy/dist/pypy/objspace: . test Message-ID: <20050321175711.065F227C1A@code1.codespeak.net> Author: arigo Date: Mon Mar 21 18:57:11 2005 New Revision: 10009 Modified: pypy/dist/pypy/objspace/test/test_thunkobjspace.py pypy/dist/pypy/objspace/thunk.py Log: For convenience, allow thunk(callable, *args, **kwds). Modified: pypy/dist/pypy/objspace/test/test_thunkobjspace.py ============================================================================== --- pypy/dist/pypy/objspace/test/test_thunkobjspace.py (original) +++ pypy/dist/pypy/objspace/test/test_thunkobjspace.py Mon Mar 21 18:57:11 2005 @@ -19,10 +19,10 @@ def test_setitem(self): computed = [] - def f(): + def f(a): computed.append(True) - return 6*7 - x = thunk(f) + return a*7 + x = thunk(f, 6) d = {5: x} d[6] = x d[7] = [] Modified: pypy/dist/pypy/objspace/thunk.py ============================================================================== --- pypy/dist/pypy/objspace/thunk.py (original) +++ pypy/dist/pypy/objspace/thunk.py Mon Mar 21 18:57:11 2005 @@ -18,28 +18,32 @@ """ from proxy import create_proxy_space -from pypy.interpreter import gateway -from pypy.interpreter.baseobjspace import W_Root +from pypy.interpreter import gateway, baseobjspace, argument # __________________________________________________________________________ -class W_Thunk(W_Root, object): - def __init__(w_self, space, w_callable): +class W_Thunk(baseobjspace.W_Root, object): + def __init__(w_self, space, w_callable, args=argument.Arguments([])): w_self.space = space w_self.w_callable = w_callable + w_self.args = args w_self.w_value = None def force(w_self): while isinstance(w_self, W_Thunk): if w_self.w_value is None: - w_self.w_value = w_self.space.call_function(w_self.w_callable) + w_self.w_value = w_self.space.call_args(w_self.w_callable, + w_self.args) w_self.w_callable = None + w_self.args = None w_self = w_self.w_value return w_self -def thunk(space, w_callable): - return W_Thunk(space, w_callable) -app_thunk = gateway.interp2app(thunk) +def thunk(space, w_callable, __args__): + return W_Thunk(space, w_callable, __args__) +app_thunk = gateway.interp2app(thunk, unwrap_spec=[baseobjspace.ObjSpace, + baseobjspace.W_Root, + argument.Arguments]) # __________________________________________________________________________ From tismer at codespeak.net Mon Mar 21 19:56:48 2005 From: tismer at codespeak.net (tismer at codespeak.net) Date: Mon, 21 Mar 2005 19:56:48 +0100 (MET) Subject: [pypy-svn] r10011 - pypy/dist/pypy/translator/tool Message-ID: <20050321185648.C26C127C1D@code1.codespeak.net> Author: tismer Date: Mon Mar 21 19:56:48 2005 New Revision: 10011 Modified: pypy/dist/pypy/translator/tool/buildpyxmodule.py Log: moved the udir import into the function that needs it, in orderto make this module importable when run under py.py Modified: pypy/dist/pypy/translator/tool/buildpyxmodule.py ============================================================================== --- pypy/dist/pypy/translator/tool/buildpyxmodule.py (original) +++ pypy/dist/pypy/translator/tool/buildpyxmodule.py Mon Mar 21 19:56:48 2005 @@ -1,5 +1,4 @@ import autopath -from pypy.tool.udir import udir import py from py.process import cmdexec @@ -155,6 +154,7 @@ # build the flow graph from pypy.objspace.flow import Space + from pypy.tool.udir import udir space = Space() name = func.func_name funcgraph = space.build_flow(func) From tismer at codespeak.net Mon Mar 21 20:18:47 2005 From: tismer at codespeak.net (tismer at codespeak.net) Date: Mon, 21 Mar 2005 20:18:47 +0100 (MET) Subject: [pypy-svn] r10012 - pypy/dist/pypy/objspace/std Message-ID: <20050321191847.1CAE127C1F@code1.codespeak.net> Author: tismer Date: Mon Mar 21 20:18:46 2005 New Revision: 10012 Modified: pypy/dist/pypy/objspace/std/inttype.py Log: __getnewargs__ to make pickle and Samuele's tool happy Modified: pypy/dist/pypy/objspace/std/inttype.py ============================================================================== --- pypy/dist/pypy/objspace/std/inttype.py (original) +++ pypy/dist/pypy/objspace/std/inttype.py Mon Mar 21 20:18:46 2005 @@ -67,8 +67,12 @@ w_obj.__init__(space, value) return w_obj +def descr__getnewargs__(space, w_obj): + from pypy.objspace.std.intobject import W_IntObject + return space.newtuple([W_IntObject(space, w_obj.intval)]) # ____________________________________________________________ int_typedef = StdTypeDef("int", __new__ = newmethod(descr__new__), + __getnewargs__ = newmethod(descr__getnewargs__), ) From rxe at codespeak.net Mon Mar 21 20:53:31 2005 From: rxe at codespeak.net (rxe at codespeak.net) Date: Mon, 21 Mar 2005 20:53:31 +0100 (MET) Subject: [pypy-svn] r10014 - pypy/dist/pypy/interpreter Message-ID: <20050321195331.06C7D27B4B@code1.codespeak.net> Author: rxe Date: Mon Mar 21 20:53:30 2005 New Revision: 10014 Modified: pypy/dist/pypy/interpreter/executioncontext.py Log: Cosmetic Modified: pypy/dist/pypy/interpreter/executioncontext.py ============================================================================== --- pypy/dist/pypy/interpreter/executioncontext.py (original) +++ pypy/dist/pypy/interpreter/executioncontext.py Mon Mar 21 20:53:30 2005 @@ -117,8 +117,6 @@ else: frame.instr_ub = sys.maxint - - def exception_trace(self, operationerr): "Trace function called upon OperationError." operationerr.record_interpreter_traceback() @@ -160,10 +158,7 @@ w_callback = frame.w_f_trace if self.is_tracing or w_callback is None: return - # To get better results when running test_trace.py - #if frame.code.co_filename.find('/lib-python-2.3.4/') <0: - # print 'Skipping', event, frame.code.co_name - # return + self.is_tracing += 1 try: try: From arigo at codespeak.net Mon Mar 21 21:01:14 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 21 Mar 2005 21:01:14 +0100 (MET) Subject: [pypy-svn] r10015 - pypy/dist/pypy/objspace Message-ID: <20050321200114.AD84B27B5D@code1.codespeak.net> Author: arigo Date: Mon Mar 21 21:01:14 2005 New Revision: 10015 Added: pypy/dist/pypy/objspace/idhack.py (contents, props changed) Log: An example of strange object space. Very crashy... Added: pypy/dist/pypy/objspace/idhack.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/objspace/idhack.py Mon Mar 21 21:01:14 2005 @@ -0,0 +1,53 @@ +"""Example usage: + + $ python interpreter/py.py -o idhack + >>> x = 6 + >>> id(x) + 12345678 + >>> become(x, 7) + >>> x + 7 + >>> id(x) + 12345678 + +""" + +import autopath +from pypy.objspace import std +from pypy.interpreter import gateway + +# ____________________________________________________________ + +def idhack(w_obj): + try: + return w_obj.__id + except AttributeError: + w_obj.__id = id(w_obj) + return w_obj.__id + + +class IdHackSpace(std.Space): + + def initialize(self): + super(IdHackSpace, self).initialize() + self.setitem(self.builtin.w_dict, self.wrap('become'), + self.wrap(app_become)) + + def is_(self, w_one, w_two): + if idhack(w_one) == idhack(w_two): + return self.w_True + return self.w_False + + def id(self, w_obj): + return self.wrap(idhack(w_obj)) + + +Space = IdHackSpace + +# ____________________________________________________________ + +def become(space, w_target, w_source): + w_target.__class__ = w_source.__class__ + w_target.__dict__ = w_source.__dict__ + return space.w_None +app_become = gateway.interp2app(become) From pedronis at codespeak.net Mon Mar 21 21:03:38 2005 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Mon, 21 Mar 2005 21:03:38 +0100 (MET) Subject: [pypy-svn] r10016 - pypy/dist/pypy/interpreter Message-ID: <20050321200338.1351B27B5A@code1.codespeak.net> Author: pedronis Date: Mon Mar 21 21:03:37 2005 New Revision: 10016 Modified: pypy/dist/pypy/interpreter/interactive.py pypy/dist/pypy/interpreter/main.py Log: let's interactive console and run func share one __main__ module. Modified: pypy/dist/pypy/interpreter/interactive.py ============================================================================== --- pypy/dist/pypy/interpreter/interactive.py (original) +++ pypy/dist/pypy/interpreter/interactive.py Mon Mar 21 21:03:37 2005 @@ -1,7 +1,7 @@ import autopath from pypy.interpreter import error -from pypy.interpreter import executioncontext, baseobjspace, module +from pypy.interpreter import executioncontext, baseobjspace, module, main import sys import code import time @@ -15,11 +15,8 @@ self.ec = executioncontext.ExecutionContext(self.space) space=self.space - w_main = space.wrap('__main__') - mainmodule = module.Module(space, w_main) - w_modules = space.sys.get('modules') - space.setitem(w_modules, w_main, mainmodule) + mainmodule = main.ensure__main__(space) self.w_globals = mainmodule.w_dict space.setitem(self.w_globals, space.wrap('__builtins__'), space.builtin) # XXX check: do we need self.ec, self.w_globals? Modified: pypy/dist/pypy/interpreter/main.py ============================================================================== --- pypy/dist/pypy/interpreter/main.py (original) +++ pypy/dist/pypy/interpreter/main.py Mon Mar 21 21:03:37 2005 @@ -3,6 +3,18 @@ from pypy.interpreter.error import OperationError import sys +def ensure__main__(space): + w_main = space.wrap('__main__') + w_modules = space.sys.get('modules') + try: + return space.getitem(w_modules, w_main) + except OperationError, e: + if not e.match(space, space.w_KeyError): + raise + mainmodule = module.Module(space, w_main) + space.setitem(w_modules, w_main, mainmodule) + return mainmodule + def _run_eval_string(source, filename, space, eval): if eval: cmd = 'eval' @@ -17,12 +29,10 @@ w = space.wrap w_code = space.builtin.call('compile', w(source), w(filename), w(cmd), w(0), w(0)) - w_main = space.wrap('__main__') - mainmodule = module.Module(space, w_main) - w_modules = space.sys.get('modules') - space.setitem(w_modules, w_main, mainmodule) + mainmodule = ensure__main__(space) w_globals = mainmodule.w_dict + space.setitem(w_globals, w('__builtins__'), space.builtin) pycode = space.interpclass_w(w_code) From jriehl at codespeak.net Mon Mar 21 21:11:06 2005 From: jriehl at codespeak.net (jriehl at codespeak.net) Date: Mon, 21 Mar 2005 21:11:06 +0100 (MET) Subject: [pypy-svn] r10017 - in pypy/dist/pypy/objspace/std: . test Message-ID: <20050321201106.4F32927B5A@code1.codespeak.net> Author: jriehl Date: Mon Mar 21 21:11:06 2005 New Revision: 10017 Modified: pypy/dist/pypy/objspace/std/stringobject.py pypy/dist/pypy/objspace/std/test/test_stringobject.py Log: Fixed bug in splitlines() implementation for string objects. Modified: pypy/dist/pypy/objspace/std/stringobject.py ============================================================================== --- pypy/dist/pypy/objspace/std/stringobject.py (original) +++ pypy/dist/pypy/objspace/std/stringobject.py Mon Mar 21 21:11:06 2005 @@ -721,7 +721,10 @@ w_item = _strip(space, w_item, W_StringObject(space,'\n'), left=0, right=1) L.append(w_item) else: - break + if oldpos < selflen: + w_item = space.wrap(u_self[oldpos:]) + L.append(w_item) + break return W_ListObject(space, L) def str_zfill__String_ANY(space, w_self, w_width): Modified: pypy/dist/pypy/objspace/std/test/test_stringobject.py ============================================================================== --- pypy/dist/pypy/objspace/std/test/test_stringobject.py (original) +++ pypy/dist/pypy/objspace/std/test/test_stringobject.py Mon Mar 21 21:11:06 2005 @@ -317,6 +317,16 @@ def test_splitlines(self): + s = "" + assert s.splitlines() == [] + assert s.splitlines() == s.splitlines(1) + s = "a + 4" + assert s.splitlines() == ['a + 4'] + # The following is true if no newline in string. + assert s.splitlines() == s.splitlines(1) + s = "a + 4\nb + 2" + assert s.splitlines() == ['a + 4', 'b + 2'] + assert s.splitlines(1) == ['a + 4\n', 'b + 2'] s="ab\nab\n \n x\n\n\n" assert s.splitlines() ==['ab', 'ab', ' ', ' x', '', ''] assert s.splitlines() ==s.splitlines(0) From arigo at codespeak.net Mon Mar 21 21:13:42 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 21 Mar 2005 21:13:42 +0100 (MET) Subject: [pypy-svn] r10018 - in pypy/dist/pypy/objspace: . test Message-ID: <20050321201342.9B71927B5A@code1.codespeak.net> Author: arigo Date: Mon Mar 21 21:13:42 2005 New Revision: 10018 Added: pypy/dist/pypy/objspace/test/test_idhackobjspace.py (contents, props changed) Modified: pypy/dist/pypy/objspace/idhack.py Log: Saner semantics for id() in the presence of become(). Modified: pypy/dist/pypy/objspace/idhack.py ============================================================================== --- pypy/dist/pypy/objspace/idhack.py (original) +++ pypy/dist/pypy/objspace/idhack.py Mon Mar 21 21:13:42 2005 @@ -22,8 +22,7 @@ try: return w_obj.__id except AttributeError: - w_obj.__id = id(w_obj) - return w_obj.__id + return id(w_obj) class IdHackSpace(std.Space): @@ -49,5 +48,6 @@ def become(space, w_target, w_source): w_target.__class__ = w_source.__class__ w_target.__dict__ = w_source.__dict__ + w_target.__id = idhack(w_source) return space.w_None app_become = gateway.interp2app(become) Added: pypy/dist/pypy/objspace/test/test_idhackobjspace.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/objspace/test/test_idhackobjspace.py Mon Mar 21 21:13:42 2005 @@ -0,0 +1,19 @@ + +class AppTest_IdHack: + + objspacename = 'idhack' + + def test_simple(self): + x = 5 + y = 6 + assert x is not y + become(x, y) + assert x is y + + def test_id(self): + # these are the Smalltalk semantics of become(). + x = 5; idx = id(x) + y = 6; idy = id(y) + assert idx != idy + become(x, y) + assert id(x) == id(y) == idy From arigo at codespeak.net Mon Mar 21 21:17:00 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 21 Mar 2005 21:17:00 +0100 (MET) Subject: [pypy-svn] r10019 - pypy/dist/pypy/objspace Message-ID: <20050321201700.1EC0D27B5A@code1.codespeak.net> Author: arigo Date: Mon Mar 21 21:16:59 2005 New Revision: 10019 Modified: pypy/dist/pypy/objspace/idhack.py Log: Typo. But test_idhack and test_thunk cannot succeed unless you run them alone, for the reason that we can't instantiate several StdObjSpace at the same time :-( Modified: pypy/dist/pypy/objspace/idhack.py ============================================================================== --- pypy/dist/pypy/objspace/idhack.py (original) +++ pypy/dist/pypy/objspace/idhack.py Mon Mar 21 21:16:59 2005 @@ -12,7 +12,6 @@ """ -import autopath from pypy.objspace import std from pypy.interpreter import gateway From rxe at codespeak.net Mon Mar 21 21:20:55 2005 From: rxe at codespeak.net (rxe at codespeak.net) Date: Mon, 21 Mar 2005 21:20:55 +0100 (MET) Subject: [pypy-svn] r10020 - in pypy/dist/pypy: objspace tool Message-ID: <20050321202055.584AE27B58@code1.codespeak.net> Author: rxe Date: Mon Mar 21 21:20:55 2005 New Revision: 10020 Modified: pypy/dist/pypy/objspace/trace.py pypy/dist/pypy/tool/traceinteractive.py pypy/dist/pypy/tool/traceop.py Log: Fix up traceobject space to trace in realtime - warranting itself the name trace object space. ResultPrinter now acts reasonably - with options to recurse on operations and to ignore any frames with code objects that are applevel. Modified: pypy/dist/pypy/objspace/trace.py ============================================================================== --- pypy/dist/pypy/objspace/trace.py (original) +++ pypy/dist/pypy/objspace/trace.py Mon Mar 21 21:20:55 2005 @@ -4,7 +4,8 @@ """ from __future__ import generators -from pypy.tool import pydis +from pypy.tool import pydis +from pypy.tool.traceop import ResultPrinter from pypy.interpreter.baseobjspace import ObjSpace # __________________________________________________________________________ @@ -49,24 +50,21 @@ def __init__(self, callinfo, e): self.callinfo = callinfo self.ex = e - + class TraceResult(object): - """ this is the state of tracing-in-progress. """ + """ This is the state of tracing-in-progress. """ def __init__(self, tracespace): self.events = [] + self.reentrant = True self.tracespace = tracespace + self.printer = ResultPrinter() - def append(self, arg): - self.events.append(arg) - - def getdisresult(self, frame, _cache = {}): - """ return (possibly cached) pydis result for the given frame. """ - try: - return _cache[id(frame.code)] - except KeyError: - res = _cache[id(frame.code)] = pydis.pydis(frame.code) - assert res is not None - return res + def append(self, event): + if self.reentrant: + self.reentrant = False + self.events.append(event) + self.printer.print_event(self.tracespace, self, event) + self.reentrant = True def getbytecodes(self): for event in self.events: @@ -83,6 +81,16 @@ for event in self.events: yield event + def getdisresult(self, frame, _cache = {}): # XXX Should perhaps be local to TraceResult + """ return (possibly cached) pydis result for the given frame. """ + + try: + return _cache[id(frame.code)] + except KeyError: + res = _cache[id(frame.code)] = pydis.pydis(frame.code) + assert res is not None + return res + # __________________________________________________________________________ # # Tracer Proxy objects @@ -93,7 +101,7 @@ def __init__(self, result, ec): self.ec = ec self.result = result - + def __getattr__(self, name): """ generically pass through everything else ... """ return getattr(self.ec, name) @@ -112,13 +120,14 @@ def bytecode_trace(self, frame): """ called just before execution of a bytecode. """ self.result.append(ExecBytecode(frame)) + self.ec.bytecode_trace(frame) class CallableTracer(object): def __init__(self, result, name, func): self.result = result self.name = name self.func = func - + def __call__(self, *args, **kwargs): callinfo = CallInfo(self.name, self.func, args, kwargs) self.result.append(CallBegin(callinfo)) @@ -152,9 +161,12 @@ global operations if operations is None: operations = dict([(r[0], r[0]) for r in ObjSpace.MethodTable]) - for name in ObjSpace.IrregularOpTable+ ["get_and_call_function"]: + for name in ObjSpace.IrregularOpTable + ["get_and_call_function"]: operations[name] = name + # Remove list + for name in ["wrap", "unwrap"]: + operations.pop(name, None) return operations def create_trace_space(space = None, operations = None): @@ -207,8 +219,7 @@ trace_clz = type("Trace" + space.__class__.__name__, (Trace,), {}) space.__oldclass__, space.__class__ = space.__class__, trace_clz - - # XXX Ensure space's sys & builtin are fully loaded? + space.settrace() return space Modified: pypy/dist/pypy/tool/traceinteractive.py ============================================================================== --- pypy/dist/pypy/tool/traceinteractive.py (original) +++ pypy/dist/pypy/tool/traceinteractive.py Mon Mar 21 21:20:55 2005 @@ -18,7 +18,6 @@ import autopath from pypy.tool import pydis -from pypy.tool.traceop import ResultPrinter from pypy.interpreter import executioncontext, pyframe, baseobjspace from pypy.interpreter.baseobjspace import ObjSpace @@ -109,7 +108,6 @@ # Trace is binary (on or off), but we have different print levels # for tracelevel > 0 self.tracelevel = 0 - self.resprinter = ResultPrinter() def interact(self, banner=None): if banner is None: @@ -160,10 +158,6 @@ self.tracelevel = tracelevel - # XXX Do something better than this - I'm not really sure what is useful - # and what isn't (rxe) - self.resprinter.operations_level = tracelevel - def runcode(self, code): # 'code' is a CPython code object from pypy.interpreter.pycode import PyCode @@ -189,14 +183,13 @@ if tracelevel != self.tracelevel: self.set_tracelevel(tracelevel) - if res is not None and self.tracelevel: - self.resprinter.print_result(s, res) + #if res is not None and self.tracelevel: + # self.resprinter.print_result(s, res) except baseobjspace.OperationError, operationerr: if self.tracelevel: res = s.getresult() s.settrace() - self.resprinter.print_result(s, res) # XXX insert exception info into the application-level sys.last_xxx print Modified: pypy/dist/pypy/tool/traceop.py ============================================================================== --- pypy/dist/pypy/tool/traceop.py (original) +++ pypy/dist/pypy/tool/traceop.py Mon Mar 21 21:20:55 2005 @@ -1,21 +1,6 @@ import autopath -from pypy.tool import pydis -from pypy.objspace import trace - -def getdisresult(obj, _cache={}): - """ return dissassemble result for the given obj which can be a - pyframe or function or a code object. - """ - obj = getattr(obj, 'func_code', obj) - obj = getattr(obj, 'code', obj) - try: - return _cache[obj] - except KeyError: - disresult = _cache[obj] = pydis.pydis(obj) - return disresult - class Stack(list): push = list.append @@ -30,50 +15,38 @@ class ResultPrinter: - def __init__(self, - operations_level = 2, - indentor = ' ', - skip_bytecodes = ["PRINT_EXPR", "PRINT_ITEM", "PRINT_NEWLINE"]): + def __init__(self, show_applevel = False, recursive_operations = False, indentor = ' '): # Configurable stuff - self.indentor = indentor - self.skip_bytecodes = skip_bytecodes - self.operations_level = operations_level - - self.reset() + self.indentor = indentor + self.show_applevel = show_applevel + self.recursive_operations = recursive_operations + + # Keeps a stack of current state to handle + # showing of applevel and recursive operations + self.indent_state = Stack() def reset(self): - # State stuff - self.ops = Stack() - self.frames = Stack() - self.frame_count = 0 - self.skip_frame_count = None + self.indent_state = Stack() def print_line(self, line, additional_indent = 0): - if self.skip_frame_count is not None: - return - - if self.frame_count: - indent = self.frame_count + additional_indent - 1 + state = self.indent_state.top() + if state is not None and not state[0]: + return + + indent_count = len([c for c, t, f in self.indent_state if c]) + if indent_count: + indent = indent_count + additional_indent - 1 assert (indent >= 0) line = (self.indentor * indent) + "|-" + line print line - + def print_line_operations(self, line, additional_indent = 0): - # Don't allow operations to be exposed if operations level is up - # but do allow operations to be printed - if len(self.ops) > self.operations_level: - return - self.print_line(line, additional_indent = additional_indent) def print_frame(self, print_type, frame): - # Don't allow frames to be exposed if operations level is up - if len(self.ops) >= self.operations_level: - return - code = getattr(frame, 'code', None) filename = getattr(code, 'co_filename', "") lineno = getattr(code, 'co_firstlineno', "") @@ -82,15 +55,9 @@ self.print_line(s) def print_bytecode(self, index, bytecode): - - # Don't allow bytecodes to be exposed if operations level is up - if len(self.ops) >= self.operations_level: - return - s = "%2d%s%s" % (index, (self.indentor * 2), bytecode) self.print_line(s) - def print_op_enter(self, name, str_args): s = " " * 17 s += ">> %s%s" % (name, str_args) @@ -102,104 +69,105 @@ s += "%s =: %s" % (name, str_res) self.print_line_operations(s) - def print_op_exc(self, name, exc): s = " " * 17 s += "x= %s %s" % (name, exc) self.print_line_operations(s) - - def print_result(self, space, traceres): + def print_result(self, space, event_result): + for event in event_result.getevents(): + print_event(space, event, event_result) + + def print_event(self, space, event_result, event): + from pypy.objspace import trace + + if isinstance(event, trace.EnterFrame): + frame = event.frame + if self.show_applevel or not frame.code.getapplevel(): + show = True + else: + show = False - self.reset() + self.indent_state.append((show, trace.EnterFrame, frame)) + self.print_frame("enter", frame) - for event in traceres.getevents(): + elif isinstance(event, trace.LeaveFrame): - if isinstance(event, trace.EnterFrame): - frame = event.frame - self.print_frame("enter", frame) - - self.frames.push(frame) - self.frame_count += 1 - - elif isinstance(event, trace.LeaveFrame): - lastframe = self.frames.pop() - self.frame_count -= 1 - - # Reset skip frame count? - if self.frame_count < self.skip_frame_count: - self.skip_frame_count = None - - self.print_frame("leave", lastframe) - - elif isinstance(event, trace.ExecBytecode): - - # Reset skip frame count? - if self.frame_count == self.skip_frame_count: - self.skip_frame_count = None - - frame = event.frame - assert (frame == self.frames.top()) - - # Get bytecode from frame - disresult = getdisresult(frame) - bytecode = disresult.getbytecode(event.index) - self.print_bytecode(event.index, bytecode) - - # When operations_level > 1, some bytecodes produce high number of - # operations / bytecodes (usually because they have been written at app - # level) - this hack avoids them recursing on them selves - if bytecode.name in self.skip_bytecodes: - self.print_line("...", 1) - self.skip_frame_count = self.frame_count - - elif isinstance(event, trace.CallBegin): - info = event.callinfo - - self.ops.push(info) - lastframe = self.frames.top() - self.print_op_enter(info.name, repr_args(space, lastframe, info.args)) - self.frame_count += 1 - - elif isinstance(event, trace.CallFinished): - info = event.callinfo - - self.frame_count -= 1 - self.print_op_leave(info.name, repr_value(space, event.res)) - - assert self.ops.pop() == event.callinfo - - elif isinstance(event, trace.CallException): - info = event.callinfo - self.frame_count -= 1 - - self.print_op_exc(info.name, event.ex) - - assert self.ops.pop() == event.callinfo + lastframe = self.indent_state.top()[2] + assert lastframe is not None - else: - pass + self.print_frame("leave", lastframe) + self.indent_state.pop() + elif isinstance(event, trace.ExecBytecode): + + frame = event.frame + assert (frame == self.get_last_frame()) + + # Get bytecode from frame + disresult = event_result.getdisresult(frame) + bytecode = disresult.getbytecode(event.index) + self.print_bytecode(event.index, bytecode) + + elif isinstance(event, trace.CallBegin): + lastframe = self.get_last_frame() + info = event.callinfo + + show = True + + # Check if we are in applevel? + if not self.show_applevel: + if lastframe is None or lastframe.code.getapplevel(): + show = False + + # Check if recursive operations? + prev_indent_state = self.indent_state.top() + if not self.recursive_operations and prev_indent_state is not None: + if prev_indent_state[1] == trace.CallBegin: + show = False + + self.indent_state.append((show, trace.CallBegin, None)) + self.print_op_enter(info.name, repr_args(space, + self.get_last_frame(), + info.args)) + + elif isinstance(event, trace.CallFinished): + info = event.callinfo + + self.print_op_leave(info.name, repr_value(space, event.res)) + self.indent_state.pop() + + elif isinstance(event, trace.CallException): + info = event.callinfo + + self.print_op_exc(info.name, event.ex) + self.indent_state.pop() + + def get_last_frame(self): + for c, t, f in self.indent_state[::-1]: + if f is not None: + return f + print_result = ResultPrinter().print_result def repr_value(space, value): """ representations for debugging purposes """ - res = str(value) try: # XXX Sure this won't go down well - didn't really want # to clutter up the interpeter code from pypy.interpreter.function import Function, Method + from pypy.interpreter.eval import Code if isinstance(value, Function): - res = "Function(%s, %s)" % (value.name, value.code) + res = "Function(%s)" % value.name if isinstance(value, Method): - res = "Method(%s, %s)" % (value.w_function.name, value.w_function.code) - - except Exception, exc: - pass + res = "Method(%s)" % value.w_function.name + raise Exception, "XXX only certain types or toooo slow" + except: + res = str(value) - return res[:240] + return res[:80] def repr_args(space, frame, args): l = [] @@ -213,7 +181,6 @@ return "(" + ", ".join(l) + ")" - def perform_trace(tspace, app_func, *args_w, **kwds_w): from pypy.interpreter.gateway import app2interp from pypy.interpreter.argument import Arguments @@ -231,8 +198,9 @@ tspace.settrace() return w_result, trace_result - if __name__ == '__main__': + + from pypy.objspace import trace from pypy.tool import option args = option.process_options(option.get_standard_options(), option.Options) @@ -250,7 +218,5 @@ return count # Note includes lazy loading of builtins - res, traceres = perform_trace(tspace, app_test, tspace.wrap(5)) - print_result(tspace, traceres) - - print "Result", res + res = perform_trace(tspace, app_test, tspace.wrap(5)) + print "Result:", res From tismer at codespeak.net Mon Mar 21 21:21:54 2005 From: tismer at codespeak.net (tismer at codespeak.net) Date: Mon, 21 Mar 2005 21:21:54 +0100 (MET) Subject: [pypy-svn] r10021 - pypy/dist/pypy/objspace/std Message-ID: <20050321202154.3433727B58@code1.codespeak.net> Author: tismer Date: Mon Mar 21 21:21:53 2005 New Revision: 10021 Modified: pypy/dist/pypy/objspace/std/floattype.py pypy/dist/pypy/objspace/std/inttype.py pypy/dist/pypy/objspace/std/longtype.py pypy/dist/pypy/objspace/std/stringtype.py pypy/dist/pypy/objspace/std/tupletype.py Log: __getnewargs__ to make pickle and Samuele's tool happy Modified: pypy/dist/pypy/objspace/std/floattype.py ============================================================================== --- pypy/dist/pypy/objspace/std/floattype.py (original) +++ pypy/dist/pypy/objspace/std/floattype.py Mon Mar 21 21:21:53 2005 @@ -19,8 +19,13 @@ w_obj.__init__(space, value) return w_obj +def descr__getnewargs__(space, w_obj): + from pypy.objspace.std.floatobject import W_FloatObject + return space.newtuple([W_FloatObject(space, w_obj.floatval)]) + # ____________________________________________________________ float_typedef = StdTypeDef("float", __new__ = newmethod(descr__new__), + __getnewargs__ = newmethod(descr__getnewargs__), ) Modified: pypy/dist/pypy/objspace/std/inttype.py ============================================================================== --- pypy/dist/pypy/objspace/std/inttype.py (original) +++ pypy/dist/pypy/objspace/std/inttype.py Mon Mar 21 21:21:53 2005 @@ -70,6 +70,7 @@ def descr__getnewargs__(space, w_obj): from pypy.objspace.std.intobject import W_IntObject return space.newtuple([W_IntObject(space, w_obj.intval)]) + # ____________________________________________________________ int_typedef = StdTypeDef("int", Modified: pypy/dist/pypy/objspace/std/longtype.py ============================================================================== --- pypy/dist/pypy/objspace/std/longtype.py (original) +++ pypy/dist/pypy/objspace/std/longtype.py Mon Mar 21 21:21:53 2005 @@ -53,10 +53,15 @@ w_obj.__init__(space, value) return w_obj +def descr__getnewargs__(space, w_obj): + from pypy.objspace.std.longobject import W_LongObject + return space.newtuple([W_LongObject(space, w_obj.longval)]) + # ____________________________________________________________ long_typedef = StdTypeDef("long", __new__ = newmethod(descr__new__), + __getnewargs__ = newmethod(descr__getnewargs__), ) # hack to allow automatic int to long conversion: the int.__xyz__ methods # will fall back to their long.__xyz__ counterparts if they fail Modified: pypy/dist/pypy/objspace/std/stringtype.py ============================================================================== --- pypy/dist/pypy/objspace/std/stringtype.py (original) +++ pypy/dist/pypy/objspace/std/stringtype.py Mon Mar 21 21:21:53 2005 @@ -49,9 +49,14 @@ w_obj.__init__(space, value) return w_obj +def descr__getnewargs__(space, w_obj): + from pypy.objspace.std.stringobject import W_StringObject + return space.newtuple([W_StringObject(space, w_obj._value)]) + # ____________________________________________________________ str_typedef = StdTypeDef("str", basestring_typedef, __new__ = newmethod(descr__new__), + __getnewargs__ = newmethod(descr__getnewargs__), ) str_typedef.registermethods(globals()) Modified: pypy/dist/pypy/objspace/std/tupletype.py ============================================================================== --- pypy/dist/pypy/objspace/std/tupletype.py (original) +++ pypy/dist/pypy/objspace/std/tupletype.py Mon Mar 21 21:21:53 2005 @@ -14,8 +14,13 @@ w_obj.__init__(space, tuple_w) return w_obj +def descr__getnewargs__(space, w_obj): + from pypy.objspace.std.tupleobject import W_TupleObject + return space.newtuple([W_TupleObject(space, w_obj.wrappeditems)]) + # ____________________________________________________________ tuple_typedef = StdTypeDef("tuple", __new__ = newmethod(descr__new__), + __getnewargs__ = newmethod(descr__getnewargs__), ) From briandorsey at codespeak.net Mon Mar 21 21:22:32 2005 From: briandorsey at codespeak.net (briandorsey at codespeak.net) Date: Mon, 21 Mar 2005 21:22:32 +0100 (MET) Subject: [pypy-svn] r10022 - pypy/dist/pypy/lib Message-ID: <20050321202232.77C8627B58@code1.codespeak.net> Author: briandorsey Date: Mon Mar 21 21:22:32 2005 New Revision: 10022 Modified: pypy/dist/pypy/lib/binascii.py Log: binascii.py - the test_uu tests now pass. Modified: pypy/dist/pypy/lib/binascii.py ============================================================================== --- pypy/dist/pypy/lib/binascii.py (original) +++ pypy/dist/pypy/lib/binascii.py Mon Mar 21 21:22:32 2005 @@ -5,28 +5,31 @@ pass def a2b_uu(s): - length = ord(s[0]) - 0x20 - a = quadruplets(s[1:]) - ''' - for A, B, C, D in a: - print chr((A - 0x20) << 2 | (((B - 0x20) >> 4) & 0x3)) - print chr(((B - 0x20) & 0xF) << 4 | (((C - 0x20) >> 2) & 0xF)) - print chr(((C - 0x20) & 0x3) << 6 | ((D - 0x20) & 0x3F)) - ''' - - result = [''.join( - [chr((A - 0x20) << 2 | (((B - 0x20) >> 4) & 0x3)), - chr(((B - 0x20) & 0xF) << 4 | (((C - 0x20) >> 2) & 0xF)), - chr(((C - 0x20) & 0x3) << 6 | ((D - 0x20) & 0x3F)) - ]) for A, B, C, D in a] - return ''.join(result)[:length] + length = (ord(s[0]) - 0x20) % 64 + a = quadruplets(s[1:].rstrip()) + try: + result = [''.join( + [chr((A - 0x20) << 2 | (((B - 0x20) >> 4) & 0x3)), + chr(((B - 0x20) & 0xF) << 4 | (((C - 0x20) >> 2) & 0xF)), + chr(((C - 0x20) & 0x3) << 6 | ((D - 0x20) & 0x3F)) + ]) for A, B, C, D in a] + except ValueError: + raise Error, 'Illegal char' + result = ''.join(result) + trailingdata = result[length:] + if trailingdata.strip('\x00'): + raise Error, 'Trailing garbage' + result = result[:length] + if len(result) < length: + result += ((length - len(result)) * '\x00') + return result def quadruplets(s): while s: try: a, b, c, d = s[0], s[1], s[2], s[3] except IndexError: - s += '\0\0\0' + s += ' ' yield ord(s[0]), ord(s[1]), ord(s[2]), ord(s[3]) return s = s[4:] @@ -43,7 +46,7 @@ chr(0x20 + (((A << 4) | ((B >> 4) & 0xF)) & 0x3F)), chr(0x20 + (((B << 2) | ((C >> 6) & 0x3)) & 0x3F)), chr(0x20 + (( C ) & 0x3F))]) for A, B, C in a] - return chr(ord(' ') + (length & 077)) + ''.join(result) + '\\n' + return chr(ord(' ') + (length & 077)) + ''.join(result) + '\n' def triples(s): while s: @@ -56,9 +59,9 @@ s = s[3:] yield ord(a), ord(b), ord(c) -print b2a_uu('1234567') -print b2a_uu('123456789012345678901234567890123456789012345') +#print b2a_uu('1234567') +#print b2a_uu('123456789012345678901234567890123456789012345') #print b2a_uu('1234567890123456789012345678901234567890123456') -print '"%s"' % a2b_uu(b2a_uu('1234567')) -print '"%s"' % a2b_uu(b2a_uu('123456789012345678901234567890123456789012345')) +#print '"%s"' % a2b_uu(b2a_uu('1234567')) +#print '"%s"' % a2b_uu(b2a_uu('123456789012345678901234567890123456789012345')) From hpk at codespeak.net Mon Mar 21 21:31:40 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Mon, 21 Mar 2005 21:31:40 +0100 (MET) Subject: [pypy-svn] r10023 - in pypy/dist/pypy/lib: . test2 Message-ID: <20050321203140.C8E6027B58@code1.codespeak.net> Author: hpk Date: Mon Mar 21 21:31:40 2005 New Revision: 10023 Modified: pypy/dist/pypy/lib/itertools.py pypy/dist/pypy/lib/test2/test_itertools.py Log: use the plain test_itertools but with slower contants Modified: pypy/dist/pypy/lib/itertools.py ============================================================================== --- pypy/dist/pypy/lib/itertools.py (original) +++ pypy/dist/pypy/lib/itertools.py Mon Mar 21 21:31:40 2005 @@ -356,20 +356,20 @@ s = slice(*args) self.start, self.stop, self.step = s.start or 0, s.stop, s.step or 1 self.donext = iter(iterable).next + self.cnt = 0 def __iter__(self): - cnt = 0 - while cnt < self.start: + return self + + def next(self): + while self.cnt < self.start: self.donext() - cnt += 1 - while self.stop is None or cnt < self.stop: - yield self.donext() - cnt += 1 - skip = self.step - 1 - while skip: - self.donext() - cnt += 1 - skip -= 1 + self.cnt += 1 + if self.stop is None or self.cnt < self.stop: + self.start += self.step + self.cnt += 1 + return self.donext() + raise StopIteration class izip: """Make an iterator that aggregates elements from each of the Modified: pypy/dist/pypy/lib/test2/test_itertools.py ============================================================================== --- pypy/dist/pypy/lib/test2/test_itertools.py (original) +++ pypy/dist/pypy/lib/test2/test_itertools.py Mon Mar 21 21:31:40 2005 @@ -95,9 +95,8 @@ zip('abc', 'def')) self.assertEqual([pair for pair in izip('abc', 'def')], zip('abc', 'def')) - - # ids = map(id, izip('abc', 'def')) - # self.assertEqual(min(ids), max(ids)) ## NOT FEASIBLE IN PYPY + ids = map(id, izip('abc', 'def')) + self.assertEqual(min(ids), max(ids)) ids = map(id, list(izip('abc', 'def'))) self.assertEqual(len(dict.fromkeys(ids)), len(ids)) @@ -334,7 +333,7 @@ class TestVariousIteratorArgs(unittest.TestCase): def test_chain(self): - for s in ("123", "", range(1000), ('do', 1.2), xrange(2000,2200,5)): + for s in ("123", "", range(6), ('do', 1.2), xrange(2000,2030,5)): for g in (G, I, Ig, S, L, R): self.assertEqual(list(chain(g(s))), list(g(s))) self.assertEqual(list(chain(g(s), g(s))), list(g(s))+list(g(s))) @@ -343,7 +342,7 @@ self.assertRaises(ZeroDivisionError, list, chain(E(s))) def test_cycle(self): - for s in ("123", "", range(1000), ('do', 1.2), xrange(2000,2200,5)): + for s in ("123", "", range(6), ('do', 1.2), xrange(2000,2030,5)): for g in (G, I, Ig, S, L, R): tgtlen = len(s) * 3 expected = list(g(s))*3 @@ -354,7 +353,7 @@ self.assertRaises(ZeroDivisionError, list, cycle(E(s))) def test_ifilter(self): - for s in (range(10), range(0), range(1000), (7,11), xrange(2000,2200,5)): + for s in (range(10), range(0), range(6), (7,11), xrange(2000,2030,5)): for g in (G, I, Ig, S, L, R): self.assertEqual(list(ifilter(isEven, g(s))), filter(isEven, g(s))) self.assertRaises(TypeError, ifilter, isEven, X(s)) @@ -362,7 +361,7 @@ self.assertRaises(ZeroDivisionError, list, ifilter(isEven, E(s))) def test_ifilterfalse(self): - for s in (range(10), range(0), range(1000), (7,11), xrange(2000,2200,5)): + for s in (range(10), range(0), range(10), (7,11), xrange(2000,2030,5)): for g in (G, I, Ig, S, L, R): self.assertEqual(list(ifilterfalse(isEven, g(s))), filter(isOdd, g(s))) self.assertRaises(TypeError, ifilterfalse, isEven, X(s)) @@ -370,7 +369,7 @@ self.assertRaises(ZeroDivisionError, list, ifilterfalse(isEven, E(s))) def test_izip(self): - for s in ("123", "", range(1000), ('do', 1.2), xrange(2000,2200,5)): + for s in ("123", "", range(10), ('do', 1.2), xrange(2000,2030,5)): for g in (G, I, Ig, S, L, R): self.assertEqual(list(izip(g(s))), zip(g(s))) self.assertEqual(list(izip(g(s), g(s))), zip(g(s), g(s))) @@ -388,7 +387,7 @@ self.assertRaises(ZeroDivisionError, list, imap(onearg, E(s))) def test_islice(self): - for s in ("12345", "", range(1000), ('do', 1.2), xrange(2000,2200,5)): + for s in ("12345", "", range(10), ('do', 1.2), xrange(2000,2030,5)): for g in (G, I, Ig, S, L, R): self.assertEqual(list(islice(g(s),1,None,2)), list(g(s))[1::2]) self.assertRaises(TypeError, islice, X(s), 10) @@ -405,7 +404,7 @@ self.assertRaises(ZeroDivisionError, list, starmap(operator.pow, E(ss))) def test_takewhile(self): - for s in (range(10), range(0), range(1000), (7,11), xrange(2000,2200,5)): + for s in (range(10), range(0), range(10), (7,11), xrange(2000,2030,5)): for g in (G, I, Ig, S, L, R): tgt = [] for elem in g(s): @@ -417,7 +416,7 @@ self.assertRaises(ZeroDivisionError, list, takewhile(isEven, E(s))) def test_dropwhile(self): - for s in (range(10), range(0), range(1000), (7,11), xrange(2000,2200,5)): + for s in (range(10), range(0), range(10), (7,11), xrange(2000,2030,5)): for g in (G, I, Ig, S, L, R): tgt = [] for elem in g(s): From jacob at codespeak.net Mon Mar 21 22:16:58 2005 From: jacob at codespeak.net (jacob at codespeak.net) Date: Mon, 21 Mar 2005 22:16:58 +0100 (MET) Subject: [pypy-svn] r10024 - in pypy/dist/pypy: lib module/sys2 Message-ID: <20050321211658.49DC827B60@code1.codespeak.net> Author: jacob Date: Mon Mar 21 22:16:58 2005 New Revision: 10024 Modified: pypy/dist/pypy/lib/binascii.py pypy/dist/pypy/module/sys2/state.py Log: Added non-working base64. Modified: pypy/dist/pypy/lib/binascii.py ============================================================================== --- pypy/dist/pypy/lib/binascii.py (original) +++ pypy/dist/pypy/lib/binascii.py Mon Mar 21 22:16:58 2005 @@ -59,6 +59,32 @@ s = s[3:] yield ord(a), ord(b), ord(c) +def b2a_base64(s): + length = len(s) + final_length = length % 3 + + a = triples(s[:length - final_length]) + result = [''.join( + [chr(0x20 + (( A >> 2 ) & 0x3F)), + chr(0x20 + (((A << 4) | ((B >> 4) & 0xF)) & 0x3F)), + chr(0x20 + (((B << 2) | ((C >> 6) & 0x3)) & 0x3F)), + chr(0x20 + (( C ) & 0x3F))]) for A, B, C in a] + final = s[length - final_length:] + if len(final) == 0: + snippet = '' + elif len(final) == 1: + a = ord(final[0]) + print a + snippet = chr(0x20 + ((a >> 2 ) & 0x3F)) + \ + chr((0x20 + (a << 4 )) & 0x3F) + '==' + else: + a = ord(final[0]) + b = ord(final[1]) + snippet = chr(0x20 + ((a >> 2 ) & 0x3F)) + \ + chr(0x20 + (((a << 4) | ((b >> 4) & 0xF)) + & 0x3F)) + chr((0x20 + (b << 2)) & 0x3F) + '=' + return ''.join(result) + snippet + '\n' + #print b2a_uu('1234567') #print b2a_uu('123456789012345678901234567890123456789012345') #print b2a_uu('1234567890123456789012345678901234567890123456') Modified: pypy/dist/pypy/module/sys2/state.py ============================================================================== --- pypy/dist/pypy/module/sys2/state.py (original) +++ pypy/dist/pypy/module/sys2/state.py Mon Mar 21 22:16:58 2005 @@ -27,7 +27,7 @@ for fn in ['posix', 'nt', 'os2', 'mac', 'ce', 'riscos', 'math', '_codecs', 'array', '_random', '_sre', 'time', '_socket', 'errno', - 'binascii', 'parser']: + 'parser']: if fn not in builtin_modules: try: builtin_modules[fn] = hack_cpython_module(fn) From jacob at codespeak.net Mon Mar 21 22:17:57 2005 From: jacob at codespeak.net (jacob at codespeak.net) Date: Mon, 21 Mar 2005 22:17:57 +0100 (MET) Subject: [pypy-svn] r10025 - pypy/dist/pypy/module/sys2 Message-ID: <20050321211757.C597B27B60@code1.codespeak.net> Author: jacob Date: Mon Mar 21 22:17:57 2005 New Revision: 10025 Modified: pypy/dist/pypy/module/sys2/state.py Log: Reverted mistake in checkin Modified: pypy/dist/pypy/module/sys2/state.py ============================================================================== --- pypy/dist/pypy/module/sys2/state.py (original) +++ pypy/dist/pypy/module/sys2/state.py Mon Mar 21 22:17:57 2005 @@ -27,7 +27,7 @@ for fn in ['posix', 'nt', 'os2', 'mac', 'ce', 'riscos', 'math', '_codecs', 'array', '_random', '_sre', 'time', '_socket', 'errno', - 'parser']: + 'binascii', 'parser']: if fn not in builtin_modules: try: builtin_modules[fn] = hack_cpython_module(fn) From tismer at codespeak.net Mon Mar 21 22:32:27 2005 From: tismer at codespeak.net (tismer at codespeak.net) Date: Mon, 21 Mar 2005 22:32:27 +0100 (MET) Subject: [pypy-svn] r10026 - pypy/dist/pypy/module/builtin Message-ID: <20050321213227.1202027B60@code1.codespeak.net> Author: tismer Date: Mon Mar 21 22:32:26 2005 New Revision: 10026 Modified: pypy/dist/pypy/module/builtin/app_io.py Log: made source ending with white space crapcompile, as Python does it. Modified: pypy/dist/pypy/module/builtin/app_io.py ============================================================================== --- pypy/dist/pypy/module/builtin/app_io.py (original) +++ pypy/dist/pypy/module/builtin/app_io.py Mon Mar 21 22:32:26 2005 @@ -18,7 +18,7 @@ finally: f.close() #Don't exec the source directly, as this loses the filename info - co = compile(source, filename, 'exec') + co = compile(source.rstrip()+"\n", filename, 'exec') exec co in glob, loc def raw_input(prompt=None): From arigo at codespeak.net Mon Mar 21 22:36:53 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 21 Mar 2005 22:36:53 +0100 (MET) Subject: [pypy-svn] r10027 - in pypy/dist/pypy: objspace/flow translator translator/test Message-ID: <20050321213653.C633227B60@code1.codespeak.net> Author: arigo Date: Mon Mar 21 22:36:53 2005 New Revision: 10027 Modified: pypy/dist/pypy/objspace/flow/model.py pypy/dist/pypy/translator/simplify.py pypy/dist/pypy/translator/test/test_translator.py Log: An invalid simplification fixed in simplify.py. Added a test for it and a way to look at the broken graphs when they occur. Modified: pypy/dist/pypy/objspace/flow/model.py ============================================================================== --- pypy/dist/pypy/objspace/flow/model.py (original) +++ pypy/dist/pypy/objspace/flow/model.py Mon Mar 21 22:36:53 2005 @@ -379,6 +379,7 @@ except AssertionError, e: # hack for debug tools only + #graph.show() <== ENABLE THIS TO SEE THE BROKEN GRAPH if this_block[0] and not hasattr(e, '__annotator_block'): setattr(e, '__annotator_block', this_block[0]) raise Modified: pypy/dist/pypy/translator/simplify.py ============================================================================== --- pypy/dist/pypy/translator/simplify.py (original) +++ pypy/dist/pypy/translator/simplify.py Mon Mar 21 22:36:53 2005 @@ -146,12 +146,20 @@ but not used in the target block. Input is a set of blocks""" read_vars = {} # set of variables really used variable_flow = {} # map {Var: list-of-Vars-it-depends-on} - + + def canremove(op, block): + if op.opname not in CanRemove: + return False + if block.exitswitch != Constant(last_exception): + return True + # cannot remove the exc-raising operation + return op is not block.operations[-1] + # compute variable_flow and an initial read_vars for block in blocks: # figure out which variables are ever read for op in block.operations: - if op.opname not in CanRemove: # mark the inputs as really needed + if not canremove(op, block): # mark the inputs as really needed for arg in op.args: read_vars[arg] = True else: @@ -198,7 +206,7 @@ for i in range(len(block.operations)-1, -1, -1): op = block.operations[i] if op.result not in read_vars: - if op.opname in CanRemove: + if canremove(op, block): del block.operations[i] elif op.opname == 'simple_call': # XXX we want to have a more effective and safe Modified: pypy/dist/pypy/translator/test/test_translator.py ============================================================================== --- pypy/dist/pypy/translator/test/test_translator.py (original) +++ pypy/dist/pypy/translator/test/test_translator.py Mon Mar 21 22:36:53 2005 @@ -1,4 +1,14 @@ import autopath from pypy.translator.translator import Translator -from pypy.translator.test import snippet + +def example(d): + try: + d['key'] + except KeyError: + d['key'] = 'value' + +def test_example(): + t = Translator(example) + t.simplify() # this specific example triggered a bug in simplify.py + #t.view() From arigo at codespeak.net Mon Mar 21 22:37:59 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 21 Mar 2005 22:37:59 +0100 (MET) Subject: [pypy-svn] r10028 - pypy/dist/pypy/translator Message-ID: <20050321213759.4EFA227B75@code1.codespeak.net> Author: arigo Date: Mon Mar 21 22:37:59 2005 New Revision: 10028 Modified: pypy/dist/pypy/translator/geninterplevel.py Log: Generate sources with a slightly different layout: a single huge initmodule() function which defines all the translated functions and "globals" as nested-scope-visible locals. Modified: pypy/dist/pypy/translator/geninterplevel.py ============================================================================== --- pypy/dist/pypy/translator/geninterplevel.py (original) +++ pypy/dist/pypy/translator/geninterplevel.py Mon Mar 21 22:37:59 2005 @@ -54,7 +54,7 @@ ' dic = space.newdict([(%s, space.w_builtins)])\n' ' space.exec_("import types", dic, dic)\n' ' return space.eval(expr, dic, dic)' % bltinsname) - self.initcode.append1('m.%s = eval_helper(%r)' % (name, expr)) + self.initcode.append1('%s = eval_helper(%r)' % (name, expr)) return name class GenRpy: @@ -69,14 +69,11 @@ def late_OperationError(): self.initcode.append1( - 'from pypy.interpreter.error import OperationError\n' - 'm.OperationError = OperationError') - return 'OperationError' + 'from pypy.interpreter.error import OperationError as gOperationError') + return 'gOperationError' def late_Arguments(): - self.initcode.append1( - 'from pypy.interpreter.argument import Arguments\n' - 'm.Arguments = Arguments') - return 'Arguments' + self.initcode.append1('from pypy.interpreter import gateway') + return 'gateway.Arguments' self.rpynames = {Constant(None).key: 'space.w_None', Constant(False).key: 'space.w_False', @@ -150,16 +147,16 @@ if op.opname == "call_args": v = op.args[0] exv = self.expr(v, localscope) - self.nameof(Arguments) # trigger init fmt = ( - "_args = Arguments.fromshape(space, %(shape)s, [%(data_w)s])\n" + "_args = %(Arg)s.fromshape(space, %(shape)s, [%(data_w)s])\n" "%(res)s = space.call_args(%(func)s, _args)") assert isinstance(op.args[1], Constant) shape = op.args[1].value return fmt % {"res": self.expr(op.result, localscope), "func": exv, "shape": repr(shape), - "data_w": self.arglist(op.args[2:], localscope) } + "data_w": self.arglist(op.args[2:], localscope), + 'Arg': self.nameof(Arguments) } if op.opname in self.has_listarg: fmt = "%s = %s([%s])" else: @@ -203,7 +200,7 @@ 'from pypy.objspace.flow.framestate import SpecTag') lbname = self.uniquename("glabel_%d" % blocknum) self._labeltable[blocknum] = lbname - self.initcode.append1('m.%s = SpecTag()' % lbname) + self.initcode.append1('%s = SpecTag()' % lbname) return lbname else: return repr(blocknum) @@ -285,11 +282,11 @@ if type(value) is not object: # try to just wrap it? name = self.uniquename('g_%sinst_%r' % (type(value).__name__, value)) - self.initcode.append1('m.%s = space.wrap(%r)' % (name, value)) + self.initcode.append1('%s = space.wrap(%r)' % (name, value)) return name name = self.uniquename('g_object') self.initcode.append('_tup = space.newtuple([])\n' - 'm.%s = space.call(space.w_object, _tup)' + '%s = space.call(space.w_object, _tup)' % name) return name @@ -301,7 +298,7 @@ "%r is not a builtin module (probably :)"%value name = self.uniquename('mod_%s' % value.__name__) self.initcode.append1('import %s as _tmp' % value.__name__) - self.initcode.append1('m.%s = space.wrap(_tmp)' % (name)) + self.initcode.append1('%s = space.wrap(_tmp)' % (name)) return name @@ -313,7 +310,7 @@ # the prefixbefore the initial '_' for easy postprocessing name = 'gi_minus_%d' % abs(value) name = self.uniquename(name) - self.initcode.append1('m.%s = space.newint(%d)' % (name, value)) + self.initcode.append1('%s = space.newint(%d)' % (name, value)) return name def nameof_long(self, value): @@ -332,7 +329,7 @@ # the prefix before the initial '_' name = 'glong_minus_%d' % abs(value) name = self.uniquename(name) - self.initcode.append1('m.%s = space.wrap(%s) # XXX implement long!' % (name, s)) + self.initcode.append1('%s = space.wrap(%s) # XXX implement long!' % (name, s)) return name def nameof_float(self, value): @@ -340,7 +337,7 @@ name = (name.replace('-', 'minus') .replace('.', 'dot')) name = self.uniquename(name) - self.initcode.append1('m.%s = space.newfloat(%r)' % (name, value)) + self.initcode.append1('%s = space.newfloat(%r)' % (name, value)) return name def nameof_str(self, value): @@ -353,9 +350,9 @@ if not namestr: namestr = "_emptystr_" name = self.uniquename('gs_' + namestr[:32]) - # self.initcode.append1('m.%s = space.newstring(%r)' % (name, value)) + # self.initcode.append1('%s = space.newstring(%r)' % (name, value)) # ick! very unhandy - self.initcode.append1('m.%s = space.wrap(%r)' % (name, value)) + self.initcode.append1('%s = space.wrap(%r)' % (name, value)) return name def skipped_function(self, func): @@ -398,7 +395,7 @@ namehint + func.__name__)) f_name = 'f_' + name[6:] self.initcode.append1('from pypy.interpreter import gateway') - self.initcode.append1('m.%s = space.wrap(gateway.interp2app(%s, unwrap_spec=[gateway.ObjSpace, gateway.Arguments]))' % (name, f_name)) + self.initcode.append1('%s = space.wrap(gateway.interp2app(%s, unwrap_spec=[gateway.ObjSpace, gateway.Arguments]))' % (name, f_name)) self.pendingfunctions.append(func) return name @@ -407,7 +404,7 @@ func = sm.__get__(42.5) name = self.uniquename('gsm_' + func.__name__) functionname = self.nameof(func) - self.initcode.append1('m.%s = space.wrap(%s)' % (name, functionname)) + self.initcode.append1('%s = space.wrap(%s)' % (name, functionname)) return name def nameof_instancemethod(self, meth): @@ -462,7 +459,7 @@ print >> sys.stderr, "Problem while generating %s of %r" % ( name, instance) raise - self.initcode.append1("m.%s = space.call_method(%s, '__new__', %s)" % ( + self.initcode.append1("%s = space.call_method(%s, '__new__', %s)" % ( name, cls, cls)) self.later(initinstance()) return name @@ -499,7 +496,7 @@ else: raise Exception, '%r not found in any built-in module' % (func,) if modname == '__builtin__': - #self.initcode.append1('m.%s = space.getattr(space.w_builtin, %s)'% ( + #self.initcode.append1('%s = space.getattr(space.w_builtin, %s)'% ( # name, self.nameof(func.__name__))) # be lazy return "(space.builtin.get(space.str_w(%s)))" % self.nameof(func.__name__) @@ -510,12 +507,12 @@ print ("WARNING: accessing builtin modules different from sys or __builtin__" " is likely producing non-sense: %s %s" % (module.__name__, func.__name__)) name = self.uniquename('gbltin_' + func.__name__) - self.initcode.append1('m.%s = space.getattr(%s, %s)' % ( + self.initcode.append1('%s = space.getattr(%s, %s)' % ( name, self.nameof(module), self.nameof(func.__name__))) else: # builtin (bound) method name = self.uniquename('gbltinmethod_' + func.__name__) - self.initcode.append1('m.%s = space.getattr(%s, %s)' % ( + self.initcode.append1('%s = space.getattr(%s, %s)' % ( name, self.nameof(func.__self__), self.nameof(func.__name__))) return name @@ -582,7 +579,7 @@ self.nameof("__doc__"),)) self.initcode.append1('_bases = space.newtuple([%(bases)s])\n' '_args = space.newtuple([%(name)s, _bases, _dic])\n' - 'm.%(klass)s = space.call(%(meta)s, _args)' + '%(klass)s = space.call(%(meta)s, _args)' % {"bases": baseargs, "klass": name, "name" : self.nameof(cls.__name__), @@ -654,7 +651,7 @@ name = self.uniquename('g%dtuple' % len(tup)) args = [self.nameof(x) for x in tup] args = ', '.join(args) - self.initcode.append1('m.%s = space.newtuple([%s])' % (name, args)) + self.initcode.append1('%s = space.newtuple([%s])' % (name, args)) return name def nameof_list(self, lis): @@ -664,8 +661,8 @@ item = self.nameof(lis[i]) yield 'space.setitem(%s, %s, %s);' % ( name, self.nameof(i), item) - self.initcode.append1('m.%s = space.newlist([space.w_None])' % (name,)) - self.initcode.append1('m.%s = space.mul(%s, %s)' % (name, name, self.nameof(len(lis)))) + self.initcode.append1('%s = space.newlist([space.w_None])' % (name,)) + self.initcode.append1('%s = space.mul(%s, %s)' % (name, name, self.nameof(len(lis)))) self.later(initlist()) return name @@ -678,7 +675,7 @@ for k in dic: yield ('space.setitem(%s, %s, %s)'%( name, self.nameof(k), self.nameof(dic[k]))) - self.initcode.append1('m.%s = space.newdict([])' % (name,)) + self.initcode.append1('%s = space.newdict([])' % (name,)) self.later(initdict()) return name @@ -689,7 +686,7 @@ md.__objclass__.__name__, md.__name__)) cls = self.nameof(md.__objclass__) # do I need to take the dict and then getitem??? - self.initcode.append1('m.%s = space.getattr(%s, %s)' % + self.initcode.append1('%s = space.getattr(%s, %s)' % (name, cls, self.nameof(md.__name__))) return name nameof_getset_descriptor = nameof_member_descriptor @@ -775,7 +772,11 @@ # make sure it is not rendered again key = Constant(doc).key self.rpynames[key] = "__doc__" - self.initcode.append1("m.__doc__ = space.wrap(m.__doc__)") + self.initcode.append1("__doc__ = space.wrap(globals()['__doc__'])") + + # header """def initmodule(space):""" + print >> f, self.RPY_INIT_HEADER % info + # function implementations while self.pendingfunctions or self.latercode: if self.pendingfunctions: @@ -794,10 +795,9 @@ # set the final splitter print >> f, "##SECTION##" # footer, init code - print >> f, self.RPY_INIT_HEADER % info for codelines in self.initcode: # keep docstrings unindented - indent = " " + indent = " " if type(codelines) is tuple: codelines = codelines[0].split("\n", 1) codelines[0] = indent + codelines[0] @@ -807,7 +807,7 @@ for codeline in codelines: print >> f, indent + codeline - self.gen_trailer(info, " ") + self.gen_trailer(info, " ") # do not close the file here! def gen_trailer(self, info, indent): @@ -905,20 +905,20 @@ # create function declaration name = self.trans_funcname(func.__name__) # for argstr = ", ".join(['space'] + fast_args) - fast_function_header = ('def %s(%s):' + fast_function_header = (' def %s(%s):' % (name, argstr)) def install_func(f_name, name): yield '' - yield '%s = %s' % (f_name, name) - import __builtin__ - dic = __builtin__.__dict__ - if dic.get(name): - yield 'del %s # hiding a builtin!' % name - else: - self.initcode.append1('del m.%s' % (name,)) + yield ' %s = %s' % (f_name, name) + #import __builtin__ + #dic = __builtin__.__dict__ + #if dic.get(name): + # yield 'del %s # hiding a builtin!' % name + #else: + # self.initcode.append1('del m.%s' % (name,)) - print >> f, 'def %s(space, __args__):' % (name,) + print >> f, ' def %s(space, __args__):' % (name,) if docstr is not None: print >> f, docstr print >> f @@ -1027,8 +1027,8 @@ # exceptional return block exc_cls = self.expr(block.inputargs[0], localscope) exc_val = self.expr(block.inputargs[1], localscope) - self.nameof(OperationError) # trigger init - yield "raise OperationError(%s, %s)" % (exc_cls, exc_val) + yield "raise %s(%s, %s)" % (self.nameof(OperationError), + exc_cls, exc_val) else: # regular return block retval = self.expr(block.inputargs[0], localscope) @@ -1049,8 +1049,7 @@ # we must catch the exception raised by the last operation, # which goes to the last err%d_%d label written above. # Since we only have OperationError, we need to select: - self.nameof(OperationError) # trigger init - yield "except OperationError, e:" + yield "except %s, e:" % (self.nameof(OperationError),) q = "if" for link in block.exits[1:]: assert issubclass(link.exitcase, Exception) @@ -1104,11 +1103,7 @@ RPY_INIT_HEADER = RPY_SEP + ''' def init%(modname)s(space): - """NOT_RPYTHON""" - class m: pass # fake module - m.__dict__ = globals() - # make sure that this function is run only once: - m.init%(modname)s = lambda *ign:True + """NOT_RPYTHON""" ''' RPY_INIT_FOOTER = ''' From alex at codespeak.net Mon Mar 21 23:20:53 2005 From: alex at codespeak.net (alex at codespeak.net) Date: Mon, 21 Mar 2005 23:20:53 +0100 (MET) Subject: [pypy-svn] r10030 - pypy/dist/pypy/lib/test2 Message-ID: <20050321222053.1EBC427B71@code1.codespeak.net> Author: alex Date: Mon Mar 21 23:20:52 2005 New Revision: 10030 Added: pypy/dist/pypy/lib/test2/test_iter_extra.py Log: test that iter raises TypeError when called on a fake-iterator Added: pypy/dist/pypy/lib/test2/test_iter_extra.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/lib/test2/test_iter_extra.py Mon Mar 21 23:20:52 2005 @@ -0,0 +1,21 @@ +# -*- coding: iso-8859-1 -*- +import unittest, test.test_support +import pickle + +class FakeIterator(object): + def __init__(self, *a): + pass + def __iter__(self): + return self + # no next method -- which is why it's *fake*! + +class IterTest(unittest.TestCase): + + def test_fakeiterator(self): + self.assertRaises(TypeError, iter, FakeIterator()) + +def test_main(): + test.test_support.run_unittest(IterTest) + +if __name__ == "__main__": + test_main() From rxe at codespeak.net Mon Mar 21 23:32:19 2005 From: rxe at codespeak.net (rxe at codespeak.net) Date: Mon, 21 Mar 2005 23:32:19 +0100 (MET) Subject: [pypy-svn] r10031 - in pypy/dist/pypy: interpreter tool Message-ID: <20050321223219.61A8927B71@code1.codespeak.net> Author: rxe Date: Mon Mar 21 23:32:19 2005 New Revision: 10031 Removed: pypy/dist/pypy/tool/traceinteractive.py Modified: pypy/dist/pypy/interpreter/interactive.py pypy/dist/pypy/interpreter/py.py Log: Merge traceinteractive.py with interactive.py. -C option on py.py enables command line completion. Modified: pypy/dist/pypy/interpreter/interactive.py ============================================================================== --- pypy/dist/pypy/interpreter/interactive.py (original) +++ pypy/dist/pypy/interpreter/interactive.py Mon Mar 21 23:32:19 2005 @@ -7,8 +7,86 @@ import time +class Completer: + """ Stolen mostly from CPython's rlcompleter.py """ + def __init__(self, space, w_globals): + self.space = space + self.w_globals = w_globals + + def complete(self, text, state): + if state == 0: + if "." in text: + self.matches = self.attr_matches(text) + else: + self.matches = self.global_matches(text) + try: + return self.matches[state] + + except IndexError: + return None + + def global_matches(self, text): + import keyword + w_res = self.space.call_method(self.w_globals, "keys") + namespace_keys = self.space.unwrap(w_res) + w_res = self.space.call_method(self.space.builtin.getdict(), "keys") + builtin_keys = self.space.unwrap(w_res) + + matches = [] + n = len(text) + + for l in [namespace_keys, builtin_keys, keyword.kwlist]: + for word in l: + if word[:n] == text and word != "__builtins__": + matches.append(word) + + return matches + + def attr_matches(self, text): + import re + m = re.match(r"(\w+(\.\w+)*)\.(\w*)", text) + if not m: + return + + expr, attr = m.group(1, 3) + s = self.space + w_obj = s.eval(expr, self.w_globals, self.w_globals) + words = self.get_words(w_obj) + + w_clz = s.getattr(w_obj, s.wrap("__class__")) + words += self.get_class_members(w_clz) + + matches = [] + n = len(attr) + for word in words: + if word[:n] == attr and word != "__builtins__": + matches.append("%s.%s" % (expr, word)) + + return matches + + def get_words(self, w_clz): + s = self.space + w_dir_func = s.builtin.get("dir") + w_res = s.call_function(w_dir_func, w_clz) + return s.unwrap(w_res) + + def get_class_members(self, w_clz): + s = self.space + words = self.get_words(w_clz) + try: + w_bases = s.getattr(w_clz, s.wrap("__bases__")) + bases_w = s.unpacktuple(w_bases) + + except OperationError: + return words + + for w_clz in bases_w: + words += self.get_class_members(w_clz) + + return words + class PyPyConsole(code.InteractiveConsole): - def __init__(self, objspace, verbose=0): + def __init__(self, objspace, verbose=0, completer=False): code.InteractiveConsole.__init__(self) self.space = objspace self.verbose = verbose @@ -19,16 +97,38 @@ mainmodule = main.ensure__main__(space) self.w_globals = mainmodule.w_dict space.setitem(self.w_globals, space.wrap('__builtins__'), space.builtin) + if completer: + self.enable_command_line_completer() # XXX check: do we need self.ec, self.w_globals? + space.exec_("__pytrace__ = 0", self.w_globals, self.w_globals) + self.tracelevel = 0 + + def enable_command_line_completer(self): + try: + import readline + # Keep here to save windoze tears + readline.set_completer(Completer(self.space, self.w_globals).complete) + readline.parse_and_bind("tab: complete") + readline.set_history_length(25000) + + try: + readline.read_history_file() + except IOError: + pass # guess it doesn't exit + + import atexit + atexit.register(readline.write_history_file) + except: + pass + def interact(self, banner=None): - if banner is None: - #banner = "Python %s in pypy\n%s / %s" % ( - # sys.version, self.__class__.__name__, - # self.space.__class__.__name__) - elapsed = time.time() - self.space._starttime - banner = "PyPy in %s on top of Python %s (startupttime: %.2f secs)" % ( - self.space.__repr__(), sys.version.split()[0], elapsed) + #banner = "Python %s in pypy\n%s / %s" % ( + # sys.version, self.__class__.__name__, + # self.space.__class__.__name__) + elapsed = time.time() - self.space._starttime + banner = "PyPy in %s on top of Python %s (startupttime: %.2f secs)" % ( + self.space.__repr__(), sys.version.split()[0], elapsed) code.InteractiveConsole.interact(self, banner) def raw_input(self, prompt=""): @@ -60,7 +160,10 @@ from pypy.interpreter.pycode import PyCode pycode = PyCode(self.space)._from_code(code) try: + self.settrace() pycode.exec_code(self.space, self.w_globals, self.w_globals) + self.checktrace() + except error.OperationError, operationerr: space = self.space try: @@ -102,7 +205,7 @@ pass def runsource(self, source, ignored_filename="", symbol="single"): - hacked_filename = '\n'+source + hacked_filename = '' + source try: code = self.compile(source, hacked_filename, symbol) except (OverflowError, SyntaxError, ValueError): @@ -113,6 +216,43 @@ self.runcode(code) return 0 + def settrace(self): + if self.tracelevel: + self.space.settrace() + + def checktrace(self): + from pypy.objspace import trace + + s = self.space + + # Did we modify __pytrace__ + tracelevel = s.int_w(s.getitem(self.w_globals, + s.wrap("__pytrace__"))) + + if self.tracelevel > 0 and tracelevel == 0: + s.reset_trace() + print "Tracing disabled" + + if self.tracelevel == 0 and tracelevel > 0: + trace.create_trace_space(s) + print "Tracing enabled" + + self.tracelevel = tracelevel + + def set_tracelevel(self, tracelevel): + # Disable tracing altogether? + from pypy.objspace import trace + + if self.tracelevel > 0 and tracelevel == 0: + self.space.reset_trace() + print self.get_banner() + + if self.tracelevel == 0 and tracelevel > 0: + trace.create_trace_space(self.space) + print self.get_banner() + + self.tracelevel = tracelevel + if __name__ == '__main__': try: import readline Modified: pypy/dist/pypy/interpreter/py.py ============================================================================== --- pypy/dist/pypy/interpreter/py.py (original) +++ pypy/dist/pypy/interpreter/py.py Mon Mar 21 23:32:19 2005 @@ -18,6 +18,7 @@ verbose = os.getenv('PYPY_TB') interactive = 0 command = [] + completer = False def get_main_options(): options = option.get_standard_options() @@ -27,6 +28,10 @@ help='show verbose interpreter-level traceback')) options.append(make_option( + '-C', action='store_true', dest='completer', + help='use readline commandline completer')) + + options.append(make_option( '-i', action="store_true", dest="interactive", help="inspect interactively after running script")) @@ -78,7 +83,7 @@ else: operationerr.print_application_traceback(space) if go_interactive: - con = interactive.PyPyConsole(space, Options.verbose) + con = interactive.PyPyConsole(space, verbose=Options.verbose, completer=Options.completer) if banner == '': banner = '%s / %s'%(con.__class__.__name__, space.__class__.__name__) Deleted: /pypy/dist/pypy/tool/traceinteractive.py ============================================================================== --- /pypy/dist/pypy/tool/traceinteractive.py Mon Mar 21 23:32:19 2005 +++ (empty file) @@ -1,252 +0,0 @@ -# Standard imports -import re -import sys -import code -import keyword - -assert sys.version_info >= (2,3), "sorry, can only run with python2.3 and greater" - -try: - import readline - have_readline = True - -except: - have_readline = False - - -# PyPy imports -import autopath - -from pypy.tool import pydis - -from pypy.interpreter import executioncontext, pyframe, baseobjspace -from pypy.interpreter.baseobjspace import ObjSpace - -from pypy.objspace import trace - -class Completer: - """ Stolen mostly from CPython's rlcompleter.py """ - def __init__(self, space): - self.space = space - - def complete(self, text, state): - if state == 0: - if "." in text: - self.matches = self.attr_matches(text) - else: - self.matches = self.global_matches(text) - try: - return self.matches[state] - - except IndexError: - return None - - def global_matches(self, text): - w_res = self.space.call_method(self.space.w_globals, "keys") - namespace_keys = self.space.unwrap(w_res) - - w_res = self.space.call_method(self.space.builtin.getdict(), "keys") - builtin_keys = self.space.unwrap(w_res) - - matches = [] - n = len(text) - - for l in [namespace_keys, builtin_keys, keyword.kwlist]: - for word in l: - if word[:n] == text and word != "__builtins__": - matches.append(word) - - return matches - - def attr_matches(self, text): - m = re.match(r"(\w+(\.\w+)*)\.(\w*)", text) - if not m: - return - - expr, attr = m.group(1, 3) - s = self.space - w_obj = s.eval(expr, s.w_globals, s.w_globals) - words = self.get_words(w_obj) - - w_clz = s.getattr(w_obj, s.wrap("__class__")) - words += self.get_class_members(w_clz) - - matches = [] - n = len(attr) - for word in words: - if word[:n] == attr and word != "__builtins__": - matches.append("%s.%s" % (expr, word)) - - return matches - - def get_words(self, w_clz): - s = self.space - w_dir_func = s.builtin.get("dir") - w_res = s.call_function(w_dir_func, w_clz) - return s.unwrap(w_res) - - def get_class_members(self, w_clz): - s = self.space - words = self.get_words(w_clz) - try: - w_bases = s.getattr(w_clz, s.wrap("__bases__")) - bases_w = s.unpacktuple(w_bases) - - except OperationError: - return words - - for w_clz in bases_w: - words += self.get_class_members(w_clz) - - return words - -class TraceConsole(code.InteractiveConsole): - def __init__(self, space): - code.InteractiveConsole.__init__(self) - s = self.space = space - s.setitem(s.w_globals, s.wrap("__pytrace__"), s.wrap(0)) - # Trace is binary (on or off), but we have different print levels - # for tracelevel > 0 - self.tracelevel = 0 - - def interact(self, banner=None): - if banner is None: - banner = self.get_banner() - code.InteractiveConsole.interact(self, banner) - - def get_banner(self): - banner = "PyPy in %s on top of CPython %s\n%s" % ( - space.__class__.__name__, sys.version.split()[0], - " [Use __pytrace__ to set trace level (zero is default and does no tracing)]" ) - return banner - - def raw_input(self, prompt=""): - # add a character to the PyPy prompt so that you know where you - # are when you debug it with "python -i py.py" - try: - return code.InteractiveConsole.raw_input(self, prompt[0] + prompt) - - except KeyboardInterrupt: - s = self.space - # fires into an interpreter-level console - print - banner = ("Python %s on %s\n" % (sys.version, sys.platform) + - "*** Entering interpreter-level console ***") - local = self.__dict__.copy() - for w_name in s.unpackiterable(s.w_globals): - local['w_' + s.unwrap(w_name)] = ( - s.getitem(s.w_globals, w_name)) - code.interact(banner=banner, local=local) - # copy back 'w_' names - for name in local: - if name.startswith('w_'): - s.setitem(s.w_globals, - s.wrap(name[2:]), - local[name]) - print '*** Leaving interpreter-level console ***' - raise - - def set_tracelevel(self, tracelevel): - # Disable tracing altogether? - if self.tracelevel > 0 and tracelevel == 0: - self.space.reset_trace() - print self.get_banner() - - if self.tracelevel == 0 and tracelevel > 0: - trace.create_trace_space(self.space) - print self.get_banner() - - self.tracelevel = tracelevel - - def runcode(self, code): - # 'code' is a CPython code object - from pypy.interpreter.pycode import PyCode - s = self.space - - pycode = PyCode(s)._from_code(code) - - try: - if self.tracelevel: - s.settrace() - - pycode.exec_code(s, s.w_globals, s.w_globals) - - res = None - if self.tracelevel: - res = s.getresult() - s.settrace() - - # Did we modify __pytrace__ - tracelevel = s.unwrap(s.getitem(s.w_globals, - s.wrap("__pytrace__"))) - - if tracelevel != self.tracelevel: - self.set_tracelevel(tracelevel) - - #if res is not None and self.tracelevel: - # self.resprinter.print_result(s, res) - - except baseobjspace.OperationError, operationerr: - if self.tracelevel: - res = s.getresult() - s.settrace() - - # XXX insert exception info into the application-level sys.last_xxx - print - operationerr.print_application_traceback(self.space) - - else: - print - - def runsource(self, source, ignored_filename = "", symbol = "single"): - hacked_filename = ' ' + source[:80] + "..." - hacked_filename = hacked_filename.replace("\n", r"\n") - try: - code = self.compile(source, hacked_filename, symbol) - - except (OverflowError, SyntaxError, ValueError): - self.showsyntaxerror(self.filename) - return False - - if code is None: - return True - - self.runcode(code) - return False - -def trace_interactive(space, banner = None): - s = space - - # Create an execution context, and set the globals - ec = s.getexecutioncontext() - s.w_globals = ec.make_standard_w_globals() - - s.setitem(s.w_globals, s.wrap("__name__"), s.wrap("__main__")) - console = TraceConsole(s) - - if have_readline: - # Keep here to save windoze tears - readline.set_completer(Completer(s).complete) - readline.parse_and_bind("tab: complete") - readline.set_history_length(25000) - - try: - readline.read_history_file() - - except IOError: - pass # guess it doesn't exit - - import atexit - atexit.register(readline.write_history_file) - - console.interact(banner) - -if __name__ == '__main__': - - from pypy.tool import option - args = option.process_options(option.get_standard_options(), - option.Options) - - # Create objspace... - space = option.objspace() - trace_interactive(space) From alex at codespeak.net Mon Mar 21 23:34:06 2005 From: alex at codespeak.net (alex at codespeak.net) Date: Mon, 21 Mar 2005 23:34:06 +0100 (MET) Subject: [pypy-svn] r10032 - pypy/dist/pypy/lib/test2 Message-ID: <20050321223406.A754827B71@code1.codespeak.net> Author: alex Date: Mon Mar 21 23:34:06 2005 New Revision: 10032 Modified: pypy/dist/pypy/lib/test2/test_iter_extra.py Log: also test for semifakehood Modified: pypy/dist/pypy/lib/test2/test_iter_extra.py ============================================================================== --- pypy/dist/pypy/lib/test2/test_iter_extra.py (original) +++ pypy/dist/pypy/lib/test2/test_iter_extra.py Mon Mar 21 23:34:06 2005 @@ -12,7 +12,10 @@ class IterTest(unittest.TestCase): def test_fakeiterator(self): - self.assertRaises(TypeError, iter, FakeIterator()) + x = FakeIterator() + self.assertRaises(TypeError, iter, x) + x.next = lambda: 23 + self.assertRaises(TypeError, iter, x) def test_main(): test.test_support.run_unittest(IterTest) From arigo at codespeak.net Mon Mar 21 23:42:42 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 21 Mar 2005 23:42:42 +0100 (MET) Subject: [pypy-svn] r10033 - in pypy/dist/pypy: documentation/revreport interpreter module/sys2 objspace Message-ID: <20050321224242.81E5527B71@code1.codespeak.net> Author: arigo Date: Mon Mar 21 23:42:42 2005 New Revision: 10033 Modified: pypy/dist/pypy/documentation/revreport/delta.py pypy/dist/pypy/interpreter/py.py pypy/dist/pypy/module/sys2/__init__.py pypy/dist/pypy/objspace/trace.py Log: Use repr(space) instead of space.__class__.__name__, to give the space a chance to provide more information (e.g. in the thunk objspace). Modified: pypy/dist/pypy/documentation/revreport/delta.py ============================================================================== --- pypy/dist/pypy/documentation/revreport/delta.py (original) +++ pypy/dist/pypy/documentation/revreport/delta.py Mon Mar 21 23:42:42 2005 @@ -160,7 +160,7 @@ class ObjSpaceExplore(Explore): def __init__(self, space): - Explore.__init__(self, "PyPy/%s" % space.__class__.__name__) + Explore.__init__(self, "PyPy/%s" % repr(space)) self.space = space def get_module(self, name): Modified: pypy/dist/pypy/interpreter/py.py ============================================================================== --- pypy/dist/pypy/interpreter/py.py (original) +++ pypy/dist/pypy/interpreter/py.py Mon Mar 21 23:42:42 2005 @@ -86,7 +86,7 @@ con = interactive.PyPyConsole(space, verbose=Options.verbose, completer=Options.completer) if banner == '': banner = '%s / %s'%(con.__class__.__name__, - space.__class__.__name__) + repr(space)) con.interact(banner) except: exc_type, value, tb = sys.exc_info() Modified: pypy/dist/pypy/module/sys2/__init__.py ============================================================================== --- pypy/dist/pypy/module/sys2/__init__.py (original) +++ pypy/dist/pypy/module/sys2/__init__.py Mon Mar 21 23:42:42 2005 @@ -9,8 +9,6 @@ self.recursionlimit = 100 interpleveldefs = { - 'pypy_objspaceclass' : '(space.wrap(space.__class__.__name__))', - '__name__' : '(space.wrap("sys"))', '__doc__' : '(space.wrap("PyPy sys module"))', @@ -26,7 +24,7 @@ 'stdout' : 'space.wrap(sys.stdout)', '__stdout__' : 'space.wrap(sys.stdout)', 'stderr' : 'space.wrap(sys.stderr)', - 'pypy_objspaceclass' : 'space.wrap(space.__class__.__name__)', + 'pypy_objspaceclass' : 'space.wrap(repr(space))', 'path' : 'state.get(space).w_path', 'modules' : 'state.get(space).w_modules', Modified: pypy/dist/pypy/objspace/trace.py ============================================================================== --- pypy/dist/pypy/objspace/trace.py (original) +++ pypy/dist/pypy/objspace/trace.py Mon Mar 21 23:42:42 2005 @@ -217,7 +217,7 @@ if hasattr(self, "_result"): del self._result - trace_clz = type("Trace" + space.__class__.__name__, (Trace,), {}) + trace_clz = type("Trace%s" % repr(space), (Trace,), {}) space.__oldclass__, space.__class__ = space.__class__, trace_clz space.settrace() From hpk at codespeak.net Mon Mar 21 23:43:25 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Mon, 21 Mar 2005 23:43:25 +0100 (MET) Subject: [pypy-svn] r10034 - pypy/dist/pypy/module/builtin Message-ID: <20050321224325.0497227B71@code1.codespeak.net> Author: hpk Date: Mon Mar 21 23:43:24 2005 New Revision: 10034 Modified: pypy/dist/pypy/module/builtin/operation.py Log: make the builtin iter() more picky about __iter__() results that don't actually have a next() method. Modified: pypy/dist/pypy/module/builtin/operation.py ============================================================================== --- pypy/dist/pypy/module/builtin/operation.py (original) +++ pypy/dist/pypy/module/builtin/operation.py Mon Mar 21 23:43:24 2005 @@ -91,7 +91,18 @@ def iter(space, w_collection_or_callable, w_sentinel=NoneNotWrapped): if w_sentinel is None: - return space.iter(w_collection_or_callable) + w_res = space.iter(w_collection_or_callable) + w_typeres = space.type(w_res) + try: + space.getattr(w_typeres, space.wrap('next')) + except OperationError, e: + if not e.match(space, space.w_AttributeError): + raise + raise OperationError(space.w_TypeError, + space.wrap("iter() returned non-iterator of type '%s'" % + w_typeres.name)) + else: + return w_res else: return iter_sentinel(space, w_collection_or_callable, w_sentinel) From tismer at codespeak.net Mon Mar 21 23:45:38 2005 From: tismer at codespeak.net (tismer at codespeak.net) Date: Mon, 21 Mar 2005 23:45:38 +0100 (MET) Subject: [pypy-svn] r10035 - pypy/dist/lib-python-2.3.4/test Message-ID: <20050321224538.7C72427B71@code1.codespeak.net> Author: tismer Date: Mon Mar 21 23:45:38 2005 New Revision: 10035 Modified: pypy/dist/lib-python-2.3.4/test/pickletester.py Log: removed one impractical test (cPickle) and three tests which computefor ages (xxx prefix). The latter might be re-enabled when PyPy gets noticably faster. Modified: pypy/dist/lib-python-2.3.4/test/pickletester.py ============================================================================== --- pypy/dist/lib-python-2.3.4/test/pickletester.py (original) +++ pypy/dist/lib-python-2.3.4/test/pickletester.py Mon Mar 21 23:45:38 2005 @@ -1,3 +1,9 @@ +# Notes about changes in this file: +# a prefix of "dont_" means the test makes no sense, +# because we don't use cPickle at all. +# "xxx_" means it works and can be done, but takes ages. +# When PyPy gets really fast, we should remove "xxx_". + import unittest import pickle import cPickle @@ -513,7 +519,7 @@ data = 'I' + str(maxint64) + 'JUNK\n.' self.assertRaises(ValueError, self.loads, data) - def test_long(self): + def xxx_test_long(self): for proto in protocols: # 256 bytes is where LONG4 begins. for nbits in 1, 8, 8*254, 8*255, 8*256, 8*257: @@ -738,7 +744,7 @@ self.produce_global_ext(0x7fffffff, pickle.EXT4) # largest EXT4 code self.produce_global_ext(0x12abcdef, pickle.EXT4) # check endianness - def test_list_chunking(self): + def xxx_test_list_chunking(self): n = 10 # too small to chunk x = range(n) for proto in protocols: @@ -760,7 +766,7 @@ else: self.failUnless(num_appends >= 2) - def test_dict_chunking(self): + def xxx_test_dict_chunking(self): n = 10 # too small to chunk x = dict.fromkeys(range(n)) for proto in protocols: From alex at codespeak.net Mon Mar 21 23:51:40 2005 From: alex at codespeak.net (alex at codespeak.net) Date: Mon, 21 Mar 2005 23:51:40 +0100 (MET) Subject: [pypy-svn] r10036 - pypy/dist/pypy/lib Message-ID: <20050321225140.A5C8227B71@code1.codespeak.net> Author: alex Date: Mon Mar 21 23:51:40 2005 New Revision: 10036 Modified: pypy/dist/pypy/lib/itertools.py Log: islice() now checks its arguments carefully Modified: pypy/dist/pypy/lib/itertools.py ============================================================================== --- pypy/dist/pypy/lib/itertools.py (original) +++ pypy/dist/pypy/lib/itertools.py Mon Mar 21 23:51:40 2005 @@ -355,6 +355,9 @@ def __init__(self, iterable, *args): s = slice(*args) self.start, self.stop, self.step = s.start or 0, s.stop, s.step or 1 + if self.start<0 or (self.stop is not None and self.stop<0 + ) or self.step<0: + raise ValueError, "indices for islice() must be positive" self.donext = iter(iterable).next self.cnt = 0 From arigo at codespeak.net Mon Mar 21 23:58:33 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 21 Mar 2005 23:58:33 +0100 (MET) Subject: [pypy-svn] r10037 - pypy/dist/pypy/documentation/revreport Message-ID: <20050321225833.E231227B71@code1.codespeak.net> Author: arigo Date: Mon Mar 21 23:58:33 2005 New Revision: 10037 Modified: pypy/dist/pypy/documentation/revreport/revreport.py Log: revreport: should not make the symlink "current" point to the max revision present, because this max revision's directory is likely to be still half-empty and being generated. If "latest != revdir" we should probably not set the symlink at all and wait until the other process finishes and sets the link itself. Modified: pypy/dist/pypy/documentation/revreport/revreport.py ============================================================================== --- pypy/dist/pypy/documentation/revreport/revreport.py (original) +++ pypy/dist/pypy/documentation/revreport/revreport.py Mon Mar 21 23:58:33 2005 @@ -11,7 +11,7 @@ assert DEST.dirpath().check() -def updatecurrent(): +def updatecurrent(revdir): l = [] for x in DEST.listdir(): try: @@ -21,6 +21,8 @@ else: l.append(x) latest = DEST.join(str(max(l))) + if latest != revdir: # another process is busy generating the next rev + return # then don't change the link! assert latest.check() current = DEST.join('current') if current.check(): @@ -52,4 +54,4 @@ print "stdout" print out print "generated into", revdir - updatecurrent() + updatecurrent(revdir) From tismer at codespeak.net Tue Mar 22 00:03:39 2005 From: tismer at codespeak.net (tismer at codespeak.net) Date: Tue, 22 Mar 2005 00:03:39 +0100 (MET) Subject: [pypy-svn] r10038 - pypy/dist/pypy/lib/test2 Message-ID: <20050321230339.8123927B71@code1.codespeak.net> Author: tismer Date: Tue Mar 22 00:03:39 2005 New Revision: 10038 Added: pypy/dist/pypy/lib/test2/pickletester.py (contents, props changed) Log: avoiding changes to the lib python stuff, this one must go here. Added: pypy/dist/pypy/lib/test2/pickletester.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/lib/test2/pickletester.py Tue Mar 22 00:03:39 2005 @@ -0,0 +1,964 @@ +# Notes about changes in this file: +# a prefix of "dont_" means the test makes no sense, +# because we don't use cPickle at all. +# "xxx_" means it works and can be done, but takes ages. +# When PyPy gets really fast, we should remove "xxx_". + +import unittest +import pickle +import cPickle +import pickletools +import copy_reg + +from test.test_support import TestFailed, have_unicode, TESTFN + +# Tests that try a number of pickle protocols should have a +# for proto in protocols: +# kind of outer loop. +assert pickle.HIGHEST_PROTOCOL == cPickle.HIGHEST_PROTOCOL == 2 +protocols = range(pickle.HIGHEST_PROTOCOL + 1) + + +# Return True if opcode code appears in the pickle, else False. +def opcode_in_pickle(code, pickle): + for op, dummy, dummy in pickletools.genops(pickle): + if op.code == code: + return True + return False + +# Return the number of times opcode code appears in pickle. +def count_opcode(code, pickle): + n = 0 + for op, dummy, dummy in pickletools.genops(pickle): + if op.code == code: + n += 1 + return n + +# We can't very well test the extension registry without putting known stuff +# in it, but we have to be careful to restore its original state. Code +# should do this: +# +# e = ExtensionSaver(extension_code) +# try: +# fiddle w/ the extension registry's stuff for extension_code +# finally: +# e.restore() + +class ExtensionSaver: + # Remember current registration for code (if any), and remove it (if + # there is one). + def __init__(self, code): + self.code = code + if code in copy_reg._inverted_registry: + self.pair = copy_reg._inverted_registry[code] + copy_reg.remove_extension(self.pair[0], self.pair[1], code) + else: + self.pair = None + + # Restore previous registration for code. + def restore(self): + code = self.code + curpair = copy_reg._inverted_registry.get(code) + if curpair is not None: + copy_reg.remove_extension(curpair[0], curpair[1], code) + pair = self.pair + if pair is not None: + copy_reg.add_extension(pair[0], pair[1], code) + +class C: + def __cmp__(self, other): + return cmp(self.__dict__, other.__dict__) + +import __main__ +__main__.C = C +C.__module__ = "__main__" + +class myint(int): + def __init__(self, x): + self.str = str(x) + +class initarg(C): + + def __init__(self, a, b): + self.a = a + self.b = b + + def __getinitargs__(self): + return self.a, self.b + +class metaclass(type): + pass + +class use_metaclass(object): + __metaclass__ = metaclass + +# DATA0 .. DATA2 are the pickles we expect under the various protocols, for +# the object returned by create_data(). + +# break into multiple strings to avoid confusing font-lock-mode +DATA0 = """(lp1 +I0 +aL1L +aF2 +ac__builtin__ +complex +p2 +""" + \ +"""(F3 +F0 +tRp3 +aI1 +aI-1 +aI255 +aI-255 +aI-256 +aI65535 +aI-65535 +aI-65536 +aI2147483647 +aI-2147483647 +aI-2147483648 +a""" + \ +"""(S'abc' +p4 +g4 +""" + \ +"""(i__main__ +C +p5 +""" + \ +"""(dp6 +S'foo' +p7 +I1 +sS'bar' +p8 +I2 +sbg5 +tp9 +ag9 +aI5 +a. +""" + +# Disassembly of DATA0. +DATA0_DIS = """\ + 0: ( MARK + 1: l LIST (MARK at 0) + 2: p PUT 1 + 5: I INT 0 + 8: a APPEND + 9: L LONG 1L + 13: a APPEND + 14: F FLOAT 2.0 + 17: a APPEND + 18: c GLOBAL '__builtin__ complex' + 39: p PUT 2 + 42: ( MARK + 43: F FLOAT 3.0 + 46: F FLOAT 0.0 + 49: t TUPLE (MARK at 42) + 50: R REDUCE + 51: p PUT 3 + 54: a APPEND + 55: I INT 1 + 58: a APPEND + 59: I INT -1 + 63: a APPEND + 64: I INT 255 + 69: a APPEND + 70: I INT -255 + 76: a APPEND + 77: I INT -256 + 83: a APPEND + 84: I INT 65535 + 91: a APPEND + 92: I INT -65535 + 100: a APPEND + 101: I INT -65536 + 109: a APPEND + 110: I INT 2147483647 + 122: a APPEND + 123: I INT -2147483647 + 136: a APPEND + 137: I INT -2147483648 + 150: a APPEND + 151: ( MARK + 152: S STRING 'abc' + 159: p PUT 4 + 162: g GET 4 + 165: ( MARK + 166: i INST '__main__ C' (MARK at 165) + 178: p PUT 5 + 181: ( MARK + 182: d DICT (MARK at 181) + 183: p PUT 6 + 186: S STRING 'foo' + 193: p PUT 7 + 196: I INT 1 + 199: s SETITEM + 200: S STRING 'bar' + 207: p PUT 8 + 210: I INT 2 + 213: s SETITEM + 214: b BUILD + 215: g GET 5 + 218: t TUPLE (MARK at 151) + 219: p PUT 9 + 222: a APPEND + 223: g GET 9 + 226: a APPEND + 227: I INT 5 + 230: a APPEND + 231: . STOP +highest protocol among opcodes = 0 +""" + +DATA1 = (']q\x01(K\x00L1L\nG@\x00\x00\x00\x00\x00\x00\x00' + 'c__builtin__\ncomplex\nq\x02(G@\x08\x00\x00\x00\x00\x00' + '\x00G\x00\x00\x00\x00\x00\x00\x00\x00tRq\x03K\x01J\xff\xff' + '\xff\xffK\xffJ\x01\xff\xff\xffJ\x00\xff\xff\xffM\xff\xff' + 'J\x01\x00\xff\xffJ\x00\x00\xff\xffJ\xff\xff\xff\x7fJ\x01\x00' + '\x00\x80J\x00\x00\x00\x80(U\x03abcq\x04h\x04(c__main__\n' + 'C\nq\x05oq\x06}q\x07(U\x03fooq\x08K\x01U\x03barq\tK\x02ubh' + '\x06tq\nh\nK\x05e.' + ) + +# Disassembly of DATA1. +DATA1_DIS = """\ + 0: ] EMPTY_LIST + 1: q BINPUT 1 + 3: ( MARK + 4: K BININT1 0 + 6: L LONG 1L + 10: G BINFLOAT 2.0 + 19: c GLOBAL '__builtin__ complex' + 40: q BINPUT 2 + 42: ( MARK + 43: G BINFLOAT 3.0 + 52: G BINFLOAT 0.0 + 61: t TUPLE (MARK at 42) + 62: R REDUCE + 63: q BINPUT 3 + 65: K BININT1 1 + 67: J BININT -1 + 72: K BININT1 255 + 74: J BININT -255 + 79: J BININT -256 + 84: M BININT2 65535 + 87: J BININT -65535 + 92: J BININT -65536 + 97: J BININT 2147483647 + 102: J BININT -2147483647 + 107: J BININT -2147483648 + 112: ( MARK + 113: U SHORT_BINSTRING 'abc' + 118: q BINPUT 4 + 120: h BINGET 4 + 122: ( MARK + 123: c GLOBAL '__main__ C' + 135: q BINPUT 5 + 137: o OBJ (MARK at 122) + 138: q BINPUT 6 + 140: } EMPTY_DICT + 141: q BINPUT 7 + 143: ( MARK + 144: U SHORT_BINSTRING 'foo' + 149: q BINPUT 8 + 151: K BININT1 1 + 153: U SHORT_BINSTRING 'bar' + 158: q BINPUT 9 + 160: K BININT1 2 + 162: u SETITEMS (MARK at 143) + 163: b BUILD + 164: h BINGET 6 + 166: t TUPLE (MARK at 112) + 167: q BINPUT 10 + 169: h BINGET 10 + 171: K BININT1 5 + 173: e APPENDS (MARK at 3) + 174: . STOP +highest protocol among opcodes = 1 +""" + +DATA2 = ('\x80\x02]q\x01(K\x00\x8a\x01\x01G@\x00\x00\x00\x00\x00\x00\x00' + 'c__builtin__\ncomplex\nq\x02G@\x08\x00\x00\x00\x00\x00\x00G\x00' + '\x00\x00\x00\x00\x00\x00\x00\x86Rq\x03K\x01J\xff\xff\xff\xffK' + '\xffJ\x01\xff\xff\xffJ\x00\xff\xff\xffM\xff\xffJ\x01\x00\xff\xff' + 'J\x00\x00\xff\xffJ\xff\xff\xff\x7fJ\x01\x00\x00\x80J\x00\x00\x00' + '\x80(U\x03abcq\x04h\x04(c__main__\nC\nq\x05oq\x06}q\x07(U\x03foo' + 'q\x08K\x01U\x03barq\tK\x02ubh\x06tq\nh\nK\x05e.') + +# Disassembly of DATA2. +DATA2_DIS = """\ + 0: \x80 PROTO 2 + 2: ] EMPTY_LIST + 3: q BINPUT 1 + 5: ( MARK + 6: K BININT1 0 + 8: \x8a LONG1 1L + 11: G BINFLOAT 2.0 + 20: c GLOBAL '__builtin__ complex' + 41: q BINPUT 2 + 43: G BINFLOAT 3.0 + 52: G BINFLOAT 0.0 + 61: \x86 TUPLE2 + 62: R REDUCE + 63: q BINPUT 3 + 65: K BININT1 1 + 67: J BININT -1 + 72: K BININT1 255 + 74: J BININT -255 + 79: J BININT -256 + 84: M BININT2 65535 + 87: J BININT -65535 + 92: J BININT -65536 + 97: J BININT 2147483647 + 102: J BININT -2147483647 + 107: J BININT -2147483648 + 112: ( MARK + 113: U SHORT_BINSTRING 'abc' + 118: q BINPUT 4 + 120: h BINGET 4 + 122: ( MARK + 123: c GLOBAL '__main__ C' + 135: q BINPUT 5 + 137: o OBJ (MARK at 122) + 138: q BINPUT 6 + 140: } EMPTY_DICT + 141: q BINPUT 7 + 143: ( MARK + 144: U SHORT_BINSTRING 'foo' + 149: q BINPUT 8 + 151: K BININT1 1 + 153: U SHORT_BINSTRING 'bar' + 158: q BINPUT 9 + 160: K BININT1 2 + 162: u SETITEMS (MARK at 143) + 163: b BUILD + 164: h BINGET 6 + 166: t TUPLE (MARK at 112) + 167: q BINPUT 10 + 169: h BINGET 10 + 171: K BININT1 5 + 173: e APPENDS (MARK at 5) + 174: . STOP +highest protocol among opcodes = 2 +""" + +def create_data(): + c = C() + c.foo = 1 + c.bar = 2 + x = [0, 1L, 2.0, 3.0+0j] + # Append some integer test cases at cPickle.c's internal size + # cutoffs. + uint1max = 0xff + uint2max = 0xffff + int4max = 0x7fffffff + x.extend([1, -1, + uint1max, -uint1max, -uint1max-1, + uint2max, -uint2max, -uint2max-1, + int4max, -int4max, -int4max-1]) + y = ('abc', 'abc', c, c) + x.append(y) + x.append(y) + x.append(5) + return x + +class AbstractPickleTests(unittest.TestCase): + # Subclass must define self.dumps, self.loads, self.error. + + _testdata = create_data() + + def setUp(self): + pass + + def test_misc(self): + # test various datatypes not tested by testdata + for proto in protocols: + x = myint(4) + s = self.dumps(x, proto) + y = self.loads(s) + self.assertEqual(x, y) + + x = (1, ()) + s = self.dumps(x, proto) + y = self.loads(s) + self.assertEqual(x, y) + + x = initarg(1, x) + s = self.dumps(x, proto) + y = self.loads(s) + self.assertEqual(x, y) + + # XXX test __reduce__ protocol? + + def test_roundtrip_equality(self): + expected = self._testdata + for proto in protocols: + s = self.dumps(expected, proto) + got = self.loads(s) + self.assertEqual(expected, got) + + def test_load_from_canned_string(self): + expected = self._testdata + for canned in DATA0, DATA1, DATA2: + got = self.loads(canned) + self.assertEqual(expected, got) + + # There are gratuitous differences between pickles produced by + # pickle and cPickle, largely because cPickle starts PUT indices at + # 1 and pickle starts them at 0. See XXX comment in cPickle's put2() -- + # there's a comment with an exclamation point there whose meaning + # is a mystery. cPickle also suppresses PUT for objects with a refcount + # of 1. + def dont_test_disassembly(self): + from cStringIO import StringIO + from pickletools import dis + + for proto, expected in (0, DATA0_DIS), (1, DATA1_DIS): + s = self.dumps(self._testdata, proto) + filelike = StringIO() + dis(s, out=filelike) + got = filelike.getvalue() + self.assertEqual(expected, got) + + def test_recursive_list(self): + l = [] + l.append(l) + for proto in protocols: + s = self.dumps(l, proto) + x = self.loads(s) + self.assertEqual(x, l) + self.assertEqual(x, x[0]) + self.assertEqual(id(x), id(x[0])) + + def test_recursive_dict(self): + d = {} + d[1] = d + for proto in protocols: + s = self.dumps(d, proto) + x = self.loads(s) + self.assertEqual(x, d) + self.assertEqual(x[1], x) + self.assertEqual(id(x[1]), id(x)) + + def test_recursive_inst(self): + i = C() + i.attr = i + for proto in protocols: + s = self.dumps(i, 2) + x = self.loads(s) + self.assertEqual(x, i) + self.assertEqual(x.attr, x) + self.assertEqual(id(x.attr), id(x)) + + def test_recursive_multi(self): + l = [] + d = {1:l} + i = C() + i.attr = d + l.append(i) + for proto in protocols: + s = self.dumps(l, proto) + x = self.loads(s) + self.assertEqual(x, l) + self.assertEqual(x[0], i) + self.assertEqual(x[0].attr, d) + self.assertEqual(x[0].attr[1], x) + self.assertEqual(x[0].attr[1][0], i) + self.assertEqual(x[0].attr[1][0].attr, d) + + def test_garyp(self): + self.assertRaises(self.error, self.loads, 'garyp') + + def test_insecure_strings(self): + insecure = ["abc", "2 + 2", # not quoted + #"'abc' + 'def'", # not a single quoted string + "'abc", # quote is not closed + "'abc\"", # open quote and close quote don't match + "'abc' ?", # junk after close quote + "'\\'", # trailing backslash + # some tests of the quoting rules + #"'abc\"\''", + #"'\\\\a\'\'\'\\\'\\\\\''", + ] + for s in insecure: + buf = "S" + s + "\012p0\012." + self.assertRaises(ValueError, self.loads, buf) + + if have_unicode: + def test_unicode(self): + endcases = [unicode(''), unicode('<\\u>'), unicode('<\\\u1234>'), + unicode('<\n>'), unicode('<\\>')] + for proto in protocols: + for u in endcases: + p = self.dumps(u, proto) + u2 = self.loads(p) + self.assertEqual(u2, u) + + def test_ints(self): + import sys + for proto in protocols: + n = sys.maxint + while n: + for expected in (-n, n): + s = self.dumps(expected, proto) + n2 = self.loads(s) + self.assertEqual(expected, n2) + n = n >> 1 + + def test_maxint64(self): + maxint64 = (1L << 63) - 1 + data = 'I' + str(maxint64) + '\n.' + got = self.loads(data) + self.assertEqual(got, maxint64) + + # Try too with a bogus literal. + data = 'I' + str(maxint64) + 'JUNK\n.' + self.assertRaises(ValueError, self.loads, data) + + def xxx_test_long(self): + for proto in protocols: + # 256 bytes is where LONG4 begins. + for nbits in 1, 8, 8*254, 8*255, 8*256, 8*257: + nbase = 1L << nbits + for npos in nbase-1, nbase, nbase+1: + for n in npos, -npos: + pickle = self.dumps(n, proto) + got = self.loads(pickle) + self.assertEqual(n, got) + # Try a monster. This is quadratic-time in protos 0 & 1, so don't + # bother with those. + nbase = long("deadbeeffeedface", 16) + nbase += nbase << 1000000 + for n in nbase, -nbase: + p = self.dumps(n, 2) + got = self.loads(p) + self.assertEqual(n, got) + + def test_reduce(self): + pass + + def test_getinitargs(self): + pass + + def test_metaclass(self): + a = use_metaclass() + for proto in protocols: + s = self.dumps(a, proto) + b = self.loads(s) + self.assertEqual(a.__class__, b.__class__) + + def test_structseq(self): + import time + import os + + t = time.localtime() + for proto in protocols: + s = self.dumps(t, proto) + u = self.loads(s) + self.assertEqual(t, u) + if hasattr(os, "stat"): + t = os.stat(os.curdir) + s = self.dumps(t, proto) + u = self.loads(s) + self.assertEqual(t, u) + if hasattr(os, "statvfs"): + t = os.statvfs(os.curdir) + s = self.dumps(t, proto) + u = self.loads(s) + self.assertEqual(t, u) + + # Tests for protocol 2 + + def test_proto(self): + build_none = pickle.NONE + pickle.STOP + for proto in protocols: + expected = build_none + if proto >= 2: + expected = pickle.PROTO + chr(proto) + expected + p = self.dumps(None, proto) + self.assertEqual(p, expected) + + oob = protocols[-1] + 1 # a future protocol + badpickle = pickle.PROTO + chr(oob) + build_none + try: + self.loads(badpickle) + except ValueError, detail: + self.failUnless(str(detail).startswith( + "unsupported pickle protocol")) + else: + self.fail("expected bad protocol number to raise ValueError") + + def test_long1(self): + x = 12345678910111213141516178920L + for proto in protocols: + s = self.dumps(x, proto) + y = self.loads(s) + self.assertEqual(x, y) + self.assertEqual(opcode_in_pickle(pickle.LONG1, s), proto >= 2) + + def test_long4(self): + x = 12345678910111213141516178920L << (256*8) + for proto in protocols: + s = self.dumps(x, proto) + y = self.loads(s) + self.assertEqual(x, y) + self.assertEqual(opcode_in_pickle(pickle.LONG4, s), proto >= 2) + + def test_short_tuples(self): + # Map (proto, len(tuple)) to expected opcode. + expected_opcode = {(0, 0): pickle.TUPLE, + (0, 1): pickle.TUPLE, + (0, 2): pickle.TUPLE, + (0, 3): pickle.TUPLE, + (0, 4): pickle.TUPLE, + + (1, 0): pickle.EMPTY_TUPLE, + (1, 1): pickle.TUPLE, + (1, 2): pickle.TUPLE, + (1, 3): pickle.TUPLE, + (1, 4): pickle.TUPLE, + + (2, 0): pickle.EMPTY_TUPLE, + (2, 1): pickle.TUPLE1, + (2, 2): pickle.TUPLE2, + (2, 3): pickle.TUPLE3, + (2, 4): pickle.TUPLE, + } + a = () + b = (1,) + c = (1, 2) + d = (1, 2, 3) + e = (1, 2, 3, 4) + for proto in protocols: + for x in a, b, c, d, e: + s = self.dumps(x, proto) + y = self.loads(s) + self.assertEqual(x, y, (proto, x, s, y)) + expected = expected_opcode[proto, len(x)] + self.assertEqual(opcode_in_pickle(expected, s), True) + + def test_singletons(self): + # Map (proto, singleton) to expected opcode. + expected_opcode = {(0, None): pickle.NONE, + (1, None): pickle.NONE, + (2, None): pickle.NONE, + + (0, True): pickle.INT, + (1, True): pickle.INT, + (2, True): pickle.NEWTRUE, + + (0, False): pickle.INT, + (1, False): pickle.INT, + (2, False): pickle.NEWFALSE, + } + for proto in protocols: + for x in None, False, True: + s = self.dumps(x, proto) + y = self.loads(s) + self.assert_(x is y, (proto, x, s, y)) + expected = expected_opcode[proto, x] + self.assertEqual(opcode_in_pickle(expected, s), True) + + def test_newobj_tuple(self): + x = MyTuple([1, 2, 3]) + x.foo = 42 + x.bar = "hello" + for proto in protocols: + s = self.dumps(x, proto) + y = self.loads(s) + self.assertEqual(tuple(x), tuple(y)) + self.assertEqual(x.__dict__, y.__dict__) + + def test_newobj_list(self): + x = MyList([1, 2, 3]) + x.foo = 42 + x.bar = "hello" + for proto in protocols: + s = self.dumps(x, proto) + y = self.loads(s) + self.assertEqual(list(x), list(y)) + self.assertEqual(x.__dict__, y.__dict__) + + def test_newobj_generic(self): + for proto in protocols: + for C in myclasses: + B = C.__base__ + x = C(C.sample) + x.foo = 42 + s = self.dumps(x, proto) + y = self.loads(s) + detail = (proto, C, B, x, y, type(y)) + self.assertEqual(B(x), B(y), detail) + self.assertEqual(x.__dict__, y.__dict__, detail) + + # Register a type with copy_reg, with extension code extcode. Pickle + # an object of that type. Check that the resulting pickle uses opcode + # (EXT[124]) under proto 2, and not in proto 1. + + def produce_global_ext(self, extcode, opcode): + e = ExtensionSaver(extcode) + try: + copy_reg.add_extension(__name__, "MyList", extcode) + x = MyList([1, 2, 3]) + x.foo = 42 + x.bar = "hello" + + # Dump using protocol 1 for comparison. + s1 = self.dumps(x, 1) + self.assert_(__name__ in s1) + self.assert_("MyList" in s1) + self.assertEqual(opcode_in_pickle(opcode, s1), False) + + y = self.loads(s1) + self.assertEqual(list(x), list(y)) + self.assertEqual(x.__dict__, y.__dict__) + + # Dump using protocol 2 for test. + s2 = self.dumps(x, 2) + self.assert_(__name__ not in s2) + self.assert_("MyList" not in s2) + self.assertEqual(opcode_in_pickle(opcode, s2), True) + + y = self.loads(s2) + self.assertEqual(list(x), list(y)) + self.assertEqual(x.__dict__, y.__dict__) + + finally: + e.restore() + + def test_global_ext1(self): + self.produce_global_ext(0x00000001, pickle.EXT1) # smallest EXT1 code + self.produce_global_ext(0x000000ff, pickle.EXT1) # largest EXT1 code + + def test_global_ext2(self): + self.produce_global_ext(0x00000100, pickle.EXT2) # smallest EXT2 code + self.produce_global_ext(0x0000ffff, pickle.EXT2) # largest EXT2 code + self.produce_global_ext(0x0000abcd, pickle.EXT2) # check endianness + + def test_global_ext4(self): + self.produce_global_ext(0x00010000, pickle.EXT4) # smallest EXT4 code + self.produce_global_ext(0x7fffffff, pickle.EXT4) # largest EXT4 code + self.produce_global_ext(0x12abcdef, pickle.EXT4) # check endianness + + def xxx_test_list_chunking(self): + n = 10 # too small to chunk + x = range(n) + for proto in protocols: + s = self.dumps(x, proto) + y = self.loads(s) + self.assertEqual(x, y) + num_appends = count_opcode(pickle.APPENDS, s) + self.assertEqual(num_appends, proto > 0) + + n = 2500 # expect at least two chunks when proto > 0 + x = range(n) + for proto in protocols: + s = self.dumps(x, proto) + y = self.loads(s) + self.assertEqual(x, y) + num_appends = count_opcode(pickle.APPENDS, s) + if proto == 0: + self.assertEqual(num_appends, 0) + else: + self.failUnless(num_appends >= 2) + + def xxx_test_dict_chunking(self): + n = 10 # too small to chunk + x = dict.fromkeys(range(n)) + for proto in protocols: + s = self.dumps(x, proto) + y = self.loads(s) + self.assertEqual(x, y) + num_setitems = count_opcode(pickle.SETITEMS, s) + self.assertEqual(num_setitems, proto > 0) + + n = 2500 # expect at least two chunks when proto > 0 + x = dict.fromkeys(range(n)) + for proto in protocols: + s = self.dumps(x, proto) + y = self.loads(s) + self.assertEqual(x, y) + num_setitems = count_opcode(pickle.SETITEMS, s) + if proto == 0: + self.assertEqual(num_setitems, 0) + else: + self.failUnless(num_setitems >= 2) + + def test_simple_newobj(self): + x = object.__new__(SimpleNewObj) # avoid __init__ + x.abc = 666 + for proto in protocols: + s = self.dumps(x, proto) + self.assertEqual(opcode_in_pickle(pickle.NEWOBJ, s), proto >= 2) + y = self.loads(s) # will raise TypeError if __init__ called + self.assertEqual(y.abc, 666) + self.assertEqual(x.__dict__, y.__dict__) + + def test_newobj_list_slots(self): + x = SlotList([1, 2, 3]) + x.foo = 42 + x.bar = "hello" + s = self.dumps(x, 2) + y = self.loads(s) + self.assertEqual(list(x), list(y)) + self.assertEqual(x.__dict__, y.__dict__) + self.assertEqual(x.foo, y.foo) + self.assertEqual(x.bar, y.bar) + + def test_reduce_overrides_default_reduce_ex(self): + for proto in 0, 1, 2: + x = REX_one() + self.assertEqual(x._reduce_called, 0) + s = self.dumps(x, proto) + self.assertEqual(x._reduce_called, 1) + y = self.loads(s) + self.assertEqual(y._reduce_called, 0) + + def test_reduce_ex_called(self): + for proto in 0, 1, 2: + x = REX_two() + self.assertEqual(x._proto, None) + s = self.dumps(x, proto) + self.assertEqual(x._proto, proto) + y = self.loads(s) + self.assertEqual(y._proto, None) + + def test_reduce_ex_overrides_reduce(self): + for proto in 0, 1, 2: + x = REX_three() + self.assertEqual(x._proto, None) + s = self.dumps(x, proto) + self.assertEqual(x._proto, proto) + y = self.loads(s) + self.assertEqual(y._proto, None) + +# Test classes for reduce_ex + +class REX_one(object): + _reduce_called = 0 + def __reduce__(self): + self._reduce_called = 1 + return REX_one, () + # No __reduce_ex__ here, but inheriting it from object + +class REX_two(object): + _proto = None + def __reduce_ex__(self, proto): + self._proto = proto + return REX_two, () + # No __reduce__ here, but inheriting it from object + +class REX_three(object): + _proto = None + def __reduce_ex__(self, proto): + self._proto = proto + return REX_two, () + def __reduce__(self): + raise TestFailed, "This __reduce__ shouldn't be called" + +# Test classes for newobj + +class MyInt(int): + sample = 1 + +class MyLong(long): + sample = 1L + +class MyFloat(float): + sample = 1.0 + +class MyComplex(complex): + sample = 1.0 + 0.0j + +class MyStr(str): + sample = "hello" + +class MyUnicode(unicode): + sample = u"hello \u1234" + +class MyTuple(tuple): + sample = (1, 2, 3) + +class MyList(list): + sample = [1, 2, 3] + +class MyDict(dict): + sample = {"a": 1, "b": 2} + +myclasses = [MyInt, MyLong, MyFloat, + MyComplex, + MyStr, MyUnicode, + MyTuple, MyList, MyDict] + + +class SlotList(MyList): + __slots__ = ["foo"] + +class SimpleNewObj(object): + def __init__(self, a, b, c): + # raise an error, to make sure this isn't called + raise TypeError("SimpleNewObj.__init__() didn't expect to get called") + +class AbstractPickleModuleTests(unittest.TestCase): + + def test_dump_closed_file(self): + import os + f = open(TESTFN, "w") + try: + f.close() + self.assertRaises(ValueError, self.module.dump, 123, f) + finally: + os.remove(TESTFN) + + def test_load_closed_file(self): + import os + f = open(TESTFN, "w") + try: + f.close() + self.assertRaises(ValueError, self.module.dump, 123, f) + finally: + os.remove(TESTFN) + + def test_highest_protocol(self): + # Of course this needs to be changed when HIGHEST_PROTOCOL changes. + self.assertEqual(self.module.HIGHEST_PROTOCOL, 2) + + +class AbstractPersistentPicklerTests(unittest.TestCase): + + # This class defines persistent_id() and persistent_load() + # functions that should be used by the pickler. All even integers + # are pickled using persistent ids. + + def persistent_id(self, object): + if isinstance(object, int) and object % 2 == 0: + self.id_count += 1 + return str(object) + else: + return None + + def persistent_load(self, oid): + self.load_count += 1 + object = int(oid) + assert object % 2 == 0 + return object + + def test_persistence(self): + self.id_count = 0 + self.load_count = 0 + L = range(10) + self.assertEqual(self.loads(self.dumps(L)), L) + self.assertEqual(self.id_count, 5) + self.assertEqual(self.load_count, 5) + + def test_bin_persistence(self): + self.id_count = 0 + self.load_count = 0 + L = range(10) + self.assertEqual(self.loads(self.dumps(L, 1)), L) + self.assertEqual(self.id_count, 5) + self.assertEqual(self.load_count, 5) From arigo at codespeak.net Tue Mar 22 00:05:49 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 22 Mar 2005 00:05:49 +0100 (MET) Subject: [pypy-svn] r10039 - pypy/dist/pypy/objspace Message-ID: <20050321230549.5C0BD27B71@code1.codespeak.net> Author: arigo Date: Tue Mar 22 00:05:49 2005 New Revision: 10039 Added: pypy/dist/pypy/objspace/thunk_and_idhack.py (contents, props changed) Modified: pypy/dist/pypy/objspace/thunk.py Log: We need a way to combine proxy levels on object spaces... For now I need the "thunk_and_idhack object space"... Modified: pypy/dist/pypy/objspace/thunk.py ============================================================================== --- pypy/dist/pypy/objspace/thunk.py (original) +++ pypy/dist/pypy/objspace/thunk.py Tue Mar 22 00:05:49 2005 @@ -63,8 +63,8 @@ return parentfn(*newargs) return proxy -def Space(): - space = create_proxy_space('thunk', proxymaker) +def Space(space=None): + space = create_proxy_space('thunk', proxymaker, space=space) space.setitem(space.builtin.w_dict, space.wrap('thunk'), space.wrap(app_thunk)) return space Added: pypy/dist/pypy/objspace/thunk_and_idhack.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/objspace/thunk_and_idhack.py Tue Mar 22 00:05:49 2005 @@ -0,0 +1,5 @@ +import thunk, idhack + +def Space(): + space = idhack.IdHackSpace() + return thunk.Space(space) From tismer at codespeak.net Tue Mar 22 00:15:00 2005 From: tismer at codespeak.net (tismer at codespeak.net) Date: Tue, 22 Mar 2005 00:15:00 +0100 (MET) Subject: [pypy-svn] r10040 - pypy/dist/lib-python-2.3.4/test Message-ID: <20050321231500.2A35427B71@code1.codespeak.net> Author: tismer Date: Tue Mar 22 00:14:59 2005 New Revision: 10040 Modified: pypy/dist/lib-python-2.3.4/test/pickletester.py Log: sorry, reverted my forbidden change to libpython Modified: pypy/dist/lib-python-2.3.4/test/pickletester.py ============================================================================== --- pypy/dist/lib-python-2.3.4/test/pickletester.py (original) +++ pypy/dist/lib-python-2.3.4/test/pickletester.py Tue Mar 22 00:14:59 2005 @@ -1,9 +1,3 @@ -# Notes about changes in this file: -# a prefix of "dont_" means the test makes no sense, -# because we don't use cPickle at all. -# "xxx_" means it works and can be done, but takes ages. -# When PyPy gets really fast, we should remove "xxx_". - import unittest import pickle import cPickle @@ -519,7 +513,7 @@ data = 'I' + str(maxint64) + 'JUNK\n.' self.assertRaises(ValueError, self.loads, data) - def xxx_test_long(self): + def test_long(self): for proto in protocols: # 256 bytes is where LONG4 begins. for nbits in 1, 8, 8*254, 8*255, 8*256, 8*257: @@ -744,7 +738,7 @@ self.produce_global_ext(0x7fffffff, pickle.EXT4) # largest EXT4 code self.produce_global_ext(0x12abcdef, pickle.EXT4) # check endianness - def xxx_test_list_chunking(self): + def test_list_chunking(self): n = 10 # too small to chunk x = range(n) for proto in protocols: @@ -766,7 +760,7 @@ else: self.failUnless(num_appends >= 2) - def xxx_test_dict_chunking(self): + def test_dict_chunking(self): n = 10 # too small to chunk x = dict.fromkeys(range(n)) for proto in protocols: From jacob at codespeak.net Tue Mar 22 00:25:59 2005 From: jacob at codespeak.net (jacob at codespeak.net) Date: Tue, 22 Mar 2005 00:25:59 +0100 (MET) Subject: [pypy-svn] r10041 - pypy/dist/pypy/lib Message-ID: <20050321232559.DB11627B71@code1.codespeak.net> Author: jacob Date: Tue Mar 22 00:25:59 2005 New Revision: 10041 Modified: pypy/dist/pypy/lib/binascii.py Log: Added support for base64 encoding/decoding. Modified: pypy/dist/pypy/lib/binascii.py ============================================================================== --- pypy/dist/pypy/lib/binascii.py (original) +++ pypy/dist/pypy/lib/binascii.py Tue Mar 22 00:25:59 2005 @@ -59,32 +59,143 @@ s = s[3:] yield ord(a), ord(b), ord(c) + +table_a2b_base64 = { + 'A': 0, + 'B': 1, + 'C': 2, + 'D': 3, + 'E': 4, + 'F': 5, + 'G': 6, + 'H': 7, + 'I': 8, + 'J': 9, + 'K': 10, + 'L': 11, + 'M': 12, + 'N': 13, + 'O': 14, + 'P': 15, + 'Q': 16, + 'R': 17, + 'S': 18, + 'T': 19, + 'U': 20, + 'V': 21, + 'W': 22, + 'X': 23, + 'Y': 24, + 'Z': 25, + 'a': 26, + 'b': 27, + 'c': 28, + 'd': 29, + 'e': 30, + 'f': 31, + 'g': 32, + 'h': 33, + 'i': 34, + 'j': 35, + 'k': 36, + 'l': 37, + 'm': 38, + 'n': 39, + 'o': 40, + 'p': 41, + 'q': 42, + 'r': 43, + 's': 44, + 't': 45, + 'u': 46, + 'v': 47, + 'w': 48, + 'x': 49, + 'y': 50, + 'z': 51, + '0': 52, + '1': 53, + '2': 54, + '3': 55, + '4': 56, + '5': 57, + '6': 58, + '7': 59, + '8': 60, + '9': 61, + '+': 62, + '/': 63, +} + +def quadruplets_base64(s): + while s: + a, b, c, d = table_a2b_base64[s[0]], table_a2b_base64[s[1]], table_a2b_base64[s[2]], table_a2b_base64[s[3]] + s = s[4:] + yield a, b, c, d + +def a2b_base64(s): + s = s.rstrip() + a = quadruplets_base64(s[:-4]) + result = [ + chr(A << 2 | ((B >> 4) & 0x3)) + + chr((B & 0xF) << 4 | ((C >> 2 ) & 0xF)) + + chr((C & 0xF) << 6 | D ) + for A, B, C, D in a] + final = s[-4:] + if final[2] == '=': + A = table_a2b_base64[final[0]] + B = table_a2b_base64[final[1]] + snippet = chr(A << 2 | ((B >> 4) & 0x3)) + elif final[3] == '=': + A = table_a2b_base64[final[0]] + B = table_a2b_base64[final[1]] + C = table_a2b_base64[final[2]] + snippet = chr(A << 2 | ((B >> 4) & 0x3)) + \ + chr((B & 0xF) << 4 | ((C >> 2 ) & 0xF)) + else: + A = table_a2b_base64[final[0]] + B = table_a2b_base64[final[1]] + C = table_a2b_base64[final[2]] + D = table_a2b_base64[final[3]] + snippet = chr(A << 2 | ((B >> 4) & 0x3)) + \ + chr((B & 0xF) << 4 | ((C >> 2 ) & 0xF)) + \ + chr((C & 0xF) << 6 | D ) + + return ''.join(result) + snippet + +table_b2a_base64 = \ +"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" + def b2a_base64(s): length = len(s) final_length = length % 3 - a = triples(s[:length - final_length]) + a = triples(s[: -final_length]) + result = [''.join( - [chr(0x20 + (( A >> 2 ) & 0x3F)), - chr(0x20 + (((A << 4) | ((B >> 4) & 0xF)) & 0x3F)), - chr(0x20 + (((B << 2) | ((C >> 6) & 0x3)) & 0x3F)), - chr(0x20 + (( C ) & 0x3F))]) for A, B, C in a] - final = s[length - final_length:] + [table_b2a_base64[( A >> 2 ) & 0x3F], + table_b2a_base64[((A << 4) | ((B >> 4) & 0xF)) & 0x3F], + table_b2a_base64[((B << 2) | ((C >> 6) & 0x3)) & 0x3F], + table_b2a_base64[( C ) & 0x3F]]) + for A, B, C in a] + + final = s[-final_length:] if len(final) == 0: snippet = '' elif len(final) == 1: a = ord(final[0]) - print a - snippet = chr(0x20 + ((a >> 2 ) & 0x3F)) + \ - chr((0x20 + (a << 4 )) & 0x3F) + '==' + snippet = table_b2a_base64[(a >> 2 ) & 0x3F] + \ + table_b2a_base64[(a << 4 ) & 0x3F] + '==' else: a = ord(final[0]) b = ord(final[1]) - snippet = chr(0x20 + ((a >> 2 ) & 0x3F)) + \ - chr(0x20 + (((a << 4) | ((b >> 4) & 0xF)) - & 0x3F)) + chr((0x20 + (b << 2)) & 0x3F) + '=' + snippet = table_b2a_base64[(a >> 2) & 0x3F] + \ + table_b2a_base64[(a << 4) | ((b >> 4) & 0xF) & 0x3F] + \ + table_b2a_base64[(b << 2) & 0x3F] + '=' return ''.join(result) + snippet + '\n' + + #print b2a_uu('1234567') #print b2a_uu('123456789012345678901234567890123456789012345') #print b2a_uu('1234567890123456789012345678901234567890123456') From arigo at codespeak.net Tue Mar 22 00:44:14 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 22 Mar 2005 00:44:14 +0100 (MET) Subject: [pypy-svn] r10043 - pypy/dist/pypy/module/sys2 Message-ID: <20050321234414.B876D27B71@code1.codespeak.net> Author: arigo Date: Tue Mar 22 00:44:14 2005 New Revision: 10043 Modified: pypy/dist/pypy/module/sys2/state.py Log: make select fakable from CPython. Modified: pypy/dist/pypy/module/sys2/state.py ============================================================================== --- pypy/dist/pypy/module/sys2/state.py (original) +++ pypy/dist/pypy/module/sys2/state.py Tue Mar 22 00:44:14 2005 @@ -25,7 +25,7 @@ # The following built-in modules are not written in PyPy, so we # steal them from Python. for fn in ['posix', 'nt', 'os2', 'mac', 'ce', 'riscos', - 'math', '_codecs', 'array', + 'math', '_codecs', 'array', 'select', '_random', '_sre', 'time', '_socket', 'errno', 'binascii', 'parser']: if fn not in builtin_modules: From jacob at codespeak.net Tue Mar 22 01:30:22 2005 From: jacob at codespeak.net (jacob at codespeak.net) Date: Tue, 22 Mar 2005 01:30:22 +0100 (MET) Subject: [pypy-svn] r10045 - pypy/dist/pypy/lib Message-ID: <20050322003022.8AF2727B7A@code1.codespeak.net> Author: jacob Date: Tue Mar 22 01:30:22 2005 New Revision: 10045 Modified: pypy/dist/pypy/lib/binascii.py Log: Bug fix to a2b_base64. Modified: pypy/dist/pypy/lib/binascii.py ============================================================================== --- pypy/dist/pypy/lib/binascii.py (original) +++ pypy/dist/pypy/lib/binascii.py Tue Mar 22 01:30:22 2005 @@ -139,7 +139,7 @@ result = [ chr(A << 2 | ((B >> 4) & 0x3)) + chr((B & 0xF) << 4 | ((C >> 2 ) & 0xF)) + - chr((C & 0xF) << 6 | D ) + chr((C & 0x3) << 6 | D ) for A, B, C, D in a] final = s[-4:] if final[2] == '=': @@ -159,7 +159,7 @@ D = table_a2b_base64[final[3]] snippet = chr(A << 2 | ((B >> 4) & 0x3)) + \ chr((B & 0xF) << 4 | ((C >> 2 ) & 0xF)) + \ - chr((C & 0xF) << 6 | D ) + chr((C & 0x3) << 6 | D ) return ''.join(result) + snippet @@ -170,7 +170,7 @@ length = len(s) final_length = length % 3 - a = triples(s[: -final_length]) + a = triples(s[ :length - final_length]) result = [''.join( [table_b2a_base64[( A >> 2 ) & 0x3F], @@ -179,10 +179,10 @@ table_b2a_base64[( C ) & 0x3F]]) for A, B, C in a] - final = s[-final_length:] - if len(final) == 0: + final = s[length - final_length:] + if final_length == 0: snippet = '' - elif len(final) == 1: + elif final_length == 1: a = ord(final[0]) snippet = table_b2a_base64[(a >> 2 ) & 0x3F] + \ table_b2a_base64[(a << 4 ) & 0x3F] + '==' @@ -190,7 +190,7 @@ a = ord(final[0]) b = ord(final[1]) snippet = table_b2a_base64[(a >> 2) & 0x3F] + \ - table_b2a_base64[(a << 4) | ((b >> 4) & 0xF) & 0x3F] + \ + table_b2a_base64[((a << 4) | (b >> 4) & 0xF) & 0x3F] + \ table_b2a_base64[(b << 2) & 0x3F] + '=' return ''.join(result) + snippet + '\n' From tismer at codespeak.net Tue Mar 22 01:35:01 2005 From: tismer at codespeak.net (tismer at codespeak.net) Date: Tue, 22 Mar 2005 01:35:01 +0100 (MET) Subject: [pypy-svn] r10046 - pypy/dist/pypy/objspace/std Message-ID: <20050322003501.504BB27B7A@code1.codespeak.net> Author: tismer Date: Tue Mar 22 01:35:01 2005 New Revision: 10046 Modified: pypy/dist/pypy/objspace/std/typeobject.py Log: corrected __base__ initialization for heaptypes Modified: pypy/dist/pypy/objspace/std/typeobject.py ============================================================================== --- pypy/dist/pypy/objspace/std/typeobject.py (original) +++ pypy/dist/pypy/objspace/std/typeobject.py Tue Mar 22 01:35:01 2005 @@ -72,7 +72,10 @@ w_self.w_bestbase = w_most_derived_base_with_slots else: nslots = 0 - + + if w_self.w_bestbase is None: + w_self.w_bestbase = bases_w[0] + wantdict = True if '__slots__' in dict_w: wantdict = False From tismer at codespeak.net Tue Mar 22 01:35:58 2005 From: tismer at codespeak.net (tismer at codespeak.net) Date: Tue, 22 Mar 2005 01:35:58 +0100 (MET) Subject: [pypy-svn] r10047 - pypy/dist/pypy/module/builtin Message-ID: <20050322003558.E431D27B7A@code1.codespeak.net> Author: tismer Date: Tue Mar 22 01:35:58 2005 New Revision: 10047 Modified: pypy/dist/pypy/module/builtin/app_complex.py Log: reverted changes and supplied what an immutable builtin type is expected to have. Pickling is happy now, and so are we. Modified: pypy/dist/pypy/module/builtin/app_complex.py ============================================================================== --- pypy/dist/pypy/module/builtin/app_complex.py (original) +++ pypy/dist/pypy/module/builtin/app_complex.py Tue Mar 22 01:35:58 2005 @@ -2,15 +2,7 @@ Plain Python definition of the 'complex' type. """ -# XXX this has been object before, -# but we need something different, or -# the __base__ will never become different from object. -# note that this is real Python behavior :-) - -# XXX would be eventually try tospecial-case this -# in typeobject to be handled as a base class? - -class complex(float): +class complex(object): """complex(real[, imag]) -> complex number Create a complex number from a real part and an optional imaginary part. @@ -21,14 +13,18 @@ # XXX this class is not well tested # provide __new__to prevend the default which has no parameters - def __new__(typ, *args, **kwds): - ret = float.__new__(typ) + def __new__(typ, real=0.0, imag=None): + ret = object.__new__(typ) + ret._init(real, imag) return ret + def __getnewargs__(self): + return (complex(self.real, self.imag),) + def __reduce__(self): - return self.__class__, (), self.__dict__ + return self.__class__, (self.real, self.imag), self.__dict__ - def __init__(self, real=0.0, imag=None): + def _init(self, real=0.0, imag=None): if isinstance(real, str): if imag is not None: msg = "complex() can't take second arg if first is a string" From arigo at codespeak.net Tue Mar 22 02:26:53 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 22 Mar 2005 02:26:53 +0100 (MET) Subject: [pypy-svn] r10048 - pypy/dist/pypy/objspace Message-ID: <20050322012653.ECDB627B75@code1.codespeak.net> Author: arigo Date: Tue Mar 22 02:26:53 2005 New Revision: 10048 Modified: pypy/dist/pypy/objspace/thunk.py Log: added is_thunk() in the thunk objspace. Modified: pypy/dist/pypy/objspace/thunk.py ============================================================================== --- pypy/dist/pypy/objspace/thunk.py (original) +++ pypy/dist/pypy/objspace/thunk.py Tue Mar 22 02:26:53 2005 @@ -45,6 +45,10 @@ baseobjspace.W_Root, argument.Arguments]) +def is_thunk(space, w_obj): + return space.newbool(isinstance(w_obj, W_Thunk)) +app_is_thunk = gateway.interp2app(is_thunk) + # __________________________________________________________________________ operation_args_that_dont_force = { @@ -67,4 +71,6 @@ space = create_proxy_space('thunk', proxymaker, space=space) space.setitem(space.builtin.w_dict, space.wrap('thunk'), space.wrap(app_thunk)) + space.setitem(space.builtin.w_dict, space.wrap('is_thunk'), + space.wrap(app_is_thunk)) return space From hpk at codespeak.net Tue Mar 22 02:55:32 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Tue, 22 Mar 2005 02:55:32 +0100 (MET) Subject: [pypy-svn] r10049 - pypy/dist/pypy/module/builtin Message-ID: <20050322015532.C362827B61@code1.codespeak.net> Author: hpk Date: Tue Mar 22 02:55:32 2005 New Revision: 10049 Modified: pypy/dist/pypy/module/builtin/operation.py Log: hum, iter() is just fishy with respect to errors/type checking Modified: pypy/dist/pypy/module/builtin/operation.py ============================================================================== --- pypy/dist/pypy/module/builtin/operation.py (original) +++ pypy/dist/pypy/module/builtin/operation.py Tue Mar 22 02:55:32 2005 @@ -91,18 +91,21 @@ def iter(space, w_collection_or_callable, w_sentinel=NoneNotWrapped): if w_sentinel is None: - w_res = space.iter(w_collection_or_callable) - w_typeres = space.type(w_res) - try: - space.getattr(w_typeres, space.wrap('next')) - except OperationError, e: - if not e.match(space, space.w_AttributeError): - raise - raise OperationError(space.w_TypeError, - space.wrap("iter() returned non-iterator of type '%s'" % - w_typeres.name)) - else: - return w_res + return space.iter(w_collection_or_callable) + # XXX it seems that CPython checks the following + # for newstyle but doesn't for oldstyle classes :-( + #w_res = space.iter(w_collection_or_callable) + #w_typeres = space.type(w_res) + #try: + # space.getattr(w_typeres, space.wrap('next')) + #except OperationError, e: + # if not e.match(space, space.w_AttributeError): + # raise + # raise OperationError(space.w_TypeError, + # space.wrap("iter() returned non-iterator of type '%s'" % + # w_typeres.name)) + #else: + # return w_res else: return iter_sentinel(space, w_collection_or_callable, w_sentinel) From arigo at codespeak.net Tue Mar 22 03:02:50 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 22 Mar 2005 03:02:50 +0100 (MET) Subject: [pypy-svn] r10050 - in pypy/dist/pypy/objspace: . test Message-ID: <20050322020250.C26A227B62@code1.codespeak.net> Author: arigo Date: Tue Mar 22 03:02:50 2005 New Revision: 10050 Modified: pypy/dist/pypy/objspace/idhack.py pypy/dist/pypy/objspace/test/test_idhackobjspace.py Log: These are really the sane semantics... The sane, I mean, "sane"... Modified: pypy/dist/pypy/objspace/idhack.py ============================================================================== --- pypy/dist/pypy/objspace/idhack.py (original) +++ pypy/dist/pypy/objspace/idhack.py Tue Mar 22 03:02:50 2005 @@ -19,9 +19,10 @@ def idhack(w_obj): try: - return w_obj.__id + w_obj = w_obj.__unified_with[-1] except AttributeError: - return id(w_obj) + pass + return id(w_obj) # XXX call the inherited space.id(), maybe class IdHackSpace(std.Space): @@ -45,8 +46,14 @@ # ____________________________________________________________ def become(space, w_target, w_source): - w_target.__class__ = w_source.__class__ - w_target.__dict__ = w_source.__dict__ - w_target.__id = idhack(w_source) + try: + targetfamily = w_target.__unified_with + except AttributeError: + targetfamily = [w_target] + w_source.__unified_with = targetfamily + targetfamily.append(w_source) + for w_obj in targetfamily: + w_obj.__class__ = w_source.__class__ + w_obj.__dict__ = w_source.__dict__ return space.w_None app_become = gateway.interp2app(become) Modified: pypy/dist/pypy/objspace/test/test_idhackobjspace.py ============================================================================== --- pypy/dist/pypy/objspace/test/test_idhackobjspace.py (original) +++ pypy/dist/pypy/objspace/test/test_idhackobjspace.py Tue Mar 22 03:02:50 2005 @@ -17,3 +17,11 @@ assert idx != idy become(x, y) assert id(x) == id(y) == idy + + def test_double_become(self): + x = 5 + y = 6 + z = 7 + become(x, y) + become(y, z) + assert x is y is z From rxe at codespeak.net Tue Mar 22 03:24:15 2005 From: rxe at codespeak.net (rxe at codespeak.net) Date: Tue, 22 Mar 2005 03:24:15 +0100 (MET) Subject: [pypy-svn] r10051 - pypy/dist/pypy/module/test Message-ID: <20050322022415.0D16F27B71@code1.codespeak.net> Author: rxe Date: Tue Mar 22 03:24:14 2005 New Revision: 10051 Modified: pypy/dist/pypy/module/test/test_sysmodule.py Log: Simple test for settrace() Modified: pypy/dist/pypy/module/test/test_sysmodule.py ============================================================================== --- pypy/dist/pypy/module/test/test_sysmodule.py (original) +++ pypy/dist/pypy/module/test/test_sysmodule.py Tue Mar 22 03:24:14 2005 @@ -97,9 +97,6 @@ raise AssertionError, "ZeroDivisionError not caught" - - - class AppTestSysModulePortedFromCPython: def setup_class(cls): @@ -352,3 +349,14 @@ assert isinstance(vi[2], int) assert vi[3] in ("alpha", "beta", "candidate", "final") assert isinstance(vi[4], int) + + def test_settrace(self): + counts = [] + def trace(x, y, z): + counts.append(None) + + def x(): + pass + sys.settrace(trace) + x() + assert len(counts) == 1 From rxe at codespeak.net Tue Mar 22 03:26:20 2005 From: rxe at codespeak.net (rxe at codespeak.net) Date: Tue, 22 Mar 2005 03:26:20 +0100 (MET) Subject: [pypy-svn] r10052 - in pypy/dist/pypy/interpreter: . test Message-ID: <20050322022620.1439C27B45@code1.codespeak.net> Author: rxe Date: Tue Mar 22 03:26:19 2005 New Revision: 10052 Modified: pypy/dist/pypy/interpreter/gateway.py pypy/dist/pypy/interpreter/test/test_pyframe.py Log: Simple test for f_back on frame. Ensure code for py.test is created NOT at applevel. Modified: pypy/dist/pypy/interpreter/gateway.py ============================================================================== --- pypy/dist/pypy/interpreter/gateway.py (original) +++ pypy/dist/pypy/interpreter/gateway.py Tue Mar 22 03:26:19 2005 @@ -485,6 +485,7 @@ interp-level function that invokes the callable with the given name at app-level.""" + applevel = True NOT_RPYTHON_ATTRIBUTES = ['code'] def __init__(self, source, filename=None): @@ -504,13 +505,17 @@ def _builddict(self, space): "NOT_RPYTHON" - - from pypy.interpreter.pycode import PyCode - code = PyCode(space)._from_code(self.code, applevel=True) + code = self._buildcode(space, self.code) w_glob = space.newdict([]) space.exec_(code, w_glob, w_glob) return w_glob - + + def _buildcode(cls, space, code): + "NOT_RPYTHON" + from pypy.interpreter.pycode import PyCode + return PyCode(space)._from_code(code, applevel=cls.applevel) + _buildcode = classmethod(_buildcode) + def wget(self, space, name): w_globals = self.getwdict(space) return space.getitem(w_globals, space.wrap(name)) @@ -578,10 +583,12 @@ # the following two will probably get merged into one class applevel_temp(applevel): + applevel = False def getwdict(self, space): return self._builddict(space) # no cache class applevelinterp_temp(applevelinterp): + applevel = False def getwdict(self, space): return self._builddict(space) # no cache Modified: pypy/dist/pypy/interpreter/test/test_pyframe.py ============================================================================== --- pypy/dist/pypy/interpreter/test/test_pyframe.py (original) +++ pypy/dist/pypy/interpreter/test/test_pyframe.py Tue Mar 22 03:26:19 2005 @@ -5,15 +5,15 @@ # test for the presence of the attributes, not functionality - def test_f_locals(self): - import sys - f = sys._getframe() - assert f.f_locals is locals() - - def test_f_globals(self): - import sys - f = sys._getframe() - assert f.f_globals is globals() +## def test_f_locals(self): +## import sys +## f = sys._getframe() +## assert f.f_locals is locals() + +## def test_f_globals(self): +## import sys +## f = sys._getframe() +## assert f.f_globals is globals() def test_f_builtins(self): import sys, __builtin__ @@ -37,3 +37,17 @@ return [x, y, z] origin = g.func_code.co_firstlineno assert g() == [origin+3, origin+4, origin+5] + + def test_f_back(self): + import sys + def trace(a,b,c): return trace + def f(): + f_frame = sys._getframe() + return g(f_frame) + def g(f_frame): + g_frame = sys._getframe() + print g_frame + print g_frame.f_back + print g_frame.f_back.f_code.co_name, f_frame.f_code.co_name + sys.settrace(trace) + f() From tismer at codespeak.net Tue Mar 22 03:37:36 2005 From: tismer at codespeak.net (tismer at codespeak.net) Date: Tue, 22 Mar 2005 03:37:36 +0100 (MET) Subject: [pypy-svn] r10053 - pypy/dist/pypy/objspace/std Message-ID: <20050322023736.F0BC227B71@code1.codespeak.net> Author: tismer Date: Tue Mar 22 03:37:36 2005 New Revision: 10053 Modified: pypy/dist/pypy/objspace/std/fake.py pypy/dist/pypy/objspace/std/typeobject.py pypy/dist/pypy/objspace/std/typetype.py Log: support for type's __module__ attribute. fake needed to be changed, too, because we want to preserve the module name of faked types Modified: pypy/dist/pypy/objspace/std/fake.py ============================================================================== --- pypy/dist/pypy/objspace/std/fake.py (original) +++ pypy/dist/pypy/objspace/std/fake.py Tue Mar 22 03:37:36 2005 @@ -59,7 +59,9 @@ if not (cpy_type is unicode and s in ['__add__', '__contains__']): if s != '__getattribute__' or cpy_type is type(sys): kw[s] = v - + + kw['__module__'] = cpy_type.__module__ + def fake__new__(space, w_type, args_w): args = [space.unwrap(w_arg) for w_arg in args_w] try: Modified: pypy/dist/pypy/objspace/std/typeobject.py ============================================================================== --- pypy/dist/pypy/objspace/std/typeobject.py (original) +++ pypy/dist/pypy/objspace/std/typeobject.py Tue Mar 22 03:37:36 2005 @@ -5,7 +5,7 @@ from pypy.objspace.std.stdtypedef import std_dict_descr, issubtypedef, Member from pypy.objspace.std.objecttype import object_typedef -from copy_reg import _HEAPTYPE # XXX is it clean to do this? +from copy_reg import _HEAPTYPE class W_TypeObject(W_Object): from pypy.objspace.std.typetype import type_typedef as typedef @@ -22,14 +22,30 @@ w_self.nslots = 0 w_self.w_bestbase = None + # initialize __module__ in the dict + if '__module__' not in dict_w: + try: + caller = space.getexecutioncontext().framestack.top() + except IndexError: + w_globals = w_locals = space.newdict([]) + else: + w_globals = caller.w_globals + w_str_name = space.wrap('__name__') + try: + w_name = space.getitem(w_globals, w_str_name) + except OperationError: + pass + else: + dict_w['__module__'] = w_name + if overridetypedef is not None: w_self.instancetypedef = overridetypedef w_self.hasdict = overridetypedef.hasdict - w_self.w__flags__ = space.wrap(0) # not a heaptype + w_self.__flags__ = 0 # not a heaptype if overridetypedef.base is not None: w_self.w_bestbase = space.gettypeobject(overridetypedef.base) else: - w_self.w__flags__ = space.wrap(_HEAPTYPE) + w_self.__flags__ = _HEAPTYPE # find the most specific typedef instancetypedef = object_typedef for w_base in bases_w: Modified: pypy/dist/pypy/objspace/std/typetype.py ============================================================================== --- pypy/dist/pypy/objspace/std/typetype.py (original) +++ pypy/dist/pypy/objspace/std/typetype.py Tue Mar 22 03:37:36 2005 @@ -2,6 +2,7 @@ from pypy.objspace.std.stdtypedef import * from pypy.objspace.std.dictproxyobject import descr_get_dictproxy +from copy_reg import _HEAPTYPE def descr__new__(space, w_typetype, w_name, w_bases, w_dict): "This is used to create user-defined classes only." @@ -89,7 +90,37 @@ return w_result def descr__flags(space, w_type): - return w_type.w__flags__ + return space.wrap(w_type.__flags__) + +def defunct_descr_get__module(space, w_type): + if w_type.__flags__ & _HEAPTYPE: + return w_type.dict_w['__module__'] + else: + # here CPython checks for a module.name in the type description. + # we skip that here and only provide the default + return space.wrap('__builtin__') + +# heaptypeness is not really the right criteria, because we +# also might get a module attribute from a faked type. +# therefore, we use the module attribute whenever it exists. + +def descr_get__module(space, w_type): + if '__module__' in w_type.dict_w: + return w_type.dict_w['__module__'] + else: + return space.wrap('__builtin__') + +def descr_set__module(space, w_type, w_value): + if not (w_type.__flags__ & _HEAPTYPE): + raise OperationError(space.w_TypeError, + space.wrap("can't set %s.__module__" % + w_type.name)) + if w_value is None: + raise OperationError(space.w_TypeError, + space.wrap("can't delete %s.__module__" % + w_type.name)) + w_type.dict_w['__module__'] = w_value + # ____________________________________________________________ type_typedef = StdTypeDef("type", @@ -102,4 +133,5 @@ __doc__ = GetSetProperty(descr__doc), mro = gateway.interp2app(descr_mro), __flags__ = GetSetProperty(descr__flags), + __module__ = GetSetProperty(descr_get__module, descr_set__module), ) From jacob at codespeak.net Tue Mar 22 03:38:21 2005 From: jacob at codespeak.net (jacob at codespeak.net) Date: Tue, 22 Mar 2005 03:38:21 +0100 (MET) Subject: [pypy-svn] r10054 - in pypy/dist/pypy: lib module/sys2 Message-ID: <20050322023821.263C327B71@code1.codespeak.net> Author: jacob Date: Tue Mar 22 03:38:20 2005 New Revision: 10054 Modified: pypy/dist/pypy/lib/binascii.py pypy/dist/pypy/module/sys2/state.py Log: Work on quoted printable. Modified: pypy/dist/pypy/lib/binascii.py ============================================================================== --- pypy/dist/pypy/lib/binascii.py (original) +++ pypy/dist/pypy/lib/binascii.py Tue Mar 22 03:38:20 2005 @@ -196,9 +196,34 @@ -#print b2a_uu('1234567') -#print b2a_uu('123456789012345678901234567890123456789012345') -#print b2a_uu('1234567890123456789012345678901234567890123456') -#print '"%s"' % a2b_uu(b2a_uu('1234567')) -#print '"%s"' % a2b_uu(b2a_uu('123456789012345678901234567890123456789012345')) +def a2b_qp(s): + pass +def b2a_qp(s): + def f(c): + if '!' <= c <= '<' or '>' <= c <= '~': + return c + return '=' + str(hex(ord(c))) + return ''.join([ f(c) for c in s]) + +hex_numbers = '0123456789ABCDEF' +def hex(n): + if n == 0: + return '0' + + if n < 0: + n = -n + sign = '-' + else: + sign = '' + arr = [] + for nibble in hexgen(n): + arr = [hex_numbers[nibble]] + arr + return sign + ''.join(arr) + +def hexgen(n): + """ Yield a nibble at a time. """ + while n: + remainder = n % 0x10 + n = n / 0x10 + yield remainder Modified: pypy/dist/pypy/module/sys2/state.py ============================================================================== --- pypy/dist/pypy/module/sys2/state.py (original) +++ pypy/dist/pypy/module/sys2/state.py Tue Mar 22 03:38:20 2005 @@ -27,7 +27,7 @@ for fn in ['posix', 'nt', 'os2', 'mac', 'ce', 'riscos', 'math', '_codecs', 'array', 'select', '_random', '_sre', 'time', '_socket', 'errno', - 'binascii', 'parser']: + 'parser']: if fn not in builtin_modules: try: builtin_modules[fn] = hack_cpython_module(fn) From hpk at codespeak.net Tue Mar 22 15:25:14 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Tue, 22 Mar 2005 15:25:14 +0100 (MET) Subject: [pypy-svn] r10056 - pypy/dist/pypy Message-ID: <20050322142514.2166027B96@code1.codespeak.net> Author: hpk Date: Tue Mar 22 15:25:13 2005 New Revision: 10056 Modified: pypy/dist/pypy/TODO Log: add a large TODO item for the testing situation Modified: pypy/dist/pypy/TODO ============================================================================== --- pypy/dist/pypy/TODO (original) +++ pypy/dist/pypy/TODO Tue Mar 22 15:25:13 2005 @@ -9,6 +9,15 @@ (probably requiring geninterp to generate less global init-code) +* extend the testing mechanisms to specifically allow: + - running plain CPython regrtests (including outputtests, + unittests, doctests, ...) + - running modified CPython regrtests againat CPython + as well as against PyPy + - running pure app-level py-test style regrtests + - running interp-level py-test style regrtests + - running doctests with py.test modules + * not all of CPython's exceptions use the same __init__! * refactor the cmdline-entrypoints to PyPy aka py.py main.py From arigo at codespeak.net Tue Mar 22 16:20:45 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 22 Mar 2005 16:20:45 +0100 (MET) Subject: [pypy-svn] r10057 - pypy/dist/pypy/objspace Message-ID: <20050322152045.5720727B92@code1.codespeak.net> Author: arigo Date: Tue Mar 22 16:20:45 2005 New Revision: 10057 Modified: pypy/dist/pypy/objspace/idhack.py pypy/dist/pypy/objspace/thunk_and_idhack.py Log: - made idhack composable (i.e. a proxy obj space) - thunk_and_idhack compose thunk and idhack in the other order Modified: pypy/dist/pypy/objspace/idhack.py ============================================================================== --- pypy/dist/pypy/objspace/idhack.py (original) +++ pypy/dist/pypy/objspace/idhack.py Tue Mar 22 16:20:45 2005 @@ -12,38 +12,16 @@ """ -from pypy.objspace import std +from proxy import create_proxy_space from pypy.interpreter import gateway # ____________________________________________________________ -def idhack(w_obj): +def canonical(w_obj): try: - w_obj = w_obj.__unified_with[-1] + return w_obj.__unified_with[-1] except AttributeError: - pass - return id(w_obj) # XXX call the inherited space.id(), maybe - - -class IdHackSpace(std.Space): - - def initialize(self): - super(IdHackSpace, self).initialize() - self.setitem(self.builtin.w_dict, self.wrap('become'), - self.wrap(app_become)) - - def is_(self, w_one, w_two): - if idhack(w_one) == idhack(w_two): - return self.w_True - return self.w_False - - def id(self, w_obj): - return self.wrap(idhack(w_obj)) - - -Space = IdHackSpace - -# ____________________________________________________________ + return w_obj def become(space, w_target, w_source): try: @@ -57,3 +35,22 @@ w_obj.__dict__ = w_source.__dict__ return space.w_None app_become = gateway.interp2app(become) + +# ____________________________________________________________ + +def proxymaker(space, opname, parentfn): + if opname == 'id': + def proxy(w_obj): + return parentfn(canonical(w_obj)) + elif opname == 'is_': + def proxy(w_a, w_b): + return parentfn(canonical(w_a), canonical(w_b)) + else: + proxy = parentfn + return proxy + +def Space(space=None): + space = create_proxy_space('idhack', proxymaker, space=space) + space.setitem(space.builtin.w_dict, space.wrap('become'), + space.wrap(app_become)) + return space Modified: pypy/dist/pypy/objspace/thunk_and_idhack.py ============================================================================== --- pypy/dist/pypy/objspace/thunk_and_idhack.py (original) +++ pypy/dist/pypy/objspace/thunk_and_idhack.py Tue Mar 22 16:20:45 2005 @@ -1,5 +1,6 @@ import thunk, idhack def Space(): - space = idhack.IdHackSpace() - return thunk.Space(space) + space = thunk.Space() + space = idhack.Space(space) + return space From hpk at codespeak.net Tue Mar 22 16:30:13 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Tue, 22 Mar 2005 16:30:13 +0100 (MET) Subject: [pypy-svn] r10058 - pypy/dist/pypy/tool Message-ID: <20050322153013.6B44727B92@code1.codespeak.net> Author: hpk Date: Tue Mar 22 16:30:13 2005 New Revision: 10058 Modified: pypy/dist/pypy/tool/option.py Log: make py.py -h work somewhat again Modified: pypy/dist/pypy/tool/option.py ============================================================================== --- pypy/dist/pypy/tool/option.py (original) +++ pypy/dist/pypy/tool/option.py Tue Mar 22 16:30:13 2005 @@ -19,8 +19,9 @@ options.append(make_option( '-o', '--objspace', action="callback", - callback=objspace_callback, type="string", + callback=objspace_callback, type="string", dest="objspacename", help="object space to run PyPy on.")) + options.append(make_option( '--oldstyle', action="store_true",dest="oldstyle", help="enable oldstyle classes as default metaclass (std objspace only)")) From arigo at codespeak.net Tue Mar 22 16:30:44 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 22 Mar 2005 16:30:44 +0100 (MET) Subject: [pypy-svn] r10059 - pypy/dist/pypy/objspace Message-ID: <20050322153044.729D127B92@code1.codespeak.net> Author: arigo Date: Tue Mar 22 16:30:44 2005 New Revision: 10059 Modified: pypy/dist/pypy/objspace/idhack.py Log: A simpler implementation of the idhack obj space. Modified: pypy/dist/pypy/objspace/idhack.py ============================================================================== --- pypy/dist/pypy/objspace/idhack.py (original) +++ pypy/dist/pypy/objspace/idhack.py Tue Mar 22 16:30:44 2005 @@ -13,26 +13,22 @@ """ from proxy import create_proxy_space -from pypy.interpreter import gateway +from pypy.interpreter import gateway, baseobjspace # ____________________________________________________________ +class W_Dead(baseobjspace.W_Root, object): + pass + def canonical(w_obj): - try: - return w_obj.__unified_with[-1] - except AttributeError: - return w_obj + while isinstance(w_obj, W_Dead): + w_obj = w_obj.__pointer + return w_obj def become(space, w_target, w_source): - try: - targetfamily = w_target.__unified_with - except AttributeError: - targetfamily = [w_target] - w_source.__unified_with = targetfamily - targetfamily.append(w_source) - for w_obj in targetfamily: - w_obj.__class__ = w_source.__class__ - w_obj.__dict__ = w_source.__dict__ + w_target = canonical(w_target) + w_target.__class__ = W_Dead + w_target.__pointer = w_source return space.w_None app_become = gateway.interp2app(become) From arigo at codespeak.net Tue Mar 22 16:39:04 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 22 Mar 2005 16:39:04 +0100 (MET) Subject: [pypy-svn] r10061 - in pypy/dist/pypy/objspace: . test Message-ID: <20050322153904.4950027B92@code1.codespeak.net> Author: arigo Date: Tue Mar 22 16:39:04 2005 New Revision: 10061 Removed: pypy/dist/pypy/objspace/idhack.py pypy/dist/pypy/objspace/test/test_idhackobjspace.py pypy/dist/pypy/objspace/thunk_and_idhack.py Modified: pypy/dist/pypy/objspace/test/test_thunkobjspace.py pypy/dist/pypy/objspace/thunk.py Log: Removed idhack and put become() in the thunk objspace, because it's really easy to do so and we avoid all the space composition nightmare. Deleted: /pypy/dist/pypy/objspace/idhack.py ============================================================================== --- /pypy/dist/pypy/objspace/idhack.py Tue Mar 22 16:39:04 2005 +++ (empty file) @@ -1,52 +0,0 @@ -"""Example usage: - - $ python interpreter/py.py -o idhack - >>> x = 6 - >>> id(x) - 12345678 - >>> become(x, 7) - >>> x - 7 - >>> id(x) - 12345678 - -""" - -from proxy import create_proxy_space -from pypy.interpreter import gateway, baseobjspace - -# ____________________________________________________________ - -class W_Dead(baseobjspace.W_Root, object): - pass - -def canonical(w_obj): - while isinstance(w_obj, W_Dead): - w_obj = w_obj.__pointer - return w_obj - -def become(space, w_target, w_source): - w_target = canonical(w_target) - w_target.__class__ = W_Dead - w_target.__pointer = w_source - return space.w_None -app_become = gateway.interp2app(become) - -# ____________________________________________________________ - -def proxymaker(space, opname, parentfn): - if opname == 'id': - def proxy(w_obj): - return parentfn(canonical(w_obj)) - elif opname == 'is_': - def proxy(w_a, w_b): - return parentfn(canonical(w_a), canonical(w_b)) - else: - proxy = parentfn - return proxy - -def Space(space=None): - space = create_proxy_space('idhack', proxymaker, space=space) - space.setitem(space.builtin.w_dict, space.wrap('become'), - space.wrap(app_become)) - return space Deleted: /pypy/dist/pypy/objspace/test/test_idhackobjspace.py ============================================================================== --- /pypy/dist/pypy/objspace/test/test_idhackobjspace.py Tue Mar 22 16:39:04 2005 +++ (empty file) @@ -1,27 +0,0 @@ - -class AppTest_IdHack: - - objspacename = 'idhack' - - def test_simple(self): - x = 5 - y = 6 - assert x is not y - become(x, y) - assert x is y - - def test_id(self): - # these are the Smalltalk semantics of become(). - x = 5; idx = id(x) - y = 6; idy = id(y) - assert idx != idy - become(x, y) - assert id(x) == id(y) == idy - - def test_double_become(self): - x = 5 - y = 6 - z = 7 - become(x, y) - become(y, z) - assert x is y is z Modified: pypy/dist/pypy/objspace/test/test_thunkobjspace.py ============================================================================== --- pypy/dist/pypy/objspace/test/test_thunkobjspace.py (original) +++ pypy/dist/pypy/objspace/test/test_thunkobjspace.py Tue Mar 22 16:39:04 2005 @@ -33,3 +33,26 @@ d[7][0] += 1 assert computed == [True] assert d[7] == [43] + + def test_become(self): + x = 5 + y = 6 + assert x is not y + become(x, y) + assert x is y + + def test_id(self): + # these are the Smalltalk semantics of become(). + x = 5; idx = id(x) + y = 6; idy = id(y) + assert idx != idy + become(x, y) + assert id(x) == id(y) == idy + + def test_double_become(self): + x = 5 + y = 6 + z = 7 + become(x, y) + become(y, z) + assert x is y is z Modified: pypy/dist/pypy/objspace/thunk.py ============================================================================== --- pypy/dist/pypy/objspace/thunk.py (original) +++ pypy/dist/pypy/objspace/thunk.py Tue Mar 22 16:39:04 2005 @@ -49,6 +49,14 @@ return space.newbool(isinstance(w_obj, W_Thunk)) app_is_thunk = gateway.interp2app(is_thunk) +def become(space, w_target, w_source): + while isinstance(w_target, W_Thunk) and w_target.w_value is not None: + w_target = w_target.w_value + w_target.__class__ = W_Thunk + w_target.__dict__ = {'w_value': w_source} + return space.w_None +app_become = gateway.interp2app(become) + # __________________________________________________________________________ operation_args_that_dont_force = { @@ -73,4 +81,6 @@ space.wrap(app_thunk)) space.setitem(space.builtin.w_dict, space.wrap('is_thunk'), space.wrap(app_is_thunk)) + space.setitem(space.builtin.w_dict, space.wrap('become'), + space.wrap(app_become)) return space Deleted: /pypy/dist/pypy/objspace/thunk_and_idhack.py ============================================================================== --- /pypy/dist/pypy/objspace/thunk_and_idhack.py Tue Mar 22 16:39:04 2005 +++ (empty file) @@ -1,6 +0,0 @@ -import thunk, idhack - -def Space(): - space = thunk.Space() - space = idhack.Space(space) - return space From alex at codespeak.net Tue Mar 22 17:38:43 2005 From: alex at codespeak.net (alex at codespeak.net) Date: Tue, 22 Mar 2005 17:38:43 +0100 (MET) Subject: [pypy-svn] r10062 - pypy/dist/pypy/lib/test2 Message-ID: <20050322163843.674AD27B5F@code1.codespeak.net> Author: alex Date: Tue Mar 22 17:38:43 2005 New Revision: 10062 Modified: pypy/dist/pypy/lib/test2/test_itertools.py Log: made one test shorter (thus faster), commented away one that's too implementation-dependent and thus unsuitable for pypy Modified: pypy/dist/pypy/lib/test2/test_itertools.py ============================================================================== --- pypy/dist/pypy/lib/test2/test_itertools.py (original) +++ pypy/dist/pypy/lib/test2/test_itertools.py Tue Mar 22 17:38:43 2005 @@ -95,8 +95,11 @@ zip('abc', 'def')) self.assertEqual([pair for pair in izip('abc', 'def')], zip('abc', 'def')) - ids = map(id, izip('abc', 'def')) - self.assertEqual(min(ids), max(ids)) + # the following test deals with a specific implementation detail, + # that izip "reuses" the SAME tuple object each time when it can; + # it does not apply correctly to pypy, so I'm commenting it -- AM + # ids = map(id, izip('abc', 'def')) + # self.assertEqual(min(ids), max(ids)) ids = map(id, list(izip('abc', 'def'))) self.assertEqual(len(dict.fromkeys(ids)), len(ids)) @@ -174,7 +177,9 @@ self.assertRaises(ValueError, islice, xrange(10), 1, 'a') self.assertRaises(ValueError, islice, xrange(10), 'a', 1, 1) self.assertRaises(ValueError, islice, xrange(10), 1, 'a', 1) - self.assertEqual(len(list(islice(count(), 1, 10, sys.maxint))), 1) + # too slow to test on pypy, weakened...: + # self.assertEqual(len(list(islice(count(), 1, 10, sys.maxint))), 1) + self.assertEqual(len(list(islice(count(), 1, 10, 99))), 1) def test_takewhile(self): data = [1, 3, 5, 20, 2, 4, 6, 8] From alex at codespeak.net Tue Mar 22 18:01:46 2005 From: alex at codespeak.net (alex at codespeak.net) Date: Tue, 22 Mar 2005 18:01:46 +0100 (MET) Subject: [pypy-svn] r10065 - pypy/dist/pypy/lib/test2 Message-ID: <20050322170146.F134E27B76@code1.codespeak.net> Author: alex Date: Tue Mar 22 18:01:46 2005 New Revision: 10065 Modified: pypy/dist/pypy/lib/test2/test_iter_extra.py Log: give up on testing iter(fakeiterator) for now, due to insoluble conflicts between CPython's behavior for oldstyle vs newstyle fakeiterators. Modified: pypy/dist/pypy/lib/test2/test_iter_extra.py ============================================================================== --- pypy/dist/pypy/lib/test2/test_iter_extra.py (original) +++ pypy/dist/pypy/lib/test2/test_iter_extra.py Tue Mar 22 18:01:46 2005 @@ -9,9 +9,16 @@ return self # no next method -- which is why it's *fake*! +# in CPython, behavior of iter(FakeIterator()) differs depending on +# whether class FakeIterator is old-style or new-style. Currently +# pypy is following the ``old-style'' diagnostic behavior since that +# appears to be necessary to make test_itertools.py work (sigh!!!). +# So we can't sensibly test this, for now, until that issue may be +# better decided in the future -- AM + class IterTest(unittest.TestCase): - def test_fakeiterator(self): + def dont_test_fakeiterator(self): x = FakeIterator() self.assertRaises(TypeError, iter, x) x.next = lambda: 23 From briandorsey at codespeak.net Tue Mar 22 18:13:42 2005 From: briandorsey at codespeak.net (briandorsey at codespeak.net) Date: Tue, 22 Mar 2005 18:13:42 +0100 (MET) Subject: [pypy-svn] r10066 - pypy/dist/pypy/lib Message-ID: <20050322171342.90BE727B7B@code1.codespeak.net> Author: briandorsey Date: Tue Mar 22 18:13:42 2005 New Revision: 10066 Modified: pypy/dist/pypy/lib/binascii.py Log: binascii now passes test_base64invalid test. Modified: pypy/dist/pypy/lib/binascii.py ============================================================================== --- pypy/dist/pypy/lib/binascii.py (original) +++ pypy/dist/pypy/lib/binascii.py Tue Mar 22 18:13:42 2005 @@ -135,33 +135,46 @@ def a2b_base64(s): s = s.rstrip() + # clean out all invalid characters, this also strips the final '=' padding + clean_s = [] + for item in s: + if item in table_a2b_base64: + clean_s.append(item) + s = ''.join(clean_s) + # Add '=' padding back into the string + if len(s) % 4: + s = s + ('=' * (4 - len(s) % 4)) + a = quadruplets_base64(s[:-4]) result = [ chr(A << 2 | ((B >> 4) & 0x3)) + chr((B & 0xF) << 4 | ((C >> 2 ) & 0xF)) + chr((C & 0x3) << 6 | D ) for A, B, C, D in a] - final = s[-4:] - if final[2] == '=': - A = table_a2b_base64[final[0]] - B = table_a2b_base64[final[1]] - snippet = chr(A << 2 | ((B >> 4) & 0x3)) - elif final[3] == '=': - A = table_a2b_base64[final[0]] - B = table_a2b_base64[final[1]] - C = table_a2b_base64[final[2]] - snippet = chr(A << 2 | ((B >> 4) & 0x3)) + \ - chr((B & 0xF) << 4 | ((C >> 2 ) & 0xF)) - else: - A = table_a2b_base64[final[0]] - B = table_a2b_base64[final[1]] - C = table_a2b_base64[final[2]] - D = table_a2b_base64[final[3]] - snippet = chr(A << 2 | ((B >> 4) & 0x3)) + \ - chr((B & 0xF) << 4 | ((C >> 2 ) & 0xF)) + \ - chr((C & 0x3) << 6 | D ) - return ''.join(result) + snippet + if s: + final = s[-4:] + if final[2] == '=': + A = table_a2b_base64[final[0]] + B = table_a2b_base64[final[1]] + snippet = chr(A << 2 | ((B >> 4) & 0x3)) + elif final[3] == '=': + A = table_a2b_base64[final[0]] + B = table_a2b_base64[final[1]] + C = table_a2b_base64[final[2]] + snippet = chr(A << 2 | ((B >> 4) & 0x3)) + \ + chr((B & 0xF) << 4 | ((C >> 2 ) & 0xF)) + else: + A = table_a2b_base64[final[0]] + B = table_a2b_base64[final[1]] + C = table_a2b_base64[final[2]] + D = table_a2b_base64[final[3]] + snippet = chr(A << 2 | ((B >> 4) & 0x3)) + \ + chr((B & 0xF) << 4 | ((C >> 2 ) & 0xF)) + \ + chr((C & 0x3) << 6 | D ) + result.append(snippet) + + return ''.join(result) table_b2a_base64 = \ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" From jacob at codespeak.net Tue Mar 22 18:15:29 2005 From: jacob at codespeak.net (jacob at codespeak.net) Date: Tue, 22 Mar 2005 18:15:29 +0100 (MET) Subject: [pypy-svn] r10067 - pypy/dist/pypy/lib Message-ID: <20050322171529.A8F5D27B7B@code1.codespeak.net> Author: jacob Date: Tue Mar 22 18:15:29 2005 New Revision: 10067 Modified: pypy/dist/pypy/lib/binascii.py Log: Quoted printable plus support. Modified: pypy/dist/pypy/lib/binascii.py ============================================================================== --- pypy/dist/pypy/lib/binascii.py (original) +++ pypy/dist/pypy/lib/binascii.py Tue Mar 22 18:15:29 2005 @@ -207,16 +207,34 @@ table_b2a_base64[(b << 2) & 0x3F] + '=' return ''.join(result) + snippet + '\n' - - def a2b_qp(s): - pass + parts = s.rstrip().split('=') + + # Change the parts in-place + for index, part in enumerate(parts[1:]): + if len(parts) > 2 and part[0] in hex_numbers and part[1] in hex_numbers: + parts[index + 1] = chr(strhex_to_int(part[0:2])) + part[2:] + else: + parts[index + 1] = '=' + parts[index + 1] + + return ''.join(parts) def b2a_qp(s): + """ In this implementation, we are quoting all spaces and tab character. + This is ok by the standard, though it slightly reduces the + readability of the quoted string. The CPython implementation + preserves internal whitespace, which is a different way of + implementing the standard. The reason we are doing things differently + is that it greatly simplifies the code. + + The CPython implementation does not escape CR and LF characters + and does not encode newlines as CRLF sequences. This seems to be + non-standard, and we copy this behaviour. + """ def f(c): - if '!' <= c <= '<' or '>' <= c <= '~': + if '!' <= c <= '<' or '>' <= c <= '~' or c in '\n\r': return c - return '=' + str(hex(ord(c))) + return '=' + two_hex_digits(ord(c)) return ''.join([ f(c) for c in s]) hex_numbers = '0123456789ABCDEF' @@ -233,10 +251,19 @@ for nibble in hexgen(n): arr = [hex_numbers[nibble]] + arr return sign + ''.join(arr) - + +def two_hex_digits(n): + return hex_numbers[n / 0x10] + hex_numbers[n % 0x10] + def hexgen(n): """ Yield a nibble at a time. """ while n: remainder = n % 0x10 n = n / 0x10 yield remainder + +def strhex_to_int(s): + i = 0 + for c in s: + i = i * 0x10 + hex_numbers.index(c) + return i From hpk at codespeak.net Tue Mar 22 18:18:43 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Tue, 22 Mar 2005 18:18:43 +0100 (MET) Subject: [pypy-svn] r10068 - in pypy/dist: lib-python-2.3.4/test pypy pypy/tool Message-ID: <20050322171843.A273927B7B@code1.codespeak.net> Author: hpk Date: Tue Mar 22 18:18:43 2005 New Revision: 10068 Modified: pypy/dist/lib-python-2.3.4/test/conftest.py pypy/dist/pypy/conftest.py pypy/dist/pypy/tool/compile.py Log: - make test_codeop.py pass again - don't patch the builtin compile when running tests - let pypy/tool/compile.compile use py.code.compile() when DEBUG is true Modified: pypy/dist/lib-python-2.3.4/test/conftest.py ============================================================================== --- pypy/dist/lib-python-2.3.4/test/conftest.py (original) +++ pypy/dist/lib-python-2.3.4/test/conftest.py Tue Mar 22 18:18:43 2005 @@ -33,7 +33,7 @@ 'test_builtin.py', 'test_call.py', 'test_cmath.py', -# 'test_codeop.py', # Commented out due to strange iteraction with py.test +'test_codeop.py', # Commented out due to strange iteraction with py.test 'test_commands.py', 'test_compare.py', 'test_compile.py', @@ -89,23 +89,36 @@ for test in all_tests: yield Module(test) -def app_list_testmethods(mod, testcaseclass): +w_testlist = None + +def getmyspace(): + space = gettestobjspace('std') + # we once and for all want to patch run_unittest + # to get us the list of intended unittest-TestClasses + # from each regression test + global w_testlist + if w_testlist is None: + w_testlist = space.newlist([]) + space.appexec([w_testlist], """ + (testlist): + def hack_run_unittest(*classes): + testlist.extend(list(classes)) + from test import test_support # humpf + test_support.run_unittest = hack_run_unittest + """) + return space + +def app_list_testmethods(mod, testcaseclass, classlist): """ return [(instance.setUp, instance.tearDown, [instance.testmethod1, ...]), ...] """ #print "entering list_testmethods" - classlist = [] if callable(getattr(mod, 'test_main', None)): - from test import test_support # humpf - def hack_run_unittest(*classes): - classlist.extend(list(classes)) - test_support.run_unittest = hack_run_unittest + classlist[:] = [] mod.test_main() assert classlist, ("found %s.test_main() but it returned no " "test classes" % mod.__name__) - test_support.run_unittest = None # nobody should really - # call it anymore else: # we try to find out fitting tests ourselves for clsname, cls in mod.__dict__.items(): @@ -144,7 +157,7 @@ self.extpy = py.path.extpy(fspath) def run(self, driver): - space = gettestobjspace('std') + space = getmyspace() try: oldsysout = sys.stdout sys.stdout = capturesysout = py.std.cStringIO.StringIO() @@ -171,7 +184,7 @@ def _prepare(self): if hasattr(self, 'space'): return - self.space = space = gettestobjspace('std') + self.space = space = getmyspace() w_mod = make_module(space, 'unittest', mydir.join('pypy_unittest.py')) self.w_TestCase = space.getattr(w_mod, space.wrap('TestCase')) @@ -188,7 +201,7 @@ name = self.fspath.purebasename space = self.space w_mod = make_module(space, name, self.fspath) - w_tlist = list_testmethods(space, w_mod, self.w_TestCase) + w_tlist = list_testmethods(space, w_mod, self.w_TestCase, w_testlist) tlist_w = space.unpackiterable(w_tlist) for item_w in tlist_w: w_setup, w_teardown, w_methods = space.unpacktuple(item_w) Modified: pypy/dist/pypy/conftest.py ============================================================================== --- pypy/dist/pypy/conftest.py (original) +++ pypy/dist/pypy/conftest.py Tue Mar 22 18:18:43 2005 @@ -34,7 +34,7 @@ try: return _spacecache[name] except KeyError: - py.magic.invoke(compile=True) + #py.magic.invoke(compile=True) module = __import__("pypy.objspace.%s" % name, None, None, ["Space"]) space = module.Space() _spacecache[name] = space Modified: pypy/dist/pypy/tool/compile.py ============================================================================== --- pypy/dist/pypy/tool/compile.py (original) +++ pypy/dist/pypy/tool/compile.py Tue Mar 22 18:18:43 2005 @@ -1,6 +1,9 @@ from __future__ import generators cache = {} +import py +DEBUG = 1 + def compile2(source, filename='', mode='exec', flags= generators.compiler_flag, dont_inherit=0): """ central compile hook for pypy initialization @@ -12,6 +15,9 @@ #print "***** duplicate code ******* " #print source except KeyError: - co = compile(source, filename, mode, flags) + if DEBUG: + co = py.code.compile(source, filename, mode, flags) + else: + co = compile(source, filename, mode, flags) cache[key] = co return co From arigo at codespeak.net Tue Mar 22 18:58:49 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 22 Mar 2005 18:58:49 +0100 (MET) Subject: [pypy-svn] r10070 - pypy/dist/pypy/documentation/revreport Message-ID: <20050322175849.96FC427B42@code1.codespeak.net> Author: arigo Date: Tue Mar 22 18:58:49 2005 New Revision: 10070 Modified: pypy/dist/pypy/documentation/revreport/delta.py Log: Ignore CPython's __cmp__ methods when it also has __eq__&friends. Modified: pypy/dist/pypy/documentation/revreport/delta.py ============================================================================== --- pypy/dist/pypy/documentation/revreport/delta.py (original) +++ pypy/dist/pypy/documentation/revreport/delta.py Tue Mar 22 18:58:49 2005 @@ -668,7 +668,13 @@ names.update(expl1.names(cls)) for cls in expl2.get_mro(cls2): - names.update(expl2.names(cls)) + d = Set(expl2.names(cls)) + if ('__cmp__' in d and '__cmp__' not in names and + '__eq__' in d and '__ne__' in d and + '__lt__' in d and '__le__' in d and + '__gt__' in d and '__ge__' in d): + del d['__cmp__'] + names.update(d) names = list(names) names.sort() From alex at codespeak.net Tue Mar 22 19:07:03 2005 From: alex at codespeak.net (alex at codespeak.net) Date: Tue, 22 Mar 2005 19:07:03 +0100 (MET) Subject: [pypy-svn] r10071 - pypy/dist/pypy/lib Message-ID: <20050322180703.7EAE527B5A@code1.codespeak.net> Author: alex Date: Tue Mar 22 19:07:03 2005 New Revision: 10071 Modified: pypy/dist/pypy/lib/itertools.py Log: Now passes all tests in lib/test2/test_itertools.py. Modified: pypy/dist/pypy/lib/itertools.py ============================================================================== --- pypy/dist/pypy/lib/itertools.py (original) +++ pypy/dist/pypy/lib/itertools.py Tue Mar 22 19:07:03 2005 @@ -354,17 +354,25 @@ """ def __init__(self, iterable, *args): s = slice(*args) - self.start, self.stop, self.step = s.start or 0, s.stop, s.step or 1 + self.start, self.stop, self.step = s.start or 0, s.stop, s.step + if self.step is None: + self.step = 1 if self.start<0 or (self.stop is not None and self.stop<0 - ) or self.step<0: + ) or self.step<=0: raise ValueError, "indices for islice() must be positive" - self.donext = iter(iterable).next + self.it = iter(iterable) + self.donext = None self.cnt = 0 def __iter__(self): return self def next(self): + if self.donext is None: + try: + self.donext = self.it.next + except AttributeError: + raise TypeError while self.cnt < self.start: self.donext() self.cnt += 1 From arigo at codespeak.net Tue Mar 22 19:09:59 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 22 Mar 2005 19:09:59 +0100 (MET) Subject: [pypy-svn] r10072 - pypy/dist/pypy/documentation/revreport Message-ID: <20050322180959.3C26A27B5A@code1.codespeak.net> Author: arigo Date: Tue Mar 22 19:09:59 2005 New Revision: 10072 Modified: pypy/dist/pypy/documentation/revreport/delta.py Log: strange type attributes we don't care about Modified: pypy/dist/pypy/documentation/revreport/delta.py ============================================================================== --- pypy/dist/pypy/documentation/revreport/delta.py (original) +++ pypy/dist/pypy/documentation/revreport/delta.py Tue Mar 22 19:09:59 2005 @@ -675,6 +675,13 @@ '__gt__' in d and '__ge__' in d): del d['__cmp__'] names.update(d) + + if cls2 is type: # strange strange attributes we don't care about + del names['__basicsize__'] + del names['__cmp__'] + del names['__dictoffset__'] + del names['__itemsize__'] + del names['__weakrefoffset__'] names = list(names) names.sort() From arigo at codespeak.net Tue Mar 22 19:12:34 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 22 Mar 2005 19:12:34 +0100 (MET) Subject: [pypy-svn] r10073 - pypy/dist/pypy/documentation/revreport Message-ID: <20050322181234.78A5B27B5A@code1.codespeak.net> Author: arigo Date: Tue Mar 22 19:12:34 2005 New Revision: 10073 Modified: pypy/dist/pypy/documentation/revreport/delta.py Log: oups. revreport fix. Modified: pypy/dist/pypy/documentation/revreport/delta.py ============================================================================== --- pypy/dist/pypy/documentation/revreport/delta.py (original) +++ pypy/dist/pypy/documentation/revreport/delta.py Tue Mar 22 19:12:34 2005 @@ -673,16 +673,16 @@ '__eq__' in d and '__ne__' in d and '__lt__' in d and '__le__' in d and '__gt__' in d and '__ge__' in d): - del d['__cmp__'] + d.remove('__cmp__') names.update(d) if cls2 is type: # strange strange attributes we don't care about - del names['__basicsize__'] - del names['__cmp__'] - del names['__dictoffset__'] - del names['__itemsize__'] - del names['__weakrefoffset__'] - + names.remove('__basicsize__') + names.remove('__cmp__') + names.remove('__dictoffset__') + names.remove('__itemsize__') + names.remove('__weakrefoffset__') + names = list(names) names.sort() From arigo at codespeak.net Tue Mar 22 19:25:17 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 22 Mar 2005 19:25:17 +0100 (MET) Subject: [pypy-svn] r10074 - in pypy/dist/pypy: lib/test2 module/builtin module/test Message-ID: <20050322182517.84A2B27B5A@code1.codespeak.net> Author: arigo Date: Tue Mar 22 19:25:17 2005 New Revision: 10074 Added: pypy/dist/pypy/module/test/test_complexobject.py - copied unchanged from r10069, pypy/dist/pypy/lib/test2/test_complexobject.py Removed: pypy/dist/pypy/lib/test2/test_complexobject.py Modified: pypy/dist/pypy/module/builtin/app_complex.py Log: - class complex now uses slots for 'real' and 'imag', made read-only with a hack. - complex.__rdivmod__(). - moved the test_complexobject.py in module/test/. Deleted: /pypy/dist/pypy/lib/test2/test_complexobject.py ============================================================================== --- /pypy/dist/pypy/lib/test2/test_complexobject.py Tue Mar 22 19:25:17 2005 +++ (empty file) @@ -1,267 +0,0 @@ -#!/usr/bin/env python - -""" - -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - -Note that this test currently runs at cpython-level and not -at any application level .... - -""" -#taken from CPython 2.3 (?) - -""" -Test module for class complex in complexobject.py - -As it seems there are some numerical differences in -the __div__ and __divmod__ methods which have to be -sorted out. -""" - -import autopath - -import math -import cmath -import sys -import types -#import unittest - -#from pypy.tool import testit -#from pypy.appspace.complexobject import complex as pycomplex - -#from pypy.module.test.applevel_in_cpython import applevel_in_cpython -#our_own_builtin = applevel_in_cpython('__builtin__') -#pycomplex = our_own_builtin.complex - -from pypy.module.builtin.app_complex import complex as pycomplex - -try: - unicode - have_unicode = 0 # pypy doesn't have unicode, we know it ... -except NameError: - have_unicode = 0 - - -def equal(a, b): - "Compare two complex or normal numbers. 0 if different, 1 if roughly equal." - - numTypes = [types.IntType, types.LongType, types.FloatType] - da, db = dir(a), dir(b) - - if 'real' in da and 'real' in db and 'imag' in da and 'imag' in db: - if math.fabs(a.real-b.real) > 1e-10: - return 0 - if math.fabs(a.imag-b.imag) > 1e-10: - return 0 - else: - return 1 - elif type(a) in numTypes and type(b) in numTypes: - if math.fabs(a-b) > 1e-10: - return 0 - else: - return 1 - - - - -def enumerate(): - valueRange = [-3, -0.5, 0, 1] - res = [] - for x0 in valueRange: - for y0 in valueRange: - for x1 in valueRange: - for y1 in valueRange: - z0c = complex(x0,y0) - z1c = complex(x1,y1) - z0p = pycomplex(x0,y0) - z1p = pycomplex(x1,y1) - res.append((z0c, z1c, z0p, z1p)) - - return res - - - -class TestComplex: - - def assertAEqual(self, a, b): - assert equal(a, b) - - def test_wrongInit1(self): - "Compare wrong init. with CPython." - - try: - complex("1", "1") - except TypeError: - pass - else: - self.fail('complex("1", "1")') - - try: - pycomplex("1", "1") - except TypeError: - pass - else: - self.fail('complex("1", "1")') - - - def test_wrongInit2(self): - "Compare wrong init. with CPython." - - try: - complex(1, "1") - except TypeError: - pass - else: - self.fail('complex(1, "1")') - - try: - pycomplex(1, "1") - except TypeError: - pass - else: - self.fail('complex(1, "1")') - - - def test_wrongInitFromString(self): - "Compare string init. with CPython." - - if complex(" 3.14+J ") != 3.14+1j: - self.fail('complex(" 3.14+J )"') - if not equal(pycomplex(" 3.14+J "), pycomplex(3.14,1)): - self.fail('complex(" 3.14+J )"') - - - def test_wrongInitFromUnicodeString(self): - "Compare unicode string init. with CPython." - - if have_unicode: - if complex(unicode(" 3.14+J ")) != 3.14+1j: - self.fail('complex(u" 3.14+J )"') - if not equal(pycomplex(unicode(" 3.14+J ")), pycomplex(3.14, 1)): - self.fail('complex(u" 3.14+J )"') - - - def test_class(self): - "Compare class with CPython." - - class Z: - def __complex__(self): - return 3.14j - z = Z() - if complex(z) != 3.14j: - self.fail('complex(classinstance)') - - if not equal(complex(z), pycomplex(0, 3.14)): - self.fail('complex(classinstance)') - - - def test_add_sub_mul_div(self): - "Compare add/sub/mul/div with CPython." - - for (z0c, z1c, z0p, z1p) in enumerate(): - mc = z0c*z1c - mp = z0p*z1p - self.assertAEqual(mc, mp) - - sc = z0c+z1c - sp = z0p+z1p - self.assertAEqual(sc, sp) - - dc = z0c-z1c - dp = z0p-z1p - self.assertAEqual(dc, dp) - - if not equal(z1c, complex(0,0)): - qc = z0c/z1c - qp = z0p/z1p - self.assertAEqual(qc, qp) - - - def test_special(self): - "Compare special methods with CPython." - - for (x, y) in [(0,0), (0,1), (1,3.)]: - zc = complex(x, y) - zp = pycomplex(x, y) - - self.assertAEqual(zc, zp) - self.assertAEqual(-zc, -zp) - self.assertAEqual(+zc, +zp) - self.assertAEqual(abs(zc), abs(zp)) - self.assertAEqual(zc, zp) - #self.assertEqual(zc.conjugate(), zp.conjugate()) XXX - assert str(zc) == str(zp) - assert hash(zc) == hash(zp) - - - # this fails on python2.3 and is depreacted anyway - def _test_divmod(self): - "Compare divmod with CPython." - - for (z0c, z1c, z0p, z1p) in enumerate(): - mc = z0c*z1c - mp = z0p*z1p - self.assertAEqual(mc, mp) - - if not equal(z1c, complex(0,0)): - ddc, mmc = divmod(z0c, z1c) - self.assertAEqual(ddc*z1c + mmc, z0c) - ddp, mmp = divmod(z0p, z1p) - self.assertAEqual(ddp*z1p + mmp, z0p) - self.assertAEqual(ddc, ddp) - self.assertAEqual(mmc, mmp) - - - # these fail on python2.3 - def _test_mod(self): - "Compare mod with CPython." - - for (z0c, z1c, z0p, z1p) in enumerate(): - mc = z0c*z1c - mp = z0p*z1p - self.assertAEqual(mc, mp) - - if not equal(z1c, complex(0,0)): - rc = z0c%z1c - rp = z0p%z1p - self.assertAEqual(rc, rp) - - def test_div(self): - "Compare mod with CPython." - - for (z0c, z1c, z0p, z1p) in enumerate(): - mc = z0c*z1c - mp = z0p*z1p - self.assertAEqual(mc, mp) - - if not equal(z1c, complex(0,0)): - rc = z0c/z1c - rp = z0p/z1p - self.assertAEqual(rc, rp) - - - def test_pow(self): - "Compare pow with CPython." - - for (z0c, z1c, z0p, z1p) in enumerate(): - if not equal(z0c, 0j) and (z1c.imag != 0.0): - pc = z0c**z1c - pp = z0p**z1p - self.assertAEqual(pc, pp) - pc = z0c**z0c.real - pp = z0p**z0p.real - self.assertAEqual(pc, pp) - - def test_complex(self): - "Compare complex() with CPython (with complex arguments)" - ours = pycomplex(pycomplex(1,10), 100) - cpy = complex(complex(1,10), 100) - self.assertAEqual(ours, cpy) - - ours = pycomplex(pycomplex(1,10), pycomplex(100,1000)) - cpy = complex(complex(1,10), complex(100,1000)) - self.assertAEqual(ours, cpy) - - ours = pycomplex(10, pycomplex(100,1000)) - cpy = complex(10, complex(100,1000)) - self.assertAEqual(ours, cpy) Modified: pypy/dist/pypy/module/builtin/app_complex.py ============================================================================== --- pypy/dist/pypy/module/builtin/app_complex.py (original) +++ pypy/dist/pypy/module/builtin/app_complex.py Tue Mar 22 19:25:17 2005 @@ -10,6 +10,8 @@ PREC_REPR = 17 PREC_STR = 12 + __slots__ = ['real', 'imag'] + # XXX this class is not well tested # provide __new__to prevend the default which has no parameters @@ -22,7 +24,8 @@ return (complex(self.real, self.imag),) def __reduce__(self): - return self.__class__, (self.real, self.imag), self.__dict__ + return (self.__class__, (self.real, self.imag), + getattr(self, '__dict__', None)) def _init(self, real=0.0, imag=None): if isinstance(real, str): @@ -46,15 +49,8 @@ elif imag is not None: im += float(imag) - self.__dict__['real'] = re - self.__dict__['imag'] = im - - def __setattr__(self, name, value): - if name in ('real', 'imag'): - raise AttributeError, "readonly attribute" - elif self.__class__ is complex: - raise AttributeError, "'complex' object has no attribute %s" % name - self.__dict__[name] = value + real_slot.__set__(self, re) + imag_slot.__set__(self, im) def _makeComplexFromString(self, string): import re @@ -212,6 +208,13 @@ mod = self - div*other return div, mod + def __rdivmod__(self, other): + result = self.__coerce__(other) + if result is NotImplemented: + return result + self, other = result + return other.__divmod__(self) + def __pow__(self, other, mod=None): if mod is not None: @@ -320,3 +323,11 @@ def __float__(self): raise TypeError, "can't convert complex to float; use e.g. float(abs(z))" + + +real_slot = complex.real +imag_slot = complex.imag + +# make the slots read-only +complex.real = property(real_slot.__get__) +complex.imag = property(imag_slot.__get__) From hpk at codespeak.net Tue Mar 22 19:39:53 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Tue, 22 Mar 2005 19:39:53 +0100 (MET) Subject: [pypy-svn] r10077 - pypy/dist/pypy/module/parser Message-ID: <20050322183953.9205627B5A@code1.codespeak.net> Author: hpk Date: Tue Mar 22 19:39:52 2005 New Revision: 10077 Added: pypy/dist/pypy/module/parser/ - copied from r10069, basil/trunk/basil/common/python/ Modified: pypy/dist/pypy/module/parser/__init__.py Log: intermediate checkin - copy of Jonathan's basil/common/python tree as the upcoming pypy parser (mixed interp/app) module Modified: pypy/dist/pypy/module/parser/__init__.py ============================================================================== --- basil/trunk/basil/common/python/__init__.py (original) +++ pypy/dist/pypy/module/parser/__init__.py Tue Mar 22 19:39:52 2005 @@ -0,0 +1,37 @@ +from pypy.interpreter.error import OperationError +from pypy.interpreter import module +from pypy.interpreter.lazymodule import LazyModule + +class Module(LazyModule): + """The builtin parser module. + """ + appleveldefs = { + 'ParserError' : 'classes.ParserError', + 'STType' : 'classes.STType', + 'ASTType' : 'classes.STType', + } + + interpleveldefs = { + '__name__' : '(space.wrap("parser"))', + '__doc__' : '(space.wrap("parser module"))', + + 'compileast' : 'pyparser.compileast', + 'st2tuple' : 'pyparser.st2tuple', + 'st2list' : 'pyparser.st2list', + 'issuite' : 'pyparser.issuite', + 'ast2tuple' : 'pyparser.ast2tuple', + 'tuple2st' : 'pyparser.tuple2st', + 'suite' : 'pyparser.suite', + 'isexpr' : 'pyparser.isexpr', + 'expr' : 'pyparser.expr', + 'ast2list' : 'pyparser.ast2list', + 'sequence2ast' : 'pyparser.sequence2ast', + 'tuple2ast' : 'pyparser.tuple2ast', + 'sequence2st' : 'pyparser.sequence2st', + '_pickler' : 'pyparser._pickler', + 'compilest' : 'pyparser.compilest', + } + + appleveldefs = { + + } From hpk at codespeak.net Tue Mar 22 19:41:39 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Tue, 22 Mar 2005 19:41:39 +0100 (MET) Subject: [pypy-svn] r10078 - pypy/dist/pypy/module/parser Message-ID: <20050322184139.61B0327B5A@code1.codespeak.net> Author: hpk Date: Tue Mar 22 19:41:39 2005 New Revision: 10078 Modified: pypy/dist/pypy/module/parser/pyparser.py Log: remove exceptions import Modified: pypy/dist/pypy/module/parser/pyparser.py ============================================================================== --- pypy/dist/pypy/module/parser/pyparser.py (original) +++ pypy/dist/pypy/module/parser/pyparser.py Tue Mar 22 19:41:39 2005 @@ -9,7 +9,7 @@ # ______________________________________________________________________ # Module imports -import token, exceptions, compiler +import token, compiler import PyTokenizer, PyGrammar, DFAParser # ______________________________________________________________________ @@ -22,7 +22,7 @@ # ______________________________________________________________________ # ParserError exception -class ParserError (exceptions.Exception): +class ParserError (Exception): """Class ParserError Exception class for parser errors (I assume). """ From ac at codespeak.net Tue Mar 22 19:47:54 2005 From: ac at codespeak.net (ac at codespeak.net) Date: Tue, 22 Mar 2005 19:47:54 +0100 (MET) Subject: [pypy-svn] r10079 - pypy/dist/pypy/interpreter Message-ID: <20050322184754.6392E27B5A@code1.codespeak.net> Author: ac Date: Tue Mar 22 19:47:54 2005 New Revision: 10079 Modified: pypy/dist/pypy/interpreter/pyframe.py pypy/dist/pypy/interpreter/typedef.py Log: Add support for setting f_lineno in frames. This makes the settrace() functionality complete. Modified: pypy/dist/pypy/interpreter/pyframe.py ============================================================================== --- pypy/dist/pypy/interpreter/pyframe.py (original) +++ pypy/dist/pypy/interpreter/pyframe.py Tue Mar 22 19:47:54 2005 @@ -5,6 +5,14 @@ from pypy.interpreter.miscutils import Stack from pypy.interpreter.error import OperationError from pypy.interpreter import pytraceback +import opcode + +# Define some opcodes used +g = globals() +for op in '''DUP_TOP POP_TOP SETUP_LOOP SETUP_EXCEPT SETUP_FINALLY +POP_BLOCK END_FINALLY'''.split(): + g[op] = opcode.opmap[op] +HAVE_ARGUMENT = opcode.HAVE_ARGUMENT import __future__ compiler_flags = 0 @@ -80,6 +88,7 @@ # dispatch() is abstract, see pyopcode. self.last_instr = self.next_instr executioncontext.bytecode_trace(self) + self.next_instr = self.last_instr self.dispatch() # catch asynchronous exceptions and turn them # into OperationErrors @@ -139,19 +148,123 @@ else: return space.wrap(self.f_lineno) -## def fset_f_lineno(space, w_self, w_f_lineo): -## "Returns the line number of the instruction currently being executed." -## f_lineo = space.int_w(w_f_lineo) - -## self = space.interpclass_w(w_self) -## if self.self.w_f_trace is None: -## raise OperationError(self.space.w_ValueError, space.wrap("f_lineo can only be set by a trace function.")) + def fset_f_lineno(space, w_self, w_new_lineno): + "Returns the line number of the instruction currently being executed." + try: + new_lineno = space.int_w(w_new_lineno) + except OperationError, e: + raise OperationError(space.w_ValueError, space.wrap("lineno must be an integer")) + + self = space.interpclass_w(w_self) + if self.w_f_trace is None: + raise OperationError(space.w_ValueError, space.wrap("f_lineo can only be set by a trace function.")) + + if new_lineno < self.code.co_firstlineno: + raise OperationError(space.w_ValueError, space.wrap("line %d comes before the current code." % new_lineno)) + code = self.code.co_code + addr = 0 + line = self.code.co_firstlineno + new_lasti = -1 + offset = 0 + lnotab = self.code.co_lnotab + for offset in xrange(0, len(lnotab), 2): + addr += ord(lnotab[offset]) + line += ord(lnotab[offset + 1]) + if line >= new_lineno: + new_lasti = addr + new_lineno = line + break -## if f_lineo < self.code.co_firstlineno: -## raise OperationError(self.space.w_ValueError, space.wrap("line %d comes before the current code." % f_lineo)) + if new_lasti == -1: + raise OperationError(space.w_ValueError, space.wrap("line %d comes after the current code." % new_lineno)) -## self.f_lineno = f_lineo + # Don't jump to a line with an except in it. + if ord(code[new_lasti]) in (DUP_TOP, POP_TOP): + raise OperationError(space.w_ValueError, space.wrap("can't jump to 'except' line as there's no exception")) + + # Don't jump into or out of a finally block. + f_lasti_setup_addr = -1 + new_lasti_setup_addr = -1 + blockstack = Stack() + addr = 0 + while addr < len(code): + op = ord(code[addr]) + if op in (SETUP_LOOP, SETUP_EXCEPT, SETUP_FINALLY): + blockstack.push([addr, False]) + elif op == POP_BLOCK: + setup_op = ord(code[blockstack.top()[0]]) + if setup_op == SETUP_FINALLY: + blockstack.top()[1] = True + else: + blockstack.pop() + elif op == END_FINALLY: + if not blockstack.empty(): + setup_op = ord(code[blockstack.top()[0]]) + if setup_op == SETUP_FINALLY: + blockstack.pop() + + if addr == new_lasti or addr == self.last_instr: + for setup_addr, in_finally in blockstack: + if in_finally: + if addr == new_lasti: + new_lasti_setup_addr = setup_addr + if addr == self.last_instr: + f_lasti_setup_addr = setup_addr + break + + if op >= HAVE_ARGUMENT: + addr += 3 + else: + addr += 1 + + assert blockstack.empty() + + if new_lasti_setup_addr != f_lasti_setup_addr: + raise OperationError(space.w_ValueError, space.wrap("can't jump into or out of a 'finally' block %d -> %d"%(f_lasti_setup_addr, new_lasti_setup_addr))) + + if new_lasti < self.last_instr: + min_addr = new_lasti + max_addr = self.last_instr + else: + min_addr = self.last_instr + max_addr = new_lasti + + delta_iblock = min_delta_iblock = 0 + addr = min_addr + while addr < max_addr: + op = ord(code[addr]) + + if op in (SETUP_LOOP, SETUP_EXCEPT, SETUP_FINALLY): + delta_iblock += 1; + elif op == POP_BLOCK: + delta_iblock -= 1 + if delta_iblock < min_delta_iblock: + min_delta_iblock = delta_iblock + + if op >= opcode.HAVE_ARGUMENT: + addr += 3 + else: + addr += 1 + + f_iblock = self.blockstack.depth() + min_iblock = f_iblock + min_delta_iblock + if new_lasti > self.last_instr: + new_iblock = f_iblock + delta_iblock + else: + new_iblock = f_iblock - delta_iblock + + if new_iblock > min_iblock: + raise OperationError(space.w_ValueError, space.wrap("can't jump into the middle of a block")) + + while f_iblock > new_iblock: + block = self.blockstack.pop() + block.cleanup(self) + f_iblock -= 1 + + self.f_lineno = new_lineno + self.last_instr = new_lasti + def get_last_lineno(self): "Returns the line number of the instruction currently being executed." return pytraceback.offset2lineno(self.code, self.next_instr-1) Modified: pypy/dist/pypy/interpreter/typedef.py ============================================================================== --- pypy/dist/pypy/interpreter/typedef.py (original) +++ pypy/dist/pypy/interpreter/typedef.py Tue Mar 22 19:47:54 2005 @@ -324,7 +324,7 @@ PyFrame.typedef = TypeDef('frame', f_builtins = GetSetProperty(PyFrame.fget_f_builtins), - f_lineno = GetSetProperty(PyFrame.fget_f_lineno), + f_lineno = GetSetProperty(PyFrame.fget_f_lineno, PyFrame.fset_f_lineno), f_back = GetSetProperty(PyFrame.fget_f_back), f_lasti = GetSetProperty(PyFrame.fget_f_lasti), f_trace = GetSetProperty(PyFrame.fget_f_trace, PyFrame.fset_f_trace), From arigo at codespeak.net Tue Mar 22 19:49:23 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 22 Mar 2005 19:49:23 +0100 (MET) Subject: [pypy-svn] r10080 - pypy/dist/pypy/documentation/revreport Message-ID: <20050322184923.C4F5627B5A@code1.codespeak.net> Author: arigo Date: Tue Mar 22 19:49:23 2005 New Revision: 10080 Modified: pypy/dist/pypy/documentation/revreport/delta.py Log: Grumble grumble __cmp__ only in CPython without rich comparisons grumble. Modified: pypy/dist/pypy/documentation/revreport/delta.py ============================================================================== --- pypy/dist/pypy/documentation/revreport/delta.py (original) +++ pypy/dist/pypy/documentation/revreport/delta.py Tue Mar 22 19:49:23 2005 @@ -668,13 +668,7 @@ names.update(expl1.names(cls)) for cls in expl2.get_mro(cls2): - d = Set(expl2.names(cls)) - if ('__cmp__' in d and '__cmp__' not in names and - '__eq__' in d and '__ne__' in d and - '__lt__' in d and '__le__' in d and - '__gt__' in d and '__ge__' in d): - d.remove('__cmp__') - names.update(d) + names.update(expl2.names(cls)) if cls2 is type: # strange strange attributes we don't care about names.remove('__basicsize__') @@ -693,6 +687,12 @@ if obj1 is NOTFOUND and obj2 is NOTFOUND: continue # spurious :( + if name == '__cmp__' and obj1 is NOTFOUND and ( + '__eq__' in names and '__ne__' in names and + '__lt__' in names and '__le__' in names and + '__gt__' in names and '__ge__' in names): + continue # __cmp__ is only in CPython, PyPy has the rich cmp instead + entry = Entry(name) if cls1_is_not_a_class: entry.status = expl2 From arigo at codespeak.net Tue Mar 22 19:49:57 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 22 Mar 2005 19:49:57 +0100 (MET) Subject: [pypy-svn] r10081 - in pypy/dist/pypy/objspace/std: . test Message-ID: <20050322184957.3973A27B5A@code1.codespeak.net> Author: arigo Date: Tue Mar 22 19:49:56 2005 New Revision: 10081 Modified: pypy/dist/pypy/objspace/std/listobject.py pypy/dist/pypy/objspace/std/test/test_listobject.py Log: list '*=' operator was missing! argh. Modified: pypy/dist/pypy/objspace/std/listobject.py ============================================================================== --- pypy/dist/pypy/objspace/std/listobject.py (original) +++ pypy/dist/pypy/objspace/std/listobject.py Tue Mar 22 19:49:56 2005 @@ -34,6 +34,10 @@ items = [space.unwrap(w_item) for w_item in w_list.ob_item[:w_list.ob_size]]# XXX generic mixed types unwrap return list(items) + def clear(w_list): + w_list.ob_item = [] + w_list.ob_size = 0 + registerimplementation(W_ListObject) @@ -42,7 +46,7 @@ w_iterable, = __args__.parse('list', (['sequence'], None, None), # signature [W_ListObject(space, [])]) # default argument - w_list.ob_size = 0 # XXX think about it later + w_list.clear() length = 0 try: @@ -145,6 +149,23 @@ def mul__ANY_List(space, w_times, w_list): return mul_list_times(space, w_list, space.int_w(w_times)) +def inplace_mul__List_ANY(space, w_list, w_times): + times = space.int_w(w_times) + if times <= 0: + w_list.clear() + return w_list + size = w_list.ob_size + newlen = size * times # XXX check overflow + _list_resize(w_list, newlen) + items = w_list.ob_item + p = size + for _ in range(1, times): + for i in range(size): + items[p] = items[i] + p += 1 + w_list.ob_size = newlen + return w_list + def eq__List_List(space, w_list1, w_list2): items1 = w_list1.ob_item items2 = w_list2.ob_item Modified: pypy/dist/pypy/objspace/std/test/test_listobject.py ============================================================================== --- pypy/dist/pypy/objspace/std/test/test_listobject.py (original) +++ pypy/dist/pypy/objspace/std/test/test_listobject.py Tue Mar 22 19:49:56 2005 @@ -366,6 +366,19 @@ assert l is l0 assert l == [1,2,3,4,5] + def test_imul(self): + l = l0 = [4,3] + l *= 2 + assert l is l0 + assert l == [4,3,4,3] + l *= 0 + assert l is l0 + assert l == [] + l = l0 = [4,3] + l *= (-1) + assert l is l0 + assert l == [] + def test_index(self): l = ['a', 'b', 'c', 'd', 'e', 'f'] raises(TypeError, l.index, 'c', 0, 4.3) From ac at codespeak.net Tue Mar 22 19:50:11 2005 From: ac at codespeak.net (ac at codespeak.net) Date: Tue, 22 Mar 2005 19:50:11 +0100 (MET) Subject: [pypy-svn] r10082 - pypy/dist/lib-python-2.3.4/test Message-ID: <20050322185011.EC9F927B5B@code1.codespeak.net> Author: ac Date: Tue Mar 22 19:50:11 2005 New Revision: 10082 Modified: pypy/dist/lib-python-2.3.4/test/conftest.py Log: Another test passes. Modified: pypy/dist/lib-python-2.3.4/test/conftest.py ============================================================================== --- pypy/dist/lib-python-2.3.4/test/conftest.py (original) +++ pypy/dist/lib-python-2.3.4/test/conftest.py Tue Mar 22 19:50:11 2005 @@ -50,6 +50,7 @@ 'test_string.py', 'test_sys.py', 'test_textwrap.py', +'test_trace.py', 'test_urlparse.py', ) From rxe at codespeak.net Tue Mar 22 20:08:48 2005 From: rxe at codespeak.net (rxe at codespeak.net) Date: Tue, 22 Mar 2005 20:08:48 +0100 (MET) Subject: [pypy-svn] r10083 - in pypy/dist/pypy: interpreter module/sys2 Message-ID: <20050322190848.76B8127B5A@code1.codespeak.net> Author: rxe Date: Tue Mar 22 20:08:48 2005 New Revision: 10083 Modified: pypy/dist/pypy/interpreter/executioncontext.py pypy/dist/pypy/module/sys2/vm.py Log: Temporary checkin to run tests on faster machine. Modified: pypy/dist/pypy/interpreter/executioncontext.py ============================================================================== --- pypy/dist/pypy/interpreter/executioncontext.py (original) +++ pypy/dist/pypy/interpreter/executioncontext.py Tue Mar 22 20:08:48 2005 @@ -12,6 +12,7 @@ self.framestack = Stack() self.stateDict = {} self.w_tracefunc = None + self.w_profilefunc = None self.is_tracing = 0 def enter(self, frame): @@ -22,12 +23,11 @@ previous_ec = locals.executioncontext locals.executioncontext = self + frame.f_back = None for ff in self.framestack: if not frame.code.getapplevel(): frame.f_back = ff break - else: - frame.f_back = None self.framestack.push(frame) return previous_ec @@ -148,28 +148,58 @@ else: self.w_tracefunc = w_func + def setprofile(self, w_func): + """Set the global trace function.""" + if self.space.is_true(self.space.is_(w_func, self.space.w_None)): + self.w_profilefunc = None + else: + self.w_profilefunc = w_func + def _trace(self, frame, event, w_arg): if frame.code.getapplevel(): return + + if self.is_tracing: + return + # Tracing if event == 'call': w_callback = self.w_tracefunc else: w_callback = frame.w_f_trace - if self.is_tracing or w_callback is None: - return - self.is_tracing += 1 - try: + if w_callback is not None: + + self.is_tracing += 1 try: - w_result = self.space.call_function(w_callback, self.space.wrap(frame), self.space.wrap(event), w_arg) - if self.space.is_true(self.space.is_(w_result, self.space.w_None)): + try: + w_result = self.space.call_function(w_callback, self.space.wrap(frame), self.space.wrap(event), w_arg) + if self.space.is_true(self.space.is_(w_result, self.space.w_None)): + frame.w_f_trace = None + else: + frame.w_f_trace = w_result + except: + self.settrace(self.space.w_None) frame.w_f_trace = None - else: - frame.w_f_trace = w_result - except: - self.settrace(self.space.w_None) - frame.w_f_trace = None - raise - finally: - self.is_tracing -= 1 + raise + finally: + self.is_tracing -= 1 + + # Profile + if event != 'call' or event != 'return': + return + + if self.w_profilefunc is not None: + assert self.is_tracing == 0 + self.is_tracing += 1 + try: + try: + w_result = self.space.call_function(self.w_profilefunc, + self.space.wrap(frame), + self.space.wrap(event), w_arg) + except: + #XXXframe.self.w_profilefunc = None + raise + finally: + self.is_tracing -= 1 + Modified: pypy/dist/pypy/module/sys2/vm.py ============================================================================== --- pypy/dist/pypy/module/sys2/vm.py (original) +++ pypy/dist/pypy/module/sys2/vm.py Tue Mar 22 20:08:48 2005 @@ -107,4 +107,5 @@ Set the profiling function. It will be called on each function call and return. See the profiler chapter in the library manual. """ + space.getexecutioncontext().setprofile(w_func) From alex at codespeak.net Tue Mar 22 20:15:50 2005 From: alex at codespeak.net (alex at codespeak.net) Date: Tue, 22 Mar 2005 20:15:50 +0100 (MET) Subject: [pypy-svn] r10084 - pypy/dist/pypy/lib/test2 Message-ID: <20050322191550.D0F2227B5A@code1.codespeak.net> Author: alex Date: Tue Mar 22 20:15:50 2005 New Revision: 10084 Modified: pypy/dist/pypy/lib/test2/test_file.py Log: changed _file.file uses to just plain file Modified: pypy/dist/pypy/lib/test2/test_file.py ============================================================================== --- pypy/dist/pypy/lib/test2/test_file.py (original) +++ pypy/dist/pypy/lib/test2/test_file.py Tue Mar 22 20:15:50 2005 @@ -1,6 +1,6 @@ import os import autopath -from pypy.appspace import _file +# from pypy.appspace import _file from pypy.tool.udir import udir import py import unittest @@ -8,7 +8,7 @@ class TestFile: def setup_method(self, method): filename = os.path.join(autopath.this_dir, 'test_file.py') - self.fd = _file.file_(filename, 'r') + self.fd = file(filename, 'r') def teardown_method(self, method): self.fd.close() @@ -18,7 +18,7 @@ def test_case_readonly(self): fn = str(udir.join('temptestfile')) - f=_file.file_(fn, 'w') + f=file(fn, 'w') assert f.name == fn assert f.mode == 'w' assert f.closed == False From alex at codespeak.net Tue Mar 22 20:16:49 2005 From: alex at codespeak.net (alex at codespeak.net) Date: Tue, 22 Mar 2005 20:16:49 +0100 (MET) Subject: [pypy-svn] r10085 - pypy/dist/pypy/lib/test2 Message-ID: <20050322191649.A69F227B5A@code1.codespeak.net> Author: alex Date: Tue Mar 22 20:16:49 2005 New Revision: 10085 Modified: pypy/dist/pypy/lib/test2/test_datetime.py Log: changed py.appspace.datetime to plain datetime. Still doesn't run due to pickling issues. Modified: pypy/dist/pypy/lib/test2/test_datetime.py ============================================================================== --- pypy/dist/pypy/lib/test2/test_datetime.py (original) +++ pypy/dist/pypy/lib/test2/test_datetime.py Tue Mar 22 20:16:49 2005 @@ -9,11 +9,19 @@ import pickle import cPickle +''' from pypy.appspace.datetime import MINYEAR, MAXYEAR from pypy.appspace.datetime import timedelta from pypy.appspace.datetime import tzinfo from pypy.appspace.datetime import time from pypy.appspace.datetime import date, datetime +''' + +from datetime import MINYEAR, MAXYEAR +from datetime import timedelta +from datetime import tzinfo +from datetime import time +from datetime import date, datetime # Before Python 2.3, proto=2 was taken as a synonym for proto=1. From jacob at codespeak.net Tue Mar 22 20:17:30 2005 From: jacob at codespeak.net (jacob at codespeak.net) Date: Tue, 22 Mar 2005 20:17:30 +0100 (MET) Subject: [pypy-svn] r10086 - pypy/dist/pypy/lib Message-ID: <20050322191730.3CF0927B5B@code1.codespeak.net> Author: jacob Date: Tue Mar 22 20:17:30 2005 New Revision: 10086 Modified: pypy/dist/pypy/lib/binascii.py Log: Quoted printablenow passes the CPython library tests. Modified: pypy/dist/pypy/lib/binascii.py ============================================================================== --- pypy/dist/pypy/lib/binascii.py (original) +++ pypy/dist/pypy/lib/binascii.py Tue Mar 22 20:17:30 2005 @@ -212,8 +212,10 @@ # Change the parts in-place for index, part in enumerate(parts[1:]): - if len(parts) > 2 and part[0] in hex_numbers and part[1] in hex_numbers: + if len(part) > 1 and part[0] in hex_numbers and part[1] in hex_numbers: parts[index + 1] = chr(strhex_to_int(part[0:2])) + part[2:] + elif index == len(parts) - 2 and len(part) < 2: + parts[index + 1] = '' else: parts[index + 1] = '=' + parts[index + 1] @@ -231,11 +233,39 @@ and does not encode newlines as CRLF sequences. This seems to be non-standard, and we copy this behaviour. """ - def f(c): - if '!' <= c <= '<' or '>' <= c <= '~' or c in '\n\r': - return c - return '=' + two_hex_digits(ord(c)) - return ''.join([ f(c) for c in s]) + crlf = s.find('\r\n') + lf = s.find('\n') + linebreak = None + if crlf >= 0 and crlf <= lf: + linebreak = '\r\n' + elif lf > 0: + linebreak = '\n' + + if linebreak: + s = s.replace('\r\n', '\n') + + lines = s.split('\n') + + result = [] + for line in lines: + charlist = [] + count = 0 + for c in line: + if '!' <= c <= '<' or '>' <= c <= '~' or c in '\n\r': + if count >= 75: + charlist.append('=\r\n') + count = 0 + charlist.append(c) + count += 1 + else: + if count >= 72: + charlist.append('=\r\n') + count = 0 + snippet = '=' + two_hex_digits(ord(c)) + count += len(snippet) + charlist.append(snippet) + result.append(''.join(charlist)) + return linebreak.join(result) hex_numbers = '0123456789ABCDEF' def hex(n): From ac at codespeak.net Tue Mar 22 21:09:34 2005 From: ac at codespeak.net (ac at codespeak.net) Date: Tue, 22 Mar 2005 21:09:34 +0100 (MET) Subject: [pypy-svn] r10087 - pypy/dist/pypy/interpreter Message-ID: <20050322200934.9E00827B5A@code1.codespeak.net> Author: ac Date: Tue Mar 22 21:09:34 2005 New Revision: 10087 Modified: pypy/dist/pypy/interpreter/executioncontext.py pypy/dist/pypy/interpreter/pyframe.py Log: Minor refactoring Modified: pypy/dist/pypy/interpreter/executioncontext.py ============================================================================== --- pypy/dist/pypy/interpreter/executioncontext.py (original) +++ pypy/dist/pypy/interpreter/executioncontext.py Tue Mar 22 21:09:34 2005 @@ -57,7 +57,7 @@ def return_trace(self, frame, w_retval): "Trace the return from a function" - self._trace(self.framestack.top(), 'return', w_retval) + self._trace(frame, 'return', w_retval) def bytecode_trace(self, frame): "Trace function called before each bytecode." @@ -117,12 +117,11 @@ else: frame.instr_ub = sys.maxint - def exception_trace(self, operationerr): + def exception_trace(self, frame, operationerr): "Trace function called upon OperationError." operationerr.record_interpreter_traceback() exc_info = self.sys_exc_info() - frame = self.framestack.top() - self._trace(self.framestack.top(), 'exception', + self._trace(frame, 'exception', exc_info) #operationerr.print_detailed_traceback(self.space) Modified: pypy/dist/pypy/interpreter/pyframe.py ============================================================================== --- pypy/dist/pypy/interpreter/pyframe.py (original) +++ pypy/dist/pypy/interpreter/pyframe.py Tue Mar 22 21:09:34 2005 @@ -108,7 +108,7 @@ except OperationError, e: pytraceback.record_application_traceback( self.space, e, self, self.last_instr) - executioncontext.exception_trace(e) + executioncontext.exception_trace(self, e) # convert an OperationError into a control flow # exception import sys From rxe at codespeak.net Tue Mar 22 21:13:24 2005 From: rxe at codespeak.net (rxe at codespeak.net) Date: Tue, 22 Mar 2005 21:13:24 +0100 (MET) Subject: [pypy-svn] r10088 - pypy/dist/pypy/interpreter Message-ID: <20050322201324.985A827B5A@code1.codespeak.net> Author: rxe Date: Tue Mar 22 21:13:24 2005 New Revision: 10088 Modified: pypy/dist/pypy/interpreter/executioncontext.py Log: Some tidies. Make setprofile work. Modified: pypy/dist/pypy/interpreter/executioncontext.py ============================================================================== --- pypy/dist/pypy/interpreter/executioncontext.py (original) +++ pypy/dist/pypy/interpreter/executioncontext.py Tue Mar 22 21:13:24 2005 @@ -33,6 +33,10 @@ return previous_ec def leave(self, previous_ec): + if self.w_profilefunc: + frame = self.framestack.top() + self._trace(frame, 'leaveframe', None) + self.framestack.pop() locals = getthreadlocals() locals.executioncontext = previous_ec @@ -64,18 +68,6 @@ if self.is_tracing or frame.w_f_trace is None: return code = getattr(frame, 'code') - doTrace = code.co_name == 'arigo_example XXX' - if doTrace: - print frame.instr_lb, frame.last_instr, frame.instr_ub - if not hasattr(self, 'dumpedLineno'): - self.dumpedLineno = None - l = 0 - a = 0 - for i in range(0, len(code.co_lnotab),2): - print 'Line %3d: %3d'%(l, a) - a += ord(code.co_lnotab[i]) - l += ord(code.co_lnotab[i+1]) - print 'Line %3d: %3d'%(l, a) if frame.instr_lb <= frame.last_instr < frame.instr_ub: return @@ -98,11 +90,7 @@ if addr == frame.last_instr: frame.f_lineno = line - if doTrace: - print 'At line', line - code.co_firstlineno, 'addr', addr self._trace(frame, 'line', self.space.w_None) - elif doTrace: - print 'Skipping line', line - code.co_firstlineno, 'addr', addr if size > 0: while True: @@ -122,7 +110,7 @@ operationerr.record_interpreter_traceback() exc_info = self.sys_exc_info() self._trace(frame, 'exception', - exc_info) + exc_info) #operationerr.print_detailed_traceback(self.space) def sys_exc_info(self): @@ -155,19 +143,16 @@ self.w_profilefunc = w_func def _trace(self, frame, event, w_arg): - if frame.code.getapplevel(): - return - - if self.is_tracing: + if self.is_tracing or frame.code.getapplevel(): return - # Tracing + # Tracing cases if event == 'call': w_callback = self.w_tracefunc else: w_callback = frame.w_f_trace - if w_callback is not None: + if w_callback is not None and event != "leaveframe": self.is_tracing += 1 try: @@ -184,11 +169,14 @@ finally: self.is_tracing -= 1 - # Profile - if event != 'call' or event != 'return': - return - + # Profile cases if self.w_profilefunc is not None: + if event not in ['leaveframe', 'call']: + return + + if event == 'leaveframe': + event = 'return' + assert self.is_tracing == 0 self.is_tracing += 1 try: @@ -197,7 +185,6 @@ self.space.wrap(frame), self.space.wrap(event), w_arg) except: - #XXXframe.self.w_profilefunc = None raise finally: self.is_tracing -= 1 From arigo at codespeak.net Tue Mar 22 21:56:04 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 22 Mar 2005 21:56:04 +0100 (MET) Subject: [pypy-svn] r10089 - pypy/dist/pypy/module/builtin Message-ID: <20050322205604.956CA27B5A@code1.codespeak.net> Author: arigo Date: Tue Mar 22 21:56:04 2005 New Revision: 10089 Modified: pypy/dist/pypy/module/builtin/app_descriptor.py Log: Added __slots__ to the built-in descriptor classes. Modified: pypy/dist/pypy/module/builtin/app_descriptor.py ============================================================================== --- pypy/dist/pypy/module/builtin/app_descriptor.py (original) +++ pypy/dist/pypy/module/builtin/app_descriptor.py Tue Mar 22 21:56:04 2005 @@ -5,6 +5,7 @@ # Descriptor code, shamelessly stolen to Raymond Hettinger: # http://users.rcn.com/python/download/Descriptor.htm class property(object): + __slots__ = ['fget', 'fset', 'fdel', '__doc__'] def __init__(self, fget=None, fset=None, fdel=None, doc=None): self.fget = fget @@ -33,30 +34,33 @@ # XXX there is an interp-level pypy.interpreter.function.StaticMethod # XXX because __new__ needs to be a StaticMethod early. class staticmethod(object): + __slots__ = ['_f'] def __init__(self, f): - self.f = f + self._f = f def __get__(self, obj, objtype=None): - return self.f + return self._f class classmethod(object): + __slots__ = ['_f'] def __init__(self, f): - self.f = f + self._f = f def __get__(self, obj, klass=None): if klass is None: klass = type(obj) def newfunc(*args, **kwargs): - return self.f(klass, *args, **kwargs) + return self._f(klass, *args, **kwargs) return newfunc # super is a modified version from Guido's tutorial # http://www.python.org/2.2.3/descrintro.html # it exposes the same special attributes as CPython's. class super(object): + __slots__ = ['__thisclass__', '__self__', '__self_class__'] def __init__(self, typ, obj=None): if obj is None: objcls = None # unbound super object From ac at codespeak.net Tue Mar 22 22:04:31 2005 From: ac at codespeak.net (ac at codespeak.net) Date: Tue, 22 Mar 2005 22:04:31 +0100 (MET) Subject: [pypy-svn] r10090 - pypy/dist/pypy/lib Message-ID: <20050322210431.C9CBD27B5A@code1.codespeak.net> Author: ac Date: Tue Mar 22 22:04:31 2005 New Revision: 10090 Added: pypy/dist/pypy/lib/gc.py (contents, props changed) Log: Add minimal module gc for test_trace Added: pypy/dist/pypy/lib/gc.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/lib/gc.py Tue Mar 22 22:04:31 2005 @@ -0,0 +1,3 @@ + +def collect(): + pass From cfbolz at codespeak.net Tue Mar 22 22:06:04 2005 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Tue, 22 Mar 2005 22:06:04 +0100 (MET) Subject: [pypy-svn] r10091 - in pypy/dist/pypy/translator/llvm: . test Message-ID: <20050322210604.583DD27B5A@code1.codespeak.net> Author: cfbolz Date: Tue Mar 22 22:06:04 2005 New Revision: 10091 Added: pypy/dist/pypy/translator/llvm/int_list.ll pypy/dist/pypy/translator/llvm/intlist.c Modified: pypy/dist/pypy/translator/llvm/genllvm.py pypy/dist/pypy/translator/llvm/list.c pypy/dist/pypy/translator/llvm/list_template.ll pypy/dist/pypy/translator/llvm/llvmbc.py pypy/dist/pypy/translator/llvm/make_runtime.py pypy/dist/pypy/translator/llvm/representation.py pypy/dist/pypy/translator/llvm/test/llvmsnippet.py pypy/dist/pypy/translator/llvm/test/test_genllvm.py Log: added support for tuples and simple inheritance Modified: pypy/dist/pypy/translator/llvm/genllvm.py ============================================================================== --- pypy/dist/pypy/translator/llvm/genllvm.py (original) +++ pypy/dist/pypy/translator/llvm/genllvm.py Tue Mar 22 22:06:04 2005 @@ -20,8 +20,10 @@ from pypy.translator.llvm.representation import * +import rlcompleter2 +rlcompleter2.setup() -debug = 0 +debug = True def llvmcompile(transl, optimize=False): @@ -142,3 +144,20 @@ yield l_dep1 yield l_repr + +def f(): + a = AAA() + b = BBB() + return a.g() + b.g() + a.get() + b.get() + AAA.get(b) + +t = Translator(f, simplifying=True) +a = t.annotate([]) +t.simplify() +a.simplify() +flg = t.getflowgraph() +bcls = a.binding(flg.startblock.operations[1].result).classdef +acls = bcls.basedef +t.view() +g = LLVMGenerator(t) +f1 = g.compile(True) +print f1(), f() Added: pypy/dist/pypy/translator/llvm/int_list.ll ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/llvm/int_list.ll Tue Mar 22 22:06:04 2005 @@ -0,0 +1,39 @@ + + +internal %std.list.int* %std.range(int %length) { +entry: + %tmp.1 = setlt int %length, 1 + %tmp.3 = malloc %std.list.int + %tmp.6 = getelementptr %std.list.int* %tmp.3, int 0, uint 0 + br bool %tmp.1, label %then, label %endif + +then: + store uint 0, uint* %tmp.6 + %tmp.8 = getelementptr %std.list.int* %tmp.3, int 0, uint 1 + store int* null, int** %tmp.8 + ret %std.list.int* %tmp.3 + +endif: + %tmp.15 = cast int %length to uint + store uint %tmp.15, uint* %tmp.6 + %tmp.17 = getelementptr %std.list.int* %tmp.3, int 0, uint 1 + %tmp.18 = malloc int, uint %tmp.15 + store int* %tmp.18, int** %tmp.17 + %tmp.255 = setgt int %length, 0 + br bool %tmp.255, label %no_exit, label %UnifiedReturnBlock + +no_exit: + %indvar = phi uint [ %indvar.next, %no_exit ], [ 0, %endif ] + %i.0.0 = cast uint %indvar to int + %tmp.29 = load int** %tmp.17 + %tmp.31 = getelementptr int* %tmp.29, uint %indvar + store int %i.0.0, int* %tmp.31 + %tmp.34 = add int %i.0.0, 1 + %tmp.25 = setlt int %tmp.34, %length + %indvar.next = add uint %indvar, 1 + br bool %tmp.25, label %no_exit, label %UnifiedReturnBlock + +UnifiedReturnBlock: + %UnifiedRetVal = phi %std.list.int* [ %tmp.3, %endif ], [ %tmp.3, %no_exit ] + ret %std.list.int* %UnifiedRetVal +} Added: pypy/dist/pypy/translator/llvm/intlist.c ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/llvm/intlist.c Tue Mar 22 22:06:04 2005 @@ -0,0 +1,25 @@ +#include + +struct list_int { + unsigned int length; + int* data; +}; + +struct list_int* range(int length) { + int i = 0; + if (length <= 0) { + struct list_int* nlist = malloc(sizeof(struct list_int)); + nlist->length = 0; + nlist->data = NULL; + return nlist; + } + struct list_int* nlist = malloc(sizeof(struct list_int)); + nlist->length = length; + nlist->data = malloc(sizeof(int) * length); + while (i < length) { + nlist->data[i] = i; + i += 1; + } + return nlist; +} + Modified: pypy/dist/pypy/translator/llvm/list.c ============================================================================== --- pypy/dist/pypy/translator/llvm/list.c (original) +++ pypy/dist/pypy/translator/llvm/list.c Tue Mar 22 22:06:04 2005 @@ -9,7 +9,6 @@ struct item** data; }; - void copy(struct item** from, struct item** to, unsigned int length) { unsigned int i = 0; while(i < length) { @@ -22,7 +21,14 @@ return (int) l->length; } -struct list* newlist(struct item* value) { +struct list* newlist() { + struct list* nlist = malloc(sizeof(struct list)); + nlist->length = 0; + nlist->data = NULL; + return nlist; +} + +struct list* newlist_ALTERNATIVE1(struct item* value) { struct list* nlist = malloc(sizeof(struct list)); nlist->length = 1; nlist->data = malloc(sizeof(struct item*)); @@ -30,6 +36,25 @@ return nlist; } +struct list* newlist_ALTERNATIVE2(struct item* v1, struct item* v2) { + struct list* nlist = malloc(sizeof(struct list)); + nlist->length = 2; + nlist->data = malloc(sizeof(struct item*) * 2); + nlist->data[0] = v1; + nlist->data[1] = v2; + return nlist; +} +struct list* newlist_ALTERNATIVE3(struct item* v1, struct item* v2, + struct item* v3) { + struct list* nlist = malloc(sizeof(struct list)); + nlist->length = 3; + nlist->data = malloc(sizeof(struct item*) * 3); + nlist->data[0] = v1; + nlist->data[1] = v2; + nlist->data[2] = v3; + return nlist; +} + struct list* alloc_and_set(int length, struct item* init) { unsigned int i = 0; struct list* nlist = malloc(sizeof(struct list)); @@ -107,3 +132,5 @@ hi -= 1; } } + + Modified: pypy/dist/pypy/translator/llvm/list_template.ll ============================================================================== --- pypy/dist/pypy/translator/llvm/list_template.ll (original) +++ pypy/dist/pypy/translator/llvm/list_template.ll Tue Mar 22 22:06:04 2005 @@ -27,6 +27,16 @@ ret int %tmp.3 } +internal %std.list.%(name)s* %std.newlist() { +entry: + %tmp.0 = malloc %std.list.%(name)s + %tmp.3 = getelementptr %std.list.%(name)s* %tmp.0, int 0, uint 0 + store uint 0, uint* %tmp.3 + %tmp.5 = getelementptr %std.list.%(name)s* %tmp.0, int 0, uint 1 + store %(item)s* null, %(item)s** %tmp.5 + ret %std.list.%(name)s* %tmp.0 +} + internal %std.list.%(name)s* %std.newlist(%(item)s %value) { entry: %tmp.0 = malloc %std.list.%(name)s @@ -39,6 +49,38 @@ ret %std.list.%(name)s* %tmp.0 } +internal %std.list.%(name)s* %std.newlist(%(item)s %v1, %(item)s %v2) { +entry: + %tmp.0 = malloc %std.list.%(name)s + %tmp.3 = getelementptr %std.list.%(name)s* %tmp.0, int 0, uint 0 + store uint 2, uint* %tmp.3 + %tmp.5 = getelementptr %std.list.%(name)s* %tmp.0, int 0, uint 1 + %tmp.6 = malloc [2 x %(item)s] + %tmp.6.sub = getelementptr [2 x %(item)s]* %tmp.6, int 0, int 0 + store %(item)s* %tmp.6.sub, %(item)s** %tmp.5 + store %(item)s %v1, %(item)s* %tmp.6.sub + %tmp.16 = getelementptr [2 x %(item)s]* %tmp.6, int 0, int 1 + store %(item)s %v2, %(item)s* %tmp.16 + ret %std.list.%(name)s* %tmp.0 +} + +internal %std.list.%(name)s* %std.newlist(%(item)s %v1, %(item)s %v2, %(item)s %v3) { +entry: + %tmp.0 = malloc %std.list.%(name)s + %tmp.3 = getelementptr %std.list.%(name)s* %tmp.0, int 0, uint 0 + store uint 3, uint* %tmp.3 + %tmp.5 = getelementptr %std.list.%(name)s* %tmp.0, int 0, uint 1 + %tmp.6 = malloc [3 x %(item)s] + %tmp.6.sub = getelementptr [3 x %(item)s]* %tmp.6, int 0, int 0 + store %(item)s* %tmp.6.sub, %(item)s** %tmp.5 + store %(item)s %v1, %(item)s* %tmp.6.sub + %tmp.16 = getelementptr [3 x %(item)s]* %tmp.6, int 0, int 1 + store %(item)s %v2, %(item)s* %tmp.16 + %tmp.21 = getelementptr [3 x %(item)s]* %tmp.6, int 0, int 2 + store %(item)s %v3, %(item)s* %tmp.21 + ret %std.list.%(name)s* %tmp.0 +} + internal %std.list.%(name)s* %std.alloc_and_set(int %length, %(item)s %init) { entry: %tmp.0 = malloc %std.list.%(name)s Modified: pypy/dist/pypy/translator/llvm/llvmbc.py ============================================================================== --- pypy/dist/pypy/translator/llvm/llvmbc.py (original) +++ pypy/dist/pypy/translator/llvm/llvmbc.py Tue Mar 22 22:06:04 2005 @@ -29,8 +29,8 @@ self.label = label self.instructions = [] - def instructions(self, instruction): #should not be used - self.instructions.append(instruction) + def instruction(self, instr): #should not be used + self.instructions.append(instr) def select(self, l_arg, l_select, l_v1, l_v2): s = "%s = select bool %s, %s, %s" @@ -84,6 +84,14 @@ blocktrue, blockfalse) self.instructions.append(s) + def switch(self, l_switch, default, rest=None): + s = "switch %s, label %s " % (l_switch.typed_name(), default) + if rest is not None: + s += "[" + "\n\t".join(["%s %s, label %s" % (l_switch.llvmtype(), + c, l) + for c, l in rest]) + "]" + self.instructions.append(s) + def malloc(self, l_target, l_type, num=1): s = "%s = malloc %s" % (l_target.llvmname(), l_type.llvmname_wo_pointer()) @@ -96,10 +104,14 @@ l_ptr.llvmtype(), l_ptr.llvmname()) adr = [] for a in adresses: - if a >= 0: - adr.append("uint %i" % a) - else: - adr.append("int %i" % a) + try: + t = a.typed_name() + adr.append(t) + except AttributeError: + if a >= 0: + adr.append("uint %i" % a) + else: + adr.append("int %i" % a) self.instructions.append(s + ", ".join(adr)) def load(self, l_target, l_pter): @@ -108,10 +120,13 @@ self.instructions.append(s) def store(self, l_value, l_pter): - s = "store %s %s, %s %s" % (l_value.llvmtype(), l_value.llvmname(), - l_pter.llvmtype(), l_pter.llvmname()) + s = "store %s, %s" % (l_value.typed_name(), l_pter.typed_name()) self.instructions.append(s) + def cast(self, l_target, l_value): + s = "%s = cast %s to %s" % (l_target.llvmname(), l_value.typed_name(), + l_target.llvmtype()) + self.instructions.append(s) def __str__(self): s = [self.label + ":\n"] Modified: pypy/dist/pypy/translator/llvm/make_runtime.py ============================================================================== --- pypy/dist/pypy/translator/llvm/make_runtime.py (original) +++ pypy/dist/pypy/translator/llvm/make_runtime.py Tue Mar 22 22:06:04 2005 @@ -71,21 +71,34 @@ ret.append(line) return "\n".join(ret) -def make_list_template(): - code = get_llvm_code("list.c") +def cleanup_code(code): code = remove_comments(code) code = add_std(code) code = remove_header(code) code = internal_functions(code) code = remove_alternatives(code) + return code + +def make_list_template(): + code = get_llvm_code("list.c") + code = cleanup_code(code) code = code.replace("%struct.list", "%std.list.%(name)s") code = code.replace("%struct.item*", "%(item)s") f = open(autopath.this_dir + "/list_template.ll", "w") print (autopath.this_dir + "/list_template.ll") f.write(code) f.close() - + +def make_int_list(): + code = get_llvm_code("intlist.c") + code = cleanup_code(code) + code = code.replace("struct.list_int", "std.list.int") + f = open(autopath.this_dir + "/int_list.ll", "w") + print (autopath.this_dir + "/int_list.ll") + f.write(code) + f.close() if __name__ == '__main__': make_list_template() + make_int_list() Modified: pypy/dist/pypy/translator/llvm/representation.py ============================================================================== --- pypy/dist/pypy/translator/llvm/representation.py (original) +++ pypy/dist/pypy/translator/llvm/representation.py Tue Mar 22 22:06:04 2005 @@ -1,7 +1,8 @@ import autopath import exceptions, sets, StringIO -from types import FunctionType +from types import FunctionType, MethodType +import new from pypy.objspace.flow.model import Variable, Constant, SpaceOperation from pypy.objspace.flow.model import FunctionGraph, Block, Link @@ -20,14 +21,19 @@ "inplace_truediv", "inplace_floordiv", "inplace_div", "inplace_mod", "inplace_pow", "inplace_lshift", "inplace_rshift", "inplace_and", "inplace_or", "inplace_xor", - "contains", "newlist", "alloc_and_set"] + "contains", "newlist", "newtuple", "alloc_and_set"] C_SIMPLE_TYPES = {annmodel.SomeChar: "char", + annmodel.SomeString: "char*", annmodel.SomeBool: "unsigned char", annmodel.SomeInteger: "int"} -debug = 0 +LLVM_SIMPLE_TYPES = {annmodel.SomeChar: "sbyte", + annmodel.SomeBool: "bool"} + + +debug = True class CompileError(exceptions.Exception): @@ -52,7 +58,7 @@ return "" def llvmname(self): - return "" + return self.name def llvmtype(self): return self.type.llvmname() @@ -69,17 +75,14 @@ class SimpleRepr(LLVMRepr): """Representation of values that are directly mapped to types in LLVM: -int, bool, char (string of length 1)""" +bool, char (string of length 1)""" - LLVM_SIMPLE_TYPES = {annmodel.SomeInteger: "int", - annmodel.SomeChar: "sbyte", - annmodel.SomeBool: "bool"} def get(obj, gen): if not isinstance(obj, Constant): return None type = gen.annotator.binding(obj) - if type.__class__ in SimpleRepr.LLVM_SIMPLE_TYPES: - llvmtype = SimpleRepr.LLVM_SIMPLE_TYPES[type.__class__] + if type.__class__ in LLVM_SIMPLE_TYPES: + llvmtype = LLVM_SIMPLE_TYPES[type.__class__] l_repr = SimpleRepr(llvmtype, repr(obj.value), gen) return l_repr return None @@ -95,15 +98,48 @@ self.gen = gen self.dependencies = sets.Set() - def llvmname(self): - return self.name - def llvmtype(self): return self.type def __getattr__(self, name): return getattr(self.type, name, None) +class IntRepr(LLVMRepr): + def get(obj, gen): + if obj.__class__ is int: + type = gen.annotator.binding(Constant(obj)) + return IntRepr(type, obj, gen) + if not isinstance(obj, Constant): + return None + type = gen.annotator.binding(obj) + if type.__class__ == annmodel.SomeInteger: + return IntRepr(type, obj.value, gen) + get = staticmethod(get) + + def __init__(self, annotation, value, gen): + if debug: + print "IntRepr", annotation, value + self.value = value + self.annotation = annotation + self.type = gen.get_repr(annotation) + self.gen = gen + self.dependencies = sets.Set() + + def llvmname(self): + return repr(self.value) + + def cast_to_unsigned(self, l_val, lblock, l_function): + if self.type.annotation.unsigned: + return self + else: + return IntRepr(annmodel.SomeInteger(True, True), + self.value, self.gen) + + def cast_to_signed(self, l_val, lblock, l_function): + if not self.type.annotation.unsigned: + return self + else: + return IntRepr(annmodel.SomeInteger(), self.value, self.gen) class VariableRepr(LLVMRepr): def get(obj, gen): @@ -126,9 +162,12 @@ def __getattr__(self, name): if name.startswith("op_"): return getattr(self.type, "t_" + name, None) + elif name.startswith("cast_"): + return getattr(self.type, name, None) else: raise AttributeError, ("VariableRepr instance has no attribute %s" % repr(name)) + class TmpVariableRepr(LLVMRepr): def __init__(self, name, type, gen): if debug: @@ -141,26 +180,43 @@ return "%" + self.name def llvmtype(self): - return self.type + return self.type.llvmname() + +class NoneRepr(LLVMRepr): + def get(obj, gen): + if isinstance(obj, Constant) and obj.value is None: + return NoneRepr(gen) + get = staticmethod(get) + + def __init__(self, gen): + self.gen = gen + self.type = gen.get_repr(type(None)) + self.dependencies = sets.Set([self.type]) + if debug: + print "NoneRepr, llvmname: %s, llvmtype: %s" % (self.llvmname(), + self.llvmtype()) + def llvmname(self): + return "null" class StringRepr(LLVMRepr): def get(obj, gen): if isinstance(obj, Constant): type = gen.annotator.binding(obj) - if type.__class__ is annmodel.SomeString: - l_repr = StringRepr(obj, gen) - return l_repr + if isinstance(type, annmodel.SomeString): + return StringRepr(obj.value, gen) + elif isinstance(obj, str): + return StringRepr(obj, gen) return None get = staticmethod(get) def __init__(self, obj, gen): if debug: - print "StringRepr: %s" % obj.value - self.s = obj.value + print "StringRepr: %s" % obj + self.s = obj self.gen = gen self.glvar1 = gen.get_global_tmp("StringRepr") self.glvar2 = gen.get_global_tmp("StringRepr") - self.type = gen.get_repr(gen.annotator.binding(obj)) + self.type = gen.get_repr(annmodel.SomeString()) self.dependencies = sets.Set([self.type]) def llvmname(self): @@ -169,22 +225,60 @@ def get_globals(self): d = {"len": len(self.s), "gv1": self.glvar1, "gv2": self.glvar2, "type": self.type.llvmname_wo_pointer(), "string": self.s} - s = """%(gv1)s = internal constant [%(len)i x sbyte] c"%(string)s" -%(gv2)s = internal constant %(type)s {uint %(len)i,\ + s = """%(gv1)s = internal global [%(len)i x sbyte] c"%(string)s" +%(gv2)s = internal global %(type)s {uint %(len)i,\ sbyte* getelementptr ([%(len)i x sbyte]* %(gv1)s, uint 0, uint 0)}""" return s % d + def __getattr__(self, name): + if name.startswith("op_"): + return getattr(self.type, "t_" + name, None) + else: + raise AttributeError, ("VariableRepr instance has no attribute %s" + % repr(name)) + +class TupleRepr(LLVMRepr): + def get(obj, gen): + if isinstance(obj, Constant): + type = gen.annotator.binding(obj) + if isinstance(type, annmodel.SomeTuple): + return TupleRepr(obj, gen) + return None + get = staticmethod(get) + + def __init__(self, obj, gen): + if debug: + print "TupleRepr", obj, obj.value + self.const = obj + self.tuple = obj.value + self.gen = gen + self.dependencies = sets.Set() + + def setup(self): + self.l_tuple = [self.gen.get_repr(l) for l in list(self.tuple)] + self.glvar = self.gen.get_global_tmp("TupleRepr") + self.dependencies.update(self.l_tuple) + self.type = self.gen.get_repr(self.gen.annotator.binding(self.const)) + + def get_globals(self): + s = "%s = internal global " % self.glvar + " " + self.llvmtype() + s += "{" + ", ".join([l.typed_name() for l in self.l_tuple]) + "}" + i = self.l_tuple[0] + return s + + def llvmname(self): + return self.glvar + + def __getattr__(self, name): + if name.startswith("op_"): + return getattr(self.type, "t_" + name, None) + else: + raise AttributeError, ("TupleRepr instance has no attribute %s" + % repr(name)) + + class TypeRepr(LLVMRepr): - l_stringtype = None def get(obj, gen): -## print "TypeRepr", obj - if obj.__class__ is annmodel.SomeString or obj is str: - if TypeRepr.l_stringtype is None: - l_repr = TypeRepr("%std.string", - "%std.string = type {uint, sbyte*}", - "string.ll", gen) - TypeRepr.l_stringtype = l_repr - return TypeRepr.l_stringtype if (isinstance(obj, annmodel.SomePBC) and \ obj.prebuiltinstances.keys()[0] is None) or obj is type(None): return TypeRepr("%std.void", "%std.void = type sbyte", "", gen) @@ -221,6 +315,34 @@ def llvmname_wo_pointer(self): return self.name +class StringTypeRepr(TypeRepr): + def get(obj, gen): + if obj.__class__ is annmodel.SomeString or obj is str: + return StringTypeRepr(gen) + get = staticmethod(get) + + def __init__(self, gen): + if debug: + print "StringTypeRepr" + self.gen = gen + self.dependencies = sets.Set() + + def setup(self): + self.l_charlist = self.gen.get_repr( + annmodel.SomeList(None, annmodel.SomeChar())) + self.dependencies.add(self.l_charlist) + self.name = self.l_charlist.llvmname_wo_pointer() + + def t_op_getitem(self, l_target, args, lblock, l_func): + l_args = [self.gen.get_repr(arg) for arg in args] + l_func.dependencies.update(l_args) + lblock.spaceop(l_target, "getitem", l_args) + + def t_op_inplace_add(self, l_target, args, lblock, l_func): + l_args = [self.gen.get_repr(arg) for arg in args] + l_func.dependencies.update(l_args) + lblock.spaceop(l_target, "add", l_args) + class ListTypeRepr(TypeRepr): l_listtypes = {} def get(obj, gen): @@ -250,6 +372,10 @@ itemtype = self.l_itemtype.llvmname() s = s.replace("%(item)s", self.l_itemtype.llvmname()) s = s.replace("%(name)s", itemtype.strip("%").replace("*", "")) + if isinstance(self.l_itemtype, IntTypeRepr): + f1 = file(autopath.this_dir + "/int_list.ll", "r") + s += f1.read() + f1.close() return s def t_op_getitem(self, l_target, args, lblock, l_func): @@ -278,14 +404,103 @@ else: raise CompileError, "List method %s not supported." % args[1].value +class TupleTypeRepr(TypeRepr): + def get(obj, gen): + if isinstance(obj, annmodel.SomeTuple): + return TupleTypeRepr(obj, gen) + return None + get = staticmethod(get) + + def __init__(self, obj, gen): + self.gen = gen + self.l_itemtypes = [gen.get_repr(l) for l in obj.items] + self.name = (("{" + ", ".join(["%s"] * len(self.l_itemtypes)) + "}") % + tuple([l.llvmname() for l in self.l_itemtypes])) + + def get_functions(self): + s = ("internal int %%std.len(%s %%t) {\n\tret int %i\n}\n" % + (self.llvmname(), len(self.l_itemtypes))) + return s + + def t_op_newtuple(self, l_target, args, lblock, l_func): + l_args = [self.gen.get_repr(arg) for arg in args] + l_func.dependencies.update(l_args) + lblock.malloc(l_target, self) + l_ptrs = [self.gen.get_local_tmp(\ + PointerTypeRepr(l.llvmname(),self.gen), l_func) + for l in self.l_itemtypes] + l_func.dependencies.update(l_ptrs) + for i, l in enumerate(self.l_itemtypes): + lblock.getelementptr(l_ptrs[i], l_target, [0, i]) + lblock.store(l_args[i], l_ptrs[i]) + + def t_op_getitem(self, l_target, args, lblock, l_func): + if not isinstance(args[1], Constant): + raise CompileError, "index for tuple's getitem has to be constant" + l_args = [self.gen.get_repr(arg) for arg in args] + l_func.dependencies.update(l_args) + l_tmp = self.gen.get_local_tmp(PointerTypeRepr(l_target.llvmtype(), + self.gen), l_func) + cast = getattr(l_args[1], "cast_to_unsigned", None) + if cast is not None: + l_unsigned = cast(l_args[1], lblock, l_func) + else: + raise CompileError, "Invalid arguments to getitem" + lblock.getelementptr(l_tmp, l_args[0], [0, l_unsigned]) + lblock.load(l_target, l_tmp) + +class IntTypeRepr(TypeRepr): + def get(obj, gen): + if obj.__class__ is annmodel.SomeInteger: + return IntTypeRepr(obj, gen) + return None + get = staticmethod(get) + + def __init__(self, annotation, gen): + if debug: + print "IntTypeRepr: %s" % annotation + self.annotation = annotation + if annotation.unsigned: + self.name = "uint" + else: + self.name = "int" + self.gen = gen + + def llvmname(self): + return self.name + + def cast_to_signed(self, l_val, lblock, l_function): + if not self.annotation.unsigned: + return l_val + ann = annmodel.SomeInteger() + l_type = self.gen.get_repr(ann) + l_tmp = self.gen.get_local_tmp(l_type, l_function) + l_function.dependencies.update([l_type, l_tmp]) + lblock.cast(l_tmp, l_val, l_type) + return l_tmp + + def cast_to_unsigned(self, l_val, lblock, l_function): + if self.annotation.unsigned: + return l_val + ann = annmodel.SomeInteger(True, True) + l_type = self.gen.get_repr(ann) + l_tmp = self.gen.get_local_tmp(l_type, l_function) + l_function.dependencies.update([l_type, l_tmp]) + lblock.cast(l_tmp, l_val, l_type) + return l_tmp + + class SimpleTypeRepr(TypeRepr): def get(obj, gen): - if obj.__class__ in [annmodel.SomeInteger, int]: + if obj.__class__ is annmodel.SomeInteger: l_repr = SimpleTypeRepr("int", gen) return l_repr - elif obj.__class__ in [annmodel.SomeBool, bool]: + elif obj.__class__ is annmodel.SomeBool: l_repr = SimpleTypeRepr("bool", gen) return l_repr + elif obj.__class__ is annmodel.SomeChar: + l_repr = SimpleTypeRepr("sbyte", gen) + return l_repr return None get = staticmethod(get) @@ -300,6 +515,17 @@ def llvmname(self): return self.name +class PointerTypeRepr(TypeRepr): + def get(obj, gen): + return None + get = staticmethod(get) + + def __init__(self, type, gen): + self.type = type + + def llvmname(self): + return self.type + "*" + class ImpossibleValueRepr(TypeRepr): def get(obj, gen): if obj.__class__ is annmodel.SomeImpossibleValue: @@ -315,71 +541,71 @@ def llvmname(self): return "void" -class NoneRepr(TypeRepr): - def get(obj, gen): - if isinstance(obj, Constant) and obj.value is None: - return NoneRepr(gen) - get = staticmethod(get) - - def __init__(self, gen): - self.gen = gen - self.type = gen.get_repr(type(None)) - self.dependencies = sets.Set([self.type]) - if debug: - print "NoneRepr, llvmname: %s, llvmtype: %s" % (self.llvmname(), - self.llvmtype()) - - def llvmname(self): - return "null" - class ClassRepr(TypeRepr): + l_classes = {} def get(obj, gen): + classdef = None if obj.__class__ is Constant: bind = gen.annotator.binding(obj) if bind.__class__ is annmodel.SomePBC and \ bind.const.__class__ == type: classdef = gen.annotator.bookkeeper.userclasses[bind.const] - return ClassRepr(classdef, gen) - if isinstance(obj, annmodel.SomeInstance): - return ClassRepr(obj.classdef, gen) - return None + elif isinstance(obj, annmodel.SomeInstance): + classdef = obj.classdef + elif isinstance(obj, ClassDef): + classdef = obj + if classdef is None: + return None + if (classdef, gen) not in ClassRepr.l_classes: + ClassRepr.l_classes[(classdef, gen)] = ClassRepr(classdef, gen) + return ClassRepr.l_classes[(classdef, gen)] get = staticmethod(get) def __init__(self, obj, gen): - if 1: - print "ClassRepr: %s", obj + if debug: + print "ClassRepr: %s, %s" % (obj, hex(id(self))) self.classdef = obj self.gen = gen self.includefile = "" self.name = gen.get_global_tmp("class.%s" % self.classdef.cls.__name__) + if debug: + print self.name self.dependencies = sets.Set() + self.setup_done = False self.attr_num = {} - self.se = False def setup(self): - self.se = True + if self.setup_done: + return + self.setup_done = True if debug: - print "ClassRepr.setup()", id(self) + print "ClassRepr.setup()", id(self), hex(id(self)), self.setup_done + print len(ClassRepr.l_classes) gen = self.gen - attribs = [] + if self.classdef.basedef is not None: + self.l_base = gen.get_repr(self.classdef.basedef) + self.dependencies.add(self.l_base) + attribs = self.l_base.attributes + else: + attribs = [] meth = [] if debug: - print "attributes" - for key, attr in self.classdef.attrs.iteritems(): + print "attributes", self.classdef.attrs + for key, attr in self.classdef.attrs.items(): if debug: print key, attr, attr.sources, attr.s_value, if len(attr.sources) != 0: func = self.classdef.cls.__dict__[attr.name] meth.append((key, func)) if debug: - print "--> method" + print "--> method1" elif isinstance(attr.s_value, annmodel.SomePBC) and \ attr.s_value.knowntype is FunctionType: func = self.classdef.cls.__dict__[attr.name] meth.append((key, func)) if debug: - print "--> method" + print "--> method2" else: attribs.append(attr) if debug: @@ -387,37 +613,71 @@ self.l_attrs_types = [gen.get_repr(attr.s_value) for attr in attribs] self.dependencies = sets.Set(self.l_attrs_types) attributes = ", ".join([at.llvmname() for at in self.l_attrs_types]) - self.definition = "%s = type {int*, %s}" % (self.name, attributes) + self.definition = "%s = type {uint, %s}" % (self.name, attributes) + self.attributes = attribs self.attr_num = {} for i, attr in enumerate(attribs): self.attr_num[attr.name] = i + 1 self.methods = dict(meth) def op_simple_call(self, l_target, args, lblock, l_func): - l_init = self.gen.get_repr(self.methods["__init__"]) - l_func.dependencies.add(l_init) - l_args = [self.gen.get_repr(arg) for arg in args[1:]] - self.dependencies.update(l_args) lblock.malloc(l_target, self) - lblock.call_void(l_init, [l_target] + l_args) + l_tmp = self.gen.get_local_tmp(PointerTypeRepr("uint", self.gen), + l_func) + lblock.getelementptr(l_tmp, l_target, [0, 0]) + #XXX: store the id of the ClassRepr for isinstance checks, + #polymorphism etc. Should probably replace this with a pointer to a + #virtual function table instead + lblock.instruction("store uint %s, %s" % + (id(self), l_tmp.typed_name())) + init = None + for cls in self.classdef.getmro(): + if "__init__" in cls.attrs: + init = cls.attrs["__init__"].getvalue() + break + if init is not None: + l_init = self.gen.get_repr(init) + l_func.dependencies.add(l_init) + l_args = [self.gen.get_repr(arg) for arg in args[1:]] + self.dependencies.update(l_args) + # XXX + if isinstance(l_init, VirtualMethodRepr): + l_init = l_init.l_funcs[l_init.classes.index(self.classdef)] + lblock.call_void(l_init, [l_target] + l_args) def t_op_getattr(self, l_target, args, lblock, l_func): - print "t_op_getattrs", l_target, args + if debug: + print "t_op_getattr of ClassRepr called", l_target, args, self.name if not isinstance(args[1], Constant): raise CompileError,"getattr called with non-constant: %s" % args[1] if args[1].value in self.attr_num: l_args0 = self.gen.get_repr(args[0]) l_func.dependencies.add(l_args0) - l_pter = self.gen.get_local_tmp(l_target.llvmtype() + "*", l_func) + l_pter = self.gen.get_local_tmp( + PointerTypeRepr(l_target.llvmtype(), self.gen), l_func) lblock.getelementptr(l_pter, l_args0, [0, self.attr_num[args[1].value]]) lblock.load(l_target, l_pter) - elif args[1].value in self.methods: - l_args0 = self.gen.get_repr(args[0]) - l_func.dependencies.add(l_args0) - l_method = BoundMethodRepr(l_target.type, l_args0, self, self.gen) - l_method.setup() - l_target.type = l_method + return + else: + if debug: + print list(self.classdef.getmro()) + for cls in self.classdef.getmro(): + l_cls = self.gen.get_repr(cls) + self.dependencies.add(l_cls) + if args[1].value in l_cls.methods: + if debug: + print "class %s, %s matches" % (cls, l_cls) + l_args0 = self.gen.get_repr(args[0]) + l_func.dependencies.add(l_args0) + l_method = BoundMethodRepr(l_target.type, l_args0, l_cls, + self.gen) + l_func.dependencies.add(l_method) + l_method.setup() + l_target.type = l_method + return + raise CompileError, ("getattr called with unknown attribute %s" % \ + args[1].value) def t_op_setattr(self, l_target, args, lblock, l_func): if not isinstance(args[1], Constant): @@ -426,11 +686,15 @@ l_args0 = self.gen.get_repr(args[0]) l_value = self.gen.get_repr(args[2]) self.dependencies.update([l_args0, l_value]) - l_pter = self.gen.get_local_tmp(l_value.llvmtype() + "*", l_func) + l_pter = self.gen.get_local_tmp( + PointerTypeRepr(l_value.llvmtype(), self.gen), l_func) lblock.getelementptr(l_pter, l_args0, [0, self.attr_num[args[1].value]]) lblock.store(l_value, l_pter) - + else: + raise CompileError, ("setattr called with unknown attribute %s" % \ + args[1].value) + class BuiltinFunctionRepr(LLVMRepr): def get(obj, gen): @@ -456,18 +720,21 @@ lblock.call(l_target, l_args[0], l_args[1:]) class FunctionRepr(LLVMRepr): + l_functions = {} def get(obj, gen): - if isinstance(obj, Constant) and \ - type(obj.value).__name__ == 'function': - name = obj.value.__name__ - l_repr = FunctionRepr(name, obj.value, gen) - return l_repr - elif isinstance(obj, annmodel.SomePBC): + if isinstance(obj, annmodel.SomePBC) and \ + len(obj.prebuiltinstances) == 1: obj = obj.prebuiltinstances.keys()[0] - if type(obj).__name__ == 'function': - name = obj.__name__ - l_repr = FunctionRepr(name, obj, gen) - return l_repr + elif isinstance(obj, Constant): + obj = obj.value + if isinstance(obj, MethodType): + obj = obj.class_.__dict__[obj.__name__] + if isinstance(obj, FunctionType): + if (obj, gen) in FunctionRepr.l_functions: + return FunctionRepr.l_functions[(obj, gen)] + l_func = FunctionRepr(obj.__name__, obj, gen) + FunctionRepr.l_functions[(obj, gen)] = l_func + return l_func return None get = staticmethod(get) @@ -485,8 +752,15 @@ self.pyrex_source = "" self.dependencies = sets.Set() self.get_bbs() + self.se = False def setup(self): + if self.se: + return + self.se = True + self.l_args = [self.gen.get_repr(ar) + for ar in self.graph.startblock.inputargs] + self.dependencies.update(self.l_args) self.retvalue = self.gen.get_repr(self.graph.returnblock.inputargs[0]) self.dependencies.add(self.retvalue) self.build_bbs() @@ -547,13 +821,19 @@ l_op = getattr(l_arg0, "op_" + op.opname, None) if l_op is not None: l_op(l_target, op.args, lblock, self) + #XXX need to find more elegant solution for this special case + elif op.opname == "newtuple": + l_target.type.t_op_newtuple(l_target, op.args, + lblock, self) elif op.opname in INTRINSIC_OPS: l_args = [self.gen.get_repr(arg) for arg in op.args[1:]] self.dependencies.update(l_args) lblock.spaceop(l_target, op.opname, [l_arg0] + l_args) else: s = "SpaceOperation %s not supported. Target: %s " \ - "Args: %s" % (op.opname, l_target, op.args) + "Args: %s " % (op.opname, l_target, op.args) + \ + "Dispatched on: %s" % l_arg0 + raise CompileError, s #Create branches if pyblock.exitswitch is None: @@ -585,12 +865,8 @@ return fd def llvmfuncdef(self): - a = self.translator.annotator - l_args = [self.gen.get_repr(ar) - for ar in self.graph.startblock.inputargs] - self.dependencies.update(l_args) s = "%s %s(" % (self.retvalue.llvmtype(), self.name) - return s + ", ".join([a.typed_name() for a in l_args]) + ")" + return s + ", ".join([a.typed_name() for a in self.l_args]) + ")" def get_pyrex_source(self): name = self.func.func_name @@ -603,7 +879,6 @@ t += ["%s" % a] t = ", ".join(t) self.pyrex_source += t + "):\n\treturn %s(%s)\n\n" % (name, t) - self.pyrex_source += "\ndef test(a):\n\treturn a + 1\n\n" self.pyrex_source = "".join(self.pyrex_source) return self.pyrex_source @@ -622,14 +897,98 @@ def op_simple_call(self, l_target, args, lblock, l_func): l_args = [self.gen.get_repr(arg) for arg in args] + for i, (l_a1, l_a2) in enumerate(zip(l_args[1:], self.l_args)): + if l_a1.llvmtype() != l_a2.llvmtype(): + l_tmp = self.gen.get_local_tmp(l_a2.type, l_func) + lblock.cast(l_tmp, l_a1) + l_args[1 + i] = l_tmp + l_func.dependencies.update(l_args) + lblock.call(l_target, l_args[0], l_args[1:]) + +class VirtualMethodRepr(LLVMRepr): + # Really stupid implementation of virtual functions: + # Should be replaced by function pointers + def get(obj, gen): + if isinstance(obj, annmodel.SomePBC) and \ + len(obj.prebuiltinstances) > 1 and \ + isinstance(obj.prebuiltinstances.keys()[0], FunctionType): + return VirtualMethodRepr(obj.prebuiltinstances, gen) + return None + get = staticmethod(get) + + def __init__(self, prebuiltinstances, gen): + if debug: + print "VirtualMethodRepr: %s" % prebuiltinstances + self.gen = gen + self.classes = prebuiltinstances.values() + commonbase = reduce(lambda a, b: a.commonbase(b), self.classes) + self.commonbase_index = self.classes.index(commonbase) + self.commonbase = commonbase + self.funcs = prebuiltinstances.keys() + self.name = "%" + self.funcs[0].__name__ + ".virtual" + self.dependencies = sets.Set() + + def setup(self): + cbi = self.commonbase_index + self.l_funcs = [self.gen.get_repr(f) for f in self.funcs] + self.dependencies.update(self.l_funcs) + self.retvalue = self.l_funcs[cbi].retvalue + self.l_classes = [self.gen.get_repr(c) for c in self.classes] + self.dependencies.update(self.l_classes) + self.l_commonbase = self.l_classes[self.commonbase_index] + self.type_numbers = [id(l_c) for l_c in self.l_classes] + self.l_args = [self.gen.get_repr(ar) + for ar in self.l_funcs[cbi].graph.startblock.inputargs] + l_retvalue = self.retvalue + self.dependencies.update(self.l_args) + entryblock = llvmbc.BasicBlock("entry") + l_ptr = self.gen.get_local_tmp(PointerTypeRepr("uint", self.gen), self) + l_type = self.gen.get_local_tmp(self.gen.get_repr( + annmodel.SomeInteger(True, True)), self) + self.dependencies.update([l_ptr, l_type]) + entryblock.getelementptr(l_ptr, self.l_args[0], [0, 0]) + entryblock.load(l_type, l_ptr) + entryblock.switch(l_type, "%a" + str(id(self.l_commonbase)), + [(id(l_c), "%a" + str(id(l_c))) + for l_c in self.l_classes]) + lfunc = llvmbc.Function(self.llvmfuncdef(), entryblock) + for i, l_cls in enumerate(self.l_classes): + lblock = llvmbc.BasicBlock("a" + str(id(l_cls))) + lfunc.basic_block(lblock) + l_tmp = self.gen.get_local_tmp(l_cls, self) + lblock.cast(l_tmp, self.l_args[0]) + l_tmp_ret = self.gen.get_local_tmp(l_retvalue.type, self) + self.l_funcs[i].op_simple_call( + l_tmp_ret, [self.l_funcs[i], l_tmp] + + self.l_funcs[cbi].graph.startblock.inputargs[1:], lblock, self) + lblock.ret(l_tmp_ret) + self.llvm_func = lfunc + + def op_simple_call(self, l_target, args, lblock, l_func): + l_args = [self.gen.get_repr(arg) for arg in args] self.dependencies.update(l_args) + if l_args[1].llvmtype() != self.l_args[0].llvmtype(): + l_tmp = self.gen.get_local_tmp(self.l_args[0].type, l_func) + lblock.cast(l_tmp, l_args[1]) + l_args[1] = l_tmp + lblock.call(l_target, l_args[0], l_args[1:]) lblock.call(l_target, l_args[0], l_args[1:]) + + def get_functions(self): + return str(self.llvm_func) + + def llvmfuncdef(self): + cbi = self.commonbase_index + s = "%s %s(" % (self.l_funcs[cbi].retvalue.llvmtype(), self.name) + return s + ", ".join([a.typed_name() for a in self.l_args]) + ")" + + def rettype(self): + return self.retvalue.llvmtype() class BoundMethodRepr(LLVMRepr): def get(obj, gen): return None get = staticmethod(get) - def __init__(self, l_func, l_self, l_class, gen): self.gen = gen self.l_func = l_func @@ -637,10 +996,14 @@ self.l_class = l_class self.dependencies = sets.Set([l_self, l_class, l_func]) - def setup(self): - pass - def t_op_simple_call(self, l_target, args, lblock, l_func): - self.l_func.op_simple_call(l_target, - [self.l_func, self.l_self] + args[1:], - lblock, l_func) + if self.l_self.llvmtype() != self.l_class.llvmname(): + l_tmp = self.gen.get_local_tmp(self.l_class, l_func) + lblock.cast(l_tmp, self.l_self) + self.l_func.op_simple_call(l_target, + [self.l_func, l_tmp] + args[1:], + lblock, l_func) + else: + self.l_func.op_simple_call(l_target, + [self.l_func, self.l_self] + args[1:], + lblock, l_func) Modified: pypy/dist/pypy/translator/llvm/test/llvmsnippet.py ============================================================================== --- pypy/dist/pypy/translator/llvm/test/llvmsnippet.py (original) +++ pypy/dist/pypy/translator/llvm/test/llvmsnippet.py Tue Mar 22 22:06:04 2005 @@ -7,9 +7,9 @@ def simple2(): return False -def simple3(): +def simple3(i): c = "Hello, Stars!" - return c + return c[i] def simple4(): return 3 + simple1() @@ -111,6 +111,9 @@ a.reverse() return a[i] +def rangetest(i): + return range(10)[i] + #class snippets class A(object): @@ -161,3 +164,57 @@ d = D(1, i + 1) d.set_range() return d.a[i] + +#simple inheritance snippets +class AAA(object): + def __init__(self): + self.a = 1 + + def get(self): + return 4 + + def g(self): + return self.a + +class BBB(AAA): + def __init__(self): + AAA.__init__(self) + self.b = 2 + + def get(self): + return 5 + +def attribute_from_base_class(): + a = AAA() + b = BBB() + return a.a + b.a + b.b + +def method_of_base_class(): + a = AAA() + b = BBB() + return a.get() + AAA.get(b) + b.get() + b.g() + + +#string snippets +def string_f1(i): + j = 0 + ret = "" + while j < i: + ret += "abc" + j += 1 + return ret + +def string_f2(i, j): + return string_f1(i)[j] + + +#tuple snippets +def tuple_f1(i): + return (1, "asdf", i)[2] + +def tuple_f2(i): + return (i, "test", "another one", [1, 2, 3]) + +def tuple_f3(i): + j, s1, s2, l = tuple_f2(i) + return j Modified: pypy/dist/pypy/translator/llvm/test/test_genllvm.py ============================================================================== --- pypy/dist/pypy/translator/llvm/test/test_genllvm.py (original) +++ pypy/dist/pypy/translator/llvm/test/test_genllvm.py Tue Mar 22 22:06:04 2005 @@ -16,6 +16,7 @@ def compile_function(function, annotate): t = Translator(function, simplifying=True) a = t.annotate(annotate) + a.simplify() gen = LLVMGenerator(t) return gen.compile() @@ -61,7 +62,7 @@ assert l_repr.llvmname() == "false" assert l_repr.typed_name() == "bool false" - def test_typerepr(self): + def DONOT_test_typerepr(self): t = Translator(llvmsnippet.simple1) a = t.annotate([]) gen = LLVMGenerator(t) @@ -169,8 +170,11 @@ f = compile_function(llvmsnippet.array_reverse, [int]) assert f(0) == 1 assert f(1) == 0 - + def test_range(self): + f = compile_function(llvmsnippet.rangetest, [int]) + for i in range(10): + assert f(i) == i class TestClass(object): def setup_method(self, method): @@ -185,15 +189,49 @@ f = compile_function(llvmsnippet.class_simple1, [int]) assert f(2) == 10 - def test_classsimple2(self): - f = compile_function(llvmsnippet.class_simple2, [int]) - assert f(2) == 10 - def test_id_int(self): f = compile_function(llvmsnippet.id_int, [int]) for i in range(1, 20): assert f(i) == i + def test_classsimple2(self): + f = compile_function(llvmsnippet.class_simple2, [int]) + assert f(2) == 10 + + def test_method_of_base_class(self): + f = compile_function(llvmsnippet.method_of_base_class, []) + assert f() == 14 + + def test_attribute_from_base_class(self): + f = compile_function(llvmsnippet.attribute_from_base_class, []) + assert f() == 4 + +class TestString(object): + def setup_method(self, method): + if not llvm_found: + py.test.skip("llvm-as not found on path.") + + def test_f2(self): + f = compile_function(llvmsnippet.string_f2, [int, int]) + assert chr(f(1, 0)) == "a" + +class TestTuple(object): + def setup_method(self, method): + if not llvm_found: + py.test.skip("llvm-as not found on path.") + + def test_f1(self): + f = compile_function(llvmsnippet.tuple_f1, [int]) + assert f(10) == 10 + assert f(15) == 15 + + def test_f3(self): + f = compile_function(llvmsnippet.tuple_f3, [int]) + assert f(10) == 10 + assert f(15) == 15 + assert f(30) == 30 + + class TestSnippet(object): def setup_method(self, method): if not llvm_found: @@ -229,6 +267,10 @@ f = compile_function(test.sieve_of_eratosthenes, []) assert f() == 1028 + def test_simple_func(self): + f = compile_function(test.simple_func, [int]) + assert f(1027) == 1028 + def test_while_func(self): while_func = compile_function(test.while_func, [int]) assert while_func(10) == 55 @@ -240,6 +282,10 @@ assert f(3) == 6 assert f(4) == 12 + def test_int_id(self): + f = compile_function(test.int_id, [int]) + assert f(1027) == 1027 + def test_factorial2(self): factorial2 = compile_function(test.factorial2, [int]) assert factorial2(5) == 120 @@ -248,5 +294,23 @@ factorial = compile_function(test.factorial, [int]) assert factorial(5) == 120 - - + def test_set_attr(self): + set_attr = compile_function(test.set_attr, []) + assert set_attr() == 2 + + def test_merge_setattr(self): + merge_setattr = compile_function(test.merge_setattr, [bool]) + assert merge_setattr(1) == 1 + + def test_simple_method(self): + simple_method = compile_function(test.simple_method, [int]) + assert simple_method(65) == 65 + + def test_with_init(self): + with_init = compile_function(test.with_init, [int]) + assert with_init(42) == 42 + + def DONOTtest_with_more_init(self): + with_more_init = compile_function(test.with_more_init, [int, bool]) + assert with_more_init(42, True) == 42 + assert with_more_init(42, False) == -42 From arigo at codespeak.net Tue Mar 22 22:06:58 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 22 Mar 2005 22:06:58 +0100 (MET) Subject: [pypy-svn] r10092 - in pypy/dist/pypy/objspace/std: . test Message-ID: <20050322210658.9D4DF27B5A@code1.codespeak.net> Author: arigo Date: Tue Mar 22 22:06:58 2005 New Revision: 10092 Modified: pypy/dist/pypy/objspace/std/sliceobject.py pypy/dist/pypy/objspace/std/test/test_sliceobject.py Log: slice.__lt__() Modified: pypy/dist/pypy/objspace/std/sliceobject.py ============================================================================== --- pypy/dist/pypy/objspace/std/sliceobject.py (original) +++ pypy/dist/pypy/objspace/std/sliceobject.py Tue Mar 22 22:06:58 2005 @@ -42,6 +42,17 @@ else: return space.w_False +def lt__Slice_Slice(space, w_slice1, w_slice2): + if space.is_w(w_slice1, w_slice2): + return space.w_False # see comments in eq__Slice_Slice() + if space.eq_w(w_slice1.w_start, w_slice2.w_start): + if space.eq_w(w_slice1.w_stop, w_slice2.w_stop): + return space.lt(w_slice1.w_step, w_slice2.w_step) + else: + return space.lt(w_slice1.w_stop, w_slice2.w_stop) + else: + return space.lt(w_slice1.w_start, w_slice2.w_start) + def hash__Slice(space, w_slice): """slices are not hashables but they must have a __hash__ method""" raise OperationError(space.w_TypeError, Modified: pypy/dist/pypy/objspace/std/test/test_sliceobject.py ============================================================================== --- pypy/dist/pypy/objspace/std/test/test_sliceobject.py (original) +++ pypy/dist/pypy/objspace/std/test/test_sliceobject.py Tue Mar 22 22:06:58 2005 @@ -61,3 +61,12 @@ assert slice1 == slice2 slice2 = slice(1, 2) assert slice1 != slice2 + + def test_lt(self): + assert slice(0, 2, 3) < slice(1, 0, 0) + assert slice(0, 1, 3) < slice(0, 2, 0) + assert slice(0, 1, 2) < slice(0, 1, 3) + assert not (slice(1, 2, 3) < slice(0, 0, 0)) + assert not (slice(1, 2, 3) < slice(1, 0, 0)) + assert not (slice(1, 2, 3) < slice(1, 2, 0)) + assert not (slice(1, 2, 3) < slice(1, 2, 3)) From rxe at codespeak.net Tue Mar 22 22:31:02 2005 From: rxe at codespeak.net (rxe at codespeak.net) Date: Tue, 22 Mar 2005 22:31:02 +0100 (MET) Subject: [pypy-svn] r10093 - pypy/dist/pypy/interpreter Message-ID: <20050322213102.65F8C27B5B@code1.codespeak.net> Author: rxe Date: Tue Mar 22 22:31:02 2005 New Revision: 10093 Modified: pypy/dist/pypy/interpreter/executioncontext.py Log: Intermediate checkin trying to track down problem with running profile.py Modified: pypy/dist/pypy/interpreter/executioncontext.py ============================================================================== --- pypy/dist/pypy/interpreter/executioncontext.py (original) +++ pypy/dist/pypy/interpreter/executioncontext.py Tue Mar 22 22:31:02 2005 @@ -122,6 +122,11 @@ return frame.last_exception return None + def clear_exception(self): + if operror is not None: + operror.clear(space) + + def get_state_dict(self): """A mechanism to store arbitrary per ExecutionContext data. Similar to cpython's PyThreadState_GetDict. @@ -173,8 +178,10 @@ if self.w_profilefunc is not None: if event not in ['leaveframe', 'call']: return - + + last_exception = None if event == 'leaveframe': + last_exception = frame.last_exception event = 'return' assert self.is_tracing == 0 @@ -185,7 +192,8 @@ self.space.wrap(frame), self.space.wrap(event), w_arg) except: - raise + pass finally: + frame.last_exception = last_exception self.is_tracing -= 1 From ac at codespeak.net Tue Mar 22 22:48:13 2005 From: ac at codespeak.net (ac at codespeak.net) Date: Tue, 22 Mar 2005 22:48:13 +0100 (MET) Subject: [pypy-svn] r10094 - pypy/dist/lib-python-2.3.4/test Message-ID: <20050322214813.5FE9827B5B@code1.codespeak.net> Author: ac Date: Tue Mar 22 22:48:13 2005 New Revision: 10094 Modified: pypy/dist/lib-python-2.3.4/test/conftest.py Log: Another test working. Modified: pypy/dist/lib-python-2.3.4/test/conftest.py ============================================================================== --- pypy/dist/lib-python-2.3.4/test/conftest.py (original) +++ pypy/dist/lib-python-2.3.4/test/conftest.py Tue Mar 22 22:48:13 2005 @@ -46,6 +46,7 @@ 'test_isinstance.py', 'test_operator.py', 'test_pprint.py', +'test_profilehooks.py', 'test_sgmllib.py', 'test_string.py', 'test_sys.py', From hpk at codespeak.net Tue Mar 22 23:21:57 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Tue, 22 Mar 2005 23:21:57 +0100 (MET) Subject: [pypy-svn] r10095 - pypy/dist/pypy/module/parser Message-ID: <20050322222157.7CCDA27B53@code1.codespeak.net> Author: hpk Date: Tue Mar 22 23:21:57 2005 New Revision: 10095 Modified: pypy/dist/pypy/module/parser/__init__.py pypy/dist/pypy/module/parser/pyparser.py Log: expose suite and expr Modified: pypy/dist/pypy/module/parser/__init__.py ============================================================================== --- pypy/dist/pypy/module/parser/__init__.py (original) +++ pypy/dist/pypy/module/parser/__init__.py Tue Mar 22 23:21:57 2005 @@ -7,21 +7,23 @@ """ appleveldefs = { 'ParserError' : 'classes.ParserError', - 'STType' : 'classes.STType', - 'ASTType' : 'classes.STType', } interpleveldefs = { '__name__' : '(space.wrap("parser"))', '__doc__' : '(space.wrap("parser module"))', + 'suite' : 'pyparser.suite', + 'STType' : 'pyparser.STType', + 'ASTType' : 'pyparser.STType', + 'eval_input' : 'pyparser.eval_input', + 'file_input' : 'pyparser.file_input', 'compileast' : 'pyparser.compileast', 'st2tuple' : 'pyparser.st2tuple', 'st2list' : 'pyparser.st2list', 'issuite' : 'pyparser.issuite', 'ast2tuple' : 'pyparser.ast2tuple', 'tuple2st' : 'pyparser.tuple2st', - 'suite' : 'pyparser.suite', 'isexpr' : 'pyparser.isexpr', 'expr' : 'pyparser.expr', 'ast2list' : 'pyparser.ast2list', Modified: pypy/dist/pypy/module/parser/pyparser.py ============================================================================== --- pypy/dist/pypy/module/parser/pyparser.py (original) +++ pypy/dist/pypy/module/parser/pyparser.py Tue Mar 22 23:21:57 2005 @@ -9,6 +9,9 @@ # ______________________________________________________________________ # Module imports +from pypy.interpreter.baseobjspace import ObjSpace, Wrappable +from pypy.interpreter.typedef import TypeDef, interp_attrproperty, GetSetProperty + import token, compiler import PyTokenizer, PyGrammar, DFAParser @@ -30,7 +33,7 @@ # ______________________________________________________________________ -class STType (object): +class STType (Wrappable): """Class STType """ # ____________________________________________________________ @@ -89,6 +92,9 @@ gen = compiler.pycodegen.ModuleCodeGenerator(compileAST) return gen.getCode() +STType.typedef = TypeDef("parser.st", +) + # ______________________________________________________________________ ASTType = STType @@ -255,21 +261,25 @@ return st.compile(file_name) # ______________________________________________________________________ -def expr (source): +def expr (space, source): """expr Tries to mock the expr() function in the Python parser module, but returns one of those silly tuple/list encoded trees. """ - return _doParse(source, eval_input) + st = _doParse(source, eval_input) + return space.wrap(st) +expr.unwrap_spec = [ObjSpace, str] # ______________________________________________________________________ -def suite (source): +def suite (space, source): """suite Tries to mock the suite() function in the Python parser module, but returns one of those silly tuple/list encoded trees. """ - return _doParse(source, file_input) + st = _doParse(source, file_input) + return space.wrap(st) +suite.unwrap_spec = [ObjSpace, str] # ______________________________________________________________________ From briandorsey at codespeak.net Tue Mar 22 23:51:25 2005 From: briandorsey at codespeak.net (briandorsey at codespeak.net) Date: Tue, 22 Mar 2005 23:51:25 +0100 (MET) Subject: [pypy-svn] r10096 - pypy/dist/pypy/lib/test2 Message-ID: <20050322225125.5F54227B56@code1.codespeak.net> Author: briandorsey Date: Tue Mar 22 23:51:25 2005 New Revision: 10096 Added: pypy/dist/pypy/lib/test2/test_binascii_extra.py Log: A few extra very simple tests for binascii. The std library tests only test round-triping the functions, without actually checking to see what the functions do. Added: pypy/dist/pypy/lib/test2/test_binascii_extra.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/lib/test2/test_binascii_extra.py Tue Mar 22 23:51:25 2005 @@ -0,0 +1,21 @@ + +import unittest +import binascii + +class TestBinAscii(unittest.TestCase): + def test_uu(self): + assert binascii.b2a_uu('1234567') == "',3(S-#4V-P \n" + assert binascii.b2a_uu('123456789012345678901234567890123456789012345') == 'M,3(S-#4V-S at Y,#$R,S0U-C Author: arigo Date: Tue Mar 22 23:51:29 2005 New Revision: 10097 Modified: pypy/dist/pypy/interpreter/function.py pypy/dist/pypy/interpreter/test/test_function.py pypy/dist/pypy/interpreter/typedef.py Log: Method.__eq__(), Method.__ne__(), Code.__ne__(). Modified: pypy/dist/pypy/interpreter/function.py ============================================================================== --- pypy/dist/pypy/interpreter/function.py (original) +++ pypy/dist/pypy/interpreter/function.py Tue Mar 22 23:51:29 2005 @@ -196,6 +196,15 @@ else: return space.get(w_result, w_self) + def descr_method_eq(self, w_other): + space = self.space + other = space.interpclass_w(w_other) + if not isinstance(other, Method): + return space.w_False + if not space.is_w(self.w_instance, other.w_instance): + return space.w_False + return space.eq(self.w_function, other.w_function) + class StaticMethod(Wrappable): """A static method. Note that there is one class staticmethod at app-level too currently; this is only used for __new__ methods.""" Modified: pypy/dist/pypy/interpreter/test/test_function.py ============================================================================== --- pypy/dist/pypy/interpreter/test/test_function.py (original) +++ pypy/dist/pypy/interpreter/test/test_function.py Tue Mar 22 23:51:29 2005 @@ -180,6 +180,19 @@ d = D() assert d.m() == d + def test_method_eq(self): + class C: + def m(): pass + c = C() + assert C.m == C.m + assert c.m == c.m + assert not (C.m == c.m) + assert not (c.m == C.m) + c2 = C() + assert (c.m == c2.m) is False + assert (c.m != c2.m) is True + assert (c.m != c.m) is False + class TestMethod: def setup_method(self, method): def c(self, bar): Modified: pypy/dist/pypy/interpreter/typedef.py ============================================================================== --- pypy/dist/pypy/interpreter/typedef.py (original) +++ pypy/dist/pypy/interpreter/typedef.py Tue Mar 22 23:51:29 2005 @@ -266,6 +266,13 @@ def descr_set_dict(space, obj, w_dict): obj.setdict(w_dict) +def generic_ne(space, w_obj1, w_obj2): + if space.eq_w(w_obj1, w_obj2): + return space.w_False + else: + return space.w_True +descr_generic_ne = interp2app(generic_ne) + # co_xxx interface emulation for built-in code objects def fget_co_varnames(space, w_code): code = space.interpclass_w(w_code) @@ -306,6 +313,7 @@ PyCode.typedef = TypeDef('code', __new__ = interp2app(PyCode.descr_code__new__.im_func), __eq__ = interp2app(PyCode.descr_code__eq__), + __ne__ = descr_generic_ne, co_argcount = interp_attrproperty('co_argcount', cls=PyCode), co_nlocals = interp_attrproperty('co_nlocals', cls=PyCode), co_stacksize = interp_attrproperty('co_stacksize', cls=PyCode), @@ -385,6 +393,8 @@ im_self = interp_attrproperty_w('w_instance', cls=Method), im_class = interp_attrproperty_w('w_class', cls=Method), __getattribute__ = interp2app(Method.descr_method_getattribute), + __eq__ = interp2app(Method.descr_method_eq), + __ne__ = descr_generic_ne, # XXX getattribute/setattribute etc.pp ) From arigo at codespeak.net Wed Mar 23 00:24:21 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Wed, 23 Mar 2005 00:24:21 +0100 (MET) Subject: [pypy-svn] r10098 - pypy/dist/pypy/lib Message-ID: <20050322232421.A642F27B57@code1.codespeak.net> Author: arigo Date: Wed Mar 23 00:24:21 2005 New Revision: 10098 Modified: pypy/dist/pypy/lib/cPickle.py pypy/dist/pypy/lib/cStringIO.py Log: Looks like we need two-line implementations for cStringIO and cPickle instead of one-liners. Modified: pypy/dist/pypy/lib/cPickle.py ============================================================================== --- pypy/dist/pypy/lib/cPickle.py (original) +++ pypy/dist/pypy/lib/cPickle.py Wed Mar 23 00:24:21 2005 @@ -3,3 +3,4 @@ # from pickle import * +from pickle import __doc__ Modified: pypy/dist/pypy/lib/cStringIO.py ============================================================================== --- pypy/dist/pypy/lib/cStringIO.py (original) +++ pypy/dist/pypy/lib/cStringIO.py Wed Mar 23 00:24:21 2005 @@ -3,3 +3,4 @@ # from StringIO import * +from StringIO import __doc__ From arigo at codespeak.net Wed Mar 23 00:27:58 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Wed, 23 Mar 2005 00:27:58 +0100 (MET) Subject: [pypy-svn] r10099 - pypy/dist/pypy/module/sys2 Message-ID: <20050322232758.CA5F127B57@code1.codespeak.net> Author: arigo Date: Wed Mar 23 00:27:58 2005 New Revision: 10099 Modified: pypy/dist/pypy/module/sys2/__init__.py Log: Added sys.__stderr__ Modified: pypy/dist/pypy/module/sys2/__init__.py ============================================================================== --- pypy/dist/pypy/module/sys2/__init__.py (original) +++ pypy/dist/pypy/module/sys2/__init__.py Wed Mar 23 00:27:58 2005 @@ -24,6 +24,7 @@ 'stdout' : 'space.wrap(sys.stdout)', '__stdout__' : 'space.wrap(sys.stdout)', 'stderr' : 'space.wrap(sys.stderr)', + '__stderr__' : 'space.wrap(sys.stderr)', 'pypy_objspaceclass' : 'space.wrap(repr(space))', 'path' : 'state.get(space).w_path', From tismer at codespeak.net Wed Mar 23 00:29:17 2005 From: tismer at codespeak.net (tismer at codespeak.net) Date: Wed, 23 Mar 2005 00:29:17 +0100 (MET) Subject: [pypy-svn] r10100 - pypy/dist/pypy/lib Message-ID: <20050322232917.25D9127B58@code1.codespeak.net> Author: tismer Date: Wed Mar 23 00:29:16 2005 New Revision: 10100 Modified: pypy/dist/pypy/lib/datetime.py Log: passes its test now. The problems were not PyPy-related, but this file really didn't implement certain things identically to the C version. It overdid by creating derived classes for __add__, for instance. Modified: pypy/dist/pypy/lib/datetime.py ============================================================================== --- pypy/dist/pypy/lib/datetime.py (original) +++ pypy/dist/pypy/lib/datetime.py Wed Mar 23 00:29:16 2005 @@ -577,9 +577,11 @@ def __add__(self, other): if isinstance(other, timedelta): - return self.__class__(self.__days + other.__days, - self.__seconds + other.__seconds, - self.__microseconds + other.__microseconds) + # for CPython compatibility, we cannot use + # our __class__ here, but need a real timedelta + return timedelta(self.__days + other.__days, + self.__seconds + other.__seconds, + self.__microseconds + other.__microseconds) return NotImplemented __radd__ = __add__ @@ -595,9 +597,11 @@ return NotImplemented def __neg__(self): - return self.__class__(-self.__days, - -self.__seconds, - -self.__microseconds) + # for CPython compatibility, we cannot use + # our __class__ here, but need a real timedelta + return timedelta(-self.__days, + -self.__seconds, + -self.__microseconds) def __pos__(self): return self @@ -610,9 +614,11 @@ def __mul__(self, other): if isinstance(other, (int, long)): - return self.__class__(self.__days * other, - self.__seconds * other, - self.__microseconds * other) + # for CPython compatibility, we cannot use + # our __class__ here, but need a real timedelta + return timedelta(self.__days * other, + self.__seconds * other, + self.__microseconds * other) return NotImplemented __rmul__ = __mul__ @@ -621,7 +627,7 @@ if isinstance(other, (int, long)): usec = ((self.__days * (24*3600L) + self.__seconds) * 1000000 + self.__microseconds) - return self.__class__(0, 0, usec // other) + return timedelta(0, 0, usec // other) return NotImplemented __floordiv__ = __div__ @@ -903,7 +909,7 @@ self.__month, self.__day + other.days) self._checkOverflow(t.year) - result = self.__class__(t.year, t.month, t.day) + result = date(t.year, t.month, t.day) return result raise TypeError # XXX Should be 'return NotImplemented', but there's a bug in 2.2... @@ -1344,7 +1350,7 @@ self._tzinfo = state[1] def __reduce__(self): - return (self.__class__, self.__getstate()) + return (time, self.__getstate()) _time_class = time # so functions w/ args named "time" can get at the class @@ -1714,7 +1720,7 @@ self.__second + other.seconds, self.__microsecond + other.microseconds) self._checkOverflow(t.year) - result = self.__class__(t.year, t.month, t.day, + result = datetime(t.year, t.month, t.day, t.hour, t.minute, t.second, t.microsecond, tzinfo=self._tzinfo) return result From hpk at codespeak.net Wed Mar 23 01:15:10 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Wed, 23 Mar 2005 01:15:10 +0100 (MET) Subject: [pypy-svn] r10101 - pypy/dist/pypy/module/parser Message-ID: <20050323001510.C421D27B57@code1.codespeak.net> Author: hpk Date: Wed Mar 23 01:15:10 2005 New Revision: 10101 Modified: pypy/dist/pypy/module/parser/pyparser.py Log: - STType now has a space - STType.compile is exposed at applevel, uses the interplevel parser-implementations but the applevel compiler package to produce code objects Modified: pypy/dist/pypy/module/parser/pyparser.py ============================================================================== --- pypy/dist/pypy/module/parser/pyparser.py (original) +++ pypy/dist/pypy/module/parser/pyparser.py Wed Mar 23 01:15:10 2005 @@ -10,7 +10,11 @@ # Module imports from pypy.interpreter.baseobjspace import ObjSpace, Wrappable -from pypy.interpreter.typedef import TypeDef, interp_attrproperty, GetSetProperty +from pypy.interpreter.gateway import interp2app, applevel +from pypy.interpreter.error import OperationError +from pypy.interpreter.typedef import TypeDef +from pypy.interpreter.typedef import interp_attrproperty, GetSetProperty +from pypy.interpreter.pycode import PyCode import token, compiler import PyTokenizer, PyGrammar, DFAParser @@ -29,7 +33,6 @@ """Class ParserError Exception class for parser errors (I assume). """ - pass # ______________________________________________________________________ @@ -37,7 +40,7 @@ """Class STType """ # ____________________________________________________________ - def __init__ (self, tup = None): + def __init__ (self, space, tup = None): """STType.__init__() Wrapper for parse tree data returned by DFAParser. @@ -45,6 +48,7 @@ is not currently checked. (XXX - should this be checked ala sequence2st()?) """ + self.space = space self.tup = tup # ____________________________________________________________ @@ -80,19 +84,41 @@ return self.tup[0][0] == file_input # ____________________________________________________________ - def compile (self, filename = None): + def descr_compile (self, w_filename = ""): """STType.compile() """ + space = self.space + tup = self.totuple(line_info=1) + w_tup = space.wrap(tup) + w_compileAST = mycompile(space, w_tup, w_filename) + if self.isexpr(): + return exprcompile(space, w_compileAST) + else: + return modcompile(space, w_compileAST) + +app = applevel(""" + import compiler + def mycompile(tup, filename): transformer = compiler.transformer.Transformer() - compileAST = transformer.compile_node(self.totuple(1)) - compiler.misc.set_filename("", compileAST) - if self.isexpr(): - gen = compiler.pycodegen.ExpressionCodeGenerator(compileAST) - else: - gen = compiler.pycodegen.ModuleCodeGenerator(compileAST) + compileAST = transformer.compile_node(tup) + compiler.misc.set_filename(filename, compileAST) + return compileAST + + def exprcompile(compileAST): + gen = compiler.pycodegen.ExpressionCodeGenerator(compileAST) return gen.getCode() + def modcompile(compileAST): + gen = compiler.pycodegen.ModuleCodeGenerator(compileAST) + return gen.getCode() +""") + +mycompile = app.interphook("mycompile") +exprcompile = app.interphook("exprcompile") +modcompile = app.interphook("modcompile") + STType.typedef = TypeDef("parser.st", + compile = interp2app(STType.descr_compile), ) # ______________________________________________________________________ @@ -170,7 +196,7 @@ tup = _seq2st(seqObj)[0] if tup[0][0] not in (file_input, eval_input): raise ParserError("parse tree does not use a valid start symbol") - return STType(tup) + return STType(space, tup) sequence2ast = sequence2st tuple2ast = sequence2st @@ -266,7 +292,7 @@ Tries to mock the expr() function in the Python parser module, but returns one of those silly tuple/list encoded trees. """ - st = _doParse(source, eval_input) + st = _doParse(space, source, eval_input) return space.wrap(st) expr.unwrap_spec = [ObjSpace, str] @@ -277,21 +303,26 @@ Tries to mock the suite() function in the Python parser module, but returns one of those silly tuple/list encoded trees. """ - st = _doParse(source, file_input) + st = _doParse(space, source, file_input) return space.wrap(st) suite.unwrap_spec = [ObjSpace, str] # ______________________________________________________________________ -def _doParse (source, start): +def _doParse (space, source, start): """_doParse() Ignore the function behind the curtain! Even if it is kinda like the CPython PyParser_SimpleParseString() (I think.) """ global pygrammar - tokenizer = PyTokenizer.PyTokenizer() - tokenizer.tokenizeString(source) - return STType(DFAParser.parsetok(tokenizer, pygrammar, start)) + try: + tokenizer = PyTokenizer.PyTokenizer() + tokenizer.tokenizeString(source) + return STType(space, DFAParser.parsetok(tokenizer, pygrammar, start)) + except SyntaxError: + raise OperationError(space.w_SyntaxError) + except ParserError: + raise OperationError(space.w_RuntimeError) # ______________________________________________________________________ From hpk at codespeak.net Wed Mar 23 01:38:40 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Wed, 23 Mar 2005 01:38:40 +0100 (MET) Subject: [pypy-svn] r10102 - pypy/dist/pypy/module/parser Message-ID: <20050323003840.57BAD27B57@code1.codespeak.net> Author: hpk Date: Wed Mar 23 01:38:40 2005 New Revision: 10102 Modified: pypy/dist/pypy/module/parser/TokenUtils.py Log: turn off debugging Modified: pypy/dist/pypy/module/parser/TokenUtils.py ============================================================================== --- pypy/dist/pypy/module/parser/TokenUtils.py (original) +++ pypy/dist/pypy/module/parser/TokenUtils.py Wed Mar 23 01:38:40 2005 @@ -18,7 +18,7 @@ # ______________________________________________________________________ -__DEBUG__ = True +__DEBUG__ = False # ______________________________________________________________________ From hpk at codespeak.net Wed Mar 23 01:41:51 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Wed, 23 Mar 2005 01:41:51 +0100 (MET) Subject: [pypy-svn] r10103 - in pypy/dist/pypy: interpreter module/parser module/sys2 Message-ID: <20050323004151.B735827B57@code1.codespeak.net> Author: hpk Date: Wed Mar 23 01:41:51 2005 New Revision: 10103 Modified: pypy/dist/pypy/interpreter/baseobjspace.py pypy/dist/pypy/module/parser/__init__.py pypy/dist/pypy/module/parser/pyparser.py pypy/dist/pypy/module/sys2/state.py Log: - make jonathan's parser replace the cpython parser module - passes regrtests (but they don't really test that much) - various fixes, especially regarding exception handling parser/pyparser.py is slightly messy (but it works and is fast) (Jonathan and holger) Modified: pypy/dist/pypy/interpreter/baseobjspace.py ============================================================================== --- pypy/dist/pypy/interpreter/baseobjspace.py (original) +++ pypy/dist/pypy/interpreter/baseobjspace.py Wed Mar 23 01:41:51 2005 @@ -55,6 +55,17 @@ def __repr__(self): return self.__class__.__name__ + def setbuiltinmodule(self, name, importname=None): + """ load a lazy pypy/module and put it into sys.modules""" + if importname is None: + importname = name + Module = __import__("pypy.module.%s" % importname, + None, None, ["Module"]).Module + w_name = self.wrap(name) + w_mod = self.wrap(Module(self, w_name)) + w_modules = self.sys.get('modules') + self.setitem(w_modules, w_name, w_mod) + def make_builtins(self): "NOT_RPYTHON: only for initializing the space." @@ -71,6 +82,8 @@ self.setitem(w_modules, w_name, w_builtin) self.setitem(self.builtin.w_dict, self.wrap('__builtins__'), w_builtin) + self.setbuiltinmodule('parser') + # initialize with "bootstrap types" from objspace (e.g. w_None) for name, value in self.__dict__.items(): if name.startswith('w_') and not name.endswith('Type'): Modified: pypy/dist/pypy/module/parser/__init__.py ============================================================================== --- pypy/dist/pypy/module/parser/__init__.py (original) +++ pypy/dist/pypy/module/parser/__init__.py Wed Mar 23 01:41:51 2005 @@ -14,26 +14,23 @@ '__doc__' : '(space.wrap("parser module"))', 'suite' : 'pyparser.suite', + 'expr' : 'pyparser.expr', 'STType' : 'pyparser.STType', 'ASTType' : 'pyparser.STType', - 'eval_input' : 'pyparser.eval_input', - 'file_input' : 'pyparser.file_input', - 'compileast' : 'pyparser.compileast', - 'st2tuple' : 'pyparser.st2tuple', - 'st2list' : 'pyparser.st2list', - 'issuite' : 'pyparser.issuite', - 'ast2tuple' : 'pyparser.ast2tuple', - 'tuple2st' : 'pyparser.tuple2st', - 'isexpr' : 'pyparser.isexpr', - 'expr' : 'pyparser.expr', - 'ast2list' : 'pyparser.ast2list', - 'sequence2ast' : 'pyparser.sequence2ast', - 'tuple2ast' : 'pyparser.tuple2ast', 'sequence2st' : 'pyparser.sequence2st', - '_pickler' : 'pyparser._pickler', - 'compilest' : 'pyparser.compilest', + #'eval_input' : 'pyparser.eval_input', + #'file_input' : 'pyparser.file_input', + #'compileast' : 'pyparser.compileast', + #'st2tuple' : 'pyparser.st2tuple', + #'st2list' : 'pyparser.st2list', + #'issuite' : 'pyparser.issuite', + #'ast2tuple' : 'pyparser.ast2tuple', + #'tuple2st' : 'pyparser.tuple2st', + #'isexpr' : 'pyparser.isexpr', + #'ast2list' : 'pyparser.ast2list', + #'sequence2ast' : 'pyparser.sequence2ast', + #'tuple2ast' : 'pyparser.tuple2ast', + #'_pickler' : 'pyparser._pickler', + #'compilest' : 'pyparser.compilest', } - appleveldefs = { - - } Modified: pypy/dist/pypy/module/parser/pyparser.py ============================================================================== --- pypy/dist/pypy/module/parser/pyparser.py (original) +++ pypy/dist/pypy/module/parser/pyparser.py Wed Mar 23 01:41:51 2005 @@ -9,7 +9,7 @@ # ______________________________________________________________________ # Module imports -from pypy.interpreter.baseobjspace import ObjSpace, Wrappable +from pypy.interpreter.baseobjspace import ObjSpace, Wrappable, W_Root from pypy.interpreter.gateway import interp2app, applevel from pypy.interpreter.error import OperationError from pypy.interpreter.typedef import TypeDef @@ -27,10 +27,10 @@ pygrammar = DFAParser.addAccelerators(PyGrammar.grammarObj) # ______________________________________________________________________ -# ParserError exception +# InternalParserError exception -class ParserError (Exception): - """Class ParserError +class InternalParserError (Exception): + """Class InternalParserError Exception class for parser errors (I assume). """ @@ -58,6 +58,11 @@ """ return _st2tuple(self.tup, line_info) + def descr_totuple(self, line_info = 0): + return self.space.wrap(self.totuple(line_info)) + + descr_totuple.unwrap_spec=['self', int] + # ____________________________________________________________ def tolist (self, line_info = 0): """STType.tolist() @@ -119,6 +124,7 @@ STType.typedef = TypeDef("parser.st", compile = interp2app(STType.descr_compile), + totuple = interp2app(STType.descr_totuple), ) # ______________________________________________________________________ @@ -144,12 +150,12 @@ next_state = states[arc_state] break if next_state == None: - raise ParserError("symbol %d should be in %s" % + raise InternalParserError("symbol %d should be in %s" % (ilabel, str(arcs))) else: crnt_state = next_state if crnt_state[2] != 1: - raise ParserError("incomplete sequence of children (ended with %s)" % + raise InternalParserError("incomplete sequence of children (ended with %s)" % str(child[0])) # ______________________________________________________________________ @@ -184,19 +190,23 @@ node = ((symbol_no, seqobj[1], 0), []) line_no = 0 else: - raise ParserError("terminal nodes must have 2 or 3 entries") + raise InternalParserError("terminal nodes must have 2 or 3 entries") return node, line_no # ______________________________________________________________________ -def sequence2st (seqObj): +def sequence2st (space, w_seqObj): """sequence2st() Do some basic checking on the input sequence and wrap in a STType. """ - tup = _seq2st(seqObj)[0] - if tup[0][0] not in (file_input, eval_input): - raise ParserError("parse tree does not use a valid start symbol") - return STType(space, tup) + try: + seqObj = space.unwrap(w_seqObj) + tup = _seq2st(seqObj)[0] + if tup[0][0] not in (file_input, eval_input): + raise InternalParserError("parse tree does not use a valid start symbol") + return STType(space, tup) + except InternalParserError, e: + reraise(space, e) sequence2ast = sequence2st tuple2ast = sequence2st @@ -321,8 +331,16 @@ return STType(space, DFAParser.parsetok(tokenizer, pygrammar, start)) except SyntaxError: raise OperationError(space.w_SyntaxError) - except ParserError: - raise OperationError(space.w_RuntimeError) + except InternalParserError, e: + reraise(space, e) + +def reraise(space, e): + w_ParserError = space.sys.getmodule('parser').get('ParserError') + if e.args: + w_msg = space.wrap(e.args[0]) + else: + w_msg = space.wrap("unknown") + raise OperationError(w_ParserError, w_msg) # ______________________________________________________________________ Modified: pypy/dist/pypy/module/sys2/state.py ============================================================================== --- pypy/dist/pypy/module/sys2/state.py (original) +++ pypy/dist/pypy/module/sys2/state.py Wed Mar 23 01:41:51 2005 @@ -27,7 +27,8 @@ for fn in ['posix', 'nt', 'os2', 'mac', 'ce', 'riscos', 'math', '_codecs', 'array', 'select', '_random', '_sre', 'time', '_socket', 'errno', - 'parser']: + #'parser' + ]: if fn not in builtin_modules: try: builtin_modules[fn] = hack_cpython_module(fn) From hpk at codespeak.net Wed Mar 23 01:43:47 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Wed, 23 Mar 2005 01:43:47 +0100 (MET) Subject: [pypy-svn] r10104 - pypy/dist/lib-python-2.3.4/test Message-ID: <20050323004347.19EC927B57@code1.codespeak.net> Author: hpk Date: Wed Mar 23 01:43:46 2005 New Revision: 10104 Modified: pypy/dist/lib-python-2.3.4/test/conftest.py Log: add test_parser.py to the list of passing tests Modified: pypy/dist/lib-python-2.3.4/test/conftest.py ============================================================================== --- pypy/dist/lib-python-2.3.4/test/conftest.py (original) +++ pypy/dist/lib-python-2.3.4/test/conftest.py Wed Mar 23 01:43:46 2005 @@ -45,6 +45,7 @@ 'test_htmlparser.py', 'test_isinstance.py', 'test_operator.py', +'test_parser.py', 'test_pprint.py', 'test_profilehooks.py', 'test_sgmllib.py', From sanxiyn at codespeak.net Wed Mar 23 02:04:05 2005 From: sanxiyn at codespeak.net (sanxiyn at codespeak.net) Date: Wed, 23 Mar 2005 02:04:05 +0100 (MET) Subject: [pypy-svn] r10105 - pypy/dist/pypy/tool Message-ID: <20050323010405.3FF4F27B57@code1.codespeak.net> Author: sanxiyn Date: Wed Mar 23 02:04:05 2005 New Revision: 10105 Modified: pypy/dist/pypy/tool/option.py Log: fix py.py -h properly (cf. r10058) Modified: pypy/dist/pypy/tool/option.py ============================================================================== --- pypy/dist/pypy/tool/option.py (original) +++ pypy/dist/pypy/tool/option.py Wed Mar 23 02:04:05 2005 @@ -18,8 +18,8 @@ parser.values.spaces.append(value) options.append(make_option( - '-o', '--objspace', action="callback", - callback=objspace_callback, type="string", dest="objspacename", + '-o', '--objspace', action="callback", metavar='NAME', + callback=objspace_callback, type="string", help="object space to run PyPy on.")) options.append(make_option( @@ -32,7 +32,6 @@ '-H', action="callback", callback=run_tb_server, help="use web browser for traceback info")) - return options From hpk at codespeak.net Wed Mar 23 02:04:30 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Wed, 23 Mar 2005 02:04:30 +0100 (MET) Subject: [pypy-svn] r10106 - pypy/dist/pypy/module/parser Message-ID: <20050323010430.E90C027B57@code1.codespeak.net> Author: hpk Date: Wed Mar 23 02:04:30 2005 New Revision: 10106 Added: pypy/dist/pypy/module/parser/app_class.py Modified: pypy/dist/pypy/module/parser/__init__.py Log: add a missing file (at the right place) Modified: pypy/dist/pypy/module/parser/__init__.py ============================================================================== --- pypy/dist/pypy/module/parser/__init__.py (original) +++ pypy/dist/pypy/module/parser/__init__.py Wed Mar 23 02:04:30 2005 @@ -6,7 +6,7 @@ """The builtin parser module. """ appleveldefs = { - 'ParserError' : 'classes.ParserError', + 'ParserError' : 'app_class.ParserError', } interpleveldefs = { @@ -16,7 +16,7 @@ 'suite' : 'pyparser.suite', 'expr' : 'pyparser.expr', 'STType' : 'pyparser.STType', - 'ASTType' : 'pyparser.STType', +# 'ASTType' : 'pyparser.STType', 'sequence2st' : 'pyparser.sequence2st', #'eval_input' : 'pyparser.eval_input', #'file_input' : 'pyparser.file_input', Added: pypy/dist/pypy/module/parser/app_class.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/module/parser/app_class.py Wed Mar 23 02:04:30 2005 @@ -0,0 +1,8 @@ + +# ______________________________________________________________________ +# ParserError exception + +class ParserError (Exception): + """Class ParserError + Exception class for parser errors (I assume). + """ From hpk at codespeak.net Wed Mar 23 02:07:01 2005 From: hpk at codespeak.net (hpk at codespeak.net) Date: Wed, 23 Mar 2005 02:07:01 +0100 (MET) Subject: [pypy-svn] r10107 - pypy/dist/pypy/module/parser Message-ID: <20050323010701.8B2C327B57@code1.codespeak.net> Author: hpk Date: Wed Mar 23 02:07:01 2005 New Revision: 10107 Modified: pypy/dist/pypy/module/parser/__init__.py Log: don't expose STType for now Modified: pypy/dist/pypy/module/parser/__init__.py ============================================================================== --- pypy/dist/pypy/module/parser/__init__.py (original) +++ pypy/dist/pypy/module/parser/__init__.py Wed Mar 23 02:07:01 2005 @@ -15,7 +15,7 @@ 'suite' : 'pyparser.suite', 'expr' : 'pyparser.expr', - 'STType' : 'pyparser.STType', +# 'STType' : 'pyparser.STType', # 'ASTType' : 'pyparser.STType', 'sequence2st' : 'pyparser.sequence2st', #'eval_input' : 'pyparser.eval_input', From tismer at codespeak.net Wed Mar 23 03:19:36 2005 From: tismer at codespeak.net (tismer at codespeak.net) Date: Wed, 23 Mar 2005 03:19:36 +0100 (MET) Subject: [pypy-svn] r10108 - pypy/dist/pypy/module/sys2 Message-ID: <20050323021936.DCEFA27B5B@code1.codespeak.net> Author: tismer Date: Wed Mar 23 03:19:35 2005 New Revision: 10108 Modified: pypy/dist/pypy/module/sys2/state.py Log: had do re-fake binascii. Reason: 16 modules break directly if binascii is not completely working. Please remove it from the list only on your machine, finalize binascii, and then check your change to state.py in. Modified: pypy/dist/pypy/module/sys2/state.py ============================================================================== --- pypy/dist/pypy/module/sys2/state.py (original) +++ pypy/dist/pypy/module/sys2/state.py Wed Mar 23 03:19:35 2005 @@ -27,6 +27,7 @@ for fn in ['posix', 'nt', 'os2', 'mac', 'ce', 'riscos', 'math', '_codecs', 'array', 'select', '_random', '_sre', 'time', '_socket', 'errno', + 'binascii', #'parser' ]: if fn not in builtin_modules: From tismer at codespeak.net Wed Mar 23 03:37:34 2005 From: tismer at codespeak.net (tismer at codespeak.net) Date: Wed, 23 Mar 2005 03:37:34 +0100 (MET) Subject: [pypy-svn] r10109 - pypy/dist/pypy/lib/test2 Message-ID: <20050323023734.915CB27B58@code1.codespeak.net> Author: tismer Date: Wed Mar 23 03:37:34 2005 New Revision: 10109 Modified: pypy/dist/pypy/lib/test2/conftest.py Log: pseudo-fixed small bug, but stilldoesn't work Modified: pypy/dist/pypy/lib/test2/conftest.py ============================================================================== --- pypy/dist/pypy/lib/test2/conftest.py (original) +++ pypy/dist/pypy/lib/test2/conftest.py Wed Mar 23 03:37:34 2005 @@ -52,7 +52,7 @@ def _iter(self): name = self.fspath.purebasename mod = make_cpy_module(name, self.fspath) - tlist = conftest.app_list_testmethods(mod, self.TestCase) + tlist = conftest.app_list_testmethods(mod, self.TestCase, []) for (setup, teardown, methods) in tlist: for name, method in methods: yield CpyTestCaseMethod(self.fspath, name, method, From tismer at codespeak.net Wed Mar 23 03:38:04 2005 From: tismer at codespeak.net (tismer at codespeak.net) Date: Wed, 23 Mar 2005 03:38:04 +0100 (MET) Subject: [pypy-svn] r10110 - pypy/dist/pypy/lib/test2 Message-ID: <20050323023804.D3F9827B58@code1.codespeak.net> Author: tismer Date: Wed Mar 23 03:38:04 2005 New Revision: 10110 Removed: pypy/dist/pypy/lib/test2/test_datetime.py Log: the standard test works completely now,so we get rid of this Deleted: /pypy/dist/pypy/lib/test2/test_datetime.py ============================================================================== --- /pypy/dist/pypy/lib/test2/test_datetime.py Wed Mar 23 03:38:04 2005 +++ (empty file) @@ -1,2912 +0,0 @@ -"""Test date/time type. - -This is a py.test conversion of the test cases in the CVS sandbox of -CPython. -""" -import autopath - -import sys -import pickle -import cPickle - -''' -from pypy.appspace.datetime import MINYEAR, MAXYEAR -from pypy.appspace.datetime import timedelta -from pypy.appspace.datetime import tzinfo -from pypy.appspace.datetime import time -from pypy.appspace.datetime import date, datetime -''' - -from datetime import MINYEAR, MAXYEAR -from datetime import timedelta -from datetime import tzinfo -from datetime import time -from datetime import date, datetime - - -# Before Python 2.3, proto=2 was taken as a synonym for proto=1. -pickle_choices = [(pickler, unpickler, proto) - for pickler in pickle, cPickle - for unpickler in pickle, cPickle - for proto in range(3)] -assert len(pickle_choices) == 2*2*3 - -# An arbitrary collection of objects of non-datetime types, for testing -# mixed-type comparisons. -OTHERSTUFF = (10, 10L, 34.5, "abc", {}, [], ()) - - -############################################################################# -# module tests - -class TestModule(object): - - def test_constants(self): - from pypy.appspace import datetime - assert datetime.MINYEAR == 1 - assert datetime.MAXYEAR == 9999 - -############################################################################# -# tzinfo tests - -class FixedOffset(tzinfo): - def __init__(self, offset, name, dstoffset=42): - if isinstance(offset, int): - offset = timedelta(minutes=offset) - if isinstance(dstoffset, int): - dstoffset = timedelta(minutes=dstoffset) - self.__offset = offset - self.__name = name - self.__dstoffset = dstoffset - def __repr__(self): - return self.__name.lower() - def utcoffset(self, dt): - return self.__offset - def tzname(self, dt): - return self.__name - def dst(self, dt): - return self.__dstoffset - -class PicklableFixedOffset(FixedOffset): - def __init__(self, offset=None, name=None, dstoffset=None): - FixedOffset.__init__(self, offset, name, dstoffset) - -class TestTZInfo(object): - - def test_non_abstractness(self): - # In order to allow subclasses to get pickled, the C implementation - # wasn't able to get away with having __init__ raise - # NotImplementedError. - useless = tzinfo() - dt = datetime.max - raises(NotImplementedError, useless.tzname, dt) - raises(NotImplementedError, useless.utcoffset, dt) - raises(NotImplementedError, useless.dst, dt) - - def test_subclass_must_override(self): - class NotEnough(tzinfo): - def __init__(self, offset, name): - self.__offset = offset - self.__name = name - assert issubclass(NotEnough, tzinfo) - ne = NotEnough(3, "NotByALongShot") - assert isinstance(ne, tzinfo) - - dt = datetime.now() - raises(NotImplementedError, ne.tzname, dt) - raises(NotImplementedError, ne.utcoffset, dt) - raises(NotImplementedError, ne.dst, dt) - - def test_normal(self): - fo = FixedOffset(3, "Three") - assert isinstance(fo, tzinfo) - for dt in datetime.now(), None: - assert fo.utcoffset(dt) == timedelta(minutes=3) - assert fo.tzname(dt) == "Three" - assert fo.dst(dt) == timedelta(minutes=42) - - def test_pickling_base(self): - # There's no point to pickling tzinfo objects on their own (they - # carry no data), but they need to be picklable anyway else - # concrete subclasses can't be pickled. - orig = tzinfo.__new__(tzinfo) - assert type(orig) is tzinfo - for pickler, unpickler, proto in pickle_choices: - green = pickler.dumps(orig, proto) - derived = unpickler.loads(green) - assert type(derived) is tzinfo - - def test_pickling_subclass(self): - # Make sure we can pickle/unpickle an instance of a subclass. - offset = timedelta(minutes=-300) - orig = PicklableFixedOffset(offset, 'cookie') - assert isinstance(orig, tzinfo) - assert type(orig) is PicklableFixedOffset - assert orig.utcoffset(None) == offset - assert orig.tzname(None) == 'cookie' - for pickler, unpickler, proto in pickle_choices: - green = pickler.dumps(orig, proto) - derived = unpickler.loads(green) - assert isinstance(derived, tzinfo) - assert type(derived) is PicklableFixedOffset - assert derived.utcoffset(None) == offset - assert derived.tzname(None) == 'cookie' - -############################################################################# -# Base clase for testing a particular aspect of timedelta, time, date and -# datetime comparisons. - -class HarmlessMixedComparison(object): - # Test that __eq__ and __ne__ don't complain for mixed-type comparisons. - - # Subclasses must define 'theclass', and theclass(1, 1, 1) must be a - # legit constructor. - - def test_harmless_mixed_comparison(self): - me = self.theclass(1, 1, 1) - - assert not me == () - assert me != () - assert not () == me - assert () != me - - assert me in [1, 20L, [], me] - assert not me not in [1, 20L, [], me] - - assert [] in [me, 1, 20L, []] - assert not [] not in [me, 1, 20L, []] - - def test_harmful_mixed_comparison(self): - me = self.theclass(1, 1, 1) - - raises(TypeError, lambda: me < ()) - raises(TypeError, lambda: me <= ()) - raises(TypeError, lambda: me > ()) - raises(TypeError, lambda: me >= ()) - - raises(TypeError, lambda: () < me) - raises(TypeError, lambda: () <= me) - raises(TypeError, lambda: () > me) - raises(TypeError, lambda: () >= me) - - raises(TypeError, cmp, (), me) - raises(TypeError, cmp, me, ()) - -############################################################################# -# timedelta tests - -class TestTimeDelta(HarmlessMixedComparison): - - theclass = timedelta - - def test_constructor(self): - td = timedelta - - # Check keyword args to constructor - assert td() == td(weeks=0, days=0, hours=0, minutes=0, seconds=0, - milliseconds=0, microseconds=0) - assert td(1) == td(days=1) - assert td(0, 1) == td(seconds=1) - assert td(0, 0, 1) == td(microseconds=1) - assert td(weeks=1) == td(days=7) - assert td(days=1) == td(hours=24) - assert td(hours=1) == td(minutes=60) - assert td(minutes=1) == td(seconds=60) - assert td(seconds=1) == td(milliseconds=1000) - assert td(milliseconds=1) == td(microseconds=1000) - - # Check float args to constructor - assert td(weeks=1.0/7) == td(days=1) - assert td(days=1.0/24) == td(hours=1) - assert td(hours=1.0/60) == td(minutes=1) - assert td(minutes=1.0/60) == td(seconds=1) - assert td(seconds=0.001) == td(milliseconds=1) - assert td(milliseconds=0.001) == td(microseconds=1) - - def test_computations(self): - td = timedelta - - a = td(7) # One week - b = td(0, 60) # One minute - c = td(0, 0, 1000) # One millisecond - assert a+b+c == td(7, 60, 1000) - assert a-b == td(6, 24*3600 - 60) - assert -a == td(-7) - assert +a == td(7) - assert -b == td(-1, 24*3600 - 60) - assert -c == td(-1, 24*3600 - 1, 999000) - assert abs(a) == a - assert abs(-a) == a - assert td(6, 24*3600) == a - assert td(0, 0, 60*1000000) == b - assert a*10 == td(70) - assert a*10 == 10*a - assert a*10L == 10*a - assert b*10 == td(0, 600) - assert 10*b == td(0, 600) - assert b*10L == td(0, 600) - assert c*10 == td(0, 0, 10000) - assert 10*c == td(0, 0, 10000) - assert c*10L == td(0, 0, 10000) - assert a*-1 == -a - assert b*-2 == -b-b - assert c*-2 == -c+-c - assert b*(60*24) == (b*60)*24 - assert b*(60*24) == (60*b)*24 - assert c*1000 == td(0, 1) - assert 1000*c == td(0, 1) - assert a//7 == td(1) - assert b//10 == td(0, 6) - assert c//1000 == td(0, 0, 1) - assert a//10 == td(0, 7*24*360) - assert a//3600000 == td(0, 0, 7*24*1000) - - def test_disallowed_computations(self): - a = timedelta(42) - - # Add/sub ints, longs, floats should be illegal - for i in 1, 1L, 1.0: - raises(TypeError, lambda: a+i) - raises(TypeError, lambda: a-i) - raises(TypeError, lambda: i+a) - raises(TypeError, lambda: i-a) - - # Mul/div by float isn't supported. - x = 2.3 - raises(TypeError, lambda: a*x) - raises(TypeError, lambda: x*a) - raises(TypeError, lambda: a/x) - raises(TypeError, lambda: x/a) - raises(TypeError, lambda: a // x) - raises(TypeError, lambda: x // a) - - # Divison of int by timedelta doesn't make sense. - # Division by zero doesn't make sense. - for zero in 0, 0L: - raises(TypeError, lambda: zero // a) - raises(ZeroDivisionError, lambda: a // zero) - - def test_basic_attributes(self): - days, seconds, us = 1, 7, 31 - td = timedelta(days, seconds, us) - assert td.days == days - assert td.seconds == seconds - assert td.microseconds == us - - def test_carries(self): - t1 = timedelta(days=100, - weeks=-7, - hours=-24*(100-49), - minutes=-3, - seconds=12, - microseconds=(3*60 - 12) * 1e6 + 1) - t2 = timedelta(microseconds=1) - assert t1 == t2 - - def test_hash_equality(self): - t1 = timedelta(days=100, - weeks=-7, - hours=-24*(100-49), - minutes=-3, - seconds=12, - microseconds=(3*60 - 12) * 1000000) - t2 = timedelta() - assert hash(t1) == hash(t2) - - t1 += timedelta(weeks=7) - t2 += timedelta(days=7*7) - assert t1 == t2 - assert hash(t1) == hash(t2) - - d = {t1: 1} - d[t2] = 2 - assert len(d) == 1 - assert d[t1] == 2 - - def test_pickling(self): - args = 12, 34, 56 - orig = timedelta(*args) - for pickler, unpickler, proto in pickle_choices: - green = pickler.dumps(orig, proto) - derived = unpickler.loads(green) - assert orig == derived - - def test_compare(self): - t1 = timedelta(2, 3, 4) - t2 = timedelta(2, 3, 4) - assert t1 == t2 - assert t1 <= t2 - assert t1 >= t2 - assert not t1 != t2 - assert not t1 < t2 - assert not t1 > t2 - assert cmp(t1, t2) == 0 - assert cmp(t2, t1) == 0 - - for args in (3, 3, 3), (2, 4, 4), (2, 3, 5): - t2 = timedelta(*args) # this is larger than t1 - assert t1 < t2 - assert t2 > t1 - assert t1 <= t2 - assert t2 >= t1 - assert t1 != t2 - assert t2 != t1 - assert not t1 == t2 - assert not t2 == t1 - assert not t1 > t2 - assert not t2 < t1 - assert not t1 >= t2 - assert not t2 <= t1 - assert cmp(t1, t2) == -1 - assert cmp(t2, t1) == 1 - - for badarg in OTHERSTUFF: - assert (t1 == badarg) == False - assert (t1 != badarg) == True - assert (badarg == t1) == False - assert (badarg != t1) == True - - raises(TypeError, lambda: t1 <= badarg) - raises(TypeError, lambda: t1 < badarg) - raises(TypeError, lambda: t1 > badarg) - raises(TypeError, lambda: t1 >= badarg) - raises(TypeError, lambda: badarg <= t1) - raises(TypeError, lambda: badarg < t1) - raises(TypeError, lambda: badarg > t1) - raises(TypeError, lambda: badarg >= t1) - - def test_str(self): - td = timedelta - - assert str(td(1)) == "1 day, 0:00:00" - assert str(td(-1)) == "-1 day, 0:00:00" - assert str(td(2)) == "2 days, 0:00:00" - assert str(td(-2)) == "-2 days, 0:00:00" - - assert str(td(hours=12, minutes=58, seconds=59)) == "12:58:59" - assert str(td(hours=2, minutes=3, seconds=4)) == "2:03:04" - assert str(td(weeks=-30, hours=23, minutes=12, seconds=34)) == ( - "-210 days, 23:12:34") - - assert str(td(milliseconds=1)) == "0:00:00.001000" - assert str(td(microseconds=3)) == "0:00:00.000003" - - assert str(td(days=999999999, hours=23, minutes=59, seconds=59, - microseconds=999999)) == ( - "999999999 days, 23:59:59.999999") - - def test_roundtrip(self): - for td in (timedelta(days=999999999, hours=23, minutes=59, - seconds=59, microseconds=999999), - timedelta(days=-999999999), - timedelta(days=1, seconds=2, microseconds=3)): - - # Verify td -> string -> td identity. - s = repr(td) - assert s.startswith('datetime.') - s = s[9:] - td2 = eval(s) - assert td == td2 - - # Verify identity via reconstructing from pieces. - td2 = timedelta(td.days, td.seconds, td.microseconds) - assert td == td2 - - def test_resolution_info(self): - assert isinstance(timedelta.min, timedelta) - assert isinstance(timedelta.max, timedelta) - assert isinstance(timedelta.resolution, timedelta) - assert timedelta.max > timedelta.min - assert timedelta.min == timedelta(-999999999) - assert timedelta.max == timedelta(999999999, 24*3600-1, 1e6-1) - assert timedelta.resolution == timedelta(0, 0, 1) - - def test_overflow(self): - tiny = timedelta.resolution - - td = timedelta.min + tiny - td -= tiny # no problem - raises(OverflowError, td.__sub__, tiny) - raises(OverflowError, td.__add__, -tiny) - - td = timedelta.max - tiny - td += tiny # no problem - raises(OverflowError, td.__add__, tiny) - raises(OverflowError, td.__sub__, -tiny) - - raises(OverflowError, lambda: -timedelta.max) - - def test_microsecond_rounding(self): - td = timedelta - - # Single-field rounding. - assert td(milliseconds=0.4/1000) == td(0) # rounds to 0 - assert td(milliseconds=-0.4/1000) == td(0) # rounds to 0 - assert td(milliseconds=0.6/1000) == td(microseconds=1) - assert td(milliseconds=-0.6/1000) == td(microseconds=-1) - - # Rounding due to contributions from more than one field. - us_per_hour = 3600e6 - us_per_day = us_per_hour * 24 - assert td(days=.4/us_per_day) == td(0) - assert td(hours=.2/us_per_hour) == td(0) - assert td(days=.4/us_per_day, hours=.2/us_per_hour) == td(microseconds=1) - - assert td(days=-.4/us_per_day) == td(0) - assert td(hours=-.2/us_per_hour) == td(0) - assert td(days=-.4/us_per_day, hours=-.2/us_per_hour) == td(microseconds=-1) - - def test_massive_normalization(self): - td = timedelta(microseconds=-1) - assert (td.days, td.seconds, td.microseconds) == ( - (-1, 24*3600-1, 999999)) - - def test_bool(self): - assert timedelta(1) - assert timedelta(0, 1) - assert timedelta(0, 0, 1) - assert timedelta(microseconds=1) - assert not timedelta(0) - -############################################################################# -# date tests - -class TestDateOnly(object): - # Tests here won't pass if also run on datetime objects, so don't - # subclass this to test datetimes too. - - def test_delta_non_days_ignored(self): - dt = date(2000, 1, 2) - delta = timedelta(days=1, hours=2, minutes=3, seconds=4, - microseconds=5) - days = timedelta(delta.days) - assert days == timedelta(1) - - dt2 = dt + delta - assert dt2 == dt + days - - dt2 = delta + dt - assert dt2 == dt + days - - dt2 = dt - delta - assert dt2 == dt - days - - delta = -delta - days = timedelta(delta.days) - assert days == timedelta(-2) - - dt2 = dt + delta - assert dt2 == dt + days - - dt2 = delta + dt - assert dt2 == dt + days - - dt2 = dt - delta - assert dt2 == dt - days - -class TestDate(HarmlessMixedComparison): - # Tests here should pass for both dates and datetimes, except for a - # few tests that TestDateTime overrides. - - theclass = date - - def test_basic_attributes(self): - dt = self.theclass(2002, 3, 1) - assert dt.year == 2002 - assert dt.month == 3 - assert dt.day == 1 - - def test_roundtrip(self): - for dt in (self.theclass(1, 2, 3), - self.theclass.today()): - # Verify dt -> string -> date identity. - s = repr(dt) - assert s.startswith('datetime.') - s = s[9:] - dt2 = eval(s) - assert dt == dt2 - - # Verify identity via reconstructing from pieces. - dt2 = self.theclass(dt.year, dt.month, dt.day) - assert dt == dt2 - - def test_ordinal_conversions(self): - # Check some fixed values. - for y, m, d, n in [(1, 1, 1, 1), # calendar origin - (1, 12, 31, 365), - (2, 1, 1, 366), - # first example from "Calendrical Calculations" - (1945, 11, 12, 710347)]: - d = self.theclass(y, m, d) - assert n == d.toordinal() - fromord = self.theclass.fromordinal(n) - assert d == fromord - if hasattr(fromord, "hour"): - # if we're checking something fancier than a date, verify - # the extra fields have been zeroed out - assert fromord.hour == 0 - assert fromord.minute == 0 - assert fromord.second == 0 - assert fromord.microsecond == 0 - - # Check first and last days of year spottily across the whole - # range of years supported. - for year in xrange(MINYEAR, MAXYEAR+1, 7): - # Verify (year, 1, 1) -> ordinal -> y, m, d is identity. - d = self.theclass(year, 1, 1) - n = d.toordinal() - d2 = self.theclass.fromordinal(n) - assert d == d2 - # Verify that moving back a day gets to the end of year-1. - if year > 1: - d = self.theclass.fromordinal(n-1) - d2 = self.theclass(year-1, 12, 31) - assert d == d2 - assert d2.toordinal() == n-1 - - # Test every day in a leap-year and a non-leap year. - dim = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] - for year, isleap in (2000, True), (2002, False): - n = self.theclass(year, 1, 1).toordinal() - for month, maxday in zip(range(1, 13), dim): - if month == 2 and isleap: - maxday += 1 - for day in range(1, maxday+1): - d = self.theclass(year, month, day) - assert d.toordinal() == n - assert d == self.theclass.fromordinal(n) - n += 1 - - def test_extreme_ordinals(self): - a = self.theclass.min - a = self.theclass(a.year, a.month, a.day) # get rid of time parts - aord = a.toordinal() - b = a.fromordinal(aord) - assert a == b - - raises(ValueError, lambda: a.fromordinal(aord - 1)) - - b = a + timedelta(days=1) - assert b.toordinal() == aord + 1 - assert b == self.theclass.fromordinal(aord + 1) - - a = self.theclass.max - a = self.theclass(a.year, a.month, a.day) # get rid of time parts - aord = a.toordinal() - b = a.fromordinal(aord) - assert a == b - - raises(ValueError, lambda: a.fromordinal(aord + 1)) - - b = a - timedelta(days=1) - assert b.toordinal() == aord - 1 - assert b == self.theclass.fromordinal(aord - 1) - - def test_bad_constructor_arguments(self): - # bad years - self.theclass(MINYEAR, 1, 1) # no exception - self.theclass(MAXYEAR, 1, 1) # no exception - raises(ValueError, self.theclass, MINYEAR-1, 1, 1) - raises(ValueError, self.theclass, MAXYEAR+1, 1, 1) - # bad months - self.theclass(2000, 1, 1) # no exception - self.theclass(2000, 12, 1) # no exception - raises(ValueError, self.theclass, 2000, 0, 1) - raises(ValueError, self.theclass, 2000, 13, 1) - # bad days - self.theclass(2000, 2, 29) # no exception - self.theclass(2004, 2, 29) # no exception - self.theclass(2400, 2, 29) # no exception - raises(ValueError, self.theclass, 2000, 2, 30) - raises(ValueError, self.theclass, 2001, 2, 29) - raises(ValueError, self.theclass, 2100, 2, 29) - raises(ValueError, self.theclass, 1900, 2, 29) - raises(ValueError, self.theclass, 2000, 1, 0) - raises(ValueError, self.theclass, 2000, 1, 32) - - def test_hash_equality(self): - d = self.theclass(2000, 12, 31) - # same thing - e = self.theclass(2000, 12, 31) - assert d == e - assert hash(d) == hash(e) - - dic = {d: 1} - dic[e] = 2 - assert len(dic) == 1 - assert dic[d] == 2 - assert dic[e] == 2 - - d = self.theclass(2001, 1, 1) - # same thing - e = self.theclass(2001, 1, 1) - assert d == e - assert hash(d) == hash(e) - - dic = {d: 1} - dic[e] = 2 - assert len(dic) == 1 - assert dic[d] == 2 - assert dic[e] == 2 - - def test_computations(self): - a = self.theclass(2002, 1, 31) - b = self.theclass(1956, 1, 31) - - diff = a-b - assert diff.days == 46*365 + len(range(1956, 2002, 4)) - assert diff.seconds == 0 - assert diff.microseconds == 0 - - day = timedelta(1) - week = timedelta(7) - a = self.theclass(2002, 3, 2) - assert a + day == self.theclass(2002, 3, 3) - assert day + a == self.theclass(2002, 3, 3) - assert a - day == self.theclass(2002, 3, 1) - assert -day + a == self.theclass(2002, 3, 1) - assert a + week == self.theclass(2002, 3, 9) - assert a - week == self.theclass(2002, 2, 23) - assert a + 52*week == self.theclass(2003, 3, 1) - assert a - 52*week == self.theclass(2001, 3, 3) - assert (a + week) - a == week - assert (a + day) - a == day - assert (a - week) - a == -week - assert (a - day) - a == -day - assert a - (a + week) == -week - assert a - (a + day) == -day - assert a - (a - week) == week - assert a - (a - day) == day - - # Add/sub ints, longs, floats should be illegal - for i in 1, 1L, 1.0: - raises(TypeError, lambda: a+i) - raises(TypeError, lambda: a-i) - raises(TypeError, lambda: i+a) - raises(TypeError, lambda: i-a) - - # delta - date is senseless. - raises(TypeError, lambda: day - a) - # mixing date and (delta or date) via * or // is senseless - raises(TypeError, lambda: day * a) - raises(TypeError, lambda: a * day) - raises(TypeError, lambda: day // a) - raises(TypeError, lambda: a // day) - raises(TypeError, lambda: a * a) - raises(TypeError, lambda: a // a) - # date + date is senseless - raises(TypeError, lambda: a + a) - - def test_overflow(self): - tiny = self.theclass.resolution - - dt = self.theclass.min + tiny - dt -= tiny # no problem - raises(OverflowError, dt.__sub__, tiny) - raises(OverflowError, dt.__add__, -tiny) - - dt = self.theclass.max - tiny - dt += tiny # no problem - raises(OverflowError, dt.__add__, tiny) - raises(OverflowError, dt.__sub__, -tiny) - - def test_fromtimestamp(self): - import time - - # Try an arbitrary fixed value. - year, month, day = 1999, 9, 19 - ts = time.mktime((year, month, day, 0, 0, 0, 0, 0, -1)) - d = self.theclass.fromtimestamp(ts) - assert d.year == year - assert d.month == month - assert d.day == day - - def test_today(self): - import time - - # We claim that today() is like fromtimestamp(time.time()), so - # prove it. - for dummy in range(3): - today = self.theclass.today() - ts = time.time() - todayagain = self.theclass.fromtimestamp(ts) - if today == todayagain: - break - # There are several legit reasons that could fail: - # 1. It recently became midnight, between the today() and the - # time() calls. - # 2. The platform time() has such fine resolution that we'll - # never get the same value twice. - # 3. The platform time() has poor resolution, and we just - # happened to call today() right before a resolution quantum - # boundary. - # 4. The system clock got fiddled between calls. - # In any case, wait a little while and try again. - time.sleep(0.1) - - # It worked or it didn't. If it didn't, assume it's reason #2, and - # let the test pass if they're within half a second of each other. - assert (today == todayagain or - abs(todayagain - today) < timedelta(seconds=0.5)) - - def test_weekday(self): - for i in range(7): - # March 4, 2002 is a Monday - assert self.theclass(2002, 3, 4+i).weekday() == i - assert self.theclass(2002, 3, 4+i).isoweekday() == i+1 - # January 2, 1956 is a Monday - assert self.theclass(1956, 1, 2+i).weekday() == i - assert self.theclass(1956, 1, 2+i).isoweekday() == i+1 - - def test_isocalendar(self): - # Check examples from - # http://www.phys.uu.nl/~vgent/calendar/isocalendar.htm - for i in range(7): - d = self.theclass(2003, 12, 22+i) - assert d.isocalendar() == (2003, 52, i+1) - d = self.theclass(2003, 12, 29) + timedelta(i) - assert d.isocalendar() == (2004, 1, i+1) - d = self.theclass(2004, 1, 5+i) - assert d.isocalendar() == (2004, 2, i+1) - d = self.theclass(2009, 12, 21+i) - assert d.isocalendar() == (2009, 52, i+1) - d = self.theclass(2009, 12, 28) + timedelta(i) - assert d.isocalendar() == (2009, 53, i+1) - d = self.theclass(2010, 1, 4+i) - assert d.isocalendar() == (2010, 1, i+1) - - def test_iso_long_years(self): - # Calculate long ISO years and compare to table from - # http://www.phys.uu.nl/~vgent/calendar/isocalendar.htm - ISO_LONG_YEARS_TABLE = """ - 4 32 60 88 - 9 37 65 93 - 15 43 71 99 - 20 48 76 - 26 54 82 - - 105 133 161 189 - 111 139 167 195 - 116 144 172 - 122 150 178 - 128 156 184 - - 201 229 257 285 - 207 235 263 291 - 212 240 268 296 - 218 246 274 - 224 252 280 - - 303 331 359 387 - 308 336 364 392 - 314 342 370 398 - 320 348 376 - 325 353 381 - """ - iso_long_years = map(int, ISO_LONG_YEARS_TABLE.split()) - iso_long_years.sort() - L = [] - for i in range(400): - d = self.theclass(2000+i, 12, 31) - d1 = self.theclass(1600+i, 12, 31) - assert d.isocalendar()[1:] == d1.isocalendar()[1:] - if d.isocalendar()[1] == 53: - L.append(i) - assert L == iso_long_years - - def test_isoformat(self): - t = self.theclass(2, 3, 2) - assert t.isoformat() == "0002-03-02" - - def test_ctime(self): - t = self.theclass(2002, 3, 2) - assert t.ctime() == "Sat Mar 2 00:00:00 2002" - - def test_strftime(self): - t = self.theclass(2005, 3, 2) - assert t.strftime("m:%m d:%d y:%y") == "m:03 d:02 y:05" - - raises(TypeError, t.strftime) # needs an arg - raises(TypeError, t.strftime, "one", "two") # too many args - raises(TypeError, t.strftime, 42) # arg wrong type - - # A naive object replaces %z and %Z w/ empty strings. - assert t.strftime("'%z' '%Z'") == "'' ''" - - def test_resolution_info(self): - assert isinstance(self.theclass.min, self.theclass) - assert isinstance(self.theclass.max, self.theclass) - assert isinstance(self.theclass.resolution, timedelta) - assert self.theclass.max > self.theclass.min - - def test_extreme_timedelta(self): - big = self.theclass.max - self.theclass.min - # 3652058 days, 23 hours, 59 minutes, 59 seconds, 999999 microseconds - n = (big.days*24*3600 + big.seconds)*1000000 + big.microseconds - # n == 315537897599999999 ~= 2**58.13 - justasbig = timedelta(0, 0, n) - assert big == justasbig - assert self.theclass.min + big == self.theclass.max - assert self.theclass.max - big == self.theclass.min - - def test_timetuple(self): - for i in range(7): - # January 2, 1956 is a Monday (0) - d = self.theclass(1956, 1, 2+i) - t = d.timetuple() - assert t == (1956, 1, 2+i, 0, 0, 0, i, 2+i, -1) - # February 1, 1956 is a Wednesday (2) - d = self.theclass(1956, 2, 1+i) - t = d.timetuple() - assert t == (1956, 2, 1+i, 0, 0, 0, (2+i)%7, 32+i, -1) - # March 1, 1956 is a Thursday (3), and is the 31+29+1 = 61st day - # of the year. - d = self.theclass(1956, 3, 1+i) - t = d.timetuple() - assert t == (1956, 3, 1+i, 0, 0, 0, (3+i)%7, 61+i, -1) - assert t.tm_year == 1956 - assert t.tm_mon == 3 - assert t.tm_mday == 1+i - assert t.tm_hour == 0 - assert t.tm_min == 0 - assert t.tm_sec == 0 - assert t.tm_wday == (3+i)%7 - assert t.tm_yday == 61+i - assert t.tm_isdst == -1 - - def test_pickling(self): - args = 6, 7, 23 - orig = self.theclass(*args) - for pickler, unpickler, proto in pickle_choices: - green = pickler.dumps(orig, proto) - derived = unpickler.loads(green) - assert orig == derived - - def test_compare(self): - t1 = self.theclass(2, 3, 4) - t2 = self.theclass(2, 3, 4) - assert t1 == t2 - assert t1 <= t2 - assert t1 >= t2 - assert not t1 != t2 - assert not t1 < t2 - assert not t1 > t2 - assert cmp(t1, t2) == 0 - assert cmp(t2, t1) == 0 - - for args in (3, 3, 3), (2, 4, 4), (2, 3, 5): - t2 = self.theclass(*args) # this is larger than t1 - assert t1 < t2 - assert t2 > t1 - assert t1 <= t2 - assert t2 >= t1 - assert t1 != t2 - assert t2 != t1 - assert not t1 == t2 - assert not t2 == t1 - assert not t1 > t2 - assert not t2 < t1 - assert not t1 >= t2 - assert not t2 <= t1 - assert cmp(t1, t2) == -1 - assert cmp(t2, t1) == 1 - - for badarg in OTHERSTUFF: - assert (t1 == badarg) == False - assert (t1 != badarg) == True - assert (badarg == t1) == False - assert (badarg != t1) == True - - raises(TypeError, lambda: t1 < badarg) - raises(TypeError, lambda: t1 > badarg) - raises(TypeError, lambda: t1 >= badarg) - raises(TypeError, lambda: badarg <= t1) - raises(TypeError, lambda: badarg < t1) - raises(TypeError, lambda: badarg > t1) - raises(TypeError, lambda: badarg >= t1) - - def test_mixed_compare(self): - our = self.theclass(2000, 4, 5) - raises(TypeError, cmp, our, 1) - raises(TypeError, cmp, 1, our) - - class AnotherDateTimeClass(object): - def __cmp__(self, other): - # Return "equal" so calling this can't be confused with - # compare-by-address (which never says "equal" for distinct - # objects). - return 0 - - # This still errors, because date and datetime comparison raise - # TypeError instead of NotImplemented when they don't know what to - # do, in order to stop comparison from falling back to the default - # compare-by-address. - their = AnotherDateTimeClass() - raises(TypeError, cmp, our, their) - # Oops: The next stab raises TypeError in the C implementation, - # but not in the Python implementation of datetime. The difference - # is due to that the Python implementation defines __cmp__ but - # the C implementation defines tp_richcompare. This is more pain - # to fix than it's worth, so commenting out the test. - # self.assertEqual(cmp(their, our), 0) - - # But date and datetime comparison return NotImplemented instead if the - # other object has a timetuple attr. This gives the other object a - # chance to do the comparison. - class Comparable(AnotherDateTimeClass): - def timetuple(self): - return () - - their = Comparable() - assert cmp(our, their) == 0 - assert cmp(their, our) == 0 - assert our == their - assert their == our - - def test_bool(self): - # All dates are considered true. - assert self.theclass.min - assert self.theclass.max - - def test_srftime_out_of_range(self): - # For nasty technical reasons, we can't handle years before 1900. - cls = self.theclass - assert cls(1900, 1, 1).strftime("%Y") == "1900" - for y in 1, 49, 51, 99, 100, 1000, 1899: - raises(ValueError, cls(y, 1, 1).strftime, "%Y") - - def test_replace(self): - cls = self.theclass - args = [1, 2, 3] - base = cls(*args) - assert base == base.replace() - - i = 0 - for name, newval in (("year", 2), - ("month", 3), - ("day", 4)): - newargs = args[:] - newargs[i] = newval - expected = cls(*newargs) - got = base.replace(**{name: newval}) - assert expected == got - i += 1 - - # Out of bounds. - base = cls(2000, 2, 29) - raises(ValueError, base.replace, year=2001) - -############################################################################# -# datetime tests - -class TestDateTime(TestDate): - - theclass = datetime - - def test_basic_attributes(self): - dt = self.theclass(2002, 3, 1, 12, 0) - assert dt.year == 2002 - assert dt.month == 3 - assert dt.day == 1 - assert dt.hour == 12 - assert dt.minute == 0 - assert dt.second == 0 - assert dt.microsecond == 0 - - def test_basic_attributes_nonzero(self): - # Make sure all attributes are non-zero so bugs in - # bit-shifting access show up. - dt = self.theclass(2002, 3, 1, 12, 59, 59, 8000) - assert dt.year == 2002 - assert dt.month == 3 - assert dt.day == 1 - assert dt.hour == 12 - assert dt.minute == 59 - assert dt.second == 59 - assert dt.microsecond == 8000 - - def test_roundtrip(self): - for dt in (self.theclass(1, 2, 3, 4, 5, 6, 7), - self.theclass.now()): - # Verify dt -> string -> datetime identity. - s = repr(dt) - assert s.startswith('datetime.') - s = s[9:] - dt2 = eval(s) - assert dt == dt2 - - # Verify identity via reconstructing from pieces. - dt2 = self.theclass(dt.year, dt.month, dt.day, - dt.hour, dt.minute, dt.second, - dt.microsecond) - assert dt == dt2 - - def test_isoformat(self): - t = self.theclass(2, 3, 2, 4, 5, 1, 123) - assert t.isoformat() == "0002-03-02T04:05:01.000123" - assert t.isoformat('T') == "0002-03-02T04:05:01.000123" - assert t.isoformat(' ') == "0002-03-02 04:05:01.000123" - # str is ISO format with the separator forced to a blank. - assert str(t) == "0002-03-02 04:05:01.000123" - - t = self.theclass(2, 3, 2) - assert t.isoformat() == "0002-03-02T00:00:00" - assert t.isoformat('T') == "0002-03-02T00:00:00" - assert t.isoformat(' ') == "0002-03-02 00:00:00" - # str is ISO format with the separator forced to a blank. - assert str(t) == "0002-03-02 00:00:00" - - def test_more_ctime(self): - # Test fields that TestDate doesn't touch. - import time - - t = self.theclass(2002, 3, 2, 18, 3, 5, 123) - assert t.ctime() == "Sat Mar 2 18:03:05 2002" - # Oops! The next line fails on Win2K under MSVC 6, so it's commented - # out. The difference is that t.ctime() produces " 2" for the day, - # but platform ctime() produces "02" for the day. According to - # C99, t.ctime() is correct here. - # self.assertEqual(t.ctime(), time.ctime(time.mktime(t.timetuple()))) - - # So test a case where that difference doesn't matter. - t = self.theclass(2002, 3, 22, 18, 3, 5, 123) - assert t.ctime() == time.ctime(time.mktime(t.timetuple())) - - def test_tz_independent_comparing(self): - dt1 = self.theclass(2002, 3, 1, 9, 0, 0) - dt2 = self.theclass(2002, 3, 1, 10, 0, 0) - dt3 = self.theclass(2002, 3, 1, 9, 0, 0) - assert dt1 == dt3 - assert dt2 > dt3 - - # Make sure comparison doesn't forget microseconds, and isn't done - # via comparing a float timestamp (an IEEE double doesn't have enough - # precision to span microsecond resolution across years 1 thru 9999, - # so comparing via timestamp necessarily calls some distinct values - # equal). - dt1 = self.theclass(MAXYEAR, 12, 31, 23, 59, 59, 999998) - us = timedelta(microseconds=1) - dt2 = dt1 + us - assert dt2 - dt1 == us - assert dt1 < dt2 - - def test_bad_constructor_arguments(self): - # bad years - self.theclass(MINYEAR, 1, 1) # no exception - self.theclass(MAXYEAR, 1, 1) # no exception - raises(ValueError, self.theclass, MINYEAR-1, 1, 1) - raises(ValueError, self.theclass, MAXYEAR+1, 1, 1) - # bad months - self.theclass(2000, 1, 1) # no exception - self.theclass(2000, 12, 1) # no exception - raises(ValueError, self.theclass, 2000, 0, 1) - raises(ValueError, self.theclass, 2000, 13, 1) - # bad days - self.theclass(2000, 2, 29) # no exception - self.theclass(2004, 2, 29) # no exception - self.theclass(2400, 2, 29) # no exception - raises(ValueError, self.theclass, 2000, 2, 30) - raises(ValueError, self.theclass, 2001, 2, 29) - raises(ValueError, self.theclass, 2100, 2, 29) - raises(ValueError, self.theclass, 1900, 2, 29) - raises(ValueError, self.theclass, 2000, 1, 0) - raises(ValueError, self.theclass, 2000, 1, 32) - # bad hours - self.theclass(2000, 1, 31, 0) # no exception - self.theclass(2000, 1, 31, 23) # no exception - raises(ValueError, self.theclass, 2000, 1, 31, -1) - raises(ValueError, self.theclass, 2000, 1, 31, 24) - # bad minutes - self.theclass(2000, 1, 31, 23, 0) # no exception - self.theclass(2000, 1, 31, 23, 59) # no exception - raises(ValueError, self.theclass, 2000, 1, 31, 23, -1) - raises(ValueError, self.theclass, 2000, 1, 31, 23, 60) - # bad seconds - self.theclass(2000, 1, 31, 23, 59, 0) # no exception - self.theclass(2000, 1, 31, 23, 59, 59) # no exception - raises(ValueError, self.theclass, 2000, 1, 31, 23, 59, -1) - raises(ValueError, self.theclass, 2000, 1, 31, 23, 59, 60) - # bad microseconds - self.theclass(2000, 1, 31, 23, 59, 59, 0) # no exception - self.theclass(2000, 1, 31, 23, 59, 59, 999999) # no exception - raises(ValueError, self.theclass, - 2000, 1, 31, 23, 59, 59, -1) - raises(ValueError, self.theclass, - 2000, 1, 31, 23, 59, 59, - 1000000) - - def test_hash_equality(self): - d = self.theclass(2000, 12, 31, 23, 30, 17) - e = self.theclass(2000, 12, 31, 23, 30, 17) - assert d == e - assert hash(d) == hash(e) - - dic = {d: 1} - dic[e] = 2 - assert len(dic) == 1 - assert dic[d] == 2 - assert dic[e] == 2 - - d = self.theclass(2001, 1, 1, 0, 5, 17) - e = self.theclass(2001, 1, 1, 0, 5, 17) - assert d == e - assert hash(d) == hash(e) - - dic = {d: 1} - dic[e] = 2 - assert len(dic) == 1 - assert dic[d] == 2 - assert dic[e] == 2 - - def test_computations(self): - a = self.theclass(2002, 1, 31) - b = self.theclass(1956, 1, 31) - diff = a-b - assert diff.days == 46*365 + len(range(1956, 2002, 4)) - assert diff.seconds == 0 - assert diff.microseconds == 0 - a = self.theclass(2002, 3, 2, 17, 6) - millisec = timedelta(0, 0, 1000) - hour = timedelta(0, 3600) - day = timedelta(1) - week = timedelta(7) - assert a + hour == self.theclass(2002, 3, 2, 18, 6) - assert hour + a == self.theclass(2002, 3, 2, 18, 6) - assert a + 10*hour == self.theclass(2002, 3, 3, 3, 6) - assert a - hour == self.theclass(2002, 3, 2, 16, 6) - assert -hour + a == self.theclass(2002, 3, 2, 16, 6) - assert a - hour == a + -hour - assert a - 20*hour == self.theclass(2002, 3, 1, 21, 6) - assert a + day == self.theclass(2002, 3, 3, 17, 6) - assert a - day == self.theclass(2002, 3, 1, 17, 6) - assert a + week == self.theclass(2002, 3, 9, 17, 6) - assert a - week == self.theclass(2002, 2, 23, 17, 6) - assert a + 52*week == self.theclass(2003, 3, 1, 17, 6) - assert a - 52*week == self.theclass(2001, 3, 3, 17, 6) - assert (a + week) - a == week - assert (a + day) - a == day - assert (a + hour) - a == hour - assert (a + millisec) - a == millisec - assert (a - week) - a == -week - assert (a - day) - a == -day - assert (a - hour) - a == -hour - assert (a - millisec) - a == -millisec - assert a - (a + week) == -week - assert a - (a + day) == -day - assert a - (a + hour) == -hour - assert a - (a + millisec) == -millisec - assert a - (a - week) == week - assert a - (a - day) == day - assert a - (a - hour) == hour - assert a - (a - millisec) == millisec - assert a + (week + day + hour + millisec) == ( - self.theclass(2002, 3, 10, 18, 6, 0, 1000)) - assert a + (week + day + hour + millisec) == ( - (((a + week) + day) + hour) + millisec) - assert a - (week + day + hour + millisec) == ( - self.theclass(2002, 2, 22, 16, 5, 59, 999000)) - assert a - (week + day + hour + millisec) == ( - (((a - week) - day) - hour) - millisec) - # Add/sub ints, longs, floats should be illegal - for i in 1, 1L, 1.0: - raises(TypeError, lambda: a+i) - raises(TypeError, lambda: a-i) - raises(TypeError, lambda: i+a) - raises(TypeError, lambda: i-a) - - # delta - datetime is senseless. - raises(TypeError, lambda: day - a) - # mixing datetime and (delta or datetime) via * or // is senseless - raises(TypeError, lambda: day * a) - raises(TypeError, lambda: a * day) - raises(TypeError, lambda: day // a) - raises(TypeError, lambda: a // day) - raises(TypeError, lambda: a * a) - raises(TypeError, lambda: a // a) - # datetime + datetime is senseless - raises(TypeError, lambda: a + a) - - def test_pickling(self): - args = 6, 7, 23, 20, 59, 1, 64**2 - orig = self.theclass(*args) - for pickler, unpickler, proto in pickle_choices: - green = pickler.dumps(orig, proto) - derived = unpickler.loads(green) - assert orig == derived - - def test_more_pickling(self): - a = self.theclass(2003, 2, 7, 16, 48, 37, 444116) - s = pickle.dumps(a) - b = pickle.loads(s) - assert b.year == 2003 - assert b.month == 2 - assert b.day == 7 - - def test_more_compare(self): - # The test_compare() inherited from TestDate covers the error cases. - # We just want to test lexicographic ordering on the members datetime - # has that date lacks. - args = [2000, 11, 29, 20, 58, 16, 999998] - t1 = self.theclass(*args) - t2 = self.theclass(*args) - assert t1 == t2 - assert t1 <= t2 - assert t1 >= t2 - assert not t1 != t2 - assert not t1 < t2 - assert not t1 > t2 - assert cmp(t1, t2) == 0 - assert cmp(t2, t1) == 0 - - for i in range(len(args)): - newargs = args[:] - newargs[i] = args[i] + 1 - t2 = self.theclass(*newargs) # this is larger than t1 - assert t1 < t2 - assert t2 > t1 - assert t1 <= t2 - assert t2 >= t1 - assert t1 != t2 - assert t2 != t1 - assert not t1 == t2 - assert not t2 == t1 - assert not t1 > t2 - assert not t2 < t1 - assert not t1 >= t2 - assert not t2 <= t1 - assert cmp(t1, t2) == -1 - assert cmp(t2, t1) == 1 - - - # A helper for timestamp constructor tests. - def verify_field_equality(self, expected, got): - assert expected.tm_year == got.year - assert expected.tm_mon == got.month - assert expected.tm_mday == got.day - assert expected.tm_hour == got.hour - assert expected.tm_min == got.minute - assert expected.tm_sec == got.second - - def test_fromtimestamp(self): - import time - - ts = time.time() - expected = time.localtime(ts) - got = self.theclass.fromtimestamp(ts) - self.verify_field_equality(expected, got) - - def test_utcfromtimestamp(self): - import time - - ts = time.time() - expected = time.gmtime(ts) - got = self.theclass.utcfromtimestamp(ts) - self.verify_field_equality(expected, got) - - def test_utcnow(self): - import time - - # Call it a success if utcnow() and utcfromtimestamp() are within - # a second of each other. - tolerance = timedelta(seconds=1) - for dummy in range(3): - from_now = self.theclass.utcnow() - from_timestamp = self.theclass.utcfromtimestamp(time.time()) - if abs(from_timestamp - from_now) <= tolerance: - break - # Else try again a few times. - assert abs(from_timestamp - from_now) <= tolerance - - def test_more_timetuple(self): - # This tests fields beyond those tested by the TestDate.test_timetuple. - t = self.theclass(2004, 12, 31, 6, 22, 33) - assert t.timetuple() == (2004, 12, 31, 6, 22, 33, 4, 366, -1) - assert t.timetuple() == ( - (t.year, t.month, t.day, - t.hour, t.minute, t.second, - t.weekday(), - t.toordinal() - date(t.year, 1, 1).toordinal() + 1, - -1)) - tt = t.timetuple() - assert tt.tm_year == t.year - assert tt.tm_mon == t.month - assert tt.tm_mday == t.day - assert tt.tm_hour == t.hour - assert tt.tm_min == t.minute - assert tt.tm_sec == t.second - assert tt.tm_wday == t.weekday() - assert tt.tm_yday == ( t.toordinal() - - date(t.year, 1, 1).toordinal() + 1) - assert tt.tm_isdst == -1 - - def test_more_strftime(self): - # This tests fields beyond those tested by the TestDate.test_strftime. - t = self.theclass(2004, 12, 31, 6, 22, 33) - assert t.strftime("%m %d %y %S %M %H %j") == ( - "12 31 04 33 22 06 366") - - def test_extract(self): - dt = self.theclass(2002, 3, 4, 18, 45, 3, 1234) - assert dt.date() == date(2002, 3, 4) - assert dt.time() == time(18, 45, 3, 1234) - - def test_combine(self): - d = date(2002, 3, 4) - t = time(18, 45, 3, 1234) - expected = self.theclass(2002, 3, 4, 18, 45, 3, 1234) - combine = self.theclass.combine - dt = combine(d, t) - assert dt == expected - - dt = combine(time=t, date=d) - assert dt == expected - - assert d == dt.date() - assert t == dt.time() - assert dt == combine(dt.date(), dt.time()) - - raises(TypeError, combine) # need an arg - raises(TypeError, combine, d) # need two args - raises(TypeError, combine, t, d) # args reversed - raises(TypeError, combine, d, t, 1) # too many args - raises(TypeError, combine, "date", "time") # wrong types - - def test_replace(self): - cls = self.theclass - args = [1, 2, 3, 4, 5, 6, 7] - base = cls(*args) - assert base == base.replace() - - i = 0 - for name, newval in (("year", 2), - ("month", 3), - ("day", 4), - ("hour", 5), - ("minute", 6), - ("second", 7), - ("microsecond", 8)): - newargs = args[:] - newargs[i] = newval - expected = cls(*newargs) - got = base.replace(**{name: newval}) - assert expected == got - i += 1 - - # Out of bounds. - base = cls(2000, 2, 29) - raises(ValueError, base.replace, year=2001) - - def test_astimezone(self): - # Pretty boring! The TZ test is more interesting here. astimezone() - # simply can't be applied to a naive object. - dt = self.theclass.now() - f = FixedOffset(44, "") - raises(TypeError, dt.astimezone) # not enough args - raises(TypeError, dt.astimezone, f, f) # too many args - raises(TypeError, dt.astimezone, dt) # arg wrong type - raises(ValueError, dt.astimezone, f) # naive - raises(ValueError, dt.astimezone, tz=f) # naive - - class Bogus(tzinfo): - def utcoffset(self, dt): return None - def dst(self, dt): return timedelta(0) - bog = Bogus() - raises(ValueError, dt.astimezone, bog) # naive - - class AlsoBogus(tzinfo): - def utcoffset(self, dt): return timedelta(0) - def dst(self, dt): return None - alsobog = AlsoBogus() - raises(ValueError, dt.astimezone, alsobog) # also naive - -class TestTime(HarmlessMixedComparison): - - theclass = time - - def test_basic_attributes(self): - t = self.theclass(12, 0) - assert t.hour == 12 - assert t.minute == 0 - assert t.second == 0 - assert t.microsecond == 0 - - def test_basic_attributes_nonzero(self): - # Make sure all attributes are non-zero so bugs in - # bit-shifting access show up. - t = self.theclass(12, 59, 59, 8000) - assert t.hour == 12 - assert t.minute == 59 - assert t.second == 59 - assert t.microsecond == 8000 - - def test_roundtrip(self): - t = self.theclass(1, 2, 3, 4) - - # Verify t -> string -> time identity. - s = repr(t) - assert s.startswith('datetime.') - s = s[9:] - t2 = eval(s) - assert t == t2 - - # Verify identity via reconstructing from pieces. - t2 = self.theclass(t.hour, t.minute, t.second, - t.microsecond) - assert t == t2 - - def test_comparing(self): - args = [1, 2, 3, 4] - t1 = self.theclass(*args) - t2 = self.theclass(*args) - assert t1 == t2 - assert t1 <= t2 - assert t1 >= t2 - assert not t1 != t2 - assert not t1 < t2 - assert not t1 > t2 - assert cmp(t1, t2) == 0 - assert cmp(t2, t1) == 0 - - for i in range(len(args)): - newargs = args[:] - newargs[i] = args[i] + 1 - t2 = self.theclass(*newargs) # this is larger than t1 - assert t1 < t2 - assert t2 > t1 - assert t1 <= t2 - assert t2 >= t1 - assert t1 != t2 - assert t2 != t1 - assert not t1 == t2 - assert not t2 == t1 - assert not t1 > t2 - assert not t2 < t1 - assert not t1 >= t2 - assert not t2 <= t1 - assert cmp(t1, t2) == -1 - assert cmp(t2, t1) == 1 - - for badarg in OTHERSTUFF: - assert (t1 == badarg) == False - assert (t1 != badarg) == True - assert (badarg == t1) == False - assert (badarg != t1) == True - - raises(TypeError, lambda: t1 <= badarg) - raises(TypeError, lambda: t1 < badarg) - raises(TypeError, lambda: t1 > badarg) - raises(TypeError, lambda: t1 >= badarg) - raises(TypeError, lambda: badarg <= t1) - raises(TypeError, lambda: badarg < t1) - raises(TypeError, lambda: badarg > t1) - raises(TypeError, lambda: badarg >= t1) - - def test_bad_constructor_arguments(self): - # bad hours - self.theclass(0, 0) # no exception - self.theclass(23, 0) # no exception - raises(ValueError, self.theclass, -1, 0) - raises(ValueError, self.theclass, 24, 0) - # bad minutes - self.theclass(23, 0) # no exception - self.theclass(23, 59) # no exception - raises(ValueError, self.theclass, 23, -1) - raises(ValueError, self.theclass, 23, 60) - # bad seconds - self.theclass(23, 59, 0) # no exception - self.theclass(23, 59, 59) # no exception - raises(ValueError, self.theclass, 23, 59, -1) - raises(ValueError, self.theclass, 23, 59, 60) - # bad microseconds - self.theclass(23, 59, 59, 0) # no exception - self.theclass(23, 59, 59, 999999) # no exception - raises(ValueError, self.theclass, 23, 59, 59, -1) - raises(ValueError, self.theclass, 23, 59, 59, 1000000) - - def test_hash_equality(self): - d = self.theclass(23, 30, 17) - e = self.theclass(23, 30, 17) - assert d == e - assert hash(d) == hash(e) - - dic = {d: 1} - dic[e] = 2 - assert len(dic) == 1 - assert dic[d] == 2 - assert dic[e] == 2 - - d = self.theclass(0, 5, 17) - e = self.theclass(0, 5, 17) - assert d == e - assert hash(d) == hash(e) - - dic = {d: 1} - dic[e] = 2 - assert len(dic) == 1 - assert dic[d] == 2 - assert dic[e] == 2 - - def test_isoformat(self): - t = self.theclass(4, 5, 1, 123) - assert t.isoformat() == "04:05:01.000123" - assert t.isoformat() == str(t) - - t = self.theclass() - assert t.isoformat() == "00:00:00" - assert t.isoformat() == str(t) - - t = self.theclass(microsecond=1) - assert t.isoformat() == "00:00:00.000001" - assert t.isoformat() == str(t) - - t = self.theclass(microsecond=10) - assert t.isoformat() == "00:00:00.000010" - assert t.isoformat() == str(t) - - t = self.theclass(microsecond=100) - assert t.isoformat() == "00:00:00.000100" - assert t.isoformat() == str(t) - - t = self.theclass(microsecond=1000) - assert t.isoformat() == "00:00:00.001000" - assert t.isoformat() == str(t) - - t = self.theclass(microsecond=10000) - assert t.isoformat() == "00:00:00.010000" - assert t.isoformat() == str(t) - - t = self.theclass(microsecond=100000) - assert t.isoformat() == "00:00:00.100000" - assert t.isoformat() == str(t) - - def test_strftime(self): - t = self.theclass(1, 2, 3, 4) - assert t.strftime('%H %M %S') == "01 02 03" - # A naive object replaces %z and %Z with empty strings. - assert t.strftime("'%z' '%Z'") == "'' ''" - - def test_str(self): - assert str(self.theclass(1, 2, 3, 4)) == "01:02:03.000004" - assert str(self.theclass(10, 2, 3, 4000)) == "10:02:03.004000" - assert str(self.theclass(0, 2, 3, 400000)) == "00:02:03.400000" - assert str(self.theclass(12, 2, 3, 0)) == "12:02:03" - assert str(self.theclass(23, 15, 0, 0)) == "23:15:00" - - def test_repr(self): - name = 'datetime.' + self.theclass.__name__ - assert repr(self.theclass(1, 2, 3, 4)) == ( - "%s(1, 2, 3, 4)" % name) - assert repr(self.theclass(10, 2, 3, 4000)) == ( - "%s(10, 2, 3, 4000)" % name) - assert repr(self.theclass(0, 2, 3, 400000)) == ( - "%s(0, 2, 3, 400000)" % name) - assert repr(self.theclass(12, 2, 3, 0)) == ( - "%s(12, 2, 3)" % name) - assert repr(self.theclass(23, 15, 0, 0)) == ( - "%s(23, 15)" % name) - - def test_resolution_info(self): - assert isinstance(self.theclass.min, self.theclass) - assert isinstance(self.theclass.max, self.theclass) - assert isinstance(self.theclass.resolution, timedelta) - assert self.theclass.max > self.theclass.min - - def test_pickling(self): - args = 20, 59, 16, 64**2 - orig = self.theclass(*args) - for pickler, unpickler, proto in pickle_choices: - green = pickler.dumps(orig, proto) - derived = unpickler.loads(green) - assert orig == derived - - def test_bool(self): - cls = self.theclass - assert cls(1) - assert cls(0, 1) - assert cls(0, 0, 1) - assert cls(0, 0, 0, 1) - assert not cls(0) - assert not cls() - - def test_replace(self): - cls = self.theclass - args = [1, 2, 3, 4] - base = cls(*args) - assert base == base.replace() - - i = 0 - for name, newval in (("hour", 5), - ("minute", 6), - ("second", 7), - ("microsecond", 8)): - newargs = args[:] - newargs[i] = newval - expected = cls(*newargs) - got = base.replace(**{name: newval}) - assert expected == got - i += 1 - - # Out of bounds. - base = cls(1) - raises(ValueError, base.replace, hour=24) - raises(ValueError, base.replace, minute=-1) - raises(ValueError, base.replace, second=100) - raises(ValueError, base.replace, microsecond=1000000) - -# A mixin for classes with a tzinfo= argument. Subclasses must define -# theclass as a class atribute, and theclass(1, 1, 1, tzinfo=whatever) -# must be legit (which is true for time and datetime). -class TZInfoBase(object): - - def test_argument_passing(self): - cls = self.theclass - # A datetime passes itself on, a time passes None. - class introspective(tzinfo): - def tzname(self, dt): return dt and "real" or "none" - def utcoffset(self, dt): - return timedelta(minutes = dt and 42 or -42) - dst = utcoffset - - obj = cls(1, 2, 3, tzinfo=introspective()) - - expected = cls is time and "none" or "real" - assert obj.tzname() == expected - - expected = timedelta(minutes=(cls is time and -42 or 42)) - assert obj.utcoffset() == expected - assert obj.dst() == expected - - def test_bad_tzinfo_classes(self): - cls = self.theclass - raises(TypeError, cls, 1, 1, 1, tzinfo=12) - - class NiceTry(object): - def __init__(self): pass - def utcoffset(self, dt): pass - raises(TypeError, cls, 1, 1, 1, tzinfo=NiceTry) - - class BetterTry(tzinfo): - def __init__(self): pass - def utcoffset(self, dt): pass - b = BetterTry() - t = cls(1, 1, 1, tzinfo=b) - assert t.tzinfo is b - - def test_utc_offset_out_of_bounds(self): - class Edgy(tzinfo): - def __init__(self, offset): - self.offset = timedelta(minutes=offset) - def utcoffset(self, dt): - return self.offset - - cls = self.theclass - for offset, legit in ((-1440, False), - (-1439, True), - (1439, True), - (1440, False)): - if cls is time: - t = cls(1, 2, 3, tzinfo=Edgy(offset)) - elif cls is datetime: - t = cls(6, 6, 6, 1, 2, 3, tzinfo=Edgy(offset)) - else: - assert 0, "impossible" - if legit: - aofs = abs(offset) - h, m = divmod(aofs, 60) - tag = "%c%02d:%02d" % (offset < 0 and '-' or '+', h, m) - if isinstance(t, datetime): - t = t.timetz() - assert str(t) == "01:02:03" + tag - else: - raises(ValueError, str, t) - - def test_tzinfo_classes(self): - cls = self.theclass - class C1(tzinfo): - def utcoffset(self, dt): return None - def dst(self, dt): return None - def tzname(self, dt): return None - for t in (cls(1, 1, 1), - cls(1, 1, 1, tzinfo=None), - cls(1, 1, 1, tzinfo=C1())): - assert t.utcoffset() is None - assert t.dst() is None - assert t.tzname() is None - - class C3(tzinfo): - def utcoffset(self, dt): return timedelta(minutes=-1439) - def dst(self, dt): return timedelta(minutes=1439) - def tzname(self, dt): return "aname" - t = cls(1, 1, 1, tzinfo=C3()) - assert t.utcoffset() == timedelta(minutes=-1439) - assert t.dst() == timedelta(minutes=1439) - assert t.tzname() == "aname" - - # Wrong types. - class C4(tzinfo): - def utcoffset(self, dt): return "aname" - def dst(self, dt): return 7 - def tzname(self, dt): return 0 - t = cls(1, 1, 1, tzinfo=C4()) - raises(TypeError, t.utcoffset) - raises(TypeError, t.dst) - raises(TypeError, t.tzname) - - # Offset out of range. - class C6(tzinfo): - def utcoffset(self, dt): return timedelta(hours=-24) - def dst(self, dt): return timedelta(hours=24) - t = cls(1, 1, 1, tzinfo=C6()) - raises(ValueError, t.utcoffset) - raises(ValueError, t.dst) - - # Not a whole number of minutes. - class C7(tzinfo): - def utcoffset(self, dt): return timedelta(seconds=61) - def dst(self, dt): return timedelta(microseconds=-81) - t = cls(1, 1, 1, tzinfo=C7()) - raises(ValueError, t.utcoffset) - raises(ValueError, t.dst) - - def test_aware_compare(self): - cls = self.theclass - - # Ensure that utcoffset() gets ignored if the comparands have - # the same tzinfo member. - class OperandDependentOffset(tzinfo): - def utcoffset(self, t): - if t.minute < 10: - # d0 and d1 equal after adjustment - return timedelta(minutes=t.minute) - else: - # d2 off in the weeds - return timedelta(minutes=59) - - base = cls(8, 9, 10, tzinfo=OperandDependentOffset()) - d0 = base.replace(minute=3) - d1 = base.replace(minute=9) - d2 = base.replace(minute=11) - for x in d0, d1, d2: - for y in d0, d1, d2: - got = cmp(x, y) - expected = cmp(x.minute, y.minute) - assert got == expected - - # However, if they're different members, uctoffset is not ignored. - # Note that a time can't actually have an operand-depedent offset, - # though (and time.utcoffset() passes None to tzinfo.utcoffset()), - # so skip this test for time. - if cls is not time: - d0 = base.replace(minute=3, tzinfo=OperandDependentOffset()) - d1 = base.replace(minute=9, tzinfo=OperandDependentOffset()) - d2 = base.replace(minute=11, tzinfo=OperandDependentOffset()) - for x in d0, d1, d2: - for y in d0, d1, d2: - got = cmp(x, y) - if (x is d0 or x is d1) and (y is d0 or y is d1): - expected = 0 - elif x is y is d2: - expected = 0 - elif x is d2: - expected = -1 - else: - assert y is d2 - expected = 1 - assert got == expected - - -# Testing time objects with a non-None tzinfo. -class TestTimeTZ(TestTime, TZInfoBase): - theclass = time - - def test_empty(self): - t = self.theclass() - assert t.hour == 0 - assert t.minute == 0 - assert t.second == 0 - assert t.microsecond == 0 - assert t.tzinfo is None - - def test_zones(self): - est = FixedOffset(-300, "EST", 1) - utc = FixedOffset(0, "UTC", -2) - met = FixedOffset(60, "MET", 3) - t1 = time( 7, 47, tzinfo=est) - t2 = time(12, 47, tzinfo=utc) - t3 = time(13, 47, tzinfo=met) - t4 = time(microsecond=40) - t5 = time(microsecond=40, tzinfo=utc) - - assert t1.tzinfo == est - assert t2.tzinfo == utc - assert t3.tzinfo == met - assert t4.tzinfo is None - assert t5.tzinfo == utc - - assert t1.utcoffset() == timedelta(minutes=-300) - assert t2.utcoffset() == timedelta(minutes=0) - assert t3.utcoffset() == timedelta(minutes=60) - assert t4.utcoffset() is None - raises(TypeError, t1.utcoffset, "no args") - - assert t1.tzname() == "EST" - assert t2.tzname() == "UTC" - assert t3.tzname() == "MET" - assert t4.tzname() is None - raises(TypeError, t1.tzname, "no args") - - assert t1.dst() == timedelta(minutes=1) - assert t2.dst() == timedelta(minutes=-2) - assert t3.dst() == timedelta(minutes=3) - assert t4.dst() is None - raises(TypeError, t1.dst, "no args") - - assert hash(t1) == hash(t2) - assert hash(t1) == hash(t3) - assert hash(t2) == hash(t3) - - assert t1 == t2 - assert t1 == t3 - assert t2 == t3 - raises(TypeError, lambda: t4 == t5) # mixed tz-aware & naive - raises(TypeError, lambda: t4 < t5) # mixed tz-aware & naive - raises(TypeError, lambda: t5 < t4) # mixed tz-aware & naive - - assert str(t1) == "07:47:00-05:00" - assert str(t2) == "12:47:00+00:00" - assert str(t3) == "13:47:00+01:00" - assert str(t4) == "00:00:00.000040" - assert str(t5) == "00:00:00.000040+00:00" - - assert t1.isoformat() == "07:47:00-05:00" - assert t2.isoformat() == "12:47:00+00:00" - assert t3.isoformat() == "13:47:00+01:00" - assert t4.isoformat() == "00:00:00.000040" - assert t5.isoformat() == "00:00:00.000040+00:00" - - d = 'datetime.time' - assert repr(t1) == d + "(7, 47, tzinfo=est)" - assert repr(t2) == d + "(12, 47, tzinfo=utc)" - assert repr(t3) == d + "(13, 47, tzinfo=met)" - assert repr(t4) == d + "(0, 0, 0, 40)" - assert repr(t5) == d + "(0, 0, 0, 40, tzinfo=utc)" - - assert t1.strftime("%H:%M:%S %%Z=%Z %%z=%z") == ( - "07:47:00 %Z=EST %z=-0500") - assert t2.strftime("%H:%M:%S %Z %z") == "12:47:00 UTC +0000" - assert t3.strftime("%H:%M:%S %Z %z") == "13:47:00 MET +0100" - - yuck = FixedOffset(-1439, "%z %Z %%z%%Z") - t1 = time(23, 59, tzinfo=yuck) - assert t1.strftime("%H:%M %%Z='%Z' %%z='%z'") == ( - "23:59 %Z='%z %Z %%z%%Z' %z='-2359'") - - # Check that an invalid tzname result raises an exception. - class Badtzname(tzinfo): - def tzname(self, dt): return 42 - t = time(2, 3, 4, tzinfo=Badtzname()) - assert t.strftime("%H:%M:%S") == "02:03:04" - raises(TypeError, t.strftime, "%Z") - - def test_hash_edge_cases(self): - # Offsets that overflow a basic time. - t1 = self.theclass(0, 1, 2, 3, tzinfo=FixedOffset(1439, "")) - t2 = self.theclass(0, 0, 2, 3, tzinfo=FixedOffset(1438, "")) - assert hash(t1) == hash(t2) - - t1 = self.theclass(23, 58, 6, 100, tzinfo=FixedOffset(-1000, "")) - t2 = self.theclass(23, 48, 6, 100, tzinfo=FixedOffset(-1010, "")) - assert hash(t1) == hash(t2) - - def test_pickling(self): - # Try one without a tzinfo. - args = 20, 59, 16, 64**2 - orig = self.theclass(*args) - for pickler, unpickler, proto in pickle_choices: - green = pickler.dumps(orig, proto) - derived = unpickler.loads(green) - assert orig == derived - - # Try one with a tzinfo. - tinfo = PicklableFixedOffset(-300, 'cookie') - orig = self.theclass(5, 6, 7, tzinfo=tinfo) - for pickler, unpickler, proto in pickle_choices: - green = pickler.dumps(orig, proto) - derived = unpickler.loads(green) - assert orig == derived - assert isinstance(derived.tzinfo, PicklableFixedOffset) - assert derived.utcoffset() == timedelta(minutes=-300) - assert derived.tzname() == 'cookie' - - def test_more_bool(self): - # Test cases with non-None tzinfo. - cls = self.theclass - - t = cls(0, tzinfo=FixedOffset(-300, "")) - assert t - - t = cls(5, tzinfo=FixedOffset(-300, "")) - assert t - - t = cls(5, tzinfo=FixedOffset(300, "")) - assert not t - - t = cls(23, 59, tzinfo=FixedOffset(23*60 + 59, "")) - assert not t - - # Mostly ensuring this doesn't overflow internally. - t = cls(0, tzinfo=FixedOffset(23*60 + 59, "")) - assert t - - # But this should yield a value error -- the utcoffset is bogus. - t = cls(0, tzinfo=FixedOffset(24*60, "")) - raises(ValueError, lambda: bool(t)) - - # Likewise. - t = cls(0, tzinfo=FixedOffset(-24*60, "")) - raises(ValueError, lambda: bool(t)) - - def test_replace(self): - cls = self.theclass - z100 = FixedOffset(100, "+100") - zm200 = FixedOffset(timedelta(minutes=-200), "-200") - args = [1, 2, 3, 4, z100] - base = cls(*args) - assert base == base.replace() - - i = 0 - for name, newval in (("hour", 5), - ("minute", 6), - ("second", 7), - ("microsecond", 8), - ("tzinfo", zm200)): - newargs = args[:] - newargs[i] = newval - expected = cls(*newargs) - got = base.replace(**{name: newval}) - assert expected == got - i += 1 - - # Ensure we can get rid of a tzinfo. - assert base.tzname() == "+100" - base2 = base.replace(tzinfo=None) - assert base2.tzinfo is None - assert base2.tzname() is None - - # Ensure we can add one. - base3 = base2.replace(tzinfo=z100) - assert base == base3 - assert base.tzinfo is base3.tzinfo - - # Out of bounds. - base = cls(1) - raises(ValueError, base.replace, hour=24) - raises(ValueError, base.replace, minute=-1) - raises(ValueError, base.replace, second=100) - raises(ValueError, base.replace, microsecond=1000000) - - def test_mixed_compare(self): - t1 = time(1, 2, 3) - t2 = time(1, 2, 3) - assert t1 == t2 - t2 = t2.replace(tzinfo=None) - assert t1 == t2 - t2 = t2.replace(tzinfo=FixedOffset(None, "")) - assert t1 == t2 - t2 = t2.replace(tzinfo=FixedOffset(0, "")) - raises(TypeError, lambda: t1 == t2) - - # In time w/ identical tzinfo objects, utcoffset is ignored. - class Varies(tzinfo): - def __init__(self): - self.offset = timedelta(minutes=22) - def utcoffset(self, t): - self.offset += timedelta(minutes=1) - return self.offset - - v = Varies() - t1 = t2.replace(tzinfo=v) - t2 = t2.replace(tzinfo=v) - assert t1.utcoffset() == timedelta(minutes=23) - assert t2.utcoffset() == timedelta(minutes=24) - assert t1 == t2 - - # But if they're not identical, it isn't ignored. - t2 = t2.replace(tzinfo=Varies()) - assert t1 < t2 # t1's offset counter still going up - - -# Testing datetime objects with a non-None tzinfo. - -class TestDateTimeTZ(TestDateTime, TZInfoBase): - theclass = datetime - - def test_trivial(self): - dt = self.theclass(1, 2, 3, 4, 5, 6, 7) - assert dt.year == 1 - assert dt.month == 2 - assert dt.day == 3 - assert dt.hour == 4 - assert dt.minute == 5 - assert dt.second == 6 - assert dt.microsecond == 7 - assert dt.tzinfo == None - - def test_even_more_compare(self): - # The test_compare() and test_more_compare() inherited from TestDate - # and TestDateTime covered non-tzinfo cases. - - # Smallest possible after UTC adjustment. - t1 = self.theclass(1, 1, 1, tzinfo=FixedOffset(1439, "")) - # Largest possible after UTC adjustment. - t2 = self.theclass(MAXYEAR, 12, 31, 23, 59, 59, 999999, - tzinfo=FixedOffset(-1439, "")) - - # Make sure those compare correctly, and w/o overflow. - assert t1 < t2 - assert t1 != t2 - assert t2 > t1 - - assert t1 == t1 - assert t2 == t2 - - # Equal afer adjustment. - t1 = self.theclass(1, 12, 31, 23, 59, tzinfo=FixedOffset(1, "")) - t2 = self.theclass(2, 1, 1, 3, 13, tzinfo=FixedOffset(3*60+13+2, "")) - assert t1 == t2 - - # Change t1 not to subtract a minute, and t1 should be larger. - t1 = self.theclass(1, 12, 31, 23, 59, tzinfo=FixedOffset(0, "")) - assert t1 > t2 - - # Change t1 to subtract 2 minutes, and t1 should be smaller. - t1 = self.theclass(1, 12, 31, 23, 59, tzinfo=FixedOffset(2, "")) - assert t1 < t2 - - # Back to the original t1, but make seconds resolve it. - t1 = self.theclass(1, 12, 31, 23, 59, tzinfo=FixedOffset(1, ""), - second=1) - assert t1 > t2 - - # Likewise, but make microseconds resolve it. - t1 = self.theclass(1, 12, 31, 23, 59, tzinfo=FixedOffset(1, ""), - microsecond=1) - assert t1 > t2 - - # Make t2 naive and it should fail. - t2 = self.theclass.min - raises(TypeError, lambda: t1 == t2) - assert t2 == t2 - - # It's also naive if it has tzinfo but tzinfo.utcoffset() is None. - class Naive(tzinfo): - def utcoffset(self, dt): return None - t2 = self.theclass(5, 6, 7, tzinfo=Naive()) - raises(TypeError, lambda: t1 == t2) - assert t2 == t2 - - # OTOH, it's OK to compare two of these mixing the two ways of being - # naive. - t1 = self.theclass(5, 6, 7) - assert t1 == t2 - - # Try a bogus uctoffset. - class Bogus(tzinfo): - def utcoffset(self, dt): - return timedelta(minutes=1440) # out of bounds - t1 = self.theclass(2, 2, 2, tzinfo=Bogus()) - t2 = self.theclass(2, 2, 2, tzinfo=FixedOffset(0, "")) - raises(ValueError, lambda: t1 == t2) - - def test_pickling(self): - # Try one without a tzinfo. - args = 6, 7, 23, 20, 59, 1, 64**2 - orig = self.theclass(*args) - for pickler, unpickler, proto in pickle_choices: - green = pickler.dumps(orig, proto) - derived = unpickler.loads(green) - assert orig == derived - - # Try one with a tzinfo. - tinfo = PicklableFixedOffset(-300, 'cookie') - orig = self.theclass(*args, **{'tzinfo': tinfo}) - derived = self.theclass(1, 1, 1, tzinfo=FixedOffset(0, "", 0)) - for pickler, unpickler, proto in pickle_choices: - green = pickler.dumps(orig, proto) - derived = unpickler.loads(green) - assert orig == derived - assert isinstance(derived.tzinfo, - PicklableFixedOffset) - assert derived.utcoffset() == timedelta(minutes=-300) - assert derived.tzname() == 'cookie' - - def test_extreme_hashes(self): - # If an attempt is made to hash these via subtracting the offset - # then hashing a datetime object, OverflowError results. The - # Python implementation used to blow up here. - t = self.theclass(1, 1, 1, tzinfo=FixedOffset(1439, "")) - hash(t) - t = self.theclass(MAXYEAR, 12, 31, 23, 59, 59, 999999, - tzinfo=FixedOffset(-1439, "")) - hash(t) - - # OTOH, an OOB offset should blow up. - t = self.theclass(5, 5, 5, tzinfo=FixedOffset(-1440, "")) - raises(ValueError, hash, t) - - def test_zones(self): - est = FixedOffset(-300, "EST") - utc = FixedOffset(0, "UTC") - met = FixedOffset(60, "MET") - t1 = datetime(2002, 3, 19, 7, 47, tzinfo=est) - t2 = datetime(2002, 3, 19, 12, 47, tzinfo=utc) - t3 = datetime(2002, 3, 19, 13, 47, tzinfo=met) - assert t1.tzinfo == est - assert t2.tzinfo == utc - assert t3.tzinfo == met - assert t1.utcoffset() == timedelta(minutes=-300) - assert t2.utcoffset() == timedelta(minutes=0) - assert t3.utcoffset() == timedelta(minutes=60) - assert t1.tzname() == "EST" - assert t2.tzname() == "UTC" - assert t3.tzname() == "MET" - assert hash(t1) == hash(t2) - assert hash(t1) == hash(t3) - assert hash(t2) == hash(t3) - assert t1 == t2 - assert t1 == t3 - assert t2 == t3 - assert str(t1) == "2002-03-19 07:47:00-05:00" - assert str(t2) == "2002-03-19 12:47:00+00:00" - assert str(t3) == "2002-03-19 13:47:00+01:00" - d = 'datetime.datetime(2002, 3, 19, ' - assert repr(t1) == d + "7, 47, tzinfo=est)" - assert repr(t2) == d + "12, 47, tzinfo=utc)" - assert repr(t3) == d + "13, 47, tzinfo=met)" - - def test_combine(self): - met = FixedOffset(60, "MET") - d = date(2002, 3, 4) - tz = time(18, 45, 3, 1234, tzinfo=met) - dt = datetime.combine(d, tz) - assert dt == datetime(2002, 3, 4, 18, 45, 3, 1234, - tzinfo=met) - - def test_extract(self): - met = FixedOffset(60, "MET") - dt = self.theclass(2002, 3, 4, 18, 45, 3, 1234, tzinfo=met) - assert dt.date() == date(2002, 3, 4) - assert dt.time() == time(18, 45, 3, 1234) - assert dt.timetz() == time(18, 45, 3, 1234, tzinfo=met) - - def test_tz_aware_arithmetic(self): - import random - - now = self.theclass.now() - tz55 = FixedOffset(-330, "west 5:30") - timeaware = now.time().replace(tzinfo=tz55) - nowaware = self.theclass.combine(now.date(), timeaware) - assert nowaware.tzinfo is tz55 - assert nowaware.timetz() == timeaware - - # Can't mix aware and non-aware. - raises(TypeError, lambda: now - nowaware) - raises(TypeError, lambda: nowaware - now) - - # And adding datetime's doesn't make sense, aware or not. - raises(TypeError, lambda: now + nowaware) - raises(TypeError, lambda: nowaware + now) - raises(TypeError, lambda: nowaware + nowaware) - - # Subtracting should yield 0. - assert now - now == timedelta(0) - assert nowaware - nowaware == timedelta(0) - - # Adding a delta should preserve tzinfo. - delta = timedelta(weeks=1, minutes=12, microseconds=5678) - nowawareplus = nowaware + delta - assert nowaware.tzinfo is tz55 - nowawareplus2 = delta + nowaware - assert nowawareplus2.tzinfo is tz55 - assert nowawareplus == nowawareplus2 - - # that - delta should be what we started with, and that - what we - # started with should be delta. - diff = nowawareplus - delta - assert diff.tzinfo is tz55 - assert nowaware == diff - raises(TypeError, lambda: delta - nowawareplus) - assert nowawareplus - nowaware == delta - - # Make up a random timezone. - tzr = FixedOffset(random.randrange(-1439, 1440), "randomtimezone") - # Attach it to nowawareplus. - nowawareplus = nowawareplus.replace(tzinfo=tzr) - assert nowawareplus.tzinfo is tzr - # Make sure the difference takes the timezone adjustments into account. - got = nowaware - nowawareplus - # Expected: (nowaware base - nowaware offset) - - # (nowawareplus base - nowawareplus offset) = - # (nowaware base - nowawareplus base) + - # (nowawareplus offset - nowaware offset) = - # -delta + nowawareplus offset - nowaware offset - expected = nowawareplus.utcoffset() - nowaware.utcoffset() - delta - assert got == expected - - # Try max possible difference. - min = self.theclass(1, 1, 1, tzinfo=FixedOffset(1439, "min")) - max = self.theclass(MAXYEAR, 12, 31, 23, 59, 59, 999999, - tzinfo=FixedOffset(-1439, "max")) - maxdiff = max - min - assert maxdiff == ( self.theclass.max - self.theclass.min + - timedelta(minutes=2*1439)) - - def test_tzinfo_now(self): - meth = self.theclass.now - # Ensure it doesn't require tzinfo (i.e., that this doesn't blow up). - base = meth() - # Try with and without naming the keyword. - off42 = FixedOffset(42, "42") - another = meth(off42) - again = meth(tz=off42) - assert another.tzinfo is again.tzinfo - assert another.utcoffset() == timedelta(minutes=42) - # Bad argument with and w/o naming the keyword. - raises(TypeError, meth, 16) - raises(TypeError, meth, tzinfo=16) - # Bad keyword name. - raises(TypeError, meth, tinfo=off42) - # Too many args. - raises(TypeError, meth, off42, off42) - - # We don't know which time zone we're in, and don't have a tzinfo - # class to represent it, so seeing whether a tz argument actually - # does a conversion is tricky. - weirdtz = FixedOffset(timedelta(hours=15, minutes=58), "weirdtz", 0) - utc = FixedOffset(0, "utc", 0) - for dummy in range(3): - now = datetime.now(weirdtz) - assert now.tzinfo is weirdtz - utcnow = datetime.utcnow().replace(tzinfo=utc) - now2 = utcnow.astimezone(weirdtz) - if abs(now - now2) < timedelta(seconds=30): - break - # Else the code is broken, or more than 30 seconds passed between - # calls; assuming the latter, just try again. - else: - # Three strikes and we're out. - raise AssertionError, "utcnow(), now(tz), or astimezone() may be broken" - - def test_tzinfo_fromtimestamp(self): - import time - meth = self.theclass.fromtimestamp - ts = time.time() - # Ensure it doesn't require tzinfo (i.e., that this doesn't blow up). - base = meth(ts) - # Try with and without naming the keyword. - off42 = FixedOffset(42, "42") - another = meth(ts, off42) - again = meth(ts, tz=off42) - assert another.tzinfo is again.tzinfo - assert another.utcoffset() == timedelta(minutes=42) - # Bad argument with and w/o naming the keyword. - raises(TypeError, meth, ts, 16) - raises(TypeError, meth, ts, tzinfo=16) - # Bad keyword name. - raises(TypeError, meth, ts, tinfo=off42) - # Too many args. - raises(TypeError, meth, ts, off42, off42) - # Too few args. - raises(TypeError, meth) - - # Try to make sure tz= actually does some conversion. - timestamp = 1000000000 - utcdatetime = datetime.utcfromtimestamp(timestamp) - # In POSIX (epoch 1970), that's 2001-09-09 01:46:40 UTC, give or take. - # But on some flavor of Mac, it's nowhere near that. So we can't have - # any idea here what time that actually is, we can only test that - # relative changes match. - utcoffset = timedelta(hours=-15, minutes=39) # arbitrary, but not zero - tz = FixedOffset(utcoffset, "tz", 0) - expected = utcdatetime + utcoffset - got = datetime.fromtimestamp(timestamp, tz) - assert expected == got.replace(tzinfo=None) - - def test_tzinfo_utcnow(self): - meth = self.theclass.utcnow - # Ensure it doesn't require tzinfo (i.e., that this doesn't blow up). - base = meth() - # Try with and without naming the keyword; for whatever reason, - # utcnow() doesn't accept a tzinfo argument. - off42 = FixedOffset(42, "42") - raises(TypeError, meth, off42) - raises(TypeError, meth, tzinfo=off42) - - def test_tzinfo_utcfromtimestamp(self): - import time - meth = self.theclass.utcfromtimestamp - ts = time.time() - # Ensure it doesn't require tzinfo (i.e., that this doesn't blow up). - base = meth(ts) - # Try with and without naming the keyword; for whatever reason, - # utcfromtimestamp() doesn't accept a tzinfo argument. - off42 = FixedOffset(42, "42") - raises(TypeError, meth, ts, off42) - raises(TypeError, meth, ts, tzinfo=off42) - - def test_tzinfo_timetuple(self): - # TestDateTime tested most of this. datetime adds a twist to the - # DST flag. - class DST(tzinfo): - def __init__(self, dstvalue): - if isinstance(dstvalue, int): - dstvalue = timedelta(minutes=dstvalue) - self.dstvalue = dstvalue - def dst(self, dt): - return self.dstvalue - - cls = self.theclass - for dstvalue, flag in (-33, 1), (33, 1), (0, 0), (None, -1): - d = cls(1, 1, 1, 10, 20, 30, 40, tzinfo=DST(dstvalue)) - t = d.timetuple() - assert 1 == t.tm_year - assert 1 == t.tm_mon - assert 1 == t.tm_mday - assert 10 == t.tm_hour - assert 20 == t.tm_min - assert 30 == t.tm_sec - assert 0 == t.tm_wday - assert 1 == t.tm_yday - assert flag == t.tm_isdst - - # dst() returns wrong type. - raises(TypeError, cls(1, 1, 1, tzinfo=DST("x")).timetuple) - - # dst() at the edge. - assert cls(1,1,1, tzinfo=DST(1439)).timetuple().tm_isdst == 1 - assert cls(1,1,1, tzinfo=DST(-1439)).timetuple().tm_isdst == 1 - - # dst() out of range. - raises(ValueError, cls(1,1,1, tzinfo=DST(1440)).timetuple) - raises(ValueError, cls(1,1,1, tzinfo=DST(-1440)).timetuple) - - def test_utctimetuple(self): - class DST(tzinfo): - def __init__(self, dstvalue): - if isinstance(dstvalue, int): - dstvalue = timedelta(minutes=dstvalue) - self.dstvalue = dstvalue - def dst(self, dt): - return self.dstvalue - - cls = self.theclass - # This can't work: DST didn't implement utcoffset. - raises(NotImplementedError, - cls(1, 1, 1, tzinfo=DST(0)).utcoffset) - - class UOFS(DST): - def __init__(self, uofs, dofs=None): - DST.__init__(self, dofs) - self.uofs = timedelta(minutes=uofs) - def utcoffset(self, dt): - return self.uofs - - # Ensure tm_isdst is 0 regardless of what dst() says: DST is never - # in effect for a UTC time. - for dstvalue in -33, 33, 0, None: - d = cls(1, 2, 3, 10, 20, 30, 40, tzinfo=UOFS(-53, dstvalue)) - t = d.utctimetuple() - assert d.year == t.tm_year - assert d.month == t.tm_mon - assert d.day == t.tm_mday - assert 11 == t.tm_hour # 20mm + 53mm = 1hn + 13mm - assert 13 == t.tm_min - assert d.second == t.tm_sec - assert d.weekday() == t.tm_wday - assert d.toordinal() - date(1, 1, 1).toordinal() + 1 == ( - t.tm_yday) - assert 0 == t.tm_isdst - - # At the edges, UTC adjustment can normalize into years out-of-range - # for a datetime object. Ensure that a correct timetuple is - # created anyway. - tiny = cls(MINYEAR, 1, 1, 0, 0, 37, tzinfo=UOFS(1439)) - # That goes back 1 minute less than a full day. - t = tiny.utctimetuple() - assert t.tm_year == MINYEAR-1 - assert t.tm_mon == 12 - assert t.tm_mday == 31 - assert t.tm_hour == 0 - assert t.tm_min == 1 - assert t.tm_sec == 37 - assert t.tm_yday == 366 # "year 0" is a leap year - assert t.tm_isdst == 0 - - huge = cls(MAXYEAR, 12, 31, 23, 59, 37, 999999, tzinfo=UOFS(-1439)) - # That goes forward 1 minute less than a full day. - t = huge.utctimetuple() - assert t.tm_year == MAXYEAR+1 - assert t.tm_mon == 1 - assert t.tm_mday == 1 - assert t.tm_hour == 23 - assert t.tm_min == 58 - assert t.tm_sec == 37 - assert t.tm_yday == 1 - assert t.tm_isdst == 0 - - def test_tzinfo_isoformat(self): - zero = FixedOffset(0, "+00:00") - plus = FixedOffset(220, "+03:40") - minus = FixedOffset(-231, "-03:51") - unknown = FixedOffset(None, "") - - cls = self.theclass - datestr = '0001-02-03' - for ofs in None, zero, plus, minus, unknown: - for us in 0, 987001: - d = cls(1, 2, 3, 4, 5, 59, us, tzinfo=ofs) - timestr = '04:05:59' + (us and '.987001' or '') - ofsstr = ofs is not None and d.tzname() or '' - tailstr = timestr + ofsstr - iso = d.isoformat() - assert iso == datestr + 'T' + tailstr - assert iso == d.isoformat('T') - assert d.isoformat('k') == datestr + 'k' + tailstr - assert str(d) == datestr + ' ' + tailstr - - def test_replace(self): - cls = self.theclass - z100 = FixedOffset(100, "+100") - zm200 = FixedOffset(timedelta(minutes=-200), "-200") - args = [1, 2, 3, 4, 5, 6, 7, z100] - base = cls(*args) - assert base == base.replace() - - i = 0 - for name, newval in (("year", 2), - ("month", 3), - ("day", 4), - ("hour", 5), - ("minute", 6), - ("second", 7), - ("microsecond", 8), - ("tzinfo", zm200)): - newargs = args[:] - newargs[i] = newval - expected = cls(*newargs) - got = base.replace(**{name: newval}) - assert expected == got - i += 1 - - # Ensure we can get rid of a tzinfo. - assert base.tzname() == "+100" - base2 = base.replace(tzinfo=None) - assert base2.tzinfo is None - assert base2.tzname() is None - - # Ensure we can add one. - base3 = base2.replace(tzinfo=z100) - assert base == base3 - assert base.tzinfo is base3.tzinfo - - # Out of bounds. - base = cls(2000, 2, 29) - raises(ValueError, base.replace, year=2001) - - def test_more_astimezone(self): - # The inherited test_astimezone covered some trivial and error cases. - fnone = FixedOffset(None, "None") - f44m = FixedOffset(44, "44") - fm5h = FixedOffset(-timedelta(hours=5), "m300") - - dt = self.theclass.now(tz=f44m) - assert dt.tzinfo is f44m - # Replacing with degenerate tzinfo raises an exception. - raises(ValueError, dt.astimezone, fnone) - # Ditto with None tz. - raises(TypeError, dt.astimezone, None) - # Replacing with same tzinfo makes no change. - x = dt.astimezone(dt.tzinfo) - assert x.tzinfo is f44m - assert x.date() == dt.date() - assert x.time() == dt.time() - - # Replacing with different tzinfo does adjust. - got = dt.astimezone(fm5h) - assert got.tzinfo is fm5h - assert got.utcoffset() == timedelta(hours=-5) - expected = dt - dt.utcoffset() # in effect, convert to UTC - expected += fm5h.utcoffset(dt) # and from there to local time - expected = expected.replace(tzinfo=fm5h) # and attach new tzinfo - assert got.date() == expected.date() - assert got.time() == expected.time() - assert got.timetz() == expected.timetz() - assert got.tzinfo is expected.tzinfo - assert got == expected - - def test_aware_subtract(self): - cls = self.theclass - - # Ensure that utcoffset() is ignored when the operands have the - # same tzinfo member. - class OperandDependentOffset(tzinfo): - def utcoffset(self, t): - if t.minute < 10: - # d0 and d1 equal after adjustment - return timedelta(minutes=t.minute) - else: - # d2 off in the weeds - return timedelta(minutes=59) - - base = cls(8, 9, 10, 11, 12, 13, 14, tzinfo=OperandDependentOffset()) - d0 = base.replace(minute=3) - d1 = base.replace(minute=9) - d2 = base.replace(minute=11) - for x in d0, d1, d2: - for y in d0, d1, d2: - got = x - y - expected = timedelta(minutes=x.minute - y.minute) - assert got == expected - - # OTOH, if the tzinfo members are distinct, utcoffsets aren't - # ignored. - base = cls(8, 9, 10, 11, 12, 13, 14) - d0 = base.replace(minute=3, tzinfo=OperandDependentOffset()) - d1 = base.replace(minute=9, tzinfo=OperandDependentOffset()) - d2 = base.replace(minute=11, tzinfo=OperandDependentOffset()) - for x in d0, d1, d2: - for y in d0, d1, d2: - got = x - y - if (x is d0 or x is d1) and (y is d0 or y is d1): - expected = timedelta(0) - elif x is y is d2: - expected = timedelta(0) - elif x is d2: - expected = timedelta(minutes=(11-59)-0) - else: - assert y is d2 - expected = timedelta(minutes=0-(11-59)) - assert got == expected - - def test_mixed_compare(self): - t1 = datetime(1, 2, 3, 4, 5, 6, 7) - t2 = datetime(1, 2, 3, 4, 5, 6, 7) - assert t1 == t2 - t2 = t2.replace(tzinfo=None) - assert t1 == t2 - t2 = t2.replace(tzinfo=FixedOffset(None, "")) - assert t1 == t2 - t2 = t2.replace(tzinfo=FixedOffset(0, "")) - raises(TypeError, lambda: t1 == t2) - - # In datetime w/ identical tzinfo objects, utcoffset is ignored. - class Varies(tzinfo): - def __init__(self): - self.offset = timedelta(minutes=22) - def utcoffset(self, t): - self.offset += timedelta(minutes=1) - return self.offset - - v = Varies() - t1 = t2.replace(tzinfo=v) - t2 = t2.replace(tzinfo=v) - assert t1.utcoffset() == timedelta(minutes=23) - assert t2.utcoffset() == timedelta(minutes=24) - assert t1 == t2 - - # But if they're not identical, it isn't ignored. - t2 = t2.replace(tzinfo=Varies()) - assert t1 < t2 # t1's offset counter still going up - -# Pain to set up DST-aware tzinfo classes. - -def first_sunday_on_or_after(dt): - days_to_go = 6 - dt.weekday() - if days_to_go: - dt += timedelta(days_to_go) - return dt - -ZERO = timedelta(0) -HOUR = timedelta(hours=1) -DAY = timedelta(days=1) -# In the US, DST starts at 2am (standard time) on the first Sunday in April. -DSTSTART = datetime(1, 4, 1, 2) -# and ends at 2am (DST time; 1am standard time) on the last Sunday of Oct, -# which is the first Sunday on or after Oct 25. Because we view 1:MM as -# being standard time on that day, there is no spelling in local time of -# the last hour of DST (that's 1:MM DST, but 1:MM is taken as standard time). -DSTEND = datetime(1, 10, 25, 1) - -class USTimeZone(tzinfo): - - def __init__(self, hours, reprname, stdname, dstname): - self.stdoffset = timedelta(hours=hours) - self.reprname = reprname - self.stdname = stdname - self.dstname = dstname - - def __repr__(self): - return self.reprname - - def tzname(self, dt): - if self.dst(dt): - return self.dstname - else: - return self.stdname - - def utcoffset(self, dt): - return self.stdoffset + self.dst(dt) - - def dst(self, dt): - if dt is None or dt.tzinfo is None: - # An exception instead may be sensible here, in one or more of - # the cases. - return ZERO - assert dt.tzinfo is self - - # Find first Sunday in April. - start = first_sunday_on_or_after(DSTSTART.replace(year=dt.year)) - assert start.weekday() == 6 and start.month == 4 and start.day <= 7 - - # Find last Sunday in October. - end = first_sunday_on_or_after(DSTEND.replace(year=dt.year)) - assert end.weekday() == 6 and end.month == 10 and end.day >= 25 - - # Can't compare naive to aware objects, so strip the timezone from - # dt first. - if start <= dt.replace(tzinfo=None) < end: - return HOUR - else: - return ZERO - -Eastern = USTimeZone(-5, "Eastern", "EST", "EDT") -Central = USTimeZone(-6, "Central", "CST", "CDT") -Mountain = USTimeZone(-7, "Mountain", "MST", "MDT") -Pacific = USTimeZone(-8, "Pacific", "PST", "PDT") -utc_real = FixedOffset(0, "UTC", 0) -# For better test coverage, we want another flavor of UTC that's west of -# the Eastern and Pacific timezones. -utc_fake = FixedOffset(-12*60, "UTCfake", 0) - -class TestTimezoneConversions(object): - # The DST switch times for 2002, in std time. - dston = datetime(2002, 4, 7, 2) - dstoff = datetime(2002, 10, 27, 1) - - theclass = datetime - - # Check a time that's inside DST. - def checkinside(self, dt, tz, utc, dston, dstoff): - assert dt.dst() == HOUR - - # Conversion to our own timezone is always an identity. - assert dt.astimezone(tz) == dt - - asutc = dt.astimezone(utc) - there_and_back = asutc.astimezone(tz) - - # Conversion to UTC and back isn't always an identity here, - # because there are redundant spellings (in local time) of - # UTC time when DST begins: the clock jumps from 1:59:59 - # to 3:00:00, and a local time of 2:MM:SS doesn't really - # make sense then. The classes above treat 2:MM:SS as - # daylight time then (it's "after 2am"), really an alias - # for 1:MM:SS standard time. The latter form is what - # conversion back from UTC produces. - if dt.date() == dston.date() and dt.hour == 2: - # We're in the redundant hour, and coming back from - # UTC gives the 1:MM:SS standard-time spelling. - assert there_and_back + HOUR == dt - # Although during was considered to be in daylight - # time, there_and_back is not. - assert there_and_back.dst() == ZERO - # They're the same times in UTC. - assert there_and_back.astimezone(utc) == ( - dt.astimezone(utc)) - else: - # We're not in the redundant hour. - assert dt == there_and_back - - # Because we have a redundant spelling when DST begins, there is - # (unforunately) an hour when DST ends that can't be spelled at all in - # local time. When DST ends, the clock jumps from 1:59 back to 1:00 - # again. The hour 1:MM DST has no spelling then: 1:MM is taken to be - # standard time. 1:MM DST == 0:MM EST, but 0:MM is taken to be - # daylight time. The hour 1:MM daylight == 0:MM standard can't be - # expressed in local time. Nevertheless, we want conversion back - # from UTC to mimic the local clock's "repeat an hour" behavior. - nexthour_utc = asutc + HOUR - nexthour_tz = nexthour_utc.astimezone(tz) - if dt.date() == dstoff.date() and dt.hour == 0: - # We're in the hour before the last DST hour. The last DST hour - # is ineffable. We want the conversion back to repeat 1:MM. - assert nexthour_tz == dt.replace(hour=1) - nexthour_utc += HOUR - nexthour_tz = nexthour_utc.astimezone(tz) - assert nexthour_tz == dt.replace(hour=1) - else: - assert nexthour_tz - dt == HOUR - - # Check a time that's outside DST. - def checkoutside(self, dt, tz, utc): - assert dt.dst() == ZERO - - # Conversion to our own timezone is always an identity. - assert dt.astimezone(tz) == dt - - # Converting to UTC and back is an identity too. - asutc = dt.astimezone(utc) - there_and_back = asutc.astimezone(tz) - assert dt == there_and_back - - def convert_between_tz_and_utc(self, tz, utc): - dston = self.dston.replace(tzinfo=tz) - # Because 1:MM on the day DST ends is taken as being standard time, - # there is no spelling in tz for the last hour of daylight time. - # For purposes of the test, the last hour of DST is 0:MM, which is - # taken as being daylight time (and 1:MM is taken as being standard - # time). - dstoff = self.dstoff.replace(tzinfo=tz) - for delta in (timedelta(weeks=13), - DAY, - HOUR, - timedelta(minutes=1), - timedelta(microseconds=1)): - - self.checkinside(dston, tz, utc, dston, dstoff) - for during in dston + delta, dstoff - delta: - self.checkinside(during, tz, utc, dston, dstoff) - - self.checkoutside(dstoff, tz, utc) - for outside in dston - delta, dstoff + delta: - self.checkoutside(outside, tz, utc) - - def test_easy(self): - # Despite the name of this test, the endcases are excruciating. - self.convert_between_tz_and_utc(Eastern, utc_real) - self.convert_between_tz_and_utc(Pacific, utc_real) - self.convert_between_tz_and_utc(Eastern, utc_fake) - self.convert_between_tz_and_utc(Pacific, utc_fake) - # The next is really dancing near the edge. It works because - # Pacific and Eastern are far enough apart that their "problem - # hours" don't overlap. - self.convert_between_tz_and_utc(Eastern, Pacific) - self.convert_between_tz_and_utc(Pacific, Eastern) - # OTOH, these fail! Don't enable them. The difficulty is that - # the edge case tests assume that every hour is representable in - # the "utc" class. This is always true for a fixed-offset tzinfo - # class (lke utc_real and utc_fake), but not for Eastern or Central. - # For these adjacent DST-aware time zones, the range of time offsets - # tested ends up creating hours in the one that aren't representable - # in the other. For the same reason, we would see failures in the - # Eastern vs Pacific tests too if we added 3*HOUR to the list of - # offset deltas in convert_between_tz_and_utc(). - # - # self.convert_between_tz_and_utc(Eastern, Central) # can't work - # self.convert_between_tz_and_utc(Central, Eastern) # can't work - - def test_tricky(self): - # 22:00 on day before daylight starts. - fourback = self.dston - timedelta(hours=4) - ninewest = FixedOffset(-9*60, "-0900", 0) - fourback = fourback.replace(tzinfo=ninewest) - # 22:00-0900 is 7:00 UTC == 2:00 EST == 3:00 DST. Since it's "after - # 2", we should get the 3 spelling. - # If we plug 22:00 the day before into Eastern, it "looks like std - # time", so its offset is returned as -5, and -5 - -9 = 4. Adding 4 - # to 22:00 lands on 2:00, which makes no sense in local time (the - # local clock jumps from 1 to 3). The point here is to make sure we - # get the 3 spelling. - expected = self.dston.replace(hour=3) - got = fourback.astimezone(Eastern).replace(tzinfo=None) - assert expected == got - - # Similar, but map to 6:00 UTC == 1:00 EST == 2:00 DST. In that - # case we want the 1:00 spelling. - sixutc = self.dston.replace(hour=6, tzinfo=utc_real) - # Now 6:00 "looks like daylight", so the offset wrt Eastern is -4, - # and adding -4-0 == -4 gives the 2:00 spelling. We want the 1:00 EST - # spelling. - expected = self.dston.replace(hour=1) - got = sixutc.astimezone(Eastern).replace(tzinfo=None) - assert expected == got - - # Now on the day DST ends, we want "repeat an hour" behavior. - # UTC 4:MM 5:MM 6:MM 7:MM checking these - # EST 23:MM 0:MM 1:MM 2:MM - # EDT 0:MM 1:MM 2:MM 3:MM - # wall 0:MM 1:MM 1:MM 2:MM against these - for utc in utc_real, utc_fake: - for tz in Eastern, Pacific: - first_std_hour = self.dstoff - timedelta(hours=2) # 23:MM - # Convert that to UTC. - first_std_hour -= tz.utcoffset(None) - # Adjust for possibly fake UTC. - asutc = first_std_hour + utc.utcoffset(None) - # First UTC hour to convert; this is 4:00 when utc=utc_real & - # tz=Eastern. - asutcbase = asutc.replace(tzinfo=utc) - for tzhour in (0, 1, 1, 2): - expectedbase = self.dstoff.replace(hour=tzhour) - for minute in 0, 30, 59: - expected = expectedbase.replace(minute=minute) - asutc = asutcbase.replace(minute=minute) - astz = asutc.astimezone(tz) - assert astz.replace(tzinfo=None) == expected - asutcbase += HOUR - - - def test_bogus_dst(self): - class ok(tzinfo): - def utcoffset(self, dt): return HOUR - def dst(self, dt): return HOUR - - now = self.theclass.now().replace(tzinfo=utc_real) - # Doesn't blow up. - now.astimezone(ok()) - - # Does blow up. - class notok(ok): - def dst(self, dt): return None - raises(ValueError, now.astimezone, notok()) - - def test_fromutc(self): - raises(TypeError, Eastern.fromutc) # not enough args - now = datetime.utcnow().replace(tzinfo=utc_real) - raises(ValueError, Eastern.fromutc, now) # wrong tzinfo - now = now.replace(tzinfo=Eastern) # insert correct tzinfo - enow = Eastern.fromutc(now) # doesn't blow up - assert enow.tzinfo == Eastern # has right tzinfo member - raises(TypeError, Eastern.fromutc, now, now) # too many args - raises(TypeError, Eastern.fromutc, date.today()) # wrong type - - # Always converts UTC to standard time. - class FauxUSTimeZone(USTimeZone): - def fromutc(self, dt): - return dt + self.stdoffset - FEastern = FauxUSTimeZone(-5, "FEastern", "FEST", "FEDT") - - # UTC 4:MM 5:MM 6:MM 7:MM 8:MM 9:MM - # EST 23:MM 0:MM 1:MM 2:MM 3:MM 4:MM - # EDT 0:MM 1:MM 2:MM 3:MM 4:MM 5:MM - - # Check around DST start. - start = self.dston.replace(hour=4, tzinfo=Eastern) - fstart = start.replace(tzinfo=FEastern) - for wall in 23, 0, 1, 3, 4, 5: - expected = start.replace(hour=wall) - if wall == 23: - expected -= timedelta(days=1) - got = Eastern.fromutc(start) - assert expected == got - - expected = fstart + FEastern.stdoffset - got = FEastern.fromutc(fstart) - assert expected == got - - # Ensure astimezone() calls fromutc() too. - got = fstart.replace(tzinfo=utc_real).astimezone(FEastern) - assert expected == got - - start += HOUR - fstart += HOUR - - # Check around DST end. - start = self.dstoff.replace(hour=4, tzinfo=Eastern) - fstart = start.replace(tzinfo=FEastern) - for wall in 0, 1, 1, 2, 3, 4: - expected = start.replace(hour=wall) - got = Eastern.fromutc(start) - assert expected == got - - expected = fstart + FEastern.stdoffset - got = FEastern.fromutc(fstart) - assert expected == got - - # Ensure astimezone() calls fromutc() too. - got = fstart.replace(tzinfo=utc_real).astimezone(FEastern) - assert expected == got - - start += HOUR - fstart += HOUR - From tismer at codespeak.net Wed Mar 23 03:47:56 2005 From: tismer at codespeak.net (tismer at codespeak.net) Date: Wed, 23 Mar 2005 03:47:56 +0100 (MET) Subject: [pypy-svn] r10111 - in pypy/dist/pypy: objspace/flow translator Message-ID: <20050323024756.852A527B58@code1.codespeak.net> Author: tismer Date: Wed Mar 23 03:47:56 2005 New Revision: 10111 Modified: pypy/dist/pypy/objspace/flow/objspace.py pypy/dist/pypy/objspace/flow/specialcase.py pypy/dist/pypy/translator/geninterplevel.py pypy/dist/pypy/translator/translator.py Log: added a flag to translator/flowspace that disables immediate imports during flowgraphing. Modified: pypy/dist/pypy/objspace/flow/objspace.py ============================================================================== --- pypy/dist/pypy/objspace/flow/objspace.py (original) +++ pypy/dist/pypy/objspace/flow/objspace.py Wed Mar 23 03:47:56 2005 @@ -30,7 +30,9 @@ full_exceptions = False builtins_can_raise_exceptions = False - + + do_imports_immediately = True # overridden in geninterplevel + def initialize(self): import __builtin__ self.concrete_mode = 0 Modified: pypy/dist/pypy/objspace/flow/specialcase.py ============================================================================== --- pypy/dist/pypy/objspace/flow/specialcase.py (original) +++ pypy/dist/pypy/objspace/flow/specialcase.py Wed Mar 23 03:47:56 2005 @@ -91,6 +91,7 @@ def setup(space): fn = pyframe.normalize_exception.get_function(space) space.specialcases[fn] = sc_normalize_exception - space.specialcases[__import__] = sc_import + if space.do_imports_immediately: + space.specialcases[__import__] = sc_import for opname in ['lt', 'le', 'eq', 'ne', 'gt', 'ge', 'is_']: space.specialcases[getattr(operator, opname)] = sc_operator Modified: pypy/dist/pypy/translator/geninterplevel.py ============================================================================== --- pypy/dist/pypy/translator/geninterplevel.py (original) +++ pypy/dist/pypy/translator/geninterplevel.py Wed Mar 23 03:47:56 2005 @@ -1335,7 +1335,9 @@ # extract certain stuff like a general module maker # and put this into tools/compile_exceptions, maybe??? dic, entrypoint = exceptions_helper() - t = Translator(None, verbose=False, simplifying=True, builtins_can_raise_exceptions=True) + t = Translator(None, verbose=False, simplifying=True, + builtins_can_raise_exceptions=True, + do_imports_immediately=False) gen = GenRpy(t, entrypoint) gen.moddict = dic gen.gen_source('/tmp/look.py') @@ -1372,7 +1374,9 @@ def test(): entrypoint() - t = Translator(test, verbose=False, simplifying=True, builtins_can_raise_exceptions=True) + t = Translator(test, verbose=False, simplifying=True, + builtins_can_raise_exceptions=True, + do_imports_immediately=False) gen2 = GenRpy(t) gen2.gen_source("/tmp/look2.py") @@ -1402,7 +1406,9 @@ exec code in dic del dic['__builtins__'] entrypoint = dic - t = Translator(None, verbose=False, simplifying=True, builtins_can_raise_exceptions=True) + t = Translator(None, verbose=False, simplifying=True, + builtins_can_raise_exceptions=True, + do_imports_immediately=False) gen = GenRpy(t, entrypoint, modname, dic) if tmpname: out = file(tmpname, 'w') Modified: pypy/dist/pypy/translator/translator.py ============================================================================== --- pypy/dist/pypy/translator/translator.py (original) +++ pypy/dist/pypy/translator/translator.py Wed Mar 23 03:47:56 2005 @@ -46,11 +46,14 @@ class Translator: - def __init__(self, func=None, verbose=False, simplifying=True, builtins_can_raise_exceptions=False): + def __init__(self, func=None, verbose=False, simplifying=True, + builtins_can_raise_exceptions=False, + do_imports_immediately=True): self.entrypoint = func self.verbose = verbose self.simplifying = simplifying self.builtins_can_raise_exceptions = builtins_can_raise_exceptions + self.do_imports_immediately = do_imports_immediately self.clear() def clear(self): @@ -76,7 +79,8 @@ func.__name__) assert not self.frozen space = FlowObjSpace() - space.builtins_can_raise_exceptions = self.builtins_can_raise_exceptions + space.builtins_can_raise_exceptions = self.builtins_can_raise_exceptions + space.do_imports_immediately = self.do_imports_immediately graph = space.build_flow(func) if self.simplifying: simplify_graph(graph) From tismer at codespeak.net Wed Mar 23 03:48:45 2005 From: tismer at codespeak.net (tismer at codespeak.net) Date: Wed, 23 Mar 2005 03:48:45 +0100 (MET) Subject: [pypy-svn] r10112 - pypy/dist/lib-python-2.3.4/test Message-ID: <20050323024845.B8A8F27B58@code1.codespeak.net> Author: tismer Date: Wed Mar 23 03:48:45 2005 New Revision: 10112 Modified: pypy/dist/lib-python-2.3.4/test/conftest.py Log: binascii works, although slow Modified: pypy/dist/lib-python-2.3.4/test/conftest.py ============================================================================== --- pypy/dist/lib-python-2.3.4/test/conftest.py (original) +++ pypy/dist/lib-python-2.3.4/test/conftest.py Wed Mar 23 03:48:45 2005 @@ -37,6 +37,7 @@ 'test_commands.py', 'test_compare.py', 'test_compile.py', +'test_datetime.py', # it takes loong time 'test_dis.py', 'test_hash.py', 'test_heapq.py', @@ -123,7 +124,8 @@ assert classlist, ("found %s.test_main() but it returned no " "test classes" % mod.__name__) else: - # we try to find out fitting tests ourselves + # we try to find out fitting tests ourselves + raise Exception, mod.__dict__.items() for clsname, cls in mod.__dict__.items(): if hasattr(cls, '__bases__') and \ issubclass(cls, testcaseclass): From rxe at codespeak.net Wed Mar 23 04:55:44 2005 From: rxe at codespeak.net (rxe at codespeak.net) Date: Wed, 23 Mar 2005 04:55:44 +0100 (MET) Subject: [pypy-svn] r10113 - in pypy/dist/pypy: interpreter lib module module/builtin objspace tool Message-ID: <20050323035544.C978627B4B@code1.codespeak.net> Author: rxe Date: Wed Mar 23 04:55:44 2005 New Revision: 10113 Modified: pypy/dist/pypy/interpreter/eval.py pypy/dist/pypy/interpreter/executioncontext.py pypy/dist/pypy/interpreter/gateway.py pypy/dist/pypy/interpreter/interactive.py pypy/dist/pypy/interpreter/miscutils.py pypy/dist/pypy/interpreter/pycode.py pypy/dist/pypy/interpreter/pyframe.py pypy/dist/pypy/lib/_classobj.py pypy/dist/pypy/module/builtin/app_inspect.py pypy/dist/pypy/module/builtin/app_io.py pypy/dist/pypy/module/classobjinterp.py pypy/dist/pypy/objspace/trace.py pypy/dist/pypy/tool/traceop.py Log: * Removed ambiguity with applevel attribute of code objects: hidden_applevel * Some tidies in pyframe.py * Don't add frames with hidden code objects to * Fixes to sys._getframe() so tells the truth! * A dummy gc.py! * Hack in interactive to use its own executioncontext * regenerated module/classobjinterp.py Modified: pypy/dist/pypy/interpreter/eval.py ============================================================================== --- pypy/dist/pypy/interpreter/eval.py (original) +++ pypy/dist/pypy/interpreter/eval.py Wed Mar 23 04:55:44 2005 @@ -69,7 +69,7 @@ try: result = self.eval(executioncontext) finally: - executioncontext.leave(previous) + executioncontext.leave(previous, self) return result # running a frame is usually the same as resuming it from its Modified: pypy/dist/pypy/interpreter/executioncontext.py ============================================================================== --- pypy/dist/pypy/interpreter/executioncontext.py (original) +++ pypy/dist/pypy/interpreter/executioncontext.py Wed Mar 23 04:55:44 2005 @@ -7,7 +7,6 @@ in the Python interpreter.""" def __init__(self, space): - # Note that self.framestack only contains PyFrames self.space = space self.framestack = Stack() self.stateDict = {} @@ -23,21 +22,22 @@ previous_ec = locals.executioncontext locals.executioncontext = self - frame.f_back = None - for ff in self.framestack: - if not frame.code.getapplevel(): - frame.f_back = ff - break + try: + frame.f_back = self.framestack.top() + except: + frame.f_back = None - self.framestack.push(frame) + if not frame.code.hidden_applevel: + self.framestack.push(frame) return previous_ec - def leave(self, previous_ec): + def leave(self, previous_ec, frame): if self.w_profilefunc: - frame = self.framestack.top() self._trace(frame, 'leaveframe', None) - self.framestack.pop() + if not frame.code.hidden_applevel: + self.framestack.pop() + locals = getthreadlocals() locals.executioncontext = previous_ec @@ -126,7 +126,6 @@ if operror is not None: operror.clear(space) - def get_state_dict(self): """A mechanism to store arbitrary per ExecutionContext data. Similar to cpython's PyThreadState_GetDict. @@ -148,7 +147,7 @@ self.w_profilefunc = w_func def _trace(self, frame, event, w_arg): - if self.is_tracing or frame.code.getapplevel(): + if self.is_tracing or frame.code.hidden_applevel: return # Tracing cases @@ -192,7 +191,9 @@ self.space.wrap(frame), self.space.wrap(event), w_arg) except: - pass + self.w_profilefunc = None + raise + finally: frame.last_exception = last_exception self.is_tracing -= 1 Modified: pypy/dist/pypy/interpreter/gateway.py ============================================================================== --- pypy/dist/pypy/interpreter/gateway.py (original) +++ pypy/dist/pypy/interpreter/gateway.py Wed Mar 23 04:55:44 2005 @@ -485,7 +485,7 @@ interp-level function that invokes the callable with the given name at app-level.""" - applevel = True + hidden_applevel = True NOT_RPYTHON_ATTRIBUTES = ['code'] def __init__(self, source, filename=None): @@ -513,7 +513,7 @@ def _buildcode(cls, space, code): "NOT_RPYTHON" from pypy.interpreter.pycode import PyCode - return PyCode(space)._from_code(code, applevel=cls.applevel) + return PyCode(space)._from_code(code, hidden_applevel=cls.hidden_applevel) _buildcode = classmethod(_buildcode) def wget(self, space, name): @@ -583,12 +583,12 @@ # the following two will probably get merged into one class applevel_temp(applevel): - applevel = False + hidden_applevel = False def getwdict(self, space): return self._builddict(space) # no cache class applevelinterp_temp(applevelinterp): - applevel = False + hidden_applevel = False def getwdict(self, space): return self._builddict(space) # no cache Modified: pypy/dist/pypy/interpreter/interactive.py ============================================================================== --- pypy/dist/pypy/interpreter/interactive.py (original) +++ pypy/dist/pypy/interpreter/interactive.py Wed Mar 23 04:55:44 2005 @@ -91,7 +91,9 @@ self.space = objspace self.verbose = verbose self.ec = executioncontext.ExecutionContext(self.space) - + # Need a way for the object space to get the execution context + setattr(self.space, "createexecutioncontext", self.get_ec) + space=self.space mainmodule = main.ensure__main__(space) @@ -99,11 +101,14 @@ space.setitem(self.w_globals, space.wrap('__builtins__'), space.builtin) if completer: self.enable_command_line_completer() - # XXX check: do we need self.ec, self.w_globals? space.exec_("__pytrace__ = 0", self.w_globals, self.w_globals) self.tracelevel = 0 + def get_ec(self): + # XXX Wont handle threads + return self.ec + def enable_command_line_completer(self): try: import readline Modified: pypy/dist/pypy/interpreter/miscutils.py ============================================================================== --- pypy/dist/pypy/interpreter/miscutils.py (original) +++ pypy/dist/pypy/interpreter/miscutils.py Wed Mar 23 04:55:44 2005 @@ -42,10 +42,10 @@ def empty(self): return not self.items - def __iter__(self): - # Walk the stack backwards - for ii in self.items[::-1]: - yield ii +## def __iter__(self): +## # Walk the stack backwards +## for ii in self.items[::-1]: +## yield ii class InitializedClass(type): """NOT_RPYTHON. A meta-class that allows a class to initialize itself (or Modified: pypy/dist/pypy/interpreter/pycode.py ============================================================================== --- pypy/dist/pypy/interpreter/pycode.py (original) +++ pypy/dist/pypy/interpreter/pycode.py Wed Mar 23 04:55:44 2005 @@ -96,15 +96,15 @@ #self.co_name (in base class)# string: name, for reference self.co_firstlineno = 0 # first source line number self.co_lnotab = "" # string: encoding addr<->lineno mapping - self.applevel = False + self.hidden_applevel = False - def _from_code(self, code, applevel=False): + def _from_code(self, code, hidden_applevel=False): """ Initialize the code object from a real (CPython) one. This is just a hack, until we have our own compile. At the moment, we just fake this. This method is called by our compile builtin function. """ - self.applevel = applevel + self.hidden_applevel = hidden_applevel import types assert isinstance(code, types.CodeType) # simply try to suck in all attributes we know of @@ -142,7 +142,7 @@ newconsts_w = [] for const in code.co_consts: if isinstance(const, types.CodeType): - const = PyCode(space)._from_code(const, applevel=applevel) + const = PyCode(space)._from_code(const, hidden_applevel=hidden_applevel) newconsts_w.append(space.wrap(const)) self.co_consts_w = newconsts_w return self @@ -161,9 +161,6 @@ return Frame(space, self, w_globals, closure) signature = cpython_code_signature - - def getapplevel(self): - return self.applevel def getvarnames(self): return self.co_varnames Modified: pypy/dist/pypy/interpreter/pyframe.py ============================================================================== --- pypy/dist/pypy/interpreter/pyframe.py (original) +++ pypy/dist/pypy/interpreter/pyframe.py Wed Mar 23 04:55:44 2005 @@ -153,14 +153,17 @@ try: new_lineno = space.int_w(w_new_lineno) except OperationError, e: - raise OperationError(space.w_ValueError, space.wrap("lineno must be an integer")) + raise OperationError(space.w_ValueError, + space.wrap("lineno must be an integer")) self = space.interpclass_w(w_self) if self.w_f_trace is None: - raise OperationError(space.w_ValueError, space.wrap("f_lineo can only be set by a trace function.")) + raise OperationError(space.w_ValueError, + space.wrap("f_lineo can only be set by a trace function.")) if new_lineno < self.code.co_firstlineno: - raise OperationError(space.w_ValueError, space.wrap("line %d comes before the current code." % new_lineno)) + raise OperationError(space.w_ValueError, + space.wrap("line %d comes before the current code." % new_lineno)) code = self.code.co_code addr = 0 line = self.code.co_firstlineno @@ -176,13 +179,14 @@ break if new_lasti == -1: - raise OperationError(space.w_ValueError, space.wrap("line %d comes after the current code." % new_lineno)) + raise OperationError(space.w_ValueError, + space.wrap("line %d comes after the current code." % new_lineno)) # Don't jump to a line with an except in it. if ord(code[new_lasti]) in (DUP_TOP, POP_TOP): - raise OperationError(space.w_ValueError, space.wrap("can't jump to 'except' line as there's no exception")) + raise OperationError(space.w_ValueError, + space.wrap("can't jump to 'except' line as there's no exception")) - # Don't jump into or out of a finally block. f_lasti_setup_addr = -1 new_lasti_setup_addr = -1 @@ -205,7 +209,8 @@ blockstack.pop() if addr == new_lasti or addr == self.last_instr: - for setup_addr, in_finally in blockstack: + for ii in range(blockstack.depth()): + setup_addr, in_finally = blockstack.top(ii) if in_finally: if addr == new_lasti: new_lasti_setup_addr = setup_addr @@ -221,7 +226,9 @@ assert blockstack.empty() if new_lasti_setup_addr != f_lasti_setup_addr: - raise OperationError(space.w_ValueError, space.wrap("can't jump into or out of a 'finally' block %d -> %d"%(f_lasti_setup_addr, new_lasti_setup_addr))) + raise OperationError(space.w_ValueError, + space.wrap("can't jump into or out of a 'finally' block %d -> %d" % + (f_lasti_setup_addr, new_lasti_setup_addr))) if new_lasti < self.last_instr: min_addr = new_lasti @@ -255,7 +262,8 @@ new_iblock = f_iblock - delta_iblock if new_iblock > min_iblock: - raise OperationError(space.w_ValueError, space.wrap("can't jump into the middle of a block")) + raise OperationError(space.w_ValueError, + space.wrap("can't jump into the middle of a block")) while f_iblock > new_iblock: block = self.blockstack.pop() Modified: pypy/dist/pypy/lib/_classobj.py ============================================================================== --- pypy/dist/pypy/lib/_classobj.py (original) +++ pypy/dist/pypy/lib/_classobj.py Wed Mar 23 04:55:44 2005 @@ -1,3 +1,7 @@ +# - classobjinterp obtained from _classobj with: +# translator/tool/tointerplevel.py --modname=classobj --out module/classobjinterp.py lib/_classobj.py classobj instance purify + + import sys, operator # producing nicer code objects by exec Modified: pypy/dist/pypy/module/builtin/app_inspect.py ============================================================================== --- pypy/dist/pypy/module/builtin/app_inspect.py (original) +++ pypy/dist/pypy/module/builtin/app_inspect.py Wed Mar 23 04:55:44 2005 @@ -6,13 +6,13 @@ import sys def globals(): - return sys._getframe(1).f_globals + return sys._getframe(0).f_globals def locals(): - return sys._getframe(1).f_locals + return sys._getframe(0).f_locals def _caller_locals(): - return sys._getframe(2).f_locals + return sys._getframe(0).f_locals def _recursive_issubclass(cls, klass_or_tuple): if cls is klass_or_tuple: Modified: pypy/dist/pypy/module/builtin/app_io.py ============================================================================== --- pypy/dist/pypy/module/builtin/app_io.py (original) +++ pypy/dist/pypy/module/builtin/app_io.py Wed Mar 23 04:55:44 2005 @@ -6,10 +6,10 @@ def execfile(filename, glob=None, loc=None): if glob is None: - caller = sys._getframe(1) - glob = caller.f_globals + # Warning this is at hidden_applevel + glob = globals() if loc is None: - loc = caller.f_locals + loc = locals() elif loc is None: loc = glob f = file(filename, 'rU') Modified: pypy/dist/pypy/module/classobjinterp.py ============================================================================== --- pypy/dist/pypy/module/classobjinterp.py (original) +++ pypy/dist/pypy/module/classobjinterp.py Wed Mar 23 04:55:44 2005 @@ -9,7 +9,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function '_coerce' -## firstlineno 7 +## firstlineno 11 ##SECTION## def _coerce(space, __args__): funcname = "_coerce" @@ -68,7 +68,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function 'uid' -## firstlineno 18 +## firstlineno 22 ##SECTION## # global declarations # global object gi_0 @@ -115,7 +115,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function 'type_err' -## firstlineno 35 +## firstlineno 39 ##SECTION## # global declaration # global object gs_argument__s_must_be__s__not__s @@ -150,7 +150,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function 'set_name' -## firstlineno 38 +## firstlineno 42 ##SECTION## # global declarations # global object gs___name___must_be_a_string_object @@ -198,7 +198,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function 'set_bases' -## firstlineno 43 +## firstlineno 47 ##SECTION## # global declarations # global object gs___bases___must_be_a_tuple_object @@ -278,7 +278,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function 'set_dict' -## firstlineno 51 +## firstlineno 55 ##SECTION## # global declarations # global object gcls_TypeError @@ -325,7 +325,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function 'retrieve' -## firstlineno 56 +## firstlineno 60 ##SECTION## # global declarations # global object gdescriptor_object___getattribute__ @@ -367,7 +367,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function 'lookup' -## firstlineno 63 +## firstlineno 67 ##SECTION## # global declaration # global object g2tuple_1 @@ -483,7 +483,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function 'get_class_module' -## firstlineno 75 +## firstlineno 79 ##SECTION## # global declarations # global object gfunc_retrieve @@ -559,7 +559,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function 'mro_lookup' -## firstlineno 84 +## firstlineno 88 ##SECTION## # global declaration # global object gs___mro__ @@ -632,7 +632,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function '__new__' -## firstlineno 112 +## firstlineno 116 ##SECTION## # global declarations # global object gfunc_type_err @@ -916,7 +916,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function '__setattr__' -## firstlineno 162 +## firstlineno 166 ##SECTION## # global declarations # global object gfunc_set_name @@ -999,7 +999,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function '__delattr__' -## firstlineno 172 +## firstlineno 176 ##SECTION## # global declarations # global object g3tuple_2 @@ -1047,7 +1047,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function '__getattribute__' -## firstlineno 179 +## firstlineno 183 ##SECTION## # global declarations # global object gs___get__ @@ -1181,7 +1181,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function '__repr__' -## firstlineno 196 +## firstlineno 200 ##SECTION## # global declarations # global object gfunc_uid @@ -1217,7 +1217,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function '__str__' -## firstlineno 200 +## firstlineno 204 ##SECTION## # global declarations # global object gfunc_get_class_module @@ -1270,7 +1270,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function '__call__' -## firstlineno 207 +## firstlineno 211 ##SECTION## # global declarations # global object gbltinmethod___new__ @@ -1334,7 +1334,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function 'instance_getattr1' -## firstlineno 228 +## firstlineno 232 ##SECTION## # global declarations # global object gs___class__ @@ -1495,7 +1495,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function '__getattribute__' -## firstlineno 252 +## firstlineno 256 ##SECTION## # global declaration # global object gs___getattr__ @@ -1576,7 +1576,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function '__new__' -## firstlineno 261 +## firstlineno 265 ##SECTION## # global declarations # global object gs_instance___first_arg_must_be_cla @@ -1660,7 +1660,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function '__setattr__' -## firstlineno 274 +## firstlineno 278 ##SECTION## # global declarations # global object gs___dict___must_be_set_to_a_dictio @@ -1777,7 +1777,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function '__delattr__' -## firstlineno 290 +## firstlineno 294 ##SECTION## # global declarations # global object g2tuple_2 @@ -1862,7 +1862,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function '__repr__' -## firstlineno 306 +## firstlineno 310 ##SECTION## # global declaration # global object gs___s__s_instance_at_0x_x_ @@ -1940,7 +1940,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function '__str__' -## firstlineno 315 +## firstlineno 319 ##SECTION## def __str__(space, __args__): funcname = "__str__" @@ -2010,7 +2010,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function '__hash__' -## firstlineno 322 +## firstlineno 326 ##SECTION## # global declarations # global object gs_unhashable_instance @@ -2117,7 +2117,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function '__len__' -## firstlineno 336 +## firstlineno 340 ##SECTION## # global declarations # global object gs___len_____should_return____0 @@ -2179,7 +2179,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function '__getitem__' -## firstlineno 345 +## firstlineno 349 ##SECTION## # global declaration # global object gs___getslice__ @@ -2256,7 +2256,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function '__setitem__' -## firstlineno 352 +## firstlineno 356 ##SECTION## # global declarations # global object gs_step @@ -2338,7 +2338,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function '__delitem__' -## firstlineno 359 +## firstlineno 363 ##SECTION## # global declaration # global object gs___delslice__ @@ -2415,7 +2415,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function '__contains__' -## firstlineno 366 +## firstlineno 370 ##SECTION## def __contains__(space, __args__): funcname = "__contains__" @@ -2483,7 +2483,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function '__abs__' -## firstlineno 381 +## firstlineno 385 ##SECTION## def __abs__(space, __args__): funcname = "__abs__" @@ -2512,7 +2512,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function '__float__' -## firstlineno 381 +## firstlineno 385 ##SECTION## def __float__(space, __args__): funcname = "__float__" @@ -2541,7 +2541,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function '__hex__' -## firstlineno 381 +## firstlineno 385 ##SECTION## def __hex__(space, __args__): funcname = "__hex__" @@ -2570,7 +2570,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function '__int__' -## firstlineno 381 +## firstlineno 385 ##SECTION## def __int__(space, __args__): funcname = "__int__" @@ -2599,7 +2599,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function '__invert__' -## firstlineno 381 +## firstlineno 385 ##SECTION## def __invert__(space, __args__): funcname = "__invert__" @@ -2628,7 +2628,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function '__long__' -## firstlineno 381 +## firstlineno 385 ##SECTION## def __long__(space, __args__): funcname = "__long__" @@ -2657,7 +2657,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function '__neg__' -## firstlineno 381 +## firstlineno 385 ##SECTION## def __neg__(space, __args__): funcname = "__neg__" @@ -2686,7 +2686,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function '__oct__' -## firstlineno 381 +## firstlineno 385 ##SECTION## def __oct__(space, __args__): funcname = "__oct__" @@ -2715,7 +2715,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function '__pos__' -## firstlineno 381 +## firstlineno 385 ##SECTION## def __pos__(space, __args__): funcname = "__pos__" @@ -2744,7 +2744,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function '__coerce__' -## firstlineno 387 +## firstlineno 391 ##SECTION## def __coerce__(space, __args__): funcname = "__coerce__" @@ -2783,7 +2783,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function '__add__' -## firstlineno 404 +## firstlineno 408 ##SECTION## def __add__(space, __args__): funcname = "__add__" @@ -2855,7 +2855,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function '__and__' -## firstlineno 404 +## firstlineno 408 ##SECTION## def __and__(space, __args__): funcname = "__and__" @@ -2927,7 +2927,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function '__div__' -## firstlineno 404 +## firstlineno 408 ##SECTION## def __div__(space, __args__): funcname = "__div__" @@ -2999,7 +2999,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function '__divmod__' -## firstlineno 404 +## firstlineno 408 ##SECTION## def __divmod__(space, __args__): funcname = "__divmod__" @@ -3071,7 +3071,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function '__floordiv__' -## firstlineno 404 +## firstlineno 408 ##SECTION## def __floordiv__(space, __args__): funcname = "__floordiv__" @@ -3143,7 +3143,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function '__lshift__' -## firstlineno 404 +## firstlineno 408 ##SECTION## def __lshift__(space, __args__): funcname = "__lshift__" @@ -3215,7 +3215,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function '__mod__' -## firstlineno 404 +## firstlineno 408 ##SECTION## def __mod__(space, __args__): funcname = "__mod__" @@ -3287,7 +3287,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function '__mul__' -## firstlineno 404 +## firstlineno 408 ##SECTION## def __mul__(space, __args__): funcname = "__mul__" @@ -3359,7 +3359,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function '__or__' -## firstlineno 404 +## firstlineno 408 ##SECTION## def __or__(space, __args__): funcname = "__or__" @@ -3431,7 +3431,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function '__rshift__' -## firstlineno 404 +## firstlineno 408 ##SECTION## def __rshift__(space, __args__): funcname = "__rshift__" @@ -3503,7 +3503,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function '__sub__' -## firstlineno 404 +## firstlineno 408 ##SECTION## def __sub__(space, __args__): funcname = "__sub__" @@ -3575,7 +3575,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function '__truediv__' -## firstlineno 404 +## firstlineno 408 ##SECTION## def __truediv__(space, __args__): funcname = "__truediv__" @@ -3647,7 +3647,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function '__xor__' -## firstlineno 404 +## firstlineno 408 ##SECTION## # global declaration # global object gfunc__coerce @@ -3722,7 +3722,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function '__radd__' -## firstlineno 414 +## firstlineno 418 ##SECTION## def __radd__(space, __args__): funcname = "__radd__" @@ -3794,7 +3794,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function '__rand__' -## firstlineno 414 +## firstlineno 418 ##SECTION## def __rand__(space, __args__): funcname = "__rand__" @@ -3866,7 +3866,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function '__rdiv__' -## firstlineno 414 +## firstlineno 418 ##SECTION## def __rdiv__(space, __args__): funcname = "__rdiv__" @@ -3938,7 +3938,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function '__rdivmod__' -## firstlineno 414 +## firstlineno 418 ##SECTION## def __rdivmod__(space, __args__): funcname = "__rdivmod__" @@ -4010,7 +4010,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function '__rfloordiv__' -## firstlineno 414 +## firstlineno 418 ##SECTION## def __rfloordiv__(space, __args__): funcname = "__rfloordiv__" @@ -4082,7 +4082,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function '__rlshift__' -## firstlineno 414 +## firstlineno 418 ##SECTION## def __rlshift__(space, __args__): funcname = "__rlshift__" @@ -4154,7 +4154,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function '__rmod__' -## firstlineno 414 +## firstlineno 418 ##SECTION## def __rmod__(space, __args__): funcname = "__rmod__" @@ -4226,7 +4226,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function '__rmul__' -## firstlineno 414 +## firstlineno 418 ##SECTION## def __rmul__(space, __args__): funcname = "__rmul__" @@ -4298,7 +4298,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function '__ror__' -## firstlineno 414 +## firstlineno 418 ##SECTION## def __ror__(space, __args__): funcname = "__ror__" @@ -4370,7 +4370,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function '__rrshift__' -## firstlineno 414 +## firstlineno 418 ##SECTION## def __rrshift__(space, __args__): funcname = "__rrshift__" @@ -4442,7 +4442,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function '__rsub__' -## firstlineno 414 +## firstlineno 418 ##SECTION## def __rsub__(space, __args__): funcname = "__rsub__" @@ -4514,7 +4514,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function '__rtruediv__' -## firstlineno 414 +## firstlineno 418 ##SECTION## def __rtruediv__(space, __args__): funcname = "__rtruediv__" @@ -4586,7 +4586,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function '__rxor__' -## firstlineno 414 +## firstlineno 418 ##SECTION## def __rxor__(space, __args__): funcname = "__rxor__" @@ -4658,7 +4658,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function '__iadd__' -## firstlineno 432 +## firstlineno 436 ##SECTION## def __iadd__(space, __args__): funcname = "__iadd__" @@ -4697,7 +4697,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function '__iand__' -## firstlineno 432 +## firstlineno 436 ##SECTION## def __iand__(space, __args__): funcname = "__iand__" @@ -4736,7 +4736,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function '__idiv__' -## firstlineno 432 +## firstlineno 436 ##SECTION## def __idiv__(space, __args__): funcname = "__idiv__" @@ -4775,7 +4775,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function '__ifloordiv__' -## firstlineno 432 +## firstlineno 436 ##SECTION## def __ifloordiv__(space, __args__): funcname = "__ifloordiv__" @@ -4814,7 +4814,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function '__ilshift__' -## firstlineno 432 +## firstlineno 436 ##SECTION## def __ilshift__(space, __args__): funcname = "__ilshift__" @@ -4853,7 +4853,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function '__imod__' -## firstlineno 432 +## firstlineno 436 ##SECTION## def __imod__(space, __args__): funcname = "__imod__" @@ -4892,7 +4892,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function '__imul__' -## firstlineno 432 +## firstlineno 436 ##SECTION## def __imul__(space, __args__): funcname = "__imul__" @@ -4931,7 +4931,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function '__ior__' -## firstlineno 432 +## firstlineno 436 ##SECTION## def __ior__(space, __args__): funcname = "__ior__" @@ -4970,7 +4970,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function '__ipow__' -## firstlineno 432 +## firstlineno 436 ##SECTION## def __ipow__(space, __args__): funcname = "__ipow__" @@ -5009,7 +5009,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function '__irshift__' -## firstlineno 432 +## firstlineno 436 ##SECTION## def __irshift__(space, __args__): funcname = "__irshift__" @@ -5048,7 +5048,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function '__isub__' -## firstlineno 432 +## firstlineno 436 ##SECTION## def __isub__(space, __args__): funcname = "__isub__" @@ -5087,7 +5087,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function '__itruediv__' -## firstlineno 432 +## firstlineno 436 ##SECTION## def __itruediv__(space, __args__): funcname = "__itruediv__" @@ -5126,7 +5126,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function '__ixor__' -## firstlineno 432 +## firstlineno 436 ##SECTION## def __ixor__(space, __args__): funcname = "__ixor__" @@ -5165,7 +5165,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function '__pow__' -## firstlineno 441 +## firstlineno 445 ##SECTION## def __pow__(space, __args__): funcname = "__pow__" @@ -5264,7 +5264,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function '__rpow__' -## firstlineno 459 +## firstlineno 463 ##SECTION## def __rpow__(space, __args__): funcname = "__rpow__" @@ -5363,7 +5363,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function '__nonzero__' -## firstlineno 477 +## firstlineno 481 ##SECTION## # global declarations # global object gs___nonzero_____should_return____0 @@ -5451,7 +5451,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function '__call__' -## firstlineno 492 +## firstlineno 496 ##SECTION## # global declaration # global object gs__s_instance_has_no___call___meth @@ -5504,7 +5504,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function '__eq__' -## firstlineno 503 +## firstlineno 507 ##SECTION## def __eq__(space, __args__): funcname = "__eq__" @@ -5574,7 +5574,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function '__ge__' -## firstlineno 503 +## firstlineno 507 ##SECTION## def __ge__(space, __args__): funcname = "__ge__" @@ -5644,7 +5644,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function '__gt__' -## firstlineno 503 +## firstlineno 507 ##SECTION## def __gt__(space, __args__): funcname = "__gt__" @@ -5714,7 +5714,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function '__le__' -## firstlineno 503 +## firstlineno 507 ##SECTION## def __le__(space, __args__): funcname = "__le__" @@ -5784,7 +5784,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function '__lt__' -## firstlineno 503 +## firstlineno 507 ##SECTION## def __lt__(space, __args__): funcname = "__lt__" @@ -5854,7 +5854,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function '__ne__' -## firstlineno 503 +## firstlineno 507 ##SECTION## def __ne__(space, __args__): funcname = "__ne__" @@ -5924,7 +5924,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function '__iter__' -## firstlineno 512 +## firstlineno 516 ##SECTION## # global declarations # global object gs___iter___returned_non_iterator_o @@ -6001,7 +6001,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function 'next' -## firstlineno 527 +## firstlineno 531 ##SECTION## # global declaration # global object gs_instance_has_no_next___method @@ -6047,7 +6047,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function '__cmp__' -## firstlineno 533 +## firstlineno 537 ##SECTION## # global declarations # global object gs___cmp___must_return_int @@ -6230,7 +6230,7 @@ ##SECTION## ## filename 'lib/_classobj.py' ## function 'purify' -## firstlineno 571 +## firstlineno 575 ##SECTION## # global declarations # global object g3tuple Modified: pypy/dist/pypy/objspace/trace.py ============================================================================== --- pypy/dist/pypy/objspace/trace.py (original) +++ pypy/dist/pypy/objspace/trace.py Wed Mar 23 04:55:44 2005 @@ -111,11 +111,10 @@ self.result.append(EnterFrame(frame)) return self.ec.enter(frame) - def leave(self, previous_ec): + def leave(self, previous_ec, frame): """ called just after evaluating of a frame is suspended/finished. """ - frame = self.ec.framestack.top() self.result.append(LeaveFrame(frame)) - return self.ec.leave(previous_ec) + return self.ec.leave(previous_ec, frame) def bytecode_trace(self, frame): """ called just before execution of a bytecode. """ Modified: pypy/dist/pypy/tool/traceop.py ============================================================================== --- pypy/dist/pypy/tool/traceop.py (original) +++ pypy/dist/pypy/tool/traceop.py Wed Mar 23 04:55:44 2005 @@ -15,11 +15,14 @@ class ResultPrinter: - def __init__(self, show_applevel = False, recursive_operations = False, indentor = ' '): + def __init__(self, + show_hidden_applevel = False, + recursive_operations = False, + indentor = ' '): # Configurable stuff self.indentor = indentor - self.show_applevel = show_applevel + self.show_hidden_applevel = show_hidden_applevel self.recursive_operations = recursive_operations # Keeps a stack of current state to handle @@ -83,7 +86,7 @@ if isinstance(event, trace.EnterFrame): frame = event.frame - if self.show_applevel or not frame.code.getapplevel(): + if self.show_hidden_applevel or not frame.code.hidden_applevel: show = True else: show = False @@ -116,8 +119,8 @@ show = True # Check if we are in applevel? - if not self.show_applevel: - if lastframe is None or lastframe.code.getapplevel(): + if not self.show_hidden_applevel: + if lastframe is None or lastframe.code.hidden_applevel: show = False # Check if recursive operations? From cfbolz at codespeak.net Wed Mar 23 16:51:20 2005 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Wed, 23 Mar 2005 16:51:20 +0100 (MET) Subject: [pypy-svn] r10120 - in pypy/dist/pypy/translator/llvm: . test Message-ID: <20050323155120.25A3827B3E@code1.codespeak.net> Author: cfbolz Date: Wed Mar 23 16:51:19 2005 New Revision: 10120 Modified: pypy/dist/pypy/translator/llvm/genllvm.py pypy/dist/pypy/translator/llvm/list.c pypy/dist/pypy/translator/llvm/list_template.ll pypy/dist/pypy/translator/llvm/make_runtime.py pypy/dist/pypy/translator/llvm/representation.py pypy/dist/pypy/translator/llvm/test/llvmsnippet.py pypy/dist/pypy/translator/llvm/test/test_genllvm.py Log: Added pop method for lists. Modified: pypy/dist/pypy/translator/llvm/genllvm.py ============================================================================== --- pypy/dist/pypy/translator/llvm/genllvm.py (original) +++ pypy/dist/pypy/translator/llvm/genllvm.py Wed Mar 23 16:51:19 2005 @@ -143,21 +143,3 @@ for l_dep1 in traverse_dependencies(l_dep, seen_reprs): yield l_dep1 yield l_repr - - -def f(): - a = AAA() - b = BBB() - return a.g() + b.g() + a.get() + b.get() + AAA.get(b) - -t = Translator(f, simplifying=True) -a = t.annotate([]) -t.simplify() -a.simplify() -flg = t.getflowgraph() -bcls = a.binding(flg.startblock.operations[1].result).classdef -acls = bcls.basedef -t.view() -g = LLVMGenerator(t) -f1 = g.compile(True) -print f1(), f() Modified: pypy/dist/pypy/translator/llvm/list.c ============================================================================== --- pypy/dist/pypy/translator/llvm/list.c (original) +++ pypy/dist/pypy/translator/llvm/list.c Wed Mar 23 16:51:19 2005 @@ -28,6 +28,7 @@ return nlist; } +//XXX implement a real newlist with an arbitrary number of args struct list* newlist_ALTERNATIVE1(struct item* value) { struct list* nlist = malloc(sizeof(struct list)); nlist->length = 1; @@ -55,6 +56,19 @@ return nlist; } +struct list* newlist_ALTERNATIVE4(struct item* v1, struct item* v2, + struct item* v3, struct item* v4) { + struct list* nlist = malloc(sizeof(struct list)); + nlist->length = 4; + nlist->data = malloc(sizeof(struct item*) * 4); + nlist->data[0] = v1; + nlist->data[1] = v2; + nlist->data[2] = v3; + nlist->data[3] = v3; + return nlist; +} + + struct list* alloc_and_set(int length, struct item* init) { unsigned int i = 0; struct list* nlist = malloc(sizeof(struct list)); @@ -120,6 +134,24 @@ a->data = newdata; } +struct item* pop(struct list* a, int index) { + if (index < 0) + index = a->length + index; + struct item* ret = a->data[index]; + struct item** newdata = malloc(sizeof(struct item*) * (a->length - 1)); + copy(a->data, newdata, index); + copy(a->data + index + 1, newdata + index, a->length - 1 - index); + a->length -= 1; + free(a->data); + a->data = newdata; + return ret; +} + +struct item* pop_ALTERNATIVE1(struct list* a) { + return pop(a, a->length - 1); +} + + void reverse(struct list* a) { unsigned int lo = 0; unsigned int hi = a->length - 1; Modified: pypy/dist/pypy/translator/llvm/list_template.ll ============================================================================== --- pypy/dist/pypy/translator/llvm/list_template.ll (original) +++ pypy/dist/pypy/translator/llvm/list_template.ll Wed Mar 23 16:51:19 2005 @@ -81,6 +81,25 @@ ret %std.list.%(name)s* %tmp.0 } +internal %std.list.%(name)s* %std.newlist(%(item)s %v1, %(item)s %v2, %(item)s %v3, %(item)s %v4) { +entry: + %tmp.0 = malloc %std.list.%(name)s + %tmp.3 = getelementptr %std.list.%(name)s* %tmp.0, int 0, uint 0 + store uint 4, uint* %tmp.3 + %tmp.5 = getelementptr %std.list.%(name)s* %tmp.0, int 0, uint 1 + %tmp.6 = malloc [4 x %(item)s] + %tmp.6.sub = getelementptr [4 x %(item)s]* %tmp.6, int 0, int 0 + store %(item)s* %tmp.6.sub, %(item)s** %tmp.5 + store %(item)s %v1, %(item)s* %tmp.6.sub + %tmp.16 = getelementptr [4 x %(item)s]* %tmp.6, int 0, int 1 + store %(item)s %v2, %(item)s* %tmp.16 + %tmp.21 = getelementptr [4 x %(item)s]* %tmp.6, int 0, int 2 + store %(item)s %v3, %(item)s* %tmp.21 + %tmp.26 = getelementptr [4 x %(item)s]* %tmp.6, int 0, int 3 + store %(item)s %v3, %(item)s* %tmp.26 + ret %std.list.%(name)s* %tmp.0 +} + internal %std.list.%(name)s* %std.alloc_and_set(int %length, %(item)s %init) { entry: %tmp.0 = malloc %std.list.%(name)s @@ -329,6 +348,79 @@ ret void } +internal %(item)s %std.pop(%std.list.%(name)s* %a, int %index.1) { +entry: + %tmp.1 = setlt int %index.1, 0 + br bool %tmp.1, label %then, label %endif + +then: + %tmp.4 = getelementptr %std.list.%(name)s* %a, int 0, uint 0 + %tmp.5 = load uint* %tmp.4 + %tmp.5 = cast uint %tmp.5 to int + %tmp.9 = add int %tmp.5, %index.1 + br label %endif + +endif: + %index_addr.0 = phi int [ %tmp.9, %then ], [ %index.1, %entry ] + %tmp.11 = getelementptr %std.list.%(name)s* %a, int 0, uint 1 + %tmp.12 = load %(item)s** %tmp.11 + %tmp.14 = getelementptr %(item)s* %tmp.12, int %index_addr.0 + %tmp.15 = load %(item)s* %tmp.14 + %tmp.18 = getelementptr %std.list.%(name)s* %a, int 0, uint 0 + %tmp.19 = load uint* %tmp.18 + %tmp.19-off = add uint %tmp.19, 1073741823 + %tmp.16 = malloc %(item)s, uint %tmp.19-off + %tmp.28 = cast int %index_addr.0 to uint + %tmp.2.i14 = seteq int %index_addr.0, 0 + br bool %tmp.2.i14, label %copy.entry, label %no_exit.i + +no_exit.i: + %i.0.i.0 = phi uint [ %tmp.14.i, %no_exit.i ], [ 0, %endif ] + %tmp.7.i = getelementptr %(item)s* %tmp.16, uint %i.0.i.0 + %tmp.11.i = getelementptr %(item)s* %tmp.12, uint %i.0.i.0 + %tmp.12.i = load %(item)s* %tmp.11.i + store %(item)s %tmp.12.i, %(item)s* %tmp.7.i + %tmp.14.i = add uint %i.0.i.0, 1 + %tmp.2.i = setlt uint %tmp.14.i, %tmp.28 + br bool %tmp.2.i, label %no_exit.i, label %copy.entry + +copy.entry: + %tmp.35.sum = add int %index_addr.0, 1 + %tmp.48 = add uint %tmp.19, 4294967295 + %tmp.49 = sub uint %tmp.48, %tmp.28 + %tmp.2.i319 = seteq uint %tmp.48, %tmp.28 + br bool %tmp.2.i319, label %copy.entry9, label %no_exit.i4 + +no_exit.i4: + %i.0.i2.0 = phi uint [ %tmp.14.i8, %no_exit.i4 ], [ 0, %copy.entry ] + %i.0.i2.020 = cast uint %i.0.i2.0 to int + %tmp.42.sum = add int %i.0.i2.020, %index_addr.0 + %tmp.7.i5 = getelementptr %(item)s* %tmp.16, int %tmp.42.sum + %tmp.37.sum = add int %i.0.i2.020, %tmp.35.sum + %tmp.11.i6 = getelementptr %(item)s* %tmp.12, int %tmp.37.sum + %tmp.12.i7 = load %(item)s* %tmp.11.i6 + store %(item)s %tmp.12.i7, %(item)s* %tmp.7.i5 + %tmp.14.i8 = add uint %i.0.i2.0, 1 + %tmp.2.i3 = setlt uint %tmp.14.i8, %tmp.49 + br bool %tmp.2.i3, label %no_exit.i4, label %copy.entry9 + +copy.entry9: + store uint %tmp.48, uint* %tmp.18 + free %(item)s* %tmp.12 + store %(item)s* %tmp.16, %(item)s** %tmp.11 + ret %(item)s %tmp.15 +} + +internal %(item)s %std.pop(%std.list.%(name)s* %a) { +entry: + %tmp.3 = getelementptr %std.list.%(name)s* %a, int 0, uint 0 + %tmp.4 = load uint* %tmp.3 + %tmp.4 = cast uint %tmp.4 to int + %tmp.6 = add int %tmp.4, -1 + %tmp.0 = call %(item)s %std.pop( %std.list.%(name)s* %a, int %tmp.6 ) + ret %(item)s %tmp.0 +} + internal void %std.reverse(%std.list.%(name)s* %a) { entry: %tmp.1 = getelementptr %std.list.%(name)s* %a, int 0, uint 0 Modified: pypy/dist/pypy/translator/llvm/make_runtime.py ============================================================================== --- pypy/dist/pypy/translator/llvm/make_runtime.py (original) +++ pypy/dist/pypy/translator/llvm/make_runtime.py Wed Mar 23 16:51:19 2005 @@ -12,7 +12,7 @@ print cfile bytecode = udir.join("temp.bc") lastdir = path.local() - ops = ["llvm-gcc -c %s -o %s" % (cfile, bytecode), + ops = ["llvm-gcc -O3 -c %s -o %s" % (cfile, bytecode), "llvm-dis %s -f" % bytecode] for op in ops: print op Modified: pypy/dist/pypy/translator/llvm/representation.py ============================================================================== --- pypy/dist/pypy/translator/llvm/representation.py (original) +++ pypy/dist/pypy/translator/llvm/representation.py Wed Mar 23 16:51:19 2005 @@ -395,7 +395,7 @@ def t_op_getattr(self, l_target, args, lblock, l_func): if isinstance(args[1], Constant) and \ - args[1].value in ["append", "reverse"]: + args[1].value in ["append", "reverse", "pop"]: l_args0 = self.gen.get_repr(args[0]) l_func.dependencies.add(l_args0) l_method = BoundMethodRepr(l_target.type, l_args0, self, self.gen) Modified: pypy/dist/pypy/translator/llvm/test/llvmsnippet.py ============================================================================== --- pypy/dist/pypy/translator/llvm/test/llvmsnippet.py (original) +++ pypy/dist/pypy/translator/llvm/test/llvmsnippet.py Wed Mar 23 16:51:19 2005 @@ -114,6 +114,11 @@ def rangetest(i): return range(10)[i] +def array_pop(i): + a = [0, 1, 2, 3] + return a.pop() + len(a) + a[i] + + #class snippets class A(object): Modified: pypy/dist/pypy/translator/llvm/test/test_genllvm.py ============================================================================== --- pypy/dist/pypy/translator/llvm/test/test_genllvm.py (original) +++ pypy/dist/pypy/translator/llvm/test/test_genllvm.py Wed Mar 23 16:51:19 2005 @@ -176,6 +176,12 @@ for i in range(10): assert f(i) == i + def test_array_pop(i): + f = compile_function(llvmsnippet.array_pop, [int]) + assert f(0) == 5 + assert f(1) == 6 + assert f(2) == 7 + class TestClass(object): def setup_method(self, method): if not llvm_found: From cfbolz at codespeak.net Wed Mar 23 17:18:20 2005 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Wed, 23 Mar 2005 17:18:20 +0100 (MET) Subject: [pypy-svn] r10127 - pypy/dist/pypy/translator/llvm Message-ID: <20050323161820.94BDF27B3E@code1.codespeak.net> Author: cfbolz Date: Wed Mar 23 17:18:20 2005 New Revision: 10127 Modified: pypy/dist/pypy/translator/llvm/genllvm.py Log: Oops, forgot to take rlcompleter2 out Modified: pypy/dist/pypy/translator/llvm/genllvm.py ============================================================================== --- pypy/dist/pypy/translator/llvm/genllvm.py (original) +++ pypy/dist/pypy/translator/llvm/genllvm.py Wed Mar 23 17:18:20 2005 @@ -20,9 +20,6 @@ from pypy.translator.llvm.representation import * -import rlcompleter2 -rlcompleter2.setup() - debug = True From cfbolz at codespeak.net Thu Mar 24 01:07:45 2005 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Thu, 24 Mar 2005 01:07:45 +0100 (MET) Subject: [pypy-svn] r10136 - in pypy/dist/pypy/translator/llvm: . test Message-ID: <20050324000745.D2D4227B3E@code1.codespeak.net> Author: cfbolz Date: Thu Mar 24 01:07:45 2005 New Revision: 10136 Modified: pypy/dist/pypy/translator/llvm/genllvm.py pypy/dist/pypy/translator/llvm/representation.py pypy/dist/pypy/translator/llvm/test/llvmsnippet.py pypy/dist/pypy/translator/llvm/test/test_genllvm.py Log: Virtual functions functions are now called directly, if no "virtuality" is needed. Furthermore I fixed a few bugs and added an init function. Modified: pypy/dist/pypy/translator/llvm/genllvm.py ============================================================================== --- pypy/dist/pypy/translator/llvm/genllvm.py (original) +++ pypy/dist/pypy/translator/llvm/genllvm.py Thu Mar 24 01:07:45 2005 @@ -20,6 +20,7 @@ from pypy.translator.llvm.representation import * + debug = True @@ -48,12 +49,16 @@ if "Repr" in s] self.llvm_reprs = {} self.depth = 0 - self.l_entrypoint = self.get_repr( - Constant(self.translator.functions[0])) + self.entryname = self.translator.functions[0].__name__ + self.l_entrypoint = EntryFunctionRepr("%__entry__" + self.entryname, + self.translator.functions[0], + self) + self.local_counts[self.l_entrypoint] = 0 + self.l_entrypoint.setup() def compile(self, optimize=False): from pypy.tool.udir import udir - name = self.l_entrypoint.llvmname()[1:] + name = self.entryname llvmfile = udir.join('%s.ll' % name) f = llvmfile.open('w') self.write(f) @@ -64,7 +69,7 @@ f.close() mod = build_llvm_module.make_module_from_llvm(llvmfile, pyxfile, optimize) - return getattr(mod, "wrap_%s" % name) + return getattr(mod, "wrap_%s" % self.l_entrypoint.llvmname()[1:]) def get_global_tmp(self, used_by=None): used_by = (used_by or "unknown") @@ -140,3 +145,4 @@ for l_dep1 in traverse_dependencies(l_dep, seen_reprs): yield l_dep1 yield l_repr + Modified: pypy/dist/pypy/translator/llvm/representation.py ============================================================================== --- pypy/dist/pypy/translator/llvm/representation.py (original) +++ pypy/dist/pypy/translator/llvm/representation.py Thu Mar 24 01:07:45 2005 @@ -583,7 +583,7 @@ print "ClassRepr.setup()", id(self), hex(id(self)), self.setup_done print len(ClassRepr.l_classes) gen = self.gen - if self.classdef.basedef is not None: + if self.classdef.basedef is not None: #get attributes from base classes self.l_base = gen.get_repr(self.classdef.basedef) self.dependencies.add(self.l_base) attribs = self.l_base.attributes @@ -592,6 +592,7 @@ meth = [] if debug: print "attributes", self.classdef.attrs + #get attributes of this class and decide wether they are methods for key, attr in self.classdef.attrs.items(): if debug: print key, attr, attr.sources, attr.s_value, @@ -642,7 +643,7 @@ self.dependencies.update(l_args) # XXX if isinstance(l_init, VirtualMethodRepr): - l_init = l_init.l_funcs[l_init.classes.index(self.classdef)] + l_init = l_init.l_funcs[l_init.l_classes.index(self)] lblock.call_void(l_init, [l_target] + l_args) def t_op_getattr(self, l_target, args, lblock, l_func): @@ -694,7 +695,13 @@ else: raise CompileError, ("setattr called with unknown attribute %s" % \ args[1].value) - + + def iter_subclasses(self): + for cls, classdef in self.classdef.subdefs.iteritems(): + l_cls = self.gen.get_repr(classdef) + yield l_cls + for l_c in l_cls.iter_subclasses(): + yield l_c class BuiltinFunctionRepr(LLVMRepr): def get(obj, gen): @@ -722,17 +729,21 @@ class FunctionRepr(LLVMRepr): l_functions = {} def get(obj, gen): + name = None if isinstance(obj, annmodel.SomePBC) and \ len(obj.prebuiltinstances) == 1: obj = obj.prebuiltinstances.keys()[0] elif isinstance(obj, Constant): obj = obj.value if isinstance(obj, MethodType): - obj = obj.class_.__dict__[obj.__name__] + name = obj.im_class.__name__ + "." + obj.im_func.__name__ + obj = obj.im_func if isinstance(obj, FunctionType): if (obj, gen) in FunctionRepr.l_functions: return FunctionRepr.l_functions[(obj, gen)] - l_func = FunctionRepr(obj.__name__, obj, gen) + if name is None: + name = obj.__name__ + l_func = FunctionRepr(gen.get_global_tmp(name), obj, gen) FunctionRepr.l_functions[(obj, gen)] = l_func return l_func return None @@ -744,7 +755,7 @@ self.gen = gen self.func = function self.translator = gen.translator - self.name = "%" + name + self.name = name self.graph = self.translator.getflowgraph(self.func) self.annotator = gen.translator.annotator self.blocknum = {} @@ -888,9 +899,6 @@ def get_functions(self): return str(self.llvm_func) - def llvmname(self): - return self.name - def llvmtype(self): assert self.llvmfuncdef().count(self.name) == 1 return self.llvmfuncdef().replace(self.name + "(", "(") + "*" @@ -905,8 +913,87 @@ l_func.dependencies.update(l_args) lblock.call(l_target, l_args[0], l_args[1:]) +class EntryFunctionRepr(LLVMRepr): + def get(obj, gen): + return None + get = staticmethod(get) + + def __init__(self, name, function, gen): + self.gen = gen + self.function = function + self.name = name + self.dependencies = sets.Set() + self.branch_added = False + + def setup(self): + self.l_function = self.gen.get_repr(self.function) + self.dependencies.add(self.l_function) + lblock = llvmbc.BasicBlock("entry") + lblock.instruction("%tmp = load bool* %Initialized.0__") + lblock.instruction("br bool %tmp, label %real_entry, label %init") + self.llvm_func = llvmbc.Function(self.llvmfuncdef(), lblock) + self.init_block = llvmbc.BasicBlock("init") + self.init_block.instruction("store bool true, bool* %Initialized.0__") + real_entry = llvmbc.BasicBlock("real_entry") + l_ret = self.gen.get_local_tmp(self.l_function.retvalue.type, self) + self.l_function.op_simple_call( + l_ret, [self.function] + self.l_function.l_args, real_entry, self) + real_entry.ret(l_ret) + self.llvm_func.basic_block(real_entry) + self.llvm_func.basic_block(self.init_block) + + def cfuncdef(self): + a = self.l_function.translator.annotator + retv = self.l_function.graph.returnblock.inputargs[0] + rettype_c = C_SIMPLE_TYPES[a.binding(retv).__class__] + args = self.l_function.graph.startblock.inputargs + argtypes_c = [C_SIMPLE_TYPES[a.binding(v).__class__] for v in args] + fd = "%s %s(%s)" % (rettype_c, self.name[1:], + ", ".join(argtypes_c)) + return fd + + def llvmfuncdef(self): + s = "%s %s(" % (self.l_function.retvalue.llvmtype(), self.name) + s += ", ".join([a.typed_name() for a in self.l_function.l_args]) + ")" + return s + + def get_pyrex_source(self): + name = self.name[1:] + args = self.l_function.graph.startblock.inputargs + self.pyrex_source = ["cdef extern %s\n" % + (self.cfuncdef())] + self.pyrex_source += ["def wrap_%s(" % name] + t = [] + for i, a in enumerate(args): + t += ["%s" % a] + t = ", ".join(t) + self.pyrex_source += t + "):\n\treturn %s(%s)\n\n" % (name, t) + self.pyrex_source = "".join(self.pyrex_source) + return self.pyrex_source + + def rettype(self): + return self.l_function.retvalue.llvmtype() + + def get_functions(self): + if not self.branch_added: + self.init_block.uncond_branch("%real_entry") + return str(self.llvm_func) + + def get_globals(self): + return "%Initialized.0__ = internal global bool false" + + def llvmtype(self): + assert self.llvmfuncdef().count(self.name) == 1 + return self.llvmfuncdef().replace(self.name + "(", "(") + "*" + + def op_simple_call(self, l_target, args, lblock, l_func): + self.l_function.op_simple_call(l_target, [self.function] + args, + lblock, l_func) + class VirtualMethodRepr(LLVMRepr): # Really stupid implementation of virtual functions: + # Do a switch on the id of the class of the object and cast the object + # to the appropriate class # Should be replaced by function pointers def get(obj, gen): if isinstance(obj, annmodel.SomePBC) and \ @@ -920,27 +1007,37 @@ if debug: print "VirtualMethodRepr: %s" % prebuiltinstances self.gen = gen - self.classes = prebuiltinstances.values() - commonbase = reduce(lambda a, b: a.commonbase(b), self.classes) - self.commonbase_index = self.classes.index(commonbase) - self.commonbase = commonbase + classes = prebuiltinstances.values() + self.commonbase = reduce(lambda a, b: a.commonbase(b), classes) self.funcs = prebuiltinstances.keys() self.name = "%" + self.funcs[0].__name__ + ".virtual" + self.attribute = self.funcs[0].__name__ self.dependencies = sets.Set() def setup(self): - cbi = self.commonbase_index - self.l_funcs = [self.gen.get_repr(f) for f in self.funcs] - self.dependencies.update(self.l_funcs) - self.retvalue = self.l_funcs[cbi].retvalue - self.l_classes = [self.gen.get_repr(c) for c in self.classes] + self.l_commonbase = self.gen.get_repr(self.commonbase) + self.l_classes = [self.l_commonbase] + \ + list(self.l_commonbase.iter_subclasses()) self.dependencies.update(self.l_classes) - self.l_commonbase = self.l_classes[self.commonbase_index] + self.l_funcs = [] + #find appropriate method for every class + for l_cls in self.l_classes: + for classdef in l_cls.classdef.getmro(): + if classdef.cls.__dict__.has_key(self.attribute): + self.l_funcs.append(self.gen.get_repr( + classdef.cls.__dict__[self.attribute])) + break + else: + raise CompileError, "Couldn't find method %s for %s" % \ + (self.attribute, l_cls.classdef.cls) + self.dependencies.update(self.l_funcs) + self.retvalue = self.l_funcs[0].retvalue self.type_numbers = [id(l_c) for l_c in self.l_classes] self.l_args = [self.gen.get_repr(ar) - for ar in self.l_funcs[cbi].graph.startblock.inputargs] + for ar in self.l_funcs[0].graph.startblock.inputargs] l_retvalue = self.retvalue self.dependencies.update(self.l_args) + #create function entryblock = llvmbc.BasicBlock("entry") l_ptr = self.gen.get_local_tmp(PointerTypeRepr("uint", self.gen), self) l_type = self.gen.get_local_tmp(self.gen.get_repr( @@ -960,26 +1057,40 @@ l_tmp_ret = self.gen.get_local_tmp(l_retvalue.type, self) self.l_funcs[i].op_simple_call( l_tmp_ret, [self.l_funcs[i], l_tmp] + - self.l_funcs[cbi].graph.startblock.inputargs[1:], lblock, self) + self.l_funcs[0].graph.startblock.inputargs[1:], lblock, self) lblock.ret(l_tmp_ret) self.llvm_func = lfunc def op_simple_call(self, l_target, args, lblock, l_func): + name = self.name[1:-8] l_args = [self.gen.get_repr(arg) for arg in args] - self.dependencies.update(l_args) + l_func.dependencies.update(l_args) + # call the method directly if no subclass of the class of args[1] has + # a special version of this method defined + for l_cls in l_args[1].type.iter_subclasses(): + if l_cls.classdef.cls.__dict__.has_key(name): + break + else: + for clsdef in l_args[1].type.classdef.getmro(): + if clsdef.cls.__dict__.has_key(name): + l_method = self.gen.get_repr(clsdef.cls.__dict__[name]) + args[0] = l_method + print l_method.llvmname(), l_method + l_method.op_simple_call(l_target, args, lblock, l_func) + return if l_args[1].llvmtype() != self.l_args[0].llvmtype(): l_tmp = self.gen.get_local_tmp(self.l_args[0].type, l_func) + l_func.dependencies.add(l_tmp) lblock.cast(l_tmp, l_args[1]) l_args[1] = l_tmp - lblock.call(l_target, l_args[0], l_args[1:]) lblock.call(l_target, l_args[0], l_args[1:]) + return def get_functions(self): return str(self.llvm_func) def llvmfuncdef(self): - cbi = self.commonbase_index - s = "%s %s(" % (self.l_funcs[cbi].retvalue.llvmtype(), self.name) + s = "%s %s(" % (self.l_funcs[0].retvalue.llvmtype(), self.name) return s + ", ".join([a.typed_name() for a in self.l_args]) + ")" def rettype(self): @@ -997,13 +1108,6 @@ self.dependencies = sets.Set([l_self, l_class, l_func]) def t_op_simple_call(self, l_target, args, lblock, l_func): - if self.l_self.llvmtype() != self.l_class.llvmname(): - l_tmp = self.gen.get_local_tmp(self.l_class, l_func) - lblock.cast(l_tmp, self.l_self) - self.l_func.op_simple_call(l_target, - [self.l_func, l_tmp] + args[1:], - lblock, l_func) - else: - self.l_func.op_simple_call(l_target, - [self.l_func, self.l_self] + args[1:], - lblock, l_func) + self.l_func.op_simple_call(l_target, + [self.l_func, self.l_self] + args[1:], + lblock, l_func) Modified: pypy/dist/pypy/translator/llvm/test/llvmsnippet.py ============================================================================== --- pypy/dist/pypy/translator/llvm/test/llvmsnippet.py (original) +++ pypy/dist/pypy/translator/llvm/test/llvmsnippet.py Thu Mar 24 01:07:45 2005 @@ -189,6 +189,11 @@ def get(self): return 5 +class CCC(BBB): + def __init__(self): + AAA.__init__(self) + BBB.__init__(self) + def attribute_from_base_class(): a = AAA() b = BBB() @@ -199,6 +204,11 @@ b = BBB() return a.get() + AAA.get(b) + b.get() + b.g() +def direct_call_of_virtual_method(): + a = AAA() + b = BBB() + c = CCC() + return a.get() + b.get() + c.get() #string snippets def string_f1(i): Modified: pypy/dist/pypy/translator/llvm/test/test_genllvm.py ============================================================================== --- pypy/dist/pypy/translator/llvm/test/test_genllvm.py (original) +++ pypy/dist/pypy/translator/llvm/test/test_genllvm.py Thu Mar 24 01:07:45 2005 @@ -211,6 +211,10 @@ def test_attribute_from_base_class(self): f = compile_function(llvmsnippet.attribute_from_base_class, []) assert f() == 4 + + def test_direct_call_of_virtual_method(self): + f = compile_function(llvmsnippet.direct_call_of_virtual_method, []) + assert f() == 14 class TestString(object): def setup_method(self, method): From tismer at codespeak.net Sun Mar 27 22:28:22 2005 From: tismer at codespeak.net (tismer at codespeak.net) Date: Sun, 27 Mar 2005 22:28:22 +0200 (MEST) Subject: [pypy-svn] r10139 - pypy/dist/pypy/translator Message-ID: <20050327202822.A633627B36@code1.codespeak.net> Author: tismer Date: Sun Mar 27 22:28:22 2005 New Revision: 10139 Modified: pypy/dist/pypy/translator/geninterplevel.py Log: special handling for __builtins__. The names there are treated like global names. Certain things like __import__ are not further flow-analysed, because we want to have late importing by default. Modified: pypy/dist/pypy/translator/geninterplevel.py ============================================================================== --- pypy/dist/pypy/translator/geninterplevel.py (original) +++ pypy/dist/pypy/translator/geninterplevel.py Sun Mar 27 22:28:22 2005 @@ -31,7 +31,6 @@ from pypy.objspace.std.restricted_int import r_int, r_uint from pypy.translator.translator import Translator -from pypy.objspace.std import StdObjSpace from pypy.objspace.flow import FlowObjSpace from pypy.interpreter.gateway import app2interp, interp2app @@ -99,6 +98,21 @@ for name in "newtuple newlist newdict newstring".split(): self.has_listarg[name] = name + # catching all builtins inj advance, to avoid problems + # with modified builtins + import __builtin__ + + class bltinstub: + def __init__(self, name): + self.__name__ = name + def __repr__(self): + return '<%s>' % self.__name__ + + self.builtin_ids = dict( [ + (id(value), bltinstub(key)) + for key, value in __builtins__.items() + if callable(value) and type(value) not in [type(Exception), type] ] ) + self.space = FlowObjSpace() # for introspection self.use_fast_call = True @@ -250,20 +264,25 @@ # assume it's a user defined thingy name = self.nameof_instance(obj) else: - for cls in type(obj).__mro__: - meth = getattr(self, - 'nameof_' + cls.__name__.replace(' ', ''), - None) - if meth: - break + # shortcutting references to __builtin__ + if id(obj) in self.builtin_ids: + func = self.builtin_ids[id(obj)] + name = "(space.builtin.get(space.str_w(%s)))" % self.nameof(func.__name__) else: - raise Exception, "nameof(%r)" % (obj,) - - code = meth.im_func.func_code - if namehint and 'namehint' in code.co_varnames[:code.co_argcount]: - name = meth(obj, namehint=namehint) - else: - name = meth(obj) + for cls in type(obj).__mro__: + meth = getattr(self, + 'nameof_' + cls.__name__.replace(' ', ''), + None) + if meth: + break + else: + raise Exception, "nameof(%r)" % (obj,) + + code = meth.im_func.func_code + if namehint and 'namehint' in code.co_varnames[:code.co_argcount]: + name = meth(obj, namehint=namehint) + else: + name = meth(obj) self.debugstack, x = self.debugstack assert x is stackentry self.rpynames[key] = name @@ -473,10 +492,9 @@ return self._space_arities def try_space_shortcut_for_builtin(self, v, nargs): - if isinstance(v, Constant) and type(v.value) is type(len): - func = v.value - name = func.__name__ - if func.__self__ is None and hasattr(self.space, name): + if isinstance(v, Constant) and id(v.value) in self.builtin_ids: + name = self.builtin_ids[id(v.value)].__name__ + if hasattr(self.space, name): if self.space_arities().get(name, -1) == nargs: return "space.%s" % name return None @@ -484,6 +502,9 @@ def nameof_builtin_function_or_method(self, func): if func.__self__ is None: # builtin function + if id(func) in self.builtin_ids: + func = self.builtin_ids[id(func)] + return "(space.builtin.get(space.str_w(%s)))" % self.nameof(func.__name__) # where does it come from? Python2.2 doesn't have func.__module__ for modname, module in sys.modules.items(): if hasattr(module, '__file__'): @@ -496,8 +517,6 @@ else: raise Exception, '%r not found in any built-in module' % (func,) if modname == '__builtin__': - #self.initcode.append1('%s = space.getattr(space.w_builtin, %s)'% ( - # name, self.nameof(func.__name__))) # be lazy return "(space.builtin.get(space.str_w(%s)))" % self.nameof(func.__name__) elif modname == 'sys': From tismer at codespeak.net Sun Mar 27 22:30:50 2005 From: tismer at codespeak.net (tismer at codespeak.net) Date: Sun, 27 Mar 2005 22:30:50 +0200 (MEST) Subject: [pypy-svn] r10140 - pypy/dist/pypy/translator/test Message-ID: <20050327203050.04F4B27B36@code1.codespeak.net> Author: tismer Date: Sun Mar 27 22:30:50 2005 New Revision: 10140 Modified: pypy/dist/pypy/translator/test/test_geninterp.py Log: added a test for import. This is for applevelonly, so we chime it in at testing time, not modifying snippets.py. Modified: pypy/dist/pypy/translator/test/test_geninterp.py ============================================================================== --- pypy/dist/pypy/translator/test/test_geninterp.py (original) +++ pypy/dist/pypy/translator/test/test_geninterp.py Sun Mar 27 22:30:50 2005 @@ -38,19 +38,27 @@ class TestGenRpyTestCase: objspacename = 'std' + snippet_ad = """if 1: + def import_func(): + import copy_reg + return copy_reg._reconstructor.func_code.co_name""" + def __init__(self): # simply compile snippets just once src = str(Source(snippet)) # truncate non-compilable stuff for now: p = src.index('Non compilable Functions') - src = src[:p] + src = src[:p] + '\n' + # put our ad into snippet + exec self.snippet_ad in snippet.__dict__ + src += self.snippet_ad # just in case of trouble, we produce a tempfile ini = translate_as_module(src, tmpname = str(udir.join("_geninterp_test.py"))) self.w_glob = ini(self.space) def build_interpfunc(self, func, *morefuncs): # we ignore morefuncs, since they live in snippets - space =self.space + space = self.space func = space.getitem(self.w_glob, space.wrap(func.__name__)) def wrapunwrap(*args): w_args = space.wrap(args) @@ -65,6 +73,12 @@ return space.unwrap(w_res) return wrapunwrap + # small addition to see whether imports look fine + def test_import(self): + import copy_reg + impfunc = self.build_interpfunc(snippet.import_func) + assert impfunc() == '_reconstructor' + def test_simple_func(self): cfunc = self.build_interpfunc(snippet.simple_func) assert cfunc(1) == 2 From tismer at codespeak.net Sun Mar 27 22:31:51 2005 From: tismer at codespeak.net (tismer at codespeak.net) Date: Sun, 27 Mar 2005 22:31:51 +0200 (MEST) Subject: [pypy-svn] r10141 - in pypy/dist/pypy: interpreter objspace/flow Message-ID: <20050327203151.152F327B36@code1.codespeak.net> Author: tismer Date: Sun Mar 27 22:31:50 2005 New Revision: 10141 Modified: pypy/dist/pypy/interpreter/gateway.py pypy/dist/pypy/objspace/flow/__init__.py Log: all imports should be absolute if possible. Modified: pypy/dist/pypy/interpreter/gateway.py ============================================================================== --- pypy/dist/pypy/interpreter/gateway.py (original) +++ pypy/dist/pypy/interpreter/gateway.py Sun Mar 27 22:31:50 2005 @@ -558,6 +558,9 @@ w_glob = self.initfunc(space) return w_glob +# comment this out to check against applevel without translation +applevel = applevelinterp + ## XXX there is a problem with the naming convention of app_xxx not allowed ## for interp2app! What shall we do? Modified: pypy/dist/pypy/objspace/flow/__init__.py ============================================================================== --- pypy/dist/pypy/objspace/flow/__init__.py (original) +++ pypy/dist/pypy/objspace/flow/__init__.py Sun Mar 27 22:31:50 2005 @@ -1,2 +1,2 @@ -from objspace import FlowObjSpace +from pypy.objspace.flow.objspace import FlowObjSpace Space = FlowObjSpace From tismer at codespeak.net Sun Mar 27 22:35:49 2005 From: tismer at codespeak.net (tismer at codespeak.net) Date: Sun, 27 Mar 2005 22:35:49 +0200 (MEST) Subject: [pypy-svn] r10142 - pypy/dist/pypy/interpreter Message-ID: <20050327203549.9377127B36@code1.codespeak.net> Author: tismer Date: Sun Mar 27 22:35:49 2005 New Revision: 10142 Modified: pypy/dist/pypy/interpreter/gateway.py Log: reverted an unwanted checkin. applevel is going to be overrridden by applevelinterp, but before, circularities in pyframe/pyopcode have to be resolved. We also need to cache generatedcode, since flowgraphing costs a lot of time during startup. Modified: pypy/dist/pypy/interpreter/gateway.py ============================================================================== --- pypy/dist/pypy/interpreter/gateway.py (original) +++ pypy/dist/pypy/interpreter/gateway.py Sun Mar 27 22:35:49 2005 @@ -559,7 +559,7 @@ return w_glob # comment this out to check against applevel without translation -applevel = applevelinterp +##applevel = applevelinterp ## XXX there is a problem with the naming convention of app_xxx not allowed ## for interp2app! What shall we do? From tismer at codespeak.net Mon Mar 28 00:19:18 2005 From: tismer at codespeak.net (tismer at codespeak.net) Date: Mon, 28 Mar 2005 00:19:18 +0200 (MEST) Subject: [pypy-svn] r10143 - pypy/dist/pypy/translator Message-ID: <20050327221918.626BC27B36@code1.codespeak.net> Author: tismer Date: Mon Mar 28 00:19:18 2005 New Revision: 10143 Modified: pypy/dist/pypy/translator/geninterplevel.py Log: be independent from__builtins__ module/dict ambiguity Modified: pypy/dist/pypy/translator/geninterplevel.py ============================================================================== --- pypy/dist/pypy/translator/geninterplevel.py (original) +++ pypy/dist/pypy/translator/geninterplevel.py Mon Mar 28 00:19:18 2005 @@ -98,7 +98,7 @@ for name in "newtuple newlist newdict newstring".split(): self.has_listarg[name] = name - # catching all builtins inj advance, to avoid problems + # catching all builtins in advance, to avoid problems # with modified builtins import __builtin__ @@ -110,7 +110,7 @@ self.builtin_ids = dict( [ (id(value), bltinstub(key)) - for key, value in __builtins__.items() + for key, value in __builtin__.__dict__.items() if callable(value) and type(value) not in [type(Exception), type] ] ) self.space = FlowObjSpace() # for introspection From cfbolz at codespeak.net Mon Mar 28 22:09:03 2005 From: cfbolz at codespeak.net (cfbolz at codespeak.net) Date: Mon, 28 Mar 2005 22:09:03 +0200 (MEST) Subject: [pypy-svn] r10149 - in pypy/dist/pypy/translator/llvm: . test Message-ID: <20050328200903.2BAD127B36@code1.codespeak.net> Author: cfbolz Date: Mon Mar 28 22:09:02 2005 New Revision: 10149 Added: pypy/dist/pypy/translator/llvm/class.ll Modified: pypy/dist/pypy/translator/llvm/genllvm.py pypy/dist/pypy/translator/llvm/operations.ll pypy/dist/pypy/translator/llvm/representation.py pypy/dist/pypy/translator/llvm/test/llvmsnippet.py pypy/dist/pypy/translator/llvm/test/test_genllvm.py Log: Added support for isinstance checks. Added: pypy/dist/pypy/translator/llvm/class.ll ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/llvm/class.ll Mon Mar 28 22:09:02 2005 @@ -0,0 +1,40 @@ +;types for type info at runtime + +%std.class = type {%std.class*, uint} +%std.object = type {%std.class*} + + +implementation + + +;functions for type info at runtime + +bool %std.issubtype(%std.class* %a, %std.class* %b) { +entry: + br label %not_null +not_null: + %curr_a = phi %std.class* [%a, %entry], [%base, %recurse] + %n = seteq %std.class* %curr_a, null + br bool %n, label %return, label %if +if: + %same = seteq %std.class* %curr_a, %b + br bool %same, label %return, label %recurse +recurse: + %baseptr = getelementptr %std.class* %curr_a, int 0, uint 0 + %base = load %std.class** %baseptr + br label %not_null +return: + %result = phi bool [false, %not_null], [true, %if] + ret bool %result +} + +bool %std.isinstance(%std.object* %a, %std.class* %b) { +entry: + %baseptr = getelementptr %std.object* %a, int 0, uint 0 + %class = load %std.class** %baseptr + %result = call bool %std.issubtype(%std.class* %class, %std.class* %b) + ret bool %result +} + + + Modified: pypy/dist/pypy/translator/llvm/genllvm.py ============================================================================== --- pypy/dist/pypy/translator/llvm/genllvm.py (original) +++ pypy/dist/pypy/translator/llvm/genllvm.py Mon Mar 28 22:09:02 2005 @@ -113,17 +113,30 @@ raise CompileError, "Can't get repr of %s, %s" % (obj, obj.__class__) def write(self, f): + init_block = self.l_entrypoint.init_block + seen_reprs = sets.Set() + for l_repr in traverse_dependencies(self.l_entrypoint, seen_reprs): + l_repr.collect_init_code(init_block, self.l_entrypoint) + include_files = ["operations.ll", "class.ll"] + for i, fn in enumerate(include_files): + f1 = file(autopath.this_dir + "/" + fn) + s = f1.read() + include_files[i] = s.split("\nimplementation") + if len(include_files[i]) == 1: + include_files[i].insert(0, "") + f1.close() f.write("\n\n; +-------+\n; |globals|\n; +-------+\n\n") + for inc in include_files: + f.write(inc[0]) seen_reprs = sets.Set() for l_repr in traverse_dependencies(self.l_entrypoint, seen_reprs): s = l_repr.get_globals() if s != "": f.write(s + "\n") + f.write("implementation\n") f.write("\n\n; +---------+\n; |space_ops|\n; +---------+\n\n") - f1 = file(autopath.this_dir + "/operations.ll", "r") - s = f1.read() - f.write(s) - f1.close() + for inc in include_files: + f.write(inc[1]) f.write("\n\n; +---------+\n; |functions|\n; +---------+\n\n") seen_reprs = sets.Set() for l_repr in traverse_dependencies(self.l_entrypoint, seen_reprs): @@ -146,3 +159,4 @@ yield l_dep1 yield l_repr + Modified: pypy/dist/pypy/translator/llvm/operations.ll ============================================================================== --- pypy/dist/pypy/translator/llvm/operations.ll (original) +++ pypy/dist/pypy/translator/llvm/operations.ll Mon Mar 28 22:09:02 2005 @@ -1,8 +1,9 @@ -;implementation of space operations for simple types - implementation +;implementation of space operations for simple types + + declare void %llvm.memmove(sbyte*, sbyte*, uint, uint) declare void %llvm.memcpy(sbyte*, sbyte*, uint, uint) declare void %llvm.memset(sbyte*, ubyte, uint, uint) @@ -115,7 +116,9 @@ ret bool %r } + ;Logical operations for ints + internal int %std.and_(int %a, int %b) { %r = and int %a, %b ret int %r Modified: pypy/dist/pypy/translator/llvm/representation.py ============================================================================== --- pypy/dist/pypy/translator/llvm/representation.py (original) +++ pypy/dist/pypy/translator/llvm/representation.py Mon Mar 28 22:09:02 2005 @@ -33,7 +33,7 @@ annmodel.SomeBool: "bool"} -debug = True +debug = False class CompileError(exceptions.Exception): @@ -57,6 +57,9 @@ def get_functions(self): return "" + def collect_init_code(self, lblock, l_func): + pass + def llvmname(self): return self.name @@ -569,6 +572,8 @@ self.gen = gen self.includefile = "" self.name = gen.get_global_tmp("class.%s" % self.classdef.cls.__name__) + self.objectname = gen.get_global_tmp("class.%s.object" % + self.classdef.cls.__name__) if debug: print self.name self.dependencies = sets.Set() @@ -588,11 +593,12 @@ self.dependencies.add(self.l_base) attribs = self.l_base.attributes else: + self.l_base = None attribs = [] meth = [] if debug: print "attributes", self.classdef.attrs - #get attributes of this class and decide wether they are methods + #get attributes of this class and decide whether they are methods for key, attr in self.classdef.attrs.items(): if debug: print key, attr, attr.sources, attr.s_value, @@ -614,23 +620,45 @@ self.l_attrs_types = [gen.get_repr(attr.s_value) for attr in attribs] self.dependencies = sets.Set(self.l_attrs_types) attributes = ", ".join([at.llvmname() for at in self.l_attrs_types]) - self.definition = "%s = type {uint, %s}" % (self.name, attributes) + self.definition = "%s = type {%%std.class*, %s}" % (self.name, + attributes) self.attributes = attribs self.attr_num = {} for i, attr in enumerate(attribs): self.attr_num[attr.name] = i + 1 self.methods = dict(meth) + def get_globals(self): + s = "\n%s = internal global %%std.class {%%std.class* null, uint %i}" + s = s % (self.objectname, abs(id(self))) + return self.definition + s + + def collect_init_code(self, lblock, l_func): + if self.l_base is None: + return + l_tmp = self.gen.get_local_tmp(None, l_func) + i = "%s = getelementptr %%std.class* %s, int 0, uint 0" % \ + (l_tmp.llvmname(), self.objectname) + lblock.instruction(i) + lblock.instruction("store %%std.class* %s, %%std.class** %s" % + (self.l_base.objectname, l_tmp.llvmname())) + + def llvmtype(self): + return "%std.class* " + + def typed_name(self): + #XXXX: Ouch. I get bitten by the fact that + # in LLVM typedef != class object + # This will work, as long as class objects are only passed to functions + return "%%std.class* %s" % self.objectname + def op_simple_call(self, l_target, args, lblock, l_func): lblock.malloc(l_target, self) - l_tmp = self.gen.get_local_tmp(PointerTypeRepr("uint", self.gen), - l_func) + l_tmp = self.gen.get_local_tmp( + PointerTypeRepr("%std.class*", self.gen), l_func) lblock.getelementptr(l_tmp, l_target, [0, 0]) - #XXX: store the id of the ClassRepr for isinstance checks, - #polymorphism etc. Should probably replace this with a pointer to a - #virtual function table instead - lblock.instruction("store uint %s, %s" % - (id(self), l_tmp.typed_name())) + lblock.instruction("store %%std.class* %s, %s" % + (self.objectname, l_tmp.typed_name())) init = None for cls in self.classdef.getmro(): if "__init__" in cls.attrs: @@ -724,6 +752,12 @@ def op_simple_call(self, l_target, args, lblock, l_func): l_args = [self.gen.get_repr(arg) for arg in args] l_func.dependencies.update(l_args) + if self.name == "%std.isinstance": + l_tmp = self.gen.get_local_tmp(PointerTypeRepr("%std.object", + self.gen), l_func) + l_func.dependencies.add(l_tmp) + lblock.cast(l_tmp, l_args[1]) + l_args[1] = l_tmp lblock.call(l_target, l_args[0], l_args[1:]) class FunctionRepr(LLVMRepr): @@ -813,6 +847,20 @@ l_v2 = self.gen.get_repr(incoming_links[0].args[i]) self.dependencies.update([l_arg, l_switch, l_v1, l_v2]) lblock.select(l_arg, l_select, l_v1, l_v2) + #special case for isinstance blocks: + #if the type changes a cast is neccessary + elif len(incoming_links) == 1: + link = incoming_links[0] + for i, arg in enumerate(pyblock.inputargs): + l_arg = self.gen.get_repr(arg) + l_value = self.gen.get_repr(link.args[i]) + self.dependencies.update([l_arg, l_value]) + if l_arg.llvmtype() == l_value.llvmtype(): + lblock.phi( + l_arg, [l_value], + ["%%block%i" % self.blocknum[link.prevblock]]) + else: + lblock.cast(l_arg, l_value) elif len(incoming_links) != 0: for i, arg in enumerate(pyblock.inputargs): l_arg = self.gen.get_repr(arg) @@ -865,34 +913,10 @@ "%%block%i" % self.blocknum[pyblock.exits[1].target], "%%block%i" % self.blocknum[pyblock.exits[0].target]) - def cfuncdef(self): - a = self.translator.annotator - retv = self.graph.returnblock.inputargs[0] - rettype_c = C_SIMPLE_TYPES[a.binding(retv).__class__] - args = self.graph.startblock.inputargs - argtypes_c = [C_SIMPLE_TYPES[a.binding(v).__class__] for v in args] - fd = "%s %s(%s)" % (rettype_c, self.func.func_name, - ", ".join(argtypes_c)) - return fd - def llvmfuncdef(self): - s = "%s %s(" % (self.retvalue.llvmtype(), self.name) + s = "internal %s %s(" % (self.retvalue.llvmtype(), self.name) return s + ", ".join([a.typed_name() for a in self.l_args]) + ")" - def get_pyrex_source(self): - name = self.func.func_name - args = self.graph.startblock.inputargs - self.pyrex_source = ["cdef extern %s\n" % - (self.cfuncdef())] - self.pyrex_source += ["def wrap_%s(" % name] - t = [] - for i, a in enumerate(args): - t += ["%s" % a] - t = ", ".join(t) - self.pyrex_source += t + "):\n\treturn %s(%s)\n\n" % (name, t) - self.pyrex_source = "".join(self.pyrex_source) - return self.pyrex_source - def rettype(self): return self.retvalue.llvmtype() @@ -1038,19 +1062,27 @@ l_retvalue = self.retvalue self.dependencies.update(self.l_args) #create function + #XXX pretty messy entryblock = llvmbc.BasicBlock("entry") - l_ptr = self.gen.get_local_tmp(PointerTypeRepr("uint", self.gen), self) - l_type = self.gen.get_local_tmp(self.gen.get_repr( - annmodel.SomeInteger(True, True)), self) - self.dependencies.update([l_ptr, l_type]) - entryblock.getelementptr(l_ptr, self.l_args[0], [0, 0]) - entryblock.load(l_type, l_ptr) - entryblock.switch(l_type, "%a" + str(id(self.l_commonbase)), - [(id(l_c), "%a" + str(id(l_c))) + l_clp = self.gen.get_local_tmp(PointerTypeRepr("%std.class*", + self.gen), self) + l_cl = self.gen.get_local_tmp(PointerTypeRepr("%std.class", + self.gen), self) + l_uip = self.gen.get_local_tmp(PointerTypeRepr("uint", self.gen), + self) + l_ui = self.gen.get_local_tmp( + self.gen.get_repr(annmodel.SomeInteger(True, True)), self) + self.dependencies.update([l_clp, l_cl, l_uip, l_ui]) + entryblock.getelementptr(l_clp, self.l_args[0], [0, 0]) + entryblock.load(l_cl, l_clp) + entryblock.getelementptr(l_uip, l_cl, [0, 1]) + entryblock.load(l_ui, l_uip) + entryblock.switch(l_ui, "%" + self.l_commonbase.classdef.cls.__name__, + [(str(abs(id(l_c))), "%" + l_c.classdef.cls.__name__) for l_c in self.l_classes]) lfunc = llvmbc.Function(self.llvmfuncdef(), entryblock) for i, l_cls in enumerate(self.l_classes): - lblock = llvmbc.BasicBlock("a" + str(id(l_cls))) + lblock = llvmbc.BasicBlock(l_cls.classdef.cls.__name__) lfunc.basic_block(lblock) l_tmp = self.gen.get_local_tmp(l_cls, self) lblock.cast(l_tmp, self.l_args[0]) @@ -1090,7 +1122,8 @@ return str(self.llvm_func) def llvmfuncdef(self): - s = "%s %s(" % (self.l_funcs[0].retvalue.llvmtype(), self.name) + s = "internal %s %s(" % (self.l_funcs[0].retvalue.llvmtype(), + self.name) return s + ", ".join([a.typed_name() for a in self.l_args]) + ")" def rettype(self): Modified: pypy/dist/pypy/translator/llvm/test/llvmsnippet.py ============================================================================== --- pypy/dist/pypy/translator/llvm/test/llvmsnippet.py (original) +++ pypy/dist/pypy/translator/llvm/test/llvmsnippet.py Mon Mar 28 22:09:02 2005 @@ -194,6 +194,9 @@ AAA.__init__(self) BBB.__init__(self) + def cmethod(self): + return 13 + def attribute_from_base_class(): a = AAA() b = BBB() @@ -210,6 +213,19 @@ c = CCC() return a.get() + b.get() + c.get() +def ifisinstance(a): + if isinstance(a, CCC): + return a.cmethod() + elif isinstance(a, BBB): + return a.b + return 1 + +def flow_type(): + a = AAA() + b = BBB() + c = CCC() + return ifisinstance(a) + ifisinstance(b) + ifisinstance(c) + #string snippets def string_f1(i): j = 0 Modified: pypy/dist/pypy/translator/llvm/test/test_genllvm.py ============================================================================== --- pypy/dist/pypy/translator/llvm/test/test_genllvm.py (original) +++ pypy/dist/pypy/translator/llvm/test/test_genllvm.py Mon Mar 28 22:09:02 2005 @@ -215,6 +215,10 @@ def test_direct_call_of_virtual_method(self): f = compile_function(llvmsnippet.direct_call_of_virtual_method, []) assert f() == 14 + + def test_flow_type(self): + f = compile_function(llvmsnippet.flow_type, []) + assert f() == 16 class TestString(object): def setup_method(self, method): From arigo at codespeak.net Tue Mar 29 11:53:02 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 29 Mar 2005 11:53:02 +0200 (MEST) Subject: [pypy-svn] r10154 - in pypy/dist/pypy/objspace/std: . test Message-ID: <20050329095302.A6F7727B36@code1.codespeak.net> Author: arigo Date: Tue Mar 29 11:53:02 2005 New Revision: 10154 Added: pypy/dist/pypy/objspace/std/listsort.py (contents, props changed) pypy/dist/pypy/objspace/std/test/test_listsort.py (contents, props changed) Modified: pypy/dist/pypy/objspace/std/listobject.py Log: Implemented Tim's sort for lists, in listsort.py which is independent from PyPy and overridden for calling space operations in listobject.py. Modified: pypy/dist/pypy/objspace/std/listobject.py ============================================================================== --- pypy/dist/pypy/objspace/std/listobject.py (original) +++ pypy/dist/pypy/objspace/std/listobject.py Tue Mar 29 11:53:02 2005 @@ -4,8 +4,9 @@ from pypy.objspace.std.tupleobject import W_TupleObject from pypy.objspace.std import slicetype -from pypy.interpreter import gateway +from pypy.interpreter import gateway, baseobjspace from pypy.objspace.std.restricted_int import r_int, r_uint +from pypy.objspace.std.listsort import TimSort class W_ListObject(W_Object): @@ -514,76 +515,21 @@ _reverse_slice(w_list.ob_item, 0, w_list.ob_size) return space.w_None - - -# Python Quicksort Written by Magnus Lie Hetland -# http://www.hetland.org/python/quicksort.html +# ____________________________________________________________ +# Sorting -# NOTE: we cannot yet detect that a user comparision -# function modifies the list in-place. The -# CPython sort() should be studied to learn how -# to implement this functionality. - -def _partition(list, key_list, start, end, lt): - pivot = list[end] - key_pivot = key_list[end] # Partition around the last value - bottom = start-1 # Start outside the area to be partitioned - top = end # Ditto - - done = 0 - while not done: # Until all elements are partitioned... - - while not done: # Until we find an out of place element... - bottom = bottom+1 # ... move the bottom up. - - if bottom == top: # If we hit the top... - done = 1 # ... we are done. - break - - if lt(key_pivot, key_list[bottom]): # Is the bottom out of place? - key_list[top] = key_list[bottom] - list[top] = list[bottom] # Then put it at the top... - break # ... and start searching from the top. - - while not done: # Until we find an out of place element... - top = top-1 # ... move the top down. - - if top == bottom: # If we hit the bottom... - done = 1 # ... we are done. - break - - if lt(key_list[top], key_pivot): # Is the top out of place? - key_list[bottom] = key_list[top] - list[bottom] = list[top] # Then put it at the bottom... - break # ...and start searching from the bottom. - - key_list[top] = key_pivot - list[top] = pivot # Put the pivot in its place. - return top # Return the split point - - -def _quicksort(list, key_list, start, end, lt): - """list is the list to be sorted - key_list is the list that will be used for comparisions - """ - if start < end: # If there are two or more elements... - split = _partition(list, key_list, start, end, lt) # ... partition the sublist... - _quicksort(list, key_list, start, split-1, lt) # ... and sort both halves. - _quicksort(list, key_list, split+1, end, lt) - -class Comparer: - """Just a dumb container class for a space and a w_cmp, because - we can't use nested scopes for that in RPython. - """ - def __init__(self, space, w_cmp): - self.space = space - self.w_cmp = w_cmp +class KeyContainer(baseobjspace.W_Root): + def __init__(self, w_key, w_item): + self.w_key = w_key + self.w_item = w_item - def simple_lt(self, a, b): +class SimpleSort(TimSort): + def lt(self, a, b): space = self.space return space.is_true(space.lt(a, b)) - def complex_lt(self, a, b): +class CustomCompareSort(TimSort): + def lt(self, a, b): space = self.space w_cmp = self.w_cmp w_result = space.call_function(w_cmp, a, b) @@ -596,45 +542,81 @@ raise return result < 0 -def list_sort__List_ANY_ANY_ANY(space, w_list, w_cmp, w_key, w_reverse): - comparer = Comparer(space, w_cmp) - if w_cmp is space.w_None: - lt = comparer.simple_lt - else: - lt = comparer.complex_lt - # The key_list is the result of map(w_key, w_list), and will be - # used for comparisons during the qsort - if w_key is not space.w_None: - key_list = [space.call_function(w_key, item) - for item in w_list.ob_item[:w_list.ob_size]] - else: - # If no key was specified, then comparison will be made on - # the original list - key_list = w_list.ob_item - # XXX Basic quicksort implementation - # XXX this is not stable !! - _quicksort(w_list.ob_item, key_list, 0, w_list.ob_size-1, lt) - # _quicksort(w_list.ob_item, 0, w_list.ob_size-1, lt) - # reverse list if needed - if space.is_true(w_reverse): - list_reverse__List(space, w_list) - return space.w_None +class CustomKeySort(TimSort): + def lt(self, a, b): + assert isinstance(a, KeyContainer) + assert isinstance(b, KeyContainer) + space = self.space + return space.is_true(space.lt(a.w_key, b.w_key)) +class CustomKeyCompareSort(CustomCompareSort): + def lt(self, a, b): + assert isinstance(a, KeyContainer) + assert isinstance(b, KeyContainer) + return CustomCompareSort.lt(self, a.w_key, b.w_key) + +SortClass = { + (False, False): SimpleSort, + (True, False): CustomCompareSort, + (False, True) : CustomKeySort, + (True, True) : CustomKeyCompareSort, + } + +def list_sort__List_ANY_ANY_ANY(space, w_list, w_cmp, w_keyfunc, w_reverse): + has_cmp = not space.is_w(w_cmp, space.w_None) + has_key = not space.is_w(w_keyfunc, space.w_None) + has_reverse = space.is_true(w_reverse) + + # create and setup a TimSort instance + sorterclass = SortClass[has_cmp, has_key] + sorter = sorterclass(w_list.ob_item, w_list.ob_size) + sorter.space = space + sorter.w_cmp = w_cmp + + try: + # The list is temporarily made empty, so that mutations performed + # by comparison functions can't affect the slice of memory we're + # sorting (allowing mutations during sorting is an IndexError or + # core-dump factory, since ob_item may change). + w_list.clear() + + # wrap each item in a KeyContainer if needed + if has_key: + for i in range(sorter.listlength): + w_item = sorter.list[i] + w_key = space.call_function(w_keyfunc, w_item) + sorter.list[i] = KeyContainer(w_key, w_item) + + # Reverse sort stability achieved by initially reversing the list, + # applying a stable forward sort, then reversing the final result. + if has_reverse: + _reverse_slice(sorter.list, 0, sorter.listlength) + + # perform the sort + sorter.sort() + + # check if the user mucked with the list during the sort + if w_list.ob_item: + raise OperationError(space.w_ValueError, + space.wrap("list modified during sort")) + + finally: + # unwrap each item if needed + if has_key: + for i in range(sorter.listlength): + w_obj = sorter.list[i] + if isinstance(w_obj, KeyContainer): + sorter.list[i] = w_obj.w_item + + if has_reverse: + _reverse_slice(sorter.list, 0, sorter.listlength) + + # put the items back into the list + w_list.ob_item = sorter.list + w_list.ob_size = sorter.listlength + + return space.w_None -""" -static PyMethodDef list_methods[] = { - {"append", (PyCFunction)listappend, METH_O, append_doc}, - {"insert", (PyCFunction)listinsert, METH_VARARGS, insert_doc}, - {"extend", (PyCFunction)listextend, METH_O, extend_doc}, - {"pop", (PyCFunction)listpop, METH_VARARGS, pop_doc}, - {"remove", (PyCFunction)listremove, METH_O, remove_doc}, - {"index", (PyCFunction)listindex, METH_O, index_doc}, - {"count", (PyCFunction)listcount, METH_O, count_doc}, - {"reverse", (PyCFunction)listreverse, METH_NOARGS, reverse_doc}, - {"sort", (PyCFunction)listsort, METH_VARARGS, sort_doc}, - {NULL, NULL} /* sentinel */ -}; -""" from pypy.objspace.std import listtype register_all(vars(), listtype) Added: pypy/dist/pypy/objspace/std/listsort.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/objspace/std/listsort.py Tue Mar 29 11:53:02 2005 @@ -0,0 +1,575 @@ + +## ------------------------------------------------------------------------ +## Lots of code for an adaptive, stable, natural mergesort. There are many +## pieces to this algorithm; read listsort.txt for overviews and details. +## ------------------------------------------------------------------------ +## Adapted from CPython, original code and algorithms by Tim Peters + + +class TimSort: + """TimSort(list).sort() + + Sorts the list in-place, using the overridable method lt() for comparison. + """ + + def __init__(self, list, listlength=None): + self.list = list + if listlength is None: + listlength = len(list) + self.listlength = listlength + + def lt(self, a, b): + return a < b + + def le(self, a, b): + return not self.lt(b, a) # always use self.lt() as the primitive + + # binarysort is the best method for sorting small arrays: it does + # few compares, but can do data movement quadratic in the number of + # elements. + # "a" is a contiguous slice of a list, and is sorted via binary insertion. + # This sort is stable. + # On entry, the first "sorted" elements are already sorted. + # Even in case of error, the output slice will be some permutation of + # the input (nothing is lost or duplicated). + + def binarysort(self, a, sorted=1): + for start in xrange(a.base + sorted, a.base + a.len): + # set l to where list[start] belongs + l = a.base + r = start + pivot = a.list[r] + # Invariants: + # pivot >= all in [base, l). + # pivot < all in [r, start). + # The second is vacuously true at the start. + while l < r: + p = l + ((r - l) >> 1) + if self.lt(pivot, a.list[p]): + r = p + else: + l = p+1 + assert l == r + # The invariants still hold, so pivot >= all in [base, l) and + # pivot < all in [l, start), so pivot belongs at l. Note + # that if there are elements equal to pivot, l points to the + # first slot after them -- that's why this sort is stable. + # Slide over to make room. + for p in xrange(start, l, -1): + a.list[p] = a.list[p-1] + a.list[l] = pivot + + # Compute the length of the run in the slice "a". + # "A run" is the longest ascending sequence, with + # + # a[0] <= a[1] <= a[2] <= ... + # + # or the longest descending sequence, with + # + # a[0] > a[1] > a[2] > ... + # + # Return (run, descending) where descending is False in the former case, + # or True in the latter. + # For its intended use in a stable mergesort, the strictness of the defn of + # "descending" is needed so that the caller can safely reverse a descending + # sequence without violating stability (strict > ensures there are no equal + # elements to get out of order). + + def count_run(self, a): + if a.len <= 1: + n = a.len + descending = False + else: + n = 2 + if self.lt(a.list[a.base + 1], a.list[a.base]): + descending = True + for p in xrange(a.base + 2, a.base + a.len): + if self.lt(a.list[p], a.list[p-1]): + n += 1 + else: + break + else: + descending = False + for p in xrange(a.base + 2, a.base + a.len): + if self.lt(a.list[p], a.list[p-1]): + break + else: + n += 1 + return ListSlice(a.list, a.base, n), descending + + # Locate the proper position of key in a sorted vector; if the vector + # contains an element equal to key, return the position immediately to the + # left of the leftmost equal element -- or to the right of the rightmost + # equal element if the flag "rightmost" is set. + # + # "hint" is an index at which to begin the search, 0 <= hint < a.len. + # The closer hint is to the final result, the faster this runs. + # + # The return value is the index 0 <= k <= a.len such that + # + # a[k-1] < key <= a[k] (if rightmost is False) + # a[k-1] <= key < a[k] (if rightmost is True) + # + # as long as the indices are in bound. IOW, key belongs at index k; + # or, IOW, the first k elements of a should precede key, and the last + # n-k should follow key. + + def gallop(self, key, a, hint, rightmost): + assert 0 <= hint < a.len + if rightmost: + lower = self.le # search for the largest k for which a[k] <= key + else: + lower = self.lt # search for the largest k for which a[k] < key + + p = a.base + hint + lastofs = 0 + ofs = 1 + if lower(a.list[p], key): + # a[hint] < key -- gallop right, until + # a[hint + lastofs] < key <= a[hint + ofs] + + maxofs = a.len - hint # a[a.len-1] is highest + while ofs < maxofs: + if lower(a.list[p + ofs], key): + lastofs = ofs + try: + ofs = (ofs << 1) + 1 + except OverflowError: + ofs = maxofs + else: # key <= a[hint + ofs] + break + + if ofs > maxofs: + ofs = maxofs + # Translate back to offsets relative to a. + lastofs += hint + ofs += hint + + else: + # key <= a[hint] -- gallop left, until + # a[hint - ofs] < key <= a[hint - lastofs] + maxofs = hint + 1 # a[0] is lowest + while ofs < maxofs: + if lower(a.list[p - ofs], key): + break + else: + # key <= a[hint - ofs] + lastofs = ofs + try: + ofs = (ofs << 1) + 1 + except OverflowError: + ofs = maxofs + if ofs > maxofs: + ofs = maxofs + # Translate back to positive offsets relative to a. + lastofs, ofs = hint-ofs, hint-lastofs + + assert -1 <= lastofs < ofs <= a.len + + # Now a[lastofs] < key <= a[ofs], so key belongs somewhere to the + # right of lastofs but no farther right than ofs. Do a binary + # search, with invariant a[lastofs-1] < key <= a[ofs]. + + lastofs += 1 + while lastofs < ofs: + m = lastofs + ((ofs - lastofs) >> 1) + if lower(a.list[a.base + m], key): + lastofs = m+1 # a[m] < key + else: + ofs = m # key <= a[m] + + assert lastofs == ofs # so a[ofs-1] < key <= a[ofs] + return ofs + + # ____________________________________________________________ + + # When we get into galloping mode, we stay there until both runs win less + # often than MIN_GALLOP consecutive times. See listsort.txt for more info. + MIN_GALLOP = 7 + + def merge_init(self): + # This controls when we get *into* galloping mode. It's initialized + # to MIN_GALLOP. merge_lo and merge_hi tend to nudge it higher for + # random data, and lower for highly structured data. + self.min_gallop = self.MIN_GALLOP + + # A stack of n pending runs yet to be merged. Run #i starts at + # address pending[i].base and extends for pending[i].len elements. + # It's always true (so long as the indices are in bounds) that + # + # pending[i].base + pending[i].len == pending[i+1].base + # + # so we could cut the storage for this, but it's a minor amount, + # and keeping all the info explicit simplifies the code. + self.pending = [] + + # Merge the slice "a" with the slice "b" in a stable way, in-place. + # a.len and b.len must be > 0, and a.base + a.len == b.base. + # Must also have that b.list[b.base] < a.list[a.base], that + # a.list[a.base+a.len-1] belongs at the end of the merge, and should have + # a.len <= b.len. See listsort.txt for more info. + + def merge_lo(self, a, b): + assert a.len > 0 and b.len > 0 and a.base + a.len == b.base + min_gallop = self.min_gallop + dest = a.base + a = a.copyitems() + + # Invariant: elements in "a" are waiting to be reinserted into the list + # at "dest". They should be merged with the elements of "b". + # b.base == dest + a.len. + # We use a finally block to ensure that the elements remaining in + # the copy "a" are reinserted back into self.list in all cases. + try: + self.list[dest] = b.popleft() + dest += 1 + if a.len == 1 or b.len == 0: + return + + while True: + acount = 0 # number of times A won in a row + bcount = 0 # number of times B won in a row + + # Do the straightforward thing until (if ever) one run + # appears to win consistently. + while True: + if self.lt(b.list[b.base], a.list[a.base]): + self.list[dest] = b.popleft() + dest += 1 + if b.len == 0: + return + bcount += 1 + acount = 0 + if bcount >= min_gallop: + break + else: + self.list[dest] = a.popleft() + dest += 1 + if a.len == 1: + return + acount += 1 + bcount = 0 + if acount >= min_gallop: + break + + # One run is winning so consistently that galloping may + # be a huge win. So try that, and continue galloping until + # (if ever) neither run appears to be winning consistently + # anymore. + min_gallop += 1 + + while True: + min_gallop -= min_gallop > 1 + self.min_gallop = min_gallop + + acount = self.gallop(b.list[b.base], a, hint=0, + rightmost=True) + for p in xrange(a.base, a.base + acount): + self.list[dest] = a.list[p] + dest += 1 + a.advance(acount) + # a.len==0 is impossible now if the comparison + # function is consistent, but we can't assume + # that it is. + if a.len <= 1: + return + + self.list[dest] = b.popleft() + dest += 1 + if b.len == 0: + return + + bcount = self.gallop(a.list[a.base], b, hint=0, + rightmost=False) + for p in xrange(b.base, b.base + bcount): + self.list[dest] = b.list[p] + dest += 1 + b.advance(bcount) + if b.len == 0: + return + + self.list[dest] = a.popleft() + dest += 1 + if a.len == 1: + return + + if acount < self.MIN_GALLOP and bcount < self.MIN_GALLOP: + break + + min_gallop += 1 # penalize it for leaving galloping mode + self.min_gallop = min_gallop + + finally: + # The last element of a belongs at the end of the merge, so we copy + # the remaining elements of b before the remaining elements of a. + assert a.len >= 0 and b.len >= 0 + for p in xrange(b.base, b.base + b.len): + self.list[dest] = b.list[p] + dest += 1 + for p in xrange(a.base, a.base + a.len): + self.list[dest] = a.list[p] + dest += 1 + + # Same as merge_lo(), but should have a.len >= b.len. + + def merge_hi(self, a, b): + assert a.len > 0 and b.len > 0 and a.base + a.len == b.base + min_gallop = self.min_gallop + dest = b.base + b.len + b = b.copyitems() + + # Invariant: elements in "b" are waiting to be reinserted into the list + # before "dest". They should be merged with the elements of "a". + # a.base + a.len == dest - b.len. + # We use a finally block to ensure that the elements remaining in + # the copy "b" are reinserted back into self.list in all cases. + try: + dest -= 1 + self.list[dest] = a.popright() + if a.len == 0 or b.len == 1: + return + + while True: + acount = 0 # number of times A won in a row + bcount = 0 # number of times B won in a row + + # Do the straightforward thing until (if ever) one run + # appears to win consistently. + while True: + nexta = a.list[a.base + a.len - 1] + nextb = b.list[b.base + b.len - 1] + if self.lt(nextb, nexta): + dest -= 1 + self.list[dest] = nexta + a.len -= 1 + if a.len == 0: + return + acount += 1 + bcount = 0 + if acount >= min_gallop: + break + else: + dest -= 1 + self.list[dest] = nextb + b.len -= 1 + if b.len == 1: + return + bcount += 1 + acount = 0 + if bcount >= min_gallop: + break + + # One run is winning so consistently that galloping may + # be a huge win. So try that, and continue galloping until + # (if ever) neither run appears to be winning consistently + # anymore. + min_gallop += 1 + + while True: + min_gallop -= min_gallop > 1 + self.min_gallop = min_gallop + + nextb = b.list[b.base + b.len - 1] + k = self.gallop(nextb, a, hint=a.len-1, rightmost=True) + acount = a.len - k + for p in xrange(a.base + a.len - 1, a.base + k - 1, -1): + dest -= 1 + self.list[dest] = a.list[p] + a.len -= acount + if a.len == 0: + return + + dest -= 1 + self.list[dest] = b.popright() + if b.len == 1: + return + + nexta = a.list[a.base + a.len - 1] + k = self.gallop(nexta, b, hint=b.len-1, rightmost=False) + bcount = b.len - k + for p in xrange(b.base + b.len - 1, b.base + k - 1, -1): + dest -= 1 + self.list[dest] = b.list[p] + b.len -= bcount + # b.len==0 is impossible now if the comparison + # function is consistent, but we can't assume + # that it is. + if b.len <= 1: + return + + dest -= 1 + self.list[dest] = a.popright() + if a.len == 0: + return + + if acount < self.MIN_GALLOP and bcount < self.MIN_GALLOP: + break + + min_gallop += 1 # penalize it for leaving galloping mode + self.min_gallop = min_gallop + + finally: + # The last element of a belongs at the end of the merge, so we copy + # the remaining elements of a and then the remaining elements of b. + assert a.len >= 0 and b.len >= 0 + for p in xrange(a.base + a.len - 1, a.base - 1, -1): + dest -= 1 + self.list[dest] = a.list[p] + for p in xrange(b.base + b.len - 1, b.base - 1, -1): + dest -= 1 + self.list[dest] = b.list[p] + + # Merge the two runs at stack indices i and i+1. + + def merge_at(self, i): + a = self.pending[i] + b = self.pending[i+1] + assert a.len > 0 and b.len > 0 + assert a.base + a.len == b.base + + # Record the length of the combined runs and remove the run b + self.pending[i] = ListSlice(self.list, a.base, a.len + b.len) + del self.pending[i+1] + + # Where does b start in a? Elements in a before that can be + # ignored (already in place). + k = self.gallop(b.list[b.base], a, hint=0, rightmost=True) + a.advance(k) + if a.len == 0: + return + + # Where does a end in b? Elements in b after that can be + # ignored (already in place). + b.len = self.gallop(a.list[a.base+a.len-1], b, hint=b.len-1, + rightmost=False) + if b.len == 0: + return + + # Merge what remains of the runs. The direction is chosen to + # minimize the temporary storage needed. + if a.len <= b.len: + self.merge_lo(a, b) + else: + self.merge_hi(a, b) + + # Examine the stack of runs waiting to be merged, merging adjacent runs + # until the stack invariants are re-established: + # + # 1. len[-3] > len[-2] + len[-1] + # 2. len[-2] > len[-1] + # + # See listsort.txt for more info. + + def merge_collapse(self): + p = self.pending + while len(p) > 1: + if len(p) >= 3 and p[-3].len <= p[-2].len + p[-1].len: + if p[-3].len < p[-1].len: + self.merge_at(-3) + else: + self.merge_at(-2) + elif p[-2].len <= p[-1].len: + self.merge_at(-2) + else: + break + + # Regardless of invariants, merge all runs on the stack until only one + # remains. This is used at the end of the mergesort. + + def merge_force_collapse(self): + p = self.pending + while len(p) > 1: + if len(p) >= 3 and p[-3].len < p[-1].len: + self.merge_at(-3) + else: + self.merge_at(-2) + + # Compute a good value for the minimum run length; natural runs shorter + # than this are boosted artificially via binary insertion. + # + # If n < 64, return n (it's too small to bother with fancy stuff). + # Else if n is an exact power of 2, return 32. + # Else return an int k, 32 <= k <= 64, such that n/k is close to, but + # strictly less than, an exact power of 2. + # + # See listsort.txt for more info. + + def merge_compute_minrun(self, n): + r = 0 # becomes 1 if any 1 bits are shifted off + while n >= 64: + r |= n & 1 + n >>= 1 + return n + r + + # ____________________________________________________________ + # Entry point. + + def sort(self): + remaining = ListSlice(self.list, 0, self.listlength) + if remaining.len < 2: + return + + # March over the array once, left to right, finding natural runs, + # and extending short natural runs to minrun elements. + self.merge_init() + minrun = self.merge_compute_minrun(remaining.len) + + while remaining.len > 0: + # Identify next run. + run, descending = self.count_run(remaining) + if descending: + run.reverse() + # If short, extend to min(minrun, nremaining). + if run.len < minrun: + sorted = run.len + run.len = min(minrun, remaining.len) + self.binarysort(run, sorted) + # Advance remaining past this run. + remaining.advance(run.len) + # Push run onto pending-runs stack, and maybe merge. + self.pending.append(run) + self.merge_collapse() + + assert remaining.base == self.listlength + + self.merge_force_collapse() + assert len(self.pending) == 1 + assert self.pending[0].base == 0 + assert self.pending[0].len == self.listlength + + +class ListSlice: + "A sublist of a list." + + def __init__(self, list, base, len): + self.list = list + self.base = base + self.len = len + + def copyitems(self): + "Make a copy of the slice of the original list." + return ListSlice(self.list[self.base:self.base+self.len], 0, self.len) + + def advance(self, n): + self.base += n + self.len -= n + + def popleft(self): + result = self.list[self.base] + self.base += 1 + self.len -= 1 + return result + + def popright(self): + self.len -= 1 + return self.list[self.base + self.len] + + def reverse(self): + "Reverse the slice in-place." + list = self.list + lo = self.base + hi = lo + self.len - 1 + while lo < hi: + list[lo], list[hi] = list[hi], list[lo] + lo += 1 + hi -= 1 Added: pypy/dist/pypy/objspace/std/test/test_listsort.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/objspace/std/test/test_listsort.py Tue Mar 29 11:53:02 2005 @@ -0,0 +1,43 @@ +import autopath +from pypy.objspace.std.listsort import TimSort +import random, os + +def makeset(lst): + result = {} + for a in lst: + result.setdefault(id(a), []).append(True) + return result + +def sorttest(lst1): + lst2 = lst1[:] + TimSort(lst2).sort() + assert len(lst1) == len(lst2) + assert makeset(lst1) == makeset(lst2) + position = {} + i = 0 + for a in lst1: + position.setdefault(id(a), []).append(i) + i += 1 + for i in range(len(lst2)-1): + a, b = lst2[i], lst2[i+1] + assert a <= b, "resulting list is not sorted" + if a == b: + assert position[id(a)][0] < position[id(b)][-1], "not stable" + + +class C(int): + pass + +def test_v(): + for v in range(137): + up = 1 + int(v * random.random() * 2.7) + lst1 = [C(random.randrange(0, up)) for i in range(v)] + sorttest(lst1) + +def test_file(): + for fn in os.listdir(autopath.this_dir): + if fn.endswith('.py'): + f = open(os.path.join(autopath.this_dir, fn), 'r') + lines1 = f.readlines() + f.close() + sorttest(lines1) From arigo at codespeak.net Tue Mar 29 11:53:51 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 29 Mar 2005 11:53:51 +0200 (MEST) Subject: [pypy-svn] r10155 - in pypy/dist/pypy/objspace/std: . test Message-ID: <20050329095351.8A8F127B36@code1.codespeak.net> Author: arigo Date: Tue Mar 29 11:53:51 2005 New Revision: 10155 Added: pypy/dist/pypy/objspace/std/test/test_obj.py - copied unchanged from r10111, pypy/dist/pypy/objspace/std/test_obj.py Removed: pypy/dist/pypy/objspace/std/test_obj.py Log: Moved test_obj.py into the test/ subdirectory. Deleted: /pypy/dist/pypy/objspace/std/test_obj.py ============================================================================== --- /pypy/dist/pypy/objspace/std/test_obj.py Tue Mar 29 11:53:51 2005 +++ (empty file) @@ -1,14 +0,0 @@ -# -*- coding: iso-8859-1 -*- - -class AppTestObject: - def test_hash_builtin(self): - o = object() - assert hash(o) == id(o) - - def test_hash_method(self): - o = object() - assert hash(o) == o.__hash__() - - def test_hash_list(self): - l = range(5) - raises(TypeError, hash, l) From arigo at codespeak.net Tue Mar 29 12:13:10 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 29 Mar 2005 12:13:10 +0200 (MEST) Subject: [pypy-svn] r10156 - in pypy/dist/pypy: interpreter interpreter/test lib lib/test2 module/parser objspace/std translator/test Message-ID: <20050329101310.3183627B36@code1.codespeak.net> Author: arigo Date: Tue Mar 29 12:13:09 2005 New Revision: 10156 Modified: pypy/dist/pypy/interpreter/pyframe.py pypy/dist/pypy/interpreter/test/test_gateway.py pypy/dist/pypy/lib/itertools.py pypy/dist/pypy/lib/test2/test_itertools.py pypy/dist/pypy/module/parser/pyparser.py pypy/dist/pypy/objspace/std/floatobject.py pypy/dist/pypy/objspace/std/listobject.py pypy/dist/pypy/objspace/std/listsort.py pypy/dist/pypy/objspace/std/stringobject.py pypy/dist/pypy/translator/test/test_annrpython.py Log: untabify. These tabs are "blamed" to various people but I seem to be responsible for the majority of them. I copied bits from CPython without thinking about tabs. Modified: pypy/dist/pypy/interpreter/pyframe.py ============================================================================== --- pypy/dist/pypy/interpreter/pyframe.py (original) +++ pypy/dist/pypy/interpreter/pyframe.py Tue Mar 29 12:13:09 2005 @@ -468,13 +468,13 @@ The concrete subclasses correspond to the various values WHY_XXX values of the why_code enumeration in ceval.c: - WHY_NOT, OK, not this one :-) - WHY_EXCEPTION, SApplicationException - WHY_RERAISE, we don't think this is needed - WHY_RETURN, SReturnValue - WHY_BREAK, SBreakLoop - WHY_CONTINUE, SContinueLoop - WHY_YIELD SYieldValue + WHY_NOT, OK, not this one :-) + WHY_EXCEPTION, SApplicationException + WHY_RERAISE, we don't think this is needed + WHY_RETURN, SReturnValue + WHY_BREAK, SBreakLoop + WHY_CONTINUE, SContinueLoop + WHY_YIELD SYieldValue """ def action(self, frame, last_instr, executioncontext): Modified: pypy/dist/pypy/interpreter/test/test_gateway.py ============================================================================== --- pypy/dist/pypy/interpreter/test/test_gateway.py (original) +++ pypy/dist/pypy/interpreter/test/test_gateway.py Tue Mar 29 12:13:09 2005 @@ -78,7 +78,7 @@ assert self.space.eq_w(g3(self.space, w('foo'), w('bar')), w('foobar')) def test_app2interp2(self): - """same but using transformed code""" + """same but using transformed code""" w = self.space.wrap def noapp_g3(a, b): return a+b Modified: pypy/dist/pypy/lib/itertools.py ============================================================================== --- pypy/dist/pypy/lib/itertools.py (original) +++ pypy/dist/pypy/lib/itertools.py Tue Mar 29 12:13:09 2005 @@ -370,9 +370,9 @@ def next(self): if self.donext is None: try: - self.donext = self.it.next + self.donext = self.it.next except AttributeError: - raise TypeError + raise TypeError while self.cnt < self.start: self.donext() self.cnt += 1 Modified: pypy/dist/pypy/lib/test2/test_itertools.py ============================================================================== --- pypy/dist/pypy/lib/test2/test_itertools.py (original) +++ pypy/dist/pypy/lib/test2/test_itertools.py Tue Mar 29 12:13:09 2005 @@ -96,8 +96,8 @@ self.assertEqual([pair for pair in izip('abc', 'def')], zip('abc', 'def')) # the following test deals with a specific implementation detail, - # that izip "reuses" the SAME tuple object each time when it can; - # it does not apply correctly to pypy, so I'm commenting it -- AM + # that izip "reuses" the SAME tuple object each time when it can; + # it does not apply correctly to pypy, so I'm commenting it -- AM # ids = map(id, izip('abc', 'def')) # self.assertEqual(min(ids), max(ids)) ids = map(id, list(izip('abc', 'def'))) Modified: pypy/dist/pypy/module/parser/pyparser.py ============================================================================== --- pypy/dist/pypy/module/parser/pyparser.py (original) +++ pypy/dist/pypy/module/parser/pyparser.py Tue Mar 29 12:13:09 2005 @@ -352,16 +352,16 @@ accepting state data; this is left to addAccelerators(). """ for dfa in igrammar[0]: - symbol_no, symbol_name, initial, states, first = dfa - acceptingStates = [] - for state in states: + symbol_no, symbol_name, initial, states, first = dfa + acceptingStates = [] + for state in states: arcs, accel, accept = state if accept: acceptingStates.append(state) if len(acceptingStates) == 0: print "!" * 70 print symbol_name, acceptingStates - if len(acceptingStates) == 0: + if len(acceptingStates) == 0: print "!" * 70 else: print Modified: pypy/dist/pypy/objspace/std/floatobject.py ============================================================================== --- pypy/dist/pypy/objspace/std/floatobject.py (original) +++ pypy/dist/pypy/objspace/std/floatobject.py Tue Mar 29 12:13:09 2005 @@ -185,7 +185,7 @@ raise OperationError(space.w_ZeroDivisionError, space.wrap("float division")) except FloatingPointError: raise FailedToImplement(space.w_FloatingPointError, space.wrap("float division")) - # no overflow + # no overflow return W_FloatObject(space, z) truediv__Float_Float = div__Float_Float Modified: pypy/dist/pypy/objspace/std/listobject.py ============================================================================== --- pypy/dist/pypy/objspace/std/listobject.py (original) +++ pypy/dist/pypy/objspace/std/listobject.py Tue Mar 29 12:13:09 2005 @@ -48,7 +48,7 @@ (['sequence'], None, None), # signature [W_ListObject(space, [])]) # default argument w_list.clear() - + length = 0 try: length = space.int_w(space.len(w_iterable)) @@ -575,7 +575,7 @@ try: # The list is temporarily made empty, so that mutations performed - # by comparison functions can't affect the slice of memory we're + # by comparison functions can't affect the slice of memory we're # sorting (allowing mutations during sorting is an IndexError or # core-dump factory, since ob_item may change). w_list.clear() @@ -588,7 +588,7 @@ sorter.list[i] = KeyContainer(w_key, w_item) # Reverse sort stability achieved by initially reversing the list, - # applying a stable forward sort, then reversing the final result. + # applying a stable forward sort, then reversing the final result. if has_reverse: _reverse_slice(sorter.list, 0, sorter.listlength) Modified: pypy/dist/pypy/objspace/std/listsort.py ============================================================================== --- pypy/dist/pypy/objspace/std/listsort.py (original) +++ pypy/dist/pypy/objspace/std/listsort.py Tue Mar 29 12:13:09 2005 @@ -145,7 +145,7 @@ lastofs += hint ofs += hint - else: + else: # key <= a[hint] -- gallop left, until # a[hint - ofs] < key <= a[hint - lastofs] maxofs = hint + 1 # a[0] is lowest @@ -156,7 +156,7 @@ # key <= a[hint - ofs] lastofs = ofs try: - ofs = (ofs << 1) + 1 + ofs = (ofs << 1) + 1 except OverflowError: ofs = maxofs if ofs > maxofs: @@ -164,22 +164,22 @@ # Translate back to positive offsets relative to a. lastofs, ofs = hint-ofs, hint-lastofs - assert -1 <= lastofs < ofs <= a.len + assert -1 <= lastofs < ofs <= a.len - # Now a[lastofs] < key <= a[ofs], so key belongs somewhere to the - # right of lastofs but no farther right than ofs. Do a binary - # search, with invariant a[lastofs-1] < key <= a[ofs]. + # Now a[lastofs] < key <= a[ofs], so key belongs somewhere to the + # right of lastofs but no farther right than ofs. Do a binary + # search, with invariant a[lastofs-1] < key <= a[ofs]. - lastofs += 1 + lastofs += 1 while lastofs < ofs: m = lastofs + ((ofs - lastofs) >> 1) if lower(a.list[a.base + m], key): - lastofs = m+1 # a[m] < key + lastofs = m+1 # a[m] < key else: ofs = m # key <= a[m] - assert lastofs == ofs # so a[ofs-1] < key <= a[ofs] - return ofs + assert lastofs == ofs # so a[ofs-1] < key <= a[ofs] + return ofs # ____________________________________________________________ @@ -188,12 +188,12 @@ MIN_GALLOP = 7 def merge_init(self): - # This controls when we get *into* galloping mode. It's initialized + # This controls when we get *into* galloping mode. It's initialized # to MIN_GALLOP. merge_lo and merge_hi tend to nudge it higher for # random data, and lower for highly structured data. self.min_gallop = self.MIN_GALLOP - # A stack of n pending runs yet to be merged. Run #i starts at + # A stack of n pending runs yet to be merged. Run #i starts at # address pending[i].base and extends for pending[i].len elements. # It's always true (so long as the indices are in bounds) that # @@ -227,10 +227,10 @@ return while True: - acount = 0 # number of times A won in a row - bcount = 0 # number of times B won in a row + acount = 0 # number of times A won in a row + bcount = 0 # number of times B won in a row - # Do the straightforward thing until (if ever) one run + # Do the straightforward thing until (if ever) one run # appears to win consistently. while True: if self.lt(b.list[b.base], a.list[a.base]): @@ -252,11 +252,11 @@ if acount >= min_gallop: break - # One run is winning so consistently that galloping may + # One run is winning so consistently that galloping may # be a huge win. So try that, and continue galloping until # (if ever) neither run appears to be winning consistently # anymore. - min_gallop += 1 + min_gallop += 1 while True: min_gallop -= min_gallop > 1 @@ -296,8 +296,8 @@ if acount < self.MIN_GALLOP and bcount < self.MIN_GALLOP: break - min_gallop += 1 # penalize it for leaving galloping mode - self.min_gallop = min_gallop + min_gallop += 1 # penalize it for leaving galloping mode + self.min_gallop = min_gallop finally: # The last element of a belongs at the end of the merge, so we copy @@ -330,10 +330,10 @@ return while True: - acount = 0 # number of times A won in a row - bcount = 0 # number of times B won in a row + acount = 0 # number of times A won in a row + bcount = 0 # number of times B won in a row - # Do the straightforward thing until (if ever) one run + # Do the straightforward thing until (if ever) one run # appears to win consistently. while True: nexta = a.list[a.base + a.len - 1] @@ -359,11 +359,11 @@ if bcount >= min_gallop: break - # One run is winning so consistently that galloping may + # One run is winning so consistently that galloping may # be a huge win. So try that, and continue galloping until # (if ever) neither run appears to be winning consistently # anymore. - min_gallop += 1 + min_gallop += 1 while True: min_gallop -= min_gallop > 1 @@ -405,8 +405,8 @@ if acount < self.MIN_GALLOP and bcount < self.MIN_GALLOP: break - min_gallop += 1 # penalize it for leaving galloping mode - self.min_gallop = min_gallop + min_gallop += 1 # penalize it for leaving galloping mode + self.min_gallop = min_gallop finally: # The last element of a belongs at the end of the merge, so we copy @@ -427,12 +427,12 @@ assert a.len > 0 and b.len > 0 assert a.base + a.len == b.base - # Record the length of the combined runs and remove the run b + # Record the length of the combined runs and remove the run b self.pending[i] = ListSlice(self.list, a.base, a.len + b.len) del self.pending[i+1] - # Where does b start in a? Elements in a before that can be - # ignored (already in place). + # Where does b start in a? Elements in a before that can be + # ignored (already in place). k = self.gallop(b.list[b.base], a, hint=0, rightmost=True) a.advance(k) if a.len == 0: @@ -440,16 +440,16 @@ # Where does a end in b? Elements in b after that can be # ignored (already in place). - b.len = self.gallop(a.list[a.base+a.len-1], b, hint=b.len-1, + b.len = self.gallop(a.list[a.base+a.len-1], b, hint=b.len-1, rightmost=False) if b.len == 0: return - # Merge what remains of the runs. The direction is chosen to + # Merge what remains of the runs. The direction is chosen to # minimize the temporary storage needed. if a.len <= b.len: self.merge_lo(a, b) - else: + else: self.merge_hi(a, b) # Examine the stack of runs waiting to be merged, merging adjacent runs @@ -495,11 +495,11 @@ # See listsort.txt for more info. def merge_compute_minrun(self, n): - r = 0 # becomes 1 if any 1 bits are shifted off + r = 0 # becomes 1 if any 1 bits are shifted off while n >= 64: r |= n & 1 n >>= 1 - return n + r + return n + r # ____________________________________________________________ # Entry point. @@ -509,10 +509,10 @@ if remaining.len < 2: return - # March over the array once, left to right, finding natural runs, - # and extending short natural runs to minrun elements. + # March over the array once, left to right, finding natural runs, + # and extending short natural runs to minrun elements. self.merge_init() - minrun = self.merge_compute_minrun(remaining.len) + minrun = self.merge_compute_minrun(remaining.len) while remaining.len > 0: # Identify next run. @@ -532,8 +532,8 @@ assert remaining.base == self.listlength - self.merge_force_collapse() - assert len(self.pending) == 1 + self.merge_force_collapse() + assert len(self.pending) == 1 assert self.pending[0].base == 0 assert self.pending[0].len == self.listlength Modified: pypy/dist/pypy/objspace/std/stringobject.py ============================================================================== --- pypy/dist/pypy/objspace/std/stringobject.py (original) +++ pypy/dist/pypy/objspace/std/stringobject.py Tue Mar 29 12:13:09 2005 @@ -767,7 +767,7 @@ x = 0 else: for c in s: - x = (1000003*x) ^ ord(c) + x = (1000003*x) ^ ord(c) x ^= len(s) # unlike CPython, there is no reason to avoid to return -1 w_hash = W_IntObject(space, intmask(x)) Modified: pypy/dist/pypy/translator/test/test_annrpython.py ============================================================================== --- pypy/dist/pypy/translator/test/test_annrpython.py (original) +++ pypy/dist/pypy/translator/test/test_annrpython.py Tue Mar 29 12:13:09 2005 @@ -432,7 +432,7 @@ assert isinstance(s, annmodel.SomeDict) assert isinstance(s.s_key, annmodel.SomeInteger) assert isinstance(s.s_value, annmodel.SomeInteger) - + a = RPythonAnnotator() s = a.build_types(snippet.dict_update, [str]) assert isinstance(s, annmodel.SomeDict) @@ -625,6 +625,17 @@ s = a.build_types(f, []) assert s.knowntype == C + def test_circular_list_type(self): + def f(n): + lst = [] + for i in range(n): + lst = [lst] + return lst + a = RPythonAnnotator() + s = a.build_types(f, [int]) + assert isinstance(s, annmodel.SomeList) + assert s.s_item == s + def g(n): return [0,1,2,n] From arigo at codespeak.net Tue Mar 29 12:20:56 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 29 Mar 2005 12:20:56 +0200 (MEST) Subject: [pypy-svn] r10157 - pypy/dist/pypy/translator/test Message-ID: <20050329102056.A8DE827B36@code1.codespeak.net> Author: arigo Date: Tue Mar 29 12:20:56 2005 New Revision: 10157 Modified: pypy/dist/pypy/translator/test/test_annrpython.py Log: Oups! A test that was not meant to be checked in yet. Modified: pypy/dist/pypy/translator/test/test_annrpython.py ============================================================================== --- pypy/dist/pypy/translator/test/test_annrpython.py (original) +++ pypy/dist/pypy/translator/test/test_annrpython.py Tue Mar 29 12:20:56 2005 @@ -625,7 +625,7 @@ s = a.build_types(f, []) assert s.knowntype == C - def test_circular_list_type(self): + def DONT_YET_test_circular_list_type(self): def f(n): lst = [] for i in range(n): From arigo at codespeak.net Tue Mar 29 12:32:23 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 29 Mar 2005 12:32:23 +0200 (MEST) Subject: [pypy-svn] r10158 - pypy/dist/pypy/module/builtin Message-ID: <20050329103223.02A7F27B36@code1.codespeak.net> Author: arigo Date: Tue Mar 29 12:32:23 2005 New Revision: 10158 Modified: pypy/dist/pypy/module/builtin/app_descriptor.py Log: Oups again. I broke 'super' when I made it use slots. Modified: pypy/dist/pypy/module/builtin/app_descriptor.py ============================================================================== --- pypy/dist/pypy/module/builtin/app_descriptor.py (original) +++ pypy/dist/pypy/module/builtin/app_descriptor.py Tue Mar 29 12:32:23 2005 @@ -83,13 +83,13 @@ else: return self def __getattribute__(self, attr): - d = object.__getattribute__(self, '__dict__') - if attr != '__class__' and d['__self_class__'] is not None: - # we want super().__class__ to be the real class - # and we don't do anything for unbound type objects - mro = iter(d['__self_class__'].__mro__) + _self_class_ = super.__self_class__.__get__(self) + if (attr != '__class__' # we want super().__class__ to be the real class + and _self_class_ is not None): # no magic for unbound type objects + _thisclass_ = super.__thisclass__.__get__(self) + mro = iter(_self_class_.__mro__) for cls in mro: - if cls is d['__thisclass__']: + if cls is _thisclass_: break # Note: mro is an iterator, so the second loop # picks up where the first one left off! @@ -99,6 +99,7 @@ except KeyError: continue if hasattr(x, '__get__'): - x = x.__get__(d['__self__'], type(d['__self__'])) + _self_ = super.__self__.__get__(self) + x = x.__get__(_self_, type(_self_)) return x return object.__getattribute__(self, attr) # fall-back From ac at codespeak.net Tue Mar 29 16:19:31 2005 From: ac at codespeak.net (ac at codespeak.net) Date: Tue, 29 Mar 2005 16:19:31 +0200 (MEST) Subject: [pypy-svn] r10159 - pypy/dist/pypy/interpreter Message-ID: <20050329141931.12C6427B33@code1.codespeak.net> Author: ac Date: Tue Mar 29 16:19:30 2005 New Revision: 10159 Modified: pypy/dist/pypy/interpreter/pyframe.py pypy/dist/pypy/interpreter/pytraceback.py Log: Do not include frames with hidden applevel code in tracebacks. Modified: pypy/dist/pypy/interpreter/pyframe.py ============================================================================== --- pypy/dist/pypy/interpreter/pyframe.py (original) +++ pypy/dist/pypy/interpreter/pyframe.py Tue Mar 29 16:19:30 2005 @@ -111,8 +111,6 @@ executioncontext.exception_trace(self, e) # convert an OperationError into a control flow # exception - import sys - tb = sys.exc_info()[2] raise SApplicationException(e) except ControlFlowException, ctlflowexc: Modified: pypy/dist/pypy/interpreter/pytraceback.py ============================================================================== --- pypy/dist/pypy/interpreter/pytraceback.py (original) +++ pypy/dist/pypy/interpreter/pytraceback.py Tue Mar 29 16:19:30 2005 @@ -20,6 +20,8 @@ def record_application_traceback(space, operror, frame, last_instruction): + if frame.code.hidden_applevel: + return lineno = offset2lineno(frame.code, last_instruction) tb = operror.application_traceback tb = PyTraceback(space, frame, last_instruction, lineno, tb) From tismer at codespeak.net Tue Mar 29 17:07:46 2005 From: tismer at codespeak.net (tismer at codespeak.net) Date: Tue, 29 Mar 2005 17:07:46 +0200 (MEST) Subject: [pypy-svn] r10160 - in pypy/dist/pypy/translator: . test Message-ID: <20050329150746.D7D6C27B38@code1.codespeak.net> Author: tismer Date: Tue Mar 29 17:07:46 2005 New Revision: 10160 Modified: pypy/dist/pypy/translator/geninterplevel.py pypy/dist/pypy/translator/test/test_geninterp.py Log: added sorted compiling to in-memory compilation using a tiny memfile class. Various cleanups. Modified: pypy/dist/pypy/translator/geninterplevel.py ============================================================================== --- pypy/dist/pypy/translator/geninterplevel.py (original) +++ pypy/dist/pypy/translator/geninterplevel.py Tue Mar 29 17:07:46 2005 @@ -721,7 +721,7 @@ return 'PySys_GetObject("stderr")' raise Exception, 'Cannot translate an already-open file: %r' % (fil,) - def gen_source(self, fname, ftmpname=None): + def gen_source(self, fname, ftmpname=None, file=file): self.fname = fname self.ftmpname = ftmpname @@ -1403,14 +1403,31 @@ import py.code import cStringIO as StringIO +class memfile(object): + _storage = {} + def __init__(self, name, mode="r"): + if mode == "w": + self._storage[name] = StringIO.StringIO() + elif mode == "r": + try: + data = self._storage[name].getvalue() + except IndexError: + data = file(name).read() + self._storage[name] = StringIO.StringIO(data) + else: + raise ValueError, "mode %s not supported" % mode + self._file = self._storage[name] + def __getattr__(self, name): + return getattr(self._file, name) + def close(self): + pass + def translate_as_module(sourcetext, modname="app2interpexec", tmpname=None): """ compile sourcetext as a module, translating to interp level. The result is the init function that creates the wrapped module dict. This init function needs a space as argument. - tmpname can be passed for debugging purposes. Note that the generated - output is not sorted, because it is not meant to be persistent. - For persistent output, please use pypy/translator/tool/tointerplevel.py - + tmpname can be passed for debugging purposes. + Example: initfunc = translate_as_module(text) @@ -1430,19 +1447,15 @@ do_imports_immediately=False) gen = GenRpy(t, entrypoint, modname, dic) if tmpname: - out = file(tmpname, 'w') - def readback(): - out.close() - return file(tmpname, 'r').read() + _file = file else: - import cStringIO as StringIO - out = StringIO.StringIO() - def readback(): - out.seek(0) - return out.read() + _file = memfile + tmpname = "nada" + out = _file(tmpname, 'w') gen.f = out - gen.gen_source_temp() - newsrc = readback() + gen.gen_source(tmpname, file=_file) + out.close() + newsrc = _file(tmpname).read() code = py.code.Source(newsrc).compile() dic = {'__name__': modname} exec code in dic Modified: pypy/dist/pypy/translator/test/test_geninterp.py ============================================================================== --- pypy/dist/pypy/translator/test/test_geninterp.py (original) +++ pypy/dist/pypy/translator/test/test_geninterp.py Tue Mar 29 17:07:46 2005 @@ -26,7 +26,6 @@ import autopath import py from pypy.tool.udir import udir -from pypy.translator.genc import GenC from pypy.objspace.flow.model import * from pypy.translator.tool.buildpyxmodule import make_module_from_c from pypy.translator.tool.buildpyxmodule import skip_missing_compiler From tismer at codespeak.net Tue Mar 29 17:53:34 2005 From: tismer at codespeak.net (tismer at codespeak.net) Date: Tue, 29 Mar 2005 17:53:34 +0200 (MEST) Subject: [pypy-svn] r10160 - in pypy/dist/pypy/translator: . test Message-ID: <20050329155334.CFA4727B38@code1.codespeak.net> Author: tismer Date: Tue Mar 29 17:07:46 2005 New Revision: 10160 Modified: pypy/dist/pypy/translator/geninterplevel.py pypy/dist/pypy/translator/test/test_geninterp.py Log: added sorted compiling to in-memory compilation using a tiny memfile class. Various cleanups. Modified: pypy/dist/pypy/translator/geninterplevel.py ============================================================================== --- pypy/dist/pypy/translator/geninterplevel.py (original) +++ pypy/dist/pypy/translator/geninterplevel.py Tue Mar 29 17:07:46 2005 @@ -721,7 +721,7 @@ return 'PySys_GetObject("stderr")' raise Exception, 'Cannot translate an already-open file: %r' % (fil,) - def gen_source(self, fname, ftmpname=None): + def gen_source(self, fname, ftmpname=None, file=file): self.fname = fname self.ftmpname = ftmpname @@ -1403,14 +1403,31 @@ import py.code import cStringIO as StringIO +class memfile(object): + _storage = {} + def __init__(self, name, mode="r"): + if mode == "w": + self._storage[name] = StringIO.StringIO() + elif mode == "r": + try: + data = self._storage[name].getvalue() + except IndexError: + data = file(name).read() + self._storage[name] = StringIO.StringIO(data) + else: + raise ValueError, "mode %s not supported" % mode + self._file = self._storage[name] + def __getattr__(self, name): + return getattr(self._file, name) + def close(self): + pass + def translate_as_module(sourcetext, modname="app2interpexec", tmpname=None): """ compile sourcetext as a module, translating to interp level. The result is the init function that creates the wrapped module dict. This init function needs a space as argument. - tmpname can be passed for debugging purposes. Note that the generated - output is not sorted, because it is not meant to be persistent. - For persistent output, please use pypy/translator/tool/tointerplevel.py - + tmpname can be passed for debugging purposes. + Example: initfunc = translate_as_module(text) @@ -1430,19 +1447,15 @@ do_imports_immediately=False) gen = GenRpy(t, entrypoint, modname, dic) if tmpname: - out = file(tmpname, 'w') - def readback(): - out.close() - return file(tmpname, 'r').read() + _file = file else: - import cStringIO as StringIO - out = StringIO.StringIO() - def readback(): - out.seek(0) - return out.read() + _file = memfile + tmpname = "nada" + out = _file(tmpname, 'w') gen.f = out - gen.gen_source_temp() - newsrc = readback() + gen.gen_source(tmpname, file=_file) + out.close() + newsrc = _file(tmpname).read() code = py.code.Source(newsrc).compile() dic = {'__name__': modname} exec code in dic Modified: pypy/dist/pypy/translator/test/test_geninterp.py ============================================================================== --- pypy/dist/pypy/translator/test/test_geninterp.py (original) +++ pypy/dist/pypy/translator/test/test_geninterp.py Tue Mar 29 17:07:46 2005 @@ -26,7 +26,6 @@ import autopath import py from pypy.tool.udir import udir -from pypy.translator.genc import GenC from pypy.objspace.flow.model import * from pypy.translator.tool.buildpyxmodule import make_module_from_c from pypy.translator.tool.buildpyxmodule import skip_missing_compiler From jacob at codespeak.net Tue Mar 29 19:19:49 2005 From: jacob at codespeak.net (jacob at codespeak.net) Date: Tue, 29 Mar 2005 19:19:49 +0200 (MEST) Subject: [pypy-svn] r10161 - pypy/extradoc/sprintinfo Message-ID: <20050329171949.3290127B47@code1.codespeak.net> Author: jacob Date: Tue Mar 29 19:19:49 2005 New Revision: 10161 Added: pypy/extradoc/sprintinfo/pycon_sprint_report.txt Log: Added first draft of report from sprint. Added: pypy/extradoc/sprintinfo/pycon_sprint_report.txt ============================================================================== --- (empty file) +++ pypy/extradoc/sprintinfo/pycon_sprint_report.txt Tue Mar 29 19:19:49 2005 @@ -0,0 +1,156 @@ +Pypy sprint and conference report + +The Pypy project held a 4 day sprint at the Marvin Center, George +Washington University in Washington DC, USA on 19-22 March 2005. + +The sprint was part of the pre-Pycon sprinting sessions and we shared +rooms with sprints for Distutils, Chandler, CPython AST, Twisted, +ZODB, Mailman, Zope and others. The environment was quite inspiring +and there was quite a bit of exchange between the different sprints. + +Participants at the Pypy sprint were: +Michael Chermside +Anders Chrigstr?m +Brian Dorsey +Richard Emslie +Jacob Hall?n +Holger Krekel +Alex Martelli +Alan Mcintyre +Lutz P?like +Samuele Pedroni +Jonathan Riehl +Armin Rigo +Christian Tismer + + +Alan Mcintyre was only present the first day. Michael Chermside joined +the sprint Monday. All the others stayed for the whole sprint. + +The sprint was started with an introduction to Pypy by Armin and +an orientation in the directory structure by Holger. + +We then had a discussion about what to focus on and how to divide the work. +We decided to put our energies into making Pypy as compliant to the CPython +implementation as possible by trying to fulfil the CPython regression tests. + +Christian and Alex worked on implementing Pickle, fixing a large number of +bugs and corner cases in the process. + +Anders and Richard worked on completing the builtin types, especially +focusing on the FrameType. + +Jacob found an already implemented version of the datetime module by talking +to Tim Peters. This required some adjustments before it was put into the +Pypy library. When we later got access to the CPython tests, it turned out +that the module needed some further fixes, which Christian applied. + +Jacob then turned to the binascii module and was later joined by Brian +in this work. About half the module was implemented by the end of the sprint. + +Holger and Brian initially worked on making the CPython tests work under +py.test. Holger then went on to assist Michael and Jonathan while Brian +went to work with Jacob. + +Jonathan focussed on implementing a Python parser in Python. + +Michael wanted to interface the sre module with Pypy, and got started +on the project. + +[More stuff about what people did. I have no clue about what Alan, +Armin, Lutz or Samuele did. Also, what I have written above is +probably incomplete and in some cases downright wrong. This phappens +if you focus tightly on your own coding. Please add and correct.] + +On the whole the sprint was very successful. We made great progress +on the compliancy issue. While there are still many modules that need +implementing, the builtin types are getting very close to being complete. +The missing types generally require interfacing to system calls, which +we are not yet able to handle. + +Talk at the conference +====================== + +Armin Rigo held a talk on the subject of Pypy and Type Inference It +was lively and animated (both abstractly and literally +speaking). Armin explained the concept of Object Spaces, first running +an interpreter with an Object Space that added integers, and then with +one that added fruit. He then went on to explain that you could run +the interpreter with any sort of Object Space; for instance one that +looks at the instructions and tries to deduce what types the variables +involved have. Another object space can do translation to lower level +languages (possibly using the annotations provided by a previous run +with the annotator). + +Holger spoke about py.test and the py lib, which are intimately connected +to the Pypy project. + +Other Pypy relevant talks at the conference were +Localized Type Inference in Python by Brett Cannon +Python on the .NET platform (IronPython) by Jim Hugunin +Decimal Module for Beginners by Michael Chermside +Decimal data type by Facundo Batista +Pulling Java Lucene into Python: PyLucene by Andi Vajda + +OpenSpace discussion about how to handle non-CPython implementations of +Python +======================================================================= +Holger Krekel +Jacob Hall?n +Armin Rigo +Samuele Pedroni +Christian Tismer +Anders Chrigstr?m +Brian Dorsey +Guido van Rossum (CPython) +Jim Hugunin (IronPython) +Brian Zimmer (Jython) + +1. We need to modify the CPython test suite so that it makes a +difference between language compliance tests and CPython +implementation tests. Guido if fine with this, but wants a proposal +written and discussed on python-dev. Jim is busy the next 2 months and +will not start testing. Pypy will modify the tests for its own +purposes and will then propose things based on the experience of +making the modifications. Jython presently has a number of "if not +jython" defines in the test suite. Some of these are CPython +implementation tests, while some are compliance tests that Jython +doesn't pass. + +2. There was a long discussion of how to handle non-portable platform +features and how to handle features that you don't know if you want or +not. It was agreed that "from __experimental__ import ..." should be +used for features that may go away. It was also agreed that it is a +good idea to use "from __jython__ import ..." when you want to +override standard builtin Python features with something that makes +better sense in a specific platform environment. + +3. There was along discussion about where the sweetspot for a platform +specific implementation should be. It didn't rellay conclude anything +special. + +Pypy post-conference meeting +============================ +After the conference, we held a meeting to discuss the division of work for +the next few weeks. + +We should go ahead with the Oxford sprint. Holger wants to do a "private" +sprint in G?teborg a week before Europython. + +Armin - will evaluate different alternatives for the translator and write +a report + +Samuele - will work on finishing the annotator + +Holger - will work on completing the test framework + +Arre - will work on making the std object space fully CPython compiant + +Christian - will work the C translator + +Lutz - will work on a GUI for generating flow graphs + +Jonathan - will continue on his parser + +Jacob - will finish binascii + From arigo at codespeak.net Tue Mar 29 19:39:48 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 29 Mar 2005 19:39:48 +0200 (MEST) Subject: [pypy-svn] r10162 - pypy/dist/pypy/objspace Message-ID: <20050329173948.9457F27B47@code1.codespeak.net> Author: arigo Date: Tue Mar 29 19:39:48 2005 New Revision: 10162 Modified: pypy/dist/pypy/objspace/descroperation.py Log: Fix error messages along CPython's line for setting or deleting a read-only attribute. Modified: pypy/dist/pypy/objspace/descroperation.py ============================================================================== --- pypy/dist/pypy/objspace/descroperation.py (original) +++ pypy/dist/pypy/objspace/descroperation.py Tue Mar 29 19:39:48 2005 @@ -6,9 +6,12 @@ from pypy.interpreter.argument import Arguments from pypy.tool.compile import compile2 -def raiseattrerror(space, w_obj, name): - w_type = space.type(w_obj) - msg = "'%s' object has no attribute '%s'" %(w_type.name, name) +def raiseattrerror(space, w_obj, name, w_descr=None): + w_type = space.type(w_obj) + if w_descr is None: + msg = "'%s' object has no attribute '%s'" %(w_type.name, name) + else: + msg = "'%s' object attribute '%s' is read-only" %(w_type.name, name) raise OperationError(space.w_AttributeError, space.wrap(msg)) class Object: @@ -34,7 +37,7 @@ w_dict = space.getdict(w_obj) if w_dict is not None: return space.setitem(w_dict, w_name, w_value) - raiseattrerror(space, w_obj, name) + raiseattrerror(space, w_obj, name, w_descr) def descr__delattr__(space, w_obj, w_name): name = space.str_w(w_name) @@ -49,7 +52,7 @@ except OperationError, ex: if not ex.match(space, space.w_KeyError): raise - raiseattrerror(space, w_obj, name) + raiseattrerror(space, w_obj, name, w_descr) def descr__init__(space, w_obj, __args__): pass # XXX some strange checking maybe From arigo at codespeak.net Tue Mar 29 19:41:35 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 29 Mar 2005 19:41:35 +0200 (MEST) Subject: [pypy-svn] r10163 - in pypy/dist/pypy: module/builtin objspace/std Message-ID: <20050329174135.8437F27B47@code1.codespeak.net> Author: arigo Date: Tue Mar 29 19:41:35 2005 New Revision: 10163 Modified: pypy/dist/pypy/module/builtin/app_descriptor.py pypy/dist/pypy/objspace/std/typetype.py Log: Who would have though that the __doc__ attribute of types was delicate to get right? It is specially so when we need a class like 'property' whose instances also have a __doc__ slot... Crazyness. Modified: pypy/dist/pypy/module/builtin/app_descriptor.py ============================================================================== --- pypy/dist/pypy/module/builtin/app_descriptor.py (original) +++ pypy/dist/pypy/module/builtin/app_descriptor.py Tue Mar 29 19:41:35 2005 @@ -2,16 +2,26 @@ Plain Python definition of the builtin descriptors. """ +# Don't look! This is needed for the property class, which has a slot +# called __doc__ but also needs a __doc__ string for itself. +class propertydoc(object): + def __get__(self, p, cls=None): + if p is None: + return PROPERTY_DOCSTRING # getting __doc__ on the class + else: + return PROPERTY_DOCSLOT.__get__(p) # on an instance + # Descriptor code, shamelessly stolen to Raymond Hettinger: # http://users.rcn.com/python/download/Descriptor.htm class property(object): - __slots__ = ['fget', 'fset', 'fdel', '__doc__'] + __slots__ = ['fget', 'fset', 'fdel', 'doc'] # NB. 'doc' hacked away below + __doc__ = propertydoc() def __init__(self, fget=None, fset=None, fdel=None, doc=None): self.fget = fget self.fset = fset self.fdel = fdel - self.__doc__ = doc or "" # XXX why: or "" ? + PROPERTY_DOCSLOT.__set__(self, doc) def __get__(self, obj, objtype=None): if obj is None: @@ -30,6 +40,20 @@ raise AttributeError, "can't delete attribute" self.fdel(obj) +PROPERTY_DOCSTRING = '''property(fget=None, fset=None, fdel=None, doc=None) -> property attribute + +fget is a function to be used for getting an attribute value, and likewise +fset is a function for setting, and fdel a function for deleting, an +attribute. Typical use is to define a managed attribute x: +class C(object): + def getx(self): return self.__x + def setx(self, value): self.__x = value + def delx(self): del self.__x + x = property(getx, setx, delx, "I am the 'x' property.")''' + +PROPERTY_DOCSLOT = property.doc +del property.doc + # XXX there is an interp-level pypy.interpreter.function.StaticMethod # XXX because __new__ needs to be a StaticMethod early. Modified: pypy/dist/pypy/objspace/std/typetype.py ============================================================================== --- pypy/dist/pypy/objspace/std/typetype.py (original) +++ pypy/dist/pypy/objspace/std/typetype.py Tue Mar 29 19:41:35 2005 @@ -87,7 +87,7 @@ if w_result is None: return space.w_None else: - return w_result + return space.get(w_result, space.w_None, w_type) def descr__flags(space, w_type): return space.wrap(w_type.__flags__) From jacob at codespeak.net Tue Mar 29 19:50:14 2005 From: jacob at codespeak.net (jacob at codespeak.net) Date: Tue, 29 Mar 2005 19:50:14 +0200 (MEST) Subject: [pypy-svn] r10164 - pypy/extradoc/sprintinfo Message-ID: <20050329175014.291CD27B48@code1.codespeak.net> Author: jacob Date: Tue Mar 29 19:50:14 2005 New Revision: 10164 Modified: pypy/extradoc/sprintinfo/pycon_sprint_report.txt Log: Added email addresses to sprint report. Modified: pypy/extradoc/sprintinfo/pycon_sprint_report.txt ============================================================================== --- pypy/extradoc/sprintinfo/pycon_sprint_report.txt (original) +++ pypy/extradoc/sprintinfo/pycon_sprint_report.txt Tue Mar 29 19:50:14 2005 @@ -9,21 +9,20 @@ and there was quite a bit of exchange between the different sprints. Participants at the Pypy sprint were: -Michael Chermside +Michael Chermside Anders Chrigstr?m -Brian Dorsey -Richard Emslie +Brian Dorsey +Richard Emslie Jacob Hall?n Holger Krekel -Alex Martelli -Alan Mcintyre -Lutz P?like +Alex Martelli +Alan Mcintyre +Lutz P?like Samuele Pedroni -Jonathan Riehl +Jonathan Riehl Armin Rigo Christian Tismer - Alan Mcintyre was only present the first day. Michael Chermside joined the sprint Monday. All the others stayed for the whole sprint. From tismer at codespeak.net Tue Mar 29 20:57:20 2005 From: tismer at codespeak.net (tismer at codespeak.net) Date: Tue, 29 Mar 2005 20:57:20 +0200 (MEST) Subject: [pypy-svn] r10165 - pypy/dist/pypy/module/sys2 Message-ID: <20050329185720.605B727B4D@code1.codespeak.net> Author: tismer Date: Tue Mar 29 20:57:20 2005 New Revision: 10165 Modified: pypy/dist/pypy/module/sys2/app.py Log: fixed a typo Modified: pypy/dist/pypy/module/sys2/app.py ============================================================================== --- pypy/dist/pypy/module/sys2/app.py (original) +++ pypy/dist/pypy/module/sys2/app.py Tue Mar 29 20:57:20 2005 @@ -14,7 +14,7 @@ def exit(exitcode=0): # note that we cannot use SystemExit(exitcode) here. # The comma version leads to an extra de-tupelizing - # in normalize_exception, which is exactlylike CPython. + # in normalize_exception, which is exactly like CPython's. raise SystemExit, exitcode #import __builtin__ From pedronis at codespeak.net Tue Mar 29 23:19:08 2005 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Tue, 29 Mar 2005 23:19:08 +0200 (MEST) Subject: [pypy-svn] r10166 - pypy/extradoc/sprintinfo Message-ID: <20050329211908.C57B927B4D@code1.codespeak.net> Author: pedronis Date: Tue Mar 29 23:19:08 2005 New Revision: 10166 Modified: pypy/extradoc/sprintinfo/pycon_sprint_report.txt Log: added some things as remembered Modified: pypy/extradoc/sprintinfo/pycon_sprint_report.txt ============================================================================== --- pypy/extradoc/sprintinfo/pycon_sprint_report.txt (original) +++ pypy/extradoc/sprintinfo/pycon_sprint_report.txt Tue Mar 29 23:19:08 2005 @@ -33,11 +33,22 @@ We decided to put our energies into making Pypy as compliant to the CPython implementation as possible by trying to fulfil the CPython regression tests. -Christian and Alex worked on implementing Pickle, fixing a large number of -bugs and corner cases in the process. +Christian and Alex worked on implementing Pickle, fixing a large +number of bugs and corner cases in the process. Samuele helped +Christian tracking a bunch of those. + +Related to pickling failing tests, we discovered that our +type.__base__ implementation was too naive, Armin reworked it. Also +Samuele found out that some of our string operations because they were +dispatching on ANY ended up being executed by unicode code (unicode +being a better match than ANY) after an automatic conversion which +would fail for non-ascii characters. This has been fixed. Anders and Richard worked on completing the builtin types, especially -focusing on the FrameType. +focusing on the FrameType. In particular they enabled sys.set_trace +and sys.set_profile functionality, also paying attention that +app-level helper frames are appropriately hidden. The design of how +to achieve the latter was discussed with Armin and Samuele. Jacob found an already implemented version of the datetime module by talking to Tim Peters. This required some adjustments before it was put into the @@ -47,15 +58,26 @@ Jacob then turned to the binascii module and was later joined by Brian in this work. About half the module was implemented by the end of the sprint. -Holger and Brian initially worked on making the CPython tests work under -py.test. Holger then went on to assist Michael and Jonathan while Brian -went to work with Jacob. +Holger and Brian initially worked on making the CPython tests work +under py.test. Samuele also paired a bit on this with Holger. Holger +then went on to assist Michael and Jonathan while Brian went to work +with Jacob. + +Holger alone and then pairing with Samuele reworked our tool to track +our builtins implementations such that there's a summary page and it +is run on codespeak after each check-in, the latest output can always +be seen at http://codespeak.net/pypy/rev/current/ . Jonathan focussed on implementing a Python parser in Python. Michael wanted to interface the sre module with Pypy, and got started on the project. +Armin wrote an example object space that can wrap a given other space +and implements lazy objects and a become operation similar to the one +found in Smalltalk implementations. + + [More stuff about what people did. I have no clue about what Alan, Armin, Lutz or Samuele did. Also, what I have written above is probably incomplete and in some cases downright wrong. This phappens From sanxiyn at codespeak.net Wed Mar 30 02:41:13 2005 From: sanxiyn at codespeak.net (sanxiyn at codespeak.net) Date: Wed, 30 Mar 2005 02:41:13 +0200 (MEST) Subject: [pypy-svn] r10167 - pypy/extradoc/sprintinfo Message-ID: <20050330004113.DD4CE27B4D@code1.codespeak.net> Author: sanxiyn Date: Wed Mar 30 02:41:13 2005 New Revision: 10167 Modified: pypy/extradoc/sprintinfo/pycon_sprint_report.txt Log: Fix function name Modified: pypy/extradoc/sprintinfo/pycon_sprint_report.txt ============================================================================== --- pypy/extradoc/sprintinfo/pycon_sprint_report.txt (original) +++ pypy/extradoc/sprintinfo/pycon_sprint_report.txt Wed Mar 30 02:41:13 2005 @@ -45,8 +45,8 @@ would fail for non-ascii characters. This has been fixed. Anders and Richard worked on completing the builtin types, especially -focusing on the FrameType. In particular they enabled sys.set_trace -and sys.set_profile functionality, also paying attention that +focusing on the FrameType. In particular they enabled sys.settrace +and sys.setprofile functionality, also paying attention that app-level helper frames are appropriately hidden. The design of how to achieve the latter was discussed with Armin and Samuele. From ac at codespeak.net Wed Mar 30 14:08:13 2005 From: ac at codespeak.net (ac at codespeak.net) Date: Wed, 30 Mar 2005 14:08:13 +0200 (MEST) Subject: [pypy-svn] r10169 - in pypy/dist/pypy: interpreter module/sys2 Message-ID: <20050330120813.A679A27B4F@code1.codespeak.net> Author: ac Date: Wed Mar 30 14:08:13 2005 New Revision: 10169 Modified: pypy/dist/pypy/interpreter/executioncontext.py pypy/dist/pypy/module/sys2/__init__.py pypy/dist/pypy/module/sys2/app.py pypy/dist/pypy/module/sys2/vm.py Log: Add ssy.call_tracing() and sys.callstats() Modified: pypy/dist/pypy/interpreter/executioncontext.py ============================================================================== --- pypy/dist/pypy/interpreter/executioncontext.py (original) +++ pypy/dist/pypy/interpreter/executioncontext.py Wed Mar 30 14:08:13 2005 @@ -146,6 +146,14 @@ else: self.w_profilefunc = w_func + def call_tracing(self, w_func, w_args): + is_tracing = self.is_tracing + self.is_tracing = 0 + try: + return self.space.call(w_func, w_args) + finally: + self.is_tracing = is_tracing + def _trace(self, frame, event, w_arg): if self.is_tracing or frame.code.hidden_applevel: return Modified: pypy/dist/pypy/module/sys2/__init__.py ============================================================================== --- pypy/dist/pypy/module/sys2/__init__.py (original) +++ pypy/dist/pypy/module/sys2/__init__.py Wed Mar 30 14:08:13 2005 @@ -45,6 +45,7 @@ 'exc_clear' : 'vm.exc_clear', 'settrace' : 'vm.settrace', 'setprofile' : 'vm.setprofile', + 'call_tracing' : 'vm.call_tracing', 'executable' : 'space.wrap("py.py")', 'copyright' : 'space.wrap("MIT-License")', @@ -65,6 +66,7 @@ '__excepthook__' : 'app.__excepthook__', 'exit' : 'app.exit', 'getfilesystemencoding' : 'app.getfilesystemencoding', + 'callstats' : 'app.callstats', } def setbuiltinmodule(self, w_module, name): Modified: pypy/dist/pypy/module/sys2/app.py ============================================================================== --- pypy/dist/pypy/module/sys2/app.py (original) +++ pypy/dist/pypy/module/sys2/app.py Wed Mar 30 14:08:13 2005 @@ -31,3 +31,26 @@ else: encoding = None return encoding + +def callstats(): + """callstats() -> tuple of integers + +Return a tuple of function call statistics, if CALL_PROFILE was defined +when Python was built. Otherwise, return None. + +When enabled, this function returns detailed, implementation-specific +details about the number of function calls executed. The return value is +a 11-tuple where the entries in the tuple are counts of: +0. all function calls +1. calls to PyFunction_Type objects +2. PyFunction calls that do not create an argument tuple +3. PyFunction calls that do not create an argument tuple + and bypass PyEval_EvalCodeEx() +4. PyMethod calls +5. PyMethod calls on bound methods +6. PyType calls +7. PyCFunction calls +8. generator calls +9. All other calls +10. Number of stack pops performed by call_function()""" + return None Modified: pypy/dist/pypy/module/sys2/vm.py ============================================================================== --- pypy/dist/pypy/module/sys2/vm.py (original) +++ pypy/dist/pypy/module/sys2/vm.py Wed Mar 30 14:08:13 2005 @@ -97,15 +97,20 @@ """settrace(function) Set the global debug tracing function. It will be called on each -function call. See the debugger chapter in the library manual. -""" +function call. See the debugger chapter in the library manual.""" space.getexecutioncontext().settrace(w_func) def setprofile(space, w_func): """setprofile(function) Set the profiling function. It will be called on each function call -and return. See the profiler chapter in the library manual. -""" +and return. See the profiler chapter in the library manual.""" space.getexecutioncontext().setprofile(w_func) +def call_tracing(space, w_func, w_args): + """call_tracing(func, args) -> object + +Call func(*args), while tracing is enabled. The tracing state is +saved, and restored afterwards. This is intended to be called from +a debugger from a checkpoint, to recursively debug some other code.""" + return space.getexecutioncontext().call_tracing(w_func, w_args) From ac at codespeak.net Wed Mar 30 16:01:19 2005 From: ac at codespeak.net (ac at codespeak.net) Date: Wed, 30 Mar 2005 16:01:19 +0200 (MEST) Subject: [pypy-svn] r10176 - pypy/dist/pypy/lib Message-ID: <20050330140119.767CB27B4F@code1.codespeak.net> Author: ac Date: Wed Mar 30 16:01:19 2005 New Revision: 10176 Modified: pypy/dist/pypy/lib/cPickle.py Log: Fix missing sattributes of cPickle. Modified: pypy/dist/pypy/lib/cPickle.py ============================================================================== --- pypy/dist/pypy/lib/cPickle.py (original) +++ pypy/dist/pypy/lib/cPickle.py Wed Mar 30 16:01:19 2005 @@ -3,4 +3,16 @@ # from pickle import * -from pickle import __doc__ +from pickle import __doc__, __version__, format_version, compatible_formats + +class UnpickleableError(PicklingError): + def __init__(self, *args): + self.args=args + + def __str__(self): + a=self.args + a=a and type(a[0]) or '(what)' + return 'Cannot pickle %s objects' % a + +class BadPickleGet(UnpicklingError): + pass From ac at codespeak.net Wed Mar 30 16:03:22 2005 From: ac at codespeak.net (ac at codespeak.net) Date: Wed, 30 Mar 2005 16:03:22 +0200 (MEST) Subject: [pypy-svn] r10177 - pypy/dist/pypy/interpreter Message-ID: <20050330140322.98DE927B4F@code1.codespeak.net> Author: ac Date: Wed Mar 30 16:03:22 2005 New Revision: 10177 Modified: pypy/dist/pypy/interpreter/executioncontext.py pypy/dist/pypy/interpreter/pyframe.py Log: Remove dead code. Modified: pypy/dist/pypy/interpreter/executioncontext.py ============================================================================== --- pypy/dist/pypy/interpreter/executioncontext.py (original) +++ pypy/dist/pypy/interpreter/executioncontext.py Wed Mar 30 16:03:22 2005 @@ -122,10 +122,6 @@ return frame.last_exception return None - def clear_exception(self): - if operror is not None: - operror.clear(space) - def get_state_dict(self): """A mechanism to store arbitrary per ExecutionContext data. Similar to cpython's PyThreadState_GetDict. Modified: pypy/dist/pypy/interpreter/pyframe.py ============================================================================== --- pypy/dist/pypy/interpreter/pyframe.py (original) +++ pypy/dist/pypy/interpreter/pyframe.py Wed Mar 30 16:03:22 2005 @@ -124,18 +124,6 @@ executioncontext.return_trace(self, w_exitvalue) return w_exitvalue - ### exception stack ### - - def clean_exceptionstack(self): - # remove all exceptions that can no longer be re-raised - # because the current valuestack is no longer deep enough - # to hold the corresponding information - while self.exceptionstack: - ctlflowexc, valuestackdepth = self.exceptionstack.top() - if valuestackdepth <= self.valuestack.depth(): - break - self.exceptionstack.pop() - ### line numbers ### def fget_f_lineno(space, w_self): From ac at codespeak.net Wed Mar 30 17:47:54 2005 From: ac at codespeak.net (ac at codespeak.net) Date: Wed, 30 Mar 2005 17:47:54 +0200 (MEST) Subject: [pypy-svn] r10179 - pypy/dist/pypy/interpreter Message-ID: <20050330154754.EF45E27B4F@code1.codespeak.net> Author: ac Date: Wed Mar 30 17:47:54 2005 New Revision: 10179 Modified: pypy/dist/pypy/interpreter/pyframe.py pypy/dist/pypy/interpreter/typedef.py Log: Add f_exc_XXX and f.restricted to frame object. Modified: pypy/dist/pypy/interpreter/pyframe.py ============================================================================== --- pypy/dist/pypy/interpreter/pyframe.py (original) +++ pypy/dist/pypy/interpreter/pyframe.py Wed Mar 30 17:47:54 2005 @@ -290,6 +290,41 @@ else: self.w_f_trace = w_trace self.f_lineno = self.get_last_lineno() + + def fget_f_exc_type(space, w_self): + self = space.interpclass_w(w_self) + if self.last_exception is not None: + f = self.f_back + while f is not None and f.last_exception is None: + f = f_back + if f is not None: + return f.last_exception.w_type + return space.w_None + + def fget_f_exc_value(space, w_self): + self = space.interpclass_w(w_self) + if self.last_exception is not None: + f = self.f_back + while f is not None and f.last_exception is None: + f = f_back + if f is not None: + return f.last_exception.w_value + return space.w_None + + def fget_f_exc_traceback(space, w_self): + self = space.interpclass_w(w_self) + if self.last_exception is not None: + f = self.f_back + while f is not None and f.last_exception is None: + f = f_back + if f is not None: + return space.wrap(f.last_exception.application_traceback) + return space.w_None + + def fget_f_restricted(space, w_self): + self = space.interpclass_w(w_self) + return space.wrap(self.builtin is not space.builtin) + ### Frame Blocks ### class FrameBlock: Modified: pypy/dist/pypy/interpreter/typedef.py ============================================================================== --- pypy/dist/pypy/interpreter/typedef.py (original) +++ pypy/dist/pypy/interpreter/typedef.py Wed Mar 30 17:47:54 2005 @@ -336,6 +336,10 @@ f_back = GetSetProperty(PyFrame.fget_f_back), f_lasti = GetSetProperty(PyFrame.fget_f_lasti), f_trace = GetSetProperty(PyFrame.fget_f_trace, PyFrame.fset_f_trace), + f_exc_type = GetSetProperty(PyFrame.fget_f_exc_type), + f_exc_value = GetSetProperty(PyFrame.fget_f_exc_value), + f_exc_traceback = GetSetProperty(PyFrame.fget_f_exc_traceback), + f_restricted = GetSetProperty(PyFrame.fget_f_restricted), **Frame.typedef.rawdict) Module.typedef = TypeDef("module", From tismer at codespeak.net Wed Mar 30 18:12:52 2005 From: tismer at codespeak.net (tismer at codespeak.net) Date: Wed, 30 Mar 2005 18:12:52 +0200 (MEST) Subject: [pypy-svn] r10180 - in pypy/dist/pypy: interpreter objspace/std translator Message-ID: <20050330161252.95F7027B53@code1.codespeak.net> Author: tismer Date: Wed Mar 30 18:12:52 2005 New Revision: 10180 Modified: pypy/dist/pypy/interpreter/baseobjspace.py pypy/dist/pypy/interpreter/gateway.py pypy/dist/pypy/interpreter/pyframe.py pypy/dist/pypy/interpreter/pyopcode.py pypy/dist/pypy/objspace/std/dicttype.py pypy/dist/pypy/translator/geninterplevel.py Log: Redirected normalize_exception through objspace, to avoid infinite recursion in flow space. Enabled applevelinterp for dicttype. Added normalize_exception to geninterplevel output. Modified: pypy/dist/pypy/interpreter/baseobjspace.py ============================================================================== --- pypy/dist/pypy/interpreter/baseobjspace.py (original) +++ pypy/dist/pypy/interpreter/baseobjspace.py Wed Mar 30 18:12:52 2005 @@ -210,6 +210,10 @@ check_list.extend(exclst) return False + def normalize_exception(self, w_type, w_value, w_tb): + from pypy.interpreter import pyframe + return pyframe.normalize_exception(self, w_type,w_value, w_tb) + def call(self, w_callable, w_args, w_kwds=None): args = Arguments.frompacked(self, w_args, w_kwds) return self.call_args(w_callable, args) Modified: pypy/dist/pypy/interpreter/gateway.py ============================================================================== --- pypy/dist/pypy/interpreter/gateway.py (original) +++ pypy/dist/pypy/interpreter/gateway.py Wed Mar 30 18:12:52 2005 @@ -540,14 +540,14 @@ class applevelinterp(applevel): """ same as applevel, but using translation to interp-level. - Hopefully this will replace applevel at some point. """ - NOT_RPYTHON_ATTRIBUTES = ['initfunc'] + NOT_RPYTHON_ATTRIBUTES = [] - def __init__(self, source, modname = 'applevelinterp'): + def __init__(self, source, filename = None, modname = 'applevelinterp'): "NOT_RPYTHON" - from pypy.translator.geninterplevel import translate_as_module - self.initfunc = translate_as_module(source, modname) + self.filename = filename + self.source = source + self.modname = modname def getwdict(self, space): return space.loadfromcache(self, applevelinterp._builddict, @@ -555,11 +555,14 @@ def _builddict(self, space): "NOT_RPYTHON" - w_glob = self.initfunc(space) + from pypy.translator.geninterplevel import translate_as_module + initfunc = translate_as_module(self.source, self.filename, + self.modname, tmpname="/tmp/look.py") + w_glob = initfunc(space) return w_glob # comment this out to check against applevel without translation -##applevel = applevelinterp +##applevelinterp = applevel ## XXX there is a problem with the naming convention of app_xxx not allowed ## for interp2app! What shall we do? Modified: pypy/dist/pypy/interpreter/pyframe.py ============================================================================== --- pypy/dist/pypy/interpreter/pyframe.py (original) +++ pypy/dist/pypy/interpreter/pyframe.py Wed Mar 30 18:12:52 2005 @@ -392,7 +392,7 @@ operationerr = unroller.args[0] w_type = operationerr.w_type w_value = operationerr.w_value - w_normalized = normalize_exception(frame.space, w_type, w_value, + w_normalized = frame.space.normalize_exception(w_type, w_value, frame.space.w_None) w_type, w_value, w_tb = frame.space.unpacktuple(w_normalized, 3) # save the normalized exception back into the OperationError @@ -410,6 +410,10 @@ return True # stop unrolling return False +# make the following flowable: need _classobj +import types, __builtin__ +__builtin__._classobj = types.ClassType + app = gateway.applevel(''' def normalize_exception(etype, value, tb): """Normalize an (exc_type, exc_value) pair: Modified: pypy/dist/pypy/interpreter/pyopcode.py ============================================================================== --- pypy/dist/pypy/interpreter/pyopcode.py (original) +++ pypy/dist/pypy/interpreter/pyopcode.py Wed Mar 30 18:12:52 2005 @@ -323,7 +323,7 @@ if nbargs >= 3: w_traceback = f.valuestack.pop() if nbargs >= 2: w_value = f.valuestack.pop() if 1: w_type = f.valuestack.pop() - w_resulttuple = pyframe.normalize_exception(f.space, w_type, w_value, + w_resulttuple = f.space.normalize_exception(w_type, w_value, w_traceback) w_type, w_value, w_traceback = f.space.unpacktuple(w_resulttuple, 3) if w_traceback is not f.space.w_None: Modified: pypy/dist/pypy/objspace/std/dicttype.py ============================================================================== --- pypy/dist/pypy/objspace/std/dicttype.py (original) +++ pypy/dist/pypy/objspace/std/dicttype.py Wed Mar 30 18:12:52 2005 @@ -21,7 +21,7 @@ # default application-level implementations for some operations # gateway is imported in the stdtypedef module -app = gateway.applevel(''' +app = gateway.applevelinterp(''' def update(d, o): for k in o.keys(): Modified: pypy/dist/pypy/translator/geninterplevel.py ============================================================================== --- pypy/dist/pypy/translator/geninterplevel.py (original) +++ pypy/dist/pypy/translator/geninterplevel.py Wed Mar 30 18:12:52 2005 @@ -1069,6 +1069,8 @@ # which goes to the last err%d_%d label written above. # Since we only have OperationError, we need to select: yield "except %s, e:" % (self.nameof(OperationError),) + yield " e.w_type, e.w_value, _ign = space.unpacktuple(" + yield " space.normalize_exception(e.w_type, e.w_value, space.w_None), 3)" q = "if" for link in block.exits[1:]: assert issubclass(link.exitcase, Exception) @@ -1422,7 +1424,7 @@ def close(self): pass -def translate_as_module(sourcetext, modname="app2interpexec", tmpname=None): +def translate_as_module(sourcetext, filename=None, modname="app2interpexec", tmpname=None): """ compile sourcetext as a module, translating to interp level. The result is the init function that creates the wrapped module dict. This init function needs a space as argument. @@ -1437,7 +1439,10 @@ # and now use the members of the dict """ # create something like a module - code = py.code.Source(sourcetext).compile() + if filename is None: + code = py.code.Source(sourcetext).compile() + else: + code = compile(sourcetext, filename, 'exec') dic = {'__name__': modname} exec code in dic del dic['__builtins__'] From tismer at codespeak.net Wed Mar 30 19:36:46 2005 From: tismer at codespeak.net (tismer at codespeak.net) Date: Wed, 30 Mar 2005 19:36:46 +0200 (MEST) Subject: [pypy-svn] r10182 - pypy/dist/pypy/translator Message-ID: <20050330173646.98DBE27B4F@code1.codespeak.net> Author: tismer Date: Wed Mar 30 19:36:46 2005 New Revision: 10182 Modified: pypy/dist/pypy/translator/geninterplevel.py Log: support for the faked builtin _classobj Modified: pypy/dist/pypy/translator/geninterplevel.py ============================================================================== --- pypy/dist/pypy/translator/geninterplevel.py (original) +++ pypy/dist/pypy/translator/geninterplevel.py Wed Mar 30 19:36:46 2005 @@ -652,7 +652,8 @@ # type(type.__dict__['__basicsize__']): "cannot eval type(type.__dict__['__basicsize__'])", # XXX there seems to be no working support for member descriptors ??? type(types.GeneratorType.gi_frame): - (eval_helper, "member_descriptor", 'type(types.GeneratorType.gi_frame)') + (eval_helper, "member_descriptor", 'type(types.GeneratorType.gi_frame)'), + types.ClassType: 'space.w_classobj', } def nameof_type(self, cls): From tismer at codespeak.net Wed Mar 30 19:37:20 2005 From: tismer at codespeak.net (tismer at codespeak.net) Date: Wed, 30 Mar 2005 19:37:20 +0200 (MEST) Subject: [pypy-svn] r10183 - pypy/dist/pypy/interpreter/test Message-ID: <20050330173720.2941827B55@code1.codespeak.net> Author: tismer Date: Wed Mar 30 19:37:19 2005 New Revision: 10183 Modified: pypy/dist/pypy/interpreter/test/test_appinterp.py Log: duplicated some applevel tests for applevelinterp Modified: pypy/dist/pypy/interpreter/test/test_appinterp.py ============================================================================== --- pypy/dist/pypy/interpreter/test/test_appinterp.py (original) +++ pypy/dist/pypy/interpreter/test/test_appinterp.py Wed Mar 30 19:37:19 2005 @@ -1,6 +1,6 @@ import py -from pypy.interpreter.gateway import appdef, applevel +from pypy.interpreter.gateway import appdef, applevel, applevelinterp def test_execwith_novars(space): val = space.appexec([], """ @@ -70,7 +70,7 @@ w_result = app(space) assert space.eq_w(w_result, space.wrap(42)) -def test_applevel_functions(space): +def test_applevel_functions(space, applevel=applevel): app = applevel(''' def f(x, y): return x-y @@ -81,7 +81,10 @@ w_res = g(space, space.wrap(10), space.wrap(1)) assert space.eq_w(w_res, space.wrap(-9)) -def test_applevel_class(space): +def test_applevelinterp_functions(space): + test_applevel_functions(space, applevel=applevelinterp) + +def test_applevel_class(space, applevel=applevel): app = applevel(''' class C: clsattr = 42 @@ -95,6 +98,9 @@ w_clsattr = space.getattr(c, space.wrap('attr')) assert space.eq_w(w_clsattr, space.wrap(17)) +def test_applevelinterp_class(space): + test_applevel_class(space, applevel=applevelinterp) + def app_test_something_at_app_level(): x = 2 assert x/2 == 1 From tismer at codespeak.net Wed Mar 30 19:38:22 2005 From: tismer at codespeak.net (tismer at codespeak.net) Date: Wed, 30 Mar 2005 19:38:22 +0200 (MEST) Subject: [pypy-svn] r10184 - pypy/dist/pypy/objspace/flow Message-ID: <20050330173822.BE1AF27B5A@code1.codespeak.net> Author: tismer Date: Wed Mar 30 19:38:22 2005 New Revision: 10184 Modified: pypy/dist/pypy/objspace/flow/objspace.py Log: redirected flow space's normalize_exception by simple inheritance Modified: pypy/dist/pypy/objspace/flow/objspace.py ============================================================================== --- pypy/dist/pypy/objspace/flow/objspace.py (original) +++ pypy/dist/pypy/objspace/flow/objspace.py Wed Mar 30 19:38:22 2005 @@ -185,6 +185,72 @@ self.executioncontext.recorder.crnt_block.exc_handler = True return ObjSpace.exception_match(self, w_exc_type, w_check_class) + def getconstclass(space, w_cls): + try: + ecls = space.unwrap(w_cls) + except UnwrapException: + pass + else: + if isinstance(ecls, (type, types.ClassType)): + return ecls + return None + + def normalize_exception(space, w_arg1, w_arg2, w_tb): + """Special-case for 'raise' statements. Case-by-case analysis: + + * raise Class + - with a constant Class, it is easy to recognize. + But we don't normalize: the associated value is None. + + * raise Class(...) + - when the class is instantiated in-place, we can figure that out + + * raise Instance + - assumes that it's not a class, and raises an exception whose class + is variable and whose value is Instance. + + * raise Class, Arg + - assumes that Arg is the value you want for the exception, and + that Class is exactly the exception class. No check or normalization. + """ + + # w_arg3 (the traceback) is ignored and replaced with None + # if it is a Variable, because pyopcode.py tries to unwrap it. + # It means that we ignore the 'tb' argument of 'raise' in most cases. + if not isinstance(w_tb, Constant): + w_tb = space.w_None + + if w_arg2 != space.w_None: + # raise Class, Arg: no normalization + return (w_arg1, w_arg2, w_tb) + + etype = space.getconstclass(w_arg1) + if etype is not None: + # raise Class + return (w_arg1, space.w_None, w_tb) + + # raise Class(..)? We need a hack to figure out of which class it is. + # Normally, Instance should have been created by the previous operation + # which should be a simple_call(, ...). + # Fetch the out of there. (This doesn't work while replaying) + # XXX this case is likely not triggered anymore, because the instance creation op + # is walled off in a different block by the surrounding it with exception + # handling logic that is always put in place for calls. + # We may want to make this more clever! + operations = space.executioncontext.recorder.crnt_block.operations + if operations: + spaceop = operations[-1] + if (spaceop.opname == 'simple_call' and + spaceop.result is w_arg1): + w_type = spaceop.args[0] + return (w_type, w_arg1, w_tb) + + # raise Instance. Fall-back. + w_type = space.do_operation('type', w_arg1) + return (w_type, w_arg1, w_tb) + # this function returns a real tuple that can be handled + # by FlowObjSpace.unpacktuple() + def build_flow(self, func, constargs={}): """ From tismer at codespeak.net Wed Mar 30 19:40:12 2005 From: tismer at codespeak.net (tismer at codespeak.net) Date: Wed, 30 Mar 2005 19:40:12 +0200 (MEST) Subject: [pypy-svn] r10185 - in pypy/dist/pypy: interpreter objspace/flow Message-ID: <20050330174012.ECF9027B5A@code1.codespeak.net> Author: tismer Date: Wed Mar 30 19:40:12 2005 New Revision: 10185 Modified: pypy/dist/pypy/interpreter/pyframe.py pypy/dist/pypy/objspace/flow/specialcase.py Log: made normalize_exception flowable by rewriting isinstance(x, tuple) into single isinstance calls. No idea if the space should support this. I might support it in geninterp for static tuples. Removed the normalize_exception special case. Modified: pypy/dist/pypy/interpreter/pyframe.py ============================================================================== --- pypy/dist/pypy/interpreter/pyframe.py (original) +++ pypy/dist/pypy/interpreter/pyframe.py Wed Mar 30 19:40:12 2005 @@ -414,7 +414,7 @@ import types, __builtin__ __builtin__._classobj = types.ClassType -app = gateway.applevel(''' +app = gateway.applevelinterp(''' def normalize_exception(etype, value, tb): """Normalize an (exc_type, exc_value) pair: exc_value will be an exception instance and exc_type its class. @@ -422,7 +422,9 @@ # mistakes here usually show up as infinite recursion, which is fun. while isinstance(etype, tuple): etype = etype[0] - if isinstance(etype, (type, _classobj)): + ## if isinstance(etype, (type, _classobj)): + ## isinstance with tuple argument doesn't map to space.isinstance, yet + if isinstance(etype, type) or isinstance(etype, _classobj): if not isinstance(value, etype): if value is None: # raise Type: we assume we have to instantiate Type Modified: pypy/dist/pypy/objspace/flow/specialcase.py ============================================================================== --- pypy/dist/pypy/objspace/flow/specialcase.py (original) +++ pypy/dist/pypy/objspace/flow/specialcase.py Wed Mar 30 19:40:12 2005 @@ -5,74 +5,6 @@ from pypy.objspace.flow.model import Constant -def getconstclass(space, w_cls): - try: - ecls = space.unwrap(w_cls) - except UnwrapException: - pass - else: - if isinstance(ecls, (type, types.ClassType)): - return ecls - return None - - -def sc_normalize_exception(space, fn, args): - """Special-case for 'raise' statements. Case-by-case analysis: - - * raise Class - - with a constant Class, it is easy to recognize. - But we don't normalize: the associated value is None. - - * raise Class(...) - - when the class is instantiated in-place, we can figure that out - - * raise Instance - - assumes that it's not a class, and raises an exception whose class - is variable and whose value is Instance. - - * raise Class, Arg - - assumes that Arg is the value you want for the exception, and - that Class is exactly the exception class. No check or normalization. - """ - w_arg1, w_arg2, w_tb = args.fixedunpack(3) - - # w_arg3 (the traceback) is ignored and replaced with None - # if it is a Variable, because pyopcode.py tries to unwrap it. - # It means that we ignore the 'tb' argument of 'raise' in most cases. - if not isinstance(w_tb, Constant): - w_tb = space.w_None - - if w_arg2 != space.w_None: - # raise Class, Arg: no normalization - return (w_arg1, w_arg2, w_tb) - - etype = getconstclass(space, w_arg1) - if etype is not None: - # raise Class - return (w_arg1, space.w_None, w_tb) - - # raise Class(..)? We need a hack to figure out of which class it is. - # Normally, Instance should have been created by the previous operation - # which should be a simple_call(, ...). - # Fetch the out of there. (This doesn't work while replaying) - # XXX this case is likely not triggered anymore, because the instance creation op - # is walled off in a different block by the surrounding it with exception - # handling logic that is always put in place for calls. - # We may want to make this more clever! - operations = space.executioncontext.recorder.crnt_block.operations - if operations: - spaceop = operations[-1] - if (spaceop.opname == 'simple_call' and - spaceop.result is w_arg1): - w_type = spaceop.args[0] - return (w_type, w_arg1, w_tb) - - # raise Instance. Fall-back. - w_type = space.do_operation('type', w_arg1) - return (w_type, w_arg1, w_tb) - # this function returns a real tuple that can be handled - # by FlowObjSpace.unpacktuple() - def sc_import(space, fn, args): w_name, w_glob, w_loc, w_frm = args.fixedunpack(4) return space.wrap(__import__(space.unwrap(w_name), @@ -89,8 +21,9 @@ def setup(space): - fn = pyframe.normalize_exception.get_function(space) - space.specialcases[fn] = sc_normalize_exception + # fn = pyframe.normalize_exception.get_function(space) + # this is now routed through the objspace, directly. + # space.specialcases[fn] = sc_normalize_exception if space.do_imports_immediately: space.specialcases[__import__] = sc_import for opname in ['lt', 'le', 'eq', 'ne', 'gt', 'ge', 'is_']: From tismer at codespeak.net Wed Mar 30 23:35:23 2005 From: tismer at codespeak.net (tismer at codespeak.net) Date: Wed, 30 Mar 2005 23:35:23 +0200 (MEST) Subject: [pypy-svn] r10191 - in pypy/dist/pypy: interpreter objspace/std translator Message-ID: <20050330213523.E184027B5F@code1.codespeak.net> Author: tismer Date: Wed Mar 30 23:35:23 2005 New Revision: 10191 Modified: pypy/dist/pypy/interpreter/gateway.py pypy/dist/pypy/objspace/std/floatobject.py pypy/dist/pypy/objspace/std/objecttype.py pypy/dist/pypy/objspace/std/slicetype.py pypy/dist/pypy/objspace/std/stringobject.py pypy/dist/pypy/objspace/std/tupleobject.py pypy/dist/pypy/translator/geninterplevel.py Log: applevelinterp-lified a lot more modules. Besides those which are not R-Pythonic due to yield, there are some things left: _formatting cannot be inlined yet, since flowspace has a problem with pow and three arguments. pyopcode.py needs a little more support by me to get at the sys objects. pyparser is not supported since it cannot be imported. Something was not checked in by the one who added it. Modified: pypy/dist/pypy/interpreter/gateway.py ============================================================================== --- pypy/dist/pypy/interpreter/gateway.py (original) +++ pypy/dist/pypy/interpreter/gateway.py Wed Mar 30 23:35:23 2005 @@ -543,11 +543,12 @@ """ NOT_RPYTHON_ATTRIBUTES = [] - def __init__(self, source, filename = None, modname = 'applevelinterp'): + def __init__(self, source, filename = None, modname = 'applevelinterp', do_imports=False): "NOT_RPYTHON" self.filename = filename self.source = source self.modname = modname + self.do_imports = do_imports def getwdict(self, space): return space.loadfromcache(self, applevelinterp._builddict, @@ -557,7 +558,7 @@ "NOT_RPYTHON" from pypy.translator.geninterplevel import translate_as_module initfunc = translate_as_module(self.source, self.filename, - self.modname, tmpname="/tmp/look.py") + self.modname, self.do_imports) w_glob = initfunc(space) return w_glob Modified: pypy/dist/pypy/objspace/std/floatobject.py ============================================================================== --- pypy/dist/pypy/objspace/std/floatobject.py (original) +++ pypy/dist/pypy/objspace/std/floatobject.py Wed Mar 30 23:35:23 2005 @@ -56,7 +56,7 @@ def float_w__Float(space, w_float): return w_float.floatval -app = gateway.applevel(''' +app = gateway.applevelinterp(''' def repr__Float(f): r = "%.17g"%f for c in r: Modified: pypy/dist/pypy/objspace/std/objecttype.py ============================================================================== --- pypy/dist/pypy/objspace/std/objecttype.py (original) +++ pypy/dist/pypy/objspace/std/objecttype.py Wed Mar 30 23:35:23 2005 @@ -61,7 +61,7 @@ w_proto = space.wrap(proto) return reduce_1(space, w_obj, w_proto) -app = gateway.applevel(r''' +app = gateway.applevelinterp(r''' def reduce_1(obj, proto): import copy_reg return copy_reg._reduce_ex(obj, proto) Modified: pypy/dist/pypy/objspace/std/slicetype.py ============================================================================== --- pypy/dist/pypy/objspace/std/slicetype.py (original) +++ pypy/dist/pypy/objspace/std/slicetype.py Wed Mar 30 23:35:23 2005 @@ -7,7 +7,7 @@ # default application-level implementations for some operations # gateway is imported in the stdtypedef module -app = gateway.applevel(""" +app = gateway.applevelinterp(""" def indices(slice, length): # this is used internally, analogous to CPython's PySlice_GetIndicesEx Modified: pypy/dist/pypy/objspace/std/stringobject.py ============================================================================== --- pypy/dist/pypy/objspace/std/stringobject.py (original) +++ pypy/dist/pypy/objspace/std/stringobject.py Wed Mar 30 23:35:23 2005 @@ -964,7 +964,7 @@ "of length %d found"%(len(w_str._value),))) return space.wrap(ord(u_str)) -app = gateway.applevel(r''' +app = gateway.applevelinterp(r''' import codecs def str_translate__String_ANY_ANY(s, table, deletechars=''): @@ -1000,6 +1000,18 @@ repr += quote return repr + def str_decode__String_ANY_ANY(str, encoding=None, errors=None): + if encoding is None and errors is None: + return unicode(str) + elif errors is None: + return codecs.getdecoder(encoding)(str)[0] + else: + return codecs.getdecoder(encoding)(str, errors)[0] +''') + +# this one should do the import of _formatting: +app2 = gateway.applevelinterp(''' + def mod__String_ANY(format, values): import _formatting if isinstance(values, tuple): @@ -1009,20 +1021,12 @@ return _formatting.format(format, (values,), values) else: return _formatting.format(format, (values,), None) - - def str_decode__String_ANY_ANY(str, encoding=None, errors=None): - if encoding is None and errors is None: - return unicode(str) - elif errors is None: - return codecs.getdecoder(encoding)(str)[0] - else: - return codecs.getdecoder(encoding)(str, errors)[0] -''') +''')## XXX not yet, error in pow: , do_imports=('_formatting', '_float_formatting')) str_translate__String_ANY_ANY = app.interphook('str_translate__String_ANY_ANY') str_decode__String_ANY_ANY = app.interphook('str_decode__String_ANY_ANY') -mod__String_ANY = app.interphook('mod__String_ANY') repr__String = app.interphook('repr__String') +mod__String_ANY = app2.interphook('mod__String_ANY') # register all methods from pypy.objspace.std import stringtype Modified: pypy/dist/pypy/objspace/std/tupleobject.py ============================================================================== --- pypy/dist/pypy/objspace/std/tupleobject.py (original) +++ pypy/dist/pypy/objspace/std/tupleobject.py Wed Mar 30 23:35:23 2005 @@ -112,7 +112,7 @@ # No more items to compare -- compare sizes return space.newbool(len(items1) > len(items2)) -app = gateway.applevel(""" +app = gateway.applevelinterp(""" def repr__Tuple(t): if len(t) == 1: return "(" + repr(t[0]) + ",)" Modified: pypy/dist/pypy/translator/geninterplevel.py ============================================================================== --- pypy/dist/pypy/translator/geninterplevel.py (original) +++ pypy/dist/pypy/translator/geninterplevel.py Wed Mar 30 23:35:23 2005 @@ -310,11 +310,12 @@ return name def nameof_module(self, value): - assert value is os or not hasattr(value, "__file__") or \ - not (value.__file__.endswith('.pyc') or - value.__file__.endswith('.py') or - value.__file__.endswith('.pyo')), \ - "%r is not a builtin module (probably :)"%value + #assert value is os or not hasattr(value, "__file__") or \ + # not (value.__file__.endswith('.pyc') or + # value.__file__.endswith('.py') or + # value.__file__.endswith('.pyo')), \ + # "%r is not a builtin module (probably :)"%value + # assume that we get a faked module name = self.uniquename('mod_%s' % value.__name__) self.initcode.append1('import %s as _tmp' % value.__name__) self.initcode.append1('%s = space.wrap(_tmp)' % (name)) @@ -1350,7 +1351,7 @@ test_complex, test_NoneType, all_entries) -entrypoint = entrypoints[-2] +entrypoint = entrypoints[5] if False and __name__ == "__main__": # XXX TODO: @@ -1425,7 +1426,8 @@ def close(self): pass -def translate_as_module(sourcetext, filename=None, modname="app2interpexec", tmpname=None): +def translate_as_module(sourcetext, filename=None, modname="app2interpexec", + do_imports=None, tmpname=None): """ compile sourcetext as a module, translating to interp level. The result is the init function that creates the wrapped module dict. This init function needs a space as argument. @@ -1434,18 +1436,31 @@ Example: initfunc = translate_as_module(text) - from pypy.objspace.stdimport Space + from pypy.objspace.std import Space space = Space() dic = ini(space) # and now use the members of the dict """ # create something like a module + if "_formatting" in sourcetext: tmpname="/tmp/look.py" if filename is None: code = py.code.Source(sourcetext).compile() else: code = compile(sourcetext, filename, 'exec') dic = {'__name__': modname} exec code in dic + print do_imports + if do_imports: + # add lib folder to path + hold = sys.path + sys.path.insert(0, os.path.join(pypy.__path__[0], "lib")) + for modname in do_imports: + print 100*modname + mod = __import__(modname) + try: del mod.__builtins__ + except:pass + dic.update(mod.__dict__) + sys.path = hold del dic['__builtins__'] entrypoint = dic t = Translator(None, verbose=False, simplifying=True, From pedronis at codespeak.net Thu Mar 31 00:04:57 2005 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Thu, 31 Mar 2005 00:04:57 +0200 (MEST) Subject: [pypy-svn] r10192 - in pypy/dist/pypy: interpreter objspace/flow objspace/flow/test Message-ID: <20050330220457.9D67127B6D@code1.codespeak.net> Author: pedronis Date: Thu Mar 31 00:04:57 2005 New Revision: 10192 Modified: pypy/dist/pypy/interpreter/executioncontext.py pypy/dist/pypy/objspace/flow/objspace.py pypy/dist/pypy/objspace/flow/test/test_objspace.py Log: use builtin pow for const pow computations, operator.pow does not accept 3 args Modified: pypy/dist/pypy/interpreter/executioncontext.py ============================================================================== --- pypy/dist/pypy/interpreter/executioncontext.py (original) +++ pypy/dist/pypy/interpreter/executioncontext.py Thu Mar 31 00:04:57 2005 @@ -107,7 +107,7 @@ def exception_trace(self, frame, operationerr): "Trace function called upon OperationError." - operationerr.record_interpreter_traceback() + #operationerr.record_interpreter_traceback() exc_info = self.sys_exc_info() self._trace(frame, 'exception', exc_info) Modified: pypy/dist/pypy/objspace/flow/objspace.py ============================================================================== --- pypy/dist/pypy/objspace/flow/objspace.py (original) +++ pypy/dist/pypy/objspace/flow/objspace.py Thu Mar 31 00:04:57 2005 @@ -462,7 +462,10 @@ if hasattr(FlowObjSpace, name): return # Shouldn't do it - op = getattr(operator, name, None) + if name == 'pow': + op = pow + else: + op = getattr(operator, name, None) if not op: #if name == 'call': # op = apply Modified: pypy/dist/pypy/objspace/flow/test/test_objspace.py ============================================================================== --- pypy/dist/pypy/objspace/flow/test/test_objspace.py (original) +++ pypy/dist/pypy/objspace/flow/test/test_objspace.py Thu Mar 31 00:04:57 2005 @@ -203,6 +203,14 @@ self.show(x) #__________________________________________________________ + def const_pow(): + return 2 ** 5 + + def test_const_pow(self): + x = self.codetest(self.const_pow) + self.show(x) + + #__________________________________________________________ def implicitIndexError(lst): try: x = lst[5] From pedronis at codespeak.net Thu Mar 31 00:06:18 2005 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Thu, 31 Mar 2005 00:06:18 +0200 (MEST) Subject: [pypy-svn] r10193 - pypy/dist/pypy/interpreter Message-ID: <20050330220618.29FCB27B6D@code1.codespeak.net> Author: pedronis Date: Thu Mar 31 00:06:18 2005 New Revision: 10193 Modified: pypy/dist/pypy/interpreter/executioncontext.py Log: this change was not intended for commit Modified: pypy/dist/pypy/interpreter/executioncontext.py ============================================================================== --- pypy/dist/pypy/interpreter/executioncontext.py (original) +++ pypy/dist/pypy/interpreter/executioncontext.py Thu Mar 31 00:06:18 2005 @@ -107,7 +107,7 @@ def exception_trace(self, frame, operationerr): "Trace function called upon OperationError." - #operationerr.record_interpreter_traceback() + operationerr.record_interpreter_traceback() exc_info = self.sys_exc_info() self._trace(frame, 'exception', exc_info) From arigo at codespeak.net Thu Mar 31 11:29:11 2005 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 31 Mar 2005 11:29:11 +0200 (MEST) Subject: [pypy-svn] r10194 - pypy/dist/pypy/translator Message-ID: <20050331092911.07BB727B5D@code1.codespeak.net> Author: arigo Date: Thu Mar 31 11:29:10 2005 New Revision: 10194 Added: pypy/dist/pypy/translator/typer.py (contents, props changed) Log: An experiment; see my mail in pypy-dev. Added: pypy/dist/pypy/translator/typer.py ============================================================================== --- (empty file) +++ pypy/dist/pypy/translator/typer.py Thu Mar 31 11:29:10 2005 @@ -0,0 +1,88 @@ +import autopath +from pypy.annotation.model import * +from pypy.objspace.flow.model import SpaceOperation, Variable, Constant +from pypy.translator.transform import fully_annotated_blocks + + +S_INT = SomeInteger() + +SpecializationTable = [ + ('add', 'int_add', S_INT, S_INT), + ('sub', 'int_sub', S_INT, S_INT), + ('is_true', 'int_is_true', S_INT), + ] + +TypesToConvert = { + SomeInteger: ('int2obj', 'obj2int'), + } + +def setup_specialization_dict(): + for e in SpecializationTable: + spectypes = e[2:] + opname1 = e[0] + opname2 = e[1] + SpecializationDict.setdefault(opname1, []).append((opname2, spectypes)) + SpecializationDict.setdefault(opname2, []).append((opname2, spectypes)) + +SpecializationDict = {} +setup_specialization_dict() + +# ____________________________________________________________ + +def specialize(annotator): + for block in fully_annotated_blocks(annotator): + if not block.operations: + continue + newops = [] + for op in block.operations: + + indices = range(len(op.args)) + args = list(op.args) + bindings = [annotator.binding(a, True) for a in args] + noteworthyindices = [] + + for i in indices: + if isinstance(args[i], Variable) and bindings[i] is not None: + if bindings[i].is_constant(): + args[i] = Constant(bindings[i].const) + else: + noteworthyindices.append(i) + + specializations = SpecializationDict.get(op.opname, ()) + for opname2, spectypes in specializations: + assert len(spectypes) == len(op.args) + for i in indices: + if bindings[i] is None: + break + if not spectypes[i].contains(bindings[i]): + break + else: + op = SpaceOperation(opname2, args, op.result) + break + else: + for i in noteworthyindices: + for cls in bindings[i].__class__.__mro__: + if cls in TypesToConvert: + convert, backconvert = TypesToConvert[cls] + result = Variable() + newops.append(SpaceOperation(convert, [args[i]], + result)) + args[i] = result + break + if args != op.args: + op = SpaceOperation(op.opname, args, op.result) + result = op.result + result_binding = annotator.binding(result, True) + if result_binding is not None: + for cls in result_binding.__class__.__mro__: + if cls in TypesToConvert: + convert, backconvert = TypesToConvert[cls] + intermediate = Variable() + newops.append(SpaceOperation(op.opname, args, + intermediate)) + op = SpaceOperation(backconvert, [intermediate], + result) + break + + newops.append(op) + block.operations[:] = newops From ac at codespeak.net Thu Mar 31 16:59:08 2005 From: ac at codespeak.net (ac at codespeak.net) Date: Thu, 31 Mar 2005 16:59:08 +0200 (MEST) Subject: [pypy-svn] r10199 - pypy/dist/pypy/interpreter Message-ID: <20050331145908.6CC3827BD0@code1.codespeak.net> Author: ac Date: Thu Mar 31 16:59:08 2005 New Revision: 10199 Modified: pypy/dist/pypy/interpreter/pyframe.py Log: Fix typo (Thanks Samuele) Modified: pypy/dist/pypy/interpreter/pyframe.py ============================================================================== --- pypy/dist/pypy/interpreter/pyframe.py (original) +++ pypy/dist/pypy/interpreter/pyframe.py Thu Mar 31 16:59:08 2005 @@ -296,7 +296,7 @@ if self.last_exception is not None: f = self.f_back while f is not None and f.last_exception is None: - f = f_back + f = f.f_back if f is not None: return f.last_exception.w_type return space.w_None @@ -306,7 +306,7 @@ if self.last_exception is not None: f = self.f_back while f is not None and f.last_exception is None: - f = f_back + f = f.f_back if f is not None: return f.last_exception.w_value return space.w_None @@ -316,7 +316,7 @@ if self.last_exception is not None: f = self.f_back while f is not None and f.last_exception is None: - f = f_back + f = f.f_back if f is not None: return space.wrap(f.last_exception.application_traceback) return space.w_None From tismer at codespeak.net Thu Mar 31 19:33:52 2005 From: tismer at codespeak.net (tismer at codespeak.net) Date: Thu, 31 Mar 2005 19:33:52 +0200 (MEST) Subject: [pypy-svn] r10201 - in pypy/dist/pypy: interpreter lib objspace/std translator Message-ID: <20050331173352.758C727BE2@code1.codespeak.net> Author: tismer Date: Thu Mar 31 19:33:52 2005 New Revision: 10201 Modified: pypy/dist/pypy/interpreter/gateway.py pypy/dist/pypy/lib/_formatting.py pypy/dist/pypy/objspace/std/stringobject.py pypy/dist/pypy/translator/geninterplevel.py Log: little changes to _formatting to make it RPythonic, hack to avoid collision with py.magic in flowing, finally succeeded with flowing all of stringobject. _formatting and _float_formatting are directly compiled in, no worries about *these* any longer! To do: cache the compiling (will do on my way home) Modified: pypy/dist/pypy/interpreter/gateway.py ============================================================================== --- pypy/dist/pypy/interpreter/gateway.py (original) +++ pypy/dist/pypy/interpreter/gateway.py Thu Mar 31 19:33:52 2005 @@ -488,7 +488,7 @@ hidden_applevel = True NOT_RPYTHON_ATTRIBUTES = ['code'] - def __init__(self, source, filename=None): + def __init__(self, source, filename=None, *args, **kwds): "NOT_RPYTHON" if filename is None: self.code = py.code.Source(source).compile() Modified: pypy/dist/pypy/lib/_formatting.py ============================================================================== --- pypy/dist/pypy/lib/_formatting.py (original) +++ pypy/dist/pypy/lib/_formatting.py Thu Mar 31 19:33:52 2005 @@ -127,7 +127,7 @@ sign = '' return v, sign - def numeric_postprocess(self, r, sign,prefix=""): + def numeric_postprocess(self, r, sign, prefix=""): assert self.char in 'iduoxXeEfFgG' padchar = ' ' if self.flags.f_zero: @@ -162,6 +162,7 @@ def funcFormatter(*funcs): + """NOT_RPYTHON""" class _F(Formatter): def format(self): r = self.value @@ -344,6 +345,7 @@ '%':funcFormatter(lambda x:'%'), } +del funcFormatter # don't irritate flow space class FmtIter(object): def __init__(self, fmt): Modified: pypy/dist/pypy/objspace/std/stringobject.py ============================================================================== --- pypy/dist/pypy/objspace/std/stringobject.py (original) +++ pypy/dist/pypy/objspace/std/stringobject.py Thu Mar 31 19:33:52 2005 @@ -1021,7 +1021,7 @@ return _formatting.format(format, (values,), values) else: return _formatting.format(format, (values,), None) -''')## XXX not yet, error in pow: , do_imports=('_formatting', '_float_formatting')) +''', do_imports=True) str_translate__String_ANY_ANY = app.interphook('str_translate__String_ANY_ANY') str_decode__String_ANY_ANY = app.interphook('str_decode__String_ANY_ANY') Modified: pypy/dist/pypy/translator/geninterplevel.py ============================================================================== --- pypy/dist/pypy/translator/geninterplevel.py (original) +++ pypy/dist/pypy/translator/geninterplevel.py Thu Mar 31 19:33:52 2005 @@ -18,6 +18,7 @@ from __future__ import generators import autopath, os, sys, exceptions, inspect, types +import cPickle as pickle, __builtin__ from pypy.objspace.flow.model import Variable, Constant, SpaceOperation from pypy.objspace.flow.model import FunctionGraph, Block, Link from pypy.objspace.flow.model import last_exception, last_exc_value @@ -46,16 +47,36 @@ def eval_helper(self, typename, expr): name = self.uniquename("gtype_%s" % typename) - bltinsname = self.nameof('__builtins__') + unique = self.uniquenameofprebuilt("eval_helper", eval_helper) self.initcode.append1( - 'def eval_helper(expr):\n' - ' import types\n' - ' dic = space.newdict([(%s, space.w_builtins)])\n' + 'def %s(expr):\n' + ' dic = space.newdict([])\n' ' space.exec_("import types", dic, dic)\n' - ' return space.eval(expr, dic, dic)' % bltinsname) - self.initcode.append1('%s = eval_helper(%r)' % (name, expr)) + ' return space.eval(expr, dic, dic)' % unique) + self.initcode.append1('%s = %s(%r)' % (name, unique, expr)) return name +def unpickle_helper(self, name, value): + unique = self.uniquenameofprebuilt("unpickle_helper", unpickle_helper) + self.initcode.append1( + 'def %s(value):\n' + ' dic = space.newdict([])\n' + ' space.exec_("import cPickle as pickle", dic, dic)\n' + ' return space.eval("pickle.loads(%%r)" %% value, dic, dic)' % unique) + self.initcode.append1('%s = %s(%r)' % ( + name, unique, pickle.dumps(value, 2)) ) + +# hey, for longs we can do even easier: +def long_helper(self, name, value): + unique = self.uniquenameofprebuilt("long_helper", long_helper) + self.initcode.append1( + 'def %s(value):\n' + ' dic = space.newdict([])\n' + ' space.exec_("", dic, dic) # init __builtins__\n' + ' return space.eval("long(%%r, 16)" %% value, dic, dic)' % unique) + self.initcode.append1('%s = %s(%r)' % ( + name, unique, hex(value)[2:-1] ) ) + class GenRpy: def __init__(self, translator, entrypoint=None, modname=None, moddict=None): self.translator = translator @@ -100,7 +121,6 @@ # catching all builtins in advance, to avoid problems # with modified builtins - import __builtin__ class bltinstub: def __init__(self, name): @@ -294,6 +314,17 @@ self.globaldecl.append('# global object %s' % (name,)) return name + def uniquenameofprebuilt(self, basename, obj): + # identifying an object and giving it a name, + # without the attempt to render it. + key = Constant(obj).key + try: + txt = self.rpynames[key] + except KeyError: + self.rpynames[key] = txt = self.uniquename(basename) + return txt + + def nameof_NotImplementedType(self, value): return "space.w_NotImplemented" @@ -334,9 +365,6 @@ return name def nameof_long(self, value): - # allow short longs only, meaning they - # must fit into a machine word. - assert (sys.maxint*2+1)&value==value, "your literal long is too long" # assume we want them in hex most of the time if value < 256L: s = "%dL" % value @@ -349,7 +377,12 @@ # the prefix before the initial '_' name = 'glong_minus_%d' % abs(value) name = self.uniquename(name) - self.initcode.append1('%s = space.wrap(%s) # XXX implement long!' % (name, s)) + # allow literally short longs only, meaning they + # must fit into a machine word. + if (sys.maxint*2+1)&value == value: + self.initcode.append1('%s = space.wrap(%s) # XXX implement long!' % (name, s)) + else: + long_helper(self, name, value) return name def nameof_float(self, value): @@ -524,8 +557,6 @@ # be lazy return "(space.sys.get(space.str_w(%s)))" % self.nameof(func.__name__) else: - print ("WARNING: accessing builtin modules different from sys or __builtin__" - " is likely producing non-sense: %s %s" % (module.__name__, func.__name__)) name = self.uniquename('gbltin_' + func.__name__) self.initcode.append1('%s = space.getattr(%s, %s)' % ( name, self.nameof(module), self.nameof(func.__name__))) @@ -538,6 +569,7 @@ def nameof_classobj(self, cls): printable_name = cls.__name__ + gaga = "ssertion" in printable_name if cls.__doc__ and cls.__doc__.lstrip().startswith('NOT_RPYTHON'): #raise Exception, "%r should never be reached" % (cls,) print "skipped class", printable_name @@ -547,7 +579,9 @@ name = self.uniquename('gcls_' + cls.__name__) if issubclass(cls, Exception): - if cls.__module__ == 'exceptions': + # if cls.__module__ == 'exceptions': + # don't rely on this, py.magic redefines AssertionError + if getattr(__builtin__,cls.__name__) is cls: # exception are defined on the space return 'space.w_%s' % cls.__name__ @@ -558,6 +592,11 @@ # metaclass = 'space.w_classobj' basenames = [self.nameof(base) for base in cls.__bases__] + if gaga: + print cls + print cls.__module__ + print type(cls) + 1/0 def initclassobj(): content = cls.__dict__.items() content.sort() @@ -1427,7 +1466,7 @@ pass def translate_as_module(sourcetext, filename=None, modname="app2interpexec", - do_imports=None, tmpname=None): + do_imports=False, tmpname=None): """ compile sourcetext as a module, translating to interp level. The result is the init function that creates the wrapped module dict. This init function needs a space as argument. @@ -1449,24 +1488,15 @@ code = compile(sourcetext, filename, 'exec') dic = {'__name__': modname} exec code in dic - print do_imports - if do_imports: - # add lib folder to path - hold = sys.path - sys.path.insert(0, os.path.join(pypy.__path__[0], "lib")) - for modname in do_imports: - print 100*modname - mod = __import__(modname) - try: del mod.__builtins__ - except:pass - dic.update(mod.__dict__) - sys.path = hold del dic['__builtins__'] entrypoint = dic t = Translator(None, verbose=False, simplifying=True, builtins_can_raise_exceptions=True, - do_imports_immediately=False) + do_imports_immediately=do_imports) + hold = sys.path + sys.path.insert(0, os.path.join(pypy.__path__[0], "lib")) gen = GenRpy(t, entrypoint, modname, dic) + sys.path = hold if tmpname: _file = file else: From pedronis at codespeak.net Thu Mar 31 20:20:47 2005 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Thu, 31 Mar 2005 20:20:47 +0200 (MEST) Subject: [pypy-svn] r10205 - in pypy/dist/pypy/translator: . test Message-ID: <20050331182047.B3FEE27C0A@code1.codespeak.net> Author: pedronis Date: Thu Mar 31 20:20:47 2005 New Revision: 10205 Modified: pypy/dist/pypy/translator/annrpython.py pypy/dist/pypy/translator/test/test_annrpython.py Log: simple way to specify annotation for functions we can't/want flow into Modified: pypy/dist/pypy/translator/annrpython.py ============================================================================== --- pypy/dist/pypy/translator/annrpython.py (original) +++ pypy/dist/pypy/translator/annrpython.py Thu Mar 31 20:20:47 2005 @@ -18,7 +18,7 @@ """Block annotator for RPython. See description in doc/translation/annotation.txt.""" - def __init__(self, translator=None): + def __init__(self, translator=None, overrides={}): self.translator = translator self.pendingblocks = {} # map {block: function} self.bindings = {} # map Variables to SomeValues @@ -39,6 +39,8 @@ # history of binding_caused_by, kept in sync with # bindingshistory self.return_bindings = {} # map return Variables to functions + # user-supplied annotation logic for functions we don't want to flow into + self.overrides = overrides # --- end of debugging information --- self.bookkeeper = Bookkeeper(self) @@ -202,6 +204,9 @@ #___ interface for annotator.factory _______ def recursivecall(self, func, position_key, inputcells): + override = self.overrides.get(func, None) + if override is not None: + return override(*inputcells) parent_fn, parent_block, parent_index = position_key graph = self.getflowgraph(func, parent_fn, position_key) # self.notify[graph.returnblock] is a dictionary of call Modified: pypy/dist/pypy/translator/test/test_annrpython.py ============================================================================== --- pypy/dist/pypy/translator/test/test_annrpython.py (original) +++ pypy/dist/pypy/translator/test/test_annrpython.py Thu Mar 31 20:20:47 2005 @@ -595,6 +595,25 @@ assert isinstance(s, annmodel.SomeInstance) assert s.knowntype is snippet.Exc + def test_overrides(self): + import sys + excs = [] + def record_exc(e): + """NOT_RPYTHON""" + excs.append(sys.exc_info) + def g(): + pass + def f(): + try: + g() + except Exception, e: + record_exc(e) + def ann_record_exc(s_e): + return a.bookkeeper.immutablevalue(None) + a = RPythonAnnotator(overrides={record_exc: ann_record_exc}) + s = a.build_types(f, []) + assert s.const is None + def test_freeze_protocol(self): class Stuff: def __init__(self, flag):