From arigo at codespeak.net Mon Dec 1 17:13:07 2003 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 1 Dec 2003 17:13:07 +0100 (MET) Subject: [pypy-svn] rev 2282 - in pypy/trunk/src/pypy: annotation annotation/testtranslator translator/test Message-ID: <20031201161307.9DCAF5BECB@thoth.codespeak.net> Author: arigo Date: Mon Dec 1 17:13:06 2003 New Revision: 2282 Modified: pypy/trunk/src/pypy/annotation/README.txt (props changed) pypy/trunk/src/pypy/annotation/__init__.py (props changed) pypy/trunk/src/pypy/annotation/model.py (props changed) pypy/trunk/src/pypy/annotation/test/ (props changed) pypy/trunk/src/pypy/annotation/test/test_annset.py (props changed) pypy/trunk/src/pypy/translator/annotation.py (props changed) pypy/trunk/src/pypy/translator/test/test_annotation.py (props changed) Log: fixeol. From arigo at codespeak.net Mon Dec 8 17:04:54 2003 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 8 Dec 2003 17:04:54 +0100 (MET) Subject: [pypy-svn] rev 2292 - pypy/trunk/src/pypy/objspace/std Message-ID: <20031208160454.CB6365BF49@thoth.codespeak.net> Author: arigo Date: Mon Dec 8 17:04:54 2003 New Revision: 2292 Modified: pypy/trunk/src/pypy/objspace/std/cpythonobject.py pypy/trunk/src/pypy/objspace/std/default.py Log: issubtype hacks to make test_exceptcomp.py work in stdobjspace with cpythonobjects. Modified: pypy/trunk/src/pypy/objspace/std/cpythonobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/cpythonobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/cpythonobject.py Mon Dec 8 17:04:54 2003 @@ -286,6 +286,9 @@ def issubtype__CPython_ANY(space, w_obj, w_other): return space.newbool(0) +def issubtype__ANY_CPython(space, w_obj, w_other): + return space.newbool(0) + def issubtype__CPython_CPython(space, w_obj, w_other): return space.newbool(issubclass(space.unwrap(w_obj), space.unwrap(w_other))) Modified: pypy/trunk/src/pypy/objspace/std/default.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/default.py (original) +++ pypy/trunk/src/pypy/objspace/std/default.py Mon Dec 8 17:04:54 2003 @@ -75,9 +75,9 @@ def is_data_descr__ANY(space, w_descr): return 0 -def issubtype__ANY_ANY(space, w_one, w_two): - # XXX -- mwh - return space.newbool(0) - # XXX why is it there ? -- Armin +#def issubtype__ANY_ANY(space, w_one, w_two): +# # XXX -- mwh +# return space.newbool(0) +# # XXX why is it there ? -- Armin register_all(vars()) From rocco at codespeak.net Sat Dec 13 20:49:49 2003 From: rocco at codespeak.net (rocco at codespeak.net) Date: Sat, 13 Dec 2003 20:49:49 +0100 (MET) Subject: [pypy-svn] rev 2315 - pypy/trunk/src/pypy/module Message-ID: <20031213194949.D52EF5BFB0@thoth.codespeak.net> Author: rocco Date: Sat Dec 13 20:49:48 2003 New Revision: 2315 Modified: pypy/trunk/src/pypy/module/_randommodule.py pypy/trunk/src/pypy/module/_sremodule.py pypy/trunk/src/pypy/module/cStringIOmodule.py pypy/trunk/src/pypy/module/itertoolsmodule.py pypy/trunk/src/pypy/module/mathmodule.py Log: Handle gracefully when C source modules are not listed in sys.builtin_module_names Modified: pypy/trunk/src/pypy/module/_randommodule.py ============================================================================== --- pypy/trunk/src/pypy/module/_randommodule.py (original) +++ pypy/trunk/src/pypy/module/_randommodule.py Sat Dec 13 20:49:48 2003 @@ -1,20 +1,16 @@ """Bootstrap the builtin _random module. """ -import sys - from pypy.interpreter.extmodule import ExtModule -_names = sys.builtin_module_names - # We use the second (metaclassish) meaning of type to construct a subclass # of ExtModule - can't modify some attributes (like __doc__) after class # creation, and wrapping code does not properly look at instance variables. def RandomHelper(space): - if '_random' in _names: + try: import _random - _randomhelper = type('_random', (ExtModule,), _random.__dict__) - return _randomhelper(space) - else: + except ImportError: return None + _randomhelper = type('_random', (ExtModule,), _random.__dict__) + return _randomhelper(space) Modified: pypy/trunk/src/pypy/module/_sremodule.py ============================================================================== --- pypy/trunk/src/pypy/module/_sremodule.py (original) +++ pypy/trunk/src/pypy/module/_sremodule.py Sat Dec 13 20:49:48 2003 @@ -1,17 +1,16 @@ """Bootstrap the builtin _sre module. """ -import sys - from pypy.interpreter.extmodule import ExtModule -_names = sys.builtin_module_names - # We use the second (metaclassish) meaning of type to construct a subclass # of ExtModule - can't modify some attributes (like __doc__) after class # creation, and wrapping code does not properly look at instance variables. def SreHelper(space): - import _sre + try: + import _sre + except ImportError: + return None _srehelper = type('_sre', (ExtModule,), _sre.__dict__) return _srehelper(space) Modified: pypy/trunk/src/pypy/module/cStringIOmodule.py ============================================================================== --- pypy/trunk/src/pypy/module/cStringIOmodule.py (original) +++ pypy/trunk/src/pypy/module/cStringIOmodule.py Sat Dec 13 20:49:48 2003 @@ -1,20 +1,16 @@ """Bootstrap the builtin cStringIO module. """ -import sys - from pypy.interpreter.extmodule import ExtModule -_names = sys.builtin_module_names - # We use the second (metaclassish) meaning of type to construct a subclass # of ExtModule - can't modify some attributes (like __doc__) after class # creation, and wrapping code does not properly look at instance variables. def CStringIO(space): - if 'cStringIO' in _names: + try: import cStringIO - _cStringIO = type('cStringIO', (ExtModule,), cStringIO.__dict__) - return _cStringIO(space) - else: + except ImportError: return None + _cStringIO = type('cStringIO', (ExtModule,), cStringIO.__dict__) + return _cStringIO(space) Modified: pypy/trunk/src/pypy/module/itertoolsmodule.py ============================================================================== --- pypy/trunk/src/pypy/module/itertoolsmodule.py (original) +++ pypy/trunk/src/pypy/module/itertoolsmodule.py Sat Dec 13 20:49:48 2003 @@ -1,20 +1,16 @@ """Bootstrap the builtin itertools module. """ -import sys - from pypy.interpreter.extmodule import ExtModule -_names = sys.builtin_module_names - # We use the second (metaclassish) meaning of type to construct a subclass # of ExtModule - can't modify some attributes (like __doc__) after class # creation, and wrapping code does not properly look at instance variables. def Itertools(space): - if 'itertools' in _names: + try: import itertools - _itertools = type('itertools', (ExtModule,), itertools.__dict__) - return _itertools(space) - else: + except ImportError: return None + _itertools = type('itertools', (ExtModule,), itertools.__dict__) + return _itertools(space) Modified: pypy/trunk/src/pypy/module/mathmodule.py ============================================================================== --- pypy/trunk/src/pypy/module/mathmodule.py (original) +++ pypy/trunk/src/pypy/module/mathmodule.py Sat Dec 13 20:49:48 2003 @@ -1,20 +1,16 @@ """Bootstrap the builtin math module. """ -import sys - from pypy.interpreter.extmodule import ExtModule -_names = sys.builtin_module_names - # We use the second (metaclassish) meaning of type to construct a subclass # of ExtModule - can't modify some attributes (like __doc__) after class # creation, and wrapping code does not properly look at instance variables. def Math(space): - if 'math' in _names: + try: import math - _math = type('math', (ExtModule,), math.__dict__) - return _math(space) - else: + except ImportError: return None + _math = type('math', (ExtModule,), math.__dict__) + return _math(space) From rocco at codespeak.net Sat Dec 13 22:14:26 2003 From: rocco at codespeak.net (rocco at codespeak.net) Date: Sat, 13 Dec 2003 22:14:26 +0100 (MET) Subject: [pypy-svn] rev 2316 - pypy/trunk/src/pypy/module Message-ID: <20031213211426.AD69F5BFB1@thoth.codespeak.net> Author: rocco Date: Sat Dec 13 22:14:26 2003 New Revision: 2316 Modified: pypy/trunk/src/pypy/module/builtin.py Log: An attempt at an app-level import which can handle package imports. It passes all regression tests with TrivialObjSpace, but it's commented out at the moment because it fails for StdObjSpace. It also needs regression tests of its own, to make sure it's working correctly. There is also the issue of namespace pollution with imp_* items in builtins - they're there for an app/interpreter level bridge. (This is a rush checkin to have it availible for the sprinters - who should feel free to trash it if they come up with something better.) Modified: pypy/trunk/src/pypy/module/builtin.py ============================================================================== --- pypy/trunk/src/pypy/module/builtin.py (original) +++ pypy/trunk/src/pypy/module/builtin.py Sat Dec 13 22:14:26 2003 @@ -4,6 +4,10 @@ from pypy.interpreter.extmodule import ExtModule from pypy.interpreter.error import OperationError +import os.path +import sys +import types + ####################### #### __builtin__ #### ####################### @@ -19,6 +23,12 @@ open = cpy_builtin.open file = cpy_builtin.file +## def __init__(self, space): +## #app level __import__ helpers +## self.w_imp_modules = space.sys.w_modules +## self.w_imp_path = space.sys.w_path +## ExtModule.__init__(self, space) + def _initcompiledbuiltins(self): """ add 'compiled' builtins to app-level dict and interp-level """ self._eval_app_source(xrange_appsource) @@ -60,6 +70,128 @@ w_exc = space.call_function(space.w_ImportError, w_modulename) raise OperationError(space.w_ImportError, w_exc) +## def app___import__(self, *args): +## # NOTE: No import statements can be done in this function, +## # as that would involve a recursive call to this function ... +## +## # args => (name[, globals[, locals[, fromlist]]]) +## +## l = len(args) +## if l >= 1: +## modulename = args[0] +## else: +## raise TypeError('__import__() takes at least 1 argument (0 given)') +## if l >= 2: +## globals = args[1] +## try: +## local_context = self.imp_dirname(globals['__file__']) +## except KeyError: +## local_context = '' +## else: +## local_context = '' +## if l >= 4: +## fromlist = args[3] +## else: +## fromlist = [] +## if l > 4: +## raise TypeError('__import__() takes at most 4 arguments (%i given)' % l) +## +## def inner_load(f, fullname): +## """Load module from file `f` with canonical name `fullname`. +## """ +## mod = self.imp_module(fullname) # XXX - add in docstring +## self.imp_modules[fullname] = mod +## mod.__file__ = f +## dict = mod.__dict__ +## execfile(f, dict, dict) +## return mod +## +## def load(path, modulename, fullname): +## """Create a module. +## +## Create a mnodule with canonical name `fullname` from file +## `modulename`+'.py' in path `path`, if it exist. +## Or alternatively from the package +## `path`/`modulename`/'__init__.py'. +## If neither are found, return None. +## """ +## +## f = self.imp_join(path, modulename + '.py') +## if self.imp_exists(f): +## return inner_load(f, fullname) +## f = self.imp_join(path, modulename, '__init__.py') +## if self.imp_exists(f): +## return inner_load(f, fullname) +## else: +## return None +## +## names = modulename.split('.') +## +## if not names: +## raise ValueError("Cannot import an empty module name.") +## if len(names) == 1: +## if self.imp_modules.has_key(modulename): +## return self.imp_modules[modulename] +## #Relative Import +## if local_context: +## #Regular Module +## module = load(local_context, modulename, modulename) +## if module: +## return module +## #Standard Library Module Import +## for path in self.imp_path: +## #Regular Module +## module = load(path, modulename, modulename) +## if module: +## return module +## #Module Not Found +## raise ImportError(modulename) +## else: +## #Find most specific module already imported. +## for i in range(len(names),0,-1): +## base_name = '.'.join(names[0:i]) +## if self.imp_modules.has_key(base_name): +## break +## #Top level package not imported - import it. +## else: +## base_name = names[0] +## i = 1 +## #Relative Import +## if ((not local_context) or +## not load(local_context, base_name, base_name)): +## #Standard Module Import +## for path in self.imp_path: +## if load(path, base_name, base_name): +## break +## else: +## #Module Not Found +## raise ImportError(base_name) +## path = self.imp_dirname(self.imp_modules[base_name].__file__) +## full_name = base_name +## for j in range(i,len(names)): +## path = self.imp_join(path, names[j]) +## full_name = '.'.join((full_name, names[j])) +## if not load(path, '__init__', full_name): +## raise ImportError(full_name) +## ### load module from path +## if fromlist: +## return self.imp_modules[modulename] +## else: +## return self.imp_modules[names[0]] +## +## # Interpreter level helpers for app level import +## def imp_dirname(self, *args_w): +## return self.space.wrap(os.path.dirname(*self.space.unwrap(args_w))) +## +## def imp_join(self, *args_w): +## return self.space.wrap(os.path.join(*self.space.unwrap(args_w))) +## +## def imp_exists(self, *args_w): +## return self.space.wrap(os.path.exists(*self.space.unwrap(args_w))) +## +## def imp_module(self, w_name): +## return self.space.wrap(Module(self.space, w_name)) + def compile(self, w_str, w_filename, w_startstr, w_supplied_flags=None, w_dont_inherit=None): space = self.space From sschwarzer at codespeak.net Mon Dec 15 14:08:32 2003 From: sschwarzer at codespeak.net (sschwarzer at codespeak.net) Date: Mon, 15 Dec 2003 14:08:32 +0100 (MET) Subject: [pypy-svn] rev 2317 - pypy/trunk/src/pypy/tool Message-ID: <20031215130832.D37115BFBF@thoth.codespeak.net> Author: sschwarzer Date: Mon Dec 15 14:08:31 2003 New Revision: 2317 Modified: pypy/trunk/src/pypy/tool/fixeol Log: Changed comment on (not) forbidden characters to include ff (form feed) as a common name instead of ^L. Modified: pypy/trunk/src/pypy/tool/fixeol ============================================================================== --- pypy/trunk/src/pypy/tool/fixeol (original) +++ pypy/trunk/src/pypy/tool/fixeol Mon Dec 15 14:08:31 2003 @@ -6,7 +6,7 @@ forbidden = range(0,32) forbidden.remove(9) # tab forbidden.remove(10) # lf -forbidden.remove(12) # ^L +forbidden.remove(12) # ff, ^L forbidden.remove(13) # cr From sschwarzer at codespeak.net Mon Dec 15 14:26:31 2003 From: sschwarzer at codespeak.net (sschwarzer at codespeak.net) Date: Mon, 15 Dec 2003 14:26:31 +0100 (MET) Subject: [pypy-svn] rev 2318 - pypy/trunk/src/pypy/tool Message-ID: <20031215132631.F11FC5BFC1@thoth.codespeak.net> Author: sschwarzer Date: Mon Dec 15 14:26:31 2003 New Revision: 2318 Modified: pypy/trunk/src/pypy/tool/fixeol Log: Removed hack for getting the native line ending; this value already exists as os.linesep . Modified: pypy/trunk/src/pypy/tool/fixeol ============================================================================== --- pypy/trunk/src/pypy/tool/fixeol (original) +++ pypy/trunk/src/pypy/tool/fixeol Mon Dec 15 14:26:31 2003 @@ -18,17 +18,7 @@ return False -# hack to get the platform's native end-of-line format -f = open('@fixeol at tmp.txt', 'w') -print >> f -f.close() -f = open('@fixeol at tmp.txt', 'rb') -native_eol = f.read() -f.close() -os.unlink('@fixeol at tmp.txt') - - -def binary2text(filename, native_eol = native_eol): +def binary2text(filename): "Convert a file to the platform's native end-of-line format if needed." f = open(filename, 'rb') data = f.read() @@ -38,7 +28,7 @@ original = data data = data.replace('\r\n', '\n') data = data.replace('\r', '\n') - data = data.replace('\n', native_eol) + data = data.replace('\n', os.linesep) if data != original: f = open(filename, 'wb') f.write(data) From arigo at codespeak.net Mon Dec 15 14:57:02 2003 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 15 Dec 2003 14:57:02 +0100 (MET) Subject: [pypy-svn] rev 2319 - pypy/trunk/src/pypy/appspace Message-ID: <20031215135702.BB69F5BFC1@thoth.codespeak.net> Author: arigo Date: Mon Dec 15 14:57:01 2003 New Revision: 2319 Added: pypy/trunk/src/pypy/appspace/_types.py (contents, props changed) Log: Application-level type definition, draft. Added: pypy/trunk/src/pypy/appspace/_types.py ============================================================================== --- (empty file) +++ pypy/trunk/src/pypy/appspace/_types.py Mon Dec 15 14:57:01 2003 @@ -0,0 +1,65 @@ +""" +Definition of the standard Python types. +""" + +class object: + + def __new__(cls): + if cls is object: + return sys.pypy.ObjectFactory() + else: + return sys.pypy.UserObjectFactory(cls, sys.pypy.ObjectFactory) + + def __repr__(self): + return '<%s object at 0x%x>' % ( + type(self).__name__, id(self)) + + +sys.pypy.registertype(sys.pypy.ObjectFactory, object) + + + +class int(object): + + def __new__(cls, *args): + if cls is int: + return sys.pypy.IntObjectFactory(args) + else: + return sys.pypy.UserObjectFactory(cls, + sys.pypy.IntObjectFactory, + args) + + def __repr__(self): + return str(self) + + +sys.pypy.registertype(sys.pypy.IntObjectFactory, int) + + +class type(object): + pass # ... + + +class dict(object): + + def __new__(cls, args): + hello + + def get(self, k, v=None): + if self.has_key(k): + return self[k] + return v + + +class str(object): + + def __new__(xxx): + xxx + + +class function(object): + + func_code = sys.pypy.builtin_property('fix') + func_globals = sys.pypy.builtin_property('me') + +sys.pypy.registertype(sys.pypy.FunctionFactory, function) From tomek at codespeak.net Mon Dec 15 15:49:20 2003 From: tomek at codespeak.net (tomek at codespeak.net) Date: Mon, 15 Dec 2003 15:49:20 +0100 (MET) Subject: [pypy-svn] rev 2320 - pypy/trunk/src/pypy/objspace Message-ID: <20031215144920.C10575BFC1@thoth.codespeak.net> Author: tomek Date: Mon Dec 15 15:49:20 2003 New Revision: 2320 Added: pypy/trunk/src/pypy/objspace/trace.py Log: An initial check-in of the the trace object space, it doesn't work now :-( Added: pypy/trunk/src/pypy/objspace/trace.py ============================================================================== --- (empty file) +++ pypy/trunk/src/pypy/objspace/trace.py Mon Dec 15 15:49:20 2003 @@ -0,0 +1,29 @@ +# ______________________________________________________________________ +import autopath +import sys, operator, types +import pypy +from pypy.objspace.std import StdObjSpace +from pypy.interpreter.baseobjspace import ObjSpace + +debug = 0 + +# ______________________________________________________________________ +class TraceObjSpace(ObjSpace): + full_exceptions = False + + def initialize(self): + space = StdObjSpace() + for key, item in space.__dict__.items(): + if not callable(item): + setattr(self, key, item) + else: + def logger(*args, **kwargs): + print "XXX" + return item(*args, **kwargs) + setattr(self, key, logger) + + +Space = TraceObjSpace + +# ______________________________________________________________________ +# End of trace.py From hpk at codespeak.net Mon Dec 15 15:54:52 2003 From: hpk at codespeak.net (hpk at codespeak.net) Date: Mon, 15 Dec 2003 15:54:52 +0100 (MET) Subject: [pypy-svn] rev 2321 - in pypy/trunk/src/pypy/translator: . tool Message-ID: <20031215145452.31EFB5BFC1@thoth.codespeak.net> Author: hpk Date: Mon Dec 15 15:54:51 2003 New Revision: 2321 Modified: pypy/trunk/src/pypy/translator/annotation.py pypy/trunk/src/pypy/translator/tool/buildpyxmodule.py pypy/trunk/src/pypy/translator/tool/make_dot.py Log: some minor beautifications and a direct "show_dot" method ... Modified: pypy/trunk/src/pypy/translator/annotation.py ============================================================================== --- pypy/trunk/src/pypy/translator/annotation.py (original) +++ pypy/trunk/src/pypy/translator/annotation.py Mon Dec 15 15:54:51 2003 @@ -46,7 +46,7 @@ return _seen[id(xcell)] except KeyError: if name is None: - name = "X%d" % len(seen) + name = "X%d" % len(_seen) _seen[id(xcell)] = name return name Modified: pypy/trunk/src/pypy/translator/tool/buildpyxmodule.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/buildpyxmodule.py (original) +++ pypy/trunk/src/pypy/translator/tool/buildpyxmodule.py Mon Dec 15 15:54:51 2003 @@ -12,6 +12,7 @@ debug = 0 def make_module_from_pyxstring(name, dirpath, string): + dirpath = Path(dirpath) pyxfile = dirpath.join('%s.pyx' % name) i = 0 while pyxfile.exists(): Modified: pypy/trunk/src/pypy/translator/tool/make_dot.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/make_dot.py (original) +++ pypy/trunk/src/pypy/translator/tool/make_dot.py Mon Dec 15 15:54:51 2003 @@ -131,6 +131,11 @@ def make_dot(graphname, graph, storedir=None, target='ps'): return make_dot_graphs(graph.name, [(graphname, graph)], storedir, target) +def show_dot(graph, storedir = None, target = 'ps'): + name = graph.name + fn = make_dot(name, graph, storedir, target) + os.system('gv %s' % fn) + def make_dot_graphs(basefilename, graphs, storedir=None, target='ps'): from vpath.adapter.process import exec_cmd From hpk at codespeak.net Mon Dec 15 15:55:54 2003 From: hpk at codespeak.net (hpk at codespeak.net) Date: Mon, 15 Dec 2003 15:55:54 +0100 (MET) Subject: [pypy-svn] rev 2322 - pypy/trunk/src/pypy/annotation Message-ID: <20031215145554.8C7D45BFC1@thoth.codespeak.net> Author: hpk Date: Mon Dec 15 15:55:53 2003 New Revision: 2322 Modified: pypy/trunk/src/pypy/annotation/annset.py Log: docstrings! Modified: pypy/trunk/src/pypy/annotation/annset.py ============================================================================== --- pypy/trunk/src/pypy/annotation/annset.py (original) +++ pypy/trunk/src/pypy/annotation/annset.py Mon Dec 15 15:55:53 2003 @@ -101,6 +101,12 @@ return None def record(self, recfunc, *args): + """ invoke the given 'recording' function by passing it a new + Recorder instance and letting it use its modification API. This API will + make sure that for the typical read/decide/write usage the read + annotations are a perequisite of the later write/modification + operation. Thus if the "causing" annotation gets invalidated we + know which "depending" annotations need to be removed. """ rec = Recorder(self) return recfunc(rec, *args) From hpk at codespeak.net Mon Dec 15 16:12:57 2003 From: hpk at codespeak.net (hpk at codespeak.net) Date: Mon, 15 Dec 2003 16:12:57 +0100 (MET) Subject: [pypy-svn] rev 2323 - pypy/trunk/src/pypy/objspace/flow Message-ID: <20031215151257.D88415BFC1@thoth.codespeak.net> Author: hpk Date: Mon Dec 15 16:12:57 2003 New Revision: 2323 Modified: pypy/trunk/src/pypy/objspace/flow/objspace.py Log: get rid of characters like "<>&" in function names Modified: pypy/trunk/src/pypy/objspace/flow/objspace.py ============================================================================== --- pypy/trunk/src/pypy/objspace/flow/objspace.py (original) +++ pypy/trunk/src/pypy/objspace/flow/objspace.py Mon Dec 15 16:12:57 2003 @@ -76,6 +76,10 @@ ec = flowcontext.FlowExecutionContext(self, code, func.func_globals) self.executioncontext = ec ec.build_flow() + name = ec.graph.name + for c in "<>&!": + name = name.replace(c, '_') + ec.graph.name = name return ec.graph # ____________________________________________________________ From hpk at codespeak.net Mon Dec 15 16:13:39 2003 From: hpk at codespeak.net (hpk at codespeak.net) Date: Mon, 15 Dec 2003 16:13:39 +0100 (MET) Subject: [pypy-svn] rev 2324 - in pypy/trunk/src/pypy: interpreter module module/test Message-ID: <20031215151339.9437C5BFC1@thoth.codespeak.net> Author: hpk Date: Mon Dec 15 16:13:38 2003 New Revision: 2324 Modified: pypy/trunk/src/pypy/interpreter/gateway.py pypy/trunk/src/pypy/module/builtin.py pypy/trunk/src/pypy/module/test/test_builtin.py Log: fixed default parameter handling for interpreter-level functions (which are exposed via interp2app to application level) Modified: pypy/trunk/src/pypy/interpreter/gateway.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/gateway.py (original) +++ pypy/trunk/src/pypy/interpreter/gateway.py Mon Dec 15 16:13:38 2003 @@ -120,12 +120,14 @@ # explicitely as the first argument (for plain function), or is read # from 'self.space' for methods. - def __init__(self, name, code, staticglobals=None, staticdefs=[]): + def __init__(self, name, code, staticglobals=None, staticdefs=[], + wrapdefaults=0): self.name = name self.code = code self.staticglobals = staticglobals self.staticdefs = staticdefs self.functioncache = WeakKeyDictionary() # map {space: Function} + self.wrapdefaults = wrapdefaults def __wrap__(self, space): # to wrap a Gateway, we first make a real Function object out of it @@ -184,7 +186,9 @@ if space in self.functioncache: fn = self.functioncache[space] else: - defs_w = [space.wrap(def_value) for def_value in self.staticdefs] + defs_w = self.staticdefs + if self.wrapdefaults: + defs_w = [space.wrap(val) for val in defs_w] fn = Function(space, self.code, w_globals, defs_w) self.functioncache[space] = fn return fn @@ -206,7 +210,8 @@ code._from_code(app.func_code) staticglobals = app.func_globals staticdefs = list(app.func_defaults or ()) - return Gateway(app_name, code, staticglobals, staticdefs) + return Gateway(app_name, code, staticglobals, + staticdefs, wrapdefaults=1) def interp2app(f, app_name=None): """Build a Gateway that calls 'f' at interp-level.""" @@ -222,7 +227,8 @@ app_name = f.func_name builtincode = BuiltinCode(f) staticdefs = list(f.func_defaults or ()) - return Gateway(app_name, builtincode, None, staticdefs) + return Gateway(app_name, builtincode, None, + staticdefs, wrapdefaults=0) def exportall(d): Modified: pypy/trunk/src/pypy/module/builtin.py ============================================================================== --- pypy/trunk/src/pypy/module/builtin.py (original) +++ pypy/trunk/src/pypy/module/builtin.py Mon Dec 15 16:13:38 2003 @@ -14,6 +14,12 @@ import __builtin__ as cpy_builtin +class _noarg: + """ use this class in interpreter level functions for default + values if you want to recognize that no specific value was + passed. + """ + class __builtin__(ExtModule): """ Template for PyPy's '__builtin__' module. """ @@ -248,13 +254,20 @@ def delattr(self, w_object, w_name): return self.space.delattr(w_object, w_name) - def getattr(self, w_object, w_name): - return self.space.getattr(w_object, w_name) + def getattr(self, w_object, w_name, w_defvalue = _noarg): + try: + return self.space.getattr(w_object, w_name) + except OperationError, e: + if e.match(self.space, self.space.w_AttributeError): + if w_defvalue is not _noarg: + return w_defvalue + raise def hash(self, w_object): return self.space.hash(w_object) def oct(self, w_val): + # XXX does this need to be a space operation? return self.space.oct(w_val) def hex(self, w_val): @@ -636,3 +649,4 @@ i+=step return gen(self) """ + Modified: pypy/trunk/src/pypy/module/test/test_builtin.py ============================================================================== --- pypy/trunk/src/pypy/module/test/test_builtin.py (original) +++ pypy/trunk/src/pypy/module/test/test_builtin.py Mon Dec 15 16:13:38 2003 @@ -17,6 +17,13 @@ self.assertRaises(ValueError, chr, -1) self.assertRaises(TypeError, chr, 'a') + def test_getattr(self): + class a: + i = 5 + self.assertEquals(getattr(a, 'i'), 5) + self.assertRaises(AttributeError, getattr, a, 'k') + self.assertEquals(getattr(a, 'k', 42), 42) + def test_type_selftest(self): self.assert_(type(type) is type) From rxe at codespeak.net Mon Dec 15 16:19:06 2003 From: rxe at codespeak.net (rxe at codespeak.net) Date: Mon, 15 Dec 2003 16:19:06 +0100 (MET) Subject: [pypy-svn] rev 2325 - pypy/trunk/src/pypy/objspace Message-ID: <20031215151906.7B4225BFC1@thoth.codespeak.net> Author: rxe Date: Mon Dec 15 16:19:05 2003 New Revision: 2325 Modified: pypy/trunk/src/pypy/objspace/trace.py Log: Testing. Modified: pypy/trunk/src/pypy/objspace/trace.py ============================================================================== --- pypy/trunk/src/pypy/objspace/trace.py (original) +++ pypy/trunk/src/pypy/objspace/trace.py Mon Dec 15 16:19:05 2003 @@ -4,7 +4,7 @@ import pypy from pypy.objspace.std import StdObjSpace from pypy.interpreter.baseobjspace import ObjSpace - +from pypy.interpreter.pycode import PyCode debug = 0 # ______________________________________________________________________ @@ -23,7 +23,36 @@ setattr(self, key, logger) -Space = TraceObjSpace + def runx(self, func, *args): + globals = {} + + w_globals = self.wrap(globals) + args_w = [self.wrap(ii) for ii in args] + + ec = self.getexecutioncontext() + + code = func.func_code + code = PyCode()._from_code(code) + frame = code.create_frame(space, w_globals) + frame.setfastscope(args_w) + + return frame.run() + + +Space = TraceObjSpace +s = Space() # ______________________________________________________________________ # End of trace.py + + +def runx(space, func, *args): + globals = {} + w_globals = space.wrap(globals) + args_w = [space.wrap(ii) for ii in args] + ec = space.getexecutioncontext() + code = func.func_code + code = PyCode()._from_code(code) + frame = code.create_frame(space, w_globals) + frame.setfastscope(args_w) + return frame.run() From sschwarzer at codespeak.net Mon Dec 15 16:34:42 2003 From: sschwarzer at codespeak.net (sschwarzer at codespeak.net) Date: Mon, 15 Dec 2003 16:34:42 +0100 (MET) Subject: [pypy-svn] rev 2328 - pypy/trunk/src/pypy/tool Message-ID: <20031215153442.9AB455BFC1@thoth.codespeak.net> Author: sschwarzer Date: Mon Dec 15 16:34:41 2003 New Revision: 2328 Added: pypy/trunk/src/pypy/tool/dotypes.py Log: one-shot code generator for the _types.py file. Added: pypy/trunk/src/pypy/tool/dotypes.py ============================================================================== --- (empty file) +++ pypy/trunk/src/pypy/tool/dotypes.py Mon Dec 15 16:34:41 2003 @@ -0,0 +1,57 @@ +#! /usr/bin/env python + +import types +import __builtin__ +builtinitems = vars(__builtin__).iteritems +import sys + +typesdone = {} +exports = [] + +def dotype(synonym): + typeobject = getattr(types, synonym) + if type(typeobject) is not type: return + exports.append(synonym) + if typeobject in typesdone: + print 'setattr(_types, %r, %s)' % (synonym, typeobject.__name__) + print + return + typesdone[typeobject] = 1 + + typename = typeobject.__name__ + typetitle = typename.title() + print 'class %s(object):' % typename + print + print ''' def __new__(cls, *args): + if cls is %s: + return pypy.%sObjectFactory(args) + else: + return pypy.UserObjectFactory(cls, pypy.%sObjectFactory, args) + + def __repr__(self): + return str(self) +''' % (typename, typetitle, typetitle) + + sys.stdout.write('_register(pypy.%sObjectFactory, %s'%(typetitle, typename)) + + for n, v in builtinitems(): + if v is typeobject: + if n != typename: + sys.stdout.write(', in_builtin=%r' % n) + break + else: + sys.stdout.write(', in_builtin=False') + + default_synonym = typetitle + 'Type' + if synonym != default_synonym: + sys.stdout.write(', synonym=%r' % synonym) + sys.stdout.write(')\n') + + print + print + +for synonym in dir(types): + dotype(synonym) +print +print '__all__ = %r' % exports + From sschwarzer at codespeak.net Mon Dec 15 16:39:25 2003 From: sschwarzer at codespeak.net (sschwarzer at codespeak.net) Date: Mon, 15 Dec 2003 16:39:25 +0100 (MET) Subject: [pypy-svn] rev 2329 - pypy/trunk/src/pypy/appspace Message-ID: <20031215153925.E45055BFC1@thoth.codespeak.net> Author: sschwarzer Date: Mon Dec 15 16:39:25 2003 New Revision: 2329 Modified: pypy/trunk/src/pypy/appspace/_types.py Log: added all of the class definition boilerplates generated by the tool script 'dotypes', and started cleaning up. Modified: pypy/trunk/src/pypy/appspace/_types.py ============================================================================== --- pypy/trunk/src/pypy/appspace/_types.py (original) +++ pypy/trunk/src/pypy/appspace/_types.py Mon Dec 15 16:39:25 2003 @@ -2,64 +2,464 @@ Definition of the standard Python types. """ +from sys import pypy +import __builtin__ +import _types + + +def _register(factory, cls, synonym=True, in_builtin=True): + """ + Register factory as type cls. If builtin is a true value (which + is the default), also register the type as a built-in. If + synonym is non-empty, also register the type in this very module + under its synonym. + """ + pypy.registertype(factory, cls) + if in_builtin: + if isinstance(str, in_builtin): + typename = in_builtin + else: + typename = cls.__name__ + setattr(__builtin__, typename, cls) + if synonym: + if isinstance(str, synonym): + typename = synonym + else: + typename = cls.__name__.title() + 'Type' + setattr(_types, typename, cls) + + class object: - + def __new__(cls): if cls is object: - return sys.pypy.ObjectFactory() + 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(object): + + 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) + +_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') + + +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 sys.pypy.UserObjectFactory(cls, sys.pypy.ObjectFactory) + return pypy.UserObjectFactory(cls, pypy.FunctionObjectFactory, args) def __repr__(self): - return '<%s object at 0x%x>' % ( - type(self).__name__, id(self)) + return str(self) + # XXX find out details for builtin properties + func_code = pypy.builtin_property('fix') + func_globals = pypy.builtin_property('me') -sys.pypy.registertype(sys.pypy.ObjectFactory, object) +_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 sys.pypy.IntObjectFactory(args) + return pypy.IntObjectFactory(args) else: - return sys.pypy.UserObjectFactory(cls, - sys.pypy.IntObjectFactory, - args) + return pypy.UserObjectFactory(cls, pypy.IntObjectFactory, args) def __repr__(self): return str(self) +_register(pypy.IntObjectFactory, int) -sys.pypy.registertype(sys.pypy.IntObjectFactory, int) +setattr(_types, 'LambdaType', function) -class type(object): - pass # ... +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 dict(object): - def __new__(cls, args): - hello +class instancemethod(object): - def get(self, k, v=None): - if self.has_key(k): - return self[k] - return v + 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) + +_register(pypy.SliceObjectFactory, slice) class str(object): - def __new__(xxx): - xxx + 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') -class function(object): - func_code = sys.pypy.builtin_property('fix') - func_globals = sys.pypy.builtin_property('me') -sys.pypy.registertype(sys.pypy.FunctionFactory, function) +__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'] From sschwarzer at codespeak.net Mon Dec 15 16:47:44 2003 From: sschwarzer at codespeak.net (sschwarzer at codespeak.net) Date: Mon, 15 Dec 2003 16:47:44 +0100 (MET) Subject: [pypy-svn] rev 2330 - pypy/trunk/src/pypy/appspace Message-ID: <20031215154744.BB5915BFC1@thoth.codespeak.net> Author: sschwarzer Date: Mon Dec 15 16:47:44 2003 New Revision: 2330 Modified: pypy/trunk/src/pypy/appspace/_types.py Log: Cleaned up formatting. Modified: pypy/trunk/src/pypy/appspace/_types.py ============================================================================== --- pypy/trunk/src/pypy/appspace/_types.py (original) +++ pypy/trunk/src/pypy/appspace/_types.py Mon Dec 15 16:47:44 2003 @@ -77,16 +77,19 @@ 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) + 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') - +_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): @@ -98,7 +101,8 @@ def __repr__(self): return str(self) -_register(pypy.ClassobjObjectFactory, classobj, in_builtin=False, synonym='ClassType') +_register(pypy.ClassobjObjectFactory, classobj, in_builtin=False, + synonym='ClassType') class code(object): @@ -135,12 +139,14 @@ if cls is dictproxy: return pypy.DictproxyObjectFactory(args) else: - return pypy.UserObjectFactory(cls, pypy.DictproxyObjectFactory, args) + return pypy.UserObjectFactory(cls, pypy.DictproxyObjectFactory, + args) def __repr__(self): return str(self) -_register(pypy.DictproxyObjectFactory, dictproxy, in_builtin=False, synonym='DictProxyType') +_register(pypy.DictproxyObjectFactory, dictproxy, in_builtin=False, + synonym='DictProxyType') class dict(object): @@ -156,9 +162,9 @@ _register(pypy.DictObjectFactory, dict) - setattr(_types, 'DictionaryType', dict) + class ellipsis(object): def __new__(cls, *args): @@ -274,9 +280,9 @@ _register(pypy.IntObjectFactory, int) - setattr(_types, 'LambdaType', function) + class list(object): def __new__(cls, *args): @@ -311,12 +317,14 @@ if cls is instancemethod: return pypy.InstancemethodObjectFactory(args) else: - return pypy.UserObjectFactory(cls, pypy.InstancemethodObjectFactory, args) + return pypy.UserObjectFactory(cls, + pypy.InstancemethodObjectFactory, args) def __repr__(self): return str(self) -_register(pypy.InstancemethodObjectFactory, instancemethod, in_builtin=False, synonym='MethodType') +_register(pypy.InstancemethodObjectFactory, instancemethod, in_builtin=False, + synonym='MethodType') class module(object): @@ -344,7 +352,8 @@ def __repr__(self): return str(self) -_register(pypy.NonetypeObjectFactory, NoneType, in_builtin=False, synonym='NoneType') +_register(pypy.NonetypeObjectFactory, NoneType, in_builtin=False, + synonym='NoneType') class NotImplementedType(object): @@ -353,12 +362,14 @@ if cls is NotImplementedType: return pypy.NotimplementedtypeObjectFactory(args) else: - return pypy.UserObjectFactory(cls, pypy.NotimplementedtypeObjectFactory, args) + return pypy.UserObjectFactory(cls, + pypy.NotimplementedtypeObjectFactory, args) def __repr__(self): return str(self) -_register(pypy.NotimplementedtypeObjectFactory, NotImplementedType, in_builtin=False, synonym='NotImplementedType') +_register(pypy.NotimplementedtypeObjectFactory, NotImplementedType, + in_builtin=False, synonym='NotImplementedType') class slice(object): @@ -395,7 +406,8 @@ if cls is traceback: return pypy.TracebackObjectFactory(args) else: - return pypy.UserObjectFactory(cls, pypy.TracebackObjectFactory, args) + return pypy.UserObjectFactory(cls, pypy.TracebackObjectFactory, + args) def __repr__(self): return str(self) @@ -430,9 +442,9 @@ _register(pypy.TypeObjectFactory, type) - setattr(_types, 'UnboundMethodType', instancemethod) + class unicode(object): def __new__(cls, *args): @@ -462,4 +474,12 @@ -__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'] +__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'] From sschwarzer at codespeak.net Mon Dec 15 16:56:45 2003 From: sschwarzer at codespeak.net (sschwarzer at codespeak.net) Date: Mon, 15 Dec 2003 16:56:45 +0100 (MET) Subject: [pypy-svn] rev 2331 - pypy/trunk/src/pypy/appspace Message-ID: <20031215155645.075A75BFC1@thoth.codespeak.net> Author: sschwarzer Date: Mon Dec 15 16:56:45 2003 New Revision: 2331 Modified: pypy/trunk/src/pypy/appspace/_types.py Log: Fixed docstring of function _register. Modified: pypy/trunk/src/pypy/appspace/_types.py ============================================================================== --- pypy/trunk/src/pypy/appspace/_types.py (original) +++ pypy/trunk/src/pypy/appspace/_types.py Mon Dec 15 16:56:45 2003 @@ -7,12 +7,19 @@ import _types -def _register(factory, cls, synonym=True, in_builtin=True): +def _register(factory, cls, in_builtin=True, synonym=True): """ - Register factory as type cls. If builtin is a true value (which - is the default), also register the type as a built-in. If - synonym is non-empty, also register the type in this very module - under its synonym. + 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: From sschwarzer at codespeak.net Mon Dec 15 16:58:10 2003 From: sschwarzer at codespeak.net (sschwarzer at codespeak.net) Date: Mon, 15 Dec 2003 16:58:10 +0100 (MET) Subject: [pypy-svn] rev 2332 - pypy/trunk/src/pypy/appspace Message-ID: <20031215155810.4A1DC5BFC1@thoth.codespeak.net> Author: sschwarzer Date: Mon Dec 15 16:58:09 2003 New Revision: 2332 Modified: pypy/trunk/src/pypy/appspace/_types.py Log: Fixed the order of the arguments to isinstance in _register. Modified: pypy/trunk/src/pypy/appspace/_types.py ============================================================================== --- pypy/trunk/src/pypy/appspace/_types.py (original) +++ pypy/trunk/src/pypy/appspace/_types.py Mon Dec 15 16:58:09 2003 @@ -23,13 +23,13 @@ """ pypy.registertype(factory, cls) if in_builtin: - if isinstance(str, in_builtin): + if isinstance(in_builtin, str): typename = in_builtin else: typename = cls.__name__ setattr(__builtin__, typename, cls) if synonym: - if isinstance(str, synonym): + if isinstance(synonym, str): typename = synonym else: typename = cls.__name__.title() + 'Type' From sschwarzer at codespeak.net Mon Dec 15 17:00:53 2003 From: sschwarzer at codespeak.net (sschwarzer at codespeak.net) Date: Mon, 15 Dec 2003 17:00:53 +0100 (MET) Subject: [pypy-svn] rev 2333 - pypy/trunk/src/pypy/appspace Message-ID: <20031215160053.607845BFC1@thoth.codespeak.net> Author: sschwarzer Date: Mon Dec 15 17:00:52 2003 New Revision: 2333 Modified: pypy/trunk/src/pypy/appspace/_types.py Log: moved __all__ to the top of the file Modified: pypy/trunk/src/pypy/appspace/_types.py ============================================================================== --- pypy/trunk/src/pypy/appspace/_types.py (original) +++ pypy/trunk/src/pypy/appspace/_types.py Mon Dec 15 17:00:52 2003 @@ -6,6 +6,15 @@ 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): """ @@ -481,12 +490,3 @@ -__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'] From tomek at codespeak.net Mon Dec 15 17:13:01 2003 From: tomek at codespeak.net (tomek at codespeak.net) Date: Mon, 15 Dec 2003 17:13:01 +0100 (MET) Subject: [pypy-svn] rev 2334 - pypy/trunk/src/pypy/objspace Message-ID: <20031215161301.A5C015BFC1@thoth.codespeak.net> Author: tomek Date: Mon Dec 15 17:13:00 2003 New Revision: 2334 Modified: pypy/trunk/src/pypy/objspace/trace.py Log: we still work on it, please ignone this commit Modified: pypy/trunk/src/pypy/objspace/trace.py ============================================================================== --- pypy/trunk/src/pypy/objspace/trace.py (original) +++ pypy/trunk/src/pypy/objspace/trace.py Mon Dec 15 17:13:00 2003 @@ -1,6 +1,6 @@ # ______________________________________________________________________ import autopath -import sys, operator, types +import sys, operator, types, new import pypy from pypy.objspace.std import StdObjSpace from pypy.interpreter.baseobjspace import ObjSpace @@ -13,15 +13,25 @@ def initialize(self): space = StdObjSpace() + self.space = space for key, item in space.__dict__.items(): if not callable(item): + print "key: %s" % key setattr(self, key, item) else: - def logger(*args, **kwargs): - print "XXX" + def logger(self, *args, **kwargs): + print "instance method %s, args: %s" % (key, args) return item(*args, **kwargs) - setattr(self, key, logger) + setattr(self, key, new.instancemethod(logger, self, TraceObjSpace)) + for key in space.__class__.__dict__.keys(): + item = getattr(space, key) + if callable(item) and not key.startswith('__'): + def logger(self, *args, **kwargs): + print "class method %s, args: %s" % (key, args) + return item(*args, **kwargs) + + setattr(self, key, new.instancemethod(logger, self, TraceObjSpace)) def runx(self, func, *args): globals = {} @@ -56,3 +66,9 @@ frame = code.create_frame(space, w_globals) frame.setfastscope(args_w) return frame.run() + +if __name__ == "__main__": + def a(b): + return b+1 + + print runx(s, a, 1) From tomek at codespeak.net Mon Dec 15 17:20:11 2003 From: tomek at codespeak.net (tomek at codespeak.net) Date: Mon, 15 Dec 2003 17:20:11 +0100 (MET) Subject: [pypy-svn] rev 2335 - pypy/trunk/src/pypy/tool Message-ID: <20031215162011.DD3855BFC3@thoth.codespeak.net> Author: tomek Date: Mon Dec 15 17:20:11 2003 New Revision: 2335 Modified: pypy/trunk/src/pypy/tool/option.py Log: Now you can use the interactive.py with a new option -P for the trace object space Modified: pypy/trunk/src/pypy/tool/option.py ============================================================================== --- pypy/trunk/src/pypy/tool/option.py (original) +++ pypy/trunk/src/pypy/tool/option.py Mon Dec 15 17:20:11 2003 @@ -22,6 +22,10 @@ callback=objspace_callback, callback_args=("trivial",), help="run in trivial object space")) options.append(make_option( + '-P', action="callback", + callback=objspace_callback, callback_args=("trace",), + help="run in trace object space")) + options.append(make_option( '-A', action="callback", callback=objspace_callback, callback_args=("ann",), help="run in annotation object space")) From sschwarzer at codespeak.net Mon Dec 15 17:25:27 2003 From: sschwarzer at codespeak.net (sschwarzer at codespeak.net) Date: Mon, 15 Dec 2003 17:25:27 +0100 (MET) Subject: [pypy-svn] rev 2336 - pypy/trunk/src/pypy/appspace Message-ID: <20031215162527.AF5BA5BFC3@thoth.codespeak.net> Author: sschwarzer Date: Mon Dec 15 17:25:27 2003 New Revision: 2336 Modified: pypy/trunk/src/pypy/appspace/_types.py Log: committed with corrected EOL setting Modified: pypy/trunk/src/pypy/appspace/_types.py ============================================================================== --- pypy/trunk/src/pypy/appspace/_types.py (original) +++ pypy/trunk/src/pypy/appspace/_types.py Mon Dec 15 17:25:27 2003 @@ -59,7 +59,7 @@ _register(pypy.ObjectFactory, object) -class bool(object): +class bool(int): def __new__(cls, *args): if cls is bool: @@ -176,6 +176,16 @@ 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) From rxe at codespeak.net Mon Dec 15 17:34:22 2003 From: rxe at codespeak.net (rxe at codespeak.net) Date: Mon, 15 Dec 2003 17:34:22 +0100 (MET) Subject: [pypy-svn] rev 2337 - pypy/trunk/src/pypy/objspace Message-ID: <20031215163422.79C355BFC3@thoth.codespeak.net> Author: rxe Date: Mon Dec 15 17:34:21 2003 New Revision: 2337 Modified: pypy/trunk/src/pypy/objspace/trace.py Log: Test Modified: pypy/trunk/src/pypy/objspace/trace.py ============================================================================== --- pypy/trunk/src/pypy/objspace/trace.py (original) +++ pypy/trunk/src/pypy/objspace/trace.py Mon Dec 15 17:34:21 2003 @@ -7,8 +7,18 @@ from pypy.interpreter.pycode import PyCode debug = 0 +class Logger(object): + def __init__(self, fn, printme): + self.fn = fn + self.printme = printme + + def __call__(self, cls, *args, **kwds): + print "%s (%s, %s)" % (self.printme, str(args), str(kwds)) + return self.fn(*args, **kwds) + + # ______________________________________________________________________ -class TraceObjSpace(ObjSpace): +class TraceObjSpace(StdObjSpace): full_exceptions = False def initialize(self): @@ -19,19 +29,16 @@ print "key: %s" % key setattr(self, key, item) else: - def logger(self, *args, **kwargs): - print "instance method %s, args: %s" % (key, args) - return item(*args, **kwargs) - setattr(self, key, new.instancemethod(logger, self, TraceObjSpace)) + l = Logger(item, "instance method") + print l + setattr(self, key, new.instancemethod(l, self, TraceObjSpace)) for key in space.__class__.__dict__.keys(): item = getattr(space, key) if callable(item) and not key.startswith('__'): - def logger(self, *args, **kwargs): - print "class method %s, args: %s" % (key, args) - return item(*args, **kwargs) - - setattr(self, key, new.instancemethod(logger, self, TraceObjSpace)) + l = Logger(item, "class method") + print l + setattr(self, key, new.instancemethod(l, self, TraceObjSpace)) def runx(self, func, *args): globals = {} @@ -57,12 +64,11 @@ def runx(space, func, *args): - globals = {} - w_globals = space.wrap(globals) args_w = [space.wrap(ii) for ii in args] ec = space.getexecutioncontext() code = func.func_code code = PyCode()._from_code(code) + w_globals = ec.make_standard_w_globals() frame = code.create_frame(space, w_globals) frame.setfastscope(args_w) return frame.run() From rxe at codespeak.net Mon Dec 15 17:59:26 2003 From: rxe at codespeak.net (rxe at codespeak.net) Date: Mon, 15 Dec 2003 17:59:26 +0100 (MET) Subject: [pypy-svn] rev 2338 - pypy/trunk/src/pypy/objspace Message-ID: <20031215165926.9599D5BFC3@thoth.codespeak.net> Author: rxe Date: Mon Dec 15 17:59:25 2003 New Revision: 2338 Modified: pypy/trunk/src/pypy/objspace/trace.py Log: Test Modified: pypy/trunk/src/pypy/objspace/trace.py ============================================================================== --- pypy/trunk/src/pypy/objspace/trace.py (original) +++ pypy/trunk/src/pypy/objspace/trace.py Mon Dec 15 17:59:25 2003 @@ -8,57 +8,38 @@ debug = 0 class Logger(object): - def __init__(self, fn, printme): + def __init__(self, name, fn, printme): self.fn = fn + self.name = name self.printme = printme def __call__(self, cls, *args, **kwds): - print "%s (%s, %s)" % (self.printme, str(args), str(kwds)) + print self.name + #print "%s %s(%s, %s)" % (self.printme, , str(args), str(kwds)) return self.fn(*args, **kwds) # ______________________________________________________________________ -class TraceObjSpace(StdObjSpace): - full_exceptions = False - - def initialize(self): - space = StdObjSpace() - self.space = space - for key, item in space.__dict__.items(): - if not callable(item): - print "key: %s" % key - setattr(self, key, item) - else: - l = Logger(item, "instance method") - print l - setattr(self, key, new.instancemethod(l, self, TraceObjSpace)) - - for key in space.__class__.__dict__.keys(): - item = getattr(space, key) - if callable(item) and not key.startswith('__'): - l = Logger(item, "class method") - print l - setattr(self, key, new.instancemethod(l, self, TraceObjSpace)) - - def runx(self, func, *args): - globals = {} - - w_globals = self.wrap(globals) - args_w = [self.wrap(ii) for ii in args] - ec = self.getexecutioncontext() +def Trace(spacecls = StdObjSpace): - code = func.func_code - code = PyCode()._from_code(code) - - frame = code.create_frame(space, w_globals) - frame.setfastscope(args_w) - - return frame.run() + class TraceObjSpace(spacecls): + def initialize(self): + self.space = spacecls() + + method_names = [ii[0] for ii in ObjSpace.MethodTable] + for key in method_names: + if key in method_names: + item = getattr(self.space, key) + l = Logger(key, item, "class method") + setattr(self, key, new.instancemethod(l, self, TraceObjSpace)) + + return TraceObjSpace() + -Space = TraceObjSpace -s = Space() +s = Trace() +print dir(s) # ______________________________________________________________________ # End of trace.py From sschwarzer at codespeak.net Mon Dec 15 18:03:42 2003 From: sschwarzer at codespeak.net (sschwarzer at codespeak.net) Date: Mon, 15 Dec 2003 18:03:42 +0100 (MET) Subject: [pypy-svn] rev 2339 - pypy/trunk/src/pypy/appspace Message-ID: <20031215170342.817C55BFC3@thoth.codespeak.net> Author: sschwarzer Date: Mon Dec 15 18:03:41 2003 New Revision: 2339 Modified: pypy/trunk/src/pypy/appspace/_types.py Log: finished first cleanup by comparison with the *type.py modules in objspace/std -- needs cooperation with objspace for any more cleanup OR testing Modified: pypy/trunk/src/pypy/appspace/_types.py ============================================================================== --- pypy/trunk/src/pypy/appspace/_types.py (original) +++ pypy/trunk/src/pypy/appspace/_types.py Mon Dec 15 18:03:41 2003 @@ -219,6 +219,12 @@ _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): @@ -409,6 +415,49 @@ 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) From rxe at codespeak.net Mon Dec 15 18:05:12 2003 From: rxe at codespeak.net (rxe at codespeak.net) Date: Mon, 15 Dec 2003 18:05:12 +0100 (MET) Subject: [pypy-svn] rev 2340 - pypy/trunk/src/pypy/objspace Message-ID: <20031215170512.077815BFC3@thoth.codespeak.net> Author: rxe Date: Mon Dec 15 18:05:11 2003 New Revision: 2340 Modified: pypy/trunk/src/pypy/objspace/trace.py Log: iasd Modified: pypy/trunk/src/pypy/objspace/trace.py ============================================================================== --- pypy/trunk/src/pypy/objspace/trace.py (original) +++ pypy/trunk/src/pypy/objspace/trace.py Mon Dec 15 18:05:11 2003 @@ -24,22 +24,24 @@ def Trace(spacecls = StdObjSpace): class TraceObjSpace(spacecls): + full_exceptions = False def initialize(self): - self.space = spacecls() + spacecls.initialize(self) method_names = [ii[0] for ii in ObjSpace.MethodTable] for key in method_names: if key in method_names: - item = getattr(self.space, key) + item = getattr(self, key) l = Logger(key, item, "class method") + #print l setattr(self, key, new.instancemethod(l, self, TraceObjSpace)) return TraceObjSpace() s = Trace() -print dir(s) +#print dir(s) # ______________________________________________________________________ # End of trace.py From tomek at codespeak.net Mon Dec 15 18:07:17 2003 From: tomek at codespeak.net (tomek at codespeak.net) Date: Mon, 15 Dec 2003 18:07:17 +0100 (MET) Subject: [pypy-svn] rev 2341 - pypy/trunk/src/pypy/objspace Message-ID: <20031215170717.DDF5B5BFC3@thoth.codespeak.net> Author: tomek Date: Mon Dec 15 18:07:17 2003 New Revision: 2341 Modified: pypy/trunk/src/pypy/objspace/trace.py Log: Added Space attribute to the trace object space Modified: pypy/trunk/src/pypy/objspace/trace.py ============================================================================== --- pypy/trunk/src/pypy/objspace/trace.py (original) +++ pypy/trunk/src/pypy/objspace/trace.py Mon Dec 15 18:07:17 2003 @@ -39,7 +39,7 @@ return TraceObjSpace() - +Space = Trace s = Trace() #print dir(s) # ______________________________________________________________________ From jacob at codespeak.net Mon Dec 15 18:21:12 2003 From: jacob at codespeak.net (jacob at codespeak.net) Date: Mon, 15 Dec 2003 18:21:12 +0100 (MET) Subject: [pypy-svn] rev 2342 - pypy/trunk/src/pypy/module Message-ID: <20031215172112.E64965BFC3@thoth.codespeak.net> Author: jacob Date: Mon Dec 15 18:21:12 2003 New Revision: 2342 Modified: pypy/trunk/src/pypy/module/sysmodule.py Log: Fixed wrapping bug. Modified: pypy/trunk/src/pypy/module/sysmodule.py ============================================================================== --- pypy/trunk/src/pypy/module/sysmodule.py (original) +++ pypy/trunk/src/pypy/module/sysmodule.py Mon Dec 15 18:21:12 2003 @@ -17,7 +17,7 @@ opd = os.path.dirname pypydir = opd(opd(os.path.abspath(pypy.__file__))) appdir = os.path.join(pypydir, 'pypy', 'appspace') - self.w_path = space.newlist([appdir] + [p for p in cpy_sys.path if p!= pypydir]) + self.w_path = space.newlist([space.wrap(appdir)] + [space.wrap(p) for p in cpy_sys.path if p!= pypydir]) self.w_modules = space.newdict([]) self.w_builtin_module_names = space.newlist([]) self.w_warnoptions = space.newlist([space.wrap(i) for i in cpy_sys.warnoptions]) From jacob at codespeak.net Mon Dec 15 18:29:31 2003 From: jacob at codespeak.net (jacob at codespeak.net) Date: Mon, 15 Dec 2003 18:29:31 +0100 (MET) Subject: [pypy-svn] rev 2343 - pypy/trunk/src/pypy/module Message-ID: <20031215172931.B90705BFC3@thoth.codespeak.net> Author: jacob Date: Mon Dec 15 18:29:31 2003 New Revision: 2343 Modified: pypy/trunk/src/pypy/module/builtin.py Log: Fixed wrapping bug. Modified: pypy/trunk/src/pypy/module/builtin.py ============================================================================== --- pypy/trunk/src/pypy/module/builtin.py (original) +++ pypy/trunk/src/pypy/module/builtin.py Mon Dec 15 18:29:31 2003 @@ -64,7 +64,7 @@ import os for path in space.unpackiterable(space.sys.w_path): - f = os.path.join(path, space.unwrap(w_modulename) + '.py') + f = os.path.join(space.unwrap(path), space.unwrap(w_modulename) + '.py') if os.path.exists(f): w_mod = space.wrap(Module(space, w_modulename)) space.setitem(space.sys.w_modules, w_modulename, w_mod) From jacob at codespeak.net Mon Dec 15 18:36:44 2003 From: jacob at codespeak.net (jacob at codespeak.net) Date: Mon, 15 Dec 2003 18:36:44 +0100 (MET) Subject: [pypy-svn] rev 2344 - pypy/trunk/src/pypy/appspace Message-ID: <20031215173644.22BC45BFC3@thoth.codespeak.net> Author: jacob Date: Mon Dec 15 18:36:43 2003 New Revision: 2344 Added: pypy/trunk/src/pypy/appspace/pprint.py Log: Added pprint module to allow __repr__ of dictionaries and others. Added: pypy/trunk/src/pypy/appspace/pprint.py ============================================================================== --- (empty file) +++ pypy/trunk/src/pypy/appspace/pprint.py Mon Dec 15 18:36:43 2003 @@ -0,0 +1,310 @@ +# Copied from CPython 2.3 + +# Author: Fred L. Drake, Jr. +# fdrake at acm.org +# +# This is a simple little module I wrote to make life easier. I didn't +# see anything quite like it in the library, though I may have overlooked +# something. I wrote this when I was trying to read some heavily nested +# tuples with fairly non-descriptive content. This is modeled very much +# after Lisp/Scheme - style pretty-printing of lists. If you find it +# useful, thank small children who sleep at night. + +"""Support to pretty-print lists, tuples, & dictionaries recursively. + +Very simple, but useful, especially in debugging data structures. + +Classes +------- + +PrettyPrinter() + Handle pretty-printing operations onto a stream using a configured + set of formatting parameters. + +Functions +--------- + +pformat() + Format a Python object into a pretty-printed representation. + +pprint() + Pretty-print a Python object to a stream [default is sys.sydout]. + +saferepr() + Generate a 'standard' repr()-like value, but protect against recursive + data structures. + +""" + +import sys as _sys + +from cStringIO import StringIO as _StringIO + +__all__ = ["pprint","pformat","isreadable","isrecursive","saferepr", + "PrettyPrinter"] + +# cache these for faster access: +_commajoin = ", ".join +_id = id +_len = len +_type = type + +def pprint(object, stream=None): + """Pretty-print a Python object to a stream [default is sys.sydout].""" + printer = PrettyPrinter(stream=stream) + printer.pprint(object) + +def pformat(object): + """Format a Python object into a pretty-printed representation.""" + return PrettyPrinter().pformat(object) + +def saferepr(object): + """Version of repr() which can handle recursive data structures.""" + return _safe_repr(object, {}, None, 0)[0] + +def isreadable(object): + """Determine if saferepr(object) is readable by eval().""" + return _safe_repr(object, {}, None, 0)[1] + +def isrecursive(object): + """Determine if object requires a recursive representation.""" + return _safe_repr(object, {}, None, 0)[2] + +class PrettyPrinter: + def __init__(self, indent=1, width=80, depth=None, stream=None): + """Handle pretty printing operations onto a stream using a set of + configured parameters. + + indent + Number of spaces to indent for each level of nesting. + + width + Attempted maximum number of columns in the output. + + depth + The maximum depth to print out nested structures. + + stream + The desired output stream. If omitted (or false), the standard + output stream available at construction will be used. + + """ + indent = int(indent) + width = int(width) + assert indent >= 0 + assert depth is None or depth > 0, "depth must be > 0" + assert width + self._depth = depth + self._indent_per_level = indent + self._width = width + if stream is not None: + self._stream = stream + else: + self._stream = _sys.stdout + + def pprint(self, object): + self._stream.write(self.pformat(object) + "\n") + + def pformat(self, object): + sio = _StringIO() + self._format(object, sio, 0, 0, {}, 0) + return sio.getvalue() + + def isrecursive(self, object): + return self.format(object, {}, 0, 0)[2] + + def isreadable(self, object): + s, readable, recursive = self.format(object, {}, 0, 0) + return readable and not recursive + + def _format(self, object, stream, indent, allowance, context, level): + level = level + 1 + objid = _id(object) + if objid in context: + stream.write(_recursion(object)) + self._recursive = True + self._readable = False + return + rep = self._repr(object, context, level - 1) + typ = _type(object) + sepLines = _len(rep) > (self._width - 1 - indent - allowance) + write = stream.write + + if sepLines: + if typ is dict: + write('{') + if self._indent_per_level > 1: + write((self._indent_per_level - 1) * ' ') + length = _len(object) + if length: + context[objid] = 1 + indent = indent + self._indent_per_level + items = object.items() + items.sort() + key, ent = items[0] + rep = self._repr(key, context, level) + write(rep) + write(': ') + self._format(ent, stream, indent + _len(rep) + 2, + allowance + 1, context, level) + if length > 1: + for key, ent in items[1:]: + rep = self._repr(key, context, level) + write(',\n%s%s: ' % (' '*indent, rep)) + self._format(ent, stream, indent + _len(rep) + 2, + allowance + 1, context, level) + indent = indent - self._indent_per_level + del context[objid] + write('}') + return + + if typ is list or typ is tuple: + if typ is list: + write('[') + endchar = ']' + else: + write('(') + endchar = ')' + if self._indent_per_level > 1: + write((self._indent_per_level - 1) * ' ') + length = _len(object) + if length: + context[objid] = 1 + indent = indent + self._indent_per_level + self._format(object[0], stream, indent, allowance + 1, + context, level) + if length > 1: + for ent in object[1:]: + write(',\n' + ' '*indent) + self._format(ent, stream, indent, + allowance + 1, context, level) + indent = indent - self._indent_per_level + del context[objid] + if typ is tuple and length == 1: + write(',') + write(endchar) + return + + write(rep) + + def _repr(self, object, context, level): + repr, readable, recursive = self.format(object, context.copy(), + self._depth, level) + if not readable: + self._readable = False + if recursive: + self._recursive = True + return repr + + def format(self, object, context, maxlevels, level): + """Format object for a specific context, returning a string + and flags indicating whether the representation is 'readable' + and whether the object represents a recursive construct. + """ + return _safe_repr(object, context, maxlevels, level) + + +# Return triple (repr_string, isreadable, isrecursive). + +def _safe_repr(object, context, maxlevels, level): + typ = _type(object) + if typ is str: + if 'locale' not in _sys.modules: + return `object`, True, False + if "'" in object and '"' not in object: + closure = '"' + quotes = {'"': '\\"'} + else: + closure = "'" + quotes = {"'": "\\'"} + qget = quotes.get + sio = _StringIO() + write = sio.write + for char in object: + if char.isalpha(): + write(char) + else: + write(qget(char, `char`[1:-1])) + return ("%s%s%s" % (closure, sio.getvalue(), closure)), True, False + + if typ is dict: + if not object: + return "{}", True, False + objid = _id(object) + if maxlevels and level > maxlevels: + return "{...}", False, objid in context + if objid in context: + return _recursion(object), False, True + context[objid] = 1 + readable = True + recursive = False + components = [] + append = components.append + level += 1 + saferepr = _safe_repr + for k, v in object.iteritems(): + krepr, kreadable, krecur = saferepr(k, context, maxlevels, level) + vrepr, vreadable, vrecur = saferepr(v, context, maxlevels, level) + append("%s: %s" % (krepr, vrepr)) + readable = readable and kreadable and vreadable + if krecur or vrecur: + recursive = True + del context[objid] + return "{%s}" % _commajoin(components), readable, recursive + + if typ is list or typ is tuple: + if typ is list: + if not object: + return "[]", True, False + format = "[%s]" + elif _len(object) == 1: + format = "(%s,)" + else: + if not object: + return "()", True, False + format = "(%s)" + objid = _id(object) + if maxlevels and level > maxlevels: + return format % "...", False, objid in context + if objid in context: + return _recursion(object), False, True + context[objid] = 1 + readable = True + recursive = False + components = [] + append = components.append + level += 1 + for o in object: + orepr, oreadable, orecur = _safe_repr(o, context, maxlevels, level) + append(orepr) + if not oreadable: + readable = False + if orecur: + recursive = True + del context[objid] + return format % _commajoin(components), readable, recursive + + rep = `object` + return rep, (rep and not rep.startswith('<')), False + + +def _recursion(object): + return ("" + % (_type(object).__name__, _id(object))) + + +def _perfcheck(object=None): + import time + if object is None: + object = [("string", (1, 2), [3, 4], {5: 6, 7: 8})] * 100000 + p = PrettyPrinter() + t1 = time.time() + _safe_repr(object, {}, None, 0) + t2 = time.time() + p.pformat(object) + t3 = time.time() + print "_safe_repr:", t2 - t1 + print "pformat:", t3 - t2 + +if __name__ == "__main__": + _perfcheck() From pmaupin at codespeak.net Mon Dec 15 18:44:27 2003 From: pmaupin at codespeak.net (pmaupin at codespeak.net) Date: Mon, 15 Dec 2003 18:44:27 +0100 (MET) Subject: [pypy-svn] rev 2345 - pypy/trunk/src/pypy/tool Message-ID: <20031215174427.2227B5BFB1@thoth.codespeak.net> Author: pmaupin Date: Mon Dec 15 18:44:26 2003 New Revision: 2345 Added: pypy/trunk/src/pypy/tool/modanalyze.py Log: Analyze differences between C and PyPy modules Added: pypy/trunk/src/pypy/tool/modanalyze.py ============================================================================== --- (empty file) +++ pypy/trunk/src/pypy/tool/modanalyze.py Mon Dec 15 18:44:26 2003 @@ -0,0 +1,41 @@ + +from pypy.interpreter.gateway import app2interp +from sets import Set + +def showdiff(name,stuff): + if stuff: + print + print name + for i in stuff: print " ",i + print + +def app_getmodattributes(modname): + moduleundertest = __import__(modname,globals(),None,[]) + return moduleundertest.__dict__.keys() + +def module_delta(space,modname): + wrapped_func = app2interp(app_getmodattributes).get_function(space) + + pypy_b = wrapped_func(space.wrap(modname)) + pypy_b = space.unpackiterable(pypy_b) + pypy_b = [space.unwrap(x) for x in pypy_b] + pypy_b = Set(pypy_b) + + import __builtin__ as c_b + c_b = Set(c_b.__dict__.keys()) | Set(['__dict__','__new__']) + diff = c_b ^ pypy_b + missing = diff & c_b + extra = diff & pypy_b + return missing,extra + +if __name__ == '__main__': + from pypy.objspace.std import StdObjSpace + print "Initializing std object space" + std = StdObjSpace() + + for modname in ['__builtin__']: + print + print 'Comparing %s module' % modname + missing,extra = module_delta(std,modname) + showdiff(" Missing from PyPy",missing) + showdiff(" Extra in PyPy",extra) From pmaupin at codespeak.net Tue Dec 16 10:41:28 2003 From: pmaupin at codespeak.net (pmaupin at codespeak.net) Date: Tue, 16 Dec 2003 10:41:28 +0100 (MET) Subject: [pypy-svn] rev 2346 - pypy/trunk/src/pypy/tool Message-ID: <20031216094128.39C1B5BFB1@thoth.codespeak.net> Author: pmaupin Date: Tue Dec 16 10:41:27 2003 New Revision: 2346 Modified: pypy/trunk/src/pypy/tool/modanalyze.py Log: Added documentation; made work with additional modules Modified: pypy/trunk/src/pypy/tool/modanalyze.py ============================================================================== --- pypy/trunk/src/pypy/tool/modanalyze.py (original) +++ pypy/trunk/src/pypy/tool/modanalyze.py Tue Dec 16 10:41:27 2003 @@ -1,41 +1,82 @@ +""" + This module analyzes the delta between the attributes of a module + as seen by the PyPy interpreter, and the same module as seen by the + CPython interpreter. It can be used to help insure that pure-python + functionality as provided by PyPy matches the original functionality + provided by CPython. + + This module may be used as a standalone script, with modules to be + analyzed listed on the command line (default if none given is to + analyze __builtin__) or the moduledelta() function may be called + from other modules. When used standalone, it always analyzes + using the standard object space. + + The current implementation does not examine function signatures -- + it only shows the attributes which are exclusively in one module + or the other. + + The current implementation also may not work for non-builtin extension + modules, depending on whether there is a different path variable + inside PyPy, or whether the presence of the PyPy pure python module + will shadow the original C module, making it unavailable for comparison. +""" +import autopath from pypy.interpreter.gateway import app2interp from sets import Set -def showdiff(name,stuff): - if stuff: - print - print name - for i in stuff: print " ",i - print - def app_getmodattributes(modname): - moduleundertest = __import__(modname,globals(),None,[]) - return moduleundertest.__dict__.keys() + """ Return the attributes of the named module """ + pypy_module = __import__(modname,globals(),None,[]) + return pypy_module.__dict__.keys() + +def moduledelta(space,modname): + """ + moduledelta(space,modname) imports the module from inside + the given space, and also from CPython, and returns a tuple + (missing,extra) which describes attributes in CPython but + not in PyPy, and the opposite. + """ -def module_delta(space,modname): wrapped_func = app2interp(app_getmodattributes).get_function(space) - pypy_b = wrapped_func(space.wrap(modname)) - pypy_b = space.unpackiterable(pypy_b) - pypy_b = [space.unwrap(x) for x in pypy_b] - pypy_b = Set(pypy_b) - - import __builtin__ as c_b - c_b = Set(c_b.__dict__.keys()) | Set(['__dict__','__new__']) - diff = c_b ^ pypy_b - missing = diff & c_b - extra = diff & pypy_b + pypy_module = wrapped_func(space.wrap(modname)) + pypy_module = space.unpackiterable(pypy_module) + pypy_module = [space.unwrap(x) for x in pypy_module] + pypy_module = Set(pypy_module) + + c_module = __import__(modname,globals(),None,[]) + c_module = Set(c_module.__dict__.keys()) | Set(['__dict__','__new__']) + diff = c_module ^ pypy_module + missing = diff & c_module + extra = diff & pypy_module return missing,extra if __name__ == '__main__': + from sys import argv from pypy.objspace.std import StdObjSpace + + def showdiff(name,stuff): + if stuff: + print + print name + for i in stuff: print " ",i + print + + modlist = argv[1:] + if not modlist: + print "modanalyze [ ...]" + print + print "Analyzing __builtin__ by default" + print + modlist = ['__builtin__'] + print "Initializing std object space" std = StdObjSpace() - for modname in ['__builtin__']: + for modname in modlist: print print 'Comparing %s module' % modname - missing,extra = module_delta(std,modname) + missing,extra = moduledelta(std,modname) showdiff(" Missing from PyPy",missing) showdiff(" Extra in PyPy",extra) From sschwarzer at codespeak.net Tue Dec 16 10:44:01 2003 From: sschwarzer at codespeak.net (sschwarzer at codespeak.net) Date: Tue, 16 Dec 2003 10:44:01 +0100 (MET) Subject: [pypy-svn] rev 2347 - pypy/trunk/src/pypy/appspace Message-ID: <20031216094401.540E95BFB1@thoth.codespeak.net> Author: sschwarzer Date: Tue Dec 16 10:44:00 2003 New Revision: 2347 Modified: pypy/trunk/src/pypy/appspace/_types.py Log: Fixed syntax error in 'for' loop. Modified: pypy/trunk/src/pypy/appspace/_types.py ============================================================================== --- pypy/trunk/src/pypy/appspace/_types.py (original) +++ pypy/trunk/src/pypy/appspace/_types.py Tue Dec 16 10:44:00 2003 @@ -2,6 +2,7 @@ Definition of the standard Python types. """ +# XXX we can't do this import yet from sys import pypy import __builtin__ import _types @@ -16,15 +17,16 @@ 'TracebackType', 'TupleType', 'TypeType', 'UnboundMethodType', 'UnicodeType', 'XRangeType'] + def _register(factory, cls, in_builtin=True, synonym=True): """ - Register factory as type cls. - + 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 @@ -182,8 +184,8 @@ # 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(): +for attribute in ('update popitem get setdefault pop' + 'iteritems iterkeys itervalues').split(): setattr(dict, attribute, UserDict.DictMixin.__dict__[attribute]) _register(pypy.DictObjectFactory, dict) @@ -547,5 +549,3 @@ _register(pypy.XrangeObjectFactory, xrange, synonym='XRangeType') - - From alex at codespeak.net Tue Dec 16 11:04:42 2003 From: alex at codespeak.net (alex at codespeak.net) Date: Tue, 16 Dec 2003 11:04:42 +0100 (MET) Subject: [pypy-svn] rev 2348 - pypy/trunk/src/pypy/objspace/std/test Message-ID: <20031216100442.4C3A15BFB1@thoth.codespeak.net> Author: alex Date: Tue Dec 16 11:04:41 2003 New Revision: 2348 Modified: pypy/trunk/src/pypy/objspace/std/test/test_boolobject.py Log: Added application-level test case Modified: pypy/trunk/src/pypy/objspace/std/test/test_boolobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/test/test_boolobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/test/test_boolobject.py Tue Dec 16 11:04:41 2003 @@ -23,6 +23,18 @@ def test_false(self): self.failIf_w(self.false) +class AppBoolTest(test.AppTestCase): + def setUp(self): + self.space = test.objspace('std') + + def test_bool_callable(self): + self.assertEquals(True, bool(1)) + self.assertEquals(False, bool(0)) + self.assertEquals(False, bool()) + + def test_bool_string(self): + self.assertEquals("True", str(True)) + self.assertEquals("False", str(False)) if __name__ == '__main__': test.main() From jacob at codespeak.net Tue Dec 16 11:19:24 2003 From: jacob at codespeak.net (jacob at codespeak.net) Date: Tue, 16 Dec 2003 11:19:24 +0100 (MET) Subject: [pypy-svn] rev 2350 - pypy/trunk/src/pypy/objspace/std Message-ID: <20031216101924.9D8AA5BFB1@thoth.codespeak.net> Author: jacob Date: Tue Dec 16 11:19:23 2003 New Revision: 2350 Modified: pypy/trunk/src/pypy/objspace/std/booltype.py Log: Fixed __new__. Modified: pypy/trunk/src/pypy/objspace/std/booltype.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/booltype.py (original) +++ pypy/trunk/src/pypy/objspace/std/booltype.py Tue Dec 16 11:19:23 2003 @@ -13,3 +13,22 @@ staticbases = (W_IntType,) registerimplementation(W_BoolType) + +def type_new__BoolType_BoolType(space, w_basetype, w_booltype, w_args, w_kwds): + if space.is_true(w_kwds): + raise OperationError(space.w_TypeError, + space.wrap("no keyword arguments expected")) + args = space.unpackiterable(w_args) + if len(args) == 0: + return space.w_False, True + elif len(args) == 1: + arg = args[0] + if space.is_true(arg): + return space.w_True, True + else: + return space.w_False, True + else: + raise OperationError(space.w_TypeError, + space.wrap("bool() takes at most 1 argument")) + +register_all(vars()) From jacob at codespeak.net Tue Dec 16 11:28:30 2003 From: jacob at codespeak.net (jacob at codespeak.net) Date: Tue, 16 Dec 2003 11:28:30 +0100 (MET) Subject: [pypy-svn] rev 2351 - pypy/trunk/src/pypy/objspace/std Message-ID: <20031216102830.3B52E5BFB1@thoth.codespeak.net> Author: jacob Date: Tue Dec 16 11:28:29 2003 New Revision: 2351 Modified: pypy/trunk/src/pypy/objspace/std/boolobject.py Log: Made str for booleans same as repr. Modified: pypy/trunk/src/pypy/objspace/std/boolobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/boolobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/boolobject.py Tue Dec 16 11:28:29 2003 @@ -43,5 +43,6 @@ else: return space.wrap('False') +str__Bool = repr__Bool register_all(vars()) From jacob at codespeak.net Tue Dec 16 11:32:28 2003 From: jacob at codespeak.net (jacob at codespeak.net) Date: Tue, 16 Dec 2003 11:32:28 +0100 (MET) Subject: [pypy-svn] rev 2352 - pypy/trunk/src/pypy/objspace/std/test Message-ID: <20031216103228.F028D5BFB1@thoth.codespeak.net> Author: jacob Date: Tue Dec 16 11:32:28 2003 New Revision: 2352 Modified: pypy/trunk/src/pypy/objspace/std/test/test_boolobject.py pypy/trunk/src/pypy/objspace/std/test/test_intobject.py Log: Added tests for str and repr. Modified: pypy/trunk/src/pypy/objspace/std/test/test_boolobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/test/test_boolobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/test/test_boolobject.py Tue Dec 16 11:32:28 2003 @@ -35,6 +35,8 @@ def test_bool_string(self): self.assertEquals("True", str(True)) self.assertEquals("False", str(False)) + self.assertEquals("True", repr(True)) + self.assertEquals("False", repr(False)) if __name__ == '__main__': test.main() Modified: pypy/trunk/src/pypy/objspace/std/test/test_intobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/test/test_intobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/test/test_intobject.py Tue Dec 16 11:32:28 2003 @@ -298,6 +298,10 @@ def test_int_float(self): self.assertEquals(4, int(4.2)) + + def test_int_str_repr(self): + self.assertEquals("42", str(42)) + self.assertEquals("42", repr(42)) if __name__ == '__main__': From tomek at codespeak.net Tue Dec 16 11:37:08 2003 From: tomek at codespeak.net (tomek at codespeak.net) Date: Tue, 16 Dec 2003 11:37:08 +0100 (MET) Subject: [pypy-svn] rev 2353 - pypy/trunk/src/pypy/objspace Message-ID: <20031216103708.9E78C5BFB1@thoth.codespeak.net> Author: tomek Date: Tue Dec 16 11:37:08 2003 New Revision: 2353 Modified: pypy/trunk/src/pypy/objspace/trace.py Log: temporary check-in Modified: pypy/trunk/src/pypy/objspace/trace.py ============================================================================== --- pypy/trunk/src/pypy/objspace/trace.py (original) +++ pypy/trunk/src/pypy/objspace/trace.py Tue Dec 16 11:37:08 2003 @@ -3,10 +3,18 @@ import sys, operator, types, new import pypy from pypy.objspace.std import StdObjSpace +from pypy.objspace.trivial import TrivialObjSpace from pypy.interpreter.baseobjspace import ObjSpace +from pypy.interpreter.executioncontext import ExecutionContext from pypy.interpreter.pycode import PyCode debug = 0 +class TraceExecutionContext(ExecutionContext): + + def bytecode_trace(self, frame): + "Trace function called before each bytecode." + print "XXX %s, %s" % frame.examineop() + class Logger(object): def __init__(self, name, fn, printme): self.fn = fn @@ -18,6 +26,9 @@ #print "%s %s(%s, %s)" % (self.printme, , str(args), str(kwds)) return self.fn(*args, **kwds) + def __getattr__(self, name): + return getattr(self.fn, name) + # ______________________________________________________________________ @@ -37,10 +48,15 @@ #print l setattr(self, key, new.instancemethod(l, self, TraceObjSpace)) + def createexecutioncontext(self): + "Factory function for execution contexts." + return TraceExecutionContext(self) + + return TraceObjSpace() Space = Trace -s = Trace() +s = Trace(TrivialObjSpace) #print dir(s) # ______________________________________________________________________ # End of trace.py @@ -58,6 +74,7 @@ if __name__ == "__main__": def a(b): + print b return b+1 print runx(s, a, 1) From alex at codespeak.net Tue Dec 16 12:06:49 2003 From: alex at codespeak.net (alex at codespeak.net) Date: Tue, 16 Dec 2003 12:06:49 +0100 (MET) Subject: [pypy-svn] rev 2354 - pypy/trunk/src/pypy/objspace/std/test Message-ID: <20031216110649.54C505BFB1@thoth.codespeak.net> Author: alex Date: Tue Dec 16 12:06:48 2003 New Revision: 2354 Modified: pypy/trunk/src/pypy/objspace/std/test/test_dictobject.py Log: Added a test for dicts' str representation Modified: pypy/trunk/src/pypy/objspace/std/test/test_dictobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/test/test_dictobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/test/test_dictobject.py Tue Dec 16 12:06:48 2003 @@ -303,6 +303,12 @@ self.assertEqual(bool, True) bool = d1 < d4 self.assertEqual(bool, False) + + def test_str_repr(self): + self.assertEqual('{}', str({})) + self.assertEqual('{1: 2}', str({1: 2})) + self.assertEqual("{'ba': 'bo'}", str({'ba': 'bo'})) + self.assertEqual("{1: 2, 'ba': 'bo'}", str({1: 2, 'ba': 'bo'})) def tooslow_test_new(self): d = dict() From hpk at codespeak.net Tue Dec 16 12:36:05 2003 From: hpk at codespeak.net (hpk at codespeak.net) Date: Tue, 16 Dec 2003 12:36:05 +0100 (MET) Subject: [pypy-svn] rev 2355 - in pypy/trunk/src/pypy/interpreter: . test Message-ID: <20031216113605.A7CC35BFB1@thoth.codespeak.net> Author: hpk Date: Tue Dec 16 12:36:04 2003 New Revision: 2355 Modified: pypy/trunk/src/pypy/interpreter/function.py pypy/trunk/src/pypy/interpreter/gateway.py pypy/trunk/src/pypy/interpreter/test/test_function.py Log: - added function object introspection (minus __class__ because we still have no appropriate type object) - refactored app2interp and interp2app to be subclasses of Gateway in order to avoid passing around millions of arguments (holger, samuele) Modified: pypy/trunk/src/pypy/interpreter/function.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/function.py (original) +++ pypy/trunk/src/pypy/interpreter/function.py Tue Dec 16 12:36:04 2003 @@ -13,17 +13,19 @@ an object space, a dictionary of globals, default arguments, and an arbitrary 'closure' passed to the code object.""" - def __init__(self, space, code, w_globals=None, defs_w=[], closure=None): - self.space = space - self.func_code = code # Code instance + def __init__(self, space, code, w_globals=None, defs_w=[], closure=None, forcename=None): + self.space = space + self.name = forcename or code.co_name + self.doc = getattr(code, 'co_consts', (None,))[0] + self.code = code # Code instance self.w_globals = w_globals # the globals dictionary self.closure = closure # normally, list of Cell instances or None self.defs_w = defs_w # list of w_default's - self.__name__ = self.func_code.co_name # XXX + self.w_dict = space.newdict([]) def call(self, w_args, w_kwds=None): scope_w = self.parse_args(w_args, w_kwds) - frame = self.func_code.create_frame(self.space, self.w_globals, + frame = self.code.create_frame(self.space, self.w_globals, self.closure) frame.setfastscope(scope_w) return frame.run() @@ -33,7 +35,7 @@ """ parse args and kwargs to initialize the frame. """ space = self.space - signature = self.func_code.signature() + signature = self.code.signature() argnames, varargname, kwargname = signature # # w_args = wrapped sequence of the normal actual parameters @@ -94,7 +96,7 @@ # helper functions to build error message for the above def raise_argerr(self, w_args, w_kwds, too_many): - argnames, varargname, kwargname = self.func_code.signature() + argnames, varargname, kwargname = self.code.signature() nargs = self.space.unwrap(self.space.len(w_args)) n = len(argnames) if n == 0: @@ -104,7 +106,7 @@ msg2 = "" nargs += self.space.unwrap(self.space.len(w_kwds)) msg = "%s() takes no %sargument (%d given)" % ( - self.func_code.co_name, + self.name, msg2, nargs) else: @@ -125,7 +127,7 @@ else: plural = "s" msg = "%s() takes %s %d %sargument%s (%d given)" % ( - self.func_code.co_name, + self.name, msg1, n, msg2, @@ -135,7 +137,7 @@ def raise_argerr_multiple_values(self, argname): msg = "%s() got multiple values for keyword argument %s" % ( - self.func_code.co_name, + self.name, argname) raise OperationError(self.space.w_TypeError, self.space.wrap(msg)) @@ -145,11 +147,11 @@ w_iter = self.space.iter(w_kwds) w_key = self.space.next(w_iter) msg = "%s() got an unexpected keyword argument '%s'" % ( - self.func_code.co_name, + self.name, self.space.unwrap(w_key)) else: msg = "%s() got %d unexpected keyword arguments" % ( - self.func_code.co_name, + self.name, nkwds) raise OperationError(self.space.w_TypeError, self.space.wrap(msg)) @@ -180,6 +182,26 @@ # (for FlowObjSpace) return self.space.call(wrap(self), w_args, w_kwds) + def pypy_getattr(self, name): + space = self.space + if name == 'func_defaults': + if not self.defs_w: + return space.w_None + else: + return space.newtuple(self.defs_w) + elif name == 'func_code': + return space.wrap(self.code) + elif name == 'func_dict': + return space.wrap(self.w_dict) + elif name == 'func_doc' or name == '__doc__': + return space.wrap(self.doc) + elif name == 'func_globals': + return self.w_globals + elif name == 'func_closure': + return space.wrap(self.closure) + elif name == 'func_name' or name == '__name__': + return space.wrap(self.name) + raise OperationError(space.w_AttributeError, space.wrap(name)) class Method(object): """A method is a function bound to a specific instance or class.""" Modified: pypy/trunk/src/pypy/interpreter/gateway.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/gateway.py (original) +++ pypy/trunk/src/pypy/interpreter/gateway.py Tue Dec 16 12:36:04 2003 @@ -120,14 +120,14 @@ # explicitely as the first argument (for plain function), or is read # from 'self.space' for methods. - def __init__(self, name, code, staticglobals=None, staticdefs=[], - wrapdefaults=0): - self.name = name - self.code = code - self.staticglobals = staticglobals - self.staticdefs = staticdefs + def __init__(self): self.functioncache = WeakKeyDictionary() # map {space: Function} - self.wrapdefaults = wrapdefaults + + # after initialization the following attributes should be set + # name + # code + # staticglobals + # staticdefs def __wrap__(self, space): # to wrap a Gateway, we first make a real Function object out of it @@ -186,50 +186,52 @@ if space in self.functioncache: fn = self.functioncache[space] else: - defs_w = self.staticdefs - if self.wrapdefaults: - defs_w = [space.wrap(val) for val in defs_w] - fn = Function(space, self.code, w_globals, defs_w) + defs = self.getdefaults(space) # needs to be implemented by subclass + fn = Function(space, self.code, w_globals, defs, forcename = self.name) self.functioncache[space] = fn return fn -def app2interp(app, app_name=None): +class app2interp(Gateway): """Build a Gateway that calls 'app' at app-level.""" - # app must be a function whose name starts with 'app_'. - if not isinstance(app, types.FunctionType): - if isinstance(app, Gateway): - return app - raise TypeError, "function expected, got %r instead" % app - if app_name is None: - if not app.func_name.startswith('app_'): - raise ValueError, ("function name must start with 'app_'; " - "%r does not" % app.func_name) - app_name = app.func_name[4:] - code = pycode.PyCode(None) - code._from_code(app.func_code) - staticglobals = app.func_globals - staticdefs = list(app.func_defaults or ()) - return Gateway(app_name, code, staticglobals, - staticdefs, wrapdefaults=1) + def __init__(self, app, app_name=None): + Gateway.__init__(self) + # app must be a function whose name starts with 'app_'. + if not isinstance(app, types.FunctionType): + raise TypeError, "function expected, got %r instead" % app + if app_name is None: + if not app.func_name.startswith('app_'): + raise ValueError, ("function name must start with 'app_'; " + "%r does not" % app.func_name) + app_name = app.func_name[4:] + self.name = app_name + self.code = pycode.PyCode(None) + self.code._from_code(app.func_code) + self.staticglobals = app.func_globals + self.staticdefs = list(app.func_defaults or ()) + + def getdefaults(self, space): + return [space.wrap(val) for val in self.staticdefs] -def interp2app(f, app_name=None): +class interp2app(Gateway): """Build a Gateway that calls 'f' at interp-level.""" - # f must be a function whose name does NOT starts with 'app_' - if not isinstance(f, types.FunctionType): - if isinstance(f, Gateway): - return f - raise TypeError, "function expected, got %r instead" % f - if app_name is None: - if f.func_name.startswith('app_'): - raise ValueError, ("function name %r suspiciously starts " - "with 'app_'" % f.func_name) - app_name = f.func_name - builtincode = BuiltinCode(f) - staticdefs = list(f.func_defaults or ()) - return Gateway(app_name, builtincode, None, - staticdefs, wrapdefaults=0) + def __init__(self, f, app_name=None): + Gateway.__init__(self) + # f must be a function whose name does NOT starts with 'app_' + if not isinstance(f, types.FunctionType): + raise TypeError, "function expected, got %r instead" % f + if app_name is None: + if f.func_name.startswith('app_'): + raise ValueError, ("function name %r suspiciously starts " + "with 'app_'" % f.func_name) + app_name = f.func_name + self.code = BuiltinCode(f) + self.name = app_name + self.staticdefs = list(f.func_defaults or ()) + self.staticglobals = None + def getdefaults(self, space): + return self.staticdefs def exportall(d): """Publish every function from a dict.""" Modified: pypy/trunk/src/pypy/interpreter/test/test_function.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/test/test_function.py (original) +++ pypy/trunk/src/pypy/interpreter/test/test_function.py Tue Dec 16 12:36:04 2003 @@ -6,6 +6,23 @@ from pypy.interpreter.pycode import PyCode +class AppTestFunctionIntrospection(test.AppTestCase): + def test_attributes(self): + def f(): pass + self.assert_(hasattr(f, 'func_code')) + self.assertEquals(f.func_defaults, None) + self.assertEquals(f.func_dict, {}) + self.assertEquals(type(f.func_globals), dict) + self.assertEquals(f.func_closure, None) + self.assertEquals(f.func_doc, None) + self.assertEquals(f.func_name, 'f') + + def test_underunder_attributes(self): + def f(): pass + self.assertEquals(f.__name__, 'f') + self.assertEquals(f.__doc__, None) + #XXX self.assert_(hasattr(f, '__class__')) + class AppTestFunction(test.AppTestCase): def test_simple_call(self): def func(arg1, arg2): From alex at codespeak.net Tue Dec 16 12:36:38 2003 From: alex at codespeak.net (alex at codespeak.net) Date: Tue, 16 Dec 2003 12:36:38 +0100 (MET) Subject: [pypy-svn] rev 2356 - pypy/trunk/src/pypy/objspace/std/test Message-ID: <20031216113638.2CFC05BFB1@thoth.codespeak.net> Author: alex Date: Tue Dec 16 12:36:37 2003 New Revision: 2356 Modified: pypy/trunk/src/pypy/objspace/std/test/test_dictobject.py Log: added repr tests Modified: pypy/trunk/src/pypy/objspace/std/test/test_dictobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/test/test_dictobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/test/test_dictobject.py Tue Dec 16 12:36:37 2003 @@ -309,6 +309,10 @@ self.assertEqual('{1: 2}', str({1: 2})) self.assertEqual("{'ba': 'bo'}", str({'ba': 'bo'})) self.assertEqual("{1: 2, 'ba': 'bo'}", str({1: 2, 'ba': 'bo'})) + self.assertEqual('{}', repr({})) + self.assertEqual('{1: 2}', repr({1: 2})) + self.assertEqual("{'ba': 'bo'}", repr({'ba': 'bo'})) + self.assertEqual("{1: 2, 'ba': 'bo'}", repr({1: 2, 'ba': 'bo'})) def tooslow_test_new(self): d = dict() From jacob at codespeak.net Tue Dec 16 12:39:12 2003 From: jacob at codespeak.net (jacob at codespeak.net) Date: Tue, 16 Dec 2003 12:39:12 +0100 (MET) Subject: [pypy-svn] rev 2357 - pypy/trunk/src/pypy/objspace/std Message-ID: <20031216113912.D7E2A5BFB1@thoth.codespeak.net> Author: jacob Date: Tue Dec 16 12:39:12 2003 New Revision: 2357 Modified: pypy/trunk/src/pypy/objspace/std/dictobject.py pypy/trunk/src/pypy/objspace/std/dicttype.py Log: Implemented str and repr for dictionaries. This will only work for the current implementation of dict. A better solution would be to dispatch in dicttype. Modified: pypy/trunk/src/pypy/objspace/std/dictobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/dictobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/dictobject.py Tue Dec 16 12:39:12 2003 @@ -6,6 +6,7 @@ """ from pypy.objspace.std.objspace import * +from pypy.interpreter import gateway from dicttype import W_DictType from stringobject import W_StringObject @@ -215,4 +216,16 @@ return cell.get() return w_default +# Now we only handle one implementation of dicts, this one. +# The fix is to move this to dicttype.py, and do a +# multimethod lookup mapping str to StdObjSpace.str +# This cannot happen until multimethods are fixed. See dicttype.py +def app_str__Dict(d): + items = [] + for k, v in d.iteritems(): + items.append("%r: %r" % (k, v)) + return "{%s}" % ', '.join(items) + +repr__Dict = str__Dict = gateway.app2interp(app_str__Dict) register_all(vars(), W_DictType) + Modified: pypy/trunk/src/pypy/objspace/std/dicttype.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/dicttype.py (original) +++ pypy/trunk/src/pypy/objspace/std/dicttype.py Tue Dec 16 12:39:12 2003 @@ -24,6 +24,8 @@ dict_iteritems = MultiMethod('iteritems', 1) dict_iterkeys = MultiMethod('iterkeys', 1) dict_itervalues = MultiMethod('itervalues', 1) + # This can return when multimethods have been fixed + #dict_str = StdObjSpace.str registerimplementation(W_DictType) @@ -78,6 +80,13 @@ def app_dict_itervalues__ANY(d): return iter(d.values()) - +# This can return when multimethods have been fixed +""" +def app_dict_str__ANY(d): + items = [] + for k, v in d.iteritems(): + items.append("%r: %r" % (k, v)) + return "{%s}" % ', '.join(items) +""" gateway.importall(globals()) register_all(vars(), W_DictType) From alex at codespeak.net Tue Dec 16 13:03:21 2003 From: alex at codespeak.net (alex at codespeak.net) Date: Tue, 16 Dec 2003 13:03:21 +0100 (MET) Subject: [pypy-svn] rev 2358 - pypy/trunk/src/pypy/interpreter/test Message-ID: <20031216120321.510245BFB1@thoth.codespeak.net> Author: alex Date: Tue Dec 16 13:03:20 2003 New Revision: 2358 Modified: pypy/trunk/src/pypy/interpreter/test/test_module.py Log: add app level test Modified: pypy/trunk/src/pypy/interpreter/test/test_module.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/test/test_module.py (original) +++ pypy/trunk/src/pypy/interpreter/test/test_module.py Tue Dec 16 13:03:20 2003 @@ -23,6 +23,25 @@ self.assertRaises_w(self.space.w_AttributeError, self.space.delattr, w_m, w('x')) +class Test_ModuleObject(test.AppTestCase): + + def setUp(self): + self.space = test.objspace('std') + + def test_attr(self): + m = __import__('math') + m.x = 15 + self.assertEqual_w(m.x, 15) + self.assertEqual_w(getattr(m, 'x'), 15) + setattr(m, 'x', 23) + self.assertEqual_w(m.x, 23) + self.assertEqual_w(getattr(m, 'x'), 23) + del m.x + self.assertRaises(AttributeError, getattr, m, 'x') + m.x = 15 + delattr(m, 'x') + self.assertRaises(AttributeError, getattr, m, 'x') + self.assertRaises(AttributeError, delattr, m, 'x') if __name__ == '__main__': test.main() From alex at codespeak.net Tue Dec 16 13:05:46 2003 From: alex at codespeak.net (alex at codespeak.net) Date: Tue, 16 Dec 2003 13:05:46 +0100 (MET) Subject: [pypy-svn] rev 2359 - pypy/trunk/src/pypy/interpreter/test Message-ID: <20031216120546.9C4075BFB1@thoth.codespeak.net> Author: alex Date: Tue Dec 16 13:05:45 2003 New Revision: 2359 Modified: pypy/trunk/src/pypy/interpreter/test/test_module.py Log: no _w in applevel test Modified: pypy/trunk/src/pypy/interpreter/test/test_module.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/test/test_module.py (original) +++ pypy/trunk/src/pypy/interpreter/test/test_module.py Tue Dec 16 13:05:45 2003 @@ -31,11 +31,11 @@ def test_attr(self): m = __import__('math') m.x = 15 - self.assertEqual_w(m.x, 15) - self.assertEqual_w(getattr(m, 'x'), 15) + self.assertEqual(m.x, 15) + self.assertEqual(getattr(m, 'x'), 15) setattr(m, 'x', 23) - self.assertEqual_w(m.x, 23) - self.assertEqual_w(getattr(m, 'x'), 23) + self.assertEqual(m.x, 23) + self.assertEqual(getattr(m, 'x'), 23) del m.x self.assertRaises(AttributeError, getattr, m, 'x') m.x = 15 From jacob at codespeak.net Tue Dec 16 13:06:03 2003 From: jacob at codespeak.net (jacob at codespeak.net) Date: Tue, 16 Dec 2003 13:06:03 +0100 (MET) Subject: [pypy-svn] rev 2360 - pypy/trunk/src/pypy/module Message-ID: <20031216120603.5DB775BFB1@thoth.codespeak.net> Author: jacob Date: Tue Dec 16 13:06:02 2003 New Revision: 2360 Modified: pypy/trunk/src/pypy/module/builtin.py Log: Default arguments for __import__ allows variable number of arguments in calls. Modified: pypy/trunk/src/pypy/module/builtin.py ============================================================================== --- pypy/trunk/src/pypy/module/builtin.py (original) +++ pypy/trunk/src/pypy/module/builtin.py Tue Dec 16 13:06:02 2003 @@ -48,7 +48,8 @@ def locals(self): return self._actframe().w_locals - def __import__(self, w_modulename, w_locals, w_globals, w_fromlist): + def __import__(self, w_modulename, w_globals=None, + w_locals=None, w_fromlist=None): space = self.space w = space.wrap try: From alex at codespeak.net Tue Dec 16 13:11:01 2003 From: alex at codespeak.net (alex at codespeak.net) Date: Tue, 16 Dec 2003 13:11:01 +0100 (MET) Subject: [pypy-svn] rev 2361 - pypy/trunk/src/pypy/objspace/std/test Message-ID: <20031216121101.724A05BFB1@thoth.codespeak.net> Author: alex Date: Tue Dec 16 13:11:00 2003 New Revision: 2361 Modified: pypy/trunk/src/pypy/objspace/std/test/test_dictobject.py Log: inserted a comment to draw attention to possible variations of dict representations Modified: pypy/trunk/src/pypy/objspace/std/test/test_dictobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/test/test_dictobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/test/test_dictobject.py Tue Dec 16 13:11:00 2003 @@ -308,11 +308,13 @@ self.assertEqual('{}', str({})) self.assertEqual('{1: 2}', str({1: 2})) self.assertEqual("{'ba': 'bo'}", str({'ba': 'bo'})) - self.assertEqual("{1: 2, 'ba': 'bo'}", str({1: 2, 'ba': 'bo'})) + # NOTE: the string repr depends on hash values of 1 and 'ba'!!! + twoitemsrepr = "{1: 2, 'ba': 'bo'}" + self.assertEqual(twoitemsrepr, str({1: 2, 'ba': 'bo'})) self.assertEqual('{}', repr({})) self.assertEqual('{1: 2}', repr({1: 2})) self.assertEqual("{'ba': 'bo'}", repr({'ba': 'bo'})) - self.assertEqual("{1: 2, 'ba': 'bo'}", repr({1: 2, 'ba': 'bo'})) + self.assertEqual(twoitemsrepr, repr({1: 2, 'ba': 'bo'})) def tooslow_test_new(self): d = dict() From arigo at codespeak.net Tue Dec 16 13:23:09 2003 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 16 Dec 2003 13:23:09 +0100 (MET) Subject: [pypy-svn] rev 2362 - pypy/trunk/src/pypy/module Message-ID: <20031216122309.7BB5F5BFB1@thoth.codespeak.net> Author: arigo Date: Tue Dec 16 13:23:08 2003 New Revision: 2362 Modified: pypy/trunk/src/pypy/module/builtin.py Log: returning w_None instead of None Modified: pypy/trunk/src/pypy/module/builtin.py ============================================================================== --- pypy/trunk/src/pypy/module/builtin.py (original) +++ pypy/trunk/src/pypy/module/builtin.py Tue Dec 16 13:23:08 2003 @@ -253,7 +253,8 @@ return self.space.len(w_obj) def delattr(self, w_object, w_name): - return self.space.delattr(w_object, w_name) + self.space.delattr(w_object, w_name) + return self.space.w_None def getattr(self, w_object, w_name, w_defvalue = _noarg): try: From tomek at codespeak.net Tue Dec 16 13:51:28 2003 From: tomek at codespeak.net (tomek at codespeak.net) Date: Tue, 16 Dec 2003 13:51:28 +0100 (MET) Subject: [pypy-svn] rev 2363 - pypy/trunk/src/pypy/objspace Message-ID: <20031216125128.7CFE55BFB1@thoth.codespeak.net> Author: tomek Date: Tue Dec 16 13:51:27 2003 New Revision: 2363 Modified: pypy/trunk/src/pypy/objspace/trace.py Log: temporary check-in, please ignore Modified: pypy/trunk/src/pypy/objspace/trace.py ============================================================================== --- pypy/trunk/src/pypy/objspace/trace.py (original) +++ pypy/trunk/src/pypy/objspace/trace.py Tue Dec 16 13:51:27 2003 @@ -9,43 +9,63 @@ from pypy.interpreter.pycode import PyCode debug = 0 -class TraceExecutionContext(ExecutionContext): - +class TraceExecutionContext(ExecutionContext): + def bytecode_trace(self, frame): "Trace function called before each bytecode." - print "XXX %s, %s" % frame.examineop() + #print "XXX %s, %s" % frame.examineop() + self.space.notify_on_bytecode(frame) + + + def dump(self): + bytecodes = self.list_of_bytecodes + self.list_of_bytecodes = [] + return bytecodes + + class Logger(object): - def __init__(self, name, fn, printme): + def __init__(self, name, fn, space, printme): self.fn = fn self.name = name + self.space = space self.printme = printme def __call__(self, cls, *args, **kwds): print self.name #print "%s %s(%s, %s)" % (self.printme, , str(args), str(kwds)) + self.space.notify_on_operation(self.name) return self.fn(*args, **kwds) def __getattr__(self, name): return getattr(self.fn, name) + +class InteractiveLogger(Logger): + + def __call__(self, cls, *args, **kwds): + res = Logger.__call__(self, cls, *args, **kwds) + raw_input() + return res # ______________________________________________________________________ -def Trace(spacecls = StdObjSpace): +def Trace(spacecls = StdObjSpace, logger_cls = Logger): class TraceObjSpace(spacecls): full_exceptions = False def initialize(self): + self.log_list = [] + self.current_frame = None spacecls.initialize(self) - + self.current_frame = None + self.log_list = [] method_names = [ii[0] for ii in ObjSpace.MethodTable] for key in method_names: if key in method_names: item = getattr(self, key) - l = Logger(key, item, "class method") - #print l + l = logger_cls(key, item, self, "class method") setattr(self, key, new.instancemethod(l, self, TraceObjSpace)) def createexecutioncontext(self): @@ -53,6 +73,20 @@ return TraceExecutionContext(self) + def notify_on_bytecode(self, frame): + if self.current_frame is None: + self.current_frame = frame + elif self.current_frame is frame: + bytecode, name = frame.examineop() + self.log_list.append((name, [])) + + + def notify_on_operation(self, name): + self.log_list[-1][1].append(name) + + def dump(self): + return self.log_list + return TraceObjSpace() Space = Trace @@ -78,3 +112,6 @@ return b+1 print runx(s, a, 1) + + print ">>>>>>" + print s.dump() From pmaupin at codespeak.net Tue Dec 16 14:25:42 2003 From: pmaupin at codespeak.net (pmaupin at codespeak.net) Date: Tue, 16 Dec 2003 14:25:42 +0100 (MET) Subject: [pypy-svn] rev 2364 - pypy/trunk/src/pypy/tool Message-ID: <20031216132542.763125BFB1@thoth.codespeak.net> Author: pmaupin Date: Tue Dec 16 14:25:41 2003 New Revision: 2364 Modified: pypy/trunk/src/pypy/tool/modanalyze.py Log: Sorted attribute lists Modified: pypy/trunk/src/pypy/tool/modanalyze.py ============================================================================== --- pypy/trunk/src/pypy/tool/modanalyze.py (original) +++ pypy/trunk/src/pypy/tool/modanalyze.py Tue Dec 16 14:25:41 2003 @@ -48,8 +48,10 @@ c_module = __import__(modname,globals(),None,[]) c_module = Set(c_module.__dict__.keys()) | Set(['__dict__','__new__']) diff = c_module ^ pypy_module - missing = diff & c_module - extra = diff & pypy_module + missing = list(diff & c_module) + extra = list(diff & pypy_module) + missing.sort() + extra.sort() return missing,extra if __name__ == '__main__': From pmaupin at codespeak.net Tue Dec 16 14:32:23 2003 From: pmaupin at codespeak.net (pmaupin at codespeak.net) Date: Tue, 16 Dec 2003 14:32:23 +0100 (MET) Subject: [pypy-svn] rev 2365 - in pypy/trunk/src/pypy/module: . test Message-ID: <20031216133223.CCDA25BFB1@thoth.codespeak.net> Author: pmaupin Date: Tue Dec 16 14:32:23 2003 New Revision: 2365 Modified: pypy/trunk/src/pypy/module/builtin.py pypy/trunk/src/pypy/module/test/test_builtin.py Log: Added iter() two-parameter functionality Modified: pypy/trunk/src/pypy/module/builtin.py ============================================================================== --- pypy/trunk/src/pypy/module/builtin.py (original) +++ pypy/trunk/src/pypy/module/builtin.py Tue Dec 16 14:32:23 2003 @@ -3,6 +3,7 @@ from pypy.interpreter.module import Module from pypy.interpreter.extmodule import ExtModule from pypy.interpreter.error import OperationError +from pypy.interpreter.gateway import app2interp import os.path import sys @@ -20,6 +21,15 @@ passed. """ +def app_iter_generator(callable_,sentinel): + while 1: + result = callable_() + if result == sentinel: + raise StopIteration + yield result + +iter_generator = app2interp(app_iter_generator) + class __builtin__(ExtModule): """ Template for PyPy's '__builtin__' module. """ @@ -283,9 +293,14 @@ def issubclass(self, w_cls1, w_cls2): return self.space.issubtype(w_cls1, w_cls2) - #XXX missing: second form of iter (callable, sentintel) - def iter(self, w_collection): - return self.space.iter(w_collection) + def iter(self, w_collection_or_callable, w_sentinel = _noarg): + if w_sentinel is _noarg: + return self.space.iter(w_collection_or_callable) + else: + if not self.space.is_true(self.callable(w_collection_or_callable)): + raise OperationError(self.space.w_TypeError, + self.space.wrap('iter(v, w): v must be callable')) + return iter_generator(self.space, w_collection_or_callable, w_sentinel) def ord(self, w_val): return self.space.ord(w_val) Modified: pypy/trunk/src/pypy/module/test/test_builtin.py ============================================================================== --- pypy/trunk/src/pypy/module/test/test_builtin.py (original) +++ pypy/trunk/src/pypy/module/test/test_builtin.py Tue Dec 16 14:32:23 2003 @@ -27,6 +27,20 @@ def test_type_selftest(self): self.assert_(type(type) is type) + def test_iter(self): + class count(object): + def __init__(self): + self.value = 0 + def __call__(self): + self.value += 1 + return self.value + self.assertRaises(TypeError,iter,3) + self.assertRaises(TypeError,iter,3,5) + x = iter(count(),3) + self.assertEquals(x.next(),1) + self.assertEquals(x.next(),2) + self.assertRaises(StopIteration,x.next) + def test_xrange_args(self): x = xrange(2) self.assertEquals(x.start, 0) From pmaupin at codespeak.net Tue Dec 16 14:32:59 2003 From: pmaupin at codespeak.net (pmaupin at codespeak.net) Date: Tue, 16 Dec 2003 14:32:59 +0100 (MET) Subject: [pypy-svn] rev 2366 - in pypy/trunk/src/pypy: interpreter objspace/std Message-ID: <20031216133259.7014E5BFB1@thoth.codespeak.net> Author: pmaupin Date: Tue Dec 16 14:32:58 2003 New Revision: 2366 Modified: pypy/trunk/src/pypy/interpreter/baseobjspace.py pypy/trunk/src/pypy/objspace/std/userobject.py Log: Fixed __call__functionality for user objects -- still broken for internals Modified: pypy/trunk/src/pypy/interpreter/baseobjspace.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/baseobjspace.py (original) +++ pypy/trunk/src/pypy/interpreter/baseobjspace.py Tue Dec 16 14:32:58 2003 @@ -247,8 +247,8 @@ ('gt', '>', 2, ['__gt__', '__lt__']), ('ge', '>=', 2, ['__ge__', '__le__']), ('contains', 'contains', 2, ['__contains__']), - ('iter', 'iter', 1, ['__iter__']), - ('call', 'call', 3, ['__call__']), + ('iter', 'iter', 1, []), + ('call', 'call', 3, []), ('get', 'get', 3, ['__get__']), ('set', 'set', 3, ['__set__']), ('delete', 'delete', 2, ['__delete__']), Modified: pypy/trunk/src/pypy/objspace/std/userobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/userobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/userobject.py Tue Dec 16 14:32:58 2003 @@ -187,6 +187,7 @@ next__User = SpecialMethod('next').next_call is_true__User = SpecialMethod('nonzero').nonzero_call object_init__User = SpecialMethod('__init__').argskwds_call +call__User_ANY_ANY = SpecialMethod('__call__').argskwds_call iter__User = SpecialMethod('__iter__').iter_call register_all(vars()) From hpk at codespeak.net Tue Dec 16 14:40:40 2003 From: hpk at codespeak.net (hpk at codespeak.net) Date: Tue, 16 Dec 2003 14:40:40 +0100 (MET) Subject: [pypy-svn] rev 2367 - pypy/trunk/src/pypy/interpreter Message-ID: <20031216134040.668CA5BFB1@thoth.codespeak.net> Author: hpk Date: Tue Dec 16 14:40:39 2003 New Revision: 2367 Modified: pypy/trunk/src/pypy/interpreter/function.py Log: some more preparations for better introspection support of core execution objects ... Modified: pypy/trunk/src/pypy/interpreter/function.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/function.py (original) +++ pypy/trunk/src/pypy/interpreter/function.py Tue Dec 16 14:40:39 2003 @@ -7,8 +7,9 @@ """ from error import OperationError +from baseobjspace import Wrappable -class Function(object): +class Function(Wrappable): """A function is a code object captured with some environment: an object space, a dictionary of globals, default arguments, and an arbitrary 'closure' passed to the code object.""" @@ -18,14 +19,14 @@ self.name = forcename or code.co_name self.doc = getattr(code, 'co_consts', (None,))[0] self.code = code # Code instance - self.w_globals = w_globals # the globals dictionary + self.w_func_globals = w_globals # the globals dictionary self.closure = closure # normally, list of Cell instances or None self.defs_w = defs_w # list of w_default's - self.w_dict = space.newdict([]) + self.w_func_dict = space.newdict([]) def call(self, w_args, w_kwds=None): scope_w = self.parse_args(w_args, w_kwds) - frame = self.code.create_frame(self.space, self.w_globals, + frame = self.code.create_frame(self.space, self.w_func_globals, self.closure) frame.setfastscope(scope_w) return frame.run() @@ -182,26 +183,23 @@ # (for FlowObjSpace) return self.space.call(wrap(self), w_args, w_kwds) - def pypy_getattr(self, name): + def pypy_getattr(self, w_name): space = self.space - if name == 'func_defaults': - if not self.defs_w: - return space.w_None - else: - return space.newtuple(self.defs_w) - elif name == 'func_code': - return space.wrap(self.code) - elif name == 'func_dict': - return space.wrap(self.w_dict) - elif name == 'func_doc' or name == '__doc__': - return space.wrap(self.doc) - elif name == 'func_globals': - return self.w_globals - elif name == 'func_closure': - return space.wrap(self.closure) - elif name == 'func_name' or name == '__name__': - return space.wrap(self.name) - raise OperationError(space.w_AttributeError, space.wrap(name)) + raise OperationError(space.w_AttributeError, w_name) + + def app_visible(self): + space = self.space + def f(*kw): + return kw.items() + return f( + func_defaults = self.defs_w and space.newtuple(self.defs_w) or space.w_None, + func_code = space.wrap(self.code), + func_dict = self.w_func_dict, + func_doc = space.wrap(self.doc), + __doc__ = space.wrap(self.doc), + func_name = space.wrap(self.name), + __name__ = space.wrap(self.name), + func_globals = self.w_func_globals) class Method(object): """A method is a function bound to a specific instance or class.""" From pedronis at codespeak.net Tue Dec 16 14:57:39 2003 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Tue, 16 Dec 2003 14:57:39 +0100 (MET) Subject: [pypy-svn] rev 2368 - pypy/trunk/src/pypy/interpreter Message-ID: <20031216135739.7F6005BFB1@thoth.codespeak.net> Author: pedronis Date: Tue Dec 16 14:57:38 2003 New Revision: 2368 Modified: pypy/trunk/src/pypy/interpreter/gateway.py Log: function.w_globals -> function.w_func_globals --This line and those below, will be ignored-- M gateway.py Modified: pypy/trunk/src/pypy/interpreter/gateway.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/gateway.py (original) +++ pypy/trunk/src/pypy/interpreter/gateway.py Tue Dec 16 14:57:38 2003 @@ -175,7 +175,7 @@ if space in value.functioncache: # yes, we share its w_globals fn = value.functioncache[space] - w_globals = fn.w_globals + w_globals = fn.w_func_globals break else: # no, we build all Gateways in the staticglobals now. From pedronis at codespeak.net Tue Dec 16 15:14:32 2003 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Tue, 16 Dec 2003 15:14:32 +0100 (MET) Subject: [pypy-svn] rev 2369 - pypy/trunk/src/pypy/interpreter Message-ID: <20031216141432.BA2C45A088@thoth.codespeak.net> Author: pedronis Date: Tue Dec 16 15:14:31 2003 New Revision: 2369 Modified: pypy/trunk/src/pypy/interpreter/baseobjspace.py pypy/trunk/src/pypy/interpreter/function.py Log: - refactored function pypy_getattr, implemented genericly in Wrappable using a dict (w_dict) mapping names to the attribute values Modified: pypy/trunk/src/pypy/interpreter/baseobjspace.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/baseobjspace.py (original) +++ pypy/trunk/src/pypy/interpreter/baseobjspace.py Tue Dec 16 15:14:31 2003 @@ -9,6 +9,29 @@ class Wrappable(object): """A subclass of Wrappable is an internal, interpreter-level class that can nevertheless be exposed at application-level by space.wrap().""" + w_dict = None + + def get_wdict(self): + space = self.space + if self.w_dict is None: + w_dict = self.w_dict = space.newdict([]) + for name,w_value in self.app_visible(): + space.setitem(w_dict,space.wrap(name),w_value) + return self.w_dict + + def app_visible(self): + """ returns [(name,w_value)...] for application-level visible attributes """ + raise NotImplementedError + + def pypy_getattr(self,w_name): + space = self.space + w_dict = self.get_wdict() + try: + return space.getitem(w_dict,w_name) + except OperationError,e: + if not e.match(space,space.w_KeyError): + raise + raise OperationError(space.w_AttributeError,w_name) class NoValue(Exception): Modified: pypy/trunk/src/pypy/interpreter/function.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/function.py (original) +++ pypy/trunk/src/pypy/interpreter/function.py Tue Dec 16 15:14:31 2003 @@ -183,15 +183,15 @@ # (for FlowObjSpace) return self.space.call(wrap(self), w_args, w_kwds) - def pypy_getattr(self, w_name): - space = self.space - raise OperationError(space.w_AttributeError, w_name) + #def pypy_getattr(self, w_name): + # space = self.space + # raise OperationError(space.w_AttributeError, w_name) def app_visible(self): space = self.space - def f(*kw): + def items(**kw): return kw.items() - return f( + return items( func_defaults = self.defs_w and space.newtuple(self.defs_w) or space.w_None, func_code = space.wrap(self.code), func_dict = self.w_func_dict, @@ -199,7 +199,8 @@ __doc__ = space.wrap(self.doc), func_name = space.wrap(self.name), __name__ = space.wrap(self.name), - func_globals = self.w_func_globals) + func_globals = self.w_func_globals, + func_closure = space.wrap(self.closure)) class Method(object): """A method is a function bound to a specific instance or class.""" From hpk at codespeak.net Tue Dec 16 15:19:36 2003 From: hpk at codespeak.net (hpk at codespeak.net) Date: Tue, 16 Dec 2003 15:19:36 +0100 (MET) Subject: [pypy-svn] rev 2370 - in pypy/trunk/src/pypy/interpreter: . test Message-ID: <20031216141936.9070D5A088@thoth.codespeak.net> Author: hpk Date: Tue Dec 16 15:19:35 2003 New Revision: 2370 Modified: pypy/trunk/src/pypy/interpreter/function.py pypy/trunk/src/pypy/interpreter/test/test_function.py Log: added __dict__ to functions and cleaner initialization with respect to object identities of e.g. __dict__ and func_dict ... Modified: pypy/trunk/src/pypy/interpreter/function.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/function.py (original) +++ pypy/trunk/src/pypy/interpreter/function.py Tue Dec 16 15:19:35 2003 @@ -189,18 +189,20 @@ def app_visible(self): space = self.space - def items(**kw): - return kw.items() - return items( + def makedict(**kw): + return kw + it = makedict( func_defaults = self.defs_w and space.newtuple(self.defs_w) or space.w_None, func_code = space.wrap(self.code), func_dict = self.w_func_dict, func_doc = space.wrap(self.doc), - __doc__ = space.wrap(self.doc), func_name = space.wrap(self.name), - __name__ = space.wrap(self.name), func_globals = self.w_func_globals, func_closure = space.wrap(self.closure)) + it['__name__'] = it['func_name'] + it['__doc__'] = it['func_doc'] + it['__dict__'] = it['func_dict'] + return it.items() class Method(object): """A method is a function bound to a specific instance or class.""" Modified: pypy/trunk/src/pypy/interpreter/test/test_function.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/test/test_function.py (original) +++ pypy/trunk/src/pypy/interpreter/test/test_function.py Tue Dec 16 15:19:35 2003 @@ -21,6 +21,9 @@ def f(): pass self.assertEquals(f.__name__, 'f') self.assertEquals(f.__doc__, None) + self.assert_(f.__name__ is f.func_name) + self.assert_(f.__doc__ is f.func_doc) + self.assert_(f.__dict__ is f.func_dict) #XXX self.assert_(hasattr(f, '__class__')) class AppTestFunction(test.AppTestCase): From alex at codespeak.net Tue Dec 16 15:19:51 2003 From: alex at codespeak.net (alex at codespeak.net) Date: Tue, 16 Dec 2003 15:19:51 +0100 (MET) Subject: [pypy-svn] rev 2371 - pypy/trunk/src/pypy/objspace/std/test Message-ID: <20031216141951.A93A45A088@thoth.codespeak.net> Author: alex Date: Tue Dec 16 15:19:50 2003 New Revision: 2371 Modified: pypy/trunk/src/pypy/objspace/std/test/test_dictobject.py Log: a decent fix for the ambiguity in dict object representation Modified: pypy/trunk/src/pypy/objspace/std/test/test_dictobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/test/test_dictobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/test/test_dictobject.py Tue Dec 16 15:19:50 2003 @@ -309,12 +309,12 @@ self.assertEqual('{1: 2}', str({1: 2})) self.assertEqual("{'ba': 'bo'}", str({'ba': 'bo'})) # NOTE: the string repr depends on hash values of 1 and 'ba'!!! - twoitemsrepr = "{1: 2, 'ba': 'bo'}" - self.assertEqual(twoitemsrepr, str({1: 2, 'ba': 'bo'})) + ok_reprs = ["{1: 2, 'ba': 'bo'}", "{'ba': 'bo', 1: 2}"] + self.assert_(str({1: 2, 'ba': 'bo'}) in ok_reprs) self.assertEqual('{}', repr({})) self.assertEqual('{1: 2}', repr({1: 2})) self.assertEqual("{'ba': 'bo'}", repr({'ba': 'bo'})) - self.assertEqual(twoitemsrepr, repr({1: 2, 'ba': 'bo'})) + self.assert_(str({1: 2, 'ba': 'bo'}) in ok_reprs) def tooslow_test_new(self): d = dict() From pmaupin at codespeak.net Tue Dec 16 15:21:12 2003 From: pmaupin at codespeak.net (pmaupin at codespeak.net) Date: Tue, 16 Dec 2003 15:21:12 +0100 (MET) Subject: [pypy-svn] rev 2372 - in pypy/trunk/src/pypy: interpreter objspace/std Message-ID: <20031216142112.B145C5A088@thoth.codespeak.net> Author: pmaupin Date: Tue Dec 16 15:21:11 2003 New Revision: 2372 Modified: pypy/trunk/src/pypy/interpreter/baseobjspace.py pypy/trunk/src/pypy/objspace/std/objspace.py pypy/trunk/src/pypy/objspace/std/userobject.py Log: Fixed default __call__ behavior (with Armin) Modified: pypy/trunk/src/pypy/interpreter/baseobjspace.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/baseobjspace.py (original) +++ pypy/trunk/src/pypy/interpreter/baseobjspace.py Tue Dec 16 15:21:11 2003 @@ -270,8 +270,8 @@ ('gt', '>', 2, ['__gt__', '__lt__']), ('ge', '>=', 2, ['__ge__', '__le__']), ('contains', 'contains', 2, ['__contains__']), - ('iter', 'iter', 1, []), - ('call', 'call', 3, []), + ('iter', 'iter', 1, ['__iter__']), + ('call', 'call', 3, ['__call__']), ('get', 'get', 3, ['__get__']), ('set', 'set', 3, ['__set__']), ('delete', 'delete', 2, ['__delete__']), Modified: pypy/trunk/src/pypy/objspace/std/objspace.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/objspace.py (original) +++ pypy/trunk/src/pypy/objspace/std/objspace.py Tue Dec 16 15:21:11 2003 @@ -251,6 +251,7 @@ getdict = MultiMethod('getdict', 1, []) # get '.__dict__' attribute next = MultiMethod('next', 1, []) # iterator interface + call = MultiMethod('call', 3, [], varargs=True, keywords=True) def is_(self, w_one, w_two): # XXX this is a hopefully temporary speed hack: @@ -267,7 +268,8 @@ # add all regular multimethods to StdObjSpace for _name, _symbol, _arity, _specialnames in ObjSpace.MethodTable: - setattr(StdObjSpace, _name, MultiMethod(_symbol, _arity, _specialnames)) + if not hasattr(StdObjSpace,_name): + setattr(StdObjSpace, _name, MultiMethod(_symbol, _arity, _specialnames)) # import the common base W_ObjectObject as well as Modified: pypy/trunk/src/pypy/objspace/std/userobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/userobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/userobject.py Tue Dec 16 15:21:11 2003 @@ -178,6 +178,8 @@ import new for multimethod in typeobject.hack_out_multimethods(StdObjSpace): + if multimethod in (StdObjSpace.iter, StdObjSpace.call): + continue for i in range(len(multimethod.specialnames)): f = SpecialMethod(multimethod.specialnames[i], i).normal_call signature = [W_ANY] * multimethod.arity From rxe at codespeak.net Tue Dec 16 15:31:19 2003 From: rxe at codespeak.net (rxe at codespeak.net) Date: Tue, 16 Dec 2003 15:31:19 +0100 (MET) Subject: [pypy-svn] rev 2373 - pypy/trunk/src/pypy/objspace Message-ID: <20031216143119.03A515A088@thoth.codespeak.net> Author: rxe Date: Tue Dec 16 15:31:18 2003 New Revision: 2373 Modified: pypy/trunk/src/pypy/objspace/trace.py Log: Intermediate checkin - does some basic tracing. Modified: pypy/trunk/src/pypy/objspace/trace.py ============================================================================== --- pypy/trunk/src/pypy/objspace/trace.py (original) +++ pypy/trunk/src/pypy/objspace/trace.py Tue Dec 16 15:31:18 2003 @@ -7,6 +7,7 @@ from pypy.interpreter.baseobjspace import ObjSpace from pypy.interpreter.executioncontext import ExecutionContext from pypy.interpreter.pycode import PyCode +from pypy.interpreter import gateway debug = 0 class TraceExecutionContext(ExecutionContext): @@ -32,21 +33,24 @@ self.printme = printme def __call__(self, cls, *args, **kwds): - print self.name + assert (not kwds) + + #print self.name #print "%s %s(%s, %s)" % (self.printme, , str(args), str(kwds)) - self.space.notify_on_operation(self.name) + self.space.notify_on_operation(self.name, None) return self.fn(*args, **kwds) def __getattr__(self, name): return getattr(self.fn, name) -class InteractiveLogger(Logger): +## XXX Interaction not in scope (yet) +## class InteractiveLogger(Logger): - def __call__(self, cls, *args, **kwds): - res = Logger.__call__(self, cls, *args, **kwds) - raw_input() - return res +## def __call__(self, cls, *args, **kwds): +## res = Logger.__call__(self, cls, *args, **kwds) +## raw_input() +## return res # ______________________________________________________________________ @@ -56,11 +60,8 @@ full_exceptions = False def initialize(self): - self.log_list = [] - self.current_frame = None + self.tracing = 0 spacecls.initialize(self) - self.current_frame = None - self.log_list = [] method_names = [ii[0] for ii in ObjSpace.MethodTable] for key in method_names: if key in method_names: @@ -68,50 +69,87 @@ l = logger_cls(key, item, self, "class method") setattr(self, key, new.instancemethod(l, self, TraceObjSpace)) + + def start_tracing(self): + self.tracing = 1 + self.log_list = [] + + + def stop_tracing(self): + self.tracing = 0 + + def createexecutioncontext(self): "Factory function for execution contexts." return TraceExecutionContext(self) def notify_on_bytecode(self, frame): - if self.current_frame is None: - self.current_frame = frame - elif self.current_frame is frame: - bytecode, name = frame.examineop() - self.log_list.append((name, [])) + if self.tracing: + opcode, opname = frame.examineop() + self.log_list.append((opname, [])) + + def notify_on_operation(self, name, args): + if self.tracing: + self.log_list[-1][1].append((name, args)) - def notify_on_operation(self, name): - self.log_list[-1][1].append(name) def dump(self): return self.log_list + return TraceObjSpace() + Space = Trace s = Trace(TrivialObjSpace) #print dir(s) # ______________________________________________________________________ # End of trace.py +def add_func(space, func, w_globals): + """ Add a function to globals. """ + func_name = func.func_name + w_func_name = space.wrap(func_name) + w_func = space.wrap(func) + space.setitem(w_globals, w_func_name, w_func) -def runx(space, func, *args): - args_w = [space.wrap(ii) for ii in args] + +def run_function(space, func, *args): + # Get execution context and globals ec = space.getexecutioncontext() + w_globals = ec.make_standard_w_globals() + + # Add the function to globals + add_func(space, func, w_globals) + + # Create wrapped args + args_w = [space.wrap(ii) for ii in args] code = func.func_code code = PyCode()._from_code(code) - w_globals = ec.make_standard_w_globals() + + # Create frame frame = code.create_frame(space, w_globals) frame.setfastscope(args_w) - return frame.run() + + # start/stop tracing while running frame + space.start_tracing() + res = frame.run() + space.stop_tracing() + + return res + if __name__ == "__main__": + def a(b): - print b - return b+1 + if b > 0: + return a(b-1) + else: + return b - print runx(s, a, 1) + print run_function(s, a, 3) print ">>>>>>" print s.dump() From sschwarzer at codespeak.net Tue Dec 16 15:32:36 2003 From: sschwarzer at codespeak.net (sschwarzer at codespeak.net) Date: Tue, 16 Dec 2003 15:32:36 +0100 (MET) Subject: [pypy-svn] rev 2374 - pypy/trunk/src/pypy Message-ID: <20031216143236.5BD195A088@thoth.codespeak.net> Author: sschwarzer Date: Tue Dec 16 15:32:35 2003 New Revision: 2374 Modified: pypy/trunk/src/pypy/test_all.py Log: Made file executable. Modified: pypy/trunk/src/pypy/test_all.py ============================================================================== --- pypy/trunk/src/pypy/test_all.py (original) +++ pypy/trunk/src/pypy/test_all.py Tue Dec 16 15:32:35 2003 @@ -1,3 +1,5 @@ +#! /usr/bin/env python + import tool.autopath from pypy.tool import test From jacob at codespeak.net Tue Dec 16 15:32:41 2003 From: jacob at codespeak.net (jacob at codespeak.net) Date: Tue, 16 Dec 2003 15:32:41 +0100 (MET) Subject: [pypy-svn] rev 2375 - pypy/trunk/src/pypy/module Message-ID: <20031216143241.2C0C35A095@thoth.codespeak.net> Author: jacob Date: Tue Dec 16 15:32:39 2003 New Revision: 2375 Modified: pypy/trunk/src/pypy/module/builtin.py Log: Make setattr return None. Modified: pypy/trunk/src/pypy/module/builtin.py ============================================================================== --- pypy/trunk/src/pypy/module/builtin.py (original) +++ pypy/trunk/src/pypy/module/builtin.py Tue Dec 16 15:32:39 2003 @@ -312,7 +312,8 @@ return self.space.repr(w_object) def setattr(self, w_object, w_name, w_val): - return self.space.setattr(w_object, w_name, w_val) + self.space.setattr(w_object, w_name, w_val) + return self.space.w_None # app-level functions From tomek at codespeak.net Tue Dec 16 15:34:47 2003 From: tomek at codespeak.net (tomek at codespeak.net) Date: Tue, 16 Dec 2003 15:34:47 +0100 (MET) Subject: [pypy-svn] rev 2376 - pypy/trunk/src/pypy/objspace Message-ID: <20031216143447.C02545A088@thoth.codespeak.net> Author: tomek Date: Tue Dec 16 15:34:45 2003 New Revision: 2376 Modified: pypy/trunk/src/pypy/objspace/trace.py Log: one morge intermediate check-in, after merge Modified: pypy/trunk/src/pypy/objspace/trace.py ============================================================================== --- pypy/trunk/src/pypy/objspace/trace.py (original) +++ pypy/trunk/src/pypy/objspace/trace.py Tue Dec 16 15:34:45 2003 @@ -17,14 +17,6 @@ #print "XXX %s, %s" % frame.examineop() self.space.notify_on_bytecode(frame) - - def dump(self): - bytecodes = self.list_of_bytecodes - self.list_of_bytecodes = [] - return bytecodes - - - class Logger(object): def __init__(self, name, fn, space, printme): self.fn = fn @@ -69,16 +61,13 @@ l = logger_cls(key, item, self, "class method") setattr(self, key, new.instancemethod(l, self, TraceObjSpace)) - def start_tracing(self): self.tracing = 1 self.log_list = [] - def stop_tracing(self): self.tracing = 0 - def createexecutioncontext(self): "Factory function for execution contexts." return TraceExecutionContext(self) @@ -94,17 +83,32 @@ if self.tracing: self.log_list[-1][1].append((name, args)) - def dump(self): return self.log_list - + def rdump(self): + bytecodes = [] + res = [] + for bytecode, ops in self.log_list: + bytecodes.append(bytecode) + if ops: + op = ops.pop(0) + res.append((op, bytecodes)) + bytecodes = [] + for op in ops: + res.append((op, [])) + + #the rest + res.append((None, bytecodes)) + return res + + return TraceObjSpace() Space = Trace -s = Trace(TrivialObjSpace) -#print dir(s) +#s = Trace(TrivialObjSpace) +s = Trace() # ______________________________________________________________________ # End of trace.py @@ -115,7 +119,6 @@ w_func = space.wrap(func) space.setitem(w_globals, w_func_name, w_func) - def run_function(space, func, *args): # Get execution context and globals ec = space.getexecutioncontext() @@ -128,11 +131,10 @@ args_w = [space.wrap(ii) for ii in args] code = func.func_code code = PyCode()._from_code(code) - # Create frame frame = code.create_frame(space, w_globals) frame.setfastscope(args_w) - + # start/stop tracing while running frame space.start_tracing() res = frame.run() @@ -152,4 +154,8 @@ print run_function(s, a, 3) print ">>>>>>" - print s.dump() + for line in s.dump(): + print line + print ">>>>>>" + for line in s.rdump(): + print line From sschwarzer at codespeak.net Tue Dec 16 15:37:44 2003 From: sschwarzer at codespeak.net (sschwarzer at codespeak.net) Date: Tue, 16 Dec 2003 15:37:44 +0100 (MET) Subject: [pypy-svn] rev 2377 - pypy/trunk/src/pypy Message-ID: <20031216143744.6B7095A095@thoth.codespeak.net> Author: sschwarzer Date: Tue Dec 16 15:37:43 2003 New Revision: 2377 Modified: pypy/trunk/src/pypy/test_all.py (contents, props changed) Log: Removed trailing whitespace. Modified: pypy/trunk/src/pypy/test_all.py ============================================================================== --- pypy/trunk/src/pypy/test_all.py (original) +++ pypy/trunk/src/pypy/test_all.py Tue Dec 16 15:37:43 2003 @@ -5,4 +5,4 @@ if __name__ == '__main__': test.main(tool.autopath.pypydir) - + From sschwarzer at codespeak.net Tue Dec 16 15:39:08 2003 From: sschwarzer at codespeak.net (sschwarzer at codespeak.net) Date: Tue, 16 Dec 2003 15:39:08 +0100 (MET) Subject: [pypy-svn] rev 2378 - pypy/trunk/src/pypy/tool Message-ID: <20031216143908.C8ED35A099@thoth.codespeak.net> Author: sschwarzer Date: Tue Dec 16 15:39:07 2003 New Revision: 2378 Modified: pypy/trunk/src/pypy/tool/test.py Log: Formatting fixes. Modified: pypy/trunk/src/pypy/tool/test.py ============================================================================== --- pypy/trunk/src/pypy/tool/test.py (original) +++ pypy/trunk/src/pypy/tool/test.py Tue Dec 16 15:39:07 2003 @@ -26,21 +26,22 @@ return result def addTest(self, test, frommodule=None): - if test.countTestCases()>0: + if test.countTestCases() > 0: test.frommodule = frommodule unittest.TestSuite.addTest(self, test) def __nonzero__(self): - return self.countTestCases()>0 - + return self.countTestCases() > 0 # register MyTestSuite to unittest unittest.TestLoader.suiteClass = MyTestSuite + class MyTestResult(unittest.TestResult): def __init__(self): unittest.TestResult.__init__(self) self.successes = [] + def addError(self, test, err): # XXX not nice: from pypy.interpreter.baseobjspace import OperationError @@ -49,13 +50,15 @@ self.addFailure(test, err) return unittest.TestResult.addError(self, test, err) + def addSuccess(self, test): self.successes.append(test) + def addSkip(self, test): self.testsRun -= 1 + class MyTextTestResult(unittest._TextTestResult): - def addError(self, test, err): from pypy.interpreter.baseobjspace import OperationError if isinstance(err[1], OperationError) and test.space.full_exceptions: @@ -64,7 +67,7 @@ return unittest._TextTestResult.addError(self, test, err) self.errors[-1] = (test, sys.exc_info()) - + def addFailure(self, test, err): unittest._TextTestResult.addFailure(self, test, err) self.failures[-1] = (test, sys.exc_info()) @@ -121,7 +124,8 @@ self.stream.writeln(self.separator2) t1 = self._exc_info_to_string(err) t2 = '' - if isinstance(err[1], OperationError) and test.space.full_exceptions: + if isinstance(err[1], + OperationError) and test.space.full_exceptions: t2 = '\nand at app-level:\n\n' sio = StringIO.StringIO() err[1].print_application_traceback(test.space, sio) @@ -129,6 +133,7 @@ self.stream.writeln("%s" % (t1 + t2,)) + class CtsTestRunner: def run(self, test): import pickle @@ -172,9 +177,9 @@ del ostatus[k] new = status[k] if old != new: - print >>output, k, 'has transitioned from', old, 'to', new + print >> output, k, 'has transitioned from', old, 'to', new elif new != 'success': - print >>output, k, "is still a", new + print >> output, k, "is still a", new for k in ostatus: print >>output, k, 'was a', ostatus[k], 'was not run this time' @@ -184,6 +189,7 @@ return result + class MyTextTestRunner(unittest.TextTestRunner): def _makeResult(self): return MyTextTestResult(self.stream, self.descriptions, self.verbosity) @@ -191,18 +197,17 @@ def testsuite_from_main(): """ return test modules from __main__ - """ loader = unittest.TestLoader() m = __import__('__main__') return loader.loadTestsFromModule(m) def testsuite_from_dir(root, filterfunc=None, recursive=0, loader=None): - """ return test modules that optionally match filterfunc. + """ return test modules that optionally match filterfunc. all files matching the glob-pattern "test_*.py" are considered. additionally their fully qualified python module path has - to be accepted by filterfunc (if it is not None). + to be accepted by filterfunc (if it is not None). """ if Options.verbose>2: print >>sys.stderr, "scanning for test files in", root @@ -237,6 +242,7 @@ suite._tests.extend(subsuite._tests) return suite + class Options(option.Options): testreldir = 0 runcts = 0 @@ -247,6 +253,7 @@ return 0 ensure_value = staticmethod(ensure_value) + class TestSkip(Exception): pass @@ -255,11 +262,12 @@ raise TestSkip return option.objspace(name) + class RegexFilterFunc: """ stateful function to filter included/excluded strings via - a Regular Expression. + a Regular Expression. - An 'excluded' regular expressions has a '%' prependend. + An 'excluded' regular expressions has a '%' prependend. """ def __init__(self, *regex): @@ -313,14 +321,14 @@ Options.spacename = spacename warnings.defaultaction = Options.showwarning and 'default' or 'ignore' - print >>sys.stderr, "running tests via", repr(objspace()) + print >> sys.stderr, "running tests via", repr(objspace()) runner.run(suite) def main(root=None): """ run this to test everything in the __main__ or in the given root-directory (recursive)""" args = option.process_options(get_test_options(), Options) - + filterfunc = RegexFilterFunc(*args) if Options.testreldir: root = os.path.abspath('.') @@ -341,6 +349,7 @@ from pypy.tool.udir import udir print "testdata (unittestsession) directory was:", str(udir) + if __name__ == '__main__': # test all of pypy main(autopath.pypydir) From arigo at codespeak.net Tue Dec 16 15:40:32 2003 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 16 Dec 2003 15:40:32 +0100 (MET) Subject: [pypy-svn] rev 2379 - pypy/trunk/src/pypy/objspace/std/test Message-ID: <20031216144032.4714D5A099@thoth.codespeak.net> Author: arigo Date: Tue Dec 16 15:40:31 2003 New Revision: 2379 Modified: pypy/trunk/src/pypy/objspace/std/test/test_typeobject.py pypy/trunk/src/pypy/objspace/std/test/test_userobject.py Log: Added tests, two of which are known to fail. Modified: pypy/trunk/src/pypy/objspace/std/test/test_typeobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/test/test_typeobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/test/test_typeobject.py Tue Dec 16 15:40:31 2003 @@ -1,59 +1,84 @@ import autopath from pypy.tool import test -from pypy.objspace.std.typeobject import SpecialMultimethodCode -class TestSpecialMultimethodCode(test.TestCase): +##class TestSpecialMultimethodCode(test.TestCase): - def setUp(self): - self.space = test.objspace('std') +## def setUp(self): +## self.space = test.objspace('std') + +## def tearDown(self): +## pass - def tearDown(self): - pass +## def test_int_sub(self): +## w = self.space.wrap +## for i in range(2): +## meth = SpecialMultimethodCode(self.space.sub.multimethod, +## self.space.w_int.__class__, i) +## self.assertEqual(meth.slice().is_empty(), False) +## # test int.__sub__ and int.__rsub__ +## self.assertEqual_w(meth.eval_code(self.space, None, +## w({'x1': 5, 'x2': 7})), +## w(-2)) +## self.assertEqual_w(meth.eval_code(self.space, None, +## w({'x1': 5, 'x2': 7.1})), +## self.space.w_NotImplemented) +## self.assertEqual_w(meth.eval_code(self.space, None, +## w({'x1': 5.5, 'x2': 7})), +## self.space.w_NotImplemented) + +## def test_empty_inplace_add(self): +## for i in range(2): +## meth = SpecialMultimethodCode(self.space.inplace_add.multimethod, +## self.space.w_int.__class__, i) +## self.assertEqual(meth.slice().is_empty(), True) + +## def test_float_sub(self): +## w = self.space.wrap +## w(1.5) # force floatobject imported +## for i in range(2): +## meth = SpecialMultimethodCode(self.space.sub.multimethod, +## self.space.w_float.__class__, i) +## self.assertEqual(meth.slice().is_empty(), False) +## # test float.__sub__ and float.__rsub__ + +## # some of these tests are pointless for Python because +## # float.__(r)sub__ should not accept an int as first argument +## self.assertEqual_w(meth.eval_code(self.space, None, +## w({'x1': 5, 'x2': 7})), +## w(-2.0)) +## self.assertEqual_w(meth.eval_code(self.space, None, +## w({'x1': 5, 'x2': 7.5})), +## w(-2.5)) +## self.assertEqual_w(meth.eval_code(self.space, None, +## w({'x1': 5.5, 'x2': 7})), +## w(-1.5)) - def test_int_sub(self): - w = self.space.wrap - for i in range(2): - meth = SpecialMultimethodCode(self.space.sub.multimethod, - self.space.w_int.__class__, i) - self.assertEqual(meth.slice().is_empty(), False) - # test int.__sub__ and int.__rsub__ - self.assertEqual_w(meth.eval_code(self.space, None, - w({'x1': 5, 'x2': 7})), - w(-2)) - self.assertEqual_w(meth.eval_code(self.space, None, - w({'x1': 5, 'x2': 7.1})), - self.space.w_NotImplemented) - self.assertEqual_w(meth.eval_code(self.space, None, - w({'x1': 5.5, 'x2': 7})), - self.space.w_NotImplemented) - - def test_empty_inplace_add(self): - for i in range(2): - meth = SpecialMultimethodCode(self.space.inplace_add.multimethod, - self.space.w_int.__class__, i) - self.assertEqual(meth.slice().is_empty(), True) - - def test_float_sub(self): - w = self.space.wrap - w(1.5) # force floatobject imported - for i in range(2): - meth = SpecialMultimethodCode(self.space.sub.multimethod, - self.space.w_float.__class__, i) - self.assertEqual(meth.slice().is_empty(), False) - # test float.__sub__ and float.__rsub__ - - # some of these tests are pointless for Python because - # float.__(r)sub__ should not accept an int as first argument - self.assertEqual_w(meth.eval_code(self.space, None, - w({'x1': 5, 'x2': 7})), - w(-2.0)) - self.assertEqual_w(meth.eval_code(self.space, None, - w({'x1': 5, 'x2': 7.5})), - w(-2.5)) - self.assertEqual_w(meth.eval_code(self.space, None, - w({'x1': 5.5, 'x2': 7})), - w(-1.5)) +class TestTypeObject(test.AppTestCase): + def setUp(self): + self.space = test.objspace('std') + def test_builtin_add(self): + x = 5 + self.assertEquals(x.__add__(6), 11) + x = 3.5 + self.assertEquals(x.__add__(2), 5.5) + self.assertEquals(x.__add__(2.0), 5.5) + + def test_builtin_call(self): + def f(*args): + return args + self.assertEquals(f.__call__(), ()) + self.assertEquals(f.__call__(5), (5,)) + self.assertEquals(f.__call__("hello", "world"), ("hello", "world")) + + def test_builtin_call_kwds(self): + def f(*args, **kwds): + return args, kwds + self.assertEquals(f.__call__(), ((), {})) + self.assertEquals(f.__call__("hello", "world"), (("hello", "world"), {})) + self.assertEquals(f.__call__(5, bla=6), ((5,), {"bla": 6})) + self.assertEquals(f.__call__(a=1, b=2, c=3), ((), {"a": 1, "b": 2, + "c": 3})) if __name__ == '__main__': test.main() Modified: pypy/trunk/src/pypy/objspace/std/test/test_userobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/test/test_userobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/test/test_userobject.py Tue Dec 16 15:40:31 2003 @@ -81,5 +81,21 @@ self.assert_(hasattr(C, 'a')) self.assertEquals(C.a, 1) + def test_add(self): + class C: + def __add__(self, other): + return self, other + c1 = C() + self.assertEquals(c1+3, (c1, 3)) + + def test_call(self): + class C: + def __call__(self, *args): + return args + c1 = C() + self.assertEquals(c1(), ()) + self.assertEquals(c1(5), (5,)) + self.assertEquals(c1("hello", "world"), ("hello", "world")) + if __name__ == '__main__': test.main() From arigo at codespeak.net Tue Dec 16 15:41:09 2003 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 16 Dec 2003 15:41:09 +0100 (MET) Subject: [pypy-svn] rev 2380 - pypy/trunk/src/pypy/appspace/test Message-ID: <20031216144109.D93C15A099@thoth.codespeak.net> Author: arigo Date: Tue Dec 16 15:41:08 2003 New Revision: 2380 Modified: pypy/trunk/src/pypy/appspace/test/test_cmathmodule.py pypy/trunk/src/pypy/appspace/test/test_complexobject.py Log: Disabled complex+cmath tests taking our highly precious time. Modified: pypy/trunk/src/pypy/appspace/test/test_cmathmodule.py ============================================================================== --- pypy/trunk/src/pypy/appspace/test/test_cmathmodule.py (original) +++ pypy/trunk/src/pypy/appspace/test/test_cmathmodule.py Tue Dec 16 15:41:08 2003 @@ -26,7 +26,9 @@ from pypy.appspace.test.test_complexobject import equal, enumerate -class TestCMathModule(test.TestCase): +if 0: # DISABLED -- we know it works all right and don't want to see them + # take time any more for the time being + class TestCMathModule(test.TestCase): def assertAEqual(self, a, b): if not equal(a, b): Modified: pypy/trunk/src/pypy/appspace/test/test_complexobject.py ============================================================================== --- pypy/trunk/src/pypy/appspace/test/test_complexobject.py (original) +++ pypy/trunk/src/pypy/appspace/test/test_complexobject.py Tue Dec 16 15:41:08 2003 @@ -68,8 +68,9 @@ - -class TestComplex(unittest.TestCase): +if 0: # DISABLED -- we know it works all right and don't want to see them + # take time any more for the time being + class TestComplex(unittest.TestCase): def assertAEqual(self, a, b): if not equal(a, b): From jacob at codespeak.net Tue Dec 16 15:43:27 2003 From: jacob at codespeak.net (jacob at codespeak.net) Date: Tue, 16 Dec 2003 15:43:27 +0100 (MET) Subject: [pypy-svn] rev 2381 - pypy/trunk/src/pypy/objspace/std Message-ID: <20031216144327.1C9945A099@thoth.codespeak.net> Author: jacob Date: Tue Dec 16 15:43:25 2003 New Revision: 2381 Modified: pypy/trunk/src/pypy/objspace/std/objecttype.py Log: Fixing delattr. Modified: pypy/trunk/src/pypy/objspace/std/objecttype.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/objecttype.py (original) +++ pypy/trunk/src/pypy/objspace/std/objecttype.py Tue Dec 16 15:43:25 2003 @@ -169,9 +169,6 @@ raise raise OperationError(space.w_AttributeError, w_attr) - raise OperationError(space.w_AttributeError, w_attr) - - # static types def object_type__ANY(space, w_obj): From pmaupin at codespeak.net Tue Dec 16 15:58:12 2003 From: pmaupin at codespeak.net (pmaupin at codespeak.net) Date: Tue, 16 Dec 2003 15:58:12 +0100 (MET) Subject: [pypy-svn] rev 2382 - pypy/trunk/src/pypy/module/test Message-ID: <20031216145812.7DBDB5A099@thoth.codespeak.net> Author: pmaupin Date: Tue Dec 16 15:58:11 2003 New Revision: 2382 Modified: pypy/trunk/src/pypy/module/test/test_builtin.py Log: Improved iter() test Modified: pypy/trunk/src/pypy/module/test/test_builtin.py ============================================================================== --- pypy/trunk/src/pypy/module/test/test_builtin.py (original) +++ pypy/trunk/src/pypy/module/test/test_builtin.py Tue Dec 16 15:58:11 2003 @@ -27,15 +27,33 @@ def test_type_selftest(self): self.assert_(type(type) is type) - def test_iter(self): + def test_iter_sequence(self): + self.assertRaises(TypeError,iter,3) + x = iter(['a','b','c']) + self.assertEquals(x.next(),'a') + self.assertEquals(x.next(),'b') + self.assertEquals(x.next(),'c') + self.assertRaises(StopIteration,x.next) + + def test_iter___iter__(self): + # This test assumes that dict.keys() method returns keys in + # the same order as dict.__iter__(). + # Also, this test is not as explicit as the other tests; + # it tests 4 calls to __iter__() in one assert. It could + # be modified if better granularity on the assert is required. + mydict = {'a':1,'b':2,'c':3} + self.assertEquals(list(iter(mydict)),mydict.keys()) + + def test_iter_callable_sentinel(self): class count(object): def __init__(self): self.value = 0 def __call__(self): self.value += 1 return self.value - self.assertRaises(TypeError,iter,3) self.assertRaises(TypeError,iter,3,5) + self.assertRaises(TypeError,iter,[],5) + self.assertRaises(TypeError,iter,{},5) x = iter(count(),3) self.assertEquals(x.next(),1) self.assertEquals(x.next(),2) From pmaupin at codespeak.net Tue Dec 16 16:05:24 2003 From: pmaupin at codespeak.net (pmaupin at codespeak.net) Date: Tue, 16 Dec 2003 16:05:24 +0100 (MET) Subject: [pypy-svn] rev 2383 - pypy/trunk/src/pypy/module Message-ID: <20031216150524.3412A5A099@thoth.codespeak.net> Author: pmaupin Date: Tue Dec 16 16:05:23 2003 New Revision: 2383 Modified: pypy/trunk/src/pypy/module/builtin.py Log: Added docstring to app_iter_generator Modified: pypy/trunk/src/pypy/module/builtin.py ============================================================================== --- pypy/trunk/src/pypy/module/builtin.py (original) +++ pypy/trunk/src/pypy/module/builtin.py Tue Dec 16 16:05:23 2003 @@ -22,6 +22,7 @@ """ def app_iter_generator(callable_,sentinel): + """ This generator implements the __iter__(callable,sentinel) protocol """ while 1: result = callable_() if result == sentinel: From jacob at codespeak.net Tue Dec 16 16:06:26 2003 From: jacob at codespeak.net (jacob at codespeak.net) Date: Tue, 16 Dec 2003 16:06:26 +0100 (MET) Subject: [pypy-svn] rev 2384 - pypy/trunk/src/pypy/module/test Message-ID: <20031216150626.3A3CE5A15F@thoth.codespeak.net> Author: jacob Date: Tue Dec 16 16:06:25 2003 New Revision: 2384 Modified: pypy/trunk/src/pypy/module/test/test_builtin.py Log: Added tests for None return values. Modified: pypy/trunk/src/pypy/module/test/test_builtin.py ============================================================================== --- pypy/trunk/src/pypy/module/test/test_builtin.py (original) +++ pypy/trunk/src/pypy/module/test/test_builtin.py Tue Dec 16 16:06:25 2003 @@ -7,10 +7,9 @@ self.space = test.objspace() def test_import(self): - d = {} - m = __import__('types', d, d, []) - self.assertEquals(m.IntType, type(123)) - self.assertEquals(m.__name__, "types") + m = __import__('pprint') + self.assertEquals(m.pformat({}), '{}') + self.assertEquals(m.__name__, "pprint") def test_chr(self): self.assertEquals(chr(65), 'A') @@ -99,6 +98,12 @@ self.assert_(cmp(0,9) < 0) self.assert_(cmp(9,0) > 0) + def test_return_None(self): + self.assertEquals(setattr(self, 'x', 11), None) + self.assertEquals(delattr(self, 'x'), None) + # To make this test, we need autopath to work in application space. + #self.assertEquals(execfile('emptyfile.py'), None) + class TestInternal(test.IntTestCase): def setUp(self): @@ -140,6 +145,7 @@ return a+2 self.failIf(not callable(Call()), "Builtin function 'callable' misreads callable object") + def test_uncallable(self): class NoCall: pass From pedronis at codespeak.net Tue Dec 16 16:15:40 2003 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Tue, 16 Dec 2003 16:15:40 +0100 (MET) Subject: [pypy-svn] rev 2385 - pypy/trunk/src/pypy/interpreter/test Message-ID: <20031216151540.C5F6A5A160@thoth.codespeak.net> Author: pedronis Date: Tue Dec 16 16:15:40 2003 New Revision: 2385 Added: pypy/trunk/src/pypy/interpreter/test/test_code.py Log: test attributes for code objects Added: pypy/trunk/src/pypy/interpreter/test/test_code.py ============================================================================== --- (empty file) +++ pypy/trunk/src/pypy/interpreter/test/test_code.py Tue Dec 16 16:15:40 2003 @@ -0,0 +1,19 @@ + +import autopath +from pypy.tool import test +import unittest + + +class AppTestCodeIntrospection(test.AppTestCase): + def test_attributes(self): + def f(): pass + code = f.func_code + self.assert_(hasattr(code, 'co_code')) + self.assert_(not hasattr(code,'__dict__')) + self.assertEquals(code.co_name,'f') + self.assertEquals(code.co_names,()) + self.assertEquals(code.co_varnames,()) + self.assertEquals(code.co_argcount,0) + +if __name__ == '__main__': + test.main() From sschwarzer at codespeak.net Tue Dec 16 16:15:50 2003 From: sschwarzer at codespeak.net (sschwarzer at codespeak.net) Date: Tue, 16 Dec 2003 16:15:50 +0100 (MET) Subject: [pypy-svn] rev 2386 - pypy/trunk/src/pypy/tool Message-ID: <20031216151550.6C24F5A160@thoth.codespeak.net> Author: sschwarzer Date: Tue Dec 16 16:15:49 2003 New Revision: 2386 Modified: pypy/trunk/src/pypy/tool/test.py Log: Make CtsTestRunner work also with other platforms than Unix. Modified: pypy/trunk/src/pypy/tool/test.py ============================================================================== --- pypy/trunk/src/pypy/tool/test.py (original) +++ pypy/trunk/src/pypy/tool/test.py Tue Dec 16 16:15:49 2003 @@ -18,9 +18,9 @@ if not count: return result - fm = getattr(self, 'frommodule','') + fm = getattr(self, 'frommodule', '') - if fm and Options.verbose==0: + if fm and Options.verbose == 0: sys.stderr.write('\n%s [%d]' %(fm, count)) result = unittest.TestSuite.__call__(self, result) return result @@ -137,18 +137,17 @@ class CtsTestRunner: def run(self, test): import pickle + import cStringIO as StringIO output = sys.stdout result = MyTestResult() - sso = sys.stdout - sse = sys.stderr try: - sys.stdout = open('/dev/null', 'w') - sys.stderr = open('/dev/null', 'w') + # discard output of test or suite + sys.stdout = sys.stderr = StringIO.StringIO() test(result) finally: - sys.stdout = sso - sys.stderr = sse + sys.stdout = sys.__stdout__ + sys.stderr = sys.__stderr__ ostatus = {} if os.path.exists('testcts.pickle'): @@ -302,8 +301,8 @@ help="enter an interactive mode on failure or error")) options.append(make_option( '-c', action="store_true", dest="runcts", - help="run CtsTestRunner (catches stdout and prints report " - "after testing) [unix only, for now]")) + help="run CtsTestRunner (discards output and prints report " + "after testing)")) return options def run_tests(suite): From sschwarzer at codespeak.net Tue Dec 16 16:21:33 2003 From: sschwarzer at codespeak.net (sschwarzer at codespeak.net) Date: Tue, 16 Dec 2003 16:21:33 +0100 (MET) Subject: [pypy-svn] rev 2387 - pypy/trunk/src/pypy/tool Message-ID: <20031216152133.1B1515A160@thoth.codespeak.net> Author: sschwarzer Date: Tue Dec 16 16:21:32 2003 New Revision: 2387 Modified: pypy/trunk/src/pypy/tool/test.py Log: In CtsTestRunner, don't use stream named output because print uses sys.stdout by default. Modified: pypy/trunk/src/pypy/tool/test.py ============================================================================== --- pypy/trunk/src/pypy/tool/test.py (original) +++ pypy/trunk/src/pypy/tool/test.py Tue Dec 16 16:21:32 2003 @@ -139,7 +139,6 @@ import pickle import cStringIO as StringIO - output = sys.stdout result = MyTestResult() try: # discard output of test or suite @@ -176,12 +175,12 @@ del ostatus[k] new = status[k] if old != new: - print >> output, k, 'has transitioned from', old, 'to', new + print k, 'has transitioned from', old, 'to', new elif new != 'success': - print >> output, k, "is still a", new + print k, "is still a", new for k in ostatus: - print >>output, k, 'was a', ostatus[k], 'was not run this time' + print k, 'was a', ostatus[k], 'was not run this time' status[k] = ostatus[k] pickle.dump(status, open('testcts.pickle','w')) From pmaupin at codespeak.net Tue Dec 16 16:38:24 2003 From: pmaupin at codespeak.net (pmaupin at codespeak.net) Date: Tue, 16 Dec 2003 16:38:24 +0100 (MET) Subject: [pypy-svn] rev 2388 - pypy/trunk/src/pypy/module Message-ID: <20031216153824.4B7D05A160@thoth.codespeak.net> Author: pmaupin Date: Tue Dec 16 16:38:23 2003 New Revision: 2388 Modified: pypy/trunk/src/pypy/module/builtin.py Log: Moved app_iter_generator into __builtin__ class by adding underscore Modified: pypy/trunk/src/pypy/module/builtin.py ============================================================================== --- pypy/trunk/src/pypy/module/builtin.py (original) +++ pypy/trunk/src/pypy/module/builtin.py Tue Dec 16 16:38:23 2003 @@ -3,7 +3,6 @@ from pypy.interpreter.module import Module from pypy.interpreter.extmodule import ExtModule from pypy.interpreter.error import OperationError -from pypy.interpreter.gateway import app2interp import os.path import sys @@ -21,16 +20,6 @@ passed. """ -def app_iter_generator(callable_,sentinel): - """ This generator implements the __iter__(callable,sentinel) protocol """ - while 1: - result = callable_() - if result == sentinel: - raise StopIteration - yield result - -iter_generator = app2interp(app_iter_generator) - class __builtin__(ExtModule): """ Template for PyPy's '__builtin__' module. """ @@ -301,7 +290,15 @@ if not self.space.is_true(self.callable(w_collection_or_callable)): raise OperationError(self.space.w_TypeError, self.space.wrap('iter(v, w): v must be callable')) - return iter_generator(self.space, w_collection_or_callable, w_sentinel) + return self._iter_generator(w_collection_or_callable, w_sentinel) + + def app__iter_generator(self,callable_,sentinel): + """ This generator implements the __iter__(callable,sentinel) protocol """ + while 1: + result = callable_() + if result == sentinel: + raise StopIteration + yield result def ord(self, w_val): return self.space.ord(w_val) From sschwarzer at codespeak.net Tue Dec 16 16:41:34 2003 From: sschwarzer at codespeak.net (sschwarzer at codespeak.net) Date: Tue, 16 Dec 2003 16:41:34 +0100 (MET) Subject: [pypy-svn] rev 2389 - pypy/trunk/src/pypy/tool Message-ID: <20031216154134.136CE5A15E@thoth.codespeak.net> Author: sschwarzer Date: Tue Dec 16 16:41:33 2003 New Revision: 2389 Modified: pypy/trunk/src/pypy/tool/test.py Log: In CtsTestRunner, extracted method __methodname. Modified: pypy/trunk/src/pypy/tool/test.py ============================================================================== --- pypy/trunk/src/pypy/tool/test.py (original) +++ pypy/trunk/src/pypy/tool/test.py Tue Dec 16 16:41:33 2003 @@ -135,6 +135,11 @@ class CtsTestRunner: + def __methodname(self, result): + """Return a normalized form of the method name for result.""" + return "%s.%s" % (result.__class__.__name__, + result._TestCase__testMethodName) + def run(self, test): import pickle import cStringIO as StringIO @@ -147,41 +152,41 @@ finally: sys.stdout = sys.__stdout__ sys.stderr = sys.__stderr__ - - ostatus = {} + + # load status from previous run + oldstatus = {} if os.path.exists('testcts.pickle'): - ostatus = pickle.load(open('testcts.pickle','r')) + oldstatus = pickle.load(open('testcts.pickle', 'r')) + # store status from this run in dictionary named status status = {} - for e in result.errors: - name = e[0].__class__.__name__ + '.' + \ - e[0]._TestCase__testMethodName + name = self.__methodname(e[0]) status[name] = 'ERROR' for f in result.failures: - name = f[0].__class__.__name__ + '.' + \ - f[0]._TestCase__testMethodName + name = self.__methodname(f[0]) status[name] = 'FAILURE' for s in result.successes: - name = s.__class__.__name__ + '.' + s._TestCase__testMethodName + name = self.__methodname(s) status[name] = 'success' + # compare statuses from previous and this run keys = status.keys() keys.sort() for k in keys: - old = ostatus.get(k, 'success') - if k in ostatus: - del ostatus[k] + old = oldstatus.get(k, 'success') + if k in oldstatus: + del oldstatus[k] new = status[k] if old != new: print k, 'has transitioned from', old, 'to', new elif new != 'success': print k, "is still a", new - for k in ostatus: - print k, 'was a', ostatus[k], 'was not run this time' - status[k] = ostatus[k] + for k in oldstatus: + print k, 'was a', oldstatus[k], 'was not run this time' + status[k] = oldstatus[k] pickle.dump(status, open('testcts.pickle','w')) From pmaupin at codespeak.net Tue Dec 16 16:55:04 2003 From: pmaupin at codespeak.net (pmaupin at codespeak.net) Date: Tue, 16 Dec 2003 16:55:04 +0100 (MET) Subject: [pypy-svn] rev 2390 - pypy/trunk/src/pypy/interpreter Message-ID: <20031216155504.9EFF25A0EA@thoth.codespeak.net> Author: pmaupin Date: Tue Dec 16 16:55:03 2003 New Revision: 2390 Modified: pypy/trunk/src/pypy/interpreter/extmodule.py Log: Stop leaking __module__ from interpreter to app level Modified: pypy/trunk/src/pypy/interpreter/extmodule.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/extmodule.py (original) +++ pypy/trunk/src/pypy/interpreter/extmodule.py Tue Dec 16 16:55:03 2003 @@ -30,7 +30,7 @@ continue # ignore CPython functions # ignore tricky class-attrs we can't send from interp to app-level - if name in ('__metaclass__',): + if name in ('__metaclass__','__module__',): continue space.call_method(self.w_dict, 'setdefault', space.wrap(name), space.wrap(value)) From jacob at codespeak.net Tue Dec 16 17:01:21 2003 From: jacob at codespeak.net (jacob at codespeak.net) Date: Tue, 16 Dec 2003 17:01:21 +0100 (MET) Subject: [pypy-svn] rev 2391 - in pypy/trunk/src/pypy/module: . test Message-ID: <20031216160121.496F05A0EA@thoth.codespeak.net> Author: jacob Date: Tue Dec 16 17:01:20 2003 New Revision: 2391 Modified: pypy/trunk/src/pypy/module/builtin.py pypy/trunk/src/pypy/module/test/test_builtin.py Log: Added tests for locals() and dir(). Also made them work (as far as the tests try them). Modified: pypy/trunk/src/pypy/module/builtin.py ============================================================================== --- pypy/trunk/src/pypy/module/builtin.py (original) +++ pypy/trunk/src/pypy/module/builtin.py Tue Dec 16 17:01:20 2003 @@ -45,8 +45,11 @@ def globals(self): return self._actframe().w_globals + def caller_locals(self): + return self._actframe(-2).getdictscope() + def locals(self): - return self._actframe().w_locals + return self._actframe().getdictscope() def __import__(self, w_modulename, w_globals=None, w_locals=None, w_fromlist=None): @@ -597,7 +600,9 @@ raise TypeError("dir expected at most 1 arguments, got %d" % len(args)) if len(args) == 0: - return self._getlocalkeys() + local_names = self.caller_locals().keys() # 2 stackframes away + local_names.sort() + return local_names obj = args[0] @@ -633,10 +638,6 @@ return Dict.keys() - def _getlocalkeys(self): - """Return the local keys of the currenly executing frame.""" - raise NotImplementedError - # source code for the builtin xrange-class xrange_appsource = """if 1: class xrange: Modified: pypy/trunk/src/pypy/module/test/test_builtin.py ============================================================================== --- pypy/trunk/src/pypy/module/test/test_builtin.py (original) +++ pypy/trunk/src/pypy/module/test/test_builtin.py Tue Dec 16 17:01:20 2003 @@ -16,6 +16,23 @@ self.assertRaises(ValueError, chr, -1) self.assertRaises(TypeError, chr, 'a') + def test_locals(self): + def f(): + return locals() + def g(x=11): + return locals() + self.assertEquals(f(), {}) + self.assertEquals(g(), {'x':11}) + + def test_dir(self): + def f(): + return dir() + self.assertEquals(f(), []) + def g(c=0, b=0, a=0): + return dir() + self.assertEquals(g(), ['a', 'b', 'c']) + + def test_getattr(self): class a: i = 5 From pmaupin at codespeak.net Tue Dec 16 17:02:45 2003 From: pmaupin at codespeak.net (pmaupin at codespeak.net) Date: Tue, 16 Dec 2003 17:02:45 +0100 (MET) Subject: [pypy-svn] rev 2392 - pypy/trunk/src/pypy/interpreter Message-ID: <20031216160245.262AD5A0EA@thoth.codespeak.net> Author: pmaupin Date: Tue Dec 16 17:02:44 2003 New Revision: 2392 Modified: pypy/trunk/src/pypy/interpreter/baseobjspace.py Log: Do not put 'sys' into __builtin__ module Modified: pypy/trunk/src/pypy/interpreter/baseobjspace.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/baseobjspace.py (original) +++ pypy/trunk/src/pypy/interpreter/baseobjspace.py Tue Dec 16 17:02:44 2003 @@ -69,7 +69,7 @@ for name, value in self.__dict__.items(): if name.startswith('w_'): name = name[2:] - if name.startswith('builtin'): + if name.startswith('builtin') or name.startswith('sys'): continue #print "setitem: space instance %-20s into builtins" % name self.setitem(self.w_builtins, self.wrap(name), value) From arigo at codespeak.net Tue Dec 16 17:06:36 2003 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 16 Dec 2003 17:06:36 +0100 (MET) Subject: [pypy-svn] rev 2393 - pypy/trunk/src/pypy/interpreter Message-ID: <20031216160636.2F2325A0EA@thoth.codespeak.net> Author: arigo Date: Tue Dec 16 17:06:35 2003 New Revision: 2393 Modified: pypy/trunk/src/pypy/interpreter/baseobjspace.py Log: There was an app-level 'w_dict' attribute with value None in all modules. Modified: pypy/trunk/src/pypy/interpreter/baseobjspace.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/baseobjspace.py (original) +++ pypy/trunk/src/pypy/interpreter/baseobjspace.py Tue Dec 16 17:06:35 2003 @@ -9,15 +9,16 @@ class Wrappable(object): """A subclass of Wrappable is an internal, interpreter-level class that can nevertheless be exposed at application-level by space.wrap().""" - w_dict = None def get_wdict(self): space = self.space - if self.w_dict is None: + try: + return self.w_dict + except AttributeError: w_dict = self.w_dict = space.newdict([]) for name,w_value in self.app_visible(): space.setitem(w_dict,space.wrap(name),w_value) - return self.w_dict + return w_dict def app_visible(self): """ returns [(name,w_value)...] for application-level visible attributes """ From arigo at codespeak.net Tue Dec 16 17:07:12 2003 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 16 Dec 2003 17:07:12 +0100 (MET) Subject: [pypy-svn] rev 2394 - pypy/trunk/src/pypy/interpreter Message-ID: <20031216160712.448265A0EA@thoth.codespeak.net> Author: arigo Date: Tue Dec 16 17:07:11 2003 New Revision: 2394 Modified: pypy/trunk/src/pypy/interpreter/extmodule.py Log: The interpreter starts up much faster now. Modified: pypy/trunk/src/pypy/interpreter/extmodule.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/extmodule.py (original) +++ pypy/trunk/src/pypy/interpreter/extmodule.py Tue Dec 16 17:07:11 2003 @@ -18,6 +18,7 @@ # to build the dictionary of the module we get all the objects # accessible as 'self.xxx'. Methods are bound. + contents = {} for cls in self.__class__.__mro__: for name in cls.__dict__: # ignore names in '_xyz' @@ -31,9 +32,11 @@ # ignore tricky class-attrs we can't send from interp to app-level if name in ('__metaclass__','__module__',): - continue - space.call_method(self.w_dict, 'setdefault', - space.wrap(name), space.wrap(value)) + continue + contents.setdefault(space.wrap(name), space.wrap(value)) + w_contents = space.newdict(contents.items()) + space.call_method(w_contents, 'update', self.w_dict) + self.w_dict = w_contents gateway.export_values(space, self.__dict__, self.w_dict) __metaclass__ = InitializedClass From pmaupin at codespeak.net Tue Dec 16 17:26:20 2003 From: pmaupin at codespeak.net (pmaupin at codespeak.net) Date: Tue, 16 Dec 2003 17:26:20 +0100 (MET) Subject: [pypy-svn] rev 2395 - pypy/trunk/src/pypy/interpreter Message-ID: <20031216162620.A1E325A0EA@thoth.codespeak.net> Author: pmaupin Date: Tue Dec 16 17:26:19 2003 New Revision: 2395 Modified: pypy/trunk/src/pypy/interpreter/extmodule.py Log: Don't leak 'w_dict' from interpreter to user space Modified: pypy/trunk/src/pypy/interpreter/extmodule.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/extmodule.py (original) +++ pypy/trunk/src/pypy/interpreter/extmodule.py Tue Dec 16 17:26:19 2003 @@ -31,7 +31,7 @@ continue # ignore CPython functions # ignore tricky class-attrs we can't send from interp to app-level - if name in ('__metaclass__','__module__',): + if name in ('__metaclass__','__module__','w_dict',): continue contents.setdefault(space.wrap(name), space.wrap(value)) w_contents = space.newdict(contents.items()) From jacob at codespeak.net Tue Dec 16 17:29:19 2003 From: jacob at codespeak.net (jacob at codespeak.net) Date: Tue, 16 Dec 2003 17:29:19 +0100 (MET) Subject: [pypy-svn] rev 2396 - in pypy/trunk/src/pypy/module: . test Message-ID: <20031216162919.D52E35A0EA@thoth.codespeak.net> Author: jacob Date: Tue Dec 16 17:29:19 2003 New Revision: 2396 Modified: pypy/trunk/src/pypy/module/builtin.py pypy/trunk/src/pypy/module/test/test_builtin.py Log: Added tests for vars(). Made vars() work. Modified: pypy/trunk/src/pypy/module/builtin.py ============================================================================== --- pypy/trunk/src/pypy/module/builtin.py (original) +++ pypy/trunk/src/pypy/module/builtin.py Tue Dec 16 17:29:19 2003 @@ -535,7 +535,7 @@ called with no argument, return the variables bound in local scope.""" if len(obj) == 0: - return locals() + return caller_locals() elif len(obj) != 1: raise TypeError, "vars() takes at most 1 argument." else: Modified: pypy/trunk/src/pypy/module/test/test_builtin.py ============================================================================== --- pypy/trunk/src/pypy/module/test/test_builtin.py (original) +++ pypy/trunk/src/pypy/module/test/test_builtin.py Tue Dec 16 17:29:19 2003 @@ -31,7 +31,14 @@ def g(c=0, b=0, a=0): return dir() self.assertEquals(g(), ['a', 'b', 'c']) - + + def test_vars(self): + def f(): + return vars() + self.assertEquals(f(), {}) + def g(c=0, b=0, a=0): + return vars() + self.assertEquals(g(), {'a':0, 'b':0, 'c':0}) def test_getattr(self): class a: From sschwarzer at codespeak.net Tue Dec 16 17:36:35 2003 From: sschwarzer at codespeak.net (sschwarzer at codespeak.net) Date: Tue, 16 Dec 2003 17:36:35 +0100 (MET) Subject: [pypy-svn] rev 2397 - pypy/trunk/src/pypy/tool Message-ID: <20031216163635.78B2B5A0EA@thoth.codespeak.net> Author: sschwarzer Date: Tue Dec 16 17:36:34 2003 New Revision: 2397 Modified: pypy/trunk/src/pypy/tool/test.py Log: Changed status comparison in CtsTestRunner.run . The new implementation is longer, but it's much easier to see what happens in which case. Modified: pypy/trunk/src/pypy/tool/test.py ============================================================================== --- pypy/trunk/src/pypy/tool/test.py (original) +++ pypy/trunk/src/pypy/tool/test.py Tue Dec 16 17:36:34 2003 @@ -138,8 +138,8 @@ def __methodname(self, result): """Return a normalized form of the method name for result.""" return "%s.%s" % (result.__class__.__name__, - result._TestCase__testMethodName) - + result._TestCase__testMethodName) + def run(self, test): import pickle import cStringIO as StringIO @@ -152,13 +152,14 @@ finally: sys.stdout = sys.__stdout__ sys.stderr = sys.__stderr__ - - # load status from previous run - oldstatus = {} + + # load status from previous run if available if os.path.exists('testcts.pickle'): oldstatus = pickle.load(open('testcts.pickle', 'r')) + else: + oldstatus = {} - # store status from this run in dictionary named status + # store status from this run in a dictionary named status status = {} for e in result.errors: name = self.__methodname(e[0]) @@ -171,24 +172,36 @@ status[name] = 'success' # compare statuses from previous and this run - keys = status.keys() - keys.sort() - - for k in keys: - old = oldstatus.get(k, 'success') - if k in oldstatus: - del oldstatus[k] - new = status[k] - if old != new: - print k, 'has transitioned from', old, 'to', new - elif new != 'success': - print k, "is still a", new - - for k in oldstatus: - print k, 'was a', oldstatus[k], 'was not run this time' - status[k] = oldstatus[k] + oldmethods = oldstatus.keys() + methods = status.keys() + allmethods = dict([(m, 1) for m in oldmethods+methods]).keys() + allmethods.sort() + + for m in allmethods: + is_old = (m in oldstatus) + is_new = (m in status) + # case: test was run previously _and_ now + if is_old and is_new: + old = oldstatus[m] + new = status[m] + if old != new: + # print all transitions + print "%s has transitioned from %s to %s" % (m, old, new) + elif new != "success": + # print old statuses only if they weren't successes + print "%s is still a %s" % (m, new) + # case: test was run previously but not now + elif is_old and not is_new: + print "%s was a %s but not run this time" % (m, oldstatus[m]) + # retain status from previous run + status[m] = oldstatus[m] + # case: test was not run previously but now + elif not is_old and is_new: + # print nothing, just keep the old status + pass - pickle.dump(status, open('testcts.pickle','w')) + # save result from this run + pickle.dump(status, open('testcts.pickle', 'w')) return result From arigo at codespeak.net Tue Dec 16 17:41:58 2003 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 16 Dec 2003 17:41:58 +0100 (MET) Subject: [pypy-svn] rev 2398 - in pypy/trunk/src/pypy: interpreter tool Message-ID: <20031216164158.C72955A0EA@thoth.codespeak.net> Author: arigo Date: Tue Dec 16 17:41:58 2003 New Revision: 2398 Modified: pypy/trunk/src/pypy/interpreter/unittest_w.py pypy/trunk/src/pypy/tool/test.py Log: We can now ignore tests whose failure we don't care about. For this, create a file '.../src/pypy/ignored_tests.txt' in which each lines is the name of a test file, class or case. For example, I know that the following two tests currently break: pypy.objspace.std.test.test_typeobject.TestTypeObject.test_builtin_call_kwds pypy.objspace.std.test.test_typeobject.TestTypeObject.test_builtin_call Modified: pypy/trunk/src/pypy/interpreter/unittest_w.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/unittest_w.py (original) +++ pypy/trunk/src/pypy/interpreter/unittest_w.py Tue Dec 16 17:41:58 2003 @@ -4,6 +4,15 @@ import unittest from pypy.interpreter import gateway +try: + f = open(os.path.join(autopath.pypydir, 'ignore_tests.txt')) +except IOError: + IGNORE_TESTS = [] +else: + IGNORE_TESTS = [s.strip() for s in f.readlines()] + f.close() + + def make_testcase_class(space, tc_w): # XXX this is all a bit insane (but it works) @@ -53,6 +62,13 @@ self.methodName = methodName unittest.TestCase.__init__(self, methodName) + def _answer(self, result, errorfn): + id = self.id() + for ignored in IGNORE_TESTS: + if id.startswith(ignored): + errorfn = result.addIgnored + errorfn(self, self._TestCase__exc_info()) + def __call__(self, result=None): from pypy.tool.test import TestSkip if result is None: result = self.defaultTestResult() @@ -67,7 +83,7 @@ except KeyboardInterrupt: raise except: - result.addError(self, self._TestCase__exc_info()) + self._answer(result, result.addError) return ok = 0 @@ -75,21 +91,21 @@ testMethod() ok = 1 except self.failureException, e: - result.addFailure(self, self._TestCase__exc_info()) + self._answer(result, result.addFailure) except TestSkip: result.addSkip(self) return except KeyboardInterrupt: raise except: - result.addError(self, self._TestCase__exc_info()) + self._answer(result, result.addError) try: self.tearDown() except KeyboardInterrupt: raise except: - result.addError(self, self._TestCase__exc_info()) + self._answer(result, result.addError) ok = 0 if ok: result.addSuccess(self) finally: Modified: pypy/trunk/src/pypy/tool/test.py ============================================================================== --- pypy/trunk/src/pypy/tool/test.py (original) +++ pypy/trunk/src/pypy/tool/test.py Tue Dec 16 17:41:58 2003 @@ -57,8 +57,13 @@ def addSkip(self, test): self.testsRun -= 1 + def addIgnored(self, test, err): + pass + class MyTextTestResult(unittest._TextTestResult): + ignored = 0 + def addError(self, test, err): from pypy.interpreter.baseobjspace import OperationError if isinstance(err[1], OperationError) and test.space.full_exceptions: @@ -79,6 +84,13 @@ elif self.dots: self.stream.write('s') + def addIgnored(self, test, err): + self.ignored += 1 + if self.showAll: + self.stream.writeln("ignored") + elif self.dots: + self.stream.write('i') + def interact(self): efs = self.errors + self.failures from pypy.tool.testpm import TestPM @@ -207,6 +219,12 @@ class MyTextTestRunner(unittest.TextTestRunner): + def run(self, test): + result = unittest.TextTestRunner.run(self, test) + if result.ignored: + self.stream.writeln("(ignored=%d)" % result.ignored) + return result + def _makeResult(self): return MyTextTestResult(self.stream, self.descriptions, self.verbosity) From pmaupin at codespeak.net Tue Dec 16 17:45:36 2003 From: pmaupin at codespeak.net (pmaupin at codespeak.net) Date: Tue, 16 Dec 2003 17:45:36 +0100 (MET) Subject: [pypy-svn] rev 2399 - in pypy/trunk/src/pypy: interpreter module module/test Message-ID: <20031216164536.E64325A0EA@thoth.codespeak.net> Author: pmaupin Date: Tue Dec 16 17:45:36 2003 New Revision: 2399 Modified: pypy/trunk/src/pypy/interpreter/extmodule.py pypy/trunk/src/pypy/module/builtin.py pypy/trunk/src/pypy/module/test/test_builtin.py Log: Added divmod Modified: pypy/trunk/src/pypy/interpreter/extmodule.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/extmodule.py (original) +++ pypy/trunk/src/pypy/interpreter/extmodule.py Tue Dec 16 17:45:36 2003 @@ -31,7 +31,7 @@ continue # ignore CPython functions # ignore tricky class-attrs we can't send from interp to app-level - if name in ('__metaclass__','__module__','w_dict',): + if name in ('__metaclass__','__module__',): continue contents.setdefault(space.wrap(name), space.wrap(value)) w_contents = space.newdict(contents.items()) Modified: pypy/trunk/src/pypy/module/builtin.py ============================================================================== --- pypy/trunk/src/pypy/module/builtin.py (original) +++ pypy/trunk/src/pypy/module/builtin.py Tue Dec 16 17:45:36 2003 @@ -520,6 +520,8 @@ max = i return max + def app_divmod(self, x, y): + return x//y, x%y def app_cmp(self, x, y): """return 0 when x == y, -1 when x < y and 1 when x > y """ Modified: pypy/trunk/src/pypy/module/test/test_builtin.py ============================================================================== --- pypy/trunk/src/pypy/module/test/test_builtin.py (original) +++ pypy/trunk/src/pypy/module/test/test_builtin.py Tue Dec 16 17:45:36 2003 @@ -128,6 +128,9 @@ # To make this test, we need autopath to work in application space. #self.assertEquals(execfile('emptyfile.py'), None) + def test_divmod(self): + self.assertEquals(divmod(15,10),(1,5)) + class TestInternal(test.IntTestCase): def setUp(self): From arigo at codespeak.net Tue Dec 16 17:47:57 2003 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 16 Dec 2003 17:47:57 +0100 (MET) Subject: [pypy-svn] rev 2400 - pypy/trunk/src/pypy Message-ID: <20031216164757.BD53A5A0EA@thoth.codespeak.net> Author: arigo Date: Tue Dec 16 17:47:57 2003 New Revision: 2400 Modified: pypy/trunk/src/pypy/ (props changed) Log: svn now ignores the file to ignore tests From pmaupin at codespeak.net Tue Dec 16 18:00:49 2003 From: pmaupin at codespeak.net (pmaupin at codespeak.net) Date: Tue, 16 Dec 2003 18:00:49 +0100 (MET) Subject: [pypy-svn] rev 2401 - pypy/trunk/src/pypy/interpreter Message-ID: <20031216170049.33DBC5A0EA@thoth.codespeak.net> Author: pmaupin Date: Tue Dec 16 18:00:48 2003 New Revision: 2401 Modified: pypy/trunk/src/pypy/interpreter/extmodule.py Log: Back out inadvertent test change Modified: pypy/trunk/src/pypy/interpreter/extmodule.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/extmodule.py (original) +++ pypy/trunk/src/pypy/interpreter/extmodule.py Tue Dec 16 18:00:48 2003 @@ -31,7 +31,7 @@ continue # ignore CPython functions # ignore tricky class-attrs we can't send from interp to app-level - if name in ('__metaclass__','__module__',): + if name in ('__metaclass__','__module__','w_dict',): continue contents.setdefault(space.wrap(name), space.wrap(value)) w_contents = space.newdict(contents.items()) From hpk at codespeak.net Tue Dec 16 18:12:49 2003 From: hpk at codespeak.net (hpk at codespeak.net) Date: Tue, 16 Dec 2003 18:12:49 +0100 (MET) Subject: [pypy-svn] rev 2402 - in pypy/trunk/src/pypy: interpreter interpreter/testmodule objspace objspace/std Message-ID: <20031216171249.743625A0EA@thoth.codespeak.net> Author: hpk Date: Tue Dec 16 18:12:48 2003 New Revision: 2402 Modified: pypy/trunk/src/pypy/interpreter/baseobjspace.py pypy/trunk/src/pypy/interpreter/function.py pypy/trunk/src/pypy/interpreter/pycode.py pypy/trunk/src/pypy/interpreter/pyframe.py pypy/trunk/src/pypy/interpreter/pyopcode.py pypy/trunk/src/pypy/interpreter/test/test_code.py pypy/trunk/src/pypy/module/builtin.py pypy/trunk/src/pypy/objspace/std/cpythonobject.py pypy/trunk/src/pypy/objspace/std/objspace.py pypy/trunk/src/pypy/objspace/trivial.py Log: - fixed introspection and lots of pypy_* protocol places to allow full introspection of codeobjects and functions. Frames are only inspectable for non-mutable attributes (due to a new ad-hoc Wrappable-mechanism) - fixed all failing tests (Samuele,Holger) Modified: pypy/trunk/src/pypy/interpreter/baseobjspace.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/baseobjspace.py (original) +++ pypy/trunk/src/pypy/interpreter/baseobjspace.py Tue Dec 16 18:12:48 2003 @@ -23,9 +23,9 @@ def app_visible(self): """ returns [(name,w_value)...] for application-level visible attributes """ raise NotImplementedError - - def pypy_getattr(self,w_name): - space = self.space + + def pypy_getattr(self, w_name): + space = self.space w_dict = self.get_wdict() try: return space.getitem(w_dict,w_name) Modified: pypy/trunk/src/pypy/interpreter/function.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/function.py (original) +++ pypy/trunk/src/pypy/interpreter/function.py Tue Dec 16 18:12:48 2003 @@ -30,6 +30,7 @@ self.closure) frame.setfastscope(scope_w) return frame.run() + pypy_call = call def parse_args(self, w_args, w_kwds=None): @@ -166,13 +167,14 @@ return Method(self.space, wrap(self), None, wrap(cls)) def pypy_get(self, w_obj, w_cls): - wrap = self.space.wrap - if not self.space.is_true(self.space.is_(w_obj, self.space.w_None)): - if self.space.is_true(self.space.is_(w_cls, self.space.w_None)): - w_cls = self.space.type(w_obj) - return wrap(Method(self.space, wrap(self), w_obj, w_cls)) + space = self.space + wrap = space.wrap + if not space.is_true(space.is_(w_obj, space.w_None)): + if space.is_true(space.is_(w_cls, space.w_None)): + w_cls = space.type(w_obj) + return wrap(Method(space, wrap(self), w_obj, w_cls)) else: - return wrap(Method(self.space, wrap(self), None, w_cls)) + return wrap(Method(space, wrap(self), None, w_cls)) def __call__(self, *args_w, **kwds_w): wrap = self.space.wrap @@ -183,10 +185,6 @@ # (for FlowObjSpace) return self.space.call(wrap(self), w_args, w_kwds) - #def pypy_getattr(self, w_name): - # space = self.space - # raise OperationError(space.w_AttributeError, w_name) - def app_visible(self): space = self.space def makedict(**kw): @@ -202,6 +200,7 @@ it['__name__'] = it['func_name'] it['__doc__'] = it['func_doc'] it['__dict__'] = it['func_dict'] + it['__call__'] = space.wrap(self) return it.items() class Method(object): @@ -230,6 +229,7 @@ raise OperationError(self.space.w_TypeError, self.space.wrap(msg)) return self.space.call(self.w_function, w_args, w_kwds) + pypy_call = call def __call__(self, *args_w, **kwds_w): Modified: pypy/trunk/src/pypy/interpreter/pycode.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/pycode.py (original) +++ pypy/trunk/src/pypy/interpreter/pycode.py Tue Dec 16 18:12:48 2003 @@ -6,6 +6,8 @@ import dis from pypy.interpreter import eval +from pypy.interpreter.error import OperationError +from pypy.interpreter.baseobjspace import Wrappable # code object contants, for co_flags below @@ -16,6 +18,32 @@ CO_NESTED = 0x0010 CO_GENERATOR = 0x0020 +class AppPyCode(Wrappable): + """ applevel representation of a PyCode object. """ + def __init__(self, pycode, space): + self.space = space + self.pycode = pycode + + def __unwrap__(self): + return self.pycode + + def pypy_id(self): + # XXX we need a type system for internal objects! + return id(self.pycode) + + def pypy_type(self): + # XXX we need a type system for internal objects! + return self.space.wrap(self.__class__) + + def app_visible(self): + + # XXX change that if we have type objects ... + l = [] + for name,value in self.pycode.__dict__.items(): + if name.startswith('co_'): + l.append( (name, self.space.wrap(value))) + l.append(('__class__', self.pypy_type())) + return l class PyCode(eval.Code): "CPython-style code objects." @@ -38,6 +66,9 @@ self.co_firstlineno = 0 # first source line number self.co_lnotab = "" # string: encoding addr<->lineno mapping + def __wrap__(self, space): + return space.wrap(AppPyCode(self, space)) + def _from_code(self, code): """ Initialize the code object from a real (CPython) one. This is just a hack, until we have our own compile. Modified: pypy/trunk/src/pypy/interpreter/pyframe.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/pyframe.py (original) +++ pypy/trunk/src/pypy/interpreter/pyframe.py Tue Dec 16 18:12:48 2003 @@ -6,7 +6,7 @@ from pypy.interpreter.error import OperationError -class PyFrame(eval.Frame): +class PyFrame(eval.Frame, baseobjspace.Wrappable): """Represents a frame for a regular Python function that needs to be interpreted. @@ -82,17 +82,19 @@ if valuestackdepth <= self.valuestack.depth(): break self.exceptionstack.pop() - - ### public attributes ### - - def pypy_getattr(self, w_attr): - # XXX surely not the Right Way to do this - attr = self.space.unwrap(w_attr) - if attr == 'f_locals': return self.w_locals - if attr == 'f_globals': return self.w_globals - if attr == 'f_builtins': return self.w_builtins - if attr == 'f_code': return self.space.wrap(self.code) - raise OperationError(self.space.w_AttributeError, w_attr) + + ### application level visible attributes ### + def app_visible(self): + def makedict(**kw): return kw + space = self.space + d = makedict( + f_code = space.wrap(self.code), + f_locals = self.getdictscope(), + f_globals = self.w_globals, + f_builtins = self.w_builtins, + # XXX f_lasti, f_back, f_exc*, f_restricted need to do pypy_getattr directly + ) + return d.items() ### Frame Blocks ### Modified: pypy/trunk/src/pypy/interpreter/pyopcode.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/pyopcode.py (original) +++ pypy/trunk/src/pypy/interpreter/pyopcode.py Tue Dec 16 18:12:48 2003 @@ -70,6 +70,7 @@ def getname(self, index): return self.code.co_names[index] + ################################################################ ## Implementation of the "operational" opcodes ## See also pyfastscope.py and pynestedscope.py for the rest. @@ -701,7 +702,7 @@ def MAKE_FUNCTION(f, numdefaults): w_codeobj = f.valuestack.pop() - codeobj = f.space.unwrap(w_codeobj) + codeobj = f.space.unwrap(w_codeobj) defaultarguments = [f.valuestack.pop() for i in range(numdefaults)] defaultarguments.reverse() fn = function.Function(f.space, codeobj, f.w_globals, defaultarguments) Modified: pypy/trunk/src/pypy/interpreter/test/test_code.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/test/test_code.py (original) +++ pypy/trunk/src/pypy/interpreter/test/test_code.py Tue Dec 16 18:12:48 2003 @@ -9,6 +9,7 @@ def f(): pass code = f.func_code self.assert_(hasattr(code, 'co_code')) + self.assert_(hasattr(code, '__class__')) self.assert_(not hasattr(code,'__dict__')) self.assertEquals(code.co_name,'f') self.assertEquals(code.co_names,()) Modified: pypy/trunk/src/pypy/module/builtin.py ============================================================================== --- pypy/trunk/src/pypy/module/builtin.py (original) +++ pypy/trunk/src/pypy/module/builtin.py Tue Dec 16 18:12:48 2003 @@ -35,6 +35,10 @@ ## self.w_imp_path = space.sys.w_path ## ExtModule.__init__(self, space) + def __init__(self, space): + self.w___debug__ = space.newbool(1) + ExtModule.__init__(self, space) + def _initcompiledbuiltins(self): """ add 'compiled' builtins to app-level dict and interp-level """ self._eval_app_source(xrange_appsource) Modified: pypy/trunk/src/pypy/objspace/std/cpythonobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/cpythonobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/cpythonobject.py Tue Dec 16 18:12:48 2003 @@ -29,7 +29,10 @@ def cpython_unwrap(space, w_obj): - return w_obj.cpyobj + cpyobj = w_obj.cpyobj + if hasattr(cpyobj, '__unwrap__'): + cpyobj = cpyobj.__unwrap__() + return cpyobj StdObjSpace.unwrap.register(cpython_unwrap, W_CPythonObject) @@ -159,19 +162,23 @@ if f: if _arity == 1: def cpython_f(space, w_1, f=f, pypymethod='pypy_'+_name): - x = space.unwrap(w_1) - if hasattr(x, pypymethod): - return getattr(x, pypymethod)() + x1 = space.unwrap(w_1) + type_x1 = type(x1) + if hasattr(type_x1, pypymethod): + return getattr(type_x1, pypymethod)(x1) try: - y = f(x) + y = f(x1) except: wrap_exception(space) return space.wrap(y) elif _arity == 2: def cpython_f(space, w_1, w_2, f=f, pypymethod='pypy_'+_name): x1 = space.unwrap(w_1) - if hasattr(x1, pypymethod): - return getattr(x1, pypymethod)(w_2) + type_x1 = type(x1) + if hasattr(type_x1, pypymethod): + return getattr(type_x1, pypymethod)(x1, w_2) + + # XXX do we really want to unwrap unknown objects here? x2 = space.unwrap(w_2) try: y = f(x1, x2) @@ -181,8 +188,10 @@ elif _arity == 3: def cpython_f(space, w_1, w_2, w_3, f=f, pypymethod='pypy_'+_name): x1 = space.unwrap(w_1) - if hasattr(x1, pypymethod): - return getattr(x1, pypymethod)(w_2, w_3) + type_x1 = type(x1) + if hasattr(type_x1, pypymethod): + return getattr(type_x1, pypymethod)(x1, w_2, w_3) + x2 = space.unwrap(w_2) x3 = space.unwrap(w_3) try: Modified: pypy/trunk/src/pypy/objspace/std/objspace.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/objspace.py (original) +++ pypy/trunk/src/pypy/objspace/std/objspace.py Tue Dec 16 18:12:48 2003 @@ -200,7 +200,7 @@ wrappeditems = [self.wrap(item) for item in x] import listobject return listobject.W_ListObject(self, wrappeditems) - if hasattr(x, '__wrap__'): + if hasattr(type(x), '__wrap__'): return x.__wrap__(self) # print "wrapping %r (%s)" % (x, type(x)) import cpythonobject @@ -254,17 +254,17 @@ call = MultiMethod('call', 3, [], varargs=True, keywords=True) def is_(self, w_one, w_two): - # XXX this is a hopefully temporary speed hack: + # XXX a bit of hacking to gain more speed + # + if w_one is w_two: + return self.newbool(1) from cpythonobject import W_CPythonObject if isinstance(w_one, W_CPythonObject): if isinstance(w_two, W_CPythonObject): - return self.newbool(w_one.cpyobj is w_two.cpyobj) - else: - return self.newbool(0) - else: - return self.newbool(w_one is w_two) - - + if w_one.cpyobj is w_two.cpyobj: + return self.newbool(1) + return self.newbool(self.unwrap(w_one) is self.unwrap(w_two)) + return self.newbool(0) # add all regular multimethods to StdObjSpace for _name, _symbol, _arity, _specialnames in ObjSpace.MethodTable: Modified: pypy/trunk/src/pypy/objspace/trivial.py ============================================================================== --- pypy/trunk/src/pypy/objspace/trivial.py (original) +++ pypy/trunk/src/pypy/objspace/trivial.py Tue Dec 16 18:12:48 2003 @@ -143,12 +143,14 @@ # general stuff def wrap(self, x): - if hasattr(x, '__wrap__'): + if hasattr(type(x), '__wrap__'): return x.__wrap__(self) else: return x def unwrap(self, w): + if hasattr(type(w), '__unwrap__'): + w = w.__unwrap__() return w def reraise(self): @@ -178,7 +180,7 @@ def _auto(name, sourcefn, classlocals): s = """ def %(name)s(self, x, *args): - if hasattr(x, 'pypy_%(name)s'): + if hasattr(type(x), 'pypy_%(name)s'): return x.pypy_%(name)s(*args) try: value = %(sourcefn)s(x, *args) From sschwarzer at codespeak.net Tue Dec 16 18:16:22 2003 From: sschwarzer at codespeak.net (sschwarzer at codespeak.net) Date: Tue, 16 Dec 2003 18:16:22 +0100 (MET) Subject: [pypy-svn] rev 2403 - pypy/trunk/src/pypy/tool Message-ID: <20031216171622.07B8A5A0EA@thoth.codespeak.net> Author: sschwarzer Date: Tue Dec 16 18:16:22 2003 New Revision: 2403 Modified: pypy/trunk/src/pypy/tool/test.py Log: Added comment on private method in CtsTestRunner.__methodname. Modified: pypy/trunk/src/pypy/tool/test.py ============================================================================== --- pypy/trunk/src/pypy/tool/test.py (original) +++ pypy/trunk/src/pypy/tool/test.py Tue Dec 16 18:16:22 2003 @@ -148,7 +148,8 @@ class CtsTestRunner: def __methodname(self, result): - """Return a normalized form of the method name for result.""" + "Return a normalized form of the method name for result." + # use private method, id() is not enough for us return "%s.%s" % (result.__class__.__name__, result._TestCase__testMethodName) @@ -283,6 +284,7 @@ spacename = '' individualtime = 0 interactive = 0 + #XXX what's the purpose of this? def ensure_value(*args): return 0 ensure_value = staticmethod(ensure_value) From arigo at codespeak.net Tue Dec 16 18:17:34 2003 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 16 Dec 2003 18:17:34 +0100 (MET) Subject: [pypy-svn] rev 2404 - pypy/trunk/src/pypy Message-ID: <20031216171734.718EC5A0EA@thoth.codespeak.net> Author: arigo Date: Tue Dec 16 18:17:33 2003 New Revision: 2404 Modified: pypy/trunk/src/pypy/TODO (props changed) Log: fixeol on the TODO file. From alex at codespeak.net Tue Dec 16 18:17:40 2003 From: alex at codespeak.net (alex at codespeak.net) Date: Tue, 16 Dec 2003 18:17:40 +0100 (MET) Subject: [pypy-svn] rev 2405 - pypy/trunk/src/pypy/appspace Message-ID: <20031216171740.0CE4A5A0EA@thoth.codespeak.net> Author: alex Date: Tue Dec 16 18:17:39 2003 New Revision: 2405 Added: pypy/trunk/src/pypy/appspace/test_support.py (contents, props changed) pypy/trunk/src/pypy/appspace/test_types.py (contents, props changed) Modified: pypy/trunk/src/pypy/appspace/pprint.py (props changed) Log: substantial testing on builtin types, stolen from CPython Added: pypy/trunk/src/pypy/appspace/test_support.py ============================================================================== --- (empty file) +++ pypy/trunk/src/pypy/appspace/test_support.py Tue Dec 16 18:17:39 2003 @@ -0,0 +1,190 @@ +"""Supporting definitions for the Python regression tests.""" + +''' +if __name__ != 'test.test_support': + raise ImportError, 'test_support must be imported from the test package' +''' + +import sys + +class Error(Exception): + """Base class for regression test exceptions.""" + +class TestFailed(Error): + """Test failed.""" + +class TestSkipped(Error): + """Test skipped. + + This can be raised to indicate that a test was deliberatly + skipped, but not because a feature wasn't available. For + example, if some resource can't be used, such as the network + appears to be unavailable, this should be raised instead of + TestFailed. + """ + +class ResourceDenied(TestSkipped): + """Test skipped because it requested a disallowed resource. + + This is raised when a test calls requires() for a resource that + has not be enabled. It is used to distinguish between expected + and unexpected skips. + """ + +verbose = 1 # Flag set to 0 by regrtest.py +use_resources = None # Flag set to [] by regrtest.py + +# _original_stdout is meant to hold stdout at the time regrtest began. +# This may be "the real" stdout, or IDLE's emulation of stdout, or whatever. +# The point is to have some flavor of stdout the user can actually see. +_original_stdout = None +def record_original_stdout(stdout): + global _original_stdout + _original_stdout = stdout + +def get_original_stdout(): + return _original_stdout or sys.stdout + +def unload(name): + try: + del sys.modules[name] + except KeyError: + pass + +def forget(modname): + '''"Forget" a module was ever imported by removing it from sys.modules and + deleting any .pyc and .pyo files.''' + unload(modname) + import os + for dirname in sys.path: + try: + os.unlink(os.path.join(dirname, modname + os.extsep + 'pyc')) + except os.error: + pass + # Deleting the .pyo file cannot be within the 'try' for the .pyc since + # the chance exists that there is no .pyc (and thus the 'try' statement + # is exited) but there is a .pyo file. + try: + os.unlink(os.path.join(dirname, modname + os.extsep + 'pyo')) + except os.error: + pass + +def is_resource_enabled(resource): + """Test whether a resource is enabled. Known resources are set by + regrtest.py.""" + return use_resources is not None and resource in use_resources + +def requires(resource, msg=None): + """Raise ResourceDenied if the specified resource is not available. + + If the caller's module is __main__ then automatically return True. The + possibility of False being returned occurs when regrtest.py is executing.""" + # see if the caller's module is __main__ - if so, treat as if + # the resource was set + if sys._getframe().f_back.f_globals.get("__name__") == "__main__": + return + if not is_resource_enabled(resource): + if msg is None: + msg = "Use of the `%s' resource not enabled" % resource + raise ResourceDenied(msg) + +FUZZ = 1e-6 + +def fcmp(x, y): # fuzzy comparison function + if type(x) == type(0.0) or type(y) == type(0.0): + try: + x, y = coerce(x, y) + fuzz = (abs(x) + abs(y)) * FUZZ + if abs(x-y) <= fuzz: + return 0 + except: + pass + elif type(x) == type(y) and type(x) in (type(()), type([])): + for i in range(min(len(x), len(y))): + outcome = fcmp(x[i], y[i]) + if outcome != 0: + return outcome + return cmp(len(x), len(y)) + return cmp(x, y) + +try: + unicode + have_unicode = 1 +except NameError: + have_unicode = 0 + +is_jython = sys.platform.startswith('java') + +TESTFN = '@test' + +# Make sure we can write to TESTFN, try in /tmp if we can't +fp = None +try: + fp = open(TESTFN, 'w+') +except IOError: + TMP_TESTFN = os.path.join('/tmp', TESTFN) + try: + fp = open(TMP_TESTFN, 'w+') + TESTFN = TMP_TESTFN + del TMP_TESTFN + except IOError: + print ('WARNING: tests will fail, unable to write to: %s or %s' % + (TESTFN, TMP_TESTFN)) +if fp is not None: + fp.close() +del fp + +def findfile(file, here=__file__): + """Try to find a file on sys.path and the working directory. If it is not + found the argument passed to the function is returned (this does not + necessarily signal failure; could still be the legitimate path).""" + import os + if os.path.isabs(file): + return file + path = sys.path + path = [os.path.dirname(here)] + path + for dn in path: + fn = os.path.join(dn, file) + if os.path.exists(fn): return fn + return file + +def verify(condition, reason='test failed'): + """Verify that condition is true. If not, raise TestFailed. + + The optional argument reason can be given to provide + a better error text. + """ + + if not condition: + raise TestFailed(reason) + +def vereq(a, b): + """Raise TestFailed if a == b is false. + + This is better than verify(a == b) because, in case of failure, the + error message incorporates repr(a) and repr(b) so you can see the + inputs. + + Note that "not (a == b)" isn't necessarily the same as "a != b"; the + former is tested. + """ + + if not (a == b): + raise TestFailed, "%r == %r" % (a, b) + +def sortdict(dict): + "Like repr(dict), but in sorted order." + items = dict.items() + items.sort() + reprpairs = ["%r: %r" % pair for pair in items] + withcommas = ", ".join(reprpairs) + return "{%s}" % withcommas + +def check_syntax(statement): + try: + compile(statement, '', 'exec') + except SyntaxError: + pass + else: + print 'Missing SyntaxError: "%s"' % statement + Added: pypy/trunk/src/pypy/appspace/test_types.py ============================================================================== --- (empty file) +++ pypy/trunk/src/pypy/appspace/test_types.py Tue Dec 16 18:17:39 2003 @@ -0,0 +1,775 @@ +# Python test set -- part 6, built-in types + +from test_support import * + +print '6. Built-in types' + +print '6.1 Truth value testing' +if None: raise TestFailed, 'None is true instead of false' +if 0: raise TestFailed, '0 is true instead of false' +if 0L: raise TestFailed, '0L is true instead of false' +if 0.0: raise TestFailed, '0.0 is true instead of false' +if '': raise TestFailed, '\'\' is true instead of false' +if (): raise TestFailed, '() is true instead of false' +if []: raise TestFailed, '[] is true instead of false' +if {}: raise TestFailed, '{} is true instead of false' +if not 1: raise TestFailed, '1 is false instead of true' +if not 1L: raise TestFailed, '1L is false instead of true' +if not 1.0: raise TestFailed, '1.0 is false instead of true' +if not 'x': raise TestFailed, '\'x\' is false instead of true' +if not (1, 1): raise TestFailed, '(1, 1) is false instead of true' +if not [1]: raise TestFailed, '[1] is false instead of true' +if not {'x': 1}: raise TestFailed, '{\'x\': 1} is false instead of true' +def f(): pass +class C: pass +import sys +x = C() +if not f: raise TestFailed, 'f is false instead of true' +if not C: raise TestFailed, 'C is false instead of true' +if not sys: raise TestFailed, 'sys is false instead of true' +if not x: raise TestFailed, 'x is false instead of true' + +print '6.2 Boolean operations' +if 0 or 0: raise TestFailed, '0 or 0 is true instead of false' +if 1 and 1: pass +else: raise TestFailed, '1 and 1 is false instead of false' +if not 1: raise TestFailed, 'not 1 is true instead of false' + +print '6.3 Comparisons' +if 0 < 1 <= 1 == 1 >= 1 > 0 != 1: pass +else: raise TestFailed, 'int comparisons failed' +if 0L < 1L <= 1L == 1L >= 1L > 0L != 1L: pass +else: raise TestFailed, 'long int comparisons failed' +if 0.0 < 1.0 <= 1.0 == 1.0 >= 1.0 > 0.0 != 1.0: pass +else: raise TestFailed, 'float comparisons failed' +if '' < 'a' <= 'a' == 'a' < 'abc' < 'abd' < 'b': pass +else: raise TestFailed, 'string comparisons failed' +if 0 in [0] and 0 not in [1]: pass +else: raise TestFailed, 'membership test failed' +if None is None and [] is not []: pass +else: raise TestFailed, 'identity test failed' + +try: float('') +except ValueError: pass +else: raise TestFailed, "float('') didn't raise ValueError" + +try: float('5\0') +except ValueError: pass +else: raise TestFailed, "float('5\0') didn't raise ValueError" + +try: 5.0 / 0.0 +except ZeroDivisionError: pass +else: raise TestFailed, "5.0 / 0.0 didn't raise ZeroDivisionError" + +try: 5.0 // 0.0 +except ZeroDivisionError: pass +else: raise TestFailed, "5.0 // 0.0 didn't raise ZeroDivisionError" + +try: 5.0 % 0.0 +except ZeroDivisionError: pass +else: raise TestFailed, "5.0 % 0.0 didn't raise ZeroDivisionError" + +try: 5 / 0L +except ZeroDivisionError: pass +else: raise TestFailed, "5 / 0L didn't raise ZeroDivisionError" + +try: 5 // 0L +except ZeroDivisionError: pass +else: raise TestFailed, "5 // 0L didn't raise ZeroDivisionError" + +try: 5 % 0L +except ZeroDivisionError: pass +else: raise TestFailed, "5 % 0L didn't raise ZeroDivisionError" + +print '6.4 Numeric types (mostly conversions)' +if 0 != 0L or 0 != 0.0 or 0L != 0.0: raise TestFailed, 'mixed comparisons' +if 1 != 1L or 1 != 1.0 or 1L != 1.0: raise TestFailed, 'mixed comparisons' +if -1 != -1L or -1 != -1.0 or -1L != -1.0: + raise TestFailed, 'int/long/float value not equal' +# calling built-in types without argument must return 0 +if int() != 0: raise TestFailed, 'int() does not return 0' +if long() != 0L: raise TestFailed, 'long() does not return 0L' +if float() != 0.0: raise TestFailed, 'float() does not return 0.0' +if int(1.9) == 1 == int(1.1) and int(-1.1) == -1 == int(-1.9): pass +else: raise TestFailed, 'int() does not round properly' +if long(1.9) == 1L == long(1.1) and long(-1.1) == -1L == long(-1.9): pass +else: raise TestFailed, 'long() does not round properly' +if float(1) == 1.0 and float(-1) == -1.0 and float(0) == 0.0: pass +else: raise TestFailed, 'float() does not work properly' +print '6.4.1 32-bit integers' +if 12 + 24 != 36: raise TestFailed, 'int op' +if 12 + (-24) != -12: raise TestFailed, 'int op' +if (-12) + 24 != 12: raise TestFailed, 'int op' +if (-12) + (-24) != -36: raise TestFailed, 'int op' +if not 12 < 24: raise TestFailed, 'int op' +if not -24 < -12: raise TestFailed, 'int op' +# Test for a particular bug in integer multiply +xsize, ysize, zsize = 238, 356, 4 +if not (xsize*ysize*zsize == zsize*xsize*ysize == 338912): + raise TestFailed, 'int mul commutativity' +# And another. +m = -sys.maxint - 1 +for divisor in 1, 2, 4, 8, 16, 32: + j = m // divisor + prod = divisor * j + if prod != m: + raise TestFailed, "%r * %r == %r != %r" % (divisor, j, prod, m) + if type(prod) is not int: + raise TestFailed, ("expected type(prod) to be int, not %r" % + type(prod)) +# Check for expected * overflow to long. +for divisor in 1, 2, 4, 8, 16, 32: + j = m // divisor - 1 + prod = divisor * j + if type(prod) is not long: + raise TestFailed, ("expected type(%r) to be long, not %r" % + (prod, type(prod))) +# Check for expected * overflow to long. +m = sys.maxint +for divisor in 1, 2, 4, 8, 16, 32: + j = m // divisor + 1 + prod = divisor * j + if type(prod) is not long: + raise TestFailed, ("expected type(%r) to be long, not %r" % + (prod, type(prod))) + +print '6.4.2 Long integers' +if 12L + 24L != 36L: raise TestFailed, 'long op' +if 12L + (-24L) != -12L: raise TestFailed, 'long op' +if (-12L) + 24L != 12L: raise TestFailed, 'long op' +if (-12L) + (-24L) != -36L: raise TestFailed, 'long op' +if not 12L < 24L: raise TestFailed, 'long op' +if not -24L < -12L: raise TestFailed, 'long op' +x = sys.maxint +if int(long(x)) != x: raise TestFailed, 'long op' +try: y = int(long(x)+1L) +except OverflowError: raise TestFailed, 'long op' +if not isinstance(y, long): raise TestFailed, 'long op' +x = -x +if int(long(x)) != x: raise TestFailed, 'long op' +x = x-1 +if int(long(x)) != x: raise TestFailed, 'long op' +try: y = int(long(x)-1L) +except OverflowError: raise TestFailed, 'long op' +if not isinstance(y, long): raise TestFailed, 'long op' + +try: 5 << -5 +except ValueError: pass +else: raise TestFailed, 'int negative shift <<' + +try: 5L << -5L +except ValueError: pass +else: raise TestFailed, 'long negative shift <<' + +try: 5 >> -5 +except ValueError: pass +else: raise TestFailed, 'int negative shift >>' + +try: 5L >> -5L +except ValueError: pass +else: raise TestFailed, 'long negative shift >>' + +print '6.4.3 Floating point numbers' +if 12.0 + 24.0 != 36.0: raise TestFailed, 'float op' +if 12.0 + (-24.0) != -12.0: raise TestFailed, 'float op' +if (-12.0) + 24.0 != 12.0: raise TestFailed, 'float op' +if (-12.0) + (-24.0) != -36.0: raise TestFailed, 'float op' +if not 12.0 < 24.0: raise TestFailed, 'float op' +if not -24.0 < -12.0: raise TestFailed, 'float op' + +print '6.5 Sequence types' + +print '6.5.1 Strings' +if len('') != 0: raise TestFailed, 'len(\'\')' +if len('a') != 1: raise TestFailed, 'len(\'a\')' +if len('abcdef') != 6: raise TestFailed, 'len(\'abcdef\')' +if 'xyz' + 'abcde' != 'xyzabcde': raise TestFailed, 'string concatenation' +if 'xyz'*3 != 'xyzxyzxyz': raise TestFailed, 'string repetition *3' +if 0*'abcde' != '': raise TestFailed, 'string repetition 0*' +if min('abc') != 'a' or max('abc') != 'c': raise TestFailed, 'min/max string' +if 'a' in 'abc' and 'b' in 'abc' and 'c' in 'abc' and 'd' not in 'abc': pass +else: raise TestFailed, 'in/not in string' +x = 'x'*103 +if '%s!'%x != x+'!': raise TestFailed, 'nasty string formatting bug' + +#extended slices for strings +a = '0123456789' +vereq(a[::], a) +vereq(a[::2], '02468') +vereq(a[1::2], '13579') +vereq(a[::-1],'9876543210') +vereq(a[::-2], '97531') +vereq(a[3::-2], '31') +vereq(a[-100:100:], a) +vereq(a[100:-100:-1], a[::-1]) +vereq(a[-100L:100L:2L], '02468') + +if have_unicode: + a = unicode('0123456789', 'ascii') + vereq(a[::], a) + vereq(a[::2], unicode('02468', 'ascii')) + vereq(a[1::2], unicode('13579', 'ascii')) + vereq(a[::-1], unicode('9876543210', 'ascii')) + vereq(a[::-2], unicode('97531', 'ascii')) + vereq(a[3::-2], unicode('31', 'ascii')) + vereq(a[-100:100:], a) + vereq(a[100:-100:-1], a[::-1]) + vereq(a[-100L:100L:2L], unicode('02468', 'ascii')) + + +print '6.5.2 Tuples' +# calling built-in types without argument must return empty +if tuple() != (): raise TestFailed,'tuple() does not return ()' +if len(()) != 0: raise TestFailed, 'len(())' +if len((1,)) != 1: raise TestFailed, 'len((1,))' +if len((1,2,3,4,5,6)) != 6: raise TestFailed, 'len((1,2,3,4,5,6))' +if (1,2)+(3,4) != (1,2,3,4): raise TestFailed, 'tuple concatenation' +if (1,2)*3 != (1,2,1,2,1,2): raise TestFailed, 'tuple repetition *3' +if 0*(1,2,3) != (): raise TestFailed, 'tuple repetition 0*' +if min((1,2)) != 1 or max((1,2)) != 2: raise TestFailed, 'min/max tuple' +if 0 in (0,1,2) and 1 in (0,1,2) and 2 in (0,1,2) and 3 not in (0,1,2): pass +else: raise TestFailed, 'in/not in tuple' +try: ()[0] +except IndexError: pass +else: raise TestFailed, "tuple index error didn't raise IndexError" +x = () +x += () +if x != (): raise TestFailed, 'tuple inplace add from () to () failed' +x += (1,) +if x != (1,): raise TestFailed, 'tuple resize from () failed' + +# extended slicing - subscript only for tuples +a = (0,1,2,3,4) +vereq(a[::], a) +vereq(a[::2], (0,2,4)) +vereq(a[1::2], (1,3)) +vereq(a[::-1], (4,3,2,1,0)) +vereq(a[::-2], (4,2,0)) +vereq(a[3::-2], (3,1)) +vereq(a[-100:100:], a) +vereq(a[100:-100:-1], a[::-1]) +vereq(a[-100L:100L:2L], (0,2,4)) + +# Check that a specific bug in _PyTuple_Resize() is squashed. +def f(): + for i in range(1000): + yield i +vereq(list(tuple(f())), range(1000)) + +# Verify that __getitem__ overrides are not recognized by __iter__ +class T(tuple): + def __getitem__(self, key): + return str(key) + '!!!' +vereq(iter(T((1,2))).next(), 1) + +print '6.5.3 Lists' +# calling built-in types without argument must return empty +if list() != []: raise TestFailed,'list() does not return []' +if len([]) != 0: raise TestFailed, 'len([])' +if len([1,]) != 1: raise TestFailed, 'len([1,])' +if len([1,2,3,4,5,6]) != 6: raise TestFailed, 'len([1,2,3,4,5,6])' +if [1,2]+[3,4] != [1,2,3,4]: raise TestFailed, 'list concatenation' +if [1,2]*3 != [1,2,1,2,1,2]: raise TestFailed, 'list repetition *3' +if [1,2]*3L != [1,2,1,2,1,2]: raise TestFailed, 'list repetition *3L' +if 0*[1,2,3] != []: raise TestFailed, 'list repetition 0*' +if 0L*[1,2,3] != []: raise TestFailed, 'list repetition 0L*' +if min([1,2]) != 1 or max([1,2]) != 2: raise TestFailed, 'min/max list' +if 0 in [0,1,2] and 1 in [0,1,2] and 2 in [0,1,2] and 3 not in [0,1,2]: pass +else: raise TestFailed, 'in/not in list' +a = [1, 2, 3, 4, 5] +a[:-1] = a +if a != [1, 2, 3, 4, 5, 5]: + raise TestFailed, "list self-slice-assign (head)" +a = [1, 2, 3, 4, 5] +a[1:] = a +if a != [1, 1, 2, 3, 4, 5]: + raise TestFailed, "list self-slice-assign (tail)" +a = [1, 2, 3, 4, 5] +a[1:-1] = a +if a != [1, 1, 2, 3, 4, 5, 5]: + raise TestFailed, "list self-slice-assign (center)" +try: [][0] +except IndexError: pass +else: raise TestFailed, "list index error didn't raise IndexError" +try: [][0] = 5 +except IndexError: pass +else: raise TestFailed, "list assignment index error didn't raise IndexError" +try: [].pop() +except IndexError: pass +else: raise TestFailed, "empty list.pop() didn't raise IndexError" +try: [1].pop(5) +except IndexError: pass +else: raise TestFailed, "[1].pop(5) didn't raise IndexError" +try: [][0:1] = 5 +except TypeError: pass +else: raise TestFailed, "bad list slice assignment didn't raise TypeError" +try: [].extend(None) +except TypeError: pass +else: raise TestFailed, "list.extend(None) didn't raise TypeError" +a = [1, 2, 3, 4] +a *= 0 +if a != []: + raise TestFailed, "list inplace repeat" + +a = [] +a[:] = tuple(range(10)) +if a != range(10): + raise TestFailed, "assigning tuple to slice" + +print '6.5.3a Additional list operations' +a = [0,1,2,3,4] +a[0L] = 1 +a[1L] = 2 +a[2L] = 3 +if a != [1,2,3,3,4]: raise TestFailed, 'list item assignment [0L], [1L], [2L]' +a[0] = 5 +a[1] = 6 +a[2] = 7 +if a != [5,6,7,3,4]: raise TestFailed, 'list item assignment [0], [1], [2]' +a[-2L] = 88 +a[-1L] = 99 +if a != [5,6,7,88,99]: raise TestFailed, 'list item assignment [-2L], [-1L]' +a[-2] = 8 +a[-1] = 9 +if a != [5,6,7,8,9]: raise TestFailed, 'list item assignment [-2], [-1]' +a[:2] = [0,4] +a[-3:] = [] +a[1:1] = [1,2,3] +if a != [0,1,2,3,4]: raise TestFailed, 'list slice assignment' +a[ 1L : 4L] = [7,8,9] +if a != [0,7,8,9,4]: raise TestFailed, 'list slice assignment using long ints' +del a[1:4] +if a != [0,4]: raise TestFailed, 'list slice deletion' +del a[0] +if a != [4]: raise TestFailed, 'list item deletion [0]' +del a[-1] +if a != []: raise TestFailed, 'list item deletion [-1]' +a=range(0,5) +del a[1L:4L] +if a != [0,4]: raise TestFailed, 'list slice deletion' +del a[0L] +if a != [4]: raise TestFailed, 'list item deletion [0]' +del a[-1L] +if a != []: raise TestFailed, 'list item deletion [-1]' +a.append(0) +a.append(1) +a.append(2) +if a != [0,1,2]: raise TestFailed, 'list append' +a.insert(0, -2) +a.insert(1, -1) +a.insert(2,0) +if a != [-2,-1,0,0,1,2]: raise TestFailed, 'list insert' +b = a[:] +b.insert(-2, "foo") +b.insert(-200, "left") +b.insert(200, "right") +if b != ["left",-2,-1,0,0,"foo",1,2,"right"]: raise TestFailed, 'list insert2' +# a = [-2,-1,0,0,1,2] +if a.count(0) != 2: raise TestFailed, ' list count' +if a.index(0) != 2: raise TestFailed, 'list index' +if a.index(0,2) != 2: raise TestFailed, 'list index, start argument' +if a.index(0,-4) != 2: raise TestFailed, 'list index, -start argument' +if a.index(-2,-10) != 0: raise TestFailed, 'list index, very -start argument' +if a.index(0,3) != 3: raise TestFailed, 'list index, start argument' +if a.index(0,-3) != 3: raise TestFailed, 'list index, -start argument' +if a.index(0,3,4) != 3: raise TestFailed, 'list index, stop argument' +if a.index(0,-3,-2) != 3: raise TestFailed, 'list index, -stop argument' +if a.index(0,-4*sys.maxint,4*sys.maxint) != 2: + raise TestFailed, 'list index, -maxint, maxint argument' +try: + a.index(0, 4*sys.maxint,-4*sys.maxint) +except ValueError: + pass +else: + raise TestFailed, 'list index, maxint,-maxint argument' + +try: + a.index(2,0,-10) +except ValueError: + pass +else: + raise TestFailed, 'list index, very -stop argument' +a.remove(0) +try: + a.index(2,0,4) +except ValueError: + pass +else: + raise TestFailed, 'list index, stop argument.' +if a != [-2,-1,0,1,2]: raise TestFailed, 'list remove' +a.reverse() +if a != [2,1,0,-1,-2]: raise TestFailed, 'list reverse' +a.sort() +if a != [-2,-1,0,1,2]: raise TestFailed, 'list sort' +def revcmp(a, b): return cmp(b, a) +a.sort(revcmp) +if a != [2,1,0,-1,-2]: raise TestFailed, 'list sort with cmp func' +# The following dumps core in unpatched Python 1.5: +def myComparison(x,y): + return cmp(x%3, y%7) +z = range(12) +z.sort(myComparison) + +try: z.sort(2) +except TypeError: pass +else: raise TestFailed, 'list sort compare function is not callable' + +def selfmodifyingComparison(x,y): + z.append(1) + return cmp(x, y) +try: z.sort(selfmodifyingComparison) +except ValueError: pass +else: raise TestFailed, 'modifying list during sort' + +try: z.sort(lambda x, y: 's') +except TypeError: pass +else: raise TestFailed, 'list sort compare function does not return int' + +''' TODO: pow is badly broken, fix! +# Test extreme cases with long ints +a = [0,1,2,3,4] +if a[ -pow(2,128L): 3 ] != [0,1,2]: + raise TestFailed, "list slicing with too-small long integer" +if a[ 3: pow(2,145L) ] != [3,4]: + raise TestFailed, "list slicing with too-large long integer" +''' + +# extended slicing + +# subscript +a = [0,1,2,3,4] +vereq(a[::], a) +vereq(a[::2], [0,2,4]) +vereq(a[1::2], [1,3]) +vereq(a[::-1], [4,3,2,1,0]) +vereq(a[::-2], [4,2,0]) +vereq(a[3::-2], [3,1]) +vereq(a[-100:100:], a) +vereq(a[100:-100:-1], a[::-1]) +vereq(a[-100L:100L:2L], [0,2,4]) +vereq(a[1000:2000:2], []) +vereq(a[-1000:-2000:-2], []) +# deletion +del a[::2] +vereq(a, [1,3]) +a = range(5) +del a[1::2] +vereq(a, [0,2,4]) +a = range(5) +del a[1::-2] +vereq(a, [0,2,3,4]) +a = range(10) +del a[::1000] +vereq(a, [1, 2, 3, 4, 5, 6, 7, 8, 9]) +# assignment +a = range(10) +a[::2] = [-1]*5 +vereq(a, [-1, 1, -1, 3, -1, 5, -1, 7, -1, 9]) +a = range(10) +a[::-4] = [10]*3 +vereq(a, [0, 10, 2, 3, 4, 10, 6, 7, 8 ,10]) +a = range(4) +a[::-1] = a +vereq(a, [3, 2, 1, 0]) +a = range(10) +b = a[:] +c = a[:] +a[2:3] = ["two", "elements"] +b[slice(2,3)] = ["two", "elements"] +c[2:3:] = ["two", "elements"] +vereq(a, b) +vereq(a, c) +a = range(10) +a[::2] = tuple(range(5)) +vereq(a, [0, 1, 1, 3, 2, 5, 3, 7, 4, 9]) + +# Verify that __getitem__ overrides are not recognized by __iter__ +class L(list): + def __getitem__(self, key): + return str(key) + '!!!' +vereq(iter(L([1,2])).next(), 1) + + +print '6.6 Mappings == Dictionaries' +# calling built-in types without argument must return empty +if dict() != {}: raise TestFailed,'dict() does not return {}' +d = {} +if d.keys() != []: raise TestFailed, '{}.keys()' +if d.values() != []: raise TestFailed, '{}.values()' +if d.items() != []: raise TestFailed, '{}.items()' +if d.has_key('a') != 0: raise TestFailed, '{}.has_key(\'a\')' +if ('a' in d) != 0: raise TestFailed, "'a' in {}" +if ('a' not in d) != 1: raise TestFailed, "'a' not in {}" +if len(d) != 0: raise TestFailed, 'len({})' +d = {'a': 1, 'b': 2} +if len(d) != 2: raise TestFailed, 'len(dict)' +k = d.keys() +k.sort() +if k != ['a', 'b']: raise TestFailed, 'dict keys()' +if d.has_key('a') and d.has_key('b') and not d.has_key('c'): pass +else: raise TestFailed, 'dict keys()' +if 'a' in d and 'b' in d and 'c' not in d: pass +else: raise TestFailed, 'dict keys() # in/not in version' +if d['a'] != 1 or d['b'] != 2: raise TestFailed, 'dict item' +d['c'] = 3 +d['a'] = 4 +if d['c'] != 3 or d['a'] != 4: raise TestFailed, 'dict item assignment' +del d['b'] +if d != {'a': 4, 'c': 3}: raise TestFailed, 'dict item deletion' +print '6.6.1 dict methods' +# dict.clear() +d = {1:1, 2:2, 3:3} +d.clear() +if d != {}: raise TestFailed, 'dict clear' +# dict.update() +d.update({1:100}) +d.update({2:20}) +d.update({1:1, 2:2, 3:3}) +if d != {1:1, 2:2, 3:3}: raise TestFailed, 'dict update' +d.clear() +try: d.update(None) +except AttributeError: pass +else: raise TestFailed, 'dict.update(None), AttributeError expected' +print '6.6.2 user-dict methods' +class SimpleUserDict: + def __init__(self): + self.d = {1:1, 2:2, 3:3} + def keys(self): + return self.d.keys() + def __getitem__(self, i): + return self.d[i] +d.update(SimpleUserDict()) +if d != {1:1, 2:2, 3:3}: raise TestFailed, 'dict.update(instance)' +d.clear() +class FailingUserDict: + def keys(self): + raise ValueError +try: d.update(FailingUserDict()) +except ValueError: pass +else: raise TestFailed, 'dict.keys() expected ValueError' +class FailingUserDict: + def keys(self): + class BogonIter: + def __iter__(self): + raise ValueError + return BogonIter() +try: d.update(FailingUserDict()) +except ValueError: pass +else: raise TestFailed, 'iter(dict.keys()) expected ValueError' +class FailingUserDict: + def keys(self): + class BogonIter: + def __init__(self): + self.i = 1 + def __iter__(self): + return self + def next(self): + if self.i: + self.i = 0 + return 'a' + raise ValueError + return BogonIter() + def __getitem__(self, key): + return key +try: d.update(FailingUserDict()) +except ValueError: pass +else: raise TestFailed, 'iter(dict.keys()).next() expected ValueError' +class FailingUserDict: + def keys(self): + class BogonIter: + def __init__(self): + self.i = ord('a') + def __iter__(self): + return self + def next(self): + if self.i <= ord('z'): + rtn = chr(self.i) + self.i += 1 + return rtn + raise StopIteration + return BogonIter() + def __getitem__(self, key): + raise ValueError +try: d.update(FailingUserDict()) +except ValueError: pass +else: raise TestFailed, 'dict.update(), __getitem__ expected ValueError' +print '6.6.3 dict.fromkeys' +# dict.fromkeys() +if dict.fromkeys('abc') != {'a':None, 'b':None, 'c':None}: + raise TestFailed, 'dict.fromkeys did not work as a class method' +d = {} +if d.fromkeys('abc') is d: + raise TestFailed, 'dict.fromkeys did not return a new dict' +if d.fromkeys('abc') != {'a':None, 'b':None, 'c':None}: + raise TestFailed, 'dict.fromkeys failed with default value' +if d.fromkeys((4,5),0) != {4:0, 5:0}: + raise TestFailed, 'dict.fromkeys failed with specified value' +if d.fromkeys([]) != {}: + raise TestFailed, 'dict.fromkeys failed with null sequence' +def g(): + yield 1 +if d.fromkeys(g()) != {1:None}: + raise TestFailed, 'dict.fromkeys failed with a generator' +try: {}.fromkeys(3) +except TypeError: pass +else: raise TestFailed, 'dict.fromkeys failed to raise TypeError' +class dictlike(dict): pass +if dictlike.fromkeys('a') != {'a':None}: + raise TestFailed, 'dictsubclass.fromkeys did not inherit' +if dictlike().fromkeys('a') != {'a':None}: + raise TestFailed, 'dictsubclass.fromkeys did not inherit' +if type(dictlike.fromkeys('a')) is not dictlike: + raise TestFailed, 'dictsubclass.fromkeys created wrong type' +if type(dictlike().fromkeys('a')) is not dictlike: + raise TestFailed, 'dictsubclass.fromkeys created wrong type' + +''' TODO: fromkeys not recognized as a classmethod here +from UserDict import UserDict +class mydict(dict): + def __new__(cls): + return UserDict() +ud = mydict.fromkeys('ab') +if ud != {'a':None, 'b':None} or not isinstance(ud,UserDict): + raise TestFailed, 'fromkeys did not instantiate using __new__' +''' + +print '6.6.4 dict copy, get, setdefault' + +# dict.copy() +d = {1:1, 2:2, 3:3} +if d.copy() != {1:1, 2:2, 3:3}: raise TestFailed, 'dict copy' +if {}.copy() != {}: raise TestFailed, 'empty dict copy' +# dict.get() +d = {} +if d.get('c') is not None: raise TestFailed, 'missing {} get, no 2nd arg' +if d.get('c', 3) != 3: raise TestFailed, 'missing {} get, w/ 2nd arg' +d = {'a' : 1, 'b' : 2} +if d.get('c') is not None: raise TestFailed, 'missing dict get, no 2nd arg' +if d.get('c', 3) != 3: raise TestFailed, 'missing dict get, w/ 2nd arg' +if d.get('a') != 1: raise TestFailed, 'present dict get, no 2nd arg' +if d.get('a', 3) != 1: raise TestFailed, 'present dict get, w/ 2nd arg' +# dict.setdefault() +d = {} +if d.setdefault('key0') is not None: + raise TestFailed, 'missing {} setdefault, no 2nd arg' +if d.setdefault('key0') is not None: + raise TestFailed, 'present {} setdefault, no 2nd arg' +d.setdefault('key', []).append(3) +if d['key'][0] != 3: + raise TestFailed, 'missing {} setdefault, w/ 2nd arg' +d.setdefault('key', []).append(4) +if len(d['key']) != 2: + raise TestFailed, 'present {} setdefault, w/ 2nd arg' + +print '6.6.5 dict popitem' + +# dict.popitem() +for copymode in -1, +1: + # -1: b has same structure as a + # +1: b is a.copy() + for log2size in range(12): + size = 2**log2size + a = {} + b = {} + for i in range(size): + a[`i`] = i + if copymode < 0: + b[`i`] = i + if copymode > 0: + b = a.copy() + for i in range(size): + ka, va = ta = a.popitem() + if va != int(ka): raise TestFailed, "a.popitem: %s" % str(ta) + kb, vb = tb = b.popitem() + if vb != int(kb): raise TestFailed, "b.popitem: %s" % str(tb) + if copymode < 0 and ta != tb: + raise TestFailed, "a.popitem != b.popitem: %s, %s" % ( + str(ta), str(tb)) + if a: raise TestFailed, 'a not empty after popitems: %s' % str(a) + if b: raise TestFailed, 'b not empty after popitems: %s' % str(b) + +d.clear() +try: d.popitem() +except KeyError: pass +else: raise TestFailed, "{}.popitem doesn't raise KeyError" + +print '6.6.6 dict pop' + +# Tests for pop with specified key +d.clear() +k, v = 'abc', 'def' +d[k] = v +try: d.pop('ghi') +except KeyError: pass +else: raise TestFailed, "{}.pop(k) doesn't raise KeyError when k not in dictionary" + +if d.pop(k) != v: raise TestFailed, "{}.pop(k) doesn't find known key/value pair" +if len(d) > 0: raise TestFailed, "{}.pop(k) failed to remove the specified pair" + +try: d.pop(k) +except KeyError: pass +else: raise TestFailed, "{}.pop(k) doesn't raise KeyError when dictionary is empty" + +# verify longs/ints get same value when key > 32 bits (for 64-bit archs) +# see SF bug #689659 +x = 4503599627370496L +y = 4503599627370496 +h = {x: 'anything', y: 'something else'} +if h[x] != h[y]: + raise TestFailed, "long/int key should match" + +if d.pop(k, v) != v: raise TestFailed, "{}.pop(k, v) doesn't return default value" +d[k] = v +if d.pop(k, 1) != v: raise TestFailed, "{}.pop(k, v) doesn't find known key/value pair" + +''' TODO: doesn't raise correctly +d[1] = 1 +try: + for i in d: + d[i+1] = 1 +except RuntimeError: + pass +else: + raise TestFailed, "changing dict size during iteration doesn't raise Error" +''' + +print '6.7 type' + +try: type(1, 2) +except TypeError: pass +else: raise TestFailed, 'type(), w/2 args expected TypeError' + +try: type(1, 2, 3, 4) +except TypeError: pass +else: raise TestFailed, 'type(), w/4 args expected TypeError' + +print '6.8 buffer' + +print 'Buffers' +try: buffer('asdf', -1) +except ValueError: pass +else: raise TestFailed, "buffer('asdf', -1) should raise ValueError" + +try: buffer(None) +except TypeError: pass +else: raise TestFailed, "buffer(None) should raise TypeError" + +a = buffer('asdf') +hash(a) +b = a * 5 +if a == b: + raise TestFailed, 'buffers should not be equal' +if str(b) != ('asdf' * 5): + raise TestFailed, 'repeated buffer has wrong content' +if str(a * 0) != '': + raise TestFailed, 'repeated buffer zero times has wrong content' +if str(a + buffer('def')) != 'asdfdef': + raise TestFailed, 'concatenation of buffers yields wrong content' + +try: a[1] = 'g' +except TypeError: pass +else: raise TestFailed, "buffer assignment should raise TypeError" + +try: a[0:1] = 'g' +except TypeError: pass +else: raise TestFailed, "buffer slice assignment should raise TypeError" From arigo at codespeak.net Tue Dec 16 18:27:03 2003 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 16 Dec 2003 18:27:03 +0100 (MET) Subject: [pypy-svn] rev 2406 - pypy/trunk/src/pypy/objspace/std Message-ID: <20031216172703.CCB385A0EA@thoth.codespeak.net> Author: arigo Date: Tue Dec 16 18:27:03 2003 New Revision: 2406 Modified: pypy/trunk/src/pypy/objspace/std/floattype.py Log: Fix float('somestring'). Modified: pypy/trunk/src/pypy/objspace/std/floattype.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/floattype.py (original) +++ pypy/trunk/src/pypy/objspace/std/floattype.py Tue Dec 16 18:27:03 2003 @@ -22,9 +22,9 @@ space.w_str)): try: return space.newfloat(float(space.unwrap(arg))), True - except TypeError: - raise OperationError(space.w_TypeError, - space.wrap("invalid literal for float()")) + except ValueError, e: + raise OperationError(space.w_ValueError, + space.wrap(str(e))) else: return space.float(args[0]), True else: From arigo at codespeak.net Tue Dec 16 18:27:28 2003 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 16 Dec 2003 18:27:28 +0100 (MET) Subject: [pypy-svn] rev 2407 - pypy/trunk/src/pypy/appspace Message-ID: <20031216172728.755BB5A0EA@thoth.codespeak.net> Author: arigo Date: Tue Dec 16 18:27:27 2003 New Revision: 2407 Added: pypy/trunk/src/pypy/appspace/builtin_types_test.py (contents, props changed) - copied, changed from rev 2405, pypy/trunk/src/pypy/appspace/test_types.py pypy/trunk/src/pypy/appspace/support_tests.py (props changed) - copied unchanged from rev 2405, pypy/trunk/src/pypy/appspace/test_support.py Removed: pypy/trunk/src/pypy/appspace/test_support.py pypy/trunk/src/pypy/appspace/test_types.py Log: Renaming files so that the test framework don't find them. Copied: pypy/trunk/src/pypy/appspace/builtin_types_test.py (from rev 2405, pypy/trunk/src/pypy/appspace/test_types.py) ============================================================================== --- pypy/trunk/src/pypy/appspace/test_types.py (original) +++ pypy/trunk/src/pypy/appspace/builtin_types_test.py Tue Dec 16 18:27:27 2003 @@ -1,6 +1,7 @@ # Python test set -- part 6, built-in types +# Slightly edited version for PyPy. -from test_support import * +from support_tests import * print '6. Built-in types' Deleted: /pypy/trunk/src/pypy/appspace/test_support.py ============================================================================== --- /pypy/trunk/src/pypy/appspace/test_support.py Tue Dec 16 18:27:27 2003 +++ (empty file) @@ -1,190 +0,0 @@ -"""Supporting definitions for the Python regression tests.""" - -''' -if __name__ != 'test.test_support': - raise ImportError, 'test_support must be imported from the test package' -''' - -import sys - -class Error(Exception): - """Base class for regression test exceptions.""" - -class TestFailed(Error): - """Test failed.""" - -class TestSkipped(Error): - """Test skipped. - - This can be raised to indicate that a test was deliberatly - skipped, but not because a feature wasn't available. For - example, if some resource can't be used, such as the network - appears to be unavailable, this should be raised instead of - TestFailed. - """ - -class ResourceDenied(TestSkipped): - """Test skipped because it requested a disallowed resource. - - This is raised when a test calls requires() for a resource that - has not be enabled. It is used to distinguish between expected - and unexpected skips. - """ - -verbose = 1 # Flag set to 0 by regrtest.py -use_resources = None # Flag set to [] by regrtest.py - -# _original_stdout is meant to hold stdout at the time regrtest began. -# This may be "the real" stdout, or IDLE's emulation of stdout, or whatever. -# The point is to have some flavor of stdout the user can actually see. -_original_stdout = None -def record_original_stdout(stdout): - global _original_stdout - _original_stdout = stdout - -def get_original_stdout(): - return _original_stdout or sys.stdout - -def unload(name): - try: - del sys.modules[name] - except KeyError: - pass - -def forget(modname): - '''"Forget" a module was ever imported by removing it from sys.modules and - deleting any .pyc and .pyo files.''' - unload(modname) - import os - for dirname in sys.path: - try: - os.unlink(os.path.join(dirname, modname + os.extsep + 'pyc')) - except os.error: - pass - # Deleting the .pyo file cannot be within the 'try' for the .pyc since - # the chance exists that there is no .pyc (and thus the 'try' statement - # is exited) but there is a .pyo file. - try: - os.unlink(os.path.join(dirname, modname + os.extsep + 'pyo')) - except os.error: - pass - -def is_resource_enabled(resource): - """Test whether a resource is enabled. Known resources are set by - regrtest.py.""" - return use_resources is not None and resource in use_resources - -def requires(resource, msg=None): - """Raise ResourceDenied if the specified resource is not available. - - If the caller's module is __main__ then automatically return True. The - possibility of False being returned occurs when regrtest.py is executing.""" - # see if the caller's module is __main__ - if so, treat as if - # the resource was set - if sys._getframe().f_back.f_globals.get("__name__") == "__main__": - return - if not is_resource_enabled(resource): - if msg is None: - msg = "Use of the `%s' resource not enabled" % resource - raise ResourceDenied(msg) - -FUZZ = 1e-6 - -def fcmp(x, y): # fuzzy comparison function - if type(x) == type(0.0) or type(y) == type(0.0): - try: - x, y = coerce(x, y) - fuzz = (abs(x) + abs(y)) * FUZZ - if abs(x-y) <= fuzz: - return 0 - except: - pass - elif type(x) == type(y) and type(x) in (type(()), type([])): - for i in range(min(len(x), len(y))): - outcome = fcmp(x[i], y[i]) - if outcome != 0: - return outcome - return cmp(len(x), len(y)) - return cmp(x, y) - -try: - unicode - have_unicode = 1 -except NameError: - have_unicode = 0 - -is_jython = sys.platform.startswith('java') - -TESTFN = '@test' - -# Make sure we can write to TESTFN, try in /tmp if we can't -fp = None -try: - fp = open(TESTFN, 'w+') -except IOError: - TMP_TESTFN = os.path.join('/tmp', TESTFN) - try: - fp = open(TMP_TESTFN, 'w+') - TESTFN = TMP_TESTFN - del TMP_TESTFN - except IOError: - print ('WARNING: tests will fail, unable to write to: %s or %s' % - (TESTFN, TMP_TESTFN)) -if fp is not None: - fp.close() -del fp - -def findfile(file, here=__file__): - """Try to find a file on sys.path and the working directory. If it is not - found the argument passed to the function is returned (this does not - necessarily signal failure; could still be the legitimate path).""" - import os - if os.path.isabs(file): - return file - path = sys.path - path = [os.path.dirname(here)] + path - for dn in path: - fn = os.path.join(dn, file) - if os.path.exists(fn): return fn - return file - -def verify(condition, reason='test failed'): - """Verify that condition is true. If not, raise TestFailed. - - The optional argument reason can be given to provide - a better error text. - """ - - if not condition: - raise TestFailed(reason) - -def vereq(a, b): - """Raise TestFailed if a == b is false. - - This is better than verify(a == b) because, in case of failure, the - error message incorporates repr(a) and repr(b) so you can see the - inputs. - - Note that "not (a == b)" isn't necessarily the same as "a != b"; the - former is tested. - """ - - if not (a == b): - raise TestFailed, "%r == %r" % (a, b) - -def sortdict(dict): - "Like repr(dict), but in sorted order." - items = dict.items() - items.sort() - reprpairs = ["%r: %r" % pair for pair in items] - withcommas = ", ".join(reprpairs) - return "{%s}" % withcommas - -def check_syntax(statement): - try: - compile(statement, '', 'exec') - except SyntaxError: - pass - else: - print 'Missing SyntaxError: "%s"' % statement - Deleted: /pypy/trunk/src/pypy/appspace/test_types.py ============================================================================== --- /pypy/trunk/src/pypy/appspace/test_types.py Tue Dec 16 18:27:27 2003 +++ (empty file) @@ -1,775 +0,0 @@ -# Python test set -- part 6, built-in types - -from test_support import * - -print '6. Built-in types' - -print '6.1 Truth value testing' -if None: raise TestFailed, 'None is true instead of false' -if 0: raise TestFailed, '0 is true instead of false' -if 0L: raise TestFailed, '0L is true instead of false' -if 0.0: raise TestFailed, '0.0 is true instead of false' -if '': raise TestFailed, '\'\' is true instead of false' -if (): raise TestFailed, '() is true instead of false' -if []: raise TestFailed, '[] is true instead of false' -if {}: raise TestFailed, '{} is true instead of false' -if not 1: raise TestFailed, '1 is false instead of true' -if not 1L: raise TestFailed, '1L is false instead of true' -if not 1.0: raise TestFailed, '1.0 is false instead of true' -if not 'x': raise TestFailed, '\'x\' is false instead of true' -if not (1, 1): raise TestFailed, '(1, 1) is false instead of true' -if not [1]: raise TestFailed, '[1] is false instead of true' -if not {'x': 1}: raise TestFailed, '{\'x\': 1} is false instead of true' -def f(): pass -class C: pass -import sys -x = C() -if not f: raise TestFailed, 'f is false instead of true' -if not C: raise TestFailed, 'C is false instead of true' -if not sys: raise TestFailed, 'sys is false instead of true' -if not x: raise TestFailed, 'x is false instead of true' - -print '6.2 Boolean operations' -if 0 or 0: raise TestFailed, '0 or 0 is true instead of false' -if 1 and 1: pass -else: raise TestFailed, '1 and 1 is false instead of false' -if not 1: raise TestFailed, 'not 1 is true instead of false' - -print '6.3 Comparisons' -if 0 < 1 <= 1 == 1 >= 1 > 0 != 1: pass -else: raise TestFailed, 'int comparisons failed' -if 0L < 1L <= 1L == 1L >= 1L > 0L != 1L: pass -else: raise TestFailed, 'long int comparisons failed' -if 0.0 < 1.0 <= 1.0 == 1.0 >= 1.0 > 0.0 != 1.0: pass -else: raise TestFailed, 'float comparisons failed' -if '' < 'a' <= 'a' == 'a' < 'abc' < 'abd' < 'b': pass -else: raise TestFailed, 'string comparisons failed' -if 0 in [0] and 0 not in [1]: pass -else: raise TestFailed, 'membership test failed' -if None is None and [] is not []: pass -else: raise TestFailed, 'identity test failed' - -try: float('') -except ValueError: pass -else: raise TestFailed, "float('') didn't raise ValueError" - -try: float('5\0') -except ValueError: pass -else: raise TestFailed, "float('5\0') didn't raise ValueError" - -try: 5.0 / 0.0 -except ZeroDivisionError: pass -else: raise TestFailed, "5.0 / 0.0 didn't raise ZeroDivisionError" - -try: 5.0 // 0.0 -except ZeroDivisionError: pass -else: raise TestFailed, "5.0 // 0.0 didn't raise ZeroDivisionError" - -try: 5.0 % 0.0 -except ZeroDivisionError: pass -else: raise TestFailed, "5.0 % 0.0 didn't raise ZeroDivisionError" - -try: 5 / 0L -except ZeroDivisionError: pass -else: raise TestFailed, "5 / 0L didn't raise ZeroDivisionError" - -try: 5 // 0L -except ZeroDivisionError: pass -else: raise TestFailed, "5 // 0L didn't raise ZeroDivisionError" - -try: 5 % 0L -except ZeroDivisionError: pass -else: raise TestFailed, "5 % 0L didn't raise ZeroDivisionError" - -print '6.4 Numeric types (mostly conversions)' -if 0 != 0L or 0 != 0.0 or 0L != 0.0: raise TestFailed, 'mixed comparisons' -if 1 != 1L or 1 != 1.0 or 1L != 1.0: raise TestFailed, 'mixed comparisons' -if -1 != -1L or -1 != -1.0 or -1L != -1.0: - raise TestFailed, 'int/long/float value not equal' -# calling built-in types without argument must return 0 -if int() != 0: raise TestFailed, 'int() does not return 0' -if long() != 0L: raise TestFailed, 'long() does not return 0L' -if float() != 0.0: raise TestFailed, 'float() does not return 0.0' -if int(1.9) == 1 == int(1.1) and int(-1.1) == -1 == int(-1.9): pass -else: raise TestFailed, 'int() does not round properly' -if long(1.9) == 1L == long(1.1) and long(-1.1) == -1L == long(-1.9): pass -else: raise TestFailed, 'long() does not round properly' -if float(1) == 1.0 and float(-1) == -1.0 and float(0) == 0.0: pass -else: raise TestFailed, 'float() does not work properly' -print '6.4.1 32-bit integers' -if 12 + 24 != 36: raise TestFailed, 'int op' -if 12 + (-24) != -12: raise TestFailed, 'int op' -if (-12) + 24 != 12: raise TestFailed, 'int op' -if (-12) + (-24) != -36: raise TestFailed, 'int op' -if not 12 < 24: raise TestFailed, 'int op' -if not -24 < -12: raise TestFailed, 'int op' -# Test for a particular bug in integer multiply -xsize, ysize, zsize = 238, 356, 4 -if not (xsize*ysize*zsize == zsize*xsize*ysize == 338912): - raise TestFailed, 'int mul commutativity' -# And another. -m = -sys.maxint - 1 -for divisor in 1, 2, 4, 8, 16, 32: - j = m // divisor - prod = divisor * j - if prod != m: - raise TestFailed, "%r * %r == %r != %r" % (divisor, j, prod, m) - if type(prod) is not int: - raise TestFailed, ("expected type(prod) to be int, not %r" % - type(prod)) -# Check for expected * overflow to long. -for divisor in 1, 2, 4, 8, 16, 32: - j = m // divisor - 1 - prod = divisor * j - if type(prod) is not long: - raise TestFailed, ("expected type(%r) to be long, not %r" % - (prod, type(prod))) -# Check for expected * overflow to long. -m = sys.maxint -for divisor in 1, 2, 4, 8, 16, 32: - j = m // divisor + 1 - prod = divisor * j - if type(prod) is not long: - raise TestFailed, ("expected type(%r) to be long, not %r" % - (prod, type(prod))) - -print '6.4.2 Long integers' -if 12L + 24L != 36L: raise TestFailed, 'long op' -if 12L + (-24L) != -12L: raise TestFailed, 'long op' -if (-12L) + 24L != 12L: raise TestFailed, 'long op' -if (-12L) + (-24L) != -36L: raise TestFailed, 'long op' -if not 12L < 24L: raise TestFailed, 'long op' -if not -24L < -12L: raise TestFailed, 'long op' -x = sys.maxint -if int(long(x)) != x: raise TestFailed, 'long op' -try: y = int(long(x)+1L) -except OverflowError: raise TestFailed, 'long op' -if not isinstance(y, long): raise TestFailed, 'long op' -x = -x -if int(long(x)) != x: raise TestFailed, 'long op' -x = x-1 -if int(long(x)) != x: raise TestFailed, 'long op' -try: y = int(long(x)-1L) -except OverflowError: raise TestFailed, 'long op' -if not isinstance(y, long): raise TestFailed, 'long op' - -try: 5 << -5 -except ValueError: pass -else: raise TestFailed, 'int negative shift <<' - -try: 5L << -5L -except ValueError: pass -else: raise TestFailed, 'long negative shift <<' - -try: 5 >> -5 -except ValueError: pass -else: raise TestFailed, 'int negative shift >>' - -try: 5L >> -5L -except ValueError: pass -else: raise TestFailed, 'long negative shift >>' - -print '6.4.3 Floating point numbers' -if 12.0 + 24.0 != 36.0: raise TestFailed, 'float op' -if 12.0 + (-24.0) != -12.0: raise TestFailed, 'float op' -if (-12.0) + 24.0 != 12.0: raise TestFailed, 'float op' -if (-12.0) + (-24.0) != -36.0: raise TestFailed, 'float op' -if not 12.0 < 24.0: raise TestFailed, 'float op' -if not -24.0 < -12.0: raise TestFailed, 'float op' - -print '6.5 Sequence types' - -print '6.5.1 Strings' -if len('') != 0: raise TestFailed, 'len(\'\')' -if len('a') != 1: raise TestFailed, 'len(\'a\')' -if len('abcdef') != 6: raise TestFailed, 'len(\'abcdef\')' -if 'xyz' + 'abcde' != 'xyzabcde': raise TestFailed, 'string concatenation' -if 'xyz'*3 != 'xyzxyzxyz': raise TestFailed, 'string repetition *3' -if 0*'abcde' != '': raise TestFailed, 'string repetition 0*' -if min('abc') != 'a' or max('abc') != 'c': raise TestFailed, 'min/max string' -if 'a' in 'abc' and 'b' in 'abc' and 'c' in 'abc' and 'd' not in 'abc': pass -else: raise TestFailed, 'in/not in string' -x = 'x'*103 -if '%s!'%x != x+'!': raise TestFailed, 'nasty string formatting bug' - -#extended slices for strings -a = '0123456789' -vereq(a[::], a) -vereq(a[::2], '02468') -vereq(a[1::2], '13579') -vereq(a[::-1],'9876543210') -vereq(a[::-2], '97531') -vereq(a[3::-2], '31') -vereq(a[-100:100:], a) -vereq(a[100:-100:-1], a[::-1]) -vereq(a[-100L:100L:2L], '02468') - -if have_unicode: - a = unicode('0123456789', 'ascii') - vereq(a[::], a) - vereq(a[::2], unicode('02468', 'ascii')) - vereq(a[1::2], unicode('13579', 'ascii')) - vereq(a[::-1], unicode('9876543210', 'ascii')) - vereq(a[::-2], unicode('97531', 'ascii')) - vereq(a[3::-2], unicode('31', 'ascii')) - vereq(a[-100:100:], a) - vereq(a[100:-100:-1], a[::-1]) - vereq(a[-100L:100L:2L], unicode('02468', 'ascii')) - - -print '6.5.2 Tuples' -# calling built-in types without argument must return empty -if tuple() != (): raise TestFailed,'tuple() does not return ()' -if len(()) != 0: raise TestFailed, 'len(())' -if len((1,)) != 1: raise TestFailed, 'len((1,))' -if len((1,2,3,4,5,6)) != 6: raise TestFailed, 'len((1,2,3,4,5,6))' -if (1,2)+(3,4) != (1,2,3,4): raise TestFailed, 'tuple concatenation' -if (1,2)*3 != (1,2,1,2,1,2): raise TestFailed, 'tuple repetition *3' -if 0*(1,2,3) != (): raise TestFailed, 'tuple repetition 0*' -if min((1,2)) != 1 or max((1,2)) != 2: raise TestFailed, 'min/max tuple' -if 0 in (0,1,2) and 1 in (0,1,2) and 2 in (0,1,2) and 3 not in (0,1,2): pass -else: raise TestFailed, 'in/not in tuple' -try: ()[0] -except IndexError: pass -else: raise TestFailed, "tuple index error didn't raise IndexError" -x = () -x += () -if x != (): raise TestFailed, 'tuple inplace add from () to () failed' -x += (1,) -if x != (1,): raise TestFailed, 'tuple resize from () failed' - -# extended slicing - subscript only for tuples -a = (0,1,2,3,4) -vereq(a[::], a) -vereq(a[::2], (0,2,4)) -vereq(a[1::2], (1,3)) -vereq(a[::-1], (4,3,2,1,0)) -vereq(a[::-2], (4,2,0)) -vereq(a[3::-2], (3,1)) -vereq(a[-100:100:], a) -vereq(a[100:-100:-1], a[::-1]) -vereq(a[-100L:100L:2L], (0,2,4)) - -# Check that a specific bug in _PyTuple_Resize() is squashed. -def f(): - for i in range(1000): - yield i -vereq(list(tuple(f())), range(1000)) - -# Verify that __getitem__ overrides are not recognized by __iter__ -class T(tuple): - def __getitem__(self, key): - return str(key) + '!!!' -vereq(iter(T((1,2))).next(), 1) - -print '6.5.3 Lists' -# calling built-in types without argument must return empty -if list() != []: raise TestFailed,'list() does not return []' -if len([]) != 0: raise TestFailed, 'len([])' -if len([1,]) != 1: raise TestFailed, 'len([1,])' -if len([1,2,3,4,5,6]) != 6: raise TestFailed, 'len([1,2,3,4,5,6])' -if [1,2]+[3,4] != [1,2,3,4]: raise TestFailed, 'list concatenation' -if [1,2]*3 != [1,2,1,2,1,2]: raise TestFailed, 'list repetition *3' -if [1,2]*3L != [1,2,1,2,1,2]: raise TestFailed, 'list repetition *3L' -if 0*[1,2,3] != []: raise TestFailed, 'list repetition 0*' -if 0L*[1,2,3] != []: raise TestFailed, 'list repetition 0L*' -if min([1,2]) != 1 or max([1,2]) != 2: raise TestFailed, 'min/max list' -if 0 in [0,1,2] and 1 in [0,1,2] and 2 in [0,1,2] and 3 not in [0,1,2]: pass -else: raise TestFailed, 'in/not in list' -a = [1, 2, 3, 4, 5] -a[:-1] = a -if a != [1, 2, 3, 4, 5, 5]: - raise TestFailed, "list self-slice-assign (head)" -a = [1, 2, 3, 4, 5] -a[1:] = a -if a != [1, 1, 2, 3, 4, 5]: - raise TestFailed, "list self-slice-assign (tail)" -a = [1, 2, 3, 4, 5] -a[1:-1] = a -if a != [1, 1, 2, 3, 4, 5, 5]: - raise TestFailed, "list self-slice-assign (center)" -try: [][0] -except IndexError: pass -else: raise TestFailed, "list index error didn't raise IndexError" -try: [][0] = 5 -except IndexError: pass -else: raise TestFailed, "list assignment index error didn't raise IndexError" -try: [].pop() -except IndexError: pass -else: raise TestFailed, "empty list.pop() didn't raise IndexError" -try: [1].pop(5) -except IndexError: pass -else: raise TestFailed, "[1].pop(5) didn't raise IndexError" -try: [][0:1] = 5 -except TypeError: pass -else: raise TestFailed, "bad list slice assignment didn't raise TypeError" -try: [].extend(None) -except TypeError: pass -else: raise TestFailed, "list.extend(None) didn't raise TypeError" -a = [1, 2, 3, 4] -a *= 0 -if a != []: - raise TestFailed, "list inplace repeat" - -a = [] -a[:] = tuple(range(10)) -if a != range(10): - raise TestFailed, "assigning tuple to slice" - -print '6.5.3a Additional list operations' -a = [0,1,2,3,4] -a[0L] = 1 -a[1L] = 2 -a[2L] = 3 -if a != [1,2,3,3,4]: raise TestFailed, 'list item assignment [0L], [1L], [2L]' -a[0] = 5 -a[1] = 6 -a[2] = 7 -if a != [5,6,7,3,4]: raise TestFailed, 'list item assignment [0], [1], [2]' -a[-2L] = 88 -a[-1L] = 99 -if a != [5,6,7,88,99]: raise TestFailed, 'list item assignment [-2L], [-1L]' -a[-2] = 8 -a[-1] = 9 -if a != [5,6,7,8,9]: raise TestFailed, 'list item assignment [-2], [-1]' -a[:2] = [0,4] -a[-3:] = [] -a[1:1] = [1,2,3] -if a != [0,1,2,3,4]: raise TestFailed, 'list slice assignment' -a[ 1L : 4L] = [7,8,9] -if a != [0,7,8,9,4]: raise TestFailed, 'list slice assignment using long ints' -del a[1:4] -if a != [0,4]: raise TestFailed, 'list slice deletion' -del a[0] -if a != [4]: raise TestFailed, 'list item deletion [0]' -del a[-1] -if a != []: raise TestFailed, 'list item deletion [-1]' -a=range(0,5) -del a[1L:4L] -if a != [0,4]: raise TestFailed, 'list slice deletion' -del a[0L] -if a != [4]: raise TestFailed, 'list item deletion [0]' -del a[-1L] -if a != []: raise TestFailed, 'list item deletion [-1]' -a.append(0) -a.append(1) -a.append(2) -if a != [0,1,2]: raise TestFailed, 'list append' -a.insert(0, -2) -a.insert(1, -1) -a.insert(2,0) -if a != [-2,-1,0,0,1,2]: raise TestFailed, 'list insert' -b = a[:] -b.insert(-2, "foo") -b.insert(-200, "left") -b.insert(200, "right") -if b != ["left",-2,-1,0,0,"foo",1,2,"right"]: raise TestFailed, 'list insert2' -# a = [-2,-1,0,0,1,2] -if a.count(0) != 2: raise TestFailed, ' list count' -if a.index(0) != 2: raise TestFailed, 'list index' -if a.index(0,2) != 2: raise TestFailed, 'list index, start argument' -if a.index(0,-4) != 2: raise TestFailed, 'list index, -start argument' -if a.index(-2,-10) != 0: raise TestFailed, 'list index, very -start argument' -if a.index(0,3) != 3: raise TestFailed, 'list index, start argument' -if a.index(0,-3) != 3: raise TestFailed, 'list index, -start argument' -if a.index(0,3,4) != 3: raise TestFailed, 'list index, stop argument' -if a.index(0,-3,-2) != 3: raise TestFailed, 'list index, -stop argument' -if a.index(0,-4*sys.maxint,4*sys.maxint) != 2: - raise TestFailed, 'list index, -maxint, maxint argument' -try: - a.index(0, 4*sys.maxint,-4*sys.maxint) -except ValueError: - pass -else: - raise TestFailed, 'list index, maxint,-maxint argument' - -try: - a.index(2,0,-10) -except ValueError: - pass -else: - raise TestFailed, 'list index, very -stop argument' -a.remove(0) -try: - a.index(2,0,4) -except ValueError: - pass -else: - raise TestFailed, 'list index, stop argument.' -if a != [-2,-1,0,1,2]: raise TestFailed, 'list remove' -a.reverse() -if a != [2,1,0,-1,-2]: raise TestFailed, 'list reverse' -a.sort() -if a != [-2,-1,0,1,2]: raise TestFailed, 'list sort' -def revcmp(a, b): return cmp(b, a) -a.sort(revcmp) -if a != [2,1,0,-1,-2]: raise TestFailed, 'list sort with cmp func' -# The following dumps core in unpatched Python 1.5: -def myComparison(x,y): - return cmp(x%3, y%7) -z = range(12) -z.sort(myComparison) - -try: z.sort(2) -except TypeError: pass -else: raise TestFailed, 'list sort compare function is not callable' - -def selfmodifyingComparison(x,y): - z.append(1) - return cmp(x, y) -try: z.sort(selfmodifyingComparison) -except ValueError: pass -else: raise TestFailed, 'modifying list during sort' - -try: z.sort(lambda x, y: 's') -except TypeError: pass -else: raise TestFailed, 'list sort compare function does not return int' - -''' TODO: pow is badly broken, fix! -# Test extreme cases with long ints -a = [0,1,2,3,4] -if a[ -pow(2,128L): 3 ] != [0,1,2]: - raise TestFailed, "list slicing with too-small long integer" -if a[ 3: pow(2,145L) ] != [3,4]: - raise TestFailed, "list slicing with too-large long integer" -''' - -# extended slicing - -# subscript -a = [0,1,2,3,4] -vereq(a[::], a) -vereq(a[::2], [0,2,4]) -vereq(a[1::2], [1,3]) -vereq(a[::-1], [4,3,2,1,0]) -vereq(a[::-2], [4,2,0]) -vereq(a[3::-2], [3,1]) -vereq(a[-100:100:], a) -vereq(a[100:-100:-1], a[::-1]) -vereq(a[-100L:100L:2L], [0,2,4]) -vereq(a[1000:2000:2], []) -vereq(a[-1000:-2000:-2], []) -# deletion -del a[::2] -vereq(a, [1,3]) -a = range(5) -del a[1::2] -vereq(a, [0,2,4]) -a = range(5) -del a[1::-2] -vereq(a, [0,2,3,4]) -a = range(10) -del a[::1000] -vereq(a, [1, 2, 3, 4, 5, 6, 7, 8, 9]) -# assignment -a = range(10) -a[::2] = [-1]*5 -vereq(a, [-1, 1, -1, 3, -1, 5, -1, 7, -1, 9]) -a = range(10) -a[::-4] = [10]*3 -vereq(a, [0, 10, 2, 3, 4, 10, 6, 7, 8 ,10]) -a = range(4) -a[::-1] = a -vereq(a, [3, 2, 1, 0]) -a = range(10) -b = a[:] -c = a[:] -a[2:3] = ["two", "elements"] -b[slice(2,3)] = ["two", "elements"] -c[2:3:] = ["two", "elements"] -vereq(a, b) -vereq(a, c) -a = range(10) -a[::2] = tuple(range(5)) -vereq(a, [0, 1, 1, 3, 2, 5, 3, 7, 4, 9]) - -# Verify that __getitem__ overrides are not recognized by __iter__ -class L(list): - def __getitem__(self, key): - return str(key) + '!!!' -vereq(iter(L([1,2])).next(), 1) - - -print '6.6 Mappings == Dictionaries' -# calling built-in types without argument must return empty -if dict() != {}: raise TestFailed,'dict() does not return {}' -d = {} -if d.keys() != []: raise TestFailed, '{}.keys()' -if d.values() != []: raise TestFailed, '{}.values()' -if d.items() != []: raise TestFailed, '{}.items()' -if d.has_key('a') != 0: raise TestFailed, '{}.has_key(\'a\')' -if ('a' in d) != 0: raise TestFailed, "'a' in {}" -if ('a' not in d) != 1: raise TestFailed, "'a' not in {}" -if len(d) != 0: raise TestFailed, 'len({})' -d = {'a': 1, 'b': 2} -if len(d) != 2: raise TestFailed, 'len(dict)' -k = d.keys() -k.sort() -if k != ['a', 'b']: raise TestFailed, 'dict keys()' -if d.has_key('a') and d.has_key('b') and not d.has_key('c'): pass -else: raise TestFailed, 'dict keys()' -if 'a' in d and 'b' in d and 'c' not in d: pass -else: raise TestFailed, 'dict keys() # in/not in version' -if d['a'] != 1 or d['b'] != 2: raise TestFailed, 'dict item' -d['c'] = 3 -d['a'] = 4 -if d['c'] != 3 or d['a'] != 4: raise TestFailed, 'dict item assignment' -del d['b'] -if d != {'a': 4, 'c': 3}: raise TestFailed, 'dict item deletion' -print '6.6.1 dict methods' -# dict.clear() -d = {1:1, 2:2, 3:3} -d.clear() -if d != {}: raise TestFailed, 'dict clear' -# dict.update() -d.update({1:100}) -d.update({2:20}) -d.update({1:1, 2:2, 3:3}) -if d != {1:1, 2:2, 3:3}: raise TestFailed, 'dict update' -d.clear() -try: d.update(None) -except AttributeError: pass -else: raise TestFailed, 'dict.update(None), AttributeError expected' -print '6.6.2 user-dict methods' -class SimpleUserDict: - def __init__(self): - self.d = {1:1, 2:2, 3:3} - def keys(self): - return self.d.keys() - def __getitem__(self, i): - return self.d[i] -d.update(SimpleUserDict()) -if d != {1:1, 2:2, 3:3}: raise TestFailed, 'dict.update(instance)' -d.clear() -class FailingUserDict: - def keys(self): - raise ValueError -try: d.update(FailingUserDict()) -except ValueError: pass -else: raise TestFailed, 'dict.keys() expected ValueError' -class FailingUserDict: - def keys(self): - class BogonIter: - def __iter__(self): - raise ValueError - return BogonIter() -try: d.update(FailingUserDict()) -except ValueError: pass -else: raise TestFailed, 'iter(dict.keys()) expected ValueError' -class FailingUserDict: - def keys(self): - class BogonIter: - def __init__(self): - self.i = 1 - def __iter__(self): - return self - def next(self): - if self.i: - self.i = 0 - return 'a' - raise ValueError - return BogonIter() - def __getitem__(self, key): - return key -try: d.update(FailingUserDict()) -except ValueError: pass -else: raise TestFailed, 'iter(dict.keys()).next() expected ValueError' -class FailingUserDict: - def keys(self): - class BogonIter: - def __init__(self): - self.i = ord('a') - def __iter__(self): - return self - def next(self): - if self.i <= ord('z'): - rtn = chr(self.i) - self.i += 1 - return rtn - raise StopIteration - return BogonIter() - def __getitem__(self, key): - raise ValueError -try: d.update(FailingUserDict()) -except ValueError: pass -else: raise TestFailed, 'dict.update(), __getitem__ expected ValueError' -print '6.6.3 dict.fromkeys' -# dict.fromkeys() -if dict.fromkeys('abc') != {'a':None, 'b':None, 'c':None}: - raise TestFailed, 'dict.fromkeys did not work as a class method' -d = {} -if d.fromkeys('abc') is d: - raise TestFailed, 'dict.fromkeys did not return a new dict' -if d.fromkeys('abc') != {'a':None, 'b':None, 'c':None}: - raise TestFailed, 'dict.fromkeys failed with default value' -if d.fromkeys((4,5),0) != {4:0, 5:0}: - raise TestFailed, 'dict.fromkeys failed with specified value' -if d.fromkeys([]) != {}: - raise TestFailed, 'dict.fromkeys failed with null sequence' -def g(): - yield 1 -if d.fromkeys(g()) != {1:None}: - raise TestFailed, 'dict.fromkeys failed with a generator' -try: {}.fromkeys(3) -except TypeError: pass -else: raise TestFailed, 'dict.fromkeys failed to raise TypeError' -class dictlike(dict): pass -if dictlike.fromkeys('a') != {'a':None}: - raise TestFailed, 'dictsubclass.fromkeys did not inherit' -if dictlike().fromkeys('a') != {'a':None}: - raise TestFailed, 'dictsubclass.fromkeys did not inherit' -if type(dictlike.fromkeys('a')) is not dictlike: - raise TestFailed, 'dictsubclass.fromkeys created wrong type' -if type(dictlike().fromkeys('a')) is not dictlike: - raise TestFailed, 'dictsubclass.fromkeys created wrong type' - -''' TODO: fromkeys not recognized as a classmethod here -from UserDict import UserDict -class mydict(dict): - def __new__(cls): - return UserDict() -ud = mydict.fromkeys('ab') -if ud != {'a':None, 'b':None} or not isinstance(ud,UserDict): - raise TestFailed, 'fromkeys did not instantiate using __new__' -''' - -print '6.6.4 dict copy, get, setdefault' - -# dict.copy() -d = {1:1, 2:2, 3:3} -if d.copy() != {1:1, 2:2, 3:3}: raise TestFailed, 'dict copy' -if {}.copy() != {}: raise TestFailed, 'empty dict copy' -# dict.get() -d = {} -if d.get('c') is not None: raise TestFailed, 'missing {} get, no 2nd arg' -if d.get('c', 3) != 3: raise TestFailed, 'missing {} get, w/ 2nd arg' -d = {'a' : 1, 'b' : 2} -if d.get('c') is not None: raise TestFailed, 'missing dict get, no 2nd arg' -if d.get('c', 3) != 3: raise TestFailed, 'missing dict get, w/ 2nd arg' -if d.get('a') != 1: raise TestFailed, 'present dict get, no 2nd arg' -if d.get('a', 3) != 1: raise TestFailed, 'present dict get, w/ 2nd arg' -# dict.setdefault() -d = {} -if d.setdefault('key0') is not None: - raise TestFailed, 'missing {} setdefault, no 2nd arg' -if d.setdefault('key0') is not None: - raise TestFailed, 'present {} setdefault, no 2nd arg' -d.setdefault('key', []).append(3) -if d['key'][0] != 3: - raise TestFailed, 'missing {} setdefault, w/ 2nd arg' -d.setdefault('key', []).append(4) -if len(d['key']) != 2: - raise TestFailed, 'present {} setdefault, w/ 2nd arg' - -print '6.6.5 dict popitem' - -# dict.popitem() -for copymode in -1, +1: - # -1: b has same structure as a - # +1: b is a.copy() - for log2size in range(12): - size = 2**log2size - a = {} - b = {} - for i in range(size): - a[`i`] = i - if copymode < 0: - b[`i`] = i - if copymode > 0: - b = a.copy() - for i in range(size): - ka, va = ta = a.popitem() - if va != int(ka): raise TestFailed, "a.popitem: %s" % str(ta) - kb, vb = tb = b.popitem() - if vb != int(kb): raise TestFailed, "b.popitem: %s" % str(tb) - if copymode < 0 and ta != tb: - raise TestFailed, "a.popitem != b.popitem: %s, %s" % ( - str(ta), str(tb)) - if a: raise TestFailed, 'a not empty after popitems: %s' % str(a) - if b: raise TestFailed, 'b not empty after popitems: %s' % str(b) - -d.clear() -try: d.popitem() -except KeyError: pass -else: raise TestFailed, "{}.popitem doesn't raise KeyError" - -print '6.6.6 dict pop' - -# Tests for pop with specified key -d.clear() -k, v = 'abc', 'def' -d[k] = v -try: d.pop('ghi') -except KeyError: pass -else: raise TestFailed, "{}.pop(k) doesn't raise KeyError when k not in dictionary" - -if d.pop(k) != v: raise TestFailed, "{}.pop(k) doesn't find known key/value pair" -if len(d) > 0: raise TestFailed, "{}.pop(k) failed to remove the specified pair" - -try: d.pop(k) -except KeyError: pass -else: raise TestFailed, "{}.pop(k) doesn't raise KeyError when dictionary is empty" - -# verify longs/ints get same value when key > 32 bits (for 64-bit archs) -# see SF bug #689659 -x = 4503599627370496L -y = 4503599627370496 -h = {x: 'anything', y: 'something else'} -if h[x] != h[y]: - raise TestFailed, "long/int key should match" - -if d.pop(k, v) != v: raise TestFailed, "{}.pop(k, v) doesn't return default value" -d[k] = v -if d.pop(k, 1) != v: raise TestFailed, "{}.pop(k, v) doesn't find known key/value pair" - -''' TODO: doesn't raise correctly -d[1] = 1 -try: - for i in d: - d[i+1] = 1 -except RuntimeError: - pass -else: - raise TestFailed, "changing dict size during iteration doesn't raise Error" -''' - -print '6.7 type' - -try: type(1, 2) -except TypeError: pass -else: raise TestFailed, 'type(), w/2 args expected TypeError' - -try: type(1, 2, 3, 4) -except TypeError: pass -else: raise TestFailed, 'type(), w/4 args expected TypeError' - -print '6.8 buffer' - -print 'Buffers' -try: buffer('asdf', -1) -except ValueError: pass -else: raise TestFailed, "buffer('asdf', -1) should raise ValueError" - -try: buffer(None) -except TypeError: pass -else: raise TestFailed, "buffer(None) should raise TypeError" - -a = buffer('asdf') -hash(a) -b = a * 5 -if a == b: - raise TestFailed, 'buffers should not be equal' -if str(b) != ('asdf' * 5): - raise TestFailed, 'repeated buffer has wrong content' -if str(a * 0) != '': - raise TestFailed, 'repeated buffer zero times has wrong content' -if str(a + buffer('def')) != 'asdfdef': - raise TestFailed, 'concatenation of buffers yields wrong content' - -try: a[1] = 'g' -except TypeError: pass -else: raise TestFailed, "buffer assignment should raise TypeError" - -try: a[0:1] = 'g' -except TypeError: pass -else: raise TestFailed, "buffer slice assignment should raise TypeError" From arigo at codespeak.net Tue Dec 16 18:29:52 2003 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 16 Dec 2003 18:29:52 +0100 (MET) Subject: [pypy-svn] rev 2408 - pypy/trunk/src/pypy/objspace/std Message-ID: <20031216172952.6A4055A0EA@thoth.codespeak.net> Author: arigo Date: Tue Dec 16 18:29:51 2003 New Revision: 2408 Modified: pypy/trunk/src/pypy/objspace/std/floatobject.py Log: Zero division fix. Modified: pypy/trunk/src/pypy/objspace/std/floatobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/floatobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/floatobject.py Tue Dec 16 18:29:51 2003 @@ -116,6 +116,8 @@ y = w_float2.floatval try: z = x / y # XXX make sure this is the new true division + except ZeroDivisionError: + raise OperationError(space.w_ZeroDivisionError, space.wrap("float division")) except FloatingPointError: raise FailedToImplement(space.w_FloatingPointError, space.wrap("float division")) # no overflow From arigo at codespeak.net Tue Dec 16 18:40:03 2003 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 16 Dec 2003 18:40:03 +0100 (MET) Subject: [pypy-svn] rev 2409 - pypy/trunk/src/pypy/appspace Message-ID: <20031216174003.D946E5A0EA@thoth.codespeak.net> Author: arigo Date: Tue Dec 16 18:40:03 2003 New Revision: 2409 Modified: pypy/trunk/src/pypy/appspace/builtin_types_test.py Log: A few tests commented out. Modified: pypy/trunk/src/pypy/appspace/builtin_types_test.py ============================================================================== --- pypy/trunk/src/pypy/appspace/builtin_types_test.py (original) +++ pypy/trunk/src/pypy/appspace/builtin_types_test.py Tue Dec 16 18:40:03 2003 @@ -62,14 +62,17 @@ except ZeroDivisionError: pass else: raise TestFailed, "5.0 / 0.0 didn't raise ZeroDivisionError" +''' TODO try: 5.0 // 0.0 except ZeroDivisionError: pass else: raise TestFailed, "5.0 // 0.0 didn't raise ZeroDivisionError" +''' try: 5.0 % 0.0 except ZeroDivisionError: pass else: raise TestFailed, "5.0 % 0.0 didn't raise ZeroDivisionError" +''' TODO try: 5 / 0L except ZeroDivisionError: pass else: raise TestFailed, "5 / 0L didn't raise ZeroDivisionError" @@ -81,6 +84,7 @@ try: 5 % 0L except ZeroDivisionError: pass else: raise TestFailed, "5 % 0L didn't raise ZeroDivisionError" +''' print '6.4 Numeric types (mostly conversions)' if 0 != 0L or 0 != 0.0 or 0L != 0.0: raise TestFailed, 'mixed comparisons' From hpk at codespeak.net Tue Dec 16 18:49:07 2003 From: hpk at codespeak.net (hpk at codespeak.net) Date: Tue, 16 Dec 2003 18:49:07 +0100 (MET) Subject: [pypy-svn] rev 2410 - in pypy/trunk/src/pypy: interpreter interpreter/testobjspace/std Message-ID: <20031216174907.D8B645A0EA@thoth.codespeak.net> Author: hpk Date: Tue Dec 16 18:49:07 2003 New Revision: 2410 Modified: pypy/trunk/src/pypy/interpreter/function.py pypy/trunk/src/pypy/interpreter/test/test_function.py pypy/trunk/src/pypy/objspace/std/cpythonobject.py pypy/trunk/src/pypy/objspace/std/objspace.py Log: the dis.dis(dis.dis) goal works on both object spaces! (samuele, holger) Modified: pypy/trunk/src/pypy/interpreter/function.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/function.py (original) +++ pypy/trunk/src/pypy/interpreter/function.py Tue Dec 16 18:49:07 2003 @@ -189,6 +189,7 @@ space = self.space def makedict(**kw): return kw + #print "APPVISI", self.code, "INTO", space.wrap(self.code) it = makedict( func_defaults = self.defs_w and space.newtuple(self.defs_w) or space.w_None, func_code = space.wrap(self.code), Modified: pypy/trunk/src/pypy/interpreter/test/test_function.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/test/test_function.py (original) +++ pypy/trunk/src/pypy/interpreter/test/test_function.py Tue Dec 16 18:49:07 2003 @@ -17,6 +17,10 @@ self.assertEquals(f.func_doc, None) self.assertEquals(f.func_name, 'f') + def test_code_is_ok(self): + def f(): pass + self.assert_(not hasattr(f.func_code, '__dict__')) + def test_underunder_attributes(self): def f(): pass self.assertEquals(f.__name__, 'f') Modified: pypy/trunk/src/pypy/objspace/std/cpythonobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/cpythonobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/cpythonobject.py Tue Dec 16 18:49:07 2003 @@ -30,7 +30,7 @@ def cpython_unwrap(space, w_obj): cpyobj = w_obj.cpyobj - if hasattr(cpyobj, '__unwrap__'): + if hasattr(type(cpyobj), '__unwrap__'): cpyobj = cpyobj.__unwrap__() return cpyobj @@ -162,7 +162,7 @@ if f: if _arity == 1: def cpython_f(space, w_1, f=f, pypymethod='pypy_'+_name): - x1 = space.unwrap(w_1) + x1 = w_1.cpyobj type_x1 = type(x1) if hasattr(type_x1, pypymethod): return getattr(type_x1, pypymethod)(x1) @@ -173,7 +173,7 @@ return space.wrap(y) elif _arity == 2: def cpython_f(space, w_1, w_2, f=f, pypymethod='pypy_'+_name): - x1 = space.unwrap(w_1) + x1 = w_1.cpyobj type_x1 = type(x1) if hasattr(type_x1, pypymethod): return getattr(type_x1, pypymethod)(x1, w_2) @@ -187,7 +187,7 @@ return space.wrap(y) elif _arity == 3: def cpython_f(space, w_1, w_2, w_3, f=f, pypymethod='pypy_'+_name): - x1 = space.unwrap(w_1) + x1 = w_1.cpyobj type_x1 = type(x1) if hasattr(type_x1, pypymethod): return getattr(type_x1, pypymethod)(x1, w_2, w_3) Modified: pypy/trunk/src/pypy/objspace/std/objspace.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/objspace.py (original) +++ pypy/trunk/src/pypy/objspace/std/objspace.py Tue Dec 16 18:49:07 2003 @@ -202,7 +202,7 @@ return listobject.W_ListObject(self, wrappeditems) if hasattr(type(x), '__wrap__'): return x.__wrap__(self) - # print "wrapping %r (%s)" % (x, type(x)) + #print "wrapping %r (%s)" % (x, type(x)) import cpythonobject return cpythonobject.W_CPythonObject(self, x) From sschwarzer at codespeak.net Wed Dec 17 10:47:12 2003 From: sschwarzer at codespeak.net (sschwarzer at codespeak.net) Date: Wed, 17 Dec 2003 10:47:12 +0100 (MET) Subject: [pypy-svn] rev 2411 - pypy/trunk/src/pypy/tool Message-ID: <20031217094712.EC1A85A160@thoth.codespeak.net> Author: sschwarzer Date: Wed Dec 17 10:47:11 2003 New Revision: 2411 Modified: pypy/trunk/src/pypy/tool/test.py Log: In CtsTestRunner, changed wording to plain English. Modified: pypy/trunk/src/pypy/tool/test.py ============================================================================== --- pypy/trunk/src/pypy/tool/test.py (original) +++ pypy/trunk/src/pypy/tool/test.py Wed Dec 17 10:47:11 2003 @@ -63,7 +63,7 @@ class MyTextTestResult(unittest._TextTestResult): ignored = 0 - + def addError(self, test, err): from pypy.interpreter.baseobjspace import OperationError if isinstance(err[1], OperationError) and test.space.full_exceptions: @@ -136,8 +136,8 @@ self.stream.writeln(self.separator2) t1 = self._exc_info_to_string(err) t2 = '' - if isinstance(err[1], - OperationError) and test.space.full_exceptions: + if isinstance(err[1], OperationError) and \ + test.space.full_exceptions: t2 = '\nand at app-level:\n\n' sio = StringIO.StringIO() err[1].print_application_traceback(test.space, sio) @@ -199,10 +199,10 @@ new = status[m] if old != new: # print all transitions - print "%s has transitioned from %s to %s" % (m, old, new) + print "%s has changed from %s to %s" % (m, old, new) elif new != "success": # print old statuses only if they weren't successes - print "%s is still a %s" % (m, new) + print "%s remains a %s" % (m, new) # case: test was run previously but not now elif is_old and not is_new: print "%s was a %s but not run this time" % (m, oldstatus[m]) From sschwarzer at codespeak.net Wed Dec 17 10:53:35 2003 From: sschwarzer at codespeak.net (sschwarzer at codespeak.net) Date: Wed, 17 Dec 2003 10:53:35 +0100 (MET) Subject: [pypy-svn] rev 2412 - pypy/trunk/src/pypy/tool Message-ID: <20031217095335.BA9CC5A160@thoth.codespeak.net> Author: sschwarzer Date: Wed Dec 17 10:53:35 2003 New Revision: 2412 Modified: pypy/trunk/src/pypy/tool/test.py Log: Removed dead code from MyTextTestResult.interact . Modified: pypy/trunk/src/pypy/tool/test.py ============================================================================== --- pypy/trunk/src/pypy/tool/test.py (original) +++ pypy/trunk/src/pypy/tool/test.py Wed Dec 17 10:53:35 2003 @@ -97,28 +97,6 @@ c = TestPM(efs) c.cmdloop() return - def proc_input(input): - r = int(input) - if r < 0 or r >= len(efs): - raise ValueError - return r - while 1: - i = 0 - for t, e in efs: - print i, t.methodName - i += 1 - while 1: - input = raw_input('itr> ') - if not input: - return - try: - r = proc_input(input) - except ValueError: - continue - else: - break - s, (t, v, tb) = efs[r] - ppdb.post_mortem(s.space, tb, v) def printErrors(self): if Options.interactive: From sschwarzer at codespeak.net Wed Dec 17 10:55:01 2003 From: sschwarzer at codespeak.net (sschwarzer at codespeak.net) Date: Wed, 17 Dec 2003 10:55:01 +0100 (MET) Subject: [pypy-svn] rev 2413 - pypy/trunk/src/pypy/tool Message-ID: <20031217095501.07C9E5A160@thoth.codespeak.net> Author: sschwarzer Date: Wed Dec 17 10:55:00 2003 New Revision: 2413 Modified: pypy/trunk/src/pypy/tool/test.py Log: Also removed return statement in MyTextTestResult.interact . Modified: pypy/trunk/src/pypy/tool/test.py ============================================================================== --- pypy/trunk/src/pypy/tool/test.py (original) +++ pypy/trunk/src/pypy/tool/test.py Wed Dec 17 10:55:00 2003 @@ -96,7 +96,6 @@ from pypy.tool.testpm import TestPM c = TestPM(efs) c.cmdloop() - return def printErrors(self): if Options.interactive: From pmaupin at codespeak.net Wed Dec 17 11:25:58 2003 From: pmaupin at codespeak.net (pmaupin at codespeak.net) Date: Wed, 17 Dec 2003 11:25:58 +0100 (MET) Subject: [pypy-svn] rev 2415 - pypy/trunk/src/pypy/appspace Message-ID: <20031217102558.3BEBC5A160@thoth.codespeak.net> Author: pmaupin Date: Wed Dec 17 11:25:57 2003 New Revision: 2415 Modified: pypy/trunk/src/pypy/appspace/builtin_types_test.py Log: Reduce time for popitem test for now Modified: pypy/trunk/src/pypy/appspace/builtin_types_test.py ============================================================================== --- pypy/trunk/src/pypy/appspace/builtin_types_test.py (original) +++ pypy/trunk/src/pypy/appspace/builtin_types_test.py Wed Dec 17 11:25:57 2003 @@ -672,7 +672,7 @@ for copymode in -1, +1: # -1: b has same structure as a # +1: b is a.copy() - for log2size in range(12): + for log2size in range(4):#(12): size = 2**log2size a = {} b = {} From arigo at codespeak.net Wed Dec 17 11:31:38 2003 From: arigo at codespeak.net (arigo at codespeak.net) Date: Wed, 17 Dec 2003 11:31:38 +0100 (MET) Subject: [pypy-svn] rev 2416 - in pypy/trunk/src/pypy: module module/test objspace Message-ID: <20031217103138.622B85A160@thoth.codespeak.net> Author: arigo Date: Wed Dec 17 11:31:37 2003 New Revision: 2416 Added: pypy/trunk/src/pypy/module/test/test_newstyleclasses.py (contents, props changed) Modified: pypy/trunk/src/pypy/module/builtin.py pypy/trunk/src/pypy/objspace/trivial.py Log: Added staticmethod, classmethod and property. Fixed a bug in trivial.py overwriting our implementations with the built-in ones. (We should write a test for properties too.) Modified: pypy/trunk/src/pypy/module/builtin.py ============================================================================== --- pypy/trunk/src/pypy/module/builtin.py (original) +++ pypy/trunk/src/pypy/module/builtin.py Wed Dec 17 11:31:37 2003 @@ -42,6 +42,7 @@ def _initcompiledbuiltins(self): """ add 'compiled' builtins to app-level dict and interp-level """ self._eval_app_source(xrange_appsource) + self._eval_app_source(newstyleclasses) def _actframe(self, index=-1): return self.space.getexecutioncontext().framestack.items[index] @@ -673,3 +674,52 @@ return gen(self) """ +newstyleclasses = """ + +class property(object): + + def __init__(self, fget=None, fset=None, fdel=None, doc=None): + self.fget = fget + self.fset = fset + self.fdel = fdel + self.__doc__ = doc or "" + + def __get__(self, obj, objtype=None): + if obj is None: + return self + if self.fget is None: + raise AttributeError, "unreadable attribute" + return self.fget(obj) + + def __set__(self, obj, value): + if self.fset is None: + raise AttributeError, "can't set attribute" + self.fset(obj, value) + + def __delete__(self, obj): + if self.fdel is None: + raise AttributeError, "can't delete attribute" + self.fdel(obj, value) + + +class staticmethod(object): + + def __init__(self, f): + self.f = f + + def __get__(self, obj, objtype=None): + return self.f + + +class classmethod(object): + + def __init__(self, f): + self.f = f + + def __get__(self, obj, klass=None): + if klass is None: + klass = type(obj) + def newfunc(*args): + return self.f(klass, *args) + return newfunc +""" Added: pypy/trunk/src/pypy/module/test/test_newstyleclasses.py ============================================================================== --- (empty file) +++ pypy/trunk/src/pypy/module/test/test_newstyleclasses.py Wed Dec 17 11:31:37 2003 @@ -0,0 +1,41 @@ +import autopath + +from pypy.tool import test + +class TestBuiltinApp(test.AppTestCase): + def setUp(self): + self.space = test.objspace() + + def test_staticmethod(self): + class C: + def f(a, b): + return a+b + f = staticmethod(f) + class D(C): + pass + + c = C() + d = D() + self.assertEquals(c.f("abc", "def"), "abcdef") + self.assertEquals(C.f("abc", "def"), "abcdef") + self.assertEquals(d.f("abc", "def"), "abcdef") + self.assertEquals(D.f("abc", "def"), "abcdef") + + def test_classmethod(self): + class C: + def f(cls, stuff): + return cls, stuff + f = classmethod(f) + class D(C): + pass + + c = C() + d = D() + self.assertEquals(c.f("abc"), (C, "abc")) + self.assertEquals(C.f("abc"), (C, "abc")) + self.assertEquals(d.f("abc"), (D, "abc")) + self.assertEquals(D.f("abc"), (D, "abc")) + + +if __name__ == '__main__': + test.main() Modified: pypy/trunk/src/pypy/objspace/trivial.py ============================================================================== --- pypy/trunk/src/pypy/objspace/trivial.py (original) +++ pypy/trunk/src/pypy/objspace/trivial.py Wed Dec 17 11:31:37 2003 @@ -139,7 +139,8 @@ self.make_builtins() # insert these into the newly-made builtins for key, w_value in newstuff.items(): - self.setitem(self.w_builtins, self.wrap(key), w_value) + self.w_builtins.setdefault(key, w_value) + # I'm tired of wrapping correctly here -- armin # general stuff def wrap(self, x): From arigo at codespeak.net Wed Dec 17 11:52:09 2003 From: arigo at codespeak.net (arigo at codespeak.net) Date: Wed, 17 Dec 2003 11:52:09 +0100 (MET) Subject: [pypy-svn] rev 2417 - pypy/trunk/src/pypy/objspace/std Message-ID: <20031217105209.623DF5A160@thoth.codespeak.net> Author: arigo Date: Wed Dec 17 11:52:08 2003 New Revision: 2417 Modified: pypy/trunk/src/pypy/objspace/std/cpythonobject.py Log: Binary operations work with a CPythonObject at the right. Modified: pypy/trunk/src/pypy/objspace/std/cpythonobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/cpythonobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/cpythonobject.py Wed Dec 17 11:52:08 2003 @@ -206,6 +206,18 @@ multimethod = getattr(StdObjSpace, _name) multimethod.register(cpython_f, *arglist) + if len(multimethod.specialnames) > 1 and _arity == 2: + def cpython_f_rev(space, w_1, w_2, f=f): + # XXX do we really want to unwrap unknown objects here? + x1 = space.unwrap(w_1) + x2 = w_2.cpyobj + try: + y = f(x1, x2) + except: + wrap_exception(space) + return space.wrap(y) + multimethod.register(cpython_f_rev, W_ANY, W_CPythonObject) + def is_true__CPython(space, w_obj): obj = space.unwrap(w_obj) From arigo at codespeak.net Wed Dec 17 12:02:14 2003 From: arigo at codespeak.net (arigo at codespeak.net) Date: Wed, 17 Dec 2003 12:02:14 +0100 (MET) Subject: [pypy-svn] rev 2418 - in pypy/trunk/src/pypy: interpreter/test objspace tool Message-ID: <20031217110214.2210B5A160@thoth.codespeak.net> Author: arigo Date: Wed Dec 17 12:02:13 2003 New Revision: 2418 Modified: pypy/trunk/src/pypy/interpreter/test/test_code.py (props changed) pypy/trunk/src/pypy/objspace/trace.py (props changed) pypy/trunk/src/pypy/tool/dotypes.py (props changed) pypy/trunk/src/pypy/tool/modanalyze.py (contents, props changed) Log: Fixeol. Modified: pypy/trunk/src/pypy/tool/modanalyze.py ============================================================================== --- pypy/trunk/src/pypy/tool/modanalyze.py (original) +++ pypy/trunk/src/pypy/tool/modanalyze.py Wed Dec 17 12:02:13 2003 @@ -1,84 +1,84 @@ -""" - This module analyzes the delta between the attributes of a module - as seen by the PyPy interpreter, and the same module as seen by the - CPython interpreter. It can be used to help insure that pure-python - functionality as provided by PyPy matches the original functionality - provided by CPython. - - This module may be used as a standalone script, with modules to be - analyzed listed on the command line (default if none given is to - analyze __builtin__) or the moduledelta() function may be called - from other modules. When used standalone, it always analyzes - using the standard object space. - - The current implementation does not examine function signatures -- - it only shows the attributes which are exclusively in one module - or the other. - - The current implementation also may not work for non-builtin extension - modules, depending on whether there is a different path variable - inside PyPy, or whether the presence of the PyPy pure python module - will shadow the original C module, making it unavailable for comparison. -""" - -import autopath -from pypy.interpreter.gateway import app2interp -from sets import Set - -def app_getmodattributes(modname): - """ Return the attributes of the named module """ - pypy_module = __import__(modname,globals(),None,[]) - return pypy_module.__dict__.keys() - -def moduledelta(space,modname): - """ - moduledelta(space,modname) imports the module from inside - the given space, and also from CPython, and returns a tuple - (missing,extra) which describes attributes in CPython but - not in PyPy, and the opposite. - """ - - wrapped_func = app2interp(app_getmodattributes).get_function(space) - - pypy_module = wrapped_func(space.wrap(modname)) - pypy_module = space.unpackiterable(pypy_module) - pypy_module = [space.unwrap(x) for x in pypy_module] - pypy_module = Set(pypy_module) - - c_module = __import__(modname,globals(),None,[]) - c_module = Set(c_module.__dict__.keys()) | Set(['__dict__','__new__']) - diff = c_module ^ pypy_module - missing = list(diff & c_module) - extra = list(diff & pypy_module) - missing.sort() - extra.sort() - return missing,extra - -if __name__ == '__main__': - from sys import argv - from pypy.objspace.std import StdObjSpace - - def showdiff(name,stuff): - if stuff: - print - print name - for i in stuff: print " ",i - print - - modlist = argv[1:] - if not modlist: - print "modanalyze [ ...]" - print - print "Analyzing __builtin__ by default" - print - modlist = ['__builtin__'] - - print "Initializing std object space" - std = StdObjSpace() - - for modname in modlist: - print - print 'Comparing %s module' % modname - missing,extra = moduledelta(std,modname) - showdiff(" Missing from PyPy",missing) - showdiff(" Extra in PyPy",extra) +""" + This module analyzes the delta between the attributes of a module + as seen by the PyPy interpreter, and the same module as seen by the + CPython interpreter. It can be used to help insure that pure-python + functionality as provided by PyPy matches the original functionality + provided by CPython. + + This module may be used as a standalone script, with modules to be + analyzed listed on the command line (default if none given is to + analyze __builtin__) or the moduledelta() function may be called + from other modules. When used standalone, it always analyzes + using the standard object space. + + The current implementation does not examine function signatures -- + it only shows the attributes which are exclusively in one module + or the other. + + The current implementation also may not work for non-builtin extension + modules, depending on whether there is a different path variable + inside PyPy, or whether the presence of the PyPy pure python module + will shadow the original C module, making it unavailable for comparison. +""" + +import autopath +from pypy.interpreter.gateway import app2interp +from sets import Set + +def app_getmodattributes(modname): + """ Return the attributes of the named module """ + pypy_module = __import__(modname,globals(),None,[]) + return pypy_module.__dict__.keys() + +def moduledelta(space,modname): + """ + moduledelta(space,modname) imports the module from inside + the given space, and also from CPython, and returns a tuple + (missing,extra) which describes attributes in CPython but + not in PyPy, and the opposite. + """ + + wrapped_func = app2interp(app_getmodattributes).get_function(space) + + pypy_module = wrapped_func(space.wrap(modname)) + pypy_module = space.unpackiterable(pypy_module) + pypy_module = [space.unwrap(x) for x in pypy_module] + pypy_module = Set(pypy_module) + + c_module = __import__(modname,globals(),None,[]) + c_module = Set(c_module.__dict__.keys()) | Set(['__dict__','__new__']) + diff = c_module ^ pypy_module + missing = list(diff & c_module) + extra = list(diff & pypy_module) + missing.sort() + extra.sort() + return missing,extra + +if __name__ == '__main__': + from sys import argv + from pypy.objspace.std import StdObjSpace + + def showdiff(name,stuff): + if stuff: + print + print name + for i in stuff: print " ",i + print + + modlist = argv[1:] + if not modlist: + print "modanalyze [ ...]" + print + print "Analyzing __builtin__ by default" + print + modlist = ['__builtin__'] + + print "Initializing std object space" + std = StdObjSpace() + + for modname in modlist: + print + print 'Comparing %s module' % modname + missing,extra = moduledelta(std,modname) + showdiff(" Missing from PyPy",missing) + showdiff(" Extra in PyPy",extra) From pmaupin at codespeak.net Wed Dec 17 12:09:00 2003 From: pmaupin at codespeak.net (pmaupin at codespeak.net) Date: Wed, 17 Dec 2003 12:09:00 +0100 (MET) Subject: [pypy-svn] rev 2419 - pypy/trunk/src/pypy/interpreter Message-ID: <20031217110900.048735A164@thoth.codespeak.net> Author: pmaupin Date: Wed Dec 17 12:09:00 2003 New Revision: 2419 Modified: pypy/trunk/src/pypy/interpreter/extmodule.py Log: Private leakage hack Modified: pypy/trunk/src/pypy/interpreter/extmodule.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/extmodule.py (original) +++ pypy/trunk/src/pypy/interpreter/extmodule.py Wed Dec 17 12:09:00 2003 @@ -26,6 +26,11 @@ value = cls.__dict__[name] if isinstance(value, gateway.Gateway): name = value.name + # This hack allows a "leakage" of a private + # module function (starts off prefixed with + # 'private_'; ends up prefixed with '_') + if name.startswith('private_'): + name = name[7:] value = value.__get__(self) # get a Method elif hasattr(value, '__get__'): continue # ignore CPython functions From sschwarzer at codespeak.net Wed Dec 17 12:20:37 2003 From: sschwarzer at codespeak.net (sschwarzer at codespeak.net) Date: Wed, 17 Dec 2003 12:20:37 +0100 (MET) Subject: [pypy-svn] rev 2420 - pypy/trunk/src/pypy/tool Message-ID: <20031217112037.2CF615A164@thoth.codespeak.net> Author: sschwarzer Date: Wed Dec 17 12:20:36 2003 New Revision: 2420 Modified: pypy/trunk/src/pypy/tool/test.py Log: Renamed method __methodname to _methodname in CtsTestRunner. Added some comments. Did several small changes. Modified: pypy/trunk/src/pypy/tool/test.py ============================================================================== --- pypy/trunk/src/pypy/tool/test.py (original) +++ pypy/trunk/src/pypy/tool/test.py Wed Dec 17 12:20:36 2003 @@ -1,5 +1,6 @@ import autopath import os, sys, unittest, re, warnings, unittest, traceback, StringIO +import fnmatch from unittest import TestCase, TestLoader import pypy.interpreter.unittest_w @@ -124,7 +125,7 @@ class CtsTestRunner: - def __methodname(self, result): + def _methodname(self, result): "Return a normalized form of the method name for result." # use private method, id() is not enough for us return "%s.%s" % (result.__class__.__name__, @@ -132,7 +133,6 @@ def run(self, test): import pickle - import cStringIO as StringIO result = MyTestResult() try: @@ -149,16 +149,16 @@ else: oldstatus = {} - # store status from this run in a dictionary named status + # store status from this run status = {} for e in result.errors: - name = self.__methodname(e[0]) + name = self._methodname(e[0]) status[name] = 'ERROR' for f in result.failures: - name = self.__methodname(f[0]) + name = self._methodname(f[0]) status[name] = 'FAILURE' for s in result.successes: - name = self.__methodname(s) + name = self._methodname(s) status[name] = 'success' # compare statuses from previous and this run @@ -208,21 +208,21 @@ def testsuite_from_main(): - """ return test modules from __main__ - """ + """Return test modules from __main__.""" loader = unittest.TestLoader() m = __import__('__main__') return loader.loadTestsFromModule(m) def testsuite_from_dir(root, filterfunc=None, recursive=0, loader=None): - """ return test modules that optionally match filterfunc. + """ + Return test modules that optionally match filterfunc. - all files matching the glob-pattern "test_*.py" are considered. - additionally their fully qualified python module path has + All files matching the glob-pattern "test_*.py" are considered. + Additionally, their fully qualified python module path has to be accepted by filterfunc (if it is not None). """ - if Options.verbose>2: - print >>sys.stderr, "scanning for test files in", root + if Options.verbose > 2: + print >> sys.stderr, "scanning for test files in", root if loader is None: loader = unittest.TestLoader() @@ -233,21 +233,22 @@ names = os.listdir(root) names.sort() for fn in names: + # ignore "hidden" files if fn.startswith('.'): continue fullfn = os.path.join(root, fn) - if os.path.isfile(fullfn) and \ - fn.startswith('test_') and \ - fn.endswith('.py'): + if os.path.isfile(fullfn) and fnmatch.fnmatch(fn, 'test_*.py'): + # strip the leading pypy directory and the .py suffix modpath = fullfn[len(autopath.pypydir)+1:-3] modpath = 'pypy.' + modpath.replace(os.sep, '.') - if not filterfunc or filterfunc(modpath): + if (filterfunc is None) or filterfunc(modpath): try: subsuite = loader.loadTestsFromName(modpath) except: print "skipping testfile (failed loading it)", modpath else: suite.addTest(subsuite, modpath) + # possibly, collect tests from subdirectories recursively elif recursive and os.path.isdir(fullfn): subsuite = testsuite_from_dir(fullfn, filterfunc, 1, loader) if subsuite: @@ -277,17 +278,17 @@ class RegexFilterFunc: - """ stateful function to filter included/excluded strings via - a Regular Expression. + """ + Stateful function to filter included/excluded strings via + a regular expression. An 'excluded' regular expressions has a '%' prependend. """ - def __init__(self, *regex): self.exclude = [] self.include = [] for x in regex: - if x[:1]=='%': + if x.startswith('%'): self.exclude.append(re.compile(x[1:]).search) else: self.include.append(re.compile(x).search) @@ -324,7 +325,7 @@ run_tests_on_space(suite, spacename) def run_tests_on_space(suite, spacename=''): - """ run the suite on the given space """ + """Run the suite on the given space.""" if Options.runcts: runner = CtsTestRunner() # verbosity=Options.verbose+1) else: @@ -338,8 +339,10 @@ runner.run(suite) def main(root=None): - """ run this to test everything in the __main__ or - in the given root-directory (recursive)""" + """ + Test everything in the __main__ or in the given root + directory (recursive). + """ args = option.process_options(get_test_options(), Options) filterfunc = RegexFilterFunc(*args) From arigo at codespeak.net Wed Dec 17 12:23:10 2003 From: arigo at codespeak.net (arigo at codespeak.net) Date: Wed, 17 Dec 2003 12:23:10 +0100 (MET) Subject: [pypy-svn] rev 2421 - pypy/trunk/src/pypy/objspace/std Message-ID: <20031217112310.6024F5A164@thoth.codespeak.net> Author: arigo Date: Wed Dec 17 12:23:09 2003 New Revision: 2421 Modified: pypy/trunk/src/pypy/objspace/std/objspace.py Log: Fix (?) multimethod delegation order to make " 0 == 0.0 " work. Modified: pypy/trunk/src/pypy/objspace/std/objspace.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/objspace.py (original) +++ pypy/trunk/src/pypy/objspace/std/objspace.py Wed Dec 17 12:23:09 2003 @@ -20,10 +20,10 @@ MultiMethod.BASE_TYPE_OBJECT = W_AbstractTypeObject # delegation priorities -PRIORITY_SAME_TYPE = 2 # converting between several impls of the same type -PRIORITY_PARENT_TYPE = 1 # converting to a base type (e.g. bool -> int) +PRIORITY_SAME_TYPE = 3 # converting between several impls of the same type +PRIORITY_PARENT_TYPE = 2 # converting to a base type (e.g. bool -> int) +PRIORITY_CHANGE_TYPE = 1 # changing type altogether (e.g. int -> float) PRIORITY_PARENT_IMPL = 0 # hard-wired in multimethod.py -PRIORITY_CHANGE_TYPE = -1 # changing type altogether (e.g. int -> float) def registerimplementation(implcls): # this function should ultimately register the implementation class somewhere From pmaupin at codespeak.net Wed Dec 17 12:31:38 2003 From: pmaupin at codespeak.net (pmaupin at codespeak.net) Date: Wed, 17 Dec 2003 12:31:38 +0100 (MET) Subject: [pypy-svn] rev 2422 - pypy/trunk/src/pypy/module/test Message-ID: <20031217113138.C88A55A164@thoth.codespeak.net> Author: pmaupin Date: Wed Dec 17 12:31:38 2003 New Revision: 2422 Modified: pypy/trunk/src/pypy/module/test/test_builtin.py Log: Added test_globals Modified: pypy/trunk/src/pypy/module/test/test_builtin.py ============================================================================== --- pypy/trunk/src/pypy/module/test/test_builtin.py (original) +++ pypy/trunk/src/pypy/module/test/test_builtin.py Wed Dec 17 12:31:38 2003 @@ -16,6 +16,15 @@ self.assertRaises(ValueError, chr, -1) self.assertRaises(TypeError, chr, 'a') + def test_globals(self): + d = {"foo":"bar"} + exec "def f(): return globals()" in d + d2 = d["f"]() + self.assertEquals(d2.keys(),d.keys()) + # repr() on recursive containers currently fails + #self.assertEquals(d2,d) + self.assertEquals(d==d2,1) + def test_locals(self): def f(): return locals() From pmaupin at codespeak.net Wed Dec 17 12:33:00 2003 From: pmaupin at codespeak.net (pmaupin at codespeak.net) Date: Wed, 17 Dec 2003 12:33:00 +0100 (MET) Subject: [pypy-svn] rev 2423 - pypy/trunk/src/pypy/module Message-ID: <20031217113300.BD8A65A164@thoth.codespeak.net> Author: pmaupin Date: Wed Dec 17 12:33:00 2003 New Revision: 2423 Modified: pypy/trunk/src/pypy/module/builtin.py Log: Leak caller_globals() with a leading underscore Modified: pypy/trunk/src/pypy/module/builtin.py ============================================================================== --- pypy/trunk/src/pypy/module/builtin.py (original) +++ pypy/trunk/src/pypy/module/builtin.py Wed Dec 17 12:33:00 2003 @@ -50,7 +50,8 @@ def globals(self): return self._actframe().w_globals - def caller_locals(self): + def private_caller_locals(self): + #print self.__dict__.keys() return self._actframe(-2).getdictscope() def locals(self): @@ -542,7 +543,7 @@ called with no argument, return the variables bound in local scope.""" if len(obj) == 0: - return caller_locals() + return _caller_locals() elif len(obj) != 1: raise TypeError, "vars() takes at most 1 argument." else: @@ -607,7 +608,7 @@ raise TypeError("dir expected at most 1 arguments, got %d" % len(args)) if len(args) == 0: - local_names = self.caller_locals().keys() # 2 stackframes away + local_names = _caller_locals().keys() # 2 stackframes away local_names.sort() return local_names From hpk at codespeak.net Wed Dec 17 12:41:57 2003 From: hpk at codespeak.net (hpk at codespeak.net) Date: Wed, 17 Dec 2003 12:41:57 +0100 (MET) Subject: [pypy-svn] rev 2424 - pypy/trunk/src/pypy/objspace/std Message-ID: <20031217114157.714D35A164@thoth.codespeak.net> Author: hpk Date: Wed Dec 17 12:41:56 2003 New Revision: 2424 Modified: pypy/trunk/src/pypy/objspace/std/dictobject.py Log: shortcut for dict-eq comparison (going over is) Modified: pypy/trunk/src/pypy/objspace/std/dictobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/dictobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/dictobject.py Wed Dec 17 12:41:56 2003 @@ -142,6 +142,9 @@ return iterobject.W_SeqIterObject(space, w_keys) def eq__Dict_Dict(space, w_left, w_right): + if space.is_true(space.is_(w_left, w_right)): + return space.w_True + dataleft = w_left.non_empties() dataright = w_right.non_empties() if len(dataleft) != len(dataright): From jacob at codespeak.net Wed Dec 17 12:42:53 2003 From: jacob at codespeak.net (jacob at codespeak.net) Date: Wed, 17 Dec 2003 12:42:53 +0100 (MET) Subject: [pypy-svn] rev 2425 - in pypy/trunk/src/pypy/objspace/std: . test Message-ID: <20031217114253.F0A485A164@thoth.codespeak.net> Author: jacob Date: Wed Dec 17 12:42:53 2003 New Revision: 2425 Modified: pypy/trunk/src/pypy/objspace/std/intobject.py pypy/trunk/src/pypy/objspace/std/test/test_intobject.py Log: Changed all integer multimethods to use the new registration protocol. Fixed 2 naming bugs in the tests. Modified: pypy/trunk/src/pypy/objspace/std/intobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/intobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/intobject.py Wed Dec 17 12:42:53 2003 @@ -41,21 +41,15 @@ print """ -def int_unwrap(space, w_int1): - return w_int1.intval +def unwrap__Int(space, w_int1): + return int(w_int1.intval) -StdObjSpace.unwrap.register(int_unwrap, W_IntObject) - -def int_repr(space, w_int1): +def repr__Int(space, w_int1): a = w_int1.intval res = "%ld" % a return space.wrap(res) -StdObjSpace.repr.register(int_repr, W_IntObject) - -int_str = int_repr - -StdObjSpace.str.register(int_str, W_IntObject) +str__Int = repr__Int ## deprecated ## we are going to support rich compare, only @@ -73,45 +67,39 @@ ## ##StdObjSpace.cmp.register(int_int_cmp, W_IntObject, W_IntObject) -def int_int_lt(space, w_int1, w_int2): +def lt__Int_Int(space, w_int1, w_int2): i = w_int1.intval j = w_int2.intval return space.newbool( i < j ) -StdObjSpace.lt.register(int_int_lt, W_IntObject, W_IntObject) -def int_int_le(space, w_int1, w_int2): +def le__Int_Int(space, w_int1, w_int2): i = w_int1.intval j = w_int2.intval return space.newbool( i <= j ) -StdObjSpace.le.register(int_int_le, W_IntObject, W_IntObject) -def int_int_eq(space, w_int1, w_int2): +def eq__Int_Int(space, w_int1, w_int2): i = w_int1.intval j = w_int2.intval return space.newbool( i == j ) -StdObjSpace.eq.register(int_int_eq, W_IntObject, W_IntObject) -def int_int_ne(space, w_int1, w_int2): +def ne__Int_Int(space, w_int1, w_int2): i = w_int1.intval j = w_int2.intval return space.newbool( i != j ) -StdObjSpace.ne.register(int_int_ne, W_IntObject, W_IntObject) -def int_int_gt(space, w_int1, w_int2): +def gt__Int_Int(space, w_int1, w_int2): i = w_int1.intval j = w_int2.intval return space.newbool( i > j ) -StdObjSpace.gt.register(int_int_gt, W_IntObject, W_IntObject) -def int_int_ge(space, w_int1, w_int2): +def ge__Int_Int(space, w_int1, w_int2): i = w_int1.intval j = w_int2.intval return space.newbool( i >= j ) -StdObjSpace.ge.register(int_int_ge, W_IntObject, W_IntObject) STRICT_HASH = True # temporary, to be put elsewhere or removed -def int_hash_strict(space, w_int1): +def _hash_strict(space, w_int1): #/* XXX If this is changed, you also need to change the way # Python's long, float and complex types are hashed. */ x = w_int1.intval @@ -119,7 +107,7 @@ x = -2 return W_IntObject(space, x) -def int_hash_liberal(space, w_int1): +def _hash_liberal(space, w_int1): # Armin: unlike CPython we have no need to special-case the value -1 return w_int1 @@ -129,14 +117,13 @@ # and we might think of some config options # or decide to drop compatibility (using pypy-dev). -if STRICT_HASH: - int_hash = int_hash_strict -else: - int_hash = int_hash_liberal - -StdObjSpace.hash.register(int_hash, W_IntObject) +def hash__Int(space, w_int1): + if STRICT_HASH: + return _hash_strict(space, w_int1) + else: + return _hash_liberal(space, w_int1) -def int_int_add(space, w_int1, w_int2): +def add__Int_Int(space, w_int1, w_int2): x = w_int1.intval y = w_int2.intval try: @@ -146,9 +133,7 @@ space.wrap("integer addition")) return W_IntObject(space, z) -StdObjSpace.add.register(int_int_add, W_IntObject, W_IntObject) - -def int_int_sub(space, w_int1, w_int2): +def sub__Int_Int(space, w_int1, w_int2): x = w_int1.intval y = w_int2.intval try: @@ -158,9 +143,7 @@ space.wrap("integer substraction")) return W_IntObject(space, z) -StdObjSpace.sub.register(int_int_sub, W_IntObject, W_IntObject) - -def int_int_mul(space, w_int1, w_int2): +def mul__Int_Int(space, w_int1, w_int2): x = w_int1.intval y = w_int2.intval try: @@ -170,9 +153,7 @@ space.wrap("integer multiplication")) return W_IntObject(space, z) -StdObjSpace.mul.register(int_int_mul, W_IntObject, W_IntObject) - -def int_int_floordiv(space, w_int1, w_int2): +def _floordiv(space, w_int1, w_int2): x = w_int1.intval y = w_int2.intval try: @@ -185,16 +166,12 @@ space.wrap("integer division")) return W_IntObject(space, z) -StdObjSpace.floordiv.register(int_int_floordiv, W_IntObject, W_IntObject) - -def int_int_truediv(space, w_int1, w_int2): +def _truediv(space, w_int1, w_int2): # cannot implement, since it gives floats raise FailedToImplement(space.w_OverflowError, space.wrap("integer division")) -StdObjSpace.truediv.register(int_int_truediv, W_IntObject, W_IntObject) - -def int_int_mod(space, w_int1, w_int2): +def mod__Int_Int(space, w_int1, w_int2): x = w_int1.intval y = w_int2.intval try: @@ -207,9 +184,7 @@ space.wrap("integer modulo")) return W_IntObject(space, z) -StdObjSpace.mod.register(int_int_mod, W_IntObject, W_IntObject) - -def int_int_divmod(space, w_int1, w_int2): +def divmod__Int_Int(space, w_int1, w_int2): x = w_int1.intval y = w_int2.intval try: @@ -224,18 +199,14 @@ m = x % y return space.wrap((z,m)) -StdObjSpace.divmod.register(int_int_divmod, W_IntObject, W_IntObject) - -## install the proper int_int_div -if 1 / 2 == 1 // 2: - int_int_div = int_int_floordiv -else: - int_int_div = int_int_truediv - -StdObjSpace.div.register(int_int_div, W_IntObject, W_IntObject) +def div__Int_Int(space, w_int1, w_int2): + # Select the proper div + if 1 / 2 == 1 // 2: + return _floordiv(space, w_int1, w_int2) + else: + return _truediv(space, w_int1, w_int2) # helper for pow() - def _impl_int_int_pow(space, iv, iw, iz=None): if iw < 0: if iz is not None: @@ -270,24 +241,20 @@ space.wrap("integer exponentiation")) return ix -def int_int_int_pow(space, w_int1, w_int2, w_int3): +def pow__Int_Int_Int(space, w_int1, w_int2, w_int3): x = w_int1.intval y = w_int2.intval z = w_int3.intval ret = _impl_int_int_pow(space, x, y, z) return W_IntObject(space, ret) -StdObjSpace.pow.register(int_int_int_pow, W_IntObject, W_IntObject, W_IntObject) - -def int_int_none_pow(space, w_int1, w_int2, w_none=None): +def pow__Int_Int_None(space, w_int1, w_int2, w_none=None): x = w_int1.intval y = w_int2.intval ret = _impl_int_int_pow(space, x, y) return W_IntObject(space, ret) -StdObjSpace.pow.register(int_int_none_pow, W_IntObject, W_IntObject, W_NoneObject) - -def int_neg(space, w_int1): +def neg__Int(space, w_int1): a = w_int1.intval try: x = -a @@ -296,49 +263,39 @@ space.wrap("integer negation")) return W_IntObject(space, x) -StdObjSpace.neg.register(int_neg, W_IntObject) - -# int_pos is supposed to do nothing, unless it has +# pos__Int is supposed to do nothing, unless it has # a derived integer object, where it should return # an exact one. -def int_pos(space, w_int1): +def pos__Int(space, w_int1): #not sure if this should be done this way: if w_int1.__class__ is W_IntObject: return w_int1 a = w_int1.intval return W_IntObject(space, a) -StdObjSpace.pos.register(int_pos, W_IntObject) - -def int_abs(space, w_int1): +def abs__Int(space, w_int1): if w_int1.intval >= 0: - return int_pos(space, w_int1) + return pos__Int(space, w_int1) else: - return int_neg(space, w_int1) + return neg__Int(space, w_int1) -StdObjSpace.abs.register(int_abs, W_IntObject) - -def int_is_true(space, w_int1): +def is_true__Int(space, w_int1): ''' note: this must return an UNWRAPPED bool!!! ''' return w_int1.intval != 0 -StdObjSpace.is_true.register(int_is_true, W_IntObject) - -def int_invert(space, w_int1): +def invert__Int(space, w_int1): x = w_int1.intval a = ~x return W_IntObject(space, a) -StdObjSpace.invert.register(int_invert, W_IntObject) - -def int_int_lshift(space, w_int1, w_int2): +def lshift__Int_Int(space, w_int1, w_int2): a = w_int1.intval b = w_int2.intval if b < 0: raise OperationError(space.w_ValueError, space.wrap("negative shift count")) if a == 0 or b == 0: - return int_pos(w_int1) + return Int_pos(w_int1) if b >= LONG_BIT: raise FailedToImplement(space.w_OverflowError, space.wrap("integer left shift")) @@ -358,16 +315,14 @@ space.wrap("integer left shift")) return W_IntObject(space, c) -StdObjSpace.lshift.register(int_int_lshift, W_IntObject, W_IntObject) - -def int_int_rshift(space, w_int1, w_int2): +def rshift__Int_Int(space, w_int1, w_int2): a = w_int1.intval b = w_int2.intval if b < 0: raise OperationError(space.w_ValueError, space.wrap("negative shift count")) if a == 0 or b == 0: - return int_pos(w_int1) + return Int_pos(w_int1) if b >= LONG_BIT: if a < 0: a = -1 @@ -379,36 +334,28 @@ a = a >> b return W_IntObject(space, a) -StdObjSpace.rshift.register(int_int_rshift, W_IntObject, W_IntObject) - -def int_int_and(space, w_int1, w_int2): +def and__Int_Int(space, w_int1, w_int2): a = w_int1.intval b = w_int2.intval res = a & b return W_IntObject(space, res) -StdObjSpace.and_.register(int_int_and, W_IntObject, W_IntObject) - -def int_int_xor(space, w_int1, w_int2): +def xor__Int_Int(space, w_int1, w_int2): a = w_int1.intval b = w_int2.intval res = a ^ b return W_IntObject(space, res) -StdObjSpace.xor.register(int_int_xor, W_IntObject, W_IntObject) - -def int_int_or(space, w_int1, w_int2): +def or__Int_Int(space, w_int1, w_int2): a = w_int1.intval b = w_int2.intval res = a | b return W_IntObject(space, res) -StdObjSpace.or_.register(int_int_or, W_IntObject, W_IntObject) - # coerce is not wanted ## ##static int -##int_coerce(PyObject **pv, PyObject **pw) +##coerce__Int(PyObject **pv, PyObject **pw) ##{ ## if (PyInt_Check(*pw)) { ## Py_INCREF(*pv); @@ -418,26 +365,23 @@ ## return 1; /* Can't do it */ ##} -def int_int(space, w_int1): +def int__Int(space, w_int1): return w_int1 -StdObjSpace.int.register(int_int, W_IntObject) - -def int_long(space, w_int1): +""" +# Not registered +def long__Int(space, w_int1): a = w_int1.intval x = long(a) ## XXX should this really be done so? return space.newlong(x) +""" -#?StdObjSpace.long.register(int_long, W_IntObject) - -def int_float(space, w_int1): +def float__Int(space, w_int1): a = w_int1.intval x = float(a) return space.newfloat(x) -StdObjSpace.float.register(int_float, W_IntObject) - -def int_oct(space, w_int1): +def oct__Int(space, w_int1): x = w_int1.intval if x < 0: ## XXX what about this warning? @@ -452,9 +396,7 @@ ret = "0%lo" % x return space.wrap(ret) -StdObjSpace.oct.register(int_oct, W_IntObject) - -def int_hex(space, w_int1): +def hex__Int(space, w_int1): x = w_int1.intval if x < 0: ## XXX what about this warning? @@ -469,4 +411,4 @@ ret = "0x%lx" % x return space.wrap(ret) -StdObjSpace.hex.register(int_hex, W_IntObject) +register_all(vars()) Modified: pypy/trunk/src/pypy/objspace/std/test/test_intobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/test/test_intobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/test/test_intobject.py Wed Dec 17 12:42:53 2003 @@ -34,19 +34,19 @@ def test_repr(self): x = 1 f1 = iobj.W_IntObject(self.space, x) - result = iobj.int_repr(self.space, f1) + result = iobj.repr__Int(self.space, f1) self.assertEquals(self.space.unwrap(result), repr(x)) def test_str(self): x = 12345 f1 = iobj.W_IntObject(self.space, x) - result = iobj.int_str(self.space, f1) + result = iobj.str__Int(self.space, f1) self.assertEquals(self.space.unwrap(result), str(x)) def test_hash(self): x = 42 f1 = iobj.W_IntObject(self.space, x) - result = iobj.int_hash(self.space, f1) + result = iobj.hash__Int(self.space, f1) self.assertEquals(result.intval, hash(x)) def test_compare(self): @@ -58,7 +58,7 @@ wx = iobj.W_IntObject(self.space, x) wy = iobj.W_IntObject(self.space, y) res = getattr(operator, op)(x, y) - method = getattr(iobj, 'int_int_%s' % op) + method = getattr(iobj, '%s__Int_Int' % op) myres = method(self.space, wx, wy) self.assertEquals(self.space.unwrap(myres), res) @@ -67,28 +67,28 @@ y = 2 f1 = iobj.W_IntObject(self.space, x) f2 = iobj.W_IntObject(self.space, y) - result = iobj.int_int_add(self.space, f1, f2) + result = iobj.add__Int_Int(self.space, f1, f2) self.assertEquals(result.intval, x+y) x = sys.maxint y = 1 f1 = iobj.W_IntObject(self.space, x) f2 = iobj.W_IntObject(self.space, y) self.assertEquals(self.space.w_OverflowError, - self._unwrap_nonimpl(iobj.int_int_add, self.space, f1, f2)) + self._unwrap_nonimpl(iobj.add__Int_Int, self.space, f1, f2)) def test_sub(self): x = 1 y = 2 f1 = iobj.W_IntObject(self.space, x) f2 = iobj.W_IntObject(self.space, y) - result = iobj.int_int_sub(self.space, f1, f2) + result = iobj.sub__Int_Int(self.space, f1, f2) self.assertEquals(result.intval, x-y) x = sys.maxint y = -1 f1 = iobj.W_IntObject(self.space, x) f2 = iobj.W_IntObject(self.space, y) self.assertEquals(self.space.w_OverflowError, - self._unwrap_nonimpl(iobj.int_int_sub, self.space, f1, f2)) + self._unwrap_nonimpl(iobj.sub__Int_Int, self.space, f1, f2)) def test_mul(self): @@ -96,14 +96,14 @@ y = 3 f1 = iobj.W_IntObject(self.space, x) f2 = iobj.W_IntObject(self.space, y) - result = iobj.int_int_mul(self.space, f1, f2) + result = iobj.mul__Int_Int(self.space, f1, f2) self.assertEquals(result.intval, x*y) x = -sys.maxint-1 y = -1 f1 = iobj.W_IntObject(self.space, x) f2 = iobj.W_IntObject(self.space, y) self.assertEquals(self.space.w_OverflowError, - self._unwrap_nonimpl(iobj.int_int_mul, self.space, f1, f2)) + self._unwrap_nonimpl(iobj.mul__Int_Int, self.space, f1, f2)) def test_div(self): @@ -111,21 +111,21 @@ res = i//3 f1 = iobj.W_IntObject(self.space, i) f2 = iobj.W_IntObject(self.space, 3) - result = iobj.int_int_div(self.space, f1, f2) + result = iobj.div__Int_Int(self.space, f1, f2) self.assertEquals(result.intval, res) x = -sys.maxint-1 y = -1 f1 = iobj.W_IntObject(self.space, x) f2 = iobj.W_IntObject(self.space, y) self.assertEquals(self.space.w_OverflowError, - self._unwrap_nonimpl(iobj.int_int_div, self.space, f1, f2)) + self._unwrap_nonimpl(iobj.div__Int_Int, self.space, f1, f2)) def test_mod(self): x = 1 y = 2 f1 = iobj.W_IntObject(self.space, x) f2 = iobj.W_IntObject(self.space, y) - v = iobj.int_int_mod(self.space, f1, f2) + v = iobj.mod__Int_Int(self.space, f1, f2) self.assertEquals(v.intval, x % y) # not that mod cannot overflow @@ -134,7 +134,7 @@ y = 2 f1 = iobj.W_IntObject(self.space, x) f2 = iobj.W_IntObject(self.space, y) - ret = iobj.int_int_divmod(self.space, f1, f2) + ret = iobj.divmod__Int_Int(self.space, f1, f2) v, w = self.space.unwrap(ret) self.assertEquals((v, w), divmod(x, y)) x = -sys.maxint-1 @@ -142,7 +142,7 @@ f1 = iobj.W_IntObject(self.space, x) f2 = iobj.W_IntObject(self.space, y) self.assertEquals(self.space.w_OverflowError, - self._unwrap_nonimpl(iobj.int_int_divmod, self.space, f1, f2)) + self._unwrap_nonimpl(iobj.divmod__Int_Int, self.space, f1, f2)) def test_pow_iii(self): x = 10 @@ -151,15 +151,15 @@ f1 = iobj.W_IntObject(self.space, x) f2 = iobj.W_IntObject(self.space, y) f3 = iobj.W_IntObject(self.space, z) - v = iobj.int_int_int_pow(self.space, f1, f2, f3) + v = iobj.pow__Int_Int_Int(self.space, f1, f2, f3) self.assertEquals(v.intval, pow(x, y, z)) f1, f2, f3 = [iobj.W_IntObject(self.space, i) for i in (10, -1, 42)] self.assertRaises_w(self.space.w_TypeError, - iobj.int_int_int_pow, + iobj.pow__Int_Int_Int, self.space, f1, f2, f3) f1, f2, f3 = [iobj.W_IntObject(self.space, i) for i in (10, 5, 0)] self.assertRaises_w(self.space.w_ValueError, - iobj.int_int_int_pow, + iobj.pow__Int_Int_Int, self.space, f1, f2, f3) def test_pow_iin(self): @@ -167,49 +167,49 @@ y = 2 f1 = iobj.W_IntObject(self.space, x) f2 = iobj.W_IntObject(self.space, y) - v = iobj.int_int_none_pow(self.space, f1, f2) + v = iobj.pow__Int_Int_None(self.space, f1, f2) self.assertEquals(v.intval, x ** y) f1, f2 = [iobj.W_IntObject(self.space, i) for i in (10, 20)] self.assertEquals(self.space.w_OverflowError, - self._unwrap_nonimpl(iobj.int_int_none_pow, self.space, f1, f2)) + self._unwrap_nonimpl(iobj.pow__Int_Int_None, self.space, f1, f2)) f1, f2 = [iobj.W_IntObject(self.space, i) for i in (10, -1)] self.assertEquals(self.space.w_ValueError, - self._unwrap_nonimpl(iobj.int_int_none_pow, self.space, f1, f2)) + self._unwrap_nonimpl(iobj.pow__Int_Int_None, self.space, f1, f2)) def test_neg(self): x = 42 f1 = iobj.W_IntObject(self.space, x) - v = iobj.int_neg(self.space, f1) + v = iobj.neg__Int(self.space, f1) self.assertEquals(v.intval, -x) x = -sys.maxint-1 f1 = iobj.W_IntObject(self.space, x) self.assertEquals(self.space.w_OverflowError, - self._unwrap_nonimpl(iobj.int_neg, self.space, f1)) + self._unwrap_nonimpl(iobj.neg__Int, self.space, f1)) def test_pos(self): x = 42 f1 = iobj.W_IntObject(self.space, x) - v = iobj.int_pos(self.space, f1) + v = iobj.pos__Int(self.space, f1) self.assertEquals(v.intval, +x) def test_abs(self): x = 42 f1 = iobj.W_IntObject(self.space, x) - v = iobj.int_abs(self.space, f1) + v = iobj.abs__Int(self.space, f1) self.assertEquals(v.intval, abs(x)) x = -42 f1 = iobj.W_IntObject(self.space, x) - v = iobj.int_abs(self.space, f1) + v = iobj.abs__Int(self.space, f1) self.assertEquals(v.intval, abs(x)) x = -sys.maxint-1 f1 = iobj.W_IntObject(self.space, x) self.assertEquals(self.space.w_OverflowError, - self._unwrap_nonimpl(iobj.int_neg, self.space, f1)) + self._unwrap_nonimpl(iobj.abs__Int, self.space, f1)) - def test_pos(self): + def test_invert(self): x = 42 f1 = iobj.W_IntObject(self.space, x) - v = iobj.int_invert(self.space, f1) + v = iobj.invert__Int(self.space, f1) self.assertEquals(v.intval, ~x) def test_lshift(self): @@ -217,20 +217,20 @@ y = 2 f1 = iobj.W_IntObject(self.space, x) f2 = iobj.W_IntObject(self.space, y) - v = iobj.int_int_lshift(self.space, f1, f2) + v = iobj.lshift__Int_Int(self.space, f1, f2) self.assertEquals(v.intval, x << y) y = self._longshiftresult(x) f1 = iobj.W_IntObject(self.space, x) f2 = iobj.W_IntObject(self.space, y) self.assertEquals(self.space.w_OverflowError, - self._unwrap_nonimpl(iobj.int_int_lshift, self.space, f1, f2)) + self._unwrap_nonimpl(iobj.lshift__Int_Int, self.space, f1, f2)) def test_rshift(self): x = 12345678 y = 2 f1 = iobj.W_IntObject(self.space, x) f2 = iobj.W_IntObject(self.space, y) - v = iobj.int_int_rshift(self.space, f1, f2) + v = iobj.rshift__Int_Int(self.space, f1, f2) self.assertEquals(v.intval, x >> y) def test_and(self): @@ -238,7 +238,7 @@ y = 2 f1 = iobj.W_IntObject(self.space, x) f2 = iobj.W_IntObject(self.space, y) - v = iobj.int_int_and(self.space, f1, f2) + v = iobj.and__Int_Int(self.space, f1, f2) self.assertEquals(v.intval, x & y) def test_xor(self): @@ -246,7 +246,7 @@ y = 2 f1 = iobj.W_IntObject(self.space, x) f2 = iobj.W_IntObject(self.space, y) - v = iobj.int_int_xor(self.space, f1, f2) + v = iobj.xor__Int_Int(self.space, f1, f2) self.assertEquals(v.intval, x ^ y) def test_or(self): @@ -254,12 +254,12 @@ y = 2 f1 = iobj.W_IntObject(self.space, x) f2 = iobj.W_IntObject(self.space, y) - v = iobj.int_int_or(self.space, f1, f2) + v = iobj.or__Int_Int(self.space, f1, f2) self.assertEquals(v.intval, x | y) def test_int(self): f1 = iobj.W_IntObject(self.space, 1) - result = iobj.int_int(self.space, f1) + result = iobj.int__Int(self.space, f1) self.assertEquals(result, f1) ## def test_long(self): @@ -277,13 +277,13 @@ def test_oct(self): x = 012345 f1 = iobj.W_IntObject(self.space, x) - result = iobj.int_oct(self.space, f1) + result = iobj.oct__Int(self.space, f1) self.assertEquals(self.space.unwrap(result), oct(x)) def test_hex(self): x = 0x12345 f1 = iobj.W_IntObject(self.space, x) - result = iobj.int_hex(self.space, f1) + result = iobj.hex__Int(self.space, f1) self.assertEquals(self.space.unwrap(result), hex(x)) class AppIntTest(test.AppTestCase): From jacob at codespeak.net Wed Dec 17 12:44:06 2003 From: jacob at codespeak.net (jacob at codespeak.net) Date: Wed, 17 Dec 2003 12:44:06 +0100 (MET) Subject: [pypy-svn] rev 2426 - pypy/trunk/src/pypy/module Message-ID: <20031217114406.36CAB5A164@thoth.codespeak.net> Author: jacob Date: Wed Dec 17 12:44:05 2003 New Revision: 2426 Modified: pypy/trunk/src/pypy/module/builtin.py Log: Changed signature of pow to the correct one. Modified: pypy/trunk/src/pypy/module/builtin.py ============================================================================== --- pypy/trunk/src/pypy/module/builtin.py (original) +++ pypy/trunk/src/pypy/module/builtin.py Wed Dec 17 12:44:05 2003 @@ -312,8 +312,10 @@ def ord(self, w_val): return self.space.ord(w_val) - def pow(self, w_val): - return self.space.pow(w_val) + def pow(self, w_base, w_exponent, w_modulus=None): + if w_modulus is None: + w_modulus = self.space.w_None + return self.space.pow(w_base, w_exponent, w_modulus) def repr(self, w_object): return self.space.repr(w_object) From jacob at codespeak.net Wed Dec 17 13:05:41 2003 From: jacob at codespeak.net (jacob at codespeak.net) Date: Wed, 17 Dec 2003 13:05:41 +0100 (MET) Subject: [pypy-svn] rev 2427 - pypy/trunk/src/pypy/objspace/std Message-ID: <20031217120541.3A59D5A164@thoth.codespeak.net> Author: jacob Date: Wed Dec 17 13:05:40 2003 New Revision: 2427 Modified: pypy/trunk/src/pypy/objspace/std/floatobject.py pypy/trunk/src/pypy/objspace/std/intobject.py Log: Changed parameters to pow. Modified: pypy/trunk/src/pypy/objspace/std/floatobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/floatobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/floatobject.py Wed Dec 17 13:05:40 2003 @@ -168,8 +168,8 @@ return space.newtuple([W_FloatObject(space, floordiv), W_FloatObject(space, mod)]) -def pow__Float_Float_ANY(space, w_float1,w_float2,thirdArg=None): - if thirdArg is not None: +def pow__Float_Float_ANY(space, w_float1, w_float2, thirdArg): + if thirdArg is not space.w_None: raise FailedToImplement(space.w_TypeError,space.wrap("pow() 3rd argument not allowed unless all arguments are integers")) x = w_float1.floatval y = w_float2.floatval Modified: pypy/trunk/src/pypy/objspace/std/intobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/intobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/intobject.py Wed Dec 17 13:05:40 2003 @@ -241,17 +241,23 @@ space.wrap("integer exponentiation")) return ix +""" def pow__Int_Int_Int(space, w_int1, w_int2, w_int3): x = w_int1.intval y = w_int2.intval z = w_int3.intval ret = _impl_int_int_pow(space, x, y, z) return W_IntObject(space, ret) +""" -def pow__Int_Int_None(space, w_int1, w_int2, w_none=None): +def pow__Int_Int_ANY(space, w_int1, w_int2, w_int3): x = w_int1.intval y = w_int2.intval - ret = _impl_int_int_pow(space, x, y) + if w_int3 is space.w_None: + ret = _impl_int_int_pow(space, x, y) + else: + z = w_int3.intval + ret = _impl_int_int_pow(space, x, y, z) return W_IntObject(space, ret) def neg__Int(space, w_int1): From jacob at codespeak.net Wed Dec 17 13:14:38 2003 From: jacob at codespeak.net (jacob at codespeak.net) Date: Wed, 17 Dec 2003 13:14:38 +0100 (MET) Subject: [pypy-svn] rev 2428 - pypy/trunk/src/pypy/objspace/std/test Message-ID: <20031217121438.EF6175A164@thoth.codespeak.net> Author: jacob Date: Wed Dec 17 13:14:38 2003 New Revision: 2428 Modified: pypy/trunk/src/pypy/objspace/std/test/test_intobject.py Log: Changed tests for changed parameters to pow. Modified: pypy/trunk/src/pypy/objspace/std/test/test_intobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/test/test_intobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/test/test_intobject.py Wed Dec 17 13:14:38 2003 @@ -90,7 +90,6 @@ self.assertEquals(self.space.w_OverflowError, self._unwrap_nonimpl(iobj.sub__Int_Int, self.space, f1, f2)) - def test_mul(self): x = 2 y = 3 @@ -105,7 +104,6 @@ self.assertEquals(self.space.w_OverflowError, self._unwrap_nonimpl(iobj.mul__Int_Int, self.space, f1, f2)) - def test_div(self): for i in range(10): res = i//3 @@ -151,15 +149,15 @@ f1 = iobj.W_IntObject(self.space, x) f2 = iobj.W_IntObject(self.space, y) f3 = iobj.W_IntObject(self.space, z) - v = iobj.pow__Int_Int_Int(self.space, f1, f2, f3) + v = iobj.pow__Int_Int_ANY(self.space, f1, f2, f3) self.assertEquals(v.intval, pow(x, y, z)) f1, f2, f3 = [iobj.W_IntObject(self.space, i) for i in (10, -1, 42)] self.assertRaises_w(self.space.w_TypeError, - iobj.pow__Int_Int_Int, + iobj.pow__Int_Int_ANY, self.space, f1, f2, f3) f1, f2, f3 = [iobj.W_IntObject(self.space, i) for i in (10, 5, 0)] self.assertRaises_w(self.space.w_ValueError, - iobj.pow__Int_Int_Int, + iobj.pow__Int_Int_ANY, self.space, f1, f2, f3) def test_pow_iin(self): @@ -167,14 +165,14 @@ y = 2 f1 = iobj.W_IntObject(self.space, x) f2 = iobj.W_IntObject(self.space, y) - v = iobj.pow__Int_Int_None(self.space, f1, f2) + v = iobj.pow__Int_Int_ANY(self.space, f1, f2, self.space.w_None) self.assertEquals(v.intval, x ** y) f1, f2 = [iobj.W_IntObject(self.space, i) for i in (10, 20)] self.assertEquals(self.space.w_OverflowError, - self._unwrap_nonimpl(iobj.pow__Int_Int_None, self.space, f1, f2)) + self._unwrap_nonimpl(iobj.pow__Int_Int_ANY, self.space, f1, f2, self.space.w_None)) f1, f2 = [iobj.W_IntObject(self.space, i) for i in (10, -1)] self.assertEquals(self.space.w_ValueError, - self._unwrap_nonimpl(iobj.pow__Int_Int_None, self.space, f1, f2)) + self._unwrap_nonimpl(iobj.pow__Int_Int_ANY, self.space, f1, f2, self.space.w_None)) def test_neg(self): x = 42 @@ -191,6 +189,10 @@ f1 = iobj.W_IntObject(self.space, x) v = iobj.pos__Int(self.space, f1) self.assertEquals(v.intval, +x) + x = -42 + f1 = iobj.W_IntObject(self.space, x) + v = iobj.pos__Int(self.space, f1) + self.assertEquals(v.intval, +x) def test_abs(self): x = 42 From pmaupin at codespeak.net Wed Dec 17 13:52:38 2003 From: pmaupin at codespeak.net (pmaupin at codespeak.net) Date: Wed, 17 Dec 2003 13:52:38 +0100 (MET) Subject: [pypy-svn] rev 2429 - pypy/trunk/src/pypy/module/test Message-ID: <20031217125238.38D515A164@thoth.codespeak.net> Author: pmaupin Date: Wed Dec 17 13:52:37 2003 New Revision: 2429 Modified: pypy/trunk/src/pypy/module/test/test_builtin.py Log: Sped up and cleaned up some tests Modified: pypy/trunk/src/pypy/module/test/test_builtin.py ============================================================================== --- pypy/trunk/src/pypy/module/test/test_builtin.py (original) +++ pypy/trunk/src/pypy/module/test/test_builtin.py Wed Dec 17 13:52:37 2003 @@ -20,33 +20,30 @@ d = {"foo":"bar"} exec "def f(): return globals()" in d d2 = d["f"]() - self.assertEquals(d2.keys(),d.keys()) - # repr() on recursive containers currently fails - #self.assertEquals(d2,d) - self.assertEquals(d==d2,1) + self.assertEquals(d2,d) def test_locals(self): def f(): return locals() - def g(x=11): + def g(c=0, b=0, a=0): return locals() self.assertEquals(f(), {}) - self.assertEquals(g(), {'x':11}) + self.assertEquals(g(), {'a':0, 'b':0, 'c':0}) def test_dir(self): def f(): return dir() - self.assertEquals(f(), []) def g(c=0, b=0, a=0): return dir() + self.assertEquals(f(), []) self.assertEquals(g(), ['a', 'b', 'c']) def test_vars(self): def f(): return vars() - self.assertEquals(f(), {}) def g(c=0, b=0, a=0): return vars() + self.assertEquals(f(), {}) self.assertEquals(g(), {'a':0, 'b':0, 'c':0}) def test_getattr(self): @@ -83,9 +80,11 @@ def __call__(self): self.value += 1 return self.value - self.assertRaises(TypeError,iter,3,5) - self.assertRaises(TypeError,iter,[],5) - self.assertRaises(TypeError,iter,{},5) + # XXX Raising errors is quite slow -- + # uncomment these lines when fixed + #self.assertRaises(TypeError,iter,3,5) + #self.assertRaises(TypeError,iter,[],5) + #self.assertRaises(TypeError,iter,{},5) x = iter(count(),3) self.assertEquals(x.next(),1) self.assertEquals(x.next(),2) From pmaupin at codespeak.net Wed Dec 17 13:53:10 2003 From: pmaupin at codespeak.net (pmaupin at codespeak.net) Date: Wed, 17 Dec 2003 13:53:10 +0100 (MET) Subject: [pypy-svn] rev 2430 - pypy/trunk/src/pypy/module Message-ID: <20031217125310.8F3CE5A164@thoth.codespeak.net> Author: pmaupin Date: Wed Dec 17 13:53:09 2003 New Revision: 2430 Modified: pypy/trunk/src/pypy/module/builtin.py Log: Sped up no-argument case of dir() Modified: pypy/trunk/src/pypy/module/builtin.py ============================================================================== --- pypy/trunk/src/pypy/module/builtin.py (original) +++ pypy/trunk/src/pypy/module/builtin.py Wed Dec 17 13:53:09 2003 @@ -577,6 +577,14 @@ Otherwise: its attributes, its class's attributes, and recursively the attributes of its class's base classes. """ + if len(args) > 1: + raise TypeError("dir expected at most 1 arguments, got %d" + % len(args)) + if len(args) == 0: + local_names = _caller_locals().keys() # 2 stackframes away + local_names.sort() + return local_names + import types def _classdir(klass): """Return a dict of the accessible attributes of class/type klass. @@ -606,14 +614,6 @@ return Dict #End _classdir - if len(args) > 1: - raise TypeError("dir expected at most 1 arguments, got %d" - % len(args)) - if len(args) == 0: - local_names = _caller_locals().keys() # 2 stackframes away - local_names.sort() - return local_names - obj = args[0] if isinstance(obj, types.ModuleType): From pmaupin at codespeak.net Wed Dec 17 13:54:13 2003 From: pmaupin at codespeak.net (pmaupin at codespeak.net) Date: Wed, 17 Dec 2003 13:54:13 +0100 (MET) Subject: [pypy-svn] rev 2431 - pypy/trunk/src/pypy/objspace/std Message-ID: <20031217125413.CFBD35A164@thoth.codespeak.net> Author: pmaupin Date: Wed Dec 17 13:54:13 2003 New Revision: 2431 Modified: pypy/trunk/src/pypy/objspace/std/intobject.py Log: Implemented // for ints Modified: pypy/trunk/src/pypy/objspace/std/intobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/intobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/intobject.py Wed Dec 17 13:54:13 2003 @@ -206,6 +206,8 @@ else: return _truediv(space, w_int1, w_int2) +floordiv__Int_Int = _floordiv + # helper for pow() def _impl_int_int_pow(space, iv, iw, iz=None): if iw < 0: From sschwarzer at codespeak.net Wed Dec 17 14:19:22 2003 From: sschwarzer at codespeak.net (sschwarzer at codespeak.net) Date: Wed, 17 Dec 2003 14:19:22 +0100 (MET) Subject: [pypy-svn] rev 2432 - pypy/trunk/src/pypy/tool Message-ID: <20031217131922.8555C5A164@thoth.codespeak.net> Author: sschwarzer Date: Wed Dec 17 14:19:21 2003 New Revision: 2432 Added: pypy/trunk/src/pypy/tool/walk_tree.py (contents, props changed) Log: Make the os.walk function from Python 2.3 also available for environments with only Python 2.2. The function is accessible under the name "walk" from this module. Added: pypy/trunk/src/pypy/tool/walk_tree.py ============================================================================== --- (empty file) +++ pypy/trunk/src/pypy/tool/walk_tree.py Wed Dec 17 14:19:21 2003 @@ -0,0 +1,95 @@ +import os + +# this is copied from os.py in Python 2.3; use it only below if the +# native walk function isn't available +def _walk(top, topdown=True, onerror=None): + """Directory tree generator. + + For each directory in the directory tree rooted at top (including top + itself, but excluding '.' and '..'), yields a 3-tuple + + dirpath, dirnames, filenames + + dirpath is a string, the path to the directory. dirnames is a list of + the names of the subdirectories in dirpath (excluding '.' and '..'). + filenames is a list of the names of the non-directory files in dirpath. + Note that the names in the lists are just names, with no path components. + To get a full path (which begins with top) to a file or directory in + dirpath, do os.path.join(dirpath, name). + + If optional arg 'topdown' is true or not specified, the triple for a + directory is generated before the triples for any of its subdirectories + (directories are generated top down). If topdown is false, the triple + for a directory is generated after the triples for all of its + subdirectories (directories are generated bottom up). + + When topdown is true, the caller can modify the dirnames list in-place + (e.g., via del or slice assignment), and walk will only recurse into the + subdirectories whose names remain in dirnames; this can be used to prune + the search, or to impose a specific order of visiting. Modifying + dirnames when topdown is false is ineffective, since the directories in + dirnames have already been generated by the time dirnames itself is + generated. + + By default errors from the os.listdir() call are ignored. If + optional arg 'onerror' is specified, it should be a function; it + will be called with one argument, an os.error instance. It can + report the error to continue with the walk, or raise the exception + to abort the walk. Note that the filename is available as the + filename attribute of the exception object. + + Caution: if you pass a relative pathname for top, don't change the + current working directory between resumptions of walk. walk never + changes the current directory, and assumes that the client doesn't + either. + + Example: + + from os.path import join, getsize + for root, dirs, files in walk('python/Lib/email'): + print root, "consumes", + print sum([getsize(join(root, name)) for name in files]), + print "bytes in", len(files), "non-directory files" + if 'CVS' in dirs: + dirs.remove('CVS') # don't visit CVS directories + """ + + from os.path import join, isdir, islink + + # We may not have read permission for top, in which case we can't + # get a list of the files the directory contains. os.path.walk + # always suppressed the exception then, rather than blow up for a + # minor reason when (say) a thousand readable directories are still + # left to visit. That logic is copied here. + try: + # Note that listdir and error are globals in this module due + # to earlier import-*. + names = listdir(top) + except error, err: + if onerror is not None: + onerror(err) + return + + dirs, nondirs = [], [] + for name in names: + if isdir(join(top, name)): + dirs.append(name) + else: + nondirs.append(name) + + if topdown: + yield top, dirs, nondirs + for name in dirs: + path = join(top, name) + if not islink(path): + for x in walk(path, topdown, onerror): + yield x + if not topdown: + yield top, dirs, nondirs + + +try: + walk = os.walk +except AttributeError: + walk = _walk + From hpk at codespeak.net Wed Dec 17 14:27:28 2003 From: hpk at codespeak.net (hpk at codespeak.net) Date: Wed, 17 Dec 2003 14:27:28 +0100 (MET) Subject: [pypy-svn] rev 2433 - pypy/trunk/src/pypy/tool Message-ID: <20031217132728.770C75A164@thoth.codespeak.net> Author: hpk Date: Wed Dec 17 14:27:27 2003 New Revision: 2433 Removed: pypy/trunk/src/pypy/tool/walk_tree.py Modified: pypy/trunk/src/pypy/tool/test.py Log: it's probably better to use vpath instead Modified: pypy/trunk/src/pypy/tool/test.py ============================================================================== --- pypy/trunk/src/pypy/tool/test.py (original) +++ pypy/trunk/src/pypy/tool/test.py Wed Dec 17 14:27:27 2003 @@ -109,14 +109,18 @@ def printErrorList(self, flavour, errors): from pypy.interpreter.baseobjspace import OperationError for test, err in errors: - self.stream.writeln(self.separator1) - self.stream.writeln("%s: %s" % (flavour,self.getDescription(test))) - self.stream.writeln(self.separator2) - t1 = self._exc_info_to_string(err) - t2 = '' + if showinterplevelexceptions: + self.stream.writeln(self.separator1) + self.stream.writeln("%s: %s" % (flavour,self.getDescription(test))) + self.stream.writeln(self.separator2) + t1 = self._exc_info_to_string(err) + t2 = '' if isinstance(err[1], OperationError) and \ test.space.full_exceptions: - t2 = '\nand at app-level:\n\n' + if showinterplevelexceptions: + t2 = '\nand at app-level:\n\n' + else: + t2 = '' sio = StringIO.StringIO() err[1].print_application_traceback(test.space, sio) t2 += sio.getvalue() Deleted: /pypy/trunk/src/pypy/tool/walk_tree.py ============================================================================== --- /pypy/trunk/src/pypy/tool/walk_tree.py Wed Dec 17 14:27:27 2003 +++ (empty file) @@ -1,95 +0,0 @@ -import os - -# this is copied from os.py in Python 2.3; use it only below if the -# native walk function isn't available -def _walk(top, topdown=True, onerror=None): - """Directory tree generator. - - For each directory in the directory tree rooted at top (including top - itself, but excluding '.' and '..'), yields a 3-tuple - - dirpath, dirnames, filenames - - dirpath is a string, the path to the directory. dirnames is a list of - the names of the subdirectories in dirpath (excluding '.' and '..'). - filenames is a list of the names of the non-directory files in dirpath. - Note that the names in the lists are just names, with no path components. - To get a full path (which begins with top) to a file or directory in - dirpath, do os.path.join(dirpath, name). - - If optional arg 'topdown' is true or not specified, the triple for a - directory is generated before the triples for any of its subdirectories - (directories are generated top down). If topdown is false, the triple - for a directory is generated after the triples for all of its - subdirectories (directories are generated bottom up). - - When topdown is true, the caller can modify the dirnames list in-place - (e.g., via del or slice assignment), and walk will only recurse into the - subdirectories whose names remain in dirnames; this can be used to prune - the search, or to impose a specific order of visiting. Modifying - dirnames when topdown is false is ineffective, since the directories in - dirnames have already been generated by the time dirnames itself is - generated. - - By default errors from the os.listdir() call are ignored. If - optional arg 'onerror' is specified, it should be a function; it - will be called with one argument, an os.error instance. It can - report the error to continue with the walk, or raise the exception - to abort the walk. Note that the filename is available as the - filename attribute of the exception object. - - Caution: if you pass a relative pathname for top, don't change the - current working directory between resumptions of walk. walk never - changes the current directory, and assumes that the client doesn't - either. - - Example: - - from os.path import join, getsize - for root, dirs, files in walk('python/Lib/email'): - print root, "consumes", - print sum([getsize(join(root, name)) for name in files]), - print "bytes in", len(files), "non-directory files" - if 'CVS' in dirs: - dirs.remove('CVS') # don't visit CVS directories - """ - - from os.path import join, isdir, islink - - # We may not have read permission for top, in which case we can't - # get a list of the files the directory contains. os.path.walk - # always suppressed the exception then, rather than blow up for a - # minor reason when (say) a thousand readable directories are still - # left to visit. That logic is copied here. - try: - # Note that listdir and error are globals in this module due - # to earlier import-*. - names = listdir(top) - except error, err: - if onerror is not None: - onerror(err) - return - - dirs, nondirs = [], [] - for name in names: - if isdir(join(top, name)): - dirs.append(name) - else: - nondirs.append(name) - - if topdown: - yield top, dirs, nondirs - for name in dirs: - path = join(top, name) - if not islink(path): - for x in walk(path, topdown, onerror): - yield x - if not topdown: - yield top, dirs, nondirs - - -try: - walk = os.walk -except AttributeError: - walk = _walk - From arigo at codespeak.net Wed Dec 17 14:28:36 2003 From: arigo at codespeak.net (arigo at codespeak.net) Date: Wed, 17 Dec 2003 14:28:36 +0100 (MET) Subject: [pypy-svn] rev 2434 - in pypy/trunk/src/pypy/objspace/std: . test Message-ID: <20031217132836.D53465A164@thoth.codespeak.net> Author: arigo Date: Wed Dec 17 14:28:35 2003 New Revision: 2434 Modified: pypy/trunk/src/pypy/objspace/std/cpythonobject.py pypy/trunk/src/pypy/objspace/std/default.py pypy/trunk/src/pypy/objspace/std/multimethod.py pypy/trunk/src/pypy/objspace/std/objecttype.py pypy/trunk/src/pypy/objspace/std/objspace.py pypy/trunk/src/pypy/objspace/std/register_all.py pypy/trunk/src/pypy/objspace/std/test/test_cpythonobject.py pypy/trunk/src/pypy/objspace/std/test/test_multimethod.py Log: Changed delegation order again (argh). Added a (cheating) 'long' built-in. Modified: pypy/trunk/src/pypy/objspace/std/cpythonobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/cpythonobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/cpythonobject.py Wed Dec 17 14:28:35 2003 @@ -11,6 +11,7 @@ from pypy.objspace.std.objspace import * from stringobject import W_StringObject +from intobject import W_IntObject import sys, operator, types class W_CPythonObject(W_Object): @@ -36,13 +37,25 @@ StdObjSpace.unwrap.register(cpython_unwrap, W_CPythonObject) +# XXX we hack a bit to delegate ints to longs here +def hacky_delegate_to_long(space, w_intobj): + return space.wrap(long(w_intobj.intval)) +hacky_delegate_to_long.result_class = W_CPythonObject # XXX +hacky_delegate_to_long.priority = PRIORITY_CHANGE_TYPE + 0.1 # XXX too +StdObjSpace.delegate.register(hacky_delegate_to_long, W_IntObject) + # real-to-wrapped exceptions def wrap_exception(space): exc, value, tb = sys.exc_info() if exc is OperationError: raise exc, value, tb # just re-raise it - raise OperationError, OperationError(space.wrap(exc), space.wrap(value)), tb + name = exc.__name__ + if hasattr(space, 'w_' + name): + w_exc = getattr(space, 'w_' + name) + else: + w_exc = space.wrap(exc) + raise OperationError, OperationError(w_exc, space.wrap(value)), tb # in-place operators def inplace_pow(x1, x2): Modified: pypy/trunk/src/pypy/objspace/std/default.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/default.py (original) +++ pypy/trunk/src/pypy/objspace/std/default.py Wed Dec 17 14:28:35 2003 @@ -3,42 +3,21 @@ from pypy.objspace.std.objspace import * -# These are operations that must fall back to some default behavior, -# but that should not appear explicitly at application-level. -# There is no default object.__xxx__() method for these. +# The following default implementations are used before delegation is tried. +# 'id' is normally the address of the wrapper. - -# 'eq' falls back to 'is' - -def eq__ANY_ANY(space, w_a, w_b): - return space.is_(w_a, w_b) - -### 'ne' -> 'eq', 'le/gt/ge' -> 'lt' -## -##def ne__ANY_ANY(space, w_a, w_b): -## return space.not_(space.eq(w_a, w_b)) -##def le__ANY_ANY(space, w_a, w_b): -## return space.not_(space.lt(w_b, w_a)) -##def gt__ANY_ANY(space, w_a, w_b): -## return space.lt(w_b, w_a) -##def ge__ANY_ANY(space, w_a, w_b): -## return space.not_(space.lt(w_a, w_b)) - -# 'id' falls back to the address of the wrapper - -def id__ANY(space, w_obj): +def id__Object(space, w_obj): import intobject return intobject.W_IntObject(space, id(w_obj)) # this 'not' implementation should be fine for most cases -def not__ANY(space, w_obj): +def not__Object(space, w_obj): return space.newbool(not space.is_true(w_obj)) - # __nonzero__ falls back to __len__ -def is_true__ANY(space, w_obj): +def is_true__Object(space, w_obj): try: w_len = space.len.perform_call((w_obj,)) except FailedToImplement: @@ -52,10 +31,173 @@ def default_inplace(space, w_1, w_2, baseop=_name[8:]): op = getattr(space, baseop) return op(w_1, w_2) - getattr(StdObjSpace, _name).register(default_inplace, W_ANY, W_ANY) + getattr(StdObjSpace, _name).register(default_inplace, + W_Object, W_ANY) + +# '__get__(descr, inst, cls)' returns 'descr' by default + +def get__Object_ANY_ANY(space, w_descr, w_inst, w_cls): + return w_descr + +def is_data_descr__Object(space, w_descr): + return 0 + +# give objects some default attributes and a default way to complain +# about missing attributes + +def getattr__Object_ANY(space, w_obj, w_attr): + # XXX build a nicer error message along these lines: + #w_type = space.type(w_obj) + #w_typename = space.getattr(w_type, space.wrap('__name__')) + #... + + w_type = space.type(w_obj) + if space.is_true(space.eq(w_attr, space.wrap('__class__'))): + return w_type + + # 1) look for descriptor + # 2) if data descriptor, call it + # 3) check __dict__ + # 4) if present, return that + # 5) if descriptor found in 2), call that + # 6) raise AttrbuteError + + w_descr = None + + from typeobject import W_TypeObject + if isinstance(w_type, W_TypeObject): # XXX must always be true at some point + try: + w_descr = w_type.lookup(w_attr) + except KeyError: + pass + else: + if space.is_data_descr(w_descr): + return space.get(w_descr, w_obj, w_type) # XXX 3rd arg is wrong + + try: + w_dict = space.getdict(w_obj) + except OperationError, e: + if not e.match(space, space.w_TypeError): # 'unsupported type for getdict' + raise + else: + if space.is_true(space.eq(w_attr, space.wrap('__dict__'))): + return w_dict + try: + w_value = space.getitem(w_dict, w_attr) + except OperationError, e: + if not e.match(space, space.w_KeyError): + raise + else: + return w_value # got a value from 'obj.__dict__[attr]' + + if w_descr is not None: + return space.get(w_descr, w_obj, w_type) + + raise OperationError(space.w_AttributeError, w_attr) + + +# set attributes, complaining about read-only ones -- +# a more declarative way to define attributes would be welcome + +def setattr__Object_ANY_ANY(space, w_obj, w_attr, w_value): + + # 1) look for descriptor + # 2) if data descriptor, call it + # 3) try to set item in __dict__ + + w_type = space.type(w_obj) + if space.is_true(space.eq(w_attr, space.wrap('__class__'))): + raise OperationError(space.w_AttributeError, + space.wrap("read-only attribute")) + if space.is_true(space.eq(w_attr, space.wrap('__dict__'))): + raise OperationError(space.w_AttributeError, + space.wrap("read-only attribute")) + + from typeobject import W_TypeObject + if isinstance(w_type, W_TypeObject): + try: + w_descr = w_type.lookup(w_attr) + except KeyError: + pass + else: + if space.is_data_descr(w_descr): + return space.set(w_descr, w_obj, w_value) + + try: + w_dict = space.getdict(w_obj) + except OperationError, e: + if not e.match(space, space.w_TypeError): # "unsupported type for getdict" + raise + raise OperationError(space.w_AttributeError, w_attr) + else: + space.setitem(w_dict, w_attr, w_value) + + +def delattr__Object_ANY(space, w_obj, w_attr): + w_type = space.type(w_obj) + if space.is_true(space.eq(w_attr, space.wrap('__class__'))): + raise OperationError(space.w_AttributeError, + space.wrap("read-only attribute")) + if space.is_true(space.eq(w_attr, space.wrap('__dict__'))): + raise OperationError(space.w_AttributeError, + space.wrap("read-only attribute")) + + from typeobject import W_TypeObject + if isinstance(w_type, W_TypeObject): + try: + w_descr = w_type.lookup(w_attr) + except KeyError: + pass + else: + #space.type(w_descr).lookup(space.wrap('__delete__')) + if space.is_data_descr(w_descr): + return space.delete(w_descr, w_obj) + + try: + w_dict = space.getdict(w_obj) + except OperationError, e: + if not e.match(space, space.w_TypeError): # "unsupported type for getdict" + raise + raise OperationError(space.w_AttributeError, w_attr) + else: + try: + space.delitem(w_dict, w_attr) + except OperationError, e: + if not e.match(space, space.w_KeyError): + raise + raise OperationError(space.w_AttributeError, w_attr) +# static types -# 'contains' falls back to iteration +def type__Object(space, w_obj): + if w_obj.statictype is None: + # XXX remove me, temporary + return space.wrap(space.unwrap(w_obj).__class__) + else: + w_type = space.get_typeinstance(w_obj.statictype) + return w_type + +# repr(), str(), hash() + +def repr__Object(space, w_obj): + return space.wrap('<%s object at %s>'%( + space.type(w_obj).typename, space.unwrap(space.id(w_obj)))) + +def str__Object(space, w_obj): + return space.repr(w_obj) + +def hash__Object(space, w_obj): + return space.id(w_obj) + + +# The following operations are fall-backs if we really cannot find +# anything else even with delegation. +# 'eq' falls back to 'is' + +def eq__ANY_ANY(space, w_a, w_b): + return space.is_(w_a, w_b) + +# 'contains' falls back to iteration. def contains__ANY_ANY(space, w_iterable, w_lookfor): w_iter = space.iter(w_iterable) @@ -67,17 +209,5 @@ if space.is_true(space.eq(w_next, w_lookfor)): return space.w_True -# '__get__(descr, inst, cls)' returns 'descr' by default - -def get__ANY_ANY_ANY(space, w_descr, w_inst, w_cls): - return w_descr - -def is_data_descr__ANY(space, w_descr): - return 0 - -#def issubtype__ANY_ANY(space, w_one, w_two): -# # XXX -- mwh -# return space.newbool(0) -# # XXX why is it there ? -- Armin register_all(vars()) Modified: pypy/trunk/src/pypy/objspace/std/multimethod.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/multimethod.py (original) +++ pypy/trunk/src/pypy/objspace/std/multimethod.py Wed Dec 17 14:28:35 2003 @@ -4,6 +4,10 @@ class FailedToImplement(Exception): "Signals the dispatcher to try harder." +class W_ANY: + "Catch-all in case multimethods don't find anything else." + statictype = None + # This file defines three major classes: # @@ -290,6 +294,7 @@ def postprocessresult(self, allowedtypes, result): # add delegation from a class to the *first* immediate parent class + # and to W_ANY arg1types, = allowedtypes for t in arg1types: if t.__bases__: @@ -302,6 +307,14 @@ # hard-wire it at priority 0 result.append(((t,), delegate_to_parent_class)) + def delegate_to_any(space, a): + return a + delegate_to_any.trivial_delegation = True + delegate_to_any.result_class = W_ANY + delegate_to_any.priority = -999 + # hard-wire it at priority -999 + result.append(((t,), delegate_to_any)) + # sort the results in priority order, and insert None marks # between jumps in the priority values. Higher priority values # first. Modified: pypy/trunk/src/pypy/objspace/std/objecttype.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/objecttype.py (original) +++ pypy/trunk/src/pypy/objspace/std/objecttype.py Wed Dec 17 14:28:35 2003 @@ -32,165 +32,4 @@ return W_ObjectObject(space), True -### The following implementations are registered to the -# W_ObjectType.object_xxx multimethods, which binds them to -# the 'object' type. They are however implemented on W_ANY, not -# on W_ObjectObject, so that they can receive any wrapped object -# unmodified (instead of an object converted to W_ObjectObject). -# The difference between these implementations and the ones -# defined in default.py lies in the fact that the latter are -# not registered against any particular type, which makes them -# invisible to application-level Python, whereas the functions -# below appear as object.__xxx__. - - -# give objects some default attributes and a default way to complain -# about missing attributes - -def object_getattr__ANY_ANY(space, w_obj, w_attr): - # XXX build a nicer error message along these lines: - #w_type = space.type(w_obj) - #w_typename = space.getattr(w_type, space.wrap('__name__')) - #... - - w_type = space.type(w_obj) - if space.is_true(space.eq(w_attr, space.wrap('__class__'))): - return w_type - - # 1) look for descriptor - # 2) if data descriptor, call it - # 3) check __dict__ - # 4) if present, return that - # 5) if descriptor found in 2), call that - # 6) raise AttrbuteError - - w_descr = None - - from typeobject import W_TypeObject - if isinstance(w_type, W_TypeObject): # XXX must always be true at some point - try: - w_descr = w_type.lookup(w_attr) - except KeyError: - pass - else: - if space.is_data_descr(w_descr): - return space.get(w_descr, w_obj, w_type) # XXX 3rd arg is wrong - - try: - w_dict = space.getdict(w_obj) - except OperationError, e: - if not e.match(space, space.w_TypeError): # 'unsupported type for getdict' - raise - else: - if space.is_true(space.eq(w_attr, space.wrap('__dict__'))): - return w_dict - try: - w_value = space.getitem(w_dict, w_attr) - except OperationError, e: - if not e.match(space, space.w_KeyError): - raise - else: - return w_value # got a value from 'obj.__dict__[attr]' - - if w_descr is not None: - return space.get(w_descr, w_obj, w_type) - - raise OperationError(space.w_AttributeError, w_attr) - - -# set attributes, complaining about read-only ones -- -# a more declarative way to define attributes would be welcome - -def object_setattr__ANY_ANY_ANY(space, w_obj, w_attr, w_value): - - # 1) look for descriptor - # 2) if data descriptor, call it - # 3) try to set item in __dict__ - - w_type = space.type(w_obj) - if space.is_true(space.eq(w_attr, space.wrap('__class__'))): - raise OperationError(space.w_AttributeError, - space.wrap("read-only attribute")) - if space.is_true(space.eq(w_attr, space.wrap('__dict__'))): - raise OperationError(space.w_AttributeError, - space.wrap("read-only attribute")) - - from typeobject import W_TypeObject - if isinstance(w_type, W_TypeObject): - try: - w_descr = w_type.lookup(w_attr) - except KeyError: - pass - else: - if space.is_data_descr(w_descr): - return space.set(w_descr, w_obj, w_value) - - try: - w_dict = space.getdict(w_obj) - except OperationError, e: - if not e.match(space, space.w_TypeError): # "unsupported type for getdict" - raise - raise OperationError(space.w_AttributeError, w_attr) - else: - space.setitem(w_dict, w_attr, w_value) - - -def object_delattr__ANY_ANY(space, w_obj, w_attr): - w_type = space.type(w_obj) - if space.is_true(space.eq(w_attr, space.wrap('__class__'))): - raise OperationError(space.w_AttributeError, - space.wrap("read-only attribute")) - if space.is_true(space.eq(w_attr, space.wrap('__dict__'))): - raise OperationError(space.w_AttributeError, - space.wrap("read-only attribute")) - - from typeobject import W_TypeObject - if isinstance(w_type, W_TypeObject): - try: - w_descr = w_type.lookup(w_attr) - except KeyError: - pass - else: - #space.type(w_descr).lookup(space.wrap('__delete__')) - if space.is_data_descr(w_descr): - return space.delete(w_descr, w_obj) - - try: - w_dict = space.getdict(w_obj) - except OperationError, e: - if not e.match(space, space.w_TypeError): # "unsupported type for getdict" - raise - raise OperationError(space.w_AttributeError, w_attr) - else: - try: - space.delitem(w_dict, w_attr) - except OperationError, e: - if not e.match(space, space.w_KeyError): - raise - raise OperationError(space.w_AttributeError, w_attr) - -# static types - -def object_type__ANY(space, w_obj): - if w_obj.statictype is None: - # XXX remove me, temporary - return space.wrap(space.unwrap(w_obj).__class__) - else: - w_type = space.get_typeinstance(w_obj.statictype) - return w_type - - -# repr(), str(), hash() - -def object_repr__ANY(space, w_obj): - return space.wrap('<%s object at %s>'%( - space.type(w_obj).typename, space.unwrap(space.id(w_obj)))) - -def object_str__ANY(space, w_obj): - return space.repr(w_obj) - -def object_hash__ANY(space, w_obj): - return space.id(w_obj) - - register_all(vars(), W_ObjectType) Modified: pypy/trunk/src/pypy/objspace/std/objspace.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/objspace.py (original) +++ pypy/trunk/src/pypy/objspace/std/objspace.py Wed Dec 17 14:28:35 2003 @@ -15,15 +15,15 @@ "Do not use. For W_TypeObject only." -W_ANY = W_Object # synonyms for use in .register() BoundMultiMethod.ASSERT_BASE_TYPE = W_Object MultiMethod.BASE_TYPE_OBJECT = W_AbstractTypeObject # delegation priorities -PRIORITY_SAME_TYPE = 3 # converting between several impls of the same type -PRIORITY_PARENT_TYPE = 2 # converting to a base type (e.g. bool -> int) -PRIORITY_CHANGE_TYPE = 1 # changing type altogether (e.g. int -> float) -PRIORITY_PARENT_IMPL = 0 # hard-wired in multimethod.py +PRIORITY_SAME_TYPE = 2 # converting between several impls of the same type +PRIORITY_PARENT_TYPE = 1 # converting to a base type (e.g. bool -> int) +PRIORITY_PARENT_IMPL = 0 # hard-wired in multimethod.py (W_IntObject->W_Object) +PRIORITY_CHANGE_TYPE = -1 # changing type altogether (e.g. int -> float) +PRIORITY_ANY = -999 # hard-wired in multimethod.py (... -> W_ANY) def registerimplementation(implcls): # this function should ultimately register the implementation class somewhere @@ -140,6 +140,7 @@ "None" : self.w_None, "NotImplemented": self.w_NotImplemented, "Ellipsis": self.w_Ellipsis, + "long": self.wrap(long), # XXX temporary } # types Modified: pypy/trunk/src/pypy/objspace/std/register_all.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/register_all.py (original) +++ pypy/trunk/src/pypy/objspace/std/register_all.py Wed Dec 17 14:28:35 2003 @@ -13,7 +13,7 @@ If the name doesn't exist then the alternative namespace is tried for registration. """ - from pypy.objspace.std.objspace import StdObjSpace, W_ANY + from pypy.objspace.std.objspace import StdObjSpace, W_ANY, W_Object namespaces = [StdObjSpace] if alt_ns: namespaces.insert(0, alt_ns) @@ -24,8 +24,10 @@ funcname, sig = name.split('__') l=[] for i in sig.split('_'): - if i == 'ANY': + if i == 'ANY': # just in case W_ANY is not in module_dict icls = W_ANY + elif i == 'Object': # just in case W_Object is not in module_dict + icls = W_Object else: icls = (module_dict.get('W_%s' % i) or module_dict.get('W_%sObject' % i)) Modified: pypy/trunk/src/pypy/objspace/std/test/test_cpythonobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/test/test_cpythonobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/test/test_cpythonobject.py Wed Dec 17 14:28:35 2003 @@ -68,7 +68,7 @@ self.assertRaises(OperationError, self.space.hash, w1) try: self.space.hash(w1) except OperationError, e: - self.assertEquals(e.w_type.cpyobj, TypeError) + self.assertEquals(e.w_type, self.space.w_TypeError) def test_hashable(self): uw = 3+4j Modified: pypy/trunk/src/pypy/objspace/std/test/test_multimethod.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/test/test_multimethod.py (original) +++ pypy/trunk/src/pypy/objspace/std/test/test_multimethod.py Wed Dec 17 14:28:35 2003 @@ -93,7 +93,7 @@ class TestMultiMethod(test.TestCase): def setUp(self): # only run when testing stdobjectspace - test.objspace('std') + #XXX removed: test.objspace('std') self.space = FakeObjSpace() def test_non_delegate(self): From pmaupin at codespeak.net Wed Dec 17 14:39:51 2003 From: pmaupin at codespeak.net (pmaupin at codespeak.net) Date: Wed, 17 Dec 2003 14:39:51 +0100 (MET) Subject: [pypy-svn] rev 2435 - pypy/trunk/src/pypy/appspace Message-ID: <20031217133951.3B7395A164@thoth.codespeak.net> Author: pmaupin Date: Wed Dec 17 14:39:50 2003 New Revision: 2435 Modified: pypy/trunk/src/pypy/appspace/builtin_types_test.py Log: Uncomment some tests which now work Modified: pypy/trunk/src/pypy/appspace/builtin_types_test.py ============================================================================== --- pypy/trunk/src/pypy/appspace/builtin_types_test.py (original) +++ pypy/trunk/src/pypy/appspace/builtin_types_test.py Wed Dec 17 14:39:50 2003 @@ -50,6 +50,8 @@ if None is None and [] is not []: pass else: raise TestFailed, 'identity test failed' + +print '6.3.1 Conversion errors' try: float('') except ValueError: pass else: raise TestFailed, "float('') didn't raise ValueError" @@ -58,21 +60,23 @@ except ValueError: pass else: raise TestFailed, "float('5\0') didn't raise ValueError" +print '6.3.2 Division errors' try: 5.0 / 0.0 except ZeroDivisionError: pass else: raise TestFailed, "5.0 / 0.0 didn't raise ZeroDivisionError" -''' TODO try: 5.0 // 0.0 except ZeroDivisionError: pass else: raise TestFailed, "5.0 // 0.0 didn't raise ZeroDivisionError" -''' try: 5.0 % 0.0 except ZeroDivisionError: pass else: raise TestFailed, "5.0 % 0.0 didn't raise ZeroDivisionError" -''' TODO +try: 5L / 0 +except ZeroDivisionError: pass +else: raise TestFailed, "5L / 0 didn't raise ZeroDivisionError" + try: 5 / 0L except ZeroDivisionError: pass else: raise TestFailed, "5 / 0L didn't raise ZeroDivisionError" @@ -84,7 +88,6 @@ try: 5 % 0L except ZeroDivisionError: pass else: raise TestFailed, "5 % 0L didn't raise ZeroDivisionError" -''' print '6.4 Numeric types (mostly conversions)' if 0 != 0L or 0 != 0.0 or 0L != 0.0: raise TestFailed, 'mixed comparisons' From pmaupin at codespeak.net Wed Dec 17 14:40:36 2003 From: pmaupin at codespeak.net (pmaupin at codespeak.net) Date: Wed, 17 Dec 2003 14:40:36 +0100 (MET) Subject: [pypy-svn] rev 2436 - pypy/trunk/src/pypy/module Message-ID: <20031217134036.875725A164@thoth.codespeak.net> Author: pmaupin Date: Wed Dec 17 14:40:35 2003 New Revision: 2436 Modified: pypy/trunk/src/pypy/module/builtin.py Log: Add 'quit' and 'exit' Modified: pypy/trunk/src/pypy/module/builtin.py ============================================================================== --- pypy/trunk/src/pypy/module/builtin.py (original) +++ pypy/trunk/src/pypy/module/builtin.py Wed Dec 17 14:40:35 2003 @@ -37,6 +37,9 @@ def __init__(self, space): self.w___debug__ = space.newbool(1) + # Fix this later to show Ctrl-D on Unix + self.w_quit = self.w_exit = space.wrap("Use Ctrl-Z (i.e. EOF) to exit.") + # XXX To-do: Add copyright, credits, and license ExtModule.__init__(self, space) def _initcompiledbuiltins(self): From pmaupin at codespeak.net Wed Dec 17 14:41:19 2003 From: pmaupin at codespeak.net (pmaupin at codespeak.net) Date: Wed, 17 Dec 2003 14:41:19 +0100 (MET) Subject: [pypy-svn] rev 2437 - pypy/trunk/src/pypy/objspace/std Message-ID: <20031217134119.3C1555A164@thoth.codespeak.net> Author: pmaupin Date: Wed Dec 17 14:41:18 2003 New Revision: 2437 Modified: pypy/trunk/src/pypy/objspace/std/floatobject.py Log: Added floordiv Modified: pypy/trunk/src/pypy/objspace/std/floatobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/floatobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/floatobject.py Wed Dec 17 14:41:18 2003 @@ -115,7 +115,19 @@ x = w_float1.floatval y = w_float2.floatval try: - z = x / y # XXX make sure this is the new true division + z = x / y + except ZeroDivisionError: + raise OperationError(space.w_ZeroDivisionError, space.wrap("float division")) + except FloatingPointError: + raise FailedToImplement(space.w_FloatingPointError, space.wrap("float division")) + # no overflow + return W_FloatObject(space, z) + +def floordiv__Float_Float(space, w_float1, w_float2): + x = w_float1.floatval + y = w_float2.floatval + try: + z = x // y except ZeroDivisionError: raise OperationError(space.w_ZeroDivisionError, space.wrap("float division")) except FloatingPointError: @@ -144,7 +156,7 @@ if y == 0.0: raise FailedToImplement(space.w_ZeroDivisionError, space.wrap("float modulo")) try: - # this is a hack!!!! must be replaced by a real fmod function + # XXX this is a hack!!!! must be replaced by a real fmod function mod = math.fmod(x,y) div = (x -mod) / y if (mod): From arigo at codespeak.net Wed Dec 17 14:42:07 2003 From: arigo at codespeak.net (arigo at codespeak.net) Date: Wed, 17 Dec 2003 14:42:07 +0100 (MET) Subject: [pypy-svn] rev 2438 - in pypy/trunk/src/pypy/objspace/std: . test Message-ID: <20031217134207.EF47C5A164@thoth.codespeak.net> Author: arigo Date: Wed Dec 17 14:42:07 2003 New Revision: 2438 Modified: pypy/trunk/src/pypy/objspace/std/multimethod.py pypy/trunk/src/pypy/objspace/std/test/test_multimethod.py Log: Checking again that multimethods are called with wrapped arguments. Modified: pypy/trunk/src/pypy/objspace/std/multimethod.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/multimethod.py (original) +++ pypy/trunk/src/pypy/objspace/std/multimethod.py Wed Dec 17 14:42:07 2003 @@ -373,7 +373,7 @@ class BoundMultiMethod: - #ASSERT_BASE_TYPE = None + ASSERT_BASE_TYPE = object def __init__(self, space, multimethod): self.space = space @@ -404,6 +404,10 @@ raise OperationError(self.space.w_TypeError, w_value) def perform_call(self, args): + for a in args: + assert isinstance(a, self.ASSERT_BASE_TYPE), ( + "'%s' multimethod got a non-wrapped argument: %r" % ( + self.multimethod.operatorsymbol, a)) arity = self.multimethod.arity argclasses = tuple([a.__class__ for a in args[:arity]]) delegate = self.space.delegate.multimethod Modified: pypy/trunk/src/pypy/objspace/std/test/test_multimethod.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/test/test_multimethod.py (original) +++ pypy/trunk/src/pypy/objspace/std/test/test_multimethod.py Wed Dec 17 14:42:07 2003 @@ -3,7 +3,7 @@ from pypy.objspace.std.multimethod import * from pypy.tool import test -BoundMultiMethod.ASSERT_BASE_TYPE = None +BoundMultiMethod.ASSERT_BASE_TYPE = object class X: From hpk at codespeak.net Wed Dec 17 14:43:21 2003 From: hpk at codespeak.net (hpk at codespeak.net) Date: Wed, 17 Dec 2003 14:43:21 +0100 (MET) Subject: [pypy-svn] rev 2439 - in pypy/trunk/src/pypy: module/test objspace/std/test tool Message-ID: <20031217134321.2B60D5A164@thoth.codespeak.net> Author: hpk Date: Wed Dec 17 14:43:20 2003 New Revision: 2439 Modified: pypy/trunk/src/pypy/module/test/test_newstyleclasses.py pypy/trunk/src/pypy/objspace/std/test/test_dictobject.py pypy/trunk/src/pypy/tool/test.py Log: - added a basic test for properties - added an equality test for dictobjects - converted testsuite_from_dir to use vpath (yeah, i could have done that in individual checkins) Modified: pypy/trunk/src/pypy/module/test/test_newstyleclasses.py ============================================================================== --- pypy/trunk/src/pypy/module/test/test_newstyleclasses.py (original) +++ pypy/trunk/src/pypy/module/test/test_newstyleclasses.py Wed Dec 17 14:43:20 2003 @@ -36,6 +36,17 @@ self.assertEquals(d.f("abc"), (D, "abc")) self.assertEquals(D.f("abc"), (D, "abc")) + def test_property_simple(self): + + class a(object): + def _get(self): return 42 + def _set(self, value): raise AttributeError + def _del(self, value): raise KeyError + name = property(_get, _set, _del) + a1 = a() + self.assertEquals(a1.name, 42) + self.assertRaises(AttributeError, setattr, a1, 'name') + self.assertRaises(KeyError, delattr, a1, 'name') if __name__ == '__main__': test.main() Modified: pypy/trunk/src/pypy/objspace/std/test/test_dictobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/test/test_dictobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/test/test_dictobject.py Wed Dec 17 14:43:20 2003 @@ -172,7 +172,13 @@ def setUp(self): self.space = test.objspace('std') - + + def test_equality(self): + d = {1:2} + f = {1:2} + self.assert_(d == f) + self.assert_(d != {1:3}) + def test_clear(self): d = {1:2, 3:4} d.clear() Modified: pypy/trunk/src/pypy/tool/test.py ============================================================================== --- pypy/trunk/src/pypy/tool/test.py (original) +++ pypy/trunk/src/pypy/tool/test.py Wed Dec 17 14:43:20 2003 @@ -109,7 +109,7 @@ def printErrorList(self, flavour, errors): from pypy.interpreter.baseobjspace import OperationError for test, err in errors: - if showinterplevelexceptions: + if Options.showinterplevelexceptions: self.stream.writeln(self.separator1) self.stream.writeln("%s: %s" % (flavour,self.getDescription(test))) self.stream.writeln(self.separator2) @@ -117,7 +117,7 @@ t2 = '' if isinstance(err[1], OperationError) and \ test.space.full_exceptions: - if showinterplevelexceptions: + if Options.showinterplevelexceptions: t2 = '\nand at app-level:\n\n' else: t2 = '' @@ -225,40 +225,34 @@ Additionally, their fully qualified python module path has to be accepted by filterfunc (if it is not None). """ + from vpath import getlocal, nodotfile + root = getlocal(root) + if Options.verbose > 2: print >> sys.stderr, "scanning for test files in", root if loader is None: loader = unittest.TestLoader() - root = os.path.abspath(root) - + def testfilefilter(path): + return path.isfile() and path.fnmatch('test_*.py') + def recfilter(path): + return recursive and nodotfile(path) + suite = unittest.TestLoader.suiteClass() - names = os.listdir(root) - names.sort() - for fn in names: - # ignore "hidden" files - if fn.startswith('.'): - continue - fullfn = os.path.join(root, fn) - if os.path.isfile(fullfn) and fnmatch.fnmatch(fn, 'test_*.py'): - # strip the leading pypy directory and the .py suffix - modpath = fullfn[len(autopath.pypydir)+1:-3] - modpath = 'pypy.' + modpath.replace(os.sep, '.') - if (filterfunc is None) or filterfunc(modpath): - try: - subsuite = loader.loadTestsFromName(modpath) - except: - print "skipping testfile (failed loading it)", modpath - else: - suite.addTest(subsuite, modpath) - # possibly, collect tests from subdirectories recursively - elif recursive and os.path.isdir(fullfn): - subsuite = testsuite_from_dir(fullfn, filterfunc, 1, loader) - if subsuite: - suite._tests.extend(subsuite._tests) - return suite + for testfn in root.visit(testfilefilter, recfilter): + # strip the leading pypy directory and the .py suffix + modpath = str(testfn)[len(autopath.pypydir)+1:-3] + modpath = 'pypy.' + modpath.replace(os.sep, '.') + if (filterfunc is None) or filterfunc(modpath): + try: + subsuite = loader.loadTestsFromName(modpath) + except: + print "skipping testfile (failed loading it)", modpath + else: + suite.addTest(subsuite, modpath) + return suite class Options(option.Options): testreldir = 0 @@ -270,6 +264,7 @@ def ensure_value(*args): return 0 ensure_value = staticmethod(ensure_value) + showinterplevelexceptions = 1 class TestSkip(Exception): From jacob at codespeak.net Wed Dec 17 14:54:45 2003 From: jacob at codespeak.net (jacob at codespeak.net) Date: Wed, 17 Dec 2003 14:54:45 +0100 (MET) Subject: [pypy-svn] rev 2440 - in pypy/trunk/src/pypy/objspace/std: . test Message-ID: <20031217135445.4E2D75A164@thoth.codespeak.net> Author: jacob Date: Wed Dec 17 14:54:44 2003 New Revision: 2440 Modified: pypy/trunk/src/pypy/objspace/std/floatobject.py pypy/trunk/src/pypy/objspace/std/intobject.py pypy/trunk/src/pypy/objspace/std/test/test_floatobject.py pypy/trunk/src/pypy/objspace/std/test/test_intobject.py Log: Added tests for pow. Modified: pypy/trunk/src/pypy/objspace/std/floatobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/floatobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/floatobject.py Wed Dec 17 14:54:44 2003 @@ -1,4 +1,5 @@ from pypy.objspace.std.objspace import * +from noneobject import W_NoneObject from floattype import W_FloatType ############################################################## @@ -182,7 +183,7 @@ def pow__Float_Float_ANY(space, w_float1, w_float2, thirdArg): if thirdArg is not space.w_None: - raise FailedToImplement(space.w_TypeError,space.wrap("pow() 3rd argument not allowed unless all arguments are integers")) + raise FailedToImplement(space.w_TypeError, space.wrap("pow() 3rd argument not allowed unless all arguments are integers")) x = w_float1.floatval y = w_float2.floatval try: Modified: pypy/trunk/src/pypy/objspace/std/intobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/intobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/intobject.py Wed Dec 17 14:54:44 2003 @@ -252,14 +252,17 @@ return W_IntObject(space, ret) """ -def pow__Int_Int_ANY(space, w_int1, w_int2, w_int3): +def pow__Int_Int_Int(space, w_int1, w_int2, w_int3): x = w_int1.intval y = w_int2.intval - if w_int3 is space.w_None: - ret = _impl_int_int_pow(space, x, y) - else: - z = w_int3.intval - ret = _impl_int_int_pow(space, x, y, z) + z = w_int3.intval + ret = _impl_int_int_pow(space, x, y, z) + return W_IntObject(space, ret) + +def pow__Int_Int_None(space, w_int1, w_int2, w_int3): + x = w_int1.intval + y = w_int2.intval + ret = _impl_int_int_pow(space, x, y) return W_IntObject(space, ret) def neg__Int(space, w_int1): Modified: pypy/trunk/src/pypy/objspace/std/test/test_floatobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/test/test_floatobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/test/test_floatobject.py Wed Dec 17 14:54:44 2003 @@ -1,7 +1,43 @@ import autopath +from pypy.objspace.std import floatobject as fobj +from pypy.objspace.std.objspace import FailedToImplement from pypy.tool import test -class FloatTestCase(test.AppTestCase): +class TestW_FloatObject(test.TestCase): + + def setUp(self): + self.space = test.objspace('std') + + def tearDown(self): + pass + + def _unwrap_nonimpl(self, func, *args, **kwds): + """ make sure that the expected exception occurs, and unwrap it """ + try: + res = func(*args, **kwds) + raise Exception, "should have failed but returned '%s'!" %repr(res) + except FailedToImplement, arg: + return arg[0] + + def test_pow_fff(self): + x = 10.0 + y = 2.0 + z = 13.0 + f1 = fobj.W_FloatObject(self.space, x) + f2 = fobj.W_FloatObject(self.space, y) + f3 = fobj.W_FloatObject(self.space, z) + self.assertEquals(self.space.w_TypeError, + self._unwrap_nonimpl(fobj.pow__Float_Float_ANY, self.space, f1, f2, f3)) + + def test_pow_ffn(self): + x = 10.0 + y = 2.0 + f1 = fobj.W_FloatObject(self.space, x) + f2 = fobj.W_FloatObject(self.space, y) + v = fobj.pow__Float_Float_ANY(self.space, f1, f2, self.space.w_None) + self.assertEquals(v.floatval, x ** y) + +class AppFloatTest(test.AppTestCase): def setUp(self): self.space = test.objspace('std') Modified: pypy/trunk/src/pypy/objspace/std/test/test_intobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/test/test_intobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/test/test_intobject.py Wed Dec 17 14:54:44 2003 @@ -149,15 +149,15 @@ f1 = iobj.W_IntObject(self.space, x) f2 = iobj.W_IntObject(self.space, y) f3 = iobj.W_IntObject(self.space, z) - v = iobj.pow__Int_Int_ANY(self.space, f1, f2, f3) + v = iobj.pow__Int_Int_Int(self.space, f1, f2, f3) self.assertEquals(v.intval, pow(x, y, z)) f1, f2, f3 = [iobj.W_IntObject(self.space, i) for i in (10, -1, 42)] self.assertRaises_w(self.space.w_TypeError, - iobj.pow__Int_Int_ANY, + iobj.pow__Int_Int_Int, self.space, f1, f2, f3) f1, f2, f3 = [iobj.W_IntObject(self.space, i) for i in (10, 5, 0)] self.assertRaises_w(self.space.w_ValueError, - iobj.pow__Int_Int_ANY, + iobj.pow__Int_Int_Int, self.space, f1, f2, f3) def test_pow_iin(self): @@ -165,14 +165,14 @@ y = 2 f1 = iobj.W_IntObject(self.space, x) f2 = iobj.W_IntObject(self.space, y) - v = iobj.pow__Int_Int_ANY(self.space, f1, f2, self.space.w_None) + v = iobj.pow__Int_Int_None(self.space, f1, f2, self.space.w_None) self.assertEquals(v.intval, x ** y) f1, f2 = [iobj.W_IntObject(self.space, i) for i in (10, 20)] self.assertEquals(self.space.w_OverflowError, - self._unwrap_nonimpl(iobj.pow__Int_Int_ANY, self.space, f1, f2, self.space.w_None)) + self._unwrap_nonimpl(iobj.pow__Int_Int_None, self.space, f1, f2, self.space.w_None)) f1, f2 = [iobj.W_IntObject(self.space, i) for i in (10, -1)] self.assertEquals(self.space.w_ValueError, - self._unwrap_nonimpl(iobj.pow__Int_Int_ANY, self.space, f1, f2, self.space.w_None)) + self._unwrap_nonimpl(iobj.pow__Int_Int_None, self.space, f1, f2, self.space.w_None)) def test_neg(self): x = 42 From hpk at codespeak.net Wed Dec 17 14:56:02 2003 From: hpk at codespeak.net (hpk at codespeak.net) Date: Wed, 17 Dec 2003 14:56:02 +0100 (MET) Subject: [pypy-svn] rev 2441 - in pypy/trunk/src/pypy: module/test tool Message-ID: <20031217135602.9FFC85A164@thoth.codespeak.net> Author: hpk Date: Wed Dec 17 14:56:02 2003 New Revision: 2441 Modified: pypy/trunk/src/pypy/module/test/test_newstyleclasses.py pypy/trunk/src/pypy/tool/test.py Log: - disabled the property test (to be reenabled soon) - added a '-q' option to all test-scripts to allow suppression of interp-level tracebacks Modified: pypy/trunk/src/pypy/module/test/test_newstyleclasses.py ============================================================================== --- pypy/trunk/src/pypy/module/test/test_newstyleclasses.py (original) +++ pypy/trunk/src/pypy/module/test/test_newstyleclasses.py Wed Dec 17 14:56:02 2003 @@ -36,16 +36,16 @@ self.assertEquals(d.f("abc"), (D, "abc")) self.assertEquals(D.f("abc"), (D, "abc")) - def test_property_simple(self): + def xtest_property_simple(self): class a(object): def _get(self): return 42 def _set(self, value): raise AttributeError - def _del(self, value): raise KeyError + def _del(self): raise KeyError name = property(_get, _set, _del) a1 = a() self.assertEquals(a1.name, 42) - self.assertRaises(AttributeError, setattr, a1, 'name') + self.assertRaises(AttributeError, setattr, a1, 'name', 42) self.assertRaises(KeyError, delattr, a1, 'name') if __name__ == '__main__': Modified: pypy/trunk/src/pypy/tool/test.py ============================================================================== --- pypy/trunk/src/pypy/tool/test.py (original) +++ pypy/trunk/src/pypy/tool/test.py Wed Dec 17 14:56:02 2003 @@ -109,22 +109,19 @@ def printErrorList(self, flavour, errors): from pypy.interpreter.baseobjspace import OperationError for test, err in errors: - if Options.showinterplevelexceptions: + t1, t2 = '', '' + if not Options.quiet: self.stream.writeln(self.separator1) self.stream.writeln("%s: %s" % (flavour,self.getDescription(test))) self.stream.writeln(self.separator2) t1 = self._exc_info_to_string(err) - t2 = '' if isinstance(err[1], OperationError) and \ test.space.full_exceptions: - if Options.showinterplevelexceptions: + if not Options.quiet: t2 = '\nand at app-level:\n\n' - else: - t2 = '' sio = StringIO.StringIO() err[1].print_application_traceback(test.space, sio) t2 += sio.getvalue() - self.stream.writeln("%s" % (t1 + t2,)) @@ -264,8 +261,7 @@ def ensure_value(*args): return 0 ensure_value = staticmethod(ensure_value) - showinterplevelexceptions = 1 - + quiet = 0 class TestSkip(Exception): pass @@ -314,6 +310,9 @@ '-i', action="store_true", dest="interactive", help="enter an interactive mode on failure or error")) options.append(make_option( + '-q', action="store_true", dest="quiet", + help="suppress some information (e.g. interpreter level exceptions)")) + options.append(make_option( '-c', action="store_true", dest="runcts", help="run CtsTestRunner (discards output and prints report " "after testing)")) From tomek at codespeak.net Wed Dec 17 14:58:40 2003 From: tomek at codespeak.net (tomek at codespeak.net) Date: Wed, 17 Dec 2003 14:58:40 +0100 (MET) Subject: [pypy-svn] rev 2442 - in pypy/trunk/src/pypy: interpreter objspace tool Message-ID: <20031217135840.E15A35A164@thoth.codespeak.net> Author: tomek Date: Wed Dec 17 14:58:40 2003 New Revision: 2442 Added: pypy/trunk/src/pypy/tool/pydis.py Modified: pypy/trunk/src/pypy/interpreter/baseobjspace.py pypy/trunk/src/pypy/interpreter/pyopcode.py pypy/trunk/src/pypy/objspace/trace.py Log: We have (Tomek and Richard) written an initial version of TraceObjectSpace. We inherit from an existing object space, and provide tracing for bytecodes and space operation. Now we will try to write a proxy object for an existing object space, so that we can take an existing object space and provide tracing for it at the runtime. Modified: pypy/trunk/src/pypy/interpreter/baseobjspace.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/baseobjspace.py (original) +++ pypy/trunk/src/pypy/interpreter/baseobjspace.py Wed Dec 17 14:58:40 2003 @@ -117,7 +117,7 @@ def getexecutioncontext(self): "Return what we consider to be the active execution context." - ec = getthreadlocals().executioncontext + ec = getthreadlocals().executioncontext #it's allways None (dec. 2003) if ec is None: ec = self.createexecutioncontext() return ec Modified: pypy/trunk/src/pypy/interpreter/pyopcode.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/pyopcode.py (original) +++ pypy/trunk/src/pypy/interpreter/pyopcode.py Wed Dec 17 14:58:40 2003 @@ -46,6 +46,7 @@ if fn.has_arg: oparg = self.nextarg() fn(self, oparg) + else: fn(self) @@ -54,6 +55,38 @@ self.next_instr += 1 return ord(c) + def examineop(self): + # XXX Testing trace object space + # rxxxe Add test? + + c = ord(self.code.co_code[self.next_instr]) + + fn = self.dispatch_table[c] + values = [] + arg= "" + if fn.has_arg: + lo = ord(self.code.co_code[self.next_instr+1]) + hi = ord(self.code.co_code[self.next_instr+2]) + arg = (hi<<8) + lo + +## for ii in [1,2,3]: +## if self.valuestack.depth() >= ii: +## value = self.valuestack.top(ii - 1) +## values.append(value) + + + if hasattr(fn, "operationname"): + fn_name = fn.operationname + else: + fn_name = fn.__name__ + + + return c, fn_name, arg, self.next_instr + + def get_index(self): + return index + + def nextarg(self): lo = self.nextop() hi = self.nextop() Modified: pypy/trunk/src/pypy/objspace/trace.py ============================================================================== --- pypy/trunk/src/pypy/objspace/trace.py (original) +++ pypy/trunk/src/pypy/objspace/trace.py Wed Dec 17 14:58:40 2003 @@ -1,6 +1,4 @@ -# ______________________________________________________________________ -import autopath -import sys, operator, types, new +import sys, operator, types, new, autopath import pypy from pypy.objspace.std import StdObjSpace from pypy.objspace.trivial import TrivialObjSpace @@ -8,57 +6,47 @@ from pypy.interpreter.executioncontext import ExecutionContext from pypy.interpreter.pycode import PyCode from pypy.interpreter import gateway -debug = 0 + +DONT_TRACK_BYTECODES = ["PRINT_ITEM", "PRINT_NEWLINE", "PRINT_EXPR", "PRINT_ITEM_TO", "PRINT_NEWLINE_TO"] + class TraceExecutionContext(ExecutionContext): - + def bytecode_trace(self, frame): "Trace function called before each bytecode." - #print "XXX %s, %s" % frame.examineop() self.space.notify_on_bytecode(frame) -class Logger(object): - def __init__(self, name, fn, space, printme): + +class Tracer(object): + def __init__(self, name, fn, space): self.fn = fn self.name = name self.space = space - self.printme = printme def __call__(self, cls, *args, **kwds): assert (not kwds) - #print self.name - #print "%s %s(%s, %s)" % (self.printme, , str(args), str(kwds)) - self.space.notify_on_operation(self.name, None) + self.space.notify_on_operation(self.name, args) return self.fn(*args, **kwds) def __getattr__(self, name): return getattr(self.fn, name) -## XXX Interaction not in scope (yet) -## class InteractiveLogger(Logger): - -## def __call__(self, cls, *args, **kwds): -## res = Logger.__call__(self, cls, *args, **kwds) -## raw_input() -## return res - -# ______________________________________________________________________ - -def Trace(spacecls = StdObjSpace, logger_cls = Logger): +def Trace(spacecls = StdObjSpace): class TraceObjSpace(spacecls): full_exceptions = False def initialize(self): self.tracing = 0 + self.ignore_up_to_frame = None spacecls.initialize(self) method_names = [ii[0] for ii in ObjSpace.MethodTable] for key in method_names: if key in method_names: item = getattr(self, key) - l = logger_cls(key, item, self, "class method") + l = Tracer(key, item, self) setattr(self, key, new.instancemethod(l, self, TraceObjSpace)) def start_tracing(self): @@ -72,16 +60,37 @@ "Factory function for execution contexts." return TraceExecutionContext(self) + def handle_default(self, frame, opcode, opname, oparg, ins_idx): + return opcode, opname, "", ins_idx + + def handle_SET_LINENO(self, frame, opcode, opname, oparg, ins_idx): + return opcode, opname, "%s" % oparg, ins_idx + + def handle_LOAD_CONST(self, frame, opcode, opname, oparg, ins_idx): + return opcode, opname, "%s (%r)" % (oparg, frame.getconstant(oparg)), ins_idx + + def handle_LOAD_FAST(self, frame, opcode, opname, oparg, ins_idx): + return opcode, opname, "%s (%s)" % (oparg, frame.getlocalvarname(oparg)), ins_idx def notify_on_bytecode(self, frame): + if not self.tracing and self.ignore_up_to_frame is frame: + self.tracing = 1 + self.ignore_up_to_frame = None if self.tracing: - opcode, opname = frame.examineop() - self.log_list.append((opname, [])) + opcode, opname, oparg, ins_idx = frame.examineop() + handle_method = getattr(self, "handle_%s" % opname, self.handle_default) + + opcode, opname, oparg, ins_idx = handle_method(frame, opcode, opname, oparg, ins_idx) + self.log_list.append(((opcode, opname, oparg, ins_idx), [])) + if opname in DONT_TRACK_BYTECODES: + self.ignore_up_to_frame = frame + self.tracing = 0 def notify_on_operation(self, name, args): if self.tracing: self.log_list[-1][1].append((name, args)) + def dump(self): return self.log_list @@ -107,55 +116,32 @@ Space = Trace -#s = Trace(TrivialObjSpace) -s = Trace() + # ______________________________________________________________________ # End of trace.py -def add_func(space, func, w_globals): - """ Add a function to globals. """ - func_name = func.func_name - w_func_name = space.wrap(func_name) - w_func = space.wrap(func) - space.setitem(w_globals, w_func_name, w_func) - -def run_function(space, func, *args): - # Get execution context and globals - ec = space.getexecutioncontext() - w_globals = ec.make_standard_w_globals() - - # Add the function to globals - add_func(space, func, w_globals) - - # Create wrapped args - args_w = [space.wrap(ii) for ii in args] - code = func.func_code - code = PyCode()._from_code(code) - # Create frame - frame = code.create_frame(space, w_globals) - frame.setfastscope(args_w) - - # start/stop tracing while running frame - space.start_tracing() - res = frame.run() - space.stop_tracing() - - return res +## if __name__ == "__main__": -if __name__ == "__main__": - def a(b): - if b > 0: - return a(b-1) - else: - return b - - print run_function(s, a, 3) - - print ">>>>>>" - for line in s.dump(): - print line - print ">>>>>>" - for line in s.rdump(): - print line +## s = Trace(TrivialObjSpace) + +## def a(b): +## print "x" +## if b > 2: +## return b*2 +## else: +## return b + +## print run_function(s, a, 1) + +## print ">>>>>>" +## for line in s.dump(): +## ((opcode, opname, arg, ins_idx), spaceops) = line +## print ins_idx, opname, spaceops +## print ">>>>>>" +## #for line in s.rdump(): +## # print line + +## #import dis +## #dis.dis(a) Added: pypy/trunk/src/pypy/tool/pydis.py ============================================================================== --- (empty file) +++ pypy/trunk/src/pypy/tool/pydis.py Wed Dec 17 14:58:40 2003 @@ -0,0 +1,137 @@ +import autopath +import repr + +from pypy.interpreter.pycode import PyCode +from pypy.objspace.std import StdObjSpace +from pypy.objspace.trivial import TrivialObjSpace +from pypy.objspace.trace import Trace + + +def get_repr(): + " Our own repr function for pretty print. " + repr_obj = repr.Repr() + repr_obj.maxstring = 120 + repr_obj.maxother = 120 + + def our_repr(*args): + try: + return repr_obj.repr(*args) + + except: + return "ERROR" + + return our_repr + + +def rpretty_print(spacedump): + " Pretty print for rdump() calls to Trace object spaces. " + + Repr = get_repr() + for operation, bytecodes in spacedump: + for opcode, opname, oparg, ins_idx in bytecodes: + print "\t%s\t%s\t\t%s" % (ins_idx, opname, oparg) + + if operation is not None: + op_name = operation[0] + args = operation[1:] + print " ***\t", op_name, " ->", + for a in args: + print Repr(a), + print + + +def add_func(space, func, w_globals): + """ Add a function to globals. """ + func_name = func.func_name + w_func_name = space.wrap(func_name) + w_func = space.wrap(func) + space.setitem(w_globals, w_func_name, w_func) + + +def run_in_space(space, func, *args): + # Get execution context and globals + ec = space.getexecutioncontext() + w_globals = ec.make_standard_w_globals() + + # Add the function to globals + add_func(space, func, w_globals) + + # Create wrapped args + args_w = [space.wrap(ii) for ii in args] + code = func.func_code + code = PyCode()._from_code(code) + + # Create frame + frame = code.create_frame(space, w_globals) + frame.setfastscope(args_w) + + # start/stop tracing while running frame + space.start_tracing() + res = frame.run() + space.stop_tracing() + + return res + + +def pretty_print(spacedump): + " Pretty print for rdump() calls to Trace object spaces. " + Repr = get_repr() + + for line in spacedump: + ((opcode, opname, arg, ins_idx), spaceops) = line + start = "%4i %s " % (ins_idx, opname) + start = start + " " * (20 - len(start)) + str(arg) + start = start + " " * (30 - len(start)) + if not spaceops: + print start + else: + op = spaceops.pop(0) + print start + for op_name, args in spaceops: + print " " * 30, op_name, Repr(args) + + +def _trace_function(space, reverse_pretty_print_flag, fn, *arg, **kwds): + res = run_in_space(space, fn, *arg, **kwds) + if reverse_pretty_print_flag: + # Get reverse dump + spacedump = space.rdump() + + # Pretty print dump + rpretty_print(spacedump) + else: + # Get dump + spacedump = space.dump() + + # Pretty dump + pretty_print(spacedump) + + return res + +def trace_function(trace_space, fn, *arg, **kwds): + return _trace_function(trace_space, False, fn, *arg, **kwds) + +def rtrace_function(trace_space, fn, *arg, **kwds): + return _trace_function(trace_space, True, fn, *arg, **kwds) + + + + +## # Create space +## if __name__ == "__main__": +## try: +## import readline +## except ImportError: +## pass + +## from pypy.tool import option +## from pypy.tool import test +## args = option.process_options(option.get_standard_options(), +## option.Options) +## objspace = option.objspace() + + +## def run(*args, **kwds): +## def run_function(space, func, *args): +## from pypy.objspace.std import StdObjSpace +## space = Trace(StdObjSpace) From tomek at codespeak.net Wed Dec 17 15:01:44 2003 From: tomek at codespeak.net (tomek at codespeak.net) Date: Wed, 17 Dec 2003 15:01:44 +0100 (MET) Subject: [pypy-svn] rev 2443 - pypy/trunk/src/pypy/interpreter Message-ID: <20031217140144.3F85E5A164@thoth.codespeak.net> Author: tomek Date: Wed Dec 17 15:01:43 2003 New Revision: 2443 Modified: pypy/trunk/src/pypy/interpreter/pyopcode.py Log: small tidies :-) Modified: pypy/trunk/src/pypy/interpreter/pyopcode.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/pyopcode.py (original) +++ pypy/trunk/src/pypy/interpreter/pyopcode.py Wed Dec 17 15:01:43 2003 @@ -56,33 +56,25 @@ return ord(c) def examineop(self): - # XXX Testing trace object space - # rxxxe Add test? + # XXX Testing trace object space - Add test? c = ord(self.code.co_code[self.next_instr]) - fn = self.dispatch_table[c] - values = [] - arg= "" - if fn.has_arg: - lo = ord(self.code.co_code[self.next_instr+1]) - hi = ord(self.code.co_code[self.next_instr+2]) - arg = (hi<<8) + lo - -## for ii in [1,2,3]: -## if self.valuestack.depth() >= ii: -## value = self.valuestack.top(ii - 1) -## values.append(value) - if hasattr(fn, "operationname"): fn_name = fn.operationname else: fn_name = fn.__name__ - + arg = "" + if fn.has_arg: + lo = ord(self.code.co_code[self.next_instr + 1]) + hi = ord(self.code.co_code[self.next_instr + 2]) + arg = (hi<<8) + lo + return c, fn_name, arg, self.next_instr + def get_index(self): return index From pmaupin at codespeak.net Wed Dec 17 15:02:36 2003 From: pmaupin at codespeak.net (pmaupin at codespeak.net) Date: Wed, 17 Dec 2003 15:02:36 +0100 (MET) Subject: [pypy-svn] rev 2444 - in pypy/trunk/src/pypy/module: . test Message-ID: <20031217140236.002565A164@thoth.codespeak.net> Author: pmaupin Date: Wed Dec 17 15:02:36 2003 New Revision: 2444 Modified: pypy/trunk/src/pypy/module/builtin.py pypy/trunk/src/pypy/module/test/test_builtin.py Log: Added sum() Modified: pypy/trunk/src/pypy/module/builtin.py ============================================================================== --- pypy/trunk/src/pypy/module/builtin.py (original) +++ pypy/trunk/src/pypy/module/builtin.py Wed Dec 17 15:02:36 2003 @@ -290,6 +290,11 @@ def id(self, w_object): return self.space.id(w_object) + def app_sum(self,sequence,total=0): + for item in sequence: + total = total+item + return total + #XXX works only for new-style classes. #So we have to fix it, when we add support for old-style classes def issubclass(self, w_cls1, w_cls2): Modified: pypy/trunk/src/pypy/module/test/test_builtin.py ============================================================================== --- pypy/trunk/src/pypy/module/test/test_builtin.py (original) +++ pypy/trunk/src/pypy/module/test/test_builtin.py Wed Dec 17 15:02:36 2003 @@ -53,6 +53,13 @@ self.assertRaises(AttributeError, getattr, a, 'k') self.assertEquals(getattr(a, 'k', 42), 42) + def test_sum(self): + self.assertEquals(sum([]),0) + self.assertEquals(sum([42]),42) + self.assertEquals(sum([1,2,3]),6) + self.assertEquals(sum([],5),5) + self.assertEquals(sum([1,2,3],4),10) + def test_type_selftest(self): self.assert_(type(type) is type) From jacob at codespeak.net Wed Dec 17 15:19:03 2003 From: jacob at codespeak.net (jacob at codespeak.net) Date: Wed, 17 Dec 2003 15:19:03 +0100 (MET) Subject: [pypy-svn] rev 2445 - pypy/trunk/src/pypy/module Message-ID: <20031217141903.B82715A164@thoth.codespeak.net> Author: jacob Date: Wed Dec 17 15:19:03 2003 New Revision: 2445 Modified: pypy/trunk/src/pypy/module/builtin.py Log: Added enumerate as application level method of builtin.py. Modified: pypy/trunk/src/pypy/module/builtin.py ============================================================================== --- pypy/trunk/src/pypy/module/builtin.py (original) +++ pypy/trunk/src/pypy/module/builtin.py Wed Dec 17 15:19:03 2003 @@ -309,7 +309,7 @@ self.space.wrap('iter(v, w): v must be callable')) return self._iter_generator(w_collection_or_callable, w_sentinel) - def app__iter_generator(self,callable_,sentinel): + def app__iter_generator(self, callable_, sentinel): """ This generator implements the __iter__(callable,sentinel) protocol """ while 1: result = callable_() @@ -317,6 +317,14 @@ raise StopIteration yield result + def app_enumerate(self, collection): + 'Generates an indexed series: (0,coll[0]), (1,coll[1]) ...' + i = 0 + it = iter(collection) + while 1: + yield (i, it.next()) + i += 1 + def ord(self, w_val): return self.space.ord(w_val) From jacob at codespeak.net Wed Dec 17 15:25:05 2003 From: jacob at codespeak.net (jacob at codespeak.net) Date: Wed, 17 Dec 2003 15:25:05 +0100 (MET) Subject: [pypy-svn] rev 2446 - pypy/trunk/src/pypy/module/test Message-ID: <20031217142505.0A4235A164@thoth.codespeak.net> Author: jacob Date: Wed Dec 17 15:25:04 2003 New Revision: 2446 Modified: pypy/trunk/src/pypy/module/test/test_builtin.py Log: Added test for enumerate. Modified: pypy/trunk/src/pypy/module/test/test_builtin.py ============================================================================== --- pypy/trunk/src/pypy/module/test/test_builtin.py (original) +++ pypy/trunk/src/pypy/module/test/test_builtin.py Wed Dec 17 15:25:04 2003 @@ -97,6 +97,13 @@ self.assertEquals(x.next(),2) self.assertRaises(StopIteration,x.next) + def test_enumerate(self): + seq = range(2,4) + enum = enumerate(seq) + self.assertEquals(enum.next(), (0, 2)) + self.assertEquals(enum.next(), (1, 3)) + self.assertRaises(StopIteration, enum.next) + def test_xrange_args(self): x = xrange(2) self.assertEquals(x.start, 0) From arigo at codespeak.net Wed Dec 17 15:25:43 2003 From: arigo at codespeak.net (arigo at codespeak.net) Date: Wed, 17 Dec 2003 15:25:43 +0100 (MET) Subject: [pypy-svn] rev 2447 - pypy/trunk/src/pypy Message-ID: <20031217142543.AE3D45A164@thoth.codespeak.net> Author: arigo Date: Wed Dec 17 15:25:42 2003 New Revision: 2447 Modified: pypy/trunk/src/pypy/TODO Log: Record bigger tasks that we'll probably not address during the sprint. Modified: pypy/trunk/src/pypy/TODO ============================================================================== --- pypy/trunk/src/pypy/TODO (original) +++ pypy/trunk/src/pypy/TODO Wed Dec 17 15:25:42 2003 @@ -29,3 +29,15 @@ AnnSpace or other deprecated stuff Task: (documentation) do more and enhance + +========================================================================== +New bigger tasks that we don't want to address during the Amsterdam sprint +========================================================================== + +* make application-level types work for (1) StdObjSpace types and (2) + core interpreter objects. + +* clear out and do a clean implementation of multimethod delegation. + The idea is to give 'kinds' to arguments according to their use, + e.g. 'numeric argument' or 'object whose identity is preserved'. + A 'kind' encapsulates a set of delegation functions. From jacob at codespeak.net Wed Dec 17 15:48:21 2003 From: jacob at codespeak.net (jacob at codespeak.net) Date: Wed, 17 Dec 2003 15:48:21 +0100 (MET) Subject: [pypy-svn] rev 2448 - in pypy/trunk/src/pypy/module: . test Message-ID: <20031217144821.C05235A164@thoth.codespeak.net> Author: jacob Date: Wed Dec 17 15:48:21 2003 New Revision: 2448 Modified: pypy/trunk/src/pypy/module/builtin.py pypy/trunk/src/pypy/module/test/test_builtin.py Log: Added intern() as null operation. Modified: pypy/trunk/src/pypy/module/builtin.py ============================================================================== --- pypy/trunk/src/pypy/module/builtin.py (original) +++ pypy/trunk/src/pypy/module/builtin.py Wed Dec 17 15:48:21 2003 @@ -664,6 +664,13 @@ return Dict.keys() + def app_intern(self, s): + """ + We don't have a string table, making intern a null operation. + This is here for backwards compatibility. + """ + return s + # source code for the builtin xrange-class xrange_appsource = """if 1: class xrange: Modified: pypy/trunk/src/pypy/module/test/test_builtin.py ============================================================================== --- pypy/trunk/src/pypy/module/test/test_builtin.py (original) +++ pypy/trunk/src/pypy/module/test/test_builtin.py Wed Dec 17 15:48:21 2003 @@ -153,6 +153,10 @@ def test_divmod(self): self.assertEquals(divmod(15,10),(1,5)) + def test_intern(self): + s = 'xxx' + self.assertEquals(intern(s), s) + class TestInternal(test.IntTestCase): def setUp(self): From jacob at codespeak.net Wed Dec 17 16:03:10 2003 From: jacob at codespeak.net (jacob at codespeak.net) Date: Wed, 17 Dec 2003 16:03:10 +0100 (MET) Subject: [pypy-svn] rev 2449 - pypy/trunk/src/pypy/module Message-ID: <20031217150310.EA8855A164@thoth.codespeak.net> Author: jacob Date: Wed Dec 17 16:03:10 2003 New Revision: 2449 Modified: pypy/trunk/src/pypy/module/builtin.py Log: Added type check to intern to mimic CPython Modified: pypy/trunk/src/pypy/module/builtin.py ============================================================================== --- pypy/trunk/src/pypy/module/builtin.py (original) +++ pypy/trunk/src/pypy/module/builtin.py Wed Dec 17 16:03:10 2003 @@ -669,6 +669,8 @@ We don't have a string table, making intern a null operation. This is here for backwards compatibility. """ + if not isinstance(s, str): + raise TypeError("intern() argument 1 must be string.") return s # source code for the builtin xrange-class From arigo at codespeak.net Wed Dec 17 16:21:58 2003 From: arigo at codespeak.net (arigo at codespeak.net) Date: Wed, 17 Dec 2003 16:21:58 +0100 (MET) Subject: [pypy-svn] rev 2450 - in pypy/trunk/src/pypy/annotation: . test Message-ID: <20031217152158.524735A164@thoth.codespeak.net> Author: arigo Date: Wed Dec 17 16:21:57 2003 New Revision: 2450 Modified: pypy/trunk/src/pypy/annotation/annset.py pypy/trunk/src/pypy/annotation/model.py pypy/trunk/src/pypy/annotation/test/test_annset.py Log: The tests pass again. Modified: pypy/trunk/src/pypy/annotation/annset.py ============================================================================== --- pypy/trunk/src/pypy/annotation/annset.py (original) +++ pypy/trunk/src/pypy/annotation/annset.py Wed Dec 17 16:21:57 2003 @@ -1,8 +1,11 @@ from __future__ import generators import types -from model import Annotation, SomeValue, ANN +from model import Annotation, SomeValue, QueryArgument, ANN from model import immutable_types, blackholevalue, basicannotations +QUERYARG = QueryArgument() + + class AnnotationSet: """An annotation set is a (large) family of Annotations.""" @@ -61,15 +64,15 @@ the queried value. """ # slightly limited implementation for ease of coding :-) - assert query.args.count(Ellipsis) == 1, ( + assert query.args.count(QUERYARG) == 1, ( "sorry, the algorithm is a bit too naive for this case") - queryarg = query.args.index(Ellipsis) + queryarg = query.args.index(QUERYARG) for ann in self._annmatches(query): # does the returned match also agree with the other queries? match = ann.args[queryarg] depends = [ann] for queryann in querylist: - boundquery = queryann.copy(renameargs={Ellipsis: match}) + boundquery = queryann.copy(renameargs={QUERYARG: match}) ann = self.findfirst(boundquery) if ann is None: break @@ -80,7 +83,7 @@ def _annmatches(self, queryann): """ yield annotations matching the given queryannotation. """ testindices = [i for i in range(queryann.predicate.arity) - if queryann.args[i] is not Ellipsis] + if queryann.args[i] is not QUERYARG] for ann in self.annlist: if ann.predicate == queryann.predicate: for i in testindices: @@ -184,8 +187,8 @@ deps.append(ann) def check_type(self, someval, checktype): - return self.query(ANN.type[someval, ...], - ANN.constant(checktype)[...]) + return bool(self.query(ANN.type[someval, QUERYARG], + ANN.constant(checktype)[QUERYARG])) def set_type(self, someval, knowntype): typeval = SomeValue() Modified: pypy/trunk/src/pypy/annotation/model.py ============================================================================== --- pypy/trunk/src/pypy/annotation/model.py (original) +++ pypy/trunk/src/pypy/annotation/model.py Wed Dec 17 16:21:57 2003 @@ -3,6 +3,9 @@ class SomeValue: pass +class QueryArgument: + pass + class Predicate: def __init__(self, debugname, arity): self.debugname = debugname @@ -42,7 +45,8 @@ # note that for predicates that are simple operations like # op.add, the result is stored as the last argument. for someval in args: - assert someval is Ellipsis or isinstance(someval, SomeValue) # bug catcher + assert isinstance(someval, (SomeValue, QueryArgument, + type(Ellipsis))) # bug catcher def copy(self, renameargs={}): args = [renameargs.get(arg, arg) for arg in self.args] @@ -76,7 +80,7 @@ } # a conventional value for representing 'all Annotations match this one' -blackholevalue = SomeValue() +blackholevalue = Ellipsis # a few values representing 'any value of the given type' # the following loops creates intvalue, strvalue, etc. Modified: pypy/trunk/src/pypy/annotation/test/test_annset.py ============================================================================== --- pypy/trunk/src/pypy/annotation/test/test_annset.py (original) +++ pypy/trunk/src/pypy/annotation/test/test_annset.py Wed Dec 17 16:21:57 2003 @@ -3,7 +3,7 @@ from pypy.tool import test from pypy.annotation.model import ANN, SomeValue -from pypy.annotation.annset import AnnotationSet +from pypy.annotation.annset import AnnotationSet, QUERYARG class TestAnnotationSet(test.IntTestCase): @@ -43,15 +43,15 @@ c1,c2,c3 = SomeValue(), SomeValue(), SomeValue() lst = [ANN.add[c1, c3, c2]] a = AnnotationSet(lst) - c = a.query(ANN.add[c1, c3, ...]) - self.assertEquals(c, [c2]) - c = a.query(ANN.add[c1, ..., c2]) - self.assertEquals(c, [c3]) - c = a.query(ANN.add[..., c3, c2]) - self.assertEquals(c, [c1]) + clist = a.query(ANN.add[c1, c3, QUERYARG]) + self.assertEquals(clist, [c2]) + clist = a.query(ANN.add[c1, QUERYARG, c2]) + self.assertEquals(clist, [c3]) + clist = a.query(ANN.add[QUERYARG, c3, c2]) + self.assertEquals(clist, [c1]) - c = a.query(ANN.add[..., c1, c2]) - self.assertEquals(c, []) + clist = a.query(ANN.add[QUERYARG, c1, c2]) + self.assertEquals(clist, []) def test_query_multiple_annotations(self): c1,c2,c3 = SomeValue(), SomeValue(), SomeValue() @@ -60,9 +60,9 @@ ANN.type[c2, c3], ] a = AnnotationSet(lst) - c = a.query(ANN.add[c1, c3, ...], - ANN.type[..., c3]) - self.assertEquals(c, [c2]) + clist = a.query(ANN.add[c1, c3, QUERYARG], + ANN.type[QUERYARG, c3]) + self.assertEquals(clist, [c2]) def test_constant(self): c1,c2,c3 = SomeValue(), SomeValue(), SomeValue() @@ -70,8 +70,8 @@ ANN.constant(42)[c1], ] a = AnnotationSet(lst) - c = a.query(ANN.constant(42)[...]) - self.assertEquals(c, [c1]) + clist = a.query(ANN.constant(42)[QUERYARG]) + self.assertEquals(clist, [c1]) c1,c2,c3,c4 = SomeValue(), SomeValue(), SomeValue(), SomeValue() @@ -102,7 +102,7 @@ def test_simple(self): a = self.annset def f(rec): - if rec.query(ANN.add[c1, c3, ...]): + if rec.query(ANN.add[c1, c3, QUERYARG]): rec.set(ANN.type[c1, c3]) a.record(f) self.assertSameSet(a, a, self.lst + [ANN.type[c1, c3]]) @@ -116,8 +116,8 @@ if rec.check_type(c1, int): rec.set_type(c2, str) a.record(f) - self.assert_(a.query(ANN.type[c2, ...], - ANN.constant(str)[...])) + self.assert_(a.query(ANN.type[c2, QUERYARG], + ANN.constant(str)[QUERYARG])) if __name__ == '__main__': test.main() From lac at codespeak.net Wed Dec 17 16:26:21 2003 From: lac at codespeak.net (lac at codespeak.net) Date: Wed, 17 Dec 2003 16:26:21 +0100 (MET) Subject: [pypy-svn] rev 2451 - pypy/trunk/src/pypy/module/test Message-ID: <20031217152621.426285A164@thoth.codespeak.net> Author: lac Date: Wed Dec 17 16:26:20 2003 New Revision: 2451 Modified: pypy/trunk/src/pypy/module/test/test_builtin.py Log: check that intern raises TypeError for non-strings Modified: pypy/trunk/src/pypy/module/test/test_builtin.py ============================================================================== --- pypy/trunk/src/pypy/module/test/test_builtin.py (original) +++ pypy/trunk/src/pypy/module/test/test_builtin.py Wed Dec 17 16:26:20 2003 @@ -156,6 +156,7 @@ def test_intern(self): s = 'xxx' self.assertEquals(intern(s), s) + self.assertRaises(TypeError, intern, 1) class TestInternal(test.IntTestCase): From pmaupin at codespeak.net Wed Dec 17 16:59:37 2003 From: pmaupin at codespeak.net (pmaupin at codespeak.net) Date: Wed, 17 Dec 2003 16:59:37 +0100 (MET) Subject: [pypy-svn] rev 2452 - in pypy/trunk/src/pypy/objspace/std: . test Message-ID: <20031217155937.5B0585A164@thoth.codespeak.net> Author: pmaupin Date: Wed Dec 17 16:59:36 2003 New Revision: 2452 Modified: pypy/trunk/src/pypy/objspace/std/listobject.py pypy/trunk/src/pypy/objspace/std/test/test_listobject.py Log: Added stride 1 slice assignments Modified: pypy/trunk/src/pypy/objspace/std/listobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/listobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/listobject.py Wed Dec 17 16:59:36 2003 @@ -177,24 +177,34 @@ items[idx] = w_any return space.w_None -# XXX not trivial! def setitem__List_Slice_List(space, w_list, w_slice, w_list2): - raise Exception, "not done!" -## items = w_list.ob_item -## w_length = space.wrap(w_list.ob_size) -## w_start, w_stop, w_step, w_slicelength = w_slice.indices(w_length) -## start = space.unwrap(w_start) -## step = space.unwrap(w_step) -## slicelength = space.unwrap(w_slicelength) -## assert slicelength >= 0 -## w_res = W_ListObject(space, []) -## _list_resize(w_res, slicelength) -## subitems = w_res.ob_item -## for i in range(slicelength): -## subitems[i] = items[start] -## start += step -## w_res.ob_size = slicelength -## return w_res + w_length = space.wrap(w_list.ob_size) + start, stop, step, slicelength = slicetype.indices4(space,w_slice,w_list.ob_size) + assert slicelength >= 0 + if step != 1: + raise OperationError(space.w_NotImplementedError, + space.wrap("Assignment to extended slices not implemented yet.")) + len2 = w_list2.ob_size + delta = len2 - slicelength + oldsize = w_list.ob_size + newsize = oldsize + delta + _list_resize(w_list, newsize) + items = w_list.ob_item + w_list.ob_size = newsize + if delta > 0: + r = range(newsize-1,stop+delta-1,-1) + elif delta < 0: + r = range(stop+delta,newsize) + else: + r = () + + for i in r: + items[i] = items[i-delta] + + for i in range(len2): + # items[start+i] = space.getitem(w_list2,space.wrap(i)) + items[start+i] = w_list2.ob_item[i] + return space.w_None def repr__List(space, w_list): w = space.wrap Modified: pypy/trunk/src/pypy/objspace/std/test/test_listobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/test/test_listobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/test/test_listobject.py Wed Dec 17 16:59:36 2003 @@ -76,9 +76,9 @@ w_result = self.space.getitem(w_list, w_slice) self.assertEqual(self.space.unwrap(w_result), expected) - for testlist in [[], [5,3,99], list(range(5,555,10))]: - for start in [-2, -1, 0, 1, 10]: - for end in [-1, 0, 2, 999]: + for testlist in [[], [5,3,99]]: + for start in [-2, 0, 1, 10]: + for end in [-1, 2, 999]: test1(testlist, start, end, 1, testlist[start:end]) test1([5,7,1,4], 3, 1, -2, [4,]) @@ -88,6 +88,24 @@ test1([5,7,1,4], -3, 11, 2, [7, 4]) test1([5,7,1,4], -5, 11, 2, [5, 1]) + def test_setslice(self): + w = self.space.wrap + + def test1(lhslist, start, stop, rhslist, expected): + w_slice = self.space.newslice(w(start), w(stop), w(1)) + w_lhslist = W_ListObject(self.space, [w(i) for i in lhslist]) + w_rhslist = W_ListObject(self.space, [w(i) for i in rhslist]) + self.space.setitem(w_lhslist, w_slice, w_rhslist) + self.assertEqual(self.space.unwrap(w_lhslist), expected) + + + test1([5,7,1,4], 1, 3, [9,8], [5,9,8,4]) + test1([5,7,1,4], 1, 3, [9], [5,9,4]) + test1([5,7,1,4], 1, 3, [9,8,6],[5,9,8,6,4]) + test1([5,7,1,4], 1, 3, [], [5,4]) + test1([5,7,1,4], 2, 2, [9], [5,7,9,1,4]) + test1([5,7,1,4], 0, 99,[9,8], [9,8]) + def test_add(self): w = self.space.wrap w_list0 = W_ListObject(self.space, []) @@ -115,28 +133,6 @@ w_res = self.space.mul(w(n), w_lis) self.assertEqual_w(w_lis3, w_res) - def test_getslice(self): - # this takes aaagggeeesss!!! - w = self.space.wrap - - def test1(testlist, start, stop, step, expected): - w_slice = self.space.newslice(w(start), w(stop), w(step)) - w_list = W_ListObject(self.space, [w(i) for i in testlist]) - w_result = self.space.getitem(w_list, w_slice) - self.assertEqual(self.space.unwrap(w_result), expected) - - for testlist in [[], [5,3,99], list(range(5,555,10))]: - for start in [-2, -1, 0, 1, 10]: - for end in [-1, 0, 2, 999]: - test1(testlist, start, end, 1, testlist[start:end]) - - test1([5,7,1,4], 3, 1, -2, [4,]) - test1([5,7,1,4], 3, 0, -2, [4, 7]) - test1([5,7,1,4], 3, -1, -2, []) - test1([5,7,1,4], -2, 11, 2, [1]) - test1([5,7,1,4], -3, 11, 2, [7, 4]) - test1([5,7,1,4], -5, 11, 2, [5, 1]) - def test_setitem(self): w = self.space.wrap w_list = W_ListObject(self.space, [w(5), w(3)]) From tomek at codespeak.net Wed Dec 17 17:00:30 2003 From: tomek at codespeak.net (tomek at codespeak.net) Date: Wed, 17 Dec 2003 17:00:30 +0100 (MET) Subject: [pypy-svn] rev 2453 - in pypy/trunk/src/pypy: objspace tool Message-ID: <20031217160030.E9F2A5A164@thoth.codespeak.net> Author: tomek Date: Wed Dec 17 17:00:30 2003 New Revision: 2453 Modified: pypy/trunk/src/pypy/objspace/trace.py pypy/trunk/src/pypy/tool/pydis.py Log: intermiedate check-in Modified: pypy/trunk/src/pypy/objspace/trace.py ============================================================================== --- pypy/trunk/src/pypy/objspace/trace.py (original) +++ pypy/trunk/src/pypy/objspace/trace.py Wed Dec 17 17:00:30 2003 @@ -33,115 +33,105 @@ return getattr(self.fn, name) -def Trace(spacecls = StdObjSpace): - class TraceObjSpace(spacecls): - full_exceptions = False +class TraceObjSpace: + + def __init__(self, space): + self.tracing = 0 + self.ignore_up_to_frame = None + self.space = space + method_names = [ii[0] for ii in ObjSpace.MethodTable] + for key in method_names: + if key in method_names: + item = getattr(self.space, key) + l = Tracer(key, item, self) + setattr(self, key, new.instancemethod(l, self, TraceObjSpace)) + + + def __getattr__(self, name): + return getattr(self.space, name) - def initialize(self): - self.tracing = 0 - self.ignore_up_to_frame = None - spacecls.initialize(self) - method_names = [ii[0] for ii in ObjSpace.MethodTable] - for key in method_names: - if key in method_names: - item = getattr(self, key) - l = Tracer(key, item, self) - setattr(self, key, new.instancemethod(l, self, TraceObjSpace)) - def start_tracing(self): + def getexecutioncontext(self): + return TraceExecutionContext(self) + + + def start_tracing(self): + self.tracing = 1 + self.log_list = [] + + + def stop_tracing(self): + self.tracing = 0 + + + def handle_default(self, frame, opcode, opname, oparg, ins_idx): + return opcode, opname, "", ins_idx + + + def handle_SET_LINENO(self, frame, opcode, opname, oparg, ins_idx): + return opcode, opname, "%s" % oparg, ins_idx + + + def handle_LOAD_CONST(self, frame, opcode, opname, oparg, ins_idx): + return opcode, opname, "%s (%r)" % (oparg, frame.getconstant(oparg)), ins_idx + + + def handle_LOAD_FAST(self, frame, opcode, opname, oparg, ins_idx): + return opcode, opname, "%s (%s)" % (oparg, frame.getlocalvarname(oparg)), ins_idx + + + def notify_on_operation(self, name, args): + if self.tracing: + #args = [self.space.unwrap(arg) for arg in args] + self.log_list[-1][1].append((name, args)) + + + def dump(self): + return self.log_list + + + def rdump(self): + bytecodes = [] + res = [] + for bytecode, ops in self.log_list: + bytecodes.append(bytecode) + if ops: + op = ops.pop(0) + res.append((op, bytecodes)) + bytecodes = [] + for op in ops: + res.append((op, [])) + + #the rest + res.append((None, bytecodes)) + return res + + + def notify_on_bytecode(self, frame): + + if not self.tracing and self.ignore_up_to_frame is frame: self.tracing = 1 - self.log_list = [] + self.ignore_up_to_frame = None + + if self.tracing: + opcode, opname, oparg, ins_idx = frame.examineop() + handle_method = getattr(self, "handle_%s" % opname, self.handle_default) - def stop_tracing(self): - self.tracing = 0 + opcode, opname, oparg, ins_idx = handle_method(frame, opcode, opname, oparg, ins_idx) + self.log_list.append(((opcode, opname, oparg, ins_idx), [])) + if opname in DONT_TRACK_BYTECODES: + self.ignore_up_to_frame = frame + self.tracing = 0 - def createexecutioncontext(self): - "Factory function for execution contexts." - return TraceExecutionContext(self) - - def handle_default(self, frame, opcode, opname, oparg, ins_idx): - return opcode, opname, "", ins_idx - - def handle_SET_LINENO(self, frame, opcode, opname, oparg, ins_idx): - return opcode, opname, "%s" % oparg, ins_idx - - def handle_LOAD_CONST(self, frame, opcode, opname, oparg, ins_idx): - return opcode, opname, "%s (%r)" % (oparg, frame.getconstant(oparg)), ins_idx - - def handle_LOAD_FAST(self, frame, opcode, opname, oparg, ins_idx): - return opcode, opname, "%s (%s)" % (oparg, frame.getlocalvarname(oparg)), ins_idx - - def notify_on_bytecode(self, frame): - if not self.tracing and self.ignore_up_to_frame is frame: - self.tracing = 1 - self.ignore_up_to_frame = None - if self.tracing: - opcode, opname, oparg, ins_idx = frame.examineop() - handle_method = getattr(self, "handle_%s" % opname, self.handle_default) - - opcode, opname, oparg, ins_idx = handle_method(frame, opcode, opname, oparg, ins_idx) - self.log_list.append(((opcode, opname, oparg, ins_idx), [])) - if opname in DONT_TRACK_BYTECODES: - self.ignore_up_to_frame = frame - self.tracing = 0 - - - def notify_on_operation(self, name, args): - if self.tracing: - self.log_list[-1][1].append((name, args)) - - - def dump(self): - return self.log_list - - def rdump(self): - bytecodes = [] - res = [] - for bytecode, ops in self.log_list: - bytecodes.append(bytecode) - if ops: - op = ops.pop(0) - res.append((op, bytecodes)) - bytecodes = [] - for op in ops: - res.append((op, [])) - - #the rest - res.append((None, bytecodes)) - return res - - return TraceObjSpace() + def __hash__(self): + return hash(self.space) +Trace = TraceObjSpace Space = Trace # ______________________________________________________________________ # End of trace.py - -## if __name__ == "__main__": - - -## s = Trace(TrivialObjSpace) - -## def a(b): -## print "x" -## if b > 2: -## return b*2 -## else: -## return b - -## print run_function(s, a, 1) - -## print ">>>>>>" -## for line in s.dump(): -## ((opcode, opname, arg, ins_idx), spaceops) = line -## print ins_idx, opname, spaceops -## print ">>>>>>" -## #for line in s.rdump(): -## # print line - -## #import dis -## #dis.dis(a) Modified: pypy/trunk/src/pypy/tool/pydis.py ============================================================================== --- pypy/trunk/src/pypy/tool/pydis.py (original) +++ pypy/trunk/src/pypy/tool/pydis.py Wed Dec 17 17:00:30 2003 @@ -115,6 +115,13 @@ return _trace_function(trace_space, True, fn, *arg, **kwds) +def trace_function2(space, fn, *arg, **kwds): + return _trace_function(Trace(space), False, fn, *arg, **kwds) + +def rtrace_function2(space, fn, *arg, **kwds): + return _trace_function(Trace(space), True, fn, *arg, **kwds) + + ## # Create space From pmaupin at codespeak.net Wed Dec 17 17:07:55 2003 From: pmaupin at codespeak.net (pmaupin at codespeak.net) Date: Wed, 17 Dec 2003 17:07:55 +0100 (MET) Subject: [pypy-svn] rev 2454 - pypy/trunk/src/pypy/objspace/std Message-ID: <20031217160755.991895A164@thoth.codespeak.net> Author: pmaupin Date: Wed Dec 17 17:07:54 2003 New Revision: 2454 Modified: pypy/trunk/src/pypy/objspace/std/listobject.py Log: Fix assigning to slice from same list Modified: pypy/trunk/src/pypy/objspace/std/listobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/listobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/listobject.py Wed Dec 17 17:07:54 2003 @@ -200,9 +200,13 @@ for i in r: items[i] = items[i-delta] - - for i in range(len2): - # items[start+i] = space.getitem(w_list2,space.wrap(i)) + + # Always copy starting from the right to avoid + # having to make a shallow copy in the case where + # the source and destination lists are the same list. + r = range(len2) + r.reverse() + for i in r: items[start+i] = w_list2.ob_item[i] return space.w_None From pmaupin at codespeak.net Wed Dec 17 17:10:09 2003 From: pmaupin at codespeak.net (pmaupin at codespeak.net) Date: Wed, 17 Dec 2003 17:10:09 +0100 (MET) Subject: [pypy-svn] rev 2455 - pypy/trunk/src/pypy/objspace/std Message-ID: <20031217161009.736055A164@thoth.codespeak.net> Author: pmaupin Date: Wed Dec 17 17:10:08 2003 New Revision: 2455 Modified: pypy/trunk/src/pypy/objspace/std/listobject.py Log: Simplify ranges in setslice Modified: pypy/trunk/src/pypy/objspace/std/listobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/listobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/listobject.py Wed Dec 17 17:10:08 2003 @@ -191,12 +191,9 @@ _list_resize(w_list, newsize) items = w_list.ob_item w_list.ob_size = newsize + r = range(stop+delta,newsize) if delta > 0: - r = range(newsize-1,stop+delta-1,-1) - elif delta < 0: - r = range(stop+delta,newsize) - else: - r = () + r.reverse() for i in r: items[i] = items[i-delta] From pmaupin at codespeak.net Wed Dec 17 17:19:50 2003 From: pmaupin at codespeak.net (pmaupin at codespeak.net) Date: Wed, 17 Dec 2003 17:19:50 +0100 (MET) Subject: [pypy-svn] rev 2456 - pypy/trunk/src/pypy/objspace/std Message-ID: <20031217161950.4D3625A164@thoth.codespeak.net> Author: pmaupin Date: Wed Dec 17 17:19:49 2003 New Revision: 2456 Modified: pypy/trunk/src/pypy/objspace/std/listobject.py Log: Add tuple assignment to list slices Modified: pypy/trunk/src/pypy/objspace/std/listobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/listobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/listobject.py Wed Dec 17 17:19:49 2003 @@ -2,6 +2,8 @@ from listtype import W_ListType from intobject import W_IntObject from sliceobject import W_SliceObject +from tupleobject import W_TupleObject + import slicetype from pypy.interpreter import gateway from restricted_int import r_int, r_uint @@ -178,13 +180,18 @@ return space.w_None def setitem__List_Slice_List(space, w_list, w_slice, w_list2): - w_length = space.wrap(w_list.ob_size) + return _setitem_slice_helper(space, w_list, w_slice, w_list2.ob_item, w_list2.ob_size) + +def setitem__List_Slice_Tuple(space, w_list, w_slice, w_tuple): + t = w_tuple.wrappeditems + return _setitem_slice_helper(space, w_list, w_slice, t, len(t)) + +def _setitem_slice_helper(space, w_list, w_slice, sequence2, len2): start, stop, step, slicelength = slicetype.indices4(space,w_slice,w_list.ob_size) assert slicelength >= 0 if step != 1: raise OperationError(space.w_NotImplementedError, space.wrap("Assignment to extended slices not implemented yet.")) - len2 = w_list2.ob_size delta = len2 - slicelength oldsize = w_list.ob_size newsize = oldsize + delta @@ -194,7 +201,7 @@ r = range(stop+delta,newsize) if delta > 0: r.reverse() - + for i in r: items[i] = items[i-delta] @@ -204,7 +211,7 @@ r = range(len2) r.reverse() for i in r: - items[start+i] = w_list2.ob_item[i] + items[start+i] = sequence2[i] return space.w_None def repr__List(space, w_list): From pmaupin at codespeak.net Wed Dec 17 17:37:47 2003 From: pmaupin at codespeak.net (pmaupin at codespeak.net) Date: Wed, 17 Dec 2003 17:37:47 +0100 (MET) Subject: [pypy-svn] rev 2457 - pypy/trunk/src/pypy/objspace/std Message-ID: <20031217163747.2645E5A164@thoth.codespeak.net> Author: pmaupin Date: Wed Dec 17 17:37:46 2003 New Revision: 2457 Modified: pypy/trunk/src/pypy/objspace/std/listobject.py Log: Added delitem Modified: pypy/trunk/src/pypy/objspace/std/listobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/listobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/listobject.py Wed Dec 17 17:37:46 2003 @@ -168,6 +168,19 @@ # upto here, lists are nearly identical to tuples, despite the # fact that we now support over-allocation! +def delitem__List_Int(space, w_list, w_idx): + i = w_idx.intval + if i < 0: + i += w_list.ob_size + if i < 0 or i >= w_list.ob_size: + raise OperationError(space.w_IndexError, + space.wrap("list deletion index out of range")) + _del_slice(w_list, i, i+1) + return space.w_None + +def delitem__List_Slice(space, w_list, w_slice): + return _setitem_slice_helper(space, w_list, w_slice, [], 0) + def setitem__List_Int_ANY(space, w_list, w_index, w_any): items = w_list.ob_item idx = w_index.intval From pmaupin at codespeak.net Wed Dec 17 18:00:51 2003 From: pmaupin at codespeak.net (pmaupin at codespeak.net) Date: Wed, 17 Dec 2003 18:00:51 +0100 (MET) Subject: [pypy-svn] rev 2458 - pypy/trunk/src/pypy/objspace/std Message-ID: <20031217170051.67BB65A164@thoth.codespeak.net> Author: pmaupin Date: Wed Dec 17 18:00:50 2003 New Revision: 2458 Modified: pypy/trunk/src/pypy/objspace/std/listobject.py pypy/trunk/src/pypy/objspace/std/listtype.py Log: Add optional arguments to [].index() Modified: pypy/trunk/src/pypy/objspace/std/listobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/listobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/listobject.py Wed Dec 17 18:00:50 2003 @@ -376,10 +376,20 @@ raise OperationError(space.w_IndexError, space.wrap("list.remove(x): x not in list")) -def list_index__List_ANY(space, w_list, w_any): +def list_index__List_ANY_Int_Int(space, w_list, w_any, w_start, w_stop): eq = space.eq items = w_list.ob_item - for i in range(w_list.ob_size): + size = w_list.ob_size + start = space.unwrap(w_start) + if start < 0: + start += size + start = min(max(0,start),size) + stop = space.unwrap(w_stop) + if stop < 0: + stop += size + stop = min(max(start,stop),size) + + for i in range(start,stop): cmp = eq(items[i], w_any) if space.is_true(cmp): return space.wrap(i) Modified: pypy/trunk/src/pypy/objspace/std/listtype.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/listtype.py (original) +++ pypy/trunk/src/pypy/objspace/std/listtype.py Wed Dec 17 18:00:50 2003 @@ -1,6 +1,6 @@ from pypy.objspace.std.objspace import * from typeobject import W_TypeObject - +from sys import maxint class W_ListType(W_TypeObject): @@ -11,7 +11,7 @@ list_extend = MultiMethod('extend', 2) list_pop = MultiMethod('pop', 2, defaults=(-1,)) list_remove = MultiMethod('remove', 2) - list_index = MultiMethod('index', 2) + list_index = MultiMethod('index', 4, defaults=(0,maxint)) list_count = MultiMethod('count', 2) list_reverse= MultiMethod('reverse',1) list_sort = MultiMethod('sort', 1) From sschwarzer at codespeak.net Wed Dec 17 18:49:45 2003 From: sschwarzer at codespeak.net (sschwarzer at codespeak.net) Date: Wed, 17 Dec 2003 18:49:45 +0100 (MET) Subject: [pypy-svn] rev 2459 - pypy/trunk/src/pypy/tool Message-ID: <20031217174945.01FBC5A164@thoth.codespeak.net> Author: sschwarzer Date: Wed Dec 17 18:49:45 2003 New Revision: 2459 Added: pypy/trunk/src/pypy/tool/newtest.py Log: Start of a new unit testing framework (hopefully sufficiently flexible but not too complicated). Much is still missing, though. Added: pypy/trunk/src/pypy/tool/newtest.py ============================================================================== --- (empty file) +++ pypy/trunk/src/pypy/tool/newtest.py Wed Dec 17 18:49:45 2003 @@ -0,0 +1,133 @@ +import autopath +import imp +import os +import sys +import unittest +import vpath + + +# named constants for test result status values +SUCCESS = 'success' +ERROR = 'error' +FAILURE = 'failure' +IGNORED = 'ignored' +SKIPPED = 'skipped' + +class TestResult: + """Represent the result of a run of a test item.""" + def __init__(self, item, status=None, fullname=None, traceback=None): + # one of SUCCESS, ERROR, FAILURE, IGNORED, SKIPPED + self.status = None + # name of the test method (without class or module name) + self.methodname = None + # full method name (with module path and class name) + self.fullname = None + # traceback object if applicable, else None + self.traceback = None + # formatted traceback (a string) + self.formatted_traceback = None + + +class TestItem: + """Represent a single test method from a TestCase class.""" + def __init__(self, testmethod): + #TODO implement the code to initialze these attributes + self.module = None + self.file = None + self.lineno = None + self.source = None + self._method = testmethod + self._class = testmethod.__class__ + + def run(self): + """Run this TestItem and return a corresponding TestResult object.""" + #XXX at a later time, this method may accept an object space + # as argument + + def __str__(self): + return "TestItem from method %s" % self._method + + __repr__ = __str__ + + +class TestSuite: + """Represent a collection of test items.""" + def __init__(self): + self.items = [] + + def _items_from_module(self, module): + """Return a list of TestItems read from the given module.""" + items = [] + # scan the module for classes derived from unittest.TestCase + for obj in vars(module).values(): + try: + is_testclass = issubclass(obj, unittest.TestCase) + except TypeError: + # not a class at all; ignore it + continue + if not is_testclass: + continue + # scan class for test methods + for obj in vars(obj).values(): + if hasattr(obj, 'func_code') and \ + obj.__name__.startswith("test"): + items.append(TestItem(obj)) + return items + + def _module_from_modpath(self, modpath): + """ + Return a module object derived from the module path + (e. g. "pypy.module.builtin.test.test_minmax"). + """ + # This __import__ call is only used to ensure that the module + # is present in sys.modules. Unfortunately, the module returned + # from the __import__ function doesn't correspond to the last + # component of the module path but the first. In the example + # listed in the docstring we thus would get the pypy module, + # not the test_minmax module. + __import__(modpath) + return sys.modules[modpath] + + def initfromdir(self, dirname, filterfunc=None, recursive=True, + loader=None): + """ + Init this suite by reading the directory denoted by dirname, + then find all test modules in it. Test modules are files that + comply with the shell pattern shell_pattern "test_*.py". + + filterfunc is a callable that can be used to filter the test + modules by module path. By default, all test modules are used. + + If recursive is true, which is the default, find all test modules + by scanning the start directory recursively. The argument loader + may be set to a test loader class to use. By default, the + TestLoader class from the unittest module is used. + """ + dirname = vpath.getlocal(dirname) + if loader is None: + loader = unittest.TestLoader() + + def testfilefilter(path): + return path.isfile() and path.fnmatch('test_*.py') + def recfilter(path): + return recursive and vpath.nodotfile(path) + + for testfn in dirname.visit(testfilefilter, recfilter): + # strip the leading pypy directory and the .py suffix + modpath = str(testfn)[len(autopath.pypydir)+1:-3] + modpath = 'pypy.' + modpath.replace(os.sep, '.') + if (filterfunc is None) or filterfunc(modpath): + try: + module = self._module_from_modpath(modpath) + items = self._items_from_module(module) + except: + print "skipping testfile (failed loading it)", modpath + else: + self.items.extend(items) + + +if __name__ == '__main__': + ts = TestSuite() + ts.initfromdir(".") + print ts.items + From sschwarzer at codespeak.net Wed Dec 17 19:20:18 2003 From: sschwarzer at codespeak.net (sschwarzer at codespeak.net) Date: Wed, 17 Dec 2003 19:20:18 +0100 (MET) Subject: [pypy-svn] rev 2460 - pypy/trunk/src/pypy/tool Message-ID: <20031217182018.EA6335A164@thoth.codespeak.net> Author: sschwarzer Date: Wed Dec 17 19:20:14 2003 New Revision: 2460 Modified: pypy/trunk/src/pypy/tool/newtest.py (contents, props changed) Log: Use inspect module to find test case classes and methods. Modified: pypy/trunk/src/pypy/tool/newtest.py ============================================================================== --- pypy/trunk/src/pypy/tool/newtest.py (original) +++ pypy/trunk/src/pypy/tool/newtest.py Wed Dec 17 19:20:14 2003 @@ -1,5 +1,5 @@ import autopath -import imp +import inspect import os import sys import unittest @@ -30,14 +30,15 @@ class TestItem: """Represent a single test method from a TestCase class.""" - def __init__(self, testmethod): + def __init__(self, module, cls, testmethod): #TODO implement the code to initialze these attributes self.module = None self.file = None self.lineno = None self.source = None + self._module = module + self._class = cls self._method = testmethod - self._class = testmethod.__class__ def run(self): """Run this TestItem and return a corresponding TestResult object.""" @@ -45,9 +46,11 @@ # as argument def __str__(self): - return "TestItem from method %s" % self._method + return "TestItem from %s.%s.%s" % (self._module.__name__,\ + self._class.__name__, self._method.__name__) - __repr__ = __str__ + def __repr__(self): + return "%s at %#x" % (str(self), id(self)) class TestSuite: @@ -60,18 +63,13 @@ items = [] # scan the module for classes derived from unittest.TestCase for obj in vars(module).values(): - try: - is_testclass = issubclass(obj, unittest.TestCase) - except TypeError: - # not a class at all; ignore it - continue - if not is_testclass: - continue - # scan class for test methods - for obj in vars(obj).values(): - if hasattr(obj, 'func_code') and \ - obj.__name__.startswith("test"): - items.append(TestItem(obj)) + if inspect.isclass(obj) and issubclass(obj, unittest.TestCase): + # we found a TestCase class, now scan it for test methods + for obj2 in vars(obj).values(): + # ismethod doesn't seem to work here + if inspect.isfunction(obj2) and \ + obj2.__name__.startswith("test"): + items.append(TestItem(module, obj, obj2)) return items def _module_from_modpath(self, modpath): @@ -122,6 +120,7 @@ items = self._items_from_module(module) except: print "skipping testfile (failed loading it)", modpath + raise else: self.items.extend(items) From sschwarzer at codespeak.net Wed Dec 17 19:20:54 2003 From: sschwarzer at codespeak.net (sschwarzer at codespeak.net) Date: Wed, 17 Dec 2003 19:20:54 +0100 (MET) Subject: [pypy-svn] rev 2461 - pypy/trunk/src/pypy/tool Message-ID: <20031217182054.5C1115A164@thoth.codespeak.net> Author: sschwarzer Date: Wed Dec 17 19:20:53 2003 New Revision: 2461 Modified: pypy/trunk/src/pypy/tool/newtest.py Log: Remove raise statement which was used for debugging. Modified: pypy/trunk/src/pypy/tool/newtest.py ============================================================================== --- pypy/trunk/src/pypy/tool/newtest.py (original) +++ pypy/trunk/src/pypy/tool/newtest.py Wed Dec 17 19:20:53 2003 @@ -120,7 +120,6 @@ items = self._items_from_module(module) except: print "skipping testfile (failed loading it)", modpath - raise else: self.items.extend(items) From sschwarzer at codespeak.net Wed Dec 17 19:30:05 2003 From: sschwarzer at codespeak.net (sschwarzer at codespeak.net) Date: Wed, 17 Dec 2003 19:30:05 +0100 (MET) Subject: [pypy-svn] rev 2462 - pypy/trunk/src/pypy/tool Message-ID: <20031217183005.BBD745A164@thoth.codespeak.net> Author: sschwarzer Date: Wed Dec 17 19:30:04 2003 New Revision: 2462 Modified: pypy/trunk/src/pypy/tool/newtest.py Log: Get filename and source code for a test method. Modified: pypy/trunk/src/pypy/tool/newtest.py ============================================================================== --- pypy/trunk/src/pypy/tool/newtest.py (original) +++ pypy/trunk/src/pypy/tool/newtest.py Wed Dec 17 19:30:04 2003 @@ -31,14 +31,13 @@ class TestItem: """Represent a single test method from a TestCase class.""" def __init__(self, module, cls, testmethod): - #TODO implement the code to initialze these attributes - self.module = None - self.file = None - self.lineno = None - self.source = None - self._module = module - self._class = cls - self._method = testmethod + self.file = inspect.getsourcefile(module) + self.source = inspect.getsource(testmethod) + self.module = module + self.cls = cls + self.method = testmethod + # we can only derive this from a frame or traceback? + #self.lineno = None def run(self): """Run this TestItem and return a corresponding TestResult object.""" @@ -46,8 +45,8 @@ # as argument def __str__(self): - return "TestItem from %s.%s.%s" % (self._module.__name__,\ - self._class.__name__, self._method.__name__) + return "TestItem from %s.%s.%s" % (self.module.__name__,\ + self.cls.__name__, self.method.__name__) def __repr__(self): return "%s at %#x" % (str(self), id(self)) From guenter at codespeak.net Wed Dec 17 20:09:46 2003 From: guenter at codespeak.net (guenter at codespeak.net) Date: Wed, 17 Dec 2003 20:09:46 +0100 (MET) Subject: [pypy-svn] rev 2463 - pypy/trunk/src/pypy/objspace/std Message-ID: <20031217190946.5BA225A164@thoth.codespeak.net> Author: guenter Date: Wed Dec 17 20:09:45 2003 New Revision: 2463 Modified: pypy/trunk/src/pypy/objspace/std/stringtype.py Log: neue Methode translate Modified: pypy/trunk/src/pypy/objspace/std/stringtype.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/stringtype.py (original) +++ pypy/trunk/src/pypy/objspace/std/stringtype.py Wed Dec 17 20:09:45 2003 @@ -37,6 +37,7 @@ str_expandtabs = MultiMethod('expandtabs', 2, defaults=(8,)) str_splitlines = MultiMethod('splitlines', 2, defaults=(0,)) str_startswith = MultiMethod('startswith', 2) #[optional arguments not supported now] + str_translate = MultiMethod('translate', 3, defaults=('',)) #unicode mimic not supported now registerimplementation(W_StringType) From guenter at codespeak.net Wed Dec 17 20:12:03 2003 From: guenter at codespeak.net (guenter at codespeak.net) Date: Wed, 17 Dec 2003 20:12:03 +0100 (MET) Subject: [pypy-svn] rev 2464 - pypy/trunk/src/pypy/objspace/std Message-ID: <20031217191203.E32EC5A164@thoth.codespeak.net> Author: guenter Date: Wed Dec 17 20:12:03 2003 New Revision: 2464 Modified: pypy/trunk/src/pypy/objspace/std/stringobject.py Log: Neue Methode translate Modified: pypy/trunk/src/pypy/objspace/std/stringobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/stringobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/stringobject.py Wed Dec 17 20:12:03 2003 @@ -66,12 +66,13 @@ strip def str_strip__String_String(space, w_self, w_chars): swapcase OK title def str_title__String(space, w_self): -translate +translate OK upper def str_upper__String(space, w_self): zfill OK """ from pypy.objspace.std.objspace import * +from pypy.interpreter import gateway from stringtype import W_StringType from intobject import W_IntObject from sliceobject import W_SliceObject @@ -723,7 +724,21 @@ return space.wrap("".join(buf)) - + +def app_str_translate__String_String_String(s, table, deletechars=''): + """charfilter - unicode handling is not implemented + + Return a copy of the string where all characters occurring + in the optional argument deletechars are removed, and the + remaining characters have been mapped through the given translation table, + which must be a string of length 256""" + + L = [ table[ord(s[i])] for i in range(len(s)) if s[i] not in deletechars ] + return ''.join(L) + +str_translate__String_String_String = gateway.app2interp(app_str_translate__String_String_String) + + def unwrap__String(space, w_str): return w_str._value From arigo at codespeak.net Thu Dec 18 10:00:46 2003 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 18 Dec 2003 10:00:46 +0100 (MET) Subject: [pypy-svn] rev 2465 - in pypy/trunk/src/pypy/annotation: . test Message-ID: <20031218090046.39B725A4F8@thoth.codespeak.net> Author: arigo Date: Thu Dec 18 10:00:44 2003 New Revision: 2465 Modified: pypy/trunk/src/pypy/annotation/annset.py pypy/trunk/src/pypy/annotation/model.py pypy/trunk/src/pypy/annotation/test/test_annset.py Log: New annotation model seems to be working. Modified: pypy/trunk/src/pypy/annotation/annset.py ============================================================================== --- pypy/trunk/src/pypy/annotation/annset.py (original) +++ pypy/trunk/src/pypy/annotation/annset.py Thu Dec 18 10:00:44 2003 @@ -13,37 +13,26 @@ def __init__(self, annlist=basicannotations): self.annlist = list(annlist) # List of annotations - self._shared = {} - self.forward_deps = {} + self._normalized = {} # maps SomeValues to some 'standard' one that + # is shared with it - def getsharelist(self, someval): - return self._shared.get(someval, [someval]) + def normalized(self, someval): + return self._normalized.get(someval, someval) def setshared(self, someval1, someval2): - list1 = self.getsharelist(someval1) - list2 = self.getsharelist(someval2) - newlist = list1 + list2 - for someval in newlist: - self._shared[someval] = newlist + someval1 = self.normalized(someval1) + someval2 = self.normalized(someval2) + for key, value in self._normalized.items(): + if value is someval1: + self._normalized[key] = someval2 + self._normalized[someval1] = someval2 def isshared(self, someval1, someval2): - return (self._shared.get(someval1, someval1) is - self._shared.get(someval2, someval2)) + return self.normalized(someval1) is self.normalized(someval2) - def tempid(self, someval): - return id(self.getsharelist(someval)[0]) - - def annequal(self, ann1, ann2): - if ann1.predicate != ann2.predicate: - return False - for a1, a2 in zip(ann1.args, ann2.args): - if not self.isshared(a1, a2): - return False - return True - - def temporarykey(self, ann): - """ a temporary hashable representation of an annotation """ - return (ann.predicate, tuple([self.tempid(arg) for arg in ann.args])) + def normalizeann(self, ann): + "Normalize the annotation's arguments in-place." + ann.args = [self.normalized(a) for a in ann.args] def dump(self): # debugging for ann in self.enumerate(): @@ -62,6 +51,9 @@ """ yield (matchanns, matchvalue) tuples with 'matchanns' beeing a list of matching annotations and 'matchvalue' beeing the queried value. """ + self.normalizeann(query) + for queryann in querylist: + self.normalizeann(queryann) # slightly limited implementation for ease of coding :-) assert query.args.count(QUERYARG) == 1, ( @@ -82,12 +74,13 @@ def _annmatches(self, queryann): """ yield annotations matching the given queryannotation. """ + self.normalizeann(queryann) testindices = [i for i in range(queryann.predicate.arity) if queryann.args[i] is not QUERYARG] for ann in self.annlist: if ann.predicate == queryann.predicate: for i in testindices: - if not self.isshared(ann.args[i], queryann.args[i]): + if ann.args[i] is not queryann.args[i]: break else: yield ann @@ -125,37 +118,107 @@ # Such keys are temporary because making SomeValues shared can # change the temporarykey(), but this doesn't occur during # one call to simplify(). + + def temporarykey(ann): + self.normalizeann(ann) + return ann.predicate, tuple(ann.args) allkeys = {} # map temporarykeys to Annotation instances for ann in self.annlist: - key = self.temporarykey(ann) + key = temporarykey(ann) if key in allkeys: # duplicate? previous = allkeys[key] - if ann in self.forward_deps: - deps = self.forward_deps.setdefault(previous, []) - deps += self.forward_deps[ann] # merge + previous.forward_deps += ann.forward_deps # merge else: allkeys[key] = ann killkeys = {} # set of temporarykeys of annotations to remove for ann in kill: - killkeys[self.temporarykey(ann)] = True + killkeys[temporarykey(ann)] = True pending = killkeys.keys() for key in pending: if key in allkeys: ann = allkeys[key] del allkeys[key] # remove annotations from the dict - if ann in self.forward_deps: - for dep in self.forward_deps[ann]: # propagate dependencies - depkey = self.temporarykey(dep) - if depkey not in killkeys: - killkeys[depkey] = True - pending.append(depkey) - del self.forward_deps[ann] + for dep in ann.forward_deps: # propagate dependencies + depkey = temporarykey(dep) + if depkey not in killkeys: + killkeys[depkey] = True + pending.append(depkey) self.annlist = allkeys.values() + def adddependency(self, hypothesisann, conclusionann): + hypothesisann.forward_deps.append(conclusionann) + + def merge(self, oldcell, newcell): + """Update the heap to account for the merging of oldcell and newcell. + Return the merged cell.""" + oldcell = self.normalized(oldcell) + newcell = self.normalized(newcell) + + if newcell is blackholevalue or newcell is oldcell: + return oldcell + elif oldcell is blackholevalue: + return newcell + + # if 'oldcell' or 'newcell' is immutable, we should not + # modify the annotations about it. If one of them is mutable, + # then we must update its annotations and return it. As a + # consequence if both are mutable then we must return them both, + # i.e. make them shared. + + mutablecells = [] + deleting = [] + annlist = self.annlist + for cell, othercell in [(oldcell, newcell), (newcell, oldcell)]: + if ANN.immutable[cell] not in annlist: + # for each mutable 'cell', kill the annotation that are + # talking about 'cell' but not existing for 'othercell'. + for ann in annlist: + if cell in ann.args: + otherann = ann.copy(renameargs={cell: othercell}) + if otherann not in annlist: + deleting.append(ann) + mutablecells.append(cell) + + if mutablecells: + # if there is at least one mutable cell we must return it. + # if there are two mutable cells we must merge them. + if len(mutablecells) == 2: + self.setshared(oldcell, newcell) + self.simplify(kill=deleting) + return self.normalized(mutablecells[0]) + else: + # no mutable cell, we can create a new result cell + # with only the common annotations. + common = [] + deleting = False # False if annotations of oldcell + # == annotations common annotations + for ann in annlist: + if oldcell in ann.args: + newann = ann.copy(renameargs={oldcell: newcell}) + try: + i = annlist.index(newann) + except ValueError: + deleting = True # this annotation about 'oldcell' + # is no longer there about 'newcell'. + else: + newann = annlist[i] # existing Annotation + common.append((ann, newann)) + + if not deleting: + return oldcell # nothing must be removed from oldcell + else: + resultcell = SomeValue() # invent a new cell + for oldann, newann in common: + resultann = newann.copy(renameargs={newcell: resultcell}) + annlist.append(resultann) + self.adddependency(oldann, resultann) + self.adddependency(newann, resultann) + return resultcell + class Recorder: """A recorder contains methods to look for annotations in the @@ -181,10 +244,10 @@ def set(self, ann): """Insert the annotation into the AnnotationSet, recording dependency from all previous queries done on this Recorder instance.""" + self.annset.normalizeann(ann) self.annset.annlist.append(ann) for previous_ann in self.using_annotations: - deps = self.annset.forward_deps.setdefault(previous_ann, []) - deps.append(ann) + self.annset.adddependency(previous_ann, ann) def check_type(self, someval, checktype): return bool(self.query(ANN.type[someval, QUERYARG], @@ -198,59 +261,6 @@ self.set(ANN.immutable[someval]) ''' - def merge(self, oldcell, newcell): - """Update the heap to account for the merging of oldcell and newcell. - Return the merged cell.""" - if newcell is nothingyet or newcell == oldcell: - return oldcell - elif oldcell is nothingyet: - return newcell - else: - # any annotation or "constantness" about oldcell that must be killed? - deleting = isinstance(oldcell, XConstant) - # find the annotations common to oldcell and newcell - common = [] - for ann in self.annlist: - if oldcell in ann.args or oldcell == ann.result: - test1 = rename(ann, oldcell, newcell) - test2 = rename(ann, newcell, oldcell) # may equal 'ann' - if test1 in self.annlist and test2 in self.annlist: - common.append(test1) - else: - deleting = True - # the involved objects are immutable if we have both - # 'immutable() -> oldcell' and 'immutable() -> newcell' - if Annotation('immutable', [], newcell) in common: - # for immutable objects we can create a new cell if necessary - if not deleting: - return oldcell # nothing must be removed from oldcell - else: - resultcell = XCell() # invent a new cell - for ann in common: - self.annlist.append(rename(ann, newcell, resultcell)) - return resultcell - else: - if Annotation('immutable', [], oldcell) in self.annlist: - pass # old was immutable, don't touch it - elif Annotation('immutable', [], newcell) in self.annlist: - # new is immutable, old was not, inverse the roles - oldcell, newcell = newcell, oldcell - else: - # two mutable objects: we identify oldcell and newcell - newcell.share(oldcell) - # only keep the common annotations by listing all annotations - # to remove, which are the ones that talk about newcell but - # are not in 'common'. - deleting = [] - for ann in self.annlist: - if newcell in ann.args or newcell == ann.result: - if ann not in common: - deleting.append(ann) - # apply changes - self.simplify(kill=deleting) - return newcell - -''' class XXXTransaction: """A transaction contains methods to look for annotations in the AnnotationHeap and create new annotations accordingly. Each @@ -343,3 +353,4 @@ val1, val2, val3 = SomeValue(), SomeValue(), SomeValue() annset = AnnotationSet() +''' Modified: pypy/trunk/src/pypy/annotation/model.py ============================================================================== --- pypy/trunk/src/pypy/annotation/model.py (original) +++ pypy/trunk/src/pypy/annotation/model.py Thu Dec 18 10:00:44 2003 @@ -30,6 +30,7 @@ class ANN: add = Predicate('add', 3) + neg = Predicate('neg', 2) constant = ConstPredicate type = Predicate('type', 2) immutable = Predicate('immutable', 1) @@ -41,6 +42,7 @@ def __init__(self, predicate, *args): self.predicate = predicate # the operation or predicate self.args = list(args) # list of SomeValues + self.forward_deps = [] # for annset.py assert len(args) == predicate.arity # note that for predicates that are simple operations like # op.add, the result is stored as the last argument. @@ -53,9 +55,17 @@ return Annotation(self.predicate, *args) def __repr__(self): - return "Annotation(%s, %s)" % ( + return "" % ( self.predicate, ", ".join(map(debugname, self.args))) + def __eq__(self, other): + return (self.__class__ is other.__class__ and + self.predicate == other.predicate and + self.args == other.args) + + def __ne__(self, other): + return not (self == other) + def debugname(someval, _seen = {}): """ return a simple name for a SomeValue. """ try: @@ -79,7 +89,9 @@ types.FunctionType: 'function', } -# a conventional value for representing 'all Annotations match this one' +# a conventional value for representing 'all Annotations match this one' +# or, equivalently, something for which it is currently impossible to exist +# (when it will exist later it will have less annotations). blackholevalue = Ellipsis # a few values representing 'any value of the given type' Modified: pypy/trunk/src/pypy/annotation/test/test_annset.py ============================================================================== --- pypy/trunk/src/pypy/annotation/test/test_annset.py (original) +++ pypy/trunk/src/pypy/annotation/test/test_annset.py Thu Dec 18 10:00:44 2003 @@ -2,45 +2,62 @@ import autopath from pypy.tool import test -from pypy.annotation.model import ANN, SomeValue +from pypy.annotation.model import ANN, SomeValue, blackholevalue from pypy.annotation.annset import AnnotationSet, QUERYARG +c1,c2,c3,c4 = SomeValue(), SomeValue(), SomeValue(), SomeValue() + + +def assertSameSet(testcase, annset, annotations): + for ann in annotations: + annset.normalizeann(ann) + a = list(annset) + b = annotations + # try to reorder a to match b, without failing if the lists + # are different -- this will be checked by assertEquals() + for i in range(len(b)): + try: + j = i + a[i:].index(b[i]) + except ValueError: + pass + else: + a[i], a[j] = a[j], a[i] + testcase.assertEquals(a, b) + +def assertSameCells(testcase, annset, *cells): + cells = [annset.normalized(c) for c in cells] + for c in cells[1:]: + testcase.assertEquals(cells[0], c) + + class TestAnnotationSet(test.IntTestCase): - - def test_shared_values(self): - c1,c2,c3 = SomeValue(), SomeValue(), SomeValue() + assertSameSet = assertSameSet + assertSameCells = assertSameCells + + def test_isshared(self): a = AnnotationSet() self.assert_(a.isshared(c1, c1)) self.failIf(a.isshared(c1, c2)) a.setshared(c1, c2) self.assert_(a.isshared(c1, c2)) self.assert_(a.isshared(c2, c1)) - self.assertEquals(a.tempid(c1), a.tempid(c2)) - self.failIfEqual(a.tempid(c1), a.tempid(c3)) self.failIf(a.isshared(c1, c3)) a.setshared(c2, c3) self.assert_(a.isshared(c1, c3)) self.assert_(a.isshared(c2, c3)) self.assert_(a.isshared(c3, c1)) - self.assertEquals(a.tempid(c1), a.tempid(c3)) - - def test_shared_values_nomatch(self): - c1,c2 = SomeValue(), SomeValue() - a = AnnotationSet() - id1 = a.tempid(c1) - id2 = a.tempid(c2) - self.assertNotEquals(id1, id2) - def test_annequal(self): - c1,c2,c3,c4 = SomeValue(), SomeValue(), SomeValue(), SomeValue() + def test_normalizeann(self): a = AnnotationSet() + ann1 = ANN.add[c1,c2,c3] + ann2 = ANN.add[c4,c2,c3] a.setshared(c1,c4) - self.assert_(a.annequal(ANN.add[c1,c2,c3], - ANN.add[c4,c2,c3])) + a.normalizeann(ann1) + a.normalizeann(ann2) + self.assertEquals(ann1, ann2) def test_query_one_annotation_arg(self): - c1,c2,c3 = SomeValue(), SomeValue(), SomeValue() lst = [ANN.add[c1, c3, c2]] a = AnnotationSet(lst) clist = a.query(ANN.add[c1, c3, QUERYARG]) @@ -54,7 +71,6 @@ self.assertEquals(clist, []) def test_query_multiple_annotations(self): - c1,c2,c3 = SomeValue(), SomeValue(), SomeValue() lst = [ ANN.add[c1, c3, c2], ANN.type[c2, c3], @@ -65,7 +81,6 @@ self.assertEquals(clist, [c2]) def test_constant(self): - c1,c2,c3 = SomeValue(), SomeValue(), SomeValue() lst = [ ANN.constant(42)[c1], ] @@ -73,9 +88,166 @@ clist = a.query(ANN.constant(42)[QUERYARG]) self.assertEquals(clist, [c1]) -c1,c2,c3,c4 = SomeValue(), SomeValue(), SomeValue(), SomeValue() + def test_simplify(self): + lst = [ANN.add[c1, c3, c2], + ANN.add[c1, c2, c2], + ANN.neg[c2, c3]] + a = AnnotationSet(lst) + a.simplify() + self.assertSameSet(a, lst) + + a.setshared(c2, c3) + a.simplify() + self.assertSameSet(a, lst[1:]) + + def test_kill(self): + ann1 = ANN.add[c1, c3, c2] + lst = [ann1, + ANN.add[c1, c2, c2], + ANN.neg[c2, c3]] + a = AnnotationSet(lst) + a.kill(ann1) + self.assertSameSet(a, lst[1:]) + + def test_adddependency(self): + ann1 = ANN.add[c1, c3, c2] + ann2 = ANN.add[c1, c2, c2] + ann3 = ANN.add[c1, c1, c2] + lst = [ann1, ann2, ann3, + ANN.neg[c2, c3]] + a = AnnotationSet(lst) + a.adddependency(ann1, ann2) + a.adddependency(ann2, ann3) + a.kill(ann1) + self.assertSameSet(a, lst[3:]) + + def test_merge_blackholevalue(self): + lst = [ANN.add[c1, c3, c2], + ANN.neg[c2, c3]] + a = AnnotationSet(lst) + # (c3) inter (all annotations) == (c3) + c = a.merge(c3, blackholevalue) + self.assertEquals(c, c3) + self.assertSameSet(a, lst) + + def test_merge_mutable1(self): + lst = [ANN.type[c1, c3], + ANN.type[c2, c3], + ANN.add[c2, c3, c3]] + a = AnnotationSet(lst) + # (c1) inter (c2) == (c1 shared with c2) + c = a.merge(c1, c2) + self.assertSameCells(a, c, c1, c2) + self.assertSameSet(a, [ANN.type[c, c3]]) + + def test_merge_mutable2(self): + lst = [ANN.type[c1, c3], + ANN.type[c2, c3], + ANN.add[c1, c3, c3]] + a = AnnotationSet(lst) + # (c1) inter (c2) == (c1 shared with c2) + c = a.merge(c1, c2) + self.assertSameCells(a, c, c1, c2) + self.assertSameSet(a, [ANN.type[c, c3]]) + + def test_merge_immutable1(self): + lst = [ANN.type[c1, c3], + ANN.type[c2, c3], + ANN.immutable[c1], + ANN.immutable[c2], + ANN.add[c2, c3, c3]] + a = AnnotationSet(lst) + # (c1) inter (c2) == (c1) + c = a.merge(c1, c2) + self.assertSameCells(a, c, c1) + self.failIf(a.isshared(c1, c2)) + self.assertSameSet(a, lst) + + def test_merge_immutable2(self): + lst = [ANN.type[c1, c3], + ANN.type[c2, c3], + ANN.immutable[c1], + ANN.immutable[c2], + ANN.add[c1, c3, c3]] + a = AnnotationSet(lst) + # (c1) inter (c2) == (some new c) + c = a.merge(c1, c2) + self.failIf(a.isshared(c, c1)) + self.failIf(a.isshared(c, c2)) # maybe not needed, but we check that + self.failIf(a.isshared(c1, c2)) + lst += [ANN.type[c, c3], + ANN.immutable[c]] + self.assertSameSet(a, lst) + + def test_merge_mutable_ex(self): + lst = [ANN.add[c1, c2, c2], + ANN.neg[c2, c1], + ANN.add[c3, c2, c2], + ANN.immutable[c2]] + a = AnnotationSet(lst) + # (c1) inter (c3) == (c1 shared with c3) + c = a.merge(c1, c3) + self.assertSameCells(a, c, c1, c3) + self.assertSameSet(a, [lst[0], lst[3]]) + self.assertSameSet(a, [lst[2], lst[3]]) + + def test_merge_immutable_ex(self): + lst = [ANN.add[c1, c2, c2], + ANN.neg[c2, c1], + ANN.add[c3, c2, c2], + ANN.immutable[c1], + ANN.immutable[c2], + ANN.immutable[c3]] + a = AnnotationSet(lst) + # (c1) inter (c3) == (some new c) + c = a.merge(c1, c3) + self.failIf(a.isshared(c, c1)) + self.failIf(a.isshared(c, c3)) + self.failIf(a.isshared(c1, c3)) + lst += [ANN.add[c, c2, c2], + ANN.immutable[c]] + self.assertSameSet(a, lst) + +## def dont_test_merge_mutable_ex(self): +## # This test is expected to fail at this point because the algorithms +## # are not 100% theoretically correct, but probably quite good and +## # clear enough right now. In theory in the intersection below +## # 'add' should be kept. In practice the extra 'c3' messes things +## # up. I can only think about much-more-obscure algos to fix that. +## lst = [ANN.add', [c1, c3], c2), +## ANN.neg', [c2], c1), +## ANN.add', [c3, c3], c2), +## ANN.immutable', [], c2)] +## a = AnnotationHeap(lst) +## # (c1) inter (c3) == (c1 shared with c3) +## c = a.merge(c1, c3) +## self.assertEquals(c, c1) +## self.assertEquals(c, c3) +## self.assertEquals(c1, c3) +## self.assertSameSet(a, [lst[0], lst[3]]) +## self.assertSameSet(a, [lst[2], lst[3]]) + +## def dont_test_merge_immutable_ex(self): +## # Disabled -- same as above. +## lst = [ANN.add', [c1, c3], c2), +## ANN.neg', [c2], c1), +## ANN.add', [c3, c3], c2), +## ANN.immutable', [], c1), +## ANN.immutable', [], c2), +## ANN.immutable', [], c3)] +## a = AnnotationHeap(lst) +## # (c1) inter (c3) == (some new c4) +## c = a.merge(c1, c3) +## self.failIfEqual(c, c1) +## self.failIfEqual(c, c3) +## lst += [ANN.add', [c, c3], c2), +## ANN.immutable', [], c)] +## self.assertSameSet(a, lst) + class TestRecording(test.IntTestCase): + assertSameSet = assertSameSet + assertSameCells = assertSameCells def setUp(self): self.lst = [ @@ -85,30 +257,16 @@ ] self.annset = AnnotationSet(self.lst) - def assertSameSet(self, annset, a, b): - a = [annset.temporarykey(a1) for a1 in a] - b = [annset.temporarykey(b1) for b1 in b] - # try to reorder a to match b, without failing if the lists - # are different -- this will be checked by assertEquals() - for i in range(len(b)): - try: - j = i + a[i:].index(b[i]) - except ValueError: - pass - else: - a[i], a[j] = a[j], a[i] - self.assertEquals(a, b) - def test_simple(self): a = self.annset def f(rec): if rec.query(ANN.add[c1, c3, QUERYARG]): rec.set(ANN.type[c1, c3]) a.record(f) - self.assertSameSet(a, a, self.lst + [ANN.type[c1, c3]]) + self.assertSameSet(a, self.lst + [ANN.type[c1, c3]]) a.kill(self.lst[0]) - self.assertSameSet(a, a, self.lst[1:]) + self.assertSameSet(a, self.lst[1:]) def test_type(self): a = self.annset From arigo at codespeak.net Thu Dec 18 10:09:13 2003 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 18 Dec 2003 10:09:13 +0100 (MET) Subject: [pypy-svn] rev 2466 - in pypy/trunk/src/pypy/annotation: . test Message-ID: <20031218090913.1EC0A5A4F8@thoth.codespeak.net> Author: arigo Date: Thu Dec 18 10:09:12 2003 New Revision: 2466 Modified: pypy/trunk/src/pypy/annotation/annset.py pypy/trunk/src/pypy/annotation/test/test_annset.py Log: 'blackholevalue' in queries. Modified: pypy/trunk/src/pypy/annotation/annset.py ============================================================================== --- pypy/trunk/src/pypy/annotation/annset.py (original) +++ pypy/trunk/src/pypy/annotation/annset.py Thu Dec 18 10:09:12 2003 @@ -76,7 +76,7 @@ """ yield annotations matching the given queryannotation. """ self.normalizeann(queryann) testindices = [i for i in range(queryann.predicate.arity) - if queryann.args[i] is not QUERYARG] + if isinstance(queryann.args[i], SomeValue)] for ann in self.annlist: if ann.predicate == queryann.predicate: for i in testindices: Modified: pypy/trunk/src/pypy/annotation/test/test_annset.py ============================================================================== --- pypy/trunk/src/pypy/annotation/test/test_annset.py (original) +++ pypy/trunk/src/pypy/annotation/test/test_annset.py Thu Dec 18 10:09:12 2003 @@ -88,6 +88,25 @@ clist = a.query(ANN.constant(42)[QUERYARG]) self.assertEquals(clist, [c1]) + def test_query_blackholevalue(self): + lst = [ + ANN.add[c1, c3, c2], + ANN.add[c1, c2, c4], + ANN.type[c2, c4], + ANN.type[c2, c3], + ] + a = AnnotationSet(lst) + clist = a.query(ANN.add[c1, ..., QUERYARG]) + clist.sort() + expected = [c2, c4] + expected.sort() + self.assertEquals(clist, expected) + clist = a.query(ANN.add[c2, ..., QUERYARG]) + self.assertEquals(clist, []) + clist = a.query(ANN.type[c2, QUERYARG], + ANN.add[c1, QUERYARG, ...]) + self.assertEquals(clist, [c3]) + def test_simplify(self): lst = [ANN.add[c1, c3, c2], ANN.add[c1, c2, c2], From pmaupin at codespeak.net Thu Dec 18 10:21:15 2003 From: pmaupin at codespeak.net (pmaupin at codespeak.net) Date: Thu, 18 Dec 2003 10:21:15 +0100 (MET) Subject: [pypy-svn] rev 2467 - pypy/trunk/src/pypy/objspace/std Message-ID: <20031218092115.7088E5A4F8@thoth.codespeak.net> Author: pmaupin Date: Thu Dec 18 10:21:14 2003 New Revision: 2467 Modified: pypy/trunk/src/pypy/objspace/std/slicetype.py Log: Simplify slicelength generation in indices4 Modified: pypy/trunk/src/pypy/objspace/std/slicetype.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/slicetype.py (original) +++ pypy/trunk/src/pypy/objspace/std/slicetype.py Thu Dec 18 10:21:14 2003 @@ -86,12 +86,10 @@ def app_slice_indices4(slice, length): start, stop, step = slice_indices3(slice, length) - if (step < 0 and stop >= start) or (step > 0 and start >= stop): - slicelength = 0 - elif step < 0: - slicelength = (stop-start+1)//step + 1 + if (step > 0 and stop > start) or (step < 0 and start < stop): + slicelength = (abs(stop-start)-1)//step + 1 else: - slicelength = (stop-start-1)//step + 1 + slicelength = 0 return start, stop, step, slicelength slice_indices4 = gateway.app2interp(app_slice_indices4) From pmaupin at codespeak.net Thu Dec 18 10:30:52 2003 From: pmaupin at codespeak.net (pmaupin at codespeak.net) Date: Thu, 18 Dec 2003 10:30:52 +0100 (MET) Subject: [pypy-svn] rev 2468 - pypy/trunk/src/pypy/objspace/std Message-ID: <20031218093052.CEC765A4F8@thoth.codespeak.net> Author: pmaupin Date: Thu Dec 18 10:30:52 2003 New Revision: 2468 Modified: pypy/trunk/src/pypy/objspace/std/listobject.py Log: Backed-out broken simplification Modified: pypy/trunk/src/pypy/objspace/std/listobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/listobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/listobject.py Thu Dec 18 10:30:52 2003 @@ -202,29 +202,37 @@ def _setitem_slice_helper(space, w_list, w_slice, sequence2, len2): start, stop, step, slicelength = slicetype.indices4(space,w_slice,w_list.ob_size) assert slicelength >= 0 - if step != 1: - raise OperationError(space.w_NotImplementedError, - space.wrap("Assignment to extended slices not implemented yet.")) - delta = len2 - slicelength - oldsize = w_list.ob_size - newsize = oldsize + delta - _list_resize(w_list, newsize) - items = w_list.ob_item - w_list.ob_size = newsize - r = range(stop+delta,newsize) - if delta > 0: - r.reverse() - - for i in r: - items[i] = items[i-delta] - # Always copy starting from the right to avoid - # having to make a shallow copy in the case where - # the source and destination lists are the same list. + if step == 1: # Support list resizing for non-extended slices + oldsize = w_list.ob_size + delta = len2 - slicelength + newsize = oldsize + delta + _list_resize(w_list, newsize) + w_list.ob_size = newsize + r = range(stop+delta, newsize) + if delta > 0: + r.reverse() + items = w_list.ob_item + for i in r: + items[i] = items[i-delta] + elif len2 != slicelength: # No resize for extended slices + raise OperationError(space.w_ValueError, space.wrap("attempt to " + "assign sequence of size %d to extended slice of size %d" % + (len2,slicelength))) + r = range(len2) - r.reverse() + items = w_list.ob_item + if sequence2 is items: + if step > 0: + # Always copy starting from the right to avoid + # having to make a shallow copy in the case where + # the source and destination lists are the same list. + r.reverse() + else: + # Make a shallow copy to more easily handle the reversal case + sequence2 = list(sequence2) for i in r: - items[start+i] = sequence2[i] + items[start+i*step] = sequence2[i] return space.w_None def repr__List(space, w_list): From pmaupin at codespeak.net Thu Dec 18 10:32:35 2003 From: pmaupin at codespeak.net (pmaupin at codespeak.net) Date: Thu, 18 Dec 2003 10:32:35 +0100 (MET) Subject: [pypy-svn] rev 2469 - pypy/trunk/src/pypy/objspace/std Message-ID: <20031218093235.BD5BE5A4F8@thoth.codespeak.net> Author: pmaupin Date: Thu Dec 18 10:32:35 2003 New Revision: 2469 Modified: pypy/trunk/src/pypy/objspace/std/slicetype.py Log: Backed-out broken simplification Modified: pypy/trunk/src/pypy/objspace/std/slicetype.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/slicetype.py (original) +++ pypy/trunk/src/pypy/objspace/std/slicetype.py Thu Dec 18 10:32:35 2003 @@ -86,10 +86,12 @@ def app_slice_indices4(slice, length): start, stop, step = slice_indices3(slice, length) - if (step > 0 and stop > start) or (step < 0 and start < stop): - slicelength = (abs(stop-start)-1)//step + 1 - else: + if (step < 0 and stop >= start) or (step > 0 and start >= stop): slicelength = 0 + elif step < 0: + slicelength = (stop-start+1)//step + 1 + else: + slicelength = (stop-start-1)//step + 1 return start, stop, step, slicelength slice_indices4 = gateway.app2interp(app_slice_indices4) From arigo at codespeak.net Thu Dec 18 10:44:20 2003 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 18 Dec 2003 10:44:20 +0100 (MET) Subject: [pypy-svn] rev 2470 - in pypy/trunk/src/pypy/annotation: . test Message-ID: <20031218094420.B23C15A4F8@thoth.codespeak.net> Author: arigo Date: Thu Dec 18 10:44:20 2003 New Revision: 2470 Modified: pypy/trunk/src/pypy/annotation/annset.py pypy/trunk/src/pypy/annotation/model.py pypy/trunk/src/pypy/annotation/test/test_annset.py Log: Added better support for constants. Modified: pypy/trunk/src/pypy/annotation/annset.py ============================================================================== --- pypy/trunk/src/pypy/annotation/annset.py (original) +++ pypy/trunk/src/pypy/annotation/annset.py Thu Dec 18 10:44:20 2003 @@ -1,6 +1,6 @@ from __future__ import generators import types -from model import Annotation, SomeValue, QueryArgument, ANN +from model import Annotation, SomeValue, QueryArgument, ANN, ConstPredicate from model import immutable_types, blackholevalue, basicannotations QUERYARG = QueryArgument() @@ -96,6 +96,15 @@ else: return None + def queryconstant(self, cell): + "Return the list of all 'x' such that ANN.constant(x)[cell] is set." + cell = self.normalized(cell) + result = [] + for ann in self.annlist: + if isinstance(ann.predicate, ConstPredicate) and ann.args[0] is cell: + result.append(ann.predicate.value) + return result + def record(self, recfunc, *args): """ invoke the given 'recording' function by passing it a new Recorder instance and letting it use its modification API. This API will @@ -260,6 +269,11 @@ if knowntype in immutable_types: self.set(ANN.immutable[someval]) + def newconstant(self, value): + cell = SomeValue() + self.set(ANN.constant(value)[cell]) + return cell + ''' class XXXTransaction: """A transaction contains methods to look for annotations in the Modified: pypy/trunk/src/pypy/annotation/model.py ============================================================================== --- pypy/trunk/src/pypy/annotation/model.py (original) +++ pypy/trunk/src/pypy/annotation/model.py Thu Dec 18 10:44:20 2003 @@ -103,3 +103,7 @@ basicannotations.append(ANN.type[_val, _tval]) basicannotations.append(ANN.constant(_type)[_tval]) basicannotations.append(ANN.immutable[_val]) + +# 'any immutable value' +immutablevalue = SomeValue() +basicannotations.append(ANN.immutable[immutablevalue]) Modified: pypy/trunk/src/pypy/annotation/test/test_annset.py ============================================================================== --- pypy/trunk/src/pypy/annotation/test/test_annset.py (original) +++ pypy/trunk/src/pypy/annotation/test/test_annset.py Thu Dec 18 10:44:20 2003 @@ -88,6 +88,23 @@ clist = a.query(ANN.constant(42)[QUERYARG]) self.assertEquals(clist, [c1]) + def test_newconstant(self): + a = AnnotationSet([]) + def f(rec): + return rec.newconstant(42) + c = a.record(f) + self.assertSameSet(a, [ANN.constant(42)[c]]) + + def test_queryconstant(self): + lst = [ + ANN.constant(42)[c1], + ] + a = AnnotationSet(lst) + vlist = a.queryconstant(c1) + self.assertEquals(vlist, [42]) + vlist = a.queryconstant(c2) + self.assertEquals(vlist, []) + def test_query_blackholevalue(self): lst = [ ANN.add[c1, c3, c2], From pmaupin at codespeak.net Thu Dec 18 11:01:34 2003 From: pmaupin at codespeak.net (pmaupin at codespeak.net) Date: Thu, 18 Dec 2003 11:01:34 +0100 (MET) Subject: [pypy-svn] rev 2472 - pypy/trunk/src/pypy/objspace/std Message-ID: <20031218100134.DEE535A4F8@thoth.codespeak.net> Author: pmaupin Date: Thu Dec 18 11:01:34 2003 New Revision: 2472 Modified: pypy/trunk/src/pypy/objspace/std/listobject.py Log: Add delete of extended slices Modified: pypy/trunk/src/pypy/objspace/std/listobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/listobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/listobject.py Thu Dec 18 11:01:34 2003 @@ -179,7 +179,23 @@ return space.w_None def delitem__List_Slice(space, w_list, w_slice): - return _setitem_slice_helper(space, w_list, w_slice, [], 0) + start, stop, step, slicelength = slicetype.indices4(space, w_slice, w_list.ob_size) + if step == 1: + return _setitem_slice_helper(space, w_list, w_slice, [], 0) + + # The current code starts from the top, to simplify + # coding. A later optimization could be to start from + # the bottom, which would reduce the list motion. + # A further later optimization would be to special-case + # a step of -1, because this version will perform a LOT + # of extra motion for this case. Anybody with a real-life + # use-case for this is welcome to write the special case. + r = range(start, stop, step) + if step > 0: + r.reverse() + for i in r: + _del_slice(w_list, i, i+1) + return space.w_None def setitem__List_Int_ANY(space, w_list, w_index, w_any): items = w_list.ob_item @@ -200,7 +216,7 @@ return _setitem_slice_helper(space, w_list, w_slice, t, len(t)) def _setitem_slice_helper(space, w_list, w_slice, sequence2, len2): - start, stop, step, slicelength = slicetype.indices4(space,w_slice,w_list.ob_size) + start, stop, step, slicelength = slicetype.indices4(space, w_slice, w_list.ob_size) assert slicelength >= 0 if step == 1: # Support list resizing for non-extended slices From pmaupin at codespeak.net Thu Dec 18 11:05:40 2003 From: pmaupin at codespeak.net (pmaupin at codespeak.net) Date: Thu, 18 Dec 2003 11:05:40 +0100 (MET) Subject: [pypy-svn] rev 2473 - pypy/trunk/src/pypy/appspace Message-ID: <20031218100540.538D75A4F8@thoth.codespeak.net> Author: pmaupin Date: Thu Dec 18 11:05:39 2003 New Revision: 2473 Modified: pypy/trunk/src/pypy/appspace/builtin_types_test.py Log: Comment out tests with longs, add back in tests which work now Modified: pypy/trunk/src/pypy/appspace/builtin_types_test.py ============================================================================== --- pypy/trunk/src/pypy/appspace/builtin_types_test.py (original) +++ pypy/trunk/src/pypy/appspace/builtin_types_test.py Thu Dec 18 11:05:39 2003 @@ -210,7 +210,9 @@ vereq(a[3::-2], '31') vereq(a[-100:100:], a) vereq(a[100:-100:-1], a[::-1]) +''' TODO Reenable when longs work better XXX vereq(a[-100L:100L:2L], '02468') +''' if have_unicode: a = unicode('0123456789', 'ascii') @@ -326,17 +328,18 @@ print '6.5.3a Additional list operations' a = [0,1,2,3,4] -a[0L] = 1 -a[1L] = 2 -a[2L] = 3 -if a != [1,2,3,3,4]: raise TestFailed, 'list item assignment [0L], [1L], [2L]' +''' TODO: Fix long indices XXX ''' +#a[0L] = 1 +#a[1L] = 2 +#a[2L] = 3 +#if a != [1,2,3,3,4]: raise TestFailed, 'list item assignment [0L], [1L], [2L]' a[0] = 5 a[1] = 6 a[2] = 7 if a != [5,6,7,3,4]: raise TestFailed, 'list item assignment [0], [1], [2]' -a[-2L] = 88 -a[-1L] = 99 -if a != [5,6,7,88,99]: raise TestFailed, 'list item assignment [-2L], [-1L]' +#a[-2L] = 88 +#a[-1L] = 99 +#if a != [5,6,7,88,99]: raise TestFailed, 'list item assignment [-2L], [-1L]' a[-2] = 8 a[-1] = 9 if a != [5,6,7,8,9]: raise TestFailed, 'list item assignment [-2], [-1]' @@ -344,21 +347,22 @@ a[-3:] = [] a[1:1] = [1,2,3] if a != [0,1,2,3,4]: raise TestFailed, 'list slice assignment' -a[ 1L : 4L] = [7,8,9] -if a != [0,7,8,9,4]: raise TestFailed, 'list slice assignment using long ints' +#a[ 1L : 4L] = [7,8,9] +#if a != [0,7,8,9,4]: raise TestFailed, 'list slice assignment using long ints' del a[1:4] if a != [0,4]: raise TestFailed, 'list slice deletion' del a[0] if a != [4]: raise TestFailed, 'list item deletion [0]' del a[-1] if a != []: raise TestFailed, 'list item deletion [-1]' -a=range(0,5) -del a[1L:4L] -if a != [0,4]: raise TestFailed, 'list slice deletion' -del a[0L] -if a != [4]: raise TestFailed, 'list item deletion [0]' -del a[-1L] -if a != []: raise TestFailed, 'list item deletion [-1]' +#a=range(0,5) +#del a[1L:4L] +#if a != [0,4]: raise TestFailed, 'list slice deletion' +#del a[0L] +#if a != [4]: raise TestFailed, 'list item deletion [0]' +#del a[-1L] +#if a != []: raise TestFailed, 'list item deletion [-1]' +a=[] a.append(0) a.append(1) a.append(2) @@ -382,6 +386,7 @@ if a.index(0,-3) != 3: raise TestFailed, 'list index, -start argument' if a.index(0,3,4) != 3: raise TestFailed, 'list index, stop argument' if a.index(0,-3,-2) != 3: raise TestFailed, 'list index, -stop argument' +''' TODO: Fix long indices XXX if a.index(0,-4*sys.maxint,4*sys.maxint) != 2: raise TestFailed, 'list index, -maxint, maxint argument' try: @@ -390,6 +395,7 @@ pass else: raise TestFailed, 'list index, maxint,-maxint argument' +''' try: a.index(2,0,-10) @@ -409,6 +415,7 @@ if a != [2,1,0,-1,-2]: raise TestFailed, 'list reverse' a.sort() if a != [-2,-1,0,1,2]: raise TestFailed, 'list sort' +''' TODO: Support comparison functions XXX def revcmp(a, b): return cmp(b, a) a.sort(revcmp) if a != [2,1,0,-1,-2]: raise TestFailed, 'list sort with cmp func' @@ -432,15 +439,14 @@ try: z.sort(lambda x, y: 's') except TypeError: pass else: raise TestFailed, 'list sort compare function does not return int' +''' -''' TODO: pow is badly broken, fix! # Test extreme cases with long ints a = [0,1,2,3,4] if a[ -pow(2,128L): 3 ] != [0,1,2]: raise TestFailed, "list slicing with too-small long integer" if a[ 3: pow(2,145L) ] != [3,4]: raise TestFailed, "list slicing with too-large long integer" -''' # extended slicing From hpk at codespeak.net Thu Dec 18 11:12:01 2003 From: hpk at codespeak.net (hpk at codespeak.net) Date: Thu, 18 Dec 2003 11:12:01 +0100 (MET) Subject: [pypy-svn] rev 2474 - pypy/trunk/src/pypy/tool Message-ID: <20031218101201.77A0C5A4F8@thoth.codespeak.net> Author: hpk Date: Thu Dec 18 11:12:00 2003 New Revision: 2474 Added: pypy/trunk/src/pypy/tool/traceop.py - copied unchanged from rev 2464, pypy/trunk/src/pypy/tool/pydis.py Removed: pypy/trunk/src/pypy/tool/pydis.py Log: rename pydis to make room for our version of dis (will be named pydis.py) Deleted: /pypy/trunk/src/pypy/tool/pydis.py ============================================================================== --- /pypy/trunk/src/pypy/tool/pydis.py Thu Dec 18 11:12:00 2003 +++ (empty file) @@ -1,144 +0,0 @@ -import autopath -import repr - -from pypy.interpreter.pycode import PyCode -from pypy.objspace.std import StdObjSpace -from pypy.objspace.trivial import TrivialObjSpace -from pypy.objspace.trace import Trace - - -def get_repr(): - " Our own repr function for pretty print. " - repr_obj = repr.Repr() - repr_obj.maxstring = 120 - repr_obj.maxother = 120 - - def our_repr(*args): - try: - return repr_obj.repr(*args) - - except: - return "ERROR" - - return our_repr - - -def rpretty_print(spacedump): - " Pretty print for rdump() calls to Trace object spaces. " - - Repr = get_repr() - for operation, bytecodes in spacedump: - for opcode, opname, oparg, ins_idx in bytecodes: - print "\t%s\t%s\t\t%s" % (ins_idx, opname, oparg) - - if operation is not None: - op_name = operation[0] - args = operation[1:] - print " ***\t", op_name, " ->", - for a in args: - print Repr(a), - print - - -def add_func(space, func, w_globals): - """ Add a function to globals. """ - func_name = func.func_name - w_func_name = space.wrap(func_name) - w_func = space.wrap(func) - space.setitem(w_globals, w_func_name, w_func) - - -def run_in_space(space, func, *args): - # Get execution context and globals - ec = space.getexecutioncontext() - w_globals = ec.make_standard_w_globals() - - # Add the function to globals - add_func(space, func, w_globals) - - # Create wrapped args - args_w = [space.wrap(ii) for ii in args] - code = func.func_code - code = PyCode()._from_code(code) - - # Create frame - frame = code.create_frame(space, w_globals) - frame.setfastscope(args_w) - - # start/stop tracing while running frame - space.start_tracing() - res = frame.run() - space.stop_tracing() - - return res - - -def pretty_print(spacedump): - " Pretty print for rdump() calls to Trace object spaces. " - Repr = get_repr() - - for line in spacedump: - ((opcode, opname, arg, ins_idx), spaceops) = line - start = "%4i %s " % (ins_idx, opname) - start = start + " " * (20 - len(start)) + str(arg) - start = start + " " * (30 - len(start)) - if not spaceops: - print start - else: - op = spaceops.pop(0) - print start - for op_name, args in spaceops: - print " " * 30, op_name, Repr(args) - - -def _trace_function(space, reverse_pretty_print_flag, fn, *arg, **kwds): - res = run_in_space(space, fn, *arg, **kwds) - if reverse_pretty_print_flag: - # Get reverse dump - spacedump = space.rdump() - - # Pretty print dump - rpretty_print(spacedump) - else: - # Get dump - spacedump = space.dump() - - # Pretty dump - pretty_print(spacedump) - - return res - -def trace_function(trace_space, fn, *arg, **kwds): - return _trace_function(trace_space, False, fn, *arg, **kwds) - -def rtrace_function(trace_space, fn, *arg, **kwds): - return _trace_function(trace_space, True, fn, *arg, **kwds) - - -def trace_function2(space, fn, *arg, **kwds): - return _trace_function(Trace(space), False, fn, *arg, **kwds) - -def rtrace_function2(space, fn, *arg, **kwds): - return _trace_function(Trace(space), True, fn, *arg, **kwds) - - - - -## # Create space -## if __name__ == "__main__": -## try: -## import readline -## except ImportError: -## pass - -## from pypy.tool import option -## from pypy.tool import test -## args = option.process_options(option.get_standard_options(), -## option.Options) -## objspace = option.objspace() - - -## def run(*args, **kwds): -## def run_function(space, func, *args): -## from pypy.objspace.std import StdObjSpace -## space = Trace(StdObjSpace) From pmaupin at codespeak.net Thu Dec 18 11:16:41 2003 From: pmaupin at codespeak.net (pmaupin at codespeak.net) Date: Thu, 18 Dec 2003 11:16:41 +0100 (MET) Subject: [pypy-svn] rev 2475 - pypy/trunk/src/pypy/objspace/std/test Message-ID: <20031218101641.0E4D35A4F8@thoth.codespeak.net> Author: pmaupin Date: Thu Dec 18 11:16:40 2003 New Revision: 2475 Modified: pypy/trunk/src/pypy/objspace/std/test/test_listobject.py Log: Added extended slice unit tests Modified: pypy/trunk/src/pypy/objspace/std/test/test_listobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/test/test_listobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/test/test_listobject.py Thu Dec 18 11:16:40 2003 @@ -292,5 +292,16 @@ l.extend((2,)) self.assertEquals(l, [1,2]) + def test_extended_slice(self): + l = range(10) + del l[::2] + self.assertEquals(l,[1,3,5,7,9]) + l[-2::-1] = l[:-1] + self.assertEquals(l,[7,5,3,1,9]) + del l[-1:2:-1] + self.assertEquals(l,[7,5,3]) + del l[:2] + self.assertEquals(l,[3]) + if __name__ == '__main__': test.main() From sschwarzer at codespeak.net Thu Dec 18 11:16:52 2003 From: sschwarzer at codespeak.net (sschwarzer at codespeak.net) Date: Thu, 18 Dec 2003 11:16:52 +0100 (MET) Subject: [pypy-svn] rev 2476 - pypy/trunk/src/pypy/tool Message-ID: <20031218101652.570415A4F8@thoth.codespeak.net> Author: sschwarzer Date: Thu Dec 18 11:16:51 2003 New Revision: 2476 Modified: pypy/trunk/src/pypy/tool/newtest.py Log: Executing tests works. Added generator method to TestSuite class. Modified: pypy/trunk/src/pypy/tool/newtest.py ============================================================================== --- pypy/trunk/src/pypy/tool/newtest.py (original) +++ pypy/trunk/src/pypy/tool/newtest.py Thu Dec 18 11:16:51 2003 @@ -2,6 +2,8 @@ import inspect import os import sys +import cStringIO as StringIO +import traceback import unittest import vpath @@ -15,18 +17,25 @@ class TestResult: """Represent the result of a run of a test item.""" - def __init__(self, item, status=None, fullname=None, traceback=None): - # one of SUCCESS, ERROR, FAILURE, IGNORED, SKIPPED + def __init__(self, item): + self.item = item + # one of None, SUCCESS, ERROR, FAILURE, IGNORED, SKIPPED (see above) self.status = None - # name of the test method (without class or module name) - self.methodname = None - # full method name (with module path and class name) - self.fullname = None - # traceback object if applicable, else None + # traceback object for errors and failures, else None self.traceback = None # formatted traceback (a string) self.formatted_traceback = None + def _setstatus(self, statuscode): + self.status = statuscode + self.excinfo = sys.exc_info() + self.traceback = self.excinfo[2] + # store formatted traceback + output = StringIO.StringIO() + args = self.excinfo + (None, output) + traceback.print_exception(*args) + self.formatted_traceback = output.getvalue().strip() + class TestItem: """Represent a single test method from a TestCase class.""" @@ -36,20 +45,73 @@ self.module = module self.cls = cls self.method = testmethod - # we can only derive this from a frame or traceback? + #XXX we can only derive this from a frame or traceback? #self.lineno = None - def run(self): - """Run this TestItem and return a corresponding TestResult object.""" + def run(self, pretest=None, posttest=None): + """ + Run this TestItem and return a corresponding TestResult object. + + pretest, if not None, is a callable which is called before + running the setUp method of the TestCase class. It is passed + the this TestItem instance as the argument. + + Similarly, posttest is called after running the TestCase + class's tearDown method (or after the test method, if that + doesn't complete successfully). Like for pretest, the + callable gets the TestItem instance as only argument. + """ + # credit: adapted from Python's unittest.TestCase.run #XXX at a later time, this method may accept an object space # as argument + # prepare result object + result = TestResult(self) + result.status = None + + # prepare test case class and test method + methodname = self.method.__name__ + testobject = self.cls(methodname) + testmethod = getattr(testobject, methodname) + + if pretest is not None: + pretest(self) + try: + try: + testobject.setUp() + except KeyboardInterrupt: + raise + except: + result._setstatus(ERROR) + return + + try: + testmethod() + result.status = SUCCESS + except AssertionError: + result._setstatus(FAILURE) + except KeyboardInterrupt: + raise + except: + result._setstatus(ERROR) + + try: + testobject.tearDown() + except KeyboardInterrupt: + raise + except: + result._setstatus(ERROR) + finally: + if posttest is not None: + posttest(self) + return result + def __str__(self): return "TestItem from %s.%s.%s" % (self.module.__name__,\ self.cls.__name__, self.method.__name__) def __repr__(self): - return "%s at %#x" % (str(self), id(self)) + return "<%s at %#x>" % (str(self), id(self)) class TestSuite: @@ -57,20 +119,6 @@ def __init__(self): self.items = [] - def _items_from_module(self, module): - """Return a list of TestItems read from the given module.""" - items = [] - # scan the module for classes derived from unittest.TestCase - for obj in vars(module).values(): - if inspect.isclass(obj) and issubclass(obj, unittest.TestCase): - # we found a TestCase class, now scan it for test methods - for obj2 in vars(obj).values(): - # ismethod doesn't seem to work here - if inspect.isfunction(obj2) and \ - obj2.__name__.startswith("test"): - items.append(TestItem(module, obj, obj2)) - return items - def _module_from_modpath(self, modpath): """ Return a module object derived from the module path @@ -85,8 +133,21 @@ __import__(modpath) return sys.modules[modpath] - def initfromdir(self, dirname, filterfunc=None, recursive=True, - loader=None): + def _items_from_module(self, module): + """Return a list of TestItems read from the given module.""" + items = [] + # scan the module for classes derived from unittest.TestCase + for obj in vars(module).values(): + if inspect.isclass(obj) and issubclass(obj, unittest.TestCase): + # we found a TestCase class, now scan it for test methods + for obj2 in vars(obj).values(): + # inspect.ismethod doesn't seem to work here + if inspect.isfunction(obj2) and \ + obj2.__name__.startswith("test"): + items.append(TestItem(module, obj, obj2)) + return items + + def initfromdir(self, dirname, filterfunc=None, recursive=True): """ Init this suite by reading the directory denoted by dirname, then find all test modules in it. Test modules are files that @@ -96,13 +157,9 @@ modules by module path. By default, all test modules are used. If recursive is true, which is the default, find all test modules - by scanning the start directory recursively. The argument loader - may be set to a test loader class to use. By default, the - TestLoader class from the unittest module is used. + by scanning the start directory recursively. """ dirname = vpath.getlocal(dirname) - if loader is None: - loader = unittest.TestLoader() def testfilefilter(path): return path.isfile() and path.fnmatch('test_*.py') @@ -122,9 +179,27 @@ else: self.items.extend(items) + def testresults(self, results=None): + """ + Return a generator to get the test result for each test item. + + If not None, the argument results must be a list which will + receive the result objects for later usage. + """ + for item in self.items: + result = item.run() + if results is not None: + results.append(result) + yield result + if __name__ == '__main__': ts = TestSuite() ts.initfromdir(".") - print ts.items + for res in ts.testresults(): + print 75 * '-' + print "%s: %s" % (res.item, res.status) + if res.traceback: + print '-----' + print res.formatted_traceback From pmaupin at codespeak.net Thu Dec 18 11:48:18 2003 From: pmaupin at codespeak.net (pmaupin at codespeak.net) Date: Thu, 18 Dec 2003 11:48:18 +0100 (MET) Subject: [pypy-svn] rev 2477 - in pypy/trunk/src/pypy/module: . test Message-ID: <20031218104818.544CC5A4F8@thoth.codespeak.net> Author: pmaupin Date: Thu Dec 18 11:48:17 2003 New Revision: 2477 Modified: pypy/trunk/src/pypy/module/builtin.py pypy/trunk/src/pypy/module/test/test_builtin.py Log: Added 'sign' built-in function Modified: pypy/trunk/src/pypy/module/builtin.py ============================================================================== --- pypy/trunk/src/pypy/module/builtin.py (original) +++ pypy/trunk/src/pypy/module/builtin.py Thu Dec 18 11:48:17 2003 @@ -295,6 +295,17 @@ total = total+item return total + # This function was not in the original builtins, + # but is quite useful for some aspects of PyPy + # implementation. + def app_sign(self,a): + if a > 0: + return 1 + elif a < 0: + return -1 + else: + return 0 + #XXX works only for new-style classes. #So we have to fix it, when we add support for old-style classes def issubclass(self, w_cls1, w_cls2): Modified: pypy/trunk/src/pypy/module/test/test_builtin.py ============================================================================== --- pypy/trunk/src/pypy/module/test/test_builtin.py (original) +++ pypy/trunk/src/pypy/module/test/test_builtin.py Thu Dec 18 11:48:17 2003 @@ -6,6 +6,11 @@ def setUp(self): self.space = test.objspace() + def test_sign(self): + self.assertEquals(sign(-4),-1) + self.assertEquals(sign(0),0) + self.assertEquals(sign(10),1) + def test_import(self): m = __import__('pprint') self.assertEquals(m.pformat({}), '{}') From pmaupin at codespeak.net Thu Dec 18 11:56:56 2003 From: pmaupin at codespeak.net (pmaupin at codespeak.net) Date: Thu, 18 Dec 2003 11:56:56 +0100 (MET) Subject: [pypy-svn] rev 2478 - pypy/trunk/src/pypy/module/test Message-ID: <20031218105656.B16675A4F8@thoth.codespeak.net> Author: pmaupin Date: Thu Dec 18 11:56:55 2003 New Revision: 2478 Modified: pypy/trunk/src/pypy/module/test/test_builtin.py Log: Fix some spaces Modified: pypy/trunk/src/pypy/module/test/test_builtin.py ============================================================================== --- pypy/trunk/src/pypy/module/test/test_builtin.py (original) +++ pypy/trunk/src/pypy/module/test/test_builtin.py Thu Dec 18 11:56:55 2003 @@ -7,9 +7,9 @@ self.space = test.objspace() def test_sign(self): - self.assertEquals(sign(-4),-1) - self.assertEquals(sign(0),0) - self.assertEquals(sign(10),1) + self.assertEquals(sign(-4), -1) + self.assertEquals(sign(0), 0) + self.assertEquals(sign(10), 1) def test_import(self): m = __import__('pprint') From arigo at codespeak.net Thu Dec 18 11:57:13 2003 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 18 Dec 2003 11:57:13 +0100 (MET) Subject: [pypy-svn] rev 2479 - in pypy/trunk/src/pypy/annotation: . test Message-ID: <20031218105713.DE5DD5A4F8@thoth.codespeak.net> Author: arigo Date: Thu Dec 18 11:57:13 2003 New Revision: 2479 Modified: pypy/trunk/src/pypy/annotation/annset.py pypy/trunk/src/pypy/annotation/test/test_annset.py Log: Last few changes before we think that dependencies are a possibly bad idea after all. Modified: pypy/trunk/src/pypy/annotation/annset.py ============================================================================== --- pypy/trunk/src/pypy/annotation/annset.py (original) +++ pypy/trunk/src/pypy/annotation/annset.py Thu Dec 18 11:57:13 2003 @@ -15,6 +15,14 @@ self.annlist = list(annlist) # List of annotations self._normalized = {} # maps SomeValues to some 'standard' one that # is shared with it + self.mappings_to_normalize = [self._normalized] + + def getbindings(self): + """Return a general-purpose mapping between whatever you want and + SomeValues. The SomeValues are kept normalized by the AnnotationSet.""" + bindings = {} + self.mappings_to_normalize.append(bindings) + return bindings def normalized(self, someval): return self._normalized.get(someval, someval) @@ -22,10 +30,11 @@ def setshared(self, someval1, someval2): someval1 = self.normalized(someval1) someval2 = self.normalized(someval2) - for key, value in self._normalized.items(): - if value is someval1: - self._normalized[key] = someval2 - self._normalized[someval1] = someval2 + for mapping in self.mappings_to_normalize: + for key, value in mapping.items(): + if value is someval2: + mapping[key] = someval1 + self._normalized[someval2] = someval1 def isshared(self, someval1, someval2): return self.normalized(someval1) is self.normalized(someval2) @@ -96,6 +105,10 @@ else: return None + def findall(self, checkann): + """ list all matching annotations.""" + return list(self._annmatches(checkann)) + def queryconstant(self, cell): "Return the list of all 'x' such that ANN.constant(x)[cell] is set." cell = self.normalized(cell) @@ -250,6 +263,16 @@ results.append(matchvalue) return results + def get(self, *querylist): + """Like query() but asserts that there is at most one answer. + Returns None if there isn't any answer.""" + resultlist = self.query(*querylist) + assert len(resultlist) <= 1, "Confusing annotations..." + if resultlist: + return resultlist[0] + else: + return None + def set(self, ann): """Insert the annotation into the AnnotationSet, recording dependency from all previous queries done on this Recorder instance.""" @@ -258,11 +281,23 @@ for previous_ann in self.using_annotations: self.annset.adddependency(previous_ann, ann) - def check_type(self, someval, checktype): - return bool(self.query(ANN.type[someval, QUERYARG], - ANN.constant(checktype)[QUERYARG])) + def delete(self, queryann): + """Kill the annotations matching the pattern.""" + matchannlist = self.annset.findall(queryann) + self.annset.simplify(kill=matchannlist) + + def checktype(self, someval, checktype): + if isinstance(checktype, tuple): + for t in checktype: + if self.checktype(someval, t): + return True + else: + return False + else: + return bool(self.query(ANN.type[someval, QUERYARG], + ANN.constant(checktype)[QUERYARG])) - def set_type(self, someval, knowntype): + def settype(self, someval, knowntype): typeval = SomeValue() self.set(ANN.type[someval, typeval]) self.set(ANN.constant(knowntype)[typeval]) Modified: pypy/trunk/src/pypy/annotation/test/test_annset.py ============================================================================== --- pypy/trunk/src/pypy/annotation/test/test_annset.py (original) +++ pypy/trunk/src/pypy/annotation/test/test_annset.py Thu Dec 18 11:57:13 2003 @@ -307,11 +307,27 @@ def test_type(self): a = self.annset def f(rec): - if rec.check_type(c1, int): - rec.set_type(c2, str) + if rec.checktype(c1, int): + rec.settype(c2, str) a.record(f) self.assert_(a.query(ANN.type[c2, QUERYARG], ANN.constant(str)[QUERYARG])) + def test_type2(self): + a = self.annset + def f(rec): + if rec.checktype(c1, (int, long)): + rec.settype(c2, str) + a.record(f) + self.assert_(a.query(ANN.type[c2, QUERYARG], + ANN.constant(str)[QUERYARG])) + + def test_delete(self): + a = self.annset + def f(rec): + rec.delete(ANN.add[c1, c3, ...]) + a.record(f) + self.assertSameSet(a, self.lst[1:]) + if __name__ == '__main__': test.main() From pmaupin at codespeak.net Thu Dec 18 11:57:47 2003 From: pmaupin at codespeak.net (pmaupin at codespeak.net) Date: Thu, 18 Dec 2003 11:57:47 +0100 (MET) Subject: [pypy-svn] rev 2480 - pypy/trunk/src/pypy/module Message-ID: <20031218105747.6B9865A4F8@thoth.codespeak.net> Author: pmaupin Date: Thu Dec 18 11:57:46 2003 New Revision: 2480 Modified: pypy/trunk/src/pypy/module/builtin.py Log: Fix some spaces Modified: pypy/trunk/src/pypy/module/builtin.py ============================================================================== --- pypy/trunk/src/pypy/module/builtin.py (original) +++ pypy/trunk/src/pypy/module/builtin.py Thu Dec 18 11:57:46 2003 @@ -298,7 +298,7 @@ # This function was not in the original builtins, # but is quite useful for some aspects of PyPy # implementation. - def app_sign(self,a): + def app_sign(self, a): if a > 0: return 1 elif a < 0: From pmaupin at codespeak.net Thu Dec 18 12:03:28 2003 From: pmaupin at codespeak.net (pmaupin at codespeak.net) Date: Thu, 18 Dec 2003 12:03:28 +0100 (MET) Subject: [pypy-svn] rev 2481 - pypy/trunk/src/pypy/objspace/std Message-ID: <20031218110328.5E6C05A4F8@thoth.codespeak.net> Author: pmaupin Date: Thu Dec 18 12:03:27 2003 New Revision: 2481 Modified: pypy/trunk/src/pypy/objspace/std/slicetype.py Log: Simplified slicelength generation (works now) Modified: pypy/trunk/src/pypy/objspace/std/slicetype.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/slicetype.py (original) +++ pypy/trunk/src/pypy/objspace/std/slicetype.py Thu Dec 18 12:03:27 2003 @@ -83,15 +83,15 @@ return start, stop, step slice_indices__ANY_ANY = slice_indices3 = gateway.app2interp(app_slice_indices3) -def app_slice_indices4(slice, length): - start, stop, step = slice_indices3(slice, length) - - if (step < 0 and stop >= start) or (step > 0 and start >= stop): - slicelength = 0 - elif step < 0: - slicelength = (stop-start+1)//step + 1 +def app_slice_indices4(slice, sequencelength): + start, stop, step = slice_indices3(slice, sequencelength) + slicelength = stop - start + lengthsign = sign(slicelength) + stepsign = sign(step) + if stepsign == lengthsign: + slicelength = (slicelength - lengthsign) // step + 1 else: - slicelength = (stop-start-1)//step + 1 + slicelength = 0 return start, stop, step, slicelength slice_indices4 = gateway.app2interp(app_slice_indices4) From arigo at codespeak.net Thu Dec 18 12:09:20 2003 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 18 Dec 2003 12:09:20 +0100 (MET) Subject: [pypy-svn] rev 2483 - in pypy/trunk/src/pypy/annotation: . test Message-ID: <20031218110920.8A2CE5A4F8@thoth.codespeak.net> Author: arigo Date: Thu Dec 18 12:09:19 2003 New Revision: 2483 Modified: pypy/trunk/src/pypy/annotation/annset.py pypy/trunk/src/pypy/annotation/model.py pypy/trunk/src/pypy/annotation/test/test_annset.py Log: Removed dependencies. They are really getting in the way. We'll try now to be more goal-oriented and work on translation with just reflowing things in the blocks. Modified: pypy/trunk/src/pypy/annotation/annset.py ============================================================================== --- pypy/trunk/src/pypy/annotation/annset.py (original) +++ pypy/trunk/src/pypy/annotation/annset.py Thu Dec 18 12:09:19 2003 @@ -132,8 +132,7 @@ self.simplify(kill=annlist) def simplify(self, kill=[]): - """Kill annotations in the list, and recursively all the annotations - that depend on them, and simplify the resulting list to remove + """Kill annotations in the 'kill' list, and normalize and remove duplicates.""" # temporarykey() returns a tuple with all the information about # the annotation; equal temporarykey() means equal annotations. @@ -148,32 +147,16 @@ allkeys = {} # map temporarykeys to Annotation instances for ann in self.annlist: key = temporarykey(ann) - if key in allkeys: # duplicate? - previous = allkeys[key] - previous.forward_deps += ann.forward_deps # merge - else: + if key not in allkeys: # if not duplicate allkeys[key] = ann - killkeys = {} # set of temporarykeys of annotations to remove for ann in kill: - killkeys[temporarykey(ann)] = True - - pending = killkeys.keys() - for key in pending: + key = temporarykey(ann) if key in allkeys: - ann = allkeys[key] - del allkeys[key] # remove annotations from the dict - for dep in ann.forward_deps: # propagate dependencies - depkey = temporarykey(dep) - if depkey not in killkeys: - killkeys[depkey] = True - pending.append(depkey) + del allkeys[key] self.annlist = allkeys.values() - def adddependency(self, hypothesisann, conclusionann): - hypothesisann.forward_deps.append(conclusionann) - def merge(self, oldcell, newcell): """Update the heap to account for the merging of oldcell and newcell. Return the merged cell.""" @@ -237,32 +220,8 @@ for oldann, newann in common: resultann = newann.copy(renameargs={newcell: resultcell}) annlist.append(resultann) - self.adddependency(oldann, resultann) - self.adddependency(newann, resultann) return resultcell - -class Recorder: - """A recorder contains methods to look for annotations in the - AnnotationSet and create new annotations accordingly. Each - Recorder instance records which Annotations were needed, which - allows dependencies to be tracked.""" - - def __init__(self, annset): - self.annset = annset - self.using_annotations = [] # annotations that we have used - - def using(self, *annlist): - """Mark all 'ann' in 'annlist' as used in this transaction.""" - self.using_annotations += annlist - - def query(self, *querylist): - results = [] - for matchanns, matchvalue in self.annset.match(*querylist): - self.using(*matchanns) - results.append(matchvalue) - return results - def get(self, *querylist): """Like query() but asserts that there is at most one answer. Returns None if there isn't any answer.""" @@ -274,17 +233,14 @@ return None def set(self, ann): - """Insert the annotation into the AnnotationSet, recording dependency - from all previous queries done on this Recorder instance.""" - self.annset.normalizeann(ann) - self.annset.annlist.append(ann) - for previous_ann in self.using_annotations: - self.annset.adddependency(previous_ann, ann) + """Insert the annotation into the AnnotationSet.""" + self.normalizeann(ann) + self.annlist.append(ann) def delete(self, queryann): """Kill the annotations matching the pattern.""" - matchannlist = self.annset.findall(queryann) - self.annset.simplify(kill=matchannlist) + matchannlist = self.findall(queryann) + self.simplify(kill=matchannlist) def checktype(self, someval, checktype): if isinstance(checktype, tuple): Modified: pypy/trunk/src/pypy/annotation/model.py ============================================================================== --- pypy/trunk/src/pypy/annotation/model.py (original) +++ pypy/trunk/src/pypy/annotation/model.py Thu Dec 18 12:09:19 2003 @@ -42,7 +42,6 @@ def __init__(self, predicate, *args): self.predicate = predicate # the operation or predicate self.args = list(args) # list of SomeValues - self.forward_deps = [] # for annset.py assert len(args) == predicate.arity # note that for predicates that are simple operations like # op.add, the result is stored as the last argument. Modified: pypy/trunk/src/pypy/annotation/test/test_annset.py ============================================================================== --- pypy/trunk/src/pypy/annotation/test/test_annset.py (original) +++ pypy/trunk/src/pypy/annotation/test/test_annset.py Thu Dec 18 12:09:19 2003 @@ -9,31 +9,27 @@ c1,c2,c3,c4 = SomeValue(), SomeValue(), SomeValue(), SomeValue() -def assertSameSet(testcase, annset, annotations): - for ann in annotations: - annset.normalizeann(ann) - a = list(annset) - b = annotations - # try to reorder a to match b, without failing if the lists - # are different -- this will be checked by assertEquals() - for i in range(len(b)): - try: - j = i + a[i:].index(b[i]) - except ValueError: - pass - else: - a[i], a[j] = a[j], a[i] - testcase.assertEquals(a, b) - -def assertSameCells(testcase, annset, *cells): - cells = [annset.normalized(c) for c in cells] - for c in cells[1:]: - testcase.assertEquals(cells[0], c) - - class TestAnnotationSet(test.IntTestCase): - assertSameSet = assertSameSet - assertSameCells = assertSameCells + def assertSameSet(self, annset, annotations): + for ann in annotations: + annset.normalizeann(ann) + a = list(annset) + b = annotations + # try to reorder a to match b, without failing if the lists + # are different -- this will be checked by assertEquals() + for i in range(len(b)): + try: + j = i + a[i:].index(b[i]) + except ValueError: + pass + else: + a[i], a[j] = a[j], a[i] + self.assertEquals(a, b) + + def assertSameCells(self, annset, *cells): + cells = [annset.normalized(c) for c in cells] + for c in cells[1:]: + self.assertEquals(cells[0], c) def test_isshared(self): a = AnnotationSet() @@ -90,9 +86,7 @@ def test_newconstant(self): a = AnnotationSet([]) - def f(rec): - return rec.newconstant(42) - c = a.record(f) + c = a.newconstant(42) self.assertSameSet(a, [ANN.constant(42)[c]]) def test_queryconstant(self): @@ -145,18 +139,6 @@ a.kill(ann1) self.assertSameSet(a, lst[1:]) - def test_adddependency(self): - ann1 = ANN.add[c1, c3, c2] - ann2 = ANN.add[c1, c2, c2] - ann3 = ANN.add[c1, c1, c2] - lst = [ann1, ann2, ann3, - ANN.neg[c2, c3]] - a = AnnotationSet(lst) - a.adddependency(ann1, ann2) - a.adddependency(ann2, ann3) - a.kill(ann1) - self.assertSameSet(a, lst[3:]) - def test_merge_blackholevalue(self): lst = [ANN.add[c1, c3, c2], ANN.neg[c2, c3]] @@ -280,54 +262,45 @@ ## ANN.immutable', [], c)] ## self.assertSameSet(a, lst) - -class TestRecording(test.IntTestCase): - assertSameSet = assertSameSet - assertSameCells = assertSameCells - - def setUp(self): - self.lst = [ + def test_set_kill(self): + lst = [ ANN.add[c1, c3, c2], ANN.type[c1, c4], ANN.constant(int)[c4], ] - self.annset = AnnotationSet(self.lst) - - def test_simple(self): - a = self.annset - def f(rec): - if rec.query(ANN.add[c1, c3, QUERYARG]): - rec.set(ANN.type[c1, c3]) - a.record(f) - self.assertSameSet(a, self.lst + [ANN.type[c1, c3]]) + a = AnnotationSet(lst) + a.set(ANN.type[c1, c3]) + lst += [ANN.type[c1, c3]] + self.assertSameSet(a, lst) - a.kill(self.lst[0]) - self.assertSameSet(a, self.lst[1:]) + a.kill(lst[0]) + del lst[0] + self.assertSameSet(a, lst) def test_type(self): - a = self.annset - def f(rec): - if rec.checktype(c1, int): - rec.settype(c2, str) - a.record(f) - self.assert_(a.query(ANN.type[c2, QUERYARG], - ANN.constant(str)[QUERYARG])) - - def test_type2(self): - a = self.annset - def f(rec): - if rec.checktype(c1, (int, long)): - rec.settype(c2, str) - a.record(f) + lst = [ + ANN.add[c1, c3, c2], + ANN.type[c1, c4], + ANN.constant(int)[c4], + ] + a = AnnotationSet(lst) + self.assert_(a.checktype(c1, int)) + self.assert_(a.checktype(c1, (int, long))) + self.failIf(a.checktype(c1, str)) + a.settype(c2, str) self.assert_(a.query(ANN.type[c2, QUERYARG], ANN.constant(str)[QUERYARG])) def test_delete(self): - a = self.annset - def f(rec): - rec.delete(ANN.add[c1, c3, ...]) - a.record(f) - self.assertSameSet(a, self.lst[1:]) + lst = [ + ANN.add[c1, c3, c2], + ANN.type[c1, c4], + ANN.constant(int)[c4], + ] + a = AnnotationSet(lst) + a.delete(ANN.add[c1, c3, ...]) + self.assertSameSet(a, lst[1:]) + if __name__ == '__main__': test.main() From sschwarzer at codespeak.net Thu Dec 18 12:34:54 2003 From: sschwarzer at codespeak.net (sschwarzer at codespeak.net) Date: Thu, 18 Dec 2003 12:34:54 +0100 (MET) Subject: [pypy-svn] rev 2484 - pypy/trunk/src/pypy/tool Message-ID: <20031218113454.E34395A4F8@thoth.codespeak.net> Author: sschwarzer Date: Thu Dec 18 12:34:54 2003 New Revision: 2484 Modified: pypy/trunk/src/pypy/tool/newtest.py Log: Turned test statuses into objects of new class TestStatus. TestItems now also get the line number of the method's source code. Modified: pypy/trunk/src/pypy/tool/newtest.py ============================================================================== --- pypy/trunk/src/pypy/tool/newtest.py (original) +++ pypy/trunk/src/pypy/tool/newtest.py Thu Dec 18 12:34:54 2003 @@ -8,12 +8,22 @@ import vpath +class TestStatus: + def __init__(self, name, longstring, shortstring): + self.name = name + self.longstring = longstring + self.shortstring = shortstring + + def __str__(self): + return self.longstring + # named constants for test result status values -SUCCESS = 'success' -ERROR = 'error' -FAILURE = 'failure' -IGNORED = 'ignored' -SKIPPED = 'skipped' +SUCCESS = TestStatus('success', 'success', '.') +ERROR = TestStatus('error', 'ERROR', 'E') +FAILURE = TestStatus('failure', 'FAILURE', 'F') +IGNORED = TestStatus('ignored', 'ignored', 'i') +SKIPPED = TestStatus('skipped', 'skipped', 's') + class TestResult: """Represent the result of a run of a test item.""" @@ -41,12 +51,12 @@ """Represent a single test method from a TestCase class.""" def __init__(self, module, cls, testmethod): self.file = inspect.getsourcefile(module) - self.source = inspect.getsource(testmethod) self.module = module self.cls = cls self.method = testmethod - #XXX we can only derive this from a frame or traceback? - #self.lineno = None + lines, self.lineno = inspect.getsourcelines(testmethod) + # removing trailing newline(s) but not the indentation + self.source = ''.join(lines).rstrip() def run(self, pretest=None, posttest=None): """ @@ -176,6 +186,7 @@ items = self._items_from_module(module) except: print "skipping testfile (failed loading it)", modpath + raise else: self.items.extend(items) From sschwarzer at codespeak.net Thu Dec 18 12:38:49 2003 From: sschwarzer at codespeak.net (sschwarzer at codespeak.net) Date: Thu, 18 Dec 2003 12:38:49 +0100 (MET) Subject: [pypy-svn] rev 2485 - pypy/trunk/src/pypy/tool Message-ID: <20031218113849.01BF25A4F8@thoth.codespeak.net> Author: sschwarzer Date: Thu Dec 18 12:38:49 2003 New Revision: 2485 Modified: pypy/trunk/src/pypy/tool/newtest.py Log: Added implementation note on TestItem run's pretest and posttest arguments. Modified: pypy/trunk/src/pypy/tool/newtest.py ============================================================================== --- pypy/trunk/src/pypy/tool/newtest.py (original) +++ pypy/trunk/src/pypy/tool/newtest.py Thu Dec 18 12:38:49 2003 @@ -71,6 +71,12 @@ doesn't complete successfully). Like for pretest, the callable gets the TestItem instance as only argument. """ + # Note on pretest and posttest: I discarded the idea to + # supply this functionality by having hypothetical methods + # pretest and posttest overwritten in derived classes. That + # approach would require to support a factory class for test + # items in TestSuite. I wanted to avoid this. + # credit: adapted from Python's unittest.TestCase.run #XXX at a later time, this method may accept an object space # as argument From sschwarzer at codespeak.net Thu Dec 18 12:49:47 2003 From: sschwarzer at codespeak.net (sschwarzer at codespeak.net) Date: Thu, 18 Dec 2003 12:49:47 +0100 (MET) Subject: [pypy-svn] rev 2486 - pypy/trunk/src/pypy/tool Message-ID: <20031218114947.2991E5A4F8@thoth.codespeak.net> Author: sschwarzer Date: Thu Dec 18 12:49:46 2003 New Revision: 2486 Modified: pypy/trunk/src/pypy/tool/newtest.py Log: Added comment on inspect.getsourcelines bug. Compare http://sourceforge.net/tracker/index.php?func=detail&aid=570300&group_id=5470&atid=105470 Modified: pypy/trunk/src/pypy/tool/newtest.py ============================================================================== --- pypy/trunk/src/pypy/tool/newtest.py (original) +++ pypy/trunk/src/pypy/tool/newtest.py Thu Dec 18 12:49:46 2003 @@ -54,11 +54,17 @@ self.module = module self.cls = cls self.method = testmethod + #XXX inspect.getsourcelines may fail if the file path stored + # in a module's pyc/pyo file doesn't match the py file's + # actual location. This can happen if a py file, together with + # its pyc/pyo file is moved to a new location. See Python + # bug "[570300] inspect.getmodule symlink-related failure": + # http://sourceforge.net/tracker/index.php?func=detail&aid=570300&group_id=5470&atid=105470 lines, self.lineno = inspect.getsourcelines(testmethod) # removing trailing newline(s) but not the indentation self.source = ''.join(lines).rstrip() - def run(self, pretest=None, posttest=None): + def run(self, pretest=None, postest=None): """ Run this TestItem and return a corresponding TestResult object. From sschwarzer at codespeak.net Thu Dec 18 12:53:39 2003 From: sschwarzer at codespeak.net (sschwarzer at codespeak.net) Date: Thu, 18 Dec 2003 12:53:39 +0100 (MET) Subject: [pypy-svn] rev 2487 - pypy/trunk/src/pypy/tool Message-ID: <20031218115339.F2CCB5A4F8@thoth.codespeak.net> Author: sschwarzer Date: Thu Dec 18 12:53:39 2003 New Revision: 2487 Modified: pypy/trunk/src/pypy/tool/newtest.py Log: Fixed typo in TestItem run's argument list. Removed support for list collecting from TestSuite.testresult. This feature doesn't seem quite right for me. The list can also be collected by the caller itself. Modified: pypy/trunk/src/pypy/tool/newtest.py ============================================================================== --- pypy/trunk/src/pypy/tool/newtest.py (original) +++ pypy/trunk/src/pypy/tool/newtest.py Thu Dec 18 12:53:39 2003 @@ -64,7 +64,7 @@ # removing trailing newline(s) but not the indentation self.source = ''.join(lines).rstrip() - def run(self, pretest=None, postest=None): + def run(self, pretest=None, posttest=None): """ Run this TestItem and return a corresponding TestResult object. @@ -202,18 +202,10 @@ else: self.items.extend(items) - def testresults(self, results=None): - """ - Return a generator to get the test result for each test item. - - If not None, the argument results must be a list which will - receive the result objects for later usage. - """ + def testresults(self): + """Return a generator to get the test result for each test item.""" for item in self.items: - result = item.run() - if results is not None: - results.append(result) - yield result + yield item.run() if __name__ == '__main__': From sschwarzer at codespeak.net Thu Dec 18 12:55:25 2003 From: sschwarzer at codespeak.net (sschwarzer at codespeak.net) Date: Thu, 18 Dec 2003 12:55:25 +0100 (MET) Subject: [pypy-svn] rev 2488 - pypy/trunk/src/pypy/tool Message-ID: <20031218115525.5BCA15A4F8@thoth.codespeak.net> Author: sschwarzer Date: Thu Dec 18 12:55:24 2003 New Revision: 2488 Modified: pypy/trunk/src/pypy/tool/newtest.py Log: Moved TODO points to top of file. Modified: pypy/trunk/src/pypy/tool/newtest.py ============================================================================== --- pypy/trunk/src/pypy/tool/newtest.py (original) +++ pypy/trunk/src/pypy/tool/newtest.py Thu Dec 18 12:55:24 2003 @@ -7,6 +7,9 @@ import unittest import vpath +#TODO +# - add support for ignored/skipped tests +# - support TestItem.run with different object spaces class TestStatus: def __init__(self, name, longstring, shortstring): @@ -84,8 +87,6 @@ # items in TestSuite. I wanted to avoid this. # credit: adapted from Python's unittest.TestCase.run - #XXX at a later time, this method may accept an object space - # as argument # prepare result object result = TestResult(self) From arigo at codespeak.net Thu Dec 18 13:16:54 2003 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 18 Dec 2003 13:16:54 +0100 (MET) Subject: [pypy-svn] rev 2489 - in pypy/trunk/src/pypy: annotation annotation/testtranslator translator/test Message-ID: <20031218121654.7E1DC5A4F8@thoth.codespeak.net> Author: arigo Date: Thu Dec 18 13:16:53 2003 New Revision: 2489 Removed: pypy/trunk/src/pypy/translator/annheap.py pypy/trunk/src/pypy/translator/annotation.py pypy/trunk/src/pypy/translator/test/test_annheap.py pypy/trunk/src/pypy/translator/test/test_annotation.py Modified: pypy/trunk/src/pypy/annotation/annset.py pypy/trunk/src/pypy/annotation/model.py pypy/trunk/src/pypy/annotation/test/test_annset.py pypy/trunk/src/pypy/translator/annrpython.py pypy/trunk/src/pypy/translator/translator.py Log: Started to port translator to the new annotations. Currently only translator.py can be imported, not gencl nor genpyrex. Modified: pypy/trunk/src/pypy/annotation/annset.py ============================================================================== --- pypy/trunk/src/pypy/annotation/annset.py (original) +++ pypy/trunk/src/pypy/annotation/annset.py Thu Dec 18 13:16:53 2003 @@ -6,6 +6,10 @@ QUERYARG = QueryArgument() +class IDontKnow(Exception): + pass + + class AnnotationSet: """An annotation set is a (large) family of Annotations.""" @@ -109,15 +113,6 @@ """ list all matching annotations.""" return list(self._annmatches(checkann)) - def queryconstant(self, cell): - "Return the list of all 'x' such that ANN.constant(x)[cell] is set." - cell = self.normalized(cell) - result = [] - for ann in self.annlist: - if isinstance(ann.predicate, ConstPredicate) and ann.args[0] is cell: - result.append(ann.predicate.value) - return result - def record(self, recfunc, *args): """ invoke the given 'recording' function by passing it a new Recorder instance and letting it use its modification API. This API will @@ -232,6 +227,28 @@ else: return None + def get_del(self, *querylist): + """Like get() but kills the matching annotation.""" + resultlist = list(self.match(*querylist)) + assert len(resultlist) <= 1, "Confusing annotations..." + if resultlist: + matchanns, matchvalue = resultlist[0] + self.kill(*matchanns) + return matchvalue + else: + return None + + def getconstant(self, cell): + """If cell is a constant, return its value; otherwise, raise IDontKnow. + Also accepts a None for convenience.""" + if not cell: + raise IDontKnow + cell = self.normalized(cell) + for ann in self.annlist: + if isinstance(ann.predicate, ConstPredicate) and ann.args[0] is cell: + return ann.predicate.value + raise IDontKnow, cell + def set(self, ann): """Insert the annotation into the AnnotationSet.""" self.normalizeann(ann) @@ -260,6 +277,12 @@ if knowntype in immutable_types: self.set(ANN.immutable[someval]) + def copytype(self, oldcell, newcell): + for typecell in self.query(ANN.type[oldcell, QUERYARG]): + self.set(ANN.type[newcell, typecell]) + if self.findfirst(ANN.immutable[oldcell]): + self.set(ANN.immutable[newcell]) + def newconstant(self, value): cell = SomeValue() self.set(ANN.constant(value)[cell]) Modified: pypy/trunk/src/pypy/annotation/model.py ============================================================================== --- pypy/trunk/src/pypy/annotation/model.py (original) +++ pypy/trunk/src/pypy/annotation/model.py Thu Dec 18 13:16:53 2003 @@ -30,6 +30,8 @@ class ANN: add = Predicate('add', 3) + len = Predicate('len', 2) + getitem = Predicate('getitem', 3) neg = Predicate('neg', 2) constant = ConstPredicate type = Predicate('type', 2) @@ -85,6 +87,7 @@ tuple: 'tuple', str: 'str', bool: 'bool', + slice: 'slice', types.FunctionType: 'function', } Modified: pypy/trunk/src/pypy/annotation/test/test_annset.py ============================================================================== --- pypy/trunk/src/pypy/annotation/test/test_annset.py (original) +++ pypy/trunk/src/pypy/annotation/test/test_annset.py Thu Dec 18 13:16:53 2003 @@ -3,7 +3,7 @@ from pypy.tool import test from pypy.annotation.model import ANN, SomeValue, blackholevalue -from pypy.annotation.annset import AnnotationSet, QUERYARG +from pypy.annotation.annset import AnnotationSet, QUERYARG, IDontKnow c1,c2,c3,c4 = SomeValue(), SomeValue(), SomeValue(), SomeValue() @@ -89,15 +89,13 @@ c = a.newconstant(42) self.assertSameSet(a, [ANN.constant(42)[c]]) - def test_queryconstant(self): + def test_getconstant(self): lst = [ ANN.constant(42)[c1], ] a = AnnotationSet(lst) - vlist = a.queryconstant(c1) - self.assertEquals(vlist, [42]) - vlist = a.queryconstant(c2) - self.assertEquals(vlist, []) + self.assertEquals(a.getconstant(c1), 42) + self.assertRaises(IDontKnow, a.getconstant, c2) def test_query_blackholevalue(self): lst = [ @@ -301,6 +299,17 @@ a.delete(ANN.add[c1, c3, ...]) self.assertSameSet(a, lst[1:]) + def test_get_del(self): + lst = [ + ANN.add[c1, c3, c2], + ANN.type[c1, c4], + ANN.constant(int)[c4], + ] + a = AnnotationSet(lst) + c = a.get_del(ANN.add[c1, c3, QUERYARG]) + self.assertSameCells(a, c, c2) + self.assertSameSet(a, lst[1:]) + if __name__ == '__main__': test.main() Deleted: /pypy/trunk/src/pypy/translator/annheap.py ============================================================================== --- /pypy/trunk/src/pypy/translator/annheap.py Thu Dec 18 13:16:53 2003 +++ (empty file) @@ -1,212 +0,0 @@ -from __future__ import generators -import types -from annotation import Annotation, XCell, XConstant, nothingyet - - -class AnnotationHeap: - """An annotation heap is a (large) family of Annotations.""" - - # XXX STORED AS A PLAIN LIST, THE COMPLEXITY IS PLAINLY WRONG - - def __init__(self, annlist=[]): - self.annlist = list(annlist) # List of annotations - - def dump(self): # debugging - for ann in self.enumerate(): - print ann - - def enumerate(self): - """Enumerates all annotations in the heap.""" - return iter(self.annlist) - - __iter__ = enumerate - - def simplify(self, kill=[]): - """Kill annotations in the list, and recursively all the annotations - that depend on them, and simplify the resulting heap to remove - duplicates.""" - # temporarykey() returns a tuple with all the information about - # the annotation; equal temporarykey() means equal annotations. - # Such keys are temporary because making new XCells shared can - # change the temporarykey(), but this doesn't occur during - # one call to simplify(). - - allkeys = {} # map temporarykeys to Annotation instances - for ann in self.annlist: - key = ann.temporarykey() - if key in allkeys: # duplicate? - previous = allkeys[key] - previous.forward_deps += ann.forward_deps # merge - else: - allkeys[key] = ann - - killkeys = {} # set of temporarykeys of annotations to remove - for ann in kill: - killkeys[ann.temporarykey()] = True - - pending = killkeys.keys() - for key in pending: - if key in allkeys: - ann = allkeys[key] - del allkeys[key] # remove annotations from the dict - for dep in ann.forward_deps: # propagate dependencies - depkey = dep.temporarykey() - if depkey not in killkeys: - killkeys[depkey] = True - pending.append(depkey) - - self.annlist = allkeys.values() - - def merge(self, oldcell, newcell): - """Update the heap to account for the merging of oldcell and newcell. - Return the merged cell.""" - if newcell is nothingyet or newcell == oldcell: - return oldcell - elif oldcell is nothingyet: - return newcell - else: - # any annotation or "constantness" about oldcell that must be killed? - deleting = isinstance(oldcell, XConstant) - # find the annotations common to oldcell and newcell - common = [] - for ann in self.annlist: - if oldcell in ann.args or oldcell == ann.result: - test1 = rename(ann, oldcell, newcell) - test2 = rename(ann, newcell, oldcell) # may equal 'ann' - if test1 in self.annlist and test2 in self.annlist: - common.append(test1) - else: - deleting = True - # the involved objects are immutable if we have both - # 'immutable() -> oldcell' and 'immutable() -> newcell' - if Annotation('immutable', [], newcell) in common: - # for immutable objects we can create a new cell if necessary - if not deleting: - return oldcell # nothing must be removed from oldcell - else: - resultcell = XCell() # invent a new cell - for ann in common: - self.annlist.append(rename(ann, newcell, resultcell)) - return resultcell - else: - if Annotation('immutable', [], oldcell) in self.annlist: - pass # old was immutable, don't touch it - elif Annotation('immutable', [], newcell) in self.annlist: - # new is immutable, old was not, inverse the roles - oldcell, newcell = newcell, oldcell - else: - # two mutable objects: we identify oldcell and newcell - newcell.share(oldcell) - # only keep the common annotations by listing all annotations - # to remove, which are the ones that talk about newcell but - # are not in 'common'. - deleting = [] - for ann in self.annlist: - if newcell in ann.args or newcell == ann.result: - if ann not in common: - deleting.append(ann) - # apply changes - self.simplify(kill=deleting) - return newcell - - -def rename(ann, oldcell, newcell): - "Make a copy of 'ann' in which 'oldcell' has been replaced by 'newcell'." - args = [] - for a in ann.args: - if a == oldcell: - a = newcell - args.append(a) - a = ann.result - if a == oldcell: - a = newcell - return Annotation(ann.opname, args, a) - - -class Transaction: - """A transaction contains methods to look for annotations in the - AnnotationHeap and create new annotations accordingly. Each - Transaction instance records which Annotations were needed, which - allows dependencies to be tracked.""" - - def __init__(self, heap): - self.heap = heap - self.using_annotations = [] # annotations that we have used - - def _list_annotations(self, opname, args): - # patch(arglist) -> arglist with None plugged where - # there is a None in the input 'args' - def patch(arglist): - return arglist - for i in range(len(args)): - if args[i] is None: - def patch(arglist, prevpatch=patch, i=i): - arglist = prevpatch(arglist)[:] - arglist[i] = None - return arglist - - matchann = [] - for ann in self.heap.annlist: - if ann.opname == opname and patch(ann.args) == args: - matchann.append(ann) - return matchann - - def get(self, opname, args): - """Return the Cell with the annotation 'opname(args) -> Cell', - or None if there is no such annotation or several different ones. - Hack to generalize: a None in the args matches anything.""" - matchann = self._list_annotations(opname, args) - if not matchann: - return None - else: - result = matchann[0].result - for ann in matchann[1:]: - if result != ann.result: - return None # conflicting results - for ann in matchann: - self.using(ann) - return result - - def delete(self, opname, args): - """Kill the annotations 'opname(args) -> *'.""" - matchann = self._list_annotations(opname, args) - self.heap.simplify(kill=matchann) - - def set(self, opname, args, result): - """Put a new annotation into the AnnotationHeap.""" - ann = Annotation(opname, args, result) - for prev in self.using_annotations: - prev.forward_deps.append(ann) - self.heap.annlist.append(ann) - - def get_type(self, cell): - """Get the type of 'cell', as specified by the annotations, or None. - Returns None if cell is None.""" - if cell is None: - return None - assert isinstance(cell, XCell) - c = self.get('type', [cell]) - if isinstance(c, XConstant): - return c.value - else: - return None - - def set_type(self, cell, type): - """Register an annotation describing the type of the object 'cell'.""" - self.set('type', [cell], XConstant(type)) - if type in immutable_types: - self.set('immutable', [], cell) - - def using(self, ann): - """Mark 'ann' as used in this transaction.""" - self.using_annotations.append(ann) - - -immutable_types = { - int: True, - long: True, - tuple: True, - str: True, - bool: True, - types.FunctionType: True, - } Deleted: /pypy/trunk/src/pypy/translator/annotation.py ============================================================================== --- /pypy/trunk/src/pypy/translator/annotation.py Thu Dec 18 13:16:53 2003 +++ (empty file) @@ -1,137 +0,0 @@ -import weakref - - -class Annotation: - """An Annotation asserts something about heap objects represented - by XCell instances.""" - - # Note that this is very much like a SpaceOperation, but we keep - # them separate because they have different purposes. - - # Attention, handle Annotations with care! Two Annotations that - # were initially different could become equal when XCells become - # shared. This is the reason why Annotations are not hashable. - - def __init__(self, opname, args, result): - self.opname = opname # operation name - self.args = list(args) # list of XCells - self.result = result # an XCell - self.forward_deps = [] # annotations that depend on this one - # catch bugs involving confusion between Variables/Constants - # and XCells/XConstants - for cell in args + [result]: - assert isinstance(cell, XCell) - - def __eq__(self, other): - return (self.__class__ is other.__class__ and - self.opname == other.opname and - self.args == other.args and - self.result == other.result) - - def __ne__(self, other): - return not (self == other) - - def __repr__(self): - return "%s(%s) -> %s" % (self.opname, ", ".join(map(repr, self.args)), - self.result) - - def temporarykey(self): - lst = [self.opname, self.result.temporarykey()] - lst += [arg.temporarykey() for arg in self.args] - return tuple(lst) - -def debugname(xcell, name=None, _seen = {}): - """ return a simple name for an xcell. """ - try: - return _seen[id(xcell)] - except KeyError: - if name is None: - name = "X%d" % len(_seen) - _seen[id(xcell)] = name - return name - -class XCell: - """A placeholder for a heap object contained in an AnnotationHeap. - It represents an object that will actually appear at run-time in the heap. - XCells are the arguments and return value of Annotations.""" - - # Multiple XCells can be "shared"; a group of shared cells - # act essentially like a single cell (they become all equal). - - def __init__(self): - self.shared = [] # list of weakrefs to XCells - # defining a group of shared cells. - - def __repr__(self): - names = [debugname(cell) for cell in self.cellsingroup()] - names.sort() - return '=='.join(names) - - def __eq__(self, other): - "Two sharing cells are equal." - return isinstance(other, XCell) and self.is_shared(other) - - def __ne__(self, other): - return not (self == other) - - def temporarykey(self): - ids = [id(cell) for cell in self.cellsingroup()] - return min(ids) - - def cellsingroup(self): - if self.shared: - l = [s() for s in self.shared] - assert self in l - return [c for c in l if c is not None] - else: - return [self] - - def getsharelist(self): - if not self.shared: - self.shared = [weakref.ref(self)] - return self.shared - - def is_shared(self, other): - "Test if two cells are shared." - return self.shared is other.shared - - def share(self, other): - "Make two cells shared." - if not self.is_shared(other): - lst1 = self.getsharelist() - lst2 = other.getsharelist() - for s in lst2: - c = s() - if c is not None: - c.shared = lst1 - lst1.append(s) - -class XConstant(XCell): - """A fully determined XCell. For immutable constants.""" - - def __init__(self, value): - XCell.__init__(self) - self.value = value - - def __eq__(self, other): - "Two constants with the same value are equal." - return (isinstance(other, XConstant) and self.value == other.value - or XCell.__eq__(self, other)) - - def __repr__(self): - if self.shared: - return 'UNEXPECTEDLY SHARED %r' % XCell.__repr__(self) - else: - return 'XConstant %r' % self.value - - -# The more annotations about an XCell, the least general -# it is. Extreme case: *all* possible annotations stand for an -# object that cannot exist (e.g. the return value of a function -# that never returns or we didn't see return so far). -# This is specified by using nothingyet instead of a real XCell(). -# Conversely, *no* annotation stands for any object. - -nothingyet = XCell() -debugname(nothingyet, 'nothingyet') - Modified: pypy/trunk/src/pypy/translator/annrpython.py ============================================================================== --- pypy/trunk/src/pypy/translator/annrpython.py (original) +++ pypy/trunk/src/pypy/translator/annrpython.py Thu Dec 18 13:16:53 2003 @@ -1,9 +1,9 @@ from __future__ import generators from types import FunctionType -from pypy.translator.annheap import AnnotationHeap, Transaction -from pypy.translator.annotation import XCell, XConstant, nothingyet -from pypy.translator.annotation import Annotation +from pypy.annotation.model import SomeValue, ANN, blackholevalue +from pypy.annotation.model import intvalue, boolvalue, slicevalue +from pypy.annotation.annset import AnnotationSet, QUERYARG, IDontKnow from pypy.objspace.flow.model import Variable, Constant, UndefinedConstant from pypy.objspace.flow.model import SpaceOperation @@ -17,18 +17,13 @@ See description in doc/transation/annotation.txt.""" def __init__(self, translator=None): - self.heap = AnnotationHeap() - self.pendingblocks = [] # list of (block, list-of-XCells) + self.heap = AnnotationSet() + self.pendingblocks = [] # list of (block, list-of-SomeValues-args) self.delayedblocks = [] # list of blocked blocks - self.bindings = {} # map Variables/Constants to XCells/XConstants + self.bindings = self.heap.getbindings() # map Variables/Constants + # to SomeValues self.annotated = {} # set of blocks already seen self.translator = translator - # build default annotations - t = self.transaction() - self.any_immutable = XCell() - t.set('immutable', [], self.any_immutable) - self.any_int = XCell() - t.set_type(self.any_int, int) #___ convenience high-level interface __________________ @@ -36,10 +31,10 @@ def build_types(self, flowgraph, input_arg_types): """Recursively build annotations about the specific entry point.""" # make input arguments and set their type - inputcells = [XCell() for arg in flowgraph.getargs()] - t = self.transaction() + inputcells = [SomeValue() for arg in flowgraph.getargs()] for cell, arg_type in zip(inputcells, input_arg_types): - t.set_type(cell, arg_type) + self.heap.settype(cell, arg_type) + # register the entry point self.addpendingblock(flowgraph.startblock, inputcells) # recursively proceed until no more pending block is left @@ -52,11 +47,6 @@ """Register an entry point into block with the given input cells.""" self.pendingblocks.append((block, cells)) - def transaction(self): - """Start a Transaction. Each new Annotation is marked as depending - on the Annotations queried for during the same Transation.""" - return Transaction(self.heap) - def complete(self): """Process pending blocks until none is left.""" while self.pendingblocks: @@ -70,28 +60,21 @@ len(delayed)) def binding(self, arg): - "XCell or XConstant corresponding to the given Variable or Constant." + "Gives the SomeValue corresponding to the given Variable or Constant." try: return self.bindings[arg] except KeyError: if not isinstance(arg, Constant): raise # propagate missing bindings for Variables if isinstance(arg, UndefinedConstant): - result = nothingyet # undefined local variables + result = blackholevalue # undefined local variables else: - result = XConstant(arg.value) - self.consider_const(result, arg) + result = self.consider_const(arg.value) self.bindings[arg] = result return result - def bindnew(self, arg): - "Force the creation of a new binding for the given Variable." - assert isinstance(arg, Variable) - self.bindings[arg] = result = XCell() - return result - def constant(self, value): - "Turn a value into an XConstant with the proper annotations." + "Turn a value into a SomeValue with the proper annotations." return self.binding(Constant(value)) @@ -104,20 +87,22 @@ def reverse_binding(self, known_variables, cell): """This is a hack.""" # In simplify_calls, when we are trying to create the new - # SpaceOperation, all we have are XCells. But SpaceOperations take - # Variables, not XCells. Trouble is, we don't always have a Variable - # that just happens to be bound to the given XCells. A typical - # example would be if the tuple of arguments was created from another - # basic block or even another function. Well I guess there is no - # clean solution. - if isinstance(cell, XConstant): - return Constant(cell.value) + # SpaceOperation, all we have are SomeValues. But SpaceOperations take + # Variables, not SomeValues. Trouble is, we don't always have a + # Variable that just happens to be bound to the given SomeValue. + # A typical example would be if the tuple of arguments was created + # from another basic block or even another function. Well I guess + # there is no clean solution. + vlist = self.heap.queryconstant(cell) + if len(vlist) == 1: + return Constant(vlist[0]) else: + cell = self.heap.normalized(cell) for v in known_variables: if self.bindings[v] == cell: return v else: - raise CannotSimplify + raise IDontKnow, cell def simplify(self): # Generic simpliciations @@ -161,7 +146,7 @@ def bindinputargs(self, block, inputcells): # Create the initial bindings for the input args of a block. for a, cell in zip(block.inputargs, inputcells): - self.bindings[a] = cell + self.bindings[a] = self.heap.normalized(cell) self.annotated[block] = False # must flowin. def mergeinputargs(self, block, inputcells): @@ -173,9 +158,11 @@ cell1 = self.bindings[a] # old binding oldcells.append(cell1) newcells.append(self.heap.merge(cell1, cell2)) + # if the merged cells changed, we must redo the analysis + oldcells = [self.heap.normalized(c) for c in oldcells] + newcells = [self.heap.normalized(c) for c in newcells] #print '** oldcells = ', oldcells #print '** newcells = ', newcells - # if the merged cells changed, we must redo the analysis if newcells != oldcells: self.bindinputargs(block, newcells) @@ -191,71 +178,80 @@ def consider_op(self,op): argcells = [self.binding(a) for a in op.args] - resultcell = self.bindnew(op.result) - consider_meth = getattr(self,'consider_op_'+op.opname,None) - if consider_meth is not None: - consider_meth(argcells, resultcell, self.transaction()) - - def consider_op_add(self, (arg1,arg2), result, t): - type1 = t.get_type(arg1) - type2 = t.get_type(arg2) - if type1 is int and type2 is int: - t.set_type(result, int) - elif type1 in (int, long) and type2 in (int, long): - t.set_type(result, long) - if type1 is str and type2 is str: - t.set_type(result, str) - if type1 is list and type2 is list: - t.set_type(result, list) + consider_meth = getattr(self,'consider_op_'+op.opname, + self.default_consider_op) + try: + resultcell = consider_meth(*argcells) + except IDontKnow: + resultcell = SomeValue() + if resultcell is blackholevalue: + raise DelayAnnotation # the operation cannot succeed + assert isinstance(resultcell, SomeValue) + assert isinstance(op.result, Variable) + self.bindings[op.result] = resultcell # bind resultcell to op.result + + def default_consider_op(self, *args): + return SomeValue() + + def consider_op_add(self, arg1, arg2): + result = SomeValue() + tp = self.heap.checktype + if tp(arg1, int) and tp(arg2, int): + self.heap.settype(result, int) + elif tp(arg1, (int, long)) and tp(arg2, (int, long)): + self.heap.settype(result, long) + if tp(arg1, str) and tp(arg2, str): + self.heap.settype(result, str) + if tp(arg1, list) and tp(arg2, list): + self.heap.settype(result, list) # XXX propagate information about the type of the elements + return result + + def consider_op_mul(self, arg1, arg2): + result = SomeValue() + tp = self.heap.checktype + if tp(arg1, int) and tp(arg2, int): + self.heap.settype(result, int) + elif tp(arg1, (int, long)) and tp(arg2, (int, long)): + self.heap.settype(result, long) + return result - def consider_op_mul(self, (arg1,arg2), result, t): - type1 = t.get_type(arg1) - type2 = t.get_type(arg2) - if type1 is int and type2 is int: - t.set_type(result, int) - elif type1 in (int, long) and type2 in (int, long): - t.set_type(result, long) - - def consider_op_inplace_add(self, (arg1,arg2), result, t): - type1 = t.get_type(arg1) - type2 = t.get_type(arg1) - if type1 is list and type2 is list: + def consider_op_inplace_add(self, arg1, arg2): + tp = self.heap.checktype + if tp(arg1, list) and tp(arg2, list): # Annotations about the items of arg2 are merged with the ones about # the items of arg1. arg2 is not modified during this operation. # result is arg1. - result.share(arg1) - t.delete('len', [arg1]) - item1 = t.get('getitem', [arg1, None]) - if item1 is not None: - item2 = t.get('getitem', [arg2, None]) - if item2 is None: - item2 = XCell() # anything at all + self.heap.delete(ANN.len[arg1, ...]) + item1 = self.heap.get_del(ANN.getitem[arg1, intvalue, QUERYARG]) + if item1: + item2 = self.heap.get(ANN.getitem[arg2, intvalue, QUERYARG]) + item2 = item2 or SomeValue() # defaults to "can be anything" item3 = self.heap.merge(item1, item2) - if item3 != item1: - t.delete('getitem', [arg1, None]) - t.set('getitem', [arg1, self.any_int], item3) + self.heap.set(ANN.getitem[arg1, intvalue, item3]) + return arg1 else: - self.consider_op_add((arg1,arg2), result, t) + return self.consider_op_add(arg1, arg2) - def consider_op_sub(self, (arg1,arg2), result, t): - type1 = t.get_type(arg1) - type2 = t.get_type(arg2) - if type1 is int and type2 is int: - t.set_type(result, int) - elif type1 in (int, long) and type2 in (int, long): - t.set_type(result, long) + def consider_op_sub(self, arg1, arg2): + result = SomeValue() + tp = self.heap.checktype + if tp(arg1, int) and tp(arg2, int): + self.heap.settype(result, int) + elif tp(arg1, (int, long)) and tp(arg2, (int, long)): + self.heap.settype(result, long) + return result consider_op_and_ = consider_op_sub # trailing underline consider_op_inplace_lshift = consider_op_sub - def consider_op_is_true(self, (arg,), result, t): - t.set_type(result, bool) + def consider_op_is_true(self, arg): + return boolvalue consider_op_not_ = consider_op_is_true - def consider_op_lt(self, (arg1,arg2), result, t): - t.set_type(result, bool) + def consider_op_lt(self, arg1, arg2): + return boolvalue consider_op_le = consider_op_lt consider_op_eq = consider_op_lt @@ -263,90 +259,88 @@ consider_op_gt = consider_op_lt consider_op_ge = consider_op_lt - def consider_op_newtuple(self, args, result, t): - t.set_type(result,tuple) - t.set("len", [result], self.constant(len(args))) + def consider_op_newtuple(self, *args): + result = SomeValue() + self.heap.settype(result, tuple) + self.heap.set(ANN.len[result, self.constant(len(args))]) for i in range(len(args)): - t.set("getitem", [result, self.constant(i)], args[i]) + self.heap.set(ANN.getitem[result, self.constant(i), args[i]]) + return result - def consider_op_newlist(self, args, result, t): - t.set_type(result, list) - t.set("len", [result], self.constant(len(args))) - item_cell = nothingyet + def consider_op_newlist(self, *args): + result = SomeValue() + self.heap.settype(result, list) + self.heap.set(ANN.len[result, self.constant(len(args))]) + item_cell = blackholevalue for a in args: item_cell = self.heap.merge(item_cell, a) - t.set("getitem", [result, self.any_int], item_cell) + self.heap.set(ANN.getitem[result, intvalue, item_cell]) + return result - def consider_op_newslice(self, args, result, t): - t.set_type(result, slice) + def consider_op_newslice(self, *args): + return slicevalue - def consider_op_newdict(self, args, result, t): - t.set_type(result, dict) + def consider_op_newdict(self, *args): + result = SomeValue() + self.heap.settype(result, dict) if not args: - t.set("len", [result], self.constant(0)) + self.heap.set(ANN.len[result, self.constant(0)]) + return result + + def consider_op_getitem(self, arg1, arg2): + tp = self.heap.checktype + result = self.heap.get(ANN.getitem[arg1, arg2, QUERYARG]) + if result: + return result + if tp(arg2, int): # not too nice, but needed for lists + result = self.heap.get(ANN.getitem[arg1, intvalue, QUERYARG]) + if result: + return result + result = SomeValue() + if tp(arg2, slice): + self.heap.copytype(arg1, result) + return result - def consider_op_getitem(self, (arg1,arg2), result, t): - type1 = t.get_type(arg1) - type2 = t.get_type(arg2) - if type1 in (list, tuple) and type2 is slice: - t.set_type(result, type1) - - def decode_simple_call(self, varargs_cell, varkwds_cell, t): - len_cell = t.get('len', [varargs_cell]) - if not isinstance(len_cell, XConstant): - return None - nbargs = len_cell.value - arg_cells = [t.get('getitem', [varargs_cell, self.constant(j)]) + def decode_simple_call(self, varargs_cell, varkwds_cell): + len_cell = self.heap.get(ANN.len[varargs_cell, QUERYARG]) + nbargs = self.heap.getconstant(len_cell) + arg_cells = [self.heap.get(ANN.getitem[varargs_cell, + self.constant(j), QUERYARG]) for j in range(nbargs)] if None in arg_cells: - return None - len_cell = t.get('len', [varkwds_cell]) - if not isinstance(len_cell, XConstant): - return None - nbkwds = len_cell.value + raise IDontKnow + len_cell = self.heap.get(ANN.len[varkwds_cell, QUERYARG]) + nbkwds = self.heap.getconstant(len_cell) if nbkwds != 0: - return None + raise IDontKnow return arg_cells - def consider_op_call(self, (func,varargs,kwargs), result, t): - if not isinstance(func, XConstant): - return - func = func.value + def consider_op_call(self, func, varargs, kwargs): + func = self.heap.getconstant(func) if isinstance(func, FunctionType) and self.translator: - args = self.decode_simple_call(varargs, kwargs, t) - if args is not None: - result_cell = self.translator.consider_call(self, func, args) - if result_cell is nothingyet: - raise DelayAnnotation - # 'result' is made shared with 'result_cell'. This has the - # effect that even if result_cell is actually an XConstant, - # result stays an XCell, but the annotations about the constant - # are also appliable to result. This is bad because it means - # functions returning constants won't propagate the constant - # but only e.g. its type. This is needed at this point because - # XConstants are not too well supported in the forward_deps - # lists: forward_deps cannot downgrade XConstant to XCell. - result.share(result_cell) + args = self.decode_simple_call(varargs, kwargs) + return self.translator.consider_call(self, func, args) # XXX: generalize this later + tp = self.heap.checktype + result = SomeValue() if func is range: - t.set_type(result, list) + self.heap.settype(result, list) if func is pow: - tp1 = t.get_type(t.get('getitem', [varargs, self.constant(0)])) - tp2 = t.get_type(t.get('getitem', [varargs, self.constant(1)])) - if tp1 is int and tp2 is int: - t.set_type(result, int) - - def consider_const(self,to_var,const): - t = self.transaction() - t.set('immutable', [], to_var) - t.set_type(to_var,type(const.value)) - if isinstance(const.value, tuple): - pass # XXX say something about the elements + args = self.decode_simple_call(varargs, kwargs) + if len(args) == 2: + if tp(args[0], int) and tp(args[1], int): + self.heap.settype(result, int) + return result + def consider_const(self, constvalue): + result = self.heap.newconstant(constvalue) + self.heap.set(ANN.immutable[result]) + self.heap.settype(result, type(constvalue)) + if isinstance(constvalue, tuple): + pass # XXX say something about the elements + return result -class CannotSimplify(Exception): - pass class DelayAnnotation(Exception): pass Deleted: /pypy/trunk/src/pypy/translator/test/test_annheap.py ============================================================================== --- /pypy/trunk/src/pypy/translator/test/test_annheap.py Thu Dec 18 13:16:53 2003 +++ (empty file) @@ -1,250 +0,0 @@ - -import autopath -from pypy.tool import test - -from pypy.translator.annotation import XCell, XConstant, nothingyet, Annotation -from pypy.translator.annheap import AnnotationHeap, Transaction - - -class TestAnnotationHeap(test.IntTestCase): - - def setUp(self): - self.c1 = XCell() - self.c2 = XCell() - self.c3 = XConstant(-2) - - def assertSameSet(self, a, b): - a = list(a) - b = list(b) - # try to reorder a to match b, without failing if the lists - # are different -- this will be checked by assertEquals() - for i in range(len(b)): - try: - j = i + a[i:].index(b[i]) - except ValueError: - pass - else: - a[i], a[j] = a[j], a[i] - self.assertEquals(a, b) - - def test_enumerate(self): - lst = [Annotation('add', [self.c1, self.c3], self.c2)] - a = AnnotationHeap(lst) - self.assertSameSet(a.enumerate(), lst) - - def test_simplify(self): - lst = [Annotation('add', [self.c1, self.c3], self.c2), - Annotation('add', [self.c1, self.c2], self.c2), - Annotation('neg', [self.c2], self.c3)] - a = AnnotationHeap(lst) - a.simplify() - self.assertSameSet(a, lst) - - self.c2.share(self.c3) - a.simplify() - self.assertSameSet(a, lst[1:]) - - def test_simplify_kill(self): - ann1 = Annotation('add', [self.c1, self.c3], self.c2) - lst = [ann1, - Annotation('add', [self.c1, self.c2], self.c2), - Annotation('neg', [self.c2], self.c3)] - a = AnnotationHeap(lst) - a.simplify(kill=[ann1]) - self.assertSameSet(a, lst[1:]) - - def test_simplify_kill_deps(self): - ann1 = Annotation('add', [self.c1, self.c3], self.c2) - ann2 = Annotation('add', [self.c1, self.c2], self.c2) - ann3 = Annotation('add', [self.c1, self.c1], self.c2) - ann1.forward_deps.append(ann2) - ann2.forward_deps.append(ann3) - lst = [ann1, ann2, ann3, - Annotation('neg', [self.c2], self.c3)] - a = AnnotationHeap(lst) - a.simplify(kill=[ann1]) - self.assertSameSet(a, lst[3:]) - - def test_merge_nothingyet(self): - lst = [Annotation('add', [self.c1, self.c3], self.c2), - Annotation('neg', [self.c2], self.c3)] - a = AnnotationHeap(lst) - # (c3) inter (all annotations) == (c3) - c = a.merge(self.c3, nothingyet) - self.assertEquals(c, self.c3) - self.failIfEqual(c, nothingyet) - self.assertSameSet(a, lst) - - def test_merge_mutable1(self): - lst = [Annotation('type', [self.c1], self.c3), - Annotation('type', [self.c2], self.c3), - Annotation('somethingelse', [self.c2, self.c3], self.c3)] - a = AnnotationHeap(lst) - # (c1) inter (c2) == (c1 shared with c2) - c = a.merge(self.c1, self.c2) - self.assertEquals(c, self.c1) - self.assertEquals(c, self.c2) - self.assertEquals(self.c1, self.c2) - self.assertSameSet(a, [Annotation('type', [c], self.c3)]) - - def test_merge_mutable2(self): - lst = [Annotation('type', [self.c1], self.c3), - Annotation('type', [self.c2], self.c3), - Annotation('somethingelse', [self.c1, self.c3], self.c3)] - a = AnnotationHeap(lst) - # (c1) inter (c2) == (c1 shared with c2) - c = a.merge(self.c1, self.c2) - self.assertEquals(c, self.c1) - self.assertEquals(c, self.c2) - self.assertEquals(self.c1, self.c2) - self.assertSameSet(a, [Annotation('type', [c], self.c3)]) - - def test_merge_immutable(self): - lst = [Annotation('type', [self.c1], self.c3), - Annotation('type', [self.c2], self.c3), - Annotation('immutable', [], self.c1), - Annotation('immutable', [], self.c2), - Annotation('somethingelse', [self.c2, self.c3], self.c3)] - a = AnnotationHeap(lst) - # (c1) inter (c2) == (some new c4) - c = a.merge(self.c1, self.c2) - self.failIfEqual(self.c1, self.c2) - # c could be equal to c1 here, but we don't require that - for op in [Annotation('type', [c], self.c3), - Annotation('immutable', [], c)]: - if op not in lst: - lst.append(op) - self.assertSameSet(a, lst) - - def test_merge_mutable_ex(self): - lst = [Annotation('add', [self.c1, self.c2], self.c2), - Annotation('neg', [self.c2], self.c1), - Annotation('add', [self.c3, self.c2], self.c2), - Annotation('immutable', [], self.c2)] - a = AnnotationHeap(lst) - # (c1) inter (c3) == (c1 shared with c3) - c = a.merge(self.c1, self.c3) - self.assertEquals(c, self.c1) - self.assertEquals(c, self.c3) - self.assertEquals(self.c1, self.c3) - self.assertSameSet(a, [lst[0], lst[3]]) - self.assertSameSet(a, [lst[2], lst[3]]) - - def test_merge_immutable_ex(self): - lst = [Annotation('add', [self.c1, self.c2], self.c2), - Annotation('neg', [self.c2], self.c1), - Annotation('add', [self.c3, self.c2], self.c2), - Annotation('immutable', [], self.c1), - Annotation('immutable', [], self.c2), - Annotation('immutable', [], self.c3)] - a = AnnotationHeap(lst) - # (c1) inter (c3) == (some new c4) - c = a.merge(self.c1, self.c3) - self.failIfEqual(c, self.c1) - self.failIfEqual(c, self.c3) - lst += [Annotation('add', [c, self.c2], self.c2), - Annotation('immutable', [], c)] - self.assertSameSet(a, lst) - - def dont_test_merge_mutable_ex(self): - # This test is expected to fail at this point because the algorithms - # are not 100% theoretically correct, but probably quite good and - # clear enough right now. In theory in the intersection below - # 'add' should be kept. In practice the extra 'c3' messes things - # up. I can only think about much-more-obscure algos to fix that. - lst = [Annotation('add', [self.c1, self.c3], self.c2), - Annotation('neg', [self.c2], self.c1), - Annotation('add', [self.c3, self.c3], self.c2), - Annotation('immutable', [], self.c2)] - a = AnnotationHeap(lst) - # (c1) inter (c3) == (c1 shared with c3) - c = a.merge(self.c1, self.c3) - self.assertEquals(c, self.c1) - self.assertEquals(c, self.c3) - self.assertEquals(self.c1, self.c3) - self.assertSameSet(a, [lst[0], lst[3]]) - self.assertSameSet(a, [lst[2], lst[3]]) - - def dont_test_merge_immutable_ex(self): - # Disabled -- same as above. - lst = [Annotation('add', [self.c1, self.c3], self.c2), - Annotation('neg', [self.c2], self.c1), - Annotation('add', [self.c3, self.c3], self.c2), - Annotation('immutable', [], self.c1), - Annotation('immutable', [], self.c2), - Annotation('immutable', [], self.c3)] - a = AnnotationHeap(lst) - # (c1) inter (c3) == (some new c4) - c = a.merge(self.c1, self.c3) - self.failIfEqual(c, self.c1) - self.failIfEqual(c, self.c3) - lst += [Annotation('add', [c, self.c3], self.c2), - Annotation('immutable', [], c)] - self.assertSameSet(a, lst) - - -class TestTransaction(test.IntTestCase): - - def setUp(self): - self.c1 = XCell() - self.c2 = XCell() - self.c3 = XConstant(-2) - self.lst = [Annotation('add', [self.c1, self.c3], self.c2), - Annotation('neg', [self.c2], self.c1), - Annotation('add', [self.c3, self.c3], self.c2), - Annotation('immutable', [], self.c1), - Annotation('type', [self.c1], self.c3), - Annotation('type', [self.c3], self.c2)] - self.a = AnnotationHeap(self.lst) - - def test_get(self): - t = Transaction(self.a) - self.assertEquals(t.get('add', [self.c1, self.c3]), self.c2) - self.assertEquals(t.get('add', [self.c1, self.c2]), None) - self.assertEquals(t.get('sub', [self.c1, self.c3]), None) - - def test_get_None(self): - t = Transaction(self.a) - self.assertEquals(t.get('add', [self.c1, None]), self.c2) - self.assertEquals(t.get('add', [None, self.c3]), self.c2) - self.assertEquals(t.get('add', [self.c2, None]), None) - self.assertEquals(t.get('type', [None]), None) - - def test_get_type(self): - t = Transaction(self.a) - self.assertEquals(t.get_type(self.c1), -2) - self.assertEquals(t.get_type(self.c2), None) - self.assertEquals(t.get_type(self.c3), None) - - def test_set(self): - t = Transaction(self.a) - t.set('dummy', [self.c2], self.c1) - self.assertEquals(t.get('dummy', [self.c2]), self.c1) - - def test_set_type(self): - t = Transaction(self.a) - t.set_type(self.c2, int) - self.assertEquals(t.get('type', [self.c2]), XConstant(int)) - - def test_dep_set(self): - t = Transaction(self.a) - t.get('add', [self.c1, self.c3]) - t.get_type(self.c1) - t.set('dummy', [self.c2], self.c1) - new_ann = Annotation('dummy', [self.c2], self.c1) - self.cases = [] - for ann in self.a.enumerate(): - if ann == Annotation('add', [self.c1, self.c3], self.c2): - self.cases.append(0) - self.assertEquals(ann.forward_deps, [new_ann]) - elif ann == Annotation('type', [self.c1], self.c3): - self.cases.append(1) - self.assertEquals(ann.forward_deps, [new_ann]) - else: - self.assertEquals(ann.forward_deps, []) - self.cases.sort() - self.assertEquals(self.cases, [0, 1]) - - -if __name__ == '__main__': - test.main() Deleted: /pypy/trunk/src/pypy/translator/test/test_annotation.py ============================================================================== --- /pypy/trunk/src/pypy/translator/test/test_annotation.py Thu Dec 18 13:16:53 2003 +++ (empty file) @@ -1,46 +0,0 @@ - -import autopath -from pypy.tool import test - -from pypy.translator.annotation import XCell, XConstant, nothingyet, Annotation - - -class TestAnnotation(test.IntTestCase): - - def test_is_shared(self): - c1 = XCell() - c2 = XCell() - c3 = XCell() - c4 = XCell() - for a in (c1,c2,c3,c4): - for b in (c1,c2,c3,c4): - if a is not b: - self.failIfEqual(a, b) - c1.share(c2) - c4.share(c2) - c1.share(c3) - for a in (c1,c2,c3,c4): - for b in (c1,c2,c3,c4): - self.assert_(a.is_shared(b)) - self.assertEquals(a, b) - - def test_constant(self): - self.assertEquals(XConstant(5), XConstant(5)) - self.failIfEqual(XConstant(5), XConstant(6)) - self.failIfEqual(XConstant(5), XCell()) - - def test_annotation(self): - c1 = XCell() - c2 = XCell() - c3 = XCell() - a1 = Annotation('hello', [c1], c2) - a2 = Annotation('hello', [c1], c3) - - self.assertEquals(a1, a1) - self.failIfEqual (a1, a2) - c2.share(c3) - self.assertEquals(a1, a2) - - -if __name__ == '__main__': - test.main() Modified: pypy/trunk/src/pypy/translator/translator.py ============================================================================== --- pypy/trunk/src/pypy/translator/translator.py (original) +++ pypy/trunk/src/pypy/translator/translator.py Thu Dec 18 13:16:53 2003 @@ -31,11 +31,12 @@ import test.autopath from pypy.objspace.flow.model import * -from pypy.translator.annotation import * +from pypy.annotation.model import * +from pypy.annotation.annset import * from pypy.translator.annrpython import RPythonAnnotator from pypy.translator.simplify import simplify_graph -from pypy.translator.genpyrex import GenPyrex -from pypy.translator.gencl import GenCL +#from pypy.translator.genpyrex import GenPyrex +#from pypy.translator.gencl import GenCL from pypy.translator.tool.buildpyxmodule import make_module_from_pyxstring from pypy.objspace.flow import FlowObjSpace From pmaupin at codespeak.net Thu Dec 18 13:24:14 2003 From: pmaupin at codespeak.net (pmaupin at codespeak.net) Date: Thu, 18 Dec 2003 13:24:14 +0100 (MET) Subject: [pypy-svn] rev 2490 - pypy/trunk/src/pypy/objspace/std Message-ID: <20031218122414.36B685A4F8@thoth.codespeak.net> Author: pmaupin Date: Thu Dec 18 13:24:13 2003 New Revision: 2490 Modified: pypy/trunk/src/pypy/objspace/std/dicttype.py Log: Fix setdefault with one parameter, and popitem on empty dict Modified: pypy/trunk/src/pypy/objspace/std/dicttype.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/dicttype.py (original) +++ pypy/trunk/src/pypy/objspace/std/dicttype.py Thu Dec 18 13:24:13 2003 @@ -19,7 +19,7 @@ dict_get = MultiMethod('get', 3, defaults=(None,)) dict_pop = MultiMethod('pop', 2, varargs=True) dict_popitem = MultiMethod('popitem', 1) - dict_setdefault = MultiMethod('setdefault', 3) + dict_setdefault = MultiMethod('setdefault', 3, defaults=(None,)) dict_update = MultiMethod('update', 2) dict_iteritems = MultiMethod('iteritems', 1) dict_iterkeys = MultiMethod('iterkeys', 1) @@ -41,7 +41,10 @@ d[k] = o[k] def app_dict_popitem__ANY(d): - k = d.keys()[0] + k = d.keys() + if not k: + raise KeyError("popitem(): dictionary is empty") + k = k[0] v = d[k] del d[k] return k, v From pmaupin at codespeak.net Thu Dec 18 13:24:49 2003 From: pmaupin at codespeak.net (pmaupin at codespeak.net) Date: Thu, 18 Dec 2003 13:24:49 +0100 (MET) Subject: [pypy-svn] rev 2491 - pypy/trunk/src/pypy/appspace Message-ID: <20031218122449.0C6C55A4F8@thoth.codespeak.net> Author: pmaupin Date: Thu Dec 18 13:24:49 2003 New Revision: 2491 Modified: pypy/trunk/src/pypy/appspace/builtin_types_test.py Log: Test finished until more functionality added Modified: pypy/trunk/src/pypy/appspace/builtin_types_test.py ============================================================================== --- pypy/trunk/src/pypy/appspace/builtin_types_test.py (original) +++ pypy/trunk/src/pypy/appspace/builtin_types_test.py Thu Dec 18 13:24:49 2003 @@ -608,6 +608,7 @@ except ValueError: pass else: raise TestFailed, 'dict.update(), __getitem__ expected ValueError' print '6.6.3 dict.fromkeys' +''' TODO: Need classmethods for built-in types # dict.fromkeys() if dict.fromkeys('abc') != {'a':None, 'b':None, 'c':None}: raise TestFailed, 'dict.fromkeys did not work as a class method' @@ -637,7 +638,6 @@ if type(dictlike().fromkeys('a')) is not dictlike: raise TestFailed, 'dictsubclass.fromkeys created wrong type' -''' TODO: fromkeys not recognized as a classmethod here from UserDict import UserDict class mydict(dict): def __new__(cls): @@ -757,9 +757,9 @@ except TypeError: pass else: raise TestFailed, 'type(), w/4 args expected TypeError' +''' TODO: No buffer support yet XXX print '6.8 buffer' -print 'Buffers' try: buffer('asdf', -1) except ValueError: pass else: raise TestFailed, "buffer('asdf', -1) should raise ValueError" @@ -787,3 +787,4 @@ try: a[0:1] = 'g' except TypeError: pass else: raise TestFailed, "buffer slice assignment should raise TypeError" +''' From sschwarzer at codespeak.net Thu Dec 18 14:10:58 2003 From: sschwarzer at codespeak.net (sschwarzer at codespeak.net) Date: Thu, 18 Dec 2003 14:10:58 +0100 (MET) Subject: [pypy-svn] rev 2492 - pypy/trunk/src/pypy/tool Message-ID: <20031218131058.DC0A25A4F8@thoth.codespeak.net> Author: sschwarzer Date: Thu Dec 18 14:10:58 2003 New Revision: 2492 Modified: pypy/trunk/src/pypy/tool/newtest.py Log: Return TestResult for failed setUp method. Remove raise statement used for debugging. Modified: pypy/trunk/src/pypy/tool/newtest.py ============================================================================== --- pypy/trunk/src/pypy/tool/newtest.py (original) +++ pypy/trunk/src/pypy/tool/newtest.py Thu Dec 18 14:10:58 2003 @@ -106,7 +106,7 @@ raise except: result._setstatus(ERROR) - return + return result try: testmethod() @@ -199,7 +199,6 @@ items = self._items_from_module(module) except: print "skipping testfile (failed loading it)", modpath - raise else: self.items.extend(items) @@ -209,13 +208,18 @@ yield item.run() -if __name__ == '__main__': +def main(): ts = TestSuite() - ts.initfromdir(".") + ts.initfromdir(autopath.pypydir) for res in ts.testresults(): + if res.status == SUCCESS: + continue print 75 * '-' print "%s: %s" % (res.item, res.status) if res.traceback: - print '-----' + print print res.formatted_traceback + +if __name__ == '__main__': + main() From sschwarzer at codespeak.net Thu Dec 18 14:15:25 2003 From: sschwarzer at codespeak.net (sschwarzer at codespeak.net) Date: Thu, 18 Dec 2003 14:15:25 +0100 (MET) Subject: [pypy-svn] rev 2493 - pypy/trunk/src/pypy/tool Message-ID: <20031218131525.EB74A5A4F8@thoth.codespeak.net> Author: sschwarzer Date: Thu Dec 18 14:15:24 2003 New Revision: 2493 Modified: pypy/trunk/src/pypy/tool/newtest.py Log: TestItem.run: If the test method causes an error or a failure, don't overwrite the result object if the readDown method also fails. Modified: pypy/trunk/src/pypy/tool/newtest.py ============================================================================== --- pypy/trunk/src/pypy/tool/newtest.py (original) +++ pypy/trunk/src/pypy/tool/newtest.py Thu Dec 18 14:15:24 2003 @@ -123,7 +123,10 @@ except KeyboardInterrupt: raise except: - result._setstatus(ERROR) + # if we already had an exception in the test method, + # don't overwrite it + if result.status not in (ERROR, FAILURE): + result._setstatus(ERROR) finally: if posttest is not None: posttest(self) From sschwarzer at codespeak.net Thu Dec 18 14:22:40 2003 From: sschwarzer at codespeak.net (sschwarzer at codespeak.net) Date: Thu, 18 Dec 2003 14:22:40 +0100 (MET) Subject: [pypy-svn] rev 2494 - pypy/trunk/src/pypy/tool Message-ID: <20031218132240.5F2985A4F8@thoth.codespeak.net> Author: sschwarzer Date: Thu Dec 18 14:22:39 2003 New Revision: 2494 Modified: pypy/trunk/src/pypy/tool/newtest.py Log: TestSuite.testresults: Store last result in self.lastresult . Modified: pypy/trunk/src/pypy/tool/newtest.py ============================================================================== --- pypy/trunk/src/pypy/tool/newtest.py (original) +++ pypy/trunk/src/pypy/tool/newtest.py Thu Dec 18 14:22:39 2003 @@ -144,6 +144,7 @@ """Represent a collection of test items.""" def __init__(self): self.items = [] + self.lastresult = [] def _module_from_modpath(self, modpath): """ @@ -207,8 +208,11 @@ def testresults(self): """Return a generator to get the test result for each test item.""" + self.lastresults = [] for item in self.items: - yield item.run() + result = item.run() + self.lastresults.append(result) + yield result def main(): @@ -217,7 +221,7 @@ for res in ts.testresults(): if res.status == SUCCESS: continue - print 75 * '-' + print 79 * '-' print "%s: %s" % (res.item, res.status) if res.traceback: print From pmaupin at codespeak.net Thu Dec 18 14:26:01 2003 From: pmaupin at codespeak.net (pmaupin at codespeak.net) Date: Thu, 18 Dec 2003 14:26:01 +0100 (MET) Subject: [pypy-svn] rev 2495 - pypy/trunk/src/pypy/appspace Message-ID: <20031218132601.D40E15A4F8@thoth.codespeak.net> Author: pmaupin Date: Thu Dec 18 14:26:01 2003 New Revision: 2495 Added: pypy/trunk/src/pypy/appspace/pystone.py (contents, props changed) Log: Slightly modified Python 2.3 pystone benchmark Added: pypy/trunk/src/pypy/appspace/pystone.py ============================================================================== --- (empty file) +++ pypy/trunk/src/pypy/appspace/pystone.py Thu Dec 18 14:26:01 2003 @@ -0,0 +1,252 @@ +#! /usr/bin/env python + +""" +"PYSTONE" Benchmark Program + +Version: Python/1.1 (corresponds to C/1.1 plus 2 Pystone fixes) + +Author: Reinhold P. Weicker, CACM Vol 27, No 10, 10/84 pg. 1013. + + Translated from ADA to C by Rick Richardson. + Every method to preserve ADA-likeness has been used, + at the expense of C-ness. + + Translated from C to Python by Guido van Rossum. + +Version History: + + Version 1.1 corrects two bugs in version 1.0: + + First, it leaked memory: in Proc1(), NextRecord ends + up having a pointer to itself. I have corrected this + by zapping NextRecord.PtrComp at the end of Proc1(). + + Second, Proc3() used the operator != to compare a + record to None. This is rather inefficient and not + true to the intention of the original benchmark (where + a pointer comparison to None is intended; the != + operator attempts to find a method __cmp__ to do value + comparison of the record). Version 1.1 runs 5-10 + percent faster than version 1.0, so benchmark figures + of different versions can't be compared directly. + +""" + +LOOPS = 50000 + +from time import clock + +__version__ = "1.1" + +[Ident1, Ident2, Ident3, Ident4, Ident5] = range(1, 6) + +class Record: + + def __init__(self, PtrComp = None, Discr = 0, EnumComp = 0, + IntComp = 0, StringComp = 0): + self.PtrComp = PtrComp + self.Discr = Discr + self.EnumComp = EnumComp + self.IntComp = IntComp + self.StringComp = StringComp + + def copy(self): + return Record(self.PtrComp, self.Discr, self.EnumComp, + self.IntComp, self.StringComp) + +TRUE = 1 +FALSE = 0 + +def main(loops=LOOPS): + benchtime, stones = pystones(loops) + print "Pystone(%s) time for %d passes = %g" % \ + (__version__, loops, benchtime) + print "This machine benchmarks at %g pystones/second" % stones + + +def pystones(loops=LOOPS): + return Proc0(loops) + +IntGlob = 0 +BoolGlob = FALSE +Char1Glob = '\0' +Char2Glob = '\0' +Array1Glob = [0]*51 +Array2Glob = map(lambda x: x[:], [Array1Glob]*51) +PtrGlb = None +PtrGlbNext = None + +def Proc0(loops=LOOPS): + global IntGlob + global BoolGlob + global Char1Glob + global Char2Glob + global Array1Glob + global Array2Glob + global PtrGlb + global PtrGlbNext + + starttime = clock() + for i in range(loops): + pass + nulltime = clock() - starttime + + PtrGlbNext = Record() + PtrGlb = Record() + PtrGlb.PtrComp = PtrGlbNext + PtrGlb.Discr = Ident1 + PtrGlb.EnumComp = Ident3 + PtrGlb.IntComp = 40 + PtrGlb.StringComp = "DHRYSTONE PROGRAM, SOME STRING" + String1Loc = "DHRYSTONE PROGRAM, 1'ST STRING" + Array2Glob[8][7] = 10 + + starttime = clock() + + for i in range(loops): + Proc5() + Proc4() + IntLoc1 = 2 + IntLoc2 = 3 + String2Loc = "DHRYSTONE PROGRAM, 2'ND STRING" + EnumLoc = Ident2 + BoolGlob = not Func2(String1Loc, String2Loc) + while IntLoc1 < IntLoc2: + IntLoc3 = 5 * IntLoc1 - IntLoc2 + IntLoc3 = Proc7(IntLoc1, IntLoc2) + IntLoc1 = IntLoc1 + 1 + Proc8(Array1Glob, Array2Glob, IntLoc1, IntLoc3) + PtrGlb = Proc1(PtrGlb) + CharIndex = 'A' + while CharIndex <= Char2Glob: + if EnumLoc == Func1(CharIndex, 'C'): + EnumLoc = Proc6(Ident1) + CharIndex = chr(ord(CharIndex)+1) + IntLoc3 = IntLoc2 * IntLoc1 + IntLoc2 = IntLoc3 / IntLoc1 + IntLoc2 = 7 * (IntLoc3 - IntLoc2) - IntLoc1 + IntLoc1 = Proc2(IntLoc1) + + benchtime = clock() - starttime - nulltime + return benchtime, (loops / benchtime) + +def Proc1(PtrParIn): + PtrParIn.PtrComp = NextRecord = PtrGlb.copy() + PtrParIn.IntComp = 5 + NextRecord.IntComp = PtrParIn.IntComp + NextRecord.PtrComp = PtrParIn.PtrComp + NextRecord.PtrComp = Proc3(NextRecord.PtrComp) + if NextRecord.Discr == Ident1: + NextRecord.IntComp = 6 + NextRecord.EnumComp = Proc6(PtrParIn.EnumComp) + NextRecord.PtrComp = PtrGlb.PtrComp + NextRecord.IntComp = Proc7(NextRecord.IntComp, 10) + else: + PtrParIn = NextRecord.copy() + NextRecord.PtrComp = None + return PtrParIn + +def Proc2(IntParIO): + IntLoc = IntParIO + 10 + while 1: + if Char1Glob == 'A': + IntLoc = IntLoc - 1 + IntParIO = IntLoc - IntGlob + EnumLoc = Ident1 + if EnumLoc == Ident1: + break + return IntParIO + +def Proc3(PtrParOut): + global IntGlob + + if PtrGlb is not None: + PtrParOut = PtrGlb.PtrComp + else: + IntGlob = 100 + PtrGlb.IntComp = Proc7(10, IntGlob) + return PtrParOut + +def Proc4(): + global Char2Glob + + BoolLoc = Char1Glob == 'A' + BoolLoc = BoolLoc or BoolGlob + Char2Glob = 'B' + +def Proc5(): + global Char1Glob + global BoolGlob + + Char1Glob = 'A' + BoolGlob = FALSE + +def Proc6(EnumParIn): + EnumParOut = EnumParIn + if not Func3(EnumParIn): + EnumParOut = Ident4 + if EnumParIn == Ident1: + EnumParOut = Ident1 + elif EnumParIn == Ident2: + if IntGlob > 100: + EnumParOut = Ident1 + else: + EnumParOut = Ident4 + elif EnumParIn == Ident3: + EnumParOut = Ident2 + elif EnumParIn == Ident4: + pass + elif EnumParIn == Ident5: + EnumParOut = Ident3 + return EnumParOut + +def Proc7(IntParI1, IntParI2): + IntLoc = IntParI1 + 2 + IntParOut = IntParI2 + IntLoc + return IntParOut + +def Proc8(Array1Par, Array2Par, IntParI1, IntParI2): + global IntGlob + + IntLoc = IntParI1 + 5 + Array1Par[IntLoc] = IntParI2 + Array1Par[IntLoc+1] = Array1Par[IntLoc] + Array1Par[IntLoc+30] = IntLoc + for IntIndex in range(IntLoc, IntLoc+2): + Array2Par[IntLoc][IntIndex] = IntLoc + Array2Par[IntLoc][IntLoc-1] = Array2Par[IntLoc][IntLoc-1] + 1 + Array2Par[IntLoc+20][IntLoc] = Array1Par[IntLoc] + IntGlob = 5 + +def Func1(CharPar1, CharPar2): + CharLoc1 = CharPar1 + CharLoc2 = CharLoc1 + if CharLoc2 != CharPar2: + return Ident1 + else: + return Ident2 + +def Func2(StrParI1, StrParI2): + IntLoc = 1 + while IntLoc <= 1: + if Func1(StrParI1[IntLoc], StrParI2[IntLoc+1]) == Ident1: + CharLoc = 'A' + IntLoc = IntLoc + 1 + if CharLoc >= 'W' and CharLoc <= 'Z': + IntLoc = 7 + if CharLoc == 'X': + return TRUE + else: + if StrParI1 > StrParI2: + IntLoc = IntLoc + 7 + return TRUE + else: + return FALSE + +def Func3(EnumParIn): + EnumLoc = EnumParIn + if EnumLoc == Ident3: return TRUE + return FALSE + +if __name__ == '__main__': + main() From pmaupin at codespeak.net Thu Dec 18 14:27:13 2003 From: pmaupin at codespeak.net (pmaupin at codespeak.net) Date: Thu, 18 Dec 2003 14:27:13 +0100 (MET) Subject: [pypy-svn] rev 2496 - pypy/trunk/src/pypy/module Message-ID: <20031218132713.C57ED5A4F8@thoth.codespeak.net> Author: pmaupin Date: Thu Dec 18 14:27:13 2003 New Revision: 2496 Added: pypy/trunk/src/pypy/module/timemodule.py (contents, props changed) Modified: pypy/trunk/src/pypy/module/__init__.py Log: Bootstrap version of time module Modified: pypy/trunk/src/pypy/module/__init__.py ============================================================================== --- pypy/trunk/src/pypy/module/__init__.py (original) +++ pypy/trunk/src/pypy/module/__init__.py Thu Dec 18 14:27:13 2003 @@ -29,6 +29,7 @@ ('os_modules','Ce',_std_spaces), ('os_modules','Riscos',_std_spaces), ('mathmodule','Math',_std_spaces), + ('timemodule','Time',_std_spaces), ('_randommodule','RandomHelper',_std_spaces), ('cStringIOmodule','CStringIO',_std_spaces), ('itertoolsmodule','Itertools',_std_spaces), Added: pypy/trunk/src/pypy/module/timemodule.py ============================================================================== --- (empty file) +++ pypy/trunk/src/pypy/module/timemodule.py Thu Dec 18 14:27:13 2003 @@ -0,0 +1,16 @@ +"""Bootstrap the builtin time module. + +""" +from pypy.interpreter.extmodule import ExtModule + +# We use the second (metaclassish) meaning of type to construct a subclass +# of ExtModule - can't modify some attributes (like __doc__) after class +# creation, and wrapping code does not properly look at instance variables. + +def Time(space): + try: + import time + except ImportError: + return None + _time = type('time', (ExtModule,), time.__dict__) + return _time(space) From hpk at codespeak.net Thu Dec 18 14:27:59 2003 From: hpk at codespeak.net (hpk at codespeak.net) Date: Thu, 18 Dec 2003 14:27:59 +0100 (MET) Subject: [pypy-svn] rev 2497 - pypy/trunk/src/pypy/tool Message-ID: <20031218132759.E220D5A4F8@thoth.codespeak.net> Author: hpk Date: Thu Dec 18 14:27:59 2003 New Revision: 2497 Added: pypy/trunk/src/pypy/tool/opcode.py - copied unchanged from rev 2312, xpython/trunk/dist/src/Lib/opcode.py pypy/trunk/src/pypy/tool/pydis.py - copied, changed from rev 2312, xpython/trunk/dist/src/Lib/dis.py Log: rewrote the python-2.3 dis.dis module, which is now in pypy/tool/pydis.py and will return a DisResult instance on invoking "pydis.pydis(object)" This allows to programmatically access the results of dissassembled byte code and will be used from the trace object space. (Holger, Richard) Copied: pypy/trunk/src/pypy/tool/pydis.py (from rev 2312, xpython/trunk/dist/src/Lib/dis.py) ============================================================================== --- xpython/trunk/dist/src/Lib/dis.py (original) +++ pypy/trunk/src/pypy/tool/pydis.py Thu Dec 18 14:27:59 2003 @@ -1,18 +1,91 @@ -"""Disassembler of Python byte code into mnemonics.""" +"""disassembler of Python byte code into mnemonics. +XXX this only works for python-2.3 because of the linenumber + optimization + +""" + +import autopath import sys import types -from opcode import * -from opcode import __all__ as _opcodes_all +from pypy.tool.opcode import * +from pypy.tool.opcode import __all__ as _opcodes_all -__all__ = ["dis","disassemble","distb","disco"] + _opcodes_all +__all__ = ["dis","pydisassemble","distb","disco"] + _opcodes_all del _opcodes_all -def dis(x=None): - """Disassemble classes, methods, functions, or code. +class Bytecode: + def __init__(self, disresult, bytecodeindex, oparg, lineno): + self.disresult = disresult + self.index = bytecodeindex + self.op = ord(disresult.code.co_code[self.index]) + self.name = opname[self.op] + self.oparg = oparg + self.lineno = lineno + + def reprargstring(self): + """ return a string representation of any arguments. (empty for no args)""" + oparg = self.oparg + if oparg is None: + return '' + co = self.disresult.code + op = self.op + + s = repr(oparg).rjust(5) + " " + if op in hasconst: + s += '(' + `co.co_consts[oparg]` + ')' + elif op in hasname: + s += '(' + co.co_names[oparg] + ')' + elif op in hasjrel: + s += '(to ' + repr(self.index + oparg) + ')' + elif op in haslocal: + s += '(' + co.co_varnames[oparg] + ')' + elif op in hascompare: + s += '(' + cmp_op[oparg] + ')' + elif op in hasfree: + if free is None: + free = co.co_cellvars + co.co_freevars + s += '(' + free[oparg] + ')' + return s + +class DisResult: + """ an instance of this class gets returned for disassembling + objects/functions/code objects whatever. + """ + def __init__(self, code): + self.code = code + self._bytecodes = [] + + def append(self, bytecodeindex, oparg, lineno): + """ append bytecode anaylsis information ...""" + bc = Bytecode(self, bytecodeindex, oparg, lineno) + self._bytecodes.append(bc) + + def format(self): + lastlineno = -1 + labels = findlabels(self.code.co_code) + lines = [] + for bc in self._bytecodes: + l = [] + if bc.lineno != lastlineno: + lastlineno = bc.lineno + l.append("%3d" % bc.lineno) + else: + l.append(" ") + l.append(bc.index in labels and ">>" or " ") + l.append(repr(bc.index).rjust(4)) + l.append(bc.name.ljust(20)) + l.append(bc.reprargstring()) + lines.append(" ".join(l)) + return "\n".join(lines) + + __repr__ = format + +def pydis(x=None): + """pydisassemble classes, methods, functions, or code. - With no argument, disassemble the last traceback. + With no argument, pydisassemble the last traceback. """ if x is None: @@ -39,26 +112,28 @@ print "Sorry:", msg print elif hasattr(x, 'co_code'): - disassemble(x) - elif isinstance(x, str): - disassemble_string(x) + return pydisassemble(x) + #elif isinstance(x, str): + # return pydisassemble_string(x) else: raise TypeError, \ - "don't know how to disassemble %s objects" % \ + "don't know how to pydisassemble %s objects" % \ type(x).__name__ def distb(tb=None): - """Disassemble a traceback (default: last traceback).""" + """pydisassemble a traceback (default: last traceback).""" if tb is None: try: tb = sys.last_traceback except AttributeError: - raise RuntimeError, "no last traceback to disassemble" + raise RuntimeError, "no last traceback to pydisassemble" while tb.tb_next: tb = tb.tb_next - disassemble(tb.tb_frame.f_code, tb.tb_lasti) + pydisassemble(tb.tb_frame.f_code, tb.tb_lasti) -def disassemble(co, lasti=-1): - """Disassemble a code object.""" +def pydisassemble(co): + """return result of dissassembling a code object. """ + + disresult = DisResult(co) code = co.co_code byte_increments = [ord(c) for c in co.co_lnotab[0::2]] @@ -74,7 +149,6 @@ addr = 0 line_incr = 0 - labels = findlabels(code) n = len(code) i = 0 extended_arg = 0 @@ -93,85 +167,18 @@ break else: addr = sys.maxint - if i > 0: - print - print "%3d"%lineno, - else: - print ' ', - - if i == lasti: print '-->', - else: print ' ', - if i in labels: print '>>', - else: print ' ', - print `i`.rjust(4), - print opname[op].ljust(20), + current_bytecodeindex = i i = i+1 + oparg = None if op >= HAVE_ARGUMENT: oparg = ord(code[i]) + ord(code[i+1])*256 + extended_arg extended_arg = 0 i = i+2 if op == EXTENDED_ARG: extended_arg = oparg*65536L - print `oparg`.rjust(5), - if op in hasconst: - print '(' + `co.co_consts[oparg]` + ')', - elif op in hasname: - print '(' + co.co_names[oparg] + ')', - elif op in hasjrel: - print '(to ' + `i + oparg` + ')', - elif op in haslocal: - print '(' + co.co_varnames[oparg] + ')', - elif op in hascompare: - print '(' + cmp_op[oparg] + ')', - elif op in hasfree: - if free is None: - free = co.co_cellvars + co.co_freevars - print '(' + free[oparg] + ')', - print - -def disassemble_string(code, lasti=-1, varnames=None, names=None, - constants=None): - labels = findlabels(code) - n = len(code) - i = 0 - while i < n: - c = code[i] - op = ord(c) - if op == opmap['SET_LINENO'] and i > 0: - print # Extra blank line - if i == lasti: print '-->', - else: print ' ', - if i in labels: print '>>', - else: print ' ', - print `i`.rjust(4), - print opname[op].ljust(15), - i = i+1 - if op >= HAVE_ARGUMENT: - oparg = ord(code[i]) + ord(code[i+1])*256 - i = i+2 - print `oparg`.rjust(5), - if op in hasconst: - if constants: - print '(' + `constants[oparg]` + ')', - else: - print '(%d)'%oparg, - elif op in hasname: - if names is not None: - print '(' + names[oparg] + ')', - else: - print '(%d)'%oparg, - elif op in hasjrel: - print '(to ' + `i + oparg` + ')', - elif op in haslocal: - if varnames: - print '(' + varnames[oparg] + ')', - else: - print '(%d)' % oparg, - elif op in hascompare: - print '(' + cmp_op[oparg] + ')', - print - -disco = disassemble # XXX For backwards compatibility + + disresult.append(current_bytecodeindex, oparg, lineno) + return disresult def findlabels(code): """Detect all offsets in a byte code which are jump targets. @@ -198,30 +205,3 @@ if label not in labels: labels.append(label) return labels - - -def _test(): - """Simple test program to disassemble a file.""" - if sys.argv[1:]: - if sys.argv[2:]: - sys.stderr.write("usage: python dis.py [-|file]\n") - sys.exit(2) - fn = sys.argv[1] - if not fn or fn == "-": - fn = None - else: - fn = None - if fn is None: - f = sys.stdin - else: - f = open(fn) - source = f.read() - if fn is not None: - f.close() - else: - fn = "" - code = compile(source, fn, "exec") - dis(code) - -if __name__ == "__main__": - _test() From guenter at codespeak.net Thu Dec 18 14:31:20 2003 From: guenter at codespeak.net (guenter at codespeak.net) Date: Thu, 18 Dec 2003 14:31:20 +0100 (MET) Subject: [pypy-svn] rev 2498 - pypy/trunk/src/pypy/appspace Message-ID: <20031218133120.533DF5A4F8@thoth.codespeak.net> Author: guenter Date: Thu Dec 18 14:31:19 2003 New Revision: 2498 Added: pypy/trunk/src/pypy/appspace/string.py Log: function maketrans Added: pypy/trunk/src/pypy/appspace/string.py ============================================================================== --- (empty file) +++ pypy/trunk/src/pypy/appspace/string.py Thu Dec 18 14:31:19 2003 @@ -0,0 +1,9 @@ +def maketrans(origin, image): + if len(origin) != len(image): + raise ValueError("maketrans arguments must have same length") + L = [chr(i) for i in range(256)] + for i in range(len(origin)): + L[ord(origin[i])] = image[i] + + tbl = ''.join(L) + return tbl \ No newline at end of file From guenter at codespeak.net Thu Dec 18 14:32:40 2003 From: guenter at codespeak.net (guenter at codespeak.net) Date: Thu, 18 Dec 2003 14:32:40 +0100 (MET) Subject: [pypy-svn] rev 2499 - pypy/trunk/src/pypy/appspace/test Message-ID: <20031218133240.046365A4F8@thoth.codespeak.net> Author: guenter Date: Thu Dec 18 14:32:39 2003 New Revision: 2499 Added: pypy/trunk/src/pypy/appspace/test/test_stringmodule.py Log: Added: pypy/trunk/src/pypy/appspace/test/test_stringmodule.py ============================================================================== --- (empty file) +++ pypy/trunk/src/pypy/appspace/test/test_stringmodule.py Thu Dec 18 14:32:39 2003 @@ -0,0 +1,39 @@ +#!/usr/bin/env python + + +""" +Test module for functions in stringmodule.py + +""" + +import string as c_py_string +import unittest + +import autopath +from pypy.tool import test +from pypy.appspace import string as pypy_string + +class TestStringmodule(unittest.TestCase): + def regression(self, sFuncname, *args, **kwargs): + try: + c_py_res = getattr(c_py_string, sFuncname)(*args, **kwargs) + except Exception, ce: + c_py_res = ce.__class__ + + try: + pypy_res = getattr(pypy_string, sFuncname)(*args, **kwargs) + except Exception, pe: + pypy_res = pe.__class__ + + self.assertEqual(c_py_res, pypy_res, 'not equal \n1:<%s>\n2:<%s>' % (c_py_res, pypy_res)) + + + def test_maketrans(self): + self.regression('maketrans','','') + self.regression('maketrans','a','b') + self.regression('maketrans','aa','bb') + self.regression('maketrans','aa','') + + +if __name__ == "__main__": + test.main() \ No newline at end of file From jacob at codespeak.net Thu Dec 18 14:43:40 2003 From: jacob at codespeak.net (jacob at codespeak.net) Date: Thu, 18 Dec 2003 14:43:40 +0100 (MET) Subject: [pypy-svn] rev 2500 - in pypy/trunk/src/pypy: module objspace/std objspace/std/test Message-ID: <20031218134340.AED235A4F8@thoth.codespeak.net> Author: jacob Date: Thu Dec 18 14:43:39 2003 New Revision: 2500 Modified: pypy/trunk/src/pypy/module/builtin.py pypy/trunk/src/pypy/objspace/std/floatobject.py pypy/trunk/src/pypy/objspace/std/test/test_floatobject.py Log: Implementation and test of round(). Modified: pypy/trunk/src/pypy/module/builtin.py ============================================================================== --- pypy/trunk/src/pypy/module/builtin.py (original) +++ pypy/trunk/src/pypy/module/builtin.py Thu Dec 18 14:43:39 2003 @@ -287,12 +287,17 @@ def hex(self, w_val): return self.space.hex(w_val) + def round(self, w_val, w_n=None): + if w_n is None: + w_n = self.space.wrap(0) + return self.space.round(w_val, w_n) + def id(self, w_object): return self.space.id(w_object) - def app_sum(self,sequence,total=0): + def app_sum(self, sequence, total=0): for item in sequence: - total = total+item + total = total + item return total # This function was not in the original builtins, Modified: pypy/trunk/src/pypy/objspace/std/floatobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/floatobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/floatobject.py Thu Dec 18 14:43:39 2003 @@ -79,7 +79,40 @@ i = w_float1.floatval j = w_float2.floatval return space.newbool( i >= j ) + +def _floor(f): + return f - (f % 1.0) + +def _ceil(f): + if f - (f % 1.0) == f: + return f + return f + 1.0 - (f % 1.0) + +def round__Float_Int(space, w_float, w_int): + x = w_float.floatval + ndigits = w_int.intval + # Algortithm copied directly from CPython + f = 1.0; + i = abs(ndigits); + + while i > 0: + f = f*10.0 + i -= 1 + if ndigits < 0: + x /= f + else: + x *= f + if x >= 0.0: + x = _floor(x + 0.5) + else: + x = _ceil(x - 0.5) + if ndigits < 0: + x *= f + else: + x /= f + return W_FloatObject(space, x) + def hash__Float(space,w_value): ## %reimplement% # real Implementation should be taken from _Py_HashDouble in object.c Modified: pypy/trunk/src/pypy/objspace/std/test/test_floatobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/test/test_floatobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/test/test_floatobject.py Thu Dec 18 14:43:39 2003 @@ -49,8 +49,20 @@ def test_float_string(self): self.assertEquals(42.0, float("42")) - + def test_round(self): + self.assertEquals(1.0, round(1.0)) + self.assertEquals(1.0, round(1.1)) + self.assertEquals(2.0, round(1.9)) + self.assertEquals(2.0, round(1.5)) + self.assertEquals(-2.0, round(-1.5)) + self.assertEquals(-2.0, round(-1.5)) + self.assertEquals(-2.0, round(-1.5, 0)) + self.assertEquals(-2.0, round(-1.5, 0)) + self.assertEquals(22.2, round(22.222222, 1)) + self.assertEquals(20.0, round(22.22222, -1)) + self.assertEquals(0.0, round(22.22222, -2)) + if __name__ == '__main__': test.main() From guenter at codespeak.net Thu Dec 18 14:49:18 2003 From: guenter at codespeak.net (guenter at codespeak.net) Date: Thu, 18 Dec 2003 14:49:18 +0100 (MET) Subject: [pypy-svn] rev 2501 - pypy/trunk/src/pypy/objspace/std/test Message-ID: <20031218134918.DF1DF5A4F8@thoth.codespeak.net> Author: guenter Date: Thu Dec 18 14:49:18 2003 New Revision: 2501 Modified: pypy/trunk/src/pypy/objspace/std/test/test_stringobject.py Log: test_translate added Modified: pypy/trunk/src/pypy/objspace/std/test/test_stringobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/test/test_stringobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/test/test_stringobject.py Thu Dec 18 14:49:18 2003 @@ -374,6 +374,13 @@ self.assertEquals("aaa AAA 111".swapcase(), "AAA aaa 111") self.assertEquals("".swapcase(), "") + def test_translate(self): + import string + string.maketrans('ae','ea') + s="abcde" + self.assertEquals('ebcda', s.translate(string.maketrans('ea','ae'))) + self.assertEquals('eda', s.translate(string.maketrans('ea','ae'),'bc')) + def test_iter(self): l=[] for i in iter("42"): From sschwarzer at codespeak.net Thu Dec 18 15:15:13 2003 From: sschwarzer at codespeak.net (sschwarzer at codespeak.net) Date: Thu, 18 Dec 2003 15:15:13 +0100 (MET) Subject: [pypy-svn] rev 2502 - pypy/trunk/src/pypy/tool Message-ID: <20031218141513.D649E5A4F8@thoth.codespeak.net> Author: sschwarzer Date: Thu Dec 18 15:15:13 2003 New Revision: 2502 Modified: pypy/trunk/src/pypy/tool/newtest.py Log: Support for skipping tests. Renamed method _setstatus in TestResult to _setexception. Modified: pypy/trunk/src/pypy/tool/newtest.py ============================================================================== --- pypy/trunk/src/pypy/tool/newtest.py (original) +++ pypy/trunk/src/pypy/tool/newtest.py Thu Dec 18 15:15:13 2003 @@ -10,6 +10,7 @@ #TODO # - add support for ignored/skipped tests # - support TestItem.run with different object spaces +# - find out why some modules can't be loaded class TestStatus: def __init__(self, name, longstring, shortstring): @@ -39,7 +40,7 @@ # formatted traceback (a string) self.formatted_traceback = None - def _setstatus(self, statuscode): + def _setexception(self, statuscode): self.status = statuscode self.excinfo = sys.exc_info() self.traceback = self.excinfo[2] @@ -47,7 +48,8 @@ output = StringIO.StringIO() args = self.excinfo + (None, output) traceback.print_exception(*args) - self.formatted_traceback = output.getvalue().strip() + # strip trailing newline + self.formatted_traceback = output.getvalue().rstrip() class TestItem: @@ -100,23 +102,28 @@ if pretest is not None: pretest(self) try: + #XXX possibly will have to change + from pypy.tool import test try: testobject.setUp() except KeyboardInterrupt: raise + except test.TestSkip: + result.status = SKIPPED + return result except: - result._setstatus(ERROR) + result._setexception(ERROR) return result try: testmethod() result.status = SUCCESS except AssertionError: - result._setstatus(FAILURE) + result._setexception(FAILURE) except KeyboardInterrupt: raise except: - result._setstatus(ERROR) + result._setexception(ERROR) try: testobject.tearDown() @@ -126,7 +133,7 @@ # if we already had an exception in the test method, # don't overwrite it if result.status not in (ERROR, FAILURE): - result._setstatus(ERROR) + result._setexception(ERROR) finally: if posttest is not None: posttest(self) @@ -216,13 +223,15 @@ def main(): + #filterfunc = lambda m: m.find("pypy.tool.testdata.") == -1 ts = TestSuite() ts.initfromdir(autopath.pypydir) for res in ts.testresults(): if res.status == SUCCESS: continue print 79 * '-' - print "%s: %s" % (res.item, res.status) + print "%s.%s: %s" % (res.item.module.__name__, res.item.method.__name__, + res.status) if res.traceback: print print res.formatted_traceback From guenter at codespeak.net Thu Dec 18 15:33:48 2003 From: guenter at codespeak.net (guenter at codespeak.net) Date: Thu, 18 Dec 2003 15:33:48 +0100 (MET) Subject: [pypy-svn] rev 2503 - pypy/trunk/src/pypy/objspace/std Message-ID: <20031218143348.2357A5A4F8@thoth.codespeak.net> Author: guenter Date: Thu Dec 18 15:33:47 2003 New Revision: 2503 Modified: pypy/trunk/src/pypy/objspace/std/stringobject.py Log: repr__String calls applevel fuction via gateway Modified: pypy/trunk/src/pypy/objspace/std/stringobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/stringobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/stringobject.py Thu Dec 18 15:33:47 2003 @@ -31,7 +31,7 @@ __ne__ def ne__String_String(space, w_str1, w_str2): __new__ __reduce__ -__repr__ def repr__String(space, w_str): #fake +__repr__ def repr__String(space, w_str): __rmul__ __setattr__ __str__ def str__String(space, w_str): @@ -123,10 +123,6 @@ o = ord(ch) return (o>=97 and o<=122) -def _isreadable(ch): #following CPython string_repr - o = ord(ch) - return (o>=32 and o <127) - def _is_generic(self, fun): space = w_self.space v = space.unwrap(w_self) @@ -902,76 +898,30 @@ return iterobject.W_SeqIterObject(space, w_list) -#for comparison and understandiong of the underlying algorithm the unrestricted implementation -#def repr__String(space, w_str): -# u_str = space.unwrap(w_str) -# -# quote = '\'' -# if '\'' in u_str and not '"' in u_str: -# quote = '"' -# -# u_repr = quote -# -# for i in range(len(u_str)): -# c = u_str[i] -# if c == '\\' or c == quote: u_repr+= '\\'+c -# elif c == '\t': u_repr+= '\\t' -# elif c == '\r': u_repr+= '\\r' -# elif c == '\n': u_repr+= '\\n' -# elif not _isreadable(c) : -# u_repr+= '\\' + hex(ord(c))[-3:] -# else: -# u_repr += c -# -# u_repr += quote -# -# return space.wrap(u_repr) - -def repr__String(space, w_str): - u_str = space.unwrap(w_str) +def app_repr__String(s): quote = '\'' - if '\'' in u_str and not '"' in u_str: + if quote in s and not '"' in s: quote = '"' - buflen = 2 - for i in range(len(u_str)): - c = u_str[i] - if c in quote+"\\\r\t\n" : - buflen+= 2 - elif _isreadable(c) : - buflen+= 1 - else: - buflen+= 4 - - buf = [' ']* buflen - - buf[0] = quote - j=1 - for i in range(len(u_str)): - #print buflen-j - c = u_str[i] - if c in quote+"\\\r\t\n" : - buf[j]= '\\' - j+=1 - if c == quote or c=='\\': buf[j] = c - elif c == '\t': buf[j] = 't' - elif c == '\r': buf[j] = 'r' - elif c == '\n': buf[j] = 'n' - j +=1 - elif not _isreadable(c) : - buf[j]= '\\' - j+=1 - for x in hex(ord(c))[-3:]: - buf[j] = x - j+=1 + repr = quote + + for i in range(len(s)): + c = s[i] + if c == '\\' or c == quote: repr += '\\'+c + elif c == '\t': repr+= '\\t' + elif c == '\r': repr+= '\\r' + elif c == '\n': repr+= '\\n' + elif not chr(32) <= c < chr(127) : + repr += '\\' + hex(ord(c))[-3:] else: - buf[j] = c - j+=1 - - buf[j] = quote + repr += c + + repr += quote + + return repr + +repr__String = gateway.app2interp(app_repr__String) - return space.wrap("".join(buf)) - def ord__String(space, w_str): return space.wrap(ord(space.unwrap(w_str))) From sschwarzer at codespeak.net Thu Dec 18 15:35:59 2003 From: sschwarzer at codespeak.net (sschwarzer at codespeak.net) Date: Thu, 18 Dec 2003 15:35:59 +0100 (MET) Subject: [pypy-svn] rev 2504 - pypy/trunk/src/pypy/tool Message-ID: <20031218143559.AA6535A4F8@thoth.codespeak.net> Author: sschwarzer Date: Thu Dec 18 15:35:59 2003 New Revision: 2504 Modified: pypy/trunk/src/pypy/tool/newtest.py Log: Add filter function to omit the self test modules of this new unit test framework. Modified: pypy/trunk/src/pypy/tool/newtest.py ============================================================================== --- pypy/trunk/src/pypy/tool/newtest.py (original) +++ pypy/trunk/src/pypy/tool/newtest.py Thu Dec 18 15:35:59 2003 @@ -8,9 +8,8 @@ import vpath #TODO -# - add support for ignored/skipped tests +# - add support for ignored tests # - support TestItem.run with different object spaces -# - find out why some modules can't be loaded class TestStatus: def __init__(self, name, longstring, shortstring): @@ -209,7 +208,8 @@ module = self._module_from_modpath(modpath) items = self._items_from_module(module) except: - print "skipping testfile (failed loading it)", modpath + print >> sys.stderr, \ + "Warning: can't load module %s" % modpath else: self.items.extend(items) @@ -222,10 +222,14 @@ yield result -def main(): - #filterfunc = lambda m: m.find("pypy.tool.testdata.") == -1 +def main(ignore_selftest=True): + # ignore dummy unit tests + if ignore_selftest: + filterfunc = lambda m: m.find("pypy.tool.testdata.") == -1 + else: + filterfunc = lambda m: True ts = TestSuite() - ts.initfromdir(autopath.pypydir) + ts.initfromdir(autopath.pypydir, filterfunc=filterfunc) for res in ts.testresults(): if res.status == SUCCESS: continue From hpk at codespeak.net Thu Dec 18 15:49:12 2003 From: hpk at codespeak.net (hpk at codespeak.net) Date: Thu, 18 Dec 2003 15:49:12 +0100 (MET) Subject: [pypy-svn] rev 2505 - pypy/trunk/src/pypy/interpreter/test Message-ID: <20031218144912.99BE45A4F8@thoth.codespeak.net> Author: hpk Date: Thu Dec 18 15:49:11 2003 New Revision: 2505 Modified: pypy/trunk/src/pypy/interpreter/test/test_module.py Log: fix the module test to use the cmdline-supplied or default objectspace (it was forcing stdobjspce) ... Modified: pypy/trunk/src/pypy/interpreter/test/test_module.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/test/test_module.py (original) +++ pypy/trunk/src/pypy/interpreter/test/test_module.py Thu Dec 18 15:49:11 2003 @@ -26,10 +26,10 @@ class Test_ModuleObject(test.AppTestCase): def setUp(self): - self.space = test.objspace('std') + self.space = test.objspace() def test_attr(self): - m = __import__('math') + m = __import__('__builtin__') m.x = 15 self.assertEqual(m.x, 15) self.assertEqual(getattr(m, 'x'), 15) From hpk at codespeak.net Thu Dec 18 15:49:58 2003 From: hpk at codespeak.net (hpk at codespeak.net) Date: Thu, 18 Dec 2003 15:49:58 +0100 (MET) Subject: [pypy-svn] rev 2506 - pypy/trunk/src/pypy/interpreter Message-ID: <20031218144958.44B005A4F8@thoth.codespeak.net> Author: hpk Date: Thu Dec 18 15:49:57 2003 New Revision: 2506 Modified: pypy/trunk/src/pypy/interpreter/pyopcode.py Log: scrap the examineop because the revised traceobjspace approach doesn'T need it (hopefully :-) Modified: pypy/trunk/src/pypy/interpreter/pyopcode.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/pyopcode.py (original) +++ pypy/trunk/src/pypy/interpreter/pyopcode.py Thu Dec 18 15:49:57 2003 @@ -55,26 +55,6 @@ self.next_instr += 1 return ord(c) - def examineop(self): - # XXX Testing trace object space - Add test? - - c = ord(self.code.co_code[self.next_instr]) - fn = self.dispatch_table[c] - - if hasattr(fn, "operationname"): - fn_name = fn.operationname - else: - fn_name = fn.__name__ - - arg = "" - if fn.has_arg: - lo = ord(self.code.co_code[self.next_instr + 1]) - hi = ord(self.code.co_code[self.next_instr + 2]) - arg = (hi<<8) + lo - - return c, fn_name, arg, self.next_instr - - def get_index(self): return index From alex at codespeak.net Thu Dec 18 16:02:43 2003 From: alex at codespeak.net (alex at codespeak.net) Date: Thu, 18 Dec 2003 16:02:43 +0100 (MET) Subject: [pypy-svn] rev 2507 - pypy/trunk/src/pypy/objspace/std/test Message-ID: <20031218150243.46A9F5A4F8@thoth.codespeak.net> Author: alex Date: Thu Dec 18 16:02:42 2003 New Revision: 2507 Modified: pypy/trunk/src/pypy/objspace/std/test/test_typeobject.py Log: add unit tests for __bases__ access Modified: pypy/trunk/src/pypy/objspace/std/test/test_typeobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/test/test_typeobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/test/test_typeobject.py Thu Dec 18 16:02:42 2003 @@ -57,6 +57,15 @@ def setUp(self): self.space = test.objspace('std') + def test_bases(self): + self.assertEquals(int.__bases__, (object,)) + class X: pass + self.assertEquals(X.__bases__, (object,)) + class Y(X): pass + self.assertEquals(Y.__bases__, (X,)) + class Z(Y,X): pass + self.assertEquals(Z.__bases__, (Y, X)) + def test_builtin_add(self): x = 5 self.assertEquals(x.__add__(6), 11) From pmaupin at codespeak.net Thu Dec 18 16:03:44 2003 From: pmaupin at codespeak.net (pmaupin at codespeak.net) Date: Thu, 18 Dec 2003 16:03:44 +0100 (MET) Subject: [pypy-svn] rev 2508 - pypy/trunk/src/pypy/objspace/std Message-ID: <20031218150344.9F1055A4F8@thoth.codespeak.net> Author: pmaupin Date: Thu Dec 18 16:03:44 2003 New Revision: 2508 Modified: pypy/trunk/src/pypy/objspace/std/typeobject.py Log: Added __bases__ attribute to type object Modified: pypy/trunk/src/pypy/objspace/std/typeobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/typeobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/typeobject.py Thu Dec 18 16:03:44 2003 @@ -208,6 +208,8 @@ return w_type.w_tpname if space.is_true(space.eq(w_attr, space.wrap('__mro__'))): return space.newtuple(list(w_type.getmro())) + if space.is_true(space.eq(w_attr, space.wrap('__bases__'))): + return space.newtuple(list(w_type.getbases())) try: desc = w_type.lookup(w_attr) except KeyError: From jacob at codespeak.net Thu Dec 18 16:04:49 2003 From: jacob at codespeak.net (jacob at codespeak.net) Date: Thu, 18 Dec 2003 16:04:49 +0100 (MET) Subject: [pypy-svn] rev 2509 - pypy/trunk/src/pypy/interpreter Message-ID: <20031218150449.301125A4F8@thoth.codespeak.net> Author: jacob Date: Thu Dec 18 16:04:48 2003 New Revision: 2509 Modified: pypy/trunk/src/pypy/interpreter/baseobjspace.py Log: Added round() among multimethods. Modified: pypy/trunk/src/pypy/interpreter/baseobjspace.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/baseobjspace.py (original) +++ pypy/trunk/src/pypy/interpreter/baseobjspace.py Thu Dec 18 16:04:48 2003 @@ -233,6 +233,7 @@ ('abs' , 'abs', 1, ['__abs__']), ('hex', 'hex', 1, ['__hex__']), ('oct', 'oct', 1, ['__oct__']), + ('round', 'round', 2, []), ('ord', 'ord', 1, []), ('invert', '~', 1, ['__invert__']), ('add', '+', 2, ['__add__', '__radd__']), From sschwarzer at codespeak.net Thu Dec 18 16:19:26 2003 From: sschwarzer at codespeak.net (sschwarzer at codespeak.net) Date: Thu, 18 Dec 2003 16:19:26 +0100 (MET) Subject: [pypy-svn] rev 2510 - pypy/trunk/src/pypy/tool Message-ID: <20031218151926.CF1255A4F8@thoth.codespeak.net> Author: sschwarzer Date: Thu Dec 18 16:19:26 2003 New Revision: 2510 Modified: pypy/trunk/src/pypy/tool/newtest.py Log: Support comparison of TestItem objects. Modified: pypy/trunk/src/pypy/tool/newtest.py ============================================================================== --- pypy/trunk/src/pypy/tool/newtest.py (original) +++ pypy/trunk/src/pypy/tool/newtest.py Thu Dec 18 16:19:26 2003 @@ -68,6 +68,26 @@ # removing trailing newline(s) but not the indentation self.source = ''.join(lines).rstrip() + def __eq__(self, other): + """ + Return true if this and the other item compare equal. This doesn't + necessarily mean that they are the same object. + """ + if self is other: + return True + # If module, cls and unbound method are the same, the files must + # also be equal. For the methods, we compare the names, not the + # methods themselves; see + # http://mail.python.org/pipermail/python-list/2002-September/121655.html + # for an explanation. + if (self.module is other.module) and (self.cls is other.cls) and \ + (self.method.__name__ == other.method.__name__): + return True + return False + + def __ne__(self, other): + return not (self == other) + def run(self, pretest=None, posttest=None): """ Run this TestItem and return a corresponding TestResult object. @@ -223,7 +243,7 @@ def main(ignore_selftest=True): - # ignore dummy unit tests + # possibly ignore dummy unit tests if ignore_selftest: filterfunc = lambda m: m.find("pypy.tool.testdata.") == -1 else: From sschwarzer at codespeak.net Thu Dec 18 16:24:50 2003 From: sschwarzer at codespeak.net (sschwarzer at codespeak.net) Date: Thu, 18 Dec 2003 16:24:50 +0100 (MET) Subject: [pypy-svn] rev 2511 - pypy/trunk/src/pypy/tool Message-ID: <20031218152450.6F0545A4F8@thoth.codespeak.net> Author: sschwarzer Date: Thu Dec 18 16:24:49 2003 New Revision: 2511 Modified: pypy/trunk/src/pypy/tool/newtest.py Log: Added comparison of TestResult values. Modified: pypy/trunk/src/pypy/tool/newtest.py ============================================================================== --- pypy/trunk/src/pypy/tool/newtest.py (original) +++ pypy/trunk/src/pypy/tool/newtest.py Thu Dec 18 16:24:49 2003 @@ -10,6 +10,8 @@ #TODO # - add support for ignored tests # - support TestItem.run with different object spaces +# - perhaps we have to be able to compare TestResult and TestItem values +# which were pickled class TestStatus: def __init__(self, name, longstring, shortstring): @@ -39,6 +41,18 @@ # formatted traceback (a string) self.formatted_traceback = None + def __eq__(self, other): + # trivial case + if self is other: + return True + if (self.item is other.item) and (self.status == other.status) and \ + (self.formatted_traceback == other.formatted_traceback): + return True + return False + + def __ne__(self, other): + return not (self == other) + def _setexception(self, statuscode): self.status = statuscode self.excinfo = sys.exc_info() @@ -73,6 +87,7 @@ Return true if this and the other item compare equal. This doesn't necessarily mean that they are the same object. """ + # trivial case if self is other: return True # If module, cls and unbound method are the same, the files must From alex at codespeak.net Thu Dec 18 16:24:55 2003 From: alex at codespeak.net (alex at codespeak.net) Date: Thu, 18 Dec 2003 16:24:55 +0100 (MET) Subject: [pypy-svn] rev 2512 - pypy/trunk/src/pypy/objspace/std/test Message-ID: <20031218152455.CA0765A4F8@thoth.codespeak.net> Author: alex Date: Thu Dec 18 16:24:54 2003 New Revision: 2512 Modified: pypy/trunk/src/pypy/objspace/std/test/test_listobject.py Log: add unit test for simple list sort (no optional argument, yet) Modified: pypy/trunk/src/pypy/objspace/std/test/test_listobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/test/test_listobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/test/test_listobject.py Thu Dec 18 16:24:54 2003 @@ -292,6 +292,17 @@ l.extend((2,)) self.assertEquals(l, [1,2]) + def test_sort(self): + l = [1, 5, 3, 0] + l.sort() + self.assertEquals(l, [0, 1, 3, 5]) + l = [] + l.sort() + self.assertEquals(l, []) + l = [1] + l.sort() + self.assertEquals(l, [1]) + def test_extended_slice(self): l = range(10) del l[::2] From pmaupin at codespeak.net Thu Dec 18 16:26:56 2003 From: pmaupin at codespeak.net (pmaupin at codespeak.net) Date: Thu, 18 Dec 2003 16:26:56 +0100 (MET) Subject: [pypy-svn] rev 2513 - pypy/trunk/src/pypy/objspace/std Message-ID: <20031218152656.A24375A4F8@thoth.codespeak.net> Author: pmaupin Date: Thu Dec 18 16:26:55 2003 New Revision: 2513 Modified: pypy/trunk/src/pypy/objspace/std/listobject.py Log: Refactor in preparation to adding second sort() parameter Modified: pypy/trunk/src/pypy/objspace/std/listobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/listobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/listobject.py Thu Dec 18 16:26:55 2003 @@ -451,7 +451,7 @@ # Python Quicksort Written by Magnus Lie Hetland # http://www.hetland.org/python/quicksort.html -def _partition(space, list, start, end): +def _partition(list, start, end, lt): pivot = list[end] # Partition around the last value bottom = start-1 # Start outside the area to be partitioned top = end # Ditto @@ -466,7 +466,7 @@ done = 1 # ... we are done. break - if space.is_true(space.gt(list[bottom], pivot)): # Is the bottom out of place? + if lt(pivot, list[bottom]): # Is the bottom out of place? list[top] = list[bottom] # Then put it at the top... break # ... and start searching from the top. @@ -477,7 +477,7 @@ done = 1 # ... we are done. break - if space.is_true(space.lt(list[top], pivot)): # Is the top out of place? + if lt(list[top], pivot): # Is the top out of place? list[bottom] = list[top] # Then put it at the bottom... break # ...and start searching from the bottom. @@ -485,17 +485,19 @@ return top # Return the split point -def _quicksort(space, list, start, end): +def _quicksort(list, start, end, lt): if start < end: # If there are two or more elements... - split = _partition(space, list, start, end) # ... partition the sublist... - _quicksort(space, list, start, split-1) # ... and sort both halves. - _quicksort(space, list, split+1, end) + split = _partition(list, start, end, lt) # ... partition the sublist... + _quicksort(list, start, split-1, lt) # ... and sort both halves. + _quicksort(list, split+1, end, lt) def list_sort__List(space, w_list): + def lt(a,b): + return space.is_true(space.lt(a,b)) + # XXX Basic quicksort implementation # XXX this is not stable !! - # XXX no optional argument yet ! - _quicksort(space, w_list.ob_item, 0, w_list.ob_size-1) + _quicksort(w_list.ob_item, 0, w_list.ob_size-1, lt) return space.w_None From sschwarzer at codespeak.net Thu Dec 18 16:28:01 2003 From: sschwarzer at codespeak.net (sschwarzer at codespeak.net) Date: Thu, 18 Dec 2003 16:28:01 +0100 (MET) Subject: [pypy-svn] rev 2514 - pypy/trunk/src/pypy/tool Message-ID: <20031218152801.7D4925A4F8@thoth.codespeak.net> Author: sschwarzer Date: Thu Dec 18 16:28:00 2003 New Revision: 2514 Modified: pypy/trunk/src/pypy/tool/newtest.py Log: Updated docstrings for comparison methods. Modified: pypy/trunk/src/pypy/tool/newtest.py ============================================================================== --- pypy/trunk/src/pypy/tool/newtest.py (original) +++ pypy/trunk/src/pypy/tool/newtest.py Thu Dec 18 16:28:00 2003 @@ -42,6 +42,10 @@ self.formatted_traceback = None def __eq__(self, other): + """ + Return True if both TestResult objects are semantically the same. + Else, return False. + """ # trivial case if self is other: return True @@ -84,8 +88,8 @@ def __eq__(self, other): """ - Return true if this and the other item compare equal. This doesn't - necessarily mean that they are the same object. + Return True if this and the other item compare equal. (This doesn't + necessarily mean that they are the same object.) Else, return False. """ # trivial case if self is other: From hpk at codespeak.net Thu Dec 18 16:32:16 2003 From: hpk at codespeak.net (hpk at codespeak.net) Date: Thu, 18 Dec 2003 16:32:16 +0100 (MET) Subject: [pypy-svn] rev 2515 - pypy/trunk/src/pypy/interpreter Message-ID: <20031218153216.ABCC05A4F8@thoth.codespeak.net> Author: hpk Date: Thu Dec 18 16:32:16 2003 New Revision: 2515 Modified: pypy/trunk/src/pypy/interpreter/pyopcode.py Log: removed bogus method Modified: pypy/trunk/src/pypy/interpreter/pyopcode.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/pyopcode.py (original) +++ pypy/trunk/src/pypy/interpreter/pyopcode.py Thu Dec 18 16:32:16 2003 @@ -55,10 +55,6 @@ self.next_instr += 1 return ord(c) - def get_index(self): - return index - - def nextarg(self): lo = self.nextop() hi = self.nextop() From alex at codespeak.net Thu Dec 18 16:38:26 2003 From: alex at codespeak.net (alex at codespeak.net) Date: Thu, 18 Dec 2003 16:38:26 +0100 (MET) Subject: [pypy-svn] rev 2516 - pypy/trunk/src/pypy/objspace/std/test Message-ID: <20031218153826.7F9735A4F8@thoth.codespeak.net> Author: alex Date: Thu Dec 18 16:38:25 2003 New Revision: 2516 Modified: pypy/trunk/src/pypy/objspace/std/test/test_listobject.py Log: add unit test for sort with comparison function Modified: pypy/trunk/src/pypy/objspace/std/test/test_listobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/test/test_listobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/test/test_listobject.py Thu Dec 18 16:38:25 2003 @@ -302,6 +302,18 @@ l = [1] l.sort() self.assertEquals(l, [1]) + + def test_sort_cmp(self): + def lencmp(a,b): return cmp(len(a), len(b)) + l = [ 'a', 'fiver', 'tre', '' ] + l.sort(lencmp) + self.assertEquals(l, ['', 'a', 'tre', 'fiver']) + l = [] + l.sort(lencmp) + self.assertEquals(l, []) + l = [ 'a' ] + l.sort(lencmp) + self.assertEquals(l, [ 'a' ]) def test_extended_slice(self): l = range(10) From pmaupin at codespeak.net Thu Dec 18 16:40:15 2003 From: pmaupin at codespeak.net (pmaupin at codespeak.net) Date: Thu, 18 Dec 2003 16:40:15 +0100 (MET) Subject: [pypy-svn] rev 2517 - pypy/trunk/src/pypy/objspace/std Message-ID: <20031218154015.D63435A4F8@thoth.codespeak.net> Author: pmaupin Date: Thu Dec 18 16:40:15 2003 New Revision: 2517 Modified: pypy/trunk/src/pypy/objspace/std/listobject.py pypy/trunk/src/pypy/objspace/std/listtype.py Log: Added sort(list,cmp) functionality Modified: pypy/trunk/src/pypy/objspace/std/listobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/listobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/listobject.py Thu Dec 18 16:40:15 2003 @@ -491,9 +491,13 @@ _quicksort(list, start, split-1, lt) # ... and sort both halves. _quicksort(list, split+1, end, lt) -def list_sort__List(space, w_list): - def lt(a,b): - return space.is_true(space.lt(a,b)) +def list_sort__List_ANY(space, w_list, w_cmp): + if w_cmp is space.w_None: + def lt(a,b): + return space.is_true(space.lt(a,b)) + else: + def lt(a,b): + return space.unwrap(space.call_function(w_cmp, a, b)) < 0 # XXX Basic quicksort implementation # XXX this is not stable !! Modified: pypy/trunk/src/pypy/objspace/std/listtype.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/listtype.py (original) +++ pypy/trunk/src/pypy/objspace/std/listtype.py Thu Dec 18 16:40:15 2003 @@ -14,7 +14,7 @@ list_index = MultiMethod('index', 4, defaults=(0,maxint)) list_count = MultiMethod('count', 2) list_reverse= MultiMethod('reverse',1) - list_sort = MultiMethod('sort', 1) + list_sort = MultiMethod('sort', 2, defaults=(None,)) registerimplementation(W_ListType) From pmaupin at codespeak.net Thu Dec 18 16:57:19 2003 From: pmaupin at codespeak.net (pmaupin at codespeak.net) Date: Thu, 18 Dec 2003 16:57:19 +0100 (MET) Subject: [pypy-svn] rev 2518 - pypy/trunk/src/pypy/appspace Message-ID: <20031218155719.C7A995A4F8@thoth.codespeak.net> Author: pmaupin Date: Thu Dec 18 16:57:18 2003 New Revision: 2518 Modified: pypy/trunk/src/pypy/appspace/support_tests.py Log: Add back in removed unittest functionality Modified: pypy/trunk/src/pypy/appspace/support_tests.py ============================================================================== --- pypy/trunk/src/pypy/appspace/support_tests.py (original) +++ pypy/trunk/src/pypy/appspace/support_tests.py Thu Dec 18 16:57:18 2003 @@ -6,6 +6,7 @@ ''' import sys +from os import unlink class Error(Exception): """Base class for regression test exceptions.""" @@ -188,3 +189,85 @@ else: print 'Missing SyntaxError: "%s"' % statement +#======================================================================= +# Preliminary PyUNIT integration. + +import unittest + + +class BasicTestRunner: + def run(self, test): + result = unittest.TestResult() + test(result) + return result + + +def run_suite(suite, testclass=None): + """Run tests from a unittest.TestSuite-derived class.""" + if verbose: + runner = unittest.TextTestRunner(sys.stdout, verbosity=2) + else: + runner = BasicTestRunner() + + result = runner.run(suite) + if not result.wasSuccessful(): + if len(result.errors) == 1 and not result.failures: + err = result.errors[0][1] + elif len(result.failures) == 1 and not result.errors: + err = result.failures[0][1] + else: + if testclass is None: + msg = "errors occurred; run in verbose mode for details" + else: + msg = "errors occurred in %s.%s" \ + % (testclass.__module__, testclass.__name__) + raise TestFailed(msg) + raise TestFailed(err) + + +def run_unittest(*classes): + """Run tests from unittest.TestCase-derived classes.""" + suite = unittest.TestSuite() + for cls in classes: + if isinstance(cls, (unittest.TestSuite, unittest.TestCase)): + suite.addTest(cls) + else: + suite.addTest(unittest.makeSuite(cls)) + if len(classes)==1: + testclass = classes[0] + else: + testclass = None + run_suite(suite, testclass) + + +#======================================================================= +# doctest driver. + +def run_doctest(module, verbosity=None): + """Run doctest on the given module. Return (#failures, #tests). + + If optional argument verbosity is not specified (or is None), pass + test_support's belief about verbosity on to doctest. Else doctest's + usual behavior is used (it searches sys.argv for -v). + """ + + import doctest + + if verbosity is None: + verbosity = verbose + else: + verbosity = None + + # Direct doctest output (normally just errors) to real stdout; doctest + # output shouldn't be compared by regrtest. + save_stdout = sys.stdout + sys.stdout = get_original_stdout() + try: + f, t = doctest.testmod(module, verbose=verbosity) + if f: + raise TestFailed("%d of %d doctests failed" % (f, t)) + finally: + sys.stdout = save_stdout + if verbose: + print 'doctest (%s) ... %d tests with zero failures' % (module.__name__, t) + return f, t From pmaupin at codespeak.net Thu Dec 18 16:58:13 2003 From: pmaupin at codespeak.net (pmaupin at codespeak.net) Date: Thu, 18 Dec 2003 16:58:13 +0100 (MET) Subject: [pypy-svn] rev 2519 - pypy/trunk/src/pypy/appspace Message-ID: <20031218155813.618EB5A4F8@thoth.codespeak.net> Author: pmaupin Date: Thu Dec 18 16:58:12 2003 New Revision: 2519 Modified: pypy/trunk/src/pypy/appspace/builtin_types_test.py Log: Update tests for sort -- added comparison function Modified: pypy/trunk/src/pypy/appspace/builtin_types_test.py ============================================================================== --- pypy/trunk/src/pypy/appspace/builtin_types_test.py (original) +++ pypy/trunk/src/pypy/appspace/builtin_types_test.py Thu Dec 18 16:58:12 2003 @@ -415,7 +415,6 @@ if a != [2,1,0,-1,-2]: raise TestFailed, 'list reverse' a.sort() if a != [-2,-1,0,1,2]: raise TestFailed, 'list sort' -''' TODO: Support comparison functions XXX def revcmp(a, b): return cmp(b, a) a.sort(revcmp) if a != [2,1,0,-1,-2]: raise TestFailed, 'list sort with cmp func' @@ -429,17 +428,18 @@ except TypeError: pass else: raise TestFailed, 'list sort compare function is not callable' +''' XXX TODO: add detection of list modification during sort def selfmodifyingComparison(x,y): z.append(1) return cmp(x, y) try: z.sort(selfmodifyingComparison) except ValueError: pass else: raise TestFailed, 'modifying list during sort' +''' try: z.sort(lambda x, y: 's') except TypeError: pass else: raise TestFailed, 'list sort compare function does not return int' -''' # Test extreme cases with long ints a = [0,1,2,3,4] @@ -788,3 +788,4 @@ except TypeError: pass else: raise TestFailed, "buffer slice assignment should raise TypeError" ''' +print '6.99999999... All tests ran to completion' \ No newline at end of file From pmaupin at codespeak.net Thu Dec 18 16:59:00 2003 From: pmaupin at codespeak.net (pmaupin at codespeak.net) Date: Thu, 18 Dec 2003 16:59:00 +0100 (MET) Subject: [pypy-svn] rev 2520 - pypy/trunk/src/pypy/objspace/std Message-ID: <20031218155900.0F2705A4F8@thoth.codespeak.net> Author: pmaupin Date: Thu Dec 18 16:58:59 2003 New Revision: 2520 Modified: pypy/trunk/src/pypy/objspace/std/listobject.py Log: Check that comparison function returns int Modified: pypy/trunk/src/pypy/objspace/std/listobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/listobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/listobject.py Thu Dec 18 16:58:59 2003 @@ -451,6 +451,12 @@ # Python Quicksort Written by Magnus Lie Hetland # http://www.hetland.org/python/quicksort.html + +# 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, start, end, lt): pivot = list[end] # Partition around the last value bottom = start-1 # Start outside the area to be partitioned @@ -497,7 +503,11 @@ return space.is_true(space.lt(a,b)) else: def lt(a,b): - return space.unwrap(space.call_function(w_cmp, a, b)) < 0 + result = space.unwrap(space.call_function(w_cmp, a, b)) + if not isinstance(result,int): + raise OperationError(space.w_TypeError, + space.wrap("comparison function must return int")) + return result < 0 # XXX Basic quicksort implementation # XXX this is not stable !! From hpk at codespeak.net Thu Dec 18 17:26:01 2003 From: hpk at codespeak.net (hpk at codespeak.net) Date: Thu, 18 Dec 2003 17:26:01 +0100 (MET) Subject: [pypy-svn] rev 2521 - in pypy/trunk/src/pypy: objspace objspace/test tool Message-ID: <20031218162601.0C1AC5A4F8@thoth.codespeak.net> Author: hpk Date: Thu Dec 18 17:26:00 2003 New Revision: 2521 Added: pypy/trunk/src/pypy/objspace/test/ (props changed) pypy/trunk/src/pypy/objspace/test/__init__.py (contents, props changed) pypy/trunk/src/pypy/objspace/test/autopath.py (props changed) - copied unchanged from rev 2464, pypy/trunk/src/pypy/tool/autopath.py pypy/trunk/src/pypy/objspace/test/test_traceobjspace.py (contents, props changed) Modified: pypy/trunk/src/pypy/objspace/trace.py pypy/trunk/src/pypy/tool/pydis.py Log: Well. The main reason for this commit is that we want to have a break. Luckily the new traceobjspace passes its tests which means it basically captures the execution of bytecodes and the operations as they happen to the underlying "traced" object space. Also the new 'pydis.py' module is there to provide disassembling of code objects in a programmatic way (i.e. it doesn't do print statements but returns a queryable result). note that pydis.py only works with Python 2.3 (michael knows why ...) Added: pypy/trunk/src/pypy/objspace/test/__init__.py ============================================================================== --- (empty file) +++ pypy/trunk/src/pypy/objspace/test/__init__.py Thu Dec 18 17:26:00 2003 @@ -0,0 +1 @@ +# Added: pypy/trunk/src/pypy/objspace/test/test_traceobjspace.py ============================================================================== --- (empty file) +++ pypy/trunk/src/pypy/objspace/test/test_traceobjspace.py Thu Dec 18 17:26:00 2003 @@ -0,0 +1,48 @@ +import autopath +from pypy.tool import test +from pypy.objspace.trace import TraceObjSpace +from pypy.interpreter.gateway import app2interp +from pypy.tool import pydis + +class Test_TraceObjSpace(test.IntTestCase): + + def setUp(self): + self.space = test.objspace('trivial') + + def tearDown(self): + pass + + def perform_trace(self, app_func): + tspace = TraceObjSpace(self.space) + func_gw = app2interp(app_func) + func = func_gw.get_function(tspace) + tspace.settrace() + func() + res = tspace.getresult() + return res + + def test_simpletrace(self): + def app_f(): + pass + res = self.perform_trace(app_f) + disresult = pydis.pydis(app_f) + self.assertEquals(disresult._bytecodes, list(res.getbytecodes())) + #self.assertEquals(len(list(res.getoperations())), 0) + + def test_trace_oneop(self): + def app_f(): + 1 + 1 + w = self.space.wrap + res = self.perform_trace(app_f) + disresult = pydis.pydis(app_f) + self.assertEquals(disresult._bytecodes, list(res.getbytecodes())) + ops = list(res.getoperations()) + self.assert_(len(ops) > 0) + #op = ops[0] + #self.assertEquals(pydis.getbytecodename(op.bytecode), 'binary_add') # XXX + #self.assertEquals(op.name, 'add') + #expected_w = (w(1), w(1)) + #self.assertEquals_w(op.args_w, expected_w) + +if __name__ == '__main__': + test.main() Modified: pypy/trunk/src/pypy/objspace/trace.py ============================================================================== --- pypy/trunk/src/pypy/objspace/trace.py (original) +++ pypy/trunk/src/pypy/objspace/trace.py Thu Dec 18 17:26:00 2003 @@ -1,137 +1,193 @@ -import sys, operator, types, new, autopath -import pypy -from pypy.objspace.std import StdObjSpace -from pypy.objspace.trivial import TrivialObjSpace -from pypy.interpreter.baseobjspace import ObjSpace -from pypy.interpreter.executioncontext import ExecutionContext -from pypy.interpreter.pycode import PyCode -from pypy.interpreter import gateway +""" + trace object space traces operations and bytecode execution + in frames. + +""" +from __future__ import generators +from pypy.tool import pydis + +# __________________________________________________________________________ +# +# Tracing Events +# __________________________________________________________________________ + +class ExecBytecode: + def __init__(self, frame): + self.frame = frame + self.index = frame.next_instr + +class EnterFrame: + def __init__(self, frame): + self.frame = frame + +class LeaveFrame: + def __init__(self, frame): + self.frame = frame + +class CallBegin: + def __init__(self, callinfo): + self.callinfo = callinfo + +class CallFinished: + def __init__(self, callinfo): + self.callinfo = callinfo + +class CallException: + def __init__(self, e, callinfo): + self.ex = e + self.callinfo = callinfo + +# __________________________________________________________________________ +# +# Tracer Proxy objects +# __________________________________________________________________________ +# +class ExecutionContextTracer: + def __init__(self, result, ec): + self.ec = ec + self.result = result -DONT_TRACK_BYTECODES = ["PRINT_ITEM", "PRINT_NEWLINE", "PRINT_EXPR", "PRINT_ITEM_TO", "PRINT_NEWLINE_TO"] - - -class TraceExecutionContext(ExecutionContext): + def __getattr__(self, name): + """ generically pass through everything we don'T have explicit + interceptors for. + """ + print "trying", name + 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): - "Trace function called before each bytecode." - self.space.notify_on_bytecode(frame) + "called just before execution of a bytecode." + self.result.append(ExecBytecode(frame)) + #def exception_trace(self, operror): + # "called if the current frame raises an operation error. """ -class Tracer(object): - def __init__(self, name, fn, space): - self.fn = fn +class CallInfo: + """ encapsulates a function call with its arguments. """ + def __init__(self, name, func, args, kwargs): self.name = name - self.space = space + self.func = func + self.args = args + self.kwargs = kwargs + +class CallableTracer: + def __init__(self, result, name, func): + self.result = result + self.name = name + self.func = func - def __call__(self, cls, *args, **kwds): - assert (not kwds) - - self.space.notify_on_operation(self.name, args) - return self.fn(*args, **kwds) - - def __getattr__(self, name): - return getattr(self.fn, name) - + 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(e, callinfo)) + raise + else: + self.result.append(CallFinished(callinfo)) + return res class TraceObjSpace: - def __init__(self, space): - self.tracing = 0 - self.ignore_up_to_frame = None self.space = space - method_names = [ii[0] for ii in ObjSpace.MethodTable] - for key in method_names: - if key in method_names: - item = getattr(self.space, key) - l = Tracer(key, item, self) - setattr(self, key, new.instancemethod(l, self, TraceObjSpace)) + self.settrace() + def settrace(self): + self.result = TraceResult(self) - def __getattr__(self, name): - return getattr(self.space, name) + def getresult(self): + return self.result + def __getattr__(self, name): + obj = getattr(self.space, name) + if callable(obj): + return CallableTracer(self.result, name, obj) + # XXX some attribute has been accessed, we don't care + return obj def getexecutioncontext(self): - return TraceExecutionContext(self) - - - def start_tracing(self): - self.tracing = 1 - self.log_list = [] - - - def stop_tracing(self): - self.tracing = 0 - - - def handle_default(self, frame, opcode, opname, oparg, ins_idx): - return opcode, opname, "", ins_idx - - - def handle_SET_LINENO(self, frame, opcode, opname, oparg, ins_idx): - return opcode, opname, "%s" % oparg, ins_idx - - - def handle_LOAD_CONST(self, frame, opcode, opname, oparg, ins_idx): - return opcode, opname, "%s (%r)" % (oparg, frame.getconstant(oparg)), ins_idx - - - def handle_LOAD_FAST(self, frame, opcode, opname, oparg, ins_idx): - return opcode, opname, "%s (%s)" % (oparg, frame.getlocalvarname(oparg)), ins_idx - - - def notify_on_operation(self, name, args): - if self.tracing: - #args = [self.space.unwrap(arg) for arg in args] - self.log_list[-1][1].append((name, args)) - - - def dump(self): - return self.log_list - - - def rdump(self): - bytecodes = [] - res = [] - for bytecode, ops in self.log_list: - bytecodes.append(bytecode) - if ops: - op = ops.pop(0) - res.append((op, bytecodes)) - bytecodes = [] - for op in ops: - res.append((op, [])) - - #the rest - res.append((None, bytecodes)) - return res - - - def notify_on_bytecode(self, frame): - - if not self.tracing and self.ignore_up_to_frame is frame: - self.tracing = 1 - self.ignore_up_to_frame = None - - if self.tracing: - opcode, opname, oparg, ins_idx = frame.examineop() - handle_method = getattr(self, "handle_%s" % opname, self.handle_default) - - opcode, opname, oparg, ins_idx = handle_method(frame, opcode, opname, oparg, ins_idx) - self.log_list.append(((opcode, opname, oparg, ins_idx), [])) - if opname in DONT_TRACK_BYTECODES: - self.ignore_up_to_frame = frame - self.tracing = 0 - + ec = self.space.getexecutioncontext() + if isinstance(ec, ExecutionContextTracer): + return ec + return ExecutionContextTracer(self.result, ec) + + def createexecutioncontext(self): + ec = self.space.createexecutioncontext() + return ExecutionContextTracer(self.result, ec) def __hash__(self): return hash(self.space) +class TraceResult: + """ this is the state of tracing-in-progress. """ + def __init__(self, tracespace): + self.tracespace = tracespace + self.events = [] + + 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)] + except KeyError: + res = _cache[id(frame)] = pydis.pydis(frame.code) + assert res is not None + return res + + def getbytecodes(self): + lastframe = None + for event in self.events: + #if isinstance(event, EnterFrame): + # lastframe = event.frame + 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, EnterFrame): + # lastframe = event.frame + if isinstance(event, CallBegin): + yield event.callinfo -Trace = TraceObjSpace -Space = Trace +Space = TraceObjSpace # ______________________________________________________________________ # End of trace.py +""" +def display(bytecodedict, codeobject): + for i in range(len(codeobject.co_bytecode)): + print display_bytecode(codeobject, i) + if i in bytecodedict: + for opinfo in bytecodedict[i]: + print display(*opinfo) + +class FrameIndex: + def __init__(self, frame, index): + self.frame = frame + self.index = index + + def __hash__(self): + return hash((id(frame), index)) + def _getframeindex(self): + frame = self.tracespace.space.getexecutioncontext().framestack[-1] + index = frame.next_instr + return FrameIndex(frame, index) + +""" Modified: pypy/trunk/src/pypy/tool/pydis.py ============================================================================== --- pypy/trunk/src/pypy/tool/pydis.py (original) +++ pypy/trunk/src/pypy/tool/pydis.py Thu Dec 18 17:26:00 2003 @@ -24,6 +24,17 @@ self.oparg = oparg self.lineno = lineno + def __eq__(self, other): + return (self.__class__ == other.__class__ and + self.index == other.index and + self.op == other.op and + self.name == other.name and + self.oparg == other.oparg and + self.lineno == other.lineno) + + def __ne__(self, other): + return not (self == other) + def reprargstring(self): """ return a string representation of any arguments. (empty for no args)""" oparg = self.oparg @@ -49,6 +60,9 @@ s += '(' + free[oparg] + ')' return s + def __repr__(self): + return self.name + self.reprargstring() + class DisResult: """ an instance of this class gets returned for disassembling objects/functions/code objects whatever. @@ -62,6 +76,13 @@ bc = Bytecode(self, bytecodeindex, oparg, lineno) self._bytecodes.append(bc) + def getbytecode(self, index): + """ return bytecode instance matching the given index. """ + for bytecode in self._bytecodes: + if bytecode.index == index: + return bytecode + raise ValueError, "no bytecode found on index %s" % index + def format(self): lastlineno = -1 labels = findlabels(self.code.co_code) @@ -82,57 +103,12 @@ __repr__ = format -def pydis(x=None): - """pydisassemble classes, methods, functions, or code. - - With no argument, pydisassemble the last traceback. - - """ - if x is None: - distb() - return - if type(x) is types.InstanceType: - x = x.__class__ - if hasattr(x, 'im_func'): - x = x.im_func - if hasattr(x, 'func_code'): - x = x.func_code - if hasattr(x, '__dict__'): - items = x.__dict__.items() - items.sort() - for name, x1 in items: - if type(x1) in (types.MethodType, - types.FunctionType, - types.CodeType, - types.ClassType): - print "Disassembly of %s:" % name - try: - dis(x1) - except TypeError, msg: - print "Sorry:", msg - print - elif hasattr(x, 'co_code'): - return pydisassemble(x) - #elif isinstance(x, str): - # return pydisassemble_string(x) - else: - raise TypeError, \ - "don't know how to pydisassemble %s objects" % \ - type(x).__name__ - -def distb(tb=None): - """pydisassemble a traceback (default: last traceback).""" - if tb is None: - try: - tb = sys.last_traceback - except AttributeError: - raise RuntimeError, "no last traceback to pydisassemble" - while tb.tb_next: tb = tb.tb_next - pydisassemble(tb.tb_frame.f_code, tb.tb_lasti) - -def pydisassemble(co): +def pydis(co): """return result of dissassembling a code object. """ + if hasattr(co, 'func_code'): + co = co.func_code + disresult = DisResult(co) code = co.co_code @@ -178,6 +154,7 @@ extended_arg = oparg*65536L disresult.append(current_bytecodeindex, oparg, lineno) + assert disresult is not None return disresult def findlabels(code): From lac at codespeak.net Thu Dec 18 17:28:12 2003 From: lac at codespeak.net (lac at codespeak.net) Date: Thu, 18 Dec 2003 17:28:12 +0100 (MET) Subject: [pypy-svn] rev 2522 - in pypy/trunk/src/pypy/objspace/std: . test Message-ID: <20031218162812.7F7415A4F8@thoth.codespeak.net> Author: lac Date: Thu Dec 18 17:28:11 2003 New Revision: 2522 Modified: pypy/trunk/src/pypy/objspace/std/stringobject.py pypy/trunk/src/pypy/objspace/std/test/test_stringobject.py Log: Added istitle(). Wrote tests for it. Found that title() was broken, fixed that. Commented out test_translate, which I am not working on and which raises an error. Modified: pypy/trunk/src/pypy/objspace/std/stringobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/stringobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/stringobject.py Thu Dec 18 17:28:11 2003 @@ -115,6 +115,7 @@ return (o>=97 and o<=122) \ or (o>=65 and o<=90) \ or (o>=48 and o<=57) + def _isupper(ch): o = ord(ch) return (o>=65 and o<=90) @@ -122,7 +123,7 @@ def _islower(ch): o = ord(ch) return (o>=97 and o<=122) - + def _is_generic(self, fun): space = w_self.space v = space.unwrap(w_self) @@ -156,8 +157,19 @@ def str_islower__String(space, w_self): return _is_generic(w_self, _islower) -def str_istitle(space, w_self): - pass +def str_istitle__String(space, w_self): + input = space.unwrap(w_self) + prev_letter='!' + + for pos in range(0, len(input)): + ch = input[pos] + if ch.isalpha(): + if (prev_letter.isalpha() and ch.isupper()) or \ + (not prev_letter.isalpha() and ch.islower()): + return space.w_False + prev_letter = ch + + return space.w_True def str_upper__String(space, w_self): self = space.unwrap(w_self) @@ -224,23 +236,19 @@ return space.wrap("".join(buffer)) def str_title__String(space, w_self): - u = space.unwrap - input = u(w_self) + input = space.unwrap(w_self) buffer = [' '] * len(input) - inword = 0 + prev_letter=' ' for pos in range(0, len(input)): ch = input[pos] - buffer[pos] = ch - if ch.isspace(): - if inword: - inword = 0 + if not prev_letter.isalpha(): + buffer[pos] = ch.upper() else: - if not inword: - if _islower(ch): - o = ord(ch) - 32 - buffer[pos] = chr(o) - inword = 1 + buffer[pos] = ch.lower() + + prev_letter = buffer[pos] + return space.wrap("".join(buffer)) def str_split__String_None_Int(space, w_self, w_none, w_maxsplit=-1): Modified: pypy/trunk/src/pypy/objspace/std/test/test_stringobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/test/test_stringobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/test/test_stringobject.py Thu Dec 18 17:28:11 2003 @@ -153,7 +153,23 @@ def test_title(self): self.assertEquals("brown fox".title(), "Brown Fox") - + self.assertEquals("!brown fox".title(), "!Brown Fox") + self.assertEquals("bROWN fOX".title(), "Brown Fox") + self.assertEquals("Brown Fox".title(), "Brown Fox") + self.assertEquals("bro!wn fox".title(), "Bro!Wn Fox") + + def test_istitle(self): + self.assertEquals("brown fox".istitle(), False) + self.assertEquals("!brown fox".istitle(), False) + self.assertEquals("bROWN fOX".istitle(), False) + self.assertEquals("Brown Fox".istitle(), True) + self.assertEquals("bro!wn fox".istitle(), False) + self.assertEquals("Bro!wn fox".istitle(), False) + self.assertEquals("!brown Fox".istitle(), False) + self.assertEquals("!Brown Fox".istitle(), True) + self.assertEquals("Brow&&&&N Fox".istitle(), True) + self.assertEquals("!Brow&&&&n Fox".istitle(), False) + def test_capitalize(self): self.assertEquals("brown fox".capitalize(), "Brown fox") self.assertEquals(' hello '.capitalize(), ' hello ') @@ -374,12 +390,15 @@ self.assertEquals("aaa AAA 111".swapcase(), "AAA aaa 111") self.assertEquals("".swapcase(), "") + """ def test_translate(self): import string string.maketrans('ae','ea') s="abcde" self.assertEquals('ebcda', s.translate(string.maketrans('ea','ae'))) self.assertEquals('eda', s.translate(string.maketrans('ea','ae'),'bc')) + go away for now, + I am not working on you and you make errors... Laura """ def test_iter(self): l=[] From sschwarzer at codespeak.net Thu Dec 18 17:52:58 2003 From: sschwarzer at codespeak.net (sschwarzer at codespeak.net) Date: Thu, 18 Dec 2003 17:52:58 +0100 (MET) Subject: [pypy-svn] rev 2523 - pypy/trunk/src/pypy/tool Message-ID: <20031218165258.E4A0D5A4F8@thoth.codespeak.net> Author: sschwarzer Date: Thu Dec 18 17:52:58 2003 New Revision: 2523 Modified: pypy/trunk/src/pypy/tool/newtest.py Log: Allow classification of test results while running through TestSuite.testresults. Modified: pypy/trunk/src/pypy/tool/newtest.py ============================================================================== --- pypy/trunk/src/pypy/tool/newtest.py (original) +++ pypy/trunk/src/pypy/tool/newtest.py Thu Dec 18 17:52:58 2003 @@ -11,7 +11,7 @@ # - add support for ignored tests # - support TestItem.run with different object spaces # - perhaps we have to be able to compare TestResult and TestItem values -# which were pickled +# which were pickled (see -c option of current test_all.py) class TestStatus: def __init__(self, name, longstring, shortstring): @@ -57,6 +57,9 @@ def __ne__(self, other): return not (self == other) + def __hash__(self): + return id(self.item) ^ id(self.status) + def _setexception(self, statuscode): self.status = statuscode self.excinfo = sys.exc_info() @@ -107,6 +110,9 @@ def __ne__(self, other): return not (self == other) + def __hash__(self): + return id(self.module) ^ id(self.cls) + def run(self, pretest=None, posttest=None): """ Run this TestItem and return a corresponding TestResult object. @@ -189,7 +195,7 @@ """Represent a collection of test items.""" def __init__(self): self.items = [] - self.lastresult = [] + self.lastresult = {} def _module_from_modpath(self, modpath): """ @@ -252,23 +258,36 @@ else: self.items.extend(items) - def testresults(self): - """Return a generator to get the test result for each test item.""" - self.lastresults = [] + def testresults(self, classify=lambda result: result.item.module.__name__): + """ + Return a generator to get the test result for each test item. + + The optional argument classify must be callable which accepts + a TestResult instance as the argument and returns something + that can be used as a dictionary key. + + During the iteration over the generator, the TestSuite object + will contain a dictionary named lastresult which maps these + keys to a list of TestResult objects that correspond to the key. + """ + self.lastresults = {} for item in self.items: result = item.run() - self.lastresults.append(result) + key = classify(result) + self.lastresults.setdefault(key, []).append(result) yield result -def main(ignore_selftest=True): +def main(skip_selftest=True): # possibly ignore dummy unit tests - if ignore_selftest: + if skip_selftest: filterfunc = lambda m: m.find("pypy.tool.testdata.") == -1 else: filterfunc = lambda m: True + # collect tests ts = TestSuite() ts.initfromdir(autopath.pypydir, filterfunc=filterfunc) + # iterate over tests and collect data for res in ts.testresults(): if res.status == SUCCESS: continue @@ -278,6 +297,15 @@ if res.traceback: print print res.formatted_traceback + # emit a summary + print 79 * '=' + modules = ts.lastresults.keys() + modules.sort() + for module in modules: + resultstring = '' + for result in ts.lastresults[module]: + resultstring += result.status.shortstring + print "%s %s" % (module, resultstring) if __name__ == '__main__': From lac at codespeak.net Thu Dec 18 17:55:26 2003 From: lac at codespeak.net (lac at codespeak.net) Date: Thu, 18 Dec 2003 17:55:26 +0100 (MET) Subject: [pypy-svn] rev 2524 - in pypy/trunk/src/pypy/objspace/std: . test Message-ID: <20031218165526.1436A5A4F8@thoth.codespeak.net> Author: lac Date: Thu Dec 18 17:55:24 2003 New Revision: 2524 Modified: pypy/trunk/src/pypy/objspace/std/stringobject.py pypy/trunk/src/pypy/objspace/std/test/test_stringobject.py Log: Added some spaces, more unit tests, fixed bug in stringobj Modified: pypy/trunk/src/pypy/objspace/std/stringobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/stringobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/stringobject.py Thu Dec 18 17:55:24 2003 @@ -124,7 +124,7 @@ o = ord(ch) return (o>=97 and o<=122) -def _is_generic(self, fun): +def _is_generic(w_self, fun): space = w_self.space v = space.unwrap(w_self) if len(v) == 0: Modified: pypy/trunk/src/pypy/objspace/std/test/test_stringobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/test/test_stringobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/test/test_stringobject.py Thu Dec 18 17:55:24 2003 @@ -277,27 +277,27 @@ def test_startswith(self): - self.assertEquals('ab'.startswith('ab'),1) - self.assertEquals('ab'.startswith('a'),1) - self.assertEquals('ab'.startswith(''),1) - self.assertEquals('x'.startswith('a'),0) - self.assertEquals('x'.startswith('x'),1) - self.assertEquals(''.startswith(''),1) - self.assertEquals(''.startswith('a'),0) - self.assertEquals('x'.startswith('xx'),0) - self.assertEquals('y'.startswith('xx'),0) + self.assertEquals('ab'.startswith('ab'), 1) + self.assertEquals('ab'.startswith('a'), 1) + self.assertEquals('ab'.startswith(''), 1) + self.assertEquals('x'.startswith('a'), 0) + self.assertEquals('x'.startswith('x'), 1) + self.assertEquals(''.startswith(''), 1) + self.assertEquals(''.startswith('a'), 0) + self.assertEquals('x'.startswith('xx'), 0) + self.assertEquals('y'.startswith('xx'), 0) def test_endswith(self): - self.assertEquals('ab'.endswith('ab'),1) - self.assertEquals('ab'.endswith('b'),1) - self.assertEquals('ab'.endswith(''),1) - self.assertEquals('x'.endswith('a'),0) - self.assertEquals('x'.endswith('x'),1) - self.assertEquals(''.endswith(''),1) - self.assertEquals(''.endswith('a'),0) - self.assertEquals('x'.endswith('xx'),0) - self.assertEquals('y'.endswith('xx'),0) + self.assertEquals('ab'.endswith('ab'), 1) + self.assertEquals('ab'.endswith('b'), 1) + self.assertEquals('ab'.endswith(''), 1) + self.assertEquals('x'.endswith('a'), 0) + self.assertEquals('x'.endswith('x'), 1) + self.assertEquals(''.endswith(''), 1) + self.assertEquals(''.endswith('a'), 0) + self.assertEquals('x'.endswith('xx'), 0) + self.assertEquals('y'.endswith('xx'), 0) def test_expandtabs(self): self.assertEquals('abc\rab\tdef\ng\thi'.expandtabs(), 'abc\rab def\ng hi') @@ -385,6 +385,13 @@ def test_upper(self): self.assertEquals("aaa AAA".upper(), "AAA AAA") self.assertEquals("".upper(), "") + + def test_alnum(self): + self.assertEquals("".isalnum(), False) + self.assertEquals("!Bro12345w&&&&n Fox".isalnum(), False) + self.assertEquals("125 Brown Foxes".isalnum(), False) + self.assertEquals("125BrownFoxes".isalnum(), True) + def test_swapcase(self): self.assertEquals("aaa AAA 111".swapcase(), "AAA aaa 111") From sschwarzer at codespeak.net Thu Dec 18 17:59:53 2003 From: sschwarzer at codespeak.net (sschwarzer at codespeak.net) Date: Thu, 18 Dec 2003 17:59:53 +0100 (MET) Subject: [pypy-svn] rev 2525 - pypy/trunk/src/pypy/tool Message-ID: <20031218165953.94D885A4F8@thoth.codespeak.net> Author: sschwarzer Date: Thu Dec 18 17:59:52 2003 New Revision: 2525 Modified: pypy/trunk/src/pypy/tool/newtest.py Log: Make the output more similar to that from test_all.py . Of course, this is only an example and can be changed. Modified: pypy/trunk/src/pypy/tool/newtest.py ============================================================================== --- pypy/trunk/src/pypy/tool/newtest.py (original) +++ pypy/trunk/src/pypy/tool/newtest.py Thu Dec 18 17:59:52 2003 @@ -302,10 +302,11 @@ modules = ts.lastresults.keys() modules.sort() for module in modules: + results = ts.lastresults[module] resultstring = '' - for result in ts.lastresults[module]: + for result in results: resultstring += result.status.shortstring - print "%s %s" % (module, resultstring) + print "%s [%d] %s" % (module, len(results), resultstring) if __name__ == '__main__': From alex at codespeak.net Thu Dec 18 18:11:22 2003 From: alex at codespeak.net (alex at codespeak.net) Date: Thu, 18 Dec 2003 18:11:22 +0100 (MET) Subject: [pypy-svn] rev 2526 - in pypy/trunk/src/pypy/module: . test Message-ID: <20031218171122.168F65A4F8@thoth.codespeak.net> Author: alex Date: Thu Dec 18 18:11:20 2003 New Revision: 2526 Modified: pypy/trunk/src/pypy/module/builtin.py pypy/trunk/src/pypy/module/test/test_builtin.py Log: make dir(something) return sorted names, and add unit tests to check that it actually does Modified: pypy/trunk/src/pypy/module/builtin.py ============================================================================== --- pypy/trunk/src/pypy/module/builtin.py (original) +++ pypy/trunk/src/pypy/module/builtin.py Thu Dec 18 18:11:20 2003 @@ -650,13 +650,17 @@ if isinstance(obj, types.ModuleType): try: - return module.__dict__.keys() + result = module.__dict__.keys() + result.sort() + return result except AttributeError: return [] elif isinstance(obj, (types.TypeType, types.ClassType)): #Don't look at __class__, as metaclass methods would be confusing. - return _classdir(obj).keys() + result = _classdir(obj).keys() + result.sort() + return result else: #(regular item) Dict = {} @@ -678,7 +682,9 @@ Dict[item] = None except (AttributeError, TypeError): pass - return Dict.keys() + result = Dict.keys() + result.sort() + return result def app_intern(self, s): """ Modified: pypy/trunk/src/pypy/module/test/test_builtin.py ============================================================================== --- pypy/trunk/src/pypy/module/test/test_builtin.py (original) +++ pypy/trunk/src/pypy/module/test/test_builtin.py Thu Dec 18 18:11:20 2003 @@ -42,6 +42,15 @@ return dir() self.assertEquals(f(), []) self.assertEquals(g(), ['a', 'b', 'c']) + class X: pass + self.assertEquals(dir(X), ['__module__', ]) + class X: a = 23 + self.assertEquals(dir(X), ['__module__', 'a']) + class X: + a = 23 + c = 45 + b = 67 + self.assertEquals(dir(X), ['__module__', 'a', 'b', 'c']) def test_vars(self): def f(): From pmaupin at codespeak.net Thu Dec 18 18:15:40 2003 From: pmaupin at codespeak.net (pmaupin at codespeak.net) Date: Thu, 18 Dec 2003 18:15:40 +0100 (MET) Subject: [pypy-svn] rev 2527 - pypy/trunk/src/pypy/appspace Message-ID: <20031218171540.333985A4F8@thoth.codespeak.net> Author: pmaupin Date: Thu Dec 18 18:15:39 2003 New Revision: 2527 Modified: pypy/trunk/src/pypy/appspace/support_tests.py Log: Remove unittest functionality -- change to use PyPy unit tests Modified: pypy/trunk/src/pypy/appspace/support_tests.py ============================================================================== --- pypy/trunk/src/pypy/appspace/support_tests.py (original) +++ pypy/trunk/src/pypy/appspace/support_tests.py Thu Dec 18 18:15:39 2003 @@ -188,86 +188,3 @@ pass else: print 'Missing SyntaxError: "%s"' % statement - -#======================================================================= -# Preliminary PyUNIT integration. - -import unittest - - -class BasicTestRunner: - def run(self, test): - result = unittest.TestResult() - test(result) - return result - - -def run_suite(suite, testclass=None): - """Run tests from a unittest.TestSuite-derived class.""" - if verbose: - runner = unittest.TextTestRunner(sys.stdout, verbosity=2) - else: - runner = BasicTestRunner() - - result = runner.run(suite) - if not result.wasSuccessful(): - if len(result.errors) == 1 and not result.failures: - err = result.errors[0][1] - elif len(result.failures) == 1 and not result.errors: - err = result.failures[0][1] - else: - if testclass is None: - msg = "errors occurred; run in verbose mode for details" - else: - msg = "errors occurred in %s.%s" \ - % (testclass.__module__, testclass.__name__) - raise TestFailed(msg) - raise TestFailed(err) - - -def run_unittest(*classes): - """Run tests from unittest.TestCase-derived classes.""" - suite = unittest.TestSuite() - for cls in classes: - if isinstance(cls, (unittest.TestSuite, unittest.TestCase)): - suite.addTest(cls) - else: - suite.addTest(unittest.makeSuite(cls)) - if len(classes)==1: - testclass = classes[0] - else: - testclass = None - run_suite(suite, testclass) - - -#======================================================================= -# doctest driver. - -def run_doctest(module, verbosity=None): - """Run doctest on the given module. Return (#failures, #tests). - - If optional argument verbosity is not specified (or is None), pass - test_support's belief about verbosity on to doctest. Else doctest's - usual behavior is used (it searches sys.argv for -v). - """ - - import doctest - - if verbosity is None: - verbosity = verbose - else: - verbosity = None - - # Direct doctest output (normally just errors) to real stdout; doctest - # output shouldn't be compared by regrtest. - save_stdout = sys.stdout - sys.stdout = get_original_stdout() - try: - f, t = doctest.testmod(module, verbose=verbosity) - if f: - raise TestFailed("%d of %d doctests failed" % (f, t)) - finally: - sys.stdout = save_stdout - if verbose: - print 'doctest (%s) ... %d tests with zero failures' % (module.__name__, t) - return f, t From pmaupin at codespeak.net Thu Dec 18 18:17:11 2003 From: pmaupin at codespeak.net (pmaupin at codespeak.net) Date: Thu, 18 Dec 2003 18:17:11 +0100 (MET) Subject: [pypy-svn] rev 2528 - pypy/trunk/src/pypy/appspace Message-ID: <20031218171711.702CE5A4F8@thoth.codespeak.net> Author: pmaupin Date: Thu Dec 18 18:17:10 2003 New Revision: 2528 Added: pypy/trunk/src/pypy/appspace/autopath.py (props changed) - copied unchanged from rev 2496, pypy/trunk/src/pypy/tool/autopath.py pypy/trunk/src/pypy/appspace/builtin_functions_test.py (contents, props changed) Log: Adapted from standard CPython test_builtins.py Added: pypy/trunk/src/pypy/appspace/builtin_functions_test.py ============================================================================== --- (empty file) +++ pypy/trunk/src/pypy/appspace/builtin_functions_test.py Thu Dec 18 18:17:10 2003 @@ -0,0 +1,1184 @@ +# Python test set -- built-in functions +import autopath +from pypy.tool import test + +class BuiltinTest(test.AppTestCase): + + def setUp(self): + global fcmp, have_unicode, TESTFN, unlink, Set, sys, cStringIO + global Squares, StrSquares, BitBucket, L + + self.space = test.objspace('std') + + try: + have_unicode + except NameError: + pass + else: + return + + from sets import Set + try: + from support_tests import fcmp, have_unicode, TESTFN + except ImportError: + raise ImportError("Copy support_tests.py from appspace to ..\.. for now :-(") + + if not have_unicode: + ''' XXX TODO -- When unicode is added we also need basestring ''' + import __builtin__ + __builtin__.basestring = str + + import sys, warnings, cStringIO + warnings.filterwarnings("ignore", "hex../oct.. of negative int", + FutureWarning, __name__) + warnings.filterwarnings("ignore", "integer argument expected", + DeprecationWarning, "unittest") + + 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), + ] + + + + def test_import(self): + __import__('sys') + __import__('time') + __import__('string') + self.assertRaises(ImportError, __import__, 'spamspam') + self.assertRaises(TypeError, __import__, 1, 2, 3, 4) + + def test_abs(self): + # int + self.assertEqual(abs(0), 0) + self.assertEqual(abs(1234), 1234) + self.assertEqual(abs(-1234), 1234) + # float + self.assertEqual(abs(0.0), 0.0) + self.assertEqual(abs(3.14), 3.14) + self.assertEqual(abs(-3.14), 3.14) + # long + self.assertEqual(abs(0L), 0L) + self.assertEqual(abs(1234L), 1234L) + self.assertEqual(abs(-1234L), 1234L) + # str + self.assertRaises(TypeError, abs, 'a') + + def test_apply(self): + def f0(*args): + self.assertEqual(args, ()) + def f1(a1): + self.assertEqual(a1, 1) + def f2(a1, a2): + self.assertEqual(a1, 1) + self.assertEqual(a2, 2) + def f3(a1, a2, a3): + self.assertEqual(a1, 1) + self.assertEqual(a2, 2) + self.assertEqual(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,), {}) + self.assertRaises(TypeError, apply, id, (1,), {"foo": 1}) + self.assertRaises(TypeError, apply) + self.assertRaises(TypeError, apply, id, 42) + self.assertRaises(TypeError, apply, id, (42,), 42) + + def test_callable(self): + self.assert_(callable(len)) + def f(): pass + self.assert_(callable(f)) + class C: + def meth(self): pass + self.assert_(callable(C)) + x = C() + self.assert_(callable(x.meth)) + self.assert_(not callable(x)) + class D(C): + def __call__(self): pass + y = D() + self.assert_(callable(y)) + y() + + def test_chr(self): + self.assertEqual(chr(32), ' ') + self.assertEqual(chr(65), 'A') + self.assertEqual(chr(97), 'a') + self.assertEqual(chr(0xff), '\xff') + self.assertRaises(ValueError, chr, 256) + self.assertRaises(TypeError, chr) + + def test_cmp(self): + self.assertEqual(cmp(-1, 1), -1) + self.assertEqual(cmp(1, -1), 1) + self.assertEqual(cmp(1, 1), 0) + # verify that circular objects are handled + a = []; a.append(a) + b = []; b.append(b) + from UserList import UserList + c = UserList(); c.append(c) + self.assertEqual(cmp(a, b), 0) + self.assertEqual(cmp(b, c), 0) + self.assertEqual(cmp(c, a), 0) + self.assertEqual(cmp(a, c), 0) + # okay, now break the cycles + a.pop(); b.pop(); c.pop() + self.assertRaises(TypeError, cmp) + + def test_coerce(self): + self.assert_(not fcmp(coerce(1, 1.1), (1.0, 1.1))) + self.assertEqual(coerce(1, 1L), (1L, 1L)) + self.assert_(not fcmp(coerce(1L, 1.1), (1.0, 1.1))) + self.assertRaises(TypeError, coerce) + class BadNumber: + def __coerce__(self, other): + raise ValueError + self.assertRaises(ValueError, coerce, 42, BadNumber()) + self.assertRaises(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') + self.assertRaises(TypeError, compile) + self.assertRaises(ValueError, compile, 'print 42\n', '', 'badmode') + self.assertRaises(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') + self.assertRaises(TypeError, delattr) + + def test_dir(self): + x = 1 + self.assert_('x' in dir()) + import sys + self.assert_('modules' in dir(sys)) + self.assertRaises(TypeError, dir, 42, 42) + + def test_divmod(self): + self.assertEqual(divmod(12, 7), (1, 5)) + self.assertEqual(divmod(-12, 7), (-2, 2)) + self.assertEqual(divmod(12, -7), (-2, -2)) + self.assertEqual(divmod(-12, -7), (1, -5)) + + self.assertEqual(divmod(12L, 7L), (1L, 5L)) + self.assertEqual(divmod(-12L, 7L), (-2L, 2L)) + self.assertEqual(divmod(12L, -7L), (-2L, -2L)) + self.assertEqual(divmod(-12L, -7L), (1L, -5L)) + + self.assertEqual(divmod(12, 7L), (1, 5L)) + self.assertEqual(divmod(-12, 7L), (-2, 2L)) + self.assertEqual(divmod(12L, -7), (-2L, -2)) + self.assertEqual(divmod(-12L, -7), (1L, -5)) + + self.assert_(not fcmp(divmod(3.25, 1.0), (3.0, 0.25))) + self.assert_(not fcmp(divmod(-3.25, 1.0), (-4.0, 0.75))) + self.assert_(not fcmp(divmod(3.25, -1.0), (-4.0, -0.75))) + self.assert_(not fcmp(divmod(-3.25, -1.0), (3.0, -0.25))) + + self.assertRaises(TypeError, divmod) + + def test_eval(self): + self.assertEqual(eval('1+1'), 2) + self.assertEqual(eval(' 1+1\n'), 2) + globals = {'a': 1, 'b': 2} + locals = {'b': 200, 'c': 300} + self.assertEqual(eval('a', globals) , 1) + self.assertEqual(eval('a', globals, locals), 1) + self.assertEqual(eval('b', globals, locals), 200) + self.assertEqual(eval('c', globals, locals), 300) + if have_unicode: + self.assertEqual(eval(unicode('1+1')), 2) + self.assertEqual(eval(unicode(' 1+1\n')), 2) + globals = {'a': 1, 'b': 2} + locals = {'b': 200, 'c': 300} + if have_unicode: + self.assertEqual(eval(unicode('a'), globals), 1) + self.assertEqual(eval(unicode('a'), globals, locals), 1) + self.assertEqual(eval(unicode('b'), globals, locals), 200) + self.assertEqual(eval(unicode('c'), globals, locals), 300) + bom = '\xef\xbb\xbf' + self.assertEqual(eval(bom + 'a', globals, locals), 1) + self.assertEqual(eval(unicode('u"\xc3\xa5"', 'utf8'), globals), + unicode('\xc3\xa5', 'utf8')) + self.assertRaises(TypeError, eval) + self.assertRaises(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} + + self.assertEqual(self.__class__.z, 2) + globals['z'] = 0 + execfile(TESTFN, globals) + self.assertEqual(globals['z'], 2) + locals['z'] = 0 + execfile(TESTFN, globals, locals) + self.assertEqual(locals['z'], 2) + unlink(TESTFN) + self.assertRaises(TypeError, execfile) + import os + self.assertRaises(IOError, execfile, os.curdir) + self.assertRaises(IOError, execfile, "I_dont_exist") + + def test_filter(self): + self.assertEqual(filter(lambda c: 'a' <= c <= 'z', 'Hello World'), 'elloorld') + self.assertEqual(filter(None, [1, 'hello', [], [3], '', None, 9, 0]), [1, 'hello', [3], 9]) + self.assertEqual(filter(lambda x: x > 0, [1, -3, 9, 0, 2]), [1, 9, 2]) + self.assertEqual(filter(None, Squares(10)), [1, 4, 9, 16, 25, 36, 49, 64, 81]) + self.assertEqual(filter(lambda x: x%2, Squares(10)), [1, 9, 25, 49, 81]) + def identity(item): + return 1 + filter(identity, Squares(5)) + self.assertRaises(TypeError, filter) + class BadSeq(object): + def __getitem__(self, index): + if index<4: + return 42 + raise ValueError + self.assertRaises(ValueError, filter, lambda x: x, BadSeq()) + def badfunc(): + pass + self.assertRaises(TypeError, filter, badfunc, range(5)) + + # test bltinmodule.c::filtertuple() + self.assertEqual(filter(None, (1, 2)), (1, 2)) + self.assertEqual(filter(lambda x: x>=3, (1, 2, 3, 4)), (3, 4)) + self.assertRaises(TypeError, filter, 42, (1, 2)) + + # test bltinmodule.c::filterstring() + self.assertEqual(filter(None, "12"), "12") + self.assertEqual(filter(lambda x: x>="3", "1234"), "34") + self.assertRaises(TypeError, filter, 42, "12") + class badstr(str): + def __getitem__(self, index): + raise ValueError + self.assertRaises(ValueError, filter, lambda x: x >="3", badstr("1234")) + + class badstr2(str): + def __getitem__(self, index): + return 42 + self.assertRaises(TypeError, filter, lambda x: x >=42, badstr2("1234")) + + class weirdstr(str): + def __getitem__(self, index): + return weirdstr(2*str.__getitem__(self, index)) + self.assertEqual(filter(lambda x: x>="33", weirdstr("1234")), "3344") + + class shiftstr(str): + def __getitem__(self, index): + return chr(ord(str.__getitem__(self, index))+1) + self.assertEqual(filter(lambda x: x>="3", shiftstr("1234")), "345") + + if have_unicode: + # test bltinmodule.c::filterunicode() + self.assertEqual(filter(None, unicode("12")), unicode("12")) + self.assertEqual(filter(lambda x: x>="3", unicode("1234")), unicode("34")) + self.assertRaises(TypeError, filter, 42, unicode("12")) + self.assertRaises(ValueError, filter, lambda x: x >="3", badstr(unicode("1234"))) + + class badunicode(unicode): + def __getitem__(self, index): + return 42 + self.assertRaises(TypeError, filter, lambda x: x >=42, badunicode("1234")) + + class weirdunicode(unicode): + def __getitem__(self, index): + return weirdunicode(2*unicode.__getitem__(self, index)) + self.assertEqual( + 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) + self.assertEqual( + 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 + self.assertEqual( + filter(funcs[0], cls(inp)), + filter(funcs[1], cls(inp)) + ) + for func in funcs: + outp = filter(func, cls(inp)) + self.assertEqual(outp, exp) + self.assert_(not isinstance(outp, cls)) + + def test_float(self): + self.assertEqual(float(3.14), 3.14) + self.assertEqual(float(314), 314.0) + self.assertEqual(float(314L), 314.0) + self.assertEqual(float(" 3.14 "), 3.14) + if have_unicode: + self.assertEqual(float(unicode(" 3.14 ")), 3.14) + self.assertEqual(float(unicode(" \u0663.\u0661\u0664 ",'raw-unicode-escape')), 3.14) + + def test_getattr(self): + import sys + self.assert_(getattr(sys, 'stdout') is sys.stdout) + self.assertRaises(TypeError, getattr, sys, 1) + self.assertRaises(TypeError, getattr, sys, 1, "foo") + self.assertRaises(TypeError, getattr) + self.assertRaises(UnicodeError, getattr, sys, unichr(sys.maxunicode)) + + def test_hasattr(self): + import sys + self.assert_(hasattr(sys, 'stdout')) + self.assertRaises(TypeError, hasattr, sys, 1) + self.assertRaises(TypeError, hasattr) + self.assertRaises(UnicodeError, hasattr, sys, unichr(sys.maxunicode)) + + def test_hash(self): + hash(None) + self.assertEqual(hash(1), hash(1L)) + self.assertEqual(hash(1), hash(1.0)) + hash('spam') + if have_unicode: + self.assertEqual(hash('spam'), hash(unicode('spam'))) + hash((0,1,2,3)) + def f(): pass + self.assertRaises(TypeError, hash, []) + self.assertRaises(TypeError, hash, {}) + + def test_hex(self): + self.assertEqual(hex(16), '0x10') + self.assertEqual(hex(16L), '0x10L') + self.assertEqual(len(hex(-1)), len(hex(sys.maxint))) + self.assert_(hex(-16) in ('0xfffffff0', '0xfffffffffffffff0')) + self.assertEqual(hex(-16L), '-0x10L') + self.assertRaises(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): + self.assertEqual(int(314), 314) + self.assertEqual(int(3.14), 3) + self.assertEqual(int(314L), 314) + # Check that conversion from float truncates towards zero + self.assertEqual(int(-3.14), -3) + self.assertEqual(int(3.9), 3) + self.assertEqual(int(-3.9), -3) + self.assertEqual(int(3.5), 3) + self.assertEqual(int(-3.5), -3) + # Different base: + self.assertEqual(int("10",16), 16L) + if have_unicode: + self.assertEqual(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: + self.assertEqual(int(ss), vv) + except v: + pass + + s = `-1-sys.maxint` + self.assertEqual(int(s)+1, -sys.maxint) + # should return long + int(s[1:]) + + # should return long + x = int(1e100) + self.assert_(isinstance(x, long)) + x = int(-1e100) + self.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 + self.assertEqual(x >> 1, x//2) + + self.assertRaises(ValueError, int, '123\0') + self.assertRaises(ValueError, int, '53', 40) + + x = int('1' * 600) + self.assert_(isinstance(x, long)) + + if have_unicode: + x = int(unichr(0x661) * 600) + self.assert_(isinstance(x, long)) + + self.assertRaises(TypeError, int, 1, 12) + + self.assertEqual(int('0123', 0), 83) + + def test_intern(self): + self.assertRaises(TypeError, intern) + s = "never interned before" + self.assert_(intern(s) is s) + s2 = s.swapcase().swapcase() + self.assert_(intern(s2) is s) + + def test_iter(self): + self.assertRaises(TypeError, iter) + self.assertRaises(TypeError, iter, 42, 42) + lists = [("1", "2"), ["1", "2"], "12"] + if have_unicode: + lists.append(unicode("12")) + for l in lists: + i = iter(l) + self.assertEqual(i.next(), '1') + self.assertEqual(i.next(), '2') + self.assertRaises(StopIteration, i.next) + + def test_isinstance(self): + class C: + pass + class D(C): + pass + class E: + pass + c = C() + d = D() + e = E() + self.assert_(isinstance(c, C)) + self.assert_(isinstance(d, C)) + self.assert_(not isinstance(e, C)) + self.assert_(not isinstance(c, D)) + self.assert_(not isinstance('foo', E)) + self.assertRaises(TypeError, isinstance, E, 'foo') + self.assertRaises(TypeError, isinstance) + + def test_issubclass(self): + class C: + pass + class D(C): + pass + class E: + pass + c = C() + d = D() + e = E() + self.assert_(issubclass(D, C)) + self.assert_(issubclass(C, C)) + self.assert_(not issubclass(C, D)) + self.assertRaises(TypeError, issubclass, 'foo', E) + self.assertRaises(TypeError, issubclass, E, 'foo') + self.assertRaises(TypeError, issubclass) + + def test_len(self): + self.assertEqual(len('123'), 3) + self.assertEqual(len(()), 0) + self.assertEqual(len((1, 2, 3, 4)), 4) + self.assertEqual(len([1, 2, 3, 4]), 4) + self.assertEqual(len({}), 0) + self.assertEqual(len({'a':1, 'b': 2}), 2) + class BadSeq: + def __len__(self): + raise ValueError + self.assertRaises(ValueError, len, BadSeq()) + + def test_list(self): + self.assertEqual(list([]), []) + l0_3 = [0, 1, 2, 3] + l0_3_bis = list(l0_3) + self.assertEqual(l0_3, l0_3_bis) + self.assert_(l0_3 is not l0_3_bis) + self.assertEqual(list(()), []) + self.assertEqual(list((0, 1, 2, 3)), [0, 1, 2, 3]) + self.assertEqual(list(''), []) + self.assertEqual(list('spam'), ['s', 'p', 'a', 'm']) + + 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 + self.assertRaises(MemoryError, list, xrange(sys.maxint // 2)) + + def test_long(self): + self.assertEqual(long(314), 314L) + self.assertEqual(long(3.14), 3L) + self.assertEqual(long(314L), 314L) + # Check that conversion from float truncates towards zero + self.assertEqual(long(-3.14), -3L) + self.assertEqual(long(3.9), 3L) + self.assertEqual(long(-3.9), -3L) + self.assertEqual(long(3.5), 3L) + self.assertEqual(long(-3.5), -3L) + self.assertEqual(long("-3"), -3L) + if have_unicode: + self.assertEqual(long(unicode("-3")), -3L) + # Different base: + self.assertEqual(long("10",16), 16L) + if have_unicode: + self.assertEqual(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: + self.assertEqual(long(ss), long(vv)) + except v: + pass + + self.assertRaises(ValueError, long, '123\0') + self.assertRaises(ValueError, long, '53', 40) + self.assertRaises(TypeError, long, 1, 12) + + def test_map(self): + self.assertEqual( + map(None, 'hello world'), + ['h','e','l','l','o',' ','w','o','r','l','d'] + ) + self.assertEqual( + map(None, 'abcd', 'efg'), + [('a', 'e'), ('b', 'f'), ('c', 'g'), ('d', None)] + ) + self.assertEqual( + map(None, range(10)), + [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] + ) + self.assertEqual( + 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) + self.assertEqual( + map(lambda x: map(sqrt,x), [[16, 4], [81, 9]]), + [[4.0, 2.0], [9.0, 3.0]] + ) + self.assertEqual( + 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 + self.assertEqual( + map(plus, [1, 3, 7]), + [1, 3, 7] + ) + self.assertEqual( + map(plus, [1, 3, 7], [4, 9, 2]), + [1+4, 3+9, 7+2] + ) + self.assertEqual( + map(plus, [1, 3, 7], [4, 9, 2], [1, 1, 0]), + [1+4+1, 3+9+1, 7+2+0] + ) + self.assertEqual( + map(None, Squares(10)), + [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] + ) + self.assertEqual( + map(int, Squares(10)), + [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] + ) + self.assertEqual( + map(None, Squares(3), Squares(2)), + [(0,0), (1,1), (4,None)] + ) + self.assertEqual( + map(max, Squares(3), Squares(2)), + [0, 1, 4] + ) + self.assertRaises(TypeError, map) + self.assertRaises(TypeError, map, lambda x: x, 42) + self.assertEqual(map(None, [42]), [42]) + class BadSeq: + def __getitem__(self, index): + raise ValueError + self.assertRaises(ValueError, map, lambda x: x, BadSeq()) + + def test_max(self): + self.assertEqual(max('123123'), '3') + self.assertEqual(max(1, 2, 3), 3) + self.assertEqual(max((1, 2, 3, 1, 2, 3)), 3) + self.assertEqual(max([1, 2, 3, 1, 2, 3]), 3) + + self.assertEqual(max(1, 2L, 3.0), 3.0) + self.assertEqual(max(1L, 2.0, 3), 3) + self.assertEqual(max(1.0, 2, 3L), 3L) + + def test_min(self): + self.assertEqual(min('123123'), '1') + self.assertEqual(min(1, 2, 3), 1) + self.assertEqual(min((1, 2, 3, 1, 2, 3)), 1) + self.assertEqual(min([1, 2, 3, 1, 2, 3]), 1) + + self.assertEqual(min(1, 2L, 3.0), 1) + self.assertEqual(min(1L, 2.0, 3), 1L) + self.assertEqual(min(1.0, 2, 3L), 1.0) + + self.assertRaises(TypeError, min) + self.assertRaises(TypeError, min, 42) + self.assertRaises(ValueError, min, ()) + class BadSeq: + def __getitem__(self, index): + raise ValueError + self.assertRaises(ValueError, min, BadSeq()) + class BadNumber: + def __cmp__(self, other): + raise ValueError + self.assertRaises(ValueError, min, (42, BadNumber())) + + def test_oct(self): + self.assertEqual(oct(100), '0144') + self.assertEqual(oct(100L), '0144L') + self.assert_(oct(-100) in ('037777777634', '01777777777777777777634')) + self.assertEqual(oct(-100L), '-0144L') + self.assertRaises(TypeError, oct, ()) + + def write_testfile(self): + # 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() + + def test_open(self): + self.write_testfile() + fp = open(TESTFN, 'r') + try: + self.assertEqual(fp.readline(4), '1+1\n') + self.assertEqual(fp.readline(4), '1+1\n') + self.assertEqual(fp.readline(), 'The quick brown fox jumps over the lazy dog.\n') + self.assertEqual(fp.readline(4), 'Dear') + self.assertEqual(fp.readline(100), ' John\n') + self.assertEqual(fp.read(300), 'XXX'*100) + self.assertEqual(fp.read(1000), 'YYY'*100) + finally: + fp.close() + unlink(TESTFN) + + def test_ord(self): + self.assertEqual(ord(' '), 32) + self.assertEqual(ord('A'), 65) + self.assertEqual(ord('a'), 97) + if have_unicode: + self.assertEqual(ord(unichr(sys.maxunicode)), sys.maxunicode) + self.assertRaises(TypeError, ord, 42) + self.assertRaises(TypeError, ord, unicode("12")) + + def test_pow(self): + self.assertEqual(pow(0,0), 1) + self.assertEqual(pow(0,1), 0) + self.assertEqual(pow(1,0), 1) + self.assertEqual(pow(1,1), 1) + + self.assertEqual(pow(2,0), 1) + self.assertEqual(pow(2,10), 1024) + self.assertEqual(pow(2,20), 1024*1024) + self.assertEqual(pow(2,30), 1024*1024*1024) + + self.assertEqual(pow(-2,0), 1) + self.assertEqual(pow(-2,1), -2) + self.assertEqual(pow(-2,2), 4) + self.assertEqual(pow(-2,3), -8) + + self.assertEqual(pow(0L,0), 1) + self.assertEqual(pow(0L,1), 0) + self.assertEqual(pow(1L,0), 1) + self.assertEqual(pow(1L,1), 1) + + self.assertEqual(pow(2L,0), 1) + self.assertEqual(pow(2L,10), 1024) + self.assertEqual(pow(2L,20), 1024*1024) + self.assertEqual(pow(2L,30), 1024*1024*1024) + + self.assertEqual(pow(-2L,0), 1) + self.assertEqual(pow(-2L,1), -2) + self.assertEqual(pow(-2L,2), 4) + self.assertEqual(pow(-2L,3), -8) + + self.assertAlmostEqual(pow(0.,0), 1.) + self.assertAlmostEqual(pow(0.,1), 0.) + self.assertAlmostEqual(pow(1.,0), 1.) + self.assertAlmostEqual(pow(1.,1), 1.) + + self.assertAlmostEqual(pow(2.,0), 1.) + self.assertAlmostEqual(pow(2.,10), 1024.) + self.assertAlmostEqual(pow(2.,20), 1024.*1024.) + self.assertAlmostEqual(pow(2.,30), 1024.*1024.*1024.) + + self.assertAlmostEqual(pow(-2.,0), 1.) + self.assertAlmostEqual(pow(-2.,1), -2.) + self.assertAlmostEqual(pow(-2.,2), 4.) + self.assertAlmostEqual(pow(-2.,3), -8.) + + 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): + self.assertRaises(TypeError, pow, x, y, z) + else: + self.assertAlmostEqual(pow(x, y, z), 24.0) + + self.assertRaises(TypeError, pow, -1, -2, 3) + self.assertRaises(ValueError, pow, 1, 2, 0) + self.assertRaises(TypeError, pow, -1L, -2L, 3L) + self.assertRaises(ValueError, pow, 1L, 2L, 0L) + self.assertRaises(ValueError, pow, -342.43, 0.234) + + self.assertRaises(TypeError, pow) + + def test_range(self): + self.assertEqual(range(3), [0, 1, 2]) + self.assertEqual(range(1, 5), [1, 2, 3, 4]) + self.assertEqual(range(0), []) + self.assertEqual(range(-3), []) + self.assertEqual(range(1, 10, 3), [1, 4, 7]) + self.assertEqual(range(5, -5, -3), [5, 2, -1, -4]) + + # Now test range() with longs + self.assertEqual(range(-2**100), []) + self.assertEqual(range(0, -2**100), []) + self.assertEqual(range(0, 2**100, -1), []) + self.assertEqual(range(0, 2**100, -1), []) + + a = long(10 * sys.maxint) + b = long(100 * sys.maxint) + c = long(50 * sys.maxint) + + self.assertEqual(range(a, a+2), [a, a+1]) + self.assertEqual(range(a+2, a, -1L), [a+2, a+1]) + self.assertEqual(range(a+4, a, -2), [a+4, a+2]) + + seq = range(a, b, c) + self.assert_(a in seq) + self.assert_(b not in seq) + self.assertEqual(len(seq), 2) + + seq = range(b, a, -c) + self.assert_(b in seq) + self.assert_(a not in seq) + self.assertEqual(len(seq), 2) + + seq = range(-a, -b, -c) + self.assert_(-a in seq) + self.assert_(-b not in seq) + self.assertEqual(len(seq), 2) + + self.assertRaises(TypeError, range) + self.assertRaises(TypeError, range, 1, 2, 3, 4) + self.assertRaises(ValueError, range, 1, 2, 0) + + # Reject floats when it would require PyLongs to represent. + # (smaller floats still accepted, but deprecated) + self.assertRaises(TypeError, range, 1e100, 1e101, 1e101) + + self.assertRaises(TypeError, range, 0, "spam") + self.assertRaises(TypeError, range, 0, 42, "spam") + + self.assertRaises(OverflowError, range, -sys.maxint, sys.maxint) + self.assertRaises(OverflowError, range, 0, 2*sys.maxint) + + 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() + self.assertEqual(input(), 2) + self.assertEqual(input('testing\n'), 2) + self.assertEqual(raw_input(), 'The quick brown fox jumps over the lazy dog.') + self.assertEqual(raw_input('testing\n'), 'Dear John') + sys.stdin = cStringIO.StringIO("NULL\0") + self.assertRaises(TypeError, input, 42, 42) + sys.stdin = cStringIO.StringIO(" 'whitespace'") + self.assertEqual(input(), 'whitespace') + sys.stdin = cStringIO.StringIO() + self.assertRaises(EOFError, input) + del sys.stdout + self.assertRaises(RuntimeError, input, 'prompt') + del sys.stdin + self.assertRaises(RuntimeError, input, 'prompt') + finally: + sys.stdin = savestdin + sys.stdout = savestdout + fp.close() + unlink(TESTFN) + + def test_reduce(self): + self.assertEqual(reduce(lambda x, y: x+y, ['a', 'b', 'c'], ''), 'abc') + self.assertEqual( + reduce(lambda x, y: x+y, [['a', 'c'], [], ['d', 'w']], []), + ['a','c','d','w'] + ) + self.assertEqual(reduce(lambda x, y: x*y, range(2,8), 1), 5040) + self.assertEqual( + reduce(lambda x, y: x*y, range(2,21), 1L), + 2432902008176640000L + ) + self.assertEqual(reduce(lambda x, y: x+y, Squares(10)), 285) + self.assertEqual(reduce(lambda x, y: x+y, Squares(10), 0), 285) + self.assertEqual(reduce(lambda x, y: x+y, Squares(0), 0), 0) + self.assertRaises(TypeError, reduce) + self.assertRaises(TypeError, reduce, 42, 42) + self.assertRaises(TypeError, reduce, 42, 42, 42) + self.assertEqual(reduce(42, "1"), "1") # func is never called with one item + self.assertEqual(reduce(42, "", "1"), "1") # func is never called with one item + self.assertRaises(TypeError, reduce, 42, (42, 42)) + + class BadSeq: + def __getitem__(self, index): + raise ValueError + self.assertRaises(ValueError, reduce, 42, BadSeq()) + + def test_reload(self): + import marshal + reload(marshal) + import string + reload(string) + ## import sys + ## self.assertRaises(ImportError, reload, sys) + + def test_repr(self): + self.assertEqual(repr(''), '\'\'') + self.assertEqual(repr(0), '0') + self.assertEqual(repr(0L), '0L') + self.assertEqual(repr(()), '()') + self.assertEqual(repr([]), '[]') + self.assertEqual(repr({}), '{}') + a = [] + a.append(a) + self.assertEqual(repr(a), '[[...]]') + a = {} + a[0] = a + self.assertEqual(repr(a), '{0: {...}}') + + def test_round(self): + self.assertEqual(round(0.0), 0.0) + self.assertEqual(round(1.0), 1.0) + self.assertEqual(round(10.0), 10.0) + self.assertEqual(round(1000000000.0), 1000000000.0) + self.assertEqual(round(1e20), 1e20) + + self.assertEqual(round(-1.0), -1.0) + self.assertEqual(round(-10.0), -10.0) + self.assertEqual(round(-1000000000.0), -1000000000.0) + self.assertEqual(round(-1e20), -1e20) + + self.assertEqual(round(0.1), 0.0) + self.assertEqual(round(1.1), 1.0) + self.assertEqual(round(10.1), 10.0) + self.assertEqual(round(1000000000.1), 1000000000.0) + + self.assertEqual(round(-1.1), -1.0) + self.assertEqual(round(-10.1), -10.0) + self.assertEqual(round(-1000000000.1), -1000000000.0) + + self.assertEqual(round(0.9), 1.0) + self.assertEqual(round(9.9), 10.0) + self.assertEqual(round(999999999.9), 1000000000.0) + + self.assertEqual(round(-0.9), -1.0) + self.assertEqual(round(-9.9), -10.0) + self.assertEqual(round(-999999999.9), -1000000000.0) + + self.assertEqual(round(-8.0, -1), -10.0) + + self.assertRaises(TypeError, round) + + def test_setattr(self): + setattr(sys, 'spam', 1) + self.assertEqual(sys.spam, 1) + self.assertRaises(TypeError, setattr, sys, 1, 'spam') + self.assertRaises(TypeError, setattr) + + def test_str(self): + self.assertEqual(str(''), '') + self.assertEqual(str(0), '0') + self.assertEqual(str(0L), '0') + self.assertEqual(str(()), '()') + self.assertEqual(str([]), '[]') + self.assertEqual(str({}), '{}') + a = [] + a.append(a) + self.assertEqual(str(a), '[[...]]') + a = {} + a[0] = a + self.assertEqual(str(a), '{0: {...}}') + + def test_sum(self): + self.assertEqual(sum([]), 0) + self.assertEqual(sum(range(2,8)), 27) + self.assertEqual(sum(iter(range(2,8))), 27) + self.assertEqual(sum(Squares(10)), 285) + self.assertEqual(sum(iter(Squares(10))), 285) + self.assertEqual(sum([[1], [2], [3]], []), [1, 2, 3]) + + self.assertRaises(TypeError, sum) + self.assertRaises(TypeError, sum, 42) + self.assertRaises(TypeError, sum, ['a', 'b', 'c']) + self.assertRaises(TypeError, sum, ['a', 'b', 'c'], '') + self.assertRaises(TypeError, sum, [[1], [2], [3]]) + self.assertRaises(TypeError, sum, [{2:3}]) + self.assertRaises(TypeError, sum, [{2:3}]*2, {2:3}) + + class BadSeq: + def __getitem__(self, index): + raise ValueError + self.assertRaises(ValueError, sum, BadSeq()) + + def test_tuple(self): + self.assertEqual(tuple(()), ()) + t0_3 = (0, 1, 2, 3) + t0_3_bis = tuple(t0_3) + self.assert_(t0_3 is t0_3_bis) + self.assertEqual(tuple([]), ()) + self.assertEqual(tuple([0, 1, 2, 3]), (0, 1, 2, 3)) + self.assertEqual(tuple(''), ()) + self.assertEqual(tuple('spam'), ('s', 'p', 'a', 'm')) + + def test_type(self): + self.assertEqual(type(''), type('123')) + self.assertNotEqual(type(''), type(())) + + def test_unichr(self): + if have_unicode: + self.assertEqual(unichr(32), unicode(' ')) + self.assertEqual(unichr(65), unicode('A')) + self.assertEqual(unichr(97), unicode('a')) + self.assertEqual( + unichr(sys.maxunicode), + unicode('\\U%08x' % (sys.maxunicode), 'unicode-escape') + ) + self.assertRaises(ValueError, unichr, sys.maxunicode+1) + self.assertRaises(TypeError, unichr) + + def get_vars_f0(): + return vars() + # we don't want self in vars(), so use staticmethod + get_vars_f0 = staticmethod(get_vars_f0) + + def get_vars_f2(): + BuiltinTest.get_vars_f0() + a = 1 + b = 2 + return vars() + get_vars_f2 = staticmethod(get_vars_f2) + + def test_vars(self): + self.assertEqual(Set(vars()), Set(dir())) + import sys + self.assertEqual(Set(vars(sys)), Set(dir(sys))) + self.assertEqual(self.get_vars_f0(), {}) + self.assertEqual(self.get_vars_f2(), {'a': 1, 'b': 2}) + self.assertRaises(TypeError, vars, 42, 42) + self.assertRaises(TypeError, vars, 42) + + def test_zip(self): + a = (1, 2, 3) + b = (4, 5, 6) + t = [(1, 4), (2, 5), (3, 6)] + self.assertEqual(zip(a, b), t) + b = [4, 5, 6] + self.assertEqual(zip(a, b), t) + b = (4, 5, 6, 7) + self.assertEqual(zip(a, b), t) + class I: + def __getitem__(self, i): + if i < 0 or i > 2: raise IndexError + return i + 4 + self.assertEqual(zip(a, I()), t) + self.assertRaises(TypeError, zip) + self.assertRaises(TypeError, zip, None) + class G: + pass + self.assertRaises(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 + self.assertEqual( + zip(SequenceWithoutALength(), xrange(2**30)), + list(enumerate(range(5))) + ) + + class BadSeq: + def __getitem__(self, i): + if i == 5: + raise ValueError + else: + return i + self.assertRaises(ValueError, zip, BadSeq(), BadSeq()) + +if __name__ == '__main__': + test.main() From lac at codespeak.net Thu Dec 18 18:19:01 2003 From: lac at codespeak.net (lac at codespeak.net) Date: Thu, 18 Dec 2003 18:19:01 +0100 (MET) Subject: [pypy-svn] rev 2529 - pypy/trunk/src/pypy/objspace/std/test Message-ID: <20031218171901.594D85A4F8@thoth.codespeak.net> Author: lac Date: Thu Dec 18 18:19:00 2003 New Revision: 2529 Modified: pypy/trunk/src/pypy/objspace/std/test/test_stringobject.py Log: added tests for iswhatevers. Modified: pypy/trunk/src/pypy/objspace/std/test/test_stringobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/test/test_stringobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/test/test_stringobject.py Thu Dec 18 18:19:00 2003 @@ -386,13 +386,53 @@ self.assertEquals("aaa AAA".upper(), "AAA AAA") self.assertEquals("".upper(), "") - def test_alnum(self): + def test_isalnum(self): self.assertEquals("".isalnum(), False) self.assertEquals("!Bro12345w&&&&n Fox".isalnum(), False) self.assertEquals("125 Brown Foxes".isalnum(), False) self.assertEquals("125BrownFoxes".isalnum(), True) + + def test_isalpha(self): + self.assertEquals("".isalpha(), False) + self.assertEquals("!Bro12345w&&&&nFox".isalpha(), False) + self.assertEquals("Brown Foxes".isalpha(), False) + self.assertEquals("125".isalpha(), False) + + def test_isdigit(self): + self.assertEquals("".isdigit(), False) + self.assertEquals("!Bro12345w&&&&nFox".isdigit(), False) + self.assertEquals("Brown Foxes".isdigit(), False) + self.assertEquals("125".isdigit(), True) + + def test_isspace(self): + self.assertEquals("".isspace(), False) + self.assertEquals("!Bro12345w&&&&nFox".isspace(), False) + self.assertEquals(" ".isspace(), True) + self.assertEquals("\t\t\b\b\n".isspace(), False) + self.assertEquals("\t\t".isspace(), True) + self.assertEquals("\t\t\r\r\n".isspace(), True) - + def test_islower(self): + self.assertEquals("".islower(), False) + self.assertEquals(" ".islower(), False) + self.assertEquals("\t\t\b\b\n".islower(), False) + self.assertEquals("b".islower(), True) + self.assertEquals("bbb".islower(), True) + self.assertEquals("!bbb".islower(), False) + self.assertEquals("BBB".islower(), False) + self.assertEquals("bbbBBB".islower(), False) + + def test_isupper(self): + self.assertEquals("".isupper(), False) + self.assertEquals(" ".isupper(), False) + self.assertEquals("\t\t\b\b\n".isupper(), False) + self.assertEquals("B".isupper(), True) + self.assertEquals("BBB".isupper(), True) + self.assertEquals("!BBB".isupper(), False) + self.assertEquals("bbb".isupper(), False) + self.assertEquals("BBBbbb".isupper(), False) + + def test_swapcase(self): self.assertEquals("aaa AAA 111".swapcase(), "AAA aaa 111") self.assertEquals("".swapcase(), "") From lac at codespeak.net Thu Dec 18 18:21:09 2003 From: lac at codespeak.net (lac at codespeak.net) Date: Thu, 18 Dec 2003 18:21:09 +0100 (MET) Subject: [pypy-svn] rev 2530 - pypy/trunk/src/pypy/objspace/std/test Message-ID: <20031218172109.564F35A4F8@thoth.codespeak.net> Author: lac Date: Thu Dec 18 18:21:08 2003 New Revision: 2530 Modified: pypy/trunk/src/pypy/objspace/std/test/test_stringobject.py Log: removed dead code, this test does esist Modified: pypy/trunk/src/pypy/objspace/std/test/test_stringobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/test/test_stringobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/test/test_stringobject.py Thu Dec 18 18:21:08 2003 @@ -114,17 +114,6 @@ w_slice = space.newslice(w(1), w_None, w(2)) self.assertEqual_w(space.getitem(w_str, w_slice), w('el')) - -#AttributeError: W_StringObject instance has no attribute 'ljust' -# def test_ljust(self): -# w = self.space.wrap -# s = "abc" -# -# self.assertEqual_w(w(s).ljust(2), w(s)) -# self.assertEqual_w(w(s).ljust(3), w(s)) -# self.assertEqual_w(w(s).ljust(4), w(s + " ")) -# self.assertEqual_w(w(s).ljust(5), w(s + " ")) - class TestStringObject(test.AppTestCase): def setUp(self): self.space = test.objspace('std') @@ -147,7 +136,6 @@ self.assertEquals('a//b//c//d'.split('//'), ['a', 'b', 'c', 'd']) self.assertEquals('endcase test'.split('test'), ['endcase ', '']) - def test_split_splitchar(self): self.assertEquals("/a/b/c".split('/'), ['','a','b','c']) @@ -189,7 +177,6 @@ self.assertEquals('abc'.rjust(3), 'abc') self.assertEquals('abc'.rjust(2), 'abc') - def test_ljust(self): s = "abc" self.assertEquals(s.ljust(2), s) From jacob at codespeak.net Thu Dec 18 18:44:27 2003 From: jacob at codespeak.net (jacob at codespeak.net) Date: Thu, 18 Dec 2003 18:44:27 +0100 (MET) Subject: [pypy-svn] rev 2531 - pypy/trunk/src/pypy/module Message-ID: <20031218174427.604E15A4F8@thoth.codespeak.net> Author: jacob Date: Thu Dec 18 18:44:26 2003 New Revision: 2531 Modified: pypy/trunk/src/pypy/module/builtin.py Log: Added license, copyright and stub help. Modified: pypy/trunk/src/pypy/module/builtin.py ============================================================================== --- pypy/trunk/src/pypy/module/builtin.py (original) +++ pypy/trunk/src/pypy/module/builtin.py Thu Dec 18 18:44:26 2003 @@ -694,8 +694,27 @@ if not isinstance(s, str): raise TypeError("intern() argument 1 must be string.") return s + + def app_copyright(self): + print 'Copyright 2002-2004 Pypy development team.\nAll rights reserved.\nFor further information see http://www.codespaek.net/pypy.\nSome materials may have a different copyright.\nIn these cases, this is explicitly noted in the source code file.' + + def app_license(self): + print \ +""" +Copyright (c) <2002-2004> + +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. +""" + + def app_help(self): + print "You must be joking." # source code for the builtin xrange-class + xrange_appsource = """if 1: class xrange: def __init__(self, start, stop=None, step=1): From jacob at codespeak.net Thu Dec 18 18:47:08 2003 From: jacob at codespeak.net (jacob at codespeak.net) Date: Thu, 18 Dec 2003 18:47:08 +0100 (MET) Subject: [pypy-svn] rev 2532 - in pypy/trunk/src/pypy/objspace/std: . test Message-ID: <20031218174708.04C8C5A4F8@thoth.codespeak.net> Author: jacob Date: Thu Dec 18 18:47:08 2003 New Revision: 2532 Modified: pypy/trunk/src/pypy/objspace/std/dicttype.py pypy/trunk/src/pypy/objspace/std/test/test_dictobject.py Log: Added fromkeys and tests for fromkeys. Modified: pypy/trunk/src/pypy/objspace/std/dicttype.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/dicttype.py (original) +++ pypy/trunk/src/pypy/objspace/std/dicttype.py Thu Dec 18 18:47:08 2003 @@ -5,25 +5,27 @@ from pypy.objspace.std.objspace import * from pypy.interpreter import gateway from typeobject import W_TypeObject +from listobject import W_ListObject class W_DictType(W_TypeObject): typename = 'dict' - dict_copy = MultiMethod('copy', 1) - dict_items = MultiMethod('items', 1) - dict_keys = MultiMethod('keys', 1) - dict_values = MultiMethod('values', 1) - dict_has_key = MultiMethod('has_key', 2) - dict_clear = MultiMethod('clear', 1) - dict_get = MultiMethod('get', 3, defaults=(None,)) - dict_pop = MultiMethod('pop', 2, varargs=True) - dict_popitem = MultiMethod('popitem', 1) - dict_setdefault = MultiMethod('setdefault', 3, defaults=(None,)) - dict_update = MultiMethod('update', 2) - dict_iteritems = MultiMethod('iteritems', 1) - dict_iterkeys = MultiMethod('iterkeys', 1) - dict_itervalues = MultiMethod('itervalues', 1) + dict_copy = MultiMethod('copy', 1) + dict_items = MultiMethod('items', 1) + dict_keys = MultiMethod('keys', 1) + dict_values = MultiMethod('values', 1) + dict_has_key = MultiMethod('has_key', 2) + dict_clear = MultiMethod('clear', 1) + dict_get = MultiMethod('get', 3, defaults=(None,)) + dict_pop = MultiMethod('pop', 2, varargs=True) + dict_popitem = MultiMethod('popitem', 1) + dict_setdefault = MultiMethod('setdefault', 3, defaults=(None,)) + dict_update = MultiMethod('update', 2) + dict_iteritems = MultiMethod('iteritems', 1) + dict_iterkeys = MultiMethod('iterkeys', 1) + dict_itervalues = MultiMethod('itervalues', 1) + dict_fromkeys = MultiMethod('fromkeys', 2, varargs=True) # This can return when multimethods have been fixed #dict_str = StdObjSpace.str @@ -83,6 +85,16 @@ def app_dict_itervalues__ANY(d): return iter(d.values()) +def app_dict_fromkeys__ANY_List(d, seq, value): + d = {} + if value: + value = value[0] + else: + value = None + for item in seq: + d[item] = value + return d + # This can return when multimethods have been fixed """ def app_dict_str__ANY(d): Modified: pypy/trunk/src/pypy/objspace/std/test/test_dictobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/test/test_dictobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/test/test_dictobject.py Thu Dec 18 18:47:08 2003 @@ -339,5 +339,12 @@ except (TypeError, ValueError): pass else: self.fail("dict([[1,2,3]]) should raise!") + def test_fromkeys(self): + self.assertEquals({}.fromkeys([1, 2], 1), {1: 1, 2: 1}) + self.assertEquals({}.fromkeys([1, 2]), {1: None, 2: None}) + self.assertEquals({}.fromkeys([]), {}) + self.assertEquals({1: 0, 2: 0, 3: 0}.fromkeys([1, '1'], 'j'), + {1: 'j', '1': 'j'}) + if __name__ == '__main__': test.main() From rxe at codespeak.net Thu Dec 18 19:33:16 2003 From: rxe at codespeak.net (rxe at codespeak.net) Date: Thu, 18 Dec 2003 19:33:16 +0100 (MET) Subject: [pypy-svn] rev 2533 - pypy/trunk/src/pypy/objspace Message-ID: <20031218183316.E46F85A4F8@thoth.codespeak.net> Author: rxe Date: Thu Dec 18 19:33:08 2003 New Revision: 2533 Modified: pypy/trunk/src/pypy/objspace/trace.py Log: Added getevents() to get all the events from TraceResult. Modified: pypy/trunk/src/pypy/objspace/trace.py ============================================================================== --- pypy/trunk/src/pypy/objspace/trace.py (original) +++ pypy/trunk/src/pypy/objspace/trace.py Thu Dec 18 19:33:08 2003 @@ -165,6 +165,11 @@ if isinstance(event, CallBegin): yield event.callinfo + def getevents(self): + for event in self.events: + yield event + + Space = TraceObjSpace # ______________________________________________________________________ From rxe at codespeak.net Thu Dec 18 19:34:09 2003 From: rxe at codespeak.net (rxe at codespeak.net) Date: Thu, 18 Dec 2003 19:34:09 +0100 (MET) Subject: [pypy-svn] rev 2534 - pypy/trunk/src/pypy/tool Message-ID: <20031218183409.D2FAB5A4F8@thoth.codespeak.net> Author: rxe Date: Thu Dec 18 19:34:05 2003 New Revision: 2534 Modified: pypy/trunk/src/pypy/tool/traceop.py Log: Intermediate checkin to work with the new TraceObjSpace. Modified: pypy/trunk/src/pypy/tool/traceop.py ============================================================================== --- pypy/trunk/src/pypy/tool/traceop.py (original) +++ pypy/trunk/src/pypy/tool/traceop.py Thu Dec 18 19:34:05 2003 @@ -1,12 +1,71 @@ import autopath -import repr -from pypy.interpreter.pycode import PyCode -from pypy.objspace.std import StdObjSpace +from pypy.tool import pydis +from pypy.interpreter.baseobjspace import ObjSpace +from pypy.objspace import trace + +from pypy.objspace.trace import TraceObjSpace from pypy.objspace.trivial import TrivialObjSpace -from pypy.objspace.trace import Trace + +from pypy.interpreter.gateway import app2interp + +# Global +operations = dict([(r[0], r[0]) for r in ObjSpace.MethodTable]) + + +def perform_trace(space, app_func, *args, **kwds): + # Wrap up our space, with a trace space + tspace = TraceObjSpace(space) + + # Add our function + func_gw = app2interp(app_func) + func = func_gw.get_function(tspace) + + # Run the func in the trace space and return results + tspace.settrace() + funcres = func(*args, **kwds) + traceres = tspace.getresult() + return funcres, traceres + + +def trace_function(space, fn, *arg, **kwds): + funcres, traceres = perform_trace(space, fn, *arg, **kwds) + disresult = pydis.pydis(fn) + + for event in traceres.getevents(): + if isinstance(event, trace.ExecBytecode): + print event.index, " ", disresult.getbytecode(event.index) + elif isinstance(event, trace.CallBegin): + info = event.callinfo + if info.name in operations: + print info.name, info.args, info.kwargs + else: + pass + return funcres, traceres + + +def app_test(): + a = 1 + x = range(1) + b = [1,2,3,4,5,6,7,8,9,10] + for ii in b: + a += ii + + return "Hello World" + + +def test(): + space = TrivialObjSpace() + funcres, traceres = trace_function(space, app_test) + print "function result -->", funcres + + +test() + +""" +import repr def get_repr(): " Our own repr function for pretty print. " repr_obj = repr.Repr() @@ -21,124 +80,127 @@ return "ERROR" return our_repr - +""" -def rpretty_print(spacedump): - " Pretty print for rdump() calls to Trace object spaces. " +## def rpretty_print(spacedump): +## " Pretty print for rdump() calls to Trace object spaces. " - Repr = get_repr() - for operation, bytecodes in spacedump: - for opcode, opname, oparg, ins_idx in bytecodes: - print "\t%s\t%s\t\t%s" % (ins_idx, opname, oparg) - - if operation is not None: - op_name = operation[0] - args = operation[1:] - print " ***\t", op_name, " ->", - for a in args: - print Repr(a), - print - - -def add_func(space, func, w_globals): - """ Add a function to globals. """ - func_name = func.func_name - w_func_name = space.wrap(func_name) - w_func = space.wrap(func) - space.setitem(w_globals, w_func_name, w_func) - - -def run_in_space(space, func, *args): - # Get execution context and globals - ec = space.getexecutioncontext() - w_globals = ec.make_standard_w_globals() - - # Add the function to globals - add_func(space, func, w_globals) - - # Create wrapped args - args_w = [space.wrap(ii) for ii in args] - code = func.func_code - code = PyCode()._from_code(code) - - # Create frame - frame = code.create_frame(space, w_globals) - frame.setfastscope(args_w) +## Repr = get_repr() +## for operation, bytecodes in spacedump: +## for opcode, opname, oparg, ins_idx in bytecodes: +## print "\t%s\t%s\t\t%s" % (ins_idx, opname, oparg) + +## if operation is not None: +## op_name = operation[0] +## args = operation[1:] +## print " ***\t", op_name, " ->", +## for a in args: +## print Repr(a), +## print + + +## def add_func(space, func, w_globals): +## """ Add a function to globals. """ +## func_name = func.func_name +## w_func_name = space.wrap(func_name) +## w_func = space.wrap(func) +## space.setitem(w_globals, w_func_name, w_func) + + +## def run_in_space(space, func, *args): +## # Get execution context and globals +## ec = space.getexecutioncontext() +## w_globals = ec.make_standard_w_globals() + +## # Add the function to globals +## add_func(space, func, w_globals) + +## # Create wrapped args +## args_w = [space.wrap(ii) for ii in args] +## code = func.func_code +## code = PyCode()._from_code(code) + +## # Create frame +## frame = code.create_frame(space, w_globals) +## frame.setfastscope(args_w) - # start/stop tracing while running frame - space.start_tracing() - res = frame.run() - space.stop_tracing() - - return res - - -def pretty_print(spacedump): - " Pretty print for rdump() calls to Trace object spaces. " - Repr = get_repr() - - for line in spacedump: - ((opcode, opname, arg, ins_idx), spaceops) = line - start = "%4i %s " % (ins_idx, opname) - start = start + " " * (20 - len(start)) + str(arg) - start = start + " " * (30 - len(start)) - if not spaceops: - print start - else: - op = spaceops.pop(0) - print start - for op_name, args in spaceops: - print " " * 30, op_name, Repr(args) +## # start/stop tracing while running frame +## space.start_tracing() +## res = frame.run() +## space.stop_tracing() + +## return res -def _trace_function(space, reverse_pretty_print_flag, fn, *arg, **kwds): - res = run_in_space(space, fn, *arg, **kwds) - if reverse_pretty_print_flag: - # Get reverse dump - spacedump = space.rdump() +## def pretty_print(spacedump): +## " Pretty print for rdump() calls to Trace object spaces. " +## Repr = get_repr() - # Pretty print dump - rpretty_print(spacedump) - else: - # Get dump - spacedump = space.dump() +## for line in spacedump: +## ((opcode, opname, arg, ins_idx), spaceops) = line +## start = "%4i %s " % (ins_idx, opname) +## start = start + " " * (20 - len(start)) + str(arg) +## start = start + " " * (30 - len(start)) +## if not spaceops: +## print start +## else: +## op = spaceops.pop(0) +## print start +## for op_name, args in spaceops: +## print " " * 30, op_name, Repr(args) - # Pretty dump - pretty_print(spacedump) - return res +## def _trace_function(space, reverse_pretty_print_flag, fn, *arg, **kwds): +## res = run_in_space(space, fn, *arg, **kwds) +## if reverse_pretty_print_flag: +## # Get reverse dump +## spacedump = space.rdump() -def trace_function(trace_space, fn, *arg, **kwds): - return _trace_function(trace_space, False, fn, *arg, **kwds) +## # Pretty print dump +## rpretty_print(spacedump) +## else: +## # Get dump +## spacedump = space.dump() -def rtrace_function(trace_space, fn, *arg, **kwds): - return _trace_function(trace_space, True, fn, *arg, **kwds) +## # Pretty dump +## pretty_print(spacedump) +## return res -def trace_function2(space, fn, *arg, **kwds): - return _trace_function(Trace(space), False, fn, *arg, **kwds) +## def trace_function(trace_space, fn, *arg, **kwds): +## return _trace_function(trace_space, False, fn, *arg, **kwds) -def rtrace_function2(space, fn, *arg, **kwds): - return _trace_function(Trace(space), True, fn, *arg, **kwds) +## def rtrace_function(trace_space, fn, *arg, **kwds): +## return _trace_function(trace_space, True, fn, *arg, **kwds) + + +## def trace_function2(space, fn, *arg, **kwds): +## return _trace_function(Trace(space), False, fn, *arg, **kwds) + +## def rtrace_function2(space, fn, *arg, **kwds): +## return _trace_function(Trace(space), True, fn, *arg, **kwds) -## # Create space -## if __name__ == "__main__": -## try: -## import readline -## except ImportError: -## pass - -## from pypy.tool import option -## from pypy.tool import test -## args = option.process_options(option.get_standard_options(), -## option.Options) -## objspace = option.objspace() - - -## def run(*args, **kwds): -## def run_function(space, func, *args): -## from pypy.objspace.std import StdObjSpace -## space = Trace(StdObjSpace) +## ## # Create space +## ## if __name__ == "__main__": +## ## try: +## ## import readline +## ## except ImportError: +## ## pass + +## ## from pypy.tool import option +## ## from pypy.tool import test +## ## args = option.process_options(option.get_standard_options(), +## ## option.Options) +## ## objspace = option.objspace() + + +## ## def run(*args, **kwds): +## ## def run_function(space, func, *args): +## ## from pypy.objspace.std import StdObjSpace +## ## space = Trace(StdObjSpace) + + + From hpk at codespeak.net Thu Dec 18 21:26:26 2003 From: hpk at codespeak.net (hpk at codespeak.net) Date: Thu, 18 Dec 2003 21:26:26 +0100 (MET) Subject: [pypy-svn] rev 2535 - in pypy/trunk/src/pypy: objspace objspace/test tool Message-ID: <20031218202626.6048C5A4F8@thoth.codespeak.net> Author: hpk Date: Thu Dec 18 21:26:25 2003 New Revision: 2535 Modified: pypy/trunk/src/pypy/objspace/test/test_traceobjspace.py pypy/trunk/src/pypy/objspace/trace.py pypy/trunk/src/pypy/objspace/trivial.py pypy/trunk/src/pypy/tool/traceop.py Log: the tests on the traceobjspace now pass nicely even for the trivial object space. note that we don'T trace class instantiation ... Modified: pypy/trunk/src/pypy/objspace/test/test_traceobjspace.py ============================================================================== --- pypy/trunk/src/pypy/objspace/test/test_traceobjspace.py (original) +++ pypy/trunk/src/pypy/objspace/test/test_traceobjspace.py Thu Dec 18 21:26:25 2003 @@ -7,7 +7,7 @@ class Test_TraceObjSpace(test.IntTestCase): def setUp(self): - self.space = test.objspace('trivial') + self.space = test.objspace() def tearDown(self): pass @@ -21,6 +21,14 @@ res = tspace.getresult() return res + def test_traceobjspace_basic(self): + t = TraceObjSpace(self.space) + self.assert_(t.is_true(t.w_builtins)) + #for name, value in vars(self.space).items(): + # if not name.startswith('_'): + # self.assert_(value is getattr(t, name)) + #self.assert_(t.is_true(t.make_standard_globals())) + def test_simpletrace(self): def app_f(): pass @@ -29,6 +37,14 @@ self.assertEquals(disresult._bytecodes, list(res.getbytecodes())) #self.assertEquals(len(list(res.getoperations())), 0) + def test_some_builtin(self): + def app_f(): + filter(None, []) # mapglobals() # ("c") + res = self.perform_trace(app_f) + disresult = pydis.pydis(app_f) + self.assertEquals(disresult._bytecodes, list(res.getbytecodes())) + #self.assertEquals(len(list(res.getoperations())), 0) + def test_trace_oneop(self): def app_f(): 1 + 1 Modified: pypy/trunk/src/pypy/objspace/trace.py ============================================================================== --- pypy/trunk/src/pypy/objspace/trace.py (original) +++ pypy/trunk/src/pypy/objspace/trace.py Thu Dec 18 21:26:25 2003 @@ -44,34 +44,32 @@ # class ExecutionContextTracer: def __init__(self, result, ec): - self.ec = ec - self.result = result + self.__ec = ec + self.__result = result def __getattr__(self, name): - """ generically pass through everything we don'T have explicit - interceptors for. - - """ - print "trying", name - return getattr(self.ec, 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) + 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) + 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)) + self.__result.append(ExecBytecode(frame)) #def exception_trace(self, operror): - # "called if the current frame raises an operation error. """ + # "called if the current frame raises an operation error. " + # print "exception trace", operror + # return self.__ec.exception_trace(operror) class CallInfo: """ encapsulates a function call with its arguments. """ @@ -83,53 +81,54 @@ class CallableTracer: def __init__(self, result, name, func): - self.result = result - self.name = name - self.func = 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)) + callinfo = CallInfo(self.__name, self.__func, args, kwargs) + self.__result.append(CallBegin(callinfo)) + #print "calling into", self.__name, [type(x).__name__ for x in args] + #print args try: - res = self.func(*args, **kwargs) + res = self.__func(*args, **kwargs) except Exception, e: - self.result.append(CallException(e, callinfo)) + #self.__result.append(CallException(e, callinfo)) raise else: - self.result.append(CallFinished(callinfo)) + self.__result.append(CallFinished(callinfo)) return res + def __getattr__(self, name): + """ generically pass through everything we don't intercept. """ + return getattr(self.__func, name) class TraceObjSpace: def __init__(self, space): - self.space = space + self.__space = space self.settrace() def settrace(self): - self.result = TraceResult(self) + self.__result = TraceResult(self) def getresult(self): - return self.result - - def __getattr__(self, name): - obj = getattr(self.space, name) - if callable(obj): - return CallableTracer(self.result, name, obj) - # XXX some attribute has been accessed, we don't care - return obj + return self.__result def getexecutioncontext(self): - ec = self.space.getexecutioncontext() + ec = self.__space.getexecutioncontext() if isinstance(ec, ExecutionContextTracer): return ec - return ExecutionContextTracer(self.result, ec) + return ExecutionContextTracer(self.__result, ec) def createexecutioncontext(self): - ec = self.space.createexecutioncontext() - return ExecutionContextTracer(self.result, ec) + ec = self.__space.createexecutioncontext() + return ExecutionContextTracer(self.__result, ec) - def __hash__(self): - return hash(self.space) + def __getattr__(self, name): + obj = getattr(self.__space, name) + if callable(obj) and not hasattr(obj, '__bases__'): + return CallableTracer(self.__result, name, obj) + return obj class TraceResult: """ this is the state of tracing-in-progress. """ Modified: pypy/trunk/src/pypy/objspace/trivial.py ============================================================================== --- pypy/trunk/src/pypy/objspace/trivial.py (original) +++ pypy/trunk/src/pypy/objspace/trivial.py Thu Dec 18 21:26:25 2003 @@ -377,6 +377,6 @@ for m in ObjSpace.MethodTable: if not hasattr(TrivialObjSpace, m[0]): - print m[0] + print m[0] # this should raise something Space = TrivialObjSpace Modified: pypy/trunk/src/pypy/tool/traceop.py ============================================================================== --- pypy/trunk/src/pypy/tool/traceop.py (original) +++ pypy/trunk/src/pypy/tool/traceop.py Thu Dec 18 21:26:25 2003 @@ -47,13 +47,13 @@ def app_test(): - a = 1 - x = range(1) - b = [1,2,3,4,5,6,7,8,9,10] - for ii in b: - a += ii + #a = 1 + range(1) + #b = [1,2,3,4,5,6,7,8,9,10] + #for ii in b: + # a += ii - return "Hello World" + #return "Hello World" def test(): From arigo at codespeak.net Thu Dec 18 21:30:30 2003 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 18 Dec 2003 21:30:30 +0100 (MET) Subject: [pypy-svn] rev 2536 - in pypy/trunk/src/pypy/annotation: . test Message-ID: <20031218203030.CA8AE5A4F8@thoth.codespeak.net> Author: arigo Date: Thu Dec 18 21:30:30 2003 New Revision: 2536 Modified: pypy/trunk/src/pypy/annotation/annset.py pypy/trunk/src/pypy/annotation/model.py pypy/trunk/src/pypy/annotation/test/test_annset.py Log: Argh. Still another refactoring of annotations. This one makes things much, much simpler. We kind of thing now that they are the correct level of generality that we need for the translator. Modified: pypy/trunk/src/pypy/annotation/annset.py ============================================================================== --- pypy/trunk/src/pypy/annotation/annset.py (original) +++ pypy/trunk/src/pypy/annotation/annset.py Thu Dec 18 21:30:30 2003 @@ -1,384 +1,161 @@ from __future__ import generators import types -from model import Annotation, SomeValue, QueryArgument, ANN, ConstPredicate -from model import immutable_types, blackholevalue, basicannotations +from model import SomeValue, ANN, immutable_types, debugname -QUERYARG = QueryArgument() - -class IDontKnow(Exception): - pass +class MostGeneralValue: + def __nonzero__(self): + return False +mostgeneralvalue = MostGeneralValue() + + +class About: + def __init__(self): + # 'annotations' maps Predicates to tuples + # (SomeValue, {set-of-blocks-depending-on-this-annotation}) + self.annotations = {} + self.subjects = {} # set of SomeValues we are about + def __repr__(self): # debugging + subjs = [debugname(c) for c in self.subjects] + subjs.sort() + lines = ['About %s:' % ' and '.join(subjs)] + annotations = [(str(pred), value) + for pred, (value, deps) in self.annotations.items()] + annotations.sort() + for name, somevalue in annotations: + lines.append('%15s --> %r' % (name, somevalue)) + return '\n'.join(lines) class AnnotationSet: - """An annotation set is a (large) family of Annotations.""" + """An annotation set is a (large) family of annotations.""" - # XXX STORED AS A PLAIN LIST, THE COMPLEXITY IS PLAINLY WRONG + # This is basically a mapping {SomeValue(): About()} + # with convenient methods. - def __init__(self, annlist=basicannotations): - self.annlist = list(annlist) # List of annotations - self._normalized = {} # maps SomeValues to some 'standard' one that - # is shared with it - self.mappings_to_normalize = [self._normalized] - - def getbindings(self): - """Return a general-purpose mapping between whatever you want and - SomeValues. The SomeValues are kept normalized by the AnnotationSet.""" - bindings = {} - self.mappings_to_normalize.append(bindings) - return bindings - - def normalized(self, someval): - return self._normalized.get(someval, someval) - - def setshared(self, someval1, someval2): - someval1 = self.normalized(someval1) - someval2 = self.normalized(someval2) - for mapping in self.mappings_to_normalize: - for key, value in mapping.items(): - if value is someval2: - mapping[key] = someval1 - self._normalized[someval2] = someval1 - - def isshared(self, someval1, someval2): - return self.normalized(someval1) is self.normalized(someval2) + def __init__(self): + self.about = {} + self.inblock = None - def normalizeann(self, ann): - "Normalize the annotation's arguments in-place." - ann.args = [self.normalized(a) for a in ann.args] - - def dump(self): # debugging - for ann in self.enumerate(): - print ann - - def enumerate(self): - """Enumerates all annotations in the heap.""" - return iter(self.annlist) - - __iter__ = enumerate - - def query(self, *querylist): - return [matchvalue for matchanns, matchvalue in self.match(*querylist)] - - def match(self, query, *querylist): - """ yield (matchanns, matchvalue) tuples with 'matchanns' - beeing a list of matching annotations and 'matchvalue' beeing - the queried value. """ - self.normalizeann(query) - for queryann in querylist: - self.normalizeann(queryann) - - # slightly limited implementation for ease of coding :-) - assert query.args.count(QUERYARG) == 1, ( - "sorry, the algorithm is a bit too naive for this case") - queryarg = query.args.index(QUERYARG) - for ann in self._annmatches(query): - # does the returned match also agree with the other queries? - match = ann.args[queryarg] - depends = [ann] - for queryann in querylist: - boundquery = queryann.copy(renameargs={QUERYARG: match}) - ann = self.findfirst(boundquery) - if ann is None: - break - depends.append(ann) - else: - yield depends, match - - def _annmatches(self, queryann): - """ yield annotations matching the given queryannotation. """ - self.normalizeann(queryann) - testindices = [i for i in range(queryann.predicate.arity) - if isinstance(queryann.args[i], SomeValue)] - for ann in self.annlist: - if ann.predicate == queryann.predicate: - for i in testindices: - if ann.args[i] is not queryann.args[i]: - break - else: - yield ann + def enter(self, block, callback): + self.inblock = block + self.callback = callback - def findfirst(self, checkann): - """ return the first matching annotation.""" - # note that we are usually not interested in multiple matching - # annotations; e.g. killing an annotation will take care - # that all matching annotations are removed, and thus also - # all dependencies listed on any of the duplicate annotation. - for ann in self._annmatches(checkann): - return ann # :-) - else: - return None + def leave(self): + self.inblock = None - def findall(self, checkann): - """ list all matching annotations.""" - return list(self._annmatches(checkann)) - - def record(self, recfunc, *args): - """ invoke the given 'recording' function by passing it a new - Recorder instance and letting it use its modification API. This API will - make sure that for the typical read/decide/write usage the read - annotations are a perequisite of the later write/modification - operation. Thus if the "causing" annotation gets invalidated we - know which "depending" annotations need to be removed. """ - rec = Recorder(self) - return recfunc(rec, *args) - - def kill(self, *annlist): - self.simplify(kill=annlist) - - def simplify(self, kill=[]): - """Kill annotations in the 'kill' list, and normalize and remove - duplicates.""" - # temporarykey() returns a tuple with all the information about - # the annotation; equal temporarykey() means equal annotations. - # Such keys are temporary because making SomeValues shared can - # change the temporarykey(), but this doesn't occur during - # one call to simplify(). - - def temporarykey(ann): - self.normalizeann(ann) - return ann.predicate, tuple(ann.args) - - allkeys = {} # map temporarykeys to Annotation instances - for ann in self.annlist: - key = temporarykey(ann) - if key not in allkeys: # if not duplicate - allkeys[key] = ann - - for ann in kill: - key = temporarykey(ann) - if key in allkeys: - del allkeys[key] - - self.annlist = allkeys.values() - - def merge(self, oldcell, newcell): - """Update the heap to account for the merging of oldcell and newcell. - Return the merged cell.""" - oldcell = self.normalized(oldcell) - newcell = self.normalized(newcell) - - if newcell is blackholevalue or newcell is oldcell: - return oldcell - elif oldcell is blackholevalue: - return newcell - - # if 'oldcell' or 'newcell' is immutable, we should not - # modify the annotations about it. If one of them is mutable, - # then we must update its annotations and return it. As a - # consequence if both are mutable then we must return them both, - # i.e. make them shared. - - mutablecells = [] - deleting = [] - annlist = self.annlist - for cell, othercell in [(oldcell, newcell), (newcell, oldcell)]: - if ANN.immutable[cell] not in annlist: - # for each mutable 'cell', kill the annotation that are - # talking about 'cell' but not existing for 'othercell'. - for ann in annlist: - if cell in ann.args: - otherann = ann.copy(renameargs={cell: othercell}) - if otherann not in annlist: - deleting.append(ann) - mutablecells.append(cell) - - if mutablecells: - # if there is at least one mutable cell we must return it. - # if there are two mutable cells we must merge them. - if len(mutablecells) == 2: - self.setshared(oldcell, newcell) - self.simplify(kill=deleting) - return self.normalized(mutablecells[0]) - else: - # no mutable cell, we can create a new result cell - # with only the common annotations. - common = [] - deleting = False # False if annotations of oldcell - # == annotations common annotations - for ann in annlist: - if oldcell in ann.args: - newann = ann.copy(renameargs={oldcell: newcell}) - try: - i = annlist.index(newann) - except ValueError: - deleting = True # this annotation about 'oldcell' - # is no longer there about 'newcell'. - else: - newann = annlist[i] # existing Annotation - common.append((ann, newann)) - - if not deleting: - return oldcell # nothing must be removed from oldcell - else: - resultcell = SomeValue() # invent a new cell - for oldann, newann in common: - resultann = newann.copy(renameargs={newcell: resultcell}) - annlist.append(resultann) - return resultcell - - def get(self, *querylist): - """Like query() but asserts that there is at most one answer. - Returns None if there isn't any answer.""" - resultlist = self.query(*querylist) - assert len(resultlist) <= 1, "Confusing annotations..." - if resultlist: - return resultlist[0] - else: - return None + def isshared(self, someval1, someval2): + return self.about[someval1] is self.about[someval2] - def get_del(self, *querylist): - """Like get() but kills the matching annotation.""" - resultlist = list(self.match(*querylist)) - assert len(resultlist) <= 1, "Confusing annotations..." - if resultlist: - matchanns, matchvalue = resultlist[0] - self.kill(*matchanns) - return matchvalue - else: - return None + def __repr__(self): # debugging + lines = ['===== AnnotationSet ====='] + abouts = [(repr(somevalue), about) + for somevalue, about in self.about.items()] + abouts.sort() + alreadyseen = {} + for name, about in abouts: + if about not in alreadyseen: + if about.annotations: # ignore empty Abouts + lines.append(repr(about)) + alreadyseen[about] = True + return '\n'.join(lines) + + def get(self, predicate, subject): + about = self._about(subject) + result = about.annotations.get(predicate) + if result: + answer, dependencies = result + if self.inblock: + dependencies[self.inblock] = True + return answer + else: + return mostgeneralvalue + + def _about(self, somevalue): + try: + return self.about[somevalue] + except KeyError: + if somevalue is mostgeneralvalue: + raise ValueError, "Unexpected mostgeneralvalue" + about = self.about[somevalue] = About() + about.subjects[somevalue] = True + return about + + def set(self, predicate, subject, answer=True): + about = self._about(subject) + if predicate in about.annotations: + raise ValueError, "There is already an annotation for %r" % subject + if answer is not mostgeneralvalue: + about.annotations[predicate] = answer, {} + + def kill(self, predicate, subject): + about = self._about(subject) + if predicate in about.annotations: + someval, deps = about.annotations[predicate] + del about.annotations[predicate] + # perform invalidations + for block in deps: + self.callback(block) + + def merge(self, oldvalue, newvalue): + """Update the heap to account for the merging of oldvalue and newvalue. + Return the merged somevalue.""" + if newvalue is mostgeneralvalue or oldvalue is mostgeneralvalue: + return mostgeneralvalue + + # build an About set that is the intersection of the two incoming ones + about1 = self._about(oldvalue) + about2 = self._about(newvalue) + about3 = About() + for pred in about1.annotations: + if pred in about2.annotations: + someval1, dep1 = about1.annotations[pred] + someval2, dep2 = about2.annotations[pred] + if someval1 == someval2: + someval3 = someval1 + elif (isinstance(someval1, SomeValue) and + isinstance(someval2, SomeValue)): + someval3 = self.merge(someval1, someval2) + if someval3 is mostgeneralvalue: + continue + else: + continue # annotation not in common + dep3 = dep1.copy() + dep3.update(dep2) + about3.annotations[pred] = someval3, dep3 - def getconstant(self, cell): - """If cell is a constant, return its value; otherwise, raise IDontKnow. - Also accepts a None for convenience.""" - if not cell: - raise IDontKnow - cell = self.normalized(cell) - for ann in self.annlist: - if isinstance(ann.predicate, ConstPredicate) and ann.args[0] is cell: - return ann.predicate.value - raise IDontKnow, cell - - def set(self, ann): - """Insert the annotation into the AnnotationSet.""" - self.normalizeann(ann) - self.annlist.append(ann) - - def delete(self, queryann): - """Kill the annotations matching the pattern.""" - matchannlist = self.findall(queryann) - self.simplify(kill=matchannlist) - - def checktype(self, someval, checktype): - if isinstance(checktype, tuple): - for t in checktype: - if self.checktype(someval, t): - return True - else: - return False - else: - return bool(self.query(ANN.type[someval, QUERYARG], - ANN.constant(checktype)[QUERYARG])) + # if 'oldvalue' or 'newvalue' is immutable, we should not + # modify the annotations about it. If one of them is mutable, + # then we must replace its About set with 'about3'. + invalidatedblocks = {} + for value, about in [(oldvalue, about1), (newvalue, about2)]: + if ANN.immutable not in about.annotations: + # find all annotations that are removed or generalized + for pred, (someval, deps) in about.annotations.items(): + if (pred not in about3.annotations or + about3.annotations[pred][0] != someval): + invalidatedblocks.update(deps) + # patch 'value' to use the new 'about3'. + for sharedvalue in about.subjects: # this includes 'value' + self.about[sharedvalue] = about3 + about3.subjects[sharedvalue] = True + + if not about3.subjects: + value3 = SomeValue() + self.about[value3] = about3 + about3.subjects[value3] = True + + # perform invalidations + for block in invalidatedblocks: + self.callback(block) + + return about3.subjects.iterkeys().next() def settype(self, someval, knowntype): - typeval = SomeValue() - self.set(ANN.type[someval, typeval]) - self.set(ANN.constant(knowntype)[typeval]) + self.set(ANN.type, someval, knowntype) if knowntype in immutable_types: - self.set(ANN.immutable[someval]) + self.set(ANN.immutable, someval) def copytype(self, oldcell, newcell): - for typecell in self.query(ANN.type[oldcell, QUERYARG]): - self.set(ANN.type[newcell, typecell]) - if self.findfirst(ANN.immutable[oldcell]): - self.set(ANN.immutable[newcell]) - - def newconstant(self, value): - cell = SomeValue() - self.set(ANN.constant(value)[cell]) - return cell - -''' -class XXXTransaction: - """A transaction contains methods to look for annotations in the - AnnotationHeap and create new annotations accordingly. Each - Transaction instance records which Annotations were needed, which - allows dependencies to be tracked.""" - - def __init__(self, heap): - self.heap = heap - self.using_annotations = [] # annotations that we have used - - def _list_annotations(self, opname, args): - # patch(arglist) -> arglist with None plugged where - # there is a None in the input 'args' - def patch(arglist): - return arglist - for i in range(len(args)): - if args[i] is None: - def patch(arglist, prevpatch=patch, i=i): - arglist = prevpatch(arglist)[:] - arglist[i] = None - return arglist - - matchann = [] - for ann in self.heap.annlist: - if ann.opname == opname and patch(ann.args) == args: - matchann.append(ann) - return matchann - - def get(self, opname, args): - """Return the Cell with the annotation 'opname(args) -> Cell', - or None if there is no such annotation or several different ones. - Hack to generalize: a None in the args matches anything.""" - matchann = self._list_annotations(opname, args) - if not matchann: - return None - else: - result = matchann[0].result - for ann in matchann[1:]: - if result != ann.result: - return None # conflicting results - for ann in matchann: - self.using(ann) - return result - - def delete(self, opname, args): - """Kill the annotations 'opname(args) -> *'.""" - matchann = self._list_annotations(opname, args) - self.heap.simplify(kill=matchann) - - def set(self, opname, args, result): - """Put a new annotation into the AnnotationHeap.""" - ann = Annotation(opname, args, result) - for prev in self.using_annotations: - prev.forward_deps.append(ann) - self.heap.annlist.append(ann) - - def get_type(self, cell): - """Get the type of 'cell', as specified by the annotations, or None. - Returns None if cell is None.""" - if cell is None: - return None - assert isinstance(cell, XCell) - c = self.get('type', [cell]) - if isinstance(c, XConstant): - return c.value - else: - return None - - def set_type(self, cell, type): - """Register an annotation describing the type of the object 'cell'.""" - self.set('type', [cell], XConstant(type)) - if type in immutable_types: - self.set('immutable', [], cell) - - def using(self, ann): - """Mark 'ann' as used in this transaction.""" - self.using_annotations.append(ann) - - -immutable_types = { - int: True, - long: True, - tuple: True, - str: True, - bool: True, - types.FunctionType: True, - } - -if __name__ == '__main__': - val1, val2, val3 = SomeValue(), SomeValue(), SomeValue() - annset = AnnotationSet() - -''' + self.set(ANN.type, newcell, self.get(ANN.type, oldcell)) + self.set(ANN.immutable, newcell, self.get(ANN.immutable, oldcell)) Modified: pypy/trunk/src/pypy/annotation/model.py ============================================================================== --- pypy/trunk/src/pypy/annotation/model.py (original) +++ pypy/trunk/src/pypy/annotation/model.py Thu Dec 18 21:30:30 2003 @@ -1,82 +1,40 @@ import types class SomeValue: - pass - -class QueryArgument: - pass + def __repr__(self): + return debugname(self) class Predicate: - def __init__(self, debugname, arity): + def __init__(self, debugname): self.debugname = debugname - self.arity = arity - def __getitem__(self, args): - if self.arity == 1: - args = (args,) - return Annotation(self, *args) def __str__(self): return self.debugname -class ConstPredicate(Predicate): - def __init__(self, value): - Predicate.__init__(self, 'const%s' % value, 1) - self.value = value - def __eq__(self, other): - return self.__class__ is other.__class__ and self.value == other.value - def __ne__(self, other): - return not (self == other) - def __hash__(self): - return hash(self.value) +class PredicateFamily: + def __init__(self, familyname): + self.familyname = familyname + self.instances = {} + def __getitem__(self, index): + try: + return self.instances[index] + except KeyError: + name = '%s[%r]' % (self.familyname, index) + pred = self.instances[index] = Predicate(name) + return pred class ANN: - add = Predicate('add', 3) - len = Predicate('len', 2) - getitem = Predicate('getitem', 3) - neg = Predicate('neg', 2) - constant = ConstPredicate - type = Predicate('type', 2) - immutable = Predicate('immutable', 1) - -class Annotation: - """An Annotation asserts something about SomeValues. - It is a Predicate applied to some arguments. """ - - def __init__(self, predicate, *args): - self.predicate = predicate # the operation or predicate - self.args = list(args) # list of SomeValues - assert len(args) == predicate.arity - # note that for predicates that are simple operations like - # op.add, the result is stored as the last argument. - for someval in args: - assert isinstance(someval, (SomeValue, QueryArgument, - type(Ellipsis))) # bug catcher - - def copy(self, renameargs={}): - args = [renameargs.get(arg, arg) for arg in self.args] - return Annotation(self.predicate, *args) - - def __repr__(self): - return "" % ( - self.predicate, ", ".join(map(debugname, self.args))) - - def __eq__(self, other): - return (self.__class__ is other.__class__ and - self.predicate == other.predicate and - self.args == other.args) + len = Predicate('len') + listitems = Predicate('listitems') + tupleitem = PredicateFamily('tupleitem') + type = Predicate('type') + immutable = Predicate('immutable') - def __ne__(self, other): - return not (self == other) def debugname(someval, _seen = {}): """ return a simple name for a SomeValue. """ try: return _seen[id(someval)] except KeyError: - if not _seen: - for name, value in globals().items(): - if isinstance(value, SomeValue): - _seen[id(value)] = name - return debugname(someval) name = "V%d" % len(_seen) _seen[id(someval)] = name return name @@ -90,22 +48,3 @@ slice: 'slice', types.FunctionType: 'function', } - -# a conventional value for representing 'all Annotations match this one' -# or, equivalently, something for which it is currently impossible to exist -# (when it will exist later it will have less annotations). -blackholevalue = Ellipsis - -# a few values representing 'any value of the given type' -# the following loops creates intvalue, strvalue, etc. -basicannotations = [] -for _type, _name in immutable_types.items(): - _val = globals()['%svalue' % _name] = SomeValue() - _tval = SomeValue() - basicannotations.append(ANN.type[_val, _tval]) - basicannotations.append(ANN.constant(_type)[_tval]) - basicannotations.append(ANN.immutable[_val]) - -# 'any immutable value' -immutablevalue = SomeValue() -basicannotations.append(ANN.immutable[immutablevalue]) Modified: pypy/trunk/src/pypy/annotation/test/test_annset.py ============================================================================== --- pypy/trunk/src/pypy/annotation/test/test_annset.py (original) +++ pypy/trunk/src/pypy/annotation/test/test_annset.py Thu Dec 18 21:30:30 2003 @@ -2,313 +2,196 @@ import autopath from pypy.tool import test -from pypy.annotation.model import ANN, SomeValue, blackholevalue -from pypy.annotation.annset import AnnotationSet, QUERYARG, IDontKnow +from pypy.annotation.model import SomeValue, ANN, Predicate +from pypy.annotation.annset import AnnotationSet, mostgeneralvalue c1,c2,c3,c4 = SomeValue(), SomeValue(), SomeValue(), SomeValue() +c5,c6,c7,c8 = SomeValue(), SomeValue(), SomeValue(), SomeValue() + +def annset(*args, **kwds): + "This constructor is just a convenient hack for the tests." + annset = AnnotationSet() + groups = [] + for a in args: + if isinstance(a, Predicate): + groups.append([a]) + else: + groups[-1].append(a) # hack hack hack + for args in groups: + annset.set(*args) + if 'links' in kwds: + links = kwds['links'] + for i in range(0, len(links), 2): + if annset.about.get(links[i]) != annset.about.get(links[i+1]): + assert links[i] not in annset.about + about = annset.about[links[i]] = annset.about[links[i+1]] + about.subjects[links[i]] = True + return annset class TestAnnotationSet(test.IntTestCase): - def assertSameSet(self, annset, annotations): - for ann in annotations: - annset.normalizeann(ann) - a = list(annset) - b = annotations - # try to reorder a to match b, without failing if the lists - # are different -- this will be checked by assertEquals() - for i in range(len(b)): - try: - j = i + a[i:].index(b[i]) - except ValueError: - pass - else: - a[i], a[j] = a[j], a[i] - self.assertEquals(a, b) - - def assertSameCells(self, annset, *cells): - cells = [annset.normalized(c) for c in cells] - for c in cells[1:]: - self.assertEquals(cells[0], c) - - def test_isshared(self): - a = AnnotationSet() - self.assert_(a.isshared(c1, c1)) - self.failIf(a.isshared(c1, c2)) - a.setshared(c1, c2) - self.assert_(a.isshared(c1, c2)) - self.assert_(a.isshared(c2, c1)) - self.failIf(a.isshared(c1, c3)) - a.setshared(c2, c3) - self.assert_(a.isshared(c1, c3)) - self.assert_(a.isshared(c2, c3)) - self.assert_(a.isshared(c3, c1)) - - def test_normalizeann(self): - a = AnnotationSet() - ann1 = ANN.add[c1,c2,c3] - ann2 = ANN.add[c4,c2,c3] - a.setshared(c1,c4) - a.normalizeann(ann1) - a.normalizeann(ann2) - self.assertEquals(ann1, ann2) + + def assertSameSet(self, annset1, annset2): + self.assertEquals(repr(annset1), repr(annset2)) - def test_query_one_annotation_arg(self): - lst = [ANN.add[c1, c3, c2]] - a = AnnotationSet(lst) - clist = a.query(ANN.add[c1, c3, QUERYARG]) - self.assertEquals(clist, [c2]) - clist = a.query(ANN.add[c1, QUERYARG, c2]) - self.assertEquals(clist, [c3]) - clist = a.query(ANN.add[QUERYARG, c3, c2]) - self.assertEquals(clist, [c1]) - - clist = a.query(ANN.add[QUERYARG, c1, c2]) - self.assertEquals(clist, []) - - def test_query_multiple_annotations(self): - lst = [ - ANN.add[c1, c3, c2], - ANN.type[c2, c3], - ] - a = AnnotationSet(lst) - clist = a.query(ANN.add[c1, c3, QUERYARG], - ANN.type[QUERYARG, c3]) - self.assertEquals(clist, [c2]) - - def test_constant(self): - lst = [ - ANN.constant(42)[c1], - ] - a = AnnotationSet(lst) - clist = a.query(ANN.constant(42)[QUERYARG]) - self.assertEquals(clist, [c1]) - - def test_newconstant(self): - a = AnnotationSet([]) - c = a.newconstant(42) - self.assertSameSet(a, [ANN.constant(42)[c]]) - - def test_getconstant(self): - lst = [ - ANN.constant(42)[c1], - ] - a = AnnotationSet(lst) - self.assertEquals(a.getconstant(c1), 42) - self.assertRaises(IDontKnow, a.getconstant, c2) - - def test_query_blackholevalue(self): - lst = [ - ANN.add[c1, c3, c2], - ANN.add[c1, c2, c4], - ANN.type[c2, c4], - ANN.type[c2, c3], - ] - a = AnnotationSet(lst) - clist = a.query(ANN.add[c1, ..., QUERYARG]) - clist.sort() - expected = [c2, c4] - expected.sort() - self.assertEquals(clist, expected) - clist = a.query(ANN.add[c2, ..., QUERYARG]) - self.assertEquals(clist, []) - clist = a.query(ANN.type[c2, QUERYARG], - ANN.add[c1, QUERYARG, ...]) - self.assertEquals(clist, [c3]) - - def test_simplify(self): - lst = [ANN.add[c1, c3, c2], - ANN.add[c1, c2, c2], - ANN.neg[c2, c3]] - a = AnnotationSet(lst) - a.simplify() - self.assertSameSet(a, lst) - - a.setshared(c2, c3) - a.simplify() - self.assertSameSet(a, lst[1:]) + def assertSameCells(self, annset, firstcell, *cells): + for cell in cells: + self.assert_(annset.isshared(firstcell, cell)) + + def test_trivial(self): + a1 = annset(ANN.len, c1, c2, + ANN.type, c2, int) + a2 = annset(ANN.len, c1, c2, + ANN.type, c2, int) + self.assertSameSet(a1, a2) + + def test_get(self): + a1 = annset(ANN.len, c1, c2, + ANN.type, c2, int) + self.assertEquals(a1.get(ANN.len, c1), c2) + self.assertEquals(a1.get(ANN.len, c2), mostgeneralvalue) + + def test_set(self): + a1 = annset(ANN.len, c1, c2, + ANN.type, c2, int) + a1.set(ANN.len, c2, c3) + self.assertSameSet(a1, + annset(ANN.len, c1, c2, + ANN.type, c2, int, + ANN.len, c2, c3)) def test_kill(self): - ann1 = ANN.add[c1, c3, c2] - lst = [ann1, - ANN.add[c1, c2, c2], - ANN.neg[c2, c3]] - a = AnnotationSet(lst) - a.kill(ann1) - self.assertSameSet(a, lst[1:]) - - def test_merge_blackholevalue(self): - lst = [ANN.add[c1, c3, c2], - ANN.neg[c2, c3]] - a = AnnotationSet(lst) - # (c3) inter (all annotations) == (c3) - c = a.merge(c3, blackholevalue) - self.assertEquals(c, c3) - self.assertSameSet(a, lst) + a1 = annset(ANN.len, c1, c2, + ANN.type, c2, int) + for i in range(2): + a1.kill(ANN.len, c1) + self.assertSameSet(a1, + annset(ANN.type, c2, int)) + + def test_merge_mostgeneralvalue(self): + a1 = annset(ANN.len, c1, c2, + ANN.type, c2, int) + a2 = annset(ANN.len, c1, c2, + ANN.type, c2, int) + # (c3) inter (mostgeneralvalue) == (mostgeneralvalue) + c = a1.merge(c3, mostgeneralvalue) + self.assertEquals(c, mostgeneralvalue) + self.assertSameSet(a1, a2) def test_merge_mutable1(self): - lst = [ANN.type[c1, c3], - ANN.type[c2, c3], - ANN.add[c2, c3, c3]] - a = AnnotationSet(lst) - # (c1) inter (c2) == (c1 shared with c2) - c = a.merge(c1, c2) - self.assertSameCells(a, c, c1, c2) - self.assertSameSet(a, [ANN.type[c, c3]]) + a1 = annset(ANN.len, c1, c2, + ANN.len, c3, c2) + a2 = annset(ANN.len, c1, c2, links=[c3,c1]) + # (c1) inter (c3) == (c1 shared with c3) + c = a1.merge(c1, c3) + self.assertSameCells(a1, c, c1, c3) + self.assertSameSet(a1, a2) def test_merge_mutable2(self): - lst = [ANN.type[c1, c3], - ANN.type[c2, c3], - ANN.add[c1, c3, c3]] - a = AnnotationSet(lst) - # (c1) inter (c2) == (c1 shared with c2) - c = a.merge(c1, c2) - self.assertSameCells(a, c, c1, c2) - self.assertSameSet(a, [ANN.type[c, c3]]) + a1 = annset(ANN.len, c1, c2, + ANN.len, c3, c2, + ANN.type, c1, list, + ANN.type, c2, str) + a2 = annset(ANN.len, c1, c2, + ANN.type, c2, str, + links=[c3,c1]) + # (c1) inter (c3) == (c1 shared with c3) + c = a1.merge(c1, c3) + self.assertSameCells(a1, c, c1, c3) + self.assertSameSet(a1, a2) def test_merge_immutable1(self): - lst = [ANN.type[c1, c3], - ANN.type[c2, c3], - ANN.immutable[c1], - ANN.immutable[c2], - ANN.add[c2, c3, c3]] - a = AnnotationSet(lst) - # (c1) inter (c2) == (c1) - c = a.merge(c1, c2) - self.assertSameCells(a, c, c1) - self.failIf(a.isshared(c1, c2)) - self.assertSameSet(a, lst) + a1 = annset(ANN.len, c1, c2, + ANN.immutable, c1, + ANN.len, c3, c2, + ANN.immutable, c3) + # (c1) inter (c3) == (some new c) + c = a1.merge(c1, c3) + a2 = annset(ANN.len, c1, c2, + ANN.immutable, c1, + ANN.len, c3, c2, + ANN.immutable, c3, + ANN.len, c, c2, + ANN.immutable, c) + self.assertSameSet(a1, a2) def test_merge_immutable2(self): - lst = [ANN.type[c1, c3], - ANN.type[c2, c3], - ANN.immutable[c1], - ANN.immutable[c2], - ANN.add[c1, c3, c3]] - a = AnnotationSet(lst) - # (c1) inter (c2) == (some new c) - c = a.merge(c1, c2) - self.failIf(a.isshared(c, c1)) - self.failIf(a.isshared(c, c2)) # maybe not needed, but we check that - self.failIf(a.isshared(c1, c2)) - lst += [ANN.type[c, c3], - ANN.immutable[c]] - self.assertSameSet(a, lst) - - def test_merge_mutable_ex(self): - lst = [ANN.add[c1, c2, c2], - ANN.neg[c2, c1], - ANN.add[c3, c2, c2], - ANN.immutable[c2]] - a = AnnotationSet(lst) - # (c1) inter (c3) == (c1 shared with c3) - c = a.merge(c1, c3) - self.assertSameCells(a, c, c1, c3) - self.assertSameSet(a, [lst[0], lst[3]]) - self.assertSameSet(a, [lst[2], lst[3]]) - - def test_merge_immutable_ex(self): - lst = [ANN.add[c1, c2, c2], - ANN.neg[c2, c1], - ANN.add[c3, c2, c2], - ANN.immutable[c1], - ANN.immutable[c2], - ANN.immutable[c3]] - a = AnnotationSet(lst) + a1 = annset(ANN.len, c1, c2, + ANN.immutable, c1, + ANN.len, c3, c2, + ANN.immutable, c3, + ANN.type, c1, list, + ANN.type, c2, str) # (c1) inter (c3) == (some new c) - c = a.merge(c1, c3) - self.failIf(a.isshared(c, c1)) - self.failIf(a.isshared(c, c3)) - self.failIf(a.isshared(c1, c3)) - lst += [ANN.add[c, c2, c2], - ANN.immutable[c]] - self.assertSameSet(a, lst) - -## def dont_test_merge_mutable_ex(self): -## # This test is expected to fail at this point because the algorithms -## # are not 100% theoretically correct, but probably quite good and -## # clear enough right now. In theory in the intersection below -## # 'add' should be kept. In practice the extra 'c3' messes things -## # up. I can only think about much-more-obscure algos to fix that. -## lst = [ANN.add', [c1, c3], c2), -## ANN.neg', [c2], c1), -## ANN.add', [c3, c3], c2), -## ANN.immutable', [], c2)] -## a = AnnotationHeap(lst) -## # (c1) inter (c3) == (c1 shared with c3) -## c = a.merge(c1, c3) -## self.assertEquals(c, c1) -## self.assertEquals(c, c3) -## self.assertEquals(c1, c3) -## self.assertSameSet(a, [lst[0], lst[3]]) -## self.assertSameSet(a, [lst[2], lst[3]]) - -## def dont_test_merge_immutable_ex(self): -## # Disabled -- same as above. -## lst = [ANN.add', [c1, c3], c2), -## ANN.neg', [c2], c1), -## ANN.add', [c3, c3], c2), -## ANN.immutable', [], c1), -## ANN.immutable', [], c2), -## ANN.immutable', [], c3)] -## a = AnnotationHeap(lst) -## # (c1) inter (c3) == (some new c4) -## c = a.merge(c1, c3) -## self.failIfEqual(c, c1) -## self.failIfEqual(c, c3) -## lst += [ANN.add', [c, c3], c2), -## ANN.immutable', [], c)] -## self.assertSameSet(a, lst) - - def test_set_kill(self): - lst = [ - ANN.add[c1, c3, c2], - ANN.type[c1, c4], - ANN.constant(int)[c4], - ] - a = AnnotationSet(lst) - a.set(ANN.type[c1, c3]) - lst += [ANN.type[c1, c3]] - self.assertSameSet(a, lst) - - a.kill(lst[0]) - del lst[0] - self.assertSameSet(a, lst) - - def test_type(self): - lst = [ - ANN.add[c1, c3, c2], - ANN.type[c1, c4], - ANN.constant(int)[c4], - ] - a = AnnotationSet(lst) - self.assert_(a.checktype(c1, int)) - self.assert_(a.checktype(c1, (int, long))) - self.failIf(a.checktype(c1, str)) - a.settype(c2, str) - self.assert_(a.query(ANN.type[c2, QUERYARG], - ANN.constant(str)[QUERYARG])) - - def test_delete(self): - lst = [ - ANN.add[c1, c3, c2], - ANN.type[c1, c4], - ANN.constant(int)[c4], - ] - a = AnnotationSet(lst) - a.delete(ANN.add[c1, c3, ...]) - self.assertSameSet(a, lst[1:]) - - def test_get_del(self): - lst = [ - ANN.add[c1, c3, c2], - ANN.type[c1, c4], - ANN.constant(int)[c4], - ] - a = AnnotationSet(lst) - c = a.get_del(ANN.add[c1, c3, QUERYARG]) - self.assertSameCells(a, c, c2) - self.assertSameSet(a, lst[1:]) + c = a1.merge(c1, c3) + a2 = annset(ANN.len, c1, c2, + ANN.immutable, c1, + ANN.len, c3, c2, + ANN.immutable, c3, + ANN.type, c1, list, + ANN.type, c2, str, + ANN.len, c, c2, + ANN.immutable, c) + self.assertSameSet(a1, a2) + + def test_recursive_merge(self): + a1 = annset(ANN.tupleitem[2], c1, c2, + ANN.immutable, c1, + ANN.type, c2, list, + ANN.listitems, c2, c3, + ANN.type, c3, int, + ANN.immutable, c3, + ANN.tupleitem[2], c5, c6, + ANN.immutable, c5, + ANN.type, c6, list, + ANN.listitems, c6, c7, + ANN.type, c7, float, + ANN.immutable, c7) + c9 = a1.merge(c1, c5) + c10 = a1.get(ANN.tupleitem[2], c9) + c11 = a1.get(ANN.listitems, c10) + self.assertSameCells(a1, c2, c6, c10) + + a2 = annset(ANN.tupleitem[2], c1, c2, + ANN.immutable, c1, + ANN.type, c3, int, + ANN.immutable, c3, + ANN.tupleitem[2], c5, c6, + ANN.immutable, c5, + ANN.type, c7, float, + ANN.immutable, c7, + + ANN.tupleitem[2], c9, c10, + ANN.immutable, c9, + ANN.type, c10, list, + ANN.listitems, c10, c11, + ANN.immutable, c11, + links=[c2,c10,c6,c10]) + self.assertSameSet(a1, a2) + + def test_settype(self): + a = annset() + a.settype(c1, int) + a.settype(c2, list) + self.assertSameSet(a, + annset(ANN.type, c1, int, + ANN.immutable, c1, + ANN.type, c2, list)) + + def test_copytype(self): + a = annset(ANN.type, c1, int, + ANN.immutable, c1, + ANN.type, c2, list) + a.copytype(c1, c3) + a.copytype(c2, c4) + self.assertSameSet(a, + annset(ANN.type, c1, int, + ANN.immutable, c1, + ANN.type, c2, list, + ANN.type, c3, int, + ANN.immutable, c3, + ANN.type, c4, list)) if __name__ == '__main__': From hpk at codespeak.net Thu Dec 18 21:36:48 2003 From: hpk at codespeak.net (hpk at codespeak.net) Date: Thu, 18 Dec 2003 21:36:48 +0100 (MET) Subject: [pypy-svn] rev 2537 - pypy/trunk/src/pypy/tool Message-ID: <20031218203648.EE5815A4F8@thoth.codespeak.net> Author: hpk Date: Thu Dec 18 21:36:48 2003 New Revision: 2537 Modified: pypy/trunk/src/pypy/tool/traceop.py Log: small test updates for the traceop utility Modified: pypy/trunk/src/pypy/tool/traceop.py ============================================================================== --- pypy/trunk/src/pypy/tool/traceop.py (original) +++ pypy/trunk/src/pypy/tool/traceop.py Thu Dec 18 21:36:48 2003 @@ -6,6 +6,7 @@ from pypy.objspace.trace import TraceObjSpace from pypy.objspace.trivial import TrivialObjSpace +from pypy.objspace.std import StdObjSpace from pypy.interpreter.gateway import app2interp @@ -38,7 +39,7 @@ elif isinstance(event, trace.CallBegin): info = event.callinfo if info.name in operations: - print info.name, info.args, info.kwargs + print info.name, info.args # , info.kwargs else: pass @@ -47,17 +48,17 @@ def app_test(): - #a = 1 - range(1) - #b = [1,2,3,4,5,6,7,8,9,10] - #for ii in b: - # a += ii + a = 1 + b = [1,2,3,4,5,6,7,8,9,10] + for ii in b: + a += ii - #return "Hello World" + return "Hello World" def test(): - space = TrivialObjSpace() + #space = TrivialObjSpace() + space = StdObjSpace() funcres, traceres = trace_function(space, app_test) print "function result -->", funcres From hpk at codespeak.net Fri Dec 19 10:32:39 2003 From: hpk at codespeak.net (hpk at codespeak.net) Date: Fri, 19 Dec 2003 10:32:39 +0100 (MET) Subject: [pypy-svn] rev 2538 - pypy/trunk/src/pypy/translator/test Message-ID: <20031219093239.E8A5E5A8C2@thoth.codespeak.net> Author: hpk Date: Fri Dec 19 10:32:38 2003 New Revision: 2538 Modified: pypy/trunk/src/pypy/translator/test/test_cltrans.py Log: a try to make looking for lisp less verbose at least on unix/linux Modified: pypy/trunk/src/pypy/translator/test/test_cltrans.py ============================================================================== --- pypy/trunk/src/pypy/translator/test/test_cltrans.py (original) +++ pypy/trunk/src/pypy/translator/test/test_cltrans.py Fri Dec 19 10:32:38 2003 @@ -24,7 +24,10 @@ return None def is_on_path(name): - return os.system("which %s >/dev/null" % name) == 0 + try: + return os.system("which %s >/dev/null 2>/dev/null" % name) == 0 + except OSError: + pass global_cl = get_cl() From pmaupin at codespeak.net Fri Dec 19 10:41:38 2003 From: pmaupin at codespeak.net (pmaupin at codespeak.net) Date: Fri, 19 Dec 2003 10:41:38 +0100 (MET) Subject: [pypy-svn] rev 2539 - pypy/trunk/src/pypy/interpreter Message-ID: <20031219094138.D008B5A8C2@thoth.codespeak.net> Author: pmaupin Date: Fri Dec 19 10:41:38 2003 New Revision: 2539 Modified: pypy/trunk/src/pypy/interpreter/function.py pypy/trunk/src/pypy/interpreter/py.py Log: Fixed typo in raising error for unknown keyword arguments Modified: pypy/trunk/src/pypy/interpreter/function.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/function.py (original) +++ pypy/trunk/src/pypy/interpreter/function.py Fri Dec 19 10:41:38 2003 @@ -92,7 +92,7 @@ # XXX this doesn't check that the keys of kwargs are strings scope_w.append(w_kwargs) elif space.is_true(w_kwargs): - self.raise_unknown_kwds(w_kwds) + self.raise_argerr_unknown_kwds(w_kwds) return scope_w # helper functions to build error message for the above Modified: pypy/trunk/src/pypy/interpreter/py.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/py.py (original) +++ pypy/trunk/src/pypy/interpreter/py.py Fri Dec 19 10:41:38 2003 @@ -38,6 +38,7 @@ except error.PyPyError, pypyerr: pypyerr.operationerr.print_detailed_traceback(pypyerr.space) elif args: + args = args[0].split()+args[1:] try: main.run_file(args[0], space) except error.PyPyError, pypyerr: From arigo at codespeak.net Fri Dec 19 10:54:01 2003 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 19 Dec 2003 10:54:01 +0100 (MET) Subject: [pypy-svn] rev 2540 - in pypy/trunk/src/pypy/annotation: . test Message-ID: <20031219095401.8627D5A8C2@thoth.codespeak.net> Author: arigo Date: Fri Dec 19 10:54:00 2003 New Revision: 2540 Modified: pypy/trunk/src/pypy/annotation/annset.py pypy/trunk/src/pypy/annotation/test/test_annset.py Log: Fixed merge() to deal with immutables-that-are-not-really-changed. Modified: pypy/trunk/src/pypy/annotation/annset.py ============================================================================== --- pypy/trunk/src/pypy/annotation/annset.py (original) +++ pypy/trunk/src/pypy/annotation/annset.py Fri Dec 19 10:54:00 2003 @@ -8,6 +8,10 @@ return False mostgeneralvalue = MostGeneralValue() +class ImpossibleValue(Exception): + pass +impossiblevalue = ImpossibleValue() + class About: def __init__(self): @@ -44,8 +48,8 @@ def leave(self): self.inblock = None - def isshared(self, someval1, someval2): - return self.about[someval1] is self.about[someval2] + def isshared(self, val1, val2): + return self.about.get(val1, val1) == self.about.get(val2, val2) def __repr__(self): # debugging lines = ['===== AnnotationSet ====='] @@ -61,15 +65,15 @@ return '\n'.join(lines) def get(self, predicate, subject): - about = self._about(subject) - result = about.annotations.get(predicate) - if result: - answer, dependencies = result - if self.inblock: - dependencies[self.inblock] = True - return answer - else: - return mostgeneralvalue + if subject is not mostgeneralvalue: + about = self._about(subject) + result = about.annotations.get(predicate) + if result: + answer, dependencies = result + if self.inblock: + dependencies[self.inblock] = True + return answer + return mostgeneralvalue def _about(self, somevalue): try: @@ -77,6 +81,8 @@ except KeyError: if somevalue is mostgeneralvalue: raise ValueError, "Unexpected mostgeneralvalue" + if isinstance(somevalue, ImpossibleValue): + raise somevalue about = self.about[somevalue] = About() about.subjects[somevalue] = True return about @@ -100,8 +106,14 @@ def merge(self, oldvalue, newvalue): """Update the heap to account for the merging of oldvalue and newvalue. Return the merged somevalue.""" + if isinstance(newvalue, ImpossibleValue): + return oldvalue + if isinstance(oldvalue, ImpossibleValue): + return newvalue if newvalue is mostgeneralvalue or oldvalue is mostgeneralvalue: return mostgeneralvalue + if self.isshared(oldvalue, newvalue): + return oldvalue # build an About set that is the intersection of the two incoming ones about1 = self._about(oldvalue) @@ -128,17 +140,24 @@ # modify the annotations about it. If one of them is mutable, # then we must replace its About set with 'about3'. invalidatedblocks = {} - for value, about in [(oldvalue, about1), (newvalue, about2)]: - if ANN.immutable not in about.annotations: - # find all annotations that are removed or generalized - for pred, (someval, deps) in about.annotations.items(): - if (pred not in about3.annotations or - about3.annotations[pred][0] != someval): - invalidatedblocks.update(deps) + for about in [about1, about2]: + # find all annotations that are removed or generalized + removedannotations = [] + for pred, (someval, deps) in about.annotations.items(): + if (pred in about3.annotations and + self.isshared(about3.annotations[pred][0], someval)): + continue # unmodified annotation + removedannotations.append(deps) + # if the existing 'value' is mutable, or if nothing has been + # removed, then we identify (by sharing) the 'value' and the + # new 'about3'. + if not removedannotations or ANN.immutable not in about.annotations: # patch 'value' to use the new 'about3'. for sharedvalue in about.subjects: # this includes 'value' self.about[sharedvalue] = about3 about3.subjects[sharedvalue] = True + for deps in removedannotations: + invalidatedblocks.update(deps) if not about3.subjects: value3 = SomeValue() Modified: pypy/trunk/src/pypy/annotation/test/test_annset.py ============================================================================== --- pypy/trunk/src/pypy/annotation/test/test_annset.py (original) +++ pypy/trunk/src/pypy/annotation/test/test_annset.py Fri Dec 19 10:54:00 2003 @@ -101,38 +101,57 @@ self.assertSameCells(a1, c, c1, c3) self.assertSameSet(a1, a2) - def test_merge_immutable1(self): + def test_merge_same_immutables(self): a1 = annset(ANN.len, c1, c2, ANN.immutable, c1, ANN.len, c3, c2, ANN.immutable, c3) - # (c1) inter (c3) == (some new c) + # (c1) inter (c3) == (c1 and c3) c = a1.merge(c1, c3) - a2 = annset(ANN.len, c1, c2, + self.assertSameCells(a1, c, c1, c3) + a2 = annset(ANN.len, c, c2, + ANN.immutable, c, + links=[c1,c,c3,c]) + self.assertSameSet(a1, a2) + + def test_merge_generalize_one_immutable(self): + a1 = annset(ANN.len, c1, c2, ANN.immutable, c1, + ANN.type, c1, list, ANN.len, c3, c2, ANN.immutable, c3, + ANN.type, c2, str) + # (c1) inter (c3) == (c3) + c = a1.merge(c1, c3) + self.assertSameCells(a1, c, c3) + a2 = annset(ANN.len, c1, c2, + ANN.immutable, c1, + ANN.type, c1, list, ANN.len, c, c2, - ANN.immutable, c) + ANN.immutable, c, + ANN.type, c2, str, + links=[c3,c]) self.assertSameSet(a1, a2) - def test_merge_immutable2(self): + def test_merge_generalize_both_immutables(self): a1 = annset(ANN.len, c1, c2, ANN.immutable, c1, + ANN.type, c1, list, ANN.len, c3, c2, ANN.immutable, c3, - ANN.type, c1, list, + ANN.type, c3, tuple, ANN.type, c2, str) - # (c1) inter (c3) == (some new c) + # (c1) inter (c3) == (a more general c) c = a1.merge(c1, c3) a2 = annset(ANN.len, c1, c2, ANN.immutable, c1, + ANN.type, c1, list, ANN.len, c3, c2, ANN.immutable, c3, - ANN.type, c1, list, - ANN.type, c2, str, + ANN.type, c3, tuple, ANN.len, c, c2, - ANN.immutable, c) + ANN.immutable, c, + ANN.type, c2, str) self.assertSameSet(a1, a2) def test_recursive_merge(self): @@ -151,23 +170,20 @@ c9 = a1.merge(c1, c5) c10 = a1.get(ANN.tupleitem[2], c9) c11 = a1.get(ANN.listitems, c10) + self.assertSameCells(a1, c1, c5, c9) self.assertSameCells(a1, c2, c6, c10) - a2 = annset(ANN.tupleitem[2], c1, c2, - ANN.immutable, c1, - ANN.type, c3, int, - ANN.immutable, c3, - ANN.tupleitem[2], c5, c6, - ANN.immutable, c5, - ANN.type, c7, float, - ANN.immutable, c7, - - ANN.tupleitem[2], c9, c10, + a2 = annset(ANN.tupleitem[2], c9, c10, ANN.immutable, c9, ANN.type, c10, list, ANN.listitems, c10, c11, ANN.immutable, c11, - links=[c2,c10,c6,c10]) + # old remaining stuff + ANN.type, c3, int, + ANN.immutable, c3, + ANN.type, c7, float, + ANN.immutable, c7, + links=[c1,c9, c5,c9, c2,c10, c6,c10]) self.assertSameSet(a1, a2) def test_settype(self): From hpk at codespeak.net Fri Dec 19 11:05:57 2003 From: hpk at codespeak.net (hpk at codespeak.net) Date: Fri, 19 Dec 2003 11:05:57 +0100 (MET) Subject: [pypy-svn] rev 2541 - in pypy/trunk/src/pypy: objspace objspace/test tool Message-ID: <20031219100557.2CF495A8C2@thoth.codespeak.net> Author: hpk Date: Fri Dec 19 11:05:56 2003 New Revision: 2541 Modified: pypy/trunk/src/pypy/objspace/test/test_traceobjspace.py pypy/trunk/src/pypy/objspace/trace.py pypy/trunk/src/pypy/objspace/trivial.py pypy/trunk/src/pypy/tool/pydis.py pypy/trunk/src/pypy/tool/traceop.py Log: - fxied traceop and traceobjspace and ... - wrote trivial.round - fixed some tests good morning :-) Modified: pypy/trunk/src/pypy/objspace/test/test_traceobjspace.py ============================================================================== --- pypy/trunk/src/pypy/objspace/test/test_traceobjspace.py (original) +++ pypy/trunk/src/pypy/objspace/test/test_traceobjspace.py Fri Dec 19 11:05:56 2003 @@ -34,7 +34,7 @@ pass res = self.perform_trace(app_f) disresult = pydis.pydis(app_f) - self.assertEquals(disresult._bytecodes, list(res.getbytecodes())) + self.assertEquals(disresult.bytecodes, list(res.getbytecodes())) #self.assertEquals(len(list(res.getoperations())), 0) def test_some_builtin(self): @@ -42,7 +42,7 @@ filter(None, []) # mapglobals() # ("c") res = self.perform_trace(app_f) disresult = pydis.pydis(app_f) - self.assertEquals(disresult._bytecodes, list(res.getbytecodes())) + self.assertEquals(disresult.bytecodes, list(res.getbytecodes())) #self.assertEquals(len(list(res.getoperations())), 0) def test_trace_oneop(self): @@ -51,7 +51,7 @@ w = self.space.wrap res = self.perform_trace(app_f) disresult = pydis.pydis(app_f) - self.assertEquals(disresult._bytecodes, list(res.getbytecodes())) + self.assertEquals(disresult.bytecodes, list(res.getbytecodes())) ops = list(res.getoperations()) self.assert_(len(ops) > 0) #op = ops[0] Modified: pypy/trunk/src/pypy/objspace/trace.py ============================================================================== --- pypy/trunk/src/pypy/objspace/trace.py (original) +++ pypy/trunk/src/pypy/objspace/trace.py Fri Dec 19 11:05:56 2003 @@ -12,9 +12,12 @@ # __________________________________________________________________________ class ExecBytecode: + """ bytecode trace. """ def __init__(self, frame): - self.frame = frame + self.frame = frame + self.code = frame.code self.index = frame.next_instr + #assert self.index < len(frame.code.co_code) class EnterFrame: def __init__(self, frame): @@ -142,9 +145,9 @@ def getdisresult(self, frame, _cache = {}): """ return (possibly cached) pydis result for the given frame. """ try: - return _cache[id(frame)] + return _cache[id(frame.code)] except KeyError: - res = _cache[id(frame)] = pydis.pydis(frame.code) + res = _cache[id(frame.code)] = pydis.pydis(frame.code) assert res is not None return res Modified: pypy/trunk/src/pypy/objspace/trivial.py ============================================================================== --- pypy/trunk/src/pypy/objspace/trivial.py (original) +++ pypy/trunk/src/pypy/objspace/trivial.py Fri Dec 19 11:05:56 2003 @@ -375,6 +375,9 @@ def int(self, ob): return int(ob) + def round(self, *args): + return round(*args) + for m in ObjSpace.MethodTable: if not hasattr(TrivialObjSpace, m[0]): print m[0] # this should raise something Modified: pypy/trunk/src/pypy/tool/pydis.py ============================================================================== --- pypy/trunk/src/pypy/tool/pydis.py (original) +++ pypy/trunk/src/pypy/tool/pydis.py Fri Dec 19 11:05:56 2003 @@ -69,25 +69,26 @@ """ def __init__(self, code): self.code = code - self._bytecodes = [] + self.bytecodes = [] def append(self, bytecodeindex, oparg, lineno): """ append bytecode anaylsis information ...""" bc = Bytecode(self, bytecodeindex, oparg, lineno) - self._bytecodes.append(bc) + self.bytecodes.append(bc) def getbytecode(self, index): """ return bytecode instance matching the given index. """ - for bytecode in self._bytecodes: + for bytecode in self.bytecodes: if bytecode.index == index: return bytecode - raise ValueError, "no bytecode found on index %s" % index + raise ValueError, "no bytecode found on index %s in code \n%s" % ( + index, pydis(self.code)) def format(self): lastlineno = -1 labels = findlabels(self.code.co_code) lines = [] - for bc in self._bytecodes: + for bc in self.bytecodes: l = [] if bc.lineno != lastlineno: lastlineno = bc.lineno Modified: pypy/trunk/src/pypy/tool/traceop.py ============================================================================== --- pypy/trunk/src/pypy/tool/traceop.py (original) +++ pypy/trunk/src/pypy/tool/traceop.py Fri Dec 19 11:05:56 2003 @@ -28,40 +28,68 @@ traceres = tspace.getresult() return funcres, traceres +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 def trace_function(space, fn, *arg, **kwds): funcres, traceres = perform_trace(space, fn, *arg, **kwds) - disresult = pydis.pydis(fn) - + indentor = ' ' + indent = ' ' + lastframe = None for event in traceres.getevents(): + if isinstance(event, trace.EnterFrame): + lastframe = event.frame + if isinstance(event, trace.ExecBytecode): - print event.index, " ", disresult.getbytecode(event.index) + disresult = getdisresult(event.frame) + print indent, event.index, " ", disresult.getbytecode(event.index) + lastframe = event.frame + elif isinstance(event, trace.CallBegin): info = event.callinfo if info.name in operations: - print info.name, info.args # , info.kwargs + print indent, " " * 40, info.name, repr_args(lastframe, info.args) + indent += indentor + elif isinstance(event, trace.CallFinished): + indent = indent[:-len(indentor)] else: pass - - return funcres, traceres +def repr_args(frame, args): + l = [] + + space = frame and frame.space or None + for arg in args: + if frame and space.is_true(space.is_(arg, frame.w_globals)): + l.append('w_globals') + elif frame and space.is_true(space.is_(arg, space.w_builtins)): + l.append('w_builtins') + else: + l.append(repr(arg) [:50]) + return ", ".join(l) def app_test(): a = 1 - b = [1,2,3,4,5,6,7,8,9,10] - for ii in b: - a += ii - + for i in range(10): + print i + return "Hello World" - def test(): - #space = TrivialObjSpace() - space = StdObjSpace() + space = TrivialObjSpace() + #space = StdObjSpace() funcres, traceres = trace_function(space, app_test) print "function result -->", funcres - test() From alex at codespeak.net Fri Dec 19 11:11:01 2003 From: alex at codespeak.net (alex at codespeak.net) Date: Fri, 19 Dec 2003 11:11:01 +0100 (MET) Subject: [pypy-svn] rev 2542 - pypy/trunk/src/pypy/module/test Message-ID: <20031219101101.A36E15A8C2@thoth.codespeak.net> Author: alex Date: Fri Dec 19 11:11:01 2003 New Revision: 2542 Modified: pypy/trunk/src/pypy/module/test/test_builtin.py Log: ensure test_dir works with trivial as well as standard objspace by ignoring all names starting with underscore in dir results Modified: pypy/trunk/src/pypy/module/test/test_builtin.py ============================================================================== --- pypy/trunk/src/pypy/module/test/test_builtin.py (original) +++ pypy/trunk/src/pypy/module/test/test_builtin.py Fri Dec 19 11:11:01 2003 @@ -40,17 +40,18 @@ return dir() def g(c=0, b=0, a=0): return dir() + def nosp(x): return [y for y in x if y[0]!='_'] self.assertEquals(f(), []) self.assertEquals(g(), ['a', 'b', 'c']) class X: pass - self.assertEquals(dir(X), ['__module__', ]) + self.assertEquals(nosp(dir(X)), nosp(['__module__', ])) class X: a = 23 - self.assertEquals(dir(X), ['__module__', 'a']) + self.assertEquals(nosp(dir(X)), nosp(['__module__', 'a'])) class X: a = 23 c = 45 b = 67 - self.assertEquals(dir(X), ['__module__', 'a', 'b', 'c']) + self.assertEquals(nosp(dir(X)), nosp(['__module__', 'a', 'b', 'c'])) def test_vars(self): def f(): From sschwarzer at codespeak.net Fri Dec 19 11:13:18 2003 From: sschwarzer at codespeak.net (sschwarzer at codespeak.net) Date: Fri, 19 Dec 2003 11:13:18 +0100 (MET) Subject: [pypy-svn] rev 2543 - pypy/trunk/src/pypy/tool Message-ID: <20031219101318.2B71A5A8C2@thoth.codespeak.net> Author: sschwarzer Date: Fri Dec 19 11:13:17 2003 New Revision: 2543 Modified: pypy/trunk/src/pypy/tool/newtest.py Log: Turned TestStatus objects into different TestResult classes. This version is still compatible with test cases derived from Python's unittest.TestCase . Modified: pypy/trunk/src/pypy/tool/newtest.py ============================================================================== --- pypy/trunk/src/pypy/tool/newtest.py (original) +++ pypy/trunk/src/pypy/tool/newtest.py Fri Dec 19 11:13:17 2003 @@ -13,33 +13,15 @@ # - perhaps we have to be able to compare TestResult and TestItem values # which were pickled (see -c option of current test_all.py) -class TestStatus: - def __init__(self, name, longstring, shortstring): - self.name = name - self.longstring = longstring - self.shortstring = shortstring - - def __str__(self): - return self.longstring - -# named constants for test result status values -SUCCESS = TestStatus('success', 'success', '.') -ERROR = TestStatus('error', 'ERROR', 'E') -FAILURE = TestStatus('failure', 'FAILURE', 'F') -IGNORED = TestStatus('ignored', 'ignored', 'i') -SKIPPED = TestStatus('skipped', 'skipped', 's') - - +# +# TestResult class family +# class TestResult: - """Represent the result of a run of a test item.""" + """Abstract class representing the outcome of a test.""" def __init__(self, item): self.item = item - # one of None, SUCCESS, ERROR, FAILURE, IGNORED, SKIPPED (see above) - self.status = None - # traceback object for errors and failures, else None + self.name = self.__class__.__name__ self.traceback = None - # formatted traceback (a string) - self.formatted_traceback = None def __eq__(self, other): """ @@ -47,10 +29,7 @@ Else, return False. """ # trivial case - if self is other: - return True - if (self.item is other.item) and (self.status == other.status) and \ - (self.formatted_traceback == other.formatted_traceback): + if (self is other) or (self.item is other.item): return True return False @@ -58,10 +37,28 @@ return not (self == other) def __hash__(self): - return id(self.item) ^ id(self.status) + return id(self.item) + +class Success(TestResult): + pass + +class Skipped(TestResult): + pass + +class Ignored(TestResult): + pass - def _setexception(self, statuscode): - self.status = statuscode + +class TestResultWithTraceback(TestResult): + def __init__(self, item): + TestResult.__init__(self, item) + self.setexception() + + def __eq__(self, other): + return TestResult.__eq__(self, other) and \ + self.formatted_traceback == other.formatted_traceback + + def setexception(self): self.excinfo = sys.exc_info() self.traceback = self.excinfo[2] # store formatted traceback @@ -71,7 +68,15 @@ # strip trailing newline self.formatted_traceback = output.getvalue().rstrip() +class Error(TestResultWithTraceback): + pass +class Failure(TestResultWithTraceback): + pass + +# +# other classes +# class TestItem: """Represent a single test method from a TestCase class.""" def __init__(self, module, cls, testmethod): @@ -134,10 +139,6 @@ # credit: adapted from Python's unittest.TestCase.run - # prepare result object - result = TestResult(self) - result.status = None - # prepare test case class and test method methodname = self.method.__name__ testobject = self.cls(methodname) @@ -152,22 +153,18 @@ testobject.setUp() except KeyboardInterrupt: raise - except test.TestSkip: - result.status = SKIPPED - return result except: - result._setexception(ERROR) - return result + return Error(self) try: testmethod() - result.status = SUCCESS - except AssertionError: - result._setexception(FAILURE) + result = Success(self) except KeyboardInterrupt: raise + except AssertionError: + result = Failure(self) except: - result._setexception(ERROR) + result = Error(self) try: testobject.tearDown() @@ -176,8 +173,8 @@ except: # if we already had an exception in the test method, # don't overwrite it - if result.status not in (ERROR, FAILURE): - result._setexception(ERROR) + if not isinstance(result, TestResultWithTraceback): + result = Error(self) finally: if posttest is not None: posttest(self) @@ -277,7 +274,9 @@ self.lastresults.setdefault(key, []).append(result) yield result - +# +# demonstrate test framework usage +# def main(skip_selftest=True): # possibly ignore dummy unit tests if skip_selftest: @@ -286,17 +285,17 @@ filterfunc = lambda m: True # collect tests ts = TestSuite() + print "Loading test modules ..." ts.initfromdir(autopath.pypydir, filterfunc=filterfunc) # iterate over tests and collect data for res in ts.testresults(): - if res.status == SUCCESS: + if res.traceback is None: continue print 79 * '-' print "%s.%s: %s" % (res.item.module.__name__, res.item.method.__name__, - res.status) - if res.traceback: - print - print res.formatted_traceback + res.name.upper()) + print + print res.formatted_traceback # emit a summary print 79 * '=' modules = ts.lastresults.keys() @@ -305,7 +304,9 @@ results = ts.lastresults[module] resultstring = '' for result in results: - resultstring += result.status.shortstring + statuschar = {Success: '.', Ignored: 'i', Skipped: 's', + Error: 'E', Failure: 'F'}[result.__class__] + resultstring += statuschar print "%s [%d] %s" % (module, len(results), resultstring) From sschwarzer at codespeak.net Fri Dec 19 11:17:42 2003 From: sschwarzer at codespeak.net (sschwarzer at codespeak.net) Date: Fri, 19 Dec 2003 11:17:42 +0100 (MET) Subject: [pypy-svn] rev 2544 - pypy/trunk/src/pypy/tool Message-ID: <20031219101742.74C005A8C2@thoth.codespeak.net> Author: sschwarzer Date: Fri Dec 19 11:17:41 2003 New Revision: 2544 Modified: pypy/trunk/src/pypy/tool/newtest.py Log: Copied unittest.TestCase and started to adapt it for our purposes. This version doesn't work as expected yet, and will also require changes to the existing test modules. Function main: Instead of the parameter skip_selftest reverse logic, away from double negation, to do_selftest . Modified: pypy/trunk/src/pypy/tool/newtest.py ============================================================================== --- pypy/trunk/src/pypy/tool/newtest.py (original) +++ pypy/trunk/src/pypy/tool/newtest.py Fri Dec 19 11:17:41 2003 @@ -4,7 +4,6 @@ import sys import cStringIO as StringIO import traceback -import unittest import vpath #TODO @@ -12,13 +11,126 @@ # - support TestItem.run with different object spaces # - perhaps we have to be able to compare TestResult and TestItem values # which were pickled (see -c option of current test_all.py) +# - add docstring to TestItem + +# +# custom TestCase class (adapted from Python's unittest module) +# +class TestCase: + """A class whose instances are single test cases. + + By default, the test code itself should be placed in a method named + 'runTest'. + + If the fixture may be used for many test cases, create as + many test methods as are needed. When instantiating such a TestCase + subclass, specify in the constructor arguments the name of the test method + that the instance is to execute. + + Test authors should subclass TestCase for their own tests. Construction + and deconstruction of the test's environment ('fixture') can be + implemented by overriding the 'setUp' and 'tearDown' methods respectively. + """ + def setUp(self): + "Hook method for setting up the test fixture before exercising it." + pass + + def tearDown(self): + "Hook method for deconstructing the test fixture after testing it." + pass + + def fail(self, msg=None): + """Fail immediately, with the given message.""" + raise Failure(msg=msg) + + def failIf(self, expr, msg=None): + """Fail the test if the expression is true.""" + if expr: + raise Failure(msg=msg) + + def failUnless(self, expr, msg=None): + """Fail the test unless the expression is true.""" + if not expr: + raise Failure(msg=msg) + + def failUnlessRaises(self, excClass, callableObj, *args, **kwargs): + """ + Fail unless an exception of class excClass is thrown + by callableObj when invoked with arguments args and keyword + arguments kwargs. If a different type of exception is + thrown, it will not be caught, and the test case will be + deemed to have suffered an error, exactly as for an + unexpected exception. + """ + try: + callableObj(*args, **kwargs) + except excClass: + return + else: + if hasattr(excClass,'__name__'): + excName = excClass.__name__ + else: + excName = str(excClass) + raise Failure(msg=excName) + + def failUnlessEqual(self, first, second, msg=None): + """ + Fail if the two objects are unequal as determined by the '==' + operator. + """ + if not first == second: + raise Failure(msg=(msg or '%s != %s' % (`first`, `second`))) + + def failIfEqual(self, first, second, msg=None): + """ + Fail if the two objects are equal as determined by the '==' + operator. + """ + if first == second: + raise Failure(msg=(msg or '%s == %s' % (`first`, `second`))) + + def failUnlessAlmostEqual(self, first, second, places=7, msg=None): + """ + Fail if the two objects are unequal as determined by their + difference rounded to the given number of decimal places + (default 7) and comparing to zero. + + Note that decimal places (from zero) is usually not the same + as significant digits (measured from the most signficant digit). + """ + if round(second-first, places) != 0: + raise Failure(msg=(msg or '%s != %s within %s places' % + (`first`, `second`, `places`))) + + def failIfAlmostEqual(self, first, second, places=7, msg=None): + """ + Fail if the two objects are equal as determined by their + difference rounded to the given number of decimal places + (default 7) and comparing to zero. + + Note that decimal places (from zero) is usually not the same + as significant digits (measured from the most signficant digit). + """ + if round(second-first, places) == 0: + raise Failure(msg=(msg or '%s == %s within %s places' % + (`first`, `second`, `places`))) + + # aliases + assertEqual = assertEquals = failUnlessEqual + assertNotEqual = assertNotEquals = failIfEqual + assertAlmostEqual = assertAlmostEquals = failUnlessAlmostEqual + assertNotAlmostEqual = assertNotAlmostEquals = failIfAlmostEqual + assertRaises = failUnlessRaises + assert_ = failUnless # # TestResult class family # -class TestResult: +class TestResult(Exception): """Abstract class representing the outcome of a test.""" - def __init__(self, item): + def __init__(self, msg="", item=None): + Exception.__init__(self, msg) + self.msg = msg self.item = item self.name = self.__class__.__name__ self.traceback = None @@ -50,7 +162,7 @@ class TestResultWithTraceback(TestResult): - def __init__(self, item): + def __init__(self, msg='', item=None): TestResult.__init__(self, item) self.setexception() @@ -139,10 +251,8 @@ # credit: adapted from Python's unittest.TestCase.run - # prepare test case class and test method - methodname = self.method.__name__ - testobject = self.cls(methodname) - testmethod = getattr(testobject, methodname) + testobject = self.cls() + testmethod = getattr(testobject, self.method.__name__) if pretest is not None: pretest(self) @@ -153,28 +263,32 @@ testobject.setUp() except KeyboardInterrupt: raise - except: - return Error(self) + except TestResult, result: + # reconstruct TestResult object, implicitly set exception + result = result.__class__(msg=result.msg, item=self) + except Exception, exc: + return Error(msg=str(exc), item=self) try: testmethod() - result = Success(self) + result = Success(msg='success', item=self) except KeyboardInterrupt: raise - except AssertionError: - result = Failure(self) - except: - result = Error(self) + except TestResult, result: + # reconstruct TestResult object, implicitly set exception + result = result.__class__(msg=result.msg, item=self) + except Exception, exc: + result = Error(msg=str(exc), item=self) try: testobject.tearDown() except KeyboardInterrupt: raise - except: + except Exception, exc: # if we already had an exception in the test method, # don't overwrite it - if not isinstance(result, TestResultWithTraceback): - result = Error(self) + if result.traceback is None: + result = Error(msg=str(exc), item=self) finally: if posttest is not None: posttest(self) @@ -211,9 +325,11 @@ def _items_from_module(self, module): """Return a list of TestItems read from the given module.""" items = [] - # scan the module for classes derived from unittest.TestCase + # scan the module for classes derived from TestCase for obj in vars(module).values(): - if inspect.isclass(obj) and issubclass(obj, unittest.TestCase): + if inspect.isclass(obj): + print obj, id(obj) + if inspect.isclass(obj) and isinstance(obj, TestCase): # we found a TestCase class, now scan it for test methods for obj2 in vars(obj).values(): # inspect.ismethod doesn't seem to work here @@ -234,6 +350,7 @@ If recursive is true, which is the default, find all test modules by scanning the start directory recursively. """ + self.items = [] dirname = vpath.getlocal(dirname) def testfilefilter(path): @@ -270,6 +387,7 @@ self.lastresults = {} for item in self.items: result = item.run() + print result.formatted_traceback key = classify(result) self.lastresults.setdefault(key, []).append(result) yield result @@ -277,16 +395,18 @@ # # demonstrate test framework usage # -def main(skip_selftest=True): +def main(do_selftest=False): # possibly ignore dummy unit tests - if skip_selftest: - filterfunc = lambda m: m.find("pypy.tool.testdata.") == -1 - else: + if do_selftest: filterfunc = lambda m: True + else: + filterfunc = lambda m: m.find("pypy.tool.testdata.") == -1 # collect tests ts = TestSuite() print "Loading test modules ..." ts.initfromdir(autopath.pypydir, filterfunc=filterfunc) + print "Loading test modules ..." + ts.initfromdir('.', filterfunc=filterfunc) # iterate over tests and collect data for res in ts.testresults(): if res.traceback is None: @@ -311,4 +431,4 @@ if __name__ == '__main__': - main() + main(do_selftest=True) From pmaupin at codespeak.net Fri Dec 19 11:30:38 2003 From: pmaupin at codespeak.net (pmaupin at codespeak.net) Date: Fri, 19 Dec 2003 11:30:38 +0100 (MET) Subject: [pypy-svn] rev 2545 - pypy/trunk/src/pypy/module Message-ID: <20031219103038.6A6545A8C2@thoth.codespeak.net> Author: pmaupin Date: Fri Dec 19 11:30:37 2003 New Revision: 2545 Modified: pypy/trunk/src/pypy/module/builtin.py Log: Propagate compile() TypeError and ValueError to app level Modified: pypy/trunk/src/pypy/module/builtin.py ============================================================================== --- pypy/trunk/src/pypy/module/builtin.py (original) +++ pypy/trunk/src/pypy/module/builtin.py Fri Dec 19 11:30:37 2003 @@ -214,7 +214,7 @@ def compile(self, w_str, w_filename, w_startstr, w_supplied_flags=None, w_dont_inherit=None): space = self.space - str = space.unwrap(w_str) + str_ = space.unwrap(w_str) filename = space.unwrap(w_filename) startstr = space.unwrap(w_startstr) if w_supplied_flags is None: @@ -230,10 +230,18 @@ if dont_inherit is None: dont_inherit = 0 - #print (str, filename, startstr, supplied_flags, dont_inherit) + #print (str_, filename, startstr, supplied_flags, dont_inherit) # XXX we additionally allow GENERATORS because compiling some builtins # requires it. doesn't feel quite right to do that here. - c = cpy_builtin.compile(str, filename, startstr, supplied_flags|4096, dont_inherit) + try: + c = cpy_builtin.compile(str_, filename, startstr, supplied_flags|4096, dont_inherit) + # It would be nice to propagate all exceptions to app level, + # but here we only propagate the 'usual' ones, until we figure + # out how to do it generically. + except ValueError,e: + raise OperationError(space.w_ValueError,space.wrap(str(e))) + except TypeError,e: + raise OperationError(space.w_TypeError,space.wrap(str(e))) from pypy.interpreter.pycode import PyCode return space.wrap(PyCode()._from_code(c)) From arigo at codespeak.net Fri Dec 19 11:37:27 2003 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 19 Dec 2003 11:37:27 +0100 (MET) Subject: [pypy-svn] rev 2546 - in pypy/trunk/src/pypy: annotation annotation/test translator Message-ID: <20031219103727.39EC75A8C2@thoth.codespeak.net> Author: arigo Date: Fri Dec 19 11:37:26 2003 New Revision: 2546 Modified: pypy/trunk/src/pypy/annotation/annset.py pypy/trunk/src/pypy/annotation/model.py pypy/trunk/src/pypy/annotation/test/test_annset.py pypy/trunk/src/pypy/translator/annrpython.py pypy/trunk/src/pypy/translator/translator.py Log: The concept seems to work. Now proceeding to fix the rest of translator/*.py. Modified: pypy/trunk/src/pypy/annotation/annset.py ============================================================================== --- pypy/trunk/src/pypy/annotation/annset.py (original) +++ pypy/trunk/src/pypy/annotation/annset.py Fri Dec 19 11:37:26 2003 @@ -1,6 +1,6 @@ from __future__ import generators import types -from model import SomeValue, ANN, immutable_types, debugname +from model import SomeValue, ANN, immutable_types class MostGeneralValue: @@ -20,7 +20,7 @@ self.annotations = {} self.subjects = {} # set of SomeValues we are about def __repr__(self): # debugging - subjs = [debugname(c) for c in self.subjects] + subjs = [repr(c) for c in self.subjects] subjs.sort() lines = ['About %s:' % ' and '.join(subjs)] annotations = [(str(pred), value) @@ -87,7 +87,7 @@ about.subjects[somevalue] = True return about - def set(self, predicate, subject, answer=True): + def set(self, predicate, subject, answer): about = self._about(subject) if predicate in about.annotations: raise ValueError, "There is already an annotation for %r" % subject @@ -103,6 +103,15 @@ for block in deps: self.callback(block) + def generalize(self, predicate, subject, otherpossibleanswer): + """Generalize the given annotation to also account for the given + answer.""" + oldanswer = self.get(predicate, subject) + newanswer = self.merge(oldanswer, otherpossibleanswer) + if not self.isshared(oldanswer, newanswer): + self.kill(predicate, subject) + self.set(predicate, subject, newanswer) + def merge(self, oldvalue, newvalue): """Update the heap to account for the merging of oldvalue and newvalue. Return the merged somevalue.""" @@ -170,10 +179,14 @@ return about3.subjects.iterkeys().next() + def checktype(self, someval, checktype): + knowntype = self.get(ANN.type, someval) + return knowntype and issubclass(knowntype, checktype) + def settype(self, someval, knowntype): self.set(ANN.type, someval, knowntype) if knowntype in immutable_types: - self.set(ANN.immutable, someval) + self.set(ANN.immutable, someval, True) def copytype(self, oldcell, newcell): self.set(ANN.type, newcell, self.get(ANN.type, oldcell)) Modified: pypy/trunk/src/pypy/annotation/model.py ============================================================================== --- pypy/trunk/src/pypy/annotation/model.py (original) +++ pypy/trunk/src/pypy/annotation/model.py Fri Dec 19 11:37:26 2003 @@ -2,7 +2,7 @@ class SomeValue: def __repr__(self): - return debugname(self) + return debugname(self, 'SV') class Predicate: def __init__(self, debugname): @@ -26,16 +26,17 @@ len = Predicate('len') listitems = Predicate('listitems') tupleitem = PredicateFamily('tupleitem') + const = Predicate('const') type = Predicate('type') immutable = Predicate('immutable') -def debugname(someval, _seen = {}): +def debugname(someval, prefix, _seen = {}): """ return a simple name for a SomeValue. """ try: return _seen[id(someval)] except KeyError: - name = "V%d" % len(_seen) + name = "%s%d" % (prefix, len(_seen)) _seen[id(someval)] = name return name Modified: pypy/trunk/src/pypy/annotation/test/test_annset.py ============================================================================== --- pypy/trunk/src/pypy/annotation/test/test_annset.py (original) +++ pypy/trunk/src/pypy/annotation/test/test_annset.py Fri Dec 19 11:37:26 2003 @@ -19,6 +19,8 @@ else: groups[-1].append(a) # hack hack hack for args in groups: + if len(args) == 2: + args = args + [True] # " " " annset.set(*args) if 'links' in kwds: links = kwds['links'] Modified: pypy/trunk/src/pypy/translator/annrpython.py ============================================================================== --- pypy/trunk/src/pypy/translator/annrpython.py (original) +++ pypy/trunk/src/pypy/translator/annrpython.py Fri Dec 19 11:37:26 2003 @@ -1,9 +1,9 @@ from __future__ import generators from types import FunctionType -from pypy.annotation.model import SomeValue, ANN, blackholevalue -from pypy.annotation.model import intvalue, boolvalue, slicevalue -from pypy.annotation.annset import AnnotationSet, QUERYARG, IDontKnow +from pypy.annotation.model import SomeValue, ANN +from pypy.annotation.annset import AnnotationSet +from pypy.annotation.annset import impossiblevalue, mostgeneralvalue from pypy.objspace.flow.model import Variable, Constant, UndefinedConstant from pypy.objspace.flow.model import SpaceOperation @@ -11,6 +11,9 @@ class AnnotatorError(Exception): pass +intvalue = SomeValue() +boolvalue = SomeValue() + class RPythonAnnotator: """Block annotator for RPython. @@ -18,10 +21,11 @@ def __init__(self, translator=None): self.heap = AnnotationSet() + self.heap.settype(intvalue, int) + self.heap.settype(boolvalue, bool) self.pendingblocks = [] # list of (block, list-of-SomeValues-args) self.delayedblocks = [] # list of blocked blocks - self.bindings = self.heap.getbindings() # map Variables/Constants - # to SomeValues + self.bindings = {} # map Variables/Constants to SomeValues self.annotated = {} # set of blocks already seen self.translator = translator @@ -67,7 +71,7 @@ if not isinstance(arg, Constant): raise # propagate missing bindings for Variables if isinstance(arg, UndefinedConstant): - result = blackholevalue # undefined local variables + result = impossiblevalue # undefined local variables else: result = self.consider_const(arg.value) self.bindings[arg] = result @@ -93,16 +97,15 @@ # A typical example would be if the tuple of arguments was created # from another basic block or even another function. Well I guess # there is no clean solution. - vlist = self.heap.queryconstant(cell) - if len(vlist) == 1: - return Constant(vlist[0]) + constvalue = self.heap.get(ANN.const, cell) + if constvalue is not mostgeneralvalue: + return Constant(constvalue) else: - cell = self.heap.normalized(cell) for v in known_variables: - if self.bindings[v] == cell: + if self.heap.isshared(self.bindings[v], cell): return v else: - raise IDontKnow, cell + raise CannotSimplify def simplify(self): # Generic simpliciations @@ -146,7 +149,7 @@ def bindinputargs(self, block, inputcells): # Create the initial bindings for the input args of a block. for a, cell in zip(block.inputargs, inputcells): - self.bindings[a] = self.heap.normalized(cell) + self.bindings[a] = cell self.annotated[block] = False # must flowin. def mergeinputargs(self, block, inputcells): @@ -159,12 +162,12 @@ oldcells.append(cell1) newcells.append(self.heap.merge(cell1, cell2)) # if the merged cells changed, we must redo the analysis - oldcells = [self.heap.normalized(c) for c in oldcells] - newcells = [self.heap.normalized(c) for c in newcells] #print '** oldcells = ', oldcells #print '** newcells = ', newcells - if newcells != oldcells: - self.bindinputargs(block, newcells) + for cell1, cell2 in zip(oldcells, newcells): + if not self.heap.isshared(cell1, cell2): + self.bindinputargs(block, newcells) + return def flowin(self, block): for op in block.operations: @@ -180,18 +183,15 @@ argcells = [self.binding(a) for a in op.args] consider_meth = getattr(self,'consider_op_'+op.opname, self.default_consider_op) - try: - resultcell = consider_meth(*argcells) - except IDontKnow: - resultcell = SomeValue() - if resultcell is blackholevalue: + resultcell = consider_meth(*argcells) + if resultcell is impossiblevalue: raise DelayAnnotation # the operation cannot succeed - assert isinstance(resultcell, SomeValue) + assert isinstance(resultcell, (SomeValue, type(mostgeneralvalue))) assert isinstance(op.result, Variable) self.bindings[op.result] = resultcell # bind resultcell to op.result def default_consider_op(self, *args): - return SomeValue() + return mostgeneralvalue def consider_op_add(self, arg1, arg2): result = SomeValue() @@ -222,13 +222,9 @@ # Annotations about the items of arg2 are merged with the ones about # the items of arg1. arg2 is not modified during this operation. # result is arg1. - self.heap.delete(ANN.len[arg1, ...]) - item1 = self.heap.get_del(ANN.getitem[arg1, intvalue, QUERYARG]) - if item1: - item2 = self.heap.get(ANN.getitem[arg2, intvalue, QUERYARG]) - item2 = item2 or SomeValue() # defaults to "can be anything" - item3 = self.heap.merge(item1, item2) - self.heap.set(ANN.getitem[arg1, intvalue, item3]) + self.heap.kill(ANN.len, arg1) + item2 = self.heap.get(ANN.listitems, arg2) + self.heap.generalize(ANN.listitems, arg1, item2) return arg1 else: return self.consider_op_add(arg1, arg2) @@ -262,85 +258,87 @@ def consider_op_newtuple(self, *args): result = SomeValue() self.heap.settype(result, tuple) - self.heap.set(ANN.len[result, self.constant(len(args))]) + self.heap.set(ANN.len, result, len(args)) for i in range(len(args)): - self.heap.set(ANN.getitem[result, self.constant(i), args[i]]) + self.heap.set(ANN.tupleitem[i], result, args[i]) return result def consider_op_newlist(self, *args): result = SomeValue() self.heap.settype(result, list) - self.heap.set(ANN.len[result, self.constant(len(args))]) - item_cell = blackholevalue + self.heap.set(ANN.len, result, len(args)) + item_cell = impossiblevalue for a in args: item_cell = self.heap.merge(item_cell, a) - self.heap.set(ANN.getitem[result, intvalue, item_cell]) + self.heap.set(ANN.listitems, result, item_cell) return result def consider_op_newslice(self, *args): - return slicevalue + result = SomeValue() + self.heap.settype(result, slice) + return result def consider_op_newdict(self, *args): result = SomeValue() self.heap.settype(result, dict) if not args: - self.heap.set(ANN.len[result, self.constant(0)]) + self.heap.set(ANN.len, result, 0) return result def consider_op_getitem(self, arg1, arg2): tp = self.heap.checktype - result = self.heap.get(ANN.getitem[arg1, arg2, QUERYARG]) - if result: - return result - if tp(arg2, int): # not too nice, but needed for lists - result = self.heap.get(ANN.getitem[arg1, intvalue, QUERYARG]) - if result: - return result + if tp(arg2, int): + if tp(arg1, tuple): + index = self.heap.get(ANN.const, arg2) + if index is not mostgeneralvalue: + return self.heap.get(ANN.tupleitem[index], arg1) + if tp(arg1, list): + return self.heap.get(ANN.listitems, arg1) result = SomeValue() if tp(arg2, slice): self.heap.copytype(arg1, result) + # XXX copy some information about the items return result def decode_simple_call(self, varargs_cell, varkwds_cell): - len_cell = self.heap.get(ANN.len[varargs_cell, QUERYARG]) - nbargs = self.heap.getconstant(len_cell) - arg_cells = [self.heap.get(ANN.getitem[varargs_cell, - self.constant(j), QUERYARG]) + nbargs = self.heap.get(ANN.len, varargs_cell) + if nbargs is mostgeneralvalue: + return None + arg_cells = [self.heap.get(ANN.tupleitem[j], varargs_cell) for j in range(nbargs)] - if None in arg_cells: - raise IDontKnow - len_cell = self.heap.get(ANN.len[varkwds_cell, QUERYARG]) - nbkwds = self.heap.getconstant(len_cell) + nbkwds = self.heap.get(ANN.len, varkwds_cell) if nbkwds != 0: - raise IDontKnow + return None # XXX deal with dictionaries with constant keys return arg_cells def consider_op_call(self, func, varargs, kwargs): - func = self.heap.getconstant(func) - if isinstance(func, FunctionType) and self.translator: - args = self.decode_simple_call(varargs, kwargs) - return self.translator.consider_call(self, func, args) - - # XXX: generalize this later - tp = self.heap.checktype result = SomeValue() + tp = self.heap.checktype + func = self.heap.get(ANN.const, func) + # XXX: generalize this later if func is range: self.heap.settype(result, list) - if func is pow: + elif func is pow: args = self.decode_simple_call(varargs, kwargs) - if len(args) == 2: + if args is not None and len(args) == 2: if tp(args[0], int) and tp(args[1], int): self.heap.settype(result, int) + elif isinstance(func, FunctionType) and self.translator: + args = self.decode_simple_call(varargs, kwargs) + return self.translator.consider_call(self, func, args) return result def consider_const(self, constvalue): - result = self.heap.newconstant(constvalue) - self.heap.set(ANN.immutable[result]) + result = SomeValue() + self.heap.set(ANN.const, result, constvalue) self.heap.settype(result, type(constvalue)) if isinstance(constvalue, tuple): pass # XXX say something about the elements return result +class CannotSimplify(Exception): + pass + class DelayAnnotation(Exception): pass Modified: pypy/trunk/src/pypy/translator/translator.py ============================================================================== --- pypy/trunk/src/pypy/translator/translator.py (original) +++ pypy/trunk/src/pypy/translator/translator.py Fri Dec 19 11:37:26 2003 @@ -193,7 +193,7 @@ except KeyError: # typical case for the 1st call, because addpendingblock() did # not actually start the analysis of the called function yet. - return nothingyet + return impossiblevalue if __name__ == '__main__': From alex at codespeak.net Fri Dec 19 11:42:56 2003 From: alex at codespeak.net (alex at codespeak.net) Date: Fri, 19 Dec 2003 11:42:56 +0100 (MET) Subject: [pypy-svn] rev 2547 - pypy/trunk/src/pypy/module Message-ID: <20031219104256.B06105A8C2@thoth.codespeak.net> Author: alex Date: Fri Dec 19 11:42:56 2003 New Revision: 2547 Modified: pypy/trunk/src/pypy/module/builtin.py Log: fix a typo in app_dir Modified: pypy/trunk/src/pypy/module/builtin.py ============================================================================== --- pypy/trunk/src/pypy/module/builtin.py (original) +++ pypy/trunk/src/pypy/module/builtin.py Fri Dec 19 11:42:56 2003 @@ -658,7 +658,7 @@ if isinstance(obj, types.ModuleType): try: - result = module.__dict__.keys() + result = obj.__dict__.keys() result.sort() return result except AttributeError: From pmaupin at codespeak.net Fri Dec 19 11:48:42 2003 From: pmaupin at codespeak.net (pmaupin at codespeak.net) Date: Fri, 19 Dec 2003 11:48:42 +0100 (MET) Subject: [pypy-svn] rev 2548 - in pypy/trunk/src/pypy: appspace module Message-ID: <20031219104842.D168D5A8C2@thoth.codespeak.net> Author: pmaupin Date: Fri Dec 19 11:48:42 2003 New Revision: 2548 Modified: pypy/trunk/src/pypy/appspace/builtin_functions_test.py pypy/trunk/src/pypy/module/builtin.py Log: Hack isinstance() to not require __class__ attribute Modified: pypy/trunk/src/pypy/appspace/builtin_functions_test.py ============================================================================== --- pypy/trunk/src/pypy/appspace/builtin_functions_test.py (original) +++ pypy/trunk/src/pypy/appspace/builtin_functions_test.py Fri Dec 19 11:48:42 2003 @@ -1,1184 +1,1204 @@ # Python test set -- built-in functions import autopath from pypy.tool import test +from pypy.interpreter.gateway import app2interp -class BuiltinTest(test.AppTestCase): +def app_init_globals(): + import __builtin__ as b - def setUp(self): - global fcmp, have_unicode, TESTFN, unlink, Set, sys, cStringIO - global Squares, StrSquares, BitBucket, L + from sets import Set + from support_tests import fcmp, have_unicode, TESTFN, unlink + + if not have_unicode: + b.basestring = str - self.space = test.objspace('std') + import sys, cStringIO - try: - have_unicode - except NameError: - pass - else: - return - - from sets import Set - try: - from support_tests import fcmp, have_unicode, TESTFN - except ImportError: - raise ImportError("Copy support_tests.py from appspace to ..\.. for now :-(") - - if not have_unicode: - ''' XXX TODO -- When unicode is added we also need basestring ''' - import __builtin__ - __builtin__.basestring = str - - import sys, warnings, cStringIO + if 0: + import warnings warnings.filterwarnings("ignore", "hex../oct.. of negative int", FutureWarning, __name__) warnings.filterwarnings("ignore", "integer argument expected", DeprecationWarning, "unittest") - 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), - ] - - - - def test_import(self): - __import__('sys') - __import__('time') - __import__('string') - self.assertRaises(ImportError, __import__, 'spamspam') - self.assertRaises(TypeError, __import__, 1, 2, 3, 4) - - def test_abs(self): - # int - self.assertEqual(abs(0), 0) - self.assertEqual(abs(1234), 1234) - self.assertEqual(abs(-1234), 1234) - # float - self.assertEqual(abs(0.0), 0.0) - self.assertEqual(abs(3.14), 3.14) - self.assertEqual(abs(-3.14), 3.14) - # long - self.assertEqual(abs(0L), 0L) - self.assertEqual(abs(1234L), 1234L) - self.assertEqual(abs(-1234L), 1234L) - # str - self.assertRaises(TypeError, abs, 'a') - - def test_apply(self): - def f0(*args): - self.assertEqual(args, ()) - def f1(a1): - self.assertEqual(a1, 1) - def f2(a1, a2): - self.assertEqual(a1, 1) - self.assertEqual(a2, 2) - def f3(a1, a2, a3): - self.assertEqual(a1, 1) - self.assertEqual(a2, 2) - self.assertEqual(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,), {}) - self.assertRaises(TypeError, apply, id, (1,), {"foo": 1}) - self.assertRaises(TypeError, apply) - self.assertRaises(TypeError, apply, id, 42) - self.assertRaises(TypeError, apply, id, (42,), 42) - - def test_callable(self): - self.assert_(callable(len)) - def f(): pass - self.assert_(callable(f)) - class C: - def meth(self): pass - self.assert_(callable(C)) - x = C() - self.assert_(callable(x.meth)) - self.assert_(not callable(x)) - class D(C): - def __call__(self): pass - y = D() - self.assert_(callable(y)) - y() - - def test_chr(self): - self.assertEqual(chr(32), ' ') - self.assertEqual(chr(65), 'A') - self.assertEqual(chr(97), 'a') - self.assertEqual(chr(0xff), '\xff') - self.assertRaises(ValueError, chr, 256) - self.assertRaises(TypeError, chr) - - def test_cmp(self): - self.assertEqual(cmp(-1, 1), -1) - self.assertEqual(cmp(1, -1), 1) - self.assertEqual(cmp(1, 1), 0) - # verify that circular objects are handled - a = []; a.append(a) - b = []; b.append(b) - from UserList import UserList - c = UserList(); c.append(c) - self.assertEqual(cmp(a, b), 0) - self.assertEqual(cmp(b, c), 0) - self.assertEqual(cmp(c, a), 0) - self.assertEqual(cmp(a, c), 0) - # okay, now break the cycles - a.pop(); b.pop(); c.pop() - self.assertRaises(TypeError, cmp) - - def test_coerce(self): - self.assert_(not fcmp(coerce(1, 1.1), (1.0, 1.1))) - self.assertEqual(coerce(1, 1L), (1L, 1L)) - self.assert_(not fcmp(coerce(1L, 1.1), (1.0, 1.1))) - self.assertRaises(TypeError, coerce) - class BadNumber: - def __coerce__(self, other): - raise ValueError - self.assertRaises(ValueError, coerce, 42, BadNumber()) - self.assertRaises(OverflowError, coerce, 0.5, int("12345" * 1000)) + 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] - def test_compile(self): - compile('print 1\n', '', 'exec') - bom = '\xef\xbb\xbf' - compile(bom + 'print 1\n', '', 'exec') - self.assertRaises(TypeError, compile) - self.assertRaises(ValueError, compile, 'print 42\n', '', 'badmode') - self.assertRaises(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') - self.assertRaises(TypeError, delattr) - - def test_dir(self): - x = 1 - self.assert_('x' in dir()) - import sys - self.assert_('modules' in dir(sys)) - self.assertRaises(TypeError, dir, 42, 42) - - def test_divmod(self): - self.assertEqual(divmod(12, 7), (1, 5)) - self.assertEqual(divmod(-12, 7), (-2, 2)) - self.assertEqual(divmod(12, -7), (-2, -2)) - self.assertEqual(divmod(-12, -7), (1, -5)) - - self.assertEqual(divmod(12L, 7L), (1L, 5L)) - self.assertEqual(divmod(-12L, 7L), (-2L, 2L)) - self.assertEqual(divmod(12L, -7L), (-2L, -2L)) - self.assertEqual(divmod(-12L, -7L), (1L, -5L)) - - self.assertEqual(divmod(12, 7L), (1, 5L)) - self.assertEqual(divmod(-12, 7L), (-2, 2L)) - self.assertEqual(divmod(12L, -7), (-2L, -2)) - self.assertEqual(divmod(-12L, -7), (1L, -5)) - - self.assert_(not fcmp(divmod(3.25, 1.0), (3.0, 0.25))) - self.assert_(not fcmp(divmod(-3.25, 1.0), (-4.0, 0.75))) - self.assert_(not fcmp(divmod(3.25, -1.0), (-4.0, -0.75))) - self.assert_(not fcmp(divmod(-3.25, -1.0), (3.0, -0.25))) - - self.assertRaises(TypeError, divmod) - - def test_eval(self): - self.assertEqual(eval('1+1'), 2) - self.assertEqual(eval(' 1+1\n'), 2) - globals = {'a': 1, 'b': 2} - locals = {'b': 200, 'c': 300} - self.assertEqual(eval('a', globals) , 1) - self.assertEqual(eval('a', globals, locals), 1) - self.assertEqual(eval('b', globals, locals), 200) - self.assertEqual(eval('c', globals, locals), 300) - if have_unicode: - self.assertEqual(eval(unicode('1+1')), 2) - self.assertEqual(eval(unicode(' 1+1\n')), 2) - globals = {'a': 1, 'b': 2} - locals = {'b': 200, 'c': 300} - if have_unicode: - self.assertEqual(eval(unicode('a'), globals), 1) - self.assertEqual(eval(unicode('a'), globals, locals), 1) - self.assertEqual(eval(unicode('b'), globals, locals), 200) - self.assertEqual(eval(unicode('c'), globals, locals), 300) - bom = '\xef\xbb\xbf' - self.assertEqual(eval(bom + 'a', globals, locals), 1) - self.assertEqual(eval(unicode('u"\xc3\xa5"', 'utf8'), globals), - unicode('\xc3\xa5', 'utf8')) - self.assertRaises(TypeError, eval) - self.assertRaises(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} - - self.assertEqual(self.__class__.z, 2) - globals['z'] = 0 - execfile(TESTFN, globals) - self.assertEqual(globals['z'], 2) - locals['z'] = 0 - execfile(TESTFN, globals, locals) - self.assertEqual(locals['z'], 2) - unlink(TESTFN) - self.assertRaises(TypeError, execfile) - import os - self.assertRaises(IOError, execfile, os.curdir) - self.assertRaises(IOError, execfile, "I_dont_exist") - - def test_filter(self): - self.assertEqual(filter(lambda c: 'a' <= c <= 'z', 'Hello World'), 'elloorld') - self.assertEqual(filter(None, [1, 'hello', [], [3], '', None, 9, 0]), [1, 'hello', [3], 9]) - self.assertEqual(filter(lambda x: x > 0, [1, -3, 9, 0, 2]), [1, 9, 2]) - self.assertEqual(filter(None, Squares(10)), [1, 4, 9, 16, 25, 36, 49, 64, 81]) - self.assertEqual(filter(lambda x: x%2, Squares(10)), [1, 9, 25, 49, 81]) - def identity(item): - return 1 - filter(identity, Squares(5)) - self.assertRaises(TypeError, filter) - class BadSeq(object): - def __getitem__(self, index): - if index<4: - return 42 - raise ValueError - self.assertRaises(ValueError, filter, lambda x: x, BadSeq()) - def badfunc(): + class BitBucket: + def write(self, line): pass - self.assertRaises(TypeError, filter, badfunc, range(5)) - - # test bltinmodule.c::filtertuple() - self.assertEqual(filter(None, (1, 2)), (1, 2)) - self.assertEqual(filter(lambda x: x>=3, (1, 2, 3, 4)), (3, 4)) - self.assertRaises(TypeError, filter, 42, (1, 2)) - # test bltinmodule.c::filterstring() - self.assertEqual(filter(None, "12"), "12") - self.assertEqual(filter(lambda x: x>="3", "1234"), "34") - self.assertRaises(TypeError, filter, 42, "12") - class badstr(str): - def __getitem__(self, index): - raise ValueError - self.assertRaises(ValueError, filter, lambda x: x >="3", badstr("1234")) + 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 badstr2(str): - def __getitem__(self, index): - return 42 - self.assertRaises(TypeError, filter, lambda x: x >=42, badstr2("1234")) +class BuiltinTest(test.AppTestCase): - class weirdstr(str): - def __getitem__(self, index): - return weirdstr(2*str.__getitem__(self, index)) - self.assertEqual(filter(lambda x: x>="33", weirdstr("1234")), "3344") + full_test = 1 + fully_initialized = False - class shiftstr(str): - def __getitem__(self, index): - return chr(ord(str.__getitem__(self, index))+1) - self.assertEqual(filter(lambda x: x>="3", shiftstr("1234")), "345") + def setUp(self): + self.space = space = test.objspace('std') + if self.fully_initialized: + return - if have_unicode: - # test bltinmodule.c::filterunicode() - self.assertEqual(filter(None, unicode("12")), unicode("12")) - self.assertEqual(filter(lambda x: x>="3", unicode("1234")), unicode("34")) - self.assertRaises(TypeError, filter, 42, unicode("12")) - self.assertRaises(ValueError, filter, lambda x: x >="3", badstr(unicode("1234"))) + app2interp(app_init_globals).get_function(space)() + self.__class__.fully_initialized = True + + if 0: + def test_import(self): + __import__('sys') + __import__('time') + __import__('string') + self.assertRaises(ImportError, __import__, 'spamspam') + self.assertRaises(TypeError, __import__, 1, 2, 3, 4) + + def test_abs(self): + # int + self.assertEqual(abs(0), 0) + self.assertEqual(abs(1234), 1234) + self.assertEqual(abs(-1234), 1234) + # float + self.assertEqual(abs(0.0), 0.0) + self.assertEqual(abs(3.14), 3.14) + self.assertEqual(abs(-3.14), 3.14) + # long + self.assertEqual(abs(0L), 0L) + self.assertEqual(abs(1234L), 1234L) + self.assertEqual(abs(-1234L), 1234L) + # str + self.assertRaises(TypeError, abs, 'a') + + def test_apply(self): + def f0(*args): + self.assertEqual(args, ()) + def f1(a1): + self.assertEqual(a1, 1) + def f2(a1, a2): + self.assertEqual(a1, 1) + self.assertEqual(a2, 2) + def f3(a1, a2, a3): + self.assertEqual(a1, 1) + self.assertEqual(a2, 2) + self.assertEqual(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,), {}) + self.assertRaises(TypeError, apply, id, (1,), {"foo": 1}) + self.assertRaises(TypeError, apply) + self.assertRaises(TypeError, apply, id, 42) + self.assertRaises(TypeError, apply, id, (42,), 42) + + def test_callable(self): + self.assert_(callable(len)) + def f(): pass + self.assert_(callable(f)) + class C: + def meth(self): pass + self.assert_(callable(C)) + x = C() + self.assert_(callable(x.meth)) + self.assert_(not callable(x)) + class D(C): + def __call__(self): pass + y = D() + self.assert_(callable(y)) + y() + + def test_chr(self): + self.assertEqual(chr(32), ' ') + self.assertEqual(chr(65), 'A') + self.assertEqual(chr(97), 'a') + self.assertEqual(chr(0xff), '\xff') + self.assertRaises(ValueError, chr, 256) + self.assertRaises(TypeError, chr) + + def test_cmp(self): + self.assertEqual(cmp(-1, 1), -1) + self.assertEqual(cmp(1, -1), 1) + self.assertEqual(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) + self.assertEqual(cmp(a, b), 0) + self.assertEqual(cmp(b, c), 0) + self.assertEqual(cmp(c, a), 0) + self.assertEqual(cmp(a, c), 0) + # okay, now break the cycles + a.pop(); b.pop(); c.pop() + ''' + self.assertRaises(TypeError, cmp) + + ''' TODO: XXX Coerce is not implemented + def test_coerce(self): + self.assert_(not fcmp(coerce(1, 1.1), (1.0, 1.1))) + self.assertEqual(coerce(1, 1L), (1L, 1L)) + self.assert_(not fcmp(coerce(1L, 1.1), (1.0, 1.1))) + self.assertRaises(TypeError, coerce) + class BadNumber: + def __coerce__(self, other): + raise ValueError + self.assertRaises(ValueError, coerce, 42, BadNumber()) + self.assertRaises(OverflowError, coerce, 0.5, int("12345" * 1000)) + ''' - class badunicode(unicode): + def test_compile(self): + compile('print 1\n', '', 'exec') + bom = '\xef\xbb\xbf' + compile(bom + 'print 1\n', '', 'exec') + self.assertRaises(TypeError, compile) + self.assertRaises(ValueError, compile, 'print 42\n', '', 'badmode') + self.assertRaises(ValueError, compile, 'print 42\n', '', 'single', 0xff) + if have_unicode: + compile(unicode('print u"\xc3\xa5"\n', 'utf8'), '', 'exec') + + if 1: + def test_delattr(self): + import sys + sys.spam = 1 + delattr(sys, 'spam') + self.assertRaises(TypeError, delattr) + + def test_dir(self): + x = 1 + self.assert_('x' in dir()) + import sys + self.assert_('modules' in dir(sys)) + self.assertRaises(TypeError, dir, 42, 42) + + def test_divmod(self): + self.assertEqual(divmod(12, 7), (1, 5)) + self.assertEqual(divmod(-12, 7), (-2, 2)) + self.assertEqual(divmod(12, -7), (-2, -2)) + self.assertEqual(divmod(-12, -7), (1, -5)) + + self.assertEqual(divmod(12L, 7L), (1L, 5L)) + self.assertEqual(divmod(-12L, 7L), (-2L, 2L)) + self.assertEqual(divmod(12L, -7L), (-2L, -2L)) + self.assertEqual(divmod(-12L, -7L), (1L, -5L)) + + self.assertEqual(divmod(12, 7L), (1, 5L)) + self.assertEqual(divmod(-12, 7L), (-2, 2L)) + self.assertEqual(divmod(12L, -7), (-2L, -2)) + self.assertEqual(divmod(-12L, -7), (1L, -5)) + + self.assert_(not fcmp(divmod(3.25, 1.0), (3.0, 0.25))) + self.assert_(not fcmp(divmod(-3.25, 1.0), (-4.0, 0.75))) + self.assert_(not fcmp(divmod(3.25, -1.0), (-4.0, -0.75))) + self.assert_(not fcmp(divmod(-3.25, -1.0), (3.0, -0.25))) + + self.assertRaises(TypeError, divmod) + + ''' XXX TODO No eval() support yet + def test_eval(self): + self.assertEqual(eval('1+1'), 2) + self.assertEqual(eval(' 1+1\n'), 2) + globals = {'a': 1, 'b': 2} + locals = {'b': 200, 'c': 300} + self.assertEqual(eval('a', globals) , 1) + self.assertEqual(eval('a', globals, locals), 1) + self.assertEqual(eval('b', globals, locals), 200) + self.assertEqual(eval('c', globals, locals), 300) + if have_unicode: + self.assertEqual(eval(unicode('1+1')), 2) + self.assertEqual(eval(unicode(' 1+1\n')), 2) + globals = {'a': 1, 'b': 2} + locals = {'b': 200, 'c': 300} + if have_unicode: + self.assertEqual(eval(unicode('a'), globals), 1) + self.assertEqual(eval(unicode('a'), globals, locals), 1) + self.assertEqual(eval(unicode('b'), globals, locals), 200) + self.assertEqual(eval(unicode('c'), globals, locals), 300) + bom = '\xef\xbb\xbf' + self.assertEqual(eval(bom + 'a', globals, locals), 1) + self.assertEqual(eval(unicode('u"\xc3\xa5"', 'utf8'), globals), + unicode('\xc3\xa5', 'utf8')) + self.assertRaises(TypeError, eval) + self.assertRaises(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} + + self.assertEqual(self.__class__.z, 2) + globals['z'] = 0 + execfile(TESTFN, globals) + self.assertEqual(globals['z'], 2) + locals['z'] = 0 + execfile(TESTFN, globals, locals) + self.assertEqual(locals['z'], 2) + unlink(TESTFN) + self.assertRaises(TypeError, execfile) + import os + self.assertRaises(IOError, execfile, os.curdir) + self.assertRaises(IOError, execfile, "I_dont_exist") + + if 0: + def test_filter(self): + self.assertEqual(filter(lambda c: 'a' <= c <= 'z', 'Hello World'), 'elloorld') + self.assertEqual(filter(None, [1, 'hello', [], [3], '', None, 9, 0]), [1, 'hello', [3], 9]) + self.assertEqual(filter(lambda x: x > 0, [1, -3, 9, 0, 2]), [1, 9, 2]) + self.assertEqual(filter(None, Squares(10)), [1, 4, 9, 16, 25, 36, 49, 64, 81]) + self.assertEqual(filter(lambda x: x%2, Squares(10)), [1, 9, 25, 49, 81]) + def identity(item): + return 1 + filter(identity, Squares(5)) + self.assertRaises(TypeError, filter) + class BadSeq(object): + def __getitem__(self, index): + if index<4: + return 42 + raise ValueError + self.assertRaises(ValueError, filter, lambda x: x, BadSeq()) + def badfunc(): + pass + self.assertRaises(TypeError, filter, badfunc, range(5)) + + # test bltinmodule.c::filtertuple() + self.assertEqual(filter(None, (1, 2)), (1, 2)) + self.assertEqual(filter(lambda x: x>=3, (1, 2, 3, 4)), (3, 4)) + self.assertRaises(TypeError, filter, 42, (1, 2)) + + # test bltinmodule.c::filterstring() + self.assertEqual(filter(None, "12"), "12") + self.assertEqual(filter(lambda x: x>="3", "1234"), "34") + self.assertRaises(TypeError, filter, 42, "12") + class badstr(str): + def __getitem__(self, index): + raise ValueError + self.assertRaises(ValueError, filter, lambda x: x >="3", badstr("1234")) + + class badstr2(str): def __getitem__(self, index): return 42 - self.assertRaises(TypeError, filter, lambda x: x >=42, badunicode("1234")) - - class weirdunicode(unicode): + self.assertRaises(TypeError, filter, lambda x: x >=42, badstr2("1234")) + + class weirdstr(str): + def __getitem__(self, index): + return weirdstr(2*str.__getitem__(self, index)) + self.assertEqual(filter(lambda x: x>="33", weirdstr("1234")), "3344") + + class shiftstr(str): + def __getitem__(self, index): + return chr(ord(str.__getitem__(self, index))+1) + self.assertEqual(filter(lambda x: x>="3", shiftstr("1234")), "345") + + if have_unicode: + # test bltinmodule.c::filterunicode() + self.assertEqual(filter(None, unicode("12")), unicode("12")) + self.assertEqual(filter(lambda x: x>="3", unicode("1234")), unicode("34")) + self.assertRaises(TypeError, filter, 42, unicode("12")) + self.assertRaises(ValueError, filter, lambda x: x >="3", badstr(unicode("1234"))) + + class badunicode(unicode): + def __getitem__(self, index): + return 42 + self.assertRaises(TypeError, filter, lambda x: x >=42, badunicode("1234")) + + class weirdunicode(unicode): + def __getitem__(self, index): + return weirdunicode(2*unicode.__getitem__(self, index)) + self.assertEqual( + 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) + self.assertEqual( + 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 weirdunicode(2*unicode.__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 + self.assertEqual( + filter(funcs[0], cls(inp)), + filter(funcs[1], cls(inp)) + ) + for func in funcs: + outp = filter(func, cls(inp)) + self.assertEqual(outp, exp) + self.assert_(not isinstance(outp, cls)) + + def test_float(self): + self.assertEqual(float(3.14), 3.14) + self.assertEqual(float(314), 314.0) + self.assertEqual(float(314L), 314.0) + self.assertEqual(float(" 3.14 "), 3.14) + if have_unicode: + self.assertEqual(float(unicode(" 3.14 ")), 3.14) + self.assertEqual(float(unicode(" \u0663.\u0661\u0664 ",'raw-unicode-escape')), 3.14) + + def test_getattr(self): + import sys + self.assert_(getattr(sys, 'stdout') is sys.stdout) + self.assertRaises(TypeError, getattr, sys, 1) + self.assertRaises(TypeError, getattr, sys, 1, "foo") + self.assertRaises(TypeError, getattr) + self.assertRaises(UnicodeError, getattr, sys, unichr(sys.maxunicode)) + + def test_hasattr(self): + import sys + self.assert_(hasattr(sys, 'stdout')) + self.assertRaises(TypeError, hasattr, sys, 1) + self.assertRaises(TypeError, hasattr) + self.assertRaises(UnicodeError, hasattr, sys, unichr(sys.maxunicode)) + + def test_hash(self): + hash(None) + self.assertEqual(hash(1), hash(1L)) + self.assertEqual(hash(1), hash(1.0)) + hash('spam') + if have_unicode: + self.assertEqual(hash('spam'), hash(unicode('spam'))) + hash((0,1,2,3)) + def f(): pass + self.assertRaises(TypeError, hash, []) + self.assertRaises(TypeError, hash, {}) + + def test_hex(self): + self.assertEqual(hex(16), '0x10') + self.assertEqual(hex(16L), '0x10L') + self.assertEqual(len(hex(-1)), len(hex(sys.maxint))) + self.assert_(hex(-16) in ('0xfffffff0', '0xfffffffffffffff0')) + self.assertEqual(hex(-16L), '-0x10L') + self.assertRaises(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): + self.assertEqual(int(314), 314) + self.assertEqual(int(3.14), 3) + self.assertEqual(int(314L), 314) + # Check that conversion from float truncates towards zero + self.assertEqual(int(-3.14), -3) + self.assertEqual(int(3.9), 3) + self.assertEqual(int(-3.9), -3) + self.assertEqual(int(3.5), 3) + self.assertEqual(int(-3.5), -3) + # Different base: + self.assertEqual(int("10",16), 16L) + if have_unicode: + self.assertEqual(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: + self.assertEqual(int(ss), vv) + except v: + pass + + s = `-1-sys.maxint` + self.assertEqual(int(s)+1, -sys.maxint) + # should return long + int(s[1:]) + + # should return long + x = int(1e100) + self.assert_(isinstance(x, long)) + x = int(-1e100) + self.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 + self.assertEqual(x >> 1, x//2) + + self.assertRaises(ValueError, int, '123\0') + self.assertRaises(ValueError, int, '53', 40) + + x = int('1' * 600) + self.assert_(isinstance(x, long)) + + if have_unicode: + x = int(unichr(0x661) * 600) + self.assert_(isinstance(x, long)) + + self.assertRaises(TypeError, int, 1, 12) + + self.assertEqual(int('0123', 0), 83) + + def test_intern(self): + self.assertRaises(TypeError, intern) + s = "never interned before" + self.assert_(intern(s) is s) + s2 = s.swapcase().swapcase() + self.assert_(intern(s2) is s) + + def test_iter(self): + self.assertRaises(TypeError, iter) + self.assertRaises(TypeError, iter, 42, 42) + lists = [("1", "2"), ["1", "2"], "12"] + if have_unicode: + lists.append(unicode("12")) + for l in lists: + i = iter(l) + self.assertEqual(i.next(), '1') + self.assertEqual(i.next(), '2') + self.assertRaises(StopIteration, i.next) + + def test_isinstance(self): + class C: + pass + class D(C): + pass + class E: + pass + c = C() + d = D() + e = E() + self.assert_(isinstance(c, C)) + self.assert_(isinstance(d, C)) + self.assert_(not isinstance(e, C)) + self.assert_(not isinstance(c, D)) + self.assert_(not isinstance('foo', E)) + self.assertRaises(TypeError, isinstance, E, 'foo') + self.assertRaises(TypeError, isinstance) + + def test_issubclass(self): + class C: + pass + class D(C): + pass + class E: + pass + c = C() + d = D() + e = E() + self.assert_(issubclass(D, C)) + self.assert_(issubclass(C, C)) + self.assert_(not issubclass(C, D)) + self.assertRaises(TypeError, issubclass, 'foo', E) + self.assertRaises(TypeError, issubclass, E, 'foo') + self.assertRaises(TypeError, issubclass) + + def test_len(self): + self.assertEqual(len('123'), 3) + self.assertEqual(len(()), 0) + self.assertEqual(len((1, 2, 3, 4)), 4) + self.assertEqual(len([1, 2, 3, 4]), 4) + self.assertEqual(len({}), 0) + self.assertEqual(len({'a':1, 'b': 2}), 2) + class BadSeq: + def __len__(self): + raise ValueError + self.assertRaises(ValueError, len, BadSeq()) + + def test_list(self): + self.assertEqual(list([]), []) + l0_3 = [0, 1, 2, 3] + l0_3_bis = list(l0_3) + self.assertEqual(l0_3, l0_3_bis) + self.assert_(l0_3 is not l0_3_bis) + self.assertEqual(list(()), []) + self.assertEqual(list((0, 1, 2, 3)), [0, 1, 2, 3]) + self.assertEqual(list(''), []) + self.assertEqual(list('spam'), ['s', 'p', 'a', 'm']) + + 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 + self.assertRaises(MemoryError, list, xrange(sys.maxint // 2)) + + def test_long(self): + self.assertEqual(long(314), 314L) + self.assertEqual(long(3.14), 3L) + self.assertEqual(long(314L), 314L) + # Check that conversion from float truncates towards zero + self.assertEqual(long(-3.14), -3L) + self.assertEqual(long(3.9), 3L) + self.assertEqual(long(-3.9), -3L) + self.assertEqual(long(3.5), 3L) + self.assertEqual(long(-3.5), -3L) + self.assertEqual(long("-3"), -3L) + if have_unicode: + self.assertEqual(long(unicode("-3")), -3L) + # Different base: + self.assertEqual(long("10",16), 16L) + if have_unicode: + self.assertEqual(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: + self.assertEqual(long(ss), long(vv)) + except v: + pass + + self.assertRaises(ValueError, long, '123\0') + self.assertRaises(ValueError, long, '53', 40) + self.assertRaises(TypeError, long, 1, 12) + + def test_map(self): self.assertEqual( - filter(lambda x: x>=unicode("33"), weirdunicode("1234")), unicode("3344")) - - class shiftunicode(unicode): + map(None, 'hello world'), + ['h','e','l','l','o',' ','w','o','r','l','d'] + ) + self.assertEqual( + map(None, 'abcd', 'efg'), + [('a', 'e'), ('b', 'f'), ('c', 'g'), ('d', None)] + ) + self.assertEqual( + map(None, range(10)), + [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] + ) + self.assertEqual( + 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) + self.assertEqual( + map(lambda x: map(sqrt,x), [[16, 4], [81, 9]]), + [[4.0, 2.0], [9.0, 3.0]] + ) + self.assertEqual( + 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 + self.assertEqual( + map(plus, [1, 3, 7]), + [1, 3, 7] + ) + self.assertEqual( + map(plus, [1, 3, 7], [4, 9, 2]), + [1+4, 3+9, 7+2] + ) + self.assertEqual( + map(plus, [1, 3, 7], [4, 9, 2], [1, 1, 0]), + [1+4+1, 3+9+1, 7+2+0] + ) + self.assertEqual( + map(None, Squares(10)), + [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] + ) + self.assertEqual( + map(int, Squares(10)), + [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] + ) + self.assertEqual( + map(None, Squares(3), Squares(2)), + [(0,0), (1,1), (4,None)] + ) + self.assertEqual( + map(max, Squares(3), Squares(2)), + [0, 1, 4] + ) + self.assertRaises(TypeError, map) + self.assertRaises(TypeError, map, lambda x: x, 42) + self.assertEqual(map(None, [42]), [42]) + class BadSeq: + def __getitem__(self, index): + raise ValueError + self.assertRaises(ValueError, map, lambda x: x, BadSeq()) + + def test_max(self): + self.assertEqual(max('123123'), '3') + self.assertEqual(max(1, 2, 3), 3) + self.assertEqual(max((1, 2, 3, 1, 2, 3)), 3) + self.assertEqual(max([1, 2, 3, 1, 2, 3]), 3) + + self.assertEqual(max(1, 2L, 3.0), 3.0) + self.assertEqual(max(1L, 2.0, 3), 3) + self.assertEqual(max(1.0, 2, 3L), 3L) + + def test_min(self): + self.assertEqual(min('123123'), '1') + self.assertEqual(min(1, 2, 3), 1) + self.assertEqual(min((1, 2, 3, 1, 2, 3)), 1) + self.assertEqual(min([1, 2, 3, 1, 2, 3]), 1) + + self.assertEqual(min(1, 2L, 3.0), 1) + self.assertEqual(min(1L, 2.0, 3), 1L) + self.assertEqual(min(1.0, 2, 3L), 1.0) + + self.assertRaises(TypeError, min) + self.assertRaises(TypeError, min, 42) + self.assertRaises(ValueError, min, ()) + class BadSeq: def __getitem__(self, index): - return unichr(ord(unicode.__getitem__(self, index))+1) + raise ValueError + self.assertRaises(ValueError, min, BadSeq()) + class BadNumber: + def __cmp__(self, other): + raise ValueError + self.assertRaises(ValueError, min, (42, BadNumber())) + + def test_oct(self): + self.assertEqual(oct(100), '0144') + self.assertEqual(oct(100L), '0144L') + self.assert_(oct(-100) in ('037777777634', '01777777777777777777634')) + self.assertEqual(oct(-100L), '-0144L') + self.assertRaises(TypeError, oct, ()) + + def write_testfile(self): + # 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() + + def test_open(self): + self.write_testfile() + fp = open(TESTFN, 'r') + try: + self.assertEqual(fp.readline(4), '1+1\n') + self.assertEqual(fp.readline(4), '1+1\n') + self.assertEqual(fp.readline(), 'The quick brown fox jumps over the lazy dog.\n') + self.assertEqual(fp.readline(4), 'Dear') + self.assertEqual(fp.readline(100), ' John\n') + self.assertEqual(fp.read(300), 'XXX'*100) + self.assertEqual(fp.read(1000), 'YYY'*100) + finally: + fp.close() + unlink(TESTFN) + + def test_ord(self): + self.assertEqual(ord(' '), 32) + self.assertEqual(ord('A'), 65) + self.assertEqual(ord('a'), 97) + if have_unicode: + self.assertEqual(ord(unichr(sys.maxunicode)), sys.maxunicode) + self.assertRaises(TypeError, ord, 42) + self.assertRaises(TypeError, ord, unicode("12")) + + def test_pow(self): + self.assertEqual(pow(0,0), 1) + self.assertEqual(pow(0,1), 0) + self.assertEqual(pow(1,0), 1) + self.assertEqual(pow(1,1), 1) + + self.assertEqual(pow(2,0), 1) + self.assertEqual(pow(2,10), 1024) + self.assertEqual(pow(2,20), 1024*1024) + self.assertEqual(pow(2,30), 1024*1024*1024) + + self.assertEqual(pow(-2,0), 1) + self.assertEqual(pow(-2,1), -2) + self.assertEqual(pow(-2,2), 4) + self.assertEqual(pow(-2,3), -8) + + self.assertEqual(pow(0L,0), 1) + self.assertEqual(pow(0L,1), 0) + self.assertEqual(pow(1L,0), 1) + self.assertEqual(pow(1L,1), 1) + + self.assertEqual(pow(2L,0), 1) + self.assertEqual(pow(2L,10), 1024) + self.assertEqual(pow(2L,20), 1024*1024) + self.assertEqual(pow(2L,30), 1024*1024*1024) + + self.assertEqual(pow(-2L,0), 1) + self.assertEqual(pow(-2L,1), -2) + self.assertEqual(pow(-2L,2), 4) + self.assertEqual(pow(-2L,3), -8) + + self.assertAlmostEqual(pow(0.,0), 1.) + self.assertAlmostEqual(pow(0.,1), 0.) + self.assertAlmostEqual(pow(1.,0), 1.) + self.assertAlmostEqual(pow(1.,1), 1.) + + self.assertAlmostEqual(pow(2.,0), 1.) + self.assertAlmostEqual(pow(2.,10), 1024.) + self.assertAlmostEqual(pow(2.,20), 1024.*1024.) + self.assertAlmostEqual(pow(2.,30), 1024.*1024.*1024.) + + self.assertAlmostEqual(pow(-2.,0), 1.) + self.assertAlmostEqual(pow(-2.,1), -2.) + self.assertAlmostEqual(pow(-2.,2), 4.) + self.assertAlmostEqual(pow(-2.,3), -8.) + + 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): + self.assertRaises(TypeError, pow, x, y, z) + else: + self.assertAlmostEqual(pow(x, y, z), 24.0) + + self.assertRaises(TypeError, pow, -1, -2, 3) + self.assertRaises(ValueError, pow, 1, 2, 0) + self.assertRaises(TypeError, pow, -1L, -2L, 3L) + self.assertRaises(ValueError, pow, 1L, 2L, 0L) + self.assertRaises(ValueError, pow, -342.43, 0.234) + + self.assertRaises(TypeError, pow) + + def test_range(self): + self.assertEqual(range(3), [0, 1, 2]) + self.assertEqual(range(1, 5), [1, 2, 3, 4]) + self.assertEqual(range(0), []) + self.assertEqual(range(-3), []) + self.assertEqual(range(1, 10, 3), [1, 4, 7]) + self.assertEqual(range(5, -5, -3), [5, 2, -1, -4]) + + # Now test range() with longs + self.assertEqual(range(-2**100), []) + self.assertEqual(range(0, -2**100), []) + self.assertEqual(range(0, 2**100, -1), []) + self.assertEqual(range(0, 2**100, -1), []) + + a = long(10 * sys.maxint) + b = long(100 * sys.maxint) + c = long(50 * sys.maxint) + + self.assertEqual(range(a, a+2), [a, a+1]) + self.assertEqual(range(a+2, a, -1L), [a+2, a+1]) + self.assertEqual(range(a+4, a, -2), [a+4, a+2]) + + seq = range(a, b, c) + self.assert_(a in seq) + self.assert_(b not in seq) + self.assertEqual(len(seq), 2) + + seq = range(b, a, -c) + self.assert_(b in seq) + self.assert_(a not in seq) + self.assertEqual(len(seq), 2) + + seq = range(-a, -b, -c) + self.assert_(-a in seq) + self.assert_(-b not in seq) + self.assertEqual(len(seq), 2) + + self.assertRaises(TypeError, range) + self.assertRaises(TypeError, range, 1, 2, 3, 4) + self.assertRaises(ValueError, range, 1, 2, 0) + + # Reject floats when it would require PyLongs to represent. + # (smaller floats still accepted, but deprecated) + self.assertRaises(TypeError, range, 1e100, 1e101, 1e101) + + self.assertRaises(TypeError, range, 0, "spam") + self.assertRaises(TypeError, range, 0, 42, "spam") + + self.assertRaises(OverflowError, range, -sys.maxint, sys.maxint) + self.assertRaises(OverflowError, range, 0, 2*sys.maxint) + + 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() + self.assertEqual(input(), 2) + self.assertEqual(input('testing\n'), 2) + self.assertEqual(raw_input(), 'The quick brown fox jumps over the lazy dog.') + self.assertEqual(raw_input('testing\n'), 'Dear John') + sys.stdin = cStringIO.StringIO("NULL\0") + self.assertRaises(TypeError, input, 42, 42) + sys.stdin = cStringIO.StringIO(" 'whitespace'") + self.assertEqual(input(), 'whitespace') + sys.stdin = cStringIO.StringIO() + self.assertRaises(EOFError, input) + del sys.stdout + self.assertRaises(RuntimeError, input, 'prompt') + del sys.stdin + self.assertRaises(RuntimeError, input, 'prompt') + finally: + sys.stdin = savestdin + sys.stdout = savestdout + fp.close() + unlink(TESTFN) + + def test_reduce(self): + self.assertEqual(reduce(lambda x, y: x+y, ['a', 'b', 'c'], ''), 'abc') self.assertEqual( - filter(lambda x: x>=unicode("3"), shiftunicode("1234")), - unicode("345") + reduce(lambda x, y: x+y, [['a', 'c'], [], ['d', 'w']], []), + ['a','c','d','w'] ) - - 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): + self.assertEqual(reduce(lambda x, y: x*y, range(2,8), 1), 5040) + self.assertEqual( + reduce(lambda x, y: x*y, range(2,21), 1L), + 2432902008176640000L + ) + self.assertEqual(reduce(lambda x, y: x+y, Squares(10)), 285) + self.assertEqual(reduce(lambda x, y: x+y, Squares(10), 0), 285) + self.assertEqual(reduce(lambda x, y: x+y, Squares(0), 0), 0) + self.assertRaises(TypeError, reduce) + self.assertRaises(TypeError, reduce, 42, 42) + self.assertRaises(TypeError, reduce, 42, 42, 42) + self.assertEqual(reduce(42, "1"), "1") # func is never called with one item + self.assertEqual(reduce(42, "", "1"), "1") # func is never called with one item + self.assertRaises(TypeError, reduce, 42, (42, 42)) + + class BadSeq: 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 + raise ValueError + self.assertRaises(ValueError, reduce, 42, BadSeq()) + + def test_reload(self): + import marshal + reload(marshal) + import string + reload(string) + ## import sys + ## self.assertRaises(ImportError, reload, sys) + + def test_repr(self): + self.assertEqual(repr(''), '\'\'') + self.assertEqual(repr(0), '0') + self.assertEqual(repr(0L), '0L') + self.assertEqual(repr(()), '()') + self.assertEqual(repr([]), '[]') + self.assertEqual(repr({}), '{}') + a = [] + a.append(a) + self.assertEqual(repr(a), '[[...]]') + a = {} + a[0] = a + self.assertEqual(repr(a), '{0: {...}}') + + def test_round(self): + self.assertEqual(round(0.0), 0.0) + self.assertEqual(round(1.0), 1.0) + self.assertEqual(round(10.0), 10.0) + self.assertEqual(round(1000000000.0), 1000000000.0) + self.assertEqual(round(1e20), 1e20) + + self.assertEqual(round(-1.0), -1.0) + self.assertEqual(round(-10.0), -10.0) + self.assertEqual(round(-1000000000.0), -1000000000.0) + self.assertEqual(round(-1e20), -1e20) + + self.assertEqual(round(0.1), 0.0) + self.assertEqual(round(1.1), 1.0) + self.assertEqual(round(10.1), 10.0) + self.assertEqual(round(1000000000.1), 1000000000.0) + + self.assertEqual(round(-1.1), -1.0) + self.assertEqual(round(-10.1), -10.0) + self.assertEqual(round(-1000000000.1), -1000000000.0) + + self.assertEqual(round(0.9), 1.0) + self.assertEqual(round(9.9), 10.0) + self.assertEqual(round(999999999.9), 1000000000.0) + + self.assertEqual(round(-0.9), -1.0) + self.assertEqual(round(-9.9), -10.0) + self.assertEqual(round(-999999999.9), -1000000000.0) + + self.assertEqual(round(-8.0, -1), -10.0) + + self.assertRaises(TypeError, round) + + def test_setattr(self): + setattr(sys, 'spam', 1) + self.assertEqual(sys.spam, 1) + self.assertRaises(TypeError, setattr, sys, 1, 'spam') + self.assertRaises(TypeError, setattr) + + def test_str(self): + self.assertEqual(str(''), '') + self.assertEqual(str(0), '0') + self.assertEqual(str(0L), '0') + self.assertEqual(str(()), '()') + self.assertEqual(str([]), '[]') + self.assertEqual(str({}), '{}') + a = [] + a.append(a) + self.assertEqual(str(a), '[[...]]') + a = {} + a[0] = a + self.assertEqual(str(a), '{0: {...}}') + + def test_sum(self): + self.assertEqual(sum([]), 0) + self.assertEqual(sum(range(2,8)), 27) + self.assertEqual(sum(iter(range(2,8))), 27) + self.assertEqual(sum(Squares(10)), 285) + self.assertEqual(sum(iter(Squares(10))), 285) + self.assertEqual(sum([[1], [2], [3]], []), [1, 2, 3]) + + self.assertRaises(TypeError, sum) + self.assertRaises(TypeError, sum, 42) + self.assertRaises(TypeError, sum, ['a', 'b', 'c']) + self.assertRaises(TypeError, sum, ['a', 'b', 'c'], '') + self.assertRaises(TypeError, sum, [[1], [2], [3]]) + self.assertRaises(TypeError, sum, [{2:3}]) + self.assertRaises(TypeError, sum, [{2:3}]*2, {2:3}) + + class BadSeq: + def __getitem__(self, index): + raise ValueError + self.assertRaises(ValueError, sum, BadSeq()) + + def test_tuple(self): + self.assertEqual(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) + self.assert_(t0_3 == t0_3_bis) + self.assertEqual(tuple([]), ()) + self.assertEqual(tuple([0, 1, 2, 3]), (0, 1, 2, 3)) + self.assertEqual(tuple(''), ()) + self.assertEqual(tuple('spam'), ('s', 'p', 'a', 'm')) + + def test_type(self): + self.assertEqual(type(''), type('123')) + self.assertNotEqual(type(''), type(())) + + def test_unichr(self): + if have_unicode: + self.assertEqual(unichr(32), unicode(' ')) + self.assertEqual(unichr(65), unicode('A')) + self.assertEqual(unichr(97), unicode('a')) self.assertEqual( - filter(funcs[0], cls(inp)), - filter(funcs[1], cls(inp)) + unichr(sys.maxunicode), + unicode('\\U%08x' % (sys.maxunicode), 'unicode-escape') ) - for func in funcs: - outp = filter(func, cls(inp)) - self.assertEqual(outp, exp) - self.assert_(not isinstance(outp, cls)) - - def test_float(self): - self.assertEqual(float(3.14), 3.14) - self.assertEqual(float(314), 314.0) - self.assertEqual(float(314L), 314.0) - self.assertEqual(float(" 3.14 "), 3.14) - if have_unicode: - self.assertEqual(float(unicode(" 3.14 ")), 3.14) - self.assertEqual(float(unicode(" \u0663.\u0661\u0664 ",'raw-unicode-escape')), 3.14) - - def test_getattr(self): - import sys - self.assert_(getattr(sys, 'stdout') is sys.stdout) - self.assertRaises(TypeError, getattr, sys, 1) - self.assertRaises(TypeError, getattr, sys, 1, "foo") - self.assertRaises(TypeError, getattr) - self.assertRaises(UnicodeError, getattr, sys, unichr(sys.maxunicode)) - - def test_hasattr(self): - import sys - self.assert_(hasattr(sys, 'stdout')) - self.assertRaises(TypeError, hasattr, sys, 1) - self.assertRaises(TypeError, hasattr) - self.assertRaises(UnicodeError, hasattr, sys, unichr(sys.maxunicode)) - - def test_hash(self): - hash(None) - self.assertEqual(hash(1), hash(1L)) - self.assertEqual(hash(1), hash(1.0)) - hash('spam') - if have_unicode: - self.assertEqual(hash('spam'), hash(unicode('spam'))) - hash((0,1,2,3)) - def f(): pass - self.assertRaises(TypeError, hash, []) - self.assertRaises(TypeError, hash, {}) - - def test_hex(self): - self.assertEqual(hex(16), '0x10') - self.assertEqual(hex(16L), '0x10L') - self.assertEqual(len(hex(-1)), len(hex(sys.maxint))) - self.assert_(hex(-16) in ('0xfffffff0', '0xfffffffffffffff0')) - self.assertEqual(hex(-16L), '-0x10L') - self.assertRaises(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): - self.assertEqual(int(314), 314) - self.assertEqual(int(3.14), 3) - self.assertEqual(int(314L), 314) - # Check that conversion from float truncates towards zero - self.assertEqual(int(-3.14), -3) - self.assertEqual(int(3.9), 3) - self.assertEqual(int(-3.9), -3) - self.assertEqual(int(3.5), 3) - self.assertEqual(int(-3.5), -3) - # Different base: - self.assertEqual(int("10",16), 16L) - if have_unicode: - self.assertEqual(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: - self.assertEqual(int(ss), vv) - except v: - pass - - s = `-1-sys.maxint` - self.assertEqual(int(s)+1, -sys.maxint) - # should return long - int(s[1:]) - - # should return long - x = int(1e100) - self.assert_(isinstance(x, long)) - x = int(-1e100) - self.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 - self.assertEqual(x >> 1, x//2) - - self.assertRaises(ValueError, int, '123\0') - self.assertRaises(ValueError, int, '53', 40) - - x = int('1' * 600) - self.assert_(isinstance(x, long)) - - if have_unicode: - x = int(unichr(0x661) * 600) - self.assert_(isinstance(x, long)) - - self.assertRaises(TypeError, int, 1, 12) - - self.assertEqual(int('0123', 0), 83) - - def test_intern(self): - self.assertRaises(TypeError, intern) - s = "never interned before" - self.assert_(intern(s) is s) - s2 = s.swapcase().swapcase() - self.assert_(intern(s2) is s) - - def test_iter(self): - self.assertRaises(TypeError, iter) - self.assertRaises(TypeError, iter, 42, 42) - lists = [("1", "2"), ["1", "2"], "12"] - if have_unicode: - lists.append(unicode("12")) - for l in lists: - i = iter(l) - self.assertEqual(i.next(), '1') - self.assertEqual(i.next(), '2') - self.assertRaises(StopIteration, i.next) - - def test_isinstance(self): - class C: - pass - class D(C): - pass - class E: - pass - c = C() - d = D() - e = E() - self.assert_(isinstance(c, C)) - self.assert_(isinstance(d, C)) - self.assert_(not isinstance(e, C)) - self.assert_(not isinstance(c, D)) - self.assert_(not isinstance('foo', E)) - self.assertRaises(TypeError, isinstance, E, 'foo') - self.assertRaises(TypeError, isinstance) - - def test_issubclass(self): - class C: - pass - class D(C): - pass - class E: - pass - c = C() - d = D() - e = E() - self.assert_(issubclass(D, C)) - self.assert_(issubclass(C, C)) - self.assert_(not issubclass(C, D)) - self.assertRaises(TypeError, issubclass, 'foo', E) - self.assertRaises(TypeError, issubclass, E, 'foo') - self.assertRaises(TypeError, issubclass) - - def test_len(self): - self.assertEqual(len('123'), 3) - self.assertEqual(len(()), 0) - self.assertEqual(len((1, 2, 3, 4)), 4) - self.assertEqual(len([1, 2, 3, 4]), 4) - self.assertEqual(len({}), 0) - self.assertEqual(len({'a':1, 'b': 2}), 2) - class BadSeq: - def __len__(self): - raise ValueError - self.assertRaises(ValueError, len, BadSeq()) - - def test_list(self): - self.assertEqual(list([]), []) - l0_3 = [0, 1, 2, 3] - l0_3_bis = list(l0_3) - self.assertEqual(l0_3, l0_3_bis) - self.assert_(l0_3 is not l0_3_bis) - self.assertEqual(list(()), []) - self.assertEqual(list((0, 1, 2, 3)), [0, 1, 2, 3]) - self.assertEqual(list(''), []) - self.assertEqual(list('spam'), ['s', 'p', 'a', 'm']) - - 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 - self.assertRaises(MemoryError, list, xrange(sys.maxint // 2)) - - def test_long(self): - self.assertEqual(long(314), 314L) - self.assertEqual(long(3.14), 3L) - self.assertEqual(long(314L), 314L) - # Check that conversion from float truncates towards zero - self.assertEqual(long(-3.14), -3L) - self.assertEqual(long(3.9), 3L) - self.assertEqual(long(-3.9), -3L) - self.assertEqual(long(3.5), 3L) - self.assertEqual(long(-3.5), -3L) - self.assertEqual(long("-3"), -3L) - if have_unicode: - self.assertEqual(long(unicode("-3")), -3L) - # Different base: - self.assertEqual(long("10",16), 16L) - if have_unicode: - self.assertEqual(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: - self.assertEqual(long(ss), long(vv)) - except v: - pass - - self.assertRaises(ValueError, long, '123\0') - self.assertRaises(ValueError, long, '53', 40) - self.assertRaises(TypeError, long, 1, 12) - - def test_map(self): - self.assertEqual( - map(None, 'hello world'), - ['h','e','l','l','o',' ','w','o','r','l','d'] - ) - self.assertEqual( - map(None, 'abcd', 'efg'), - [('a', 'e'), ('b', 'f'), ('c', 'g'), ('d', None)] - ) - self.assertEqual( - map(None, range(10)), - [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] - ) - self.assertEqual( - 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) - self.assertEqual( - map(lambda x: map(sqrt,x), [[16, 4], [81, 9]]), - [[4.0, 2.0], [9.0, 3.0]] - ) - self.assertEqual( - 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 - self.assertEqual( - map(plus, [1, 3, 7]), - [1, 3, 7] - ) - self.assertEqual( - map(plus, [1, 3, 7], [4, 9, 2]), - [1+4, 3+9, 7+2] - ) - self.assertEqual( - map(plus, [1, 3, 7], [4, 9, 2], [1, 1, 0]), - [1+4+1, 3+9+1, 7+2+0] - ) - self.assertEqual( - map(None, Squares(10)), - [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] - ) - self.assertEqual( - map(int, Squares(10)), - [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] - ) - self.assertEqual( - map(None, Squares(3), Squares(2)), - [(0,0), (1,1), (4,None)] - ) - self.assertEqual( - map(max, Squares(3), Squares(2)), - [0, 1, 4] - ) - self.assertRaises(TypeError, map) - self.assertRaises(TypeError, map, lambda x: x, 42) - self.assertEqual(map(None, [42]), [42]) - class BadSeq: - def __getitem__(self, index): - raise ValueError - self.assertRaises(ValueError, map, lambda x: x, BadSeq()) - - def test_max(self): - self.assertEqual(max('123123'), '3') - self.assertEqual(max(1, 2, 3), 3) - self.assertEqual(max((1, 2, 3, 1, 2, 3)), 3) - self.assertEqual(max([1, 2, 3, 1, 2, 3]), 3) - - self.assertEqual(max(1, 2L, 3.0), 3.0) - self.assertEqual(max(1L, 2.0, 3), 3) - self.assertEqual(max(1.0, 2, 3L), 3L) - - def test_min(self): - self.assertEqual(min('123123'), '1') - self.assertEqual(min(1, 2, 3), 1) - self.assertEqual(min((1, 2, 3, 1, 2, 3)), 1) - self.assertEqual(min([1, 2, 3, 1, 2, 3]), 1) - - self.assertEqual(min(1, 2L, 3.0), 1) - self.assertEqual(min(1L, 2.0, 3), 1L) - self.assertEqual(min(1.0, 2, 3L), 1.0) - - self.assertRaises(TypeError, min) - self.assertRaises(TypeError, min, 42) - self.assertRaises(ValueError, min, ()) - class BadSeq: - def __getitem__(self, index): - raise ValueError - self.assertRaises(ValueError, min, BadSeq()) - class BadNumber: - def __cmp__(self, other): - raise ValueError - self.assertRaises(ValueError, min, (42, BadNumber())) - - def test_oct(self): - self.assertEqual(oct(100), '0144') - self.assertEqual(oct(100L), '0144L') - self.assert_(oct(-100) in ('037777777634', '01777777777777777777634')) - self.assertEqual(oct(-100L), '-0144L') - self.assertRaises(TypeError, oct, ()) - - def write_testfile(self): - # 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() - - def test_open(self): - self.write_testfile() - fp = open(TESTFN, 'r') - try: - self.assertEqual(fp.readline(4), '1+1\n') - self.assertEqual(fp.readline(4), '1+1\n') - self.assertEqual(fp.readline(), 'The quick brown fox jumps over the lazy dog.\n') - self.assertEqual(fp.readline(4), 'Dear') - self.assertEqual(fp.readline(100), ' John\n') - self.assertEqual(fp.read(300), 'XXX'*100) - self.assertEqual(fp.read(1000), 'YYY'*100) - finally: - fp.close() - unlink(TESTFN) - - def test_ord(self): - self.assertEqual(ord(' '), 32) - self.assertEqual(ord('A'), 65) - self.assertEqual(ord('a'), 97) - if have_unicode: - self.assertEqual(ord(unichr(sys.maxunicode)), sys.maxunicode) - self.assertRaises(TypeError, ord, 42) - self.assertRaises(TypeError, ord, unicode("12")) - - def test_pow(self): - self.assertEqual(pow(0,0), 1) - self.assertEqual(pow(0,1), 0) - self.assertEqual(pow(1,0), 1) - self.assertEqual(pow(1,1), 1) - - self.assertEqual(pow(2,0), 1) - self.assertEqual(pow(2,10), 1024) - self.assertEqual(pow(2,20), 1024*1024) - self.assertEqual(pow(2,30), 1024*1024*1024) - - self.assertEqual(pow(-2,0), 1) - self.assertEqual(pow(-2,1), -2) - self.assertEqual(pow(-2,2), 4) - self.assertEqual(pow(-2,3), -8) - - self.assertEqual(pow(0L,0), 1) - self.assertEqual(pow(0L,1), 0) - self.assertEqual(pow(1L,0), 1) - self.assertEqual(pow(1L,1), 1) - - self.assertEqual(pow(2L,0), 1) - self.assertEqual(pow(2L,10), 1024) - self.assertEqual(pow(2L,20), 1024*1024) - self.assertEqual(pow(2L,30), 1024*1024*1024) - - self.assertEqual(pow(-2L,0), 1) - self.assertEqual(pow(-2L,1), -2) - self.assertEqual(pow(-2L,2), 4) - self.assertEqual(pow(-2L,3), -8) - - self.assertAlmostEqual(pow(0.,0), 1.) - self.assertAlmostEqual(pow(0.,1), 0.) - self.assertAlmostEqual(pow(1.,0), 1.) - self.assertAlmostEqual(pow(1.,1), 1.) - - self.assertAlmostEqual(pow(2.,0), 1.) - self.assertAlmostEqual(pow(2.,10), 1024.) - self.assertAlmostEqual(pow(2.,20), 1024.*1024.) - self.assertAlmostEqual(pow(2.,30), 1024.*1024.*1024.) - - self.assertAlmostEqual(pow(-2.,0), 1.) - self.assertAlmostEqual(pow(-2.,1), -2.) - self.assertAlmostEqual(pow(-2.,2), 4.) - self.assertAlmostEqual(pow(-2.,3), -8.) - - 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): - self.assertRaises(TypeError, pow, x, y, z) + self.assertRaises(ValueError, unichr, sys.maxunicode+1) + self.assertRaises(TypeError, unichr) + + def get_vars_f0(): + return vars() + # we don't want self in vars(), so use staticmethod + get_vars_f0 = staticmethod(get_vars_f0) + + def get_vars_f2(): + BuiltinTest.get_vars_f0() + a = 1 + b = 2 + return vars() + get_vars_f2 = staticmethod(get_vars_f2) + + def test_vars(self): + self.assertEqual(Set(vars()), Set(dir())) + import sys + self.assertEqual(Set(vars(sys)), Set(dir(sys))) + self.assertEqual(self.get_vars_f0(), {}) + self.assertEqual(self.get_vars_f2(), {'a': 1, 'b': 2}) + self.assertRaises(TypeError, vars, 42, 42) + self.assertRaises(TypeError, vars, 42) + + def test_zip(self): + a = (1, 2, 3) + b = (4, 5, 6) + t = [(1, 4), (2, 5), (3, 6)] + self.assertEqual(zip(a, b), t) + b = [4, 5, 6] + self.assertEqual(zip(a, b), t) + b = (4, 5, 6, 7) + self.assertEqual(zip(a, b), t) + class I: + def __getitem__(self, i): + if i < 0 or i > 2: raise IndexError + return i + 4 + self.assertEqual(zip(a, I()), t) + self.assertRaises(TypeError, zip) + self.assertRaises(TypeError, zip, None) + class G: + pass + self.assertRaises(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: - self.assertAlmostEqual(pow(x, y, z), 24.0) - - self.assertRaises(TypeError, pow, -1, -2, 3) - self.assertRaises(ValueError, pow, 1, 2, 0) - self.assertRaises(TypeError, pow, -1L, -2L, 3L) - self.assertRaises(ValueError, pow, 1L, 2L, 0L) - self.assertRaises(ValueError, pow, -342.43, 0.234) - - self.assertRaises(TypeError, pow) - - def test_range(self): - self.assertEqual(range(3), [0, 1, 2]) - self.assertEqual(range(1, 5), [1, 2, 3, 4]) - self.assertEqual(range(0), []) - self.assertEqual(range(-3), []) - self.assertEqual(range(1, 10, 3), [1, 4, 7]) - self.assertEqual(range(5, -5, -3), [5, 2, -1, -4]) - - # Now test range() with longs - self.assertEqual(range(-2**100), []) - self.assertEqual(range(0, -2**100), []) - self.assertEqual(range(0, 2**100, -1), []) - self.assertEqual(range(0, 2**100, -1), []) - - a = long(10 * sys.maxint) - b = long(100 * sys.maxint) - c = long(50 * sys.maxint) - - self.assertEqual(range(a, a+2), [a, a+1]) - self.assertEqual(range(a+2, a, -1L), [a+2, a+1]) - self.assertEqual(range(a+4, a, -2), [a+4, a+2]) - - seq = range(a, b, c) - self.assert_(a in seq) - self.assert_(b not in seq) - self.assertEqual(len(seq), 2) - - seq = range(b, a, -c) - self.assert_(b in seq) - self.assert_(a not in seq) - self.assertEqual(len(seq), 2) - - seq = range(-a, -b, -c) - self.assert_(-a in seq) - self.assert_(-b not in seq) - self.assertEqual(len(seq), 2) - - self.assertRaises(TypeError, range) - self.assertRaises(TypeError, range, 1, 2, 3, 4) - self.assertRaises(ValueError, range, 1, 2, 0) - - # Reject floats when it would require PyLongs to represent. - # (smaller floats still accepted, but deprecated) - self.assertRaises(TypeError, range, 1e100, 1e101, 1e101) - - self.assertRaises(TypeError, range, 0, "spam") - self.assertRaises(TypeError, range, 0, 42, "spam") - - self.assertRaises(OverflowError, range, -sys.maxint, sys.maxint) - self.assertRaises(OverflowError, range, 0, 2*sys.maxint) - - 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() - self.assertEqual(input(), 2) - self.assertEqual(input('testing\n'), 2) - self.assertEqual(raw_input(), 'The quick brown fox jumps over the lazy dog.') - self.assertEqual(raw_input('testing\n'), 'Dear John') - sys.stdin = cStringIO.StringIO("NULL\0") - self.assertRaises(TypeError, input, 42, 42) - sys.stdin = cStringIO.StringIO(" 'whitespace'") - self.assertEqual(input(), 'whitespace') - sys.stdin = cStringIO.StringIO() - self.assertRaises(EOFError, input) - del sys.stdout - self.assertRaises(RuntimeError, input, 'prompt') - del sys.stdin - self.assertRaises(RuntimeError, input, 'prompt') - finally: - sys.stdin = savestdin - sys.stdout = savestdout - fp.close() - unlink(TESTFN) - - def test_reduce(self): - self.assertEqual(reduce(lambda x, y: x+y, ['a', 'b', 'c'], ''), 'abc') - self.assertEqual( - reduce(lambda x, y: x+y, [['a', 'c'], [], ['d', 'w']], []), - ['a','c','d','w'] - ) - self.assertEqual(reduce(lambda x, y: x*y, range(2,8), 1), 5040) - self.assertEqual( - reduce(lambda x, y: x*y, range(2,21), 1L), - 2432902008176640000L - ) - self.assertEqual(reduce(lambda x, y: x+y, Squares(10)), 285) - self.assertEqual(reduce(lambda x, y: x+y, Squares(10), 0), 285) - self.assertEqual(reduce(lambda x, y: x+y, Squares(0), 0), 0) - self.assertRaises(TypeError, reduce) - self.assertRaises(TypeError, reduce, 42, 42) - self.assertRaises(TypeError, reduce, 42, 42, 42) - self.assertEqual(reduce(42, "1"), "1") # func is never called with one item - self.assertEqual(reduce(42, "", "1"), "1") # func is never called with one item - self.assertRaises(TypeError, reduce, 42, (42, 42)) - - class BadSeq: - def __getitem__(self, index): - raise ValueError - self.assertRaises(ValueError, reduce, 42, BadSeq()) - - def test_reload(self): - import marshal - reload(marshal) - import string - reload(string) - ## import sys - ## self.assertRaises(ImportError, reload, sys) - - def test_repr(self): - self.assertEqual(repr(''), '\'\'') - self.assertEqual(repr(0), '0') - self.assertEqual(repr(0L), '0L') - self.assertEqual(repr(()), '()') - self.assertEqual(repr([]), '[]') - self.assertEqual(repr({}), '{}') - a = [] - a.append(a) - self.assertEqual(repr(a), '[[...]]') - a = {} - a[0] = a - self.assertEqual(repr(a), '{0: {...}}') - - def test_round(self): - self.assertEqual(round(0.0), 0.0) - self.assertEqual(round(1.0), 1.0) - self.assertEqual(round(10.0), 10.0) - self.assertEqual(round(1000000000.0), 1000000000.0) - self.assertEqual(round(1e20), 1e20) - - self.assertEqual(round(-1.0), -1.0) - self.assertEqual(round(-10.0), -10.0) - self.assertEqual(round(-1000000000.0), -1000000000.0) - self.assertEqual(round(-1e20), -1e20) - - self.assertEqual(round(0.1), 0.0) - self.assertEqual(round(1.1), 1.0) - self.assertEqual(round(10.1), 10.0) - self.assertEqual(round(1000000000.1), 1000000000.0) - - self.assertEqual(round(-1.1), -1.0) - self.assertEqual(round(-10.1), -10.0) - self.assertEqual(round(-1000000000.1), -1000000000.0) - - self.assertEqual(round(0.9), 1.0) - self.assertEqual(round(9.9), 10.0) - self.assertEqual(round(999999999.9), 1000000000.0) - - self.assertEqual(round(-0.9), -1.0) - self.assertEqual(round(-9.9), -10.0) - self.assertEqual(round(-999999999.9), -1000000000.0) - - self.assertEqual(round(-8.0, -1), -10.0) - - self.assertRaises(TypeError, round) - - def test_setattr(self): - setattr(sys, 'spam', 1) - self.assertEqual(sys.spam, 1) - self.assertRaises(TypeError, setattr, sys, 1, 'spam') - self.assertRaises(TypeError, setattr) - - def test_str(self): - self.assertEqual(str(''), '') - self.assertEqual(str(0), '0') - self.assertEqual(str(0L), '0') - self.assertEqual(str(()), '()') - self.assertEqual(str([]), '[]') - self.assertEqual(str({}), '{}') - a = [] - a.append(a) - self.assertEqual(str(a), '[[...]]') - a = {} - a[0] = a - self.assertEqual(str(a), '{0: {...}}') - - def test_sum(self): - self.assertEqual(sum([]), 0) - self.assertEqual(sum(range(2,8)), 27) - self.assertEqual(sum(iter(range(2,8))), 27) - self.assertEqual(sum(Squares(10)), 285) - self.assertEqual(sum(iter(Squares(10))), 285) - self.assertEqual(sum([[1], [2], [3]], []), [1, 2, 3]) - - self.assertRaises(TypeError, sum) - self.assertRaises(TypeError, sum, 42) - self.assertRaises(TypeError, sum, ['a', 'b', 'c']) - self.assertRaises(TypeError, sum, ['a', 'b', 'c'], '') - self.assertRaises(TypeError, sum, [[1], [2], [3]]) - self.assertRaises(TypeError, sum, [{2:3}]) - self.assertRaises(TypeError, sum, [{2:3}]*2, {2:3}) - - class BadSeq: - def __getitem__(self, index): - raise ValueError - self.assertRaises(ValueError, sum, BadSeq()) - - def test_tuple(self): - self.assertEqual(tuple(()), ()) - t0_3 = (0, 1, 2, 3) - t0_3_bis = tuple(t0_3) - self.assert_(t0_3 is t0_3_bis) - self.assertEqual(tuple([]), ()) - self.assertEqual(tuple([0, 1, 2, 3]), (0, 1, 2, 3)) - self.assertEqual(tuple(''), ()) - self.assertEqual(tuple('spam'), ('s', 'p', 'a', 'm')) - - def test_type(self): - self.assertEqual(type(''), type('123')) - self.assertNotEqual(type(''), type(())) - - def test_unichr(self): - if have_unicode: - self.assertEqual(unichr(32), unicode(' ')) - self.assertEqual(unichr(65), unicode('A')) - self.assertEqual(unichr(97), unicode('a')) + return i self.assertEqual( - unichr(sys.maxunicode), - unicode('\\U%08x' % (sys.maxunicode), 'unicode-escape') + zip(SequenceWithoutALength(), xrange(2**30)), + list(enumerate(range(5))) ) - self.assertRaises(ValueError, unichr, sys.maxunicode+1) - self.assertRaises(TypeError, unichr) - - def get_vars_f0(): - return vars() - # we don't want self in vars(), so use staticmethod - get_vars_f0 = staticmethod(get_vars_f0) - - def get_vars_f2(): - BuiltinTest.get_vars_f0() - a = 1 - b = 2 - return vars() - get_vars_f2 = staticmethod(get_vars_f2) - - def test_vars(self): - self.assertEqual(Set(vars()), Set(dir())) - import sys - self.assertEqual(Set(vars(sys)), Set(dir(sys))) - self.assertEqual(self.get_vars_f0(), {}) - self.assertEqual(self.get_vars_f2(), {'a': 1, 'b': 2}) - self.assertRaises(TypeError, vars, 42, 42) - self.assertRaises(TypeError, vars, 42) - - def test_zip(self): - a = (1, 2, 3) - b = (4, 5, 6) - t = [(1, 4), (2, 5), (3, 6)] - self.assertEqual(zip(a, b), t) - b = [4, 5, 6] - self.assertEqual(zip(a, b), t) - b = (4, 5, 6, 7) - self.assertEqual(zip(a, b), t) - class I: - def __getitem__(self, i): - if i < 0 or i > 2: raise IndexError - return i + 4 - self.assertEqual(zip(a, I()), t) - self.assertRaises(TypeError, zip) - self.assertRaises(TypeError, zip, None) - class G: - pass - self.assertRaises(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 - self.assertEqual( - zip(SequenceWithoutALength(), xrange(2**30)), - list(enumerate(range(5))) - ) - - class BadSeq: - def __getitem__(self, i): - if i == 5: - raise ValueError - else: - return i - self.assertRaises(ValueError, zip, BadSeq(), BadSeq()) + + class BadSeq: + def __getitem__(self, i): + if i == 5: + raise ValueError + else: + return i + self.assertRaises(ValueError, zip, BadSeq(), BadSeq()) if __name__ == '__main__': test.main() Modified: pypy/trunk/src/pypy/module/builtin.py ============================================================================== --- pypy/trunk/src/pypy/module/builtin.py (original) +++ pypy/trunk/src/pypy/module/builtin.py Fri Dec 19 11:48:42 2003 @@ -477,7 +477,10 @@ return initial def app_isinstance(self, obj, klass_or_tuple): - objcls = obj.__class__ + try: + objcls = obj.__class__ + except AttributeError: + objcls = type(obj) if issubclass(klass_or_tuple.__class__, tuple): for klass in klass_or_tuple: if issubclass(objcls, klass): From sschwarzer at codespeak.net Fri Dec 19 11:49:26 2003 From: sschwarzer at codespeak.net (sschwarzer at codespeak.net) Date: Fri, 19 Dec 2003 11:49:26 +0100 (MET) Subject: [pypy-svn] rev 2549 - pypy/trunk/src/pypy/tool Message-ID: <20031219104926.1CDF85A8C2@thoth.codespeak.net> Author: sschwarzer Date: Fri Dec 19 11:49:25 2003 New Revision: 2549 Modified: pypy/trunk/src/pypy/tool/newtest.py Log: TestSuite._items_from_module: Use issubclass instead of wrong isinstance to find TestCase classes. Also, import newtest locally to make sure that this method and modules import newtest refer to the same TestCase class. Note: Module doesn't work right now. Modified: pypy/trunk/src/pypy/tool/newtest.py ============================================================================== --- pypy/trunk/src/pypy/tool/newtest.py (original) +++ pypy/trunk/src/pypy/tool/newtest.py Fri Dec 19 11:49:25 2003 @@ -324,12 +324,14 @@ def _items_from_module(self, module): """Return a list of TestItems read from the given module.""" + # make sure that this method and modules import newtest refer + # to the same TestCase class + from pypy.tool import newtest + items = [] # scan the module for classes derived from TestCase for obj in vars(module).values(): - if inspect.isclass(obj): - print obj, id(obj) - if inspect.isclass(obj) and isinstance(obj, TestCase): + if inspect.isclass(obj) and issubclass(obj, newtest.TestCase): # we found a TestCase class, now scan it for test methods for obj2 in vars(obj).values(): # inspect.ismethod doesn't seem to work here @@ -387,7 +389,6 @@ self.lastresults = {} for item in self.items: result = item.run() - print result.formatted_traceback key = classify(result) self.lastresults.setdefault(key, []).append(result) yield result @@ -404,8 +405,7 @@ # collect tests ts = TestSuite() print "Loading test modules ..." - ts.initfromdir(autopath.pypydir, filterfunc=filterfunc) - print "Loading test modules ..." + #ts.initfromdir(autopath.pypydir, filterfunc=filterfunc) ts.initfromdir('.', filterfunc=filterfunc) # iterate over tests and collect data for res in ts.testresults(): From sschwarzer at codespeak.net Fri Dec 19 11:58:50 2003 From: sschwarzer at codespeak.net (sschwarzer at codespeak.net) Date: Fri, 19 Dec 2003 11:58:50 +0100 (MET) Subject: [pypy-svn] rev 2550 - pypy/trunk/src/pypy/tool/testdata Message-ID: <20031219105850.0B6065A8C2@thoth.codespeak.net> Author: sschwarzer Date: Fri Dec 19 11:58:49 2003 New Revision: 2550 Added: pypy/trunk/src/pypy/tool/testdata/ pypy/trunk/src/pypy/tool/testdata/__init__.py pypy/trunk/src/pypy/tool/testdata/test_dummy.py Log: Test module for testing the unit test framework. Added: pypy/trunk/src/pypy/tool/testdata/__init__.py ============================================================================== Added: pypy/trunk/src/pypy/tool/testdata/test_dummy.py ============================================================================== --- (empty file) +++ pypy/trunk/src/pypy/tool/testdata/test_dummy.py Fri Dec 19 11:58:49 2003 @@ -0,0 +1,36 @@ +import autopath +from pypy.tool import newtest + +class TestDummy1(newtest.TestCase): + def test_success1(self): + self.assertEquals(1+1, 2) + + def test_error1(self): + raise ValueError + + def test_failure1(self): + raise newtest.Failure + + +class TestDummy2(newtest.TestCase): + def test_success2(self): + self.assertEquals(1+1, 2) + + def test_error2(self): + raise ValueError + + def test_failure2(self): + raise newtest.Failure + + +class TestSkip1(newtest.TestCase): + def setUp(self): + raise newtest.Skipped + + def test_skip1(self): + pass + + +class TestSkip2(newtest.TestCase): + def test_skip2(self): + raise newtest.Skipped From arigo at codespeak.net Fri Dec 19 11:59:05 2003 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 19 Dec 2003 11:59:05 +0100 (MET) Subject: [pypy-svn] rev 2551 - in pypy/trunk/src/pypy/translator: . test Message-ID: <20031219105905.A20725A8C2@thoth.codespeak.net> Author: arigo Date: Fri Dec 19 11:59:04 2003 New Revision: 2551 Modified: pypy/trunk/src/pypy/translator/annrpython.py pypy/trunk/src/pypy/translator/gencl.py pypy/trunk/src/pypy/translator/genpyrex.py pypy/trunk/src/pypy/translator/test/test_annrpython.py pypy/trunk/src/pypy/translator/transform.py pypy/trunk/src/pypy/translator/translator.py Log: Finished the translator refactoring. Now the consider_op_xxx() methods in annrpython are really more clear and straightforward. Modified: pypy/trunk/src/pypy/translator/annrpython.py ============================================================================== --- pypy/trunk/src/pypy/translator/annrpython.py (original) +++ pypy/trunk/src/pypy/translator/annrpython.py Fri Dec 19 11:59:04 2003 @@ -44,6 +44,21 @@ # recursively proceed until no more pending block is left self.complete() + def gettype(self, variable): + """Return the known type of a control flow graph variable, or None.""" + if isinstance(variable, Constant): + return type(variable.value) + elif isinstance(variable, Variable): + cell = self.bindings.get(variable) + if cell: + cell = self.heap.get(ANN.type, cell) + if cell: + return cell + return None + else: + raise TypeError, ("Variable or Constant instance expected, " + "got %r" % (variable,)) + #___ medium-level interface ____________________________ Modified: pypy/trunk/src/pypy/translator/gencl.py ============================================================================== --- pypy/trunk/src/pypy/translator/gencl.py (original) +++ pypy/trunk/src/pypy/translator/gencl.py Fri Dec 19 11:59:04 2003 @@ -165,11 +165,8 @@ self.setannotator(ann) def setannotator(self, annotator): self.ann = annotator - self.bindings = annotator.bindings - self.transaction = annotator.transaction() def get_type(self, var): - cell = self.bindings.get(var) - return self.transaction.get_type(cell) + return self.ann.gettype(var) def str(self, obj): if isinstance(obj, Variable): return obj.name Modified: pypy/trunk/src/pypy/translator/genpyrex.py ============================================================================== --- pypy/trunk/src/pypy/translator/genpyrex.py (original) +++ pypy/trunk/src/pypy/translator/genpyrex.py Fri Dec 19 11:59:04 2003 @@ -146,7 +146,7 @@ oparity[opname] = arity self.ops = ops self.oparity = oparity - self.bindings = {} + self.annotator = None def annotate(self, input_arg_types): a = RPythonAnnotator() @@ -154,8 +154,7 @@ self.setannotator(a) def setannotator(self, annotator): - self.bindings = annotator.bindings - self.transaction = annotator.transaction() + self.annotator = annotator def emitcode(self): self.blockids = {} @@ -209,9 +208,8 @@ def get_type(self, var): if isinstance(var, Constant): return type(var.value) - elif var in self.bindings: - cell = self.bindings[var] - return self.transaction.get_type(cell) + elif self.annotator: + return self.annotator.gettype(var) else: return None Modified: pypy/trunk/src/pypy/translator/test/test_annrpython.py ============================================================================== --- pypy/trunk/src/pypy/translator/test/test_annrpython.py (original) +++ pypy/trunk/src/pypy/translator/test/test_annrpython.py Fri Dec 19 11:59:04 2003 @@ -3,7 +3,7 @@ from pypy.tool import test from pypy.tool.udir import udir -from pypy.translator.annrpython import RPythonAnnotator +from pypy.translator.annrpython import RPythonAnnotator, ANN from pypy.translator.translator import Translator from pypy.objspace.flow.model import * @@ -45,8 +45,7 @@ block.closeblock(Link([result], fun.returnblock)) a = RPythonAnnotator() a.build_types(fun, [int]) - end_cell = a.binding(fun.getreturnvar()) - self.assertEquals(a.transaction().get_type(end_cell), int) + self.assertEquals(a.gettype(fun.getreturnvar()), int) def test_while(self): """ @@ -73,8 +72,7 @@ a = RPythonAnnotator() a.build_types(fun, [int]) - end_cell = a.binding(fun.getreturnvar()) - self.assertEquals(a.transaction().get_type(end_cell), int) + self.assertEquals(a.gettype(fun.getreturnvar()), int) def test_while_sum(self): """ @@ -109,8 +107,7 @@ a = RPythonAnnotator() a.build_types(fun, [int]) - end_cell = a.binding(fun.getreturnvar()) - self.assertEquals(a.transaction().get_type(end_cell), int) + self.assertEquals(a.gettype(fun.getreturnvar()), int) #def test_simplify_calls(self): # fun = self.make_fun(f_calls_g) @@ -125,12 +122,11 @@ a = RPythonAnnotator() a.build_types(fun, [int]) # result should be a list of integers - t = a.transaction() + self.assertEquals(a.gettype(fun.getreturnvar()), list) end_cell = a.binding(fun.getreturnvar()) - self.assertEquals(t.get_type(end_cell), list) - item_cell = t.get('getitem', [end_cell, None]) - self.failIf(item_cell is None) - self.assertEquals(t.get_type(item_cell), int) + item_cell = a.heap.get(ANN.listitems, end_cell) + self.assert_(item_cell) + self.assertEquals(a.heap.get(ANN.type, item_cell), int) def test_factorial(self): translator = Translator(snippet.factorial) @@ -138,9 +134,7 @@ a = RPythonAnnotator(translator) a.build_types(graph, [int]) # result should be an integer - t = a.transaction() - end_cell = a.binding(graph.getreturnvar()) - self.assertEquals(t.get_type(end_cell), int) + self.assertEquals(a.gettype(graph.getreturnvar()), int) def g(n): Modified: pypy/trunk/src/pypy/translator/transform.py ============================================================================== --- pypy/trunk/src/pypy/translator/transform.py (original) +++ pypy/trunk/src/pypy/translator/transform.py Fri Dec 19 11:59:04 2003 @@ -6,7 +6,7 @@ import types from pypy.objspace.flow.model import SpaceOperation -from pypy.translator.annotation import XCell, XConstant +from pypy.annotation.model import SomeValue from pypy.translator.annrpython import CannotSimplify # XXX: Lots of duplicated codes. Fix this! @@ -20,7 +20,6 @@ def transform_allocate(self): """Transforms [a] * b to alloc_and_set(b, a) where b is int.""" - t = self.transaction() for block in self.annotated: operations = block.operations[:] n_op = len(operations) @@ -31,7 +30,7 @@ len(op1.args) == 1 and op2.opname == 'mul' and op1.result is op2.args[0] and - t.get_type(self.binding(op2.args[1])) is int): + self.gettype(op2.args[1]) is int): new_op = SpaceOperation('alloc_and_set', (op2.args[1], op1.args[0]), op2.result) @@ -46,7 +45,6 @@ def transform_slice(self): """Transforms a[b:c] to getslice(a, b, c).""" - t = self.transaction() for block in self.annotated: operations = block.operations[:] n_op = len(operations) @@ -54,7 +52,7 @@ op1 = operations[i] op2 = operations[i+1] if (op1.opname == 'newslice' and - t.get_type(self.binding(op1.args[2])) is types.NoneType and + self.gettype(op1.args[2]) is types.NoneType and op2.opname == 'getitem' and op1.result is op2.args[1]): new_op = SpaceOperation('getslice', @@ -72,7 +70,6 @@ def transform_simple_call(self): """Transforms call(a, (...), {}) to simple_call(a, ...)""" - t = self.transaction() for block in self.annotated: known_vars = block.inputargs[:] operations = [] @@ -83,7 +80,7 @@ varargs_cell = self.binding(op.args[1]) varkwds_cell = self.binding(op.args[2]) arg_cells = self.decode_simple_call(varargs_cell, - varkwds_cell, t) + varkwds_cell) if arg_cells is None: raise CannotSimplify Modified: pypy/trunk/src/pypy/translator/translator.py ============================================================================== --- pypy/trunk/src/pypy/translator/translator.py (original) +++ pypy/trunk/src/pypy/translator/translator.py Fri Dec 19 11:59:04 2003 @@ -35,7 +35,7 @@ from pypy.annotation.annset import * from pypy.translator.annrpython import RPythonAnnotator from pypy.translator.simplify import simplify_graph -#from pypy.translator.genpyrex import GenPyrex +from pypy.translator.genpyrex import GenPyrex #from pypy.translator.gencl import GenCL from pypy.translator.tool.buildpyxmodule import make_module_from_pyxstring from pypy.objspace.flow import FlowObjSpace From pmaupin at codespeak.net Fri Dec 19 12:00:04 2003 From: pmaupin at codespeak.net (pmaupin at codespeak.net) Date: Fri, 19 Dec 2003 12:00:04 +0100 (MET) Subject: [pypy-svn] rev 2552 - in pypy/trunk/src/pypy: appspace appspace/test tool Message-ID: <20031219110004.B35DC5ABD2@thoth.codespeak.net> Author: pmaupin Date: Fri Dec 19 12:00:02 2003 New Revision: 2552 Modified: pypy/trunk/src/pypy/appspace/builtin_functions_test.py pypy/trunk/src/pypy/appspace/string.py (contents, props changed) pypy/trunk/src/pypy/appspace/test/test_stringmodule.py (contents, props changed) pypy/trunk/src/pypy/tool/opcode.py (props changed) pypy/trunk/src/pypy/tool/pydis.py (props changed) pypy/trunk/src/pypy/tool/traceop.py (props changed) Log: Fix eol Modified: pypy/trunk/src/pypy/appspace/builtin_functions_test.py ============================================================================== --- pypy/trunk/src/pypy/appspace/builtin_functions_test.py (original) +++ pypy/trunk/src/pypy/appspace/builtin_functions_test.py Fri Dec 19 12:00:02 2003 @@ -311,8 +311,6 @@ f.write('z = z*2\n') f.close() execfile(TESTFN) - '\'' - ''' def test_execfile(self): globals = {'a': 1, 'b': 2} @@ -330,6 +328,8 @@ import os self.assertRaises(IOError, execfile, os.curdir) self.assertRaises(IOError, execfile, "I_dont_exist") + '\'' + ''' if 0: def test_filter(self): Modified: pypy/trunk/src/pypy/appspace/string.py ============================================================================== --- pypy/trunk/src/pypy/appspace/string.py (original) +++ pypy/trunk/src/pypy/appspace/string.py Fri Dec 19 12:00:02 2003 @@ -1,9 +1,9 @@ -def maketrans(origin, image): - if len(origin) != len(image): - raise ValueError("maketrans arguments must have same length") - L = [chr(i) for i in range(256)] - for i in range(len(origin)): - L[ord(origin[i])] = image[i] - - tbl = ''.join(L) +def maketrans(origin, image): + if len(origin) != len(image): + raise ValueError("maketrans arguments must have same length") + L = [chr(i) for i in range(256)] + for i in range(len(origin)): + L[ord(origin[i])] = image[i] + + tbl = ''.join(L) return tbl \ No newline at end of file Modified: pypy/trunk/src/pypy/appspace/test/test_stringmodule.py ============================================================================== --- pypy/trunk/src/pypy/appspace/test/test_stringmodule.py (original) +++ pypy/trunk/src/pypy/appspace/test/test_stringmodule.py Fri Dec 19 12:00:02 2003 @@ -1,39 +1,39 @@ -#!/usr/bin/env python - - -""" -Test module for functions in stringmodule.py - -""" - -import string as c_py_string -import unittest - -import autopath -from pypy.tool import test -from pypy.appspace import string as pypy_string - -class TestStringmodule(unittest.TestCase): - def regression(self, sFuncname, *args, **kwargs): - try: - c_py_res = getattr(c_py_string, sFuncname)(*args, **kwargs) - except Exception, ce: - c_py_res = ce.__class__ - - try: - pypy_res = getattr(pypy_string, sFuncname)(*args, **kwargs) - except Exception, pe: - pypy_res = pe.__class__ - - self.assertEqual(c_py_res, pypy_res, 'not equal \n1:<%s>\n2:<%s>' % (c_py_res, pypy_res)) - - - def test_maketrans(self): - self.regression('maketrans','','') - self.regression('maketrans','a','b') - self.regression('maketrans','aa','bb') - self.regression('maketrans','aa','') - - -if __name__ == "__main__": +#!/usr/bin/env python + + +""" +Test module for functions in stringmodule.py + +""" + +import string as c_py_string +import unittest + +import autopath +from pypy.tool import test +from pypy.appspace import string as pypy_string + +class TestStringmodule(unittest.TestCase): + def regression(self, sFuncname, *args, **kwargs): + try: + c_py_res = getattr(c_py_string, sFuncname)(*args, **kwargs) + except Exception, ce: + c_py_res = ce.__class__ + + try: + pypy_res = getattr(pypy_string, sFuncname)(*args, **kwargs) + except Exception, pe: + pypy_res = pe.__class__ + + self.assertEqual(c_py_res, pypy_res, 'not equal \n1:<%s>\n2:<%s>' % (c_py_res, pypy_res)) + + + def test_maketrans(self): + self.regression('maketrans','','') + self.regression('maketrans','a','b') + self.regression('maketrans','aa','bb') + self.regression('maketrans','aa','') + + +if __name__ == "__main__": test.main() \ No newline at end of file From arigo at codespeak.net Fri Dec 19 12:04:02 2003 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 19 Dec 2003 12:04:02 +0100 (MET) Subject: [pypy-svn] rev 2553 - pypy/trunk/src/pypy/annotation/test Message-ID: <20031219110402.CA9925A8C2@thoth.codespeak.net> Author: arigo Date: Fri Dec 19 12:04:02 2003 New Revision: 2553 Added: pypy/trunk/src/pypy/annotation/test/__init__.py (props changed) - copied unchanged from rev 2551, pypy/trunk/src/pypy/translator/test/__init__.py Log: Missing package file. From rxe at codespeak.net Fri Dec 19 13:04:21 2003 From: rxe at codespeak.net (rxe at codespeak.net) Date: Fri, 19 Dec 2003 13:04:21 +0100 (MET) Subject: [pypy-svn] rev 2554 - pypy/trunk/src/pypy/tool Message-ID: <20031219120421.E790D5A8C2@thoth.codespeak.net> Author: rxe Date: Fri Dec 19 13:04:21 2003 New Revision: 2554 Added: pypy/trunk/src/pypy/tool/traceinteractive.py Modified: pypy/trunk/src/pypy/tool/traceop.py Log: Added a hacked up interactive tool to show the tracing of statements. Requires a pretty big refactor. Added: pypy/trunk/src/pypy/tool/traceinteractive.py ============================================================================== --- (empty file) +++ pypy/trunk/src/pypy/tool/traceinteractive.py Fri Dec 19 13:04:21 2003 @@ -0,0 +1,184 @@ +# Python imports +import sys +import code +import repr +import keyword +import linecache + +try: + import readline + import rlcompleter + have_readline = True + +except: + have_readline = False + + +# PyPy imports +import autopath + +from pypy.tool import pydis +from pypy.tool.traceop import print_result + +from pypy.interpreter import executioncontext, pyframe, baseobjspace +from pypy.interpreter.baseobjspace import ObjSpace + +from pypy.objspace import trace + +# Global +operations = dict([(r[0], r[0]) for r in ObjSpace.MethodTable]) + + +#////////////////////////////////////////////////////////////////////////// + +if have_readline: + class Completer(rlcompleter.Completer): + # TODO Tailor this for own means + + def __init__(self, objspace): + self.objspace = objspace + + + # Very frustratingly, we have a lot of duplication of rlcompleter here + def global_matches(self, text): + print "GERE" + locals = self.objspace.unwrap(self.objspace.w_locals) + matches = [] + n = len(text) + for l in [locals.keys(), __builtin__.__dict__.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) + object = self.locals[expr] + words = dir(object) + if hasattr(object, '__class__'): + words.append('__class__') + words = words + self.get_class_members(object.__class__) + + 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_class_members(self, klass): + ret = dir(klass) + if hasattr(klass, '__bases__'): + for base in klass.__bases__: + ret = ret + self.get_class_members(base) + return ret + + +#////////////////////////////////////////////////////////////////////////// + +class TraceConsole(code.InteractiveConsole): + def __init__(self, objspace): + code.InteractiveConsole.__init__(self) + s = self.space = trace.TraceObjSpace(objspace) + s.setitem(s.w_globals, s.wrap("__pytrace__"), s.w_True) + self.objspacename = objspace.__class__.__name__ + + + def interact(self, banner=None): + if banner is None: + banner = "Python %s in pypy(trace)\n%s / %s - %s" % ( + sys.version, self.__class__.__name__, + self.objspacename, + " [Use __pytrace__ flag to turn off tracing.]" ) + code.InteractiveConsole.interact(self, 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" + return code.InteractiveConsole.raw_input(self, prompt[0] + prompt) + + + def runcode(self, code): + # 'code' is a CPython code object + from pypy.interpreter.pycode import PyCode + pycode = PyCode()._from_code(code) + try: + s = self.space + trace_flag = s.unwrap(s.getitem(s.w_globals, + s.wrap("__pytrace__"))) + if trace_flag: + s.settrace() + + pycode.exec_code(s, s.w_globals, s.w_globals) + if trace_flag: + res = s.getresult() + s.settrace() + print_result(res) + + except baseobjspace.OperationError, operationerr: + # XXX insert exception info into the application-level sys.last_xxx + operationerr.print_detailed_traceback(self.space) + + else: + try: + if sys.stdout.softspace: + print + + except AttributeError: + # Don't crash if user defined stdout doesn't have softspace + pass + + def runsource(self, source, ignored_filename="", symbol="single"): + hacked_filename = '\n'+source + try: + code = self.compile(source, hacked_filename, symbol) + except (OverflowError, SyntaxError, ValueError): + self.showsyntaxerror(self.filename) + return 0 + if code is None: + return 1 + self.runcode(code) + return 0 + + + + +def trace_interactive(objspace, banner = None): + s = objspace + + 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) + readline.read_history_file() + + import atexit + atexit.register(readline.write_history_file) + + console.interact(banner) + + +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() + trace_interactive(objspace) + Modified: pypy/trunk/src/pypy/tool/traceop.py ============================================================================== --- pypy/trunk/src/pypy/tool/traceop.py (original) +++ pypy/trunk/src/pypy/tool/traceop.py Fri Dec 19 13:04:21 2003 @@ -40,7 +40,60 @@ disresult = _cache[obj] = pydis.pydis(obj) return disresult +import repr +def get_repr(): + " Our own repr function for pretty print. " + repr_obj = repr.Repr() + repr_obj.maxstring = 120 + repr_obj.maxother = 120 + + def our_repr(*args): + try: + return repr_obj.repr(*args) + + except: + return "ERROR" + + return our_repr +Repr = get_repr() + +def line_begin(indent): + if indent: + return (" " * indent) + "|-" + else: + return "" + +def print_result(traceres): + indentor = ' ' + lastframe = None + frame_count = 0 + indent = "" + for event in traceres.getevents(): + if isinstance(event, trace.EnterFrame): + print line_begin(frame_count) + ("<<<<>>>>>>" % event.frame) + lastframe = event.frame + frame_count += 1 + elif isinstance(event, trace.LeaveFrame): + frame_count -= 1 + print line_begin(frame_count) + ("<<<<>>>>>>" % lastframe) + elif isinstance(event, trace.ExecBytecode): + disresult = getdisresult(event.frame) + print line_begin(frame_count), event.index, " ", disresult.getbytecode(event.index) + lastframe = event.frame + + elif isinstance(event, trace.CallBegin): + info = event.callinfo + if info.name in operations: + print line_begin(frame_count), " " * 40, info.name, repr_args(lastframe, info.args) + indent += indentor + elif isinstance(event, trace.CallFinished): + indent = indent[:-len(indentor)] + else: + pass + + def trace_function(space, fn, *arg, **kwds): + funcres, traceres = perform_trace(space, fn, *arg, **kwds) indentor = ' ' indent = ' ' @@ -75,7 +128,7 @@ elif frame and space.is_true(space.is_(arg, space.w_builtins)): l.append('w_builtins') else: - l.append(repr(arg) [:50]) + l.append(Repr(arg) [:50]) return ", ".join(l) def app_test(): @@ -83,33 +136,20 @@ for i in range(10): print i - return "Hello World" def test(): space = TrivialObjSpace() #space = StdObjSpace() + + funcres, traceres = trace_function(space, app_test) print "function result -->", funcres -test() - -""" -import repr -def get_repr(): - " Our own repr function for pretty print. " - repr_obj = repr.Repr() - repr_obj.maxstring = 120 - repr_obj.maxother = 120 - - def our_repr(*args): - try: - return repr_obj.repr(*args) - - except: - return "ERROR" - - return our_repr -""" +## from earthenware.utils.stacktrace +## try: +## test() +## except: +## earthenware.utils.stacktrace.print_exception(sys. ## def rpretty_print(spacedump): ## " Pretty print for rdump() calls to Trace object spaces. " From arigo at codespeak.net Fri Dec 19 13:29:12 2003 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 19 Dec 2003 13:29:12 +0100 (MET) Subject: [pypy-svn] rev 2556 - pypy/trunk/src/pypy/translator Message-ID: <20031219122912.DE2615A8C2@thoth.codespeak.net> Author: arigo Date: Fri Dec 19 13:29:12 2003 New Revision: 2556 Modified: pypy/trunk/src/pypy/translator/annrpython.py Log: Added the dependency tracking and block reflowing. XXX Needs to be tested explicitely. Modified: pypy/trunk/src/pypy/translator/annrpython.py ============================================================================== --- pypy/trunk/src/pypy/translator/annrpython.py (original) +++ pypy/trunk/src/pypy/translator/annrpython.py Fri Dec 19 13:29:12 2003 @@ -62,7 +62,7 @@ #___ medium-level interface ____________________________ - def addpendingblock(self, block, cells): + def addpendingblock(self, block, cells=None): """Register an entry point into block with the given input cells.""" self.pendingblocks.append((block, cells)) @@ -158,7 +158,7 @@ # When flowin succeeds, i.e. when the analysis progress, # we can tentatively re-schedlue the delayed blocks. for block in self.delayedblocks: - self.pendingblocks.append((block, None)) + self.addpendingblock(block) del self.delayedblocks[:] def bindinputargs(self, block, inputcells): @@ -185,8 +185,10 @@ return def flowin(self, block): + self.heap.enter(block, self.addpendingblock) for op in block.operations: self.consider_op(op) + self.heap.leave() for link in block.exits: cells = [self.binding(a) for a in link.args] self.addpendingblock(link.target, cells) From arigo at codespeak.net Fri Dec 19 13:38:16 2003 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 19 Dec 2003 13:38:16 +0100 (MET) Subject: [pypy-svn] rev 2557 - pypy/trunk/src/pypy/translator Message-ID: <20031219123816.2A0CE5A8C2@thoth.codespeak.net> Author: arigo Date: Fri Dec 19 13:38:15 2003 New Revision: 2557 Modified: pypy/trunk/src/pypy/translator/annrpython.py Log: Fix to reflow. Modified: pypy/trunk/src/pypy/translator/annrpython.py ============================================================================== --- pypy/trunk/src/pypy/translator/annrpython.py (original) +++ pypy/trunk/src/pypy/translator/annrpython.py Fri Dec 19 13:38:15 2003 @@ -62,7 +62,7 @@ #___ medium-level interface ____________________________ - def addpendingblock(self, block, cells=None): + def addpendingblock(self, block, cells): """Register an entry point into block with the given input cells.""" self.pendingblocks.append((block, cells)) @@ -158,9 +158,14 @@ # When flowin succeeds, i.e. when the analysis progress, # we can tentatively re-schedlue the delayed blocks. for block in self.delayedblocks: - self.addpendingblock(block) + self.addpendingblock(block, None) del self.delayedblocks[:] + def reflowpendingblock(self, block): + self.pendingblocks.append((block, None)) + assert block in self.annotated + self.annotated[block] = False # must re-flow + def bindinputargs(self, block, inputcells): # Create the initial bindings for the input args of a block. for a, cell in zip(block.inputargs, inputcells): @@ -185,7 +190,7 @@ return def flowin(self, block): - self.heap.enter(block, self.addpendingblock) + self.heap.enter(block, self.reflowpendingblock) for op in block.operations: self.consider_op(op) self.heap.leave() From sschwarzer at codespeak.net Fri Dec 19 14:06:00 2003 From: sschwarzer at codespeak.net (sschwarzer at codespeak.net) Date: Fri, 19 Dec 2003 14:06:00 +0100 (MET) Subject: [pypy-svn] rev 2558 - pypy/trunk/src/pypy/tool Message-ID: <20031219130600.DD3695A8C2@thoth.codespeak.net> Author: sschwarzer Date: Fri Dec 19 14:06:00 2003 New Revision: 2558 Modified: pypy/trunk/src/pypy/tool/newtest.py Log: In class TestSuite, renamed method testresults to result_generator. Still having some problems with module, class etc. identities but also have a solution in mind. Modified: pypy/trunk/src/pypy/tool/newtest.py ============================================================================== --- pypy/trunk/src/pypy/tool/newtest.py (original) +++ pypy/trunk/src/pypy/tool/newtest.py Fri Dec 19 14:06:00 2003 @@ -135,6 +135,8 @@ self.name = self.__class__.__name__ self.traceback = None + #XXX possibly, we need an attribute/method has_traceback? + def __eq__(self, other): """ Return True if both TestResult objects are semantically the same. @@ -163,7 +165,7 @@ class TestResultWithTraceback(TestResult): def __init__(self, msg='', item=None): - TestResult.__init__(self, item) + TestResult.__init__(self, msg, item) self.setexception() def __eq__(self, other): @@ -251,34 +253,36 @@ # credit: adapted from Python's unittest.TestCase.run + # make sure that TestResult classes refer to the same objects + # as in test modules importing this module + from pypy.tool import newtest + testobject = self.cls() testmethod = getattr(testobject, self.method.__name__) if pretest is not None: pretest(self) try: - #XXX possibly will have to change - from pypy.tool import test try: testobject.setUp() except KeyboardInterrupt: raise - except TestResult, result: + except newtest.TestResult, result: # reconstruct TestResult object, implicitly set exception result = result.__class__(msg=result.msg, item=self) except Exception, exc: - return Error(msg=str(exc), item=self) + return newtest.Error(msg=str(exc), item=self) try: testmethod() - result = Success(msg='success', item=self) + result = newtest.Success(msg='success', item=self) except KeyboardInterrupt: raise - except TestResult, result: + except newtest.TestResult, result: # reconstruct TestResult object, implicitly set exception result = result.__class__(msg=result.msg, item=self) except Exception, exc: - result = Error(msg=str(exc), item=self) + result = newtest.Error(msg=str(exc), item=self) try: testobject.tearDown() @@ -288,7 +292,7 @@ # if we already had an exception in the test method, # don't overwrite it if result.traceback is None: - result = Error(msg=str(exc), item=self) + result = newtest.Error(msg=str(exc), item=self) finally: if posttest is not None: posttest(self) @@ -317,8 +321,8 @@ # is present in sys.modules. Unfortunately, the module returned # from the __import__ function doesn't correspond to the last # component of the module path but the first. In the example - # listed in the docstring we thus would get the pypy module, - # not the test_minmax module. + # listed in the docstring we thus would get the pypy module + # (i. e. package), not the test_minmax module. __import__(modpath) return sys.modules[modpath] @@ -374,7 +378,8 @@ else: self.items.extend(items) - def testresults(self, classify=lambda result: result.item.module.__name__): + def result_generator(self, + classify=lambda result: result.item.module.__name__): """ Return a generator to get the test result for each test item. @@ -393,6 +398,15 @@ self.lastresults.setdefault(key, []).append(result) yield result + def run(self): + """ + Run all the test items. After that, the results are available + via the attribute lastresults. + """ + # perform all the tests by using the existing generator; discard + # the results; they are then available via self.lastresults + [result for result in self.generator()] + # # demonstrate test framework usage # @@ -408,7 +422,7 @@ #ts.initfromdir(autopath.pypydir, filterfunc=filterfunc) ts.initfromdir('.', filterfunc=filterfunc) # iterate over tests and collect data - for res in ts.testresults(): + for res in ts.result_generator(): if res.traceback is None: continue print 79 * '-' From sschwarzer at codespeak.net Fri Dec 19 14:11:17 2003 From: sschwarzer at codespeak.net (sschwarzer at codespeak.net) Date: Fri, 19 Dec 2003 14:11:17 +0100 (MET) Subject: [pypy-svn] rev 2559 - pypy/trunk/src/pypy/tool Message-ID: <20031219131117.7BEDD5A8C2@thoth.codespeak.net> Author: sschwarzer Date: Fri Dec 19 14:11:16 2003 New Revision: 2559 Modified: pypy/trunk/src/pypy/tool/newtest.py Log: Addition for last commit: Added a method 'run' to TestSuite class. This one runs all tests at once. Remedied subtle problems by using an import statement before executing the function main and qualifying main as newtest.main . Modified: pypy/trunk/src/pypy/tool/newtest.py ============================================================================== --- pypy/trunk/src/pypy/tool/newtest.py (original) +++ pypy/trunk/src/pypy/tool/newtest.py Fri Dec 19 14:11:16 2003 @@ -253,10 +253,6 @@ # credit: adapted from Python's unittest.TestCase.run - # make sure that TestResult classes refer to the same objects - # as in test modules importing this module - from pypy.tool import newtest - testobject = self.cls() testmethod = getattr(testobject, self.method.__name__) @@ -267,22 +263,22 @@ testobject.setUp() except KeyboardInterrupt: raise - except newtest.TestResult, result: + except TestResult, result: # reconstruct TestResult object, implicitly set exception result = result.__class__(msg=result.msg, item=self) except Exception, exc: - return newtest.Error(msg=str(exc), item=self) + return Error(msg=str(exc), item=self) try: testmethod() - result = newtest.Success(msg='success', item=self) + result = Success(msg='success', item=self) except KeyboardInterrupt: raise - except newtest.TestResult, result: + except TestResult, result: # reconstruct TestResult object, implicitly set exception result = result.__class__(msg=result.msg, item=self) except Exception, exc: - result = newtest.Error(msg=str(exc), item=self) + result = Error(msg=str(exc), item=self) try: testobject.tearDown() @@ -292,7 +288,7 @@ # if we already had an exception in the test method, # don't overwrite it if result.traceback is None: - result = newtest.Error(msg=str(exc), item=self) + result = Error(msg=str(exc), item=self) finally: if posttest is not None: posttest(self) @@ -335,7 +331,7 @@ items = [] # scan the module for classes derived from TestCase for obj in vars(module).values(): - if inspect.isclass(obj) and issubclass(obj, newtest.TestCase): + if inspect.isclass(obj) and issubclass(obj, TestCase): # we found a TestCase class, now scan it for test methods for obj2 in vars(obj).values(): # inspect.ismethod doesn't seem to work here @@ -445,4 +441,7 @@ if __name__ == '__main__': - main(do_selftest=True) + # used to avoid subtle problems with class matching after different + # import statements + from pypy.tool import newtest + newtest.main(do_selftest=True) From sschwarzer at codespeak.net Fri Dec 19 14:12:55 2003 From: sschwarzer at codespeak.net (sschwarzer at codespeak.net) Date: Fri, 19 Dec 2003 14:12:55 +0100 (MET) Subject: [pypy-svn] rev 2560 - pypy/trunk/src/pypy/tool Message-ID: <20031219131255.5C4865A8C2@thoth.codespeak.net> Author: sschwarzer Date: Fri Dec 19 14:12:54 2003 New Revision: 2560 Modified: pypy/trunk/src/pypy/tool/newtest.py Log: Removed redundant import statement from TestSuite._items_from_module . Modified: pypy/trunk/src/pypy/tool/newtest.py ============================================================================== --- pypy/trunk/src/pypy/tool/newtest.py (original) +++ pypy/trunk/src/pypy/tool/newtest.py Fri Dec 19 14:12:54 2003 @@ -324,10 +324,6 @@ def _items_from_module(self, module): """Return a list of TestItems read from the given module.""" - # make sure that this method and modules import newtest refer - # to the same TestCase class - from pypy.tool import newtest - items = [] # scan the module for classes derived from TestCase for obj in vars(module).values(): From pmaupin at codespeak.net Fri Dec 19 14:19:01 2003 From: pmaupin at codespeak.net (pmaupin at codespeak.net) Date: Fri, 19 Dec 2003 14:19:01 +0100 (MET) Subject: [pypy-svn] rev 2561 - pypy/trunk/src/pypy/objspace/std Message-ID: <20031219131901.003505A8C2@thoth.codespeak.net> Author: pmaupin Date: Fri Dec 19 14:19:01 2003 New Revision: 2561 Modified: pypy/trunk/src/pypy/objspace/std/typeobject.py Log: Propagate attribute error to app level Modified: pypy/trunk/src/pypy/objspace/std/typeobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/typeobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/typeobject.py Fri Dec 19 14:19:01 2003 @@ -51,7 +51,8 @@ space = w_self.space multimethods = getmultimethods(space.__class__, w_self.__class__) key = space.unwrap(w_key) - assert isinstance(key, str) + if not isinstance(key, str): + raise OperationError(space.w_TypeError,space.wrap('attribute name must be string')) try: code = multimethods[key] except KeyError: From sschwarzer at codespeak.net Fri Dec 19 14:22:25 2003 From: sschwarzer at codespeak.net (sschwarzer at codespeak.net) Date: Fri, 19 Dec 2003 14:22:25 +0100 (MET) Subject: [pypy-svn] rev 2562 - pypy/trunk/src/pypy/tool Message-ID: <20031219132225.7F3435A8C2@thoth.codespeak.net> Author: sschwarzer Date: Fri Dec 19 14:22:24 2003 New Revision: 2562 Modified: pypy/trunk/src/pypy/tool/newtest.py Log: In TestSuite.run, fixed name of generator method. Added "from __future__ import generators" for Python 2.2 compatibility. Updated TODO comment at file's top. Modified: pypy/trunk/src/pypy/tool/newtest.py ============================================================================== --- pypy/trunk/src/pypy/tool/newtest.py (original) +++ pypy/trunk/src/pypy/tool/newtest.py Fri Dec 19 14:22:24 2003 @@ -1,3 +1,6 @@ +# for Python 2.2 compatibilty +from __future__ import generators + import autopath import inspect import os @@ -7,11 +10,12 @@ import vpath #TODO -# - add support for ignored tests +# - add support for ignored tests (do we need to differentiate between +# skipped and ignored tests at all?) # - support TestItem.run with different object spaces -# - perhaps we have to be able to compare TestResult and TestItem values -# which were pickled (see -c option of current test_all.py) -# - add docstring to TestItem +# - add docstring of loaded test method to TestItem +# - unify naming of methods/functions +# - support for pickling and retrieving TestItems and TestResults? # # custom TestCase class (adapted from Python's unittest module) @@ -258,6 +262,8 @@ if pretest is not None: pretest(self) + #FIXME raising Skipped in setUp should cause the result to be + # recognized as "skipped" try: try: testobject.setUp() @@ -397,7 +403,7 @@ """ # perform all the tests by using the existing generator; discard # the results; they are then available via self.lastresults - [result for result in self.generator()] + [result for result in self.result_generator()] # # demonstrate test framework usage From sschwarzer at codespeak.net Fri Dec 19 14:28:11 2003 From: sschwarzer at codespeak.net (sschwarzer at codespeak.net) Date: Fri, 19 Dec 2003 14:28:11 +0100 (MET) Subject: [pypy-svn] rev 2563 - in pypy/trunk/src/pypy/tool: . testdata Message-ID: <20031219132811.37C885A8C2@thoth.codespeak.net> Author: sschwarzer Date: Fri Dec 19 14:28:10 2003 New Revision: 2563 Modified: pypy/trunk/src/pypy/tool/newtest.py pypy/trunk/src/pypy/tool/testdata/test_dummy.py Log: Added method skip to TestCase class. When setting do_selftest in function main is true, execute _only_ the selftest. Modified: pypy/trunk/src/pypy/tool/newtest.py ============================================================================== --- pypy/trunk/src/pypy/tool/newtest.py (original) +++ pypy/trunk/src/pypy/tool/newtest.py Fri Dec 19 14:28:10 2003 @@ -43,6 +43,10 @@ "Hook method for deconstructing the test fixture after testing it." pass + def skip(self, msg=None): + """Skip this test by raising exception Skipped.""" + raise Skipped(msg=msg) + def fail(self, msg=None): """Fail immediately, with the given message.""" raise Failure(msg=msg) @@ -411,14 +415,13 @@ def main(do_selftest=False): # possibly ignore dummy unit tests if do_selftest: - filterfunc = lambda m: True + filterfunc = lambda m: m.find("pypy.tool.testdata.") != -1 else: filterfunc = lambda m: m.find("pypy.tool.testdata.") == -1 # collect tests ts = TestSuite() print "Loading test modules ..." - #ts.initfromdir(autopath.pypydir, filterfunc=filterfunc) - ts.initfromdir('.', filterfunc=filterfunc) + ts.initfromdir(autopath.pypydir, filterfunc=filterfunc) # iterate over tests and collect data for res in ts.result_generator(): if res.traceback is None: Modified: pypy/trunk/src/pypy/tool/testdata/test_dummy.py ============================================================================== --- pypy/trunk/src/pypy/tool/testdata/test_dummy.py (original) +++ pypy/trunk/src/pypy/tool/testdata/test_dummy.py Fri Dec 19 14:28:10 2003 @@ -25,7 +25,7 @@ class TestSkip1(newtest.TestCase): def setUp(self): - raise newtest.Skipped + self.skip() def test_skip1(self): pass @@ -33,4 +33,4 @@ class TestSkip2(newtest.TestCase): def test_skip2(self): - raise newtest.Skipped + self.skip() From sschwarzer at codespeak.net Fri Dec 19 14:34:14 2003 From: sschwarzer at codespeak.net (sschwarzer at codespeak.net) Date: Fri, 19 Dec 2003 14:34:14 +0100 (MET) Subject: [pypy-svn] rev 2564 - pypy/trunk/src/pypy/tool Message-ID: <20031219133414.747175A8C2@thoth.codespeak.net> Author: sschwarzer Date: Fri Dec 19 14:34:13 2003 New Revision: 2564 Modified: pypy/trunk/src/pypy/tool/newtest.py Log: Previously, the test result wasn't Skipped if the exception was raised in the setUp method of TestCase. Modified: pypy/trunk/src/pypy/tool/newtest.py ============================================================================== --- pypy/trunk/src/pypy/tool/newtest.py (original) +++ pypy/trunk/src/pypy/tool/newtest.py Fri Dec 19 14:34:13 2003 @@ -266,8 +266,6 @@ if pretest is not None: pretest(self) - #FIXME raising Skipped in setUp should cause the result to be - # recognized as "skipped" try: try: testobject.setUp() @@ -275,7 +273,7 @@ raise except TestResult, result: # reconstruct TestResult object, implicitly set exception - result = result.__class__(msg=result.msg, item=self) + return result.__class__(msg=result.msg, item=self) except Exception, exc: return Error(msg=str(exc), item=self) @@ -415,8 +413,10 @@ def main(do_selftest=False): # possibly ignore dummy unit tests if do_selftest: + # include only selftest module filterfunc = lambda m: m.find("pypy.tool.testdata.") != -1 else: + # exclude selftest module filterfunc = lambda m: m.find("pypy.tool.testdata.") == -1 # collect tests ts = TestSuite() From pmaupin at codespeak.net Fri Dec 19 14:37:25 2003 From: pmaupin at codespeak.net (pmaupin at codespeak.net) Date: Fri, 19 Dec 2003 14:37:25 +0100 (MET) Subject: [pypy-svn] rev 2565 - pypy/trunk/src/pypy/interpreter Message-ID: <20031219133725.9BB0B5A8C2@thoth.codespeak.net> Author: pmaupin Date: Fri Dec 19 14:37:25 2003 New Revision: 2565 Modified: pypy/trunk/src/pypy/interpreter/module.py Log: Check that module attributes are strings Modified: pypy/trunk/src/pypy/interpreter/module.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/module.py (original) +++ pypy/trunk/src/pypy/interpreter/module.py Fri Dec 19 14:37:25 2003 @@ -5,6 +5,11 @@ from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.error import OperationError +def _checkattrtype(space, w_attr): + attr = space.unwrap(w_attr) + if not isinstance(attr, str): + raise OperationError(space.w_TypeError, + space.wrap('attribute name must be string')) class Module(Wrappable): """A module.""" @@ -16,6 +21,7 @@ def pypy_getattr(self, w_attr): space = self.space + _checkattrtype(space, w_attr) if space.is_true(space.eq(w_attr, space.wrap('__dict__'))): return self.w_dict try: @@ -27,10 +33,13 @@ raise OperationError(space.w_AttributeError, w_attr) def pypy_setattr(self, w_attr, w_value): - self.space.setitem(self.w_dict, w_attr, w_value) + space = self.space + _checkattrtype(space, w_attr) + space.setitem(self.w_dict, w_attr, w_value) def pypy_delattr(self, w_attr): space = self.space + _checkattrtype(space, w_attr) try: space.delitem(self.w_dict, w_attr) except OperationError, e: From pmaupin at codespeak.net Fri Dec 19 14:37:53 2003 From: pmaupin at codespeak.net (pmaupin at codespeak.net) Date: Fri, 19 Dec 2003 14:37:53 +0100 (MET) Subject: [pypy-svn] rev 2566 - pypy/trunk/src/pypy/objspace/std Message-ID: <20031219133753.470955A8C2@thoth.codespeak.net> Author: pmaupin Date: Fri Dec 19 14:37:52 2003 New Revision: 2566 Modified: pypy/trunk/src/pypy/objspace/std/typeobject.py Log: Reformat (break a line up) Modified: pypy/trunk/src/pypy/objspace/std/typeobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/typeobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/typeobject.py Fri Dec 19 14:37:52 2003 @@ -52,7 +52,8 @@ multimethods = getmultimethods(space.__class__, w_self.__class__) key = space.unwrap(w_key) if not isinstance(key, str): - raise OperationError(space.w_TypeError,space.wrap('attribute name must be string')) + raise OperationError(space.w_TypeError, + space.wrap('attribute name must be string')) try: code = multimethods[key] except KeyError: From sschwarzer at codespeak.net Fri Dec 19 14:39:23 2003 From: sschwarzer at codespeak.net (sschwarzer at codespeak.net) Date: Fri, 19 Dec 2003 14:39:23 +0100 (MET) Subject: [pypy-svn] rev 2567 - pypy/trunk/src/pypy/tool Message-ID: <20031219133923.8751F5A8C2@thoth.codespeak.net> Author: sschwarzer Date: Fri Dec 19 14:39:22 2003 New Revision: 2567 Modified: pypy/trunk/src/pypy/tool/newtest.py Log: Introduced underscores into some identifiers for better readability. This applies to set_exception, last_results, init_from_dir . Modified: pypy/trunk/src/pypy/tool/newtest.py ============================================================================== --- pypy/trunk/src/pypy/tool/newtest.py (original) +++ pypy/trunk/src/pypy/tool/newtest.py Fri Dec 19 14:39:22 2003 @@ -174,13 +174,13 @@ class TestResultWithTraceback(TestResult): def __init__(self, msg='', item=None): TestResult.__init__(self, msg, item) - self.setexception() + self.set_exception() def __eq__(self, other): return TestResult.__eq__(self, other) and \ self.formatted_traceback == other.formatted_traceback - def setexception(self): + def set_exception(self): self.excinfo = sys.exc_info() self.traceback = self.excinfo[2] # store formatted traceback @@ -314,7 +314,7 @@ """Represent a collection of test items.""" def __init__(self): self.items = [] - self.lastresult = {} + self.last_results = {} def _module_from_modpath(self, modpath): """ @@ -344,7 +344,7 @@ items.append(TestItem(module, obj, obj2)) return items - def initfromdir(self, dirname, filterfunc=None, recursive=True): + def init_from_dir(self, dirname, filterfunc=None, recursive=True): """ Init this suite by reading the directory denoted by dirname, then find all test modules in it. Test modules are files that @@ -391,20 +391,20 @@ will contain a dictionary named lastresult which maps these keys to a list of TestResult objects that correspond to the key. """ - self.lastresults = {} + self.last_results = {} for item in self.items: result = item.run() key = classify(result) - self.lastresults.setdefault(key, []).append(result) + self.last_results.setdefault(key, []).append(result) yield result def run(self): """ Run all the test items. After that, the results are available - via the attribute lastresults. + via the attribute last_results. """ # perform all the tests by using the existing generator; discard - # the results; they are then available via self.lastresults + # the results; they are then available via self.last_results [result for result in self.result_generator()] # @@ -421,7 +421,7 @@ # collect tests ts = TestSuite() print "Loading test modules ..." - ts.initfromdir(autopath.pypydir, filterfunc=filterfunc) + ts.init_from_dir(autopath.pypydir, filterfunc=filterfunc) # iterate over tests and collect data for res in ts.result_generator(): if res.traceback is None: @@ -433,15 +433,15 @@ print res.formatted_traceback # emit a summary print 79 * '=' - modules = ts.lastresults.keys() + modules = ts.last_results.keys() modules.sort() for module in modules: - results = ts.lastresults[module] + results = ts.last_results[module] resultstring = '' for result in results: - statuschar = {Success: '.', Ignored: 'i', Skipped: 's', - Error: 'E', Failure: 'F'}[result.__class__] - resultstring += statuschar + status_char = {Success: '.', Ignored: 'i', Skipped: 's', + Error: 'E', Failure: 'F'}[result.__class__] + resultstring += status_char print "%s [%d] %s" % (module, len(results), resultstring) From sschwarzer at codespeak.net Fri Dec 19 15:01:35 2003 From: sschwarzer at codespeak.net (sschwarzer at codespeak.net) Date: Fri, 19 Dec 2003 15:01:35 +0100 (MET) Subject: [pypy-svn] rev 2568 - in pypy/trunk/src/pypy/tool: . testdata Message-ID: <20031219140135.68FF85A8C2@thoth.codespeak.net> Author: sschwarzer Date: Fri Dec 19 15:01:34 2003 New Revision: 2568 Modified: pypy/trunk/src/pypy/tool/newtest.py pypy/trunk/src/pypy/tool/testdata/test_dummy.py Log: Include docstrings of module, class and test method in TestItem. Modified: pypy/trunk/src/pypy/tool/newtest.py ============================================================================== --- pypy/trunk/src/pypy/tool/newtest.py (original) +++ pypy/trunk/src/pypy/tool/newtest.py Fri Dec 19 15:01:34 2003 @@ -13,8 +13,7 @@ # - add support for ignored tests (do we need to differentiate between # skipped and ignored tests at all?) # - support TestItem.run with different object spaces -# - add docstring of loaded test method to TestItem -# - unify naming of methods/functions +# - unify naming of methods/functions; what about the TestCase class? # - support for pickling and retrieving TestItems and TestResults? # @@ -206,6 +205,10 @@ self.module = module self.cls = cls self.method = testmethod + # remove trailing whitespace but leave things such indentation + # of first line(s) alone + self.docs = (self._docstring(module), self._docstring(cls), + self._docstring(testmethod)) #XXX inspect.getsourcelines may fail if the file path stored # in a module's pyc/pyo file doesn't match the py file's # actual location. This can happen if a py file, together with @@ -216,6 +219,13 @@ # removing trailing newline(s) but not the indentation self.source = ''.join(lines).rstrip() + def _docstring(self, obj): + """ + Return the docstring of object obj or an empty string, if the + docstring doesn't exist, i. e. is None. + """ + return inspect.getdoc(obj) or "" + def __eq__(self, other): """ Return True if this and the other item compare equal. (This doesn't Modified: pypy/trunk/src/pypy/tool/testdata/test_dummy.py ============================================================================== --- pypy/trunk/src/pypy/tool/testdata/test_dummy.py (original) +++ pypy/trunk/src/pypy/tool/testdata/test_dummy.py Fri Dec 19 15:01:34 2003 @@ -1,7 +1,12 @@ +"""Module docstring.""" + import autopath from pypy.tool import newtest class TestDummy1(newtest.TestCase): + """ + Example of a docstring for a class. + """ def test_success1(self): self.assertEquals(1+1, 2) @@ -17,6 +22,7 @@ self.assertEquals(1+1, 2) def test_error2(self): + """Docstring of a method.""" raise ValueError def test_failure2(self): From sschwarzer at codespeak.net Fri Dec 19 15:44:44 2003 From: sschwarzer at codespeak.net (sschwarzer at codespeak.net) Date: Fri, 19 Dec 2003 15:44:44 +0100 (MET) Subject: [pypy-svn] rev 2569 - pypy/trunk/doc/devel Message-ID: <20031219144444.CFA745A8C2@thoth.codespeak.net> Author: sschwarzer Date: Fri Dec 19 15:44:44 2003 New Revision: 2569 Modified: pypy/trunk/doc/devel/testdesign.txt Log: Minor formatting changes. Modified: pypy/trunk/doc/devel/testdesign.txt ============================================================================== --- pypy/trunk/doc/devel/testdesign.txt (original) +++ pypy/trunk/doc/devel/testdesign.txt Fri Dec 19 15:44:44 2003 @@ -2,10 +2,12 @@ Test Design ============= -Our tests are based on the unittest framework. All tests of modules in a directory usually reside -in a subdirectory **test**. There are basically two types of unit tests: +Our tests are based on the unittest framework. All tests of modules +in a directory usually reside in a subdirectory **test**. There are +basically two types of unit tests: -- **Interpreter Level tests**. They run at the same level as PyPy's interpreter. +- **Interpreter Level tests**. They run at the same level as PyPy's + interpreter. - **Application Level tests**. They run at application level which means that they look like straight python code but they are interpreted by PyPy. @@ -15,26 +17,23 @@ can usually give the '-S', '-T' or '-A' switch for using the Standard, Trivial or Ann-ObjectSpace respectively. - Writing a test -------------- The best reference is to go to some test files and look how they are done. Almost all tests start with the following lines:: - import autopath - from pypy.tool import test + import autopath + from pypy.tool import test of which the first line determines the package path automatically by searching for **pypy** among the parents of the test-file's directory. The second line imports PyPy's test-hook of which ''test.main()'' is the most important -and is usually the last line of the testfile. -For more info please refer to a pypy-dev mail_ where the current testing -framework was introduced. - +and is usually the last line of the testfile. For more info please refer to +a pypy-dev mail_ where the current testing framework was introduced. Command line tool test_all ---------------------------- +-------------------------- You can run almost all of PyPy's tests by invoking:: @@ -43,12 +42,10 @@ which will run all tests against the Trivial Object Space. If you want to test against the StandardObjectSpace then issue:: - python test_all.py -S - For more switches invoke "python test_all.py -h". ------------------------------------------------------------------------------------------------ +------------------------------------------------------------------------------- .. _mail: http://codespeak.net/pipermail/pypy-dev/2003q2/000789.html From tomek at codespeak.net Fri Dec 19 15:53:12 2003 From: tomek at codespeak.net (tomek at codespeak.net) Date: Fri, 19 Dec 2003 15:53:12 +0100 (MET) Subject: [pypy-svn] rev 2570 - pypy/trunk/doc/devel Message-ID: <20031219145312.7E5A25A8C2@thoth.codespeak.net> Author: tomek Date: Fri Dec 19 15:53:11 2003 New Revision: 2570 Modified: pypy/trunk/doc/devel/howtosvn.txt Log: updated two links Modified: pypy/trunk/doc/devel/howtosvn.txt ============================================================================== --- pypy/trunk/doc/devel/howtosvn.txt (original) +++ pypy/trunk/doc/devel/howtosvn.txt Fri Dec 19 15:53:11 2003 @@ -120,13 +120,14 @@ -------------------------------------------------------------------------------- -.. _commandline: http://subversion.tigris.org/files/documents/15/7442/svn-0.32.1-setup.exe +.. _commandline: +http://subversion.tigris.org/files/documents/15/7442/svn-0.34.0-setup.exe .. _website: http://support.microsoft.com/default.aspx?scid=kb%3Ben-us%3B259403 .. _GUI: http://tortoisesvn.tigris.org/files/documents/406/7481/TortoiseSVN-0.21-UNICODE.msi .. _Win: http://www.microsoft.com/downloads/details.aspx?displaylang=en&FamilyID=4B6140F9-2D36-4977-8FA1-6F8A0F5DCA8F .. _MacOS: http://codespeak.net/~jum/svn-0.32.1-darwin-ppc.tar.gz .. _iconv: http://codespeak.net/~jum/iconv-darwin-ppc.tar.gz -.. _tarball: http://svn.collab.net/tarballs/subversion-0.32.1.tar.gz +.. _tarball: http://svn.collab.net/tarballs/subversion-0.34.0.tar.gz .. _guide: http://svnbook.red-bean.com/book.html#svn-ch-1 .. _archives: http://codespeak.net/pipermail/pypy-svn/ From guenter at codespeak.net Fri Dec 19 16:17:10 2003 From: guenter at codespeak.net (guenter at codespeak.net) Date: Fri, 19 Dec 2003 16:17:10 +0100 (MET) Subject: [pypy-svn] rev 2572 - pypy/trunk/src/pypy/objspace/std/test Message-ID: <20031219151710.C25765A8C2@thoth.codespeak.net> Author: guenter Date: Fri Dec 19 16:17:10 2003 New Revision: 2572 Modified: pypy/trunk/src/pypy/objspace/std/test/test_stringobject.py Log: test_translate runs now without import of string (Problems with string.maketrans) Modified: pypy/trunk/src/pypy/objspace/std/test/test_stringobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/test/test_stringobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/test/test_stringobject.py Fri Dec 19 16:17:10 2003 @@ -424,15 +424,27 @@ self.assertEquals("aaa AAA 111".swapcase(), "AAA aaa 111") self.assertEquals("".swapcase(), "") - """ def test_translate(self): - import string - string.maketrans('ae','ea') - s="abcde" - self.assertEquals('ebcda', s.translate(string.maketrans('ea','ae'))) - self.assertEquals('eda', s.translate(string.maketrans('ea','ae'),'bc')) - go away for now, - I am not working on you and you make errors... Laura """ + def maketrans(origin, image): + if len(origin) != len(image): + raise ValueError("maketrans arguments must have same length") + L = [chr(i) for i in range(256)] + for i in range(len(origin)): + L[ord(origin[i])] = image[i] + + tbl = ''.join(L) + return tbl + + table = maketrans('abc', 'xyz') + self.assertEquals('xyzxyz', 'xyzabcdef'.translate(table, 'def')) + + table = maketrans('a', 'A') + self.assertEquals('Abc', 'abc'.translate(table)) + self.assertEquals('xyz', 'xyz'.translate(table)) + self.assertEquals('yz', 'xyz'.translate(table, 'x')) + + #self.assertRaises(ValueError, 'xyz'.translate('too short', 'strip')) + #self.assertRaises(ValueError, 'xyz'.translate('too short')) def test_iter(self): l=[] From guenter at codespeak.net Fri Dec 19 16:19:09 2003 From: guenter at codespeak.net (guenter at codespeak.net) Date: Fri, 19 Dec 2003 16:19:09 +0100 (MET) Subject: [pypy-svn] rev 2573 - pypy/trunk/src/pypy/objspace/std Message-ID: <20031219151909.11F675AA0B@thoth.codespeak.net> Author: guenter Date: Fri Dec 19 16:19:08 2003 New Revision: 2573 Modified: pypy/trunk/src/pypy/objspace/std/stringobject.py Log: raise ValueError in translate when table has len different from 256 Modified: pypy/trunk/src/pypy/objspace/std/stringobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/stringobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/stringobject.py Fri Dec 19 16:19:08 2003 @@ -737,6 +737,9 @@ remaining characters have been mapped through the given translation table, which must be a string of length 256""" + if len(table) < 256: + raise ValueError("translation table must be 256 characters long") + L = [ table[ord(s[i])] for i in range(len(s)) if s[i] not in deletechars ] return ''.join(L) From sschwarzer at codespeak.net Fri Dec 19 16:51:40 2003 From: sschwarzer at codespeak.net (sschwarzer at codespeak.net) Date: Fri, 19 Dec 2003 16:51:40 +0100 (MET) Subject: [pypy-svn] rev 2575 - pypy/trunk/src/pypy/tool Message-ID: <20031219155140.070515A8C2@thoth.codespeak.net> Author: sschwarzer Date: Fri Dec 19 16:51:40 2003 New Revision: 2575 Modified: pypy/trunk/src/pypy/tool/newtest.py Log: Added UML class diagram of unit testing framework. Modified: pypy/trunk/src/pypy/tool/newtest.py ============================================================================== --- pypy/trunk/src/pypy/tool/newtest.py (original) +++ pypy/trunk/src/pypy/tool/newtest.py Fri Dec 19 16:51:40 2003 @@ -1,3 +1,32 @@ +""" +Unit testing framework for PyPy. + ++------------+ 1 1 +----------+ +| TestResult |----------------------------------------| TestItem | +| (abstract) | +----------+ ++------------+ | * + A | + - | + | | 1 + +----------------------------+-----------+ +-----------+ + | | | | TestSuite | ++-------------------------+ +---------+ +---------+ +-----------+ +| TestResultWithTraceback | | Success | | Skipped | A +| (abstract) | +---------+ +---------+ | ++-------------------------+ | loaded by + A A | + - - +------------+ + | | | TestCase | + | | | (abstract) | ++-------+ +---------+ +------------+ +| Error | | Failure | A ++-------+ +---------+ - + | + | + concrete test + case classes + +""" # for Python 2.2 compatibilty from __future__ import generators @@ -405,7 +434,7 @@ for item in self.items: result = item.run() key = classify(result) - self.last_results.setdefault(key, []).append(result) + self.last_resuaalts.setdefault(key, []).append(result) yield result def run(self): @@ -459,4 +488,4 @@ # used to avoid subtle problems with class matching after different # import statements from pypy.tool import newtest - newtest.main(do_selftest=True) + newtest.main(do_selftest=False) From hpk at codespeak.net Fri Dec 19 17:02:36 2003 From: hpk at codespeak.net (hpk at codespeak.net) Date: Fri, 19 Dec 2003 17:02:36 +0100 (MET) Subject: [pypy-svn] rev 2577 - pypy/trunk/doc Message-ID: <20031219160236.B0D225AA0B@thoth.codespeak.net> Author: hpk Date: Fri Dec 19 17:02:35 2003 New Revision: 2577 Added: pypy/trunk/doc/amsterdam.sxi (contents, props changed) Log: small architecture overview/presentation i did at the Amsterdam Sprint. OpenOffice format. Added: pypy/trunk/doc/amsterdam.sxi ============================================================================== Binary file. No diff available. From pmaupin at codespeak.net Fri Dec 19 17:10:12 2003 From: pmaupin at codespeak.net (pmaupin at codespeak.net) Date: Fri, 19 Dec 2003 17:10:12 +0100 (MET) Subject: [pypy-svn] rev 2578 - pypy/trunk/doc/devel Message-ID: <20031219161012.DD7B45AA0B@thoth.codespeak.net> Author: pmaupin Date: Fri Dec 19 17:10:11 2003 New Revision: 2578 Added: pypy/trunk/doc/devel/howtopypy.txt (contents, props changed) Modified: pypy/trunk/doc/devel/ (props changed) pypy/trunk/doc/devel/coding-style.txt (props changed) pypy/trunk/doc/devel/howtosvn.txt (contents, props changed) pypy/trunk/doc/devel/testdesign.txt (props changed) Log: Added howtopypy.txt Added: pypy/trunk/doc/devel/howtopypy.txt ============================================================================== --- (empty file) +++ pypy/trunk/doc/devel/howtopypy.txt Fri Dec 19 17:10:11 2003 @@ -0,0 +1,91 @@ +================================== +Getting started with PyPy +================================== + +PyPy sources can be browsed on the web at: + + ``http://codespeak.net/svn/pypy/trunk/`` + +If you are ready to download and try PyPy out: + +1. Download subversion_ if you do not already have it + +2. Use subversion to download the source: + + ``svn co http://codespeak.net/svn/pypy/trunk/src`` + + If desired, you can also download the documentation: + + ``svn co http://codespeak.net/svn/pypy/trunk/doc`` + +3. To start interpreting Python with PyPy: + + ``cd src/pypy/interpreter`` + ``python23 py.py -S`` + + After a few seconds, you should be at the PyPy prompt, which is + the same as the Python prompt, but with an extra ">". + + The "-S" given on the command line insructs the PyPy interpreter + to use the Standard_ `object space`_. PyPy has the concept of different + object spaces, but the standard space is the one which contains + the "real" Python interpreter. + +4. Now you are ready to start running Python code. Some real Python + modules will not run yet, and others will run too slowly to be + worth waiting for, but a few are fun to run: + + ``>>>> import pystone`` + ``>>>> pystone.main(2)`` + + Note that this is a slightly modified version of pystone -- the + original version does not accept the parameter to main(). The + parameter is the number of loops to run through the test, and the + default is 50000, which is far too many to run this year. + +5. The PyPy interpreter command line options are listed by typing + + ``python23 py.py --help`` + + As an example of using PyPy from the command line, you could type: + + ``python23 py.py -S -c "import pystone; pystone.main(2)`` + + Alternatively, as with regular Python, you can simply give a + script name on the command line: + + ``python23 py.py -S ../appspace/pystone.py`` + + (Note that this will run forever.) + +6. The PyPy project uses test-driven-development. Right now, there are + a couple of different categories of tests which can be run. + To run all the unit tests: + + ``cd src/pypy`` + ``python23 test_all.py -S`` + + Alternatively, subtests may be run by going to the correct subdirectory + and running them individually: + + ``cd src/pypy/module/test`` + ``python23 test_builtin.py -S`` + + Finally, there are some more advanced tests (which are derived from + some of the standard CPython tests). These are not part of the unit + tests, because they take longer than the standard unit tests. + + ``cd src/pypy/interpreter`` + ``python23 py.py -S -c "import builtin_types_test"`` + +7. To learn more about PyPy and its development process, read the documentation_, + and consider subscribing to the `mailing lists`_ (or simply read the archives + online) or communicating via irc.freenode.net:6667, channel #pypy. + +-------------------------------------------------------------------------------- + +.. _subversion: http://codespeak.net/pypy/index.cgi?doc/devel/howtosvn.html +.. _Standard: http://codespeak.net/pypy/index.cgi?doc/objspace/stdobjspace.html +.. _object space: http://codespeak.net/pypy/index.cgi?doc/objspace/objspace.html +.. _mailing lists: http://codespeak.net/pypy/index.cgi?lists +.. _documentation: http://codespeak.net/pypy/index.cgi?doc \ No newline at end of file Modified: pypy/trunk/doc/devel/howtosvn.txt ============================================================================== --- pypy/trunk/doc/devel/howtosvn.txt (original) +++ pypy/trunk/doc/devel/howtosvn.txt Fri Dec 19 17:10:11 2003 @@ -12,19 +12,19 @@ installation files which should help you to install subversion on your computer. -+ Unix source tarball_ ++ Download_ Unix source tarball or prepackaged versions for MacOS, Windows, FreeBSD and Linux -+ windows commandline_ utility ++ Additional information for Windows users: - (See Microsoft website_ if you have .DLL issues.) + * See Microsoft website_ if you have .DLL issues. -+ Windows Installer file for Tortoise SVN (like Tortoise CVS) GUI_ + * Windows Installer file for Tortoise SVN (like Tortoise CVS) GUI_ - (See Win_ 2000, NT if you have problems loading it.) + (See Win_ 2000, NT if you have problems loading it.) -+ MacOS_ X binary tar ball ++ Local copy of MacOS_ X binary tar ball - this will also need iconv_ MacOS X tar ball + * this will also need iconv_ MacOS X tar ball + Debian instructions below... @@ -127,7 +127,7 @@ .. _Win: http://www.microsoft.com/downloads/details.aspx?displaylang=en&FamilyID=4B6140F9-2D36-4977-8FA1-6F8A0F5DCA8F .. _MacOS: http://codespeak.net/~jum/svn-0.32.1-darwin-ppc.tar.gz .. _iconv: http://codespeak.net/~jum/iconv-darwin-ppc.tar.gz -.. _tarball: http://svn.collab.net/tarballs/subversion-0.34.0.tar.gz +.. _Download: http://subversion.tigris.org/project_packages.html .. _guide: http://svnbook.red-bean.com/book.html#svn-ch-1 .. _archives: http://codespeak.net/pipermail/pypy-svn/ From pmaupin at codespeak.net Fri Dec 19 17:11:54 2003 From: pmaupin at codespeak.net (pmaupin at codespeak.net) Date: Fri, 19 Dec 2003 17:11:54 +0100 (MET) Subject: [pypy-svn] rev 2579 - pypy/trunk/doc/devel Message-ID: <20031219161154.0C2D75AA0B@thoth.codespeak.net> Author: pmaupin Date: Fri Dec 19 17:11:53 2003 New Revision: 2579 Modified: pypy/trunk/doc/devel/howtopypy.txt Log: Bug fixes Modified: pypy/trunk/doc/devel/howtopypy.txt ============================================================================== --- pypy/trunk/doc/devel/howtopypy.txt (original) +++ pypy/trunk/doc/devel/howtopypy.txt Fri Dec 19 17:11:53 2003 @@ -21,6 +21,7 @@ 3. To start interpreting Python with PyPy: ``cd src/pypy/interpreter`` + ``python23 py.py -S`` After a few seconds, you should be at the PyPy prompt, which is @@ -36,6 +37,7 @@ worth waiting for, but a few are fun to run: ``>>>> import pystone`` + ``>>>> pystone.main(2)`` Note that this is a slightly modified version of pystone -- the @@ -63,12 +65,14 @@ To run all the unit tests: ``cd src/pypy`` + ``python23 test_all.py -S`` Alternatively, subtests may be run by going to the correct subdirectory and running them individually: ``cd src/pypy/module/test`` + ``python23 test_builtin.py -S`` Finally, there are some more advanced tests (which are derived from @@ -76,6 +80,7 @@ tests, because they take longer than the standard unit tests. ``cd src/pypy/interpreter`` + ``python23 py.py -S -c "import builtin_types_test"`` 7. To learn more about PyPy and its development process, read the documentation_, From sschwarzer at codespeak.net Fri Dec 19 17:16:51 2003 From: sschwarzer at codespeak.net (sschwarzer at codespeak.net) Date: Fri, 19 Dec 2003 17:16:51 +0100 (MET) Subject: [pypy-svn] rev 2580 - pypy/trunk/src/pypy/tool Message-ID: <20031219161651.207175AA0B@thoth.codespeak.net> Author: sschwarzer Date: Fri Dec 19 17:16:50 2003 New Revision: 2580 Modified: pypy/trunk/src/pypy/tool/newtest.py Log: Added more documentation to the docstring. Modified: pypy/trunk/src/pypy/tool/newtest.py ============================================================================== --- pypy/trunk/src/pypy/tool/newtest.py (original) +++ pypy/trunk/src/pypy/tool/newtest.py Fri Dec 19 17:16:50 2003 @@ -1,6 +1,8 @@ """ Unit testing framework for PyPy. +The following picture is an UML class diagram of the framework. + +------------+ 1 1 +----------+ | TestResult |----------------------------------------| TestItem | | (abstract) | +----------+ @@ -15,18 +17,48 @@ | (abstract) | +---------+ +---------+ | +-------------------------+ | loaded by A A | - - - +------------+ + - - | * + | | +------------+ | | | TestCase | - | | | (abstract) | -+-------+ +---------+ +------------+ -| Error | | Failure | A -+-------+ +---------+ - ++-------+ +---------+ | (abstract) | +| Error | | Failure | +------------+ ++-------+ +---------+ A + - | | concrete test case classes +Like the unittest framework of Python, our framework implements +tests as test methods in TestCase classes. Custom test case classes +derive from the shown TestCase class, defined in this module. As in +Python's unittest, a test case class can contain setUp and tearDown +methods. Additionally, it contains a method 'skip' which can be +called to stop a test prematurely. This won't be counted as a failure. + +Test cases are loaded by a TestSuite class via the method init_from_dir. +init_from_dir will read all test modules in and below a specified +directory, inspect them for classes derived from TestCase (i. e. _our_ +TestCase), and in turn inspect them for test methods (like in +unittest, all methods which start with "test"). + +For every found method, TestSuite will store it's module, class, +unbound method objects in a TestItem object. There are also other +properties stored, e. g. the source code for each method and its +docstring. + +When the TestSuite's method 'run' is called, all collected TestItems +are run and, according to the outcome of the test, a TestResult object +is generated which holds a reference to "its" TestItem object. + +The TestResult classes Success and Skipped denote a passed test. A +skipped test means that not all test code has been run (and no error +or failure occurred before the skip method was called). If a test +fails, resulting in a Failure object, a test, e. g. tested with +assertEqual, has failed. An Error object is generated if something +else causes an unforeseen exception to be raised. """ + # for Python 2.2 compatibilty from __future__ import generators From pmaupin at codespeak.net Fri Dec 19 17:17:16 2003 From: pmaupin at codespeak.net (pmaupin at codespeak.net) Date: Fri, 19 Dec 2003 17:17:16 +0100 (MET) Subject: [pypy-svn] rev 2581 - pypy/trunk/doc/devel Message-ID: <20031219161716.52BAC5AA0B@thoth.codespeak.net> Author: pmaupin Date: Fri Dec 19 17:17:15 2003 New Revision: 2581 Modified: pypy/trunk/doc/devel/howtosvn.txt Log: Bug fixes Modified: pypy/trunk/doc/devel/howtosvn.txt ============================================================================== --- pypy/trunk/doc/devel/howtosvn.txt (original) +++ pypy/trunk/doc/devel/howtosvn.txt Fri Dec 19 17:17:15 2003 @@ -12,7 +12,7 @@ installation files which should help you to install subversion on your computer. -+ Download_ Unix source tarball or prepackaged versions for MacOS, Windows, FreeBSD and Linux ++ Download Unix source tarball or prepackaged versions_ for MacOS, Windows, FreeBSD and Linux + Additional information for Windows users: @@ -120,6 +120,7 @@ -------------------------------------------------------------------------------- + .. _commandline: http://subversion.tigris.org/files/documents/15/7442/svn-0.34.0-setup.exe .. _website: http://support.microsoft.com/default.aspx?scid=kb%3Ben-us%3B259403 @@ -127,7 +128,7 @@ .. _Win: http://www.microsoft.com/downloads/details.aspx?displaylang=en&FamilyID=4B6140F9-2D36-4977-8FA1-6F8A0F5DCA8F .. _MacOS: http://codespeak.net/~jum/svn-0.32.1-darwin-ppc.tar.gz .. _iconv: http://codespeak.net/~jum/iconv-darwin-ppc.tar.gz -.. _Download: http://subversion.tigris.org/project_packages.html +.. _versions: http://subversion.tigris.org/project_packages.html .. _guide: http://svnbook.red-bean.com/book.html#svn-ch-1 .. _archives: http://codespeak.net/pipermail/pypy-svn/ From pmaupin at codespeak.net Fri Dec 19 17:18:25 2003 From: pmaupin at codespeak.net (pmaupin at codespeak.net) Date: Fri, 19 Dec 2003 17:18:25 +0100 (MET) Subject: [pypy-svn] rev 2582 - pypy/trunk/doc/devel Message-ID: <20031219161825.CE82E5AA0B@thoth.codespeak.net> Author: pmaupin Date: Fri Dec 19 17:18:25 2003 New Revision: 2582 Modified: pypy/trunk/doc/devel/howtosvn.txt Log: Bug fixes Modified: pypy/trunk/doc/devel/howtosvn.txt ============================================================================== --- pypy/trunk/doc/devel/howtosvn.txt (original) +++ pypy/trunk/doc/devel/howtosvn.txt Fri Dec 19 17:18:25 2003 @@ -121,8 +121,7 @@ -------------------------------------------------------------------------------- -.. _commandline: -http://subversion.tigris.org/files/documents/15/7442/svn-0.34.0-setup.exe +.. _commandline: http://subversion.tigris.org/files/documents/15/7442/svn-0.34.0-setup.exe .. _website: http://support.microsoft.com/default.aspx?scid=kb%3Ben-us%3B259403 .. _GUI: http://tortoisesvn.tigris.org/files/documents/406/7481/TortoiseSVN-0.21-UNICODE.msi .. _Win: http://www.microsoft.com/downloads/details.aspx?displaylang=en&FamilyID=4B6140F9-2D36-4977-8FA1-6F8A0F5DCA8F From pmaupin at codespeak.net Fri Dec 19 17:21:36 2003 From: pmaupin at codespeak.net (pmaupin at codespeak.net) Date: Fri, 19 Dec 2003 17:21:36 +0100 (MET) Subject: [pypy-svn] rev 2583 - pypy/trunk/doc/devel Message-ID: <20031219162136.BEF6E5AA0B@thoth.codespeak.net> Author: pmaupin Date: Fri Dec 19 17:21:35 2003 New Revision: 2583 Modified: pypy/trunk/doc/devel/howtopypy.txt Log: Formatting test change Modified: pypy/trunk/doc/devel/howtopypy.txt ============================================================================== --- pypy/trunk/doc/devel/howtopypy.txt (original) +++ pypy/trunk/doc/devel/howtopypy.txt Fri Dec 19 17:21:35 2003 @@ -10,9 +10,9 @@ 1. Download subversion_ if you do not already have it -2. Use subversion to download the source: +2. Use subversion to download the source:: - ``svn co http://codespeak.net/svn/pypy/trunk/src`` + svn co http://codespeak.net/svn/pypy/trunk/src If desired, you can also download the documentation: From pmaupin at codespeak.net Fri Dec 19 17:24:22 2003 From: pmaupin at codespeak.net (pmaupin at codespeak.net) Date: Fri, 19 Dec 2003 17:24:22 +0100 (MET) Subject: [pypy-svn] rev 2584 - pypy/trunk/doc/devel Message-ID: <20031219162422.9C41F5AA0B@thoth.codespeak.net> Author: pmaupin Date: Fri Dec 19 17:24:21 2003 New Revision: 2584 Modified: pypy/trunk/doc/devel/howtopypy.txt Log: Formatting test change Modified: pypy/trunk/doc/devel/howtopypy.txt ============================================================================== --- pypy/trunk/doc/devel/howtopypy.txt (original) +++ pypy/trunk/doc/devel/howtopypy.txt Fri Dec 19 17:24:21 2003 @@ -14,15 +14,14 @@ svn co http://codespeak.net/svn/pypy/trunk/src - If desired, you can also download the documentation: + If desired, you can also download the documentation:: - ``svn co http://codespeak.net/svn/pypy/trunk/doc`` + svn co http://codespeak.net/svn/pypy/trunk/doc -3. To start interpreting Python with PyPy: +3. To start interpreting Python with PyPy:: - ``cd src/pypy/interpreter`` - - ``python23 py.py -S`` + cd src/pypy/interpreter + python23 py.py -S After a few seconds, you should be at the PyPy prompt, which is the same as the Python prompt, but with an extra ">". @@ -34,54 +33,50 @@ 4. Now you are ready to start running Python code. Some real Python modules will not run yet, and others will run too slowly to be - worth waiting for, but a few are fun to run: + worth waiting for, but a few are fun to run:: - ``>>>> import pystone`` - - ``>>>> pystone.main(2)`` + >>>> import pystone + >>>> pystone.main(2) Note that this is a slightly modified version of pystone -- the original version does not accept the parameter to main(). The parameter is the number of loops to run through the test, and the default is 50000, which is far too many to run this year. -5. The PyPy interpreter command line options are listed by typing +5. The PyPy interpreter command line options are listed by typing:: - ``python23 py.py --help`` + python23 py.py --help - As an example of using PyPy from the command line, you could type: + As an example of using PyPy from the command line, you could type:: - ``python23 py.py -S -c "import pystone; pystone.main(2)`` + python23 py.py -S -c "import pystone; pystone.main(2) Alternatively, as with regular Python, you can simply give a - script name on the command line: + script name on the command line:: - ``python23 py.py -S ../appspace/pystone.py`` + python23 py.py -S ../appspace/pystone.py (Note that this will run forever.) 6. The PyPy project uses test-driven-development. Right now, there are a couple of different categories of tests which can be run. - To run all the unit tests: - - ``cd src/pypy`` + To run all the unit tests:: - ``python23 test_all.py -S`` + cd src/pypy + python23 test_all.py -S Alternatively, subtests may be run by going to the correct subdirectory - and running them individually: + and running them individually:: - ``cd src/pypy/module/test`` - - ``python23 test_builtin.py -S`` + cd src/pypy/module/test + python23 test_builtin.py -S Finally, there are some more advanced tests (which are derived from some of the standard CPython tests). These are not part of the unit - tests, because they take longer than the standard unit tests. - - ``cd src/pypy/interpreter`` + tests, because they take longer than the standard unit tests:: - ``python23 py.py -S -c "import builtin_types_test"`` + cd src/pypy/interpreter + python23 py.py -S -c "import builtin_types_test" 7. To learn more about PyPy and its development process, read the documentation_, and consider subscribing to the `mailing lists`_ (or simply read the archives From pmaupin at codespeak.net Fri Dec 19 17:26:29 2003 From: pmaupin at codespeak.net (pmaupin at codespeak.net) Date: Fri, 19 Dec 2003 17:26:29 +0100 (MET) Subject: [pypy-svn] rev 2585 - pypy/trunk/doc/devel Message-ID: <20031219162629.1D7FB5AA0B@thoth.codespeak.net> Author: pmaupin Date: Fri Dec 19 17:26:28 2003 New Revision: 2585 Modified: pypy/trunk/doc/devel/howtopypy.txt Log: Formatting test change Modified: pypy/trunk/doc/devel/howtopypy.txt ============================================================================== --- pypy/trunk/doc/devel/howtopypy.txt (original) +++ pypy/trunk/doc/devel/howtopypy.txt Fri Dec 19 17:26:28 2003 @@ -10,6 +10,7 @@ 1. Download subversion_ if you do not already have it + 2. Use subversion to download the source:: svn co http://codespeak.net/svn/pypy/trunk/src @@ -17,6 +18,7 @@ If desired, you can also download the documentation:: svn co http://codespeak.net/svn/pypy/trunk/doc + 3. To start interpreting Python with PyPy:: @@ -31,6 +33,7 @@ object spaces, but the standard space is the one which contains the "real" Python interpreter. + 4. Now you are ready to start running Python code. Some real Python modules will not run yet, and others will run too slowly to be worth waiting for, but a few are fun to run:: @@ -43,6 +46,7 @@ parameter is the number of loops to run through the test, and the default is 50000, which is far too many to run this year. + 5. The PyPy interpreter command line options are listed by typing:: python23 py.py --help @@ -58,6 +62,7 @@ (Note that this will run forever.) + 6. The PyPy project uses test-driven-development. Right now, there are a couple of different categories of tests which can be run. To run all the unit tests:: @@ -78,6 +83,7 @@ cd src/pypy/interpreter python23 py.py -S -c "import builtin_types_test" + 7. To learn more about PyPy and its development process, read the documentation_, and consider subscribing to the `mailing lists`_ (or simply read the archives online) or communicating via irc.freenode.net:6667, channel #pypy. From jacob at codespeak.net Fri Dec 19 17:28:07 2003 From: jacob at codespeak.net (jacob at codespeak.net) Date: Fri, 19 Dec 2003 17:28:07 +0100 (MET) Subject: [pypy-svn] rev 2586 - pypy/trunk/doc/overview Message-ID: <20031219162807.A816D5AA0B@thoth.codespeak.net> Author: jacob Date: Fri Dec 19 17:28:06 2003 New Revision: 2586 Added: pypy/trunk/doc/overview/ pypy/trunk/doc/overview/architecture Log: Initial arcitecture description. Added: pypy/trunk/doc/overview/architecture ============================================================================== --- (empty file) +++ pypy/trunk/doc/overview/architecture Fri Dec 19 17:28:06 2003 @@ -0,0 +1,71 @@ +PyPy - an implementation of Python in Python + +Architecture overview +===================== +In its current, rather simple incarnation Pypy has 2 major parts - The +interpreter and an object space. Both parts are implemented in Python +and run under CPython. + +The Interpreter +=============== +The interpreter accepts a Python source code file and turns it into a +series of byte codes, which are stored in .pyc file. The byte codes +are instructions for a virtual machine, just like with regular +CPython. + +The interpreter then takes the bytecodes one by one and performs +whatever the bytecode instructs it to do. For all operations that +affect objects, the actual change of the object is delegated to the +object space. + +The Object Space +================ +The object space contains all objects that have been created and knows +how to perform operations on the objects. We currently have 2 working +object spaces which are more or less interchangeable: + +- The trivial object space, which is a thin wrapper around CPython +types. It was used to test the interpreter and is used from time to +time for testing purposes. It is currently of little interest. + +- The standard object space, which is an almost complete +implementation of Python types in Python. This is the main focus of +this document, since it is the foundation of PyPy. + +The Standard Object Space +========================= +The Standard Object Space (SOS) itself is an object which implements a +number of logistic services. At startup the SOS examines certain +directories for modules that contain the implementation of the available +Python types. It loads each such module, which in turn registers its +type and all the operations on the type in multimethods in the SOS. + +Later in the execution, when the interpreter delegates the execution +of an instruction to the SOS, the correct operation to perform is +selected through the multimethod. + +We will examine how the multimethod mechanism works through an example. + +We examine the types float and int and disregard all other types for +the moment. Each type has an __add__ operator, which is registered +with the SOS at startup. The float add operator is registered with the +type signature __add__(Float, Float) and the integer add operator is +registered with the signature __add__(Int, Int). + +If we in our application program write the expression 2+3, the +interpreter will create an object containing the value 2 and an object +containing the value 3. We annotate these as Int(2) and Int(3) +respectively. The interpreter then calls the SOS with +__add__(Int(2), Int(3)). + +The SOS then looks in its __add__ multimethod and finds a version that +has the signature __add__(Int, Int). Since this is a direct hit, it +can immediately dispatch the operation to the correct method. + +If we don't have any registered functions with the correct signature, +as we would if we had the expression 2+3.0, we will test if we can use +coercion to find a function with a signature that works. In this case +we would coerce Int(2) to Float(2.0) in order to find a function in +the multimethod that has a correct signature. + + From hpk at codespeak.net Fri Dec 19 17:30:03 2003 From: hpk at codespeak.net (hpk at codespeak.net) Date: Fri, 19 Dec 2003 17:30:03 +0100 (MET) Subject: [pypy-svn] rev 2587 - in pypy/trunk/src/pypy/tool: . testdata Message-ID: <20031219163003.C0CE05AA0B@thoth.codespeak.net> Author: hpk Date: Fri Dec 19 17:30:03 2003 New Revision: 2587 Modified: pypy/trunk/src/pypy/tool/newtest.py pypy/trunk/src/pypy/tool/testdata/ (props changed) pypy/trunk/src/pypy/tool/testdata/__init__.py (props changed) pypy/trunk/src/pypy/tool/testdata/test_dummy.py (props changed) pypy/trunk/src/pypy/tool/traceinteractive.py (props changed) Log: fixeol + minor changes to the newtest module Modified: pypy/trunk/src/pypy/tool/newtest.py ============================================================================== --- pypy/trunk/src/pypy/tool/newtest.py (original) +++ pypy/trunk/src/pypy/tool/newtest.py Fri Dec 19 17:30:03 2003 @@ -466,7 +466,7 @@ for item in self.items: result = item.run() key = classify(result) - self.last_resuaalts.setdefault(key, []).append(result) + self.last_results.setdefault(key, []).append(result) yield result def run(self): @@ -476,7 +476,7 @@ """ # perform all the tests by using the existing generator; discard # the results; they are then available via self.last_results - [result for result in self.result_generator()] + return [result for result in self.result_generator()] # # demonstrate test framework usage From pmaupin at codespeak.net Fri Dec 19 17:31:19 2003 From: pmaupin at codespeak.net (pmaupin at codespeak.net) Date: Fri, 19 Dec 2003 17:31:19 +0100 (MET) Subject: [pypy-svn] rev 2588 - pypy/trunk/doc/devel Message-ID: <20031219163119.6F0B25AA0B@thoth.codespeak.net> Author: pmaupin Date: Fri Dec 19 17:31:18 2003 New Revision: 2588 Modified: pypy/trunk/doc/devel/howtopypy.txt Log: Added reference to moin Modified: pypy/trunk/doc/devel/howtopypy.txt ============================================================================== --- pypy/trunk/doc/devel/howtopypy.txt (original) +++ pypy/trunk/doc/devel/howtopypy.txt Fri Dec 19 17:31:18 2003 @@ -84,9 +84,9 @@ python23 py.py -S -c "import builtin_types_test" -7. To learn more about PyPy and its development process, read the documentation_, - and consider subscribing to the `mailing lists`_ (or simply read the archives - online) or communicating via irc.freenode.net:6667, channel #pypy. +7. To learn more about PyPy and its development process, read the documentation_ + and the moin_, and consider subscribing to the `mailing lists`_ (or simply + read the archives online) or communicating via irc.freenode.net:6667, channel #pypy. -------------------------------------------------------------------------------- @@ -94,4 +94,5 @@ .. _Standard: http://codespeak.net/pypy/index.cgi?doc/objspace/stdobjspace.html .. _object space: http://codespeak.net/pypy/index.cgi?doc/objspace/objspace.html .. _mailing lists: http://codespeak.net/pypy/index.cgi?lists -.. _documentation: http://codespeak.net/pypy/index.cgi?doc \ No newline at end of file +.. _documentation: http://codespeak.net/pypy/index.cgi?doc +.. _moin: http://codespeak.net/moin/pypy/moin.cgi/FrontPage?action=show \ No newline at end of file From sschwarzer at codespeak.net Fri Dec 19 17:33:31 2003 From: sschwarzer at codespeak.net (sschwarzer at codespeak.net) Date: Fri, 19 Dec 2003 17:33:31 +0100 (MET) Subject: [pypy-svn] rev 2590 - pypy/trunk/src/pypy/tool Message-ID: <20031219163331.592995A8C2@thoth.codespeak.net> Author: sschwarzer Date: Fri Dec 19 17:33:30 2003 New Revision: 2590 Modified: pypy/trunk/src/pypy/tool/newtest.py Log: Fixed docstring of TestSuite.run . Modified: pypy/trunk/src/pypy/tool/newtest.py ============================================================================== --- pypy/trunk/src/pypy/tool/newtest.py (original) +++ pypy/trunk/src/pypy/tool/newtest.py Fri Dec 19 17:33:30 2003 @@ -471,8 +471,8 @@ def run(self): """ - Run all the test items. After that, the results are available - via the attribute last_results. + Run all the test items and return a list of the results. After + that, the results are available via the attribute last_results. """ # perform all the tests by using the existing generator; discard # the results; they are then available via self.last_results From sschwarzer at codespeak.net Fri Dec 19 17:49:13 2003 From: sschwarzer at codespeak.net (sschwarzer at codespeak.net) Date: Fri, 19 Dec 2003 17:49:13 +0100 (MET) Subject: [pypy-svn] rev 2591 - pypy/trunk/src/pypy/tool Message-ID: <20031219164913.10C775AA0B@thoth.codespeak.net> Author: sschwarzer Date: Fri Dec 19 17:49:12 2003 New Revision: 2591 Modified: pypy/trunk/src/pypy/tool/newtest.py Log: Fixed some typos in the docstring. Modified: pypy/trunk/src/pypy/tool/newtest.py ============================================================================== --- pypy/trunk/src/pypy/tool/newtest.py (original) +++ pypy/trunk/src/pypy/tool/newtest.py Fri Dec 19 17:49:12 2003 @@ -34,15 +34,16 @@ derive from the shown TestCase class, defined in this module. As in Python's unittest, a test case class can contain setUp and tearDown methods. Additionally, it contains a method 'skip' which can be -called to stop a test prematurely. This won't be counted as a failure. +called to stop a test prematurely. This won't be counted as a failure +or error. Test cases are loaded by a TestSuite class via the method init_from_dir. -init_from_dir will read all test modules in and below a specified +This method will read all test modules in and below a specified directory, inspect them for classes derived from TestCase (i. e. _our_ TestCase), and in turn inspect them for test methods (like in unittest, all methods which start with "test"). -For every found method, TestSuite will store it's module, class, +For every found method, TestSuite will store its module, class and unbound method objects in a TestItem object. There are also other properties stored, e. g. the source code for each method and its docstring. From sschwarzer at codespeak.net Fri Dec 19 17:52:05 2003 From: sschwarzer at codespeak.net (sschwarzer at codespeak.net) Date: Fri, 19 Dec 2003 17:52:05 +0100 (MET) Subject: [pypy-svn] rev 2592 - pypy/trunk/doc/devel Message-ID: <20031219165205.C4F495AA0B@thoth.codespeak.net> Author: sschwarzer Date: Fri Dec 19 17:52:04 2003 New Revision: 2592 Modified: pypy/trunk/doc/devel/testdesign.txt Log: Added information on new unit testing framework. Modified: pypy/trunk/doc/devel/testdesign.txt ============================================================================== --- pypy/trunk/doc/devel/testdesign.txt (original) +++ pypy/trunk/doc/devel/testdesign.txt Fri Dec 19 17:52:04 2003 @@ -6,8 +6,8 @@ in a directory usually reside in a subdirectory **test**. There are basically two types of unit tests: -- **Interpreter Level tests**. They run at the same level as PyPy's - interpreter. +- **Interpreter Level tests**. They run at the same level as PyPy's + interpreter. - **Application Level tests**. They run at application level which means that they look like straight python code but they are interpreted by PyPy. @@ -15,12 +15,12 @@ Both types of tests need an object-space they can run with (the interpreter dispatches operations on objects to an objectspace). If you run a test you can usually give the '-S', '-T' or '-A' switch for using the Standard, Trivial -or Ann-ObjectSpace respectively. +or Ann-ObjectSpace respectively. -Writing a test +Writing a test -------------- -The best reference is to go to some test files and look how they are done. +The best reference is to go to some test files and look how they are done. Almost all tests start with the following lines:: import autopath @@ -30,7 +30,7 @@ for **pypy** among the parents of the test-file's directory. The second line imports PyPy's test-hook of which ''test.main()'' is the most important and is usually the last line of the testfile. For more info please refer to -a pypy-dev mail_ where the current testing framework was introduced. +a pypy-dev mail_ where the current testing framework was introduced. Command line tool test_all -------------------------- @@ -39,7 +39,7 @@ python test_all.py -which will run all tests against the Trivial Object Space. If you want +which will run all tests against the Trivial Object Space. If you want to test against the StandardObjectSpace then issue:: python test_all.py -S @@ -49,3 +49,83 @@ ------------------------------------------------------------------------------- .. _mail: http://codespeak.net/pipermail/pypy-dev/2003q2/000789.html + +New unit testing framework (not ready yet) +------------------------------------------ + +Current implementation +~~~~~~~~~~~~~~~~~~~~~~ + +The following picture is an UML class diagram of the framework. This +diagram is taken from the source code, which can currently be found +at src/pypy/tool/newtest.py as of 2003-12-19. (Most probably, the name +of the file will change, however.) + +:: + + +------------+ 1 1 +----------+ + | TestResult |----------------------------------------| TestItem | + | (abstract) | +----------+ + +------------+ | * + A | + - | + | | 1 + +----------------------------+-----------+ +-----------+ + | | | | TestSuite | + +-------------------------+ +---------+ +---------+ +-----------+ + | TestResultWithTraceback | | Success | | Skipped | A + | (abstract) | +---------+ +---------+ | + +-------------------------+ | loaded by + A A | + - - | * + | | +------------+ + | | | TestCase | + +-------+ +---------+ | (abstract) | + | Error | | Failure | +------------+ + +-------+ +---------+ A + - + | + | + concrete test + case classes + +Like the unittest framework of Python, our framework implements +tests as test methods in TestCase classes. Custom test case classes +derive from the shown TestCase class, defined in this module. As in +Python's unittest, a test case class can contain setUp and tearDown +methods. Additionally, it contains a method 'skip' which can be +called to stop a test prematurely. This won't be counted as a failure +or error. + +Test cases are loaded by a TestSuite class via the method init_from_dir. +This method will read all test modules in and below a specified +directory, inspect them for classes derived from TestCase (i. e. *our* +TestCase), and in turn inspect them for test methods (like in +unittest, all methods which start with "test"). + +For every found method, TestSuite will store its module, class and +unbound method objects in a TestItem object. There are also other +properties stored, e. g. the source code for each method and its +docstring. + +When the TestSuite's method 'run' is called, all collected TestItems +are run and, according to the outcome of the test, a TestResult object +is generated which holds a reference to "its" TestItem object. + +The TestResult classes Success and Skipped denote a passed test. A +skipped test means that not all test code has been run (and no error +or failure occurred before the skip method was called). If a test +fails, resulting in a Failure object, a test, e. g. tested with +assertEqual, has failed. An Error object is generated if something +else causes an unforeseen exception to be raised. + +Outlook +~~~~~~~ + +To be directly usable for the PyPy project, the selection of specific +object spaces has to be implemented. Moreover, the existing test +modules have to be converted. Because the TestCase class interface +remains compatible, this should only involve changes which can be +performed automatically, that is, changing the import statement for +this test module and the base class of test cases. + From pmaupin at codespeak.net Fri Dec 19 17:56:01 2003 From: pmaupin at codespeak.net (pmaupin at codespeak.net) Date: Fri, 19 Dec 2003 17:56:01 +0100 (MET) Subject: [pypy-svn] rev 2594 - pypy/trunk/doc/devel Message-ID: <20031219165601.5B90E5A8C2@thoth.codespeak.net> Author: pmaupin Date: Fri Dec 19 17:56:00 2003 New Revision: 2594 Modified: pypy/trunk/doc/devel/howtopypy.txt Log: Minor cleanup Modified: pypy/trunk/doc/devel/howtopypy.txt ============================================================================== --- pypy/trunk/doc/devel/howtopypy.txt (original) +++ pypy/trunk/doc/devel/howtopypy.txt Fri Dec 19 17:56:00 2003 @@ -20,10 +20,10 @@ svn co http://codespeak.net/svn/pypy/trunk/doc -3. To start interpreting Python with PyPy:: +3. To start interpreting Python with PyPy, use Python 2.3 or greater:: cd src/pypy/interpreter - python23 py.py -S + python py.py -S After a few seconds, you should be at the PyPy prompt, which is the same as the Python prompt, but with an extra ">". @@ -39,26 +39,27 @@ worth waiting for, but a few are fun to run:: >>>> import pystone - >>>> pystone.main(2) + >>>> pystone.main(10) Note that this is a slightly modified version of pystone -- the original version does not accept the parameter to main(). The parameter is the number of loops to run through the test, and the - default is 50000, which is far too many to run this year. + default is 50000, which is far too many to run in a reasonable time + on the current PyPy implementation. 5. The PyPy interpreter command line options are listed by typing:: - python23 py.py --help + python py.py --help As an example of using PyPy from the command line, you could type:: - python23 py.py -S -c "import pystone; pystone.main(2) + python py.py -S -c "import pystone; pystone.main(10)" Alternatively, as with regular Python, you can simply give a script name on the command line:: - python23 py.py -S ../appspace/pystone.py + python py.py -S ../appspace/pystone.py (Note that this will run forever.) @@ -68,24 +69,24 @@ To run all the unit tests:: cd src/pypy - python23 test_all.py -S + python test_all.py -S Alternatively, subtests may be run by going to the correct subdirectory and running them individually:: cd src/pypy/module/test - python23 test_builtin.py -S + python test_builtin.py -S Finally, there are some more advanced tests (which are derived from some of the standard CPython tests). These are not part of the unit tests, because they take longer than the standard unit tests:: cd src/pypy/interpreter - python23 py.py -S -c "import builtin_types_test" + python py.py -S -c "import builtin_types_test" 7. To learn more about PyPy and its development process, read the documentation_ - and the moin_, and consider subscribing to the `mailing lists`_ (or simply + and the wiki_, and consider subscribing to the `mailing lists`_ (or simply read the archives online) or communicating via irc.freenode.net:6667, channel #pypy. -------------------------------------------------------------------------------- @@ -95,4 +96,4 @@ .. _object space: http://codespeak.net/pypy/index.cgi?doc/objspace/objspace.html .. _mailing lists: http://codespeak.net/pypy/index.cgi?lists .. _documentation: http://codespeak.net/pypy/index.cgi?doc -.. _moin: http://codespeak.net/moin/pypy/moin.cgi/FrontPage?action=show \ No newline at end of file +.. _wiki: http://codespeak.net/moin/pypy/moin.cgi/FrontPage?action=show \ No newline at end of file From arigo at codespeak.net Fri Dec 19 17:59:01 2003 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 19 Dec 2003 17:59:01 +0100 (MET) Subject: [pypy-svn] rev 2595 - pypy/trunk/doc/overview Message-ID: <20031219165901.A55585A8C2@thoth.codespeak.net> Author: arigo Date: Fri Dec 19 17:59:00 2003 New Revision: 2595 Modified: pypy/trunk/doc/overview/architecture Log: minor editing on the existing draft, addition of the two other missing "major headings". Modified: pypy/trunk/doc/overview/architecture ============================================================================== --- pypy/trunk/doc/overview/architecture (original) +++ pypy/trunk/doc/overview/architecture Fri Dec 19 17:59:00 2003 @@ -2,47 +2,60 @@ Architecture overview ===================== -In its current, rather simple incarnation Pypy has 2 major parts - The -interpreter and an object space. Both parts are implemented in Python +In its current, rather simple incarnation, Pypy has 2 major parts - the +*interpreter* and an *object space*. Both parts are implemented in Python and run under CPython. The Interpreter =============== -The interpreter accepts a Python source code file and turns it into a -series of byte codes, which are stored in .pyc file. The byte codes -are instructions for a virtual machine, just like with regular -CPython. - -The interpreter then takes the bytecodes one by one and performs -whatever the bytecode instructs it to do. For all operations that -affect objects, the actual change of the object is delegated to the -object space. +The interpreter accepts a Python source code file and hands it off +to the compiler (PyPy's currently using CPython's built-in compiler) +which turns it into a series of *byte codes* (the byte codes may be +stored in a .pyc file, if the source code is being imported rather +than directly run). The byte codes are instructions for a virtual +machine, which is just the same as the one used in regular CPython. +Each byte code is made up of an operation code (opcode) and optionally +some operands. + +The interpreter then takes the bytecodes, one by one, and performs +whatever operation each opcode instructs it to do. For all operations +that affect or consult objects, the PyPy interpreter delegates all +actual work on the object to the object space. The Object Space ================ The object space contains all objects that have been created and knows -how to perform operations on the objects. We currently have 2 working -object spaces which are more or less interchangeable: +how to perform operations on the objects. You may think of an object +space as being essentially a complete library implementing a fixed API, +a set of *operations*, with implementations that correspond to giving +some semantics to Python object types. An example of an operation might +be *add*: add's implementations are responsible for performing numeric +addition when add works on built-in numbers, concatenation when it +works on built-in sequences. + +We currently have 2 working object spaces which are more or less +interchangeable: - The trivial object space, which is a thin wrapper around CPython types. It was used to test the interpreter and is used from time to time for testing purposes. It is currently of little interest. -- The standard object space, which is an almost complete -implementation of Python types in Python. This is the main focus of -this document, since it is the foundation of PyPy. +- The standard object space, which is an almost complete implementation +of Python types in Python. This is the main focus of this document, +since it is the foundation of PyPy. The Standard Object Space ========================= The Standard Object Space (SOS) itself is an object which implements a -number of logistic services. At startup the SOS examines certain +number of logistic services. At startup, the SOS examines certain directories for modules that contain the implementation of the available -Python types. It loads each such module, which in turn registers its -type and all the operations on the type in multimethods in the SOS. +Python types. The SOS loads each such module, and, in turn, each module +so loaded registers the type it deals with, and all the operations and +implementations for the type, in *multimethod* objects in the SOS. Later in the execution, when the interpreter delegates the execution -of an instruction to the SOS, the correct operation to perform is -selected through the multimethod. +of an instruction to the SOS, the SOS selects the correct +implementation of the operation to perform through the multimethod. We will examine how the multimethod mechanism works through an example. @@ -52,20 +65,32 @@ type signature __add__(Float, Float) and the integer add operator is registered with the signature __add__(Int, Int). -If we in our application program write the expression 2+3, the +If in our application program we write the expression 2+3, the interpreter will create an object containing the value 2 and an object containing the value 3. We annotate these as Int(2) and Int(3) respectively. The interpreter then calls the SOS with __add__(Int(2), Int(3)). -The SOS then looks in its __add__ multimethod and finds a version that -has the signature __add__(Int, Int). Since this is a direct hit, it -can immediately dispatch the operation to the correct method. - -If we don't have any registered functions with the correct signature, -as we would if we had the expression 2+3.0, we will test if we can use -coercion to find a function with a signature that works. In this case -we would coerce Int(2) to Float(2.0) in order to find a function in -the multimethod that has a correct signature. +The SOS then delegates the operation to the __add__ multimethod, which +finds an implementation that has the signature __add__(Int, Int). Since +this is a "direct hit", the multimethod can immediately dispatch the +operation to the correct method, i.e., the one registered as the +implementation for this signature. + +If the multimethod doesn't have any registered functions with the +correct signature, as would be the case for example for the expression +2+3.0, the multimethod tests if it can use coercion to find a function +with a signature that works. In this case we would coerce Int(2) to +Float(2.0) in order to find a function in the multimethod that has a +correct signature. + +Application-level and interpreter-level +======================================= + +foobar + +Wrapping +======== +barfoo From pedronis at codespeak.net Fri Dec 19 18:02:14 2003 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Fri, 19 Dec 2003 18:02:14 +0100 (MET) Subject: [pypy-svn] rev 2596 - pypy/trunk/doc/overview Message-ID: <20031219170214.876235A8C2@thoth.codespeak.net> Author: pedronis Date: Fri Dec 19 18:02:13 2003 New Revision: 2596 Added: pypy/trunk/doc/overview/RPy-translation-overview.txt Log: very rough first cut at a high-level description of RPy translation. Added: pypy/trunk/doc/overview/RPy-translation-overview.txt ============================================================================== --- (empty file) +++ pypy/trunk/doc/overview/RPy-translation-overview.txt Fri Dec 19 18:02:13 2003 @@ -0,0 +1,24 @@ +RPython translation overview +------------------------------- + +Translation of RPython code of PyPy works on bytecode as found in the +interpreter functions object after the PyPy system has been loaded and +initialized. These bytecodes will be abstractly interpreted using the +PyPy interpreter itself with a specific Object Space, the Flow Object +Space, plugged in. The Flow Object Space drives the execution in such +a way that all paths in the code are followed. As a side-effect it +produce flow graphs, that means graph capturing the control flow of +the code, nodes there are basic blocks of logged Object Space +operations executed sequentially, how values flow is also encoded. + +These flow graphs can be fed then as input to the Annotator. Under the +constraints of RPython, the Annotator given entry point types should +be able to infer the types of values that flow through the program +variables. + +In a last phase the type annotated flow graphs can be visited by the +Translator, which out of the types annotation, the basic block listed +operations and control flow information encoded in the graphs, should +be able to emit "low-level" code. Our first target would be probably +Pyrex code, which then can be translated to compilable C by Pyrex +itself. From pmaupin at codespeak.net Fri Dec 19 18:13:57 2003 From: pmaupin at codespeak.net (pmaupin at codespeak.net) Date: Fri, 19 Dec 2003 18:13:57 +0100 (MET) Subject: [pypy-svn] rev 2597 - pypy/trunk/doc/devel Message-ID: <20031219171357.CC9645A8C2@thoth.codespeak.net> Author: pmaupin Date: Fri Dec 19 18:13:56 2003 New Revision: 2597 Modified: pypy/trunk/doc/devel/howtopypy.txt Log: Minor cleanup, and add exhortation to help Modified: pypy/trunk/doc/devel/howtopypy.txt ============================================================================== --- pypy/trunk/doc/devel/howtopypy.txt (original) +++ pypy/trunk/doc/devel/howtopypy.txt Fri Dec 19 18:13:56 2003 @@ -29,8 +29,8 @@ the same as the Python prompt, but with an extra ">". The "-S" given on the command line insructs the PyPy interpreter - to use the Standard_ `object space`_. PyPy has the concept of different - object spaces, but the standard space is the one which contains + to use the `Standard object space`_. PyPy has the concept of different + object spaces_, but the standard space is the one which contains the "real" Python interpreter. @@ -89,11 +89,16 @@ and the wiki_, and consider subscribing to the `mailing lists`_ (or simply read the archives online) or communicating via irc.freenode.net:6667, channel #pypy. +8. To help PyPy become Python-the-next-generation, write some `unit tests`_ and + file some `bug reports`_! + -------------------------------------------------------------------------------- -.. _subversion: http://codespeak.net/pypy/index.cgi?doc/devel/howtosvn.html -.. _Standard: http://codespeak.net/pypy/index.cgi?doc/objspace/stdobjspace.html -.. _object space: http://codespeak.net/pypy/index.cgi?doc/objspace/objspace.html -.. _mailing lists: http://codespeak.net/pypy/index.cgi?lists -.. _documentation: http://codespeak.net/pypy/index.cgi?doc -.. _wiki: http://codespeak.net/moin/pypy/moin.cgi/FrontPage?action=show \ No newline at end of file +.. _subversion: http://codespeak.net/pypy/index.cgi?doc/devel/howtosvn.html +.. _Standard object space: http://codespeak.net/pypy/index.cgi?doc/objspace/stdobjspace.html +.. _spaces: http://codespeak.net/pypy/index.cgi?doc/objspace/objspace.html +.. _mailing lists: http://codespeak.net/pypy/index.cgi?lists +.. _documentation: http://codespeak.net/pypy/index.cgi?doc +.. _wiki: http://codespeak.net/moin/pypy/moin.cgi/FrontPage?action=show +.. _unit tests: http://codespeak.net/pypy/index.cgi?doc/devel/testdesign.html +.. _bug reports: http://codespeak.net/issues/pypy/ From arigo at codespeak.net Fri Dec 19 18:14:11 2003 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 19 Dec 2003 18:14:11 +0100 (MET) Subject: [pypy-svn] rev 2598 - pypy/trunk/doc/overview Message-ID: <20031219171411.D199A5A8C2@thoth.codespeak.net> Author: arigo Date: Fri Dec 19 18:14:10 2003 New Revision: 2598 Modified: pypy/trunk/doc/overview/architecture Log: a first paragraph about application and interpreter level; careful markup of all inline literals. Modified: pypy/trunk/doc/overview/architecture ============================================================================== --- pypy/trunk/doc/overview/architecture (original) +++ pypy/trunk/doc/overview/architecture Fri Dec 19 18:14:10 2003 @@ -11,7 +11,7 @@ The interpreter accepts a Python source code file and hands it off to the compiler (PyPy's currently using CPython's built-in compiler) which turns it into a series of *byte codes* (the byte codes may be -stored in a .pyc file, if the source code is being imported rather +stored in a ``.pyc`` file, if the source code is being imported rather than directly run). The byte codes are instructions for a virtual machine, which is just the same as the one used in regular CPython. Each byte code is made up of an operation code (opcode) and optionally @@ -59,35 +59,46 @@ We will examine how the multimethod mechanism works through an example. -We examine the types float and int and disregard all other types for -the moment. Each type has an __add__ operator, which is registered +We examine the types ``float`` and ``int`` and disregard all other types for +the moment. Each type has an ``__add__`` operator, which is registered with the SOS at startup. The float add operator is registered with the -type signature __add__(Float, Float) and the integer add operator is -registered with the signature __add__(Int, Int). +type signature ``__add__(Float, Float)`` and the integer add operator is +registered with the signature ``__add__(Int, Int)``. -If in our application program we write the expression 2+3, the -interpreter will create an object containing the value 2 and an object -containing the value 3. We annotate these as Int(2) and Int(3) -respectively. The interpreter then calls the SOS with -__add__(Int(2), Int(3)). +If in our application program we write the expression ``2+3``, the +interpreter will create an object containing the value ``2`` and an +object containing the value ``3``. We annotate these as ``Int(2)`` and +``Int(3)`` respectively. The interpreter then calls the SOS with +``__add__(Int(2), Int(3))``. -The SOS then delegates the operation to the __add__ multimethod, which -finds an implementation that has the signature __add__(Int, Int). Since +The SOS then delegates the operation to the ``__add__`` multimethod, which +finds an implementation that has the signature ``__add__(Int, Int)``. Since this is a "direct hit", the multimethod can immediately dispatch the operation to the correct method, i.e., the one registered as the implementation for this signature. If the multimethod doesn't have any registered functions with the correct signature, as would be the case for example for the expression -2+3.0, the multimethod tests if it can use coercion to find a function -with a signature that works. In this case we would coerce Int(2) to -Float(2.0) in order to find a function in the multimethod that has a +``2+3.0``, the multimethod tests if it can use coercion to find a function +with a signature that works. In this case we would coerce ``Int(2)`` to +``Float(2.0)`` in order to find a function in the multimethod that has a correct signature. Application-level and interpreter-level ======================================= +Since the same language (Python) is what PyPy both **uses** and **deals +with**, a given piece of Python source can be playing either of two +rather distinct roles in the PyPy system. To be systematic in +distinguishing these roles, we call them *interpreter level* (Python +used to implement the interpreter and object space) and *application +level* (Python that we are interpreting). To show the difference with +an example: to sum the contents of two variables ``a`` and ``b``, typical +application-level code is ``a+b`` -- in constrast, typical +interpreter-level code is ``space.add(w_a, w_b)``, where ``space`` is an +instance of the standard object space class and ``w_a`` and ``w_b`` are +typical names for the *wrapped* versions of the two variables. + -foobar Wrapping ======== From pmaupin at codespeak.net Fri Dec 19 18:16:20 2003 From: pmaupin at codespeak.net (pmaupin at codespeak.net) Date: Fri, 19 Dec 2003 18:16:20 +0100 (MET) Subject: [pypy-svn] rev 2599 - pypy/trunk/doc/devel Message-ID: <20031219171620.DB2715A8C2@thoth.codespeak.net> Author: pmaupin Date: Fri Dec 19 18:16:20 2003 New Revision: 2599 Modified: pypy/trunk/doc/devel/howtopypy.txt Log: Added a period Modified: pypy/trunk/doc/devel/howtopypy.txt ============================================================================== --- pypy/trunk/doc/devel/howtopypy.txt (original) +++ pypy/trunk/doc/devel/howtopypy.txt Fri Dec 19 18:16:20 2003 @@ -8,7 +8,7 @@ If you are ready to download and try PyPy out: -1. Download subversion_ if you do not already have it +1. Download subversion_ if you do not already have it. 2. Use subversion to download the source:: From guenter at codespeak.net Fri Dec 19 18:45:06 2003 From: guenter at codespeak.net (guenter at codespeak.net) Date: Fri, 19 Dec 2003 18:45:06 +0100 (MET) Subject: [pypy-svn] rev 2600 - pypy/trunk/doc/overview Message-ID: <20031219174506.26C275AAA7@thoth.codespeak.net> Author: guenter Date: Fri Dec 19 18:45:05 2003 New Revision: 2600 Added: pypy/trunk/doc/overview/svf08.tmp (contents, props changed) Log: Added: pypy/trunk/doc/overview/svf08.tmp ============================================================================== Binary file. No diff available. From alex at codespeak.net Fri Dec 19 18:49:28 2003 From: alex at codespeak.net (alex at codespeak.net) Date: Fri, 19 Dec 2003 18:49:28 +0100 (MET) Subject: [pypy-svn] rev 2601 - pypy/trunk/doc/overview Message-ID: <20031219174928.8D5415AAA7@thoth.codespeak.net> Author: alex Date: Fri Dec 19 18:49:27 2003 New Revision: 2601 Added: pypy/trunk/doc/overview/architecture.txt - copied, changed from rev 2598, pypy/trunk/doc/overview/architecture Log: renamed, and more material at the end Copied: pypy/trunk/doc/overview/architecture.txt (from rev 2598, pypy/trunk/doc/overview/architecture) ============================================================================== --- pypy/trunk/doc/overview/architecture (original) +++ pypy/trunk/doc/overview/architecture.txt Fri Dec 19 18:49:27 2003 @@ -93,10 +93,30 @@ used to implement the interpreter and object space) and *application level* (Python that we are interpreting). To show the difference with an example: to sum the contents of two variables ``a`` and ``b``, typical -application-level code is ``a+b`` -- in constrast, typical +application-level code is ``a+b`` -- in sharp contrast, typical interpreter-level code is ``space.add(w_a, w_b)``, where ``space`` is an instance of the standard object space class and ``w_a`` and ``w_b`` are -typical names for the *wrapped* versions of the two variables. +typical names for the *wrapped* versions of the two variables. By +contrast, think of traditional CPython: it has the same +application-level code, but interpreter-level code is C source, and +typical code for the addition would be ``PyNumber_Add(p_a, p_b)`` +where ``p_a`` and ``p_b`` are C variables of type ``PyObject*``. + +You might think that the need to keep the two roles for the same +language distinguished is a cause of confusion; sometimes, indeed, it is +possible to get confused between the two levels while developing PyPy. +However, the existence of the two levels for the same language also +offers a powerful advantage, fully offsetting the possibility of +confusion (and then some): PyPy lets you use application-level code for +the purpose of implementing interpreter-level operations. + +Application-level code is much higher-level, and therefore easier to +write and debug. Instead of implementing a dict object's update method +by simple, application-level code that goes something like:: + + def app_dict_update__ANY_ANY(d, o): + for k in o.keys(): + d[k] = o[k] From lac at codespeak.net Fri Dec 19 18:58:20 2003 From: lac at codespeak.net (lac at codespeak.net) Date: Fri, 19 Dec 2003 18:58:20 +0100 (MET) Subject: [pypy-svn] rev 2602 - pypy/trunk/doc Message-ID: <20031219175820.129885AAA7@thoth.codespeak.net> Author: lac Date: Fri Dec 19 18:58:19 2003 New Revision: 2602 Added: pypy/trunk/doc/goals.txt Log: gleaned from the proposal Added: pypy/trunk/doc/goals.txt ============================================================================== --- (empty file) +++ pypy/trunk/doc/goals.txt Fri Dec 19 18:58:19 2003 @@ -0,0 +1,177 @@ +**Infrastructure and tools** + +Supporting the PyPy project by producing and enhancing the tools. + +Support the development process with reusing existing or developing +new debugging opensource tools. + +- provide access over http/https and ssh server + +- build extensions for automatic document extraction + +- implement a search facility over all content + +- maintain and enhance website infrastructure + +- setup a mirror repository which is kept up-to-date and which + can be used readonly in case of failure of the main repository. + +- Design a strict backup policy. + +- help with automated testing + + what more do we want to do? + +- http-server to present runtime/introspection information aiding + debugging and understanding of PyPy internals + +- automated (unit-)testing framework with html/pdf reports + +**Synchronisation with Standard Python** + +- 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. + +**Replace PyPy Core** + +Building a complete Python interpreter written in Python, +using a subset of Python that avoids dynamic features +which would impair the objectives of RPython. + +- Design and implement the PyPy bytecode interpreter and + build an object space library in RPython. + The resulting interpreter must cover the complete Python + language specification. -- mostly done, test coverage. + +- Port the built-in Python library to PyPy (functions, types and + modules currently implemented in C) -- types needs refactoring, + the rest is mostly done. + +- Decide on a case-by-case basis which features are to + be implemented using RPython or just general Python. -- moving target. + +- Implement a Python parser and bytecode compiler in Python. + -- we have soemthing, but it is not well integrated. + +- A partial Python implementation that passses 75% of the official + Python test suite that don't depend on extension modules. + -- write this test and then pass it. + +**The PyPy Translation** + +- Analysis and translation of the PyPy core into efficient low-level code + (C, Pyrex, Java, others). - moving target + +- Provide a Runtime Library for the translated versions + of PyPy. - not even started + +- Create a code analysis tool for a subset of the Python + language (RPython). Coordinate the definition of RPython + being the implementation language of the core. + + - we can analyse functions, but not classes, modules, spaces etc. + +- Complete implementation of Python, conforming to the language + definition and passing all relevant tests of the official Python + test suite. -- global goal, which we will think more about when + it is very close to being done. + +**Stackless Integration + More Performance Hacks** + +- Identification and Implementation of Optimisations through modifications + of the Translator. + +- Enable Massive Parallelism in a Single Thread. + +- Provide support for real-time parallelism. + +- Allow Pickling of a Running Program. + +- Enhance the translator to support continuation passing + style by integrating technology from the Stackless project. + +- Implement the necessary runtime system to support massive parallelism. + +- Implement a single-threaded, pre-emptive scheduler with + priorities, complementing the OS threads. + +- Study approaches concerning code size vs. speed trade-offs. + +- Implement and compare different object layout and memory management + strategy or strategies. + +- Enhance multimethod dispatching. + +- Implement schemes of pointer tagging. + +- Create reports and merge the results back into the optimization effort. + +**Psyco Integration** + +- Outperform the state-of-the art (Psyco, Stackless). + +- 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. + +- Apply and enhance techniques from the Psyco project. Promote parts + of the static translator to be used for run-time specialization. + +- Design and implement a back-end component for dynamically emitting + machine code for multiple processor architectures. Enable dynamic + foreign function calls. + +- Research optimisation heuristics for the Just-In-Time compiler. + + +- A Just-In-Time compiler for PyPy !!! Outperform the + state-of-the art (Psyco, Stackless). + +**Embed in Specialized Hardware** + +if we get funding. + +**Implement Security, Distribution and Persistence** + +- Research and validate the flexibility of PyPy by building key middleware + features into the language itself. + +- Analyze and implement security models at the language level. + +- Implement the "RExec" restricted execution model. (It was removed + from the official Python implementation because it is false security.) + +- Analyze and implement distributed execution models at the language level. + +- Implement network-transparent execution of Python programs. (Typical + libraries require programs to be aware of the remote execution model.) + +- Analyze and implement persistence at the language level. -- talk to + Patrick O'Brien who is really hot for the idea. + +- Implement an orthogonally persistent object space for Python programs. + (Persistence is never fully orthogonal without advanced language support.) + +**PyPy A la Carte** + +- Develop tools that will allow to chose from available features and runtime + restrictions to build a custom PyPy version. + +- Analyse and integrate all results from the results of other workpackages. + This involves identifying and resolving conflicts which could prevent + a combintation of desired optimization goals. + +- 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. + +- Make a build- and configuration tool that allows to build custom PyPy + versions suitable for specialized environments such as small or very large + computing devices. + From lac at codespeak.net Fri Dec 19 19:04:41 2003 From: lac at codespeak.net (lac at codespeak.net) Date: Fri, 19 Dec 2003 19:04:41 +0100 (MET) Subject: [pypy-svn] rev 2603 - pypy/trunk/doc/devel Message-ID: <20031219180441.18BA55AAA7@thoth.codespeak.net> Author: lac Date: Fri Dec 19 19:04:30 2003 New Revision: 2603 Added: pypy/trunk/doc/devel/checking_ReST.txt Log: add reminder for me on how to sin Added: pypy/trunk/doc/devel/checking_ReST.txt ============================================================================== --- (empty file) +++ pypy/trunk/doc/devel/checking_ReST.txt Fri Dec 19 19:04:30 2003 @@ -0,0 +1,9 @@ +1. You need to have docutils installed. +2. docutils/tools/buildhtml.py converts your ReST .txt files into .html + files, and complains when your document has errors. +3. There is one problem. It converts _every_ .txt to an .html, and there + is no option to just specify one file. I get around this problem by + making a directory and moving my new file there for testing, and then + moving it back when I am done. 0 Elegance points for that fix ... + + Laura \ No newline at end of file From jacob at codespeak.net Fri Dec 19 19:07:27 2003 From: jacob at codespeak.net (jacob at codespeak.net) Date: Fri, 19 Dec 2003 19:07:27 +0100 (MET) Subject: [pypy-svn] rev 2604 - pypy/trunk/doc/overview Message-ID: <20031219180727.1C37E5AAA7@thoth.codespeak.net> Author: jacob Date: Fri Dec 19 19:07:23 2003 New Revision: 2604 Added: pypy/trunk/doc/overview/Diagrams.sxi (contents, props changed) Removed: pypy/trunk/doc/overview/svf08.tmp Log: Added diagrams belonging to architecture overview. Added: pypy/trunk/doc/overview/Diagrams.sxi ============================================================================== Binary file. No diff available. Deleted: /pypy/trunk/doc/overview/svf08.tmp ============================================================================== Binary file. No diff available. From pmaupin at codespeak.net Fri Dec 19 19:08:54 2003 From: pmaupin at codespeak.net (pmaupin at codespeak.net) Date: Fri, 19 Dec 2003 19:08:54 +0100 (MET) Subject: [pypy-svn] rev 2605 - pypy/trunk/src/pypy/objspace/std/test Message-ID: <20031219180854.DDB505AAA7@thoth.codespeak.net> Author: pmaupin Date: Fri Dec 19 19:08:53 2003 New Revision: 2605 Modified: pypy/trunk/src/pypy/objspace/std/test/test_intobject.py Log: Add tests for two parameter int() Modified: pypy/trunk/src/pypy/objspace/std/test/test_intobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/test/test_intobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/test/test_intobject.py Fri Dec 19 19:08:53 2003 @@ -304,7 +304,14 @@ def test_int_str_repr(self): self.assertEquals("42", str(42)) self.assertEquals("42", repr(42)) + self.assertRaises(ValueError, int, '0x2A') + def test_int_two_param(self): + self.assertEquals(42, int('0x2A', 0)) + self.assertEquals(42, int('2A', 16)) + self.assertEquals(42, int('42', 10)) + self.assertRaises(TypeError, int, 1, 10) + if __name__ == '__main__': test.main() From pmaupin at codespeak.net Fri Dec 19 19:09:58 2003 From: pmaupin at codespeak.net (pmaupin at codespeak.net) Date: Fri, 19 Dec 2003 19:09:58 +0100 (MET) Subject: [pypy-svn] rev 2606 - pypy/trunk/src/pypy/objspace/std Message-ID: <20031219180958.85C7E5AAA7@thoth.codespeak.net> Author: pmaupin Date: Fri Dec 19 19:09:57 2003 New Revision: 2606 Modified: pypy/trunk/src/pypy/objspace/std/inttype.py Log: Reorganize int() to allow two parameters, and to propagate most exceptions Modified: pypy/trunk/src/pypy/objspace/std/inttype.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/inttype.py (original) +++ pypy/trunk/src/pypy/objspace/std/inttype.py Fri Dec 19 19:09:57 2003 @@ -14,21 +14,32 @@ raise OperationError(space.w_TypeError, space.wrap("no keyword arguments expected")) args = space.unpackiterable(w_args) - if len(args) == 0: + arglen = len(args) + + if arglen == 0: return space.newint(0), True - elif len(args) == 1: - arg = args[0] - if space.is_true(space.issubtype(space.type(arg), - space.w_str)): - try: - return space.newint(int(space.unwrap(arg))), True - except TypeError: - raise OperationError(space.w_TypeError, - space.wrap("invalid literal for int()")) - else: - return space.int(args[0]), True - else: + elif arglen > 2: + raise OperationError(space.w_TypeError, + space.wrap("int() takes at most 2 arguments")) + elif space.is_true(space.issubtype(space.type(args[0]), space.w_str)): + try: + if arglen == 1: + return space.newint(int(space.unwrap(args[0]))), True + else: + return space.newint(int(space.unwrap(args[0]),space.unwrap(args[1]))), True + except TypeError, e: + raise OperationError(space.w_TypeError, + space.wrap(str(e))) + except ValueError, e: + raise OperationError(space.w_ValueError, + space.wrap(str(e))) + except OverflowError, e: + raise OperationError(space.w_OverflowError, + space.wrap(str(e))) + elif arglen == 2: raise OperationError(space.w_TypeError, - space.wrap("int() takes at most 1 argument")) + space.wrap("int() can't convert non-string with explicit base")) + else: + return space.int(args[0]), True register_all(vars()) From hpk at codespeak.net Fri Dec 19 19:13:26 2003 From: hpk at codespeak.net (hpk at codespeak.net) Date: Fri, 19 Dec 2003 19:13:26 +0100 (MET) Subject: [pypy-svn] rev 2607 - pypy/trunk/doc/devel Message-ID: <20031219181326.456225AAA7@thoth.codespeak.net> Author: hpk Date: Fri Dec 19 19:13:16 2003 New Revision: 2607 Modified: pypy/trunk/doc/devel/testdesign.txt Log: small updates Modified: pypy/trunk/doc/devel/testdesign.txt ============================================================================== --- pypy/trunk/doc/devel/testdesign.txt (original) +++ pypy/trunk/doc/devel/testdesign.txt Fri Dec 19 19:13:16 2003 @@ -12,10 +12,10 @@ - **Application Level tests**. They run at application level which means that they look like straight python code but they are interpreted by PyPy. -Both types of tests need an object-space they can run with (the interpreter +Both types of tests need an objectspace they can run with (the interpreter dispatches operations on objects to an objectspace). If you run a test you -can usually give the '-S', '-T' or '-A' switch for using the Standard, Trivial -or Ann-ObjectSpace respectively. +can usually give the '-S' or '-T' switch for using the Standard or the Trivial +ObjectSpace respectively. Writing a test -------------- @@ -24,13 +24,16 @@ Almost all tests start with the following lines:: import autopath - from pypy.tool import test + from pypy.tool import test of which the first line determines the package path automatically by searching for **pypy** among the parents of the test-file's directory. The second line imports PyPy's test-hook of which ''test.main()'' is the most important -and is usually the last line of the testfile. For more info please refer to -a pypy-dev mail_ where the current testing framework was introduced. +and is usually the last line of the testfile. Further below you will find +some preliminary information about a new test module that was recently +developed at the Amsterdam Sprint (Dec. 2003) and still is under development. + +Note that we are using a unittest2 framework Command line tool test_all -------------------------- From alex at codespeak.net Fri Dec 19 19:15:36 2003 From: alex at codespeak.net (alex at codespeak.net) Date: Fri, 19 Dec 2003 19:15:36 +0100 (MET) Subject: [pypy-svn] rev 2608 - pypy/trunk/doc/overview Message-ID: <20031219181536.A5EED5AAA7@thoth.codespeak.net> Author: alex Date: Fri Dec 19 19:15:31 2003 New Revision: 2608 Removed: pypy/trunk/doc/overview/architecture Modified: pypy/trunk/doc/overview/architecture.txt Log: close to finished, with more editing and materials, but still needs more work to be considered a complete first draft. Deleted: /pypy/trunk/doc/overview/architecture ============================================================================== --- /pypy/trunk/doc/overview/architecture Fri Dec 19 19:15:31 2003 +++ (empty file) @@ -1,107 +0,0 @@ -PyPy - an implementation of Python in Python - -Architecture overview -===================== -In its current, rather simple incarnation, Pypy has 2 major parts - the -*interpreter* and an *object space*. Both parts are implemented in Python -and run under CPython. - -The Interpreter -=============== -The interpreter accepts a Python source code file and hands it off -to the compiler (PyPy's currently using CPython's built-in compiler) -which turns it into a series of *byte codes* (the byte codes may be -stored in a ``.pyc`` file, if the source code is being imported rather -than directly run). The byte codes are instructions for a virtual -machine, which is just the same as the one used in regular CPython. -Each byte code is made up of an operation code (opcode) and optionally -some operands. - -The interpreter then takes the bytecodes, one by one, and performs -whatever operation each opcode instructs it to do. For all operations -that affect or consult objects, the PyPy interpreter delegates all -actual work on the object to the object space. - -The Object Space -================ -The object space contains all objects that have been created and knows -how to perform operations on the objects. You may think of an object -space as being essentially a complete library implementing a fixed API, -a set of *operations*, with implementations that correspond to giving -some semantics to Python object types. An example of an operation might -be *add*: add's implementations are responsible for performing numeric -addition when add works on built-in numbers, concatenation when it -works on built-in sequences. - -We currently have 2 working object spaces which are more or less -interchangeable: - -- The trivial object space, which is a thin wrapper around CPython -types. It was used to test the interpreter and is used from time to -time for testing purposes. It is currently of little interest. - -- The standard object space, which is an almost complete implementation -of Python types in Python. This is the main focus of this document, -since it is the foundation of PyPy. - -The Standard Object Space -========================= -The Standard Object Space (SOS) itself is an object which implements a -number of logistic services. At startup, the SOS examines certain -directories for modules that contain the implementation of the available -Python types. The SOS loads each such module, and, in turn, each module -so loaded registers the type it deals with, and all the operations and -implementations for the type, in *multimethod* objects in the SOS. - -Later in the execution, when the interpreter delegates the execution -of an instruction to the SOS, the SOS selects the correct -implementation of the operation to perform through the multimethod. - -We will examine how the multimethod mechanism works through an example. - -We examine the types ``float`` and ``int`` and disregard all other types for -the moment. Each type has an ``__add__`` operator, which is registered -with the SOS at startup. The float add operator is registered with the -type signature ``__add__(Float, Float)`` and the integer add operator is -registered with the signature ``__add__(Int, Int)``. - -If in our application program we write the expression ``2+3``, the -interpreter will create an object containing the value ``2`` and an -object containing the value ``3``. We annotate these as ``Int(2)`` and -``Int(3)`` respectively. The interpreter then calls the SOS with -``__add__(Int(2), Int(3))``. - -The SOS then delegates the operation to the ``__add__`` multimethod, which -finds an implementation that has the signature ``__add__(Int, Int)``. Since -this is a "direct hit", the multimethod can immediately dispatch the -operation to the correct method, i.e., the one registered as the -implementation for this signature. - -If the multimethod doesn't have any registered functions with the -correct signature, as would be the case for example for the expression -``2+3.0``, the multimethod tests if it can use coercion to find a function -with a signature that works. In this case we would coerce ``Int(2)`` to -``Float(2.0)`` in order to find a function in the multimethod that has a -correct signature. - -Application-level and interpreter-level -======================================= -Since the same language (Python) is what PyPy both **uses** and **deals -with**, a given piece of Python source can be playing either of two -rather distinct roles in the PyPy system. To be systematic in -distinguishing these roles, we call them *interpreter level* (Python -used to implement the interpreter and object space) and *application -level* (Python that we are interpreting). To show the difference with -an example: to sum the contents of two variables ``a`` and ``b``, typical -application-level code is ``a+b`` -- in constrast, typical -interpreter-level code is ``space.add(w_a, w_b)``, where ``space`` is an -instance of the standard object space class and ``w_a`` and ``w_b`` are -typical names for the *wrapped* versions of the two variables. - - - -Wrapping -======== - -barfoo - Modified: pypy/trunk/doc/overview/architecture.txt ============================================================================== --- pypy/trunk/doc/overview/architecture.txt (original) +++ pypy/trunk/doc/overview/architecture.txt Fri Dec 19 19:15:31 2003 @@ -111,17 +111,58 @@ the purpose of implementing interpreter-level operations. Application-level code is much higher-level, and therefore easier to -write and debug. Instead of implementing a dict object's update method -by simple, application-level code that goes something like:: - - def app_dict_update__ANY_ANY(d, o): - for k in o.keys(): - d[k] = o[k] - - +write and debug. For example, suppose we want to implement the +``update`` method of dict objects. Programming at the application +level, we can write the obvious, simple implementation, one that looks +like an executable-pseudocode **definition** of ``update``:: + + def update(self, other): + for k in other.keys(): + self[k] = other[k] + +If we had to code only at the interpreter level, we would have to +code something much lower-level and involved, say something like:: + + def update(space, w_self, w_other): + w_keys = space.call_method(w_other, 'keys') + w_iter = space.iter(w_keys) + while True: + try: w_key = space.next(w_iter) + except NoValue: break + w_value = space.getitem(w_other, w_key) + space.setitem(w_self, w_key, w_value) + +This interpreter-level implementation looks much closer to the C source +code implementing this functionality in CPython, although, depending on +one's relative familiarity with C, Python, and PyPy's coding +conventions, it may still be considered somewhat more readable. In any +case, it should be obvious that the application-level implementation is +definitely more readable and maintainable than the interpreter-level +one. Wrapping ======== -barfoo +The ``w_`` prefixes so lavishly used in the previous example indicate, +by PyPy coding convention, that we are dealing with *wrapped* objects, +that is, objects constructed by the object space at interpreter level to +implement corresponding application-level objects. Each object space +supplies ``wrap`` and ``unwrap`` operations that move between the two +levels for objects of simple built-in types; other Python types are +implemented by interpreter-level classes with some amount of internal +structure. + +For example, an application-level Python ``list`` is implemented as an +instance of ``W_ListObject```, which has an instance attribute +``ob_item`` (an interpreter-level list which contains the +application-level list's items as wrapped objects) and another attribute +``ob_size`` which records the application-level list's length (we want +to be able to do "over-allocation" in ``ob_item``, for the same reasons +of performance that lead CPython to do it, and therefore the length of +``ob_item`` is allowed to be greater than the length of the +application-level list -- it is for this reason that the length in +question has to be explicitly recorded in ``ob_size``). + + +TODO: review and see what else we need to add! From pmaupin at codespeak.net Fri Dec 19 19:15:43 2003 From: pmaupin at codespeak.net (pmaupin at codespeak.net) Date: Fri, 19 Dec 2003 19:15:43 +0100 (MET) Subject: [pypy-svn] rev 2609 - pypy/trunk/src/pypy/appspace Message-ID: <20031219181543.29AF95AAA7@thoth.codespeak.net> Author: pmaupin Date: Fri Dec 19 19:15:41 2003 New Revision: 2609 Modified: pypy/trunk/src/pypy/appspace/builtin_functions_test.py Log: Change which tests are being run, and comment out some long problems Modified: pypy/trunk/src/pypy/appspace/builtin_functions_test.py ============================================================================== --- pypy/trunk/src/pypy/appspace/builtin_functions_test.py (original) +++ pypy/trunk/src/pypy/appspace/builtin_functions_test.py Fri Dec 19 19:15:41 2003 @@ -239,7 +239,6 @@ if have_unicode: compile(unicode('print u"\xc3\xa5"\n', 'utf8'), '', 'exec') - if 1: def test_delattr(self): import sys sys.spam = 1 @@ -331,7 +330,6 @@ '\'' ''' - if 0: def test_filter(self): self.assertEqual(filter(lambda c: 'a' <= c <= 'z', 'Hello World'), 'elloorld') self.assertEqual(filter(None, [1, 'hello', [], [3], '', None, 9, 0]), [1, 'hello', [3], 9]) @@ -458,14 +456,16 @@ self.assertRaises(TypeError, getattr, sys, 1) self.assertRaises(TypeError, getattr, sys, 1, "foo") self.assertRaises(TypeError, getattr) - self.assertRaises(UnicodeError, getattr, sys, unichr(sys.maxunicode)) + if have_unicode: + self.assertRaises(UnicodeError, getattr, sys, unichr(sys.maxunicode)) def test_hasattr(self): import sys self.assert_(hasattr(sys, 'stdout')) self.assertRaises(TypeError, hasattr, sys, 1) self.assertRaises(TypeError, hasattr) - self.assertRaises(UnicodeError, hasattr, sys, unichr(sys.maxunicode)) + if have_unicode: + self.assertRaises(UnicodeError, hasattr, sys, unichr(sys.maxunicode)) def test_hash(self): hash(None) @@ -487,6 +487,7 @@ self.assertEqual(hex(-16L), '-0x10L') self.assertRaises(TypeError, hex, {}) + if 1: def test_id(self): id(None) id(1) @@ -529,6 +530,7 @@ s = `-1-sys.maxint` self.assertEqual(int(s)+1, -sys.maxint) # should return long + ''' XXX TODO: Longs not supported yet int(s[1:]) # should return long @@ -536,7 +538,7 @@ self.assert_(isinstance(x, long)) x = int(-1e100) self.assert_(isinstance(x, long)) - + ''' # SF bug 434186: 0x80000000/2 != 0x80000000>>1. # Worked by accident in Windows release build, but failed in debug build. @@ -547,6 +549,7 @@ self.assertRaises(ValueError, int, '123\0') self.assertRaises(ValueError, int, '53', 40) + ''' XXX TODO: Longs not supported yet x = int('1' * 600) self.assert_(isinstance(x, long)) @@ -555,6 +558,7 @@ self.assert_(isinstance(x, long)) self.assertRaises(TypeError, int, 1, 12) + ''' self.assertEqual(int('0123', 0), 83) @@ -565,6 +569,7 @@ s2 = s.swapcase().swapcase() self.assert_(intern(s2) is s) + if 0: def test_iter(self): self.assertRaises(TypeError, iter) self.assertRaises(TypeError, iter, 42, 42) From sschwarzer at codespeak.net Sat Dec 20 09:53:40 2003 From: sschwarzer at codespeak.net (sschwarzer at codespeak.net) Date: Sat, 20 Dec 2003 09:53:40 +0100 (MET) Subject: [pypy-svn] rev 2610 - pypy/trunk/src/pypy/tool Message-ID: <20031220085340.93EB45AAA7@thoth.codespeak.net> Author: sschwarzer Date: Sat Dec 20 09:53:39 2003 New Revision: 2610 Modified: pypy/trunk/src/pypy/tool/newtest.py Log: Removed support for pretest and posttest argument from TestItem.run . Modified: pypy/trunk/src/pypy/tool/newtest.py ============================================================================== --- pypy/trunk/src/pypy/tool/newtest.py (original) +++ pypy/trunk/src/pypy/tool/newtest.py Sat Dec 20 09:53:39 2003 @@ -313,65 +313,42 @@ return id(self.module) ^ id(self.cls) def run(self, pretest=None, posttest=None): - """ - Run this TestItem and return a corresponding TestResult object. - - pretest, if not None, is a callable which is called before - running the setUp method of the TestCase class. It is passed - the this TestItem instance as the argument. - - Similarly, posttest is called after running the TestCase - class's tearDown method (or after the test method, if that - doesn't complete successfully). Like for pretest, the - callable gets the TestItem instance as only argument. - """ - # Note on pretest and posttest: I discarded the idea to - # supply this functionality by having hypothetical methods - # pretest and posttest overwritten in derived classes. That - # approach would require to support a factory class for test - # items in TestSuite. I wanted to avoid this. - + """Run this TestItem and return a corresponding TestResult object.""" # credit: adapted from Python's unittest.TestCase.run testobject = self.cls() testmethod = getattr(testobject, self.method.__name__) - if pretest is not None: - pretest(self) try: - try: - testobject.setUp() - except KeyboardInterrupt: - raise - except TestResult, result: - # reconstruct TestResult object, implicitly set exception - return result.__class__(msg=result.msg, item=self) - except Exception, exc: - return Error(msg=str(exc), item=self) - - try: - testmethod() - result = Success(msg='success', item=self) - except KeyboardInterrupt: - raise - except TestResult, result: - # reconstruct TestResult object, implicitly set exception - result = result.__class__(msg=result.msg, item=self) - except Exception, exc: - result = Error(msg=str(exc), item=self) + testobject.setUp() + except KeyboardInterrupt: + raise + except TestResult, result: + # reconstruct TestResult object, implicitly set exception + return result.__class__(msg=result.msg, item=self) + except Exception, exc: + return Error(msg=str(exc), item=self) - try: - testobject.tearDown() - except KeyboardInterrupt: - raise - except Exception, exc: - # if we already had an exception in the test method, - # don't overwrite it - if result.traceback is None: - result = Error(msg=str(exc), item=self) - finally: - if posttest is not None: - posttest(self) + try: + testmethod() + result = Success(msg='success', item=self) + except KeyboardInterrupt: + raise + except TestResult, result: + # reconstruct TestResult object, implicitly set exception + result = result.__class__(msg=result.msg, item=self) + except Exception, exc: + result = Error(msg=str(exc), item=self) + + try: + testobject.tearDown() + except KeyboardInterrupt: + raise + except Exception, exc: + # if we already had an exception in the test method, + # don't overwrite it + if result.traceback is None: + result = Error(msg=str(exc), item=self) return result def __str__(self): From sschwarzer at codespeak.net Sat Dec 20 09:55:25 2003 From: sschwarzer at codespeak.net (sschwarzer at codespeak.net) Date: Sat, 20 Dec 2003 09:55:25 +0100 (MET) Subject: [pypy-svn] rev 2611 - in pypy/trunk/src/pypy/tool: . testdata Message-ID: <20031220085525.0A4465AAA7@thoth.codespeak.net> Author: sschwarzer Date: Sat Dec 20 09:55:25 2003 New Revision: 2611 Modified: pypy/trunk/src/pypy/tool/newtest.py pypy/trunk/src/pypy/tool/testdata/test_dummy.py Log: Added support for test functions. These are functions, starting with "test_", in the found test modules. Modified: pypy/trunk/src/pypy/tool/newtest.py ============================================================================== --- pypy/trunk/src/pypy/tool/newtest.py (original) +++ pypy/trunk/src/pypy/tool/newtest.py Sat Dec 20 09:55:25 2003 @@ -192,6 +192,13 @@ assertRaises = failUnlessRaises assert_ = failUnless + +# provide services from TestCase class also to test functions, e. g. +# def test_func4711(): +# service.assertEqual(3, 3.0, msg="objects with same value should be equal") +#XXX maybe use another name +service = TestCase() + # # TestResult class family # @@ -261,23 +268,33 @@ # other classes # class TestItem: - """Represent a single test method from a TestCase class.""" - def __init__(self, module, cls, testmethod): + """ + Represent either a test function, or a single test method from a + TestCase class. + """ + def __init__(self, module, callable=None, cls=None): + """ + Construct a test item. The argument callable must be either a + plain function or an unbound method of a class. In the latter + case, the argument cls must receive the test case class. + """ + # do we have a plain function, or a class and a method? + self._isfunction = (cls is None) self.file = inspect.getsourcefile(module) self.module = module + self.callable = callable self.cls = cls - self.method = testmethod # remove trailing whitespace but leave things such indentation # of first line(s) alone self.docs = (self._docstring(module), self._docstring(cls), - self._docstring(testmethod)) + self._docstring(callable)) #XXX inspect.getsourcelines may fail if the file path stored # in a module's pyc/pyo file doesn't match the py file's # actual location. This can happen if a py file, together with # its pyc/pyo file is moved to a new location. See Python # bug "[570300] inspect.getmodule symlink-related failure": # http://sourceforge.net/tracker/index.php?func=detail&aid=570300&group_id=5470&atid=105470 - lines, self.lineno = inspect.getsourcelines(testmethod) + lines, self.lineno = inspect.getsourcelines(callable) # removing trailing newline(s) but not the indentation self.source = ''.join(lines).rstrip() @@ -286,6 +303,8 @@ Return the docstring of object obj or an empty string, if the docstring doesn't exist, i. e. is None. """ + if obj is None: + return None return inspect.getdoc(obj) or "" def __eq__(self, other): @@ -302,7 +321,7 @@ # http://mail.python.org/pipermail/python-list/2002-September/121655.html # for an explanation. if (self.module is other.module) and (self.cls is other.cls) and \ - (self.method.__name__ == other.method.__name__): + (self.callable.__name__ == other.callable.__name__): return True return False @@ -312,15 +331,19 @@ def __hash__(self): return id(self.module) ^ id(self.cls) - def run(self, pretest=None, posttest=None): + # credit: adapted from Python's unittest.TestCase.run + def run(self): """Run this TestItem and return a corresponding TestResult object.""" - # credit: adapted from Python's unittest.TestCase.run - - testobject = self.cls() - testmethod = getattr(testobject, self.method.__name__) + if self._isfunction: + test = self.callable + else: + # make the test callable a bound method + cls_object = self.cls() + test = getattr(cls_object, self.callable.__name__) try: - testobject.setUp() + # call setUp only for a class + self._isfunction or cls_object.setUp() except KeyboardInterrupt: raise except TestResult, result: @@ -330,7 +353,7 @@ return Error(msg=str(exc), item=self) try: - testmethod() + test() result = Success(msg='success', item=self) except KeyboardInterrupt: raise @@ -341,7 +364,8 @@ result = Error(msg=str(exc), item=self) try: - testobject.tearDown() + # call tearDown only for a class + self._isfunction or cls_object.tearDown() except KeyboardInterrupt: raise except Exception, exc: @@ -352,8 +376,12 @@ return result def __str__(self): - return "TestItem from %s.%s.%s" % (self.module.__name__,\ - self.cls.__name__, self.method.__name__) + if self._isfunction: + return "TestItem from %s.%s" % (self.module.__name__, + self.callable.__name__) + else: + return "TestItem from %s.%s.%s" % (self.module.__name__, + self.cls.__name__, self.callable.__name__) def __repr__(self): return "<%s at %#x>" % (str(self), id(self)) @@ -390,7 +418,10 @@ # inspect.ismethod doesn't seem to work here if inspect.isfunction(obj2) and \ obj2.__name__.startswith("test"): - items.append(TestItem(module, obj, obj2)) + items.append(TestItem(module, cls=obj, callable=obj2)) + elif (callable(obj) and hasattr(obj, '__name__') and + obj.__name__.startswith('test_')): + items.append(TestItem(module, callable=obj)) return items def init_from_dir(self, dirname, filterfunc=None, recursive=True): @@ -476,7 +507,8 @@ if res.traceback is None: continue print 79 * '-' - print "%s.%s: %s" % (res.item.module.__name__, res.item.method.__name__, + print "%s.%s: %s" % (res.item.module.__name__, + res.item.callable.__name__, res.name.upper()) print print res.formatted_traceback @@ -498,4 +530,4 @@ # used to avoid subtle problems with class matching after different # import statements from pypy.tool import newtest - newtest.main(do_selftest=False) + newtest.main(do_selftest=True) Modified: pypy/trunk/src/pypy/tool/testdata/test_dummy.py ============================================================================== --- pypy/trunk/src/pypy/tool/testdata/test_dummy.py (original) +++ pypy/trunk/src/pypy/tool/testdata/test_dummy.py Sat Dec 20 09:55:25 2003 @@ -3,6 +3,14 @@ import autopath from pypy.tool import newtest + +def test_function1(): + raise newtest.Failure("failed test") + +def test_function2(): + newtest.skip() + + class TestDummy1(newtest.TestCase): """ Example of a docstring for a class. @@ -40,3 +48,13 @@ class TestSkip2(newtest.TestCase): def test_skip2(self): self.skip() + + +# these items shouldn't be identified as testable objects +def f(): + raise TypeError + + +class X: + def test_skip(self): + newtest.skip() From arigo at codespeak.net Sat Dec 20 10:02:21 2003 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 20 Dec 2003 10:02:21 +0100 (MET) Subject: [pypy-svn] rev 2612 - pypy/trunk/src/pypy/annotation Message-ID: <20031220090221.3BCAF5AAA7@thoth.codespeak.net> Author: arigo Date: Sat Dec 20 10:02:20 2003 New Revision: 2612 Modified: pypy/trunk/src/pypy/annotation/annset.py Log: Don't record dependencies when generalize() is called. Modified: pypy/trunk/src/pypy/annotation/annset.py ============================================================================== --- pypy/trunk/src/pypy/annotation/annset.py (original) +++ pypy/trunk/src/pypy/annotation/annset.py Sat Dec 20 10:02:20 2003 @@ -106,7 +106,14 @@ def generalize(self, predicate, subject, otherpossibleanswer): """Generalize the given annotation to also account for the given answer.""" - oldanswer = self.get(predicate, subject) + # We shouldn't record a dependency so + # we can't just do 'oldanswer = self.get(predicate, subject)' + oldanswer = mostgeneralvalue + if subject is not mostgeneralvalue: + about = self._about(subject) + old = about.annotations.get(predicate) + if old: + oldanswer, dependencies = old newanswer = self.merge(oldanswer, otherpossibleanswer) if not self.isshared(oldanswer, newanswer): self.kill(predicate, subject) From arigo at codespeak.net Sat Dec 20 10:02:48 2003 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 20 Dec 2003 10:02:48 +0100 (MET) Subject: [pypy-svn] rev 2613 - in pypy/trunk/src/pypy/translator: . test tool Message-ID: <20031220090248.AE7AA5AAA7@thoth.codespeak.net> Author: arigo Date: Sat Dec 20 10:02:48 2003 New Revision: 2613 Added: pypy/trunk/src/pypy/translator/tool/temptest.py (contents, props changed) pypy/trunk/src/pypy/translator/tool/tracer.py (contents, props changed) Modified: pypy/trunk/src/pypy/translator/annrpython.py pypy/trunk/src/pypy/translator/test/snippet.py Log: Added a new example which shows a problem. Modified: pypy/trunk/src/pypy/translator/annrpython.py ============================================================================== --- pypy/trunk/src/pypy/translator/annrpython.py (original) +++ pypy/trunk/src/pypy/translator/annrpython.py Sat Dec 20 10:02:48 2003 @@ -149,12 +149,13 @@ elif cells is not None: self.mergeinputargs(block, cells) if not self.annotated[block]: + self.annotated[block] = True try: self.flowin(block) except DelayAnnotation: - self.delayedblocks.append(block) # failed, hopefully temporarily + self.annotated[block] = False # failed, hopefully temporarily + self.delayedblocks.append(block) else: - self.annotated[block] = True # When flowin succeeds, i.e. when the analysis progress, # we can tentatively re-schedlue the delayed blocks. for block in self.delayedblocks: Modified: pypy/trunk/src/pypy/translator/test/snippet.py ============================================================================== --- pypy/trunk/src/pypy/translator/test/snippet.py (original) +++ pypy/trunk/src/pypy/translator/test/snippet.py Sat Dec 20 10:02:48 2003 @@ -266,3 +266,11 @@ return 1 else: return n * factorial(n-1) + +def append_five(lst): + lst += [5] + +def call_five(): + a = [] + h(a) + return a Added: pypy/trunk/src/pypy/translator/tool/temptest.py ============================================================================== --- (empty file) +++ pypy/trunk/src/pypy/translator/tool/temptest.py Sat Dec 20 10:02:48 2003 @@ -0,0 +1,34 @@ +import sys +from pypy.translator.translator import * +from pypy.translator.test import snippet as test + +from pypy.translator.tool import tracer +tracer.trace(AnnotationSet) +tracer.trace(RPythonAnnotator) + +def h(lst): + lst += [5] + +def calling_h(): + a = [] + h(a) + return a + + +t = Translator(calling_h) # test.poor_man_rev_range) +t.simplify() +a = t.annotate([]) +lines = [] +for key, value in a.bindings.items(): + lines.append('%r: %r' % (key, value)) +lines.sort() +for line in lines: + print line +print '-'*50 +print a.heap +sys.stdout.flush() + +print '-'*50 +print t.pyrex() + +t.gv() Added: pypy/trunk/src/pypy/translator/tool/tracer.py ============================================================================== --- (empty file) +++ pypy/trunk/src/pypy/translator/tool/tracer.py Sat Dec 20 10:02:48 2003 @@ -0,0 +1,42 @@ +import types, sys +from pypy.annotation.model import SomeValue, debugname +from pypy.annotation.annset import AnnotationSet +from pypy.translator.annrpython import RPythonAnnotator + +indent1 = [''] + +def show(n): + if isinstance(n, AnnotationSet): + return 'heap' + elif isinstance(n, RPythonAnnotator): + return 'rpyann' + else: + return repr(n) + +def trace(o): + if isinstance(o, types.ClassType): + for key, value in o.__dict__.items(): + o.__dict__[key] = trace(value) + elif isinstance(o, types.FunctionType): + d = {'o': o, 'show': show, 'indent1': indent1, 'stderr': sys.stderr} + exec """ +def %s(*args, **kwds): + indent, = indent1 + rargs = [show(a) for a in args] + for kw, value in kwds.items(): + rargs.append('%%s=%%r' %% (kw, value)) + print >> stderr, indent + %r + '(%%s)' %% ', '.join(rargs) + indent1[0] += '| ' + try: + result = o(*args, **kwds) + except Exception, e: + indent1[0] = indent + print >> stderr, indent + '+--> %%s: %%s' %% (e.__class__.__name__, e) + raise + indent1[0] = indent + if result is not None: + print >> stderr, indent + '+-->', show(result) + return result +result = %s +""" % (o.__name__, o.__name__, o.__name__) in d + return d['result'] From sschwarzer at codespeak.net Sat Dec 20 10:04:34 2003 From: sschwarzer at codespeak.net (sschwarzer at codespeak.net) Date: Sat, 20 Dec 2003 10:04:34 +0100 (MET) Subject: [pypy-svn] rev 2614 - pypy/trunk/src/pypy/tool Message-ID: <20031220090434.9D7235AAA7@thoth.codespeak.net> Author: sschwarzer Date: Sat Dec 20 10:04:33 2003 New Revision: 2614 Modified: pypy/trunk/src/pypy/tool/newtest.py Log: Added support for test_runner argument to TestItem.run . Modified: pypy/trunk/src/pypy/tool/newtest.py ============================================================================== --- pypy/trunk/src/pypy/tool/newtest.py (original) +++ pypy/trunk/src/pypy/tool/newtest.py Sat Dec 20 10:04:33 2003 @@ -196,7 +196,7 @@ # provide services from TestCase class also to test functions, e. g. # def test_func4711(): # service.assertEqual(3, 3.0, msg="objects with same value should be equal") -#XXX maybe use another name +#XXX maybe use another name instead of 'service' service = TestCase() # @@ -332,8 +332,20 @@ return id(self.module) ^ id(self.cls) # credit: adapted from Python's unittest.TestCase.run - def run(self): - """Run this TestItem and return a corresponding TestResult object.""" + def run(self, test_runner=None): + """ + Run this TestItem and return a corresponding TestResult object. + + If the test item corresponds to a class method, the setUp and + tearDown methods of the associated class are called before and + after the invocation of the test method, repectively. + + If the optional argument test_runner is None, the test function + or method is merely called with no arguments. Else, test_runner + must be a callable accepting one argument. Instead of only calling + the test callable, the test_runner object will be called with the + test function/method as its argument. + """ if self._isfunction: test = self.callable else: @@ -353,7 +365,10 @@ return Error(msg=str(exc), item=self) try: - test() + if test_runner is None: + test() + else: + test_runner(test) result = Success(msg='success', item=self) except KeyboardInterrupt: raise From pmaupin at codespeak.net Sat Dec 20 10:07:45 2003 From: pmaupin at codespeak.net (pmaupin at codespeak.net) Date: Sat, 20 Dec 2003 10:07:45 +0100 (MET) Subject: [pypy-svn] rev 2615 - pypy/trunk/doc/devel Message-ID: <20031220090745.3AE585AAA7@thoth.codespeak.net> Author: pmaupin Date: Sat Dec 20 10:07:44 2003 New Revision: 2615 Modified: pypy/trunk/doc/devel/howtopypy.txt Log: Added instructions to get in a DOS box, and info about creating the source tree Modified: pypy/trunk/doc/devel/howtopypy.txt ============================================================================== --- pypy/trunk/doc/devel/howtopypy.txt (original) +++ pypy/trunk/doc/devel/howtopypy.txt Sat Dec 20 10:07:44 2003 @@ -6,15 +6,22 @@ ``http://codespeak.net/svn/pypy/trunk/`` -If you are ready to download and try PyPy out: +Once you are ready to download and try PyPy out, +follow these instructions, which assume that you +are working in a DOS box (Windows) or terminal (MacOS/X or Linux). 1. Download subversion_ if you do not already have it. -2. Use subversion to download the source:: +2. Change to the directory where you wish to install the source tree, + and use subversion to download the source:: svn co http://codespeak.net/svn/pypy/trunk/src + This will create a subdirectory named ``src``, and will create + the PyPy source tree under this directory. + + If desired, you can also download the documentation:: svn co http://codespeak.net/svn/pypy/trunk/doc From sschwarzer at codespeak.net Sat Dec 20 10:08:19 2003 From: sschwarzer at codespeak.net (sschwarzer at codespeak.net) Date: Sat, 20 Dec 2003 10:08:19 +0100 (MET) Subject: [pypy-svn] rev 2616 - pypy/trunk/src/pypy/tool Message-ID: <20031220090819.D4B705AAA7@thoth.codespeak.net> Author: sschwarzer Date: Sat Dec 20 10:08:18 2003 New Revision: 2616 Modified: pypy/trunk/src/pypy/tool/newtest.py Log: Simplify implementation of test_runner support. Modified: pypy/trunk/src/pypy/tool/newtest.py ============================================================================== --- pypy/trunk/src/pypy/tool/newtest.py (original) +++ pypy/trunk/src/pypy/tool/newtest.py Sat Dec 20 10:08:18 2003 @@ -332,24 +332,25 @@ return id(self.module) ^ id(self.cls) # credit: adapted from Python's unittest.TestCase.run - def run(self, test_runner=None): + def run(self, test_runner=lambda callable: callable()): """ Run this TestItem and return a corresponding TestResult object. - + If the test item corresponds to a class method, the setUp and tearDown methods of the associated class are called before and after the invocation of the test method, repectively. - If the optional argument test_runner is None, the test function + If the optional argument test_runner is absent, the test function or method is merely called with no arguments. Else, test_runner must be a callable accepting one argument. Instead of only calling the test callable, the test_runner object will be called with the test function/method as its argument. """ if self._isfunction: + # use the test function directly test = self.callable else: - # make the test callable a bound method + # turn the test callable, an unbound method, into a bound method cls_object = self.cls() test = getattr(cls_object, self.callable.__name__) @@ -365,10 +366,7 @@ return Error(msg=str(exc), item=self) try: - if test_runner is None: - test() - else: - test_runner(test) + test_runner(test) result = Success(msg='success', item=self) except KeyboardInterrupt: raise From jacob at codespeak.net Sat Dec 20 10:12:00 2003 From: jacob at codespeak.net (jacob at codespeak.net) Date: Sat, 20 Dec 2003 10:12:00 +0100 (MET) Subject: [pypy-svn] rev 2617 - pypy/trunk/doc/overview Message-ID: <20031220091200.082985AAA7@thoth.codespeak.net> Author: jacob Date: Sat Dec 20 10:12:00 2003 New Revision: 2617 Modified: pypy/trunk/doc/overview/architecture.txt Log: Fixed REST problem. Modified: pypy/trunk/doc/overview/architecture.txt ============================================================================== --- pypy/trunk/doc/overview/architecture.txt (original) +++ pypy/trunk/doc/overview/architecture.txt Sat Dec 20 10:12:00 2003 @@ -36,13 +36,9 @@ We currently have 2 working object spaces which are more or less interchangeable: -- The trivial object space, which is a thin wrapper around CPython -types. It was used to test the interpreter and is used from time to -time for testing purposes. It is currently of little interest. - -- The standard object space, which is an almost complete implementation -of Python types in Python. This is the main focus of this document, -since it is the foundation of PyPy. +- The trivial object space, which is a thin wrapper around CPython types. It was used to test the interpreter and is used from time to time for testing purposes. It is currently of little interest. + +- The standard object space, which is an almost complete implementation of Python types in Python. This is the main focus of this document, since it is the foundation of PyPy. The Standard Object Space ========================= From pedronis at codespeak.net Sat Dec 20 10:13:06 2003 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Sat, 20 Dec 2003 10:13:06 +0100 (MET) Subject: [pypy-svn] rev 2618 - pypy/trunk/src/pypy/translator/tool Message-ID: <20031220091306.E92D75AAA7@thoth.codespeak.net> Author: pedronis Date: Sat Dec 20 10:13:06 2003 New Revision: 2618 Modified: pypy/trunk/src/pypy/translator/tool/temptest.py Log: added autopath to temptest Modified: pypy/trunk/src/pypy/translator/tool/temptest.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/temptest.py (original) +++ pypy/trunk/src/pypy/translator/tool/temptest.py Sat Dec 20 10:13:06 2003 @@ -1,4 +1,7 @@ import sys + +import autopath + from pypy.translator.translator import * from pypy.translator.test import snippet as test From sschwarzer at codespeak.net Sat Dec 20 10:14:28 2003 From: sschwarzer at codespeak.net (sschwarzer at codespeak.net) Date: Sat, 20 Dec 2003 10:14:28 +0100 (MET) Subject: [pypy-svn] rev 2619 - pypy/trunk/src/pypy/tool/testdata Message-ID: <20031220091428.9F9145AAA7@thoth.codespeak.net> Author: sschwarzer Date: Sat Dec 20 10:14:28 2003 New Revision: 2619 Modified: pypy/trunk/src/pypy/tool/testdata/test_dummy.py Log: Fixed examples with respect to test functions. Modified: pypy/trunk/src/pypy/tool/testdata/test_dummy.py ============================================================================== --- pypy/trunk/src/pypy/tool/testdata/test_dummy.py (original) +++ pypy/trunk/src/pypy/tool/testdata/test_dummy.py Sat Dec 20 10:14:28 2003 @@ -5,10 +5,10 @@ def test_function1(): - raise newtest.Failure("failed test") + raise newtest.service.fail("failed test") def test_function2(): - newtest.skip() + newtest.service.skip() class TestDummy1(newtest.TestCase): @@ -19,10 +19,10 @@ self.assertEquals(1+1, 2) def test_error1(self): - raise ValueError + raise TypeError("intentional TypeError") def test_failure1(self): - raise newtest.Failure + raise self.fail("fail deliberately in test_failure1") class TestDummy2(newtest.TestCase): @@ -31,10 +31,10 @@ def test_error2(self): """Docstring of a method.""" - raise ValueError + raise ValueError("intentional ValueError") def test_failure2(self): - raise newtest.Failure + raise self.fail("fail deliberately in test_failure2") class TestSkip1(newtest.TestCase): @@ -57,4 +57,4 @@ class X: def test_skip(self): - newtest.skip() + newtest.service.skip() From arigo at codespeak.net Sat Dec 20 10:16:01 2003 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 20 Dec 2003 10:16:01 +0100 (MET) Subject: [pypy-svn] rev 2620 - pypy/trunk/src/pypy/translator Message-ID: <20031220091601.EABBE5AAA7@thoth.codespeak.net> Author: arigo Date: Sat Dec 20 10:16:01 2003 New Revision: 2620 Modified: pypy/trunk/src/pypy/translator/translator.py Log: Fixed "t.cl()". Modified: pypy/trunk/src/pypy/translator/translator.py ============================================================================== --- pypy/trunk/src/pypy/translator/translator.py (original) +++ pypy/trunk/src/pypy/translator/translator.py Sat Dec 20 10:16:01 2003 @@ -36,7 +36,7 @@ from pypy.translator.annrpython import RPythonAnnotator from pypy.translator.simplify import simplify_graph from pypy.translator.genpyrex import GenPyrex -#from pypy.translator.gencl import GenCL +from pypy.translator.gencl import GenCL from pypy.translator.tool.buildpyxmodule import make_module_from_pyxstring from pypy.objspace.flow import FlowObjSpace @@ -129,7 +129,7 @@ """ return self.generatecode(GenPyrex, input_arg_types, func) - def cl(self, input_arg_types=None): + def cl(self, input_arg_types=None, func=None): """cl(self[, input_arg_types][, func]) -> Common Lisp translation Returns Common Lisp translation. If input_arg_types is provided, From sschwarzer at codespeak.net Sat Dec 20 10:16:10 2003 From: sschwarzer at codespeak.net (sschwarzer at codespeak.net) Date: Sat, 20 Dec 2003 10:16:10 +0100 (MET) Subject: [pypy-svn] rev 2621 - pypy/trunk/src/pypy/tool Message-ID: <20031220091610.664935AAA7@thoth.codespeak.net> Author: sschwarzer Date: Sat Dec 20 10:16:09 2003 New Revision: 2621 Modified: pypy/trunk/src/pypy/tool/newtest.py Log: Extended some comments. Modified: pypy/trunk/src/pypy/tool/newtest.py ============================================================================== --- pypy/trunk/src/pypy/tool/newtest.py (original) +++ pypy/trunk/src/pypy/tool/newtest.py Sat Dec 20 10:16:09 2003 @@ -423,8 +423,10 @@ def _items_from_module(self, module): """Return a list of TestItems read from the given module.""" items = [] - # scan the module for classes derived from TestCase + # scan the module for test functions, and for classes derived + # from TestCase for obj in vars(module).values(): + # find TestCase classes and methods within them if inspect.isclass(obj) and issubclass(obj, TestCase): # we found a TestCase class, now scan it for test methods for obj2 in vars(obj).values(): @@ -432,6 +434,7 @@ if inspect.isfunction(obj2) and \ obj2.__name__.startswith("test"): items.append(TestItem(module, cls=obj, callable=obj2)) + # find test functions elif (callable(obj) and hasattr(obj, '__name__') and obj.__name__.startswith('test_')): items.append(TestItem(module, callable=obj)) From alex at codespeak.net Sat Dec 20 10:18:25 2003 From: alex at codespeak.net (alex at codespeak.net) Date: Sat, 20 Dec 2003 10:18:25 +0100 (MET) Subject: [pypy-svn] rev 2622 - pypy/trunk/doc/devel Message-ID: <20031220091825.903A15AAA7@thoth.codespeak.net> Author: alex Date: Sat Dec 20 10:18:24 2003 New Revision: 2622 Modified: pypy/trunk/doc/devel/howtopypy.txt Log: fix a couple typos, turn passive forms into active Modified: pypy/trunk/doc/devel/howtopypy.txt ============================================================================== --- pypy/trunk/doc/devel/howtopypy.txt (original) +++ pypy/trunk/doc/devel/howtopypy.txt Sat Dec 20 10:18:24 2003 @@ -35,10 +35,10 @@ After a few seconds, you should be at the PyPy prompt, which is the same as the Python prompt, but with an extra ">". - The "-S" given on the command line insructs the PyPy interpreter + The "-S" given on the command line instructs the PyPy interpreter to use the `Standard object space`_. PyPy has the concept of different object spaces_, but the standard space is the one which contains - the "real" Python interpreter. + the "real" Python-in-Python interpreter. 4. Now you are ready to start running Python code. Some real Python @@ -55,7 +55,7 @@ on the current PyPy implementation. -5. The PyPy interpreter command line options are listed by typing:: +5. To list the PyPy interpreter command line options, type:: python py.py --help @@ -68,17 +68,18 @@ python py.py -S ../appspace/pystone.py - (Note that this will run forever.) + (Note that this will run "forever" -- actually, "just" for many + hours, with the current implementation of PyPy.) 6. The PyPy project uses test-driven-development. Right now, there are - a couple of different categories of tests which can be run. + a couple of different categories of tests which you can run. To run all the unit tests:: cd src/pypy python test_all.py -S - Alternatively, subtests may be run by going to the correct subdirectory + Alternatively, you may run subtests by going to the correct subdirectory and running them individually:: cd src/pypy/module/test From sschwarzer at codespeak.net Sat Dec 20 10:19:32 2003 From: sschwarzer at codespeak.net (sschwarzer at codespeak.net) Date: Sat, 20 Dec 2003 10:19:32 +0100 (MET) Subject: [pypy-svn] rev 2623 - pypy/trunk/src/pypy/tool Message-ID: <20031220091932.B45B05AAA7@thoth.codespeak.net> Author: sschwarzer Date: Sat Dec 20 10:19:32 2003 New Revision: 2623 Modified: pypy/trunk/src/pypy/tool/newtest.py Log: Renamed TestItem._isfunction to isfunction after recognizing it is useful outside the class. Modified: pypy/trunk/src/pypy/tool/newtest.py ============================================================================== --- pypy/trunk/src/pypy/tool/newtest.py (original) +++ pypy/trunk/src/pypy/tool/newtest.py Sat Dec 20 10:19:32 2003 @@ -279,7 +279,7 @@ case, the argument cls must receive the test case class. """ # do we have a plain function, or a class and a method? - self._isfunction = (cls is None) + self.isfunction = (cls is None) self.file = inspect.getsourcefile(module) self.module = module self.callable = callable @@ -346,7 +346,7 @@ the test callable, the test_runner object will be called with the test function/method as its argument. """ - if self._isfunction: + if self.isfunction: # use the test function directly test = self.callable else: @@ -356,7 +356,7 @@ try: # call setUp only for a class - self._isfunction or cls_object.setUp() + self.isfunction or cls_object.setUp() except KeyboardInterrupt: raise except TestResult, result: @@ -378,7 +378,7 @@ try: # call tearDown only for a class - self._isfunction or cls_object.tearDown() + self.isfunction or cls_object.tearDown() except KeyboardInterrupt: raise except Exception, exc: @@ -389,7 +389,7 @@ return result def __str__(self): - if self._isfunction: + if self.isfunction: return "TestItem from %s.%s" % (self.module.__name__, self.callable.__name__) else: @@ -523,9 +523,15 @@ if res.traceback is None: continue print 79 * '-' - print "%s.%s: %s" % (res.item.module.__name__, - res.item.callable.__name__, - res.name.upper()) + if res.item.isfunction: + print "%s.%s: %s" % (res.item.module.__name__, + res.item.callable.__name__, + res.name.upper()) + else: + print "%s.%s.%s: %s" % (res.item.module.__name__, + res.item.cls.__name__, + res.item.callable.__name__, + res.name.upper()) print print res.formatted_traceback # emit a summary From sschwarzer at codespeak.net Sat Dec 20 10:29:16 2003 From: sschwarzer at codespeak.net (sschwarzer at codespeak.net) Date: Sat, 20 Dec 2003 10:29:16 +0100 (MET) Subject: [pypy-svn] rev 2624 - pypy/trunk/src/pypy/tool Message-ID: <20031220092916.6940D5AAA7@thoth.codespeak.net> Author: sschwarzer Date: Sat Dec 20 10:29:15 2003 New Revision: 2624 Modified: pypy/trunk/src/pypy/tool/newtest.py Log: Rephrased printing of errors and failures. Modified: pypy/trunk/src/pypy/tool/newtest.py ============================================================================== --- pypy/trunk/src/pypy/tool/newtest.py (original) +++ pypy/trunk/src/pypy/tool/newtest.py Sat Dec 20 10:29:15 2003 @@ -523,15 +523,14 @@ if res.traceback is None: continue print 79 * '-' + # print a line with the qualified name of the bad callable + item = res.item if res.item.isfunction: - print "%s.%s: %s" % (res.item.module.__name__, - res.item.callable.__name__, + print "%s.%s: %s" % (item.module.__name__, item.callable.__name__, res.name.upper()) else: - print "%s.%s.%s: %s" % (res.item.module.__name__, - res.item.cls.__name__, - res.item.callable.__name__, - res.name.upper()) + print "%s.%s.%s: %s" % (item.module.__name__, item.cls.__name__, + item.callable.__name__, res.name.upper()) print print res.formatted_traceback # emit a summary From pmaupin at codespeak.net Sat Dec 20 11:01:53 2003 From: pmaupin at codespeak.net (pmaupin at codespeak.net) Date: Sat, 20 Dec 2003 11:01:53 +0100 (MET) Subject: [pypy-svn] rev 2625 - pypy/trunk/src/pypy/module/test Message-ID: <20031220100153.70DF75AAA7@thoth.codespeak.net> Author: pmaupin Date: Sat Dec 20 11:01:52 2003 New Revision: 2625 Modified: pypy/trunk/src/pypy/module/test/test_builtin.py Log: Added test for intern() Modified: pypy/trunk/src/pypy/module/test/test_builtin.py ============================================================================== --- pypy/trunk/src/pypy/module/test/test_builtin.py (original) +++ pypy/trunk/src/pypy/module/test/test_builtin.py Sat Dec 20 11:01:52 2003 @@ -21,6 +21,16 @@ self.assertRaises(ValueError, chr, -1) self.assertRaises(TypeError, chr, 'a') + def test_intern(self): + self.assertRaises(TypeError, intern) + s = "never interned before" + s2 = intern(s) + self.assertEquals(s, s2) + s3 = s.swapcase() + self.assert_(s3 != s2) + s4 = s3.swapcase() + self.assert_(intern(s4) is s2) + def test_globals(self): d = {"foo":"bar"} exec "def f(): return globals()" in d From pedronis at codespeak.net Sat Dec 20 11:22:27 2003 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Sat, 20 Dec 2003 11:22:27 +0100 (MET) Subject: [pypy-svn] rev 2626 - in pypy/trunk/src/pypy/annotation: . test Message-ID: <20031220102227.5B63A5AAA7@thoth.codespeak.net> Author: pedronis Date: Sat Dec 20 11:22:26 2003 New Revision: 2626 Modified: pypy/trunk/src/pypy/annotation/annset.py pypy/trunk/src/pypy/annotation/test/test_annset.py Log: fixed second level rec merge involving impossiblevalues & in general not SomeValue values. Modified: pypy/trunk/src/pypy/annotation/annset.py ============================================================================== --- pypy/trunk/src/pypy/annotation/annset.py (original) +++ pypy/trunk/src/pypy/annotation/annset.py Sat Dec 20 11:22:26 2003 @@ -131,6 +131,10 @@ if self.isshared(oldvalue, newvalue): return oldvalue + if not (isinstance(oldvalue, SomeValue) and + isinstance(newvalue, SomeValue)): + return mostgeneralvalue + # build an About set that is the intersection of the two incoming ones about1 = self._about(oldvalue) about2 = self._about(newvalue) @@ -141,13 +145,10 @@ someval2, dep2 = about2.annotations[pred] if someval1 == someval2: someval3 = someval1 - elif (isinstance(someval1, SomeValue) and - isinstance(someval2, SomeValue)): + else: someval3 = self.merge(someval1, someval2) if someval3 is mostgeneralvalue: - continue - else: - continue # annotation not in common + continue # annotation not in common dep3 = dep1.copy() dep3.update(dep2) about3.annotations[pred] = someval3, dep3 Modified: pypy/trunk/src/pypy/annotation/test/test_annset.py ============================================================================== --- pypy/trunk/src/pypy/annotation/test/test_annset.py (original) +++ pypy/trunk/src/pypy/annotation/test/test_annset.py Sat Dec 20 11:22:26 2003 @@ -3,7 +3,7 @@ from pypy.tool import test from pypy.annotation.model import SomeValue, ANN, Predicate -from pypy.annotation.annset import AnnotationSet, mostgeneralvalue +from pypy.annotation.annset import AnnotationSet, mostgeneralvalue,impossiblevalue c1,c2,c3,c4 = SomeValue(), SomeValue(), SomeValue(), SomeValue() @@ -135,6 +135,19 @@ links=[c3,c]) self.assertSameSet(a1, a2) + def test_level2_merge_w_impossible(self): + a1 = annset(ANN.type, c1, list, + ANN.listitems, c1, impossiblevalue, + ANN.type, c2, list, + ANN.listitems, c2, c3, + ANN.type, c3, int) + c = a1.merge(c1,c2) + a2 = annset(ANN.type, c , list, + ANN.listitems, c, c3, + ANN.type, c3, int, + links=[c1,c]) + self.assertSameSet(a1,a2) + def test_merge_generalize_both_immutables(self): a1 = annset(ANN.len, c1, c2, ANN.immutable, c1, From pedronis at codespeak.net Sat Dec 20 11:24:52 2003 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Sat, 20 Dec 2003 11:24:52 +0100 (MET) Subject: [pypy-svn] rev 2627 - pypy/trunk/src/pypy/translator/test Message-ID: <20031220102452.C1A4B5AAA7@thoth.codespeak.net> Author: pedronis Date: Sat Dec 20 11:24:52 2003 New Revision: 2627 Modified: pypy/trunk/src/pypy/translator/test/snippet.py Log: fixed call_five snippet. Modified: pypy/trunk/src/pypy/translator/test/snippet.py ============================================================================== --- pypy/trunk/src/pypy/translator/test/snippet.py (original) +++ pypy/trunk/src/pypy/translator/test/snippet.py Sat Dec 20 11:24:52 2003 @@ -272,5 +272,5 @@ def call_five(): a = [] - h(a) + append_five(a) return a From alex at codespeak.net Sat Dec 20 11:29:43 2003 From: alex at codespeak.net (alex at codespeak.net) Date: Sat, 20 Dec 2003 11:29:43 +0100 (MET) Subject: [pypy-svn] rev 2628 - pypy/trunk/src/pypy/module/test Message-ID: <20031220102943.AE1E85AAA7@thoth.codespeak.net> Author: alex Date: Sat Dec 20 11:29:43 2003 New Revision: 2628 Modified: pypy/trunk/src/pypy/module/test/test_builtin.py Log: removed a duplicate test_intern Modified: pypy/trunk/src/pypy/module/test/test_builtin.py ============================================================================== --- pypy/trunk/src/pypy/module/test/test_builtin.py (original) +++ pypy/trunk/src/pypy/module/test/test_builtin.py Sat Dec 20 11:29:43 2003 @@ -23,6 +23,7 @@ def test_intern(self): self.assertRaises(TypeError, intern) + self.assertRaises(TypeError, intern, 1) s = "never interned before" s2 = intern(s) self.assertEquals(s, s2) @@ -178,10 +179,6 @@ def test_divmod(self): self.assertEquals(divmod(15,10),(1,5)) - def test_intern(self): - s = 'xxx' - self.assertEquals(intern(s), s) - self.assertRaises(TypeError, intern, 1) class TestInternal(test.IntTestCase): From pmaupin at codespeak.net Sat Dec 20 11:31:32 2003 From: pmaupin at codespeak.net (pmaupin at codespeak.net) Date: Sat, 20 Dec 2003 11:31:32 +0100 (MET) Subject: [pypy-svn] rev 2629 - pypy/trunk/src/pypy/module Message-ID: <20031220103132.CB1995AAA7@thoth.codespeak.net> Author: pmaupin Date: Sat Dec 20 11:31:32 2003 New Revision: 2629 Modified: pypy/trunk/src/pypy/module/builtin.py Log: Added intern() implementation Modified: pypy/trunk/src/pypy/module/builtin.py ============================================================================== --- pypy/trunk/src/pypy/module/builtin.py (original) +++ pypy/trunk/src/pypy/module/builtin.py Sat Dec 20 11:31:32 2003 @@ -698,13 +698,13 @@ return result def app_intern(self, s): - """ - We don't have a string table, making intern a null operation. - This is here for backwards compatibility. - """ if not isinstance(s, str): raise TypeError("intern() argument 1 must be string.") - return s + try: + t = self._stringtable + except AttributeError: + t = self._stringtable = {} + return t.setdefault(s,s) def app_copyright(self): print 'Copyright 2002-2004 Pypy development team.\nAll rights reserved.\nFor further information see http://www.codespaek.net/pypy.\nSome materials may have a different copyright.\nIn these cases, this is explicitly noted in the source code file.' From sschwarzer at codespeak.net Sat Dec 20 11:47:55 2003 From: sschwarzer at codespeak.net (sschwarzer at codespeak.net) Date: Sat, 20 Dec 2003 11:47:55 +0100 (MET) Subject: [pypy-svn] rev 2630 - in pypy/trunk/src/pypy/tool: . testdata Message-ID: <20031220104755.289FA5AAA7@thoth.codespeak.net> Author: sschwarzer Date: Sat Dec 20 11:47:54 2003 New Revision: 2630 Modified: pypy/trunk/src/pypy/tool/newtest.py pypy/trunk/src/pypy/tool/testdata/test_dummy.py Log: TestSuite objects now can determine test items in dicts, modules and directory trees. newtest.main is there, but doesn't find the right module for the tests yet. Modified: pypy/trunk/src/pypy/tool/newtest.py ============================================================================== --- pypy/trunk/src/pypy/tool/newtest.py (original) +++ pypy/trunk/src/pypy/tool/newtest.py Sat Dec 20 11:47:54 2003 @@ -403,29 +403,36 @@ class TestSuite: """Represent a collection of test items.""" def __init__(self): - self.items = [] - self.last_results = {} + self.reset() - def _module_from_modpath(self, modpath): + def reset(self): """ - Return a module object derived from the module path - (e. g. "pypy.module.builtin.test.test_minmax"). + Clear this TestSuite instance from all stored items and + test results. """ - # This __import__ call is only used to ensure that the module - # is present in sys.modules. Unfortunately, the module returned - # from the __import__ function doesn't correspond to the last - # component of the module path but the first. In the example - # listed in the docstring we thus would get the pypy module - # (i. e. package), not the test_minmax module. - __import__(modpath) - return sys.modules[modpath] + self.items = [] + self.last_results = {} - def _items_from_module(self, module): - """Return a list of TestItems read from the given module.""" + # + # get lists of TestItems from a dictionary, a module, or a directory tree + # + def items_from_dict(self, dict_, module=None): + """ + Return a list of TestItems as extracted from the given dictionary + dict_. The keys of the dictionary are names of objects, the values + are the corresponding objects. Think of the value returned by the + builtin function globals. + + You may pass in a module object via the optional argument module. + If the argument is present, it will be included in the TestItems. + Else, the __main__ module will be used. + """ + if module is None: + module = sys.modules['__main__'] items = [] - # scan the module for test functions, and for classes derived + # scan the values for test functions, and for classes derived # from TestCase - for obj in vars(module).values(): + for obj in dict_.values(): # find TestCase classes and methods within them if inspect.isclass(obj) and issubclass(obj, TestCase): # we found a TestCase class, now scan it for test methods @@ -433,18 +440,37 @@ # inspect.ismethod doesn't seem to work here if inspect.isfunction(obj2) and \ obj2.__name__.startswith("test"): - items.append(TestItem(module, cls=obj, callable=obj2)) + items.append(TestItem(module=module, cls=obj, + callable=obj2)) # find test functions elif (callable(obj) and hasattr(obj, '__name__') and obj.__name__.startswith('test_')): items.append(TestItem(module, callable=obj)) return items - def init_from_dir(self, dirname, filterfunc=None, recursive=True): + def items_from_module(self, module): + """Return a list of TestItems read from the given module.""" + return self.items_from_dict(vars(module), module=module) + + def _module_from_modpath(self, modpath): + """ + Return a module object derived from the module path + (e. g. "pypy.module.builtin.test.test_minmax"). """ - Init this suite by reading the directory denoted by dirname, - then find all test modules in it. Test modules are files that - comply with the shell pattern shell_pattern "test_*.py". + # This __import__ call is only used to ensure that the module + # is present in sys.modules. Unfortunately, the module returned + # from the __import__ function doesn't correspond to the last + # component of the module path but the first. In the example + # listed in the docstring we thus would get the pypy module + # (i. e. package), not the test_minmax module. + __import__(modpath) + return sys.modules[modpath] + + def items_from_dir(self, dirname, filterfunc=None, recursive=True): + """ + Return a list of TestItems found by reading the directory denoted + by dirname. Find all test modules in it. Test modules are files that + comply with the shell pattern "test_*.py". filterfunc is a callable that can be used to filter the test modules by module path. By default, all test modules are used. @@ -452,7 +478,7 @@ If recursive is true, which is the default, find all test modules by scanning the start directory recursively. """ - self.items = [] + items = [] dirname = vpath.getlocal(dirname) def testfilefilter(path): @@ -467,13 +493,34 @@ if (filterfunc is None) or filterfunc(modpath): try: module = self._module_from_modpath(modpath) - items = self._items_from_module(module) + module_items = self.items_from_module(module) except: print >> sys.stderr, \ "Warning: can't load module %s" % modpath + raise else: - self.items.extend(items) + items.extend(module_items) + return items + # + # init TestSuite instance from a dictionary, a module, or a directory tree + # + def init_from_dict(self, dict_, module=None): + self.reset() + self.items = self.items_from_dict(dict_, module=module) + + def init_from_module(self, module): + self.reset() + self.items = self.items_from_module(module) + + def init_from_dir(self, dirname, filterfunc=None, recursive=True): + self.reset() + self.items = self.items_from_dir(dirname, filterfunc=None, + recursive=True) + + # + # running tests and getting results + # def result_generator(self, classify=lambda result: result.item.module.__name__): """ @@ -503,42 +550,30 @@ # the results; they are then available via self.last_results return [result for result in self.result_generator()] -# -# demonstrate test framework usage -# -def main(do_selftest=False): - # possibly ignore dummy unit tests - if do_selftest: - # include only selftest module - filterfunc = lambda m: m.find("pypy.tool.testdata.") != -1 - else: - # exclude selftest module - filterfunc = lambda m: m.find("pypy.tool.testdata.") == -1 - # collect tests - ts = TestSuite() - print "Loading test modules ..." - ts.init_from_dir(autopath.pypydir, filterfunc=filterfunc) + +def _print_results(suite): + """Print results for the items in a test suite.""" # iterate over tests and collect data - for res in ts.result_generator(): - if res.traceback is None: + for result in suite.result_generator(): + if result.traceback is None: continue print 79 * '-' # print a line with the qualified name of the bad callable - item = res.item - if res.item.isfunction: + item = result.item + if result.item.isfunction: print "%s.%s: %s" % (item.module.__name__, item.callable.__name__, - res.name.upper()) + result.name.upper()) else: print "%s.%s.%s: %s" % (item.module.__name__, item.cls.__name__, - item.callable.__name__, res.name.upper()) + item.callable.__name__, result.name.upper()) print - print res.formatted_traceback + print result.formatted_traceback # emit a summary print 79 * '=' - modules = ts.last_results.keys() + modules = suite.last_results.keys() modules.sort() for module in modules: - results = ts.last_results[module] + results = suite.last_results[module] resultstring = '' for result in results: status_char = {Success: '.', Ignored: 'i', Skipped: 's', @@ -546,9 +581,34 @@ resultstring += status_char print "%s [%d] %s" % (module, len(results), resultstring) +def main(): + """ + Find all tests in the current module (i. e. the module from which this + function is called), execute them and print results. + """ + from pypy.tool import newtest + suite = TestSuite() + print globals() + suite.init_from_dict(globals()) + _print_results(suite) + +def test(do_selftest=False): + # possibly ignore dummy unit tests + if do_selftest: + # include only selftest module + filterfunc = lambda m: m.find("pypy.tool.testdata.") != -1 + else: + # exclude selftest module + filterfunc = lambda m: m.find("pypy.tool.testdata.") == -1 + # collect tests + suite = TestSuite() + print "Loading test modules ..." + suite.init_from_dir(autopath.pypydir, filterfunc=filterfunc) + _print_results(suite) + if __name__ == '__main__': # used to avoid subtle problems with class matching after different # import statements from pypy.tool import newtest - newtest.main(do_selftest=True) + newtest.test(do_selftest=True) Modified: pypy/trunk/src/pypy/tool/testdata/test_dummy.py ============================================================================== --- pypy/trunk/src/pypy/tool/testdata/test_dummy.py (original) +++ pypy/trunk/src/pypy/tool/testdata/test_dummy.py Sat Dec 20 11:47:54 2003 @@ -1,6 +1,6 @@ """Module docstring.""" -import autopath +#import autopath from pypy.tool import newtest @@ -58,3 +58,7 @@ class X: def test_skip(self): newtest.service.skip() + + +if __name__ == '__main__': + newtest.main() From pedronis at codespeak.net Sat Dec 20 11:49:15 2003 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Sat, 20 Dec 2003 11:49:15 +0100 (MET) Subject: [pypy-svn] rev 2631 - pypy/trunk/src/pypy/translator/tool Message-ID: <20031220104915.36A7E5AAA7@thoth.codespeak.net> Author: pedronis Date: Sat Dec 20 11:49:14 2003 New Revision: 2631 Modified: pypy/trunk/src/pypy/translator/tool/temptest.py Log: made temptest.py a more generally useful tool. Modified: pypy/trunk/src/pypy/translator/tool/temptest.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/temptest.py (original) +++ pypy/trunk/src/pypy/translator/tool/temptest.py Sat Dec 20 11:49:14 2003 @@ -1,3 +1,18 @@ +""" + +- annotate and translate snippet producing tracing of calls +to AnnotationSet and RPythonAnnotator +- print bindings and final annotation set +and pyrex + +- display flow graph + +call it like: + +traceann >result.txt 2>trace.txt + +""" + import sys import autopath @@ -9,18 +24,19 @@ tracer.trace(AnnotationSet) tracer.trace(RPythonAnnotator) -def h(lst): - lst += [5] +try: + snippet_name = sys.argv[1] +except IndexError: + snippet_name = "call_five" -def calling_h(): - a = [] - h(a) - return a +argtypes = [] +for argtype in sys.argv[2:]: + argtypes.append(eval(argtype)) -t = Translator(calling_h) # test.poor_man_rev_range) +t = Translator(getattr(test,snippet_name)) t.simplify() -a = t.annotate([]) +a = t.annotate(argtypes) lines = [] for key, value in a.bindings.items(): lines.append('%r: %r' % (key, value)) From pedronis at codespeak.net Sat Dec 20 11:50:22 2003 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Sat, 20 Dec 2003 11:50:22 +0100 (MET) Subject: [pypy-svn] rev 2632 - pypy/trunk/src/pypy/translator/tool Message-ID: <20031220105022.988CF5AAA7@thoth.codespeak.net> Author: pedronis Date: Sat Dec 20 11:50:22 2003 New Revision: 2632 Added: pypy/trunk/src/pypy/translator/tool/traceann.py (props changed) - copied unchanged from rev 2631, pypy/trunk/src/pypy/translator/tool/temptest.py Removed: pypy/trunk/src/pypy/translator/tool/temptest.py Log: changed name to traceann usage: traceann [type ...] >result.txt 2>trace.txt Deleted: /pypy/trunk/src/pypy/translator/tool/temptest.py ============================================================================== --- /pypy/trunk/src/pypy/translator/tool/temptest.py Sat Dec 20 11:50:22 2003 +++ (empty file) @@ -1,53 +0,0 @@ -""" - -- annotate and translate snippet producing tracing of calls -to AnnotationSet and RPythonAnnotator -- print bindings and final annotation set -and pyrex - -- display flow graph - -call it like: - -traceann >result.txt 2>trace.txt - -""" - -import sys - -import autopath - -from pypy.translator.translator import * -from pypy.translator.test import snippet as test - -from pypy.translator.tool import tracer -tracer.trace(AnnotationSet) -tracer.trace(RPythonAnnotator) - -try: - snippet_name = sys.argv[1] -except IndexError: - snippet_name = "call_five" - -argtypes = [] - -for argtype in sys.argv[2:]: - argtypes.append(eval(argtype)) - -t = Translator(getattr(test,snippet_name)) -t.simplify() -a = t.annotate(argtypes) -lines = [] -for key, value in a.bindings.items(): - lines.append('%r: %r' % (key, value)) -lines.sort() -for line in lines: - print line -print '-'*50 -print a.heap -sys.stdout.flush() - -print '-'*50 -print t.pyrex() - -t.gv() From sschwarzer at codespeak.net Sat Dec 20 11:59:26 2003 From: sschwarzer at codespeak.net (sschwarzer at codespeak.net) Date: Sat, 20 Dec 2003 11:59:26 +0100 (MET) Subject: [pypy-svn] rev 2633 - pypy/trunk/src/pypy/tool Message-ID: <20031220105926.CED075AAA7@thoth.codespeak.net> Author: sschwarzer Date: Sat Dec 20 11:59:26 2003 New Revision: 2633 Modified: pypy/trunk/src/pypy/tool/newtest.py Log: newtest.main now works as expected. Modified: pypy/trunk/src/pypy/tool/newtest.py ============================================================================== --- pypy/trunk/src/pypy/tool/newtest.py (original) +++ pypy/trunk/src/pypy/tool/newtest.py Sat Dec 20 11:59:26 2003 @@ -428,7 +428,7 @@ Else, the __main__ module will be used. """ if module is None: - module = sys.modules['__main__'] + module = __import__('__main__') items = [] # scan the values for test functions, and for classes derived # from TestCase @@ -586,10 +586,10 @@ Find all tests in the current module (i. e. the module from which this function is called), execute them and print results. """ + import __main__ from pypy.tool import newtest suite = TestSuite() - print globals() - suite.init_from_dict(globals()) + suite.init_from_dict(vars(__main__)) _print_results(suite) def test(do_selftest=False): From jacob at codespeak.net Sat Dec 20 12:00:27 2003 From: jacob at codespeak.net (jacob at codespeak.net) Date: Sat, 20 Dec 2003 12:00:27 +0100 (MET) Subject: [pypy-svn] rev 2634 - pypy/trunk/doc/overview Message-ID: <20031220110027.E84725AAA7@thoth.codespeak.net> Author: jacob Date: Sat Dec 20 12:00:27 2003 New Revision: 2634 Modified: pypy/trunk/doc/overview/RPy-translation-overview.txt pypy/trunk/doc/overview/architecture.txt Log: Integrated and expanded RPython translation chapter. Modified: pypy/trunk/doc/overview/RPy-translation-overview.txt ============================================================================== --- pypy/trunk/doc/overview/RPy-translation-overview.txt (original) +++ pypy/trunk/doc/overview/RPy-translation-overview.txt Sat Dec 20 12:00:27 2003 @@ -7,18 +7,16 @@ PyPy interpreter itself with a specific Object Space, the Flow Object Space, plugged in. The Flow Object Space drives the execution in such a way that all paths in the code are followed. As a side-effect it -produce flow graphs, that means graph capturing the control flow of +produces flow graphs, that means graph capturing the control flow of the code, nodes there are basic blocks of logged Object Space operations executed sequentially, how values flow is also encoded. -These flow graphs can be fed then as input to the Annotator. Under the -constraints of RPython, the Annotator given entry point types should -be able to infer the types of values that flow through the program -variables. +These flow graphs can then be fed as input to the Annotator. Under the +constraints of RPython, the Annotator given entry point types infers +the types of values that flow through the program variables. -In a last phase the type annotated flow graphs can be visited by the +In the last phase the type annotated flow graphs are visited by the Translator, which out of the types annotation, the basic block listed -operations and control flow information encoded in the graphs, should -be able to emit "low-level" code. Our first target would be probably -Pyrex code, which then can be translated to compilable C by Pyrex -itself. +operations and control flow information encoded in the graphs, emits +"low-level" code. Our first target will probably be Pyrex code, which +is then translated to compilable C by Pyrex itself. Modified: pypy/trunk/doc/overview/architecture.txt ============================================================================== --- pypy/trunk/doc/overview/architecture.txt (original) +++ pypy/trunk/doc/overview/architecture.txt Sat Dec 20 12:00:27 2003 @@ -36,9 +36,13 @@ We currently have 2 working object spaces which are more or less interchangeable: -- The trivial object space, which is a thin wrapper around CPython types. It was used to test the interpreter and is used from time to time for testing purposes. It is currently of little interest. +- The Trivial Object Space, which is a thin wrapper around CPython types. It was used to test the interpreter and is used from time to time for testing purposes. It is currently of little interest and will not be described here. -- The standard object space, which is an almost complete implementation of Python types in Python. This is the main focus of this document, since it is the foundation of PyPy. +- The Standard Object Space, which is an almost complete implementation of Python types in Python. This is the main focus of this document, since it is the foundation of PyPy. + +In addition, we have 2 special purpose object spaces under +development; the *Flow Object Space* and the *Trace Object Space*. These +will be described later. The Standard Object Space ========================= @@ -138,7 +142,6 @@ Wrapping ======== - The ``w_`` prefixes so lavishly used in the previous example indicate, by PyPy coding convention, that we are dealing with *wrapped* objects, that is, objects constructed by the object space at interpreter level to @@ -160,5 +163,40 @@ question has to be explicitly recorded in ``ob_size``). +RPython translation +=================== +All the interpreter level code is implemented in a subset of Python +called RPython. This subset has not been fully defined yet, but it has +some restrictions on parts of Python you can use, as well as some +restrictions on how you can combine different constructs. The purpose +of this to have a language that is suitable for turning into optimised +code in a low level language. Our current target is C, but going +directly to machine code for a real or virtual machine are other paths +that could be taken. + +In order to produce a fast version of the PyPy interpreter we apply a +special version of the PyPy interpreter on the regular PyPy +interpreter. Once we have loaded the entire interpreter and the SOS, +we have a collection of byte codes that constitute the PyPy +interpreter program. This is then fed to the special interpreter, +which has the SOS replaced with a Flow Object Space. + +The Flow Object Space drives the execution in such a way that all +paths in the code are followed. As a side-effect it produces flow +graphs, which are graphs capturing the control flow of the code. The +nodes of the graphs are basic blocks of logged Object Space operations +executed sequentially. How values flow is also encoded in the graphs. + +The flow graphs are fed as input to the Annotator. The Annotator, +given entry point types, infers the types of values that flow through +the program variables. This is possible because of the constraints +that RPython places on the interpreter code. + +In the last phase the type annotated flow graphs are visited by the +Translator, which emits "low-level code". To do this, it uses the +types annotation, the basic block listed operations and control flow +information encoded in the graphs. Our first target will probably be +Pyrex code, which is then translated to compilable C by Pyrex itself. + TODO: review and see what else we need to add! From jacob at codespeak.net Sat Dec 20 12:01:15 2003 From: jacob at codespeak.net (jacob at codespeak.net) Date: Sat, 20 Dec 2003 12:01:15 +0100 (MET) Subject: [pypy-svn] rev 2635 - pypy/trunk/doc/overview Message-ID: <20031220110115.2A9765AAA7@thoth.codespeak.net> Author: jacob Date: Sat Dec 20 12:01:14 2003 New Revision: 2635 Removed: pypy/trunk/doc/overview/RPy-translation-overview.txt Log: Removed original RPython translation chapter. Deleted: /pypy/trunk/doc/overview/RPy-translation-overview.txt ============================================================================== --- /pypy/trunk/doc/overview/RPy-translation-overview.txt Sat Dec 20 12:01:14 2003 +++ (empty file) @@ -1,22 +0,0 @@ -RPython translation overview -------------------------------- - -Translation of RPython code of PyPy works on bytecode as found in the -interpreter functions object after the PyPy system has been loaded and -initialized. These bytecodes will be abstractly interpreted using the -PyPy interpreter itself with a specific Object Space, the Flow Object -Space, plugged in. The Flow Object Space drives the execution in such -a way that all paths in the code are followed. As a side-effect it -produces flow graphs, that means graph capturing the control flow of -the code, nodes there are basic blocks of logged Object Space -operations executed sequentially, how values flow is also encoded. - -These flow graphs can then be fed as input to the Annotator. Under the -constraints of RPython, the Annotator given entry point types infers -the types of values that flow through the program variables. - -In the last phase the type annotated flow graphs are visited by the -Translator, which out of the types annotation, the basic block listed -operations and control flow information encoded in the graphs, emits -"low-level" code. Our first target will probably be Pyrex code, which -is then translated to compilable C by Pyrex itself. From pmaupin at codespeak.net Sat Dec 20 12:06:35 2003 From: pmaupin at codespeak.net (pmaupin at codespeak.net) Date: Sat, 20 Dec 2003 12:06:35 +0100 (MET) Subject: [pypy-svn] rev 2636 - pypy/trunk/src/pypy/module/test Message-ID: <20031220110635.6C31A5AA0B@thoth.codespeak.net> Author: pmaupin Date: Sat Dec 20 12:06:34 2003 New Revision: 2636 Modified: pypy/trunk/src/pypy/module/test/test_builtin.py Log: Added tests for import failures Modified: pypy/trunk/src/pypy/module/test/test_builtin.py ============================================================================== --- pypy/trunk/src/pypy/module/test/test_builtin.py (original) +++ pypy/trunk/src/pypy/module/test/test_builtin.py Sat Dec 20 12:06:34 2003 @@ -15,6 +15,8 @@ m = __import__('pprint') self.assertEquals(m.pformat({}), '{}') self.assertEquals(m.__name__, "pprint") + self.assertRaises(ImportError, __import__, 'spamspam') + self.assertRaises(TypeError, __import__, 1, 2, 3, 4) def test_chr(self): self.assertEquals(chr(65), 'A') From pmaupin at codespeak.net Sat Dec 20 12:11:41 2003 From: pmaupin at codespeak.net (pmaupin at codespeak.net) Date: Sat, 20 Dec 2003 12:11:41 +0100 (MET) Subject: [pypy-svn] rev 2637 - pypy/trunk/src/pypy/module Message-ID: <20031220111141.C499E5AA0B@thoth.codespeak.net> Author: pmaupin Date: Sat Dec 20 12:11:41 2003 New Revision: 2637 Modified: pypy/trunk/src/pypy/module/builtin.py Log: Test that first parameter to __import__() is a string Modified: pypy/trunk/src/pypy/module/builtin.py ============================================================================== --- pypy/trunk/src/pypy/module/builtin.py (original) +++ pypy/trunk/src/pypy/module/builtin.py Sat Dec 20 12:11:41 2003 @@ -63,31 +63,41 @@ def __import__(self, w_modulename, w_globals=None, w_locals=None, w_fromlist=None): space = self.space + modulename = space.unwrap(w_modulename) + if not isinstance(modulename, str): + try: + helper = ', not ' + modulename.__class__.__name__ + except AttributeError: + helper = '' + raise OperationError(space.w_TypeError, + space.wrap("__import__() argument 1 must be string" + helper)) w = space.wrap try: w_mod = space.getitem(space.sys.w_modules, w_modulename) - return w_mod except OperationError,e: - if not e.match(space, space.w_KeyError): - raise - w_mod = space.get_builtin_module(space.unwrap(w_modulename)) - if w_mod is not None: + pass + else: + return w_mod + if not e.match(space, space.w_KeyError): + raise + w_mod = space.get_builtin_module(modulename) + if w_mod is not None: + space.setitem(space.sys.w_modules, w_modulename, w_mod) + return w_mod + + import os + for path in space.unpackiterable(space.sys.w_path): + f = os.path.join(space.unwrap(path), modulename + '.py') + if os.path.exists(f): + w_mod = space.wrap(Module(space, w_modulename)) space.setitem(space.sys.w_modules, w_modulename, w_mod) + space.setattr(w_mod, w('__file__'), w(f)) + w_dict = space.getattr(w_mod, w('__dict__')) + self.execfile(w(f), w_dict, w_dict) return w_mod - - import os - for path in space.unpackiterable(space.sys.w_path): - f = os.path.join(space.unwrap(path), space.unwrap(w_modulename) + '.py') - if os.path.exists(f): - w_mod = space.wrap(Module(space, w_modulename)) - space.setitem(space.sys.w_modules, w_modulename, w_mod) - space.setattr(w_mod, w('__file__'), w(f)) - w_dict = space.getattr(w_mod, w('__dict__')) - self.execfile(w(f), w_dict, w_dict) - return w_mod - - w_exc = space.call_function(space.w_ImportError, w_modulename) - raise OperationError(space.w_ImportError, w_exc) + + w_exc = space.call_function(space.w_ImportError, w_modulename) + raise OperationError(space.w_ImportError, w_exc) ## def app___import__(self, *args): ## # NOTE: No import statements can be done in this function, From alex at codespeak.net Sat Dec 20 12:23:02 2003 From: alex at codespeak.net (alex at codespeak.net) Date: Sat, 20 Dec 2003 12:23:02 +0100 (MET) Subject: [pypy-svn] rev 2638 - pypy/trunk/src/pypy/module/test Message-ID: <20031220112302.75B235AA0B@thoth.codespeak.net> Author: alex Date: Sat Dec 20 12:23:01 2003 New Revision: 2638 Modified: pypy/trunk/src/pypy/module/test/test_builtin.py Log: beef up the test of callable built-in Modified: pypy/trunk/src/pypy/module/test/test_builtin.py ============================================================================== --- pypy/trunk/src/pypy/module/test/test_builtin.py (original) +++ pypy/trunk/src/pypy/module/test/test_builtin.py Sat Dec 20 12:23:01 2003 @@ -223,13 +223,18 @@ return a+2 self.failIf(not callable(Call()), "Builtin function 'callable' misreads callable object") + self.assert_(callable(int), + "Builtin function 'callable' misreads int") def test_uncallable(self): class NoCall: pass - self.failIf(callable(NoCall()), + a = NoCall() + self.failIf(callable(a), "Builtin function 'callable' misreads uncallable object") - + a.__call__ = lambda: "foo" + self.failIf(callable(a), + "Builtin function 'callable' tricked by instance-__call__") if __name__ == '__main__': From alex at codespeak.net Sat Dec 20 12:32:44 2003 From: alex at codespeak.net (alex at codespeak.net) Date: Sat, 20 Dec 2003 12:32:44 +0100 (MET) Subject: [pypy-svn] rev 2639 - pypy/trunk/src/pypy/module/test Message-ID: <20031220113244.3D50A5AA0B@thoth.codespeak.net> Author: alex Date: Sat Dec 20 12:32:43 2003 New Revision: 2639 Modified: pypy/trunk/src/pypy/module/test/test_builtin.py Log: more the tests for callable at app level, where they should be Modified: pypy/trunk/src/pypy/module/test/test_builtin.py ============================================================================== --- pypy/trunk/src/pypy/module/test/test_builtin.py (original) +++ pypy/trunk/src/pypy/module/test/test_builtin.py Sat Dec 20 12:32:43 2003 @@ -181,6 +181,26 @@ def test_divmod(self): self.assertEquals(divmod(15,10),(1,5)) + def test_callable(self): + class Call: + def __call__(self, a): + return a+2 + self.failIf(not callable(Call()), + "Builtin function 'callable' misreads callable object") + self.assert_(callable(int), + "Builtin function 'callable' misreads int") + + def test_uncallable(self): + class NoCall: + pass + a = NoCall() + self.failIf(callable(a), + "Builtin function 'callable' misreads uncallable object") + a.__call__ = lambda: "foo" + self.failIf(callable(a), + "Builtin function 'callable' tricked by instance-__call__") + + class TestInternal(test.IntTestCase): @@ -217,25 +237,6 @@ self.assert_(hasattr(self.space.builtin, 'xrange')) self.assertEquals(self.space.builtin.xrange(3).stop, 3) - def test_callable(self): - class Call: - def __call__(self, a): - return a+2 - self.failIf(not callable(Call()), - "Builtin function 'callable' misreads callable object") - self.assert_(callable(int), - "Builtin function 'callable' misreads int") - - def test_uncallable(self): - class NoCall: - pass - a = NoCall() - self.failIf(callable(a), - "Builtin function 'callable' misreads uncallable object") - a.__call__ = lambda: "foo" - self.failIf(callable(a), - "Builtin function 'callable' tricked by instance-__call__") - if __name__ == '__main__': test.main() From alex at codespeak.net Sat Dec 20 12:34:07 2003 From: alex at codespeak.net (alex at codespeak.net) Date: Sat, 20 Dec 2003 12:34:07 +0100 (MET) Subject: [pypy-svn] rev 2640 - pypy/trunk/src/pypy/module Message-ID: <20031220113407.D72EA5AA0B@thoth.codespeak.net> Author: alex Date: Sat Dec 20 12:34:07 2003 New Revision: 2640 Modified: pypy/trunk/src/pypy/module/builtin.py Log: fix the built-in callable Modified: pypy/trunk/src/pypy/module/builtin.py ============================================================================== --- pypy/trunk/src/pypy/module/builtin.py (original) +++ pypy/trunk/src/pypy/module/builtin.py Sat Dec 20 12:34:07 2003 @@ -615,7 +615,8 @@ return False def app_callable(self, ob): - return hasattr(ob, '__call__') + t = type(ob) + return t is type or hasattr(t, '__call__') def app_dir(self, *args): """dir([object]) -> list of strings From lac at codespeak.net Sat Dec 20 14:04:55 2003 From: lac at codespeak.net (lac at codespeak.net) Date: Sat, 20 Dec 2003 14:04:55 +0100 (MET) Subject: [pypy-svn] rev 2641 - pypy/trunk/doc Message-ID: <20031220130455.60F455AA0B@thoth.codespeak.net> Author: lac Date: Sat Dec 20 14:04:54 2003 New Revision: 2641 Modified: pypy/trunk/doc/goals.txt Log: added what has changed since 2.2 so we can check that we do this. Modified: pypy/trunk/doc/goals.txt ============================================================================== --- pypy/trunk/doc/goals.txt (original) +++ pypy/trunk/doc/goals.txt Sat Dec 20 14:04:54 2003 @@ -20,7 +20,7 @@ - help with automated testing - what more do we want to do? + XXX add what more do we want to do? - http-server to present runtime/introspection information aiding debugging and understanding of PyPy internals @@ -35,10 +35,209 @@ - Facilitate porting of extension modules to PyPy. +- What's new since 2.2? + see http://www.python.org/doc/2.3.3/whatsnew -- Thank you amk! + +**PEPS** + ++ PEP 218: A Standard Set Datatype -- set module -- + ++ PEP 263 defining Python Source Code encodings + ++ PEP 273 Importing Modules from Zip Archives -- zipimport module -- + ++ PEP 277: Unicode file name support for Windows NT + ++ PEP 278: Universal Newline Support + ++ PEP 279: enumerate() + ++ PEP 282: The logging Package + ++ PEP 285: A Boolean Type + ++ PEP 293: Codec Error Handling Callbacks + ++ PEP 301: Package Index and Metadata for Distutils + ++ PEP 302: New Import Hooks + ++ PEP 307: Pickle Enhancements + +**Check and see we have implemented these** + +* Extended Slices + +* The yield statement is now always a keyword + +* new built-in function enumerate() + +* Two new constants, True and False + +* The int() type constructor will now return a long integer instead of + raising an OverflowError when a string or floating-point number is too + large to fit into an integer. This can lead to the paradoxical result + that isinstance(int(expression), int) is false. + +* Built-in types now support the extended slicing syntax + +* A new built-in function, sum(iterable, start=0), adds up the numeric + items in the iterable object and returns their sum. sum() only accepts + numbers, meaning that you can't use it to concatenate a bunch of strings. + +does it handle mixed floats and ints? + +* list.insert(pos, value) used to insert value at the front of the list + when pos was negative. The behaviour has now been changed to be consistent + with slice indexing, so when pos is -1 the value will be inserted before + the last element, and so forth. + +so to insert at the front? + +* list.index(value), which searches for value within the list and + returns its index, now takes optional start and stop arguments to limit + the search to only part of the list. + +* Dictionaries have a new method, pop(key[, default]), that returns the + value corresponding to key and removes that key/value pair from the + dictionary. If the requested key isn't present in the dictionary, + default is returned if it's specified and KeyError raised if it isn't. + +* There's also a new class method, dict.fromkeys(iterable, value), that + creates a dictionary with keys taken from the supplied iterator iterable + and all values set to value, defaulting to None. + + Also, the dict() constructor now accepts keyword arguments to simplify + creating small dictionaries: + + >>> dict(red=1, blue=2, green=3, black=4) + {'blue': 2, 'black': 4, 'green': 3, 'red': 1} + + +* The assert statement no longer checks the __debug__ flag, so you can no + longer disable assertions by assigning to __debug__. Running Python with + the -O switch will still generate code that doesn't execute any assertions. + +So what if you want to disable assertions just within one module? + +* Most type objects are now callable, so you can use them to create new + objects such as functions, classes, and modules. (This means that the + new module can be deprecated in a future Python version, because you + can now use the type objects available in the types module.) For example, + you can create a new module object with the following code: + + >>> import types + >>> m = types.ModuleType('abc','docstring') + >>> m + + >>> m.__doc__ + 'docstring' + +* A new warning, PendingDeprecationWarning was added to indicate features + which are in the process of being deprecated. The warning will not be + printed by default. To check for use of features that will be deprecated + in the future, supply -Walways::PendingDeprecationWarning:: on the + command line or use warnings.filterwarnings(). + +* The process of deprecating string-based exceptions, as in + raise "Error occurred", has begun. Raising a string will now trigger + PendingDeprecationWarning. + +* Using None as a variable name will now result in a SyntaxWarning warning. + In a future version of Python, None may finally become a keyword. + +* The xreadlines() method of file objects, introduced in Python 2.1, + is no longer necessary because files now behave as their own + iterator. xreadlines() was originally introduced as a faster way to + loop over all the lines in a file, but now you can simply write + for line in file_obj. File objects also have a new read-only encoding + attribute that gives the encoding used by the file; Unicode strings + written to the file will be automatically converted to bytes using + the given encoding. + +* The method resolution order used by new-style classes has changed, + though you'll only notice the difference if you have a really + complicated inheritance hierarchy. Classic classes are unaffected by + this change. Python 2.2 originally used a topological sort of a + class's ancestors, but 2.3 now uses the C3 algorithm as described in + the paper ``A Monotonic Superclass Linearization for Dylan''. To + understand the motivation for this change, read Michele Simionato's + article ``Python 2.3 Method Resolution Order'', or read the thread + on python-dev starting with the message at + http://mail.python.org/pipermail/python-dev/2002-October/029035.html. Samuele + Pedroni first pointed out the problem and also implemented the fix + by coding the C3 algorithm. + +* Python runs multithreaded programs by switching between threads + after executing N bytecodes. The default value for N has been + increased from 10 to 100 bytecodes, speeding up single-threaded + applications by reducing the switching overhead. Some multithreaded + applications may suffer slower response time, but that's easily + fixed by setting the limit back to a lower number using + sys.setcheckinterval(N). The limit can be retrieved with the new + sys.getcheckinterval() function. + +* One minor but far-reaching change is that the names of extension + types defined by the modules included with Python now contain the + module and a "." in front of the type name. For example, in Python + 2.2, if you created a socket and printed its __class__, you'd get + this output: + + >>> s = socket.socket() + >>> s.__class__ + + + In 2.3, you get this: + + >>> s.__class__ + + +* One of the noted incompatibilities between old- and new-style + classes has been removed: you can now assign to the __name__ and + __bases__ attributes of new-style classes. There are some + restrictions on what can be assigned to __bases__ along the lines of + those relating to assigning to an instance's __class__ attribute. + +**String Changes** + +* The in operator now works differently for strings. Previously, when + evaluating X in Y where X and Y are strings, X could only be a + single character. That's now changed; X can be a string of any + length, and X in Y will return True if X is a substring of Y. If X + is the empty string, the result is always True. + + >>> 'ab' in 'abcd' + True + >>> 'ad' in 'abcd' + False + >>> '' in 'abcd' + True + +* The strip(), lstrip(), and rstrip() string methods now have an + optional argument for specifying the characters to strip. The + default is still to remove all whitespace characters: + +* The startswith() and endswith() string methods now accept negative + numbers for the start and end parameters. + +* Another new string method is zfill(), originally a function in the + string module. zfill() pads a numeric string with zeros on the left + until it's the specified width. Note that the % operator is still + more flexible and powerful than zfill(). + +* A new type object, basestring, has been added. Both 8-bit strings + and Unicode strings inherit from this type, so isinstance(obj, basestring) + will return True for either kind of string. It's a completely abstract + type, so you can't create basestring instances. + +* Interned strings are no longer immortal and will now be + garbage-collected in the usual way when the only reference to them + is from the internal dictionary of interned strings. + **Replace PyPy Core** Building a complete Python interpreter written in Python, -using a subset of Python that avoids dynamic features +using a subset of Python that avoids dynamic featureslll which would impair the objectives of RPython. - Design and implement the PyPy bytecode interpreter and From lac at codespeak.net Sat Dec 20 14:09:49 2003 From: lac at codespeak.net (lac at codespeak.net) Date: Sat, 20 Dec 2003 14:09:49 +0100 (MET) Subject: [pypy-svn] rev 2642 - pypy/trunk/doc Message-ID: <20031220130949.A0F535AA0B@thoth.codespeak.net> Author: lac Date: Sat Dec 20 14:09:48 2003 New Revision: 2642 Modified: pypy/trunk/doc/goals.txt Log: fixed ReST bug. buildhtml.py did not complain about this, but rudely stuck the warning into the html. grrrr. Modified: pypy/trunk/doc/goals.txt ============================================================================== --- pypy/trunk/doc/goals.txt (original) +++ pypy/trunk/doc/goals.txt Sat Dec 20 14:09:48 2003 @@ -35,8 +35,7 @@ - Facilitate porting of extension modules to PyPy. -- What's new since 2.2? - see http://www.python.org/doc/2.3.3/whatsnew -- Thank you amk! +- What's new since 2.2? see http://www.python.org/doc/2.3.3/whatsnew -- Thank you amk! **PEPS** From lac at codespeak.net Sat Dec 20 14:12:53 2003 From: lac at codespeak.net (lac at codespeak.net) Date: Sat, 20 Dec 2003 14:12:53 +0100 (MET) Subject: [pypy-svn] rev 2643 - pypy/trunk/doc Message-ID: <20031220131253.12D8A5AA0B@thoth.codespeak.net> Author: lac Date: Sat Dec 20 14:12:53 2003 New Revision: 2643 Modified: pypy/trunk/doc/goals.txt Log: more silent ReST formatting glitches Modified: pypy/trunk/doc/goals.txt ============================================================================== --- pypy/trunk/doc/goals.txt (original) +++ pypy/trunk/doc/goals.txt Sat Dec 20 14:12:53 2003 @@ -159,9 +159,9 @@ complicated inheritance hierarchy. Classic classes are unaffected by this change. Python 2.2 originally used a topological sort of a class's ancestors, but 2.3 now uses the C3 algorithm as described in - the paper ``A Monotonic Superclass Linearization for Dylan''. To + the paper _A Monotonic Superclass Linearization for Dylan__. To understand the motivation for this change, read Michele Simionato's - article ``Python 2.3 Method Resolution Order'', or read the thread + article _Python 2.3 Method Resolution Order_, or read the thread on python-dev starting with the message at http://mail.python.org/pipermail/python-dev/2002-October/029035.html. Samuele Pedroni first pointed out the problem and also implemented the fix From lac at codespeak.net Sat Dec 20 14:15:59 2003 From: lac at codespeak.net (lac at codespeak.net) Date: Sat, 20 Dec 2003 14:15:59 +0100 (MET) Subject: [pypy-svn] rev 2644 - pypy/trunk/doc Message-ID: <20031220131559.164865AA0B@thoth.codespeak.net> Author: lac Date: Sat Dec 20 14:15:58 2003 New Revision: 2644 Modified: pypy/trunk/doc/goals.txt Log: more silent ReST formatting glitches Modified: pypy/trunk/doc/goals.txt ============================================================================== --- pypy/trunk/doc/goals.txt (original) +++ pypy/trunk/doc/goals.txt Sat Dec 20 14:15:58 2003 @@ -159,12 +159,12 @@ complicated inheritance hierarchy. Classic classes are unaffected by this change. Python 2.2 originally used a topological sort of a class's ancestors, but 2.3 now uses the C3 algorithm as described in - the paper _A Monotonic Superclass Linearization for Dylan__. To + the paper *A Monotonic Superclass Linearization for Dylan*. To understand the motivation for this change, read Michele Simionato's - article _Python 2.3 Method Resolution Order_, or read the thread + article *Python 2.3 Method Resolution Order*, or read the thread on python-dev starting with the message at - http://mail.python.org/pipermail/python-dev/2002-October/029035.html. Samuele - Pedroni first pointed out the problem and also implemented the fix + http://mail.python.org/pipermail/python-dev/2002-October/029035.html. + Samuele Pedroni first pointed out the problem and also implemented the fix by coding the C3 algorithm. * Python runs multithreaded programs by switching between threads @@ -252,7 +252,7 @@ be implemented using RPython or just general Python. -- moving target. - Implement a Python parser and bytecode compiler in Python. - -- we have soemthing, but it is not well integrated. + -- we have something, but it is not well integrated. - A partial Python implementation that passses 75% of the official Python test suite that don't depend on extension modules. From pmaupin at codespeak.net Sat Dec 20 14:37:40 2003 From: pmaupin at codespeak.net (pmaupin at codespeak.net) Date: Sat, 20 Dec 2003 14:37:40 +0100 (MET) Subject: [pypy-svn] rev 2645 - pypy/trunk/src/pypy/objspace/std Message-ID: <20031220133740.A942F5AA0B@thoth.codespeak.net> Author: pmaupin Date: Sat Dec 20 14:37:40 2003 New Revision: 2645 Modified: pypy/trunk/src/pypy/objspace/std/floatobject.py Log: Fix float.__neg__() Modified: pypy/trunk/src/pypy/objspace/std/floatobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/floatobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/floatobject.py Sat Dec 20 14:37:40 2003 @@ -226,7 +226,7 @@ return W_FloatObject(space, z) def neg__Float(space, w_float1): - return W_FloatObject(space, w_float1.floatval) + return W_FloatObject(space, -w_float1.floatval) def pos__Float(space, w_float): if w_float.__class__ == W_FloatObject: From alex at codespeak.net Sat Dec 20 14:41:29 2003 From: alex at codespeak.net (alex at codespeak.net) Date: Sat, 20 Dec 2003 14:41:29 +0100 (MET) Subject: [pypy-svn] rev 2646 - pypy/trunk/src/pypy/objspace/std/test Message-ID: <20031220134129.23BD55AA0B@thoth.codespeak.net> Author: alex Date: Sat Dec 20 14:41:28 2003 New Revision: 2646 Modified: pypy/trunk/src/pypy/objspace/std/test/test_floatobject.py Log: catch the bug whereby -0.1<0 didn't work (unary-negative was a noop, which didn't matter for e.g. -1.1 due to different bytecode being generated then) Modified: pypy/trunk/src/pypy/objspace/std/test/test_floatobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/test/test_floatobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/test/test_floatobject.py Sat Dec 20 14:41:28 2003 @@ -41,6 +41,10 @@ def setUp(self): self.space = test.objspace('std') + def test_negatives(self): + self.assert_(-1.1 < 0) + self.assert_(-0.1 < 0) + def test_float_callable(self): self.assertEquals(0.125, float(0.125)) From pedronis at codespeak.net Sat Dec 20 14:43:06 2003 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Sat, 20 Dec 2003 14:43:06 +0100 (MET) Subject: [pypy-svn] rev 2647 - in pypy/trunk/src/pypy/translator: . test Message-ID: <20031220134306.69AD75AA0B@thoth.codespeak.net> Author: pedronis Date: Sat Dec 20 14:43:05 2003 New Revision: 2647 Modified: pypy/trunk/src/pypy/translator/annrpython.py pypy/trunk/src/pypy/translator/test/snippet.py pypy/trunk/src/pypy/translator/test/test_annrpython.py Log: first tiny steps to support annotations involving class Modified: pypy/trunk/src/pypy/translator/annrpython.py ============================================================================== --- pypy/trunk/src/pypy/translator/annrpython.py (original) +++ pypy/trunk/src/pypy/translator/annrpython.py Sat Dec 20 14:43:05 2003 @@ -349,6 +349,9 @@ elif isinstance(func, FunctionType) and self.translator: args = self.decode_simple_call(varargs, kwargs) return self.translator.consider_call(self, func, args) + elif isinstance(func,type): + # XXX flow into __init__/__new__ + self.heap.settype(result,func) return result def consider_const(self, constvalue): Modified: pypy/trunk/src/pypy/translator/test/snippet.py ============================================================================== --- pypy/trunk/src/pypy/translator/test/snippet.py (original) +++ pypy/trunk/src/pypy/translator/test/snippet.py Sat Dec 20 14:43:05 2003 @@ -274,3 +274,10 @@ a = [] append_five(a) return a + + +class C(object): pass + +def build_instance(): + c = C() + return c Modified: pypy/trunk/src/pypy/translator/test/test_annrpython.py ============================================================================== --- pypy/trunk/src/pypy/translator/test/test_annrpython.py (original) +++ pypy/trunk/src/pypy/translator/test/test_annrpython.py Sat Dec 20 14:43:05 2003 @@ -136,6 +136,15 @@ # result should be an integer self.assertEquals(a.gettype(graph.getreturnvar()), int) + def test_build_instance(self): + translator = Translator(snippet.build_instance) + graph = translator.getflowgraph() + a = RPythonAnnotator(translator) + a.build_types(graph, []) + # result should be a snippet.C instance + self.assertEquals(a.gettype(graph.getreturnvar()), snippet.C) + + def g(n): return [0,1,2,n] From pmaupin at codespeak.net Sat Dec 20 14:46:22 2003 From: pmaupin at codespeak.net (pmaupin at codespeak.net) Date: Sat, 20 Dec 2003 14:46:22 +0100 (MET) Subject: [pypy-svn] rev 2648 - pypy/trunk/src/pypy/appspace Message-ID: <20031220134622.3AB2D5AA0B@thoth.codespeak.net> Author: pmaupin Date: Sat Dec 20 14:46:21 2003 New Revision: 2648 Modified: pypy/trunk/src/pypy/appspace/support_tests.py Log: Don't use coerce() in support_tests -- not supported Modified: pypy/trunk/src/pypy/appspace/support_tests.py ============================================================================== --- pypy/trunk/src/pypy/appspace/support_tests.py (original) +++ pypy/trunk/src/pypy/appspace/support_tests.py Sat Dec 20 14:46:21 2003 @@ -94,7 +94,7 @@ def fcmp(x, y): # fuzzy comparison function if type(x) == type(0.0) or type(y) == type(0.0): try: - x, y = coerce(x, y) + x, y = float(x), float(y) fuzz = (abs(x) + abs(y)) * FUZZ if abs(x-y) <= fuzz: return 0 From alex at codespeak.net Sat Dec 20 15:38:02 2003 From: alex at codespeak.net (alex at codespeak.net) Date: Sat, 20 Dec 2003 15:38:02 +0100 (MET) Subject: [pypy-svn] rev 2649 - pypy/trunk/src/pypy/objspace/std Message-ID: <20031220143802.7C9FA5AA0B@thoth.codespeak.net> Author: alex Date: Sat Dec 20 15:38:01 2003 New Revision: 2649 Modified: pypy/trunk/src/pypy/objspace/std/dictobject.py Log: simplified implementation by making has_key a synonym for __contains__ Modified: pypy/trunk/src/pypy/objspace/std/dictobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/dictobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/dictobject.py Sat Dec 20 15:38:01 2003 @@ -136,6 +136,8 @@ return space.w_True return space.w_False +dict_has_key__Dict_ANY = contains__Dict_ANY + def iter__Dict(space, w_dict): import iterobject w_keys = dict_keys__Dict(space, w_dict) @@ -200,15 +202,6 @@ for w_key,cell in w_self.non_empties()]) -def dict_has_key__Dict_ANY(space, w_self, w_lookup): - data = w_self.non_empties() - # XXX hashing? -- mwh - for w_key, cell in data: - if space.is_true(space.eq(w_lookup, w_key)): - return space.newbool(1) - else: - return space.newbool(0) - def dict_clear__Dict(space, w_self): w_self.data = [] From pedronis at codespeak.net Sat Dec 20 15:38:22 2003 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Sat, 20 Dec 2003 15:38:22 +0100 (MET) Subject: [pypy-svn] rev 2650 - in pypy/trunk/src/pypy/translator: . test tool Message-ID: <20031220143822.021B85AA0B@thoth.codespeak.net> Author: pedronis Date: Sat Dec 20 15:38:22 2003 New Revision: 2650 Modified: pypy/trunk/src/pypy/translator/annrpython.py pypy/trunk/src/pypy/translator/test/snippet.py pypy/trunk/src/pypy/translator/test/test_annrpython.py pypy/trunk/src/pypy/translator/tool/traceann.py Log: first half-baked try at getattr/setattr ops support for user-defined classes, there's a XXX comment on the fact that it should be decided how to trigger reflow when annotations for an attr get added. Modified: pypy/trunk/src/pypy/translator/annrpython.py ============================================================================== --- pypy/trunk/src/pypy/translator/annrpython.py (original) +++ pypy/trunk/src/pypy/translator/annrpython.py Sat Dec 20 15:38:22 2003 @@ -29,6 +29,7 @@ self.annotated = {} # set of blocks already seen self.translator = translator + self.classes = {} # map classes to attr-name -> SomaValue dicts #___ convenience high-level interface __________________ @@ -76,7 +77,7 @@ self.processblock(block, cells) if self.delayedblocks: raise AnnotatorError('%d block(s) are still blocked' % - len(delayed)) + len(delayedblocks)) def binding(self, arg): "Gives the SomeValue corresponding to the given Variable or Constant." @@ -213,6 +214,45 @@ assert isinstance(op.result, Variable) self.bindings[op.result] = resultcell # bind resultcell to op.result + def consider_op_setattr(self,obj,attr,newval): + objtype = self.heap.get(ANN.type,obj) + if isinstance(objtype,type): + attrdict = self.classes.setdefault(objtype,{}) + attr = self.heap.get(ANN.const,attr) + if attr is not mostgeneralvalue: + oldval = attrdict.get(attr,impossiblevalue) + newval = self.heap.merge(oldval,newval) + # XXX + # if newval is not oldval (using isshared) + # we should reflow the places that depend on this + # we really need to make the attrdict an annotation + # on the type as const + # or invent a fake annotation + # that we get on getattr and kill and reset on setattr + # to trigger that + attrdict[attr] = newval + else: + raise ValueError,"setattr op with non-const attrname not expected" + return SomeValue() + + def consider_op_getattr(self,obj,attr): + result = SomeValue() + objtype = self.heap.get(ANN.type,obj) + if isinstance(objtype,type): + attrdict = self.classes.setdefault(objtype,{}) + attr = self.heap.get(ANN.const,attr) + if attr is not mostgeneralvalue: + if hasattr(objtype,attr): # XXX shortcut to keep methods working + return result + oldval = attrdict.get(attr,impossiblevalue) + if oldval is impossiblevalue: + return impossiblevalue + return oldval + else: + raise ValueError,"getattr op with non-const attrname not expected" + return result + + def default_consider_op(self, *args): return mostgeneralvalue Modified: pypy/trunk/src/pypy/translator/test/snippet.py ============================================================================== --- pypy/trunk/src/pypy/translator/test/snippet.py (original) +++ pypy/trunk/src/pypy/translator/test/snippet.py Sat Dec 20 15:38:22 2003 @@ -281,3 +281,9 @@ def build_instance(): c = C() return c + +def set_attr(): + c = C() + c.a = 1 + c.a = 2 + return c.a Modified: pypy/trunk/src/pypy/translator/test/test_annrpython.py ============================================================================== --- pypy/trunk/src/pypy/translator/test/test_annrpython.py (original) +++ pypy/trunk/src/pypy/translator/test/test_annrpython.py Sat Dec 20 15:38:22 2003 @@ -144,7 +144,15 @@ # result should be a snippet.C instance self.assertEquals(a.gettype(graph.getreturnvar()), snippet.C) - + def test_set_attr(self): + translator = Translator(snippet.set_attr) + graph = translator.getflowgraph() + a = RPythonAnnotator(translator) + a.build_types(graph, []) + # result should be an integer + self.assertEquals(a.gettype(graph.getreturnvar()), int) + + def g(n): return [0,1,2,n] Modified: pypy/trunk/src/pypy/translator/tool/traceann.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/traceann.py (original) +++ pypy/trunk/src/pypy/translator/tool/traceann.py Sat Dec 20 15:38:22 2003 @@ -40,6 +40,8 @@ lines = [] for key, value in a.bindings.items(): lines.append('%r: %r' % (key, value)) +for cl, attrdict in a.classes.items(): + lines.append('%s: %r' % (cl.__name__,attrdict)) lines.sort() for line in lines: print line From pmaupin at codespeak.net Sat Dec 20 15:46:18 2003 From: pmaupin at codespeak.net (pmaupin at codespeak.net) Date: Sat, 20 Dec 2003 15:46:18 +0100 (MET) Subject: [pypy-svn] rev 2651 - pypy/trunk/src/pypy/module/test Message-ID: <20031220144618.104285AA0B@thoth.codespeak.net> Author: pmaupin Date: Sat Dec 20 15:46:17 2003 New Revision: 2651 Modified: pypy/trunk/src/pypy/module/test/test_builtin.py Log: Add test_hash unittest Modified: pypy/trunk/src/pypy/module/test/test_builtin.py ============================================================================== --- pypy/trunk/src/pypy/module/test/test_builtin.py (original) +++ pypy/trunk/src/pypy/module/test/test_builtin.py Sat Dec 20 15:46:17 2003 @@ -200,6 +200,16 @@ self.failIf(callable(a), "Builtin function 'callable' tricked by instance-__call__") + def test_hash(self): + self.assertEquals(hash(23), hash(23)) + self.assertEquals(hash(2.3), hash(2.3)) + self.assertEquals(hash('23'), hash("23")) + self.assertEquals(hash((23,)), hash((23,))) + self.assertNotEquals(hash(22), hash(23)) + self.assertRaises(TypeError, hash, []) + self.assertRaises(TypeError, hash, {}) + + class TestInternal(test.IntTestCase): @@ -237,7 +247,6 @@ self.assert_(hasattr(self.space.builtin, 'xrange')) self.assertEquals(self.space.builtin.xrange(3).stop, 3) - if __name__ == '__main__': test.main() From jacob at codespeak.net Sat Dec 20 15:47:04 2003 From: jacob at codespeak.net (jacob at codespeak.net) Date: Sat, 20 Dec 2003 15:47:04 +0100 (MET) Subject: [pypy-svn] rev 2652 - pypy/trunk/doc/overview Message-ID: <20031220144704.5D8715AA0B@thoth.codespeak.net> Author: jacob Date: Sat Dec 20 15:47:03 2003 New Revision: 2652 Modified: pypy/trunk/doc/overview/architecture.txt Log: Added text about object space tricks. Modified: pypy/trunk/doc/overview/architecture.txt ============================================================================== --- pypy/trunk/doc/overview/architecture.txt (original) +++ pypy/trunk/doc/overview/architecture.txt Sat Dec 20 15:47:03 2003 @@ -46,61 +46,67 @@ The Standard Object Space ========================= -The Standard Object Space (SOS) itself is an object which implements a -number of logistic services. At startup, the SOS examines certain -directories for modules that contain the implementation of the available -Python types. The SOS loads each such module, and, in turn, each module -so loaded registers the type it deals with, and all the operations and -implementations for the type, in *multimethod* objects in the SOS. +The Standard Object Space itself is an object which implements a +number of logistic services. At startup, the Standard Object Space +examines certain directories for modules that contain the +implementation of the available Python types. The Standard Object +Space loads each such module, and, in turn, each module so loaded +registers the type it deals with, and all the operations and +implementations for the type, in *multimethod* objects in the Standard +Object Space. Later in the execution, when the interpreter delegates the execution -of an instruction to the SOS, the SOS selects the correct -implementation of the operation to perform through the multimethod. +of an instruction to the Standard Object Space, the Standard Object +Space selects the correct implementation of the operation to perform +through the multimethod. We will examine how the multimethod mechanism works through an example. -We examine the types ``float`` and ``int`` and disregard all other types for -the moment. Each type has an ``__add__`` operator, which is registered -with the SOS at startup. The float add operator is registered with the -type signature ``__add__(Float, Float)`` and the integer add operator is -registered with the signature ``__add__(Int, Int)``. +We examine the types ``float`` and ``int`` and disregard all other +types for the moment. Each type has an ``__add__`` operator, which is +registered with the Standard Object Space at startup. The float add +operator is registered with the type signature ``__add__(Float, +Float)`` and the integer add operator is registered with the signature +``__add__(Int, Int)``. If in our application program we write the expression ``2+3``, the interpreter will create an object containing the value ``2`` and an object containing the value ``3``. We annotate these as ``Int(2)`` and -``Int(3)`` respectively. The interpreter then calls the SOS with -``__add__(Int(2), Int(3))``. +``Int(3)`` respectively. The interpreter then calls the Standard +Object Space with ``__add__(Int(2), Int(3))``. -The SOS then delegates the operation to the ``__add__`` multimethod, which -finds an implementation that has the signature ``__add__(Int, Int)``. Since -this is a "direct hit", the multimethod can immediately dispatch the -operation to the correct method, i.e., the one registered as the -implementation for this signature. +The Standard Object Space then delegates the operation to the +``__add__`` multimethod, which finds an implementation that has the +signature ``__add__(Int, Int)``. Since this is a "direct hit", the +multimethod can immediately dispatch the operation to the correct +method, i.e., the one registered as the implementation for this +signature. If the multimethod doesn't have any registered functions with the correct signature, as would be the case for example for the expression -``2+3.0``, the multimethod tests if it can use coercion to find a function -with a signature that works. In this case we would coerce ``Int(2)`` to -``Float(2.0)`` in order to find a function in the multimethod that has a -correct signature. +``2+3.0``, the multimethod tests if it can use coercion to find a +function with a signature that works. In this case we would coerce +``Int(2)`` to ``Float(2.0)`` in order to find a function in the +multimethod that has a correct signature. Application-level and interpreter-level ======================================= -Since the same language (Python) is what PyPy both **uses** and **deals -with**, a given piece of Python source can be playing either of two -rather distinct roles in the PyPy system. To be systematic in +Since the same language (Python) is what PyPy both **uses** and +**deals with**, a given piece of Python source can be playing either +of two rather distinct roles in the PyPy system. To be systematic in distinguishing these roles, we call them *interpreter level* (Python used to implement the interpreter and object space) and *application level* (Python that we are interpreting). To show the difference with -an example: to sum the contents of two variables ``a`` and ``b``, typical -application-level code is ``a+b`` -- in sharp contrast, typical -interpreter-level code is ``space.add(w_a, w_b)``, where ``space`` is an -instance of the standard object space class and ``w_a`` and ``w_b`` are -typical names for the *wrapped* versions of the two variables. By -contrast, think of traditional CPython: it has the same -application-level code, but interpreter-level code is C source, and -typical code for the addition would be ``PyNumber_Add(p_a, p_b)`` -where ``p_a`` and ``p_b`` are C variables of type ``PyObject*``. +an example: to sum the contents of two variables ``a`` and ``b``, +typical application-level code is ``a+b`` -- in sharp contrast, +typical interpreter-level code is ``space.add(w_a, w_b)``, where +``space`` is an instance of the standard object space class and +``w_a`` and ``w_b`` are typical names for the *wrapped* versions of +the two variables. By contrast, think of traditional CPython: it has +the same application-level code, but interpreter-level code is C +source, and typical code for the addition would be ``PyNumber_Add(p_a, +p_b)`` where ``p_a`` and ``p_b`` are C variables of type +``PyObject*``. You might think that the need to keep the two roles for the same language distinguished is a cause of confusion; sometimes, indeed, it is @@ -176,10 +182,11 @@ In order to produce a fast version of the PyPy interpreter we apply a special version of the PyPy interpreter on the regular PyPy -interpreter. Once we have loaded the entire interpreter and the SOS, -we have a collection of byte codes that constitute the PyPy -interpreter program. This is then fed to the special interpreter, -which has the SOS replaced with a Flow Object Space. +interpreter. Once we have loaded the entire interpreter and the +Standard Object Space, we have a collection of byte codes that +constitute the PyPy interpreter program. This is then fed to the +special interpreter, which has the Standard Object Space replaced with +a Flow Object Space. The Flow Object Space drives the execution in such a way that all paths in the code are followed. As a side-effect it produces flow @@ -187,7 +194,7 @@ nodes of the graphs are basic blocks of logged Object Space operations executed sequentially. How values flow is also encoded in the graphs. -The flow graphs are fed as input to the Annotator. The Annotator, +The flow graphs are fed as input to the Annotator. The Annotator, given entry point types, infers the types of values that flow through the program variables. This is possible because of the constraints that RPython places on the interpreter code. @@ -198,5 +205,45 @@ information encoded in the graphs. Our first target will probably be Pyrex code, which is then translated to compilable C by Pyrex itself. +Object Space tricks +=================== +The fact that the Interpreter and the Object Spaces are separate +packages with an explicit and stable API in between gives us some new +and interesting possibilities. + +The first one is that it is easy to write an Object Space that wraps +the Standard Object Space and interfaces to the Interpreter. + +One such Object Space is the Trace Object Space, which allows us to +examine and trace all instructions that are passed to the Standard +Object Space as well as all results being passed back to the +Interpreter. Since all object spaces have the same API, the Trace +Object Space should be able to trace the execution of any version of +the PyPy interpreter, e.g. the one compiling RPython. + +*Up to here we have been speaking about things that we have, or are +working on. The rest of this chapter is about things that could be +done with our architecture.* + +Another possibility is an object space that interfaces to a Standard +Object Space on another machine. From this it is not far to an object +space that keeps tab of where its objects reside and is able to +delegate its operations to more than one object space. For instance, +we can have multiple objects spaces which reside in different threads +in the same process. + +At the other end, it is possible to replace the Interpreter with one +that interprets instructions for a different Virtual Machine, but +still uses the Standard Object Space. It is a rather short conceptual +step from this to allowing delegation between multiple Interpreters, +making it possible to mix both source languages and bytcode +instruction sets. Naturally there are limits to how different the +underlying models of the virtual machines can be before they become +incompatible with the Standard Object Space, but even this could be +solved, using multiple interpreters delegating to multiple object +spaces. However, the code for interaction between the object spaces +would probably be quite complex. + + TODO: review and see what else we need to add! From pmaupin at codespeak.net Sat Dec 20 15:48:25 2003 From: pmaupin at codespeak.net (pmaupin at codespeak.net) Date: Sat, 20 Dec 2003 15:48:25 +0100 (MET) Subject: [pypy-svn] rev 2653 - pypy/trunk/src/pypy/objspace/std Message-ID: <20031220144825.2D4FB5AA0B@thoth.codespeak.net> Author: pmaupin Date: Sat Dec 20 15:48:24 2003 New Revision: 2653 Modified: pypy/trunk/src/pypy/objspace/std/listobject.py Log: Add list.__hash__() Modified: pypy/trunk/src/pypy/objspace/std/listobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/listobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/listobject.py Sat Dec 20 15:48:24 2003 @@ -260,6 +260,9 @@ return a(a(w('['), space.call_function(w_bm, space.newlist(reprs_w))), w(']')) return space.newstring([]) +def hash__List(space,w_list): + raise OperationError(space.w_TypeError,space.wrap("list objects are unhashable")) + # adapted C code def _roundupsize(n): nbits = r_uint(0) From pmaupin at codespeak.net Sat Dec 20 15:51:07 2003 From: pmaupin at codespeak.net (pmaupin at codespeak.net) Date: Sat, 20 Dec 2003 15:51:07 +0100 (MET) Subject: [pypy-svn] rev 2654 - pypy/trunk/src/pypy/objspace/std Message-ID: <20031220145107.8C4435AA0B@thoth.codespeak.net> Author: pmaupin Date: Sat Dec 20 15:51:06 2003 New Revision: 2654 Modified: pypy/trunk/src/pypy/objspace/std/dictobject.py Log: Add dict.__hash__() Modified: pypy/trunk/src/pypy/objspace/std/dictobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/dictobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/dictobject.py Sat Dec 20 15:51:06 2003 @@ -183,6 +183,9 @@ # The dictionaries are equal. This is correct. return space.w_False +def hash__Dict(space,w_dict): + raise OperationError(space.w_TypeError,space.wrap("dict objects are unhashable")) + def dict_copy__Dict(space, w_self): return W_DictObject(space, [(w_key,cell.get()) for w_key,cell in From alex at codespeak.net Sat Dec 20 15:52:13 2003 From: alex at codespeak.net (alex at codespeak.net) Date: Sat, 20 Dec 2003 15:52:13 +0100 (MET) Subject: [pypy-svn] rev 2655 - pypy/trunk/src/pypy/objspace/std Message-ID: <20031220145213.3D3A85AA0B@thoth.codespeak.net> Author: alex Date: Sat Dec 20 15:52:12 2003 New Revision: 2655 Modified: pypy/trunk/src/pypy/objspace/std/tupleobject.py Log: implement a simple but correct hash for tuples Modified: pypy/trunk/src/pypy/objspace/std/tupleobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/tupleobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/tupleobject.py Sat Dec 20 15:52:12 2003 @@ -108,5 +108,8 @@ # XXX slimy! --mwh return space.wrap(repr(space.unwrap(w_tuple))) +def hash__Tuple(space, w_tuple): + # silly-ish, but _correct_, while lacking it would be WRONG + return space.len(w_tuple) register_all(vars()) From rxe at codespeak.net Sat Dec 20 15:59:57 2003 From: rxe at codespeak.net (rxe at codespeak.net) Date: Sat, 20 Dec 2003 15:59:57 +0100 (MET) Subject: [pypy-svn] rev 2656 - pypy/trunk/src/pypy/interpreter Message-ID: <20031220145957.41F825AA0B@thoth.codespeak.net> Author: rxe Date: Sat Dec 20 15:59:56 2003 New Revision: 2656 Modified: pypy/trunk/src/pypy/interpreter/pyopcode.py Log: Simplified LOAD_NAME and avoid two calls to w_globals. Modified: pypy/trunk/src/pypy/interpreter/pyopcode.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/pyopcode.py (original) +++ pypy/trunk/src/pypy/interpreter/pyopcode.py Sat Dec 20 15:59:56 2003 @@ -452,26 +452,31 @@ def LOAD_NAME(f, nameindex): varname = f.getname(nameindex) w_varname = f.space.wrap(varname) - try: - w_value = f.space.getitem(f.w_locals, w_varname) - except OperationError, e: - if not e.match(f.space, f.space.w_KeyError): - raise + + if f.w_globals is f.w_locals: + try_list_w = [f.w_globals, f.w_builtins] + + else: + try_list_w = [f.w_locals, f.w_globals, f.w_builtins] + + w_value = None + for wrapped in try_list_w: try: - w_value = f.space.getitem(f.w_globals, w_varname) + w_value = f.space.getitem(wrapped, w_varname) + f.valuestack.push(w_value) + return + except OperationError, e: if not e.match(f.space, f.space.w_KeyError): raise - try: - w_value = f.space.getitem(f.w_builtins, w_varname) - except OperationError, e: - if not e.match(f.space, f.space.w_KeyError): - raise - message = "global name '%s' is not defined" % varname - w_exc_type = f.space.w_NameError - w_exc_value = f.space.wrap(message) - raise OperationError(w_exc_type, w_exc_value) - f.valuestack.push(w_value) + # rxe Why global??? + #message = "global name '%s' is not defined" % varname + message = "name '%s' is not defined" % varname + w_exc_type = f.space.w_NameError + w_exc_value = f.space.wrap(message) + raise OperationError(w_exc_type, w_exc_value) + + # XXX the implementation can be pushed back into app-space as an # when exception handling begins to behave itself. For now, it # was getting on my nerves -- mwh From hpk at codespeak.net Sun Dec 21 20:27:48 2003 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sun, 21 Dec 2003 20:27:48 +0100 (MET) Subject: [pypy-svn] rev 2658 - in pypy/trunk/doc: . devel irclog objspace overviewsprintinfo translation Message-ID: <20031221192748.903AA5AB38@thoth.codespeak.net> Author: hpk Date: Sun Dec 21 20:27:47 2003 New Revision: 2658 Added: pypy/trunk/doc/Diagrams.sxi (props changed) - copied unchanged from rev 2657, pypy/trunk/doc/overview/Diagrams.sxi pypy/trunk/doc/architecture.txt (contents, props changed) - copied, changed from rev 2657, pypy/trunk/doc/overview/architecture.txt Removed: pypy/trunk/doc/overview/ Modified: pypy/trunk/doc/ (props changed) pypy/trunk/doc/devel/checking_ReST.txt (props changed) pypy/trunk/doc/goals.txt (props changed) pypy/trunk/doc/irclog/ (props changed) pypy/trunk/doc/irclog/annotations.txt (props changed) pypy/trunk/doc/irclog/llvm.txt (props changed) pypy/trunk/doc/objspace/ (props changed) pypy/trunk/doc/objspace/abstractobjspace.txt (props changed) pypy/trunk/doc/objspace/annotateobjspace.txt (props changed) pypy/trunk/doc/objspace/basicblock.asc (props changed) pypy/trunk/doc/objspace/multimethod.txt (props changed) pypy/trunk/doc/objspace/objspace.txt (props changed) pypy/trunk/doc/objspace/objspaceinterface.txt (props changed) pypy/trunk/doc/objspace/restrictedpy.txt (contents, props changed) pypy/trunk/doc/objspace/stdobjspace.txt (props changed) pypy/trunk/doc/objspace/trivialobjspace.txt (props changed) pypy/trunk/doc/sprintinfo/ (props changed) pypy/trunk/doc/sprintinfo/AmsterdamAnnouncement.txt (props changed) pypy/trunk/doc/sprintinfo/BerlinReport.txt (props changed) pypy/trunk/doc/sprintinfo/HildesheimReport.txt (props changed) pypy/trunk/doc/sprintinfo/LouvainLaNeuvePlan.txt (props changed) pypy/trunk/doc/sprintinfo/checklist.txt (props changed) pypy/trunk/doc/translation/ (props changed) pypy/trunk/doc/translation/annotation.txt (props changed) pypy/trunk/doc/translation/controlflow.txt (props changed) Log: some thourough refactoring of our new 'architecture' document. It is also moved to top-level so that together with the 'goals' and the still missing 'status' document it is a top-level link on the documentation screen. Copied: pypy/trunk/doc/architecture.txt (from rev 2657, pypy/trunk/doc/overview/architecture.txt) ============================================================================== --- pypy/trunk/doc/overview/architecture.txt (original) +++ pypy/trunk/doc/architecture.txt Sun Dec 21 20:27:47 2003 @@ -1,126 +1,148 @@ -PyPy - an implementation of Python in Python - -Architecture overview -===================== -In its current, rather simple incarnation, Pypy has 2 major parts - the -*interpreter* and an *object space*. Both parts are implemented in Python -and run under CPython. +Overview on PyPy's current architecture (Dec. 2003) +==================================================== +The different parts of PyPy have always been under more or less +heavy refacting during our five one-week sprints in 2003. +However, the basic architecture remains rather simple and unchanged: +a plain interpreter reads and dispatches bytecodes, shuffling objects +around on the stack and between namespaces of which it knows almost +nothing. For any operation on an object it delegates to an so called +Object Space which performs modifications, creation and and destruction +of objects. Such objects are often refered to as application level +objects because they are the objects you naturally work with from +a python program. + The Interpreter =============== -The interpreter accepts a Python source code file and hands it off -to the compiler (PyPy's currently using CPython's built-in compiler) -which turns it into a series of *byte codes* (the byte codes may be -stored in a ``.pyc`` file, if the source code is being imported rather -than directly run). The byte codes are instructions for a virtual -machine, which is just the same as the one used in regular CPython. -Each byte code is made up of an operation code (opcode) and optionally -some operands. - -The interpreter then takes the bytecodes, one by one, and performs -whatever operation each opcode instructs it to do. For all operations -that affect or consult objects, the PyPy interpreter delegates all -actual work on the object to the object space. + +The interpreter accepts python code objects which it obtains by invoking +Python's builtin compiler (we have a way of constructing those code +objects from python code only but it's still not integrated). Code +objects are a nicely preprocessed structured representation of source +code and their main content is *Bytecode*. In addition code objects +also know how to create a *Frame* object which has the responsibility to +*interpret* a code object's bytecode. Each bytecode is implemented via +a python function which in turn will delegate operations on an +application's objects to an object space. The Object Space ================ -The object space contains all objects that have been created and knows -how to perform operations on the objects. You may think of an object -space as being essentially a complete library implementing a fixed API, -a set of *operations*, with implementations that correspond to giving -some semantics to Python object types. An example of an operation might -be *add*: add's implementations are responsible for performing numeric -addition when add works on built-in numbers, concatenation when it -works on built-in sequences. - -We currently have 2 working object spaces which are more or less -interchangeable: - -- The Trivial Object Space, which is a thin wrapper around CPython types. It was used to test the interpreter and is used from time to time for testing purposes. It is currently of little interest and will not be described here. -- The Standard Object Space, which is an almost complete implementation of Python types in Python. This is the main focus of this document, since it is the foundation of PyPy. +The object space creates all objects and knows how to perform operations +on the objects. You may think of an object space as being a +library offering a fixed API, a set of *operations*, with +implementations that correspond to the known semantics of Python objects. +An example of an operation is *add*: add's implementations are e.g. responsible for +performing numeric addition if *add* works on numbers, concatenation when it +works on built-in sequences. -In addition, we have 2 special purpose object spaces under -development; the *Flow Object Space* and the *Trace Object Space*. These -will be described later. +All object space operations take and return "application level" objects. +There is only one minimal operation that allows the interpreter to gain +knowledge about the value of an application level object: *is_true()* which +will return a boolean interpreter level value. This is neccessary for +implementing e.g. if-statements (or rather their branching bytecodes). + +We currently have 4 working object spaces which can be plugged into the +interpreter. + +- The Trivial Object Space, which is basically delegating almost all operations + to the underlying CPython interpreter. It was and still is used to test our + interpreter. Though it is not essential it stays useful for testing and is + thus there to stay for some time. + +- The Standard Object Space, which is an almost complete implementation + of the various Python objects. This is the main focus of this document, + since it is - together with the interpreter - the foundation of our + Python implementation. + +- the Flow Object Space which is used for transforming a python program + into a flow graph representation. It does this by "abstract interpretation" + which will be explained later. + +- the Trace Object Space which wraps the trivial or standard object + space in order to trace the execution of bytecodes, frames and + object space operations. The Standard Object Space ========================= -The Standard Object Space itself is an object which implements a -number of logistic services. At startup, the Standard Object Space -examines certain directories for modules that contain the -implementation of the available Python types. The Standard Object -Space loads each such module, and, in turn, each module so loaded -registers the type it deals with, and all the operations and -implementations for the type, in *multimethod* objects in the Standard -Object Space. - -Later in the execution, when the interpreter delegates the execution -of an instruction to the Standard Object Space, the Standard Object -Space selects the correct implementation of the operation to perform -through the multimethod. +The Standard Object Space implements python's objects and types +and all operations between them. It is thus an essential +component in order to reach CPython comptability. + +The implementations of ints, floats, strings, dicts, lists etc. +all live in separate files and are bound together by a "multimethod" +mechanism. Multimethods allow a caller - most notably the interpreter - +to stay free from knowing anything about an object's implementation. +Thus multimethods implement a way of delegating to the right implementation +based on the passed in objects (which it previously created, anyway). We will examine how the multimethod mechanism works through an example. -We examine the types ``float`` and ``int`` and disregard all other -types for the moment. Each type has an ``__add__`` operator, which is -registered with the Standard Object Space at startup. The float add -operator is registered with the type signature ``__add__(Float, -Float)`` and the integer add operator is registered with the signature -``__add__(Int, Int)``. - -If in our application program we write the expression ``2+3``, the -interpreter will create an object containing the value ``2`` and an -object containing the value ``3``. We annotate these as ``Int(2)`` and -``Int(3)`` respectively. The interpreter then calls the Standard -Object Space with ``__add__(Int(2), Int(3))``. - -The Standard Object Space then delegates the operation to the -``__add__`` multimethod, which finds an implementation that has the -signature ``__add__(Int, Int)``. Since this is a "direct hit", the -multimethod can immediately dispatch the operation to the correct -method, i.e., the one registered as the implementation for this -signature. +We examine the add-operation of ``int`` and ``float`` objects and disregard +all other objects for the moment. There is one multimethod ``add`` that both +implementations of add(intimpl, intimpl) and add(floatimpl, floatimpl) +register with. + +If in our application program we have the expression ``2+3``, the +interpreter will create an application-level object containing the +value ``2`` and one containing the value ``3``. We will here talk about +them as ``W_Int(2)`` and ``W_Int(3)`` respectively. The interpreter then +calls the Standard Object Space with ``add(W_Int(2), W_Int(3))``. + +The Object Space then examines the objects passed in and delegates directly +to the add(intimpl, intimpl) function: since this is a "direct hit", the +multimethod can immediately dispatch the operation to the correct implementation +i.e., the one registered as the implementation for this signature. -If the multimethod doesn't have any registered functions with the -correct signature, as would be the case for example for the expression +If the multimethod doesn't have any registered functions for the +exact given signature, as would be the case for example for the expression ``2+3.0``, the multimethod tests if it can use coercion to find a function with a signature that works. In this case we would coerce -``Int(2)`` to ``Float(2.0)`` in order to find a function in the -multimethod that has a correct signature. +``W_Int(2)`` to ``W_Float(2.0)`` in order to find a function in the +multimethod that has a correct signature. Note that the multimethod +mechanism is still considered a major refactoring target as it is +not easy to get it completly right, fast and accurate. + +Application-level and interpreter-level execution and objects +============================================================= + +Since Python is used for implementing all of our code base there +is a crucial distinction to be aware of: interpreter level objects +and application level objects. The latter are the ones that you +deal with when you write normal python programs. Interpreter level +code, however, cannot invoke operations or access attributes from +our application-level objects. You will immediately recognize any +interpreter level code in PyPy because all variable and object names +start with a `w_` which indicates that they are wrapped/application +level values. + +To show the difference with an example: to sum the contents of two +variables ``a`` and ``b``, typical application-level code is ``a+b`` +-- in sharp contrast, typical interpreter-level code is ``space.add(w_a, w_b)``, +where ``space`` is an instance of an object space and ``w_a`` and ``w_b`` +are typical names for the *wrapped* versions of the two variables. + +It also helps to remember how CPython deals with the same issue: +interpreter level code is written in C and thus typical code for the +addition is ``PyNumber_Add(p_a, p_b)`` where ``p_a`` and ``p_b`` are C +variables of type ``PyObject*``. This is very similar to how we write +our interpreter-level python code. + +Moreover, in PyPy we have to make a sharp distinction between +interpreter and application level *exceptions*: application exceptions +are always contained in an ``OperationError``. This makes it easy +to distinguish failures in our interpreter-level code from those +appearing in a python application level program. + -Application-level and interpreter-level -======================================= -Since the same language (Python) is what PyPy both **uses** and -**deals with**, a given piece of Python source can be playing either -of two rather distinct roles in the PyPy system. To be systematic in -distinguishing these roles, we call them *interpreter level* (Python -used to implement the interpreter and object space) and *application -level* (Python that we are interpreting). To show the difference with -an example: to sum the contents of two variables ``a`` and ``b``, -typical application-level code is ``a+b`` -- in sharp contrast, -typical interpreter-level code is ``space.add(w_a, w_b)``, where -``space`` is an instance of the standard object space class and -``w_a`` and ``w_b`` are typical names for the *wrapped* versions of -the two variables. By contrast, think of traditional CPython: it has -the same application-level code, but interpreter-level code is C -source, and typical code for the addition would be ``PyNumber_Add(p_a, -p_b)`` where ``p_a`` and ``p_b`` are C variables of type -``PyObject*``. - -You might think that the need to keep the two roles for the same -language distinguished is a cause of confusion; sometimes, indeed, it is -possible to get confused between the two levels while developing PyPy. -However, the existence of the two levels for the same language also -offers a powerful advantage, fully offsetting the possibility of -confusion (and then some): PyPy lets you use application-level code for -the purpose of implementing interpreter-level operations. +Application level is often preferable +------------------------------------- Application-level code is much higher-level, and therefore easier to write and debug. For example, suppose we want to implement the ``update`` method of dict objects. Programming at the application level, we can write the obvious, simple implementation, one that looks -like an executable-pseudocode **definition** of ``update``:: +like an **executable definition** of ``update``:: def update(self, other): for k in other.keys(): @@ -138,16 +160,22 @@ w_value = space.getitem(w_other, w_key) space.setitem(w_self, w_key, w_value) -This interpreter-level implementation looks much closer to the C source -code implementing this functionality in CPython, although, depending on -one's relative familiarity with C, Python, and PyPy's coding -conventions, it may still be considered somewhat more readable. In any -case, it should be obvious that the application-level implementation is -definitely more readable and maintainable than the interpreter-level -one. +This interpreter-level implementation looks much more similar to the C source +code although it is probably still more readable. In any case, it should be +obvious that the application-level implementation is definitely more readable, +more elegant and maintainable than the interpreter-level one. + +In fact, in almost all parts of PyPy you will find application level code +in the middle of interpreter-level code. Apart from some bootstrapping +problems (application level functions need a certain initialization level +of the object space to be executed) application level code is usually +preferable. We have an abstraction (called 'Gateway') which allows the caller +of a function to stay ignorant whether a particular function is implemented +at application or interpreter level. Wrapping ======== + The ``w_`` prefixes so lavishly used in the previous example indicate, by PyPy coding convention, that we are dealing with *wrapped* objects, that is, objects constructed by the object space at interpreter level to @@ -169,81 +197,60 @@ question has to be explicitly recorded in ``ob_size``). -RPython translation -=================== -All the interpreter level code is implemented in a subset of Python -called RPython. This subset has not been fully defined yet, but it has -some restrictions on parts of Python you can use, as well as some -restrictions on how you can combine different constructs. The purpose -of this to have a language that is suitable for turning into optimised -code in a low level language. Our current target is C, but going -directly to machine code for a real or virtual machine are other paths -that could be taken. - -In order to produce a fast version of the PyPy interpreter we apply a -special version of the PyPy interpreter on the regular PyPy -interpreter. Once we have loaded the entire interpreter and the -Standard Object Space, we have a collection of byte codes that -constitute the PyPy interpreter program. This is then fed to the -special interpreter, which has the Standard Object Space replaced with -a Flow Object Space. - -The Flow Object Space drives the execution in such a way that all -paths in the code are followed. As a side-effect it produces flow -graphs, which are graphs capturing the control flow of the code. The -nodes of the graphs are basic blocks of logged Object Space operations -executed sequentially. How values flow is also encoded in the graphs. - -The flow graphs are fed as input to the Annotator. The Annotator, -given entry point types, infers the types of values that flow through -the program variables. This is possible because of the constraints -that RPython places on the interpreter code. - -In the last phase the type annotated flow graphs are visited by the -Translator, which emits "low-level code". To do this, it uses the -types annotation, the basic block listed operations and control flow -information encoded in the graphs. Our first target will probably be -Pyrex code, which is then translated to compilable C by Pyrex itself. - -Object Space tricks -=================== -The fact that the Interpreter and the Object Spaces are separate -packages with an explicit and stable API in between gives us some new -and interesting possibilities. - -The first one is that it is easy to write an Object Space that wraps -the Standard Object Space and interfaces to the Interpreter. - -One such Object Space is the Trace Object Space, which allows us to -examine and trace all instructions that are passed to the Standard -Object Space as well as all results being passed back to the -Interpreter. Since all object spaces have the same API, the Trace -Object Space should be able to trace the execution of any version of -the PyPy interpreter, e.g. the one compiling RPython. - -*Up to here we have been speaking about things that we have, or are -working on. The rest of this chapter is about things that could be -done with our architecture.* - -Another possibility is an object space that interfaces to a Standard -Object Space on another machine. From this it is not far to an object -space that keeps tab of where its objects reside and is able to -delegate its operations to more than one object space. For instance, -we can have multiple objects spaces which reside in different threads -in the same process. - -At the other end, it is possible to replace the Interpreter with one -that interprets instructions for a different Virtual Machine, but -still uses the Standard Object Space. It is a rather short conceptual -step from this to allowing delegation between multiple Interpreters, -making it possible to mix both source languages and bytcode -instruction sets. Naturally there are limits to how different the -underlying models of the virtual machines can be before they become -incompatible with the Standard Object Space, but even this could be -solved, using multiple interpreters delegating to multiple object -spaces. However, the code for interaction between the object spaces -would probably be quite complex. - - -TODO: review and see what else we need to add! +RPython, the Flow Object Space and translation +============================================== +At last we want to translate our interpreter and standard object +space into a low level language. In order for our translation +and type inference mechanisms to work effectively we need to restrict +the dynamism of our interpreter-level Python code at some point. However, +we are completly free to do all kind of nice python constructs up to +using metaclasses and executing dynamically constructed strings. +When the initialization phase finishes (mainly ``objspace.initialize()``) +all involved code objects need to adhere to a (non-formally defined) more +static subset of Python: Restricted Python or 'RPython'. + +A so called Flow Object Space will then - with the help of our plain +interpreter - work through those initialized "RPython" code objects. +The result of this *abstract interpretation* is a flow graph: yet another +representation of a python program which is suitable for applying +translation and type inference techniques. The nodes of the graphs are +basic blocks consisting of Object Space operations, flowing of values +and an exitswitch to one, two or multiple links which connect it to +other basic blocks. + +The flow graphs are fed as input to the Annotator. The Annotator, given +entry point types, infers the types of values that flow through the +program variables. And here we have one of the informal definitions of +RPython: it's restricted in a way that the translator can still compile +low-level typed code. How much dynamism we allow in RPython depends and +is restricted by the Flow Object Space and the Annotator implementation. +The more we can improve this translation phase the more we can allow +dynamism. But in some cases it will probably more feasible to just get +rid of some dynamism we use in our interpreter level code. It is mainly +because of this trade-off situatio that we don't currently try to +formally define 'RPython'. + +The actual low-level code (or in fact also other high-level code) +is emitted by visiting the type-annotated flow graph. Currently +we have a Pyrex backend and a Lisp backend. We use (a slightly +hacked version of) Pyrex to generate C libraries. As Pyrex also +accepts plain non-typed python code we can test translation even +though it is not complete. + +Trace Object Space +================== + +A recent addition is the Trace Object space which allows to wrap +a standard and trivial object space in order to trace all object +space operations, frame creation, deletion and bytecode execution. +The ease with which the Trace Object Space could be implemented +at the Amsterdam Sprint underlines the power of the Object Space +abstraction. (Of course the formerly implemented Flow Object Space +producing the flow graph already was proof enough). + +There are certainly many more possibly useful Object Space ideas +like a ProxySpace that connects to a remote machine where the +actual operations are performed. At the other end, we wouldn't +need to change object spaces at all if we want to extend or modify +the interpreter by e.g. adding or removing some bytecodes. Modified: pypy/trunk/doc/objspace/restrictedpy.txt ============================================================================== --- pypy/trunk/doc/objspace/restrictedpy.txt (original) +++ pypy/trunk/doc/objspace/restrictedpy.txt Sun Dec 21 20:27:47 2003 @@ -2,73 +2,73 @@ Restricted Python ================== -We are writing a Python interpreter in Python, using Python's well known ability -to step behind the algorithmic problems as language. At first glance, one might -think this achieves nothing but a better understanding for everybody how the -interpreter works. This alone would make it worth doing, but we have much larger +We are writing a Python interpreter in Python, using Python's well known ability +to step behind the algorithmic problems as language. At first glance, one might +think this achieves nothing but a better understanding for everybody how the +interpreter works. This alone would make it worth doing, but we have much larger goals. CPython vs. PyPy ------------------- -Compared to the CPython implementation, Python takes the role of the C Code. So -actually, we describe something by Python, which has been coded in C already, -with all the restrictions that are implied by C. We are not trying to make the -structures of the CPython interpreter more flexible by rewriting things in C, +Compared to the CPython implementation, Python takes the role of the C Code. So +actually, we describe something by Python, which has been coded in C already, +with all the restrictions that are implied by C. We are not trying to make the +structures of the CPython interpreter more flexible by rewriting things in C, but we want to use Python to give an alternative description of the interpreter. -The clear advantage is that this description is probably shorter and simpler to -read, and many implementation details vanish. The drawback of this approach is +The clear advantage is that this description is probably shorter and simpler to +read, and many implementation details vanish. The drawback of this approach is that this interpreter will be unbearably slow. -To get to a useful interpreter again, we need to apply some mappings to the -implementation, later. One rather straight-forward is to do a whole program -analysis of the PyPy interpreter and create a C source, again. There are many +To get to a useful interpreter again, we need to apply some mappings to the +implementation, later. One rather straight-forward is to do a whole program +analysis of the PyPy interpreter and create a C source, again. There are many other ways, but let's stick with the easiest approach, first. -In order to make a C code generator simple, we restrict ourselves to a subset of -the Python language, and we adhere to some rules, which make code generation +In order to make a C code generator simple, we restrict ourselves to a subset of +the Python language, and we adhere to some rules, which make code generation obvious and easy. Restricted Python is Runtime Python ------------------------------------- -Restricted Python describes a runnable Python interpreter implementation. This -is a quite static object that can be suitably described by RPython. But the +Restricted Python describes a runnable Python interpreter implementation. This +is a quite static object that can be suitably described by RPython. But the restrictions do not apply during the startup phase. PyPy Bootstrap ------------------- -When the PyPy interpreter is started as a CPython program, it can use all of -CPython for a while, until it reaches runtime. That is, all executable code will +When the PyPy interpreter is started as a CPython program, it can use all of +CPython for a while, until it reaches runtime. That is, all executable code will be executed using the full power of Python. -An example can be found in the implementation, which is quite elegant: For the -definition of all the opcodes of the Python interpreter, the module dis is -imported and used. This saves us from adding extra modules to PyPy. The import -code is run at startup time, and we are allowed to use the CPython builtin +An example can be found in the implementation, which is quite elegant: For the +definition of all the opcodes of the Python interpreter, the module dis is +imported and used. This saves us from adding extra modules to PyPy. The import +code is run at startup time, and we are allowed to use the CPython builtin import function. -When the startup code is done, all resulting objects, functions, code blocks -etc. must adhere to the runtime restrictions. All initialized modules are -written out in a persistent manner. Our current idea is to emit a huge C source -file which contains everything created so far. During this process, a whole -program analysis is performed, which makes use of the restrictions defined in -RPython. This enables the code generator to emit efficient replacements for pure +When the startup code is done, all resulting objects, functions, code blocks +etc. must adhere to the runtime restrictions. All initialized modules are +written out in a persistent manner. Our current idea is to emit a huge C source +file which contains everything created so far. During this process, a whole +program analysis is performed, which makes use of the restrictions defined in +RPython. This enables the code generator to emit efficient replacements for pure integer objects, for instance. RPython Definition -------------------- -It might make sense to define a sub-language of Python called RPython, with the -restrictions depicted below. This is an evolving topic, and we're just -collecting things which come up during trying to code the interpreter, so this -is no language at all, but an arbitrary set of rules, which are about to be +It might make sense to define a sub-language of Python called RPython, with the +restrictions depicted below. This is an evolving topic, and we're just +collecting things which come up during trying to code the interpreter, so this +is no language at all, but an arbitrary set of rules, which are about to be changed all day. @@ -79,10 +79,10 @@ **variables** - the same variable in the same context can receive values of different types, - at a possible overhead cost. For example, a variable that can contain a - wrapped object or None is efficiently implemented as a PyObject* pointer that - can be NULL, but a variable that can contain either an integer or a float must + the same variable in the same context can receive values of different types, + at a possible overhead cost. For example, a variable that can contain a + wrapped object or None is efficiently implemented as a PyObject* pointer that + can be NULL, but a variable that can contain either an integer or a float must be implemented as a union with a type tag in C. **constants** @@ -95,12 +95,12 @@ **tuples** - no variable-length tuples; use them to store or return pairs or n-tuples of + no variable-length tuples; use them to store or return pairs or n-tuples of values **lists** - lists are used as an allocated array; list.append() does naive resizing, so as + lists are used as an allocated array; list.append() does naive resizing, so as far as possible use list comprehensions (see below) **dicts** @@ -113,35 +113,35 @@ **list comprehensions** - may be used to create allocated, initialized array. the array size must be + may be used to create allocated, initialized array. the array size must be computable in advance, which implies that we don't allow an if clause. **functions** -+ statically called functions may use defaults and a variable number of - arguments (which may be passed as a list instead of a tuple, so write code that ++ statically called functions may use defaults and a variable number of + arguments (which may be passed as a list instead of a tuple, so write code that does not depend on it being a tuple). -+ dynamic dispatch enforces use of very simple signatures, equal for all - functions to be called in that context. At the moment, this occurs in the opcode ++ dynamic dispatch enforces use of very simple signatures, equal for all + functions to be called in that context. At the moment, this occurs in the opcode dispatch, only. **builtin functions** - A few builtin functions will be used, while this set is not defined + A few builtin functions will be used, while this set is not defined completely, yet. Some builtin functions are special forms: **range** - does not create an array. It is only allowed in for loops. The step argument + does not create an array. It is only allowed in for loops. The step argument must be a constant. **len** -+ may be used with basic types that have a length. But len is a special form ++ may be used with basic types that have a length. But len is a special form that is recognized by the compiler. -+ If a certain structure is never touched by len, the compiler might save the ++ If a certain structure is never touched by len, the compiler might save the length field from the underlying structure. ``int, float, ord, chr``... are available as simple conversion functions. @@ -162,8 +162,8 @@ **objects** - wrapped objects are borrowed from the object space. Just like in CPython, code - that needs e.g. a dictionary can use a wrapped dict and the object space + wrapped objects are borrowed from the object space. Just like in CPython, code + that needs e.g. a dictionary can use a wrapped dict and the object space operations on it. This layout makes the number of types to take care about quite limited. @@ -172,28 +172,28 @@ Example: Integer Types ------------------------- -While implementing the integer type, I (Chris) stumbled over the problem, that -integers are quite in flux in CPython right now. Depending on the version, -integers either raise an overflow exception or mutate into longs on overflow. -Also, shifting right now truncates (up to 2.3) but is going to extend to longs -as well. In order to enable us to run the restricted Python stuff in CPython, I -needed to use a derived class r_int(int), which always behaves the same: Never +While implementing the integer type, I (Chris) stumbled over the problem, that +integers are quite in flux in CPython right now. Depending on the version, +integers either raise an overflow exception or mutate into longs on overflow. +Also, shifting right now truncates (up to 2.3) but is going to extend to longs +as well. In order to enable us to run the restricted Python stuff in CPython, I +needed to use a derived class r_int(int), which always behaves the same: Never leaving its domain, but always staying an integer. -The r_int type is implemented in a pervasive way: Every operation that involves -an r_int creates an r_int as the result. Therefore, the implementation is not -cluttered with special type casts. Just the initial value of an emulated -integer's intval field is initialized by obj.intval = r_int(val) . This way, the -r_int type propagates itself through all operations without extra effort of the +The r_int type is implemented in a pervasive way: Every operation that involves +an r_int creates an r_int as the result. Therefore, the implementation is not +cluttered with special type casts. Just the initial value of an emulated +integer's intval field is initialized by obj.intval = r_int(val) . This way, the +r_int type propagates itself through all operations without extra effort of the programmer. -This concept looks promising, and since we will need unsigned integers which do -not overflow as well, I also created r_uint. It is always a word-sized unsigned -integer and never overflows. This will be a building block for things like -computing hash values, where wrap-around effects are intended and should be +This concept looks promising, and since we will need unsigned integers which do +not overflow as well, I also created r_uint. It is always a word-sized unsigned +integer and never overflows. This will be a building block for things like +computing hash values, where wrap-around effects are intended and should be easily coded without lots of explicit mask shuffling. -Now I think to extend this even more and build a full set of primitive types, +Now I think to extend this even more and build a full set of primitive types, which are intended to + define the semantics of the primitive type @@ -219,8 +219,8 @@ # implement using longs -Code with no exception handlers does not raise exceptions. By supplying an -exception handler, you ask for error checking. Without, you assure the system +Code with no exception handlers does not raise exceptions. By supplying an +exception handler, you ask for error checking. Without, you assure the system that the operation cannot overflow. Exceptions explicitly raised will always be generated. @@ -229,7 +229,7 @@ Testing ------------ -Besides extra tests which have to be written, PyPy has the advantage that it is -runnable on standard CPython. That means, we can run all of PyPy with all -exception handling enabled, so we might catch cases where we failed to adhere to +Besides extra tests which have to be written, PyPy has the advantage that it is +runnable on standard CPython. That means, we can run all of PyPy with all +exception handling enabled, so we might catch cases where we failed to adhere to our implicit assertions. From hpk at codespeak.net Sun Dec 21 20:40:12 2003 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sun, 21 Dec 2003 20:40:12 +0100 (MET) Subject: [pypy-svn] rev 2659 - in pypy/trunk/doc: . devel Message-ID: <20031221194012.38C2D5AA0B@thoth.codespeak.net> Author: hpk Date: Sun Dec 21 20:40:11 2003 New Revision: 2659 Added: pypy/trunk/doc/howtopypy.txt (props changed) - copied unchanged from rev 2657, pypy/trunk/doc/devel/howtopypy.txt Removed: pypy/trunk/doc/devel/howtopypy.txt Log: move howtopypy to top-level (because i think it belongs there) Deleted: /pypy/trunk/doc/devel/howtopypy.txt ============================================================================== --- /pypy/trunk/doc/devel/howtopypy.txt Sun Dec 21 20:40:11 2003 +++ (empty file) @@ -1,112 +0,0 @@ -================================== -Getting started with PyPy -================================== - -PyPy sources can be browsed on the web at: - - ``http://codespeak.net/svn/pypy/trunk/`` - -Once you are ready to download and try PyPy out, -follow these instructions, which assume that you -are working in a DOS box (Windows) or terminal (MacOS/X or Linux). - -1. Download subversion_ if you do not already have it. - - -2. Change to the directory where you wish to install the source tree, - and use subversion to download the source:: - - svn co http://codespeak.net/svn/pypy/trunk/src - - This will create a subdirectory named ``src``, and will create - the PyPy source tree under this directory. - - - If desired, you can also download the documentation:: - - svn co http://codespeak.net/svn/pypy/trunk/doc - - -3. To start interpreting Python with PyPy, use Python 2.3 or greater:: - - cd src/pypy/interpreter - python py.py -S - - After a few seconds, you should be at the PyPy prompt, which is - the same as the Python prompt, but with an extra ">". - - The "-S" given on the command line instructs the PyPy interpreter - to use the `Standard object space`_. PyPy has the concept of different - object spaces_, but the standard space is the one which contains - the "real" Python-in-Python interpreter. - - -4. Now you are ready to start running Python code. Some real Python - modules will not run yet, and others will run too slowly to be - worth waiting for, but a few are fun to run:: - - >>>> import pystone - >>>> pystone.main(10) - - Note that this is a slightly modified version of pystone -- the - original version does not accept the parameter to main(). The - parameter is the number of loops to run through the test, and the - default is 50000, which is far too many to run in a reasonable time - on the current PyPy implementation. - - -5. To list the PyPy interpreter command line options, type:: - - python py.py --help - - As an example of using PyPy from the command line, you could type:: - - python py.py -S -c "import pystone; pystone.main(10)" - - Alternatively, as with regular Python, you can simply give a - script name on the command line:: - - python py.py -S ../appspace/pystone.py - - (Note that this will run "forever" -- actually, "just" for many - hours, with the current implementation of PyPy.) - - -6. The PyPy project uses test-driven-development. Right now, there are - a couple of different categories of tests which you can run. - To run all the unit tests:: - - cd src/pypy - python test_all.py -S - - Alternatively, you may run subtests by going to the correct subdirectory - and running them individually:: - - cd src/pypy/module/test - python test_builtin.py -S - - Finally, there are some more advanced tests (which are derived from - some of the standard CPython tests). These are not part of the unit - tests, because they take longer than the standard unit tests:: - - cd src/pypy/interpreter - python py.py -S -c "import builtin_types_test" - - -7. To learn more about PyPy and its development process, read the documentation_ - and the wiki_, and consider subscribing to the `mailing lists`_ (or simply - read the archives online) or communicating via irc.freenode.net:6667, channel #pypy. - -8. To help PyPy become Python-the-next-generation, write some `unit tests`_ and - file some `bug reports`_! - --------------------------------------------------------------------------------- - -.. _subversion: http://codespeak.net/pypy/index.cgi?doc/devel/howtosvn.html -.. _Standard object space: http://codespeak.net/pypy/index.cgi?doc/objspace/stdobjspace.html -.. _spaces: http://codespeak.net/pypy/index.cgi?doc/objspace/objspace.html -.. _mailing lists: http://codespeak.net/pypy/index.cgi?lists -.. _documentation: http://codespeak.net/pypy/index.cgi?doc -.. _wiki: http://codespeak.net/moin/pypy/moin.cgi/FrontPage?action=show -.. _unit tests: http://codespeak.net/pypy/index.cgi?doc/devel/testdesign.html -.. _bug reports: http://codespeak.net/issues/pypy/ From alex at codespeak.net Mon Dec 22 00:17:22 2003 From: alex at codespeak.net (alex at codespeak.net) Date: Mon, 22 Dec 2003 00:17:22 +0100 (MET) Subject: [pypy-svn] rev 2661 - in pypy/trunk/src/pypy/interpreter: . test Message-ID: <20031221231722.B8CAB5AAA7@thoth.codespeak.net> Author: alex Date: Mon Dec 22 00:17:22 2003 New Revision: 2661 Modified: pypy/trunk/src/pypy/interpreter/generator.py pypy/trunk/src/pypy/interpreter/pyopcode.py pypy/trunk/src/pypy/interpreter/test/test_generator.py Log: generators which raised StopIteration used to fail (added a unit test method to show that); fixed by tweaking pyopcode.py's RAISE_VARARGS method to use a simple "Template Method" Design Pattern via a new hook method _make_op_err (which in pyopcode.py just does the "raise OperationError", but which generator.py can and does override to specialcase StopIteration only). Modified: pypy/trunk/src/pypy/interpreter/generator.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/generator.py (original) +++ pypy/trunk/src/pypy/interpreter/generator.py Mon Dec 22 00:17:22 2003 @@ -35,6 +35,13 @@ raise SYieldValue(w_yieldedvalue) YIELD_STMT = YIELD_VALUE # misnamed in old versions of dis.opname + def _make_op_err(f, w_type, w_value): + # hook to let a "raise StopIteration" in a generator be a + # normal termination for that generator: + if w_type is f.space.w_StopIteration: + raise SGeneratorReturn() + else: + raise OperationError(w_type, w_value) class GeneratorIterator(object): "An iterator created by a generator." Modified: pypy/trunk/src/pypy/interpreter/pyopcode.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/pyopcode.py (original) +++ pypy/trunk/src/pypy/interpreter/pyopcode.py Mon Dec 22 00:17:22 2003 @@ -303,6 +303,11 @@ w_resulttuple = prepare_raise(f.space, w_type, w_value, w_traceback) w_type, w_value, w_traceback = f.space.unpacktuple(w_resulttuple, 3) # XXX the three-arguments 'raise' is not supported yet + raise f._make_op_err(w_type, w_value) + + def _make_op_err(f, w_type, w_value): + # hook to let a "raise StopIteration" in a generator be a + # normal termination for that generator: raise OperationError(w_type, w_value) def LOAD_LOCALS(f): Modified: pypy/trunk/src/pypy/interpreter/test/test_generator.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/test/test_generator.py (original) +++ pypy/trunk/src/pypy/interpreter/test/test_generator.py Mon Dec 22 00:17:22 2003 @@ -27,6 +27,13 @@ yield 1 g = f() self.assertEquals([x for x in g], [1]) + + def test_generator_explicit_stopiteration(self): + def f(): + yield 1 + raise StopIteration + g = f() + self.assertEquals([x for x in g], [1]) def test_generator_restart(self): def g(): From alex at codespeak.net Mon Dec 22 00:43:18 2003 From: alex at codespeak.net (alex at codespeak.net) Date: Mon, 22 Dec 2003 00:43:18 +0100 (MET) Subject: [pypy-svn] rev 2662 - pypy/trunk/src/pypy/module Message-ID: <20031221234318.4AB1D5AAA7@thoth.codespeak.net> Author: alex Date: Mon Dec 22 00:43:17 2003 New Revision: 2662 Modified: pypy/trunk/src/pypy/module/builtin.py Log: fixes for map [[ map(None,x) must return list(x), NOT x ]] and for sum [[ sum(blah, '') must raise TypeError ]]. Modified: pypy/trunk/src/pypy/module/builtin.py ============================================================================== --- pypy/trunk/src/pypy/module/builtin.py (original) +++ pypy/trunk/src/pypy/module/builtin.py Mon Dec 22 00:43:17 2003 @@ -314,6 +314,8 @@ return self.space.id(w_object) def app_sum(self, sequence, total=0): + # must forbid "summing" strings, per specs of built-in 'sum' + if isinstance(total, str): raise TypeError for item in sequence: total = total + item return total @@ -393,17 +395,18 @@ 3. if function is not None, and there are several collections, repeatedly call the function with one argument from each collection. If the collections have different lengths, - shorter ones are padded with None""" + shorter ones are padded with None + """ if len(collections) == 0: raise TypeError, "map() requires at least one sequence" elif len(collections) == 1: - #it's the most common case, so make it faster - if function is None: - return collections[0] - else: - return [function(x) for x in collections[0]] + #it's the most common case, so make it faster + if function is None: + return list(collections[0]) + else: + return [function(x) for x in collections[0]] else: res = [] idx = 0 From alex at codespeak.net Mon Dec 22 00:44:18 2003 From: alex at codespeak.net (alex at codespeak.net) Date: Mon, 22 Dec 2003 00:44:18 +0100 (MET) Subject: [pypy-svn] rev 2663 - pypy/trunk/src/pypy/module Message-ID: <20031221234418.8997D5AAA7@thoth.codespeak.net> Author: alex Date: Mon Dec 22 00:44:17 2003 New Revision: 2663 Modified: pypy/trunk/src/pypy/module/builtin.py Log: fixed some indentations Modified: pypy/trunk/src/pypy/module/builtin.py ============================================================================== --- pypy/trunk/src/pypy/module/builtin.py (original) +++ pypy/trunk/src/pypy/module/builtin.py Mon Dec 22 00:44:17 2003 @@ -453,18 +453,18 @@ ignoring the trailing items in the other collections.""" if len(collections) == 0: - raise TypeError, "zip() requires at least one sequence" + raise TypeError, "zip() requires at least one sequence" res = [] idx = 0 while 1: - try: - elems = [] - for collection in collections: - elems.append(collection[idx]) - res.append(tuple(elems)) - except IndexError: - break - idx = idx + 1 + try: + elems = [] + for collection in collections: + elems.append(collection[idx]) + res.append(tuple(elems)) + except IndexError: + break + idx = idx + 1 return res def app_reduce(self, function, l, *initialt): From alex at codespeak.net Mon Dec 22 00:46:56 2003 From: alex at codespeak.net (alex at codespeak.net) Date: Mon, 22 Dec 2003 00:46:56 +0100 (MET) Subject: [pypy-svn] rev 2664 - in pypy/trunk/src/pypy: module objspace/std Message-ID: <20031221234656.D74F85AAA7@thoth.codespeak.net> Author: alex Date: Mon Dec 22 00:46:56 2003 New Revision: 2664 Modified: pypy/trunk/src/pypy/module/builtin.py pypy/trunk/src/pypy/objspace/std/slicetype.py Log: removed the new builtin 'sign' and its uses in slicetype (easily replaced with cmp(..., 0), as Patrick Maupin suggested last night over a beer). Modified: pypy/trunk/src/pypy/module/builtin.py ============================================================================== --- pypy/trunk/src/pypy/module/builtin.py (original) +++ pypy/trunk/src/pypy/module/builtin.py Mon Dec 22 00:46:56 2003 @@ -320,17 +320,6 @@ total = total + item return total - # This function was not in the original builtins, - # but is quite useful for some aspects of PyPy - # implementation. - def app_sign(self, a): - if a > 0: - return 1 - elif a < 0: - return -1 - else: - return 0 - #XXX works only for new-style classes. #So we have to fix it, when we add support for old-style classes def issubclass(self, w_cls1, w_cls2): Modified: pypy/trunk/src/pypy/objspace/std/slicetype.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/slicetype.py (original) +++ pypy/trunk/src/pypy/objspace/std/slicetype.py Mon Dec 22 00:46:56 2003 @@ -86,8 +86,8 @@ def app_slice_indices4(slice, sequencelength): start, stop, step = slice_indices3(slice, sequencelength) slicelength = stop - start - lengthsign = sign(slicelength) - stepsign = sign(step) + lengthsign = cmp(slicelength, 0) + stepsign = cmp(step, 0) if stepsign == lengthsign: slicelength = (slicelength - lengthsign) // step + 1 else: From alex at codespeak.net Mon Dec 22 00:55:39 2003 From: alex at codespeak.net (alex at codespeak.net) Date: Mon, 22 Dec 2003 00:55:39 +0100 (MET) Subject: [pypy-svn] rev 2665 - pypy/trunk/src/pypy/module/test Message-ID: <20031221235539.5FC365AAA7@thoth.codespeak.net> Author: alex Date: Mon Dec 22 00:55:38 2003 New Revision: 2665 Modified: pypy/trunk/src/pypy/module/test/test_builtin.py Log: removed test for builtin 'sign' which was also removed; added a test to show that xrange incorrectly lacks len(). Modified: pypy/trunk/src/pypy/module/test/test_builtin.py ============================================================================== --- pypy/trunk/src/pypy/module/test/test_builtin.py (original) +++ pypy/trunk/src/pypy/module/test/test_builtin.py Mon Dec 22 00:55:38 2003 @@ -6,11 +6,6 @@ def setUp(self): self.space = test.objspace() - def test_sign(self): - self.assertEquals(sign(-4), -1) - self.assertEquals(sign(0), 0) - self.assertEquals(sign(10), 1) - def test_import(self): m = __import__('pprint') self.assertEquals(m.pformat({}), '{}') @@ -167,6 +162,22 @@ def test_xrange_has_type_identity(self): self.assertEquals(type(xrange(1)), type(xrange(1))) + def test_xrange_len(self): + x = xrange(33) + self.assertEquals(len(x), 33) + x = xrange(33,0,-1) + self.assertEquals(len(x), 33) + x = xrange(33,0) + self.assertEquals(len(x), 0) + x = xrange(0,33) + self.assertEquals(len(x), 33) + x = xrange(0,33,-1) + self.assertEquals(len(x), 0) + x = xrange(0,33,2) + self.assertEquals(len(x), 17) + x = xrange(0,32,2) + self.assertEquals(len(x), 16) + def test_cmp(self): self.assertEquals(cmp(9,9), 0) self.assert_(cmp(0,9) < 0) From alex at codespeak.net Mon Dec 22 00:58:11 2003 From: alex at codespeak.net (alex at codespeak.net) Date: Mon, 22 Dec 2003 00:58:11 +0100 (MET) Subject: [pypy-svn] rev 2666 - pypy/trunk/src/pypy/module Message-ID: <20031221235811.352DE5AAA7@thoth.codespeak.net> Author: alex Date: Mon Dec 22 00:58:10 2003 New Revision: 2666 Modified: pypy/trunk/src/pypy/module/builtin.py Log: added implementation of __len__ to xrange Modified: pypy/trunk/src/pypy/module/builtin.py ============================================================================== --- pypy/trunk/src/pypy/module/builtin.py (original) +++ pypy/trunk/src/pypy/module/builtin.py Mon Dec 22 00:58:10 2003 @@ -742,6 +742,17 @@ raise ValueError, 'xrange() step-argument (arg 3) must not be zero' self.step = step + def __len__(self): + if not hasattr(self, '_len'): + slicelength = self.stop - self.start + lengthsign = cmp(slicelength, 0) + stepsign = cmp(self.step, 0) + if stepsign == lengthsign: + self._len = (slicelength - lengthsign) // self.step + 1 + else: + self._len = 0 + return self._len + def __iter__(self): def gen(self): start, stop, step = self.start, self.stop, self.step From alex at codespeak.net Mon Dec 22 01:02:47 2003 From: alex at codespeak.net (alex at codespeak.net) Date: Mon, 22 Dec 2003 01:02:47 +0100 (MET) Subject: [pypy-svn] rev 2667 - pypy/trunk/src/pypy/module/test Message-ID: <20031222000247.C0B0B5AAA7@thoth.codespeak.net> Author: alex Date: Mon Dec 22 01:02:47 2003 New Revision: 2667 Modified: pypy/trunk/src/pypy/module/test/test_builtin.py Log: xrange is not indexable -- added a unit test method to show this bug Modified: pypy/trunk/src/pypy/module/test/test_builtin.py ============================================================================== --- pypy/trunk/src/pypy/module/test/test_builtin.py (original) +++ pypy/trunk/src/pypy/module/test/test_builtin.py Mon Dec 22 01:02:47 2003 @@ -178,6 +178,14 @@ x = xrange(0,32,2) self.assertEquals(len(x), 16) + def test_xrange_indexing(self): + x = xrange(0,33,2) + self.assertEquals(x[7], 14) + self.assertEquals(x[-7], 20) + self.assertRaises(IndexError, x.__getitem__, 16) + self.assertRaises(IndexError, x.__getitem__, -16) + self.assertRaises(TypeError, x.__getitem__, slice(0,3,1)) + def test_cmp(self): self.assertEquals(cmp(9,9), 0) self.assert_(cmp(0,9) < 0) From alex at codespeak.net Mon Dec 22 01:11:34 2003 From: alex at codespeak.net (alex at codespeak.net) Date: Mon, 22 Dec 2003 01:11:34 +0100 (MET) Subject: [pypy-svn] rev 2668 - pypy/trunk/src/pypy/module/test Message-ID: <20031222001134.A70FD5AAA7@thoth.codespeak.net> Author: alex Date: Mon Dec 22 01:11:34 2003 New Revision: 2668 Modified: pypy/trunk/src/pypy/module/test/test_builtin.py Log: slightly accelerated test_dir (it's still too slow!); fixed test_xrange_indexing (was using incorrect values). Modified: pypy/trunk/src/pypy/module/test/test_builtin.py ============================================================================== --- pypy/trunk/src/pypy/module/test/test_builtin.py (original) +++ pypy/trunk/src/pypy/module/test/test_builtin.py Mon Dec 22 01:11:34 2003 @@ -52,14 +52,12 @@ self.assertEquals(f(), []) self.assertEquals(g(), ['a', 'b', 'c']) class X: pass - self.assertEquals(nosp(dir(X)), nosp(['__module__', ])) - class X: a = 23 - self.assertEquals(nosp(dir(X)), nosp(['__module__', 'a'])) + self.assertEquals(nosp(dir(X)), []) class X: a = 23 c = 45 b = 67 - self.assertEquals(nosp(dir(X)), nosp(['__module__', 'a', 'b', 'c'])) + self.assertEquals(nosp(dir(X)), ['a', 'b', 'c']) def test_vars(self): def f(): @@ -182,8 +180,8 @@ x = xrange(0,33,2) self.assertEquals(x[7], 14) self.assertEquals(x[-7], 20) - self.assertRaises(IndexError, x.__getitem__, 16) - self.assertRaises(IndexError, x.__getitem__, -16) + self.assertRaises(IndexError, x.__getitem__, 17) + self.assertRaises(IndexError, x.__getitem__, -18) self.assertRaises(TypeError, x.__getitem__, slice(0,3,1)) def test_cmp(self): From alex at codespeak.net Mon Dec 22 01:12:11 2003 From: alex at codespeak.net (alex at codespeak.net) Date: Mon, 22 Dec 2003 01:12:11 +0100 (MET) Subject: [pypy-svn] rev 2669 - pypy/trunk/src/pypy/module Message-ID: <20031222001211.0F3875AAA7@thoth.codespeak.net> Author: alex Date: Mon Dec 22 01:12:10 2003 New Revision: 2669 Modified: pypy/trunk/src/pypy/module/builtin.py Log: added implementation of __getitem__ to xrange. Modified: pypy/trunk/src/pypy/module/builtin.py ============================================================================== --- pypy/trunk/src/pypy/module/builtin.py (original) +++ pypy/trunk/src/pypy/module/builtin.py Mon Dec 22 01:12:10 2003 @@ -753,6 +753,17 @@ self._len = 0 return self._len + def __getitem__(self, index): + # xrange does NOT support slicing + if not isinstance(index, int): + raise TypeError, "sequence index must be integer" + len = self.__len__() + if index<0: + index += len + if 0 <= index < len: + return self.start + index * self.step + raise IndexError, "xrange object index out of range" + def __iter__(self): def gen(self): start, stop, step = self.start, self.stop, self.step From alex at codespeak.net Mon Dec 22 01:17:45 2003 From: alex at codespeak.net (alex at codespeak.net) Date: Mon, 22 Dec 2003 01:17:45 +0100 (MET) Subject: [pypy-svn] rev 2670 - pypy/trunk/src/pypy/appspace Message-ID: <20031222001745.AD8D05AAA7@thoth.codespeak.net> Author: alex Date: Mon Dec 22 01:17:45 2003 New Revision: 2670 Modified: pypy/trunk/src/pypy/appspace/builtin_functions_test.py Log: edited to make max line length 80; commented out some unworkable tests; removed use of enumerate from test_zip to decouple the two issues (as is proper in _unit_ tests...). Modified: pypy/trunk/src/pypy/appspace/builtin_functions_test.py ============================================================================== --- pypy/trunk/src/pypy/appspace/builtin_functions_test.py (original) +++ pypy/trunk/src/pypy/appspace/builtin_functions_test.py Mon Dec 22 01:17:45 2003 @@ -14,13 +14,6 @@ import sys, cStringIO - if 0: - import warnings - warnings.filterwarnings("ignore", "hex../oct.. of negative int", - FutureWarning, __name__) - warnings.filterwarnings("ignore", "integer argument expected", - DeprecationWarning, "unittest") - class Squares: def __init__(self, max): @@ -110,6 +103,7 @@ b.BitBucket = BitBucket b.L = L + class BuiltinTest(test.AppTestCase): full_test = 1 @@ -164,9 +158,9 @@ 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. + # 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,), {}) self.assertRaises(TypeError, apply, id, (1,), {"foo": 1}) self.assertRaises(TypeError, apply) @@ -234,8 +228,10 @@ bom = '\xef\xbb\xbf' compile(bom + 'print 1\n', '', 'exec') self.assertRaises(TypeError, compile) - self.assertRaises(ValueError, compile, 'print 42\n', '', 'badmode') - self.assertRaises(ValueError, compile, 'print 42\n', '', 'single', 0xff) + self.assertRaises(ValueError, compile, + 'print 42\n', '', 'badmode') + self.assertRaises(ValueError, compile, + 'print 42\n', '', 'single', 0xff) if have_unicode: compile(unicode('print u"\xc3\xa5"\n', 'utf8'), '', 'exec') @@ -330,16 +326,29 @@ '\'' ''' + ''' 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): - self.assertEqual(filter(lambda c: 'a' <= c <= 'z', 'Hello World'), 'elloorld') - self.assertEqual(filter(None, [1, 'hello', [], [3], '', None, 9, 0]), [1, 'hello', [3], 9]) - self.assertEqual(filter(lambda x: x > 0, [1, -3, 9, 0, 2]), [1, 9, 2]) - self.assertEqual(filter(None, Squares(10)), [1, 4, 9, 16, 25, 36, 49, 64, 81]) - self.assertEqual(filter(lambda x: x%2, Squares(10)), [1, 9, 25, 49, 81]) + self.assertEqual(filter(lambda c: 'a' <= c <= 'z', 'Hello World'), + 'elloorld') + self.assertEqual(filter(None, [1, 'hello', [], [3], '', None, 9, 0]) + , [1, 'hello', [3], 9]) + self.assertEqual(filter(lambda x: x > 0, [1, -3, 9, 0, 2]), + [1, 9, 2]) + self.assertEqual(filter(None, Squares(10)), + [1, 4, 9, 16, 25, 36, 49, 64, 81]) + self.assertEqual(filter(lambda x: x%2, Squares(10)), + [1, 9, 25, 49, 81]) def identity(item): return 1 filter(identity, Squares(5)) self.assertRaises(TypeError, filter) + ''' XXX rest of test disabled as above explained class BadSeq(object): def __getitem__(self, index): if index<4: @@ -362,17 +371,20 @@ class badstr(str): def __getitem__(self, index): raise ValueError - self.assertRaises(ValueError, filter, lambda x: x >="3", badstr("1234")) + self.assertRaises(ValueError, filter, + lambda x: x >="3", badstr("1234")) class badstr2(str): def __getitem__(self, index): return 42 - self.assertRaises(TypeError, filter, lambda x: x >=42, badstr2("1234")) + self.assertRaises(TypeError, filter, + lambda x: x >=42, badstr2("1234")) class weirdstr(str): def __getitem__(self, index): return weirdstr(2*str.__getitem__(self, index)) - self.assertEqual(filter(lambda x: x>="33", weirdstr("1234")), "3344") + self.assertEqual(filter(lambda x: x>="33", weirdstr("1234")), + "3344") class shiftstr(str): def __getitem__(self, index): @@ -382,20 +394,24 @@ if have_unicode: # test bltinmodule.c::filterunicode() self.assertEqual(filter(None, unicode("12")), unicode("12")) - self.assertEqual(filter(lambda x: x>="3", unicode("1234")), unicode("34")) + self.assertEqual(filter(lambda x: x>="3", unicode("1234")), + unicode("34")) self.assertRaises(TypeError, filter, 42, unicode("12")) - self.assertRaises(ValueError, filter, lambda x: x >="3", badstr(unicode("1234"))) + self.assertRaises(ValueError, filter, lambda x: x >="3", + badstr(unicode("1234"))) class badunicode(unicode): def __getitem__(self, index): return 42 - self.assertRaises(TypeError, filter, lambda x: x >=42, badunicode("1234")) + self.assertRaises(TypeError, filter, lambda x: x >=42, + badunicode("1234")) class weirdunicode(unicode): def __getitem__(self, index): return weirdunicode(2*unicode.__getitem__(self, index)) self.assertEqual( - filter(lambda x: x>=unicode("33"), weirdunicode("1234")), unicode("3344")) + filter(lambda x: x>=unicode("33"), weirdunicode("1234")), + unicode("3344")) class shiftunicode(unicode): def __getitem__(self, index): @@ -440,6 +456,7 @@ outp = filter(func, cls(inp)) self.assertEqual(outp, exp) self.assert_(not isinstance(outp, cls)) + ''' def test_float(self): self.assertEqual(float(3.14), 3.14) @@ -448,7 +465,8 @@ self.assertEqual(float(" 3.14 "), 3.14) if have_unicode: self.assertEqual(float(unicode(" 3.14 ")), 3.14) - self.assertEqual(float(unicode(" \u0663.\u0661\u0664 ",'raw-unicode-escape')), 3.14) + self.assertEqual(float(unicode( + " \u0663.\u0661\u0664 ",'raw-unicode-escape')), 3.14) def test_getattr(self): import sys @@ -457,7 +475,8 @@ self.assertRaises(TypeError, getattr, sys, 1, "foo") self.assertRaises(TypeError, getattr) if have_unicode: - self.assertRaises(UnicodeError, getattr, sys, unichr(sys.maxunicode)) + self.assertRaises(UnicodeError, getattr, sys, + unichr(sys.maxunicode)) def test_hasattr(self): import sys @@ -465,7 +484,8 @@ self.assertRaises(TypeError, hasattr, sys, 1) self.assertRaises(TypeError, hasattr) if have_unicode: - self.assertRaises(UnicodeError, hasattr, sys, unichr(sys.maxunicode)) + self.assertRaises(UnicodeError, hasattr, sys, + unichr(sys.maxunicode)) def test_hash(self): hash(None) @@ -487,7 +507,6 @@ self.assertEqual(hex(-16L), '-0x10L') self.assertRaises(TypeError, hex, {}) - if 1: def test_id(self): id(None) id(1) @@ -530,7 +549,7 @@ s = `-1-sys.maxint` self.assertEqual(int(s)+1, -sys.maxint) # should return long - ''' XXX TODO: Longs not supported yet + ''' XXX TODO: Longs not well supported yet int(s[1:]) # should return long @@ -541,8 +560,8 @@ ''' # SF bug 434186: 0x80000000/2 != 0x80000000>>1. - # Worked by accident in Windows release build, but failed in debug build. - # Failed in all Linux builds. + # Worked by accident in Windows release build, but failed in + # debug build. Failed in all Linux builds. x = -1-sys.maxint self.assertEqual(x >> 1, x//2) @@ -569,7 +588,6 @@ s2 = s.swapcase().swapcase() self.assert_(intern(s2) is s) - if 0: def test_iter(self): self.assertRaises(TypeError, iter) self.assertRaises(TypeError, iter, 42, 42) @@ -628,6 +646,8 @@ def __len__(self): raise ValueError self.assertRaises(ValueError, len, BadSeq()) + + if 1: def test_list(self): self.assertEqual(list([]), []) @@ -640,6 +660,7 @@ self.assertEqual(list(''), []) self.assertEqual(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 @@ -656,7 +677,9 @@ # http://sources.redhat.com/ml/newlib/2002/msg00369.html self.assertRaises(MemoryError, list, xrange(sys.maxint // 2)) + ''' + ''' XXX TODO: disabled for now -- long not yet well supported def test_long(self): self.assertEqual(long(314), 314L) self.assertEqual(long(3.14), 3L) @@ -700,6 +723,7 @@ self.assertRaises(ValueError, long, '123\0') self.assertRaises(ValueError, long, '53', 40) self.assertRaises(TypeError, long, 1, 12) + ''' def test_map(self): self.assertEqual( @@ -964,6 +988,7 @@ self.assertRaises(OverflowError, range, -sys.maxint, sys.maxint) self.assertRaises(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') @@ -991,6 +1016,7 @@ sys.stdout = savestdout fp.close() unlink(TESTFN) + ''' def test_reduce(self): self.assertEqual(reduce(lambda x, y: x+y, ['a', 'b', 'c'], ''), 'abc') @@ -1192,9 +1218,10 @@ raise IndexError else: return i + s = SequenceWithoutALength() self.assertEqual( - zip(SequenceWithoutALength(), xrange(2**30)), - list(enumerate(range(5))) + zip(s, xrange(2**30)), + [(x,x) for x in s] ) class BadSeq: From alex at codespeak.net Mon Dec 22 01:37:33 2003 From: alex at codespeak.net (alex at codespeak.net) Date: Mon, 22 Dec 2003 01:37:33 +0100 (MET) Subject: [pypy-svn] rev 2671 - pypy/trunk/src/pypy/appspace Message-ID: <20031222003733.3D4615AAA7@thoth.codespeak.net> Author: alex Date: Mon Dec 22 01:37:32 2003 New Revision: 2671 Modified: pypy/trunk/src/pypy/appspace/builtin_functions_test.py Log: latest version -- currently, 8 errors on 44 tests Modified: pypy/trunk/src/pypy/appspace/builtin_functions_test.py ============================================================================== --- pypy/trunk/src/pypy/appspace/builtin_functions_test.py (original) +++ pypy/trunk/src/pypy/appspace/builtin_functions_test.py Mon Dec 22 01:37:32 2003 @@ -117,7 +117,7 @@ app2interp(app_init_globals).get_function(space)() self.__class__.fully_initialized = True - if 0: + if 1: def test_import(self): __import__('sys') __import__('time') From alex at codespeak.net Mon Dec 22 01:38:13 2003 From: alex at codespeak.net (alex at codespeak.net) Date: Mon, 22 Dec 2003 01:38:13 +0100 (MET) Subject: [pypy-svn] rev 2672 - pypy/trunk/src/pypy/objspace/std Message-ID: <20031222003813.93D525AAA7@thoth.codespeak.net> Author: alex Date: Mon Dec 22 01:38:12 2003 New Revision: 2672 Modified: pypy/trunk/src/pypy/objspace/std/multimethod.py pypy/trunk/src/pypy/objspace/std/objspace.py pypy/trunk/src/pypy/objspace/std/typeobject.py pypy/trunk/src/pypy/objspace/std/usertype.py Log: added some __repr__ methods to ease "debugging by print-statement insertion" Modified: pypy/trunk/src/pypy/objspace/std/multimethod.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/multimethod.py (original) +++ pypy/trunk/src/pypy/objspace/std/multimethod.py Mon Dec 22 01:38:12 2003 @@ -44,6 +44,9 @@ self.cache_table = {} self.cache_delegator_key = None + def __repr__(self): + return '<%s %s>' % (self.__class__.__name__, self.operatorsymbol) + def register(self, function, *types): functions = self.dispatch_table.setdefault(types, []) if function not in functions: @@ -256,6 +259,7 @@ self.extras = extras self.unbound_versions = {} + def __get__(self, space, cls=object): # cls is some W_xxxType if issubclass(cls, self.BASE_TYPE_OBJECT): return self.slice(cls).get(space) Modified: pypy/trunk/src/pypy/objspace/std/objspace.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/objspace.py (original) +++ pypy/trunk/src/pypy/objspace/std/objspace.py Mon Dec 22 01:38:12 2003 @@ -10,6 +10,11 @@ def __init__(w_self, space): w_self.space = space # XXX not sure this is ever used any more + def __repr__(self): + return '' % ( + self.__class__.__name__, + getattr(self, 'statictype', '') + ) class W_AbstractTypeObject(W_Object): "Do not use. For W_TypeObject only." Modified: pypy/trunk/src/pypy/objspace/std/typeobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/typeobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/typeobject.py Mon Dec 22 01:38:12 2003 @@ -19,6 +19,12 @@ W_Object.__init__(w_self, space) w_self.w_tpname = space.wrap(w_self.typename) + def __repr__(self): + return '' % ( + self.__class__.__name__, + getattr(self, 'statictype', '') + ) + def getbases(w_self): parents = w_self.staticbases if parents is None: Modified: pypy/trunk/src/pypy/objspace/std/usertype.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/usertype.py (original) +++ pypy/trunk/src/pypy/objspace/std/usertype.py Mon Dec 22 01:38:12 2003 @@ -53,6 +53,7 @@ # but we're documenting it here as there seems no better place!!! # The problem is actually that, currently, several types such as # int and float just cannot be CALLED -- this needs to be fixed soon. +# Note: currently (03-12-21) this appears to be fully & correctly fixed. def type_new__UserType_UserType(space, w_basetype, w_usertype, w_args, w_kwds): import typetype # XXX this uses the following algorithm: From alex at codespeak.net Mon Dec 22 01:46:23 2003 From: alex at codespeak.net (alex at codespeak.net) Date: Mon, 22 Dec 2003 01:46:23 +0100 (MET) Subject: [pypy-svn] rev 2673 - in pypy/trunk/src/pypy: . annotation annotation/testappspace appspace/compiler appspace/test interpreter interpreter/test module module/test objspace objspace/flow objspace/flow/test objspace/std objspace/std/attic objspace/std/test objspace/test tool tool/testdata translator translator/test translator/tool Message-ID: <20031222004623.099AA5AAA7@thoth.codespeak.net> Author: alex Date: Mon Dec 22 01:46:22 2003 New Revision: 2673 Modified: pypy/trunk/src/pypy/ (props changed) pypy/trunk/src/pypy/annotation/ (props changed) pypy/trunk/src/pypy/annotation/test/ (props changed) pypy/trunk/src/pypy/appspace/ (props changed) pypy/trunk/src/pypy/appspace/compiler/ (props changed) pypy/trunk/src/pypy/appspace/test/ (props changed) pypy/trunk/src/pypy/interpreter/ (props changed) pypy/trunk/src/pypy/interpreter/test/ (props changed) pypy/trunk/src/pypy/module/ (props changed) pypy/trunk/src/pypy/module/test/ (props changed) pypy/trunk/src/pypy/objspace/ (props changed) pypy/trunk/src/pypy/objspace/flow/ (props changed) pypy/trunk/src/pypy/objspace/flow/test/ (props changed) pypy/trunk/src/pypy/objspace/std/ (props changed) pypy/trunk/src/pypy/objspace/std/attic/ (props changed) pypy/trunk/src/pypy/objspace/std/test/ (props changed) pypy/trunk/src/pypy/objspace/test/ (props changed) pypy/trunk/src/pypy/tool/ (props changed) pypy/trunk/src/pypy/tool/testdata/ (props changed) pypy/trunk/src/pypy/translator/ (props changed) pypy/trunk/src/pypy/translator/test/ (props changed) pypy/trunk/src/pypy/translator/tool/ (props changed) Log: added *.pyo to the pre-existing *.pyc as the value of property svn:ignore From alex at codespeak.net Mon Dec 22 16:26:21 2003 From: alex at codespeak.net (alex at codespeak.net) Date: Mon, 22 Dec 2003 16:26:21 +0100 (MET) Subject: [pypy-svn] rev 2674 - pypy/trunk/doc Message-ID: <20031222152621.56CBF5AAA7@thoth.codespeak.net> Author: alex Date: Mon Dec 22 16:26:20 2003 New Revision: 2674 Modified: pypy/trunk/doc/architecture.txt Log: Lots of editing, mostly "copy-editing level" (typo fixes, removal of some passive forms, general enhancement of Englisg, etc). Modified: pypy/trunk/doc/architecture.txt ============================================================================== --- pypy/trunk/doc/architecture.txt (original) +++ pypy/trunk/doc/architecture.txt Mon Dec 22 16:26:20 2003 @@ -1,138 +1,146 @@ Overview on PyPy's current architecture (Dec. 2003) ==================================================== -The different parts of PyPy have always been under more or less -heavy refacting during our five one-week sprints in 2003. -However, the basic architecture remains rather simple and unchanged: -a plain interpreter reads and dispatches bytecodes, shuffling objects -around on the stack and between namespaces of which it knows almost -nothing. For any operation on an object it delegates to an so called -Object Space which performs modifications, creation and and destruction -of objects. Such objects are often refered to as application level -objects because they are the objects you naturally work with from -a python program. - +The various parts of PyPy have always been under more or less heavy +refactoring during our five one-week sprints in 2003. However, the +basic architecture remains rather simple and unchanged: a plain +*interpreter* reads and dispatches *bytecodes*, shuffling objects around +on the stack and between namespaces of which it knows almost nothing. +For any operation on an object, the interpreter delegates to an +so-called "Object Space", which performs modifications, creation and +destruction of objects. Such objects are often refered to as +*application-level objects*, because they are the objects you naturally +work with from a python program. + The Interpreter =============== -The interpreter accepts python code objects which it obtains by invoking -Python's builtin compiler (we have a way of constructing those code -objects from python code only but it's still not integrated). Code -objects are a nicely preprocessed structured representation of source -code and their main content is *Bytecode*. In addition code objects -also know how to create a *Frame* object which has the responsibility to -*interpret* a code object's bytecode. Each bytecode is implemented via -a python function which in turn will delegate operations on an -application's objects to an object space. +The interpreter handles python code objects. The interpreter can built +code objects from Python sources, when needed, by invoking Python's +builtin compiler (we also have a way of constructing those code objects +from python code only, but we have not integrated it yet). Code objects +are a nicely preprocessed, structured representation of source code, and +their main content is *bytecode*. In addition, code objects also know +how to create a *frame* object which has the responsibility to +*interpret* a code object's bytecode. Each bytecode is implemented by a +python function, which, in turn, delegates operations on +application-level objects to an object space. The Object Space ================ -The object space creates all objects and knows how to perform operations -on the objects. You may think of an object space as being a -library offering a fixed API, a set of *operations*, with -implementations that correspond to the known semantics of Python objects. -An example of an operation is *add*: add's implementations are e.g. responsible for -performing numeric addition if *add* works on numbers, concatenation when it -works on built-in sequences. - -All object space operations take and return "application level" objects. -There is only one minimal operation that allows the interpreter to gain -knowledge about the value of an application level object: *is_true()* which -will return a boolean interpreter level value. This is neccessary for -implementing e.g. if-statements (or rather their branching bytecodes). - -We currently have 4 working object spaces which can be plugged into the -interpreter. - -- The Trivial Object Space, which is basically delegating almost all operations - to the underlying CPython interpreter. It was and still is used to test our - interpreter. Though it is not essential it stays useful for testing and is - thus there to stay for some time. +The object space creates all objects and knows how to perform operations +on the objects. You may think of an object space as being a library +offering a fixed API, a set of *operations*, with implementations that +correspond to the known semantics of Python objects. An example of an +operation is *add*: add's implementations are, for example, responsible +for performing numeric addition when add works on numbers, concatenation +when add works on built-in sequences. + +All object-space operations take and return "application level" objects. +There is only one, very simple, object-space operation which allows the +interpreter to gain some knowledge about the value of an +application-level object: ``is_true()``, which returns a boolean +interpreter-level value. This is necessary to implement, for example, +if-statements (or rather, to be pedantic, to implement the +conditional-branching bytecodes into which if-statements get compiled). + +We currently have four working object spaces which can be plugged into +the interpreter: + +- The Trivial Object Space, which basically delegates almost all + operations to the underlying CPython interpreter. It was, and still + is, used to test our interpreter. Alhough it is not essential, it + remains useful for testing, and thus it is here to stay. - The Standard Object Space, which is an almost complete implementation - of the various Python objects. This is the main focus of this document, - since it is - together with the interpreter - the foundation of our - Python implementation. - -- the Flow Object Space which is used for transforming a python program - into a flow graph representation. It does this by "abstract interpretation" - which will be explained later. + of the various Python objects. This is the main focus of this + document, since the Standard Object Space, together with the + interpreter, is the foundation of our Python implementation. + +- the Flow Object Space, which transforms a python program into a + flow-graph representation. The Flow Object Space performs this + transformation task through "abstract interpretation", which we will + explain later in this document. -- the Trace Object Space which wraps the trivial or standard object - space in order to trace the execution of bytecodes, frames and +- the Trace Object Space, which wraps either the trivial or the standard + object space in order to trace the execution of bytecodes, frames and object space operations. The Standard Object Space ========================= -The Standard Object Space implements python's objects and types -and all operations between them. It is thus an essential -component in order to reach CPython comptability. - -The implementations of ints, floats, strings, dicts, lists etc. -all live in separate files and are bound together by a "multimethod" -mechanism. Multimethods allow a caller - most notably the interpreter - -to stay free from knowing anything about an object's implementation. -Thus multimethods implement a way of delegating to the right implementation -based on the passed in objects (which it previously created, anyway). -We will examine how the multimethod mechanism works through an example. - -We examine the add-operation of ``int`` and ``float`` objects and disregard -all other objects for the moment. There is one multimethod ``add`` that both -implementations of add(intimpl, intimpl) and add(floatimpl, floatimpl) -register with. - -If in our application program we have the expression ``2+3``, the -interpreter will create an application-level object containing the -value ``2`` and one containing the value ``3``. We will here talk about -them as ``W_Int(2)`` and ``W_Int(3)`` respectively. The interpreter then -calls the Standard Object Space with ``add(W_Int(2), W_Int(3))``. - -The Object Space then examines the objects passed in and delegates directly -to the add(intimpl, intimpl) function: since this is a "direct hit", the -multimethod can immediately dispatch the operation to the correct implementation -i.e., the one registered as the implementation for this signature. +The Standard Object Space implements python objects and types, and all +operations on them. It is thus an essential component in order to reach +CPython compatibility. + +The implementations of ints, floats, strings, dicts, lists, etc, all +live in separate files, and are bound together by a "multimethod" +mechanism. Multimethods allow a caller - most notably the interpreter - +to stay free from knowing anything about objects' implementations. Thus +multimethods implement a way of delegating to the right implementation +based on the passed in objects (objects previously created by the same +subsystem). We examine how the multimethod mechanism works through an +example. + +We consider the add-operation of ``int`` and ``float`` objects, and +disregard all other object types for the moment. There is one +multimethod ``add``, and both relevant implementations, ``add(intimpl, +intimpl)`` and ``add(floatimpl, floatimpl)``, *register* with that one +``add`` multimethod. + +When in our application program we have the expression ``2+3``, the +interpreter creates an application-level object containing the value +``2`` and one containing the value ``3``. We talk about them as +``W_Int(2)`` and ``W_Int(3)`` respectively. The interpreter then calls +the Standard Object Space with ``add(W_Int(2), W_Int(3))``. + +The Object Space then examines the objects passed in, and delegates +directly to the ``add(intimpl, intimpl)`` function: since this is a +"direct hit", the multimethod immediately dispatches the operation to +the correct implementation, i.e., the one registered as the +implementation for this signature. -If the multimethod doesn't have any registered functions for the -exact given signature, as would be the case for example for the expression +If the multimethod doesn't have any registered functions for the exact +given signature, as would be the case for example for the expression ``2+3.0``, the multimethod tests if it can use coercion to find a function with a signature that works. In this case we would coerce ``W_Int(2)`` to ``W_Float(2.0)`` in order to find a function in the multimethod that has a correct signature. Note that the multimethod -mechanism is still considered a major refactoring target as it is +mechanism is still considered a major refactoring target, since it is not easy to get it completly right, fast and accurate. Application-level and interpreter-level execution and objects ============================================================= -Since Python is used for implementing all of our code base there -is a crucial distinction to be aware of: interpreter level objects -and application level objects. The latter are the ones that you -deal with when you write normal python programs. Interpreter level -code, however, cannot invoke operations or access attributes from -our application-level objects. You will immediately recognize any -interpreter level code in PyPy because all variable and object names -start with a `w_` which indicates that they are wrapped/application -level values. - -To show the difference with an example: to sum the contents of two -variables ``a`` and ``b``, typical application-level code is ``a+b`` --- in sharp contrast, typical interpreter-level code is ``space.add(w_a, w_b)``, -where ``space`` is an instance of an object space and ``w_a`` and ``w_b`` -are typical names for the *wrapped* versions of the two variables. +Since Python is used for implementing all of our code base, there is a +crucial distinction to be aware of: *interpreter-level* objects versus +*application level* objects. The latter are the ones that you deal with +when you write normal python programs. Interpreter-level code, however, +cannot invoke operations nor access attributes from application-level +objects. You will immediately recognize any interpreter level code in +PyPy, because all variable and object names start with a ``w_``, which +indicates that they are "wrapped" application-level values. + +Let's show the difference with a simple example. To sum the contents of +two variables ``a`` and ``b``, typical application-level code is ``a+b`` +-- in sharp contrast, typical interpreter-level code is ``space.add(w_a, +w_b)``, where ``space`` is an instance of an object space, and ``w_a`` +and ``w_b`` are typical names for the *wrapped* versions of the two +variables. -It also helps to remember how CPython deals with the same issue: -interpreter level code is written in C and thus typical code for the +It helps to remember how CPython deals with the same issue: interpreter +level code, in CPython, is written in C, and thus typical code for the addition is ``PyNumber_Add(p_a, p_b)`` where ``p_a`` and ``p_b`` are C variables of type ``PyObject*``. This is very similar to how we write -our interpreter-level python code. +our interpreter-level code in Python. Moreover, in PyPy we have to make a sharp distinction between interpreter and application level *exceptions*: application exceptions -are always contained in an ``OperationError``. This makes it easy -to distinguish failures in our interpreter-level code from those -appearing in a python application level program. +are always contained inside an instance of ``OperationError``. This +makes it easy to distinguish failures in our interpreter-level code from +those appearing in a python application level program that we are +interpreting. Application level is often preferable @@ -142,7 +150,7 @@ write and debug. For example, suppose we want to implement the ``update`` method of dict objects. Programming at the application level, we can write the obvious, simple implementation, one that looks -like an **executable definition** of ``update``:: +like an **executable definition** of ``update``, for example:: def update(self, other): for k in other.keys(): @@ -160,18 +168,20 @@ w_value = space.getitem(w_other, w_key) space.setitem(w_self, w_key, w_value) -This interpreter-level implementation looks much more similar to the C source -code although it is probably still more readable. In any case, it should be -obvious that the application-level implementation is definitely more readable, -more elegant and maintainable than the interpreter-level one. - -In fact, in almost all parts of PyPy you will find application level code -in the middle of interpreter-level code. Apart from some bootstrapping -problems (application level functions need a certain initialization level -of the object space to be executed) application level code is usually -preferable. We have an abstraction (called 'Gateway') which allows the caller -of a function to stay ignorant whether a particular function is implemented -at application or interpreter level. +This interpreter-level implementation looks much more similar to the C +source code, although it is probably still more readable. In any case, +it should be obvious that the application-level implementation is +definitely more readable, more elegant and more maintainable than the +interpreter-level one. + +In fact, in almost all parts of PyPy, you find application level code in +the middle of interpreter-level code. Apart from some bootstrapping +problems (application level functions need a certain initialization +level of the object space before they can be executed), application +level code is usually preferable. We have an abstraction (called +'Gateway') which allows the caller of a function to remain ignorant of +whether a particular function is implemented at application or +interpreter level. Wrapping ======== @@ -200,57 +210,63 @@ RPython, the Flow Object Space and translation ============================================== -At last we want to translate our interpreter and standard object -space into a low level language. In order for our translation -and type inference mechanisms to work effectively we need to restrict -the dynamism of our interpreter-level Python code at some point. However, -we are completly free to do all kind of nice python constructs up to -using metaclasses and executing dynamically constructed strings. -When the initialization phase finishes (mainly ``objspace.initialize()``) -all involved code objects need to adhere to a (non-formally defined) more -static subset of Python: Restricted Python or 'RPython'. - -A so called Flow Object Space will then - with the help of our plain -interpreter - work through those initialized "RPython" code objects. -The result of this *abstract interpretation* is a flow graph: yet another -representation of a python program which is suitable for applying -translation and type inference techniques. The nodes of the graphs are -basic blocks consisting of Object Space operations, flowing of values -and an exitswitch to one, two or multiple links which connect it to -other basic blocks. +One of PyPy's longer-term objectives is to enable translation of our +interpreter and standard object space into a lower-level language. In +order for our translation and type inference mechanisms to work +effectively, we need to restrict the dynamism of our interpreter-level +Python code at some point. However, in the start-up phase, we are +completly free to use all kind of nice python constructs. including +metaclasses and execution of dynamically constructed strings. When the +initialization phase (mainly, the function ``objspace.initialize()``) +finishes, however, all code objects involved need to adhere to a +(non-formally defined) more static subset of Python: Restricted Python, +also known as 'RPython'. + +The Flow Object Space will then, with the help of our plain interpreter, +work through those initialized "RPython" code objects. The result of +this *abstract interpretation* is a flow graph: yet another +representation of a python program, but one which is suitable for +applying translation and type inference techniques. The nodes of the +graphs are basic blocks consisting of Object Space operations, flowing +of values and an exitswitch to one, two or multiple links which connect +it to other basic blocks. The flow graphs are fed as input to the Annotator. The Annotator, given entry point types, infers the types of values that flow through the -program variables. And here we have one of the informal definitions of -RPython: it's restricted in a way that the translator can still compile -low-level typed code. How much dynamism we allow in RPython depends and -is restricted by the Flow Object Space and the Annotator implementation. -The more we can improve this translation phase the more we can allow -dynamism. But in some cases it will probably more feasible to just get -rid of some dynamism we use in our interpreter level code. It is mainly -because of this trade-off situatio that we don't currently try to -formally define 'RPython'. - -The actual low-level code (or in fact also other high-level code) -is emitted by visiting the type-annotated flow graph. Currently -we have a Pyrex backend and a Lisp backend. We use (a slightly -hacked version of) Pyrex to generate C libraries. As Pyrex also -accepts plain non-typed python code we can test translation even -though it is not complete. +program variables. Here, one of the informal definitions of RPython +comes into play: RPython code is restricted in a way that the translator +can still compile low-level typed code. How much dynamism we allow in +RPython depends, and is restricted by, the Flow Object Space and the +Annotator implementation. The more we can improve this translation +phase, the more dynamism we can allow. In some cases, however, it will +probably be more feasible and practical to just get rid of some of the +dynamism we use in our interpreter level code. It is mainly because of +this trade-off situation that we don't currently try to formally define +'RPython'. + +The actual low-level code (and, in fact, also other high-level code) is +emitted by "visiting" the type-annotated flow graph. Currently, we have +a Pyrex-producing backend, and a Lisp-producing backend. We use (a +slightly hacked version of) Pyrex to generate C libraries. Since Pyrex +also accepts plain non-typed python code. we can test translation even +though type annotation is not complete. Trace Object Space ================== -A recent addition is the Trace Object space which allows to wrap -a standard and trivial object space in order to trace all object -space operations, frame creation, deletion and bytecode execution. -The ease with which the Trace Object Space could be implemented -at the Amsterdam Sprint underlines the power of the Object Space -abstraction. (Of course the formerly implemented Flow Object Space -producing the flow graph already was proof enough). - -There are certainly many more possibly useful Object Space ideas -like a ProxySpace that connects to a remote machine where the -actual operations are performed. At the other end, we wouldn't -need to change object spaces at all if we want to extend or modify -the interpreter by e.g. adding or removing some bytecodes. +A recent addition is the Trace Object space, which wraps a standard or +trivial object space in order to trace all object space operations, +frame creation, deletion and bytecode execution. The ease with which +the Trace Object Space was implemented at the Amsterdam Sprint +underlines the power of the Object Space abstraction. (Of course, the +previously-implemented Flow Object Space producing the flow graph +already was proof enough). + +There are certainly many more possibly useful Object Space ideas, such +as a ProxySpace that connects to a remote machine where the actual +operations are performed. At the other end, we wouldn't need to change +object spaces at all if we want to extend or modify the interpreter, +e.g. by adding or removing some bytecodes. Thus, the interpreter and +object-space cooperation nicely splits the python runtime into two +reasonably-independent halves, cooperating along a reasonably narrow +interface, and suitable for multiple separate implementations. From alex at codespeak.net Mon Dec 22 16:43:37 2003 From: alex at codespeak.net (alex at codespeak.net) Date: Mon, 22 Dec 2003 16:43:37 +0100 (MET) Subject: [pypy-svn] rev 2675 - pypy/trunk/doc Message-ID: <20031222154337.64D485AAA7@thoth.codespeak.net> Author: alex Date: Mon Dec 22 16:43:36 2003 New Revision: 2675 Modified: pypy/trunk/doc/architecture.txt Log: several more minor edits (typo fixes &c). Modified: pypy/trunk/doc/architecture.txt ============================================================================== --- pypy/trunk/doc/architecture.txt (original) +++ pypy/trunk/doc/architecture.txt Mon Dec 22 16:43:36 2003 @@ -6,8 +6,8 @@ basic architecture remains rather simple and unchanged: a plain *interpreter* reads and dispatches *bytecodes*, shuffling objects around on the stack and between namespaces of which it knows almost nothing. -For any operation on an object, the interpreter delegates to an -so-called "Object Space", which performs modifications, creation and +For any operation on an object, the interpreter delegates to a so-called +"Object Space", which performs creation, modification, access, and destruction of objects. Such objects are often refered to as *application-level objects*, because they are the objects you naturally work with from a python program. @@ -15,7 +15,7 @@ The Interpreter =============== -The interpreter handles python code objects. The interpreter can built +The interpreter handles python code objects. The interpreter can build code objects from Python sources, when needed, by invoking Python's builtin compiler (we also have a way of constructing those code objects from python code only, but we have not integrated it yet). Code objects @@ -89,11 +89,12 @@ intimpl)`` and ``add(floatimpl, floatimpl)``, *register* with that one ``add`` multimethod. -When in our application program we have the expression ``2+3``, the -interpreter creates an application-level object containing the value -``2`` and one containing the value ``3``. We talk about them as -``W_Int(2)`` and ``W_Int(3)`` respectively. The interpreter then calls -the Standard Object Space with ``add(W_Int(2), W_Int(3))``. +When we have the expression ``2+3`` in our application program, the +interpreter creates an application-level object containing ("wrapping") +the value ``2`` and another one containing the value ``3``. We talk +about them as ``W_Int(2)`` and ``W_Int(3)`` respectively. The +interpreter then calls the Standard Object Space with ``add(W_Int(2), +W_Int(3))``. The Object Space then examines the objects passed in, and delegates directly to the ``add(intimpl, intimpl)`` function: since this is a @@ -136,28 +137,29 @@ our interpreter-level code in Python. Moreover, in PyPy we have to make a sharp distinction between -interpreter and application level *exceptions*: application exceptions +interpreter- and application-level *exceptions*: application exceptions are always contained inside an instance of ``OperationError``. This makes it easy to distinguish failures in our interpreter-level code from -those appearing in a python application level program that we are +failures appearing in a python application level program that we are interpreting. Application level is often preferable ------------------------------------- -Application-level code is much higher-level, and therefore easier to -write and debug. For example, suppose we want to implement the -``update`` method of dict objects. Programming at the application -level, we can write the obvious, simple implementation, one that looks -like an **executable definition** of ``update``, for example:: +Application-level code is substantially higher-level, and therefore +correspondingly easier to write and debug. For example, suppose we want +to implement the ``update`` method of dict objects. Programming at +application level, we can write an obvious, simple implementation, one +that looks like an **executable definition** of ``update``, for +example:: def update(self, other): for k in other.keys(): self[k] = other[k] -If we had to code only at the interpreter level, we would have to -code something much lower-level and involved, say something like:: +If we had to code only at interpreter level, we would have to code +something much lower-level and involved, say something like:: def update(space, w_self, w_other): w_keys = space.call_method(w_other, 'keys') @@ -188,15 +190,15 @@ The ``w_`` prefixes so lavishly used in the previous example indicate, by PyPy coding convention, that we are dealing with *wrapped* objects, -that is, objects constructed by the object space at interpreter level to +that is, interpreter-level objects which the object space constructs to implement corresponding application-level objects. Each object space supplies ``wrap`` and ``unwrap`` operations that move between the two -levels for objects of simple built-in types; other Python types are -implemented by interpreter-level classes with some amount of internal -structure. +levels for objects of simple built-in types; each object space also +implements other Python types with suitable interpreter-level classes +with some amount of internal structure. For example, an application-level Python ``list`` is implemented as an -instance of ``W_ListObject```, which has an instance attribute +instance of ``W_ListObject``, which has an instance attribute ``ob_item`` (an interpreter-level list which contains the application-level list's items as wrapped objects) and another attribute ``ob_size`` which records the application-level list's length (we want @@ -210,45 +212,45 @@ RPython, the Flow Object Space and translation ============================================== -One of PyPy's longer-term objectives is to enable translation of our +One of PyPy's -term objectives is to enable translation of our interpreter and standard object space into a lower-level language. In order for our translation and type inference mechanisms to work effectively, we need to restrict the dynamism of our interpreter-level Python code at some point. However, in the start-up phase, we are -completly free to use all kind of nice python constructs. including -metaclasses and execution of dynamically constructed strings. When the -initialization phase (mainly, the function ``objspace.initialize()``) -finishes, however, all code objects involved need to adhere to a -(non-formally defined) more static subset of Python: Restricted Python, -also known as 'RPython'. +completly free to use all kind of nice python constructs, including +metaclasses and execution of dynamically constructed strings. However, +when the initialization phase (mainly, the function +``objspace.initialize()``) finishes, all code objects involved need to +adhere to a (non-formally defined) more static subset of Python: +Restricted Python, also known as 'RPython'. -The Flow Object Space will then, with the help of our plain interpreter, -work through those initialized "RPython" code objects. The result of +The Flow Object Space then, with the help of our plain interpreter, +works through those initialized "RPython" code objects. The result of this *abstract interpretation* is a flow graph: yet another representation of a python program, but one which is suitable for applying translation and type inference techniques. The nodes of the -graphs are basic blocks consisting of Object Space operations, flowing -of values and an exitswitch to one, two or multiple links which connect -it to other basic blocks. - -The flow graphs are fed as input to the Annotator. The Annotator, given -entry point types, infers the types of values that flow through the -program variables. Here, one of the informal definitions of RPython -comes into play: RPython code is restricted in a way that the translator -can still compile low-level typed code. How much dynamism we allow in -RPython depends, and is restricted by, the Flow Object Space and the -Annotator implementation. The more we can improve this translation -phase, the more dynamism we can allow. In some cases, however, it will -probably be more feasible and practical to just get rid of some of the -dynamism we use in our interpreter level code. It is mainly because of -this trade-off situation that we don't currently try to formally define -'RPython'. +graph are basic blocks consisting of Object Space operations, flowing +of values, and an exitswitch to one, two or multiple links which connect +each basic block to other basic blocks. + +The flow graphs are fed as input into the Annotator. The Annotator, +given entry point types, infers the types of values that flow through +the program variables. Here, one of the informal definitions of RPython +comes into play: RPython code is restricted in such a way that the +translator is able to compile low-level **typed** code. How much +dynamism we allow in RPython depends, and is restricted by, the Flow +Object Space and the Annotator implementation. The more we can improve +this translation phase, the more dynamism we can allow. In some cases, +however, it will probably be more feasible and practical to just get rid +of some of the dynamism we use in our interpreter level code. It is +mainly because of this trade-off situation that we don't currently try +to formally define 'RPython'. The actual low-level code (and, in fact, also other high-level code) is emitted by "visiting" the type-annotated flow graph. Currently, we have a Pyrex-producing backend, and a Lisp-producing backend. We use (a slightly hacked version of) Pyrex to generate C libraries. Since Pyrex -also accepts plain non-typed python code. we can test translation even +also accepts plain non-typed python code, we can test translation even though type annotation is not complete. Trace Object Space @@ -265,8 +267,8 @@ There are certainly many more possibly useful Object Space ideas, such as a ProxySpace that connects to a remote machine where the actual operations are performed. At the other end, we wouldn't need to change -object spaces at all if we want to extend or modify the interpreter, -e.g. by adding or removing some bytecodes. Thus, the interpreter and +object spaces at all in order to extend or modify the interpreter, e.g. +by adding or removing some bytecodes. Thus, the interpreter and object-space cooperation nicely splits the python runtime into two reasonably-independent halves, cooperating along a reasonably narrow interface, and suitable for multiple separate implementations. From alex at codespeak.net Mon Dec 22 16:50:27 2003 From: alex at codespeak.net (alex at codespeak.net) Date: Mon, 22 Dec 2003 16:50:27 +0100 (MET) Subject: [pypy-svn] rev 2676 - pypy/trunk/src/pypy/interpreter/test Message-ID: <20031222155027.920A85AA0B@thoth.codespeak.net> Author: alex Date: Mon Dec 22 16:50:26 2003 New Revision: 2676 Modified: pypy/trunk/src/pypy/interpreter/test/test_generator.py Log: added unit-test to show a bug in generators when a StopIteration propagates from something the generator call (typically a .next() call). Modified: pypy/trunk/src/pypy/interpreter/test/test_generator.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/test/test_generator.py (original) +++ pypy/trunk/src/pypy/interpreter/test/test_generator.py Mon Dec 22 16:50:26 2003 @@ -8,13 +8,13 @@ def f(): yield 1 self.assertEquals(f().next(), 1) - + def test_generator2(self): def f(): yield 1 g = f() self.assertEquals(g.next(), 1) - self.assertRaises(StopIteration, g.next) + self.assertRaises(StopIteration, g.next) def test_generator3(self): def f(): @@ -34,7 +34,14 @@ raise StopIteration g = f() self.assertEquals([x for x in g], [1]) - + + def test_generator_propagate_stopiteration(self): + def f(): + it = iter([1]) + while 1: yield it.next() + g = f() + self.assertEquals([x for x in g], [1]) + def test_generator_restart(self): def g(): i = me.next() From alex at codespeak.net Mon Dec 22 17:02:32 2003 From: alex at codespeak.net (alex at codespeak.net) Date: Mon, 22 Dec 2003 17:02:32 +0100 (MET) Subject: [pypy-svn] rev 2677 - pypy/trunk/src/pypy/interpreter Message-ID: <20031222160232.776585AA0B@thoth.codespeak.net> Author: alex Date: Mon Dec 22 17:02:31 2003 New Revision: 2677 Modified: pypy/trunk/src/pypy/interpreter/generator.py Log: fixed the bug w/generators and propagating StopIteration exceptions Modified: pypy/trunk/src/pypy/interpreter/generator.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/generator.py (original) +++ pypy/trunk/src/pypy/interpreter/generator.py Mon Dec 22 17:02:31 2003 @@ -64,7 +64,12 @@ raise NoValue self.running = True try: - return Frame.run(self.frame) + try: return Frame.run(self.frame) + except OperationError, e: + if e.w_type is self.space.w_StopIteration: + raise NoValue + else: + raise finally: self.running = False From alex at codespeak.net Mon Dec 22 17:09:25 2003 From: alex at codespeak.net (alex at codespeak.net) Date: Mon, 22 Dec 2003 17:09:25 +0100 (MET) Subject: [pypy-svn] rev 2678 - pypy/trunk/src/pypy/interpreter Message-ID: <20031222160925.19F215AA0B@thoth.codespeak.net> Author: alex Date: Mon Dec 22 17:09:24 2003 New Revision: 2678 Modified: pypy/trunk/src/pypy/interpreter/generator.py pypy/trunk/src/pypy/interpreter/pyopcode.py Log: removed the now-useles hook for generators raising StopIteration (the issue is now covered in a more general way in pypy_next). Modified: pypy/trunk/src/pypy/interpreter/generator.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/generator.py (original) +++ pypy/trunk/src/pypy/interpreter/generator.py Mon Dec 22 17:09:24 2003 @@ -35,13 +35,6 @@ raise SYieldValue(w_yieldedvalue) YIELD_STMT = YIELD_VALUE # misnamed in old versions of dis.opname - def _make_op_err(f, w_type, w_value): - # hook to let a "raise StopIteration" in a generator be a - # normal termination for that generator: - if w_type is f.space.w_StopIteration: - raise SGeneratorReturn() - else: - raise OperationError(w_type, w_value) class GeneratorIterator(object): "An iterator created by a generator." Modified: pypy/trunk/src/pypy/interpreter/pyopcode.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/pyopcode.py (original) +++ pypy/trunk/src/pypy/interpreter/pyopcode.py Mon Dec 22 17:09:24 2003 @@ -302,12 +302,6 @@ if nbargs >= 1: w_type = f.valuestack.pop() w_resulttuple = prepare_raise(f.space, w_type, w_value, w_traceback) w_type, w_value, w_traceback = f.space.unpacktuple(w_resulttuple, 3) - # XXX the three-arguments 'raise' is not supported yet - raise f._make_op_err(w_type, w_value) - - def _make_op_err(f, w_type, w_value): - # hook to let a "raise StopIteration" in a generator be a - # normal termination for that generator: raise OperationError(w_type, w_value) def LOAD_LOCALS(f): From alex at codespeak.net Mon Dec 22 17:39:56 2003 From: alex at codespeak.net (alex at codespeak.net) Date: Mon, 22 Dec 2003 17:39:56 +0100 (MET) Subject: [pypy-svn] rev 2679 - in pypy/trunk/src/pypy/objspace/std: . test Message-ID: <20031222163956.A0BFF5AA0B@thoth.codespeak.net> Author: alex Date: Mon Dec 22 17:39:55 2003 New Revision: 2679 Modified: pypy/trunk/src/pypy/objspace/std/floatobject.py pypy/trunk/src/pypy/objspace/std/test/test_floatobject.py Log: added test to show a bug (pow(-2.3,4.5) was not wrapping the exception) and fixed the bug. Modified: pypy/trunk/src/pypy/objspace/std/floatobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/floatobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/floatobject.py Mon Dec 22 17:39:55 2003 @@ -223,6 +223,9 @@ z = x ** y except OverflowError: raise FailedToImplement(space.w_OverflowError, space.wrap("float power")) + except ValueError, e: + raise FailedToImplement(space.w_ValueError, space.wrap(str(e))) + return W_FloatObject(space, z) def neg__Float(space, w_float1): Modified: pypy/trunk/src/pypy/objspace/std/test/test_floatobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/test/test_floatobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/test/test_floatobject.py Mon Dec 22 17:39:55 2003 @@ -27,7 +27,8 @@ f2 = fobj.W_FloatObject(self.space, y) f3 = fobj.W_FloatObject(self.space, z) self.assertEquals(self.space.w_TypeError, - self._unwrap_nonimpl(fobj.pow__Float_Float_ANY, self.space, f1, f2, f3)) + self._unwrap_nonimpl(fobj.pow__Float_Float_ANY, + self.space, f1, f2, f3)) def test_pow_ffn(self): x = 10.0 @@ -36,6 +37,12 @@ f2 = fobj.W_FloatObject(self.space, y) v = fobj.pow__Float_Float_ANY(self.space, f1, f2, self.space.w_None) self.assertEquals(v.floatval, x ** y) + f1 = fobj.W_FloatObject(self.space, -1.23) + f2 = fobj.W_FloatObject(self.space, -4.56) + self.assertEquals(self.space.w_ValueError, + self._unwrap_nonimpl(fobj.pow__Float_Float_ANY, + self.space, f1, f2, + self.space.w_None)) class AppFloatTest(test.AppTestCase): def setUp(self): From alex at codespeak.net Mon Dec 22 22:38:03 2003 From: alex at codespeak.net (alex at codespeak.net) Date: Mon, 22 Dec 2003 22:38:03 +0100 (MET) Subject: [pypy-svn] rev 2680 - pypy/trunk/src/pypy/appspace Message-ID: <20031222213803.1FF725AA0B@thoth.codespeak.net> Author: alex Date: Mon Dec 22 22:38:01 2003 New Revision: 2680 Modified: pypy/trunk/src/pypy/appspace/builtin_functions_test.py Log: "Ran 43 tests in 162.555s" (out of 50 tests in the original, which CPython 2.3 runs in about 0.1s on the same machine), with several limitations &c as seen in TODO and XXX comments/docstrings here. Still, about 80% the unit-tests, and roughly a 1:2000 speed ratio, isn't THAT terrible after all... (btw, this same machine has about 2 pystones/sec with pypy, 25,000 with CPython). Modified: pypy/trunk/src/pypy/appspace/builtin_functions_test.py ============================================================================== --- pypy/trunk/src/pypy/appspace/builtin_functions_test.py (original) +++ pypy/trunk/src/pypy/appspace/builtin_functions_test.py Mon Dec 22 22:38:01 2003 @@ -4,24 +4,25 @@ from pypy.interpreter.gateway import app2interp 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) @@ -31,14 +32,14 @@ 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 @@ -116,7 +117,10 @@ app2interp(app_init_globals).get_function(space)() self.__class__.fully_initialized = True - + + # 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') @@ -140,7 +144,7 @@ self.assertEqual(abs(-1234L), 1234L) # str self.assertRaises(TypeError, abs, 'a') - + def test_apply(self): def f0(*args): self.assertEqual(args, ()) @@ -157,7 +161,7 @@ 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. @@ -166,7 +170,7 @@ self.assertRaises(TypeError, apply) self.assertRaises(TypeError, apply, id, 42) self.assertRaises(TypeError, apply, id, (42,), 42) - + def test_callable(self): self.assert_(callable(len)) def f(): pass @@ -182,7 +186,7 @@ y = D() self.assert_(callable(y)) y() - + def test_chr(self): self.assertEqual(chr(32), ' ') self.assertEqual(chr(65), 'A') @@ -190,7 +194,7 @@ self.assertEqual(chr(0xff), '\xff') self.assertRaises(ValueError, chr, 256) self.assertRaises(TypeError, chr) - + def test_cmp(self): self.assertEqual(cmp(-1, 1), -1) self.assertEqual(cmp(1, -1), 1) @@ -240,38 +244,38 @@ sys.spam = 1 delattr(sys, 'spam') self.assertRaises(TypeError, delattr) - + def test_dir(self): x = 1 self.assert_('x' in dir()) import sys self.assert_('modules' in dir(sys)) self.assertRaises(TypeError, dir, 42, 42) - + def test_divmod(self): self.assertEqual(divmod(12, 7), (1, 5)) self.assertEqual(divmod(-12, 7), (-2, 2)) self.assertEqual(divmod(12, -7), (-2, -2)) self.assertEqual(divmod(-12, -7), (1, -5)) - + self.assertEqual(divmod(12L, 7L), (1L, 5L)) self.assertEqual(divmod(-12L, 7L), (-2L, 2L)) self.assertEqual(divmod(12L, -7L), (-2L, -2L)) self.assertEqual(divmod(-12L, -7L), (1L, -5L)) - + self.assertEqual(divmod(12, 7L), (1, 5L)) self.assertEqual(divmod(-12, 7L), (-2, 2L)) self.assertEqual(divmod(12L, -7), (-2L, -2)) self.assertEqual(divmod(-12L, -7), (1L, -5)) - + self.assert_(not fcmp(divmod(3.25, 1.0), (3.0, 0.25))) self.assert_(not fcmp(divmod(-3.25, 1.0), (-4.0, 0.75))) self.assert_(not fcmp(divmod(3.25, -1.0), (-4.0, -0.75))) self.assert_(not fcmp(divmod(-3.25, -1.0), (3.0, -0.25))) - + self.assertRaises(TypeError, divmod) - ''' XXX TODO No eval() support yet + ''' XXX TODO No eval() support yet def test_eval(self): self.assertEqual(eval('1+1'), 2) self.assertEqual(eval(' 1+1\n'), 2) @@ -297,7 +301,7 @@ unicode('\xc3\xa5', 'utf8')) self.assertRaises(TypeError, eval) self.assertRaises(TypeError, eval, ()) - + '\'' XXX TODO: Figure out later # Done outside of the method test_z to get the correct scope z = 0 @@ -306,11 +310,11 @@ f.write('z = z*2\n') f.close() execfile(TESTFN) - + def test_execfile(self): globals = {'a': 1, 'b': 2} locals = {'b': 200, 'c': 300} - + self.assertEqual(self.__class__.z, 2) globals['z'] = 0 execfile(TESTFN, globals) @@ -325,7 +329,7 @@ self.assertRaises(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 @@ -358,12 +362,12 @@ def badfunc(): pass self.assertRaises(TypeError, filter, badfunc, range(5)) - + # test bltinmodule.c::filtertuple() self.assertEqual(filter(None, (1, 2)), (1, 2)) self.assertEqual(filter(lambda x: x>=3, (1, 2, 3, 4)), (3, 4)) self.assertRaises(TypeError, filter, 42, (1, 2)) - + # test bltinmodule.c::filterstring() self.assertEqual(filter(None, "12"), "12") self.assertEqual(filter(lambda x: x>="3", "1234"), "34") @@ -373,24 +377,24 @@ raise ValueError self.assertRaises(ValueError, filter, lambda x: x >="3", badstr("1234")) - + class badstr2(str): def __getitem__(self, index): return 42 self.assertRaises(TypeError, filter, lambda x: x >=42, badstr2("1234")) - + class weirdstr(str): def __getitem__(self, index): return weirdstr(2*str.__getitem__(self, index)) self.assertEqual(filter(lambda x: x>="33", weirdstr("1234")), "3344") - + class shiftstr(str): def __getitem__(self, index): return chr(ord(str.__getitem__(self, index))+1) self.assertEqual(filter(lambda x: x>="3", shiftstr("1234")), "345") - + if have_unicode: # test bltinmodule.c::filterunicode() self.assertEqual(filter(None, unicode("12")), unicode("12")) @@ -399,20 +403,20 @@ self.assertRaises(TypeError, filter, 42, unicode("12")) self.assertRaises(ValueError, filter, lambda x: x >="3", badstr(unicode("1234"))) - + class badunicode(unicode): def __getitem__(self, index): return 42 self.assertRaises(TypeError, filter, lambda x: x >=42, badunicode("1234")) - + class weirdunicode(unicode): def __getitem__(self, index): return weirdunicode(2*unicode.__getitem__(self, index)) self.assertEqual( 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) @@ -420,7 +424,7 @@ 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__ @@ -443,7 +447,7 @@ 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__ @@ -457,7 +461,7 @@ self.assertEqual(outp, exp) self.assert_(not isinstance(outp, cls)) ''' - + def test_float(self): self.assertEqual(float(3.14), 3.14) self.assertEqual(float(314), 314.0) @@ -467,7 +471,7 @@ self.assertEqual(float(unicode(" 3.14 ")), 3.14) self.assertEqual(float(unicode( " \u0663.\u0661\u0664 ",'raw-unicode-escape')), 3.14) - + def test_getattr(self): import sys self.assert_(getattr(sys, 'stdout') is sys.stdout) @@ -477,7 +481,7 @@ if have_unicode: self.assertRaises(UnicodeError, getattr, sys, unichr(sys.maxunicode)) - + def test_hasattr(self): import sys self.assert_(hasattr(sys, 'stdout')) @@ -486,7 +490,7 @@ if have_unicode: self.assertRaises(UnicodeError, hasattr, sys, unichr(sys.maxunicode)) - + def test_hash(self): hash(None) self.assertEqual(hash(1), hash(1L)) @@ -498,7 +502,7 @@ def f(): pass self.assertRaises(TypeError, hash, []) self.assertRaises(TypeError, hash, {}) - + def test_hex(self): self.assertEqual(hex(16), '0x10') self.assertEqual(hex(16L), '0x10L') @@ -506,7 +510,7 @@ self.assert_(hex(-16) in ('0xfffffff0', '0xfffffffffffffff0')) self.assertEqual(hex(-16L), '-0x10L') self.assertRaises(TypeError, hex, {}) - + def test_id(self): id(None) id(1) @@ -516,9 +520,9 @@ 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): self.assertEqual(int(314), 314) self.assertEqual(int(3.14), 3) @@ -545,49 +549,49 @@ self.assertEqual(int(ss), vv) except v: pass - + s = `-1-sys.maxint` self.assertEqual(int(s)+1, -sys.maxint) # should return long ''' XXX TODO: Longs not well supported yet int(s[1:]) - + # should return long x = int(1e100) self.assert_(isinstance(x, long)) x = int(-1e100) self.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 self.assertEqual(x >> 1, x//2) - + self.assertRaises(ValueError, int, '123\0') self.assertRaises(ValueError, int, '53', 40) - + ''' XXX TODO: Longs not supported yet x = int('1' * 600) self.assert_(isinstance(x, long)) - + if have_unicode: x = int(unichr(0x661) * 600) self.assert_(isinstance(x, long)) - + self.assertRaises(TypeError, int, 1, 12) ''' - + self.assertEqual(int('0123', 0), 83) - + def test_intern(self): self.assertRaises(TypeError, intern) s = "never interned before" self.assert_(intern(s) is s) s2 = s.swapcase().swapcase() self.assert_(intern(s2) is s) - + def test_iter(self): self.assertRaises(TypeError, iter) self.assertRaises(TypeError, iter, 42, 42) @@ -599,7 +603,7 @@ self.assertEqual(i.next(), '1') self.assertEqual(i.next(), '2') self.assertRaises(StopIteration, i.next) - + def test_isinstance(self): class C: pass @@ -617,7 +621,7 @@ self.assert_(not isinstance('foo', E)) self.assertRaises(TypeError, isinstance, E, 'foo') self.assertRaises(TypeError, isinstance) - + def test_issubclass(self): class C: pass @@ -634,7 +638,7 @@ self.assertRaises(TypeError, issubclass, 'foo', E) self.assertRaises(TypeError, issubclass, E, 'foo') self.assertRaises(TypeError, issubclass) - + def test_len(self): self.assertEqual(len('123'), 3) self.assertEqual(len(()), 0) @@ -648,7 +652,7 @@ self.assertRaises(ValueError, len, BadSeq()) if 1: - + def test_list(self): self.assertEqual(list([]), []) l0_3 = [0, 1, 2, 3] @@ -659,7 +663,7 @@ self.assertEqual(list((0, 1, 2, 3)), [0, 1, 2, 3]) self.assertEqual(list(''), []) self.assertEqual(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. @@ -674,11 +678,11 @@ # 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 self.assertRaises(MemoryError, list, xrange(sys.maxint // 2)) ''' - + ''' XXX TODO: disabled for now -- long not yet well supported def test_long(self): self.assertEqual(long(314), 314L) @@ -719,12 +723,12 @@ self.assertEqual(long(ss), long(vv)) except v: pass - + self.assertRaises(ValueError, long, '123\0') self.assertRaises(ValueError, long, '53', 40) self.assertRaises(TypeError, long, 1, 12) ''' - + def test_map(self): self.assertEqual( map(None, 'hello world'), @@ -755,7 +759,7 @@ 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 @@ -795,27 +799,27 @@ def __getitem__(self, index): raise ValueError self.assertRaises(ValueError, map, lambda x: x, BadSeq()) - + def test_max(self): self.assertEqual(max('123123'), '3') self.assertEqual(max(1, 2, 3), 3) self.assertEqual(max((1, 2, 3, 1, 2, 3)), 3) self.assertEqual(max([1, 2, 3, 1, 2, 3]), 3) - + self.assertEqual(max(1, 2L, 3.0), 3.0) self.assertEqual(max(1L, 2.0, 3), 3) self.assertEqual(max(1.0, 2, 3L), 3L) - + def test_min(self): self.assertEqual(min('123123'), '1') self.assertEqual(min(1, 2, 3), 1) self.assertEqual(min((1, 2, 3, 1, 2, 3)), 1) self.assertEqual(min([1, 2, 3, 1, 2, 3]), 1) - + self.assertEqual(min(1, 2L, 3.0), 1) self.assertEqual(min(1L, 2.0, 3), 1L) self.assertEqual(min(1.0, 2, 3L), 1.0) - + self.assertRaises(TypeError, min) self.assertRaises(TypeError, min, 42) self.assertRaises(ValueError, min, ()) @@ -823,34 +827,36 @@ def __getitem__(self, index): raise ValueError self.assertRaises(ValueError, min, BadSeq()) + ''' XXX TODO: some weird bug in pypy here -- fix later class BadNumber: def __cmp__(self, other): raise ValueError self.assertRaises(ValueError, min, (42, BadNumber())) - + ''' + def test_oct(self): self.assertEqual(oct(100), '0144') self.assertEqual(oct(100L), '0144L') self.assert_(oct(-100) in ('037777777634', '01777777777777777777634')) self.assertEqual(oct(-100L), '-0144L') self.assertRaises(TypeError, oct, ()) - - def write_testfile(self): - # 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() - + + def test_open(self): - self.write_testfile() + 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: self.assertEqual(fp.readline(4), '1+1\n') @@ -863,62 +869,62 @@ finally: fp.close() unlink(TESTFN) - + def test_ord(self): self.assertEqual(ord(' '), 32) self.assertEqual(ord('A'), 65) self.assertEqual(ord('a'), 97) + self.assertRaises(TypeError, ord, 42) if have_unicode: self.assertEqual(ord(unichr(sys.maxunicode)), sys.maxunicode) - self.assertRaises(TypeError, ord, 42) - self.assertRaises(TypeError, ord, unicode("12")) - + self.assertRaises(TypeError, ord, unicode("12")) + def test_pow(self): self.assertEqual(pow(0,0), 1) self.assertEqual(pow(0,1), 0) self.assertEqual(pow(1,0), 1) self.assertEqual(pow(1,1), 1) - + self.assertEqual(pow(2,0), 1) self.assertEqual(pow(2,10), 1024) self.assertEqual(pow(2,20), 1024*1024) self.assertEqual(pow(2,30), 1024*1024*1024) - + self.assertEqual(pow(-2,0), 1) self.assertEqual(pow(-2,1), -2) self.assertEqual(pow(-2,2), 4) self.assertEqual(pow(-2,3), -8) - + self.assertEqual(pow(0L,0), 1) self.assertEqual(pow(0L,1), 0) self.assertEqual(pow(1L,0), 1) self.assertEqual(pow(1L,1), 1) - + self.assertEqual(pow(2L,0), 1) self.assertEqual(pow(2L,10), 1024) self.assertEqual(pow(2L,20), 1024*1024) self.assertEqual(pow(2L,30), 1024*1024*1024) - + self.assertEqual(pow(-2L,0), 1) self.assertEqual(pow(-2L,1), -2) self.assertEqual(pow(-2L,2), 4) self.assertEqual(pow(-2L,3), -8) - + self.assertAlmostEqual(pow(0.,0), 1.) self.assertAlmostEqual(pow(0.,1), 0.) self.assertAlmostEqual(pow(1.,0), 1.) self.assertAlmostEqual(pow(1.,1), 1.) - + self.assertAlmostEqual(pow(2.,0), 1.) self.assertAlmostEqual(pow(2.,10), 1024.) self.assertAlmostEqual(pow(2.,20), 1024.*1024.) self.assertAlmostEqual(pow(2.,30), 1024.*1024.*1024.) - + self.assertAlmostEqual(pow(-2.,0), 1.) self.assertAlmostEqual(pow(-2.,1), -2.) self.assertAlmostEqual(pow(-2.,2), 4.) self.assertAlmostEqual(pow(-2.,3), -8.) - + for x in 2, 2L, 2.0: for y in 10, 10L, 10.0: for z in 1000, 1000L, 1000.0: @@ -928,15 +934,15 @@ self.assertRaises(TypeError, pow, x, y, z) else: self.assertAlmostEqual(pow(x, y, z), 24.0) - + self.assertRaises(TypeError, pow, -1, -2, 3) self.assertRaises(ValueError, pow, 1, 2, 0) self.assertRaises(TypeError, pow, -1L, -2L, 3L) self.assertRaises(ValueError, pow, 1L, 2L, 0L) self.assertRaises(ValueError, pow, -342.43, 0.234) - + self.assertRaises(TypeError, pow) - + def test_range(self): self.assertEqual(range(3), [0, 1, 2]) self.assertEqual(range(1, 5), [1, 2, 3, 4]) @@ -944,50 +950,50 @@ self.assertEqual(range(-3), []) self.assertEqual(range(1, 10, 3), [1, 4, 7]) self.assertEqual(range(5, -5, -3), [5, 2, -1, -4]) - + # Now test range() with longs self.assertEqual(range(-2**100), []) self.assertEqual(range(0, -2**100), []) self.assertEqual(range(0, 2**100, -1), []) self.assertEqual(range(0, 2**100, -1), []) - + a = long(10 * sys.maxint) b = long(100 * sys.maxint) c = long(50 * sys.maxint) - + self.assertEqual(range(a, a+2), [a, a+1]) self.assertEqual(range(a+2, a, -1L), [a+2, a+1]) self.assertEqual(range(a+4, a, -2), [a+4, a+2]) - + seq = range(a, b, c) self.assert_(a in seq) self.assert_(b not in seq) self.assertEqual(len(seq), 2) - + seq = range(b, a, -c) self.assert_(b in seq) self.assert_(a not in seq) self.assertEqual(len(seq), 2) - + seq = range(-a, -b, -c) self.assert_(-a in seq) self.assert_(-b not in seq) self.assertEqual(len(seq), 2) - + self.assertRaises(TypeError, range) self.assertRaises(TypeError, range, 1, 2, 3, 4) self.assertRaises(ValueError, range, 1, 2, 0) - + # Reject floats when it would require PyLongs to represent. # (smaller floats still accepted, but deprecated) self.assertRaises(TypeError, range, 1e100, 1e101, 1e101) - + self.assertRaises(TypeError, range, 0, "spam") self.assertRaises(TypeError, range, 0, 42, "spam") - + self.assertRaises(OverflowError, range, -sys.maxint, sys.maxint) self.assertRaises(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() @@ -1017,7 +1023,7 @@ fp.close() unlink(TESTFN) ''' - + def test_reduce(self): self.assertEqual(reduce(lambda x, y: x+y, ['a', 'b', 'c'], ''), 'abc') self.assertEqual( @@ -1038,20 +1044,22 @@ self.assertEqual(reduce(42, "1"), "1") # func is never called with one item self.assertEqual(reduce(42, "", "1"), "1") # func is never called with one item self.assertRaises(TypeError, reduce, 42, (42, 42)) - + class BadSeq: def __getitem__(self, index): raise ValueError self.assertRaises(ValueError, reduce, 42, BadSeq()) - + + ''' XXX TODO: we don't have reload yet def test_reload(self): - import marshal - reload(marshal) + import sys + reload(sys) import string reload(string) ## import sys ## self.assertRaises(ImportError, reload, sys) - + ''' + def test_repr(self): self.assertEqual(repr(''), '\'\'') self.assertEqual(repr(0), '0') @@ -1059,52 +1067,54 @@ self.assertEqual(repr(()), '()') self.assertEqual(repr([]), '[]') self.assertEqual(repr({}), '{}') + ''' XXX TODO: we don't yet support "circular" objects! a = [] a.append(a) self.assertEqual(repr(a), '[[...]]') a = {} a[0] = a self.assertEqual(repr(a), '{0: {...}}') - + ''' + def test_round(self): self.assertEqual(round(0.0), 0.0) self.assertEqual(round(1.0), 1.0) self.assertEqual(round(10.0), 10.0) self.assertEqual(round(1000000000.0), 1000000000.0) self.assertEqual(round(1e20), 1e20) - + self.assertEqual(round(-1.0), -1.0) self.assertEqual(round(-10.0), -10.0) self.assertEqual(round(-1000000000.0), -1000000000.0) self.assertEqual(round(-1e20), -1e20) - + self.assertEqual(round(0.1), 0.0) self.assertEqual(round(1.1), 1.0) self.assertEqual(round(10.1), 10.0) self.assertEqual(round(1000000000.1), 1000000000.0) - + self.assertEqual(round(-1.1), -1.0) self.assertEqual(round(-10.1), -10.0) self.assertEqual(round(-1000000000.1), -1000000000.0) - + self.assertEqual(round(0.9), 1.0) self.assertEqual(round(9.9), 10.0) self.assertEqual(round(999999999.9), 1000000000.0) - + self.assertEqual(round(-0.9), -1.0) self.assertEqual(round(-9.9), -10.0) self.assertEqual(round(-999999999.9), -1000000000.0) - + self.assertEqual(round(-8.0, -1), -10.0) - + self.assertRaises(TypeError, round) - + def test_setattr(self): setattr(sys, 'spam', 1) self.assertEqual(sys.spam, 1) self.assertRaises(TypeError, setattr, sys, 1, 'spam') self.assertRaises(TypeError, setattr) - + def test_str(self): self.assertEqual(str(''), '') self.assertEqual(str(0), '0') @@ -1112,13 +1122,15 @@ self.assertEqual(str(()), '()') self.assertEqual(str([]), '[]') self.assertEqual(str({}), '{}') + ''' XXX TODO: we don't yet support "circular" objects! a = [] a.append(a) self.assertEqual(str(a), '[[...]]') a = {} a[0] = a self.assertEqual(str(a), '{0: {...}}') - + ''' + def test_sum(self): self.assertEqual(sum([]), 0) self.assertEqual(sum(range(2,8)), 27) @@ -1126,7 +1138,7 @@ self.assertEqual(sum(Squares(10)), 285) self.assertEqual(sum(iter(Squares(10))), 285) self.assertEqual(sum([[1], [2], [3]], []), [1, 2, 3]) - + self.assertRaises(TypeError, sum) self.assertRaises(TypeError, sum, 42) self.assertRaises(TypeError, sum, ['a', 'b', 'c']) @@ -1134,12 +1146,12 @@ self.assertRaises(TypeError, sum, [[1], [2], [3]]) self.assertRaises(TypeError, sum, [{2:3}]) self.assertRaises(TypeError, sum, [{2:3}]*2, {2:3}) - + class BadSeq: def __getitem__(self, index): raise ValueError self.assertRaises(ValueError, sum, BadSeq()) - + def test_tuple(self): self.assertEqual(tuple(()), ()) t0_3 = (0, 1, 2, 3) @@ -1151,11 +1163,11 @@ self.assertEqual(tuple([0, 1, 2, 3]), (0, 1, 2, 3)) self.assertEqual(tuple(''), ()) self.assertEqual(tuple('spam'), ('s', 'p', 'a', 'm')) - + def test_type(self): self.assertEqual(type(''), type('123')) self.assertNotEqual(type(''), type(())) - + def test_unichr(self): if have_unicode: self.assertEqual(unichr(32), unicode(' ')) @@ -1167,28 +1179,25 @@ ) self.assertRaises(ValueError, unichr, sys.maxunicode+1) self.assertRaises(TypeError, unichr) - - def get_vars_f0(): - return vars() - # we don't want self in vars(), so use staticmethod - get_vars_f0 = staticmethod(get_vars_f0) - - def get_vars_f2(): - BuiltinTest.get_vars_f0() - a = 1 - b = 2 - return vars() - get_vars_f2 = staticmethod(get_vars_f2) - + def test_vars(self): + def get_vars_f0(): + return vars() + def get_vars_f2(): + get_vars_f0() + a = 1 + b = 2 + return vars() self.assertEqual(Set(vars()), Set(dir())) import sys self.assertEqual(Set(vars(sys)), Set(dir(sys))) - self.assertEqual(self.get_vars_f0(), {}) - self.assertEqual(self.get_vars_f2(), {'a': 1, 'b': 2}) + self.assertEqual(get_vars_f0(), {}) + ''' XXX TODO: known bug: free-var 'get_vars_0' ``leaks`` + self.assertEqual(get_vars_f2(), {'a': 1, 'b': 2}) + ''' self.assertRaises(TypeError, vars, 42, 42) self.assertRaises(TypeError, vars, 42) - + def test_zip(self): a = (1, 2, 3) b = (4, 5, 6) @@ -1208,7 +1217,7 @@ class G: pass self.assertRaises(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. @@ -1223,7 +1232,7 @@ zip(s, xrange(2**30)), [(x,x) for x in s] ) - + class BadSeq: def __getitem__(self, i): if i == 5: From arigo at codespeak.net Tue Dec 23 12:40:16 2003 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 23 Dec 2003 12:40:16 +0100 (MET) Subject: [pypy-svn] rev 2681 - pypy/trunk/src/pypy/interpreter Message-ID: <20031223114016.81D7A5AA0B@thoth.codespeak.net> Author: arigo Date: Tue Dec 23 12:40:15 2003 New Revision: 2681 Modified: pypy/trunk/src/pypy/interpreter/generator.py pypy/trunk/src/pypy/interpreter/pyopcode.py Log: "raise StopIteration" in generators: M interpreter/generator.py Must use "e.match()" to check for exception match. M interpreter/pyopcode.py Restored XXX comment. Modified: pypy/trunk/src/pypy/interpreter/generator.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/generator.py (original) +++ pypy/trunk/src/pypy/interpreter/generator.py Tue Dec 23 12:40:15 2003 @@ -59,7 +59,7 @@ try: try: return Frame.run(self.frame) except OperationError, e: - if e.w_type is self.space.w_StopIteration: + if e.match(self.space, self.space.w_StopIteration): raise NoValue else: raise Modified: pypy/trunk/src/pypy/interpreter/pyopcode.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/pyopcode.py (original) +++ pypy/trunk/src/pypy/interpreter/pyopcode.py Tue Dec 23 12:40:15 2003 @@ -302,6 +302,7 @@ if nbargs >= 1: w_type = f.valuestack.pop() w_resulttuple = prepare_raise(f.space, w_type, w_value, w_traceback) w_type, w_value, w_traceback = f.space.unpacktuple(w_resulttuple, 3) + # XXX the three-arguments 'raise' is not supported yet raise OperationError(w_type, w_value) def LOAD_LOCALS(f): From hpk at codespeak.net Tue Dec 23 15:12:47 2003 From: hpk at codespeak.net (hpk at codespeak.net) Date: Tue, 23 Dec 2003 15:12:47 +0100 (MET) Subject: [pypy-svn] rev 2682 - pypy/trunk/src/pypy/appspace Message-ID: <20031223141247.A314F5AA0B@thoth.codespeak.net> Author: hpk Date: Tue Dec 23 15:12:47 2003 New Revision: 2682 Removed: pypy/trunk/src/pypy/appspace/string.py Log: removed the string module. One shouldn't put python modules into pypy that can as well be taken from the underlying cpython-distro, at least for the time beeing. Deleted: /pypy/trunk/src/pypy/appspace/string.py ============================================================================== --- /pypy/trunk/src/pypy/appspace/string.py Tue Dec 23 15:12:47 2003 +++ (empty file) @@ -1,9 +0,0 @@ -def maketrans(origin, image): - if len(origin) != len(image): - raise ValueError("maketrans arguments must have same length") - L = [chr(i) for i in range(256)] - for i in range(len(origin)): - L[ord(origin[i])] = image[i] - - tbl = ''.join(L) - return tbl \ No newline at end of file From hpk at codespeak.net Tue Dec 23 17:35:27 2003 From: hpk at codespeak.net (hpk at codespeak.net) Date: Tue, 23 Dec 2003 17:35:27 +0100 (MET) Subject: [pypy-svn] rev 2683 - in pypy/trunk/src/pypy: appspace interpreter interpreter/test Message-ID: <20031223163527.8F2555AA0B@thoth.codespeak.net> Author: hpk Date: Tue Dec 23 17:35:26 2003 New Revision: 2683 Modified: pypy/trunk/src/pypy/appspace/builtin_functions_test.py pypy/trunk/src/pypy/interpreter/nestedscope.py pypy/trunk/src/pypy/interpreter/test/test_nestedscope.py Log: fixed the nested scope issue Alex mentioned in his mail. I think we should make a complete analysis of the corresponding CPython code regarding the scopes, though. On first read it seems that CPython should produce the wrong results for calling vars()/locals() in inner scopes so i must be missing something. Whatever, the tests pass and also the appspace/builtin_functions_test.py pass that Alex had commented out ... Modified: pypy/trunk/src/pypy/appspace/builtin_functions_test.py ============================================================================== --- pypy/trunk/src/pypy/appspace/builtin_functions_test.py (original) +++ pypy/trunk/src/pypy/appspace/builtin_functions_test.py Tue Dec 23 17:35:26 2003 @@ -1192,9 +1192,7 @@ import sys self.assertEqual(Set(vars(sys)), Set(dir(sys))) self.assertEqual(get_vars_f0(), {}) - ''' XXX TODO: known bug: free-var 'get_vars_0' ``leaks`` self.assertEqual(get_vars_f2(), {'a': 1, 'b': 2}) - ''' self.assertRaises(TypeError, vars, 42, 42) self.assertRaises(TypeError, vars, 42) Modified: pypy/trunk/src/pypy/interpreter/nestedscope.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/nestedscope.py (original) +++ pypy/trunk/src/pypy/interpreter/nestedscope.py Tue Dec 23 17:35:26 2003 @@ -71,7 +71,11 @@ def fast2locals(self): PyInterpFrame.fast2locals(self) - freevarnames = self.code.co_cellvars + self.code.co_freevars + # cellvars are values exported to inner scopes + # freevars are values coming from outer scopes + # for locals we only want the ones exported to inner-scopes + # XXX check more exactly how CPython does it + freevarnames = self.code.co_cellvars # + self.code.co_freevars for name, cell in zip(freevarnames, self.cells): try: w_value = cell.get() Modified: pypy/trunk/src/pypy/interpreter/test/test_nestedscope.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/test/test_nestedscope.py (original) +++ pypy/trunk/src/pypy/interpreter/test/test_nestedscope.py Tue Dec 23 17:35:26 2003 @@ -34,6 +34,28 @@ return (a, b) self.assertEquals(f(), (3, 4)) + def test_nested_scope_locals(self): + def f(): + x = 3 + def g(): + i = x + return locals() + return g() + d = f() + self.assertEquals(d, {'i':3}) + + def test_deeply_nested_scope_locals(self): + def f(): + x = 3 + def g(): + def h(): + i = x + return locals() + return locals(), h() + return g() + outer_locals, inner_locals = f() + self.assertEquals(inner_locals, {'i':3}) + self.assertEquals(len(outer_locals), 1, "len!=1 for %r" % outer_locals) if __name__ == '__main__': test.main() From arigo at codespeak.net Tue Dec 23 17:53:09 2003 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 23 Dec 2003 17:53:09 +0100 (MET) Subject: [pypy-svn] rev 2684 - in pypy/trunk/src/pypy: interpreter module module/test objspace tool Message-ID: <20031223165309.72EB15AA0B@thoth.codespeak.net> Author: arigo Date: Tue Dec 23 17:53:08 2003 New Revision: 2684 Added: pypy/trunk/src/pypy/module/__builtin__interp.py (contents, props changed) - copied, changed from rev 2565, pypy/trunk/src/pypy/module/builtin.py pypy/trunk/src/pypy/module/__builtin__module.py (contents, props changed) - copied, changed from rev 2565, pypy/trunk/src/pypy/module/builtin.py Modified: pypy/trunk/src/pypy/interpreter/baseobjspace.py pypy/trunk/src/pypy/interpreter/extmodule.py pypy/trunk/src/pypy/interpreter/gateway.py pypy/trunk/src/pypy/interpreter/main.py pypy/trunk/src/pypy/interpreter/module.py pypy/trunk/src/pypy/interpreter/pyopcode.py pypy/trunk/src/pypy/module/test/test_builtin.py pypy/trunk/src/pypy/objspace/trivial.py pypy/trunk/src/pypy/tool/fixeol Log: Refactoring of built-in modules. They are now written as application-level code with "escapes" to evaluate arbitrary interp-level code at initialization time. See the new rewritten "module/__builtin__module.py". M interpreter/gateway.py Added flexibility to BuiltinCode class. M interpreter/extmodule.py New BuiltinModule class that loads the module/*module.py and module/*interp.py files in the correct order with the correct hooks. Next step is to completely remove the old content of extmodule.py. M interpreter/baseobjspace.py Create the __builtin__ module as a BuiltinModule instance. New convenience method unwrapdefault(). M interpreter/pyopcode.py Moved the implementation of IMPORT_FROM from app-level to interp-level for bootstrapping reasons. M interpreter/main.py Unrelated minor fix. M interpreter/module.py Module constructor optionally takes a w_dict argument. M module/test/test_builtin.py Removed a test: it doesn't seem important to be able to access class xrange from interp-level, and it would now require a few hacks to be done. AM module/__builtin__module.py AM module/__builtin__interp.py The new version of the previous builtin.py module. M objspace/trivial.py A detail (which makes the whole thing ever more hacky). M tool/fixeol Adding *.pyo to svn:ignore programmatically. Modified: pypy/trunk/src/pypy/interpreter/baseobjspace.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/baseobjspace.py (original) +++ pypy/trunk/src/pypy/interpreter/baseobjspace.py Tue Dec 23 17:53:08 2003 @@ -59,12 +59,11 @@ if not hasattr(self, 'sys'): self.make_sys() - from pypy.module import builtin + from pypy.interpreter.extmodule import BuiltinModule - # the builtins are iteratively initialized - self.builtin = builtin.__builtin__(self) + # the builtins are iteratively initialized + self.builtin = BuiltinModule(self, '__builtin__', self.w_builtins) self.w_builtin = self.wrap(self.builtin) - self.w_builtins = self.builtin.w_dict # initialize with "bootstrap types" from objspace (e.g. w_None) for name, value in self.__dict__.items(): @@ -75,11 +74,6 @@ #print "setitem: space instance %-20s into builtins" % name self.setitem(self.w_builtins, self.wrap(name), value) - # only here can we add those builtins that require - # execution of source code -- because this requires - # an almost functional 'builtin' attribute on the space - self.builtin._initcompiledbuiltins() - self.sys._setbuiltinmodule(self.w_builtin) #Now we can load all the builtin (interpreter level) modules. @@ -136,6 +130,12 @@ w_id_y = self.id(w_y) return self.eq(w_id_x, w_id_y) + def unwrapdefault(self, w_value, default): + if w_value is None or w_value == self.w_None: + return default + else: + return self.unwrap(w_value) + def newbool(self, b): if b: return self.w_True Modified: pypy/trunk/src/pypy/interpreter/extmodule.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/extmodule.py (original) +++ pypy/trunk/src/pypy/interpreter/extmodule.py Tue Dec 23 17:53:08 2003 @@ -4,7 +4,146 @@ """ +from __future__ import generators +import os, sys, types +import autopath from pypy.interpreter import gateway +from pypy.interpreter.error import OperationError +from pypy.interpreter.pycode import PyCode +from pypy.interpreter.function import Function +from pypy.interpreter.module import Module + + +class BuiltinModule(Module): + + def __init__(self, space, modulename, w_dict=None): + Module.__init__(self, space, space.wrap(modulename), w_dict) + + # Compile the xxxmodule.py source file + modulefile = os.path.join(autopath.pypydir, 'module', + modulename+'module.py') + f = open(modulefile, 'r') + modulesource = f.read() + f.close() + code = compile(modulesource, modulefile, 'exec', + generators.compiler_flag) + pycode = PyCode()._from_code(code) + + # Set the hooks that call back from app-level to interp-level + w_builtins = space.w_builtins + self.__saved_hooks = {} + self.__interplevelfile = os.path.join(autopath.pypydir, 'module', + modulename+'interp.py') + newhooks = {} + for name, hook in [('__interplevel__exec', self.app_interplevelexec), + ('__interplevel__eval', self.app_interpleveleval), + ('__import__', self.app_interplevelimport)]: + w_name = space.wrap(name) + try: + self.__saved_hooks[name] = space.getitem(w_builtins, w_name) + except OperationError: + pass + w_hook = space.wrap(hook) + space.setitem(w_builtins, w_name, w_hook) + newhooks[name] = w_hook + space.setitem(self.w_dict, space.wrap('__builtins__'), + space.w_builtins) + + # Run the app-level module definition (xxxmodule.py) + pycode.exec_code(space, w_dict, w_dict) + + # Run the interp-level definition (xxxinterp.py) + # if xxxmodule.py didn't do so already + self.loadinterplevelfile() + + # Remove/restore the hooks unless they have been modified at app-level + for name, w_hook in newhooks.items(): + w_name = space.wrap(name) + try: + w_current = space.getitem(w_builtins, w_name) + except OperationError: + pass + else: + if space.is_true(space.is_(w_current, w_hook)): + if name in self.__saved_hooks: + space.setitem(w_builtins, w_name, + self.__saved_hooks[name]) + else: + space.delitem(w_builtins, w_name) + del self.__saved_hooks + + def loadinterplevelfile(self): + try: + filename = self.__interplevelfile + except AttributeError: + pass # already loaded + else: + del self.__interplevelfile + # temporarily install an '__applevel__' pseudo-module + sys.modules['__applevel__'] = BuiltinModule.AppModuleHack(self) + execfile(filename, self.__dict__) + del sys.modules['__applevel__'] + + def get_interp2app(self, result): + space = self.space + if result is None: + result = space.w_None + elif isinstance(result, types.FunctionType): + f = result + code = gateway.BuiltinCode(f, ismethod=False, spacearg=False) + defs_w = list(f.func_defaults or ()) + func = Function(space, code, self.w_dict, defs_w) + result = space.wrap(func) + else: + pass # assume that 'result' is a wrapped object in other cases + return result + + def interplevelexec(self, w_codestring): + codestring = self.space.unwrap(w_codestring) + exec codestring in self.__dict__ + return self.space.w_None + + def interpleveleval(self, w_codestring): + space = self.space + codestring = space.unwrap(w_codestring) + result = eval(codestring, self.__dict__) + return self.get_interp2app(result) + + def interplevelimport(self, w_modulename, w_globals, w_locals, w_fromlist): + space = self.space + w = space.wrap + if space.is_true(space.eq(w_modulename, w('__interplevel__'))): + self.loadinterplevelfile() + if w_fromlist == space.w_None: + raise ImportError, "must use 'from __interplevel__ import xx'" + for w_name in space.unpacktuple(w_fromlist): + result = getattr(self, space.unwrap(w_name)) + w_result = self.get_interp2app(result) + space.setitem(self.w_dict, w_name, w_result) + return space.wrap(self) + else: + return space.call_function(self.__saved_hooks['__import__'], + w_modulename, w_globals, + w_locals, w_fromlist) + + app_interplevelexec = gateway.interp2app(interplevelexec) + app_interpleveleval = gateway.interp2app(interpleveleval) + app_interplevelimport = gateway.interp2app(interplevelimport) + + class AppModuleHack: + def __init__(self, builtinmodule): + self.space = builtinmodule.space + self.w_dict = builtinmodule.w_dict + def __getattr__(self, name): + w_func = self.space.getitem(self.w_dict, self.space.wrap(name)) + def caller(*args, **kwds): + return self.space.call_function(w_func, *args, **kwds) + return caller + + +# XXX delete everything below. + + from pypy.interpreter.miscutils import InitializedClass, RwDictProxy from pypy.interpreter.module import Module Modified: pypy/trunk/src/pypy/interpreter/gateway.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/gateway.py (original) +++ pypy/trunk/src/pypy/interpreter/gateway.py Tue Dec 23 17:53:08 2003 @@ -23,7 +23,7 @@ # When a BuiltinCode is stored in a Function object, # you get the functionality of CPython's built-in function type. - def __init__(self, func): + def __init__(self, func, ismethod=None, spacearg=None): # 'implfunc' is the interpreter-level function. # Note that this uses a lot of (construction-time) introspection. eval.Code.__init__(self, func.__name__) @@ -39,16 +39,16 @@ # Not exactly a clean approach XXX. argnames, varargname, kwargname = tmp.signature() argnames = list(argnames) - if argnames[0] == 'self': - self.ismethod = True - elif argnames[0] == 'space': - self.ismethod = False + lookslikemethod = argnames[:1] == ['self'] + if ismethod is None: + ismethod = lookslikemethod + if spacearg is None: + spacearg = not lookslikemethod + self.ismethod = ismethod + self.spacearg = spacearg + if spacearg: del argnames[0] - else: - raise AssertionError, ( - "first argument must be called 'self' in methods " - "and 'space' in global functions") - for i in range(self.ismethod, len(argnames)): + for i in range(ismethod, len(argnames)): a = argnames[i] assert a.startswith('w_'), ( "argument %s of built-in function %r should start with 'w_'" % @@ -83,7 +83,7 @@ argarray = self.fastlocals_w if self.code.ismethod: argarray = [self.space.unwrap(argarray[0])] + argarray[1:] - else: + if self.code.spacearg: argarray = [self.space] + argarray return call_with_prepared_arguments(self.space, self.code.func, argarray) Modified: pypy/trunk/src/pypy/interpreter/main.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/main.py (original) +++ pypy/trunk/src/pypy/interpreter/main.py Tue Dec 23 17:53:08 2003 @@ -1,6 +1,7 @@ import autopath from pypy.tool import option from pypy.interpreter import executioncontext, baseobjspace, gateway, module +from pypy.interpreter.error import OperationError, PyPyError import sys, os def _run_eval_string(source, filename, space, eval): @@ -24,9 +25,9 @@ mainmodule = module.Module(space, space.wrap("__main__")) w_globals = mainmodule.w_dict - except baseobjspace.OperationError, operationerr: + except OperationError, operationerr: operationerr.record_interpreter_traceback() - raise baseobjspace.PyPyError(space, operationerr) + raise PyPyError(space, operationerr) else: pycode = space.unwrap(w_code) retval = pycode.exec_code(space, w_globals, w_globals) @@ -56,7 +57,7 @@ space = option.objspace() try: run_file(argv[0], space) - except baseobjspace.PyPyError, pypyerr: + except PyPyError, pypyerr: pypyerr.operationerr.print_detailed_traceback(pypyerr.space) if __name__ == '__main__': Modified: pypy/trunk/src/pypy/interpreter/module.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/module.py (original) +++ pypy/trunk/src/pypy/interpreter/module.py Tue Dec 23 17:53:08 2003 @@ -14,10 +14,13 @@ class Module(Wrappable): """A module.""" - def __init__(self, space, w_name): + def __init__(self, space, w_name, w_dict=None): self.space = space - self.w_dict = space.newdict([(space.wrap('__name__'), w_name)]) + if w_dict is None: + w_dict = space.newdict([]) + self.w_dict = w_dict self.w_name = w_name + space.setitem(w_dict, space.wrap('__name__'), w_name) def pypy_getattr(self, w_attr): space = self.space Modified: pypy/trunk/src/pypy/interpreter/pyopcode.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/pyopcode.py (original) +++ pypy/trunk/src/pypy/interpreter/pyopcode.py Tue Dec 23 17:53:08 2003 @@ -605,7 +605,13 @@ name = f.getname(nameindex) w_name = f.space.wrap(name) w_module = f.valuestack.top() - w_obj = import_from(f.space, w_module, w_name) + try: + w_obj = f.space.getattr(w_module, w_name) + except OperationError, e: + if not e.match(f.space, f.space.w_AttributeError): + raise + raise OperationError(f.space.w_ImportError, + f.space.wrap("cannot import name '%s'" % name)) f.valuestack.push(w_obj) def JUMP_FORWARD(f, stepby): @@ -882,11 +888,5 @@ continue into_locals[name] = getattr(module, name) -def app_import_from(module, name): - try: - return getattr(module, name) - except AttributeError: - raise ImportError("cannot import name '%s'" % name) - gateway.importall(globals()) # app_xxx() -> xxx() Copied: pypy/trunk/src/pypy/module/__builtin__interp.py (from rev 2565, pypy/trunk/src/pypy/module/builtin.py) ============================================================================== --- pypy/trunk/src/pypy/module/builtin.py (original) +++ pypy/trunk/src/pypy/module/__builtin__interp.py Tue Dec 23 17:53:08 2003 @@ -1,805 +1,165 @@ -from __future__ import generators -from pypy.interpreter import executioncontext +""" +Implementation of interpreter-level builtins. +""" +import os from pypy.interpreter.module import Module -from pypy.interpreter.extmodule import ExtModule +from pypy.interpreter.pycode import PyCode from pypy.interpreter.error import OperationError - -import os.path -import sys -import types - -####################### -#### __builtin__ #### -####################### +_noarg = object() import __builtin__ as cpy_builtin +file = space.wrap(cpy_builtin.file) -class _noarg: - """ use this class in interpreter level functions for default - values if you want to recognize that no specific value was - passed. - """ - -class __builtin__(ExtModule): - """ Template for PyPy's '__builtin__' module. - """ - - __name__ = '__builtin__' - - open = cpy_builtin.open - file = cpy_builtin.file - -## def __init__(self, space): -## #app level __import__ helpers -## self.w_imp_modules = space.sys.w_modules -## self.w_imp_path = space.sys.w_path -## ExtModule.__init__(self, space) - - def __init__(self, space): - self.w___debug__ = space.newbool(1) - # Fix this later to show Ctrl-D on Unix - self.w_quit = self.w_exit = space.wrap("Use Ctrl-Z (i.e. EOF) to exit.") - # XXX To-do: Add copyright, credits, and license - ExtModule.__init__(self, space) - - def _initcompiledbuiltins(self): - """ add 'compiled' builtins to app-level dict and interp-level """ - self._eval_app_source(xrange_appsource) - self._eval_app_source(newstyleclasses) - - def _actframe(self, index=-1): - return self.space.getexecutioncontext().framestack.items[index] - - def globals(self): - return self._actframe().w_globals - - def private_caller_locals(self): - #print self.__dict__.keys() - return self._actframe(-2).getdictscope() - - def locals(self): - return self._actframe().getdictscope() - - def __import__(self, w_modulename, w_globals=None, - w_locals=None, w_fromlist=None): - space = self.space - w = space.wrap - try: - w_mod = space.getitem(space.sys.w_modules, w_modulename) - return w_mod - except OperationError,e: - if not e.match(space, space.w_KeyError): - raise - w_mod = space.get_builtin_module(space.unwrap(w_modulename)) - if w_mod is not None: - space.setitem(space.sys.w_modules, w_modulename, w_mod) - return w_mod - - import os - for path in space.unpackiterable(space.sys.w_path): - f = os.path.join(space.unwrap(path), space.unwrap(w_modulename) + '.py') - if os.path.exists(f): - w_mod = space.wrap(Module(space, w_modulename)) - space.setitem(space.sys.w_modules, w_modulename, w_mod) - space.setattr(w_mod, w('__file__'), w(f)) - w_dict = space.getattr(w_mod, w('__dict__')) - self.execfile(w(f), w_dict, w_dict) - return w_mod - - w_exc = space.call_function(space.w_ImportError, w_modulename) - raise OperationError(space.w_ImportError, w_exc) - -## def app___import__(self, *args): -## # NOTE: No import statements can be done in this function, -## # as that would involve a recursive call to this function ... -## -## # args => (name[, globals[, locals[, fromlist]]]) -## -## l = len(args) -## if l >= 1: -## modulename = args[0] -## else: -## raise TypeError('__import__() takes at least 1 argument (0 given)') -## if l >= 2: -## globals = args[1] -## try: -## local_context = self.imp_dirname(globals['__file__']) -## except KeyError: -## local_context = '' -## else: -## local_context = '' -## if l >= 4: -## fromlist = args[3] -## else: -## fromlist = [] -## if l > 4: -## raise TypeError('__import__() takes at most 4 arguments (%i given)' % l) -## -## def inner_load(f, fullname): -## """Load module from file `f` with canonical name `fullname`. -## """ -## mod = self.imp_module(fullname) # XXX - add in docstring -## self.imp_modules[fullname] = mod -## mod.__file__ = f -## dict = mod.__dict__ -## execfile(f, dict, dict) -## return mod -## -## def load(path, modulename, fullname): -## """Create a module. -## -## Create a mnodule with canonical name `fullname` from file -## `modulename`+'.py' in path `path`, if it exist. -## Or alternatively from the package -## `path`/`modulename`/'__init__.py'. -## If neither are found, return None. -## """ -## -## f = self.imp_join(path, modulename + '.py') -## if self.imp_exists(f): -## return inner_load(f, fullname) -## f = self.imp_join(path, modulename, '__init__.py') -## if self.imp_exists(f): -## return inner_load(f, fullname) -## else: -## return None -## -## names = modulename.split('.') -## -## if not names: -## raise ValueError("Cannot import an empty module name.") -## if len(names) == 1: -## if self.imp_modules.has_key(modulename): -## return self.imp_modules[modulename] -## #Relative Import -## if local_context: -## #Regular Module -## module = load(local_context, modulename, modulename) -## if module: -## return module -## #Standard Library Module Import -## for path in self.imp_path: -## #Regular Module -## module = load(path, modulename, modulename) -## if module: -## return module -## #Module Not Found -## raise ImportError(modulename) -## else: -## #Find most specific module already imported. -## for i in range(len(names),0,-1): -## base_name = '.'.join(names[0:i]) -## if self.imp_modules.has_key(base_name): -## break -## #Top level package not imported - import it. -## else: -## base_name = names[0] -## i = 1 -## #Relative Import -## if ((not local_context) or -## not load(local_context, base_name, base_name)): -## #Standard Module Import -## for path in self.imp_path: -## if load(path, base_name, base_name): -## break -## else: -## #Module Not Found -## raise ImportError(base_name) -## path = self.imp_dirname(self.imp_modules[base_name].__file__) -## full_name = base_name -## for j in range(i,len(names)): -## path = self.imp_join(path, names[j]) -## full_name = '.'.join((full_name, names[j])) -## if not load(path, '__init__', full_name): -## raise ImportError(full_name) -## ### load module from path -## if fromlist: -## return self.imp_modules[modulename] -## else: -## return self.imp_modules[names[0]] -## -## # Interpreter level helpers for app level import -## def imp_dirname(self, *args_w): -## return self.space.wrap(os.path.dirname(*self.space.unwrap(args_w))) -## -## def imp_join(self, *args_w): -## return self.space.wrap(os.path.join(*self.space.unwrap(args_w))) -## -## def imp_exists(self, *args_w): -## return self.space.wrap(os.path.exists(*self.space.unwrap(args_w))) -## -## def imp_module(self, w_name): -## return self.space.wrap(Module(self.space, w_name)) - - def compile(self, w_str, w_filename, w_startstr, - w_supplied_flags=None, w_dont_inherit=None): - space = self.space - str_ = space.unwrap(w_str) - filename = space.unwrap(w_filename) - startstr = space.unwrap(w_startstr) - if w_supplied_flags is None: - supplied_flags = 0 - else: - supplied_flags = space.unwrap(w_supplied_flags) - if supplied_flags is None: - supplied_flags = 0 - if w_dont_inherit is None: - dont_inherit = 0 - else: - dont_inherit = space.unwrap(w_dont_inherit) - if dont_inherit is None: - dont_inherit = 0 - - #print (str_, filename, startstr, supplied_flags, dont_inherit) - # XXX we additionally allow GENERATORS because compiling some builtins - # requires it. doesn't feel quite right to do that here. - try: - c = cpy_builtin.compile(str_, filename, startstr, supplied_flags|4096, dont_inherit) - # It would be nice to propagate all exceptions to app level, - # but here we only propagate the 'usual' ones, until we figure - # out how to do it generically. - except ValueError,e: - raise OperationError(space.w_ValueError,space.wrap(str(e))) - except TypeError,e: - raise OperationError(space.w_TypeError,space.wrap(str(e))) - from pypy.interpreter.pycode import PyCode - return space.wrap(PyCode()._from_code(c)) - - def app_execfile(self, filename, glob=None, loc=None): - if glob is None: - glob = globals() - if loc is None: - loc = locals() - elif loc is None: - loc = glob - f = file(filename) - try: - source = f.read() - finally: - f.close() - #Don't exec the source directly, as this loses the filename info - co = compile(source, filename, 'exec') - exec co in glob, loc - - ####essentially implemented by the objectspace - def abs(self, w_val): - return self.space.abs(w_val) - - def chr(self, w_ascii): - w_character = self.space.newstring([w_ascii]) - return w_character - - def len(self, w_obj): - return self.space.len(w_obj) - - def delattr(self, w_object, w_name): - self.space.delattr(w_object, w_name) - return self.space.w_None - - def getattr(self, w_object, w_name, w_defvalue = _noarg): - try: - return self.space.getattr(w_object, w_name) - except OperationError, e: - if e.match(self.space, self.space.w_AttributeError): - if w_defvalue is not _noarg: - return w_defvalue - raise - - def hash(self, w_object): - return self.space.hash(w_object) - - def oct(self, w_val): - # XXX does this need to be a space operation? - return self.space.oct(w_val) - - def hex(self, w_val): - return self.space.hex(w_val) - - def round(self, w_val, w_n=None): - if w_n is None: - w_n = self.space.wrap(0) - return self.space.round(w_val, w_n) - - def id(self, w_object): - return self.space.id(w_object) - - def app_sum(self, sequence, total=0): - for item in sequence: - total = total + item - return total - - # This function was not in the original builtins, - # but is quite useful for some aspects of PyPy - # implementation. - def app_sign(self, a): - if a > 0: - return 1 - elif a < 0: - return -1 - else: - return 0 - - #XXX works only for new-style classes. - #So we have to fix it, when we add support for old-style classes - def issubclass(self, w_cls1, w_cls2): - return self.space.issubtype(w_cls1, w_cls2) - - def iter(self, w_collection_or_callable, w_sentinel = _noarg): - if w_sentinel is _noarg: - return self.space.iter(w_collection_or_callable) - else: - if not self.space.is_true(self.callable(w_collection_or_callable)): - raise OperationError(self.space.w_TypeError, - self.space.wrap('iter(v, w): v must be callable')) - return self._iter_generator(w_collection_or_callable, w_sentinel) - - def app__iter_generator(self, callable_, sentinel): - """ This generator implements the __iter__(callable,sentinel) protocol """ - while 1: - result = callable_() - if result == sentinel: - raise StopIteration - yield result - - def app_enumerate(self, collection): - 'Generates an indexed series: (0,coll[0]), (1,coll[1]) ...' - i = 0 - it = iter(collection) - while 1: - yield (i, it.next()) - i += 1 - - def ord(self, w_val): - return self.space.ord(w_val) - - def pow(self, w_base, w_exponent, w_modulus=None): - if w_modulus is None: - w_modulus = self.space.w_None - return self.space.pow(w_base, w_exponent, w_modulus) - - def repr(self, w_object): - return self.space.repr(w_object) - - def setattr(self, w_object, w_name, w_val): - self.space.setattr(w_object, w_name, w_val) - return self.space.w_None - - # app-level functions - - def app_apply(self, function, args, kwds={}): - """call a function (or other callable object) and return its result""" - return function(*args, **kwds) - - def app_map(self, function, *collections): - """does 3 separate things, hence this enormous docstring. - 1. if function is None, return a list of tuples, each with one - item from each collection. If the collections have different - lengths, shorter ones are padded with None. - - 2. if function is not None, and there is only one collection, - apply function to every item in the collection and return a - list of the results. - - 3. if function is not None, and there are several collections, - repeatedly call the function with one argument from each - collection. If the collections have different lengths, - shorter ones are padded with None""" - - if len(collections) == 0: - raise TypeError, "map() requires at least one sequence" - - elif len(collections) == 1: - #it's the most common case, so make it faster - if function is None: - return collections[0] - else: - return [function(x) for x in collections[0]] - else: - res = [] - idx = 0 - while 1: - cont = 0 #is any collection not empty? - args = [] - for collection in collections: - try: - elem = collection[idx] - cont = cont + 1 - except IndexError: - elem = None - args.append(elem) - if cont: - if function is None: - res.append(tuple(args)) - else: - res.append(function(*args)) - else: - return res - idx = idx + 1 - - def app_filter(self, function, collection): - """construct a list of those elements of collection for which function - is True. If function is None, then return the items in the sequence - which are True.""" - - if function is None: - res = [item for item in collection if item] - else: - res = [item for item in collection if function(item)] - - if type(collection) is tuple: - return tuple(res) - elif type(collection) is str: - return "".join(res) - else: - return res - - def app_zip(self, *collections): - """return a list of tuples, where the nth tuple contains every - nth item of each collection. If the collections have different - lengths, zip returns a list as long as the shortest collection, - ignoring the trailing items in the other collections.""" - - if len(collections) == 0: - raise TypeError, "zip() requires at least one sequence" - res = [] - idx = 0 - while 1: - try: - elems = [] - for collection in collections: - elems.append(collection[idx]) - res.append(tuple(elems)) - except IndexError: - break - idx = idx + 1 - return res - - def app_reduce(self, function, l, *initialt): - """ Apply function of two arguments cumulatively to the items of - sequence, from left to right, so as to reduce the sequence to a - single value. Optionally begin with an initial value.""" - - if initialt: - initial, = initialt - idx = 0 - else: - try: - initial = l[0] - except IndexError: - raise TypeError, "reduce() of empty sequence with no initial value" - idx = 1 - while 1: - try: - initial = function(initial, l[idx]) - idx = idx + 1 - except IndexError: - break - return initial - - def app_isinstance(self, obj, klass_or_tuple): - try: - objcls = obj.__class__ - except AttributeError: - objcls = type(obj) - if issubclass(klass_or_tuple.__class__, tuple): - for klass in klass_or_tuple: - if issubclass(objcls, klass): - return 1 - return 0 - else: - try: - return issubclass(objcls, klass_or_tuple) - except TypeError: - raise TypeError, "isinstance() arg 2 must be a class or type" - - def app_range(self, x, y=None, step=1): - """ returns a list of integers in arithmetic position from start (defaults - to zero) to stop - 1 by step (defaults to 1). Use a negative step to - get a list in decending order.""" - - if y is None: - start = 0 - stop = x - else: - start = x - stop = y - - if step == 0: - raise ValueError, 'range() arg 3 must not be zero' - - elif step > 0: - if stop <= start: # no work for us - return [] - howmany = (stop - start + step - 1)/step - - else: # step must be < 0, or we would have raised ValueError - if stop >= start: # no work for us - return [] - howmany = (start - stop - step - 1)/-step - - arr = [None] * howmany # this is to avoid using append. - - i = start - n = 0 - while n < howmany: - arr[n] = i - i += step - n += 1 - - return arr - - # min and max could be one function if we had operator.__gt__ and - # operator.__lt__ Perhaps later when we have operator. - - def app_min(self, *arr): - """return the smallest number in a list""" +# import useful app-level functions +from __applevel__ import execfile, callable, _iter_generator - if not arr: - raise TypeError, 'min() takes at least one argument' - if len(arr) == 1: - arr = arr[0] +def _actframe(position=0): + return space.getexecutioncontext().framestack.top(position) - iterator = iter(arr) - try: - min = iterator.next() - except StopIteration: - raise ValueError, 'min() arg is an empty sequence' +def globals(): + return _actframe().w_globals - for i in iterator: - if min > i: - min = i - return min +def locals(): + return _actframe().getdictscope() - def app_max(self, *arr): - """return the largest number in a list""" +def _caller_globals(w_index=None): + position = space.unwrapdefault(w_index, 1) + return _actframe(position).w_globals - if not arr: - raise TypeError, 'max() takes at least one argument' +def _caller_locals(w_index=None): + position = space.unwrapdefault(w_index, 1) + return _actframe(position).getdictscope() - if len(arr) == 1: - arr = arr[0] - iterator = iter(arr) +def __import__(w_modulename, w_globals=None, + w_locals=None, w_fromlist=None): + modulename = space.unwrap(w_modulename) + if not isinstance(modulename, str): try: - max = iterator.next() - except StopIteration: - raise ValueError, 'max() arg is an empty sequence' - - for i in iterator: - if max < i: - max = i - return max - - def app_divmod(self, x, y): - return x//y, x%y - - def app_cmp(self, x, y): - """return 0 when x == y, -1 when x < y and 1 when x > y """ - if x < y: - return -1 - elif x == y: - return 0 - else: - return 1 - - def app_vars(self, *obj): - """return a dictionary of all the attributes currently bound in obj. If - called with no argument, return the variables bound in local scope.""" - - if len(obj) == 0: - return _caller_locals() - elif len(obj) != 1: - raise TypeError, "vars() takes at most 1 argument." - else: - try: - return obj[0].__dict__ - except AttributeError: - raise TypeError, "vars() argument must have __dict__ attribute" - - def app_hasattr(self, ob, attr): - try: - getattr(ob, attr) - return True + helper = ', not ' + modulename.__class__.__name__ except AttributeError: - return False - - def app_callable(self, ob): - return hasattr(ob, '__call__') - - def app_dir(self, *args): - """dir([object]) -> list of strings - - Return an alphabetized list of names comprising (some of) the attributes - of the given object, and of attributes reachable from it: - - No argument: the names in the current scope. - Module object: the module attributes. - Type or class object: its attributes, and recursively the attributes of - its bases. - Otherwise: its attributes, its class's attributes, and recursively the - attributes of its class's base classes. - """ - if len(args) > 1: - raise TypeError("dir expected at most 1 arguments, got %d" - % len(args)) - if len(args) == 0: - local_names = _caller_locals().keys() # 2 stackframes away - local_names.sort() - return local_names - - import types - def _classdir(klass): - """Return a dict of the accessible attributes of class/type klass. - - This includes all attributes of klass and all of the - base classes recursively. - - The values of this dict have no meaning - only the keys have - meaning. - """ - Dict = {} - try: - Dict.update(klass.__dict__) - except AttributeError: pass - try: - # XXX - Use of .__mro__ would be suggested, if the existance - # of that attribute could be guarranted. - bases = klass.__bases__ - except AttributeError: pass - else: - try: - #Note that since we are only interested in the keys, - # the order we merge classes is unimportant - for base in bases: - Dict.update(_classdir(base)) - except TypeError: pass - return Dict - #End _classdir - - obj = args[0] - - if isinstance(obj, types.ModuleType): - try: - result = obj.__dict__.keys() - result.sort() - return result - except AttributeError: - return [] - - elif isinstance(obj, (types.TypeType, types.ClassType)): - #Don't look at __class__, as metaclass methods would be confusing. - result = _classdir(obj).keys() - result.sort() - return result - - else: #(regular item) - Dict = {} - try: - Dict.update(obj.__dict__) - except AttributeError: pass - try: - Dict.update(_classdir(obj.__class__)) - except AttributeError: pass - - ## Comment from object.c: - ## /* Merge in __members__ and __methods__ (if any). - ## XXX Would like this to go away someday; for now, it's - ## XXX needed to get at im_self etc of method objects. */ - for attr in ['__members__','__methods__']: - try: - for item in getattr(obj, attr): - if isinstance(item, types.StringTypes): - Dict[item] = None - except (AttributeError, TypeError): pass - - result = Dict.keys() - result.sort() - return result - - def app_intern(self, s): - """ - We don't have a string table, making intern a null operation. - This is here for backwards compatibility. - """ - if not isinstance(s, str): - raise TypeError("intern() argument 1 must be string.") - return s - - def app_copyright(self): - print 'Copyright 2002-2004 Pypy development team.\nAll rights reserved.\nFor further information see http://www.codespaek.net/pypy.\nSome materials may have a different copyright.\nIn these cases, this is explicitly noted in the source code file.' - - def app_license(self): - print \ -""" -Copyright (c) <2002-2004> - -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. -""" - - def app_help(self): - print "You must be joking." - -# source code for the builtin xrange-class - -xrange_appsource = """if 1: - class xrange: - def __init__(self, start, stop=None, step=1): - if stop is None: - self.start = 0 - self.stop = start - else: - self.start = start - self.stop = stop - if step == 0: - raise ValueError, 'xrange() step-argument (arg 3) must not be zero' - self.step = step - - def __iter__(self): - def gen(self): - start, stop, step = self.start, self.stop, self.step - i = start - if step > 0: - while i < stop: - yield i - i+=step - else: - while i > stop: - yield i - i+=step - return gen(self) -""" - -newstyleclasses = """ - -class property(object): - - def __init__(self, fget=None, fset=None, fdel=None, doc=None): - self.fget = fget - self.fset = fset - self.fdel = fdel - self.__doc__ = doc or "" - - def __get__(self, obj, objtype=None): - if obj is None: - return self - if self.fget is None: - raise AttributeError, "unreadable attribute" - return self.fget(obj) - - def __set__(self, obj, value): - if self.fset is None: - raise AttributeError, "can't set attribute" - self.fset(obj, value) - - def __delete__(self, obj): - if self.fdel is None: - raise AttributeError, "can't delete attribute" - self.fdel(obj, value) - - -class staticmethod(object): - - def __init__(self, f): - self.f = f - - def __get__(self, obj, objtype=None): - return self.f - + helper = '' + raise OperationError(space.w_TypeError, + space.wrap("__import__() argument 1 must be string" + helper)) + w = space.wrap + try: + w_mod = space.getitem(space.sys.w_modules, w_modulename) + except OperationError,e: + pass + else: + return w_mod + if not e.match(space, space.w_KeyError): + raise + w_mod = space.get_builtin_module(modulename) + if w_mod is not None: + space.setitem(space.sys.w_modules, w_modulename, w_mod) + return w_mod + + import os + for path in space.unpackiterable(space.sys.w_path): + f = os.path.join(space.unwrap(path), modulename + '.py') + if os.path.exists(f): + w_mod = space.wrap(Module(space, w_modulename)) + space.setitem(space.sys.w_modules, w_modulename, w_mod) + space.setattr(w_mod, w('__file__'), w(f)) + w_dict = space.getattr(w_mod, w('__dict__')) + execfile(w(f), w_dict, w_dict) + return w_mod -class classmethod(object): + w_exc = space.call_function(space.w_ImportError, w_modulename) + raise OperationError(space.w_ImportError, w_exc) - def __init__(self, f): - self.f = f - def __get__(self, obj, klass=None): - if klass is None: - klass = type(obj) - def newfunc(*args): - return self.f(klass, *args) - return newfunc -""" +def compile(w_str, w_filename, w_startstr, + w_supplied_flags=None, w_dont_inherit=None): + str_ = space.unwrap(w_str) + filename = space.unwrap(w_filename) + startstr = space.unwrap(w_startstr) + supplied_flags = space.unwrapdefault(w_supplied_flags, 0) + dont_inherit = space.unwrapdefault(w_dont_inherit, 0) + + #print (str_, filename, startstr, supplied_flags, dont_inherit) + # XXX we additionally allow GENERATORS because compiling some builtins + # requires it. doesn't feel quite right to do that here. + try: + c = cpy_builtin.compile(str_, filename, startstr, supplied_flags|4096, dont_inherit) + # It would be nice to propagate all exceptions to app level, + # but here we only propagate the 'usual' ones, until we figure + # out how to do it generically. + except ValueError,e: + raise OperationError(space.w_ValueError,space.wrap(str(e))) + except TypeError,e: + raise OperationError(space.w_TypeError,space.wrap(str(e))) + return space.wrap(PyCode()._from_code(c)) + + +def abs(w_val): + return space.abs(w_val) + +def chr(w_ascii): + w_character = space.newstring([w_ascii]) + return w_character + +def len(w_obj): + return space.len(w_obj) + +def delattr(w_object, w_name): + space.delattr(w_object, w_name) + return space.w_None + +def getattr(w_object, w_name, w_defvalue = _noarg): + try: + return space.getattr(w_object, w_name) + except OperationError, e: + if e.match(space, space.w_AttributeError): + if w_defvalue is not _noarg: + return w_defvalue + raise + +def hash(w_object): + return space.hash(w_object) + +def oct(w_val): + # XXX does this need to be a space operation? + return space.oct(w_val) + +def hex(w_val): + return space.hex(w_val) + +def round(w_val, w_n=None): + if w_n is None: + w_n = space.wrap(0) + return space.round(w_val, w_n) + +def id(w_object): + return space.id(w_object) + +#XXX works only for new-style classes. +#So we have to fix it, when we add support for old-style classes +def issubclass(w_cls1, w_cls2): + return space.issubtype(w_cls1, w_cls2) + +def iter(w_collection_or_callable, w_sentinel = _noarg): + if w_sentinel is _noarg: + return space.iter(w_collection_or_callable) + else: + if not space.is_true(callable(w_collection_or_callable)): + raise OperationError(space.w_TypeError, + space.wrap('iter(v, w): v must be callable')) + return _iter_generator(w_collection_or_callable, w_sentinel) + +def ord(w_val): + return space.ord(w_val) + +def pow(w_base, w_exponent, w_modulus=None): + if w_modulus is None: + w_modulus = space.w_None + return space.pow(w_base, w_exponent, w_modulus) + +def repr(w_object): + return space.repr(w_object) + +def setattr(w_object, w_name, w_val): + space.setattr(w_object, w_name, w_val) + return space.w_None Copied: pypy/trunk/src/pypy/module/__builtin__module.py (from rev 2565, pypy/trunk/src/pypy/module/builtin.py) ============================================================================== --- pypy/trunk/src/pypy/module/builtin.py (original) +++ pypy/trunk/src/pypy/module/__builtin__module.py Tue Dec 23 17:53:08 2003 @@ -1,95 +1,541 @@ -from __future__ import generators -from pypy.interpreter import executioncontext -from pypy.interpreter.module import Module -from pypy.interpreter.extmodule import ExtModule -from pypy.interpreter.error import OperationError - -import os.path -import sys -import types - -####################### -#### __builtin__ #### -####################### - -import __builtin__ as cpy_builtin - -class _noarg: - """ use this class in interpreter level functions for default - values if you want to recognize that no specific value was - passed. +"""Built-in functions, exceptions, and other objects. + +Noteworthy: None is the `nil' object; Ellipsis represents `...' in slices. +""" + +__builtins__['None'] = __interplevel__eval('space.w_None') +__builtins__['False'] = __interplevel__eval('space.w_False') +__builtins__['True'] = __interplevel__eval('space.w_True') +__builtins__['type'] = __interplevel__eval('space.w_type') +__builtins__['__debug__'] = True + +object = __interplevel__eval('space.w_object') + + +# TODO Fix this later to show Ctrl-D on Unix +quit = exit = "Use Ctrl-Z (i.e. EOF) to exit." + +def execfile(filename, glob=None, loc=None): + if glob is None: + glob = _caller_globals() + if loc is None: + loc = _caller_locals() + elif loc is None: + loc = glob + f = file(filename) + try: + source = f.read() + finally: + f.close() + #Don't exec the source directly, as this loses the filename info + co = compile(source, filename, 'exec') + exec co in glob, loc + + +def sum(sequence, total=0): + # must forbid "summing" strings, per specs of built-in 'sum' + if isinstance(total, str): raise TypeError + for item in sequence: + total = total + item + return total + +def _iter_generator(callable_, sentinel): + """ This generator implements the __iter__(callable,sentinel) protocol """ + while 1: + result = callable_() + if result == sentinel: + return + yield result + +def enumerate(collection): + 'Generates an indexed series: (0,coll[0]), (1,coll[1]) ...' + i = 0 + it = iter(collection) + while 1: + yield (i, it.next()) + i += 1 + +def apply(function, args, kwds={}): + """call a function (or other callable object) and return its result""" + return function(*args, **kwds) + +def map(function, *collections): + """does 3 separate things, hence this enormous docstring. + 1. if function is None, return a list of tuples, each with one + item from each collection. If the collections have different + lengths, shorter ones are padded with None. + + 2. if function is not None, and there is only one collection, + apply function to every item in the collection and return a + list of the results. + + 3. if function is not None, and there are several collections, + repeatedly call the function with one argument from each + collection. If the collections have different lengths, + shorter ones are padded with None """ -class __builtin__(ExtModule): - """ Template for PyPy's '__builtin__' module. + if len(collections) == 0: + raise TypeError, "map() requires at least one sequence" + + elif len(collections) == 1: + #it's the most common case, so make it faster + if function is None: + return list(collections[0]) + else: + return [function(x) for x in collections[0]] + else: + res = [] + idx = 0 + while 1: + cont = 0 #is any collection not empty? + args = [] + for collection in collections: + try: + elem = collection[idx] + cont = cont + 1 + except IndexError: + elem = None + args.append(elem) + if cont: + if function is None: + res.append(tuple(args)) + else: + res.append(function(*args)) + else: + return res + idx = idx + 1 + +def filter(function, collection): + """construct a list of those elements of collection for which function + is True. If function is None, then return the items in the sequence + which are True.""" + + if function is None: + res = [item for item in collection if item] + else: + res = [item for item in collection if function(item)] + + if type(collection) is tuple: + return tuple(res) + elif type(collection) is str: + return "".join(res) + else: + return res + +def zip(*collections): + """return a list of tuples, where the nth tuple contains every + nth item of each collection. If the collections have different + lengths, zip returns a list as long as the shortest collection, + ignoring the trailing items in the other collections.""" + + if len(collections) == 0: + raise TypeError, "zip() requires at least one sequence" + res = [] + idx = 0 + while 1: + try: + elems = [] + for collection in collections: + elems.append(collection[idx]) + res.append(tuple(elems)) + except IndexError: + break + idx = idx + 1 + return res + +def reduce(function, l, *initialt): + """ Apply function of two arguments cumulatively to the items of + sequence, from left to right, so as to reduce the sequence to a + single value. Optionally begin with an initial value.""" + + if initialt: + initial, = initialt + idx = 0 + else: + try: + initial = l[0] + except IndexError: + raise TypeError, "reduce() of empty sequence with no initial value" + idx = 1 + while 1: + try: + initial = function(initial, l[idx]) + idx = idx + 1 + except IndexError: + break + return initial + +def isinstance(obj, klass_or_tuple): + try: + objcls = obj.__class__ + except AttributeError: + objcls = type(obj) + if issubclass(klass_or_tuple.__class__, tuple): + for klass in klass_or_tuple: + if issubclass(objcls, klass): + return 1 + return 0 + else: + try: + return issubclass(objcls, klass_or_tuple) + except TypeError: + raise TypeError, "isinstance() arg 2 must be a class or type" + +def range(x, y=None, step=1): + """ returns a list of integers in arithmetic position from start (defaults + to zero) to stop - 1 by step (defaults to 1). Use a negative step to + get a list in decending order.""" + + if y is None: + start = 0 + stop = x + else: + start = x + stop = y + + if step == 0: + raise ValueError, 'range() arg 3 must not be zero' + + elif step > 0: + if stop <= start: # no work for us + return [] + howmany = (stop - start + step - 1)/step + + else: # step must be < 0, or we would have raised ValueError + if stop >= start: # no work for us + return [] + howmany = (start - stop - step - 1)/-step + + arr = [None] * howmany # this is to avoid using append. + + i = start + n = 0 + while n < howmany: + arr[n] = i + i += step + n += 1 + + return arr + +# min and max could be one function if we had operator.__gt__ and +# operator.__lt__ Perhaps later when we have operator. + +def min(*arr): + """return the smallest number in a list""" + + if not arr: + raise TypeError, 'min() takes at least one argument' + + if len(arr) == 1: + arr = arr[0] + + iterator = iter(arr) + try: + min = iterator.next() + except StopIteration: + raise ValueError, 'min() arg is an empty sequence' + + for i in iterator: + if min > i: + min = i + return min + +def max(*arr): + """return the largest number in a list""" + + if not arr: + raise TypeError, 'max() takes at least one argument' + + if len(arr) == 1: + arr = arr[0] + + iterator = iter(arr) + try: + max = iterator.next() + except StopIteration: + raise ValueError, 'max() arg is an empty sequence' + + for i in iterator: + if max < i: + max = i + return max + +def divmod(x, y): + return x//y, x%y + +def cmp(x, y): + """return 0 when x == y, -1 when x < y and 1 when x > y """ + if x < y: + return -1 + elif x == y: + return 0 + else: + return 1 + +def vars(*obj): + """return a dictionary of all the attributes currently bound in obj. If + called with no argument, return the variables bound in local scope.""" + + if len(obj) == 0: + return _caller_locals() + elif len(obj) != 1: + raise TypeError, "vars() takes at most 1 argument." + else: + try: + return obj[0].__dict__ + except AttributeError: + raise TypeError, "vars() argument must have __dict__ attribute" + +def hasattr(ob, attr): + try: + getattr(ob, attr) + return True + except AttributeError: + return False + +def callable(ob): + # XXX remove 't is type' when we have proper types + # that make this check no longer needed + t = type(ob) + return t is type or hasattr(t, '__call__') + +def dir(*args): + """dir([object]) -> list of strings + + Return an alphabetized list of names comprising (some of) the attributes + of the given object, and of attributes reachable from it: + + No argument: the names in the current scope. + Module object: the module attributes. + Type or class object: its attributes, and recursively the attributes of + its bases. + Otherwise: its attributes, its class's attributes, and recursively the + attributes of its class's base classes. """ - - __name__ = '__builtin__' + if len(args) > 1: + raise TypeError("dir expected at most 1 arguments, got %d" + % len(args)) + if len(args) == 0: + local_names = _caller_locals().keys() # 2 stackframes away + local_names.sort() + return local_names + + import types + def _classdir(klass): + """Return a dict of the accessible attributes of class/type klass. - open = cpy_builtin.open - file = cpy_builtin.file + This includes all attributes of klass and all of the + base classes recursively. -## def __init__(self, space): -## #app level __import__ helpers -## self.w_imp_modules = space.sys.w_modules -## self.w_imp_path = space.sys.w_path -## ExtModule.__init__(self, space) - - def __init__(self, space): - self.w___debug__ = space.newbool(1) - # Fix this later to show Ctrl-D on Unix - self.w_quit = self.w_exit = space.wrap("Use Ctrl-Z (i.e. EOF) to exit.") - # XXX To-do: Add copyright, credits, and license - ExtModule.__init__(self, space) - - def _initcompiledbuiltins(self): - """ add 'compiled' builtins to app-level dict and interp-level """ - self._eval_app_source(xrange_appsource) - self._eval_app_source(newstyleclasses) - - def _actframe(self, index=-1): - return self.space.getexecutioncontext().framestack.items[index] - - def globals(self): - return self._actframe().w_globals - - def private_caller_locals(self): - #print self.__dict__.keys() - return self._actframe(-2).getdictscope() - - def locals(self): - return self._actframe().getdictscope() - - def __import__(self, w_modulename, w_globals=None, - w_locals=None, w_fromlist=None): - space = self.space - w = space.wrap + The values of this dict have no meaning - only the keys have + meaning. + """ + Dict = {} try: - w_mod = space.getitem(space.sys.w_modules, w_modulename) - return w_mod - except OperationError,e: - if not e.match(space, space.w_KeyError): - raise - w_mod = space.get_builtin_module(space.unwrap(w_modulename)) - if w_mod is not None: - space.setitem(space.sys.w_modules, w_modulename, w_mod) - return w_mod - - import os - for path in space.unpackiterable(space.sys.w_path): - f = os.path.join(space.unwrap(path), space.unwrap(w_modulename) + '.py') - if os.path.exists(f): - w_mod = space.wrap(Module(space, w_modulename)) - space.setitem(space.sys.w_modules, w_modulename, w_mod) - space.setattr(w_mod, w('__file__'), w(f)) - w_dict = space.getattr(w_mod, w('__dict__')) - self.execfile(w(f), w_dict, w_dict) - return w_mod - - w_exc = space.call_function(space.w_ImportError, w_modulename) - raise OperationError(space.w_ImportError, w_exc) + Dict.update(klass.__dict__) + except AttributeError: pass + try: + # XXX - Use of .__mro__ would be suggested, if the existance + # of that attribute could be guarranted. + bases = klass.__bases__ + except AttributeError: pass + else: + try: + #Note that since we are only interested in the keys, + # the order we merge classes is unimportant + for base in bases: + Dict.update(_classdir(base)) + except TypeError: pass + return Dict + #End _classdir + + obj = args[0] + + if isinstance(obj, types.ModuleType): + try: + result = obj.__dict__.keys() + result.sort() + return result + except AttributeError: + return [] + + elif isinstance(obj, (types.TypeType, types.ClassType)): + #Don't look at __class__, as metaclass methods would be confusing. + result = _classdir(obj).keys() + result.sort() + return result + + else: #(regular item) + Dict = {} + try: + Dict.update(obj.__dict__) + except AttributeError: pass + try: + Dict.update(_classdir(obj.__class__)) + except AttributeError: pass + + ## Comment from object.c: + ## /* Merge in __members__ and __methods__ (if any). + ## XXX Would like this to go away someday; for now, it's + ## XXX needed to get at im_self etc of method objects. */ + for attr in ['__members__','__methods__']: + try: + for item in getattr(obj, attr): + if isinstance(item, types.StringTypes): + Dict[item] = None + except (AttributeError, TypeError): pass + + result = Dict.keys() + result.sort() + return result + +_stringtable = {} +def intern(s): + # XXX CPython has also non-immortal interned strings + if not isinstance(s, str): + raise TypeError("intern() argument 1 must be string.") + return _stringtable.setdefault(s,s) + +def copyright(self): + print 'Copyright 2003-2004 Pypy development team.\nAll rights reserved.\nFor further information see http://www.codespaek.net/pypy.\nSome materials may have a different copyright.\nIn these cases, this is explicitly noted in the source code file.' + +def license(self): + print \ +""" +Copyright (c) <2003-2004> + +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. +""" + +def help(self): + print "You must be joking." + + +# ______________________________________________________________________ +# +# Interpreter-level function definitions +# + +from __interplevel__ import abs, chr, len, ord, pow, repr +from __interplevel__ import hash, oct, hex, round +from __interplevel__ import getattr, setattr, delattr, iter, hash, id +from __interplevel__ import issubclass +from __interplevel__ import compile +from __interplevel__ import globals, locals, _caller_globals, _caller_locals + +from __interplevel__ import file +from __interplevel__ import file as open + +# The following must be the last import from __interplevel__ because it +# overwrites the special __import__ hook with the normal one. +from __interplevel__ import __import__ + -## def app___import__(self, *args): +# ________________________________________________________________________ + +class xrange: + def __init__(self, start, stop=None, step=1): + if stop is None: + self.start = 0 + self.stop = start + else: + self.start = start + self.stop = stop + if step == 0: + raise ValueError, 'xrange() step-argument (arg 3) must not be zero' + self.step = step + + def __len__(self): + if not hasattr(self, '_len'): + slicelength = self.stop - self.start + lengthsign = cmp(slicelength, 0) + stepsign = cmp(self.step, 0) + if stepsign == lengthsign: + self._len = (slicelength - lengthsign) // self.step + 1 + else: + self._len = 0 + return self._len + + def __getitem__(self, index): + # xrange does NOT support slicing + if not isinstance(index, int): + raise TypeError, "sequence index must be integer" + len = self.__len__() + if index<0: + index += len + if 0 <= index < len: + return self.start + index * self.step + raise IndexError, "xrange object index out of range" + + def __iter__(self): + start, stop, step = self.start, self.stop, self.step + i = start + if step > 0: + while i < stop: + yield i + i+=step + else: + while i > stop: + yield i + i+=step + + +# XXX the following comes from http://<<>> +class property(object): + + def __init__(self, fget=None, fset=None, fdel=None, doc=None): + self.fget = fget + self.fset = fset + self.fdel = fdel + self.__doc__ = doc or "" + + def __get__(self, obj, objtype=None): + if obj is None: + return self + if self.fget is None: + raise AttributeError, "unreadable attribute" + return self.fget(obj) + + def __set__(self, obj, value): + if self.fset is None: + raise AttributeError, "can't set attribute" + self.fset(obj, value) + + def __delete__(self, obj): + if self.fdel is None: + raise AttributeError, "can't delete attribute" + self.fdel(obj, value) + + +class staticmethod(object): + + def __init__(self, f): + self.f = f + + def __get__(self, obj, objtype=None): + return self.f + + +class classmethod(object): + + def __init__(self, f): + self.f = f + + def __get__(self, obj, klass=None): + if klass is None: + klass = type(obj) + def newfunc(*args): + return self.f(klass, *args) + return newfunc + + +# ________________________________________________________________________ +## def app___import__(*args): ## # NOTE: No import statements can be done in this function, ## # as that would involve a recursive call to this function ... ## @@ -199,607 +645,14 @@ ## return self.imp_modules[names[0]] ## ## # Interpreter level helpers for app level import -## def imp_dirname(self, *args_w): +## def imp_dirname(*args_w): ## return self.space.wrap(os.path.dirname(*self.space.unwrap(args_w))) ## -## def imp_join(self, *args_w): +## def imp_join(*args_w): ## return self.space.wrap(os.path.join(*self.space.unwrap(args_w))) ## -## def imp_exists(self, *args_w): +## def imp_exists(*args_w): ## return self.space.wrap(os.path.exists(*self.space.unwrap(args_w))) ## -## def imp_module(self, w_name): +## def imp_module(w_name): ## return self.space.wrap(Module(self.space, w_name)) - - def compile(self, w_str, w_filename, w_startstr, - w_supplied_flags=None, w_dont_inherit=None): - space = self.space - str_ = space.unwrap(w_str) - filename = space.unwrap(w_filename) - startstr = space.unwrap(w_startstr) - if w_supplied_flags is None: - supplied_flags = 0 - else: - supplied_flags = space.unwrap(w_supplied_flags) - if supplied_flags is None: - supplied_flags = 0 - if w_dont_inherit is None: - dont_inherit = 0 - else: - dont_inherit = space.unwrap(w_dont_inherit) - if dont_inherit is None: - dont_inherit = 0 - - #print (str_, filename, startstr, supplied_flags, dont_inherit) - # XXX we additionally allow GENERATORS because compiling some builtins - # requires it. doesn't feel quite right to do that here. - try: - c = cpy_builtin.compile(str_, filename, startstr, supplied_flags|4096, dont_inherit) - # It would be nice to propagate all exceptions to app level, - # but here we only propagate the 'usual' ones, until we figure - # out how to do it generically. - except ValueError,e: - raise OperationError(space.w_ValueError,space.wrap(str(e))) - except TypeError,e: - raise OperationError(space.w_TypeError,space.wrap(str(e))) - from pypy.interpreter.pycode import PyCode - return space.wrap(PyCode()._from_code(c)) - - def app_execfile(self, filename, glob=None, loc=None): - if glob is None: - glob = globals() - if loc is None: - loc = locals() - elif loc is None: - loc = glob - f = file(filename) - try: - source = f.read() - finally: - f.close() - #Don't exec the source directly, as this loses the filename info - co = compile(source, filename, 'exec') - exec co in glob, loc - - ####essentially implemented by the objectspace - def abs(self, w_val): - return self.space.abs(w_val) - - def chr(self, w_ascii): - w_character = self.space.newstring([w_ascii]) - return w_character - - def len(self, w_obj): - return self.space.len(w_obj) - - def delattr(self, w_object, w_name): - self.space.delattr(w_object, w_name) - return self.space.w_None - - def getattr(self, w_object, w_name, w_defvalue = _noarg): - try: - return self.space.getattr(w_object, w_name) - except OperationError, e: - if e.match(self.space, self.space.w_AttributeError): - if w_defvalue is not _noarg: - return w_defvalue - raise - - def hash(self, w_object): - return self.space.hash(w_object) - - def oct(self, w_val): - # XXX does this need to be a space operation? - return self.space.oct(w_val) - - def hex(self, w_val): - return self.space.hex(w_val) - - def round(self, w_val, w_n=None): - if w_n is None: - w_n = self.space.wrap(0) - return self.space.round(w_val, w_n) - - def id(self, w_object): - return self.space.id(w_object) - - def app_sum(self, sequence, total=0): - for item in sequence: - total = total + item - return total - - # This function was not in the original builtins, - # but is quite useful for some aspects of PyPy - # implementation. - def app_sign(self, a): - if a > 0: - return 1 - elif a < 0: - return -1 - else: - return 0 - - #XXX works only for new-style classes. - #So we have to fix it, when we add support for old-style classes - def issubclass(self, w_cls1, w_cls2): - return self.space.issubtype(w_cls1, w_cls2) - - def iter(self, w_collection_or_callable, w_sentinel = _noarg): - if w_sentinel is _noarg: - return self.space.iter(w_collection_or_callable) - else: - if not self.space.is_true(self.callable(w_collection_or_callable)): - raise OperationError(self.space.w_TypeError, - self.space.wrap('iter(v, w): v must be callable')) - return self._iter_generator(w_collection_or_callable, w_sentinel) - - def app__iter_generator(self, callable_, sentinel): - """ This generator implements the __iter__(callable,sentinel) protocol """ - while 1: - result = callable_() - if result == sentinel: - raise StopIteration - yield result - - def app_enumerate(self, collection): - 'Generates an indexed series: (0,coll[0]), (1,coll[1]) ...' - i = 0 - it = iter(collection) - while 1: - yield (i, it.next()) - i += 1 - - def ord(self, w_val): - return self.space.ord(w_val) - - def pow(self, w_base, w_exponent, w_modulus=None): - if w_modulus is None: - w_modulus = self.space.w_None - return self.space.pow(w_base, w_exponent, w_modulus) - - def repr(self, w_object): - return self.space.repr(w_object) - - def setattr(self, w_object, w_name, w_val): - self.space.setattr(w_object, w_name, w_val) - return self.space.w_None - - # app-level functions - - def app_apply(self, function, args, kwds={}): - """call a function (or other callable object) and return its result""" - return function(*args, **kwds) - - def app_map(self, function, *collections): - """does 3 separate things, hence this enormous docstring. - 1. if function is None, return a list of tuples, each with one - item from each collection. If the collections have different - lengths, shorter ones are padded with None. - - 2. if function is not None, and there is only one collection, - apply function to every item in the collection and return a - list of the results. - - 3. if function is not None, and there are several collections, - repeatedly call the function with one argument from each - collection. If the collections have different lengths, - shorter ones are padded with None""" - - if len(collections) == 0: - raise TypeError, "map() requires at least one sequence" - - elif len(collections) == 1: - #it's the most common case, so make it faster - if function is None: - return collections[0] - else: - return [function(x) for x in collections[0]] - else: - res = [] - idx = 0 - while 1: - cont = 0 #is any collection not empty? - args = [] - for collection in collections: - try: - elem = collection[idx] - cont = cont + 1 - except IndexError: - elem = None - args.append(elem) - if cont: - if function is None: - res.append(tuple(args)) - else: - res.append(function(*args)) - else: - return res - idx = idx + 1 - - def app_filter(self, function, collection): - """construct a list of those elements of collection for which function - is True. If function is None, then return the items in the sequence - which are True.""" - - if function is None: - res = [item for item in collection if item] - else: - res = [item for item in collection if function(item)] - - if type(collection) is tuple: - return tuple(res) - elif type(collection) is str: - return "".join(res) - else: - return res - - def app_zip(self, *collections): - """return a list of tuples, where the nth tuple contains every - nth item of each collection. If the collections have different - lengths, zip returns a list as long as the shortest collection, - ignoring the trailing items in the other collections.""" - - if len(collections) == 0: - raise TypeError, "zip() requires at least one sequence" - res = [] - idx = 0 - while 1: - try: - elems = [] - for collection in collections: - elems.append(collection[idx]) - res.append(tuple(elems)) - except IndexError: - break - idx = idx + 1 - return res - - def app_reduce(self, function, l, *initialt): - """ Apply function of two arguments cumulatively to the items of - sequence, from left to right, so as to reduce the sequence to a - single value. Optionally begin with an initial value.""" - - if initialt: - initial, = initialt - idx = 0 - else: - try: - initial = l[0] - except IndexError: - raise TypeError, "reduce() of empty sequence with no initial value" - idx = 1 - while 1: - try: - initial = function(initial, l[idx]) - idx = idx + 1 - except IndexError: - break - return initial - - def app_isinstance(self, obj, klass_or_tuple): - try: - objcls = obj.__class__ - except AttributeError: - objcls = type(obj) - if issubclass(klass_or_tuple.__class__, tuple): - for klass in klass_or_tuple: - if issubclass(objcls, klass): - return 1 - return 0 - else: - try: - return issubclass(objcls, klass_or_tuple) - except TypeError: - raise TypeError, "isinstance() arg 2 must be a class or type" - - def app_range(self, x, y=None, step=1): - """ returns a list of integers in arithmetic position from start (defaults - to zero) to stop - 1 by step (defaults to 1). Use a negative step to - get a list in decending order.""" - - if y is None: - start = 0 - stop = x - else: - start = x - stop = y - - if step == 0: - raise ValueError, 'range() arg 3 must not be zero' - - elif step > 0: - if stop <= start: # no work for us - return [] - howmany = (stop - start + step - 1)/step - - else: # step must be < 0, or we would have raised ValueError - if stop >= start: # no work for us - return [] - howmany = (start - stop - step - 1)/-step - - arr = [None] * howmany # this is to avoid using append. - - i = start - n = 0 - while n < howmany: - arr[n] = i - i += step - n += 1 - - return arr - - # min and max could be one function if we had operator.__gt__ and - # operator.__lt__ Perhaps later when we have operator. - - def app_min(self, *arr): - """return the smallest number in a list""" - - if not arr: - raise TypeError, 'min() takes at least one argument' - - if len(arr) == 1: - arr = arr[0] - - iterator = iter(arr) - try: - min = iterator.next() - except StopIteration: - raise ValueError, 'min() arg is an empty sequence' - - for i in iterator: - if min > i: - min = i - return min - - def app_max(self, *arr): - """return the largest number in a list""" - - if not arr: - raise TypeError, 'max() takes at least one argument' - - if len(arr) == 1: - arr = arr[0] - - iterator = iter(arr) - try: - max = iterator.next() - except StopIteration: - raise ValueError, 'max() arg is an empty sequence' - - for i in iterator: - if max < i: - max = i - return max - - def app_divmod(self, x, y): - return x//y, x%y - - def app_cmp(self, x, y): - """return 0 when x == y, -1 when x < y and 1 when x > y """ - if x < y: - return -1 - elif x == y: - return 0 - else: - return 1 - - def app_vars(self, *obj): - """return a dictionary of all the attributes currently bound in obj. If - called with no argument, return the variables bound in local scope.""" - - if len(obj) == 0: - return _caller_locals() - elif len(obj) != 1: - raise TypeError, "vars() takes at most 1 argument." - else: - try: - return obj[0].__dict__ - except AttributeError: - raise TypeError, "vars() argument must have __dict__ attribute" - - def app_hasattr(self, ob, attr): - try: - getattr(ob, attr) - return True - except AttributeError: - return False - - def app_callable(self, ob): - return hasattr(ob, '__call__') - - def app_dir(self, *args): - """dir([object]) -> list of strings - - Return an alphabetized list of names comprising (some of) the attributes - of the given object, and of attributes reachable from it: - - No argument: the names in the current scope. - Module object: the module attributes. - Type or class object: its attributes, and recursively the attributes of - its bases. - Otherwise: its attributes, its class's attributes, and recursively the - attributes of its class's base classes. - """ - if len(args) > 1: - raise TypeError("dir expected at most 1 arguments, got %d" - % len(args)) - if len(args) == 0: - local_names = _caller_locals().keys() # 2 stackframes away - local_names.sort() - return local_names - - import types - def _classdir(klass): - """Return a dict of the accessible attributes of class/type klass. - - This includes all attributes of klass and all of the - base classes recursively. - - The values of this dict have no meaning - only the keys have - meaning. - """ - Dict = {} - try: - Dict.update(klass.__dict__) - except AttributeError: pass - try: - # XXX - Use of .__mro__ would be suggested, if the existance - # of that attribute could be guarranted. - bases = klass.__bases__ - except AttributeError: pass - else: - try: - #Note that since we are only interested in the keys, - # the order we merge classes is unimportant - for base in bases: - Dict.update(_classdir(base)) - except TypeError: pass - return Dict - #End _classdir - - obj = args[0] - - if isinstance(obj, types.ModuleType): - try: - result = obj.__dict__.keys() - result.sort() - return result - except AttributeError: - return [] - - elif isinstance(obj, (types.TypeType, types.ClassType)): - #Don't look at __class__, as metaclass methods would be confusing. - result = _classdir(obj).keys() - result.sort() - return result - - else: #(regular item) - Dict = {} - try: - Dict.update(obj.__dict__) - except AttributeError: pass - try: - Dict.update(_classdir(obj.__class__)) - except AttributeError: pass - - ## Comment from object.c: - ## /* Merge in __members__ and __methods__ (if any). - ## XXX Would like this to go away someday; for now, it's - ## XXX needed to get at im_self etc of method objects. */ - for attr in ['__members__','__methods__']: - try: - for item in getattr(obj, attr): - if isinstance(item, types.StringTypes): - Dict[item] = None - except (AttributeError, TypeError): pass - - result = Dict.keys() - result.sort() - return result - - def app_intern(self, s): - """ - We don't have a string table, making intern a null operation. - This is here for backwards compatibility. - """ - if not isinstance(s, str): - raise TypeError("intern() argument 1 must be string.") - return s - - def app_copyright(self): - print 'Copyright 2002-2004 Pypy development team.\nAll rights reserved.\nFor further information see http://www.codespaek.net/pypy.\nSome materials may have a different copyright.\nIn these cases, this is explicitly noted in the source code file.' - - def app_license(self): - print \ -""" -Copyright (c) <2002-2004> - -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. -""" - - def app_help(self): - print "You must be joking." - -# source code for the builtin xrange-class - -xrange_appsource = """if 1: - class xrange: - def __init__(self, start, stop=None, step=1): - if stop is None: - self.start = 0 - self.stop = start - else: - self.start = start - self.stop = stop - if step == 0: - raise ValueError, 'xrange() step-argument (arg 3) must not be zero' - self.step = step - - def __iter__(self): - def gen(self): - start, stop, step = self.start, self.stop, self.step - i = start - if step > 0: - while i < stop: - yield i - i+=step - else: - while i > stop: - yield i - i+=step - return gen(self) -""" - -newstyleclasses = """ - -class property(object): - - def __init__(self, fget=None, fset=None, fdel=None, doc=None): - self.fget = fget - self.fset = fset - self.fdel = fdel - self.__doc__ = doc or "" - - def __get__(self, obj, objtype=None): - if obj is None: - return self - if self.fget is None: - raise AttributeError, "unreadable attribute" - return self.fget(obj) - - def __set__(self, obj, value): - if self.fset is None: - raise AttributeError, "can't set attribute" - self.fset(obj, value) - - def __delete__(self, obj): - if self.fdel is None: - raise AttributeError, "can't delete attribute" - self.fdel(obj, value) - - -class staticmethod(object): - - def __init__(self, f): - self.f = f - - def __get__(self, obj, objtype=None): - return self.f - - -class classmethod(object): - - def __init__(self, f): - self.f = f - - def __get__(self, obj, klass=None): - if klass is None: - klass = type(obj) - def newfunc(*args): - return self.f(klass, *args) - return newfunc -""" Modified: pypy/trunk/src/pypy/module/test/test_builtin.py ============================================================================== --- pypy/trunk/src/pypy/module/test/test_builtin.py (original) +++ pypy/trunk/src/pypy/module/test/test_builtin.py Tue Dec 23 17:53:08 2003 @@ -260,10 +260,6 @@ import os os.remove(fn) - def test_xrange(self): - self.assert_(hasattr(self.space.builtin, 'xrange')) - self.assertEquals(self.space.builtin.xrange(3).stop, 3) - if __name__ == '__main__': test.main() Modified: pypy/trunk/src/pypy/objspace/trivial.py ============================================================================== --- pypy/trunk/src/pypy/objspace/trivial.py (original) +++ pypy/trunk/src/pypy/objspace/trivial.py Tue Dec 23 17:53:08 2003 @@ -130,7 +130,11 @@ "slice": slice, } for n, c in __builtin__.__dict__.iteritems(): - if n == 'xrange': # we define this in builtin_app + 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) Modified: pypy/trunk/src/pypy/tool/fixeol ============================================================================== --- pypy/trunk/src/pypy/tool/fixeol (original) +++ pypy/trunk/src/pypy/tool/fixeol Tue Dec 23 17:53:08 2003 @@ -59,12 +59,16 @@ asserttextfile(os.path.join(dirname, fname)) numpyfiles += 1 if numpyfiles: - # ignore '*.pyc' in any directory containing .py files + # ignore '*.pyc' and '*.pyo' in any directory containing .py files g = os.popen('svn propget svn:ignore %s' % dirname) content = g.readlines() g.close() + oldlen = len(content) if '*.pyc\n' not in content: content.append('*.pyc\n') + if '*.pyo\n' not in content: + content.append('*.pyo\n') + if len(content) > oldlen: g = open('svn-ignore.tmp', 'w') g.writelines(content) g.close() From arigo at codespeak.net Tue Dec 23 17:54:37 2003 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 23 Dec 2003 17:54:37 +0100 (MET) Subject: [pypy-svn] rev 2685 - pypy/trunk/src/pypy/module Message-ID: <20031223165437.DC3645AA0B@thoth.codespeak.net> Author: arigo Date: Tue Dec 23 17:54:37 2003 New Revision: 2685 Removed: pypy/trunk/src/pypy/module/builtin.py Log: D module/builtin.py Code moved into __builtin__module.py and __builtin__interp.py. Deleted: /pypy/trunk/src/pypy/module/builtin.py ============================================================================== --- /pypy/trunk/src/pypy/module/builtin.py Tue Dec 23 17:54:37 2003 +++ (empty file) @@ -1,830 +0,0 @@ -from __future__ import generators -from pypy.interpreter import executioncontext -from pypy.interpreter.module import Module -from pypy.interpreter.extmodule import ExtModule -from pypy.interpreter.error import OperationError - -import os.path -import sys -import types - -####################### -#### __builtin__ #### -####################### - -import __builtin__ as cpy_builtin - -class _noarg: - """ use this class in interpreter level functions for default - values if you want to recognize that no specific value was - passed. - """ - -class __builtin__(ExtModule): - """ Template for PyPy's '__builtin__' module. - """ - - __name__ = '__builtin__' - - open = cpy_builtin.open - file = cpy_builtin.file - -## def __init__(self, space): -## #app level __import__ helpers -## self.w_imp_modules = space.sys.w_modules -## self.w_imp_path = space.sys.w_path -## ExtModule.__init__(self, space) - - def __init__(self, space): - self.w___debug__ = space.newbool(1) - # Fix this later to show Ctrl-D on Unix - self.w_quit = self.w_exit = space.wrap("Use Ctrl-Z (i.e. EOF) to exit.") - # XXX To-do: Add copyright, credits, and license - ExtModule.__init__(self, space) - - def _initcompiledbuiltins(self): - """ add 'compiled' builtins to app-level dict and interp-level """ - self._eval_app_source(xrange_appsource) - self._eval_app_source(newstyleclasses) - - def _actframe(self, index=-1): - return self.space.getexecutioncontext().framestack.items[index] - - def globals(self): - return self._actframe().w_globals - - def private_caller_locals(self): - #print self.__dict__.keys() - return self._actframe(-2).getdictscope() - - def locals(self): - return self._actframe().getdictscope() - - def __import__(self, w_modulename, w_globals=None, - w_locals=None, w_fromlist=None): - space = self.space - modulename = space.unwrap(w_modulename) - if not isinstance(modulename, str): - try: - helper = ', not ' + modulename.__class__.__name__ - except AttributeError: - helper = '' - raise OperationError(space.w_TypeError, - space.wrap("__import__() argument 1 must be string" + helper)) - w = space.wrap - try: - w_mod = space.getitem(space.sys.w_modules, w_modulename) - except OperationError,e: - pass - else: - return w_mod - if not e.match(space, space.w_KeyError): - raise - w_mod = space.get_builtin_module(modulename) - if w_mod is not None: - space.setitem(space.sys.w_modules, w_modulename, w_mod) - return w_mod - - import os - for path in space.unpackiterable(space.sys.w_path): - f = os.path.join(space.unwrap(path), modulename + '.py') - if os.path.exists(f): - w_mod = space.wrap(Module(space, w_modulename)) - space.setitem(space.sys.w_modules, w_modulename, w_mod) - space.setattr(w_mod, w('__file__'), w(f)) - w_dict = space.getattr(w_mod, w('__dict__')) - self.execfile(w(f), w_dict, w_dict) - return w_mod - - w_exc = space.call_function(space.w_ImportError, w_modulename) - raise OperationError(space.w_ImportError, w_exc) - -## def app___import__(self, *args): -## # NOTE: No import statements can be done in this function, -## # as that would involve a recursive call to this function ... -## -## # args => (name[, globals[, locals[, fromlist]]]) -## -## l = len(args) -## if l >= 1: -## modulename = args[0] -## else: -## raise TypeError('__import__() takes at least 1 argument (0 given)') -## if l >= 2: -## globals = args[1] -## try: -## local_context = self.imp_dirname(globals['__file__']) -## except KeyError: -## local_context = '' -## else: -## local_context = '' -## if l >= 4: -## fromlist = args[3] -## else: -## fromlist = [] -## if l > 4: -## raise TypeError('__import__() takes at most 4 arguments (%i given)' % l) -## -## def inner_load(f, fullname): -## """Load module from file `f` with canonical name `fullname`. -## """ -## mod = self.imp_module(fullname) # XXX - add in docstring -## self.imp_modules[fullname] = mod -## mod.__file__ = f -## dict = mod.__dict__ -## execfile(f, dict, dict) -## return mod -## -## def load(path, modulename, fullname): -## """Create a module. -## -## Create a mnodule with canonical name `fullname` from file -## `modulename`+'.py' in path `path`, if it exist. -## Or alternatively from the package -## `path`/`modulename`/'__init__.py'. -## If neither are found, return None. -## """ -## -## f = self.imp_join(path, modulename + '.py') -## if self.imp_exists(f): -## return inner_load(f, fullname) -## f = self.imp_join(path, modulename, '__init__.py') -## if self.imp_exists(f): -## return inner_load(f, fullname) -## else: -## return None -## -## names = modulename.split('.') -## -## if not names: -## raise ValueError("Cannot import an empty module name.") -## if len(names) == 1: -## if self.imp_modules.has_key(modulename): -## return self.imp_modules[modulename] -## #Relative Import -## if local_context: -## #Regular Module -## module = load(local_context, modulename, modulename) -## if module: -## return module -## #Standard Library Module Import -## for path in self.imp_path: -## #Regular Module -## module = load(path, modulename, modulename) -## if module: -## return module -## #Module Not Found -## raise ImportError(modulename) -## else: -## #Find most specific module already imported. -## for i in range(len(names),0,-1): -## base_name = '.'.join(names[0:i]) -## if self.imp_modules.has_key(base_name): -## break -## #Top level package not imported - import it. -## else: -## base_name = names[0] -## i = 1 -## #Relative Import -## if ((not local_context) or -## not load(local_context, base_name, base_name)): -## #Standard Module Import -## for path in self.imp_path: -## if load(path, base_name, base_name): -## break -## else: -## #Module Not Found -## raise ImportError(base_name) -## path = self.imp_dirname(self.imp_modules[base_name].__file__) -## full_name = base_name -## for j in range(i,len(names)): -## path = self.imp_join(path, names[j]) -## full_name = '.'.join((full_name, names[j])) -## if not load(path, '__init__', full_name): -## raise ImportError(full_name) -## ### load module from path -## if fromlist: -## return self.imp_modules[modulename] -## else: -## return self.imp_modules[names[0]] -## -## # Interpreter level helpers for app level import -## def imp_dirname(self, *args_w): -## return self.space.wrap(os.path.dirname(*self.space.unwrap(args_w))) -## -## def imp_join(self, *args_w): -## return self.space.wrap(os.path.join(*self.space.unwrap(args_w))) -## -## def imp_exists(self, *args_w): -## return self.space.wrap(os.path.exists(*self.space.unwrap(args_w))) -## -## def imp_module(self, w_name): -## return self.space.wrap(Module(self.space, w_name)) - - def compile(self, w_str, w_filename, w_startstr, - w_supplied_flags=None, w_dont_inherit=None): - space = self.space - str_ = space.unwrap(w_str) - filename = space.unwrap(w_filename) - startstr = space.unwrap(w_startstr) - if w_supplied_flags is None: - supplied_flags = 0 - else: - supplied_flags = space.unwrap(w_supplied_flags) - if supplied_flags is None: - supplied_flags = 0 - if w_dont_inherit is None: - dont_inherit = 0 - else: - dont_inherit = space.unwrap(w_dont_inherit) - if dont_inherit is None: - dont_inherit = 0 - - #print (str_, filename, startstr, supplied_flags, dont_inherit) - # XXX we additionally allow GENERATORS because compiling some builtins - # requires it. doesn't feel quite right to do that here. - try: - c = cpy_builtin.compile(str_, filename, startstr, supplied_flags|4096, dont_inherit) - # It would be nice to propagate all exceptions to app level, - # but here we only propagate the 'usual' ones, until we figure - # out how to do it generically. - except ValueError,e: - raise OperationError(space.w_ValueError,space.wrap(str(e))) - except TypeError,e: - raise OperationError(space.w_TypeError,space.wrap(str(e))) - from pypy.interpreter.pycode import PyCode - return space.wrap(PyCode()._from_code(c)) - - def app_execfile(self, filename, glob=None, loc=None): - if glob is None: - glob = globals() - if loc is None: - loc = locals() - elif loc is None: - loc = glob - f = file(filename) - try: - source = f.read() - finally: - f.close() - #Don't exec the source directly, as this loses the filename info - co = compile(source, filename, 'exec') - exec co in glob, loc - - ####essentially implemented by the objectspace - def abs(self, w_val): - return self.space.abs(w_val) - - def chr(self, w_ascii): - w_character = self.space.newstring([w_ascii]) - return w_character - - def len(self, w_obj): - return self.space.len(w_obj) - - def delattr(self, w_object, w_name): - self.space.delattr(w_object, w_name) - return self.space.w_None - - def getattr(self, w_object, w_name, w_defvalue = _noarg): - try: - return self.space.getattr(w_object, w_name) - except OperationError, e: - if e.match(self.space, self.space.w_AttributeError): - if w_defvalue is not _noarg: - return w_defvalue - raise - - def hash(self, w_object): - return self.space.hash(w_object) - - def oct(self, w_val): - # XXX does this need to be a space operation? - return self.space.oct(w_val) - - def hex(self, w_val): - return self.space.hex(w_val) - - def round(self, w_val, w_n=None): - if w_n is None: - w_n = self.space.wrap(0) - return self.space.round(w_val, w_n) - - def id(self, w_object): - return self.space.id(w_object) - - def app_sum(self, sequence, total=0): - # must forbid "summing" strings, per specs of built-in 'sum' - if isinstance(total, str): raise TypeError - for item in sequence: - total = total + item - return total - - #XXX works only for new-style classes. - #So we have to fix it, when we add support for old-style classes - def issubclass(self, w_cls1, w_cls2): - return self.space.issubtype(w_cls1, w_cls2) - - def iter(self, w_collection_or_callable, w_sentinel = _noarg): - if w_sentinel is _noarg: - return self.space.iter(w_collection_or_callable) - else: - if not self.space.is_true(self.callable(w_collection_or_callable)): - raise OperationError(self.space.w_TypeError, - self.space.wrap('iter(v, w): v must be callable')) - return self._iter_generator(w_collection_or_callable, w_sentinel) - - def app__iter_generator(self, callable_, sentinel): - """ This generator implements the __iter__(callable,sentinel) protocol """ - while 1: - result = callable_() - if result == sentinel: - raise StopIteration - yield result - - def app_enumerate(self, collection): - 'Generates an indexed series: (0,coll[0]), (1,coll[1]) ...' - i = 0 - it = iter(collection) - while 1: - yield (i, it.next()) - i += 1 - - def ord(self, w_val): - return self.space.ord(w_val) - - def pow(self, w_base, w_exponent, w_modulus=None): - if w_modulus is None: - w_modulus = self.space.w_None - return self.space.pow(w_base, w_exponent, w_modulus) - - def repr(self, w_object): - return self.space.repr(w_object) - - def setattr(self, w_object, w_name, w_val): - self.space.setattr(w_object, w_name, w_val) - return self.space.w_None - - # app-level functions - - def app_apply(self, function, args, kwds={}): - """call a function (or other callable object) and return its result""" - return function(*args, **kwds) - - def app_map(self, function, *collections): - """does 3 separate things, hence this enormous docstring. - 1. if function is None, return a list of tuples, each with one - item from each collection. If the collections have different - lengths, shorter ones are padded with None. - - 2. if function is not None, and there is only one collection, - apply function to every item in the collection and return a - list of the results. - - 3. if function is not None, and there are several collections, - repeatedly call the function with one argument from each - collection. If the collections have different lengths, - shorter ones are padded with None - """ - - if len(collections) == 0: - raise TypeError, "map() requires at least one sequence" - - elif len(collections) == 1: - #it's the most common case, so make it faster - if function is None: - return list(collections[0]) - else: - return [function(x) for x in collections[0]] - else: - res = [] - idx = 0 - while 1: - cont = 0 #is any collection not empty? - args = [] - for collection in collections: - try: - elem = collection[idx] - cont = cont + 1 - except IndexError: - elem = None - args.append(elem) - if cont: - if function is None: - res.append(tuple(args)) - else: - res.append(function(*args)) - else: - return res - idx = idx + 1 - - def app_filter(self, function, collection): - """construct a list of those elements of collection for which function - is True. If function is None, then return the items in the sequence - which are True.""" - - if function is None: - res = [item for item in collection if item] - else: - res = [item for item in collection if function(item)] - - if type(collection) is tuple: - return tuple(res) - elif type(collection) is str: - return "".join(res) - else: - return res - - def app_zip(self, *collections): - """return a list of tuples, where the nth tuple contains every - nth item of each collection. If the collections have different - lengths, zip returns a list as long as the shortest collection, - ignoring the trailing items in the other collections.""" - - if len(collections) == 0: - raise TypeError, "zip() requires at least one sequence" - res = [] - idx = 0 - while 1: - try: - elems = [] - for collection in collections: - elems.append(collection[idx]) - res.append(tuple(elems)) - except IndexError: - break - idx = idx + 1 - return res - - def app_reduce(self, function, l, *initialt): - """ Apply function of two arguments cumulatively to the items of - sequence, from left to right, so as to reduce the sequence to a - single value. Optionally begin with an initial value.""" - - if initialt: - initial, = initialt - idx = 0 - else: - try: - initial = l[0] - except IndexError: - raise TypeError, "reduce() of empty sequence with no initial value" - idx = 1 - while 1: - try: - initial = function(initial, l[idx]) - idx = idx + 1 - except IndexError: - break - return initial - - def app_isinstance(self, obj, klass_or_tuple): - try: - objcls = obj.__class__ - except AttributeError: - objcls = type(obj) - if issubclass(klass_or_tuple.__class__, tuple): - for klass in klass_or_tuple: - if issubclass(objcls, klass): - return 1 - return 0 - else: - try: - return issubclass(objcls, klass_or_tuple) - except TypeError: - raise TypeError, "isinstance() arg 2 must be a class or type" - - def app_range(self, x, y=None, step=1): - """ returns a list of integers in arithmetic position from start (defaults - to zero) to stop - 1 by step (defaults to 1). Use a negative step to - get a list in decending order.""" - - if y is None: - start = 0 - stop = x - else: - start = x - stop = y - - if step == 0: - raise ValueError, 'range() arg 3 must not be zero' - - elif step > 0: - if stop <= start: # no work for us - return [] - howmany = (stop - start + step - 1)/step - - else: # step must be < 0, or we would have raised ValueError - if stop >= start: # no work for us - return [] - howmany = (start - stop - step - 1)/-step - - arr = [None] * howmany # this is to avoid using append. - - i = start - n = 0 - while n < howmany: - arr[n] = i - i += step - n += 1 - - return arr - - # min and max could be one function if we had operator.__gt__ and - # operator.__lt__ Perhaps later when we have operator. - - def app_min(self, *arr): - """return the smallest number in a list""" - - if not arr: - raise TypeError, 'min() takes at least one argument' - - if len(arr) == 1: - arr = arr[0] - - iterator = iter(arr) - try: - min = iterator.next() - except StopIteration: - raise ValueError, 'min() arg is an empty sequence' - - for i in iterator: - if min > i: - min = i - return min - - def app_max(self, *arr): - """return the largest number in a list""" - - if not arr: - raise TypeError, 'max() takes at least one argument' - - if len(arr) == 1: - arr = arr[0] - - iterator = iter(arr) - try: - max = iterator.next() - except StopIteration: - raise ValueError, 'max() arg is an empty sequence' - - for i in iterator: - if max < i: - max = i - return max - - def app_divmod(self, x, y): - return x//y, x%y - - def app_cmp(self, x, y): - """return 0 when x == y, -1 when x < y and 1 when x > y """ - if x < y: - return -1 - elif x == y: - return 0 - else: - return 1 - - def app_vars(self, *obj): - """return a dictionary of all the attributes currently bound in obj. If - called with no argument, return the variables bound in local scope.""" - - if len(obj) == 0: - return _caller_locals() - elif len(obj) != 1: - raise TypeError, "vars() takes at most 1 argument." - else: - try: - return obj[0].__dict__ - except AttributeError: - raise TypeError, "vars() argument must have __dict__ attribute" - - def app_hasattr(self, ob, attr): - try: - getattr(ob, attr) - return True - except AttributeError: - return False - - def app_callable(self, ob): - t = type(ob) - return t is type or hasattr(t, '__call__') - - def app_dir(self, *args): - """dir([object]) -> list of strings - - Return an alphabetized list of names comprising (some of) the attributes - of the given object, and of attributes reachable from it: - - No argument: the names in the current scope. - Module object: the module attributes. - Type or class object: its attributes, and recursively the attributes of - its bases. - Otherwise: its attributes, its class's attributes, and recursively the - attributes of its class's base classes. - """ - if len(args) > 1: - raise TypeError("dir expected at most 1 arguments, got %d" - % len(args)) - if len(args) == 0: - local_names = _caller_locals().keys() # 2 stackframes away - local_names.sort() - return local_names - - import types - def _classdir(klass): - """Return a dict of the accessible attributes of class/type klass. - - This includes all attributes of klass and all of the - base classes recursively. - - The values of this dict have no meaning - only the keys have - meaning. - """ - Dict = {} - try: - Dict.update(klass.__dict__) - except AttributeError: pass - try: - # XXX - Use of .__mro__ would be suggested, if the existance - # of that attribute could be guarranted. - bases = klass.__bases__ - except AttributeError: pass - else: - try: - #Note that since we are only interested in the keys, - # the order we merge classes is unimportant - for base in bases: - Dict.update(_classdir(base)) - except TypeError: pass - return Dict - #End _classdir - - obj = args[0] - - if isinstance(obj, types.ModuleType): - try: - result = obj.__dict__.keys() - result.sort() - return result - except AttributeError: - return [] - - elif isinstance(obj, (types.TypeType, types.ClassType)): - #Don't look at __class__, as metaclass methods would be confusing. - result = _classdir(obj).keys() - result.sort() - return result - - else: #(regular item) - Dict = {} - try: - Dict.update(obj.__dict__) - except AttributeError: pass - try: - Dict.update(_classdir(obj.__class__)) - except AttributeError: pass - - ## Comment from object.c: - ## /* Merge in __members__ and __methods__ (if any). - ## XXX Would like this to go away someday; for now, it's - ## XXX needed to get at im_self etc of method objects. */ - for attr in ['__members__','__methods__']: - try: - for item in getattr(obj, attr): - if isinstance(item, types.StringTypes): - Dict[item] = None - except (AttributeError, TypeError): pass - - result = Dict.keys() - result.sort() - return result - - def app_intern(self, s): - if not isinstance(s, str): - raise TypeError("intern() argument 1 must be string.") - try: - t = self._stringtable - except AttributeError: - t = self._stringtable = {} - return t.setdefault(s,s) - - def app_copyright(self): - print 'Copyright 2002-2004 Pypy development team.\nAll rights reserved.\nFor further information see http://www.codespaek.net/pypy.\nSome materials may have a different copyright.\nIn these cases, this is explicitly noted in the source code file.' - - def app_license(self): - print \ -""" -Copyright (c) <2002-2004> - -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. -""" - - def app_help(self): - print "You must be joking." - -# source code for the builtin xrange-class - -xrange_appsource = """if 1: - class xrange: - def __init__(self, start, stop=None, step=1): - if stop is None: - self.start = 0 - self.stop = start - else: - self.start = start - self.stop = stop - if step == 0: - raise ValueError, 'xrange() step-argument (arg 3) must not be zero' - self.step = step - - def __len__(self): - if not hasattr(self, '_len'): - slicelength = self.stop - self.start - lengthsign = cmp(slicelength, 0) - stepsign = cmp(self.step, 0) - if stepsign == lengthsign: - self._len = (slicelength - lengthsign) // self.step + 1 - else: - self._len = 0 - return self._len - - def __getitem__(self, index): - # xrange does NOT support slicing - if not isinstance(index, int): - raise TypeError, "sequence index must be integer" - len = self.__len__() - if index<0: - index += len - if 0 <= index < len: - return self.start + index * self.step - raise IndexError, "xrange object index out of range" - - def __iter__(self): - def gen(self): - start, stop, step = self.start, self.stop, self.step - i = start - if step > 0: - while i < stop: - yield i - i+=step - else: - while i > stop: - yield i - i+=step - return gen(self) -""" - -newstyleclasses = """ - -class property(object): - - def __init__(self, fget=None, fset=None, fdel=None, doc=None): - self.fget = fget - self.fset = fset - self.fdel = fdel - self.__doc__ = doc or "" - - def __get__(self, obj, objtype=None): - if obj is None: - return self - if self.fget is None: - raise AttributeError, "unreadable attribute" - return self.fget(obj) - - def __set__(self, obj, value): - if self.fset is None: - raise AttributeError, "can't set attribute" - self.fset(obj, value) - - def __delete__(self, obj): - if self.fdel is None: - raise AttributeError, "can't delete attribute" - self.fdel(obj, value) - - -class staticmethod(object): - - def __init__(self, f): - self.f = f - - def __get__(self, obj, objtype=None): - return self.f - - -class classmethod(object): - - def __init__(self, f): - self.f = f - - def __get__(self, obj, klass=None): - if klass is None: - klass = type(obj) - def newfunc(*args): - return self.f(klass, *args) - return newfunc -""" From arigo at codespeak.net Tue Dec 23 19:02:54 2003 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 23 Dec 2003 19:02:54 +0100 (MET) Subject: [pypy-svn] rev 2686 - in pypy/trunk/src/pypy: interpreter module Message-ID: <20031223180254.BD0665AA0B@thoth.codespeak.net> Author: arigo Date: Tue Dec 23 19:02:48 2003 New Revision: 2686 Added: pypy/trunk/src/pypy/module/sysinterp.py (contents, props changed) Modified: pypy/trunk/src/pypy/interpreter/baseobjspace.py pypy/trunk/src/pypy/interpreter/extmodule.py pypy/trunk/src/pypy/module/__builtin__interp.py pypy/trunk/src/pypy/module/sysmodule.py Log: Converted the 'sys' module to the new format. Slightly simplified the logic in extmodule.py to assume that interpreter-level objects are prefixed with 'w_' when wrapped, and are otherwise plain functions to be exported at app-level. Modified: pypy/trunk/src/pypy/interpreter/baseobjspace.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/baseobjspace.py (original) +++ pypy/trunk/src/pypy/interpreter/baseobjspace.py Tue Dec 23 19:02:48 2003 @@ -74,17 +74,17 @@ #print "setitem: space instance %-20s into builtins" % name self.setitem(self.w_builtins, self.wrap(name), value) - self.sys._setbuiltinmodule(self.w_builtin) + self.sys.setbuiltinmodule(self.w_builtin) #Now we can load all the builtin (interpreter level) modules. self.make_builtin_modules() def make_sys(self): + from pypy.interpreter.extmodule import BuiltinModule assert not hasattr(self, 'sys') - from pypy.module import sysmodule - self.sys = sysmodule.Sys(self) + self.sys = BuiltinModule(self, 'sys') self.w_sys = self.wrap(self.sys) - self.sys._setbuiltinmodule(self.w_sys) + self.sys.setbuiltinmodule(self.w_sys) def make_builtin_modules(self): for filename, classname, spaces in pypy.module._builtin_modules: @@ -95,7 +95,7 @@ klass = getattr(mod, classname) module = klass(self) if module is not None: - self.sys._setbuiltinmodule(self.wrap(module)) + self.sys.setbuiltinmodule(self.wrap(module)) # XXX get rid of this. def get_builtin_module(self, name): Modified: pypy/trunk/src/pypy/interpreter/extmodule.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/extmodule.py (original) +++ pypy/trunk/src/pypy/interpreter/extmodule.py Tue Dec 23 19:02:48 2003 @@ -18,6 +18,7 @@ def __init__(self, space, modulename, w_dict=None): Module.__init__(self, space, space.wrap(modulename), w_dict) + w_dict = self.w_dict # Compile the xxxmodule.py source file modulefile = os.path.join(autopath.pypydir, 'module', @@ -32,8 +33,9 @@ # Set the hooks that call back from app-level to interp-level w_builtins = space.w_builtins self.__saved_hooks = {} - self.__interplevelfile = os.path.join(autopath.pypydir, 'module', - modulename+'interp.py') + self.__file__ = os.path.join(autopath.pypydir, 'module', + modulename+'interp.py') + self.__import_interplevel = True newhooks = {} for name, hook in [('__interplevel__exec', self.app_interplevelexec), ('__interplevel__eval', self.app_interpleveleval), @@ -50,6 +52,7 @@ space.w_builtins) # Run the app-level module definition (xxxmodule.py) + space.setitem(w_dict, space.wrap('__file__'), space.wrap(modulefile)) pycode.exec_code(space, w_dict, w_dict) # Run the interp-level definition (xxxinterp.py) @@ -74,30 +77,16 @@ def loadinterplevelfile(self): try: - filename = self.__interplevelfile + self.__import_interplevel except AttributeError: pass # already loaded else: - del self.__interplevelfile + del self.__import_interplevel # temporarily install an '__applevel__' pseudo-module sys.modules['__applevel__'] = BuiltinModule.AppModuleHack(self) - execfile(filename, self.__dict__) + execfile(self.__file__, self.__dict__) del sys.modules['__applevel__'] - def get_interp2app(self, result): - space = self.space - if result is None: - result = space.w_None - elif isinstance(result, types.FunctionType): - f = result - code = gateway.BuiltinCode(f, ismethod=False, spacearg=False) - defs_w = list(f.func_defaults or ()) - func = Function(space, code, self.w_dict, defs_w) - result = space.wrap(func) - else: - pass # assume that 'result' is a wrapped object in other cases - return result - def interplevelexec(self, w_codestring): codestring = self.space.unwrap(w_codestring) exec codestring in self.__dict__ @@ -106,8 +95,10 @@ def interpleveleval(self, w_codestring): space = self.space codestring = space.unwrap(w_codestring) - result = eval(codestring, self.__dict__) - return self.get_interp2app(result) + w_result = eval(codestring, self.__dict__) + if w_result is None: + w_result = space.w_None # else assume that it is already wrapped + return w_result def interplevelimport(self, w_modulename, w_globals, w_locals, w_fromlist): space = self.space @@ -117,8 +108,16 @@ if w_fromlist == space.w_None: raise ImportError, "must use 'from __interplevel__ import xx'" for w_name in space.unpacktuple(w_fromlist): - result = getattr(self, space.unwrap(w_name)) - w_result = self.get_interp2app(result) + name = space.unwrap(w_name) + if hasattr(self, name): + f = getattr(self, name) + code = gateway.BuiltinCode(f, ismethod=False, + spacearg=False) + defs_w = list(f.func_defaults or ()) + func = Function(space, code, self.w_dict, defs_w) + w_result = space.wrap(func) + else: + w_result = getattr(self, 'w_' + name) space.setitem(self.w_dict, w_name, w_result) return space.wrap(self) else: Modified: pypy/trunk/src/pypy/module/__builtin__interp.py ============================================================================== --- pypy/trunk/src/pypy/module/__builtin__interp.py (original) +++ pypy/trunk/src/pypy/module/__builtin__interp.py Tue Dec 23 19:02:48 2003 @@ -8,7 +8,7 @@ _noarg = object() import __builtin__ as cpy_builtin -file = space.wrap(cpy_builtin.file) +w_file = space.wrap(cpy_builtin.file) # import useful app-level functions from __applevel__ import execfile, callable, _iter_generator Added: pypy/trunk/src/pypy/module/sysinterp.py ============================================================================== --- (empty file) +++ pypy/trunk/src/pypy/module/sysinterp.py Tue Dec 23 19:02:48 2003 @@ -0,0 +1,58 @@ +""" +Implementation of interpreter-level 'sys' routines. +""" +import os +from pypy.interpreter import autopath +from pypy.interpreter.module import Module +from pypy.interpreter.pycode import PyCode +from pypy.interpreter.error import OperationError + +import sys as cpy_sys + +# Common data structures +w_modules = space.newdict([]) +w_warnoptions = space.newlist([]) +w_builtin_module_names = space.newlist([]) + +# Initialize the default path +srcdir = os.path.dirname(autopath.pypydir) +appdir = os.path.join(autopath.pypydir, 'appspace') +w_path = space.newlist([space.wrap(appdir)] + + [space.wrap(p) for p in cpy_sys.path if p!= srcdir]) + +# XXX - Replace with appropriate PyPy version numbering +w_hexversion = space.wrap(cpy_sys.hexversion) +w_platform = space.wrap(cpy_sys.platform) +w_maxint = space.wrap(cpy_sys.maxint) + +w_stdin = space.wrap(cpy_sys.stdin) +w_stdout = space.wrap(cpy_sys.stdout) +w_stderr = space.wrap(cpy_sys.stderr) + + +def setmodule(w_module): + """ put a module into the modules list """ + w_name = space.getattr(w_module, space.wrap('__name__')) + space.setitem(w_modules, w_name, w_module) + +def setbuiltinmodule(w_module): + """ put a module into modules list and builtin_module_names """ + w_name = space.getattr(w_module, space.wrap('__name__')) + w_append = space.getattr(w_builtin_module_names, space.wrap('append')) + space.call_function(w_append, w_name) + space.setitem(w_modules, w_name, w_module) + +def displayhook(w_x): + w = space.wrap + if not space.is_true(space.is_(w_x, space.w_None)): + try: + # XXX don't use print, send to sys.stdout instead + print space.unwrap(space.repr(w_x)) + except OperationError: + print "! could not print", w_x + space.setitem(space.w_builtins, w('_'), w_x) + +def _getframe(): + # XXX No Argument Accepted Yet + f = space.getexecutioncontext().framestack.items[-1] + return space.wrap(f) Modified: pypy/trunk/src/pypy/module/sysmodule.py ============================================================================== --- pypy/trunk/src/pypy/module/sysmodule.py (original) +++ pypy/trunk/src/pypy/module/sysmodule.py Tue Dec 23 19:02:48 2003 @@ -1,61 +1,13 @@ -from pypy.interpreter.error import OperationError -from pypy.interpreter.extmodule import ExtModule -from pypy.interpreter.gateway import interp2app -import os, pypy +""" +The 'sys' module. +""" + +# Common data structures +from __interplevel__ import path, modules, warnoptions, builtin_module_names + +# Objects from interpreter-level +from __interplevel__ import stdin, stdout, stderr, maxint +from __interplevel__ import hexversion, platform -import sys as cpy_sys - -class Sys(ExtModule): - """ Template for PyPy's 'sys' module. - - Currently we only provide a handful of attributes. - """ - - __name__ = 'sys' - - def __init__(self, space): - opd = os.path.dirname - pypydir = opd(opd(os.path.abspath(pypy.__file__))) - appdir = os.path.join(pypydir, 'pypy', 'appspace') - self.w_path = space.newlist([space.wrap(appdir)] + [space.wrap(p) for p in cpy_sys.path if p!= pypydir]) - self.w_modules = space.newdict([]) - self.w_builtin_module_names = space.newlist([]) - self.w_warnoptions = space.newlist([space.wrap(i) for i in cpy_sys.warnoptions]) - # XXX - Replace with appropriate PyPy version numbering - self.w_hexversion = space.wrap(cpy_sys.hexversion) - self.w_platform = space.wrap(cpy_sys.platform) - ExtModule.__init__(self, space) - - stdout = cpy_sys.stdout - stderr = cpy_sys.stderr - maxint = cpy_sys.maxint - - def _setmodule(self, w_module): - """ put a module into the modules list """ - w_name = self.space.getattr(w_module, self.space.wrap('__name__')) - self.space.setitem(self.w_modules, w_name, w_module) - - def _setbuiltinmodule(self, w_module): - """ put a module into modules list and builtin_module_names """ - w_name = self.space.getattr(w_module, self.space.wrap('__name__')) - append = self.space.getattr(self.w_builtin_module_names, - self.space.wrap('append')) - self.space.call(append, self.space.newtuple((w_name,)), - self.space.newdict([])) - self.space.setitem(self.w_modules, w_name, w_module) - - def displayhook(self, w_x): - space = self.space - w = space.wrap - if not space.is_true(space.is_(w_x, space.w_None)): - try: - print space.unwrap(self.space.repr(w_x)) - except OperationError: - print "! could not print", w_x - space.setitem(space.w_builtins, w('_'), w_x) - - def _getframe(self): - # XXX No Argument Accepted Yet - f = self.space.getexecutioncontext().framestack.items[-1] - return self.space.wrap(f) - app__getframe = interp2app(_getframe) +# Functions from interpreter-level +from __interplevel__ import displayhook, _getframe From sschwarzer at codespeak.net Tue Dec 23 21:33:41 2003 From: sschwarzer at codespeak.net (sschwarzer at codespeak.net) Date: Tue, 23 Dec 2003 21:33:41 +0100 (MET) Subject: [pypy-svn] rev 2687 - in pypy/trunk/src/pypy: . tool Message-ID: <20031223203341.EB6F15AA0B@thoth.codespeak.net> Author: sschwarzer Date: Tue Dec 23 21:33:40 2003 New Revision: 2687 Added: pypy/trunk/src/pypy/tool/testit.py (props changed) - copied unchanged from rev 2686, pypy/trunk/src/pypy/tool/test.py Removed: pypy/trunk/src/pypy/tool/test.py Modified: pypy/trunk/src/pypy/test_all.py Log: Renamed test.py to testit.py to avoid conflict with soon-to-come directory pypy/tool/test. Modified: pypy/trunk/src/pypy/test_all.py ============================================================================== --- pypy/trunk/src/pypy/test_all.py (original) +++ pypy/trunk/src/pypy/test_all.py Tue Dec 23 21:33:40 2003 @@ -1,8 +1,8 @@ #! /usr/bin/env python import tool.autopath -from pypy.tool import test +from pypy.tool import testit if __name__ == '__main__': - test.main(tool.autopath.pypydir) + testit.main(tool.autopath.pypydir) Deleted: /pypy/trunk/src/pypy/tool/test.py ============================================================================== --- /pypy/trunk/src/pypy/tool/test.py Tue Dec 23 21:33:40 2003 +++ (empty file) @@ -1,369 +0,0 @@ -import autopath -import os, sys, unittest, re, warnings, unittest, traceback, StringIO -import fnmatch -from unittest import TestCase, TestLoader - -import pypy.interpreter.unittest_w -from pypy.tool.optik import make_option -from pypy.tool import optik, option, ppdb - -IntTestCase = pypy.interpreter.unittest_w.IntTestCase -AppTestCase = pypy.interpreter.unittest_w.AppTestCase -TestCase = IntTestCase - -class MyTestSuite(unittest.TestSuite): - def __call__(self, result): - """ execute the tests, invokes underlying unittest.__call__""" - - count = self.countTestCases() - if not count: - return result - - fm = getattr(self, 'frommodule', '') - - if fm and Options.verbose == 0: - sys.stderr.write('\n%s [%d]' %(fm, count)) - result = unittest.TestSuite.__call__(self, result) - return result - - def addTest(self, test, frommodule=None): - if test.countTestCases() > 0: - test.frommodule = frommodule - unittest.TestSuite.addTest(self, test) - - def __nonzero__(self): - return self.countTestCases() > 0 - -# register MyTestSuite to unittest -unittest.TestLoader.suiteClass = MyTestSuite - - -class MyTestResult(unittest.TestResult): - def __init__(self): - unittest.TestResult.__init__(self) - self.successes = [] - - def addError(self, test, err): - # XXX not nice: - from pypy.interpreter.baseobjspace import OperationError - if isinstance(err[1], OperationError) and test.space.full_exceptions: - if err[1].match(test.space, test.space.w_AssertionError): - self.addFailure(test, err) - return - unittest.TestResult.addError(self, test, err) - - def addSuccess(self, test): - self.successes.append(test) - - def addSkip(self, test): - self.testsRun -= 1 - - def addIgnored(self, test, err): - pass - - -class MyTextTestResult(unittest._TextTestResult): - ignored = 0 - - def addError(self, test, err): - from pypy.interpreter.baseobjspace import OperationError - if isinstance(err[1], OperationError) and test.space.full_exceptions: - if err[1].match(test.space, test.space.w_AssertionError): - self.addFailure(test, err) - return - unittest._TextTestResult.addError(self, test, err) - self.errors[-1] = (test, sys.exc_info()) - - def addFailure(self, test, err): - unittest._TextTestResult.addFailure(self, test, err) - self.failures[-1] = (test, sys.exc_info()) - - def addSkip(self, test): - self.testsRun -= 1 - if self.showAll: - self.stream.writeln("skipped") - elif self.dots: - self.stream.write('s') - - def addIgnored(self, test, err): - self.ignored += 1 - if self.showAll: - self.stream.writeln("ignored") - elif self.dots: - self.stream.write('i') - - def interact(self): - efs = self.errors + self.failures - from pypy.tool.testpm import TestPM - c = TestPM(efs) - c.cmdloop() - - def printErrors(self): - if Options.interactive: - print - if self.errors or self.failures: - self.interact() - else: - unittest._TextTestResult.printErrors(self) - - def printErrorList(self, flavour, errors): - from pypy.interpreter.baseobjspace import OperationError - for test, err in errors: - t1, t2 = '', '' - if not Options.quiet: - self.stream.writeln(self.separator1) - self.stream.writeln("%s: %s" % (flavour,self.getDescription(test))) - self.stream.writeln(self.separator2) - t1 = self._exc_info_to_string(err) - if isinstance(err[1], OperationError) and \ - test.space.full_exceptions: - if not Options.quiet: - t2 = '\nand at app-level:\n\n' - sio = StringIO.StringIO() - err[1].print_application_traceback(test.space, sio) - t2 += sio.getvalue() - self.stream.writeln("%s" % (t1 + t2,)) - - -class CtsTestRunner: - def _methodname(self, result): - "Return a normalized form of the method name for result." - # use private method, id() is not enough for us - return "%s.%s" % (result.__class__.__name__, - result._TestCase__testMethodName) - - def run(self, test): - import pickle - - result = MyTestResult() - try: - # discard output of test or suite - sys.stdout = sys.stderr = StringIO.StringIO() - test(result) - finally: - sys.stdout = sys.__stdout__ - sys.stderr = sys.__stderr__ - - # load status from previous run if available - if os.path.exists('testcts.pickle'): - oldstatus = pickle.load(open('testcts.pickle', 'r')) - else: - oldstatus = {} - - # store status from this run - status = {} - for e in result.errors: - name = self._methodname(e[0]) - status[name] = 'ERROR' - for f in result.failures: - name = self._methodname(f[0]) - status[name] = 'FAILURE' - for s in result.successes: - name = self._methodname(s) - status[name] = 'success' - - # compare statuses from previous and this run - oldmethods = oldstatus.keys() - methods = status.keys() - allmethods = dict([(m, 1) for m in oldmethods+methods]).keys() - allmethods.sort() - - for m in allmethods: - is_old = (m in oldstatus) - is_new = (m in status) - # case: test was run previously _and_ now - if is_old and is_new: - old = oldstatus[m] - new = status[m] - if old != new: - # print all transitions - print "%s has changed from %s to %s" % (m, old, new) - elif new != "success": - # print old statuses only if they weren't successes - print "%s remains a %s" % (m, new) - # case: test was run previously but not now - elif is_old and not is_new: - print "%s was a %s but not run this time" % (m, oldstatus[m]) - # retain status from previous run - status[m] = oldstatus[m] - # case: test was not run previously but now - elif not is_old and is_new: - # print nothing, just keep the old status - pass - - # save result from this run - pickle.dump(status, open('testcts.pickle', 'w')) - - return result - - -class MyTextTestRunner(unittest.TextTestRunner): - def run(self, test): - result = unittest.TextTestRunner.run(self, test) - if result.ignored: - self.stream.writeln("(ignored=%d)" % result.ignored) - return result - - def _makeResult(self): - return MyTextTestResult(self.stream, self.descriptions, self.verbosity) - - -def testsuite_from_main(): - """Return test modules from __main__.""" - loader = unittest.TestLoader() - m = __import__('__main__') - return loader.loadTestsFromModule(m) - -def testsuite_from_dir(root, filterfunc=None, recursive=0, loader=None): - """ - Return test modules that optionally match filterfunc. - - All files matching the glob-pattern "test_*.py" are considered. - Additionally, their fully qualified python module path has - to be accepted by filterfunc (if it is not None). - """ - from vpath import getlocal, nodotfile - root = getlocal(root) - - if Options.verbose > 2: - print >> sys.stderr, "scanning for test files in", root - - if loader is None: - loader = unittest.TestLoader() - - def testfilefilter(path): - return path.isfile() and path.fnmatch('test_*.py') - def recfilter(path): - return recursive and nodotfile(path) - - suite = unittest.TestLoader.suiteClass() - - for testfn in root.visit(testfilefilter, recfilter): - # strip the leading pypy directory and the .py suffix - modpath = str(testfn)[len(autopath.pypydir)+1:-3] - modpath = 'pypy.' + modpath.replace(os.sep, '.') - if (filterfunc is None) or filterfunc(modpath): - try: - subsuite = loader.loadTestsFromName(modpath) - except: - print "skipping testfile (failed loading it)", modpath - else: - suite.addTest(subsuite, modpath) - return suite - -class Options(option.Options): - testreldir = 0 - runcts = 0 - spacename = '' - individualtime = 0 - interactive = 0 - #XXX what's the purpose of this? - def ensure_value(*args): - return 0 - ensure_value = staticmethod(ensure_value) - quiet = 0 - -class TestSkip(Exception): - pass - -def objspace(name=''): - if name and Options.spacename and name != Options.spacename: - raise TestSkip - return option.objspace(name) - - -class RegexFilterFunc: - """ - Stateful function to filter included/excluded strings via - a regular expression. - - An 'excluded' regular expressions has a '%' prependend. - """ - def __init__(self, *regex): - self.exclude = [] - self.include = [] - for x in regex: - if x.startswith('%'): - self.exclude.append(re.compile(x[1:]).search) - else: - self.include.append(re.compile(x).search) - - def __call__(self, arg): - for exclude in self.exclude: - if exclude(arg): - return - if not self.include: - return arg - for include in self.include: - if include(arg): - return arg - -def get_test_options(): - options = option.get_standard_options() - options.append(make_option( - '-r', action="store_true", dest="testreldir", - help="gather only tests relative to current dir")) - options.append(make_option( - '-t', action="store_true", dest="individualtime", - help="time each test individually")) - options.append(make_option( - '-i', action="store_true", dest="interactive", - help="enter an interactive mode on failure or error")) - options.append(make_option( - '-q', action="store_true", dest="quiet", - help="suppress some information (e.g. interpreter level exceptions)")) - options.append(make_option( - '-c', action="store_true", dest="runcts", - help="run CtsTestRunner (discards output and prints report " - "after testing)")) - return options - -def run_tests(suite): - for spacename in Options.spaces or ['']: - run_tests_on_space(suite, spacename) - -def run_tests_on_space(suite, spacename=''): - """Run the suite on the given space.""" - if Options.runcts: - runner = CtsTestRunner() # verbosity=Options.verbose+1) - else: - runner = MyTextTestRunner(verbosity=Options.verbose+1) - - if spacename: - Options.spacename = spacename - - warnings.defaultaction = Options.showwarning and 'default' or 'ignore' - print >> sys.stderr, "running tests via", repr(objspace()) - runner.run(suite) - -def main(root=None): - """ - Test everything in the __main__ or in the given root - directory (recursive). - """ - args = option.process_options(get_test_options(), Options) - - filterfunc = RegexFilterFunc(*args) - if Options.testreldir: - root = os.path.abspath('.') - if root is None: - suite = testsuite_from_main() - else: - suite = testsuite_from_dir(root, filterfunc, 1) - if Options.individualtime and hasattr(suite, '_tests'): - for test in suite._tests: - if hasattr(test, '_tests'): - for subtest in test._tests: - run_tests(subtest) - else: - run_tests(test) - else: - run_tests(suite) - if Options.verbose: - from pypy.tool.udir import udir - print "testdata (unittestsession) directory was:", str(udir) - - -if __name__ == '__main__': - # test all of pypy - main(autopath.pypydir) From sschwarzer at codespeak.net Tue Dec 23 21:34:24 2003 From: sschwarzer at codespeak.net (sschwarzer at codespeak.net) Date: Tue, 23 Dec 2003 21:34:24 +0100 (MET) Subject: [pypy-svn] rev 2688 - pypy/trunk/src/pypy/tool/test Message-ID: <20031223203424.278F35AA0B@thoth.codespeak.net> Author: sschwarzer Date: Tue Dec 23 21:34:23 2003 New Revision: 2688 Added: pypy/trunk/src/pypy/tool/test/ Log: Added directory for tests. From hpk at codespeak.net Wed Dec 24 00:01:56 2003 From: hpk at codespeak.net (hpk at codespeak.net) Date: Wed, 24 Dec 2003 00:01:56 +0100 (MET) Subject: [pypy-svn] rev 2689 - in pypy/trunk/src/pypy: annotation/test appspaceappspace/test interpreter interpreter/test module/test objspace/flow/test objspace/std/test objspace/test tool tool/testdata translator translator/test translator/tool Message-ID: <20031223230156.629445AA0B@thoth.codespeak.net> Author: hpk Date: Wed Dec 24 00:01:48 2003 New Revision: 2689 Modified: pypy/trunk/src/pypy/annotation/test/test_annset.py pypy/trunk/src/pypy/appspace/builtin_functions_test.py pypy/trunk/src/pypy/appspace/test/test_cmathmodule.py pypy/trunk/src/pypy/appspace/test/test_complexobject.py pypy/trunk/src/pypy/appspace/test/test_stringmodule.py pypy/trunk/src/pypy/interpreter/interactive.py pypy/trunk/src/pypy/interpreter/test/test_class.py pypy/trunk/src/pypy/interpreter/test/test_code.py pypy/trunk/src/pypy/interpreter/test/test_eval.py pypy/trunk/src/pypy/interpreter/test/test_exceptcomp.py pypy/trunk/src/pypy/interpreter/test/test_exec.py pypy/trunk/src/pypy/interpreter/test/test_extmodule.py pypy/trunk/src/pypy/interpreter/test/test_function.py pypy/trunk/src/pypy/interpreter/test/test_gateway.py pypy/trunk/src/pypy/interpreter/test/test_generator.py pypy/trunk/src/pypy/interpreter/test/test_interpreter.py pypy/trunk/src/pypy/interpreter/test/test_main.py pypy/trunk/src/pypy/interpreter/test/test_module.py pypy/trunk/src/pypy/interpreter/test/test_nestedscope.py pypy/trunk/src/pypy/interpreter/test/test_objspace.py pypy/trunk/src/pypy/interpreter/test/test_pyframe.py pypy/trunk/src/pypy/interpreter/unittest_w.py pypy/trunk/src/pypy/module/test/test_apply.py pypy/trunk/src/pypy/module/test/test_builtin.py pypy/trunk/src/pypy/module/test/test_filter.py pypy/trunk/src/pypy/module/test/test_functional.py pypy/trunk/src/pypy/module/test/test_minmax.py pypy/trunk/src/pypy/module/test/test_newstyleclasses.py pypy/trunk/src/pypy/module/test/test_range.py pypy/trunk/src/pypy/module/test/test_reduce.py pypy/trunk/src/pypy/module/test/test_sysmodule.py pypy/trunk/src/pypy/module/test/test_vars.py pypy/trunk/src/pypy/module/test/test_zip.py pypy/trunk/src/pypy/objspace/flow/test/test_framestate.py pypy/trunk/src/pypy/objspace/flow/test/test_model.py pypy/trunk/src/pypy/objspace/flow/test/test_objspace.py pypy/trunk/src/pypy/objspace/std/test/test_boolobject.py pypy/trunk/src/pypy/objspace/std/test/test_cpythonobject.py pypy/trunk/src/pypy/objspace/std/test/test_dictobject.py pypy/trunk/src/pypy/objspace/std/test/test_floatobject.py pypy/trunk/src/pypy/objspace/std/test/test_instmethobject.py pypy/trunk/src/pypy/objspace/std/test/test_intobject.py pypy/trunk/src/pypy/objspace/std/test/test_iterobject.py pypy/trunk/src/pypy/objspace/std/test/test_listobject.py pypy/trunk/src/pypy/objspace/std/test/test_moduleobject.py pypy/trunk/src/pypy/objspace/std/test/test_multimethod.py pypy/trunk/src/pypy/objspace/std/test/test_noneobject.py pypy/trunk/src/pypy/objspace/std/test/test_restricted_int.py pypy/trunk/src/pypy/objspace/std/test/test_sliceobject.py pypy/trunk/src/pypy/objspace/std/test/test_stdobjspace.py pypy/trunk/src/pypy/objspace/std/test/test_stringobject.py pypy/trunk/src/pypy/objspace/std/test/test_tupleobject.py pypy/trunk/src/pypy/objspace/std/test/test_typeobject.py pypy/trunk/src/pypy/objspace/std/test/test_userobject.py pypy/trunk/src/pypy/objspace/test/test_traceobjspace.py pypy/trunk/src/pypy/tool/newtest.py pypy/trunk/src/pypy/tool/pydis.py pypy/trunk/src/pypy/tool/testdata/test_dummy.py pypy/trunk/src/pypy/tool/testit.py pypy/trunk/src/pypy/tool/traceinteractive.py pypy/trunk/src/pypy/tool/traceop.py pypy/trunk/src/pypy/translator/test/test_annrpython.py pypy/trunk/src/pypy/translator/test/test_cltrans.py pypy/trunk/src/pypy/translator/test/test_pyrextrans.py pypy/trunk/src/pypy/translator/test/test_sourcegen.py pypy/trunk/src/pypy/translator/tool/benchmark.py pypy/trunk/src/pypy/translator/tool/buildpyxmodule.py pypy/trunk/src/pypy/translator/translator.py Log: fixed Stefan's somewhat optimistic test.py -> testit.py renaming. Actually we have a lot of references to our test module (in all of our test files) so they need fixing. And i don't like the "testit" name so i will change that soon, i guess. Modified: pypy/trunk/src/pypy/annotation/test/test_annset.py ============================================================================== --- pypy/trunk/src/pypy/annotation/test/test_annset.py (original) +++ pypy/trunk/src/pypy/annotation/test/test_annset.py Wed Dec 24 00:01:48 2003 @@ -1,6 +1,6 @@ import autopath -from pypy.tool import test +from pypy.tool import testit from pypy.annotation.model import SomeValue, ANN, Predicate from pypy.annotation.annset import AnnotationSet, mostgeneralvalue,impossiblevalue @@ -32,7 +32,7 @@ return annset -class TestAnnotationSet(test.IntTestCase): +class TestAnnotationSet(testit.IntTestCase): def assertSameSet(self, annset1, annset2): self.assertEquals(repr(annset1), repr(annset2)) @@ -226,4 +226,4 @@ if __name__ == '__main__': - test.main() + testit.main() Modified: pypy/trunk/src/pypy/appspace/builtin_functions_test.py ============================================================================== --- pypy/trunk/src/pypy/appspace/builtin_functions_test.py (original) +++ pypy/trunk/src/pypy/appspace/builtin_functions_test.py Wed Dec 24 00:01:48 2003 @@ -1,6 +1,6 @@ # Python test set -- built-in functions import autopath -from pypy.tool import test +from pypy.tool import testit from pypy.interpreter.gateway import app2interp def app_init_globals(): @@ -105,13 +105,13 @@ b.L = L -class BuiltinTest(test.AppTestCase): +class BuiltinTest(testit.AppTestCase): full_test = 1 fully_initialized = False def setUp(self): - self.space = space = test.objspace('std') + self.space = space = testit.objspace('std') if self.fully_initialized: return @@ -1240,4 +1240,4 @@ self.assertRaises(ValueError, zip, BadSeq(), BadSeq()) if __name__ == '__main__': - test.main() + testit.main() Modified: pypy/trunk/src/pypy/appspace/test/test_cmathmodule.py ============================================================================== --- pypy/trunk/src/pypy/appspace/test/test_cmathmodule.py (original) +++ pypy/trunk/src/pypy/appspace/test/test_cmathmodule.py Wed Dec 24 00:01:48 2003 @@ -16,7 +16,7 @@ import autopath #try: -from pypy.tool import test +from pypy.tool import testit from pypy.appspace import cmathmodule from pypy.appspace.complexobject import complex as pycomplex #except ImportError: @@ -28,7 +28,7 @@ if 0: # DISABLED -- we know it works all right and don't want to see them # take time any more for the time being - class TestCMathModule(test.TestCase): + class TestCMathModule(testit.TestCase): def assertAEqual(self, a, b): if not equal(a, b): @@ -70,4 +70,4 @@ if __name__ == "__main__": - test.main() + testit.main() Modified: pypy/trunk/src/pypy/appspace/test/test_complexobject.py ============================================================================== --- pypy/trunk/src/pypy/appspace/test/test_complexobject.py (original) +++ pypy/trunk/src/pypy/appspace/test/test_complexobject.py Wed Dec 24 00:01:48 2003 @@ -18,7 +18,7 @@ import types import unittest -from pypy.tool import test +from pypy.tool import testit from pypy.appspace.complexobject import complex as pycomplex Modified: pypy/trunk/src/pypy/appspace/test/test_stringmodule.py ============================================================================== --- pypy/trunk/src/pypy/appspace/test/test_stringmodule.py (original) +++ pypy/trunk/src/pypy/appspace/test/test_stringmodule.py Wed Dec 24 00:01:48 2003 @@ -10,7 +10,7 @@ import unittest import autopath -from pypy.tool import test +from pypy.tool import testit from pypy.appspace import string as pypy_string class TestStringmodule(unittest.TestCase): @@ -36,4 +36,4 @@ if __name__ == "__main__": - test.main() \ No newline at end of file + testit.main() \ No newline at end of file Modified: pypy/trunk/src/pypy/interpreter/interactive.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/interactive.py (original) +++ pypy/trunk/src/pypy/interpreter/interactive.py Wed Dec 24 00:01:48 2003 @@ -75,7 +75,7 @@ pass from pypy.tool import option - from pypy.tool import test + from pypy.tool import testit args = option.process_options(option.get_standard_options(), option.Options) objspace = option.objspace() Modified: pypy/trunk/src/pypy/interpreter/test/test_class.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/test/test_class.py (original) +++ pypy/trunk/src/pypy/interpreter/test/test_class.py Wed Dec 24 00:01:48 2003 @@ -1,8 +1,8 @@ import autopath -from pypy.tool import test +from pypy.tool import testit -class TestClassApp(test.AppTestCase): +class TestClassApp(testit.AppTestCase): def test_class(self): @@ -64,4 +64,4 @@ if __name__ == '__main__': - test.main() + testit.main() Modified: pypy/trunk/src/pypy/interpreter/test/test_code.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/test/test_code.py (original) +++ pypy/trunk/src/pypy/interpreter/test/test_code.py Wed Dec 24 00:01:48 2003 @@ -1,10 +1,10 @@ import autopath -from pypy.tool import test +from pypy.tool import testit import unittest -class AppTestCodeIntrospection(test.AppTestCase): +class AppTestCodeIntrospection(testit.AppTestCase): def test_attributes(self): def f(): pass code = f.func_code @@ -17,4 +17,4 @@ self.assertEquals(code.co_argcount,0) if __name__ == '__main__': - test.main() + testit.main() Modified: pypy/trunk/src/pypy/interpreter/test/test_eval.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/test/test_eval.py (original) +++ pypy/trunk/src/pypy/interpreter/test/test_eval.py Wed Dec 24 00:01:48 2003 @@ -1,13 +1,13 @@ import autopath -from pypy.tool import test +from pypy.tool import testit from pypy.interpreter.eval import Frame, UNDEFINED from pypy.interpreter.pycode import PyCode -class TestFrame(test.IntTestCase): +class TestFrame(testit.IntTestCase): def setUp(self): - self.space = test.objspace() + self.space = testit.objspace() def c(x, y, *args): pass code = PyCode()._from_code(c.func_code) @@ -55,4 +55,4 @@ UNDEFINED, UNDEFINED]) if __name__ == '__main__': - test.main() + testit.main() Modified: pypy/trunk/src/pypy/interpreter/test/test_exceptcomp.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/test/test_exceptcomp.py (original) +++ pypy/trunk/src/pypy/interpreter/test/test_exceptcomp.py Wed Dec 24 00:01:48 2003 @@ -3,12 +3,12 @@ New for PyPy - Could be incorporated into CPython regression tests. """ import autopath -from pypy.tool import test +from pypy.tool import testit -class TestExceptionComp(test.AppTestCase): +class TestExceptionComp(testit.AppTestCase): def setUp(self): - self.space = test.objspace() + self.space = testit.objspace() ### XXX - String exceptions depreciated? ## def test_string(self): @@ -135,4 +135,4 @@ self.fail("Exception does not match self in deeply nested tuple.") if __name__ == "__main__": - test.main() + testit.main() Modified: pypy/trunk/src/pypy/interpreter/test/test_exec.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/test/test_exec.py (original) +++ pypy/trunk/src/pypy/interpreter/test/test_exec.py Wed Dec 24 00:01:48 2003 @@ -3,12 +3,12 @@ New for PyPy - Could be incorporated into CPython regression tests. """ import autopath -from pypy.tool import test +from pypy.tool import testit -class TestExecStmt(test.AppTestCase): +class TestExecStmt(testit.AppTestCase): def setUp(self): - self.space = test.objspace() + self.space = testit.objspace() def test_string(self): g = {} @@ -73,4 +73,4 @@ self.failUnlessRaises(TypeError,f) if __name__ == "__main__": - test.main() + testit.main() Modified: pypy/trunk/src/pypy/interpreter/test/test_extmodule.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/test/test_extmodule.py (original) +++ pypy/trunk/src/pypy/interpreter/test/test_extmodule.py Wed Dec 24 00:01:48 2003 @@ -1,12 +1,12 @@ import autopath -from pypy.tool import test +from pypy.tool import testit from pypy.interpreter.extmodule import ExtModule -class TestExtModule(test.IntTestCase): +class TestExtModule(testit.IntTestCase): def setUp(self): - self.space = test.objspace() + self.space = testit.objspace() class M(ExtModule): __name__ = 'm' @@ -44,4 +44,4 @@ if __name__ == '__main__': - test.main() + testit.main() Modified: pypy/trunk/src/pypy/interpreter/test/test_function.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/test/test_function.py (original) +++ pypy/trunk/src/pypy/interpreter/test/test_function.py Wed Dec 24 00:01:48 2003 @@ -1,12 +1,12 @@ import autopath -from pypy.tool import test +from pypy.tool import testit import unittest from pypy.interpreter.function import Function, Method from pypy.interpreter.pycode import PyCode -class AppTestFunctionIntrospection(test.AppTestCase): +class AppTestFunctionIntrospection(testit.AppTestCase): def test_attributes(self): def f(): pass self.assert_(hasattr(f, 'func_code')) @@ -30,7 +30,7 @@ self.assert_(f.__dict__ is f.func_dict) #XXX self.assert_(hasattr(f, '__class__')) -class AppTestFunction(test.AppTestCase): +class AppTestFunction(testit.AppTestCase): def test_simple_call(self): def func(arg1, arg2): return arg1, arg2 @@ -108,9 +108,9 @@ self.assertRaises(TypeError, func, 42, **{'arg1': 23}) -class TestMethod(test.IntTestCase): +class TestMethod(testit.IntTestCase): def setUp(self): - self.space = test.objspace() + self.space = testit.objspace() def c(self, bar): return bar code = PyCode()._from_code(c.func_code) @@ -137,4 +137,4 @@ if __name__ == '__main__': - test.main() + testit.main() Modified: pypy/trunk/src/pypy/interpreter/test/test_gateway.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/test/test_gateway.py (original) +++ pypy/trunk/src/pypy/interpreter/test/test_gateway.py Wed Dec 24 00:01:48 2003 @@ -1,12 +1,12 @@ import autopath -from pypy.tool import test +from pypy.tool import testit from pypy.interpreter import gateway -class TestBuiltinCode(test.IntTestCase): +class TestBuiltinCode(testit.IntTestCase): def setUp(self): - self.space = test.objspace() + self.space = testit.objspace() def test_signature(self): def c(space, w_x, w_y, *args_w, **kw_w): @@ -35,9 +35,9 @@ self.assertEqual_w(w_result, w(1020)) -class TestGateway(test.IntTestCase): +class TestGateway(testit.IntTestCase): def setUp(self): - self.space = test.objspace() + self.space = testit.objspace() def test_app2interp(self): w = self.space.wrap @@ -81,4 +81,4 @@ if __name__ == '__main__': - test.main() + testit.main() Modified: pypy/trunk/src/pypy/interpreter/test/test_generator.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/test/test_generator.py (original) +++ pypy/trunk/src/pypy/interpreter/test/test_generator.py Wed Dec 24 00:01:48 2003 @@ -1,8 +1,8 @@ from __future__ import generators import autopath -from pypy.tool import test +from pypy.tool import testit -class AppTestGenerator(test.AppTestCase): +class AppTestGenerator(testit.AppTestCase): def test_generator(self): def f(): @@ -51,4 +51,4 @@ if __name__ == '__main__': - test.main() + testit.main() Modified: pypy/trunk/src/pypy/interpreter/test/test_interpreter.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/test/test_interpreter.py (original) +++ pypy/trunk/src/pypy/interpreter/test/test_interpreter.py Wed Dec 24 00:01:48 2003 @@ -1,7 +1,7 @@ import autopath -from pypy.tool import test +from pypy.tool import testit -class TestInterpreter(test.TestCase): +class TestInterpreter(testit.TestCase): def codetest(self, source, functionname, args): """Compile and run the given code string, and then call its function @@ -35,7 +35,7 @@ return space.unwrap(w_output) def setUp(self): - self.space = test.objspace() + self.space = testit.objspace() def test_exception_trivial(self): x = self.codetest(''' @@ -143,7 +143,7 @@ self.assertEquals(self.codetest(code, 'f', [9]), 1+2+3 + 5+6+7+8+900) -class AppTestInterpreter(test.AppTestCase): +class AppTestInterpreter(testit.AppTestCase): def test_exception(self): try: raise Exception, 1 @@ -215,4 +215,4 @@ if __name__ == '__main__': - test.main() + testit.main() Modified: pypy/trunk/src/pypy/interpreter/test/test_main.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/test/test_main.py (original) +++ pypy/trunk/src/pypy/interpreter/test/test_main.py Wed Dec 24 00:01:48 2003 @@ -2,7 +2,7 @@ import autopath from cStringIO import StringIO -from pypy.tool import test +from pypy.tool import testit from pypy.interpreter.baseobjspace import OperationError from pypy.interpreter import main @@ -20,7 +20,7 @@ capture = StringIO() def checkoutput(expected_output,f,*args): - space = test.objspace() + space = testit.objspace() w_sys = space.get_builtin_module("sys") w_oldout = space.getattr(w_sys, space.wrap("stdout")) capture.reset() @@ -34,10 +34,10 @@ testfn = 'tmp_hello_world.py' -class TestMain(test.TestCase): +class TestMain(testit.TestCase): def setUp(self): - self.space = test.objspace() + self.space = testit.objspace() ofile = open(testfn, 'w') ofile.write(testcode) ofile.close() @@ -58,4 +58,4 @@ self.assertEqual_w(w_x, self.space.wrap(4)) if __name__ == '__main__': - test.main() + testit.main() Modified: pypy/trunk/src/pypy/interpreter/test/test_module.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/test/test_module.py (original) +++ pypy/trunk/src/pypy/interpreter/test/test_module.py Wed Dec 24 00:01:48 2003 @@ -1,12 +1,12 @@ import autopath -from pypy.tool import test +from pypy.tool import testit from pypy.interpreter.module import Module -class TestModule(test.IntTestCase): +class TestModule(testit.IntTestCase): def setUp(self): - self.space = test.objspace() + self.space = testit.objspace() self.m = Module(self.space, self.space.wrap('m')) def test_name(self): @@ -23,10 +23,10 @@ self.assertRaises_w(self.space.w_AttributeError, self.space.delattr, w_m, w('x')) -class Test_ModuleObject(test.AppTestCase): +class Test_ModuleObject(testit.AppTestCase): def setUp(self): - self.space = test.objspace() + self.space = testit.objspace() def test_attr(self): m = __import__('__builtin__') @@ -44,4 +44,4 @@ self.assertRaises(AttributeError, delattr, m, 'x') if __name__ == '__main__': - test.main() + testit.main() Modified: pypy/trunk/src/pypy/interpreter/test/test_nestedscope.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/test/test_nestedscope.py (original) +++ pypy/trunk/src/pypy/interpreter/test/test_nestedscope.py Wed Dec 24 00:01:48 2003 @@ -1,8 +1,8 @@ import autopath -from pypy.tool import test +from pypy.tool import testit -class AppTestNestedScope(test.AppTestCase): +class AppTestNestedScope(testit.AppTestCase): def test_nested_scope(self): x = 42 @@ -58,4 +58,4 @@ self.assertEquals(len(outer_locals), 1, "len!=1 for %r" % outer_locals) if __name__ == '__main__': - test.main() + testit.main() Modified: pypy/trunk/src/pypy/interpreter/test/test_objspace.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/test/test_objspace.py (original) +++ pypy/trunk/src/pypy/interpreter/test/test_objspace.py Wed Dec 24 00:01:48 2003 @@ -1,13 +1,13 @@ import autopath -from pypy.tool import test +from pypy.tool import testit # this test isn't so much to test that the objspace interface *works* # -- it's more to test that it's *there* -class TestObjSpace(test.TestCase): +class TestObjSpace(testit.TestCase): def setUp(self): - self.space = test.objspace() + self.space = testit.objspace() def tearDown(self): pass @@ -94,9 +94,9 @@ self.failIf(self.space.exception_match(self.space.w_ValueError, self.space.w_LookupError)) -class ModuleMinimalTest(test.IntTestCase): +class ModuleMinimalTest(testit.IntTestCase): def setUp(self): - self.space = test.objspace() + self.space = testit.objspace() def test_sys_exists(self): w_sys = self.space.get_builtin_module('sys') @@ -115,4 +115,4 @@ run_string('import sys', space=self.space) if __name__ == '__main__': - test.main() + testit.main() Modified: pypy/trunk/src/pypy/interpreter/test/test_pyframe.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/test/test_pyframe.py (original) +++ pypy/trunk/src/pypy/interpreter/test/test_pyframe.py Wed Dec 24 00:01:48 2003 @@ -1,8 +1,8 @@ import autopath -from pypy.tool import test +from pypy.tool import testit -class AppTestPyFrame(test.AppTestCase): +class AppTestPyFrame(testit.AppTestCase): # test for the presence of the attributes, not functionality @@ -30,4 +30,4 @@ if __name__ == '__main__': - test.main() + testit.main() Modified: pypy/trunk/src/pypy/interpreter/unittest_w.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/unittest_w.py (original) +++ pypy/trunk/src/pypy/interpreter/unittest_w.py Wed Dec 24 00:01:48 2003 @@ -70,7 +70,7 @@ errorfn(self, self._TestCase__exc_info()) def __call__(self, result=None): - from pypy.tool.test import TestSkip + from pypy.tool.testit import TestSkip if result is None: result = self.defaultTestResult() result.startTest(self) testMethod = getattr(self, self.methodName) @@ -161,5 +161,5 @@ return IntTestCase.__call__(self, result) def setUp(self): - from pypy.tool import test - self.space = test.objspace() + from pypy.tool import testit + self.space = testit.objspace() Modified: pypy/trunk/src/pypy/module/test/test_apply.py ============================================================================== --- pypy/trunk/src/pypy/module/test/test_apply.py (original) +++ pypy/trunk/src/pypy/module/test/test_apply.py Wed Dec 24 00:01:48 2003 @@ -1,11 +1,11 @@ import autopath -from pypy.tool import test +from pypy.tool import testit # This is a very trivial series of tests. If apply is subtlely broken, # we will have to find out some other way. -class TestApply(test.AppTestCase): +class TestApply(testit.AppTestCase): def test_trivial_listonly(self): def mymin(*args): @@ -28,6 +28,6 @@ (-4)) if __name__ == '__main__': - test.main() + testit.main() Modified: pypy/trunk/src/pypy/module/test/test_builtin.py ============================================================================== --- pypy/trunk/src/pypy/module/test/test_builtin.py (original) +++ pypy/trunk/src/pypy/module/test/test_builtin.py Wed Dec 24 00:01:48 2003 @@ -1,10 +1,10 @@ import autopath -from pypy.tool import test +from pypy.tool import testit -class TestBuiltinApp(test.AppTestCase): +class TestBuiltinApp(testit.AppTestCase): def setUp(self): - self.space = test.objspace() + self.space = testit.objspace() def test_import(self): m = __import__('pprint') @@ -229,10 +229,10 @@ -class TestInternal(test.IntTestCase): +class TestInternal(testit.IntTestCase): def setUp(self): - self.space = space = test.objspace() + self.space = space = testit.objspace() def get_builtin(self, name): w = self.space.wrap @@ -261,5 +261,5 @@ os.remove(fn) if __name__ == '__main__': - test.main() + testit.main() Modified: pypy/trunk/src/pypy/module/test/test_filter.py ============================================================================== --- pypy/trunk/src/pypy/module/test/test_filter.py (original) +++ pypy/trunk/src/pypy/module/test/test_filter.py Wed Dec 24 00:01:48 2003 @@ -1,9 +1,9 @@ import autopath -from pypy.tool import test +from pypy.tool import testit # trivial functions for testing -class TestFilter(test.AppTestCase): +class TestFilter(testit.AppTestCase): def test_filter_no_arguments(self): self.assertRaises(TypeError, filter) @@ -38,4 +38,4 @@ self.assertEqual(filter(lambda x: x>'a', 'xyzabcd'), 'xyzbcd') if __name__ == '__main__': - test.main() + testit.main() Modified: pypy/trunk/src/pypy/module/test/test_functional.py ============================================================================== --- pypy/trunk/src/pypy/module/test/test_functional.py (original) +++ pypy/trunk/src/pypy/module/test/test_functional.py Wed Dec 24 00:01:48 2003 @@ -1,8 +1,8 @@ import autopath -from pypy.tool import test +from pypy.tool import testit -class TestMap(test.AppTestCase): +class TestMap(testit.AppTestCase): def test_trivial_map_one_seq(self): self.assertEqual(map(lambda x: x+2, [1, 2, 3, 4]), [3, 4, 5, 6]) @@ -59,14 +59,14 @@ b = [] self.assertEqual(map(lambda x, y: x, a, b), a) -class TestZip(test.AppTestCase): +class TestZip(testit.AppTestCase): def test_one_list(self): self.assertEqual(zip([1,2,3]), [(1,), (2,), (3,)]) def test_three_lists(self): self.assertEqual(zip([1,2,3], [1,2], [1,2,3]), [(1,1,1), (2,2,2)]) -class TestReduce(test.TestCase): +class TestReduce(testit.TestCase): def test_None(self): self.assertRaises(TypeError, reduce, lambda x, y: x+y, [1,2,3], None) @@ -78,7 +78,7 @@ self.assertEqual(reduce(lambda x, y: x-y, [10, 2, 8]), 0) self.assertEqual(reduce(lambda x, y: x-y, [2, 8], 10), 0) -class TestFilter(test.AppTestCase): +class TestFilter(testit.AppTestCase): def test_None(self): self.assertEqual(filter(None, ['a', 'b', 1, 0, None]), ['a', 'b', 1]) @@ -92,6 +92,6 @@ self.assertEqual(filter(lambda x: x != "a", "a small text"), " smll text") if __name__ == '__main__': - test.main() + testit.main() Modified: pypy/trunk/src/pypy/module/test/test_minmax.py ============================================================================== --- pypy/trunk/src/pypy/module/test/test_minmax.py (original) +++ pypy/trunk/src/pypy/module/test/test_minmax.py Wed Dec 24 00:01:48 2003 @@ -1,7 +1,7 @@ import autopath -from pypy.tool import test +from pypy.tool import testit -class TestMin(test.AppTestCase): +class TestMin(testit.AppTestCase): def test_min_notseq(self): self.assertRaises(TypeError, min, 1) @@ -34,7 +34,7 @@ def test_min_empty(self): self.assertRaises(ValueError, min, []) -class TestMax(test.AppTestCase): +class TestMax(testit.AppTestCase): def test_max_notseq(self): self.assertRaises(TypeError, max, 1) @@ -68,4 +68,4 @@ self.assertRaises(ValueError, max, []) if __name__ == '__main__': - test.main() + testit.main() Modified: pypy/trunk/src/pypy/module/test/test_newstyleclasses.py ============================================================================== --- pypy/trunk/src/pypy/module/test/test_newstyleclasses.py (original) +++ pypy/trunk/src/pypy/module/test/test_newstyleclasses.py Wed Dec 24 00:01:48 2003 @@ -1,10 +1,10 @@ import autopath -from pypy.tool import test +from pypy.tool import testit -class TestBuiltinApp(test.AppTestCase): +class TestBuiltinApp(testit.AppTestCase): def setUp(self): - self.space = test.objspace() + self.space = testit.objspace() def test_staticmethod(self): class C: @@ -49,4 +49,4 @@ self.assertRaises(KeyError, delattr, a1, 'name') if __name__ == '__main__': - test.main() + testit.main() Modified: pypy/trunk/src/pypy/module/test/test_range.py ============================================================================== --- pypy/trunk/src/pypy/module/test/test_range.py (original) +++ pypy/trunk/src/pypy/module/test/test_range.py Wed Dec 24 00:01:48 2003 @@ -1,7 +1,7 @@ import autopath -from pypy.tool import test +from pypy.tool import testit -class TestRange(test.AppTestCase): +class TestRange(testit.AppTestCase): def test_range_toofew(self): self.assertRaises(TypeError, range) @@ -68,6 +68,6 @@ """ if __name__ == '__main__': - test.main() + testit.main() Modified: pypy/trunk/src/pypy/module/test/test_reduce.py ============================================================================== --- pypy/trunk/src/pypy/module/test/test_reduce.py (original) +++ pypy/trunk/src/pypy/module/test/test_reduce.py Wed Dec 24 00:01:48 2003 @@ -1,7 +1,7 @@ import autopath -from pypy.tool import test +from pypy.tool import testit -class TestReduce(test.AppTestCase): +class TestReduce(testit.AppTestCase): def test_None(self): self.assertRaises(TypeError, reduce, lambda x, y: x+y, [1,2,3], None) @@ -14,6 +14,6 @@ self.assertEqual(reduce(lambda x, y: x-y, [2, 8], 10), 0) if __name__ == '__main__': - test.main() + testit.main() Modified: pypy/trunk/src/pypy/module/test/test_sysmodule.py ============================================================================== --- pypy/trunk/src/pypy/module/test/test_sysmodule.py (original) +++ pypy/trunk/src/pypy/module/test/test_sysmodule.py Wed Dec 24 00:01:48 2003 @@ -1,9 +1,9 @@ import autopath -from pypy.tool import test +from pypy.tool import testit -class SysTests(test.TestCase): +class SysTests(testit.TestCase): def setUp(self): - self.space = test.objspace() + self.space = testit.objspace() self.sys_w = self.space.get_builtin_module("sys") def tearDown(self): pass @@ -12,7 +12,7 @@ s = self.space self.failUnless_w(s.getattr(self.sys_w, s.wrap("stdout"))) -class AppSysTests(test.AppTestCase): +class AppSysTests(testit.AppTestCase): def test_path_exists(self): import sys self.failUnless(hasattr(sys, 'path'), "sys.path gone missing") @@ -66,5 +66,5 @@ "__builtin__ is not listed as a builtin module.") if __name__ == '__main__': - test.main() + testit.main() Modified: pypy/trunk/src/pypy/module/test/test_vars.py ============================================================================== --- pypy/trunk/src/pypy/module/test/test_vars.py (original) +++ pypy/trunk/src/pypy/module/test/test_vars.py Wed Dec 24 00:01:48 2003 @@ -1,7 +1,7 @@ import autopath -from pypy.tool import test +from pypy.tool import testit -class TestVars(test.AppTestCase): +class TestVars(testit.AppTestCase): def _test_vars_no_arguments(self): self.assertEqual(vars(), locals()) @@ -19,6 +19,6 @@ self.assertEqual(vars(a1).get('res'),42) if __name__ == '__main__': - test.main() + testit.main() Modified: pypy/trunk/src/pypy/module/test/test_zip.py ============================================================================== --- pypy/trunk/src/pypy/module/test/test_zip.py (original) +++ pypy/trunk/src/pypy/module/test/test_zip.py Wed Dec 24 00:01:48 2003 @@ -1,7 +1,7 @@ import autopath -from pypy.tool import test +from pypy.tool import testit -class TestZip(test.AppTestCase): +class TestZip(testit.AppTestCase): def test_zip_no_arguments(self): self.assertRaises(TypeError, zip) @@ -32,6 +32,6 @@ [('h', 1, 7), ('e', 2, 8), ('l', 3, 9), ('l', 4, 10)]) if __name__ == '__main__': - test.main() + testit.main() Modified: pypy/trunk/src/pypy/objspace/flow/test/test_framestate.py ============================================================================== --- pypy/trunk/src/pypy/objspace/flow/test/test_framestate.py (original) +++ pypy/trunk/src/pypy/objspace/flow/test/test_framestate.py Wed Dec 24 00:01:48 2003 @@ -1,14 +1,14 @@ import autopath -from pypy.tool import test +from pypy.tool import testit from pypy.objspace.flow.flowcontext import * from pypy.objspace.flow.model import * from pypy.interpreter.pycode import PyCode -class TestFrameState(test.TestCase): +class TestFrameState(testit.TestCase): def setUp(self): - self.space = test.objspace('flow') + self.space = testit.objspace('flow') def getframe(self, func): space = self.space @@ -99,7 +99,7 @@ self.assert_(isinstance(frame.fastlocals_w[-1], Variable)) # generalized if __name__ == '__main__': - test.main() + testit.main() Modified: pypy/trunk/src/pypy/objspace/flow/test/test_model.py ============================================================================== --- pypy/trunk/src/pypy/objspace/flow/test/test_model.py (original) +++ pypy/trunk/src/pypy/objspace/flow/test/test_model.py Wed Dec 24 00:01:48 2003 @@ -1,11 +1,11 @@ import autopath -from pypy.tool import test +from pypy.tool import testit from pypy.objspace.flow.model import * -class TestModel(test.TestCase): +class TestModel(testit.TestCase): def setUp(self): - self.space = test.objspace('flow') + self.space = testit.objspace('flow') def getflow(self, func): import inspect @@ -81,4 +81,4 @@ if __name__ == '__main__': - test.main() + testit.main() Modified: pypy/trunk/src/pypy/objspace/flow/test/test_objspace.py ============================================================================== --- pypy/trunk/src/pypy/objspace/flow/test/test_objspace.py (original) +++ pypy/trunk/src/pypy/objspace/flow/test/test_objspace.py Wed Dec 24 00:01:48 2003 @@ -1,12 +1,12 @@ import autopath -from pypy.tool import test +from pypy.tool import testit from pypy.objspace.flow.wrapper import * from pypy.translator.flowmodel import * -class TestFlowOjSpace(test.TestCase): +class TestFlowOjSpace(testit.TestCase): def setUp(self): - self.space = test.objspace('flow') + self.space = testit.objspace('flow') def codetest(self, func): import inspect @@ -216,4 +216,4 @@ if __name__ == '__main__': - test.main() + testit.main() Modified: pypy/trunk/src/pypy/objspace/std/test/test_boolobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/test/test_boolobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/test/test_boolobject.py Wed Dec 24 00:01:48 2003 @@ -1,11 +1,11 @@ import autopath -from pypy.tool import test +from pypy.tool import testit -class TestW_BoolObject(test.TestCase): +class TestW_BoolObject(testit.TestCase): def setUp(self): - self.space = test.objspace('std') + self.space = testit.objspace('std') self.true = self.space.w_True self.false = self.space.w_False self.wrap = self.space.wrap @@ -23,9 +23,9 @@ def test_false(self): self.failIf_w(self.false) -class AppBoolTest(test.AppTestCase): +class AppBoolTest(testit.AppTestCase): def setUp(self): - self.space = test.objspace('std') + self.space = testit.objspace('std') def test_bool_callable(self): self.assertEquals(True, bool(1)) @@ -39,4 +39,4 @@ self.assertEquals("False", repr(False)) if __name__ == '__main__': - test.main() + testit.main() Modified: pypy/trunk/src/pypy/objspace/std/test/test_cpythonobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/test/test_cpythonobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/test/test_cpythonobject.py Wed Dec 24 00:01:48 2003 @@ -1,14 +1,14 @@ import unittest, sys, array import autopath -from pypy.tool import test +from pypy.tool import testit from pypy.objspace.std import cpythonobject from pypy.objspace.std.objspace import OperationError -class TestW_CPythonObject(test.TestCase): +class TestW_CPythonObject(testit.TestCase): def setUp(self): - self.space = test.objspace('std') + self.space = testit.objspace('std') # arbitrary always-wrapped object self.stuff = array.array('b', [5,-2,77]) @@ -88,4 +88,4 @@ self.assertEqual_w(self.space.wrap(5), self.space.next(nx)) if __name__ == '__main__': - test.main() + testit.main() Modified: pypy/trunk/src/pypy/objspace/std/test/test_dictobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/test/test_dictobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/test/test_dictobject.py Wed Dec 24 00:01:48 2003 @@ -1,12 +1,12 @@ import autopath -from pypy.tool import test +from pypy.tool import testit from pypy.objspace.std.dictobject import W_DictObject -class TestW_DictObject(test.TestCase): +class TestW_DictObject(testit.TestCase): def setUp(self): - self.space = test.objspace('std') + self.space = testit.objspace('std') def tearDown(self): pass @@ -168,10 +168,10 @@ -class Test_DictObject(test.AppTestCase): +class Test_DictObject(testit.AppTestCase): def setUp(self): - self.space = test.objspace('std') + self.space = testit.objspace('std') def test_equality(self): d = {1:2} @@ -347,4 +347,4 @@ {1: 'j', '1': 'j'}) if __name__ == '__main__': - test.main() + testit.main() Modified: pypy/trunk/src/pypy/objspace/std/test/test_floatobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/test/test_floatobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/test/test_floatobject.py Wed Dec 24 00:01:48 2003 @@ -1,12 +1,12 @@ import autopath from pypy.objspace.std import floatobject as fobj from pypy.objspace.std.objspace import FailedToImplement -from pypy.tool import test +from pypy.tool import testit -class TestW_FloatObject(test.TestCase): +class TestW_FloatObject(testit.TestCase): def setUp(self): - self.space = test.objspace('std') + self.space = testit.objspace('std') def tearDown(self): pass @@ -44,9 +44,9 @@ self.space, f1, f2, self.space.w_None)) -class AppFloatTest(test.AppTestCase): +class AppFloatTest(testit.AppTestCase): def setUp(self): - self.space = test.objspace('std') + self.space = testit.objspace('std') def test_negatives(self): self.assert_(-1.1 < 0) @@ -75,5 +75,5 @@ self.assertEquals(0.0, round(22.22222, -2)) if __name__ == '__main__': - test.main() + testit.main() Modified: pypy/trunk/src/pypy/objspace/std/test/test_instmethobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/test/test_instmethobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/test/test_instmethobject.py Wed Dec 24 00:01:48 2003 @@ -1,12 +1,12 @@ import autopath -from pypy.tool import test +from pypy.tool import testit # NB. instmethobject.py has been removed, # but the following tests still make sense -class TestInstMethObjectApp(test.AppTestCase): +class TestInstMethObjectApp(testit.AppTestCase): def setUp(self): - self.space = test.objspace('std') + self.space = testit.objspace('std') def test_callBound(self): boundMethod = [1,2,3].__len__ @@ -20,4 +20,4 @@ self.assertRaises(TypeError, unboundMethod, [1,2,3], 333) if __name__ == '__main__': - test.main() + testit.main() Modified: pypy/trunk/src/pypy/objspace/std/test/test_intobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/test/test_intobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/test/test_intobject.py Wed Dec 24 00:01:48 2003 @@ -2,12 +2,12 @@ import autopath from pypy.objspace.std import intobject as iobj from pypy.objspace.std.objspace import FailedToImplement -from pypy.tool import test +from pypy.tool import testit -class TestW_IntObject(test.TestCase): +class TestW_IntObject(testit.TestCase): def setUp(self): - self.space = test.objspace('std') + self.space = testit.objspace('std') def tearDown(self): pass @@ -288,9 +288,9 @@ result = iobj.hex__Int(self.space, f1) self.assertEquals(self.space.unwrap(result), hex(x)) -class AppIntTest(test.AppTestCase): +class AppIntTest(testit.AppTestCase): def setUp(self): - self.space = test.objspace('std') + self.space = testit.objspace('std') def test_int_callable(self): self.assertEquals(42, int(42)) @@ -314,4 +314,4 @@ if __name__ == '__main__': - test.main() + testit.main() Modified: pypy/trunk/src/pypy/objspace/std/test/test_iterobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/test/test_iterobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/test/test_iterobject.py Wed Dec 24 00:01:48 2003 @@ -1,12 +1,12 @@ import autopath from pypy.objspace.std.iterobject import W_SeqIterObject from pypy.objspace.std.objspace import NoValue -from pypy.tool import test +from pypy.tool import testit -class TestW_IterObject(test.TestCase): +class TestW_IterObject(testit.TestCase): def setUp(self): - self.space = test.objspace('std') + self.space = testit.objspace('std') def tearDown(self): pass @@ -44,9 +44,9 @@ w_iter = self.space.iter(w_list) self.body0(w_iter) -class TestW_IterObjectApp(test.AppTestCase): +class TestW_IterObjectApp(testit.AppTestCase): def setUp(self): - self.space = test.objspace('std') + self.space = testit.objspace('std') def test_user_iter(self): class C: @@ -71,4 +71,4 @@ if __name__ == '__main__': - test.main() + testit.main() Modified: pypy/trunk/src/pypy/objspace/std/test/test_listobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/test/test_listobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/test/test_listobject.py Wed Dec 24 00:01:48 2003 @@ -2,13 +2,13 @@ import autopath from pypy.objspace.std.listobject import W_ListObject from pypy.objspace.std.objspace import NoValue -from pypy.tool import test +from pypy.tool import testit -class TestW_ListObject(test.TestCase): +class TestW_ListObject(testit.TestCase): def setUp(self): - self.space = test.objspace('std') + self.space = testit.objspace('std') def tearDown(self): pass @@ -271,9 +271,9 @@ self.assertEqual_w(self.space.le(w_list4, w_list3), self.space.w_True) -class AppTestW_ListObject(test.AppTestCase): +class AppTestW_ListObject(testit.AppTestCase): def setUp(self): - self.space = test.objspace('std') + self.space = testit.objspace('std') def test_explicit_new_init(self): l = list.__new__(list) @@ -327,4 +327,4 @@ self.assertEquals(l,[3]) if __name__ == '__main__': - test.main() + testit.main() Modified: pypy/trunk/src/pypy/objspace/std/test/test_moduleobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/test/test_moduleobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/test/test_moduleobject.py Wed Dec 24 00:01:48 2003 @@ -1,11 +1,11 @@ import autopath from pypy.objspace.std.moduleobject import W_ModuleObject -from pypy.tool import test +from pypy.tool import testit -class TestW_ModuleObject(test.TestCase): +class TestW_ModuleObject(testit.TestCase): def setUp(self): - self.space = test.objspace('std') + self.space = testit.objspace('std') def tearDown(self): pass @@ -31,4 +31,4 @@ self.assertEqual_w(space.getattr(w_m, space.wrap('yy')), w_yy) if __name__ == '__main__': - test.main() + testit.main() Modified: pypy/trunk/src/pypy/objspace/std/test/test_multimethod.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/test/test_multimethod.py (original) +++ pypy/trunk/src/pypy/objspace/std/test/test_multimethod.py Wed Dec 24 00:01:48 2003 @@ -1,7 +1,7 @@ import autopath from pypy.objspace.std.multimethod import * -from pypy.tool import test +from pypy.tool import testit BoundMultiMethod.ASSERT_BASE_TYPE = object @@ -90,10 +90,10 @@ return x -class TestMultiMethod(test.TestCase): +class TestMultiMethod(testit.TestCase): def setUp(self): # only run when testing stdobjectspace - #XXX removed: test.objspace('std') + #XXX removed: testit.objspace('std') self.space = FakeObjSpace() def test_non_delegate(self): @@ -146,4 +146,4 @@ if __name__ == '__main__': - test.main() + testit.main() Modified: pypy/trunk/src/pypy/objspace/std/test/test_noneobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/test/test_noneobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/test/test_noneobject.py Wed Dec 24 00:01:48 2003 @@ -1,11 +1,11 @@ import autopath -from pypy.tool import test +from pypy.tool import testit -class TestW_NoneObject(test.TestCase): +class TestW_NoneObject(testit.TestCase): def setUp(self): - self.space = test.objspace('std') + self.space = testit.objspace('std') def tearDown(self): pass @@ -22,4 +22,4 @@ if __name__ == '__main__': - test.main() + testit.main() Modified: pypy/trunk/src/pypy/objspace/std/test/test_restricted_int.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/test/test_restricted_int.py (original) +++ pypy/trunk/src/pypy/objspace/std/test/test_restricted_int.py Wed Dec 24 00:01:48 2003 @@ -1,12 +1,12 @@ import unittest import autopath -from pypy.tool import test +from pypy.tool import testit from pypy.objspace.std.restricted_int import * -class Test_r_int(test.TestCase): +class Test_r_int(testit.TestCase): def setUp(self): - space = test.objspace('std') + space = testit.objspace('std') def tearDown(self): pass @@ -63,10 +63,10 @@ cmp = f(left(larg), right(rarg)) self.assertEquals(res, cmp) -class Test_r_uint(test.TestCase): +class Test_r_uint(testit.TestCase): def setUp(self): - space = test.objspace('std') + space = testit.objspace('std') def tearDown(self): pass @@ -130,4 +130,4 @@ self.assertEquals(res, cmp) if __name__ == '__main__': - test.main() + testit.main() Modified: pypy/trunk/src/pypy/objspace/std/test/test_sliceobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/test/test_sliceobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/test/test_sliceobject.py Wed Dec 24 00:01:48 2003 @@ -1,10 +1,10 @@ import autopath -from pypy.tool import test +from pypy.tool import testit -class TestW_SliceObject(test.TestCase): +class TestW_SliceObject(testit.TestCase): def setUp(self): - self.space = test.objspace('std') + self.space = testit.objspace('std') def tearDown(self): pass @@ -35,9 +35,9 @@ self.assertRaises_w(space.w_ValueError, slicetype.indices3, space, w_slice, 10) -class Test_SliceObject(test.AppTestCase): +class Test_SliceObject(testit.AppTestCase): def setUp(self): - self.space = test.objspace('std') + self.space = testit.objspace('std') def test_new(self): def cmp_slice(sl1, sl2): @@ -59,4 +59,4 @@ self.assertEqual(slice(11,4,-2).indices(2), (1, 2, -2)) if __name__ == '__main__': - test.main() + testit.main() Modified: pypy/trunk/src/pypy/objspace/std/test/test_stdobjspace.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/test/test_stdobjspace.py (original) +++ pypy/trunk/src/pypy/objspace/std/test/test_stdobjspace.py Wed Dec 24 00:01:48 2003 @@ -1,10 +1,10 @@ import autopath -from pypy.tool import test +from pypy.tool import testit -class TestW_StdObjSpace(test.TestCase): +class TestW_StdObjSpace(testit.TestCase): def setUp(self): - self.space = test.objspace('std') + self.space = testit.objspace('std') def tearDown(self): pass @@ -20,4 +20,4 @@ if __name__ == '__main__': - test.main() + testit.main() Modified: pypy/trunk/src/pypy/objspace/std/test/test_stringobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/test/test_stringobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/test/test_stringobject.py Wed Dec 24 00:01:48 2003 @@ -1,14 +1,14 @@ import autopath -from pypy.tool import test +from pypy.tool import testit from pypy.objspace.std import stringobject from pypy.objspace.std.stringobject import \ string_richcompare, W_StringObject, EQ, LT, GT, NE, LE, GE -class TestW_StringObject(test.TestCase): +class TestW_StringObject(testit.TestCase): def setUp(self): - self.space = test.objspace('std') + self.space = testit.objspace('std') def tearDown(self): pass @@ -114,9 +114,9 @@ w_slice = space.newslice(w(1), w_None, w(2)) self.assertEqual_w(space.getitem(w_str, w_slice), w('el')) -class TestStringObject(test.AppTestCase): +class TestStringObject(testit.AppTestCase): def setUp(self): - self.space = test.objspace('std') + self.space = testit.objspace('std') def test_split(self): self.assertEquals("".split(), []) @@ -472,4 +472,4 @@ if __name__ == '__main__': - test.main() + testit.main() Modified: pypy/trunk/src/pypy/objspace/std/test/test_tupleobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/test/test_tupleobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/test/test_tupleobject.py Wed Dec 24 00:01:48 2003 @@ -1,14 +1,14 @@ #from __future__ import nested_scopes import autopath -from pypy.tool import test +from pypy.tool import testit from pypy.objspace.std.tupleobject import W_TupleObject from pypy.objspace.std.objspace import NoValue -class TestW_TupleObject(test.TestCase): +class TestW_TupleObject(testit.TestCase): def setUp(self): - self.space = test.objspace('std') + self.space = testit.objspace('std') def tearDown(self): pass @@ -240,4 +240,4 @@ self.space.w_True) if __name__ == '__main__': - test.main() + testit.main() Modified: pypy/trunk/src/pypy/objspace/std/test/test_typeobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/test/test_typeobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/test/test_typeobject.py Wed Dec 24 00:01:48 2003 @@ -1,10 +1,10 @@ import autopath -from pypy.tool import test +from pypy.tool import testit -##class TestSpecialMultimethodCode(test.TestCase): +##class TestSpecialMultimethodCode(testit.TestCase): ## def setUp(self): -## self.space = test.objspace('std') +## self.space = testit.objspace('std') ## def tearDown(self): ## pass @@ -53,9 +53,9 @@ ## w({'x1': 5.5, 'x2': 7})), ## w(-1.5)) -class TestTypeObject(test.AppTestCase): +class TestTypeObject(testit.AppTestCase): def setUp(self): - self.space = test.objspace('std') + self.space = testit.objspace('std') def test_bases(self): self.assertEquals(int.__bases__, (object,)) @@ -90,4 +90,4 @@ "c": 3})) if __name__ == '__main__': - test.main() + testit.main() Modified: pypy/trunk/src/pypy/objspace/std/test/test_userobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/test/test_userobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/test/test_userobject.py Wed Dec 24 00:01:48 2003 @@ -1,9 +1,9 @@ import autopath -from pypy.tool import test +from pypy.tool import testit -class TestUserObject(test.AppTestCase): +class TestUserObject(testit.AppTestCase): def setUp(self): - self.space = test.objspace('std') + self.space = testit.objspace('std') def test_emptyclass(self): class empty: pass @@ -98,4 +98,4 @@ self.assertEquals(c1("hello", "world"), ("hello", "world")) if __name__ == '__main__': - test.main() + testit.main() Modified: pypy/trunk/src/pypy/objspace/test/test_traceobjspace.py ============================================================================== --- pypy/trunk/src/pypy/objspace/test/test_traceobjspace.py (original) +++ pypy/trunk/src/pypy/objspace/test/test_traceobjspace.py Wed Dec 24 00:01:48 2003 @@ -1,13 +1,13 @@ import autopath -from pypy.tool import test +from pypy.tool import testit from pypy.objspace.trace import TraceObjSpace from pypy.interpreter.gateway import app2interp from pypy.tool import pydis -class Test_TraceObjSpace(test.IntTestCase): +class Test_TraceObjSpace(testit.IntTestCase): def setUp(self): - self.space = test.objspace() + self.space = testit.objspace() def tearDown(self): pass @@ -61,4 +61,4 @@ #self.assertEquals_w(op.args_w, expected_w) if __name__ == '__main__': - test.main() + testit.main() Modified: pypy/trunk/src/pypy/tool/newtest.py ============================================================================== --- pypy/trunk/src/pypy/tool/newtest.py (original) +++ pypy/trunk/src/pypy/tool/newtest.py Wed Dec 24 00:01:48 2003 @@ -596,10 +596,10 @@ # possibly ignore dummy unit tests if do_selftest: # include only selftest module - filterfunc = lambda m: m.find("pypy.tool.testdata.") != -1 + filterfunc = lambda m: m.find("pypy.tool.testitdata.") != -1 else: # exclude selftest module - filterfunc = lambda m: m.find("pypy.tool.testdata.") == -1 + filterfunc = lambda m: m.find("pypy.tool.testitdata.") == -1 # collect tests suite = TestSuite() print "Loading test modules ..." Modified: pypy/trunk/src/pypy/tool/pydis.py ============================================================================== --- pypy/trunk/src/pypy/tool/pydis.py (original) +++ pypy/trunk/src/pypy/tool/pydis.py Wed Dec 24 00:01:48 2003 @@ -55,8 +55,8 @@ elif op in hascompare: s += '(' + cmp_op[oparg] + ')' elif op in hasfree: - if free is None: - free = co.co_cellvars + co.co_freevars + #if free is None: + free = co.co_cellvars + co.co_freevars s += '(' + free[oparg] + ')' return s Modified: pypy/trunk/src/pypy/tool/testdata/test_dummy.py ============================================================================== --- pypy/trunk/src/pypy/tool/testdata/test_dummy.py (original) +++ pypy/trunk/src/pypy/tool/testdata/test_dummy.py Wed Dec 24 00:01:48 2003 @@ -11,7 +11,7 @@ newtest.service.skip() -class TestDummy1(newtest.TestCase): +class TestDummy1(newtestit.TestCase): """ Example of a docstring for a class. """ @@ -25,7 +25,7 @@ raise self.fail("fail deliberately in test_failure1") -class TestDummy2(newtest.TestCase): +class TestDummy2(newtestit.TestCase): def test_success2(self): self.assertEquals(1+1, 2) @@ -37,7 +37,7 @@ raise self.fail("fail deliberately in test_failure2") -class TestSkip1(newtest.TestCase): +class TestSkip1(newtestit.TestCase): def setUp(self): self.skip() @@ -45,7 +45,7 @@ pass -class TestSkip2(newtest.TestCase): +class TestSkip2(newtestit.TestCase): def test_skip2(self): self.skip() @@ -61,4 +61,4 @@ if __name__ == '__main__': - newtest.main() + newtestit.main() Modified: pypy/trunk/src/pypy/tool/testit.py ============================================================================== --- pypy/trunk/src/pypy/tool/testit.py (original) +++ pypy/trunk/src/pypy/tool/testit.py Wed Dec 24 00:01:48 2003 @@ -94,7 +94,7 @@ def interact(self): efs = self.errors + self.failures - from pypy.tool.testpm import TestPM + from pypy.tool.testitpm import TestPM c = TestPM(efs) c.cmdloop() Modified: pypy/trunk/src/pypy/tool/traceinteractive.py ============================================================================== --- pypy/trunk/src/pypy/tool/traceinteractive.py (original) +++ pypy/trunk/src/pypy/tool/traceinteractive.py Wed Dec 24 00:01:48 2003 @@ -173,7 +173,7 @@ if __name__ == '__main__': from pypy.tool import option - from pypy.tool import test + from pypy.tool import testit args = option.process_options(option.get_standard_options(), option.Options) Modified: pypy/trunk/src/pypy/tool/traceop.py ============================================================================== --- pypy/trunk/src/pypy/tool/traceop.py (original) +++ pypy/trunk/src/pypy/tool/traceop.py Wed Dec 24 00:01:48 2003 @@ -78,7 +78,7 @@ print line_begin(frame_count) + ("<<<<>>>>>>" % lastframe) elif isinstance(event, trace.ExecBytecode): disresult = getdisresult(event.frame) - print line_begin(frame_count), event.index, " ", disresult.getbytecode(event.index) + print line_begin(frame_count), "%2d" % event.index, " ", disresult.getbytecode(event.index) lastframe = event.frame elif isinstance(event, trace.CallBegin): @@ -260,7 +260,7 @@ ## ## pass ## ## from pypy.tool import option -## ## from pypy.tool import test +## ## from pypy.tool import testit ## ## args = option.process_options(option.get_standard_options(), ## ## option.Options) ## ## objspace = option.objspace() Modified: pypy/trunk/src/pypy/translator/test/test_annrpython.py ============================================================================== --- pypy/trunk/src/pypy/translator/test/test_annrpython.py (original) +++ pypy/trunk/src/pypy/translator/test/test_annrpython.py Wed Dec 24 00:01:48 2003 @@ -1,6 +1,6 @@ import autopath -from pypy.tool import test +from pypy.tool import testit from pypy.tool.udir import udir from pypy.translator.annrpython import RPythonAnnotator, ANN @@ -9,9 +9,9 @@ from pypy.translator.test import snippet -class AnnonateTestCase(test.IntTestCase): +class AnnonateTestCase(testit.IntTestCase): def setUp(self): - self.space = test.objspace('flow') + self.space = testit.objspace('flow') def make_fun(self, func): import inspect @@ -165,4 +165,4 @@ if __name__ == '__main__': - test.main() + testit.main() Modified: pypy/trunk/src/pypy/translator/test/test_cltrans.py ============================================================================== --- pypy/trunk/src/pypy/translator/test/test_cltrans.py (original) +++ pypy/trunk/src/pypy/translator/test/test_cltrans.py Wed Dec 24 00:01:48 2003 @@ -1,5 +1,5 @@ import autopath -from pypy.tool import test +from pypy.tool import testit from pypy.tool.udir import udir @@ -39,11 +39,11 @@ from pypy.translator.test import snippet as t from pypy.translator.tool.buildcl import Literal -class GenCLTestCase(test.IntTestCase): +class GenCLTestCase(testit.IntTestCase): def setUp(self): if not global_cl: - raise (test.TestSkip, + raise (testit.TestSkip, "Common Lisp neither configured nor detected.") def test_if(self): @@ -134,4 +134,4 @@ if __name__ == '__main__': - test.main() + testit.main() Modified: pypy/trunk/src/pypy/translator/test/test_pyrextrans.py ============================================================================== --- pypy/trunk/src/pypy/translator/test/test_pyrextrans.py (original) +++ pypy/trunk/src/pypy/translator/test/test_pyrextrans.py Wed Dec 24 00:01:48 2003 @@ -1,5 +1,5 @@ import autopath -from pypy.tool import test +from pypy.tool import testit from pypy.tool.udir import udir from pypy.translator.genpyrex import GenPyrex from pypy.objspace.flow.model import * @@ -7,16 +7,16 @@ from pypy.translator.test import snippet as t -class TypedPyrexGenTestCase(test.IntTestCase): +class TypedPyrexGenTestCase(testit.IntTestCase): def setUp(self): - self.space = test.objspace('flow') + self.space = testit.objspace('flow') def build_cfunc(self, func): try: func = func.im_func except AttributeError: pass - dot = test.Options.verbose >0 and 1 or 0 + dot = testit.Options.verbose >0 and 1 or 0 options = { 'simplify' : 1, 'dot' : dot, @@ -90,7 +90,7 @@ try: func = func.im_func except AttributeError: pass - dot = test.Options.verbose >0 and 1 or 0 + dot = testit.Options.verbose >0 and 1 or 0 options = { 'simplify' : 1, 'dot' : dot, @@ -98,4 +98,4 @@ return build_cfunc(func, **options) if __name__ == '__main__': - test.main() + testit.main() Modified: pypy/trunk/src/pypy/translator/test/test_sourcegen.py ============================================================================== --- pypy/trunk/src/pypy/translator/test/test_sourcegen.py (original) +++ pypy/trunk/src/pypy/translator/test/test_sourcegen.py Wed Dec 24 00:01:48 2003 @@ -1,6 +1,6 @@ import autopath -from pypy.tool import test +from pypy.tool import testit from pypy.tool.udir import udir from pypy.translator.genpyrex import GenPyrex @@ -9,7 +9,7 @@ from pypy.translator.tool.buildpyxmodule import make_module_from_pyxstring #from pypy.translator.test.make_dot import make_ps -class SourceGenTestCase(test.IntTestCase): +class SourceGenTestCase(testit.IntTestCase): def test_simple_func(self): """ one test source: @@ -90,4 +90,4 @@ self.assertEquals(mod.f(-3), 0) if __name__ == '__main__': - test.main() + testit.main() Modified: pypy/trunk/src/pypy/translator/tool/benchmark.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/benchmark.py (original) +++ pypy/trunk/src/pypy/translator/tool/benchmark.py Wed Dec 24 00:01:48 2003 @@ -1,5 +1,5 @@ import autopath -from pypy.tool import test +from pypy.tool import testit from pypy.tool.udir import udir from pypy.translator.tool.buildpyxmodule import build_cfunc from pypy.translator.test.test_cltrans import global_cl, make_cl_func Modified: pypy/trunk/src/pypy/translator/tool/buildpyxmodule.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/buildpyxmodule.py (original) +++ pypy/trunk/src/pypy/translator/tool/buildpyxmodule.py Wed Dec 24 00:01:48 2003 @@ -1,5 +1,5 @@ import autopath -from pypy.tool import test +from pypy.tool import testit from pypy.tool.udir import udir from vpath.adapter.process import exec_cmd Modified: pypy/trunk/src/pypy/translator/translator.py ============================================================================== --- pypy/trunk/src/pypy/translator/translator.py (original) +++ pypy/trunk/src/pypy/translator/translator.py Wed Dec 24 00:01:48 2003 @@ -28,7 +28,7 @@ Try dir(test) for list of current snippets. """ -import test.autopath +import testit.autopath from pypy.objspace.flow.model import * from pypy.annotation.model import * From alex at codespeak.net Wed Dec 24 14:08:54 2003 From: alex at codespeak.net (alex at codespeak.net) Date: Wed, 24 Dec 2003 14:08:54 +0100 (MET) Subject: [pypy-svn] rev 2690 - pypy/trunk/src/pypy/module/test Message-ID: <20031224130854.64C375B089@thoth.codespeak.net> Author: alex Date: Wed Dec 24 14:08:53 2003 New Revision: 2690 Modified: pypy/trunk/src/pypy/module/test/test_builtin.py Log: added a comment to test_builtin.py Modified: pypy/trunk/src/pypy/module/test/test_builtin.py ============================================================================== --- pypy/trunk/src/pypy/module/test/test_builtin.py (original) +++ pypy/trunk/src/pypy/module/test/test_builtin.py Wed Dec 24 14:08:53 2003 @@ -208,7 +208,11 @@ "Builtin function 'callable' misreads int") def test_uncallable(self): - class NoCall: + # XXX TODO: I made the NoCall class explicitly newstyle to try and + # remedy the failure in this test observed when running this with + # the trivial objectspace, but the test _still_ fails then (it + # doesn't fail with the standard objectspace, though). + class NoCall(object): pass a = NoCall() self.failIf(callable(a), From arigo at codespeak.net Sat Dec 27 13:02:44 2003 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 27 Dec 2003 13:02:44 +0100 (MET) Subject: [pypy-svn] rev 2691 - pypy/trunk/doc/translation Message-ID: <20031227120244.682235B089@thoth.codespeak.net> Author: arigo Date: Sat Dec 27 13:02:42 2003 New Revision: 2691 Modified: pypy/trunk/doc/translation/annotation.txt Log: A few words about the current annotations implementation. Modified: pypy/trunk/doc/translation/annotation.txt ============================================================================== --- pypy/trunk/doc/translation/annotation.txt (original) +++ pypy/trunk/doc/translation/annotation.txt Sat Dec 27 13:02:42 2003 @@ -1,13 +1,15 @@ The annotation pass =================== -Let's assume that the control flow graph building pass can be -done entierely before the annotation pass. (See notes at the -end for why we'd like to mix them.) +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 +(e.g. C/Lisp/Pyrex). -Factorial ---------- +An example: the factorial +------------------------- Say we want to make the control flow graph and type inference on the following program:: @@ -44,23 +46,23 @@ We start type inference on the first block:: Analyse(StartBlock): - v1 ----> X1 type(X1)=int - v2 ----> X2 type(X2)=bool + 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 (X1, X2, X3...). Annotations give some information +here be unknown (SV1, SV2, SV3...). Annotations give some information about the unknown heap objects. The arrows represent binding from -variables to objects. +variables to objects. ``SV`` means ``SomeValue``. After StartBlock, we proceed to the type inference of its exits; first Block2:: Analyse(Block2): - v3 ------------> X1 # copied from StartBlock - v4 ------------> X4 type(X4)=int - v7 ------------> failure + 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 @@ -68,46 +70,47 @@ from the StackBlock, which is jumping to Block3:: Analyse(Block3): - v9 --------> 1 # and we have type(1)=int automatically + v9 --------> SV31 # const(SV31)=1, type(SV31)=int +The object SV31 is the constant object 1. Then we proceed to ReturnBlock:: Analyse(ReturnBlock): - retval --------> 1 + 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 ------------> X1 # copied from StartBlock - v4 ------------> X4 type(X4)=int - v7 ------------> 1 # because that's the retval of f - v8 ------------> X8 type(X8)=int eq(X1,X8)=True # because X8=X1*1 + 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 -------> 1 type(1)=int - new annotations for retval ------------> X8 type(X8)=int eq(X8,X1)=True - intersection of both is retval --------> X10 type(X10)=int + 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 ------------> X1 # with type(X1)=int - v4 ------------> X4 type(X4)=int - v7 ------------> X10 # with type(X10)=int - v8 ------------> X11 type(X11)=int + 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 -------> X10 type(X10)=int - new annotations for retval ------------> X11 type(X11)=int + 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 @@ -115,24 +118,24 @@ in retval are properly annotated:: Bindings: - v1 ------> X1 - v2 ------> X2 - v3 ------> X1 - v4 ------> X4 - v7 ------> X10 - v8 ------> X11 - v9 ------> 1 - retval --> X10 + v1 ------> SV1 + v2 ------> SV2 + v3 ------> SV1 + v4 ------> SV4 + v7 ------> SV10 + v8 ------> SV11 + v9 ------> SV31 + retval --> SV10 Annotations: - type(X1)=int - type(X2)=bool - type(X4)=int - type(X10)=int - type(X11)=int + 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 AnnSet instance. +an AnnotationSet instance. More about it below. Whole-program analysis @@ -170,29 +173,55 @@ v3 = simple_call(g, v1, 6) Analyse(F_StartBlock): - v1 -------> X1 type(X1)=list len(X1)=0 getitem(X1,*)=? - v2 -------> crash + v1 -------> SV1 type(SV1)=list len(SV1)=0 listitems(SV1)=impossiblevalue + v2 -------> impossiblevalue -The ``?`` is a special value meaning ``no analysis information``, and ``*`` is a special catch-all value. The type analysis fails because of the calls to ``g``, but it triggers the analysis of ``g`` with the input arguments' annotations:: +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 -------> X1 # from the call above - v5 -------> 5 # from the call above - v6 -------> X6 im_self(X6)=X1 im_func(X6)=list_append - v7 -------> None REMOVE{len(X1)=0} getitem(X1,?)=5 - -Note that the call to list_append corrects the annotations about ``X1``. -This would invalidate any type inference that would depend on the modified -annotations. (Hopefully, we eventually reach a fixpoint; this could be -enforced by requiring that we can only either remove annotations or give -a value to a ``?``.) + 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 ``X1`` with the correct annotations: +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 @@ -200,23 +229,23 @@ previously thought to be used with ``5`` only:: Intersection(G_StartBlock): - previous annotations for v5 -------> 5 type(5)=int - new annotations for v5 ------------> 6 type(6)=int - intersection of both is v5 --------> X5 type(X5)=int + 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 ``X1`` is updated with:: +And so this time the list ``SV1`` is updated with:: - getitem(X1,*)=X5 + 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 ``X1``. +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 ``X10`` or ``X11``, and the intersection said it was fine because they -had the same annotations. It would not be fine if ``X10`` and ``X11`` -could be of a mutable type. In this case we must force ``X10==X11`` for +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 @@ -227,6 +256,8 @@ 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. @@ -252,3 +283,84 @@ 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. + + +SomeValue +--------- + +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 interection algorithm is implemented in the ``merge()`` method +of AnnotationSet. From arigo at codespeak.net Sat Dec 27 17:44:46 2003 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 27 Dec 2003 17:44:46 +0100 (MET) Subject: [pypy-svn] rev 2692 - pypy/trunk/doc/objspace Message-ID: <20031227164446.237365AA0B@thoth.codespeak.net> Author: arigo Date: Sat Dec 27 17:44:45 2003 New Revision: 2692 Modified: pypy/trunk/doc/objspace/multimethod.txt Log: A possible clean specification of multimethods. Modified: pypy/trunk/doc/objspace/multimethod.txt ============================================================================== --- pypy/trunk/doc/objspace/multimethod.txt (original) +++ pypy/trunk/doc/objspace/multimethod.txt Sat Dec 27 17:44:45 2003 @@ -1,143 +1,251 @@ -======================== -PyPy MultiMethod -======================== - -Notes on Multimethods ------------------------- - -Interpreter-level classes correspond to implementations of application-level -types. Several implementations can be given for the same type (e.g. several -ways to code strings or dictionaries), and conversely the same implementation -can cover several types (e.g. all instances of user-defined types currently -share the same implementation). - -The hierarchy among the classes used for the implementations is convenient -for implementation purposes. It is not related to any application-level type -hierarchy. - -Dispatch -------------------- - -Multimethods dispatch by looking in a set of registered functions. Each -registered function has a signature, which defines which object implementation -classes are accepted at the corresponding argument position. - -The name 'W_ANY' is a synonym for 'W_Object' (currently, possibly 'object' -later). As it accepts anything, it is the only way to guarantee that the -registered function will be called with exactly the same object as was -passed originally. ATTENTION: in all other cases the argument received by -the function may have been converted in some way. It must thus not be -considered to be 'id'entical to the original argument. For example it should -not be stored in a data structure, nor be queried for type, nor be used for -another multimethod dispatch -- the only thing you should do is read and -write its internal data. - -For example, 'getattr(obj, attr)' is implemented with a ``W_StringObject`` second -argument when all it needs is just the name of the attr, and with a W_ANY -when the 'attr' object could be used as a key in ``obj.__dict__``. - - -Delegation ---------------- - -Delegation is a transparent conversion mechanism between object -implementations. The conversion can give a result of a different type -(e.g. int -> float) or of the same type (e.g. W_VeryLongString -> str). -There is a global table of delegators. We should not rely on the delegators -to be tried in any particular order, or at all (e.g. the int -> float delegator -could be ignored when we know that no registered function will accept a float -anyway). - -Delegation is also used to emulate inheritance between built-in types -(e.g. bool -> int). This is done by delegation because there is no reason -that a particular implementation of a sub-type can be trivially typecast -to some other particular implementation of the parent type; the process might -require some work. +========================= +MultiMethods and Coercion +========================= + +Introduction +------------ + +A "multimethod" is the generalization of the OOP notion of "method". +Theoretically, a method is a "message name" and signature attached to a +particular base class, which is implementated in the class or its subclasses. +To do a "method call" means to send a message to an object, using a message +name and actual arguments. We call "message dispatch" the operation of +finding which actual implementation is suitable for a particular call. For +methods, a message is dispatched by looking up the class of the "self" object, +and finding an implementation in that class, or in its base classes, in a +certain order. + +A multimethod is a message name and signature that can have implementations +that depend not only on the class of the first "self" argument, but on the +class of several arguments. Because of this we cannot use Python's nice model +of storing method implementations as functions, in the attributes of the +class. + +Here is a common implementation of multimethods: they are instances of a +specific MultiMethod class, and the instances are callable (there is a +__call__ operator on MultiMethod). When a MultiMethod is called, a dispatch +algorithm is used to find which, among the registered implementations, is the +one that should be called; this implementation is then immediately called. The +most important difference with normal methods is that the MultiMethod object +to call is no longer syntactically attached to classes. In other words, +whereas a method is called with ``obj.somemethod(args)``, a multimethod is +called much like a function, e.g. ``dosomething(obj1, obj2, obj3...)``. You +have to find the MultiMethod object ``dosomething`` in some namespace; it is +no longer implicitely looked up in the namespace of the "self" object. + +In PyPy the MultiMethod objects are stored in the object space instance, thus +``space.add`` is the name of a MultiMethod. The ``space`` argument is not +used for the dispatch, but just as a convenient place to put the MultiMethod +object. + + +Concept Trees +------------- + +A multimethod is a "signature" and a set of "implementations", which are +regular Python functions. The difficulty is to figure out an algorithm that +should be used to know, given actual argument values, which implementation +should be called. + +This algorithm should only depend on the types of the arguments. For +explicitness we will *not* use the Python class inheritance at all (because it +is better suited to normal methods, and anyway it can be emulated if needed). +Thus the following diagram looks like inheritance diagrams, but it is actually +just an explicitely specified tree:: + + Value + \ + \ + Float + / \ + / \ + Integer \ + / \ V + / \ + T U + +This diagram contains three Python types T, U and V, and three "concepts" +Integer, Float and Value, which are just names. The types T and U could be +two different ways to implement integers (e.g. machine-sized ints, and +variable-sized longs), and the type V could be the IEEE doubles. Note that in +this model the real Python types are the "leaves" of the tree. + +Consider the multimethod ``add(Value, Value)``. The signature specifies that +the two arguments should be two Values (remember that Value is not a type, +just some "concept"; you cannot ask whether a Python object is a Value or +not). Suppose that this multimethod has got three implementations: +``add(T,T)``, ``add(U,T)`` and ``add(V,V)``. If you call ``add(t1,t2)`` with +two objects of type ``T``, the first implementation is used; if you call it +with a ``U`` and a ``T``, the second one is used; and if you call it with two +``V``, the third one is used. + +But if you call it with another pattern of types, there is no direct match. +To be able to satisfy the call, at least one of the arguments will have to be +converted to another type. This is where the shape of the tree becomes +important. Remember that the signature of the multimethod is ``add(Value, +Value)``. The two ``Value`` here mean that conversions are allowed inside of +the part of the tree that is below ``Value``. (This is the tree shown above; +maybe there are other "concepts" above ``Value`` outside the picture, but they +are ignored.) The intuitive meaning of the signature is: "add() is an +operation between two Values". It allows a object of type T to be converted +into an object of type U or V and vice-versa, as long as the objects have the +same "Value", in an intuitive sense. An example of conversion that destroys +the Value would be casting a T object into an instance of ``object``, which is +a parent class of any Python class. + + +Conversion +---------- + +All conversions that don't change the "Value" of an object can be registered +as Python functions. For example:: + + def f(x): + return V(x) + +might be a conversion from T to V. But we can say more: this conversion is +more precisely defined at the level of "Float" in the tree above. +Similarily, a conversion from T to U would probably be defined at the +"Integer" level. + +Suppose that we have defined these two conversions, from T to V and from T to +U. Suppose now that we call ``add(t,v)`` where ``t`` is of type T and ``v`` +is of type V. Clearly, we want ``t`` to be converted into a V, which allows +``add(V,V)`` to be called. To find this conversion, the algorithm looks into +the subconcepts of ``Value``, starting from the leaves and going back to the +higher levels, until it can satisfy the call request by inserting conversions +registered at these levels. + +Starting from the lower levels and going up allows the tree to prioritize the +solutions: it is better to try to convert between Integers, and only if that +fails, to try to convert at the Float level, which might promote integer +objects into floats. + + +Multimethod signature +--------------------- + +The signature ``add(Value, Value)`` of the multimethod is essential to specify +that conversions are indeed allowed for the addition. In other multimethods, +some arguments might play different roles. Consider a multimethod for +"in-place addition": as this operation might mutate its first argument, it +must never be automatically converted. This is expressed by saying that the +signature of this multimethod is ``inplace_add(Identity, Value)`` where +``Identity`` is another concept that intuitively means "a Python object whose +identity is important". ``Identity`` would not appear in a tree, or if it +would, it would not have conversions between its subtypes. + +Note how a real Python object of type T can either be an "Integer" or an +"Identity" depending on its role in a multimethod call. This is why we cannot +use normal inheritance as the (global) conversion tree: which tree to use +depends on the role of the argument, which changes in different positions of +different multimethods. + +This approach is general enough to allow arguments to play very different +roles. For example, the same mecanisms could be used for an argument that +must be an integer: the multimethod signature would specify ``Integer`` +instead of ``Value``. It still allows conversion between integer +representations, but not from float to int. + +In PyPy, some "concepts" are tied to the application-level types: ``Integer`` +corresponds to the application-level ``class int``, and ``Float`` to ``class +float``. The T, U and V types are interpreter-level implementations, and they +are normally not visible at application-level. It is then natural to define +what the method ``int.__add__(self, other)`` should do: it should require an +``Integer`` as its first argument, but it could be T or U -- appropriate +conversions can be done, as long as we don't convert ``self`` outside the +realm of ``Integer``. -Types ---------- - -Types are implemented by the class W_TypeObject. This is where inheritance -and the Method Resolution Order are defined, and where attribute look-ups -are done. - -Instances of user-defined types are implemented as W_UserObjects. -A user-defined type can inherit from built-in types (maybe more than one, -although this is incompatible with CPython). The W_UserObject delegator -converts the object into any of these "parent objects" if needed. This is -how user-defined types appear to inherit all built-in operator -implementations. - -Delegators should be able to invoke user code; this would let us -implement special methods like __int__() by calling them within a -W_UserObject -> int delegator. - -Specifics of multimethods ---------------------------- - -Multimethods dispatch more-specific-first, left-to-right (i.e. if there is -an exact match for the first argument it will always be tried first). - -Delegators are automatically chained (i.e. A -> B and B -> C would be -combined to allow for A -> C delegation). - -Delegators do not publish the class of the converted object in advance, -so that the W_UserObject delegator can potentially produce any other -built-in implementation. This means chaining and chain loop detection cannot -be done statically (at least without help from an analysis tool like the -translator-to-C). To break loops, we can assume (unless a particular need -arises) that delegators are looping when they return an object of an -already-seen class. - -Registration --------------------- - -The register() method of multimethods adds a function to its database of -functions, with the given signature. A function that raises -!FailedToImplement causes the next match to be tried. - -'delegate' is the special unary multimethod that should try to convert -its argument to something else. For greater control, it can also return -a list of 2-tuples (class, object), or an empty list for failure to convert -the argument to anything. All delegators will potentially be tried, and -recursively on each other's results to do chaining. - -A priority ordering between delegators is used. See ``objspace.PRIORITY_*``. +Conversion multimethods +----------------------- +As conversion functions are linked to levels in the tree, and there can be +several conversions for each level, they are much like multimethods +themselves. In other words, for each "concept" (Value, Float, Integer) we can +introduce a multimethod (valueconv, floatconv, integerconv) with the +corresponding signature (``valueconv(Value)``, ``floatconv(Float)``, +``integerconv(Integer)``). Specific conversion functions are implementations +of one of these multimethods. For example, if ``g`` is a T-to-U conversion, +it is an implementation of ``integerconv(Integer)``, with the type ``g(T)``. + +The job of the multimethod dispatcher algorithm is to insert the appropriate +implementations of the allowed ``xxxconv(Xxx)`` multimethods until the call +can be satisfied. + +A nice point of view is that these conversion multimethod are identity +functions (i.e. functions that do nothing, and return their argument +unmodified): ``integerconv(Integer)`` is the abstract function that takes an +Integer and just returns it; an implementation like ``g(T)`` actually takes a +T and returns a U, which is different, but when you look at it abstractedly at +the Integer level, you just see an Integer input argument and the same Integer +result. -Translation ------------------------ -The code in multimethod.py is not supposed to be read by the -translator-to-C. Special optimized code will be generated instead -(typically some kind of precomputed dispatch tables). - -Delegation is special-cased too. Most delegators will be found -to return an object of a statically known class, which means that -most of the chaining and loop detection can be done in advance. - - -Multimethod slicing ------------------------- - -Multimethods are visible to user code as (bound or unbound) methods -defined for the corresponding types. (At some point built-in functions -like len() and the operator.xxx() should really directly map to the -multimethods themselves, too.) - -To build a method from a multimethod (e.g. as in 'l.append' or -'int.__add__'), the result is actually a "slice" of the whole -multimethod, i.e. a sub-multimethod in which the registration table has -been trimmed down. (Delegation mechanisms are not restricted for sliced -multimethods.) - -Say that C is the class the new method is attached to (in the above -examples, respectively, C=type(l) and C=int). The restriction is -based on the registered class of the first argument ('self' for the -new method) in the signature. If this class corresponds to a fixed -type (as advertised by 'statictype'), and this fixed type is C or a -superclass of C, then we keep it. +Algorithm +--------- -Some multimethods can also be sliced along their second argument, -e.g. for __radd__(). +Here is a suggested algorithm. Roughly, it assumes that arguments with the +same abstract signature (e.g. ``Value`` in ``add(Value, Value)``) work +together, but arguments with distinct signature are independent. + +Assume that the signature of a multimethod is ``m(C1,...,Cn)``, and we want to +dispatch the call ``m(A1,...,An)``, where the arguments have types +``T1,...,Tn`` respectively. Each type ``Ti`` must appear in the subtree below +``Ci``, otherwise it is a TypeError. + +We use a single set S of types and concepts, which will grow until it is large +enough to contain the appropriate conversion functions:: + + S = { } # empty set + sortedmatches = [] + while 1: + find_matches_in(S) + i = the largest integer in {1,...,n} such that Ci not in S + or break if there isn't any such i any more + C = the first item in order(Ci) such that C not in S + add C into S + also add into S the whole subtree of C + +where ``order(C)`` is a kind of "method resolution order" of everything +*under* ``C`` (instead of *over* ``C`` for Python's MRO). For example, +following Python 2.2:: + + def order(C): + lst = [] + for j in range(n,0,-1): + if Tj in subtree(C): + lst += [Tj, parent(Tj), parent(parent(Tj)), ..., C] + for each D that appears more than once in lst: + remove all but the last occurrence of D in lst + return lst + +The algorithm in Python 2.3 is slightly different, and could probably be used +instead, though the difference should not be significant for the kind of trees +we are using. + +Finally:: + + def find_matches_in(S): + matches = list_matches_in(S) + remove from matches the items already in sortedmatches + if len(matches) > 1: + warning ambiguity, or maybe use performance hints + sortedmatches += matches + + def list_matches_in(S): + conv = { implementations of the conversion multimethod of C + for C in S } + combine in all possible ways the functions in conv to change + the types T1,...,Tn into the types U1,...,Un of an + implementation of the multimethod to call + +The resulting ``sortedmatches`` list contains, in preference order, the +implementations that are available to be dispatched to. We generally just +call the first one, but it (or any later one) may raise FailedToImplement; in +this case the dispatcher tries the next one. + +The rest of the algorithm are implementation and performance tricks, e.g. it +should try to call a given conversion function only once and remember the +value of the converted argument in case we need it again after a +FailedToImplement. From hpk at codespeak.net Sat Dec 27 18:39:14 2003 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sat, 27 Dec 2003 18:39:14 +0100 (MET) Subject: [pypy-svn] rev 2693 - pypy/trunk/doc/objspace Message-ID: <20031227173914.C9F815AA0B@thoth.codespeak.net> Author: hpk Date: Sat Dec 27 18:39:14 2003 New Revision: 2693 Modified: pypy/trunk/doc/objspace/multimethod.txt Log: took the freedom to rename the variables in Armin's Multimethod rewrite a bit in order to make it easier to connect the concept "Integer" and "Float" to its implementations I1,I2 and F1 respectively. At least my brain can only remember so many 't,u,v,g,T,V,U,...' :-) Other than that, i like the multimethod documenetation and the idea fine but would recommend to repeat the Concept/Implementation asci-tree (maybe including the conversion functions). Otherwise it seems hard to remember all the different single variable-names during the example. Modified: pypy/trunk/doc/objspace/multimethod.txt ============================================================================== --- pypy/trunk/doc/objspace/multimethod.txt (original) +++ pypy/trunk/doc/objspace/multimethod.txt Sat Dec 27 18:39:14 2003 @@ -60,24 +60,24 @@ / \ / \ Integer \ - / \ V + / \ F1 / \ - T U + I1 I2 -This diagram contains three Python types T, U and V, and three "concepts" -Integer, Float and Value, which are just names. The types T and U could be +This diagram contains three Python types I1, I2 and F1, and three "concepts" +Integer, Float and Value, which are just names. The types I1 and I2 could be two different ways to implement integers (e.g. machine-sized ints, and -variable-sized longs), and the type V could be the IEEE doubles. Note that in +variable-sized longs), and the type F1 could be the IEEE doubles. Note that in this model the real Python types are the "leaves" of the tree. Consider the multimethod ``add(Value, Value)``. The signature specifies that the two arguments should be two Values (remember that Value is not a type, just some "concept"; you cannot ask whether a Python object is a Value or not). Suppose that this multimethod has got three implementations: -``add(T,T)``, ``add(U,T)`` and ``add(V,V)``. If you call ``add(t1,t2)`` with -two objects of type ``T``, the first implementation is used; if you call it -with a ``U`` and a ``T``, the second one is used; and if you call it with two -``V``, the third one is used. +``add(I1,I1)``, ``add(I1,I2)`` and ``add(F1,F1)``. If you call ``add(t1,t2)`` with +two objects of type ``I1``, the first implementation is used; if you call it +with a ``I1`` and a ``I2``, the second one is used; and if you call it with two +``F1``, the third one is used. But if you call it with another pattern of types, there is no direct match. To be able to satisfy the call, at least one of the arguments will have to be @@ -87,10 +87,10 @@ the part of the tree that is below ``Value``. (This is the tree shown above; maybe there are other "concepts" above ``Value`` outside the picture, but they are ignored.) The intuitive meaning of the signature is: "add() is an -operation between two Values". It allows a object of type T to be converted -into an object of type U or V and vice-versa, as long as the objects have the +operation between two Values". It allows an object of type I1 to be converted +into an object of type I2 or F1 and vice-versa, as long as the objects have the same "Value", in an intuitive sense. An example of conversion that destroys -the Value would be casting a T object into an instance of ``object``, which is +the Value would be casting a I1 object into an instance of ``object``, which is a parent class of any Python class. @@ -101,20 +101,22 @@ as Python functions. For example:: def f(x): - return V(x) + return F1(x) -might be a conversion from T to V. But we can say more: this conversion is +might be a conversion from I1 to F1. But we can say more: this conversion is more precisely defined at the level of "Float" in the tree above. -Similarily, a conversion from T to U would probably be defined at the +Similarily, a conversion from I1 to I2 would probably be defined at the "Integer" level. -Suppose that we have defined these two conversions, from T to V and from T to -U. Suppose now that we call ``add(t,v)`` where ``t`` is of type T and ``v`` -is of type V. Clearly, we want ``t`` to be converted into a V, which allows -``add(V,V)`` to be called. To find this conversion, the algorithm looks into -the subconcepts of ``Value``, starting from the leaves and going back to the -higher levels, until it can satisfy the call request by inserting conversions -registered at these levels. +Suppose that we have defined these two conversions, from I1 to F1 and +from I1 to I2. Suppose now that we call ``add(i,f)`` where ``i`` is of +type I1 and ``f`` is of type F1. Clearly, we want ``i`` to be converted +into a F1, which allows ``add(Value, Value)`` to be called and +dispatched to the ``add(F1,F1)`` implementation. To find this +conversion, the algorithm looks into the subconcepts of ``Value``, +starting from the leaves and going back to the higher levels, until it +can satisfy the call request by inserting conversions registered at +these levels. Starting from the lower levels and going up allows the tree to prioritize the solutions: it is better to try to convert between Integers, and only if that @@ -135,7 +137,7 @@ identity is important". ``Identity`` would not appear in a tree, or if it would, it would not have conversions between its subtypes. -Note how a real Python object of type T can either be an "Integer" or an +Note how a real Python object of type I1 can either be an "Integer" or an "Identity" depending on its role in a multimethod call. This is why we cannot use normal inheritance as the (global) conversion tree: which tree to use depends on the role of the argument, which changes in different positions of @@ -147,14 +149,15 @@ instead of ``Value``. It still allows conversion between integer representations, but not from float to int. -In PyPy, some "concepts" are tied to the application-level types: ``Integer`` -corresponds to the application-level ``class int``, and ``Float`` to ``class -float``. The T, U and V types are interpreter-level implementations, and they -are normally not visible at application-level. It is then natural to define -what the method ``int.__add__(self, other)`` should do: it should require an -``Integer`` as its first argument, but it could be T or U -- appropriate -conversions can be done, as long as we don't convert ``self`` outside the -realm of ``Integer``. +In PyPy, some "concepts" are by convention tied to the application-level +types: ``Integer`` corresponds to the application-level ``class int``, +and ``Float`` to ``class float``. The I1, I2 and F1 types are +interpreter-level implementations, and they are normally not visible at +application-level. It is then natural to define what the method +``int.__add__(self, other)`` should do: it should require an ``Integer`` +as its first argument, but it could be I1 or I2 -- appropriate conversions +can be done, as long as we don't convert ``self`` outside the realm of +``Integer``. Conversion multimethods @@ -166,8 +169,8 @@ introduce a multimethod (valueconv, floatconv, integerconv) with the corresponding signature (``valueconv(Value)``, ``floatconv(Float)``, ``integerconv(Integer)``). Specific conversion functions are implementations -of one of these multimethods. For example, if ``g`` is a T-to-U conversion, -it is an implementation of ``integerconv(Integer)``, with the type ``g(T)``. +of one of these multimethods. For example, if ``g`` is a I1-to-I2 conversion, +it is an implementation of ``integerconv(Integer)``, with the type ``g(I1)``. The job of the multimethod dispatcher algorithm is to insert the appropriate implementations of the allowed ``xxxconv(Xxx)`` multimethods until the call @@ -176,8 +179,8 @@ A nice point of view is that these conversion multimethod are identity functions (i.e. functions that do nothing, and return their argument unmodified): ``integerconv(Integer)`` is the abstract function that takes an -Integer and just returns it; an implementation like ``g(T)`` actually takes a -T and returns a U, which is different, but when you look at it abstractedly at +Integer and just returns it; an implementation like ``g(I1)`` actually takes a +I1 and returns a I2, which is different, but when you look at it abstractedly at the Integer level, you just see an Integer input argument and the same Integer result. From hpk at codespeak.net Sun Dec 28 19:05:38 2003 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sun, 28 Dec 2003 19:05:38 +0100 (MET) Subject: [pypy-svn] rev 2694 - pypy/trunk/doc Message-ID: <20031228180538.1C9415A5AE@thoth.codespeak.net> Author: hpk Date: Sun Dec 28 19:05:36 2003 New Revision: 2694 Modified: pypy/trunk/doc/architecture.txt Log: Wrote a higher level instruction to our architecture. Modified: pypy/trunk/doc/architecture.txt ============================================================================== --- pypy/trunk/doc/architecture.txt (original) +++ pypy/trunk/doc/architecture.txt Sun Dec 28 19:05:36 2003 @@ -1,16 +1,52 @@ -Overview on PyPy's current architecture (Dec. 2003) -==================================================== +Overview on PyPy's current architecture (Dec. 2003) +=================================================== + + +Introduction and higher level picture +------------------------------------- The various parts of PyPy have always been under more or less heavy refactoring during our five one-week sprints in 2003. However, the -basic architecture remains rather simple and unchanged: a plain -*interpreter* reads and dispatches *bytecodes*, shuffling objects around -on the stack and between namespaces of which it knows almost nothing. -For any operation on an object, the interpreter delegates to a so-called -"Object Space", which performs creation, modification, access, and -destruction of objects. Such objects are often refered to as -*application-level objects*, because they are the objects you naturally -work with from a python program. +higher level architecture remains rather simple and unchanged. There +are two independent basic subsystems: + +- the *standard interpreter* which implements the Python language + and is composed out of two components: + + - the *plain interpreter* which is responsible for interpreting + code objects and implementing bytecodes, + + - the *standard object space* which implements creation, access and + modification of application level objects, + + Note that the *standard interpreter* can run fine on top of CPython + (the C Implementation of Python led by Guido van Rossum) but of course + the double-interpretation penalty lets us interpret python programs + rather slowly. + +- the *translation process* which aims at producing a different (low-level) + representation of our standard interpreter. The *translation process* + is done in three steps: + + - producing a *flow graph* representation of the standard interpreter. + A combination of a *plain interpreter* and a *flow object space* + performs "abstract interpretation" to record the flow of objects + and execution throughout a python program into such a *flow graph*. + + - the *annotator* which performs type inference on the flow graph + + - the *translator* which translates the (annotated) flow graph into + another language, currently Pyrex/C and LISP. + +Please note that we are using the term *interpreter* most often in +reference to the *plain interpreter* which just knows enough to read, +dispatch and implement *bytecodes* thus shuffling objects around on the +stack and between namespaces. The (plain) interpreter is completly +ignorant of how to access, modify or construct objects and their +structure and thus delegates such operations to a so called "Object Space". + +XXX mention Parser and compiler (we have one available since the Berlin +sprint but it is not integrated) The Interpreter =============== From jum at codespeak.net Mon Dec 29 21:56:33 2003 From: jum at codespeak.net (jum at codespeak.net) Date: Mon, 29 Dec 2003 21:56:33 +0100 (MET) Subject: [pypy-svn] rev 2701 - pypy/trunk/doc/devel Message-ID: <20031229205633.796125B261@thoth.codespeak.net> Author: jum Date: Mon Dec 29 21:56:32 2003 New Revision: 2701 Modified: pypy/trunk/doc/devel/howtosvn.txt Log: Made the reference to TortoiseSVN generic, removed unused link. Modified: pypy/trunk/doc/devel/howtosvn.txt ============================================================================== --- pypy/trunk/doc/devel/howtosvn.txt (original) +++ pypy/trunk/doc/devel/howtosvn.txt Mon Dec 29 21:56:32 2003 @@ -19,6 +19,7 @@ * See Microsoft website_ if you have .DLL issues. * Windows Installer file for Tortoise SVN (like Tortoise CVS) GUI_ + (Pick the UNICODE version for Windows 2000 and XP) (See Win_ 2000, NT if you have problems loading it.) @@ -121,10 +122,8 @@ -------------------------------------------------------------------------------- -.. _commandline: http://subversion.tigris.org/files/documents/15/7442/svn-0.34.0-setup.exe .. _website: http://support.microsoft.com/default.aspx?scid=kb%3Ben-us%3B259403 -.. _GUI: http://tortoisesvn.tigris.org/files/documents/406/7481/TortoiseSVN-0.21-UNICODE.msi -.. _Win: http://www.microsoft.com/downloads/details.aspx?displaylang=en&FamilyID=4B6140F9-2D36-4977-8FA1-6F8A0F5DCA8F +.. _GUI: http://tortoisesvn.tigris.org/servlets/ProjectDocumentList?folderID=616 .. _MacOS: http://codespeak.net/~jum/svn-0.32.1-darwin-ppc.tar.gz .. _iconv: http://codespeak.net/~jum/iconv-darwin-ppc.tar.gz .. _versions: http://subversion.tigris.org/project_packages.html From hpk at codespeak.net Mon Dec 29 23:51:34 2003 From: hpk at codespeak.net (hpk at codespeak.net) Date: Mon, 29 Dec 2003 23:51:34 +0100 (MET) Subject: [pypy-svn] r2704 - pypy/trunk/doc/devel Message-ID: <20031229225134.8DC0F5A5AE@thoth.codespeak.net> Author: hpk Date: Mon Dec 29 23:51:33 2003 New Revision: 2704 Modified: pypy/trunk/doc/devel/howtosvn.txt Log: fixed some markup (hopefully correctly) Modified: pypy/trunk/doc/devel/howtosvn.txt ============================================================================== --- pypy/trunk/doc/devel/howtosvn.txt (original) +++ pypy/trunk/doc/devel/howtosvn.txt Mon Dec 29 23:51:33 2003 @@ -19,9 +19,8 @@ * See Microsoft website_ if you have .DLL issues. * Windows Installer file for Tortoise SVN (like Tortoise CVS) GUI_ - (Pick the UNICODE version for Windows 2000 and XP) - - (See Win_ 2000, NT if you have problems loading it.) + (Pick the UNICODE version for Windows 2000 and XP and + see Win_ 2000, NT if you have problems loading it.) + Local copy of MacOS_ X binary tar ball @@ -127,6 +126,7 @@ .. _MacOS: http://codespeak.net/~jum/svn-0.32.1-darwin-ppc.tar.gz .. _iconv: http://codespeak.net/~jum/iconv-darwin-ppc.tar.gz .. _versions: http://subversion.tigris.org/project_packages.html +.. _Win: http://www.microsoft.com/downloads/details.aspx?displaylang=en&FamilyID=4B6140F9-2D36-4977-8FA1-6F8A0F5DCA8F .. _guide: http://svnbook.red-bean.com/book.html#svn-ch-1 .. _archives: http://codespeak.net/pipermail/pypy-svn/ From jum at codespeak.net Tue Dec 30 00:00:29 2003 From: jum at codespeak.net (jum at codespeak.net) Date: Tue, 30 Dec 2003 00:00:29 +0100 (MET) Subject: [pypy-svn] r2705 - pypy/trunk/doc/devel Message-ID: <20031229230029.CC9335A5AE@thoth.codespeak.net> Author: jum Date: Tue Dec 30 00:00:28 2003 New Revision: 2705 Modified: pypy/trunk/doc/devel/howtosvn.txt Log: Updates OS X build to latest version, removed iconv reference as Panther now has its own iconv lib. Modified: pypy/trunk/doc/devel/howtosvn.txt ============================================================================== --- pypy/trunk/doc/devel/howtosvn.txt (original) +++ pypy/trunk/doc/devel/howtosvn.txt Tue Dec 30 00:00:28 2003 @@ -24,7 +24,7 @@ + Local copy of MacOS_ X binary tar ball - * this will also need iconv_ MacOS X tar ball +(This requires at least OS X 10.3) + Debian instructions below... @@ -123,8 +123,7 @@ .. _website: http://support.microsoft.com/default.aspx?scid=kb%3Ben-us%3B259403 .. _GUI: http://tortoisesvn.tigris.org/servlets/ProjectDocumentList?folderID=616 -.. _MacOS: http://codespeak.net/~jum/svn-0.32.1-darwin-ppc.tar.gz -.. _iconv: http://codespeak.net/~jum/iconv-darwin-ppc.tar.gz +.. _MacOS: http://codespeak.net/~jum/svn-0.35.1-darwin-ppc.tar.gz .. _versions: http://subversion.tigris.org/project_packages.html .. _Win: http://www.microsoft.com/downloads/details.aspx?displaylang=en&FamilyID=4B6140F9-2D36-4977-8FA1-6F8A0F5DCA8F From jum at codespeak.net Tue Dec 30 00:03:25 2003 From: jum at codespeak.net (jum at codespeak.net) Date: Tue, 30 Dec 2003 00:03:25 +0100 (MET) Subject: [pypy-svn] r2706 - pypy/trunk/doc/devel Message-ID: <20031229230325.C2FB35A5AE@thoth.codespeak.net> Author: jum Date: Tue Dec 30 00:03:24 2003 New Revision: 2706 Modified: pypy/trunk/doc/devel/howtosvn.txt Log: Fix formatting. Modified: pypy/trunk/doc/devel/howtosvn.txt ============================================================================== --- pypy/trunk/doc/devel/howtosvn.txt (original) +++ pypy/trunk/doc/devel/howtosvn.txt Tue Dec 30 00:03:24 2003 @@ -23,8 +23,7 @@ see Win_ 2000, NT if you have problems loading it.) + Local copy of MacOS_ X binary tar ball - -(This requires at least OS X 10.3) + (This requires at least OS X 10.3) + Debian instructions below... From sanxiyn at codespeak.net Wed Dec 31 21:51:10 2003 From: sanxiyn at codespeak.net (sanxiyn at codespeak.net) Date: Wed, 31 Dec 2003 21:51:10 +0100 (MET) Subject: [pypy-svn] r2707 - pypy/trunk/src/pypy/appspace Message-ID: <20031231205110.DBC945AC54@thoth.codespeak.net> Author: sanxiyn Date: Wed Dec 31 21:51:08 2003 New Revision: 2707 Modified: pypy/trunk/src/pypy/appspace/complexobject.py Log: Uses types.StringTypes. We don't have unicode, yet. Modified: pypy/trunk/src/pypy/appspace/complexobject.py ============================================================================== --- pypy/trunk/src/pypy/appspace/complexobject.py (original) +++ pypy/trunk/src/pypy/appspace/complexobject.py Wed Dec 31 21:51:08 2003 @@ -23,7 +23,7 @@ msg = "complex() second arg can't be a string" raise TypeError, msg - if type(real) in (types.StringType, types.UnicodeType): + if type(real) in types.StringTypes: real, imag = self._makeComplexFromString(real) self.__dict__['real'] = real self.__dict__['imag'] = imag From sschwarzer at codespeak.net Wed Dec 31 21:53:28 2003 From: sschwarzer at codespeak.net (sschwarzer at codespeak.net) Date: Wed, 31 Dec 2003 21:53:28 +0100 (MET) Subject: [pypy-svn] r2708 - in pypy/trunk/src/pypy/tool: . test testdata Message-ID: <20031231205328.6F5975AC54@thoth.codespeak.net> Author: sschwarzer Date: Wed Dec 31 21:53:27 2003 New Revision: 2708 Added: pypy/trunk/src/pypy/tool/test/__init__.py pypy/trunk/src/pypy/tool/test/autopath.py pypy/trunk/src/pypy/tool/test/test_newtest.py pypy/trunk/src/pypy/tool/testdata/autopath.py Modified: pypy/trunk/src/pypy/tool/newtest.py pypy/trunk/src/pypy/tool/testdata/test_dummy.py Log: Making TestItem instances now is much easier; class and module are determined automatically. Reworked building of TestSuite instances (i. e. the test items within). Added some unit tests, more are still needed, however. Modified: pypy/trunk/src/pypy/tool/newtest.py ============================================================================== --- pypy/trunk/src/pypy/tool/newtest.py (original) +++ pypy/trunk/src/pypy/tool/newtest.py Wed Dec 31 21:53:27 2003 @@ -3,31 +3,31 @@ The following picture is an UML class diagram of the framework. -+------------+ 1 1 +----------+ -| TestResult |----------------------------------------| TestItem | -| (abstract) | +----------+ -+------------+ | * - A | - - | - | | 1 - +----------------------------+-----------+ +-----------+ - | | | | TestSuite | -+-------------------------+ +---------+ +---------+ +-----------+ -| TestResultWithTraceback | | Success | | Skipped | A -| (abstract) | +---------+ +---------+ | -+-------------------------+ | loaded by - A A | - - - | * - | | +------------+ - | | | TestCase | -+-------+ +---------+ | (abstract) | -| Error | | Failure | +------------+ -+-------+ +---------+ A - - - | - | - concrete test - case classes + +----------+ 1 1 +------------+ + | TestItem |------------------------| TestResult | + +----------+ | (abstract) | + | * +------------+ + | A + | - + | 1 | + +-----------+ +-----------+--------+----------+ + | TestSuite | | | | + +-----------+ +---------+ +---------+ +-------------------------+ + A | Success | | Skipped | | TestResultWithTraceback | + | +---------+ +---------+ | (abstract) | + | loaded by +-------------------------+ + | A A + | * - - + +------------+ | | + | TestCase | | | + | (abstract) | +-------+ +---------+ + +------------+ | Error | | Failure | + A +-------+ +---------+ + - + | + | + concrete test + case classes Like the unittest framework of Python, our framework implements tests as test methods in TestCase classes. Custom test case classes @@ -64,11 +64,14 @@ from __future__ import generators import autopath + +import cStringIO as StringIO import inspect +import new import os import sys -import cStringIO as StringIO import traceback +import types import vpath #TODO @@ -267,36 +270,74 @@ # # other classes # +_dummy_module = new.module('') + class TestItem: """ Represent either a test function, or a single test method from a TestCase class. """ - def __init__(self, module, callable=None, cls=None): + def __init__(self, callable_=None): """ - Construct a test item. The argument callable must be either a - plain function or an unbound method of a class. In the latter - case, the argument cls must receive the test case class. - """ - # do we have a plain function, or a class and a method? - self.isfunction = (cls is None) - self.file = inspect.getsourcefile(module) - self.module = module - self.callable = callable - self.cls = cls - # remove trailing whitespace but leave things such indentation - # of first line(s) alone - self.docs = (self._docstring(module), self._docstring(cls), - self._docstring(callable)) + Construct a test item. The argument callable_ must be a + callable object, i. e. a plain function, a bound or unbound + method of a class, or an object with __call__ attribute. + """ + assert callable(callable_), \ + "must get a callable item, but got '%s'" % callable_ + self.callable = callable_ + # determine additional attributes (e. g. for error reporting) + self.call_via_class = False + # - class + if hasattr(callable_, 'im_class'): + # unbound and bound methods; __class__ would be instancemethod, + # not the one containing the methods + self.cls = callable_.im_class + if callable_.im_self is None: + # unbound methods are not directly callable without + # arguments + self.call_via_class = True + elif hasattr(callable_, '__class__') and \ + not inspect.isfunction(callable_): + # class instances with __call__ attribute + self.cls = callable_.__class__ + else: + self.cls = None + # - module (sometimes, using the class works better than the callable) + self.module = inspect.getmodule(self.cls or callable_) + # - name + try: + self.name = callable_.__name__ + except AttributeError: + self.name = '' + # - file + try: + if self.module is None: + self.file = inspect.getsourcefile(self.cls or callable_) + else: + self.file = inspect.getsourcefile(self.module) + except IOError: + self.file = '' + except TypeError: + self.file = '' + # - docstrings + self.docs = (self._docstring(self.module), self._docstring(self.cls), + self._docstring(self.callable)) + # - source code properties #XXX inspect.getsourcelines may fail if the file path stored # in a module's pyc/pyo file doesn't match the py file's # actual location. This can happen if a py file, together with # its pyc/pyo file is moved to a new location. See Python # bug "[570300] inspect.getmodule symlink-related failure": # http://sourceforge.net/tracker/index.php?func=detail&aid=570300&group_id=5470&atid=105470 - lines, self.lineno = inspect.getsourcelines(callable) - # removing trailing newline(s) but not the indentation - self.source = ''.join(lines).rstrip() + try: + lines, self.lineno = inspect.getsourcelines(callable) + # removing trailing newline(s) but not the indentation + self.source = ''.join(lines).rstrip() + except IOError: + self.source, self.lineno = '', None + except TypeError: + self.source, self.lineno = '', None def _docstring(self, obj): """ @@ -346,17 +387,17 @@ the test callable, the test_runner object will be called with the test function/method as its argument. """ - if self.isfunction: - # use the test function directly - test = self.callable - else: + if self.call_via_class: # turn the test callable, an unbound method, into a bound method cls_object = self.cls() test = getattr(cls_object, self.callable.__name__) + else: + # use the test function directly + test = self.callable try: # call setUp only for a class - self.isfunction or cls_object.setUp() + self.call_via_class and cls_object.setUp() except KeyboardInterrupt: raise except TestResult, result: @@ -378,23 +419,22 @@ try: # call tearDown only for a class - self.isfunction or cls_object.tearDown() + self.call_via_class and cls_object.tearDown() except KeyboardInterrupt: raise except Exception, exc: # if we already had an exception in the test method, - # don't overwrite it + # don't overwrite/mask it if result.traceback is None: result = Error(msg=str(exc), item=self) return result def __str__(self): - if self.isfunction: - return "TestItem from %s.%s" % (self.module.__name__, - self.callable.__name__) + if self.cls is None: + return "TestItem from %s.%s" % (self.module.__name__, self.name) else: return "TestItem from %s.%s.%s" % (self.module.__name__, - self.cls.__name__, self.callable.__name__) + self.cls.__name__, self.name) def __repr__(self): return "<%s at %#x>" % (str(self), id(self)) @@ -414,44 +454,8 @@ self.last_results = {} # - # get lists of TestItems from a dictionary, a module, or a directory tree + # get lists of TestItems from a class, a module, or a directory tree # - def items_from_dict(self, dict_, module=None): - """ - Return a list of TestItems as extracted from the given dictionary - dict_. The keys of the dictionary are names of objects, the values - are the corresponding objects. Think of the value returned by the - builtin function globals. - - You may pass in a module object via the optional argument module. - If the argument is present, it will be included in the TestItems. - Else, the __main__ module will be used. - """ - if module is None: - module = __import__('__main__') - items = [] - # scan the values for test functions, and for classes derived - # from TestCase - for obj in dict_.values(): - # find TestCase classes and methods within them - if inspect.isclass(obj) and issubclass(obj, TestCase): - # we found a TestCase class, now scan it for test methods - for obj2 in vars(obj).values(): - # inspect.ismethod doesn't seem to work here - if inspect.isfunction(obj2) and \ - obj2.__name__.startswith("test"): - items.append(TestItem(module=module, cls=obj, - callable=obj2)) - # find test functions - elif (callable(obj) and hasattr(obj, '__name__') and - obj.__name__.startswith('test_')): - items.append(TestItem(module, callable=obj)) - return items - - def items_from_module(self, module): - """Return a list of TestItems read from the given module.""" - return self.items_from_dict(vars(module), module=module) - def _module_from_modpath(self, modpath): """ Return a module object derived from the module path @@ -466,7 +470,45 @@ __import__(modpath) return sys.modules[modpath] - def items_from_dir(self, dirname, filterfunc=None, recursive=True): + def _add_items(self, items): + """Add TestItems from list 'items' to TestSuite.""" + self.items.extend(items) + + def _items_from_class(self, cls): + """ + Return TestItems extracted from class cls. + + This includes all unbound methods whose names start with + "test_". + """ + items = [] + for attrname in cls.__dict__: + # don't use cls.__dict__[attrname]; for unbound methods, + # we would get function objects, i. e. + # cls.__dict__[attrname] != getattr(cls, attrname) + attr = getattr(cls, attrname) + if callable(attr) and attrname.startswith("test_"): + items.append(TestItem(attr)) + return items + + def _items_from_module(self, module): + """ + Return TestItems extracted from module. + + This includes all TestItems of classes derived from + TestCase and functions whose names start with "test_". + """ + items = [] + for attrname in module.__dict__: + # see comment in _items_from_class + attr = getattr(module, attrname) + if inspect.isclass(attr) and issubclass(attr, TestCase): + items.extend(self._items_from_class(attr)) + elif inspect.isfunction(attr) and attrname.startswith("test_"): + items.append(TestItem(attr)) + return items + + def _items_from_dir(self, dirname, filterfunc=None, recursive=True): """ Return a list of TestItems found by reading the directory denoted by dirname. Find all test modules in it. Test modules are files that @@ -493,30 +535,43 @@ if (filterfunc is None) or filterfunc(modpath): try: module = self._module_from_modpath(modpath) - module_items = self.items_from_module(module) + module_items = self._items_from_module(module) except: print >> sys.stderr, \ "Warning: can't load module %s" % modpath - raise + #raise else: items.extend(module_items) return items - # - # init TestSuite instance from a dictionary, a module, or a directory tree - # - def init_from_dict(self, dict_, module=None): - self.reset() - self.items = self.items_from_dict(dict_, module=module) - - def init_from_module(self, module): - self.reset() - self.items = self.items_from_module(module) + def add(self, *args): + """ + Extract TestItems from the given args and add them to this + TestSuite. - def init_from_dir(self, dirname, filterfunc=None, recursive=True): - self.reset() - self.items = self.items_from_dir(dirname, filterfunc=None, - recursive=True) + The given objects can be: + - callable (function, unbound or bound method, class instance + with __call__ attribute): convert to TestItem + - class: extract all test methods, i. e. whose names start + with "test_" + - module: extract all test classes, i. e. classes derived + from newtest.TestCase, and all functions whose names + start with "test_" + - string: interpret the string as a file system path and + search it for Python files located in (sub)directories + named "test" and matching the shell pattern "test_*.py" + """ + for arg in args: + if isinstance(arg, (types.ClassType, types.TypeType)): + self._add_items(self._items_from_class(arg)) + elif callable(arg): + self._add_items([arg]) + elif isinstance(arg, types.ModuleType): + self._add_items(self._items_from_module(arg)) + elif isinstance(arg, (str, unicode)): + self._add_items(self._items_from_dir(arg)) + else: + raise TypeError("unsupported TestItem source '%s'" % arg) # # running tests and getting results @@ -560,7 +615,7 @@ print 79 * '-' # print a line with the qualified name of the bad callable item = result.item - if result.item.isfunction: + if result.item.cls is None: print "%s.%s: %s" % (item.module.__name__, item.callable.__name__, result.name.upper()) else: @@ -589,17 +644,17 @@ import __main__ from pypy.tool import newtest suite = TestSuite() - suite.init_from_dict(vars(__main__)) + suite.add(__main__) _print_results(suite) def test(do_selftest=False): # possibly ignore dummy unit tests if do_selftest: # include only selftest module - filterfunc = lambda m: m.find("pypy.tool.testitdata.") != -1 + filterfunc = lambda m: m.find("pypy.tool.testdata.") != -1 else: # exclude selftest module - filterfunc = lambda m: m.find("pypy.tool.testitdata.") == -1 + filterfunc = lambda m: m.find("pypy.tool.testdata.") == -1 # collect tests suite = TestSuite() print "Loading test modules ..." Added: pypy/trunk/src/pypy/tool/test/__init__.py ============================================================================== Added: pypy/trunk/src/pypy/tool/test/autopath.py ============================================================================== --- (empty file) +++ pypy/trunk/src/pypy/tool/test/autopath.py Wed Dec 31 21:53:27 2003 @@ -0,0 +1,78 @@ +""" +self cloning, automatic path configuration + +copy this into any subdirectory of pypy from which scripts need +to be run, typically all of the test subdirs. +The idea is that any such script simply issues + + import autopath + +and this will make sure that the parent directory containing "pypy" +is in sys.path. + +If you modify the master "autopath.py" version (in pypy/tool/autopath.py) +you can directly run it which will copy itself on all autopath.py files +it finds under the pypy root directory. + +This module always provides these attributes: + + pypydir pypy root directory path + this_dir directory where this autopath.py resides + +""" + + +def __dirinfo(part): + """ return (partdir, this_dir) and insert parent of partdir + into sys.path. If the parent directories dont have the part + an EnvironmentError is raised.""" + + import sys, os + try: + head = this_dir = os.path.abspath(os.path.dirname(__file__)) + except NameError: + head = this_dir = os.path.abspath(os.path.dirname(sys.argv[0])) + + while head: + partdir = head + head, tail = os.path.split(head) + if tail == part: + sys.path = [p for p in sys.path if not p.startswith(head)] + if head not in sys.path: + sys.path.insert(0, head) + return partdir, this_dir + + raise EnvironmentError, "'%s' missing in '%r'" % (pathpart,this_path) + +def __clone(): + """ clone master version of autopath.py into all subdirs """ + from os.path import join, walk + if not this_dir.endswith(join('pypy','tool')): + raise EnvironmentError("can only clone master version " + "'%s'" % join(pypydir, 'tool',_myname)) + + + def sync_walker(arg, dirname, fnames): + if _myname in fnames: + fn = join(dirname, _myname) + f = open(fn, 'rwb+') + try: + if f.read() == arg: + print "checkok", fn + else: + print "syncing", fn + f = open(fn, 'w') + f.write(arg) + finally: + f.close() + s = open(join(pypydir, 'tool', _myname), 'rb').read() + walk(pypydir, sync_walker, s) + +_myname = 'autopath.py' + +# set guaranteed attributes + +pypydir, this_dir = __dirinfo('pypy') + +if __name__ == '__main__': + __clone() Added: pypy/trunk/src/pypy/tool/test/test_newtest.py ============================================================================== --- (empty file) +++ pypy/trunk/src/pypy/tool/test/test_newtest.py Wed Dec 31 21:53:27 2003 @@ -0,0 +1,81 @@ +import inspect +import unittest + +import autopath +from pypy.tool import newtest + + +class TestTestItem(unittest.TestCase): + def _test_function(self, func, expected_name): + item = newtest.TestItem(func) + self.assertEqual(item.name, expected_name) + self.assertEqual(item.call_via_class, False) + self.assertEqual(item.cls, None) + self.failUnless(item.module is module) + self.assertEqual(item.file, file) + + def test_plain_function(self): + f = lambda: 'anything' + self._test_function(f, expected_name='') + def f(): pass + self._test_function(f, expected_name='f') + + def test_bound_method(self): + class X: + def f(self): pass + x = X() + item = newtest.TestItem(x.f) + self.assertEqual(item.name, 'f') + self.assertEqual(item.call_via_class, False) + self.failUnless(item.cls is X) + self.failUnless(item.module is module) + self.assertEqual(item.file, file) + + def test_unbound_method(self): + class X: + def f(self): pass + item = newtest.TestItem(X.f) + self.assertEqual(item.name, 'f') + self.assertEqual(item.call_via_class, True) + self.failUnless(item.cls is X) + self.failUnless(item.module is module) + self.assertEqual(item.file, file) + + def test_class_instance(self): + class X: + def __call__(self): pass + item = newtest.TestItem(X()) + self.assertEqual(item.name, '') + self.assertEqual(item.call_via_class, False) + self.failUnless(item.cls is X) + self.failUnless(item.module is module) + self.assertEqual(item.file, file) + + #XXX best way to trigger execptions in TestItem's constructor + # without getting rather complicated? + + def test_docstrings(self): + class X: + def f(self): + "Method docstring" + item = newtest.TestItem(X.f) + self.assertEqual(item.docs, ('', '', "Method docstring")) + + class X: + "Class docstring" + def f(self): pass + item = newtest.TestItem(X.f) + self.assertEqual(item.docs, ('', "Class docstring", '')) + + def test_items_from_class(self): + ts = newtest.TestSuite() + ts._items_from_class(TestTestItem) + + +# used in unit tests above; placed here, so that TestTestItem is accessible +module = inspect.getmodule(TestTestItem) +file = inspect.getsourcefile(TestTestItem) + + +if __name__ == '__main__': + unittest.main() Added: pypy/trunk/src/pypy/tool/testdata/autopath.py ============================================================================== --- (empty file) +++ pypy/trunk/src/pypy/tool/testdata/autopath.py Wed Dec 31 21:53:27 2003 @@ -0,0 +1,78 @@ +""" +self cloning, automatic path configuration + +copy this into any subdirectory of pypy from which scripts need +to be run, typically all of the test subdirs. +The idea is that any such script simply issues + + import autopath + +and this will make sure that the parent directory containing "pypy" +is in sys.path. + +If you modify the master "autopath.py" version (in pypy/tool/autopath.py) +you can directly run it which will copy itself on all autopath.py files +it finds under the pypy root directory. + +This module always provides these attributes: + + pypydir pypy root directory path + this_dir directory where this autopath.py resides + +""" + + +def __dirinfo(part): + """ return (partdir, this_dir) and insert parent of partdir + into sys.path. If the parent directories dont have the part + an EnvironmentError is raised.""" + + import sys, os + try: + head = this_dir = os.path.abspath(os.path.dirname(__file__)) + except NameError: + head = this_dir = os.path.abspath(os.path.dirname(sys.argv[0])) + + while head: + partdir = head + head, tail = os.path.split(head) + if tail == part: + sys.path = [p for p in sys.path if not p.startswith(head)] + if head not in sys.path: + sys.path.insert(0, head) + return partdir, this_dir + + raise EnvironmentError, "'%s' missing in '%r'" % (pathpart,this_path) + +def __clone(): + """ clone master version of autopath.py into all subdirs """ + from os.path import join, walk + if not this_dir.endswith(join('pypy','tool')): + raise EnvironmentError("can only clone master version " + "'%s'" % join(pypydir, 'tool',_myname)) + + + def sync_walker(arg, dirname, fnames): + if _myname in fnames: + fn = join(dirname, _myname) + f = open(fn, 'rwb+') + try: + if f.read() == arg: + print "checkok", fn + else: + print "syncing", fn + f = open(fn, 'w') + f.write(arg) + finally: + f.close() + s = open(join(pypydir, 'tool', _myname), 'rb').read() + walk(pypydir, sync_walker, s) + +_myname = 'autopath.py' + +# set guaranteed attributes + +pypydir, this_dir = __dirinfo('pypy') + +if __name__ == '__main__': + __clone() Modified: pypy/trunk/src/pypy/tool/testdata/test_dummy.py ============================================================================== --- pypy/trunk/src/pypy/tool/testdata/test_dummy.py (original) +++ pypy/trunk/src/pypy/tool/testdata/test_dummy.py Wed Dec 31 21:53:27 2003 @@ -1,6 +1,6 @@ """Module docstring.""" -#import autopath +import autopath from pypy.tool import newtest @@ -11,7 +11,7 @@ newtest.service.skip() -class TestDummy1(newtestit.TestCase): +class TestDummy1(newtest.TestCase): """ Example of a docstring for a class. """ @@ -25,7 +25,7 @@ raise self.fail("fail deliberately in test_failure1") -class TestDummy2(newtestit.TestCase): +class TestDummy2(newtest.TestCase): def test_success2(self): self.assertEquals(1+1, 2) @@ -37,7 +37,7 @@ raise self.fail("fail deliberately in test_failure2") -class TestSkip1(newtestit.TestCase): +class TestSkip1(newtest.TestCase): def setUp(self): self.skip() @@ -45,7 +45,7 @@ pass -class TestSkip2(newtestit.TestCase): +class TestSkip2(newtest.TestCase): def test_skip2(self): self.skip() @@ -61,4 +61,4 @@ if __name__ == '__main__': - newtestit.main() + newtest.main() From sschwarzer at codespeak.net Wed Dec 31 21:55:06 2003 From: sschwarzer at codespeak.net (sschwarzer at codespeak.net) Date: Wed, 31 Dec 2003 21:55:06 +0100 (MET) Subject: [pypy-svn] r2709 - in pypy/trunk/src/pypy/tool: test testdata Message-ID: <20031231205506.507575AC54@thoth.codespeak.net> Author: sschwarzer Date: Wed Dec 31 21:55:05 2003 New Revision: 2709 Modified: pypy/trunk/src/pypy/tool/test/ (props changed) pypy/trunk/src/pypy/tool/test/__init__.py (props changed) pypy/trunk/src/pypy/tool/test/autopath.py (props changed) pypy/trunk/src/pypy/tool/test/test_newtest.py (props changed) pypy/trunk/src/pypy/tool/testdata/autopath.py (props changed) Log: Ran fixeol. From sschwarzer at codespeak.net Wed Dec 31 21:55:39 2003 From: sschwarzer at codespeak.net (sschwarzer at codespeak.net) Date: Wed, 31 Dec 2003 21:55:39 +0100 (MET) Subject: [pypy-svn] r2710 - pypy/trunk/src/pypy/tool Message-ID: <20031231205539.5F1305B0EF@thoth.codespeak.net> Author: sschwarzer Date: Wed Dec 31 21:55:38 2003 New Revision: 2710 Modified: pypy/trunk/src/pypy/tool/newtest.py Log: Removed the dummy module, it's no longer needed. Modified: pypy/trunk/src/pypy/tool/newtest.py ============================================================================== --- pypy/trunk/src/pypy/tool/newtest.py (original) +++ pypy/trunk/src/pypy/tool/newtest.py Wed Dec 31 21:55:38 2003 @@ -67,7 +67,6 @@ import cStringIO as StringIO import inspect -import new import os import sys import traceback @@ -270,8 +269,6 @@ # # other classes # -_dummy_module = new.module('') - class TestItem: """ Represent either a test function, or a single test method from a From sschwarzer at codespeak.net Wed Dec 31 21:59:46 2003 From: sschwarzer at codespeak.net (sschwarzer at codespeak.net) Date: Wed, 31 Dec 2003 21:59:46 +0100 (MET) Subject: [pypy-svn] r2711 - pypy/trunk/src/pypy/tool Message-ID: <20031231205946.6DC0B5AC54@thoth.codespeak.net> Author: sschwarzer Date: Wed Dec 31 21:59:45 2003 New Revision: 2711 Modified: pypy/trunk/src/pypy/tool/newtest.py Log: TestItem's callable_ argument is no longer optional. That was a workaround in a previous implementation. Modified: pypy/trunk/src/pypy/tool/newtest.py ============================================================================== --- pypy/trunk/src/pypy/tool/newtest.py (original) +++ pypy/trunk/src/pypy/tool/newtest.py Wed Dec 31 21:59:45 2003 @@ -274,7 +274,7 @@ Represent either a test function, or a single test method from a TestCase class. """ - def __init__(self, callable_=None): + def __init__(self, callable_): """ Construct a test item. The argument callable_ must be a callable object, i. e. a plain function, a bound or unbound From sschwarzer at codespeak.net Wed Dec 31 22:18:17 2003 From: sschwarzer at codespeak.net (sschwarzer at codespeak.net) Date: Wed, 31 Dec 2003 22:18:17 +0100 (MET) Subject: [pypy-svn] r2712 - in pypy/trunk/src/pypy/tool: . test Message-ID: <20031231211817.E42DD5AC54@thoth.codespeak.net> Author: sschwarzer Date: Wed Dec 31 22:18:17 2003 New Revision: 2712 Modified: pypy/trunk/src/pypy/tool/newtest.py pypy/trunk/src/pypy/tool/test/test_newtest.py Log: Bugfix in TestSuite.add. Added some unit tests for TestSuite. Modified: pypy/trunk/src/pypy/tool/newtest.py ============================================================================== --- pypy/trunk/src/pypy/tool/newtest.py (original) +++ pypy/trunk/src/pypy/tool/newtest.py Wed Dec 31 22:18:17 2003 @@ -274,11 +274,17 @@ Represent either a test function, or a single test method from a TestCase class. """ - def __init__(self, callable_): + def __init__(self, callable_, name=None): """ - Construct a test item. The argument callable_ must be a - callable object, i. e. a plain function, a bound or unbound - method of a class, or an object with __call__ attribute. + Construct a test item. + + The argument callable_ must be a callable object, i. e. a + plain function, a bound or unbound method of a class, or an + object with __call__ attribute. + + The optional argument name can be a string which will be used + as the object's name. Else, the name will be tried to be + determined from the object's __name__ attribute. """ assert callable(callable_), \ "must get a callable item, but got '%s'" % callable_ @@ -304,7 +310,7 @@ self.module = inspect.getmodule(self.cls or callable_) # - name try: - self.name = callable_.__name__ + self.name = name or callable_.__name__ except AttributeError: self.name = '' # - file @@ -485,7 +491,7 @@ # cls.__dict__[attrname] != getattr(cls, attrname) attr = getattr(cls, attrname) if callable(attr) and attrname.startswith("test_"): - items.append(TestItem(attr)) + items.append(TestItem(attr, attrname)) return items def _items_from_module(self, module): @@ -502,7 +508,7 @@ if inspect.isclass(attr) and issubclass(attr, TestCase): items.extend(self._items_from_class(attr)) elif inspect.isfunction(attr) and attrname.startswith("test_"): - items.append(TestItem(attr)) + items.append(TestItem(attr, attrname)) return items def _items_from_dir(self, dirname, filterfunc=None, recursive=True): @@ -562,7 +568,7 @@ if isinstance(arg, (types.ClassType, types.TypeType)): self._add_items(self._items_from_class(arg)) elif callable(arg): - self._add_items([arg]) + self._add_items([TestItem(arg)]) elif isinstance(arg, types.ModuleType): self._add_items(self._items_from_module(arg)) elif isinstance(arg, (str, unicode)): Modified: pypy/trunk/src/pypy/tool/test/test_newtest.py ============================================================================== --- pypy/trunk/src/pypy/tool/test/test_newtest.py (original) +++ pypy/trunk/src/pypy/tool/test/test_newtest.py Wed Dec 31 22:18:17 2003 @@ -67,9 +67,38 @@ item = newtest.TestItem(X.f) self.assertEqual(item.docs, ('', "Class docstring", '')) + def test_name_argument(self): + def f(): pass + item = newtest.TestItem(f, 'g') + self.assertEqual(item.name, 'g') + + +class TestTestSuite(unittest.TestCase): + def check_names(self, test_suite, expected_item_names): + item_names = [item.name for item in test_suite.items] + item_names.sort() + expected_item_names.sort() + self.assertEqual(item_names, expected_item_names) + + def test_items_from_callables(self): + def f(): pass + g = lambda: None + class X: + def thisone(self): pass + ts = newtest.TestSuite() + ts.add(f, g, X.thisone) + self.check_names(ts, ['f', '', 'thisone']) + def test_items_from_class(self): + class X: + """Docstring - don't find it.""" + def test_this(self): pass + def no_test(self): pass + def test_that(self): pass ts = newtest.TestSuite() - ts._items_from_class(TestTestItem) + ts.add(X) + self.check_names(ts, ['test_this', 'test_that']) + # used in unit tests above; placed here, so that TestTestItem is accessible From sschwarzer at codespeak.net Wed Dec 31 22:31:54 2003 From: sschwarzer at codespeak.net (sschwarzer at codespeak.net) Date: Wed, 31 Dec 2003 22:31:54 +0100 (MET) Subject: [pypy-svn] r2713 - pypy/trunk/src/pypy/tool/test Message-ID: <20031231213154.89A8C5AC54@thoth.codespeak.net> Author: sschwarzer Date: Wed Dec 31 22:31:53 2003 New Revision: 2713 Modified: pypy/trunk/src/pypy/tool/test/test_newtest.py Log: Added more unit tests. Modified: pypy/trunk/src/pypy/tool/test/test_newtest.py ============================================================================== --- pypy/trunk/src/pypy/tool/test/test_newtest.py (original) +++ pypy/trunk/src/pypy/tool/test/test_newtest.py Wed Dec 31 22:31:53 2003 @@ -1,9 +1,12 @@ import inspect +import new import unittest import autopath from pypy.tool import newtest +#TODO test(s) for adding TestItems from directory + class TestTestItem(unittest.TestCase): def _test_function(self, func, expected_name): @@ -88,6 +91,14 @@ ts = newtest.TestSuite() ts.add(f, g, X.thisone) self.check_names(ts, ['f', '', 'thisone']) + # add a bound method and an instance with __call__ attribute + class Y: + def thatone(self): pass + class Z: + def __call__(self): pass + ts.add(Y().thatone, Z()) + self.check_names(ts, ['f', '', 'thisone', 'thatone', + '']) def test_items_from_class(self): class X: @@ -99,6 +110,20 @@ ts.add(X) self.check_names(ts, ['test_this', 'test_that']) + def test_items_from_module(self): + mod = new.module('new_module') + class X(newtest.TestCase): + "Don't add docstring." + def dont_add_method(self): pass + def test_this_method(self): pass + def dont_add(): pass + def add_this(): pass + for name, object in [('X', X), ('dont_add', dont_add), + ('test_other_name', add_this)]: + setattr(mod, name, object) + ts = newtest.TestSuite() + ts.add(mod) + self.check_names(ts, ['test_this_method', 'test_other_name']) # used in unit tests above; placed here, so that TestTestItem is accessible From sschwarzer at codespeak.net Wed Dec 31 22:42:16 2003 From: sschwarzer at codespeak.net (sschwarzer at codespeak.net) Date: Wed, 31 Dec 2003 22:42:16 +0100 (MET) Subject: [pypy-svn] r2714 - pypy/trunk/src/pypy/tool Message-ID: <20031231214216.F2AD55AC54@thoth.codespeak.net> Author: sschwarzer Date: Wed Dec 31 22:42:16 2003 New Revision: 2714 Modified: pypy/trunk/src/pypy/tool/newtest.py Log: Added full name to TestItem and use this in __str__ and in printing the "bad" test results in _print_results. Modified: pypy/trunk/src/pypy/tool/newtest.py ============================================================================== --- pypy/trunk/src/pypy/tool/newtest.py (original) +++ pypy/trunk/src/pypy/tool/newtest.py Wed Dec 31 22:42:16 2003 @@ -313,6 +313,15 @@ self.name = name or callable_.__name__ except AttributeError: self.name = '' + # - full name (including module and class, if applicable) + try: + parts = [self.module.__name__] + except AttributeError: + parts = [] + if self.cls: + parts.append(self.cls.__name__) + parts.append(self.name) + self.full_name = '.'.join(parts) # - file try: if self.module is None: @@ -433,11 +442,7 @@ return result def __str__(self): - if self.cls is None: - return "TestItem from %s.%s" % (self.module.__name__, self.name) - else: - return "TestItem from %s.%s.%s" % (self.module.__name__, - self.cls.__name__, self.name) + return "TestItem from %s" % self.full_name def __repr__(self): return "<%s at %#x>" % (str(self), id(self)) @@ -618,12 +623,7 @@ print 79 * '-' # print a line with the qualified name of the bad callable item = result.item - if result.item.cls is None: - print "%s.%s: %s" % (item.module.__name__, item.callable.__name__, - result.name.upper()) - else: - print "%s.%s.%s: %s" % (item.module.__name__, item.cls.__name__, - item.callable.__name__, result.name.upper()) + print "%s: %s" % (item.full_name, result.name.upper()) print print result.formatted_traceback # emit a summary