From fijal at codespeak.net Sat Aug 4 16:24:38 2007 From: fijal at codespeak.net (fijal at codespeak.net) Date: Sat, 4 Aug 2007 16:24:38 +0200 (CEST) Subject: [py-svn] r45483 - py/trunk/py/code Message-ID: <20070804142438.F059F80E3@code0.codespeak.net> Author: fijal Date: Sat Aug 4 16:24:37 2007 New Revision: 45483 Modified: py/trunk/py/code/excinfo.py Log: Fix 2.5 issue when str(excinfo.type) produced different thing than expected Modified: py/trunk/py/code/excinfo.py ============================================================================== --- py/trunk/py/code/excinfo.py (original) +++ py/trunk/py/code/excinfo.py Sat Aug 4 16:24:37 2007 @@ -19,6 +19,9 @@ self._excinfo = tup self.type, self.value, tb = self._excinfo self.typename = str(self.type) + if issubclass(self.type, object): + # cpy 2.5 + self.typename = self.typename[7:-2] self.traceback = py.code.Traceback(tb) def exconly(self, tryshort=False): From fijal at codespeak.net Sat Aug 4 16:24:56 2007 From: fijal at codespeak.net (fijal at codespeak.net) Date: Sat, 4 Aug 2007 16:24:56 +0200 (CEST) Subject: [py-svn] r45484 - py/trunk/py/code Message-ID: <20070804142456.B615E80E4@code0.codespeak.net> Author: fijal Date: Sat Aug 4 16:24:56 2007 New Revision: 45484 Modified: py/trunk/py/code/traceback2.py Log: A comment why this will not work on different python version Modified: py/trunk/py/code/traceback2.py ============================================================================== --- py/trunk/py/code/traceback2.py (original) +++ py/trunk/py/code/traceback2.py Sat Aug 4 16:24:56 2007 @@ -1,5 +1,6 @@ from __future__ import generators -import py +import py +import sys class TracebackEntry(object): """ a single entry in a traceback """ @@ -9,6 +10,9 @@ def __init__(self, rawentry): self._rawentry = rawentry self.frame = py.code.Frame(rawentry.tb_frame) + # Ugh. 2.4 and 2.5 differs here when encountering + # multi-line statements. Not sure about the solution, but + # should be portable self.lineno = rawentry.tb_lineno - 1 self.relline = self.lineno - self.frame.code.firstlineno From fijal at codespeak.net Mon Aug 6 15:57:55 2007 From: fijal at codespeak.net (fijal at codespeak.net) Date: Mon, 6 Aug 2007 15:57:55 +0200 (CEST) Subject: [py-svn] r45518 - py/trunk/py/test/rsession Message-ID: <20070806135755.DB22380D0@code0.codespeak.net> Author: fijal Date: Mon Aug 6 15:57:55 2007 New Revision: 45518 Modified: py/trunk/py/test/rsession/reporter.py Log: Print out communicate atomically Modified: py/trunk/py/test/rsession/reporter.py ============================================================================== --- py/trunk/py/test/rsession/reporter.py (original) +++ py/trunk/py/test/rsession/reporter.py Mon Aug 6 15:57:55 2007 @@ -14,6 +14,7 @@ from py.__.test.representation import Presenter import sys +import thread class AbstractReporter(object): def __init__(self, config, hosts): @@ -27,23 +28,28 @@ self.skipped = dict([(host, 0) for host in hosts]) self.passed = dict([(host, 0) for host in hosts]) self.to_rsync = {} + self.lock = thread.allocate_lock() def get_item_name(self, event, colitem): return "/".join(colitem.listnames()) def report(self, what): - repfun = getattr(self, "report_" + what.__class__.__name__, - self.report_unknown) try: - return repfun(what) - except (KeyboardInterrupt, SystemExit): - raise - except: - print "Internal reporting problem" - excinfo = py.code.ExceptionInfo() - for i in excinfo.traceback: - print str(i)[2:-1] - print excinfo + self.lock.acquire() + repfun = getattr(self, "report_" + what.__class__.__name__, + self.report_unknown) + try: + return repfun(what) + except (KeyboardInterrupt, SystemExit): + raise + except: + print "Internal reporting problem" + excinfo = py.code.ExceptionInfo() + for i in excinfo.traceback: + print str(i)[2:-1] + print excinfo + finally: + self.lock.release() def report_unknown(self, what): if self.config.option.verbose: From fijal at codespeak.net Mon Aug 6 15:58:19 2007 From: fijal at codespeak.net (fijal at codespeak.net) Date: Mon, 6 Aug 2007 15:58:19 +0200 (CEST) Subject: [py-svn] r45519 - py/trunk/py/bin Message-ID: <20070806135819.6544180D0@code0.codespeak.net> Author: fijal Date: Mon Aug 6 15:58:18 2007 New Revision: 45519 Modified: py/trunk/py/bin/py.lookup Log: Ignore non-existing files Modified: py/trunk/py/bin/py.lookup ============================================================================== --- py/trunk/py/bin/py.lookup (original) +++ py/trunk/py/bin/py.lookup Mon Aug 6 15:58:18 2007 @@ -42,8 +42,11 @@ string = args[0] if options.ignorecase: string = string.lower() - for x in curdir.visit('*.py', rec): - s = x.read() + for x in curdir.visit('*.py', rec): + try: + s = x.read() + except py.error.ENOENT: + pass # whatever, probably broken link (ie emacs lock) searchs = s if options.ignorecase: searchs = s.lower() From fijal at codespeak.net Mon Aug 6 15:58:55 2007 From: fijal at codespeak.net (fijal at codespeak.net) Date: Mon, 6 Aug 2007 15:58:55 +0200 (CEST) Subject: [py-svn] r45520 - py/trunk/py/doc/future Message-ID: <20070806135855.C479480CD@code0.codespeak.net> Author: fijal Date: Mon Aug 6 15:58:54 2007 New Revision: 45520 Added: py/trunk/py/doc/future/planning2.txt (contents, props changed) Log: Add some rough ideas about pylib plannign Added: py/trunk/py/doc/future/planning2.txt ============================================================================== --- (empty file) +++ py/trunk/py/doc/future/planning2.txt Mon Aug 6 15:58:54 2007 @@ -0,0 +1,39 @@ +What I miss in py.test (personally): +==================================== + +* new skip method, so web interface would show skips which + are broken (say py.test.skip("stuff", reason=py.test.BORKEN)), + proposed by me and xoraxax + +* integration of session classes - needed for developement + +* more robust failure recovery from execnet - not sure how to perform + it, but select() approach sounds like a plan (instead of threads) + (unsure what than) + +* provide a bit more patchy approach to green stuff, ie you import it and + all (known) operations on sockets are performed via the green interface, + this should allow using arbitrary applications (well, not using C-level + I/O) to mix with green threads. + +* integrate green execnet a bit more (?) + +* once session integration is done, it would be cool to have nightly + testing done in a systematic manner (instead of bunch of hacks, which + is how it looks like right now), so for example codespeak would be able + to store information (ie via svn) and when I woke up I can type py.test show + and see the information of all nightly test runs which I like. + +* py.test.pdb - there is my hack for a while now, which integrates + rlcompleter2 with pdb. First of all it requires some strange changes + to rlcompleter itself, which has no tests. Long-term plan would be + to have pyrepl+rlcompleter2+pdb fixes integrated into pylib and + have it tested. This requires work though. + +* add a link to pylib in pypy/lib? Since pylib features mostly work on top + of pypy-c, it would be nice to have it (as we do have it in svn anyway) + +* fix generative tests. + - they should be distributed atomically (for various reasons) + - fix setup/teardown logic (ie setup_generator/teardown_generator) + - XXX there was sth else From fijal at codespeak.net Tue Aug 7 09:11:20 2007 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 7 Aug 2007 09:11:20 +0200 (CEST) Subject: [py-svn] r45525 - py/trunk/py/doc/future Message-ID: <20070807071120.1E81380C5@code0.codespeak.net> Author: fijal Date: Tue Aug 7 09:11:18 2007 New Revision: 45525 Modified: py/trunk/py/doc/future/planning2.txt Log: be a bit more impersonal Modified: py/trunk/py/doc/future/planning2.txt ============================================================================== --- py/trunk/py/doc/future/planning2.txt (original) +++ py/trunk/py/doc/future/planning2.txt Tue Aug 7 09:11:18 2007 @@ -1,4 +1,4 @@ -What I miss in py.test (personally): +Missing features/bugs in pylib: ==================================== * new skip method, so web interface would show skips which @@ -21,8 +21,8 @@ * once session integration is done, it would be cool to have nightly testing done in a systematic manner (instead of bunch of hacks, which is how it looks like right now), so for example codespeak would be able - to store information (ie via svn) and when I woke up I can type py.test show - and see the information of all nightly test runs which I like. + to store information (ie via svn) and when one woke up he can type py.test + show and see the information of all nightly test runs which he likes. * py.test.pdb - there is my hack for a while now, which integrates rlcompleter2 with pdb. First of all it requires some strange changes From hpk at codespeak.net Tue Aug 7 18:08:38 2007 From: hpk at codespeak.net (hpk at codespeak.net) Date: Tue, 7 Aug 2007 18:08:38 +0200 (CEST) Subject: [py-svn] r45534 - py/branch/lessthread/py/doc/talk Message-ID: <20070807160838.51C6480D7@code0.codespeak.net> Author: hpk Date: Tue Aug 7 18:08:37 2007 New Revision: 45534 Removed: py/branch/lessthread/py/doc/talk/notes.txt Log: fijal says i can delete this Deleted: /py/branch/lessthread/py/doc/talk/notes.txt ============================================================================== --- /py/branch/lessthread/py/doc/talk/notes.txt Tue Aug 7 18:08:37 2007 +++ (empty file) @@ -1,15 +0,0 @@ - -* Persistant storage layer for storing py.test output, sharing such stuff - and presenting (Presenting mostly means combining tones of hacks here - and there). We need to store test results, revisions and additional - metadata like apigen output - -* Having some kind of pdbplus, which will combine rlcompleter, apigen - information and other various fixes. - -* Improve distributed testing by: - - sharing even more code with normal testing - - using greenexecnet wherever possible (falling back to normal - execnet) - - make test redistribution somehow (in a clean way!) - - C-c support From fijal at codespeak.net Tue Aug 7 18:19:36 2007 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 7 Aug 2007 18:19:36 +0200 (CEST) Subject: [py-svn] r45535 - py/trunk/py/code Message-ID: <20070807161936.9A1F880D7@code0.codespeak.net> Author: fijal Date: Tue Aug 7 18:19:35 2007 New Revision: 45535 Modified: py/trunk/py/code/excinfo.py Log: Avoid hacks when creating exception name Modified: py/trunk/py/code/excinfo.py ============================================================================== --- py/trunk/py/code/excinfo.py (original) +++ py/trunk/py/code/excinfo.py Tue Aug 7 18:19:35 2007 @@ -18,10 +18,7 @@ self._striptext = 'AssertionError: ' self._excinfo = tup self.type, self.value, tb = self._excinfo - self.typename = str(self.type) - if issubclass(self.type, object): - # cpy 2.5 - self.typename = self.typename[7:-2] + self.typename = self.type.__module__ + '.' + self.type.__name__ self.traceback = py.code.Traceback(tb) def exconly(self, tryshort=False): From hpk at codespeak.net Tue Aug 7 18:49:58 2007 From: hpk at codespeak.net (hpk at codespeak.net) Date: Tue, 7 Aug 2007 18:49:58 +0200 (CEST) Subject: [py-svn] r45536 - py/branch/lessthread/py/net/test Message-ID: <20070807164958.6709E80D4@code0.codespeak.net> Author: hpk Date: Tue Aug 7 18:49:57 2007 New Revision: 45536 Added: py/branch/lessthread/py/net/test/__init__.py - copied unchanged from r45534, py/branch/lessthread/py/net/__init__.py Log: adding a missing __init__ From hpk at codespeak.net Tue Aug 7 18:53:00 2007 From: hpk at codespeak.net (hpk at codespeak.net) Date: Tue, 7 Aug 2007 18:53:00 +0200 (CEST) Subject: [py-svn] r45537 - py/branch/lessthread/py/execnet Message-ID: <20070807165300.D87E780D4@code0.codespeak.net> Author: hpk Date: Tue Aug 7 18:52:59 2007 New Revision: 45537 Modified: py/branch/lessthread/py/execnet/gateway.py py/branch/lessthread/py/execnet/register.py Log: (fijal,hpk) for now remove possibility to allow execution locally (i.e. if "A" instantiates a gateway on "B" then B may not execute code on A). fix an issue with dangling processes with "remote_init_threads" instantiate receiver thread and requestqueue from _servemain() instantiate receiver thread from local gateway initialiaztion Modified: py/branch/lessthread/py/execnet/gateway.py ============================================================================== --- py/branch/lessthread/py/execnet/gateway.py (original) +++ py/branch/lessthread/py/execnet/gateway.py Tue Aug 7 18:52:59 2007 @@ -32,9 +32,10 @@ class Gateway(object): _ThreadOut = ThreadOut - _requestqueue = None remoteaddress = "" - def __init__(self, io, allowexec=False, _startcount=2): + _requestqueue = None + + def __init__(self, io, _startcount=2): """ initialize core gateway, using the given inputoutput object. """ @@ -45,7 +46,9 @@ atexit.register(cleanup_atexit) registered_cleanup = True _activegateways[self] = True - if allowexec: + + def _initreceive(self, requestqueue=False): + if requestqueue: self._requestqueue = Queue.Queue() self._receiverthread = threading.Thread(name="receiver", target=self._thread_receiver) @@ -70,9 +73,6 @@ return "<%s%s %s/%s (%s active channels)>" %( self.__class__.__name__, addr, r, s, i) -## def _local_trystopexec(self): -## self._execpool.shutdown() - def _trace(self, *args): if debug: try: @@ -156,6 +156,7 @@ def _servemain(self, joining=True): from sys import exc_info + self._initreceive(requestqueue=True) try: while 1: item = self._requestqueue.get() @@ -185,7 +186,9 @@ while 1: task = gw._requestqueue.get() if task is None: + gw._stopsend() execpool.shutdown() + execpool.join() raise StopExecLoop execpool.dispatch(gw._executetask, task) """ % num) Modified: py/branch/lessthread/py/execnet/register.py ============================================================================== --- py/branch/lessthread/py/execnet/register.py (original) +++ py/branch/lessthread/py/execnet/register.py Tue Aug 7 18:52:59 2007 @@ -28,6 +28,8 @@ def __init__(self, io): self._remote_bootstrap_gateway(io) super(InstallableGateway, self).__init__(io=io, _startcount=1) + # XXX we dissallow execution form the other side + self._initreceive(requestqueue=False) def _remote_bootstrap_gateway(self, io, extra=''): """ return Gateway with a asynchronously remotely @@ -40,7 +42,7 @@ bootstrap = [extra] bootstrap += [getsource(x) for x in startup_modules] bootstrap += [io.server_stmt, - "Gateway(io=io, allowexec=True, _startcount=2)._servemain()", + "Gateway(io=io, _startcount=2)._servemain()", ] source = "\n".join(bootstrap) self._trace("sending gateway bootstrap code") From hpk at codespeak.net Tue Aug 7 18:59:10 2007 From: hpk at codespeak.net (hpk at codespeak.net) Date: Tue, 7 Aug 2007 18:59:10 +0200 (CEST) Subject: [py-svn] r45538 - py/trunk/py Message-ID: <20070807165910.AF155809F@code0.codespeak.net> Author: hpk Date: Tue Aug 7 18:59:09 2007 New Revision: 45538 Modified: py/trunk/py/__init__.py Log: not exported Modified: py/trunk/py/__init__.py ============================================================================== --- py/trunk/py/__init__.py (original) +++ py/trunk/py/__init__.py Tue Aug 7 18:59:09 2007 @@ -31,7 +31,6 @@ 'test.skip' : ('./test/item.py', 'skip'), 'test.fail' : ('./test/item.py', 'fail'), 'test.exit' : ('./test/session.py', 'exit'), - 'test.pdb' : ('./test/pdbplus.py', 'start_pdb'), # configuration/initialization related test api 'test.config' : ('./test/config.py', 'config_per_process'), From hpk at codespeak.net Tue Aug 7 19:34:59 2007 From: hpk at codespeak.net (hpk at codespeak.net) Date: Tue, 7 Aug 2007 19:34:59 +0200 (CEST) Subject: [py-svn] r45539 - py/trunk/py/execnet Message-ID: <20070807173459.CF5F480AD@code0.codespeak.net> Author: hpk Date: Tue Aug 7 19:34:59 2007 New Revision: 45539 Added: py/trunk/py/execnet/ - copied from r45538, py/branch/lessthread/py/execnet/ Log: merge the execnet lessthreads branch (using the branch'es history): * now by default Gateways DO NOT SPAWN execution threads you can call "remote_init_threads(NUM)" on an already instantiated gateway, which will install a loop on the other side which will dispatch each execution task to its own thread. * execution is dissallowed on the side which initiates a gateway (rarely used, anyway) * some cleanups (hopefully) From hpk at codespeak.net Tue Aug 7 19:39:35 2007 From: hpk at codespeak.net (hpk at codespeak.net) Date: Tue, 7 Aug 2007 19:39:35 +0200 (CEST) Subject: [py-svn] r45540 - py/branch/lessthread Message-ID: <20070807173935.2726380AD@code0.codespeak.net> Author: hpk Date: Tue Aug 7 19:39:34 2007 New Revision: 45540 Removed: py/branch/lessthread/ Log: removing merged lessthread branch From hpk at codespeak.net Tue Aug 7 19:54:10 2007 From: hpk at codespeak.net (hpk at codespeak.net) Date: Tue, 7 Aug 2007 19:54:10 +0200 (CEST) Subject: [py-svn] r45541 - py/trunk/py/execnet Message-ID: <20070807175410.73D2C80AC@code0.codespeak.net> Author: hpk Date: Tue Aug 7 19:54:09 2007 New Revision: 45541 Modified: py/trunk/py/execnet/gateway.py Log: don't use globals when we might be called from destructors Modified: py/trunk/py/execnet/gateway.py ============================================================================== --- py/trunk/py/execnet/gateway.py (original) +++ py/trunk/py/execnet/gateway.py Tue Aug 7 19:54:09 2007 @@ -24,13 +24,14 @@ ThreadOut = py._thread.ThreadOut import os -debug = open('/tmp/execnet-debug-%d' % os.getpid() , 'wa') +debug = 0 # open('/tmp/execnet-debug-%d' % os.getpid() , 'wa') sysex = (KeyboardInterrupt, SystemExit) class StopExecLoop(Exception): pass class Gateway(object): + _StopExecLoop = StopExecLoop _ThreadOut = ThreadOut remoteaddress = "" _requestqueue = None @@ -165,7 +166,7 @@ break try: self._executetask(item) - except StopExecLoop: + except self._StopExecLoop: break finally: self._trace("_servemain finished") @@ -189,7 +190,7 @@ gw._stopsend() execpool.shutdown() execpool.join() - raise StopExecLoop + raise gw._StopExecLoop execpool.dispatch(gw._executetask, task) """ % num) self._remotechannelthread = self.remote_exec(source) @@ -211,7 +212,7 @@ self._trace("execution finished:", repr(source)[:50]) except (KeyboardInterrupt, SystemExit): pass - except StopExecLoop: + except self._StopExecLoop: channel.close() raise except: From fijal at codespeak.net Wed Aug 8 11:36:09 2007 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 8 Aug 2007 11:36:09 +0200 (CEST) Subject: [py-svn] r45545 - py/trunk/py/test/rsession Message-ID: <20070808093609.7F18C80F6@code0.codespeak.net> Author: fijal Date: Wed Aug 8 11:36:08 2007 New Revision: 45545 Modified: py/trunk/py/test/rsession/reporter.py Log: Kill lock. Modified: py/trunk/py/test/rsession/reporter.py ============================================================================== --- py/trunk/py/test/rsession/reporter.py (original) +++ py/trunk/py/test/rsession/reporter.py Wed Aug 8 11:36:08 2007 @@ -28,28 +28,23 @@ self.skipped = dict([(host, 0) for host in hosts]) self.passed = dict([(host, 0) for host in hosts]) self.to_rsync = {} - self.lock = thread.allocate_lock() def get_item_name(self, event, colitem): return "/".join(colitem.listnames()) def report(self, what): + repfun = getattr(self, "report_" + what.__class__.__name__, + self.report_unknown) try: - self.lock.acquire() - repfun = getattr(self, "report_" + what.__class__.__name__, - self.report_unknown) - try: - return repfun(what) - except (KeyboardInterrupt, SystemExit): - raise - except: - print "Internal reporting problem" - excinfo = py.code.ExceptionInfo() - for i in excinfo.traceback: - print str(i)[2:-1] - print excinfo - finally: - self.lock.release() + return repfun(what) + except (KeyboardInterrupt, SystemExit): + raise + except: + print "Internal reporting problem" + excinfo = py.code.ExceptionInfo() + for i in excinfo.traceback: + print str(i)[2:-1] + print excinfo def report_unknown(self, what): if self.config.option.verbose: From hpk at codespeak.net Wed Aug 8 12:38:23 2007 From: hpk at codespeak.net (hpk at codespeak.net) Date: Wed, 8 Aug 2007 12:38:23 +0200 (CEST) Subject: [py-svn] r45547 - py/trunk/py/execnet Message-ID: <20070808103823.042FA80E4@code0.codespeak.net> Author: hpk Date: Wed Aug 8 12:38:22 2007 New Revision: 45547 Modified: py/trunk/py/execnet/gateway.py Log: remove global Modified: py/trunk/py/execnet/gateway.py ============================================================================== --- py/trunk/py/execnet/gateway.py (original) +++ py/trunk/py/execnet/gateway.py Wed Aug 8 12:38:22 2007 @@ -27,11 +27,9 @@ debug = 0 # open('/tmp/execnet-debug-%d' % os.getpid() , 'wa') sysex = (KeyboardInterrupt, SystemExit) -class StopExecLoop(Exception): - pass class Gateway(object): - _StopExecLoop = StopExecLoop + class _StopExecLoop(Exception): pass _ThreadOut = ThreadOut remoteaddress = "" _requestqueue = None From hpk at codespeak.net Wed Aug 8 13:45:05 2007 From: hpk at codespeak.net (hpk at codespeak.net) Date: Wed, 8 Aug 2007 13:45:05 +0200 (CEST) Subject: [py-svn] r45548 - py/trunk/py/execnet Message-ID: <20070808114505.6DBE2810A@code0.codespeak.net> Author: hpk Date: Wed Aug 8 13:45:04 2007 New Revision: 45548 Modified: py/trunk/py/execnet/gateway.py Log: - refactoring cleanup mechanics into its own class - have setDaemon(1) for the receiverThread as otherwise on python2.5 atexit will not be invoked (the receiver thread apparently blocks it) Modified: py/trunk/py/execnet/gateway.py ============================================================================== --- py/trunk/py/execnet/gateway.py (original) +++ py/trunk/py/execnet/gateway.py Wed Aug 8 13:45:04 2007 @@ -28,30 +28,55 @@ sysex = (KeyboardInterrupt, SystemExit) +# ---------------------------------------------------------- +# cleanup machinery (for exiting processes) +# ---------------------------------------------------------- + +class GatewayCleanup: + def __init__(self): + self._activegateways = weakref.WeakKeyDictionary() + atexit.register(self.cleanup_atexit) + + def register(self, gateway): + assert gateway not in self._activegateways + self._activegateways[gateway] = True + + def unregister(self, gateway): + del self._activegateways[gateway] + + def cleanup_atexit(self): + if debug: + print >>debug, "="*20 + "cleaning up" + "=" * 20 + debug.flush() + for gw in self._activegateways.keys(): + gw.exit() + gw.join() # should work as well + +# ---------------------------------------------------------- +# Base Gateway (used for both remote and local side) +# ---------------------------------------------------------- + class Gateway(object): class _StopExecLoop(Exception): pass _ThreadOut = ThreadOut remoteaddress = "" _requestqueue = None + _cleanup = GatewayCleanup() def __init__(self, io, _startcount=2): """ initialize core gateway, using the given inputoutput object. """ - global registered_cleanup, _activegateways self._io = io self._channelfactory = ChannelFactory(self, _startcount) - if not registered_cleanup: - atexit.register(cleanup_atexit) - registered_cleanup = True - _activegateways[self] = True + self._cleanup.register(self) def _initreceive(self, requestqueue=False): if requestqueue: self._requestqueue = Queue.Queue() self._receiverthread = threading.Thread(name="receiver", target=self._thread_receiver) - self._receiverthread.setDaemon(0) + self._receiverthread.setDaemon(1) self._receiverthread.start() def __repr__(self): @@ -296,6 +321,7 @@ def exit(self): """ Try to stop all exec and IO activity. """ + self._cleanup.unregister(self) self._stopexec() self._stopsend() @@ -323,13 +349,3 @@ cache[name][id(gw)] = x = "%s:%s.%d" %(os.getpid(), gw.__class__.__name__, len(cache[name])) return x -registered_cleanup = False -_activegateways = weakref.WeakKeyDictionary() -def cleanup_atexit(): - if debug: - print >>debug, "="*20 + "cleaning up" + "=" * 20 - debug.flush() - while _activegateways: - gw, ignored = _activegateways.popitem() - gw.exit() - #gw.join() should work as well From hpk at codespeak.net Wed Aug 8 14:02:59 2007 From: hpk at codespeak.net (hpk at codespeak.net) Date: Wed, 8 Aug 2007 14:02:59 +0200 (CEST) Subject: [py-svn] r45549 - py/trunk/py/execnet Message-ID: <20070808120259.0EFD080F8@code0.codespeak.net> Author: hpk Date: Wed Aug 8 14:02:55 2007 New Revision: 45549 Modified: py/trunk/py/execnet/gateway.py Log: fix a bug that servemain() wouldn't actually try to join threads at exit because of a (hidden) attribute error. Modified: py/trunk/py/execnet/gateway.py ============================================================================== --- py/trunk/py/execnet/gateway.py (original) +++ py/trunk/py/execnet/gateway.py Wed Aug 8 14:02:55 2007 @@ -50,7 +50,7 @@ debug.flush() for gw in self._activegateways.keys(): gw.exit() - gw.join() # should work as well + #gw.join() # should work as well # ---------------------------------------------------------- # Base Gateway (used for both remote and local side) @@ -141,15 +141,15 @@ self._channelfactory._finished_receiving() self._trace('leaving %r' % threading.currentThread()) + from sys import exc_info def _send(self, msg): - from sys import exc_info if msg is None: self._io.close_write() else: try: msg.writeto(self._io) except: - excinfo = exc_info() + excinfo = self.exc_info() self._traceex(excinfo) msg.post_sent(self, excinfo) else: @@ -193,7 +193,7 @@ break finally: self._trace("_servemain finished") - if self.joining: + if joining: self.join() def remote_init_threads(self, num=None): From fijal at codespeak.net Wed Aug 8 14:03:05 2007 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 8 Aug 2007 14:03:05 +0200 (CEST) Subject: [py-svn] r45550 - py/trunk/py/green Message-ID: <20070808120305.B0FB58109@code0.codespeak.net> Author: fijal Date: Wed Aug 8 14:03:03 2007 New Revision: 45550 Added: py/trunk/py/green/conftest.py (contents, props changed) Log: Skip those tests on windows Added: py/trunk/py/green/conftest.py ============================================================================== --- (empty file) +++ py/trunk/py/green/conftest.py Wed Aug 8 14:03:03 2007 @@ -0,0 +1,4 @@ +import py, os + +if os.name == 'nt': + py.test.skip("Cannot test green layer on windows") From fijal at codespeak.net Tue Aug 14 11:45:06 2007 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 14 Aug 2007 11:45:06 +0200 (CEST) Subject: [py-svn] r45646 - py/trunk/py/test/rsession/testing Message-ID: <20070814094506.E92838106@code0.codespeak.net> Author: fijal Date: Tue Aug 14 11:45:04 2007 New Revision: 45646 Modified: py/trunk/py/test/rsession/testing/test_reporter.py py/trunk/py/test/rsession/testing/test_rsession.py Log: Rewrite it a bit not to rely on exact formatting (rather checking whether information is there) Modified: py/trunk/py/test/rsession/testing/test_reporter.py ============================================================================== --- py/trunk/py/test/rsession/testing/test_reporter.py (original) +++ py/trunk/py/test/rsession/testing/test_reporter.py Tue Aug 14 11:45:04 2007 @@ -18,7 +18,6 @@ import py, os -#py.test.skip("in progress") from py.__.test.rsession.rsession import LocalReporter, AbstractSession,\ RemoteReporter from py.__.test.rsession import repevent @@ -173,23 +172,19 @@ reporter = LocalReporter def test_report_received_item_outcome(self): - #py.test.skip("XXX rewrite test to not rely on exact formatting") assert self.report_received_item_outcome() == 'FsF.' def test_module(self): - #py.test.skip("XXX rewrite test to not rely on exact formatting") output = self._test_module() assert output.find("test_one") != -1 assert output.endswith("FsF."), output def test_full_module(self): - #py.test.skip("XXX rewrite test to not rely on exact formatting") received = self._test_full_module() - expected = """ -repmod/test_one.py[1] -repmod/test_three.py[0] - FAILED TO LOAD MODULE -repmod/test_two.py[0] - skipped (reason)""" - assert received.find(expected) != -1 + expected_lst = ["repmod/test_one.py", "FAILED TO LOAD MODULE", + "skipped", "reason"] + for i in expected_lst: + assert received.find(i) != -1 class TestRemoteReporter(AbstractTestReporter): reporter = RemoteReporter @@ -198,28 +193,24 @@ self._test_still_to_go() def test_report_received_item_outcome(self): - py.test.skip("XXX rewrite test to not rely on exact formatting") val = self.report_received_item_outcome() - expected = """ localhost: FAILED py.test.rsession.testing.test_slave.py funcpass - localhost: SKIPPED py.test.rsession.testing.test_slave.py funcpass - localhost: FAILED py.test.rsession.testing.test_slave.py funcpass - localhost: PASSED py.test.rsession.testing.test_slave.py funcpass -""" - assert val.find(expected) != -1 + expected_lst = ["localhost", "FAILED", + "funcpass", "test_one", + "SKIPPED", + "PASSED"] + for expected in expected_lst: + assert val.find(expected) != -1 def test_module(self): - py.test.skip("XXX rewrite test to not rely on exact formatting") val = self._test_module() - print val - expected = """ localhost: FAILED py.test.rsession.testing.test_slave.py funcpass - localhost: SKIPPED py.test.rsession.testing.test_slave.py funcpass - localhost: FAILED py.test.rsession.testing.test_slave.py funcpass - localhost: PASSED py.test.rsession.testing.test_slave.py funcpass -""" - assert val.find(expected) != -1 + expected_lst = ["localhost", "FAILED", + "funcpass", "test_one", + "SKIPPED", + "PASSED"] + for expected in expected_lst: + assert val.find(expected) != -1 def test_full_module(self): - #py.test.skip("XXX rewrite test to not rely on exact formatting") val = self._test_full_module() - assert val.find('FAILED TO LOAD MODULE: repmod/test_three.py\n'\ - '\nSkipped (reason) repmod/test_two.py') != -1 + assert val.find("FAILED TO LOAD MODULE: repmod/test_three.py\n"\ + "\nSkipped ('reason') repmod/test_two.py") != -1 Modified: py/trunk/py/test/rsession/testing/test_rsession.py ============================================================================== --- py/trunk/py/test/rsession/testing/test_rsession.py (original) +++ py/trunk/py/test/rsession/testing/test_rsession.py Tue Aug 14 11:45:04 2007 @@ -29,7 +29,7 @@ rootcol = py.test.collect.Directory(tmpdir) data = list(rootcol._tryiter(reporterror=events.append)) assert len(events) == 2 - assert str(events[1][0].value) == "Reason" + assert str(events[1][0].value).find("Reason") != -1 class TestRSessionRemote(DirSetup, BasicRsessionTest): def test_example_distribution_minus_x(self): From fijal at codespeak.net Tue Aug 14 11:47:28 2007 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 14 Aug 2007 11:47:28 +0200 (CEST) Subject: [py-svn] r45647 - py/trunk/py/test Message-ID: <20070814094728.40E30810C@code0.codespeak.net> Author: fijal Date: Tue Aug 14 11:47:27 2007 New Revision: 45647 Modified: py/trunk/py/test/outcome.py Log: use repr() rather than direct return Modified: py/trunk/py/test/outcome.py ============================================================================== --- py/trunk/py/test/outcome.py (original) +++ py/trunk/py/test/outcome.py Tue Aug 14 11:47:27 2007 @@ -9,7 +9,7 @@ def __repr__(self): if self.msg: - return self.msg + return repr(self.msg) return "<%s instance>" %(self.__class__.__name__,) __str__ = __repr__ From fijal at codespeak.net Tue Aug 14 11:48:16 2007 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 14 Aug 2007 11:48:16 +0200 (CEST) Subject: [py-svn] r45648 - in py/trunk/py/test: . testing Message-ID: <20070814094816.23C3B810E@code0.codespeak.net> Author: fijal Date: Tue Aug 14 11:48:15 2007 New Revision: 45648 Modified: py/trunk/py/test/item.py py/trunk/py/test/testing/test_session.py Log: Add possibility to specify reason for skips Modified: py/trunk/py/test/item.py ============================================================================== --- py/trunk/py/test/item.py (original) +++ py/trunk/py/test/item.py Tue Aug 14 11:48:15 2007 @@ -70,7 +70,25 @@ # # triggering specific outcomes while executing Items # -def skip(msg="unknown reason"): +class BaseReason(object): + def __init__(self, msg="unknown reason", **kwds): + self.msg = msg + self.__dict__.update(kwds) + + def __repr__(self): + return self.msg + +class Broken(BaseReason): + def __repr__(self): + return "Broken: %s" % (self.msg,) + +class _NotImplemented(BaseReason): + def __repr__(self): + return "Not implemented: %s" % (self.msg,) + +# whatever comes here.... + +def skip(msg=BaseReason()): """ skip with the given Message. """ __tracebackhide__ = True raise Skipped(msg=msg) Modified: py/trunk/py/test/testing/test_session.py ============================================================================== --- py/trunk/py/test/testing/test_session.py (original) +++ py/trunk/py/test/testing/test_session.py Tue Aug 14 11:48:15 2007 @@ -325,3 +325,24 @@ expected_output = '\nE ' + line_to_report + '\n' print 'Looking for:', expected_output assert expected_output in out + + +def test_skip_reasons(): + tmp = py.test.ensuretemp("check_skip_reasons") + tmp.ensure("test_one.py").write(py.code.Source(""" + import py + def test_1(): + py.test.skip(py.test.broken('stuff')) + + def test_2(): + py.test.skip(py.test.notimplemented('stuff')) + """)) + tmp.ensure("__init__.py") + config = py.test.config._reparse([tmp]) + session = config.initsession() + session.main() + skips = session.getitemoutcomepairs(Skipped) + assert len(skips) == 2 + assert repr(skips[0][1]) == 'Broken: stuff' + assert repr(skips[1][1]) == 'Not implemented: stuff' + From fijal at codespeak.net Tue Aug 14 11:49:04 2007 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 14 Aug 2007 11:49:04 +0200 (CEST) Subject: [py-svn] r45649 - py/trunk/py Message-ID: <20070814094904.93E7A8110@code0.codespeak.net> Author: fijal Date: Tue Aug 14 11:49:04 2007 New Revision: 45649 Modified: py/trunk/py/__init__.py Log: Two possible skip reasons Modified: py/trunk/py/__init__.py ============================================================================== --- py/trunk/py/__init__.py (original) +++ py/trunk/py/__init__.py Tue Aug 14 11:49:04 2007 @@ -31,6 +31,8 @@ 'test.skip' : ('./test/item.py', 'skip'), 'test.fail' : ('./test/item.py', 'fail'), 'test.exit' : ('./test/session.py', 'exit'), + 'test.broken' : ('./test/item.py', 'Broken'), + 'test.notimplemented' : ('./test/item.py', '_NotImplemented'), # configuration/initialization related test api 'test.config' : ('./test/config.py', 'config_per_process'), From fijal at codespeak.net Tue Aug 14 17:21:02 2007 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 14 Aug 2007 17:21:02 +0200 (CEST) Subject: [py-svn] r45655 - py/trunk/py/test Message-ID: <20070814152102.DB17A8109@code0.codespeak.net> Author: fijal Date: Tue Aug 14 17:21:02 2007 New Revision: 45655 Modified: py/trunk/py/test/collect.py Log: Kill unnecessary sanity check Modified: py/trunk/py/test/collect.py ============================================================================== --- py/trunk/py/test/collect.py (original) +++ py/trunk/py/test/collect.py Tue Aug 14 17:21:02 2007 @@ -46,9 +46,6 @@ self.name = name self.parent = parent self._config = getattr(parent, '_config', py.test.config) - if parent is not None: - if hasattr(parent, 'config'): - py.test.pdb() self.fspath = getattr(parent, 'fspath', None) Module = configproperty('Module') @@ -333,7 +330,7 @@ raise except: self._name2items_exception = py.std.sys.exc_info() - raise + raise def run(self): self._prepare() From fijal at codespeak.net Wed Aug 15 10:34:42 2007 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 15 Aug 2007 10:34:42 +0200 (CEST) Subject: [py-svn] r45661 - py/branch/session-cleanups Message-ID: <20070815083442.ABD708136@code0.codespeak.net> Author: fijal Date: Wed Aug 15 10:34:41 2007 New Revision: 45661 Added: py/branch/session-cleanups/ - copied from r45660, py/trunk/ Log: New branch to work a bit on session cleanups, ie reporter merging, collection merging From fijal at codespeak.net Wed Aug 15 11:04:02 2007 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 15 Aug 2007 11:04:02 +0200 (CEST) Subject: [py-svn] r45663 - py/branch/session-cleanups/py/test/testing Message-ID: <20070815090402.18C038113@code0.codespeak.net> Author: fijal Date: Wed Aug 15 11:04:01 2007 New Revision: 45663 Modified: py/branch/session-cleanups/py/test/testing/test_collect.py Log: A test that I would like to pass Modified: py/branch/session-cleanups/py/test/testing/test_collect.py ============================================================================== --- py/branch/session-cleanups/py/test/testing/test_collect.py (original) +++ py/branch/session-cleanups/py/test/testing/test_collect.py Wed Aug 15 11:04:01 2007 @@ -420,6 +420,24 @@ l = list(col._tryiter(reporterror=errors.append)) assert len(errors) == 2 +def test_generator_setup_invoked_twice(): + py.test.skip("Test for generators not invoking setup, needs thinking") + tmp = py.test.ensuretemp("generator_setup_invoke") + tmp.ensure("test_one.py").write(py.code.Source(""" + def setup_module(mod): + mod.x = [] + + def setup_function(fun): + x.append(1) + + def test_one(): + yield lambda: None + """)) + tmp.ensure("__init__.py") + col = py.test.collect.Module(tmp.join("test_one.py")) + l = list(col._tryiter()) + assert not hasattr(col.obj, 'x') + def test_check_collect_hashes(): tmp = py.test.ensuretemp("check_collect_hashes") tmp.ensure("test_one.py").write(py.code.Source(""" From fijal at codespeak.net Wed Aug 15 11:15:01 2007 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 15 Aug 2007 11:15:01 +0200 (CEST) Subject: [py-svn] r45664 - py/branch/session-cleanups/py/test/testing Message-ID: <20070815091501.8A55D814E@code0.codespeak.net> Author: fijal Date: Wed Aug 15 11:15:01 2007 New Revision: 45664 Modified: py/branch/session-cleanups/py/test/testing/test_collect.py py/branch/session-cleanups/py/test/testing/test_config.py Log: Kill some dead code Modified: py/branch/session-cleanups/py/test/testing/test_collect.py ============================================================================== --- py/branch/session-cleanups/py/test/testing/test_collect.py (original) +++ py/branch/session-cleanups/py/test/testing/test_collect.py Wed Aug 15 11:15:01 2007 @@ -7,10 +7,6 @@ mod.datadir = setupdatadir() mod.tmpdir = py.test.ensuretemp('test_collect') -def skipboxed(): - if py.test.config.option.boxed: - py.test.skip("test does not work with boxed tests") - def test_failing_import_execfile(): dest = datadir / 'failingimport.py' col = py.test.collect.Module(dest) Modified: py/branch/session-cleanups/py/test/testing/test_config.py ============================================================================== --- py/branch/session-cleanups/py/test/testing/test_config.py (original) +++ py/branch/session-cleanups/py/test/testing/test_config.py Wed Aug 15 11:15:01 2007 @@ -2,7 +2,6 @@ import py from py.__.test.config import gettopdir -from py.__.test.testing.test_collect import skipboxed def test_tmpdir(): d1 = py.test.ensuretemp('hello') From fijal at codespeak.net Wed Aug 15 12:35:46 2007 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 15 Aug 2007 12:35:46 +0200 (CEST) Subject: [py-svn] r45665 - py/branch/session-cleanups/py/test/rsession/testing Message-ID: <20070815103546.E1EE38135@code0.codespeak.net> Author: fijal Date: Wed Aug 15 12:35:45 2007 New Revision: 45665 Modified: py/branch/session-cleanups/py/test/rsession/testing/test_reporter.py Log: Skip broken test Modified: py/branch/session-cleanups/py/test/rsession/testing/test_reporter.py ============================================================================== --- py/branch/session-cleanups/py/test/rsession/testing/test_reporter.py (original) +++ py/branch/session-cleanups/py/test/rsession/testing/test_reporter.py Wed Aug 15 12:35:45 2007 @@ -25,6 +25,7 @@ from py.__.test.rsession.hostmanage import HostInfo from py.__.test.rsession.box import Box from py.__.test.rsession.testing.basetest import BasicRsessionTest +from py.__.test.rsession.master import itemgen import sys from StringIO import StringIO @@ -111,7 +112,7 @@ rootcol = py.test.collect.Directory(tmpdir) hosts = [HostInfo('localhost')] r = self.reporter(config, hosts) - list(rootcol._tryiter(reporterror=lambda x : AbstractSession.reporterror(r.report, x))) + list(itemgen([rootcol], r.report)) cap = py.io.StdCaptureFD() boxfun() @@ -132,7 +133,7 @@ r = self.reporter(config, [host]) r.report(repevent.TestStarted([host], config.topdir, ["a"])) r.report(repevent.RsyncFinished()) - list(rootcol._tryiter(reporterror=lambda x : AbstractSession.reporterror(r.report, x))) + list(itemgen([rootcol], r.report)) r.report(repevent.TestFinished()) return r @@ -190,6 +191,7 @@ reporter = RemoteReporter def test_still_to_go(self): + py.test.skip("XXX fix it, there is shadowed internal reporting problem") self._test_still_to_go() def test_report_received_item_outcome(self): From fijal at codespeak.net Wed Aug 15 12:36:11 2007 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 15 Aug 2007 12:36:11 +0200 (CEST) Subject: [py-svn] r45666 - py/branch/session-cleanups/py/test/rsession Message-ID: <20070815103611.4B8AD813C@code0.codespeak.net> Author: fijal Date: Wed Aug 15 12:36:10 2007 New Revision: 45666 Modified: py/branch/session-cleanups/py/test/rsession/reporter.py Log: Some info Modified: py/branch/session-cleanups/py/test/rsession/reporter.py ============================================================================== --- py/branch/session-cleanups/py/test/rsession/reporter.py (original) +++ py/branch/session-cleanups/py/test/rsession/reporter.py Wed Aug 15 12:36:10 2007 @@ -45,6 +45,9 @@ for i in excinfo.traceback: print str(i)[2:-1] print excinfo + # XXX reenable test before removing below line and + # run it with raise + #raise def report_unknown(self, what): if self.config.option.verbose: From fijal at codespeak.net Wed Aug 15 12:36:44 2007 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 15 Aug 2007 12:36:44 +0200 (CEST) Subject: [py-svn] r45667 - py/branch/session-cleanups/py/test/rsession Message-ID: <20070815103644.82596813C@code0.codespeak.net> Author: fijal Date: Wed Aug 15 12:36:44 2007 New Revision: 45667 Modified: py/branch/session-cleanups/py/test/rsession/master.py py/branch/session-cleanups/py/test/rsession/rsession.py Log: Remove _tryiter from rsession Modified: py/branch/session-cleanups/py/test/rsession/master.py ============================================================================== --- py/branch/session-cleanups/py/test/rsession/master.py (original) +++ py/branch/session-cleanups/py/test/rsession/master.py Wed Aug 15 12:36:44 2007 @@ -4,6 +4,7 @@ import py from py.__.test.rsession.outcome import ReprOutcome from py.__.test.rsession import repevent +from py.__.test.outcome import Skipped class MasterNode(object): def __init__(self, channel, reporter): @@ -39,12 +40,30 @@ # of hanging nodes and such raise -def itemgen(colitems, reporter, keyword, reporterror): - def rep(x): - reporterror(reporter, x) - for x in colitems: - for y in x._tryiter(reporterror=rep, keyword=keyword): - yield y +def itemgen(colitems, reporter, keyword=None): + stopitems = py.test.collect.Item # XXX should be generator here as well + for next in colitems: + if isinstance(next, stopitems): + try: + next._skipbykeyword(keyword) + yield next + except Skipped: + excinfo = py.code.ExceptionInfo() + reporter(repevent.SkippedTryiter(excinfo, next)) + else: + reporter(repevent.ItemStart(next)) + try: + for x in itemgen([next.join(x) for x in next.run()], reporter, + keyword): + yield x + except (KeyboardInterrupt, SystemExit): + raise + except: + excinfo = py.code.ExceptionInfo() + if excinfo.type is Skipped: + reporter(repevent.SkippedTryiter(excinfo, next)) + else: + reporter(repevent.FailedTryiter(excinfo, next)) def dispatch_loop(masternodes, itemgenerator, shouldstop, waiter = lambda: py.std.time.sleep(0.1), Modified: py/branch/session-cleanups/py/test/rsession/rsession.py ============================================================================== --- py/branch/session-cleanups/py/test/rsession/rsession.py (original) +++ py/branch/session-cleanups/py/test/rsession/rsession.py Wed Aug 15 12:36:44 2007 @@ -69,16 +69,6 @@ return reporter, startserverflag - def reporterror(reporter, data): - excinfo, item = data - if excinfo is None: - reporter(repevent.ItemStart(item)) - elif excinfo.type is Skipped: - reporter(repevent.SkippedTryiter(excinfo, item)) - else: - reporter(repevent.FailedTryiter(excinfo, item)) - reporterror = staticmethod(reporterror) - def kill_server(self, startserverflag): """ Kill web server """ @@ -171,8 +161,7 @@ def dispatch_tests(self, nodes, reporter, checkfun): colitems = self.config.getcolitems() keyword = self.config.option.keyword - itemgenerator = itemgen(colitems, reporter, keyword, self.reporterror) - + itemgenerator = itemgen(colitems, reporter, keyword) all_tests = dispatch_loop(nodes, itemgenerator, checkfun) class LSession(AbstractSession): @@ -200,7 +189,7 @@ keyword = self.config.option.keyword - itemgenerator = itemgen(colitems, reporter, keyword, self.reporterror) + itemgenerator = itemgen(colitems, reporter, keyword) local_loop(self, reporter, itemgenerator, checkfun, self.config, runner=runner) retval = reporter(repevent.TestFinished()) From fijal at codespeak.net Wed Aug 15 12:38:04 2007 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 15 Aug 2007 12:38:04 +0200 (CEST) Subject: [py-svn] r45668 - py/branch/session-cleanups/py/test/rsession/testing Message-ID: <20070815103804.61D798135@code0.codespeak.net> Author: fijal Date: Wed Aug 15 12:38:03 2007 New Revision: 45668 Modified: py/branch/session-cleanups/py/test/rsession/testing/test_rsession.py Log: This test makes no sense any more (although some itemgen test might fit here) Modified: py/branch/session-cleanups/py/test/rsession/testing/test_rsession.py ============================================================================== --- py/branch/session-cleanups/py/test/rsession/testing/test_rsession.py (original) +++ py/branch/session-cleanups/py/test/rsession/testing/test_rsession.py Wed Aug 15 12:38:03 2007 @@ -14,23 +14,6 @@ if py.std.sys.platform == "win32": py.test.skip("rsession tests disabled for win32") -def test_example_tryiter(): - events = [] - tmpdir = py.test.ensuretemp("tryitertest") - tmpdir.ensure("a", "__init__.py") - tmpdir.ensure("conftest.py").write(py.code.Source(""" - import py - py.test.skip("Reason") - """)) - tmpdir.ensure("a", "test_empty.py").write(py.code.Source(""" - def test_empty(): - pass - """)) - rootcol = py.test.collect.Directory(tmpdir) - data = list(rootcol._tryiter(reporterror=events.append)) - assert len(events) == 2 - assert str(events[1][0].value).find("Reason") != -1 - class TestRSessionRemote(DirSetup, BasicRsessionTest): def test_example_distribution_minus_x(self): self.source.ensure("sub", "conftest.py").write(py.code.Source(""" From fijal at codespeak.net Wed Aug 15 12:51:34 2007 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 15 Aug 2007 12:51:34 +0200 (CEST) Subject: [py-svn] r45670 - in py/branch/session-cleanups/py/test: . testing Message-ID: <20070815105134.1894C812F@code0.codespeak.net> Author: fijal Date: Wed Aug 15 12:51:34 2007 New Revision: 45670 Modified: py/branch/session-cleanups/py/test/collect.py py/branch/session-cleanups/py/test/testing/test_collect.py Log: Kill _tryiter arguments! Hooray! Modified: py/branch/session-cleanups/py/test/collect.py ============================================================================== --- py/branch/session-cleanups/py/test/collect.py (original) +++ py/branch/session-cleanups/py/test/collect.py Wed Aug 15 12:51:34 2007 @@ -189,7 +189,7 @@ return True return False - def _tryiter(self, yieldtype=None, reporterror=None, keyword=None): + def _tryiter(self, yieldtype=None): """ yield stop item instances from flattening the collector. XXX deprecated: this way of iteration is not safe in all cases. @@ -197,28 +197,17 @@ if yieldtype is None: yieldtype = py.test.collect.Item if isinstance(self, yieldtype): - try: - self._skipbykeyword(keyword) - yield self - except Skipped: - if reporterror is not None: - excinfo = py.code.ExceptionInfo() - reporterror((excinfo, self)) + yield self else: if not isinstance(self, py.test.collect.Item): try: - if reporterror is not None: - reporterror((None, self)) for x in self.run(): - for y in self.join(x)._tryiter(yieldtype, - reporterror, keyword): + for y in self.join(x)._tryiter(yieldtype): yield y except KeyboardInterrupt: raise - except: - if reporterror is not None: - excinfo = py.code.ExceptionInfo() - reporterror((excinfo, self)) + except: + pass def _getsortvalue(self): return self.name Modified: py/branch/session-cleanups/py/test/testing/test_collect.py ============================================================================== --- py/branch/session-cleanups/py/test/testing/test_collect.py (original) +++ py/branch/session-cleanups/py/test/testing/test_collect.py Wed Aug 15 12:51:34 2007 @@ -371,10 +371,6 @@ py.test.fail("should not have raised: %s" %(exc,)) l = [] - list(col._tryiter(reporterror=l.append)) - assert len(l) == 2 - excinfo, item = l[-1] - assert isinstance(excinfo, py.code.ExceptionInfo) def test_tryiter_handles_keyboardinterrupt(): tmp = py.test.ensuretemp("tryiterkeyboard") @@ -412,9 +408,7 @@ """)) tmp.ensure("__init__.py") col = py.test.collect.Module(tmp.join("test_one.py")) - errors = [] - l = list(col._tryiter(reporterror=errors.append)) - assert len(errors) == 2 + assert len(col.join('test_one').run()) == 3 def test_generator_setup_invoked_twice(): py.test.skip("Test for generators not invoking setup, needs thinking") From fijal at codespeak.net Wed Aug 15 12:53:27 2007 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 15 Aug 2007 12:53:27 +0200 (CEST) Subject: [py-svn] r45671 - py/trunk/py/path/local Message-ID: <20070815105327.8A1888137@code0.codespeak.net> Author: fijal Date: Wed Aug 15 12:53:26 2007 New Revision: 45671 Modified: py/trunk/py/path/local/local.py Log: Change lines for code.txt not to fail on cpy2.5 Problem is described in tests (skipped) anyway, hence there is no point in failing code snippet in documentation Modified: py/trunk/py/path/local/local.py ============================================================================== --- py/trunk/py/path/local/local.py (original) +++ py/trunk/py/path/local/local.py Wed Aug 15 12:53:26 2007 @@ -68,9 +68,8 @@ elif isinstance(path, str): self.strpath = os.path.abspath(os.path.normpath(str(path))) else: - raise ValueError( - "can only pass None, Path instances " - "or non-empty strings to LocalPath") + raise ValueError("can only pass None, Path instances " + "or non-empty strings to LocalPath") assert isinstance(self.strpath, str) return self From fijal at codespeak.net Sat Aug 18 12:41:09 2007 From: fijal at codespeak.net (fijal at codespeak.net) Date: Sat, 18 Aug 2007 12:41:09 +0200 (CEST) Subject: [py-svn] r45844 - py/branch/session-cleanups/py/execnet Message-ID: <20070818104109.E19598202@code0.codespeak.net> Author: fijal Date: Sat Aug 18 12:41:09 2007 New Revision: 45844 Modified: py/branch/session-cleanups/py/execnet/inputoutput.py Log: Hum. I don't like the idea, but this lock prevents segfault and/or double free. Modified: py/branch/session-cleanups/py/execnet/inputoutput.py ============================================================================== --- py/branch/session-cleanups/py/execnet/inputoutput.py (original) +++ py/branch/session-cleanups/py/execnet/inputoutput.py Sat Aug 18 12:41:09 2007 @@ -3,7 +3,7 @@ across process or computer barriers. """ -import socket, os, sys +import socket, os, sys, thread class SocketIO: server_stmt = """ @@ -76,6 +76,7 @@ msvcrt.setmode(outfile.fileno(), os.O_BINARY) self.outfile, self.infile = infile, outfile self.readable = self.writeable = True + self.lock = thread.allocate_lock() def read(self, numbytes): """Read exactly 'bytes' bytes from the pipe. """ @@ -99,6 +100,10 @@ self.infile.close() self.readable = None def close_write(self): - if self.writeable: - self.outfile.close() - self.writeable = None + self.lock.acquire() + try: + if self.writeable: + self.outfile.close() + self.writeable = None + finally: + self.lock.release() From fijal at codespeak.net Sat Aug 18 13:07:19 2007 From: fijal at codespeak.net (fijal at codespeak.net) Date: Sat, 18 Aug 2007 13:07:19 +0200 (CEST) Subject: [py-svn] r45846 - in py/branch/session-cleanups/py/test: . rsession rsession/testing testing Message-ID: <20070818110719.448C48200@code0.codespeak.net> Author: fijal Date: Sat Aug 18 13:07:18 2007 New Revision: 45846 Added: py/branch/session-cleanups/py/test/repevent.py - copied unchanged from r45661, py/branch/session-cleanups/py/test/rsession/repevent.py py/branch/session-cleanups/py/test/reporter.py - copied, changed from r45666, py/branch/session-cleanups/py/test/rsession/reporter.py py/branch/session-cleanups/py/test/testing/test_outcome.py - copied, changed from r45661, py/branch/session-cleanups/py/test/rsession/testing/test_outcome.py py/branch/session-cleanups/py/test/testing/test_repevent.py - copied, changed from r45661, py/branch/session-cleanups/py/test/rsession/testing/test_repevent.py py/branch/session-cleanups/py/test/testing/test_reporter.py - copied, changed from r45665, py/branch/session-cleanups/py/test/rsession/testing/test_reporter.py Removed: py/branch/session-cleanups/py/test/rsession/outcome.py py/branch/session-cleanups/py/test/rsession/repevent.py py/branch/session-cleanups/py/test/rsession/reporter.py py/branch/session-cleanups/py/test/rsession/testing/test_outcome.py py/branch/session-cleanups/py/test/rsession/testing/test_repevent.py py/branch/session-cleanups/py/test/rsession/testing/test_reporter.py Modified: py/branch/session-cleanups/py/test/outcome.py py/branch/session-cleanups/py/test/rsession/executor.py py/branch/session-cleanups/py/test/rsession/hostmanage.py py/branch/session-cleanups/py/test/rsession/local.py py/branch/session-cleanups/py/test/rsession/master.py py/branch/session-cleanups/py/test/rsession/rest.py py/branch/session-cleanups/py/test/rsession/rsession.py py/branch/session-cleanups/py/test/rsession/slave.py py/branch/session-cleanups/py/test/rsession/testing/test_executor.py py/branch/session-cleanups/py/test/rsession/testing/test_hostmanage.py py/branch/session-cleanups/py/test/rsession/testing/test_lsession.py py/branch/session-cleanups/py/test/rsession/testing/test_master.py py/branch/session-cleanups/py/test/rsession/testing/test_rest.py py/branch/session-cleanups/py/test/rsession/testing/test_rsession.py py/branch/session-cleanups/py/test/rsession/testing/test_slave.py py/branch/session-cleanups/py/test/rsession/web.py Log: Shuffling files around to have reporter in test rather than in rsession. Fixing imports. Might be cool to have reporter somewhere else (ie reporter dir or sth) Modified: py/branch/session-cleanups/py/test/outcome.py ============================================================================== --- py/branch/session-cleanups/py/test/outcome.py (original) +++ py/branch/session-cleanups/py/test/outcome.py Sat Aug 18 13:07:18 2007 @@ -1,7 +1,10 @@ -""" File defining possible outcomes of running +""" File defining possible outcomes of running and also +serialization of outcomes """ +import py, sys + class Outcome: def __init__(self, msg=None, excinfo=None): self.msg = msg @@ -27,3 +30,120 @@ class Skipped(Outcome): pass + + +class SerializableOutcome(object): + def __init__(self, setupfailure=False, excinfo=None, skipped=None, + is_critical=False): + self.passed = not excinfo and not skipped + self.skipped = skipped + self.setupfailure = setupfailure + self.excinfo = excinfo + self.is_critical = is_critical + self.signal = 0 + self.stdout = "" # XXX temporary + self.stderr = "" + assert bool(self.passed) + bool(excinfo) + bool(skipped) == 1 + + def make_excinfo_repr(self, tbstyle): + if self.excinfo is None: + return None + excinfo = self.excinfo + tb_info = [self.traceback_entry_repr(x, tbstyle) + for x in excinfo.traceback] + rec_index = excinfo.traceback.recursionindex() + if hasattr(excinfo, 'type'): + etype = excinfo.type + if hasattr(etype, '__name__'): + etype = etype.__name__ + else: + etype = excinfo.typename + val = getattr(excinfo, 'value', None) + if not val: + val = excinfo.exconly() + val = str(val) + return (etype, val, (tb_info, rec_index)) + + def traceback_entry_repr(self, tb_entry, tb_style): + lineno = tb_entry.lineno + relline = lineno - tb_entry.frame.code.firstlineno + path = str(tb_entry.path) + #try: + try: + if tb_style == 'long': + source = str(tb_entry.getsource()) + else: + source = str(tb_entry.getsource()).split("\n")[relline] + except py.error.ENOENT: + source = "[cannot get source]" + name = str(tb_entry.frame.code.name) + # XXX: Bare except. What can getsource() raise anyway? + # SyntaxError, AttributeError, IndentationError for sure, check it + #except: + # source = "" + return (relline, lineno, source, path, name) + + def make_repr(self, tbstyle="long"): + return (self.passed, self.setupfailure, + self.make_excinfo_repr(tbstyle), + self.skipped, self.is_critical, 0, self.stdout, self.stderr) + +class TracebackEntryRepr(object): + def __init__(self, tbentry): + relline, lineno, self.source, self.path, self.name = tbentry + self.relline = int(relline) + self.path = py.path.local(self.path) + self.lineno = int(lineno) + self.locals = {} + + def __repr__(self): + return "line %s in %s\n %s" %(self.lineno, self.path, self.source[100:]) + + def getsource(self): + return py.code.Source(self.source).strip() + + def getfirstlinesource(self): + return self.lineno - self.relline + +class TracebackRepr(list): + def recursionindex(self): + return self.recursion_index + +class ExcInfoRepr(object): + def __init__(self, excinfo): + self.typename, self.value, tb_i = excinfo + tb, rec_index = tb_i + self.traceback = TracebackRepr([TracebackEntryRepr(x) for x in tb]) + self.traceback.recursion_index = rec_index + + def __repr__(self): + l = ["%s=%s" %(x, getattr(self, x)) + for x in "typename value traceback".split()] + return "" %(" ".join(l),) + + def exconly(self, tryshort=False): + """ Somehow crippled version of original one + """ + return "%s: %s" % (self.typename, self.value) + + def errisinstance(self, exc_t): + if not isinstance(exc_t, tuple): + exc_t = (exc_t,) + for exc in exc_t: + if self.typename == str(exc).split('.')[-1]: + return True + return False + +class ReprOutcome(object): + def __init__(self, repr_tuple): + (self.passed, self.setupfailure, excinfo, self.skipped, + self.is_critical, self.signal, self.stdout, self.stderr) = repr_tuple + if excinfo is None: + self.excinfo = None + else: + self.excinfo = ExcInfoRepr(excinfo) + + def __repr__(self): + l = ["%s=%s" %(x, getattr(self, x)) + for x in "signal passed skipped setupfailure excinfo stdout stderr".split()] + return "" %(" ".join(l),) Copied: py/branch/session-cleanups/py/test/reporter.py (from r45666, py/branch/session-cleanups/py/test/rsession/reporter.py) ============================================================================== --- py/branch/session-cleanups/py/test/rsession/reporter.py (original) +++ py/branch/session-cleanups/py/test/reporter.py Sat Aug 18 13:07:18 2007 @@ -8,8 +8,8 @@ import py from py.__.test.terminal.out import getout -from py.__.test.rsession import repevent -from py.__.test.rsession import outcome +from py.__.test import repevent +from py.__.test import outcome from py.__.misc.terminal_helper import ansi_print, get_terminal_width from py.__.test.representation import Presenter @@ -155,7 +155,7 @@ self.repr_failure(event.item, event.outcome) else: self.out.sep('_', " ".join(event.item.listnames())) - out = outcome.Outcome(excinfo=event.excinfo) + out = outcome.SerializableOutcome(excinfo=event.excinfo) self.repr_failure(event.item, outcome.ReprOutcome(out.make_repr())) def gethost(self, event): Modified: py/branch/session-cleanups/py/test/rsession/executor.py ============================================================================== --- py/branch/session-cleanups/py/test/rsession/executor.py (original) +++ py/branch/session-cleanups/py/test/rsession/executor.py Sat Aug 18 13:07:18 2007 @@ -3,9 +3,9 @@ import py, os, sys -from py.__.test.rsession.outcome import Outcome, ReprOutcome +from py.__.test.outcome import SerializableOutcome, ReprOutcome from py.__.test.rsession.box import Box -from py.__.test.rsession import repevent +from py.__.test import repevent from py.__.test.outcome import Skipped, Failed class RunExecutor(object): @@ -33,9 +33,9 @@ def execute(self, capture=True): try: self.run(capture) - outcome = Outcome() + outcome = SerializableOutcome() except Skipped, e: - outcome = Outcome(skipped=str(e)) + outcome = SerializableOutcome(skipped=str(e)) except (SystemExit, KeyboardInterrupt): raise except: @@ -49,7 +49,7 @@ code = py.code.Code(fun) excinfo.traceback = excinfo.traceback.cut( path=code.path, firstlineno=code.firstlineno) - outcome = Outcome(excinfo=excinfo, setupfailure=False) + outcome = SerializableOutcome(excinfo=excinfo, setupfailure=False) if self.usepdb: if self.reporter is not None: self.reporter(repevent.ImmediateFailure(self.item, Modified: py/branch/session-cleanups/py/test/rsession/hostmanage.py ============================================================================== --- py/branch/session-cleanups/py/test/rsession/hostmanage.py (original) +++ py/branch/session-cleanups/py/test/rsession/hostmanage.py Sat Aug 18 13:07:18 2007 @@ -5,7 +5,7 @@ from py.__.test.rsession.master import MasterNode from py.__.test.rsession.slave import setup_slave -from py.__.test.rsession import repevent +from py.__.test import repevent class HostInfo(object): """ Class trying to store all necessary attributes Modified: py/branch/session-cleanups/py/test/rsession/local.py ============================================================================== --- py/branch/session-cleanups/py/test/rsession/local.py (original) +++ py/branch/session-cleanups/py/test/rsession/local.py Sat Aug 18 13:07:18 2007 @@ -5,8 +5,8 @@ import py from py.__.test.rsession.executor import BoxExecutor, RunExecutor,\ ApigenExecutor -from py.__.test.rsession import repevent -from py.__.test.rsession.outcome import ReprOutcome +from py.__.test import repevent +from py.__.test.outcome import ReprOutcome # XXX copied from session.py def startcapture(session): Modified: py/branch/session-cleanups/py/test/rsession/master.py ============================================================================== --- py/branch/session-cleanups/py/test/rsession/master.py (original) +++ py/branch/session-cleanups/py/test/rsession/master.py Sat Aug 18 13:07:18 2007 @@ -2,8 +2,8 @@ Node code for Master. """ import py -from py.__.test.rsession.outcome import ReprOutcome -from py.__.test.rsession import repevent +from py.__.test.outcome import ReprOutcome +from py.__.test import repevent from py.__.test.outcome import Skipped class MasterNode(object): Deleted: /py/branch/session-cleanups/py/test/rsession/outcome.py ============================================================================== --- /py/branch/session-cleanups/py/test/rsession/outcome.py Sat Aug 18 13:07:18 2007 +++ (empty file) @@ -1,126 +0,0 @@ - -""" Classes for representing outcomes on master and slavenode sides -""" - -# WARNING! is_critical is debugging flag which means something -# wrong went on a different level. Usually that means -# internal bug. - -import sys -import py - -class Outcome(object): - def __init__(self, setupfailure=False, excinfo=None, skipped=None, - is_critical=False): - self.passed = not excinfo and not skipped - self.skipped = skipped - self.setupfailure = setupfailure - self.excinfo = excinfo - self.is_critical = is_critical - self.signal = 0 - self.stdout = "" # XXX temporary - self.stderr = "" - assert bool(self.passed) + bool(excinfo) + bool(skipped) == 1 - - def make_excinfo_repr(self, tbstyle): - if self.excinfo is None: - return None - excinfo = self.excinfo - tb_info = [self.traceback_entry_repr(x, tbstyle) - for x in excinfo.traceback] - rec_index = excinfo.traceback.recursionindex() - if hasattr(excinfo, 'type'): - etype = excinfo.type - if hasattr(etype, '__name__'): - etype = etype.__name__ - else: - etype = excinfo.typename - val = getattr(excinfo, 'value', None) - if not val: - val = excinfo.exconly() - val = str(val) - return (etype, val, (tb_info, rec_index)) - - def traceback_entry_repr(self, tb_entry, tb_style): - lineno = tb_entry.lineno - relline = lineno - tb_entry.frame.code.firstlineno - path = str(tb_entry.path) - #try: - try: - if tb_style == 'long': - source = str(tb_entry.getsource()) - else: - source = str(tb_entry.getsource()).split("\n")[relline] - except py.error.ENOENT: - source = "[cannot get source]" - name = str(tb_entry.frame.code.name) - # XXX: Bare except. What can getsource() raise anyway? - # SyntaxError, AttributeError, IndentationError for sure, check it - #except: - # source = "" - return (relline, lineno, source, path, name) - - def make_repr(self, tbstyle="long"): - return (self.passed, self.setupfailure, - self.make_excinfo_repr(tbstyle), - self.skipped, self.is_critical, 0, self.stdout, self.stderr) - -class TracebackEntryRepr(object): - def __init__(self, tbentry): - relline, lineno, self.source, self.path, self.name = tbentry - self.relline = int(relline) - self.path = py.path.local(self.path) - self.lineno = int(lineno) - self.locals = {} - - def __repr__(self): - return "line %s in %s\n %s" %(self.lineno, self.path, self.source[100:]) - - def getsource(self): - return py.code.Source(self.source).strip() - - def getfirstlinesource(self): - return self.lineno - self.relline - -class TracebackRepr(list): - def recursionindex(self): - return self.recursion_index - -class ExcInfoRepr(object): - def __init__(self, excinfo): - self.typename, self.value, tb_i = excinfo - tb, rec_index = tb_i - self.traceback = TracebackRepr([TracebackEntryRepr(x) for x in tb]) - self.traceback.recursion_index = rec_index - - def __repr__(self): - l = ["%s=%s" %(x, getattr(self, x)) - for x in "typename value traceback".split()] - return "" %(" ".join(l),) - - def exconly(self, tryshort=False): - """ Somehow crippled version of original one - """ - return "%s: %s" % (self.typename, self.value) - - def errisinstance(self, exc_t): - if not isinstance(exc_t, tuple): - exc_t = (exc_t,) - for exc in exc_t: - if self.typename == str(exc).split('.')[-1]: - return True - return False - -class ReprOutcome(object): - def __init__(self, repr_tuple): - (self.passed, self.setupfailure, excinfo, self.skipped, - self.is_critical, self.signal, self.stdout, self.stderr) = repr_tuple - if excinfo is None: - self.excinfo = None - else: - self.excinfo = ExcInfoRepr(excinfo) - - def __repr__(self): - l = ["%s=%s" %(x, getattr(self, x)) - for x in "signal passed skipped setupfailure excinfo stdout stderr".split()] - return "" %(" ".join(l),) Deleted: /py/branch/session-cleanups/py/test/rsession/repevent.py ============================================================================== --- /py/branch/session-cleanups/py/test/rsession/repevent.py Sat Aug 18 13:07:18 2007 +++ (empty file) @@ -1,145 +0,0 @@ -""" Reporter classes for showing asynchronous and synchronous status events -""" - -import py -import time - -def basic_report(msg_type, message): - print msg_type, message - -#def report(msg_type, message): -# pass - -##def report_error(excinfo): -## if isinstance(excinfo, py.test.collect.Item.Skipped): -## # we need to dispatch this info -## report(Skipped(excinfo)) -## else: -## report("itererror", excinfo) - -def wrapcall(reporter, func, *args, **kwargs): - reporter(CallStart(func, args, kwargs)) - try: - retval = func(*args, **kwargs) - except: - reporter(CallException(func, args, kwargs)) - raise - else: - reporter(CallFinish(func, args, kwargs)) - return retval - -# ---------------------------------------------------------------------- -# Reporting Events -# ---------------------------------------------------------------------- - -class ReportEvent(object): - def __repr__(self): - l = ["%s=%s" %(key, value) - for key, value in self.__dict__.items()] - return "<%s %s>" %(self.__class__.__name__, " ".join(l),) - -class SendItem(ReportEvent): - def __init__(self, channel, item): - self.item = item - self.channel = channel - if channel: - self.host = channel.gateway.host - -class ReceivedItemOutcome(ReportEvent): - def __init__(self, channel, item, outcome): - self.channel = channel - if channel: - self.host = channel.gateway.host - self.item = item - self.outcome = outcome - -class CallEvent(ReportEvent): - def __init__(self, func, args, kwargs): - self.func = func - self.args = args - self.kwargs = kwargs - - def __repr__(self): - call = "%s args=%s, kwargs=%s" %(self.func.__name__, - self.args, self.kwargs) - return '<%s %s>' %(self.__class__.__name__, call) - -class CallStart(CallEvent): - pass - -class CallException(CallEvent): - pass - -class CallFinish(CallEvent): - pass - -class HostRSyncing(ReportEvent): - def __init__(self, host, root, remotepath, synced): - self.host = host - self.root = root - self.remotepath = remotepath - self.synced = synced - -class HostGatewayReady(ReportEvent): - def __init__(self, host, roots): - self.host = host - self.roots = roots - -class HostRSyncRootReady(ReportEvent): - def __init__(self, host, root): - self.host = host - self.root = root - -class TestStarted(ReportEvent): - def __init__(self, hosts, topdir, roots): - self.hosts = hosts - self.topdir = topdir - self.roots = roots - self.timestart = time.time() - -class TestFinished(ReportEvent): - def __init__(self): - self.timeend = time.time() - -class Nodes(ReportEvent): - def __init__(self, nodes): - self.nodes = nodes - -class SkippedTryiter(ReportEvent): - def __init__(self, excinfo, item): - self.excinfo = excinfo - self.item = item - -class FailedTryiter(ReportEvent): - def __init__(self, excinfo, item): - self.excinfo = excinfo - self.item = item - -class ItemStart(ReportEvent): - """ This class shows most of the start stuff, like directory, module, class - can be used for containers - """ - def __init__(self, item): - self.item = item - -class RsyncFinished(ReportEvent): - def __init__(self): - self.time = time.time() - -class ImmediateFailure(ReportEvent): - def __init__(self, item, outcome): - self.item = item - self.outcome = outcome - -class PongReceived(ReportEvent): - def __init__(self, hostid, result): - self.hostid = hostid - self.result = result - -class InterruptedExecution(ReportEvent): - def __init__(self): - self.timeend = time.time() - -class CrashedExecution(ReportEvent): - def __init__(self): - self.timeend = time.time() Deleted: /py/branch/session-cleanups/py/test/rsession/reporter.py ============================================================================== --- /py/branch/session-cleanups/py/test/rsession/reporter.py Sat Aug 18 13:07:18 2007 +++ (empty file) @@ -1,350 +0,0 @@ - -""" reporter - different reporter for different purposes ;-) - Still lacks: - - 1. Hanging nodes are not done well -""" - -import py - -from py.__.test.terminal.out import getout -from py.__.test.rsession import repevent -from py.__.test.rsession import outcome -from py.__.misc.terminal_helper import ansi_print, get_terminal_width -from py.__.test.representation import Presenter - -import sys -import thread - -class AbstractReporter(object): - def __init__(self, config, hosts): - self.config = config - self.hosts = hosts - self.failed_tests_outcome = [] - self.skipped_tests_outcome = [] - self.out = getout(py.std.sys.stdout) - self.presenter = Presenter(self.out, config) - self.failed = dict([(host, 0) for host in hosts]) - self.skipped = dict([(host, 0) for host in hosts]) - self.passed = dict([(host, 0) for host in hosts]) - self.to_rsync = {} - - def get_item_name(self, event, colitem): - return "/".join(colitem.listnames()) - - def report(self, what): - repfun = getattr(self, "report_" + what.__class__.__name__, - self.report_unknown) - try: - return repfun(what) - except (KeyboardInterrupt, SystemExit): - raise - except: - print "Internal reporting problem" - excinfo = py.code.ExceptionInfo() - for i in excinfo.traceback: - print str(i)[2:-1] - print excinfo - # XXX reenable test before removing below line and - # run it with raise - #raise - - def report_unknown(self, what): - if self.config.option.verbose: - print "Unknown report: %s" % what - - def report_SendItem(self, item): - address = item.host.hostname - assert isinstance(item.host.hostname, str) - if self.config.option.verbose: - print "Sending %s to %s" % (item.item, - address) - - def report_HostRSyncing(self, item): - hostrepr = self._hostrepr(item.host) - if item.synced: - if (item.host.hostname == "localhost" and - item.root == item.remotepath): - print "%15s: skipping inplace rsync of %r" %( - hostrepr, item.remotepath) - else: - print "%15s: skip duplicate rsync to %r" % ( - hostrepr, item.remotepath) - else: - print "%15s: rsync %r to remote %r" % (hostrepr, - item.root.basename, - item.remotepath) - - def report_HostGatewayReady(self, item): - self.to_rsync[item.host] = len(item.roots) - hostrepr = self._hostrepr(item.host) - self.out.write("%15s: gateway initialised (remote topdir: %s)\n"\ - % (hostrepr, item.host.gw_remotepath)) - - def report_HostRSyncRootReady(self, item): - self.to_rsync[item.host] -= 1 - if not self.to_rsync[item.host]: - self._host_ready(item) - - def _host_ready(self, item): - self.hosts_to_rsync -= 1 - hostrepr = self._hostrepr(item.host) - if self.hosts_to_rsync: - print "%15s: READY (still %d to go)" % (hostrepr, - self.hosts_to_rsync) - else: - print "%15s: READY" % hostrepr - - def report_TestStarted(self, item): - hostreprs = [self._hostrepr(host) for host in item.hosts] - txt = " Test started, hosts: %s " % ", ".join(hostreprs) - self.hosts_to_rsync = len(item.hosts) - self.out.sep("=", txt) - self.timestart = item.timestart - self.out.write("local top directory: %s\n" % item.topdir) - for i, root in py.builtin.enumerate(item.roots): - outof = "%d/%d" %(i+1, len(item.roots)) - self.out.write("local RSync root [%s]: %s\n" % - (outof, root)) - - def report_RsyncFinished(self, item): - self.timersync = item.time - - def report_ImmediateFailure(self, event): - self.repr_failure(event.item, event.outcome) - - def report_TestFinished(self, item): - self.out.line() - assert hasattr(self, 'timestart') - self.timeend = item.timeend - self.skips() - self.failures() - if hasattr(self, 'nodes'): # XXX: Testing - self.hangs() - self.summary() - return len(self.failed_tests_outcome) > 0 - - report_InterruptedExecution = report_TestFinished - report_CrashedExecution = report_TestFinished - - def hangs(self): - h = [] - if self.config.option.exitfirst: - # reporting hanging nodes in that case makes no sense at all - # but we should share some code in all reporters than - return - for node in self.nodes: - h += [(i, node.channel.gateway.sshaddress) for i in node.pending] - if h: - self.out.sep("=", " HANGING NODES ") - for i, node in h: - self.out.line("%s on %s" % (" ".join(i.listnames()), node)) - - def failures(self): - if self.failed_tests_outcome: - self.out.sep("=", " FAILURES ") - for event in self.failed_tests_outcome: - if isinstance(event, repevent.ReceivedItemOutcome): - host = self.gethost(event) - self.out.sep('_', "%s on %s" % - (" ".join(event.item.listnames()), host)) - if event.outcome.signal: - self.presenter.repr_item_info(event.item) - self.repr_signal(event.item, event.outcome) - else: - self.repr_failure(event.item, event.outcome) - else: - self.out.sep('_', " ".join(event.item.listnames())) - out = outcome.Outcome(excinfo=event.excinfo) - self.repr_failure(event.item, outcome.ReprOutcome(out.make_repr())) - - def gethost(self, event): - return event.host.hostname - - def repr_failure(self, item, outcome): - excinfo = outcome.excinfo - traceback = excinfo.traceback - if not traceback: - self.out.line("empty traceback from item %r" % (item,)) - return - - handler = getattr(self.presenter, 'repr_failure_tb%s' % self.config.option.tbstyle) - handler(item, excinfo, traceback, lambda: self.repr_out_err(outcome)) - - def repr_out_err(self, outcome): - if outcome.stdout: - self.out.sep('-', " Captured process stdout: ") - self.out.write(outcome.stdout) - if outcome.stderr: - self.out.sep('-', " Captured process stderr: ") - self.out.write(outcome.stderr) - - def repr_signal(self, item, outcome): - signal = outcome.signal - self.out.line("Received signal: %d" % outcome.signal) - self.repr_out_err(outcome) - - def _hostrepr(self, host): - return host.hostid - - def skips(self): - texts = {} - for event in self.skipped_tests_outcome: - colitem = event.item - if isinstance(event, repevent.ReceivedItemOutcome): - outcome = event.outcome - text = outcome.skipped - itemname = self.get_item_name(event, colitem) - elif isinstance(event, repevent.SkippedTryiter): - text = str(event.excinfo.value) - itemname = "/".join(colitem.listnames()) - if text not in texts: - texts[text] = [itemname] - else: - texts[text].append(itemname) - - if texts: - self.out.line() - self.out.sep('_', 'reasons for skipped tests') - for text, items in texts.items(): - for item in items: - self.out.line('Skipped in %s' % item) - self.out.line("reason: %s" % text) - - def summary(self): - def gather(dic): - total = 0 - for key, val in dic.iteritems(): - total += val - return total - - def create_str(name, count): - if count: - return ", %d %s" % (count, name) - return "" - - total_passed = gather(self.passed) - total_failed = gather(self.failed) - total_skipped = gather(self.skipped) - total = total_passed + total_failed + total_skipped - skipped_str = create_str("skipped", total_skipped) - failed_str = create_str("failed", total_failed) - self.print_summary(total, skipped_str, failed_str) - - def print_summary(self, total, skipped_str, failed_str): - self.out.sep("=", " %d test run%s%s in %.2fs (rsync: %.2f)" % - (total, skipped_str, failed_str, self.timeend - self.timestart, - self.timersync - self.timestart)) - - def report_SkippedTryiter(self, event): - #event.outcome.excinfo.source = - self.skipped_tests_outcome.append(event) - - def report_FailedTryiter(self, event): - pass - # XXX: right now we do not do anything with it - - def report_ReceivedItemOutcome(self, event): - host = event.host - hostrepr = self._hostrepr(host) - if event.outcome.passed: - self.passed[host] += 1 - sys.stdout.write("%15s: PASSED " % hostrepr) - elif event.outcome.skipped: - self.skipped_tests_outcome.append(event) - self.skipped[host] += 1 - sys.stdout.write("%15s: SKIPPED " % hostrepr) - else: - self.failed[host] += 1 - self.failed_tests_outcome.append(event) - sys.stdout.write("%15s: " % hostrepr) - ansi_print("FAILED", esc=(31,1), newline=False, file=sys.stdout) - sys.stdout.write(" ") - # we should have printed 20 characters to this point - itempath = ".".join(event.item.listnames()[1:-1]) - funname = event.item.listnames()[-1] - lgt = get_terminal_width() - 20 - # mark the function name, to be sure - to_display = len(itempath) + len(funname) + 1 - if to_display > lgt: - sys.stdout.write("..." + itempath[to_display-lgt+4:]) - else: - sys.stdout.write(itempath) - sys.stdout.write(" ") - ansi_print(funname, esc=32, file=sys.stdout) - - def report_Nodes(self, event): - self.nodes = event.nodes - -class RemoteReporter(AbstractReporter): - def get_item_name(self, event, colitem): - return event.host.hostname + ":" + \ - "/".join(colitem.listnames()) - - def report_FailedTryiter(self, event): - self.out.line("FAILED TO LOAD MODULE: %s\n" % "/".join(event.item.listnames())) - self.failed_tests_outcome.append(event) - # argh! bad hack, need to fix it - self.failed[self.hosts[0]] += 1 - - def report_SkippedTryiter(self, event): - self.out.line("Skipped (%s) %s\n" % (str(event.excinfo.value), "/". - join(event.item.listnames()))) - -class LocalReporter(AbstractReporter): - def get_item_name(self, event, colitem): - return "/".join(colitem.listnames()) - - def report_SkippedTryiter(self, event): - #self.show_item(event.item, False) - if isinstance(event.item, py.test.collect.Module): - self.out.write("- skipped (%s)" % event.excinfo.value) - else: - self.out.write("s") - self.skipped_tests_outcome.append(event) - - def report_FailedTryiter(self, event): - #self.show_item(event.item, False) - self.out.write("- FAILED TO LOAD MODULE") - self.failed_tests_outcome.append(event) - self.failed[self.hosts[0]] += 1 - - def report_ReceivedItemOutcome(self, event): - host = self.hosts[0] - if event.outcome.passed: - self.passed[host] += 1 - self.out.write(".") - elif event.outcome.skipped: - self.skipped_tests_outcome.append(event) - self.skipped[host] += 1 - self.out.write("s") - else: - self.failed[host] += 1 - self.failed_tests_outcome.append(event) - self.out.write("F") - - def report_ItemStart(self, event): - self.show_item(event.item) - - def show_item(self, item, count_elems = True): - if isinstance(item, py.test.collect.Module): - # XXX This is a terrible hack, I don't like it - # and will rewrite it at some point - #self.count = 0 - lgt = len(list(item._tryiter())) - #self.lgt = lgt - # print names relative to current workdir - name = "/".join(item.listnames()) - local = str(py.path.local()) - d = str(self.config.topdir) - if local.startswith(d): - local = local[len(d) + 1:] - if local and name.startswith(local): - name = name[len(local) + 1:] - self.out.write("\n%s[%d] " % (name, lgt)) - - def gethost(self, event): - return 'localhost' - - def hangs(self): - pass Modified: py/branch/session-cleanups/py/test/rsession/rest.py ============================================================================== --- py/branch/session-cleanups/py/test/rsession/rest.py (original) +++ py/branch/session-cleanups/py/test/rsession/rest.py Sat Aug 18 13:07:18 2007 @@ -5,8 +5,8 @@ import py import sys from StringIO import StringIO -from py.__.test.rsession.reporter import AbstractReporter -from py.__.test.rsession import repevent +from py.__.test.reporter import AbstractReporter +from py.__.test import repevent from py.__.rest.rst import * class RestReporter(AbstractReporter): Modified: py/branch/session-cleanups/py/test/rsession/rsession.py ============================================================================== --- py/branch/session-cleanups/py/test/rsession/rsession.py (original) +++ py/branch/session-cleanups/py/test/rsession/rsession.py Sat Aug 18 13:07:18 2007 @@ -8,12 +8,12 @@ import re import time -from py.__.test.rsession import repevent +from py.__.test import repevent from py.__.test.rsession.master import MasterNode, dispatch_loop, itemgen from py.__.test.rsession.hostmanage import HostInfo, HostManager from py.__.test.rsession.local import local_loop, plain_runner, apigen_runner,\ box_runner -from py.__.test.rsession.reporter import LocalReporter, RemoteReporter +from py.__.test.reporter import LocalReporter, RemoteReporter from py.__.test.session import Session from py.__.test.outcome import Skipped, Failed Modified: py/branch/session-cleanups/py/test/rsession/slave.py ============================================================================== --- py/branch/session-cleanups/py/test/rsession/slave.py (original) +++ py/branch/session-cleanups/py/test/rsession/slave.py Sat Aug 18 13:07:18 2007 @@ -4,7 +4,7 @@ import py from py.__.test.rsession.executor import RunExecutor, BoxExecutor, AsyncExecutor -from py.__.test.rsession.outcome import Outcome +from py.__.test.outcome import SerializableOutcome from py.__.test.outcome import Skipped import thread import os @@ -53,10 +53,10 @@ node = getnode(nextitem) res = node.run(nextitem) except Skipped, s: - send(Outcome(skipped=str(s)).make_repr()) + send(SerializableOutcome(skipped=str(s)).make_repr()) except: excinfo = py.code.ExceptionInfo() - send(Outcome(excinfo=excinfo, is_critical=True).make_repr()) + send(SerializableOutcome(excinfo=excinfo, is_critical=True).make_repr()) else: if not res[0] and not res[3] and config.option.exitfirst: # we're finished, but need to eat what we can Modified: py/branch/session-cleanups/py/test/rsession/testing/test_executor.py ============================================================================== --- py/branch/session-cleanups/py/test/rsession/testing/test_executor.py (original) +++ py/branch/session-cleanups/py/test/rsession/testing/test_executor.py Sat Aug 18 13:07:18 2007 @@ -4,7 +4,7 @@ from py.__.test.rsession.executor import RunExecutor, BoxExecutor,\ AsyncExecutor, ApigenExecutor -from py.__.test.rsession.outcome import ReprOutcome +from py.__.test.outcome import ReprOutcome from py.__.test.rsession.testing.basetest import BasicRsessionTest from py.__.test.outcome import Failed Modified: py/branch/session-cleanups/py/test/rsession/testing/test_hostmanage.py ============================================================================== --- py/branch/session-cleanups/py/test/rsession/testing/test_hostmanage.py (original) +++ py/branch/session-cleanups/py/test/rsession/testing/test_hostmanage.py Sat Aug 18 13:07:18 2007 @@ -5,7 +5,7 @@ import py from py.__.test.rsession.hostmanage import HostRSync, HostInfo, HostManager from py.__.test.rsession.hostmanage import sethomedir, gethomedir, getpath_relto_home -from py.__.test.rsession import repevent +from py.__.test import repevent class DirSetup: def setup_method(self, method): Modified: py/branch/session-cleanups/py/test/rsession/testing/test_lsession.py ============================================================================== --- py/branch/session-cleanups/py/test/rsession/testing/test_lsession.py (original) +++ py/branch/session-cleanups/py/test/rsession/testing/test_lsession.py Sat Aug 18 13:07:18 2007 @@ -4,7 +4,7 @@ import py from py.__.test.rsession.rsession import LSession -from py.__.test.rsession import repevent +from py.__.test import repevent from py.__.test.rsession.local import box_runner, plain_runner, apigen_runner def setup_module(mod): Modified: py/branch/session-cleanups/py/test/rsession/testing/test_master.py ============================================================================== --- py/branch/session-cleanups/py/test/rsession/testing/test_master.py (original) +++ py/branch/session-cleanups/py/test/rsession/testing/test_master.py Sat Aug 18 13:07:18 2007 @@ -11,8 +11,8 @@ from py.__.test.rsession.master import dispatch_loop, MasterNode from py.__.test.rsession.slave import setup_slave -from py.__.test.rsession.outcome import ReprOutcome, Outcome -from py.__.test.rsession import repevent +from py.__.test.outcome import ReprOutcome, SerializableOutcome +from py.__.test import repevent from py.__.test.rsession.hostmanage import HostInfo def setup_module(mod): @@ -64,8 +64,8 @@ mnode = MasterNode(ch, reportlist.append) mnode.send(Item("ok")) mnode.send(Item("notok")) - ch.callback(Outcome().make_repr()) - ch.callback(Outcome(excinfo=excinfo).make_repr()) + ch.callback(SerializableOutcome().make_repr()) + ch.callback(SerializableOutcome(excinfo=excinfo).make_repr()) assert len(reportlist) == 4 received = [i for i in reportlist if isinstance(i, repevent.ReceivedItemOutcome)] @@ -91,12 +91,12 @@ mnode = MasterNode(ch, reportlist.append) mnode.send(Item("ok")) mnode.send(Item("ok")) - ch.callback(Outcome().make_repr()) - ch.callback(Outcome().make_repr()) + ch.callback(SerializableOutcome().make_repr()) + ch.callback(SerializableOutcome().make_repr()) assert len(reportlist) == 4 def test_outcome_repr(): - out = ReprOutcome(Outcome(skipped=True).make_repr()) + out = ReprOutcome(SerializableOutcome(skipped=True).make_repr()) s = repr(out) assert s.lower().find("skip") != -1 Deleted: /py/branch/session-cleanups/py/test/rsession/testing/test_outcome.py ============================================================================== --- /py/branch/session-cleanups/py/test/rsession/testing/test_outcome.py Sat Aug 18 13:07:18 2007 +++ (empty file) @@ -1,50 +0,0 @@ - -import py -from py.__.test.rsession.outcome import Outcome, ReprOutcome, ExcInfoRepr - -import marshal - -def test_critical_debugging_flag(): - outcome = Outcome(is_critical=True) - r = ReprOutcome(outcome.make_repr()) - assert r.is_critical - -def f1(): - 1 - 2 - 3 - 4 - raise ValueError(42) - -def f2(): - f1() - -def f3(): - f2() - -def test_exception_info_repr(): - try: - f3() - except: - outcome = Outcome(excinfo=py.code.ExceptionInfo()) - - repr = outcome.make_excinfo_repr("long") - assert marshal.dumps(repr) - excinfo = ExcInfoRepr(repr) - - assert str(excinfo.typename) == "ValueError" - assert str(excinfo.value) == "42" - assert len(excinfo.traceback) == 4 - myfile = py.magic.autopath() - assert excinfo.traceback[3].path == myfile - assert excinfo.traceback[3].lineno == f1.func_code.co_firstlineno + 4 - assert excinfo.traceback[3].relline == 5 - assert excinfo.traceback[2].path == myfile - assert excinfo.traceback[2].lineno == f2.func_code.co_firstlineno - assert excinfo.traceback[2].relline == 1 - assert excinfo.traceback[1].path == myfile - assert excinfo.traceback[1].lineno == f3.func_code.co_firstlineno - assert excinfo.traceback[1].relline == 1 - -#def test_f3(): -# f3() Deleted: /py/branch/session-cleanups/py/test/rsession/testing/test_repevent.py ============================================================================== --- /py/branch/session-cleanups/py/test/rsession/testing/test_repevent.py Sat Aug 18 13:07:18 2007 +++ (empty file) @@ -1,36 +0,0 @@ -""" test reporting functionality. """ - -import py -from py.__.test.rsession import repevent - -def test_wrapcall_ok(): - l = [] - def ok(x): - return x+1 - i = repevent.wrapcall(l.append, ok, 1) - assert i == 2 - assert len(l) == 2 - assert isinstance(l[0], repevent.CallStart) - assert isinstance(l[1], repevent.CallFinish) - assert repr(l[0]) - assert repr(l[1]) - -def test_wrapcall_exception(): - l = [] - def fail(x): - raise ValueError - py.test.raises(ValueError, "repevent.wrapcall(l.append, fail, 1)") - assert len(l) == 2 - assert isinstance(l[0], repevent.CallStart) - assert isinstance(l[1], repevent.CallException) - -def test_reporter_methods_sanity(): - """ Checks if all the methods of reporter are sane - """ - from py.__.test.rsession.rsession import RemoteReporter - from py.__.test.rsession import repevent - - for method in dir(RemoteReporter): - - if method.startswith("report_") and method != "report_unknown": - assert method[len('report_'):] in repevent.__dict__ Deleted: /py/branch/session-cleanups/py/test/rsession/testing/test_reporter.py ============================================================================== --- /py/branch/session-cleanups/py/test/rsession/testing/test_reporter.py Sat Aug 18 13:07:18 2007 +++ (empty file) @@ -1,218 +0,0 @@ - -""" reporter tests. - -XXX there are a few disabled reporting tests because -they test for exact formatting as far as i can see. -I think it's rather better to directly invoke a -reporter and pass it some hand-prepared events to see -that running the reporter doesn't break shallowly. - -Otherwise, i suppose that some "visual" testing can usually be driven -manually by user-input. And when passing particular events -to a reporter it's also easier to check for one line -instead of having to know the order in which things are printed -etc. - - -""" - - -import py, os -from py.__.test.rsession.rsession import LocalReporter, AbstractSession,\ - RemoteReporter -from py.__.test.rsession import repevent -from py.__.test.rsession.outcome import ReprOutcome, Outcome -from py.__.test.rsession.hostmanage import HostInfo -from py.__.test.rsession.box import Box -from py.__.test.rsession.testing.basetest import BasicRsessionTest -from py.__.test.rsession.master import itemgen -import sys -from StringIO import StringIO - -class DummyGateway(object): - def __init__(self, host): - self.host = host - -class DummyChannel(object): - def __init__(self, host): - self.gateway = DummyGateway(host) - -class AbstractTestReporter(BasicRsessionTest): - def prepare_outcomes(self): - # possible outcomes - try: - 1/0 - except: - exc = py.code.ExceptionInfo() - - outcomes = [Outcome(()), - Outcome(skipped=True), - Outcome(excinfo=exc), - Outcome()] - - outcomes = [ReprOutcome(outcome.make_repr()) for outcome in outcomes] - outcomes[3].signal = 11 - outcomes[0].passed = False - - return outcomes - - def report_received_item_outcome(self): - item = self.getexample("pass") - outcomes = self.prepare_outcomes() - - def boxfun(config, item, outcomes): - hosts = [HostInfo("localhost")] - r = self.reporter(config, hosts) - ch = DummyChannel(hosts[0]) - for outcome in outcomes: - r.report(repevent.ReceivedItemOutcome(ch, item, outcome)) - - cap = py.io.StdCaptureFD() - boxfun(self.config, item, outcomes) - out, err = cap.reset() - assert not err - return out - - def _test_module(self): - funcitem = self.getexample("pass") - moditem = self.getmod() - outcomes = self.prepare_outcomes() - - def boxfun(config, item, funcitem, outcomes): - hosts = [HostInfo('localhost')] - r = self.reporter(config, hosts) - r.report(repevent.ItemStart(item)) - ch = DummyChannel(hosts[0]) - for outcome in outcomes: - r.report(repevent.ReceivedItemOutcome(ch, funcitem, outcome)) - - cap = py.io.StdCaptureFD() - boxfun(self.config, moditem, funcitem, outcomes) - out, err = cap.reset() - assert not err - return out - - def _test_full_module(self): - tmpdir = py.test.ensuretemp("repmod") - tmpdir.ensure("__init__.py") - tmpdir.ensure("test_one.py").write(py.code.Source(""" - def test_x(): - pass - """)) - tmpdir.ensure("test_two.py").write(py.code.Source(""" - import py - py.test.skip("reason") - """)) - tmpdir.ensure("test_three.py").write(py.code.Source(""" - sadsadsa - """)) - - def boxfun(): - config = py.test.config._reparse([str(tmpdir)]) - rootcol = py.test.collect.Directory(tmpdir) - hosts = [HostInfo('localhost')] - r = self.reporter(config, hosts) - list(itemgen([rootcol], r.report)) - - cap = py.io.StdCaptureFD() - boxfun() - out, err = cap.reset() - assert not err - return out - - def test_failed_to_load(self): - tmpdir = py.test.ensuretemp("failedtoload") - tmpdir.ensure("__init__.py") - tmpdir.ensure("test_three.py").write(py.code.Source(""" - sadsadsa - """)) - def boxfun(): - config = py.test.config._reparse([str(tmpdir)]) - rootcol = py.test.collect.Directory(tmpdir) - host = HostInfo('localhost') - r = self.reporter(config, [host]) - r.report(repevent.TestStarted([host], config.topdir, ["a"])) - r.report(repevent.RsyncFinished()) - list(itemgen([rootcol], r.report)) - r.report(repevent.TestFinished()) - return r - - cap = py.io.StdCaptureFD() - r = boxfun() - out, err = cap.reset() - assert not err - assert out.find("1 failed in") != -1 - assert out.find("NameError: name 'sadsadsa' is not defined") != -1 - - def _test_still_to_go(self): - tmpdir = py.test.ensuretemp("stilltogo") - tmpdir.ensure("__init__.py") - cap = py.io.StdCaptureFD() - config = py.test.config._reparse([str(tmpdir)]) - hosts = [HostInfo(i) for i in ["host1", "host2", "host3"]] - r = self.reporter(config, hosts) - r.report(repevent.TestStarted(hosts, config.topdir, ["a", "b", "c"])) - for host in hosts: - r.report(repevent.HostGatewayReady(host, ["a", "b", "c"])) - for host in hosts: - for root in ["a", "b", "c"]: - r.report(repevent.HostRSyncRootReady(host, root)) - out, err = cap.reset() - assert not err - expected1 = "Test started, hosts: host1[0], host2[0], host3[0]" - assert out.find(expected1) != -1 - for expected in py.code.Source(""" - host1[0]: READY (still 2 to go) - host2[0]: READY (still 1 to go) - host3[0]: READY - """).lines: - expected = expected.strip() - assert out.find(expected) != -1 - -class TestLocalReporter(AbstractTestReporter): - reporter = LocalReporter - - def test_report_received_item_outcome(self): - assert self.report_received_item_outcome() == 'FsF.' - - def test_module(self): - output = self._test_module() - assert output.find("test_one") != -1 - assert output.endswith("FsF."), output - - def test_full_module(self): - received = self._test_full_module() - expected_lst = ["repmod/test_one.py", "FAILED TO LOAD MODULE", - "skipped", "reason"] - for i in expected_lst: - assert received.find(i) != -1 - -class TestRemoteReporter(AbstractTestReporter): - reporter = RemoteReporter - - def test_still_to_go(self): - py.test.skip("XXX fix it, there is shadowed internal reporting problem") - self._test_still_to_go() - - def test_report_received_item_outcome(self): - val = self.report_received_item_outcome() - expected_lst = ["localhost", "FAILED", - "funcpass", "test_one", - "SKIPPED", - "PASSED"] - for expected in expected_lst: - assert val.find(expected) != -1 - - def test_module(self): - val = self._test_module() - expected_lst = ["localhost", "FAILED", - "funcpass", "test_one", - "SKIPPED", - "PASSED"] - for expected in expected_lst: - assert val.find(expected) != -1 - - def test_full_module(self): - val = self._test_full_module() - assert val.find("FAILED TO LOAD MODULE: repmod/test_three.py\n"\ - "\nSkipped ('reason') repmod/test_two.py") != -1 Modified: py/branch/session-cleanups/py/test/rsession/testing/test_rest.py ============================================================================== --- py/branch/session-cleanups/py/test/rsession/testing/test_rest.py (original) +++ py/branch/session-cleanups/py/test/rsession/testing/test_rest.py Sat Aug 18 13:07:18 2007 @@ -3,13 +3,13 @@ """ import py -from py.__.test.rsession.testing.test_reporter import AbstractTestReporter,\ +from py.__.test.testing.test_reporter import AbstractTestReporter,\ DummyChannel -from py.__.test.rsession import repevent +from py.__.test import repevent from py.__.test.rsession.rest import RestReporter, NoLinkWriter from py.__.rest.rst import * from py.__.test.rsession.hostmanage import HostInfo -from py.__.test.rsession.outcome import Outcome +from py.__.test.outcome import SerializableOutcome class Container(object): def __init__(self, **args): @@ -109,7 +109,7 @@ """ def test_ReceivedItemOutcome_PASSED(self): - outcome = Outcome() + outcome = SerializableOutcome() item = Container(listnames=lambda: ['', 'foo.py', 'bar', '()', 'baz']) event = repevent.ReceivedItemOutcome(channel=ch, outcome=outcome, item=item) reporter.report(event) @@ -117,7 +117,7 @@ 'foo.py/bar()/baz\n\n') def test_ReceivedItemOutcome_SKIPPED(self): - outcome = Outcome(skipped="reason") + outcome = SerializableOutcome(skipped="reason") item = Container(listnames=lambda: ['', 'foo.py', 'bar', '()', 'baz']) event = repevent.ReceivedItemOutcome(channel=ch, outcome=outcome, item=item) reporter.report(event) @@ -125,7 +125,7 @@ 'foo.py/bar()/baz\n\n') def test_ReceivedItemOutcome_FAILED(self): - outcome = Outcome(excinfo="xxx") + outcome = SerializableOutcome(excinfo="xxx") item = Container(listnames=lambda: ['', 'foo.py', 'bar', '()', 'baz']) event = repevent.ReceivedItemOutcome(channel=ch, outcome=outcome, item=item) reporter.report(event) @@ -153,7 +153,7 @@ ), ] ) - outcome = Outcome(excinfo=excinfo) + outcome = SerializableOutcome(excinfo=excinfo) outcome.stdout = '' outcome.stderr = '' parent = Container(parent=None, fspath=py.path.local('.')) Modified: py/branch/session-cleanups/py/test/rsession/testing/test_rsession.py ============================================================================== --- py/branch/session-cleanups/py/test/rsession/testing/test_rsession.py (original) +++ py/branch/session-cleanups/py/test/rsession/testing/test_rsession.py Sat Aug 18 13:07:18 2007 @@ -3,7 +3,7 @@ """ import py -from py.__.test.rsession import repevent +from py.__.test import repevent from py.__.test.rsession.rsession import RSession from py.__.test.rsession.hostmanage import HostManager, HostInfo from py.__.test.rsession.testing.basetest import BasicRsessionTest Modified: py/branch/session-cleanups/py/test/rsession/testing/test_slave.py ============================================================================== --- py/branch/session-cleanups/py/test/rsession/testing/test_slave.py (original) +++ py/branch/session-cleanups/py/test/rsession/testing/test_slave.py Sat Aug 18 13:07:18 2007 @@ -1,7 +1,7 @@ """ Testing the slave side node code (in a local way). """ from py.__.test.rsession.slave import SlaveNode, slave_main, setup -from py.__.test.rsession.outcome import ReprOutcome +from py.__.test.outcome import ReprOutcome import py, sys from py.__.test.rsession.testing.basetest import BasicRsessionTest Modified: py/branch/session-cleanups/py/test/rsession/web.py ============================================================================== --- py/branch/session-cleanups/py/test/rsession/web.py (original) +++ py/branch/session-cleanups/py/test/rsession/web.py Sat Aug 18 13:07:18 2007 @@ -15,7 +15,7 @@ import py from py.__.test.rsession.rsession import RSession -from py.__.test.rsession import repevent +from py.__.test import repevent from py.__.test import collect from py.__.test.rsession.webdata import json Copied: py/branch/session-cleanups/py/test/testing/test_outcome.py (from r45661, py/branch/session-cleanups/py/test/rsession/testing/test_outcome.py) ============================================================================== --- py/branch/session-cleanups/py/test/rsession/testing/test_outcome.py (original) +++ py/branch/session-cleanups/py/test/testing/test_outcome.py Sat Aug 18 13:07:18 2007 @@ -1,11 +1,11 @@ import py -from py.__.test.rsession.outcome import Outcome, ReprOutcome, ExcInfoRepr +from py.__.test.outcome import SerializableOutcome, ReprOutcome, ExcInfoRepr import marshal def test_critical_debugging_flag(): - outcome = Outcome(is_critical=True) + outcome = SerializableOutcome(is_critical=True) r = ReprOutcome(outcome.make_repr()) assert r.is_critical @@ -26,7 +26,7 @@ try: f3() except: - outcome = Outcome(excinfo=py.code.ExceptionInfo()) + outcome = SerializableOutcome(excinfo=py.code.ExceptionInfo()) repr = outcome.make_excinfo_repr("long") assert marshal.dumps(repr) Copied: py/branch/session-cleanups/py/test/testing/test_repevent.py (from r45661, py/branch/session-cleanups/py/test/rsession/testing/test_repevent.py) ============================================================================== --- py/branch/session-cleanups/py/test/rsession/testing/test_repevent.py (original) +++ py/branch/session-cleanups/py/test/testing/test_repevent.py Sat Aug 18 13:07:18 2007 @@ -1,7 +1,7 @@ """ test reporting functionality. """ import py -from py.__.test.rsession import repevent +from py.__.test import repevent def test_wrapcall_ok(): l = [] @@ -27,8 +27,8 @@ def test_reporter_methods_sanity(): """ Checks if all the methods of reporter are sane """ - from py.__.test.rsession.rsession import RemoteReporter - from py.__.test.rsession import repevent + from py.__.test.reporter import RemoteReporter + from py.__.test import repevent for method in dir(RemoteReporter): Copied: py/branch/session-cleanups/py/test/testing/test_reporter.py (from r45665, py/branch/session-cleanups/py/test/rsession/testing/test_reporter.py) ============================================================================== --- py/branch/session-cleanups/py/test/rsession/testing/test_reporter.py (original) +++ py/branch/session-cleanups/py/test/testing/test_reporter.py Sat Aug 18 13:07:18 2007 @@ -20,8 +20,8 @@ import py, os from py.__.test.rsession.rsession import LocalReporter, AbstractSession,\ RemoteReporter -from py.__.test.rsession import repevent -from py.__.test.rsession.outcome import ReprOutcome, Outcome +from py.__.test import repevent +from py.__.test.outcome import ReprOutcome, SerializableOutcome from py.__.test.rsession.hostmanage import HostInfo from py.__.test.rsession.box import Box from py.__.test.rsession.testing.basetest import BasicRsessionTest @@ -45,10 +45,10 @@ except: exc = py.code.ExceptionInfo() - outcomes = [Outcome(()), - Outcome(skipped=True), - Outcome(excinfo=exc), - Outcome()] + outcomes = [SerializableOutcome(()), + SerializableOutcome(skipped=True), + SerializableOutcome(excinfo=exc), + SerializableOutcome()] outcomes = [ReprOutcome(outcome.make_repr()) for outcome in outcomes] outcomes[3].signal = 11 From fijal at codespeak.net Sat Aug 18 14:59:19 2007 From: fijal at codespeak.net (fijal at codespeak.net) Date: Sat, 18 Aug 2007 14:59:19 +0200 (CEST) Subject: [py-svn] r45849 - in py/branch/session-cleanups/py/test: . rsession rsession/webdata Message-ID: <20070818125919.C7D398208@code0.codespeak.net> Author: fijal Date: Sat Aug 18 14:59:18 2007 New Revision: 45849 Modified: py/branch/session-cleanups/py/test/reporter.py py/branch/session-cleanups/py/test/rsession/rsession.py py/branch/session-cleanups/py/test/rsession/web.py py/branch/session-cleanups/py/test/rsession/webdata/source.js Log: A minor simplification how to finish off the web server (web stuff needs refactoring anyway) Modified: py/branch/session-cleanups/py/test/reporter.py ============================================================================== --- py/branch/session-cleanups/py/test/reporter.py (original) +++ py/branch/session-cleanups/py/test/reporter.py Sat Aug 18 14:59:18 2007 @@ -14,7 +14,7 @@ from py.__.test.representation import Presenter import sys -import thread +import thread class AbstractReporter(object): def __init__(self, config, hosts): Modified: py/branch/session-cleanups/py/test/rsession/rsession.py ============================================================================== --- py/branch/session-cleanups/py/test/rsession/rsession.py (original) +++ py/branch/session-cleanups/py/test/rsession/rsession.py Sat Aug 18 14:59:18 2007 @@ -64,18 +64,9 @@ else: reporter_instance = reporter_class(self.config, hosts) reporter = reporter_instance.report - else: - startserverflag = False - return reporter, startserverflag + return reporter - def kill_server(self, startserverflag): - """ Kill web server - """ - if startserverflag: - from py.__.test.rsession.web import kill_server - kill_server() - def wrap_reporter(self, reporter): """ We wrap reporter around, which makes it possible to us to track existance of failures @@ -122,7 +113,7 @@ args = self.config.args hm = HostManager(self.config) - reporter, startserverflag = self.init_reporter(reporter, + reporter = self.init_reporter(reporter, hm.hosts, RemoteReporter) reporter, checkfun = self.wrap_reporter(reporter) @@ -147,15 +138,12 @@ exitfirst=self.config.option.exitfirst) reporter(repevent.Nodes(nodes)) retval = reporter(repevent.TestFinished()) - self.kill_server(startserverflag) return retval except (KeyboardInterrupt, SystemExit): reporter(repevent.InterruptedExecution()) - self.kill_server(startserverflag) raise except: reporter(repevent.CrashedExecution()) - self.kill_server(startserverflag) raise def dispatch_tests(self, nodes, reporter, checkfun): @@ -176,7 +164,7 @@ if not self.config.option.nomagic: py.magic.invoke(assertion=1) - reporter, startserverflag = self.init_reporter(reporter, + reporter = self.init_reporter(reporter, hosts, LocalReporter, args[0]) reporter, checkfun = self.wrap_reporter(reporter) @@ -193,7 +181,6 @@ local_loop(self, reporter, itemgenerator, checkfun, self.config, runner=runner) retval = reporter(repevent.TestFinished()) - self.kill_server(startserverflag) if not self.config.option.nomagic: py.magic.revoke(assertion=1) Modified: py/branch/session-cleanups/py/test/rsession/web.py ============================================================================== --- py/branch/session-cleanups/py/test/rsession/web.py (original) +++ py/branch/session-cleanups/py/test/rsession/web.py Sat Aug 18 14:59:18 2007 @@ -305,9 +305,8 @@ if not self.to_rsync[item.host]: self._host_ready(item) - def report_TestStarted(self, event): - # XXX: It overrides out self.hosts + # XXX: It overrides our self.hosts self.hosts = {} self.ready_hosts = {} for host in event.hosts: @@ -315,6 +314,13 @@ self.ready_hosts[host] = False self.start_event.set() self.pending_events.put(event) + + def report_TestFinished(self, event): + self.pending_events.put(event) + kill_server() + + report_InterruptedExecution = report_TestFinished + report_CrashedExecution = report_TestFinished def report(self, what): repfun = getattr(self, "report_" + what.__class__.__name__, @@ -330,13 +336,6 @@ print str(i)[2:-1] print excinfo -## try: -## self.wait_flag.acquire() -## self.pending_events.insert(0, event) -## self.wait_flag.notify() -## finally: -## self.wait_flag.release() - exported_methods = ExportedMethods() class TestHandler(BaseHTTPRequestHandler): Modified: py/branch/session-cleanups/py/test/rsession/webdata/source.js ============================================================================== Binary files. No diff available. From fijal at codespeak.net Sat Aug 18 15:51:48 2007 From: fijal at codespeak.net (fijal at codespeak.net) Date: Sat, 18 Aug 2007 15:51:48 +0200 (CEST) Subject: [py-svn] r45850 - in py/branch/session-cleanups/py/test/rsession: . webdata Message-ID: <20070818135148.D70E88291@code0.codespeak.net> Author: fijal Date: Sat Aug 18 15:51:47 2007 New Revision: 45850 Modified: py/branch/session-cleanups/py/test/rsession/master.py py/branch/session-cleanups/py/test/rsession/web.py py/branch/session-cleanups/py/test/rsession/webdata/source.js Log: Oops, checked in "or 1" somewhere Don't eat GeneratorExit Modified: py/branch/session-cleanups/py/test/rsession/master.py ============================================================================== --- py/branch/session-cleanups/py/test/rsession/master.py (original) +++ py/branch/session-cleanups/py/test/rsession/master.py Sat Aug 18 15:51:47 2007 @@ -56,7 +56,7 @@ for x in itemgen([next.join(x) for x in next.run()], reporter, keyword): yield x - except (KeyboardInterrupt, SystemExit): + except (KeyboardInterrupt, SystemExit, GeneratorExit): raise except: excinfo = py.code.ExceptionInfo() Modified: py/branch/session-cleanups/py/test/rsession/web.py ============================================================================== --- py/branch/session-cleanups/py/test/rsession/web.py (original) +++ py/branch/session-cleanups/py/test/rsession/web.py Sat Aug 18 15:51:47 2007 @@ -399,7 +399,7 @@ js_name = py.path.local(__file__).dirpath("webdata").join("source.js") web_name = py.path.local(__file__).dirpath().join("webjs.py") if IMPORTED_PYPY and web_name.mtime() > js_name.mtime() or \ - (not js_name.check()) or 1: + (not js_name.check()): from py.__.test.rsession import webjs javascript_source = rpython2javascript(webjs, Modified: py/branch/session-cleanups/py/test/rsession/webdata/source.js ============================================================================== Binary files. No diff available. From fijal at codespeak.net Sun Aug 19 16:13:39 2007 From: fijal at codespeak.net (fijal at codespeak.net) Date: Sun, 19 Aug 2007 16:13:39 +0200 (CEST) Subject: [py-svn] r45866 - in py/branch/session-cleanups/py/test: . rsession Message-ID: <20070819141339.23302816E@code0.codespeak.net> Author: fijal Date: Sun Aug 19 16:13:37 2007 New Revision: 45866 Modified: py/branch/session-cleanups/py/test/reporter.py py/branch/session-cleanups/py/test/rsession/rsession.py py/branch/session-cleanups/py/test/rsession/web.py Log: Move web server initialization to web.py from rsession.py (where it belongs) Modified: py/branch/session-cleanups/py/test/reporter.py ============================================================================== --- py/branch/session-cleanups/py/test/reporter.py (original) +++ py/branch/session-cleanups/py/test/reporter.py Sun Aug 19 16:13:37 2007 @@ -14,7 +14,6 @@ from py.__.test.representation import Presenter import sys -import thread class AbstractReporter(object): def __init__(self, config, hosts): Modified: py/branch/session-cleanups/py/test/rsession/rsession.py ============================================================================== --- py/branch/session-cleanups/py/test/rsession/rsession.py (original) +++ py/branch/session-cleanups/py/test/rsession/rsession.py Sun Aug 19 16:13:37 2007 @@ -40,21 +40,8 @@ restflag = self.config.option.restreport if startserverflag and reporter is None: - from py.__.test.rsession.web import start_server, exported_methods - if self.config.option.runbrowser: - from socket import INADDR_ANY - port = INADDR_ANY # pick a random port when starting browser - else: - port = 8000 # stick to a fixed port otherwise - - reporter = exported_methods.report - httpd = start_server(server_address = ('', port)) - port = httpd.server_port - if self.config.option.runbrowser: - import webbrowser, thread - # webbrowser.open() may block until the browser finishes or not - url = "http://localhost:%d" % (port,) - thread.start_new_thread(webbrowser.open, (url,)) + from py.__.test.rsession.web import start_server_from_config + reporter = start_server_from_config(self.config) elif reporter is None: if restflag: from py.__.test.rsession.rest import RestReporter Modified: py/branch/session-cleanups/py/test/rsession/web.py ============================================================================== --- py/branch/session-cleanups/py/test/rsession/web.py (original) +++ py/branch/session-cleanups/py/test/rsession/web.py Sun Aug 19 16:13:37 2007 @@ -417,6 +417,22 @@ self.end_headers() self.wfile.write(data) +def start_server_from_config(config): + if config.option.runbrowser: + port = socket.INADDR_ANY + else: + port = 8000 + + httpd = start_server(server_address = ('', port)) + port = httpd.server_port + if config.option.runbrowser: + import webbrowser, thread + # webbrowser.open() may block until the browser finishes or not + url = "http://localhost:%d" % (port,) + thread.start_new_thread(webbrowser.open, (url,)) + + return exported_methods.report + def start_server(server_address = ('', 8000), handler=TestHandler, start_new=True): httpd = HTTPServer(server_address, handler) From fijal at codespeak.net Sun Aug 19 16:23:52 2007 From: fijal at codespeak.net (fijal at codespeak.net) Date: Sun, 19 Aug 2007 16:23:52 +0200 (CEST) Subject: [py-svn] r45867 - in py/branch/session-cleanups/py/test: rsession rsession/testing testing Message-ID: <20070819142352.450F0816E@code0.codespeak.net> Author: fijal Date: Sun Aug 19 16:23:51 2007 New Revision: 45867 Modified: py/branch/session-cleanups/py/test/rsession/rsession.py py/branch/session-cleanups/py/test/rsession/testing/test_rest.py py/branch/session-cleanups/py/test/testing/test_reporter.py Log: Some simplification and avoiding some test skips. Modified: py/branch/session-cleanups/py/test/rsession/rsession.py ============================================================================== --- py/branch/session-cleanups/py/test/rsession/rsession.py (original) +++ py/branch/session-cleanups/py/test/rsession/rsession.py Sun Aug 19 16:23:51 2007 @@ -31,7 +31,7 @@ option.boxed = True super(AbstractSession, self).fixoptions() - def init_reporter(self, reporter, hosts, reporter_class, arg=""): + def init_reporter(self, reporter, hosts, reporter_class): """ This initialises so called `reporter` class, which will handle all event presenting to user. Does not get called if main received custom reporter @@ -46,10 +46,7 @@ if restflag: from py.__.test.rsession.rest import RestReporter reporter_class = RestReporter - if arg: - reporter_instance = reporter_class(self.config, hosts) - else: - reporter_instance = reporter_class(self.config, hosts) + reporter_instance = reporter_class(self.config, hosts) reporter = reporter_instance.report return reporter @@ -97,8 +94,6 @@ def main(self, reporter=None): """ main loop for running tests. """ - args = self.config.args - hm = HostManager(self.config) reporter = self.init_reporter(reporter, hm.hosts, RemoteReporter) @@ -144,15 +139,13 @@ """ def main(self, reporter=None, runner=None): # check out if used options makes any sense - args = self.config.args - hm = HostManager(self.config, hosts=[HostInfo('localhost')]) hosts = hm.hosts if not self.config.option.nomagic: py.magic.invoke(assertion=1) reporter = self.init_reporter(reporter, - hosts, LocalReporter, args[0]) + hosts, LocalReporter) reporter, checkfun = self.wrap_reporter(reporter) reporter(repevent.TestStarted(hosts, self.config.topdir, [])) Modified: py/branch/session-cleanups/py/test/rsession/testing/test_rest.py ============================================================================== --- py/branch/session-cleanups/py/test/rsession/testing/test_rest.py (original) +++ py/branch/session-cleanups/py/test/rsession/testing/test_rest.py Sun Aug 19 16:23:51 2007 @@ -336,18 +336,15 @@ py.test.skip("Not implemented") def test_report_received_item_outcome(self): - py.test.skip("Relying on exact output matching") val = self.report_received_item_outcome() - expected = """\ -* localhost\: **FAILED** `traceback0`_\n py/test/rsession/testing/test\_slave.py/funcpass + expected_list = [ + "**FAILED**", + "**SKIPPED**", + "**PASSED**", + "* localhost\:", + "`traceback0`_ test\_one.py/funcpass", + "test\_one.py/funcpass"] + for expected in expected_list: + assert val.find(expected) != -1 -* localhost\: **SKIPPED** py/test/rsession/testing/test\_slave.py/funcpass - -* localhost\: **FAILED** `traceback1`_\n py/test/rsession/testing/test\_slave.py/funcpass - -* localhost\: **PASSED** py/test/rsession/testing/test\_slave.py/funcpass - -""" - print val - assert val == expected Modified: py/branch/session-cleanups/py/test/testing/test_reporter.py ============================================================================== --- py/branch/session-cleanups/py/test/testing/test_reporter.py (original) +++ py/branch/session-cleanups/py/test/testing/test_reporter.py Sun Aug 19 16:23:51 2007 @@ -150,6 +150,8 @@ cap = py.io.StdCaptureFD() config = py.test.config._reparse([str(tmpdir)]) hosts = [HostInfo(i) for i in ["host1", "host2", "host3"]] + for host in hosts: + host.gw_remotepath = '' r = self.reporter(config, hosts) r.report(repevent.TestStarted(hosts, config.topdir, ["a", "b", "c"])) for host in hosts: @@ -191,7 +193,6 @@ reporter = RemoteReporter def test_still_to_go(self): - py.test.skip("XXX fix it, there is shadowed internal reporting problem") self._test_still_to_go() def test_report_received_item_outcome(self): From fijal at codespeak.net Sun Aug 19 16:57:12 2007 From: fijal at codespeak.net (fijal at codespeak.net) Date: Sun, 19 Aug 2007 16:57:12 +0200 (CEST) Subject: [py-svn] r45868 - in py/branch/session-cleanups/py/test: . rsession testing Message-ID: <20070819145712.E047581BD@code0.codespeak.net> Author: fijal Date: Sun Aug 19 16:57:12 2007 New Revision: 45868 Modified: py/branch/session-cleanups/py/test/reporter.py py/branch/session-cleanups/py/test/rsession/rsession.py py/branch/session-cleanups/py/test/rsession/web.py py/branch/session-cleanups/py/test/testing/test_reporter.py Log: shuffle stuff around, so no the choice of reporter is done independently of session (based solely on config) Modified: py/branch/session-cleanups/py/test/reporter.py ============================================================================== --- py/branch/session-cleanups/py/test/reporter.py (original) +++ py/branch/session-cleanups/py/test/reporter.py Sun Aug 19 16:57:12 2007 @@ -15,6 +15,20 @@ import sys +def choose_reporter(config): + option = config.option + if option.startserver or option.runbrowser: + from py.__.test.rsession.web import WebReporter + return WebReporter + if option.restreport: + from py.__.test.rsession.rest import RestReporter + return RestReporter + else: + if option.dist: + return RemoteReporter + else: + return LocalReporter + class AbstractReporter(object): def __init__(self, config, hosts): self.config = config Modified: py/branch/session-cleanups/py/test/rsession/rsession.py ============================================================================== --- py/branch/session-cleanups/py/test/rsession/rsession.py (original) +++ py/branch/session-cleanups/py/test/rsession/rsession.py Sun Aug 19 16:57:12 2007 @@ -30,30 +30,11 @@ if self.config.getvalue("dist_boxed"): option.boxed = True super(AbstractSession, self).fixoptions() - - def init_reporter(self, reporter, hosts, reporter_class): - """ This initialises so called `reporter` class, which will - handle all event presenting to user. Does not get called - if main received custom reporter - """ - startserverflag = self.config.option.startserver - restflag = self.config.option.restreport - - if startserverflag and reporter is None: - from py.__.test.rsession.web import start_server_from_config - reporter = start_server_from_config(self.config) - elif reporter is None: - if restflag: - from py.__.test.rsession.rest import RestReporter - reporter_class = RestReporter - reporter_instance = reporter_class(self.config, hosts) - reporter = reporter_instance.report - - return reporter def wrap_reporter(self, reporter): """ We wrap reporter around, which makes it possible to us to track existance of failures + XXX kill this bastard """ self.was_failure = False def new_reporter(event): @@ -94,9 +75,10 @@ def main(self, reporter=None): """ main loop for running tests. """ - hm = HostManager(self.config) - reporter = self.init_reporter(reporter, - hm.hosts, RemoteReporter) + config = self.config + hm = HostManager(config) + if reporter is None: + reporter = choose_reporter(config)(config, hm.hosts).report reporter, checkfun = self.wrap_reporter(reporter) reporter(repevent.TestStarted(hm.hosts, self.config.topdir, @@ -139,13 +121,13 @@ """ def main(self, reporter=None, runner=None): # check out if used options makes any sense - hm = HostManager(self.config, hosts=[HostInfo('localhost')]) + config = self.config + hm = HostManager(config, hosts=[HostInfo('localhost')]) hosts = hm.hosts if not self.config.option.nomagic: py.magic.invoke(assertion=1) - - reporter = self.init_reporter(reporter, - hosts, LocalReporter) + if reporter is None: + reporter = choose_reporter(config)(config, hosts).report reporter, checkfun = self.wrap_reporter(reporter) reporter(repevent.TestStarted(hosts, self.config.topdir, [])) Modified: py/branch/session-cleanups/py/test/rsession/web.py ============================================================================== --- py/branch/session-cleanups/py/test/rsession/web.py (original) +++ py/branch/session-cleanups/py/test/rsession/web.py Sun Aug 19 16:57:12 2007 @@ -417,6 +417,17 @@ self.end_headers() self.wfile.write(data) +class WebReporter(object): + """ A simple wrapper, this file needs ton of refactoring + anyway, so this is just to satisfy things below + (and start to create saner interface as well) + """ + def __init__(self, config, hosts): + start_server_from_config(config) + + # rebind + report = exported_methods.report + def start_server_from_config(config): if config.option.runbrowser: port = socket.INADDR_ANY Modified: py/branch/session-cleanups/py/test/testing/test_reporter.py ============================================================================== --- py/branch/session-cleanups/py/test/testing/test_reporter.py (original) +++ py/branch/session-cleanups/py/test/testing/test_reporter.py Sun Aug 19 16:57:12 2007 @@ -18,8 +18,8 @@ import py, os -from py.__.test.rsession.rsession import LocalReporter, AbstractSession,\ - RemoteReporter +from py.__.test.rsession.rsession import AbstractSession +from py.__.test.reporter import RemoteReporter, LocalReporter, choose_reporter from py.__.test import repevent from py.__.test.outcome import ReprOutcome, SerializableOutcome from py.__.test.rsession.hostmanage import HostInfo @@ -217,3 +217,17 @@ val = self._test_full_module() assert val.find("FAILED TO LOAD MODULE: repmod/test_three.py\n"\ "\nSkipped ('reason') repmod/test_two.py") != -1 + +def test_reporter_choice(): + from py.__.test.rsession.web import WebReporter + from py.__.test.rsession.rest import RestReporter + choices = [ + (['-d'], RemoteReporter), + (['-d', '--rest'], RestReporter), + ([], LocalReporter), + (['-w'], WebReporter), + (['-r'], WebReporter)] + for opts, reporter in choices: + config = py.test.config._reparse(['xxx'] + opts) + assert choose_reporter(config) is reporter + From fijal at codespeak.net Sun Aug 19 17:27:00 2007 From: fijal at codespeak.net (fijal at codespeak.net) Date: Sun, 19 Aug 2007 17:27:00 +0200 (CEST) Subject: [py-svn] r45869 - in py/branch/session-cleanups/py/test: . rsession rsession/testing testing Message-ID: <20070819152700.B0E728180@code0.codespeak.net> Author: fijal Date: Sun Aug 19 17:26:59 2007 New Revision: 45869 Modified: py/branch/session-cleanups/py/test/repevent.py py/branch/session-cleanups/py/test/reporter.py py/branch/session-cleanups/py/test/rsession/rsession.py py/branch/session-cleanups/py/test/rsession/testing/test_rsession.py py/branch/session-cleanups/py/test/rsession/web.py py/branch/session-cleanups/py/test/testing/test_repevent.py Log: Kill another hack. This simplifies a bit what's going on in a reporter. Modified: py/branch/session-cleanups/py/test/repevent.py ============================================================================== --- py/branch/session-cleanups/py/test/repevent.py (original) +++ py/branch/session-cleanups/py/test/repevent.py Sun Aug 19 17:26:59 2007 @@ -38,6 +38,9 @@ for key, value in self.__dict__.items()] return "<%s %s>" %(self.__class__.__name__, " ".join(l),) + def is_failure(self): + return False + class SendItem(ReportEvent): def __init__(self, channel, item): self.item = item @@ -53,6 +56,9 @@ self.item = item self.outcome = outcome + def is_failure(self): + return not (self.outcome.passed or self.outcome.skipped) + class CallEvent(ReportEvent): def __init__(self, func, args, kwargs): self.func = func @@ -115,6 +121,9 @@ self.excinfo = excinfo self.item = item + def is_failure(self): + return True + class ItemStart(ReportEvent): """ This class shows most of the start stuff, like directory, module, class can be used for containers Modified: py/branch/session-cleanups/py/test/reporter.py ============================================================================== --- py/branch/session-cleanups/py/test/reporter.py (original) +++ py/branch/session-cleanups/py/test/reporter.py Sun Aug 19 17:26:59 2007 @@ -29,6 +29,25 @@ else: return LocalReporter +class TestReporter(object): + """ Simple test reporter which tracks failures + and also calls arbitrary provided function, + useful for tests + """ + def __init__(self, reportfun): + self.reportfun = reportfun + self.flag = False + + def report(self, event): + if event.is_failure(): + self.flag = True + self.reportfun(event) + + __call__ = report + + def was_failure(self): + return self.flag + class AbstractReporter(object): def __init__(self, config, hosts): self.config = config @@ -61,6 +80,8 @@ # XXX reenable test before removing below line and # run it with raise #raise + + __call__ = report def report_unknown(self, what): if self.config.option.verbose: @@ -289,6 +310,9 @@ def report_Nodes(self, event): self.nodes = event.nodes + def was_failure(self): + return len(self.failed) > 0 + class RemoteReporter(AbstractReporter): def get_item_name(self, event, colitem): return event.host.hostname + ":" + \ Modified: py/branch/session-cleanups/py/test/rsession/rsession.py ============================================================================== --- py/branch/session-cleanups/py/test/rsession/rsession.py (original) +++ py/branch/session-cleanups/py/test/rsession/rsession.py Sun Aug 19 17:26:59 2007 @@ -13,7 +13,7 @@ from py.__.test.rsession.hostmanage import HostInfo, HostManager from py.__.test.rsession.local import local_loop, plain_runner, apigen_runner,\ box_runner -from py.__.test.reporter import LocalReporter, RemoteReporter +from py.__.test.reporter import LocalReporter, RemoteReporter, TestReporter from py.__.test.session import Session from py.__.test.outcome import Skipped, Failed @@ -30,25 +30,16 @@ if self.config.getvalue("dist_boxed"): option.boxed = True super(AbstractSession, self).fixoptions() - - def wrap_reporter(self, reporter): - """ We wrap reporter around, which makes it possible to us to track - existance of failures - XXX kill this bastard - """ - self.was_failure = False - def new_reporter(event): - if isinstance(event, repevent.ReceivedItemOutcome) and \ - not event.outcome.passed and \ - not event.outcome.skipped: - self.was_failure = True - return reporter(event) - checkfun = lambda : self.config.option.exitfirst and \ - self.was_failure - # for tests - self.checkfun = checkfun - return new_reporter, checkfun + def init_reporter(self, reporter, config, hosts): + if reporter is None: + reporter = choose_reporter(config)(config, hm.hosts) + else: + reporter = TestReporter(reporter) + checkfun = lambda : self.config.option.exitfirst and \ + reporter.was_failure() + return reporter, checkfun + class RSession(AbstractSession): """ Remote version of session """ @@ -77,9 +68,7 @@ """ main loop for running tests. """ config = self.config hm = HostManager(config) - if reporter is None: - reporter = choose_reporter(config)(config, hm.hosts).report - reporter, checkfun = self.wrap_reporter(reporter) + reporter, checkfun = self.init_reporter(reporter, config, hm.hosts) reporter(repevent.TestStarted(hm.hosts, self.config.topdir, hm.roots)) @@ -126,9 +115,8 @@ hosts = hm.hosts if not self.config.option.nomagic: py.magic.invoke(assertion=1) - if reporter is None: - reporter = choose_reporter(config)(config, hosts).report - reporter, checkfun = self.wrap_reporter(reporter) + + reporter, checkfun = self.init_reporter(reporter, config, hosts) reporter(repevent.TestStarted(hosts, self.config.topdir, [])) colitems = self.config.getcolitems() Modified: py/branch/session-cleanups/py/test/rsession/testing/test_rsession.py ============================================================================== --- py/branch/session-cleanups/py/test/rsession/testing/test_rsession.py (original) +++ py/branch/session-cleanups/py/test/rsession/testing/test_rsession.py Sun Aug 19 17:26:59 2007 @@ -40,7 +40,6 @@ testevents = [x for x in allevents if isinstance(x, repevent.ReceivedItemOutcome)] assert len(testevents) == 3 - assert rsession.checkfun() def test_distribution_rsync_roots_example(self): destdir = py.test.ensuretemp("example_dist_destdir") Modified: py/branch/session-cleanups/py/test/rsession/web.py ============================================================================== --- py/branch/session-cleanups/py/test/rsession/web.py (original) +++ py/branch/session-cleanups/py/test/rsession/web.py Sun Aug 19 17:26:59 2007 @@ -427,6 +427,7 @@ # rebind report = exported_methods.report + __call__ = report def start_server_from_config(config): if config.option.runbrowser: Modified: py/branch/session-cleanups/py/test/testing/test_repevent.py ============================================================================== --- py/branch/session-cleanups/py/test/testing/test_repevent.py (original) +++ py/branch/session-cleanups/py/test/testing/test_repevent.py Sun Aug 19 17:26:59 2007 @@ -28,9 +28,26 @@ """ Checks if all the methods of reporter are sane """ from py.__.test.reporter import RemoteReporter - from py.__.test import repevent for method in dir(RemoteReporter): if method.startswith("report_") and method != "report_unknown": assert method[len('report_'):] in repevent.__dict__ + +def test_repevent_failures(): + from py.__.test.outcome import SerializableOutcome, ReprOutcome + + assert not repevent.ReportEvent().is_failure() + assert not repevent.CallEvent(None, None, None).is_failure() + assert repevent.FailedTryiter(None, None).is_failure() + out = ReprOutcome(SerializableOutcome().make_repr()) + assert not repevent.ReceivedItemOutcome(None, None, out).is_failure() + out = ReprOutcome(SerializableOutcome(skipped=True).make_repr()) + assert not repevent.ReceivedItemOutcome(None, None, out).is_failure() + try: + 1/0 + except: + exc = py.code.ExceptionInfo() + out = ReprOutcome(SerializableOutcome(excinfo=exc).make_repr()) + assert repevent.ReceivedItemOutcome(None, None, out).is_failure() + From ac at codespeak.net Tue Aug 21 20:39:22 2007 From: ac at codespeak.net (ac at codespeak.net) Date: Tue, 21 Aug 2007 20:39:22 +0200 (CEST) Subject: [py-svn] r45901 - py/trunk/py/io Message-ID: <20070821183922.91C698168@code0.codespeak.net> Author: ac Date: Tue Aug 21 20:39:21 2007 New Revision: 45901 Modified: py/trunk/py/io/fdcapture.py Log: Do not use os.tmpfile() as it will fail on Windows unless You are Administrator. Modified: py/trunk/py/io/fdcapture.py ============================================================================== --- py/trunk/py/io/fdcapture.py (original) +++ py/trunk/py/io/fdcapture.py Tue Aug 21 20:39:21 2007 @@ -2,6 +2,7 @@ import os import sys import py +import tempfile class FDCapture: """ Capture IO to/from a given os-level filedescriptor. """ @@ -41,7 +42,7 @@ def maketmpfile(self): """ create a temporary file """ - f = os.tmpfile() + f = tempfile.TemporaryFile() newf = py.io.dupfile(f) f.close() return newf @@ -49,7 +50,7 @@ def writeorg(self, str): """ write a string to the original file descriptor """ - tempfp = os.tmpfile() + tempfp = tempfile.TemporaryFile() try: os.dup2(self._savefd, tempfp.fileno()) tempfp.write(str) From fijal at codespeak.net Wed Aug 22 14:43:54 2007 From: fijal at codespeak.net (fijal at codespeak.net) Date: Wed, 22 Aug 2007 14:43:54 +0200 (CEST) Subject: [py-svn] r45907 - py/trunk/py/test/rsession Message-ID: <20070822124354.B493E813F@code0.codespeak.net> Author: fijal Date: Wed Aug 22 14:43:50 2007 New Revision: 45907 Modified: py/trunk/py/test/rsession/reporter.py Log: Fix number Modified: py/trunk/py/test/rsession/reporter.py ============================================================================== --- py/trunk/py/test/rsession/reporter.py (original) +++ py/trunk/py/test/rsession/reporter.py Wed Aug 22 14:43:50 2007 @@ -254,13 +254,13 @@ else: self.failed[host] += 1 self.failed_tests_outcome.append(event) - sys.stdout.write("%15s: " % hostrepr) + sys.stdout.write("%15s: " % hostrepr) ansi_print("FAILED", esc=(31,1), newline=False, file=sys.stdout) sys.stdout.write(" ") # we should have printed 20 characters to this point itempath = ".".join(event.item.listnames()[1:-1]) funname = event.item.listnames()[-1] - lgt = get_terminal_width() - 20 + lgt = get_terminal_width() - 25 # mark the function name, to be sure to_display = len(itempath) + len(funname) + 1 if to_display > lgt: From guido at codespeak.net Sun Aug 26 14:31:23 2007 From: guido at codespeak.net (guido at codespeak.net) Date: Sun, 26 Aug 2007 14:31:23 +0200 (CEST) Subject: [py-svn] r45994 - in py/trunk/py/path/svn: . testing Message-ID: <20070826123123.5F6098134@code0.codespeak.net> Author: guido Date: Sun Aug 26 14:31:20 2007 New Revision: 45994 Modified: py/trunk/py/path/svn/testing/test_wccommand.py py/trunk/py/path/svn/wccommand.py Log: Adding support for locking and non-recursive commits (a somewhat obscure feature, but was easy to implement) to svnwc. Not tested on SVN 1.2 (anyone?). Modified: py/trunk/py/path/svn/testing/test_wccommand.py ============================================================================== --- py/trunk/py/path/svn/testing/test_wccommand.py (original) +++ py/trunk/py/path/svn/testing/test_wccommand.py Sun Aug 26 14:31:20 2007 @@ -226,6 +226,50 @@ p.remove(rec=1) f.remove() + def test_lock_unlock(self): + root = self.root + somefile = root.join('somefile') + somefile.ensure(file=True) + # not yet added to repo + py.test.raises(py.process.cmdexec.Error, 'somefile.lock()') + somefile.write('foo') + somefile.commit('test') + assert somefile.check(versioned=True) + somefile.lock() + try: + locked = root.status().locked + assert len(locked) == 1 + assert str(locked[0]) == str(somefile) + #assert somefile.locked() + py.test.raises(Exception, 'somefile.lock()') + finally: + somefile.unlock() + #assert not somefile.locked() + locked = root.status().locked + assert locked == [] + py.test.raises(Exception, 'somefile,unlock()') + somefile.remove() + + def test_commit_nonrecursive(self): + root = self.root + somedir = root.join('sampledir') + somefile = somedir.join('otherfile') + somefile.write('foo') + somedir.propset('foo', 'bar') + status = somedir.status() + assert len(status.prop_modified) == 1 + assert len(status.modified) == 1 + + somedir.commit('non-recursive commit', rec=0) + status = somedir.status() + assert len(status.prop_modified) == 0 + assert len(status.modified) == 1 + + somedir.commit('recursive commit') + status = somedir.status() + assert len(status.prop_modified) == 0 + assert len(status.modified) == 0 + #def test_log(self): # l = self.root.log() # assert len(l) == 3 # might need to be upped if more tests are added Modified: py/trunk/py/path/svn/wccommand.py ============================================================================== --- py/trunk/py/path/svn/wccommand.py (original) +++ py/trunk/py/path/svn/wccommand.py Sun Aug 26 14:31:20 2007 @@ -199,6 +199,28 @@ _rex_status = re.compile(r'\s+(\d+|-)\s+(\S+)\s+(\S+)\s+(.*)') + def lock(self): + """ set a lock (exclusive) on the resource """ + out = self._svn('lock').strip() + if not out: + # warning or error, raise exception + raise Exception(out[4:]) + + def unlock(self): + """ unset a previously set lock """ + out = self._svn('unlock').strip() + if out.startswith('svn:'): + # warning or error, raise exception + raise Exception(out[4:]) + + def cleanup(self): + """ remove any locks from the resource """ + # XXX should be fixed properly!!! + try: + self.unlock() + except: + pass + def status(self, updates=0, rec=0, externals=0): """ return (collective) Status object for this file. """ # http://svnbook.red-bean.com/book.html#svn-ch-3-sect-4.3.1 @@ -234,7 +256,7 @@ #print "processing %r" % line flags, rest = line[:8], line[8:] # first column - c0,c1,c2,c3,c4,x5,x6,c7 = flags + c0,c1,c2,c3,c4,c5,x6,c7 = flags #if '*' in line: # print "flags", repr(flags), "rest", repr(rest) @@ -291,7 +313,8 @@ if c1 == 'M': rootstatus.prop_modified.append(wcpath) - if c2 == 'L': + # XXX do we cover all client versions here? + if c2 == 'L' or c5 == 'K': rootstatus.locked.append(wcpath) if c7 == '*': rootstatus.update_available.append(wcpath) @@ -333,11 +356,14 @@ return result _rex_commit = re.compile(r'.*Committed revision (\d+)\.$', re.DOTALL) - def commit(self, message=""): - """commit() returns None if there was nothing to commit - and the revision number of the commit otherwise. - """ - out = self._svn('commit -m "%s"' % message) + def commit(self, msg='', rec=1): + """ commit with support for non-recursive commits """ + from py.__.path.svn import cache + # XXX i guess escaping should be done better here?!? + cmd = 'commit -m "%s" --force-log' % (msg.replace('"', '\\"'),) + if not rec: + cmd += ' -N' + out = self._svn(cmd) try: del cache.info[self] except KeyError: @@ -540,7 +566,7 @@ class WCStatus: attrnames = ('modified','added', 'conflict', 'unchanged', 'external', 'deleted', 'prop_modified', 'unknown', 'update_available', - 'incomplete', 'kindmismatch', 'ignored' + 'incomplete', 'kindmismatch', 'ignored', 'locked' ) def __init__(self, wcpath, rev=None, modrev=None, author=None): From fijal at codespeak.net Mon Aug 27 10:41:57 2007 From: fijal at codespeak.net (fijal at codespeak.net) Date: Mon, 27 Aug 2007 10:41:57 +0200 (CEST) Subject: [py-svn] r46009 - in py/branch/session-cleanups/py/test: . rsession testing Message-ID: <20070827084157.00FCA81E8@code0.codespeak.net> Author: fijal Date: Mon Aug 27 10:41:57 2007 New Revision: 46009 Modified: py/branch/session-cleanups/py/test/rsession/rsession.py py/branch/session-cleanups/py/test/session.py py/branch/session-cleanups/py/test/testing/test_reporter.py Log: A bit more shuffling stuff around Modified: py/branch/session-cleanups/py/test/rsession/rsession.py ============================================================================== --- py/branch/session-cleanups/py/test/rsession/rsession.py (original) +++ py/branch/session-cleanups/py/test/rsession/rsession.py Mon Aug 27 10:41:57 2007 @@ -14,31 +14,8 @@ from py.__.test.rsession.local import local_loop, plain_runner, apigen_runner,\ box_runner from py.__.test.reporter import LocalReporter, RemoteReporter, TestReporter -from py.__.test.session import Session +from py.__.test.session import AbstractSession from py.__.test.outcome import Skipped, Failed - -class AbstractSession(Session): - """ - An abstract session executes collectors/items through a runner. - - """ - def fixoptions(self): - option = self.config.option - if option.runbrowser and not option.startserver: - #print "--runbrowser implies --startserver" - option.startserver = True - if self.config.getvalue("dist_boxed"): - option.boxed = True - super(AbstractSession, self).fixoptions() - - def init_reporter(self, reporter, config, hosts): - if reporter is None: - reporter = choose_reporter(config)(config, hm.hosts) - else: - reporter = TestReporter(reporter) - checkfun = lambda : self.config.option.exitfirst and \ - reporter.was_failure() - return reporter, checkfun class RSession(AbstractSession): """ Remote version of session Modified: py/branch/session-cleanups/py/test/session.py ============================================================================== --- py/branch/session-cleanups/py/test/session.py (original) +++ py/branch/session-cleanups/py/test/session.py Mon Aug 27 10:41:57 2007 @@ -1,33 +1,23 @@ import py from py.__.test.outcome import Outcome, Failed, Passed, Skipped +from py.__.test.reporter import choose_reporter, TestReporter -class Session(object): - """ - A Session gets test Items from Collectors, # executes the - Items and sends the Outcome to the Reporter. +class AbstractSession(object): + """ An abstract session executes collectors/items through a runner. """ def __init__(self, config): self._memo = [] self.config = config self._keyword = config.option.keyword - def shouldclose(self): - return False - - def header(self, colitems): - """ setup any neccessary resources ahead of the test run. """ - if not self.config.option.nomagic: - py.magic.invoke(assertion=1) - - def footer(self, colitems): - """ teardown any resources after a test run. """ - py.test.collect.Function._state.teardown_all() - if not self.config.option.nomagic: - py.magic.revoke(assertion=1) - def fixoptions(self): """ check, fix and determine conflicting options. """ - option = self.config.option + option = self.config.option + if option.runbrowser and not option.startserver: + #print "--runbrowser implies --startserver" + option.startserver = True + if self.config.getvalue("dist_boxed") and option.dist: + option.boxed = True # implied options if option.usepdb: if not option.nocapture: @@ -43,6 +33,34 @@ if option.keyword_oneshot and not option.keyword: raise ValueError, "--keyword-oneshot makes sense only when --keyword is supplied" + def init_reporter(self, reporter, config, hosts): + if reporter is None: + reporter = choose_reporter(config)(config, hosts) + else: + reporter = TestReporter(reporter) + checkfun = lambda : self.config.option.exitfirst and \ + reporter.was_failure() + return reporter, checkfun + +class Session(AbstractSession): + """ + A Session gets test Items from Collectors, # executes the + Items and sends the Outcome to the Reporter. + """ + def shouldclose(self): + return False + + def header(self, colitems): + """ setup any neccessary resources ahead of the test run. """ + if not self.config.option.nomagic: + py.magic.invoke(assertion=1) + + def footer(self, colitems): + """ teardown any resources after a test run. """ + py.test.collect.Function._state.teardown_all() + if not self.config.option.nomagic: + py.magic.revoke(assertion=1) + def start(self, colitem): """ hook invoked before each colitem.run() invocation. """ Modified: py/branch/session-cleanups/py/test/testing/test_reporter.py ============================================================================== --- py/branch/session-cleanups/py/test/testing/test_reporter.py (original) +++ py/branch/session-cleanups/py/test/testing/test_reporter.py Mon Aug 27 10:41:57 2007 @@ -18,7 +18,7 @@ import py, os -from py.__.test.rsession.rsession import AbstractSession +from py.__.test.session import AbstractSession from py.__.test.reporter import RemoteReporter, LocalReporter, choose_reporter from py.__.test import repevent from py.__.test.outcome import ReprOutcome, SerializableOutcome From fijal at codespeak.net Mon Aug 27 10:45:04 2007 From: fijal at codespeak.net (fijal at codespeak.net) Date: Mon, 27 Aug 2007 10:45:04 +0200 (CEST) Subject: [py-svn] r46010 - py/trunk/py/execnet Message-ID: <20070827084504.AEE9881E8@code0.codespeak.net> Author: fijal Date: Mon Aug 27 10:45:03 2007 New Revision: 46010 Modified: py/trunk/py/execnet/inputoutput.py Log: Merge from branch - a lock for files, prevents segfaults of cpython Modified: py/trunk/py/execnet/inputoutput.py ============================================================================== --- py/trunk/py/execnet/inputoutput.py (original) +++ py/trunk/py/execnet/inputoutput.py Mon Aug 27 10:45:03 2007 @@ -3,7 +3,7 @@ across process or computer barriers. """ -import socket, os, sys +import socket, os, sys, thread class SocketIO: server_stmt = """ @@ -76,6 +76,7 @@ msvcrt.setmode(outfile.fileno(), os.O_BINARY) self.outfile, self.infile = infile, outfile self.readable = self.writeable = True + self.lock = thread.allocate_lock() def read(self, numbytes): """Read exactly 'bytes' bytes from the pipe. """ @@ -99,6 +100,10 @@ self.infile.close() self.readable = None def close_write(self): - if self.writeable: - self.outfile.close() - self.writeable = None + self.lock.acquire() + try: + if self.writeable: + self.outfile.close() + self.writeable = None + finally: + self.lock.release() From fijal at codespeak.net Mon Aug 27 11:02:51 2007 From: fijal at codespeak.net (fijal at codespeak.net) Date: Mon, 27 Aug 2007 11:02:51 +0200 (CEST) Subject: [py-svn] r46011 - in py/trunk/py/test: . rsession rsession/testing rsession/webdata testing Message-ID: <20070827090251.865EA81E4@code0.codespeak.net> Author: fijal Date: Mon Aug 27 11:02:50 2007 New Revision: 46011 Added: py/trunk/py/test/repevent.py - copied unchanged from r46010, py/branch/session-cleanups/py/test/repevent.py py/trunk/py/test/reporter.py - copied unchanged from r46010, py/branch/session-cleanups/py/test/reporter.py py/trunk/py/test/testing/test_outcome.py - copied unchanged from r46010, py/branch/session-cleanups/py/test/testing/test_outcome.py py/trunk/py/test/testing/test_repevent.py - copied unchanged from r46010, py/branch/session-cleanups/py/test/testing/test_repevent.py py/trunk/py/test/testing/test_reporter.py - copied unchanged from r46010, py/branch/session-cleanups/py/test/testing/test_reporter.py Removed: py/trunk/py/test/rsession/outcome.py py/trunk/py/test/rsession/repevent.py py/trunk/py/test/rsession/reporter.py py/trunk/py/test/rsession/testing/test_outcome.py py/trunk/py/test/rsession/testing/test_repevent.py py/trunk/py/test/rsession/testing/test_reporter.py Modified: py/trunk/py/test/collect.py py/trunk/py/test/outcome.py py/trunk/py/test/rsession/executor.py py/trunk/py/test/rsession/hostmanage.py py/trunk/py/test/rsession/local.py py/trunk/py/test/rsession/master.py py/trunk/py/test/rsession/rest.py py/trunk/py/test/rsession/rsession.py py/trunk/py/test/rsession/slave.py py/trunk/py/test/rsession/testing/test_executor.py py/trunk/py/test/rsession/testing/test_hostmanage.py py/trunk/py/test/rsession/testing/test_lsession.py py/trunk/py/test/rsession/testing/test_master.py py/trunk/py/test/rsession/testing/test_rest.py py/trunk/py/test/rsession/testing/test_rsession.py py/trunk/py/test/rsession/testing/test_slave.py py/trunk/py/test/rsession/web.py py/trunk/py/test/rsession/webdata/source.js py/trunk/py/test/session.py py/trunk/py/test/testing/test_collect.py py/trunk/py/test/testing/test_config.py Log: Branch merge of session cleanups. * killed _tryiter usage in rsession * moved reporter one level up, so it can be reused later for normal session * a lot of small simplifications Modified: py/trunk/py/test/collect.py ============================================================================== --- py/trunk/py/test/collect.py (original) +++ py/trunk/py/test/collect.py Mon Aug 27 11:02:50 2007 @@ -189,7 +189,7 @@ return True return False - def _tryiter(self, yieldtype=None, reporterror=None, keyword=None): + def _tryiter(self, yieldtype=None): """ yield stop item instances from flattening the collector. XXX deprecated: this way of iteration is not safe in all cases. @@ -197,28 +197,17 @@ if yieldtype is None: yieldtype = py.test.collect.Item if isinstance(self, yieldtype): - try: - self._skipbykeyword(keyword) - yield self - except Skipped: - if reporterror is not None: - excinfo = py.code.ExceptionInfo() - reporterror((excinfo, self)) + yield self else: if not isinstance(self, py.test.collect.Item): try: - if reporterror is not None: - reporterror((None, self)) for x in self.run(): - for y in self.join(x)._tryiter(yieldtype, - reporterror, keyword): + for y in self.join(x)._tryiter(yieldtype): yield y except KeyboardInterrupt: raise - except: - if reporterror is not None: - excinfo = py.code.ExceptionInfo() - reporterror((excinfo, self)) + except: + pass def _getsortvalue(self): return self.name Modified: py/trunk/py/test/outcome.py ============================================================================== --- py/trunk/py/test/outcome.py (original) +++ py/trunk/py/test/outcome.py Mon Aug 27 11:02:50 2007 @@ -1,7 +1,10 @@ -""" File defining possible outcomes of running +""" File defining possible outcomes of running and also +serialization of outcomes """ +import py, sys + class Outcome: def __init__(self, msg=None, excinfo=None): self.msg = msg @@ -27,3 +30,120 @@ class Skipped(Outcome): pass + + +class SerializableOutcome(object): + def __init__(self, setupfailure=False, excinfo=None, skipped=None, + is_critical=False): + self.passed = not excinfo and not skipped + self.skipped = skipped + self.setupfailure = setupfailure + self.excinfo = excinfo + self.is_critical = is_critical + self.signal = 0 + self.stdout = "" # XXX temporary + self.stderr = "" + assert bool(self.passed) + bool(excinfo) + bool(skipped) == 1 + + def make_excinfo_repr(self, tbstyle): + if self.excinfo is None: + return None + excinfo = self.excinfo + tb_info = [self.traceback_entry_repr(x, tbstyle) + for x in excinfo.traceback] + rec_index = excinfo.traceback.recursionindex() + if hasattr(excinfo, 'type'): + etype = excinfo.type + if hasattr(etype, '__name__'): + etype = etype.__name__ + else: + etype = excinfo.typename + val = getattr(excinfo, 'value', None) + if not val: + val = excinfo.exconly() + val = str(val) + return (etype, val, (tb_info, rec_index)) + + def traceback_entry_repr(self, tb_entry, tb_style): + lineno = tb_entry.lineno + relline = lineno - tb_entry.frame.code.firstlineno + path = str(tb_entry.path) + #try: + try: + if tb_style == 'long': + source = str(tb_entry.getsource()) + else: + source = str(tb_entry.getsource()).split("\n")[relline] + except py.error.ENOENT: + source = "[cannot get source]" + name = str(tb_entry.frame.code.name) + # XXX: Bare except. What can getsource() raise anyway? + # SyntaxError, AttributeError, IndentationError for sure, check it + #except: + # source = "" + return (relline, lineno, source, path, name) + + def make_repr(self, tbstyle="long"): + return (self.passed, self.setupfailure, + self.make_excinfo_repr(tbstyle), + self.skipped, self.is_critical, 0, self.stdout, self.stderr) + +class TracebackEntryRepr(object): + def __init__(self, tbentry): + relline, lineno, self.source, self.path, self.name = tbentry + self.relline = int(relline) + self.path = py.path.local(self.path) + self.lineno = int(lineno) + self.locals = {} + + def __repr__(self): + return "line %s in %s\n %s" %(self.lineno, self.path, self.source[100:]) + + def getsource(self): + return py.code.Source(self.source).strip() + + def getfirstlinesource(self): + return self.lineno - self.relline + +class TracebackRepr(list): + def recursionindex(self): + return self.recursion_index + +class ExcInfoRepr(object): + def __init__(self, excinfo): + self.typename, self.value, tb_i = excinfo + tb, rec_index = tb_i + self.traceback = TracebackRepr([TracebackEntryRepr(x) for x in tb]) + self.traceback.recursion_index = rec_index + + def __repr__(self): + l = ["%s=%s" %(x, getattr(self, x)) + for x in "typename value traceback".split()] + return "" %(" ".join(l),) + + def exconly(self, tryshort=False): + """ Somehow crippled version of original one + """ + return "%s: %s" % (self.typename, self.value) + + def errisinstance(self, exc_t): + if not isinstance(exc_t, tuple): + exc_t = (exc_t,) + for exc in exc_t: + if self.typename == str(exc).split('.')[-1]: + return True + return False + +class ReprOutcome(object): + def __init__(self, repr_tuple): + (self.passed, self.setupfailure, excinfo, self.skipped, + self.is_critical, self.signal, self.stdout, self.stderr) = repr_tuple + if excinfo is None: + self.excinfo = None + else: + self.excinfo = ExcInfoRepr(excinfo) + + def __repr__(self): + l = ["%s=%s" %(x, getattr(self, x)) + for x in "signal passed skipped setupfailure excinfo stdout stderr".split()] + return "" %(" ".join(l),) Modified: py/trunk/py/test/rsession/executor.py ============================================================================== --- py/trunk/py/test/rsession/executor.py (original) +++ py/trunk/py/test/rsession/executor.py Mon Aug 27 11:02:50 2007 @@ -3,9 +3,9 @@ import py, os, sys -from py.__.test.rsession.outcome import Outcome, ReprOutcome +from py.__.test.outcome import SerializableOutcome, ReprOutcome from py.__.test.rsession.box import Box -from py.__.test.rsession import repevent +from py.__.test import repevent from py.__.test.outcome import Skipped, Failed class RunExecutor(object): @@ -33,9 +33,9 @@ def execute(self, capture=True): try: self.run(capture) - outcome = Outcome() + outcome = SerializableOutcome() except Skipped, e: - outcome = Outcome(skipped=str(e)) + outcome = SerializableOutcome(skipped=str(e)) except (SystemExit, KeyboardInterrupt): raise except: @@ -49,7 +49,7 @@ code = py.code.Code(fun) excinfo.traceback = excinfo.traceback.cut( path=code.path, firstlineno=code.firstlineno) - outcome = Outcome(excinfo=excinfo, setupfailure=False) + outcome = SerializableOutcome(excinfo=excinfo, setupfailure=False) if self.usepdb: if self.reporter is not None: self.reporter(repevent.ImmediateFailure(self.item, Modified: py/trunk/py/test/rsession/hostmanage.py ============================================================================== --- py/trunk/py/test/rsession/hostmanage.py (original) +++ py/trunk/py/test/rsession/hostmanage.py Mon Aug 27 11:02:50 2007 @@ -5,7 +5,7 @@ from py.__.test.rsession.master import MasterNode from py.__.test.rsession.slave import setup_slave -from py.__.test.rsession import repevent +from py.__.test import repevent class HostInfo(object): """ Class trying to store all necessary attributes Modified: py/trunk/py/test/rsession/local.py ============================================================================== --- py/trunk/py/test/rsession/local.py (original) +++ py/trunk/py/test/rsession/local.py Mon Aug 27 11:02:50 2007 @@ -5,8 +5,8 @@ import py from py.__.test.rsession.executor import BoxExecutor, RunExecutor,\ ApigenExecutor -from py.__.test.rsession import repevent -from py.__.test.rsession.outcome import ReprOutcome +from py.__.test import repevent +from py.__.test.outcome import ReprOutcome # XXX copied from session.py def startcapture(session): Modified: py/trunk/py/test/rsession/master.py ============================================================================== --- py/trunk/py/test/rsession/master.py (original) +++ py/trunk/py/test/rsession/master.py Mon Aug 27 11:02:50 2007 @@ -2,8 +2,9 @@ Node code for Master. """ import py -from py.__.test.rsession.outcome import ReprOutcome -from py.__.test.rsession import repevent +from py.__.test.outcome import ReprOutcome +from py.__.test import repevent +from py.__.test.outcome import Skipped class MasterNode(object): def __init__(self, channel, reporter): @@ -39,12 +40,30 @@ # of hanging nodes and such raise -def itemgen(colitems, reporter, keyword, reporterror): - def rep(x): - reporterror(reporter, x) - for x in colitems: - for y in x._tryiter(reporterror=rep, keyword=keyword): - yield y +def itemgen(colitems, reporter, keyword=None): + stopitems = py.test.collect.Item # XXX should be generator here as well + for next in colitems: + if isinstance(next, stopitems): + try: + next._skipbykeyword(keyword) + yield next + except Skipped: + excinfo = py.code.ExceptionInfo() + reporter(repevent.SkippedTryiter(excinfo, next)) + else: + reporter(repevent.ItemStart(next)) + try: + for x in itemgen([next.join(x) for x in next.run()], reporter, + keyword): + yield x + except (KeyboardInterrupt, SystemExit, GeneratorExit): + raise + except: + excinfo = py.code.ExceptionInfo() + if excinfo.type is Skipped: + reporter(repevent.SkippedTryiter(excinfo, next)) + else: + reporter(repevent.FailedTryiter(excinfo, next)) def dispatch_loop(masternodes, itemgenerator, shouldstop, waiter = lambda: py.std.time.sleep(0.1), Deleted: /py/trunk/py/test/rsession/outcome.py ============================================================================== --- /py/trunk/py/test/rsession/outcome.py Mon Aug 27 11:02:50 2007 +++ (empty file) @@ -1,126 +0,0 @@ - -""" Classes for representing outcomes on master and slavenode sides -""" - -# WARNING! is_critical is debugging flag which means something -# wrong went on a different level. Usually that means -# internal bug. - -import sys -import py - -class Outcome(object): - def __init__(self, setupfailure=False, excinfo=None, skipped=None, - is_critical=False): - self.passed = not excinfo and not skipped - self.skipped = skipped - self.setupfailure = setupfailure - self.excinfo = excinfo - self.is_critical = is_critical - self.signal = 0 - self.stdout = "" # XXX temporary - self.stderr = "" - assert bool(self.passed) + bool(excinfo) + bool(skipped) == 1 - - def make_excinfo_repr(self, tbstyle): - if self.excinfo is None: - return None - excinfo = self.excinfo - tb_info = [self.traceback_entry_repr(x, tbstyle) - for x in excinfo.traceback] - rec_index = excinfo.traceback.recursionindex() - if hasattr(excinfo, 'type'): - etype = excinfo.type - if hasattr(etype, '__name__'): - etype = etype.__name__ - else: - etype = excinfo.typename - val = getattr(excinfo, 'value', None) - if not val: - val = excinfo.exconly() - val = str(val) - return (etype, val, (tb_info, rec_index)) - - def traceback_entry_repr(self, tb_entry, tb_style): - lineno = tb_entry.lineno - relline = lineno - tb_entry.frame.code.firstlineno - path = str(tb_entry.path) - #try: - try: - if tb_style == 'long': - source = str(tb_entry.getsource()) - else: - source = str(tb_entry.getsource()).split("\n")[relline] - except py.error.ENOENT: - source = "[cannot get source]" - name = str(tb_entry.frame.code.name) - # XXX: Bare except. What can getsource() raise anyway? - # SyntaxError, AttributeError, IndentationError for sure, check it - #except: - # source = "" - return (relline, lineno, source, path, name) - - def make_repr(self, tbstyle="long"): - return (self.passed, self.setupfailure, - self.make_excinfo_repr(tbstyle), - self.skipped, self.is_critical, 0, self.stdout, self.stderr) - -class TracebackEntryRepr(object): - def __init__(self, tbentry): - relline, lineno, self.source, self.path, self.name = tbentry - self.relline = int(relline) - self.path = py.path.local(self.path) - self.lineno = int(lineno) - self.locals = {} - - def __repr__(self): - return "line %s in %s\n %s" %(self.lineno, self.path, self.source[100:]) - - def getsource(self): - return py.code.Source(self.source).strip() - - def getfirstlinesource(self): - return self.lineno - self.relline - -class TracebackRepr(list): - def recursionindex(self): - return self.recursion_index - -class ExcInfoRepr(object): - def __init__(self, excinfo): - self.typename, self.value, tb_i = excinfo - tb, rec_index = tb_i - self.traceback = TracebackRepr([TracebackEntryRepr(x) for x in tb]) - self.traceback.recursion_index = rec_index - - def __repr__(self): - l = ["%s=%s" %(x, getattr(self, x)) - for x in "typename value traceback".split()] - return "" %(" ".join(l),) - - def exconly(self, tryshort=False): - """ Somehow crippled version of original one - """ - return "%s: %s" % (self.typename, self.value) - - def errisinstance(self, exc_t): - if not isinstance(exc_t, tuple): - exc_t = (exc_t,) - for exc in exc_t: - if self.typename == str(exc).split('.')[-1]: - return True - return False - -class ReprOutcome(object): - def __init__(self, repr_tuple): - (self.passed, self.setupfailure, excinfo, self.skipped, - self.is_critical, self.signal, self.stdout, self.stderr) = repr_tuple - if excinfo is None: - self.excinfo = None - else: - self.excinfo = ExcInfoRepr(excinfo) - - def __repr__(self): - l = ["%s=%s" %(x, getattr(self, x)) - for x in "signal passed skipped setupfailure excinfo stdout stderr".split()] - return "" %(" ".join(l),) Deleted: /py/trunk/py/test/rsession/repevent.py ============================================================================== --- /py/trunk/py/test/rsession/repevent.py Mon Aug 27 11:02:50 2007 +++ (empty file) @@ -1,145 +0,0 @@ -""" Reporter classes for showing asynchronous and synchronous status events -""" - -import py -import time - -def basic_report(msg_type, message): - print msg_type, message - -#def report(msg_type, message): -# pass - -##def report_error(excinfo): -## if isinstance(excinfo, py.test.collect.Item.Skipped): -## # we need to dispatch this info -## report(Skipped(excinfo)) -## else: -## report("itererror", excinfo) - -def wrapcall(reporter, func, *args, **kwargs): - reporter(CallStart(func, args, kwargs)) - try: - retval = func(*args, **kwargs) - except: - reporter(CallException(func, args, kwargs)) - raise - else: - reporter(CallFinish(func, args, kwargs)) - return retval - -# ---------------------------------------------------------------------- -# Reporting Events -# ---------------------------------------------------------------------- - -class ReportEvent(object): - def __repr__(self): - l = ["%s=%s" %(key, value) - for key, value in self.__dict__.items()] - return "<%s %s>" %(self.__class__.__name__, " ".join(l),) - -class SendItem(ReportEvent): - def __init__(self, channel, item): - self.item = item - self.channel = channel - if channel: - self.host = channel.gateway.host - -class ReceivedItemOutcome(ReportEvent): - def __init__(self, channel, item, outcome): - self.channel = channel - if channel: - self.host = channel.gateway.host - self.item = item - self.outcome = outcome - -class CallEvent(ReportEvent): - def __init__(self, func, args, kwargs): - self.func = func - self.args = args - self.kwargs = kwargs - - def __repr__(self): - call = "%s args=%s, kwargs=%s" %(self.func.__name__, - self.args, self.kwargs) - return '<%s %s>' %(self.__class__.__name__, call) - -class CallStart(CallEvent): - pass - -class CallException(CallEvent): - pass - -class CallFinish(CallEvent): - pass - -class HostRSyncing(ReportEvent): - def __init__(self, host, root, remotepath, synced): - self.host = host - self.root = root - self.remotepath = remotepath - self.synced = synced - -class HostGatewayReady(ReportEvent): - def __init__(self, host, roots): - self.host = host - self.roots = roots - -class HostRSyncRootReady(ReportEvent): - def __init__(self, host, root): - self.host = host - self.root = root - -class TestStarted(ReportEvent): - def __init__(self, hosts, topdir, roots): - self.hosts = hosts - self.topdir = topdir - self.roots = roots - self.timestart = time.time() - -class TestFinished(ReportEvent): - def __init__(self): - self.timeend = time.time() - -class Nodes(ReportEvent): - def __init__(self, nodes): - self.nodes = nodes - -class SkippedTryiter(ReportEvent): - def __init__(self, excinfo, item): - self.excinfo = excinfo - self.item = item - -class FailedTryiter(ReportEvent): - def __init__(self, excinfo, item): - self.excinfo = excinfo - self.item = item - -class ItemStart(ReportEvent): - """ This class shows most of the start stuff, like directory, module, class - can be used for containers - """ - def __init__(self, item): - self.item = item - -class RsyncFinished(ReportEvent): - def __init__(self): - self.time = time.time() - -class ImmediateFailure(ReportEvent): - def __init__(self, item, outcome): - self.item = item - self.outcome = outcome - -class PongReceived(ReportEvent): - def __init__(self, hostid, result): - self.hostid = hostid - self.result = result - -class InterruptedExecution(ReportEvent): - def __init__(self): - self.timeend = time.time() - -class CrashedExecution(ReportEvent): - def __init__(self): - self.timeend = time.time() Deleted: /py/trunk/py/test/rsession/reporter.py ============================================================================== --- /py/trunk/py/test/rsession/reporter.py Mon Aug 27 11:02:50 2007 +++ (empty file) @@ -1,347 +0,0 @@ - -""" reporter - different reporter for different purposes ;-) - Still lacks: - - 1. Hanging nodes are not done well -""" - -import py - -from py.__.test.terminal.out import getout -from py.__.test.rsession import repevent -from py.__.test.rsession import outcome -from py.__.misc.terminal_helper import ansi_print, get_terminal_width -from py.__.test.representation import Presenter - -import sys -import thread - -class AbstractReporter(object): - def __init__(self, config, hosts): - self.config = config - self.hosts = hosts - self.failed_tests_outcome = [] - self.skipped_tests_outcome = [] - self.out = getout(py.std.sys.stdout) - self.presenter = Presenter(self.out, config) - self.failed = dict([(host, 0) for host in hosts]) - self.skipped = dict([(host, 0) for host in hosts]) - self.passed = dict([(host, 0) for host in hosts]) - self.to_rsync = {} - - def get_item_name(self, event, colitem): - return "/".join(colitem.listnames()) - - def report(self, what): - repfun = getattr(self, "report_" + what.__class__.__name__, - self.report_unknown) - try: - return repfun(what) - except (KeyboardInterrupt, SystemExit): - raise - except: - print "Internal reporting problem" - excinfo = py.code.ExceptionInfo() - for i in excinfo.traceback: - print str(i)[2:-1] - print excinfo - - def report_unknown(self, what): - if self.config.option.verbose: - print "Unknown report: %s" % what - - def report_SendItem(self, item): - address = item.host.hostname - assert isinstance(item.host.hostname, str) - if self.config.option.verbose: - print "Sending %s to %s" % (item.item, - address) - - def report_HostRSyncing(self, item): - hostrepr = self._hostrepr(item.host) - if item.synced: - if (item.host.hostname == "localhost" and - item.root == item.remotepath): - print "%15s: skipping inplace rsync of %r" %( - hostrepr, item.remotepath) - else: - print "%15s: skip duplicate rsync to %r" % ( - hostrepr, item.remotepath) - else: - print "%15s: rsync %r to remote %r" % (hostrepr, - item.root.basename, - item.remotepath) - - def report_HostGatewayReady(self, item): - self.to_rsync[item.host] = len(item.roots) - hostrepr = self._hostrepr(item.host) - self.out.write("%15s: gateway initialised (remote topdir: %s)\n"\ - % (hostrepr, item.host.gw_remotepath)) - - def report_HostRSyncRootReady(self, item): - self.to_rsync[item.host] -= 1 - if not self.to_rsync[item.host]: - self._host_ready(item) - - def _host_ready(self, item): - self.hosts_to_rsync -= 1 - hostrepr = self._hostrepr(item.host) - if self.hosts_to_rsync: - print "%15s: READY (still %d to go)" % (hostrepr, - self.hosts_to_rsync) - else: - print "%15s: READY" % hostrepr - - def report_TestStarted(self, item): - hostreprs = [self._hostrepr(host) for host in item.hosts] - txt = " Test started, hosts: %s " % ", ".join(hostreprs) - self.hosts_to_rsync = len(item.hosts) - self.out.sep("=", txt) - self.timestart = item.timestart - self.out.write("local top directory: %s\n" % item.topdir) - for i, root in py.builtin.enumerate(item.roots): - outof = "%d/%d" %(i+1, len(item.roots)) - self.out.write("local RSync root [%s]: %s\n" % - (outof, root)) - - def report_RsyncFinished(self, item): - self.timersync = item.time - - def report_ImmediateFailure(self, event): - self.repr_failure(event.item, event.outcome) - - def report_TestFinished(self, item): - self.out.line() - assert hasattr(self, 'timestart') - self.timeend = item.timeend - self.skips() - self.failures() - if hasattr(self, 'nodes'): # XXX: Testing - self.hangs() - self.summary() - return len(self.failed_tests_outcome) > 0 - - report_InterruptedExecution = report_TestFinished - report_CrashedExecution = report_TestFinished - - def hangs(self): - h = [] - if self.config.option.exitfirst: - # reporting hanging nodes in that case makes no sense at all - # but we should share some code in all reporters than - return - for node in self.nodes: - h += [(i, node.channel.gateway.sshaddress) for i in node.pending] - if h: - self.out.sep("=", " HANGING NODES ") - for i, node in h: - self.out.line("%s on %s" % (" ".join(i.listnames()), node)) - - def failures(self): - if self.failed_tests_outcome: - self.out.sep("=", " FAILURES ") - for event in self.failed_tests_outcome: - if isinstance(event, repevent.ReceivedItemOutcome): - host = self.gethost(event) - self.out.sep('_', "%s on %s" % - (" ".join(event.item.listnames()), host)) - if event.outcome.signal: - self.presenter.repr_item_info(event.item) - self.repr_signal(event.item, event.outcome) - else: - self.repr_failure(event.item, event.outcome) - else: - self.out.sep('_', " ".join(event.item.listnames())) - out = outcome.Outcome(excinfo=event.excinfo) - self.repr_failure(event.item, outcome.ReprOutcome(out.make_repr())) - - def gethost(self, event): - return event.host.hostname - - def repr_failure(self, item, outcome): - excinfo = outcome.excinfo - traceback = excinfo.traceback - if not traceback: - self.out.line("empty traceback from item %r" % (item,)) - return - - handler = getattr(self.presenter, 'repr_failure_tb%s' % self.config.option.tbstyle) - handler(item, excinfo, traceback, lambda: self.repr_out_err(outcome)) - - def repr_out_err(self, outcome): - if outcome.stdout: - self.out.sep('-', " Captured process stdout: ") - self.out.write(outcome.stdout) - if outcome.stderr: - self.out.sep('-', " Captured process stderr: ") - self.out.write(outcome.stderr) - - def repr_signal(self, item, outcome): - signal = outcome.signal - self.out.line("Received signal: %d" % outcome.signal) - self.repr_out_err(outcome) - - def _hostrepr(self, host): - return host.hostid - - def skips(self): - texts = {} - for event in self.skipped_tests_outcome: - colitem = event.item - if isinstance(event, repevent.ReceivedItemOutcome): - outcome = event.outcome - text = outcome.skipped - itemname = self.get_item_name(event, colitem) - elif isinstance(event, repevent.SkippedTryiter): - text = str(event.excinfo.value) - itemname = "/".join(colitem.listnames()) - if text not in texts: - texts[text] = [itemname] - else: - texts[text].append(itemname) - - if texts: - self.out.line() - self.out.sep('_', 'reasons for skipped tests') - for text, items in texts.items(): - for item in items: - self.out.line('Skipped in %s' % item) - self.out.line("reason: %s" % text) - - def summary(self): - def gather(dic): - total = 0 - for key, val in dic.iteritems(): - total += val - return total - - def create_str(name, count): - if count: - return ", %d %s" % (count, name) - return "" - - total_passed = gather(self.passed) - total_failed = gather(self.failed) - total_skipped = gather(self.skipped) - total = total_passed + total_failed + total_skipped - skipped_str = create_str("skipped", total_skipped) - failed_str = create_str("failed", total_failed) - self.print_summary(total, skipped_str, failed_str) - - def print_summary(self, total, skipped_str, failed_str): - self.out.sep("=", " %d test run%s%s in %.2fs (rsync: %.2f)" % - (total, skipped_str, failed_str, self.timeend - self.timestart, - self.timersync - self.timestart)) - - def report_SkippedTryiter(self, event): - #event.outcome.excinfo.source = - self.skipped_tests_outcome.append(event) - - def report_FailedTryiter(self, event): - pass - # XXX: right now we do not do anything with it - - def report_ReceivedItemOutcome(self, event): - host = event.host - hostrepr = self._hostrepr(host) - if event.outcome.passed: - self.passed[host] += 1 - sys.stdout.write("%15s: PASSED " % hostrepr) - elif event.outcome.skipped: - self.skipped_tests_outcome.append(event) - self.skipped[host] += 1 - sys.stdout.write("%15s: SKIPPED " % hostrepr) - else: - self.failed[host] += 1 - self.failed_tests_outcome.append(event) - sys.stdout.write("%15s: " % hostrepr) - ansi_print("FAILED", esc=(31,1), newline=False, file=sys.stdout) - sys.stdout.write(" ") - # we should have printed 20 characters to this point - itempath = ".".join(event.item.listnames()[1:-1]) - funname = event.item.listnames()[-1] - lgt = get_terminal_width() - 25 - # mark the function name, to be sure - to_display = len(itempath) + len(funname) + 1 - if to_display > lgt: - sys.stdout.write("..." + itempath[to_display-lgt+4:]) - else: - sys.stdout.write(itempath) - sys.stdout.write(" ") - ansi_print(funname, esc=32, file=sys.stdout) - - def report_Nodes(self, event): - self.nodes = event.nodes - -class RemoteReporter(AbstractReporter): - def get_item_name(self, event, colitem): - return event.host.hostname + ":" + \ - "/".join(colitem.listnames()) - - def report_FailedTryiter(self, event): - self.out.line("FAILED TO LOAD MODULE: %s\n" % "/".join(event.item.listnames())) - self.failed_tests_outcome.append(event) - # argh! bad hack, need to fix it - self.failed[self.hosts[0]] += 1 - - def report_SkippedTryiter(self, event): - self.out.line("Skipped (%s) %s\n" % (str(event.excinfo.value), "/". - join(event.item.listnames()))) - -class LocalReporter(AbstractReporter): - def get_item_name(self, event, colitem): - return "/".join(colitem.listnames()) - - def report_SkippedTryiter(self, event): - #self.show_item(event.item, False) - if isinstance(event.item, py.test.collect.Module): - self.out.write("- skipped (%s)" % event.excinfo.value) - else: - self.out.write("s") - self.skipped_tests_outcome.append(event) - - def report_FailedTryiter(self, event): - #self.show_item(event.item, False) - self.out.write("- FAILED TO LOAD MODULE") - self.failed_tests_outcome.append(event) - self.failed[self.hosts[0]] += 1 - - def report_ReceivedItemOutcome(self, event): - host = self.hosts[0] - if event.outcome.passed: - self.passed[host] += 1 - self.out.write(".") - elif event.outcome.skipped: - self.skipped_tests_outcome.append(event) - self.skipped[host] += 1 - self.out.write("s") - else: - self.failed[host] += 1 - self.failed_tests_outcome.append(event) - self.out.write("F") - - def report_ItemStart(self, event): - self.show_item(event.item) - - def show_item(self, item, count_elems = True): - if isinstance(item, py.test.collect.Module): - # XXX This is a terrible hack, I don't like it - # and will rewrite it at some point - #self.count = 0 - lgt = len(list(item._tryiter())) - #self.lgt = lgt - # print names relative to current workdir - name = "/".join(item.listnames()) - local = str(py.path.local()) - d = str(self.config.topdir) - if local.startswith(d): - local = local[len(d) + 1:] - if local and name.startswith(local): - name = name[len(local) + 1:] - self.out.write("\n%s[%d] " % (name, lgt)) - - def gethost(self, event): - return 'localhost' - - def hangs(self): - pass Modified: py/trunk/py/test/rsession/rest.py ============================================================================== --- py/trunk/py/test/rsession/rest.py (original) +++ py/trunk/py/test/rsession/rest.py Mon Aug 27 11:02:50 2007 @@ -5,8 +5,8 @@ import py import sys from StringIO import StringIO -from py.__.test.rsession.reporter import AbstractReporter -from py.__.test.rsession import repevent +from py.__.test.reporter import AbstractReporter +from py.__.test import repevent from py.__.rest.rst import * class RestReporter(AbstractReporter): Modified: py/trunk/py/test/rsession/rsession.py ============================================================================== --- py/trunk/py/test/rsession/rsession.py (original) +++ py/trunk/py/test/rsession/rsession.py Mon Aug 27 11:02:50 2007 @@ -8,101 +8,15 @@ import re import time -from py.__.test.rsession import repevent +from py.__.test import repevent from py.__.test.rsession.master import MasterNode, dispatch_loop, itemgen from py.__.test.rsession.hostmanage import HostInfo, HostManager from py.__.test.rsession.local import local_loop, plain_runner, apigen_runner,\ box_runner -from py.__.test.rsession.reporter import LocalReporter, RemoteReporter -from py.__.test.session import Session +from py.__.test.reporter import LocalReporter, RemoteReporter, TestReporter +from py.__.test.session import AbstractSession from py.__.test.outcome import Skipped, Failed - -class AbstractSession(Session): - """ - An abstract session executes collectors/items through a runner. - - """ - def fixoptions(self): - option = self.config.option - if option.runbrowser and not option.startserver: - #print "--runbrowser implies --startserver" - option.startserver = True - if self.config.getvalue("dist_boxed"): - option.boxed = True - super(AbstractSession, self).fixoptions() - - def init_reporter(self, reporter, hosts, reporter_class, arg=""): - """ This initialises so called `reporter` class, which will - handle all event presenting to user. Does not get called - if main received custom reporter - """ - startserverflag = self.config.option.startserver - restflag = self.config.option.restreport - - if startserverflag and reporter is None: - from py.__.test.rsession.web import start_server, exported_methods - if self.config.option.runbrowser: - from socket import INADDR_ANY - port = INADDR_ANY # pick a random port when starting browser - else: - port = 8000 # stick to a fixed port otherwise - - reporter = exported_methods.report - httpd = start_server(server_address = ('', port)) - port = httpd.server_port - if self.config.option.runbrowser: - import webbrowser, thread - # webbrowser.open() may block until the browser finishes or not - url = "http://localhost:%d" % (port,) - thread.start_new_thread(webbrowser.open, (url,)) - elif reporter is None: - if restflag: - from py.__.test.rsession.rest import RestReporter - reporter_class = RestReporter - if arg: - reporter_instance = reporter_class(self.config, hosts) - else: - reporter_instance = reporter_class(self.config, hosts) - reporter = reporter_instance.report - else: - startserverflag = False - - return reporter, startserverflag - def reporterror(reporter, data): - excinfo, item = data - if excinfo is None: - reporter(repevent.ItemStart(item)) - elif excinfo.type is Skipped: - reporter(repevent.SkippedTryiter(excinfo, item)) - else: - reporter(repevent.FailedTryiter(excinfo, item)) - reporterror = staticmethod(reporterror) - - def kill_server(self, startserverflag): - """ Kill web server - """ - if startserverflag: - from py.__.test.rsession.web import kill_server - kill_server() - - def wrap_reporter(self, reporter): - """ We wrap reporter around, which makes it possible to us to track - existance of failures - """ - self.was_failure = False - def new_reporter(event): - if isinstance(event, repevent.ReceivedItemOutcome) and \ - not event.outcome.passed and \ - not event.outcome.skipped: - self.was_failure = True - return reporter(event) - checkfun = lambda : self.config.option.exitfirst and \ - self.was_failure - # for tests - self.checkfun = checkfun - return new_reporter, checkfun - class RSession(AbstractSession): """ Remote version of session """ @@ -129,12 +43,9 @@ def main(self, reporter=None): """ main loop for running tests. """ - args = self.config.args - - hm = HostManager(self.config) - reporter, startserverflag = self.init_reporter(reporter, - hm.hosts, RemoteReporter) - reporter, checkfun = self.wrap_reporter(reporter) + config = self.config + hm = HostManager(config) + reporter, checkfun = self.init_reporter(reporter, config, hm.hosts) reporter(repevent.TestStarted(hm.hosts, self.config.topdir, hm.roots)) @@ -157,22 +68,18 @@ exitfirst=self.config.option.exitfirst) reporter(repevent.Nodes(nodes)) retval = reporter(repevent.TestFinished()) - self.kill_server(startserverflag) return retval except (KeyboardInterrupt, SystemExit): reporter(repevent.InterruptedExecution()) - self.kill_server(startserverflag) raise except: reporter(repevent.CrashedExecution()) - self.kill_server(startserverflag) raise def dispatch_tests(self, nodes, reporter, checkfun): colitems = self.config.getcolitems() keyword = self.config.option.keyword - itemgenerator = itemgen(colitems, reporter, keyword, self.reporterror) - + itemgenerator = itemgen(colitems, reporter, keyword) all_tests = dispatch_loop(nodes, itemgenerator, checkfun) class LSession(AbstractSession): @@ -180,16 +87,13 @@ """ def main(self, reporter=None, runner=None): # check out if used options makes any sense - args = self.config.args - - hm = HostManager(self.config, hosts=[HostInfo('localhost')]) + config = self.config + hm = HostManager(config, hosts=[HostInfo('localhost')]) hosts = hm.hosts if not self.config.option.nomagic: py.magic.invoke(assertion=1) - reporter, startserverflag = self.init_reporter(reporter, - hosts, LocalReporter, args[0]) - reporter, checkfun = self.wrap_reporter(reporter) + reporter, checkfun = self.init_reporter(reporter, config, hosts) reporter(repevent.TestStarted(hosts, self.config.topdir, [])) colitems = self.config.getcolitems() @@ -200,11 +104,10 @@ keyword = self.config.option.keyword - itemgenerator = itemgen(colitems, reporter, keyword, self.reporterror) + itemgenerator = itemgen(colitems, reporter, keyword) local_loop(self, reporter, itemgenerator, checkfun, self.config, runner=runner) retval = reporter(repevent.TestFinished()) - self.kill_server(startserverflag) if not self.config.option.nomagic: py.magic.revoke(assertion=1) Modified: py/trunk/py/test/rsession/slave.py ============================================================================== --- py/trunk/py/test/rsession/slave.py (original) +++ py/trunk/py/test/rsession/slave.py Mon Aug 27 11:02:50 2007 @@ -4,7 +4,7 @@ import py from py.__.test.rsession.executor import RunExecutor, BoxExecutor, AsyncExecutor -from py.__.test.rsession.outcome import Outcome +from py.__.test.outcome import SerializableOutcome from py.__.test.outcome import Skipped import thread import os @@ -53,10 +53,10 @@ node = getnode(nextitem) res = node.run(nextitem) except Skipped, s: - send(Outcome(skipped=str(s)).make_repr()) + send(SerializableOutcome(skipped=str(s)).make_repr()) except: excinfo = py.code.ExceptionInfo() - send(Outcome(excinfo=excinfo, is_critical=True).make_repr()) + send(SerializableOutcome(excinfo=excinfo, is_critical=True).make_repr()) else: if not res[0] and not res[3] and config.option.exitfirst: # we're finished, but need to eat what we can Modified: py/trunk/py/test/rsession/testing/test_executor.py ============================================================================== --- py/trunk/py/test/rsession/testing/test_executor.py (original) +++ py/trunk/py/test/rsession/testing/test_executor.py Mon Aug 27 11:02:50 2007 @@ -4,7 +4,7 @@ from py.__.test.rsession.executor import RunExecutor, BoxExecutor,\ AsyncExecutor, ApigenExecutor -from py.__.test.rsession.outcome import ReprOutcome +from py.__.test.outcome import ReprOutcome from py.__.test.rsession.testing.basetest import BasicRsessionTest from py.__.test.outcome import Failed Modified: py/trunk/py/test/rsession/testing/test_hostmanage.py ============================================================================== --- py/trunk/py/test/rsession/testing/test_hostmanage.py (original) +++ py/trunk/py/test/rsession/testing/test_hostmanage.py Mon Aug 27 11:02:50 2007 @@ -5,7 +5,7 @@ import py from py.__.test.rsession.hostmanage import HostRSync, HostInfo, HostManager from py.__.test.rsession.hostmanage import sethomedir, gethomedir, getpath_relto_home -from py.__.test.rsession import repevent +from py.__.test import repevent class DirSetup: def setup_method(self, method): Modified: py/trunk/py/test/rsession/testing/test_lsession.py ============================================================================== --- py/trunk/py/test/rsession/testing/test_lsession.py (original) +++ py/trunk/py/test/rsession/testing/test_lsession.py Mon Aug 27 11:02:50 2007 @@ -4,7 +4,7 @@ import py from py.__.test.rsession.rsession import LSession -from py.__.test.rsession import repevent +from py.__.test import repevent from py.__.test.rsession.local import box_runner, plain_runner, apigen_runner def setup_module(mod): Modified: py/trunk/py/test/rsession/testing/test_master.py ============================================================================== --- py/trunk/py/test/rsession/testing/test_master.py (original) +++ py/trunk/py/test/rsession/testing/test_master.py Mon Aug 27 11:02:50 2007 @@ -11,8 +11,8 @@ from py.__.test.rsession.master import dispatch_loop, MasterNode from py.__.test.rsession.slave import setup_slave -from py.__.test.rsession.outcome import ReprOutcome, Outcome -from py.__.test.rsession import repevent +from py.__.test.outcome import ReprOutcome, SerializableOutcome +from py.__.test import repevent from py.__.test.rsession.hostmanage import HostInfo def setup_module(mod): @@ -64,8 +64,8 @@ mnode = MasterNode(ch, reportlist.append) mnode.send(Item("ok")) mnode.send(Item("notok")) - ch.callback(Outcome().make_repr()) - ch.callback(Outcome(excinfo=excinfo).make_repr()) + ch.callback(SerializableOutcome().make_repr()) + ch.callback(SerializableOutcome(excinfo=excinfo).make_repr()) assert len(reportlist) == 4 received = [i for i in reportlist if isinstance(i, repevent.ReceivedItemOutcome)] @@ -91,12 +91,12 @@ mnode = MasterNode(ch, reportlist.append) mnode.send(Item("ok")) mnode.send(Item("ok")) - ch.callback(Outcome().make_repr()) - ch.callback(Outcome().make_repr()) + ch.callback(SerializableOutcome().make_repr()) + ch.callback(SerializableOutcome().make_repr()) assert len(reportlist) == 4 def test_outcome_repr(): - out = ReprOutcome(Outcome(skipped=True).make_repr()) + out = ReprOutcome(SerializableOutcome(skipped=True).make_repr()) s = repr(out) assert s.lower().find("skip") != -1 Deleted: /py/trunk/py/test/rsession/testing/test_outcome.py ============================================================================== --- /py/trunk/py/test/rsession/testing/test_outcome.py Mon Aug 27 11:02:50 2007 +++ (empty file) @@ -1,50 +0,0 @@ - -import py -from py.__.test.rsession.outcome import Outcome, ReprOutcome, ExcInfoRepr - -import marshal - -def test_critical_debugging_flag(): - outcome = Outcome(is_critical=True) - r = ReprOutcome(outcome.make_repr()) - assert r.is_critical - -def f1(): - 1 - 2 - 3 - 4 - raise ValueError(42) - -def f2(): - f1() - -def f3(): - f2() - -def test_exception_info_repr(): - try: - f3() - except: - outcome = Outcome(excinfo=py.code.ExceptionInfo()) - - repr = outcome.make_excinfo_repr("long") - assert marshal.dumps(repr) - excinfo = ExcInfoRepr(repr) - - assert str(excinfo.typename) == "ValueError" - assert str(excinfo.value) == "42" - assert len(excinfo.traceback) == 4 - myfile = py.magic.autopath() - assert excinfo.traceback[3].path == myfile - assert excinfo.traceback[3].lineno == f1.func_code.co_firstlineno + 4 - assert excinfo.traceback[3].relline == 5 - assert excinfo.traceback[2].path == myfile - assert excinfo.traceback[2].lineno == f2.func_code.co_firstlineno - assert excinfo.traceback[2].relline == 1 - assert excinfo.traceback[1].path == myfile - assert excinfo.traceback[1].lineno == f3.func_code.co_firstlineno - assert excinfo.traceback[1].relline == 1 - -#def test_f3(): -# f3() Deleted: /py/trunk/py/test/rsession/testing/test_repevent.py ============================================================================== --- /py/trunk/py/test/rsession/testing/test_repevent.py Mon Aug 27 11:02:50 2007 +++ (empty file) @@ -1,36 +0,0 @@ -""" test reporting functionality. """ - -import py -from py.__.test.rsession import repevent - -def test_wrapcall_ok(): - l = [] - def ok(x): - return x+1 - i = repevent.wrapcall(l.append, ok, 1) - assert i == 2 - assert len(l) == 2 - assert isinstance(l[0], repevent.CallStart) - assert isinstance(l[1], repevent.CallFinish) - assert repr(l[0]) - assert repr(l[1]) - -def test_wrapcall_exception(): - l = [] - def fail(x): - raise ValueError - py.test.raises(ValueError, "repevent.wrapcall(l.append, fail, 1)") - assert len(l) == 2 - assert isinstance(l[0], repevent.CallStart) - assert isinstance(l[1], repevent.CallException) - -def test_reporter_methods_sanity(): - """ Checks if all the methods of reporter are sane - """ - from py.__.test.rsession.rsession import RemoteReporter - from py.__.test.rsession import repevent - - for method in dir(RemoteReporter): - - if method.startswith("report_") and method != "report_unknown": - assert method[len('report_'):] in repevent.__dict__ Deleted: /py/trunk/py/test/rsession/testing/test_reporter.py ============================================================================== --- /py/trunk/py/test/rsession/testing/test_reporter.py Mon Aug 27 11:02:50 2007 +++ (empty file) @@ -1,216 +0,0 @@ - -""" reporter tests. - -XXX there are a few disabled reporting tests because -they test for exact formatting as far as i can see. -I think it's rather better to directly invoke a -reporter and pass it some hand-prepared events to see -that running the reporter doesn't break shallowly. - -Otherwise, i suppose that some "visual" testing can usually be driven -manually by user-input. And when passing particular events -to a reporter it's also easier to check for one line -instead of having to know the order in which things are printed -etc. - - -""" - - -import py, os -from py.__.test.rsession.rsession import LocalReporter, AbstractSession,\ - RemoteReporter -from py.__.test.rsession import repevent -from py.__.test.rsession.outcome import ReprOutcome, Outcome -from py.__.test.rsession.hostmanage import HostInfo -from py.__.test.rsession.box import Box -from py.__.test.rsession.testing.basetest import BasicRsessionTest -import sys -from StringIO import StringIO - -class DummyGateway(object): - def __init__(self, host): - self.host = host - -class DummyChannel(object): - def __init__(self, host): - self.gateway = DummyGateway(host) - -class AbstractTestReporter(BasicRsessionTest): - def prepare_outcomes(self): - # possible outcomes - try: - 1/0 - except: - exc = py.code.ExceptionInfo() - - outcomes = [Outcome(()), - Outcome(skipped=True), - Outcome(excinfo=exc), - Outcome()] - - outcomes = [ReprOutcome(outcome.make_repr()) for outcome in outcomes] - outcomes[3].signal = 11 - outcomes[0].passed = False - - return outcomes - - def report_received_item_outcome(self): - item = self.getexample("pass") - outcomes = self.prepare_outcomes() - - def boxfun(config, item, outcomes): - hosts = [HostInfo("localhost")] - r = self.reporter(config, hosts) - ch = DummyChannel(hosts[0]) - for outcome in outcomes: - r.report(repevent.ReceivedItemOutcome(ch, item, outcome)) - - cap = py.io.StdCaptureFD() - boxfun(self.config, item, outcomes) - out, err = cap.reset() - assert not err - return out - - def _test_module(self): - funcitem = self.getexample("pass") - moditem = self.getmod() - outcomes = self.prepare_outcomes() - - def boxfun(config, item, funcitem, outcomes): - hosts = [HostInfo('localhost')] - r = self.reporter(config, hosts) - r.report(repevent.ItemStart(item)) - ch = DummyChannel(hosts[0]) - for outcome in outcomes: - r.report(repevent.ReceivedItemOutcome(ch, funcitem, outcome)) - - cap = py.io.StdCaptureFD() - boxfun(self.config, moditem, funcitem, outcomes) - out, err = cap.reset() - assert not err - return out - - def _test_full_module(self): - tmpdir = py.test.ensuretemp("repmod") - tmpdir.ensure("__init__.py") - tmpdir.ensure("test_one.py").write(py.code.Source(""" - def test_x(): - pass - """)) - tmpdir.ensure("test_two.py").write(py.code.Source(""" - import py - py.test.skip("reason") - """)) - tmpdir.ensure("test_three.py").write(py.code.Source(""" - sadsadsa - """)) - - def boxfun(): - config = py.test.config._reparse([str(tmpdir)]) - rootcol = py.test.collect.Directory(tmpdir) - hosts = [HostInfo('localhost')] - r = self.reporter(config, hosts) - list(rootcol._tryiter(reporterror=lambda x : AbstractSession.reporterror(r.report, x))) - - cap = py.io.StdCaptureFD() - boxfun() - out, err = cap.reset() - assert not err - return out - - def test_failed_to_load(self): - tmpdir = py.test.ensuretemp("failedtoload") - tmpdir.ensure("__init__.py") - tmpdir.ensure("test_three.py").write(py.code.Source(""" - sadsadsa - """)) - def boxfun(): - config = py.test.config._reparse([str(tmpdir)]) - rootcol = py.test.collect.Directory(tmpdir) - host = HostInfo('localhost') - r = self.reporter(config, [host]) - r.report(repevent.TestStarted([host], config.topdir, ["a"])) - r.report(repevent.RsyncFinished()) - list(rootcol._tryiter(reporterror=lambda x : AbstractSession.reporterror(r.report, x))) - r.report(repevent.TestFinished()) - return r - - cap = py.io.StdCaptureFD() - r = boxfun() - out, err = cap.reset() - assert not err - assert out.find("1 failed in") != -1 - assert out.find("NameError: name 'sadsadsa' is not defined") != -1 - - def _test_still_to_go(self): - tmpdir = py.test.ensuretemp("stilltogo") - tmpdir.ensure("__init__.py") - cap = py.io.StdCaptureFD() - config = py.test.config._reparse([str(tmpdir)]) - hosts = [HostInfo(i) for i in ["host1", "host2", "host3"]] - r = self.reporter(config, hosts) - r.report(repevent.TestStarted(hosts, config.topdir, ["a", "b", "c"])) - for host in hosts: - r.report(repevent.HostGatewayReady(host, ["a", "b", "c"])) - for host in hosts: - for root in ["a", "b", "c"]: - r.report(repevent.HostRSyncRootReady(host, root)) - out, err = cap.reset() - assert not err - expected1 = "Test started, hosts: host1[0], host2[0], host3[0]" - assert out.find(expected1) != -1 - for expected in py.code.Source(""" - host1[0]: READY (still 2 to go) - host2[0]: READY (still 1 to go) - host3[0]: READY - """).lines: - expected = expected.strip() - assert out.find(expected) != -1 - -class TestLocalReporter(AbstractTestReporter): - reporter = LocalReporter - - def test_report_received_item_outcome(self): - assert self.report_received_item_outcome() == 'FsF.' - - def test_module(self): - output = self._test_module() - assert output.find("test_one") != -1 - assert output.endswith("FsF."), output - - def test_full_module(self): - received = self._test_full_module() - expected_lst = ["repmod/test_one.py", "FAILED TO LOAD MODULE", - "skipped", "reason"] - for i in expected_lst: - assert received.find(i) != -1 - -class TestRemoteReporter(AbstractTestReporter): - reporter = RemoteReporter - - def test_still_to_go(self): - self._test_still_to_go() - - def test_report_received_item_outcome(self): - val = self.report_received_item_outcome() - expected_lst = ["localhost", "FAILED", - "funcpass", "test_one", - "SKIPPED", - "PASSED"] - for expected in expected_lst: - assert val.find(expected) != -1 - - def test_module(self): - val = self._test_module() - expected_lst = ["localhost", "FAILED", - "funcpass", "test_one", - "SKIPPED", - "PASSED"] - for expected in expected_lst: - assert val.find(expected) != -1 - - def test_full_module(self): - val = self._test_full_module() - assert val.find("FAILED TO LOAD MODULE: repmod/test_three.py\n"\ - "\nSkipped ('reason') repmod/test_two.py") != -1 Modified: py/trunk/py/test/rsession/testing/test_rest.py ============================================================================== --- py/trunk/py/test/rsession/testing/test_rest.py (original) +++ py/trunk/py/test/rsession/testing/test_rest.py Mon Aug 27 11:02:50 2007 @@ -3,13 +3,13 @@ """ import py -from py.__.test.rsession.testing.test_reporter import AbstractTestReporter,\ +from py.__.test.testing.test_reporter import AbstractTestReporter,\ DummyChannel -from py.__.test.rsession import repevent +from py.__.test import repevent from py.__.test.rsession.rest import RestReporter, NoLinkWriter from py.__.rest.rst import * from py.__.test.rsession.hostmanage import HostInfo -from py.__.test.rsession.outcome import Outcome +from py.__.test.outcome import SerializableOutcome class Container(object): def __init__(self, **args): @@ -109,7 +109,7 @@ """ def test_ReceivedItemOutcome_PASSED(self): - outcome = Outcome() + outcome = SerializableOutcome() item = Container(listnames=lambda: ['', 'foo.py', 'bar', '()', 'baz']) event = repevent.ReceivedItemOutcome(channel=ch, outcome=outcome, item=item) reporter.report(event) @@ -117,7 +117,7 @@ 'foo.py/bar()/baz\n\n') def test_ReceivedItemOutcome_SKIPPED(self): - outcome = Outcome(skipped="reason") + outcome = SerializableOutcome(skipped="reason") item = Container(listnames=lambda: ['', 'foo.py', 'bar', '()', 'baz']) event = repevent.ReceivedItemOutcome(channel=ch, outcome=outcome, item=item) reporter.report(event) @@ -125,7 +125,7 @@ 'foo.py/bar()/baz\n\n') def test_ReceivedItemOutcome_FAILED(self): - outcome = Outcome(excinfo="xxx") + outcome = SerializableOutcome(excinfo="xxx") item = Container(listnames=lambda: ['', 'foo.py', 'bar', '()', 'baz']) event = repevent.ReceivedItemOutcome(channel=ch, outcome=outcome, item=item) reporter.report(event) @@ -153,7 +153,7 @@ ), ] ) - outcome = Outcome(excinfo=excinfo) + outcome = SerializableOutcome(excinfo=excinfo) outcome.stdout = '' outcome.stderr = '' parent = Container(parent=None, fspath=py.path.local('.')) @@ -336,18 +336,15 @@ py.test.skip("Not implemented") def test_report_received_item_outcome(self): - py.test.skip("Relying on exact output matching") val = self.report_received_item_outcome() - expected = """\ -* localhost\: **FAILED** `traceback0`_\n py/test/rsession/testing/test\_slave.py/funcpass - -* localhost\: **SKIPPED** py/test/rsession/testing/test\_slave.py/funcpass - -* localhost\: **FAILED** `traceback1`_\n py/test/rsession/testing/test\_slave.py/funcpass + expected_list = [ + "**FAILED**", + "**SKIPPED**", + "**PASSED**", + "* localhost\:", + "`traceback0`_ test\_one.py/funcpass", + "test\_one.py/funcpass"] + for expected in expected_list: + assert val.find(expected) != -1 -* localhost\: **PASSED** py/test/rsession/testing/test\_slave.py/funcpass - -""" - print val - assert val == expected Modified: py/trunk/py/test/rsession/testing/test_rsession.py ============================================================================== --- py/trunk/py/test/rsession/testing/test_rsession.py (original) +++ py/trunk/py/test/rsession/testing/test_rsession.py Mon Aug 27 11:02:50 2007 @@ -3,7 +3,7 @@ """ import py -from py.__.test.rsession import repevent +from py.__.test import repevent from py.__.test.rsession.rsession import RSession from py.__.test.rsession.hostmanage import HostManager, HostInfo from py.__.test.rsession.testing.basetest import BasicRsessionTest @@ -14,23 +14,6 @@ if py.std.sys.platform == "win32": py.test.skip("rsession tests disabled for win32") -def test_example_tryiter(): - events = [] - tmpdir = py.test.ensuretemp("tryitertest") - tmpdir.ensure("a", "__init__.py") - tmpdir.ensure("conftest.py").write(py.code.Source(""" - import py - py.test.skip("Reason") - """)) - tmpdir.ensure("a", "test_empty.py").write(py.code.Source(""" - def test_empty(): - pass - """)) - rootcol = py.test.collect.Directory(tmpdir) - data = list(rootcol._tryiter(reporterror=events.append)) - assert len(events) == 2 - assert str(events[1][0].value).find("Reason") != -1 - class TestRSessionRemote(DirSetup, BasicRsessionTest): def test_example_distribution_minus_x(self): self.source.ensure("sub", "conftest.py").write(py.code.Source(""" @@ -57,7 +40,6 @@ testevents = [x for x in allevents if isinstance(x, repevent.ReceivedItemOutcome)] assert len(testevents) == 3 - assert rsession.checkfun() def test_distribution_rsync_roots_example(self): destdir = py.test.ensuretemp("example_dist_destdir") Modified: py/trunk/py/test/rsession/testing/test_slave.py ============================================================================== --- py/trunk/py/test/rsession/testing/test_slave.py (original) +++ py/trunk/py/test/rsession/testing/test_slave.py Mon Aug 27 11:02:50 2007 @@ -1,7 +1,7 @@ """ Testing the slave side node code (in a local way). """ from py.__.test.rsession.slave import SlaveNode, slave_main, setup -from py.__.test.rsession.outcome import ReprOutcome +from py.__.test.outcome import ReprOutcome import py, sys from py.__.test.rsession.testing.basetest import BasicRsessionTest Modified: py/trunk/py/test/rsession/web.py ============================================================================== --- py/trunk/py/test/rsession/web.py (original) +++ py/trunk/py/test/rsession/web.py Mon Aug 27 11:02:50 2007 @@ -15,7 +15,7 @@ import py from py.__.test.rsession.rsession import RSession -from py.__.test.rsession import repevent +from py.__.test import repevent from py.__.test import collect from py.__.test.rsession.webdata import json @@ -305,9 +305,8 @@ if not self.to_rsync[item.host]: self._host_ready(item) - def report_TestStarted(self, event): - # XXX: It overrides out self.hosts + # XXX: It overrides our self.hosts self.hosts = {} self.ready_hosts = {} for host in event.hosts: @@ -315,6 +314,13 @@ self.ready_hosts[host] = False self.start_event.set() self.pending_events.put(event) + + def report_TestFinished(self, event): + self.pending_events.put(event) + kill_server() + + report_InterruptedExecution = report_TestFinished + report_CrashedExecution = report_TestFinished def report(self, what): repfun = getattr(self, "report_" + what.__class__.__name__, @@ -330,13 +336,6 @@ print str(i)[2:-1] print excinfo -## try: -## self.wait_flag.acquire() -## self.pending_events.insert(0, event) -## self.wait_flag.notify() -## finally: -## self.wait_flag.release() - exported_methods = ExportedMethods() class TestHandler(BaseHTTPRequestHandler): @@ -400,7 +399,7 @@ js_name = py.path.local(__file__).dirpath("webdata").join("source.js") web_name = py.path.local(__file__).dirpath().join("webjs.py") if IMPORTED_PYPY and web_name.mtime() > js_name.mtime() or \ - (not js_name.check()) or 1: + (not js_name.check()): from py.__.test.rsession import webjs javascript_source = rpython2javascript(webjs, @@ -418,6 +417,34 @@ self.end_headers() self.wfile.write(data) +class WebReporter(object): + """ A simple wrapper, this file needs ton of refactoring + anyway, so this is just to satisfy things below + (and start to create saner interface as well) + """ + def __init__(self, config, hosts): + start_server_from_config(config) + + # rebind + report = exported_methods.report + __call__ = report + +def start_server_from_config(config): + if config.option.runbrowser: + port = socket.INADDR_ANY + else: + port = 8000 + + httpd = start_server(server_address = ('', port)) + port = httpd.server_port + if config.option.runbrowser: + import webbrowser, thread + # webbrowser.open() may block until the browser finishes or not + url = "http://localhost:%d" % (port,) + thread.start_new_thread(webbrowser.open, (url,)) + + return exported_methods.report + def start_server(server_address = ('', 8000), handler=TestHandler, start_new=True): httpd = HTTPServer(server_address, handler) Modified: py/trunk/py/test/rsession/webdata/source.js ============================================================================== Binary files. No diff available. Modified: py/trunk/py/test/session.py ============================================================================== --- py/trunk/py/test/session.py (original) +++ py/trunk/py/test/session.py Mon Aug 27 11:02:50 2007 @@ -1,33 +1,23 @@ import py from py.__.test.outcome import Outcome, Failed, Passed, Skipped +from py.__.test.reporter import choose_reporter, TestReporter -class Session(object): - """ - A Session gets test Items from Collectors, # executes the - Items and sends the Outcome to the Reporter. +class AbstractSession(object): + """ An abstract session executes collectors/items through a runner. """ def __init__(self, config): self._memo = [] self.config = config self._keyword = config.option.keyword - def shouldclose(self): - return False - - def header(self, colitems): - """ setup any neccessary resources ahead of the test run. """ - if not self.config.option.nomagic: - py.magic.invoke(assertion=1) - - def footer(self, colitems): - """ teardown any resources after a test run. """ - py.test.collect.Function._state.teardown_all() - if not self.config.option.nomagic: - py.magic.revoke(assertion=1) - def fixoptions(self): """ check, fix and determine conflicting options. """ - option = self.config.option + option = self.config.option + if option.runbrowser and not option.startserver: + #print "--runbrowser implies --startserver" + option.startserver = True + if self.config.getvalue("dist_boxed") and option.dist: + option.boxed = True # implied options if option.usepdb: if not option.nocapture: @@ -43,6 +33,34 @@ if option.keyword_oneshot and not option.keyword: raise ValueError, "--keyword-oneshot makes sense only when --keyword is supplied" + def init_reporter(self, reporter, config, hosts): + if reporter is None: + reporter = choose_reporter(config)(config, hosts) + else: + reporter = TestReporter(reporter) + checkfun = lambda : self.config.option.exitfirst and \ + reporter.was_failure() + return reporter, checkfun + +class Session(AbstractSession): + """ + A Session gets test Items from Collectors, # executes the + Items and sends the Outcome to the Reporter. + """ + def shouldclose(self): + return False + + def header(self, colitems): + """ setup any neccessary resources ahead of the test run. """ + if not self.config.option.nomagic: + py.magic.invoke(assertion=1) + + def footer(self, colitems): + """ teardown any resources after a test run. """ + py.test.collect.Function._state.teardown_all() + if not self.config.option.nomagic: + py.magic.revoke(assertion=1) + def start(self, colitem): """ hook invoked before each colitem.run() invocation. """ Modified: py/trunk/py/test/testing/test_collect.py ============================================================================== --- py/trunk/py/test/testing/test_collect.py (original) +++ py/trunk/py/test/testing/test_collect.py Mon Aug 27 11:02:50 2007 @@ -7,10 +7,6 @@ mod.datadir = setupdatadir() mod.tmpdir = py.test.ensuretemp('test_collect') -def skipboxed(): - if py.test.config.option.boxed: - py.test.skip("test does not work with boxed tests") - def test_failing_import_execfile(): dest = datadir / 'failingimport.py' col = py.test.collect.Module(dest) @@ -375,10 +371,6 @@ py.test.fail("should not have raised: %s" %(exc,)) l = [] - list(col._tryiter(reporterror=l.append)) - assert len(l) == 2 - excinfo, item = l[-1] - assert isinstance(excinfo, py.code.ExceptionInfo) def test_tryiter_handles_keyboardinterrupt(): tmp = py.test.ensuretemp("tryiterkeyboard") @@ -416,9 +408,25 @@ """)) tmp.ensure("__init__.py") col = py.test.collect.Module(tmp.join("test_one.py")) - errors = [] - l = list(col._tryiter(reporterror=errors.append)) - assert len(errors) == 2 + assert len(col.join('test_one').run()) == 3 + +def test_generator_setup_invoked_twice(): + py.test.skip("Test for generators not invoking setup, needs thinking") + tmp = py.test.ensuretemp("generator_setup_invoke") + tmp.ensure("test_one.py").write(py.code.Source(""" + def setup_module(mod): + mod.x = [] + + def setup_function(fun): + x.append(1) + + def test_one(): + yield lambda: None + """)) + tmp.ensure("__init__.py") + col = py.test.collect.Module(tmp.join("test_one.py")) + l = list(col._tryiter()) + assert not hasattr(col.obj, 'x') def test_check_collect_hashes(): tmp = py.test.ensuretemp("check_collect_hashes") Modified: py/trunk/py/test/testing/test_config.py ============================================================================== --- py/trunk/py/test/testing/test_config.py (original) +++ py/trunk/py/test/testing/test_config.py Mon Aug 27 11:02:50 2007 @@ -2,7 +2,6 @@ import py from py.__.test.config import gettopdir -from py.__.test.testing.test_collect import skipboxed def test_tmpdir(): d1 = py.test.ensuretemp('hello')