From hpk at codespeak.net Fri Feb 1 10:22:57 2008 From: hpk at codespeak.net (hpk at codespeak.net) Date: Fri, 1 Feb 2008 10:22:57 +0100 (CET) Subject: [py-svn] r51163 - py/branch/event/py/test2/testing Message-ID: <20080201092257.D9B4E1684CF@codespeak.net> Author: hpk Date: Fri Feb 1 10:22:56 2008 New Revision: 51163 Modified: py/branch/event/py/test2/testing/test_remote.py Log: disabling the last failing output-checking test Modified: py/branch/event/py/test2/testing/test_remote.py ============================================================================== --- py/branch/event/py/test2/testing/test_remote.py (original) +++ py/branch/event/py/test2/testing/test_remote.py Fri Feb 1 10:22:56 2008 @@ -15,13 +15,15 @@ ['--exec=' + py.std.sys.executable, o]) session = config.initsession() - allevents = getevents_runmain(session) - print allevents - failures = [x for x in allevents - if isinstance(x, repevent.ReceivedItemOutcome)] + #allevents = getevents_runmain(session) + #print allevents + #failures = [x for x in allevents + # if isinstance(x, repevent.ReceivedItemOutcome)] + failures = session.main() assert failures def test_looponfailing(self): + py.test.skip("fix output checking tests to check for events") o = tmpdir.ensure('looponfailing', dir=1) tfile = o.join('test_looponfailing.py') tfile.write(py.code.Source(""" @@ -30,6 +32,9 @@ """)) print py.std.sys.executable config = py.test2.config._reparse(['--looponfailing', str(o)]) + session = config.initsession() + failures = session.main() + cls = config._getsessionclass() out = py.std.Queue.Queue() session = cls(config, out.put) From hpk at codespeak.net Fri Feb 1 11:01:26 2008 From: hpk at codespeak.net (hpk at codespeak.net) Date: Fri, 1 Feb 2008 11:01:26 +0100 (CET) Subject: [py-svn] r51166 - in py/branch/event/py/test2: . testing Message-ID: <20080201100126.9454D168469@codespeak.net> Author: hpk Date: Fri Feb 1 11:01:25 2008 New Revision: 51166 Modified: py/branch/event/py/test2/collect.py py/branch/event/py/test2/repevent.py py/branch/event/py/test2/session.py py/branch/event/py/test2/testing/test_session.py Log: refactor itemgen to produce these events: * CollectionStart * CollectionFailure * CollectionFinish and DeselectedTest (previous 'SkippedTryiter' aka "Skipped by keyword") Modified: py/branch/event/py/test2/collect.py ============================================================================== --- py/branch/event/py/test2/collect.py (original) +++ py/branch/event/py/test2/collect.py Fri Feb 1 11:01:25 2008 @@ -169,19 +169,19 @@ newl.append(x.name) return ".".join(newl) - def _skipbykeyword(self, keyword): - """ raise Skipped() exception if the given keyword - matches for this collector. + def _skipbykeyword(self, keywordexpr): + """ return True if they given keyword expression means to + skip this collector/item. """ - if not keyword: + if not keywordexpr: return chain = self.listchain() - for key in filter(None, keyword.split()): + for key in filter(None, keywordexpr.split()): eor = key[:1] == '-' if eor: key = key[1:] if not (eor ^ self._matchonekeyword(key, chain)): - py.test2.skip("test not selected by keyword %r" %(keyword,)) + return True def _matchonekeyword(self, key, chain): elems = key.split(".") Modified: py/branch/event/py/test2/repevent.py ============================================================================== --- py/branch/event/py/test2/repevent.py (original) +++ py/branch/event/py/test2/repevent.py Fri Feb 1 11:01:25 2008 @@ -60,20 +60,20 @@ def __init__(self): self.timeend = time.time() -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 +class DeselectedTest(ReportEvent): + def __init__(self, item, keywordexpr): self.item = item + self.keywordexpr = keywordexpr class CollectionStart(ReportEvent): def __init__(self, collector): self.collector = collector +class CollectionFailure(ReportEvent): + def __init__(self, collector, excinfo): + self.excinfo = excinfo + self.collector = collector + class CollectionFinish(ReportEvent): def __init__(self, collector): self.collector = collector Modified: py/branch/event/py/test2/session.py ============================================================================== --- py/branch/event/py/test2/session.py (original) +++ py/branch/event/py/test2/session.py Fri Feb 1 11:01:25 2008 @@ -15,41 +15,31 @@ and tells reporter about that """ -try: - GeneratorExit -except NameError: - GeneratorExit = StopIteration # I think +GeneratorExit = py.builtin.GeneratorExit -def itemgen(session, colitems, keyword=None): +def itemgen(session, colitems, keywordexpr=None): hub = session.config.hub stopitems = py.test2.collect.Item # XXX should be generator here as well - while 1: - if not colitems: - break + while colitems: next = colitems.pop(0) if isinstance(next, stopitems): - try: - next._skipbykeyword(keyword) - yield next - except Skipped: + if next._skipbykeyword(keywordexpr): + hub.notify(repevent.DeselectedTest(next, keywordexpr)) if session.config.option.keyword_oneshot: - keyword = None - excinfo = py.code.ExceptionInfo() - hub.notify(repevent.SkippedTryiter(excinfo, next)) + keywordexpr = None + else: + yield next else: hub.notify(repevent.CollectionStart(next)) try: cols = [next.join(x) for x in next.run()] - for x in itemgen(session, cols, keyword): + for x in itemgen(session, cols, keywordexpr): yield x except (KeyboardInterrupt, SystemExit, GeneratorExit): raise except: excinfo = py.code.ExceptionInfo() - if excinfo.type is Skipped: - hub.notify(repevent.SkippedTryiter(excinfo, next)) - else: - hub.notify(repevent.FailedTryiter(excinfo, next)) + hub.notify(repevent.CollectionFailure(next, excinfo)) hub.notify(repevent.CollectionFinish(next)) class AbstractSession(object): Modified: py/branch/event/py/test2/testing/test_session.py ============================================================================== --- py/branch/event/py/test2/testing/test_session.py (original) +++ py/branch/event/py/test2/testing/test_session.py Fri Feb 1 11:01:25 2008 @@ -2,8 +2,7 @@ from setupdata import setup_module # sets up global 'tmpdir' from py.__.test2.outcome import Skipped, Failed, Passed, Outcome from py.__.test2.terminal.out import getout -from py.__.test2.repevent import ReceivedItemOutcome, SkippedTryiter,\ - FailedTryiter +from py.__.test2 import repevent from test_session2 import getevents_runmain @@ -19,7 +18,7 @@ ) def getoutcomes(all): - return [i.outcome for i in all if isinstance(i, ReceivedItemOutcome)] + return [i.outcome for i in all if isinstance(i, repevent.ReceivedItemOutcome)] def getpassed(all): @@ -27,11 +26,11 @@ def getskipped(all): return [i for i in getoutcomes(all) if i.skipped] + \ - [i for i in all if isinstance(i, SkippedTryiter)] + [i for i in all if isinstance(i, repevent.DeselectedTest)] def getfailed(all): return [i for i in getoutcomes(all) if i.excinfo] + \ - [i for i in all if isinstance(i, FailedTryiter)] + [i for i in all if isinstance(i, repevent.CollectionFailure)] def test_conflict_options(): for spec in conflict_options: @@ -78,7 +77,7 @@ '-s', '-k', keyword]) session = config._getsessionclass()(config) all = getevents_runmain(session) - outcomes = [i for i in all if isinstance(i, ReceivedItemOutcome)] + outcomes = [i for i in all if isinstance(i, repevent.ReceivedItemOutcome)] assert len(getfailed(all)) == 1 assert outcomes[0].item.name == name l = getskipped(all) @@ -110,7 +109,7 @@ all = getevents_runmain(session) print "keyword", repr(keyword) l = getpassed(all) - outcomes = [i for i in all if isinstance(i, ReceivedItemOutcome)] + outcomes = [i for i in all if isinstance(i, repevent.ReceivedItemOutcome)] assert len(l) == 1 assert outcomes[0].item.name == 'test_2' l = getskipped(all) From hpk at codespeak.net Fri Feb 1 11:20:19 2008 From: hpk at codespeak.net (hpk at codespeak.net) Date: Fri, 1 Feb 2008 11:20:19 +0100 (CET) Subject: [py-svn] r51167 - in py/branch/event/py/test2: . rsession rsession/testing testing Message-ID: <20080201102019.6C7BB1684CF@codespeak.net> Author: hpk Date: Fri Feb 1 11:20:17 2008 New Revision: 51167 Modified: py/branch/event/py/test2/collect.py py/branch/event/py/test2/collectonly.py py/branch/event/py/test2/item.py py/branch/event/py/test2/outcome.py py/branch/event/py/test2/reporter.py py/branch/event/py/test2/rsession/hostmanage.py py/branch/event/py/test2/rsession/local.py py/branch/event/py/test2/rsession/master.py py/branch/event/py/test2/rsession/rest.py py/branch/event/py/test2/rsession/rsession.py py/branch/event/py/test2/rsession/slave.py py/branch/event/py/test2/rsession/testing/test_rest.py py/branch/event/py/test2/rsession/web.py py/branch/event/py/test2/rsession/webjs.py py/branch/event/py/test2/session.py py/branch/event/py/test2/testing/test_itemgen.py py/branch/event/py/test2/testing/test_session2.py Log: * getting rid of many unused imports * more event naming cleanup Modified: py/branch/event/py/test2/collect.py ============================================================================== --- py/branch/event/py/test2/collect.py (original) +++ py/branch/event/py/test2/collect.py Fri Feb 1 11:20:17 2008 @@ -25,7 +25,6 @@ """ from __future__ import generators import py -from py.__.test2.outcome import Skipped def configproperty(name): def fget(self): Modified: py/branch/event/py/test2/collectonly.py ============================================================================== --- py/branch/event/py/test2/collectonly.py (original) +++ py/branch/event/py/test2/collectonly.py Fri Feb 1 11:20:17 2008 @@ -21,12 +21,11 @@ def report_ItemFinish(self, event): self.indent -= 2 - def report_FailedTryiter(self, event): + def report_CollectionFailed(self, event): self.out.line(" " * self.indent + "- FAILED TO LOAD MODULE -") - def report_SkippedTryiter(self, event): + def report_DeselectedTest(self, event): self.out.line(" " * self.indent + "- skipped -") def summary(self): self.out.sep("=", "Total time: %.1f" % (self.timeend - self.timestart)) - Modified: py/branch/event/py/test2/item.py ============================================================================== --- py/branch/event/py/test2/item.py (original) +++ py/branch/event/py/test2/item.py Fri Feb 1 11:20:17 2008 @@ -1,7 +1,7 @@ import py from inspect import isclass, ismodule -from py.__.test2.outcome import Skipped, Failed, Passed +from py.__.test2 import outcome from py.__.test2.collect import FunctionMixin _dummy = object() @@ -72,10 +72,10 @@ def skip(msg=""): """ skip with the given Message. """ __tracebackhide__ = True - raise Skipped(msg=msg) + raise outcome.Skipped(msg=msg) def fail(msg="unknown failure"): """ fail with the given Message. """ __tracebackhide__ = True - raise Failed(msg=msg) + raise outcome.Failed(msg=msg) Modified: py/branch/event/py/test2/outcome.py ============================================================================== --- py/branch/event/py/test2/outcome.py (original) +++ py/branch/event/py/test2/outcome.py Fri Feb 1 11:20:17 2008 @@ -3,7 +3,7 @@ serialization of outcomes """ -import py, sys +import py class Outcome: def __init__(self, msg=None, excinfo=None): Modified: py/branch/event/py/test2/reporter.py ============================================================================== --- py/branch/event/py/test2/reporter.py (original) +++ py/branch/event/py/test2/reporter.py Fri Feb 1 11:20:17 2008 @@ -231,7 +231,7 @@ outcome = event.outcome text = outcome.skipped.value itemname = repr(outcome.skipped.traceback[-2]).split("\n")[0] - elif isinstance(event, repevent.SkippedTryiter): + elif isinstance(event, repevent.DeselectedTest): text = str(event.excinfo.value) itemname = "/".join(colitem.listnames()) if text not in texts: @@ -277,7 +277,7 @@ (total, skipped_str, failed_str, self.timeend - self.timestart, self.timersync - self.timestart)) - def report_SkippedTryiter(self, event): + def report_DeselectedTest(self, event): #event.outcome.excinfo.source = self.skipped_tests_outcome.append(event) @@ -337,7 +337,7 @@ # argh! bad hack, need to fix it self.failed[self.hosts[0]] += 1 - def report_SkippedTryiter(self, event): + def report_DeselectedTest(self, event): self.out.line("Skipped (%s) %s\n" % (str(event.excinfo.value), "/". join(event.item.listnames()))) @@ -376,7 +376,7 @@ self.out.sep("=", " %d test run%s%s in %.2fs" % (total, skipped_str, failed_str, self.timeend - self.timestart)) - def report_SkippedTryiter(self, event): + def report_DeselectedTest(self, event): #self.show_item(event.item, False) if isinstance(event.item, py.test2.collect.Module): self.out.write("- skipped (%s)" % event.excinfo.value) Modified: py/branch/event/py/test2/rsession/hostmanage.py ============================================================================== --- py/branch/event/py/test2/rsession/hostmanage.py (original) +++ py/branch/event/py/test2/rsession/hostmanage.py Fri Feb 1 11:20:17 2008 @@ -1,10 +1,7 @@ -import sys, os import py -import time -import thread, threading +import sys, os from py.__.test2.rsession.master import MasterNode from py.__.test2.rsession.slave import setup_slave - from py.__.test2 import repevent class HostInfo(object): Modified: py/branch/event/py/test2/rsession/local.py ============================================================================== --- py/branch/event/py/test2/rsession/local.py (original) +++ py/branch/event/py/test2/rsession/local.py Fri Feb 1 11:20:17 2008 @@ -1,4 +1,3 @@ - """ local-only operations """ Modified: py/branch/event/py/test2/rsession/master.py ============================================================================== --- py/branch/event/py/test2/rsession/master.py (original) +++ py/branch/event/py/test2/rsession/master.py Fri Feb 1 11:20:17 2008 @@ -4,8 +4,6 @@ import py from py.__.test2.outcome import ReprOutcome from py.__.test2 import repevent -from py.__.test2.outcome import Skipped -from py.builtin import GeneratorExit class MasterNode(object): def __init__(self, channel, notify): Modified: py/branch/event/py/test2/rsession/rest.py ============================================================================== --- py/branch/event/py/test2/rsession/rest.py (original) +++ py/branch/event/py/test2/rsession/rest.py Fri Feb 1 11:20:17 2008 @@ -132,7 +132,7 @@ outcome = event.outcome text = outcome.skipped itemname = self.get_item_name(event, colitem) - elif isinstance(event, repevent.SkippedTryiter): + elif isinstance(event, repevent.DeselectedTest): text = str(event.excinfo.value) itemname = "/".join(colitem.listnames()) if text not in texts: Modified: py/branch/event/py/test2/rsession/rsession.py ============================================================================== --- py/branch/event/py/test2/rsession/rsession.py (original) +++ py/branch/event/py/test2/rsession/rsession.py Fri Feb 1 11:20:17 2008 @@ -10,11 +10,8 @@ from py.__.test2 import repevent from py.__.test2.rsession.master import dispatch_loop -from py.__.test2.rsession.hostmanage import HostInfo, HostManager -from py.__.test2.rsession.local import local_loop, plain_runner, apigen_runner,\ - box_runner +from py.__.test2.rsession.hostmanage import HostManager from py.__.test2.session import AbstractSession, itemgen -from py.__.test2.outcome import Skipped, Failed class RSession(AbstractSession): """ Remote version of session Modified: py/branch/event/py/test2/rsession/slave.py ============================================================================== --- py/branch/event/py/test2/rsession/slave.py (original) +++ py/branch/event/py/test2/rsession/slave.py Fri Feb 1 11:20:17 2008 @@ -6,7 +6,6 @@ from py.__.test2.executor import RunExecutor, BoxExecutor, AsyncExecutor from py.__.test2.outcome import SerializableOutcome from py.__.test2.outcome import Skipped -import thread import os class SlaveNode(object): Modified: py/branch/event/py/test2/rsession/testing/test_rest.py ============================================================================== --- py/branch/event/py/test2/rsession/testing/test_rest.py (original) +++ py/branch/event/py/test2/rsession/testing/test_rest.py Fri Feb 1 11:20:17 2008 @@ -178,7 +178,7 @@ class FakeOutcome(Container, repevent.ReceivedItemOutcome): pass - class FakeTryiter(Container, repevent.SkippedTryiter): + class FakeTryiter(Container, repevent.DeselectedTest): pass reporter.skips() Modified: py/branch/event/py/test2/rsession/web.py ============================================================================== --- py/branch/event/py/test2/rsession/web.py (original) +++ py/branch/event/py/test2/rsession/web.py Fri Feb 1 11:20:17 2008 @@ -250,7 +250,7 @@ args = {'hostname' : event.host.hostname, 'hostkey' : event.host.hostid} elif isinstance(event, repevent.FailedTryiter): args = add_item(event) - elif isinstance(event, repevent.SkippedTryiter): + elif isinstance(event, repevent.DeselectedTest): args = add_item(event) args['reason'] = str(event.excinfo.value) else: Modified: py/branch/event/py/test2/rsession/webjs.py ============================================================================== --- py/branch/event/py/test2/rsession/webjs.py (original) +++ py/branch/event/py/test2/rsession/webjs.py Fri Feb 1 11:20:17 2008 @@ -222,7 +222,7 @@ module_part.appendChild(tr) item_name = msg['fullitemname'] exported_methods.show_fail(item_name, fail_come_back) - elif msg['type'] == 'SkippedTryiter': + elif msg['type'] == 'DeselectedTest': module_part = get_elem(msg['fullitemname']) if not module_part: glob.pending.append(msg) Modified: py/branch/event/py/test2/session.py ============================================================================== --- py/branch/event/py/test2/session.py (original) +++ py/branch/event/py/test2/session.py Fri Feb 1 11:20:17 2008 @@ -1,20 +1,15 @@ +""" basic test session implementation. + +* drives collection of tests +* triggers executions of tests +* produces events used by reporting +""" + import py -import sys -from py.__.test2.outcome import Outcome, Failed, Passed, Skipped from py.__.test2 import repevent -from py.__.test2.outcome import SerializableOutcome, ReprOutcome -from py.__.test2.reporter import LocalReporter +from py.__.test2.outcome import ReprOutcome from py.__.test2.executor import RunExecutor, BoxExecutor -""" The session implementation - reporter version: - -* itemgen is responsible for iterating and telling reporter - about skipped and failed iterations (this is for collectors only), - this should be probably moved to session (for uniformity) -* session gets items which needs to be executed one after another - and tells reporter about that -""" - GeneratorExit = py.builtin.GeneratorExit def itemgen(session, colitems, keywordexpr=None): @@ -73,8 +68,6 @@ A Session gets test Items from Collectors, executes the Items and sends the Outcome to the Reporter. """ - reporterclass = LocalReporter - def shouldclose(self): return False @@ -116,7 +109,6 @@ finally: self.footer(colitems) return failures - return self.getitemoutcomepairs(Failed) def run(self, item): if not self.config.option.boxed: Modified: py/branch/event/py/test2/testing/test_itemgen.py ============================================================================== --- py/branch/event/py/test2/testing/test_itemgen.py (original) +++ py/branch/event/py/test2/testing/test_itemgen.py Fri Feb 1 11:20:17 2008 @@ -31,7 +31,7 @@ colitems = [py.test2.collect.Directory(self.tmp)] gen = itemgen(None, colitems, l.append) items = [i for i in gen] - assert len([i for i in l if isinstance(i, repevent.SkippedTryiter)]) == 1 + assert len([i for i in l if isinstance(i, repevent.DeselectedTest)]) == 1 assert len([i for i in l if isinstance(i, repevent.FailedTryiter)]) == 1 assert len(items) == 3 assert items[0].name == 'test_one' Modified: py/branch/event/py/test2/testing/test_session2.py ============================================================================== --- py/branch/event/py/test2/testing/test_session2.py (original) +++ py/branch/event/py/test2/testing/test_session2.py Fri Feb 1 11:20:17 2008 @@ -241,7 +241,7 @@ if isinstance(x, repevent.FailedTryiter)] assert len(failedtryiter) == 1 skippedtryiter = [x for x in allevents - if isinstance(x, repevent.SkippedTryiter)] + if isinstance(x, repevent.DeselectedTest)] assert len(skippedtryiter) == 1 From hpk at codespeak.net Fri Feb 1 22:50:58 2008 From: hpk at codespeak.net (hpk at codespeak.net) Date: Fri, 1 Feb 2008 22:50:58 +0100 (CET) Subject: [py-svn] r51194 - in py/branch/bugfix-0.9.0: . py/execnet Message-ID: <20080201215058.81969168074@codespeak.net> Author: hpk Date: Fri Feb 1 22:50:56 2008 New Revision: 51194 Added: py/branch/bugfix-0.9.0/ - copied from r50525, py/release/0.9.0/ Modified: py/branch/bugfix-0.9.0/py/execnet/gateway.py Log: * branching off 0.9.0 for bugfixing purposes * setting debug to true for execnet Modified: py/branch/bugfix-0.9.0/py/execnet/gateway.py ============================================================================== --- py/release/0.9.0/py/execnet/gateway.py (original) +++ py/branch/bugfix-0.9.0/py/execnet/gateway.py Fri Feb 1 22:50:56 2008 @@ -26,7 +26,7 @@ NamedThreadPool = py._thread.NamedThreadPool import os -debug = 0 # open('/tmp/execnet-debug-%d' % os.getpid() , 'wa') +debug = open('/tmp/execnet-debug-%d' % os.getpid() , 'wa') sysex = (KeyboardInterrupt, SystemExit) From hpk at codespeak.net Sat Feb 2 18:33:04 2008 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sat, 2 Feb 2008 18:33:04 +0100 (CET) Subject: [py-svn] r51217 - in py/branch/event/py/test2: . rsession rsession/testing testing Message-ID: <20080202173304.30C48168451@codespeak.net> Author: hpk Date: Sat Feb 2 18:33:02 2008 New Revision: 51217 Modified: py/branch/event/py/test2/collectonly.py py/branch/event/py/test2/outcome.py py/branch/event/py/test2/repevent.py py/branch/event/py/test2/reporter.py py/branch/event/py/test2/rsession/local.py py/branch/event/py/test2/rsession/master.py py/branch/event/py/test2/rsession/rest.py py/branch/event/py/test2/rsession/rsession.py py/branch/event/py/test2/rsession/testing/test_master.py py/branch/event/py/test2/rsession/testing/test_rest.py py/branch/event/py/test2/rsession/testing/test_rsession.py py/branch/event/py/test2/rsession/testing/test_webjs.py py/branch/event/py/test2/rsession/web.py py/branch/event/py/test2/rsession/webjs.py py/branch/event/py/test2/session.py py/branch/event/py/test2/testing/test_collect.py py/branch/event/py/test2/testing/test_collectonly.py py/branch/event/py/test2/testing/test_remote.py py/branch/event/py/test2/testing/test_reporter.py py/branch/event/py/test2/testing/test_session.py py/branch/event/py/test2/testing/test_session2.py Log: sorting out and renaming Events some more still all intermediate (but tests are passing) Modified: py/branch/event/py/test2/collectonly.py ============================================================================== --- py/branch/event/py/test2/collectonly.py (original) +++ py/branch/event/py/test2/collectonly.py Sat Feb 2 18:33:02 2008 @@ -11,7 +11,7 @@ super(LocalReporter, self).__init__(*args, **kwds) self.indent = 0 - def report_ReceivedItemOutcome(self, event): + def report_ItemFinish(self, event): pass def report_ItemStart(self, event): Modified: py/branch/event/py/test2/outcome.py ============================================================================== --- py/branch/event/py/test2/outcome.py (original) +++ py/branch/event/py/test2/outcome.py Sat Feb 2 18:33:02 2008 @@ -1,6 +1,6 @@ - -""" File defining possible outcomes of running and also -serialization of outcomes +""" + File defining possible outcomes of running and also + serialization of outcomes """ import py Modified: py/branch/event/py/test2/repevent.py ============================================================================== --- py/branch/event/py/test2/repevent.py (original) +++ py/branch/event/py/test2/repevent.py Sat Feb 2 18:33:02 2008 @@ -4,112 +4,118 @@ import py import time -def basic_report(msg_type, message): - print msg_type, message -# ---------------------------------------------------------------------- -# Reporting Events -# ---------------------------------------------------------------------- - -class ReportEvent(object): +class BaseEvent(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 ReceivedItemOutcome(ReportEvent): - def __init__(self, channel, item, outcome): - self.channel = channel - if channel: - self.host = channel.gateway.host +def timestamp(): + return time.time() + +# ---------------------------------------------------------------------- +# Basic Live Reporting Events +# ---------------------------------------------------------------------- + +class SessionStart(BaseEvent): + def __init__(self, session): + self.session = session + self.timestart = time.time() + +class SessionFinish(BaseEvent): + def __init__(self, session): + self.session = session + self.timeend = time.time() + +class CollectionStart(BaseEvent): + def __init__(self, collector): + self.collector = collector + +class CollectionFinish(BaseEvent): + def __init__(self, collector, excinfo=None): + self.collector = collector + self.excinfo = excinfo + +class DeselectedTest(BaseEvent): + def __init__(self, item, keywordexpr): self.item = item - self.outcome = outcome + self.keywordexpr = keywordexpr + +class ItemStart(BaseEvent): + def __init__(self, item): + self.item = item + self.time = timestamp() + +from outcome import Skipped +class ItemFinish(BaseEvent): + def __init__(self, item, excinfo=None): + self.item = item + self.time = timestamp() + self.excinfo = excinfo + self.passed = not excinfo + self.skipped = excinfo and excinfo.errisinstance(Skipped) + self.failed = not (self.passed or self.skipped) + +# ---------------------------------------------------------------------- +# Report of the run of a single test (might come from a disttributed run) +# ---------------------------------------------------------------------- + +class ItemTestReport(BaseEvent): + passed = failed = skipped = False + def __init__(self, trail, outcome, info=None): + self.trail = trail + assert outcome in ("passed", "failed", "skipped") + setattr(self, outcome, True) + self.outcome = outcome + self.info = info -class SendItem(ReportEvent): +# ---------------------------------------------------------------------- +# Distributed Testing Events +# ---------------------------------------------------------------------- + +class SendItem(BaseEvent): def __init__(self, channel, item): self.item = item self.channel = channel if channel: self.host = channel.gateway.host -class HostRSyncing(ReportEvent): +class HostRSyncing(BaseEvent): def __init__(self, host, root, remotepath, synced): self.host = host self.root = root self.remotepath = remotepath self.synced = synced -class HostGatewayReady(ReportEvent): +class RsyncFinished(BaseEvent): + def __init__(self): + self.time = timestamp() + +class HostGatewayReady(BaseEvent): def __init__(self, host, roots): self.host = host self.roots = roots -class HostRSyncRootReady(ReportEvent): +class HostRSyncRootReady(BaseEvent): def __init__(self, host, root): self.host = host self.root = root -class SessionStart(ReportEvent): - def __init__(self, hosts, config, roots): - self.hosts = hosts - self.roots = roots - self.timestart = time.time() - self.config = config - -class SessionFinish(ReportEvent): - def __init__(self): - self.timeend = time.time() - -class DeselectedTest(ReportEvent): - def __init__(self, item, keywordexpr): - self.item = item - self.keywordexpr = keywordexpr - -class CollectionStart(ReportEvent): - def __init__(self, collector): - self.collector = collector - -class CollectionFailure(ReportEvent): - def __init__(self, collector, excinfo): - self.excinfo = excinfo - self.collector = collector -class CollectionFinish(ReportEvent): - def __init__(self, collector): - self.collector = collector - -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 ItemFinish(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() +# ---------------------------------------------------------------------- +# XXX Extra Events XXX +# ---------------------------------------------------------------------- -class ImmediateFailure(ReportEvent): +class ImmediateFailure(BaseEvent): 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): +class InterruptedExecution(BaseEvent): def __init__(self): - self.timeend = time.time() + self.timeend = timestamp() -class CrashedExecution(ReportEvent): +class CrashedExecution(BaseEvent): def __init__(self): - self.timeend = time.time() + self.timeend = timestamp() Modified: py/branch/event/py/test2/reporter.py ============================================================================== --- py/branch/event/py/test2/reporter.py (original) +++ py/branch/event/py/test2/reporter.py Sat Feb 2 18:33:02 2008 @@ -177,7 +177,7 @@ if self.failed_tests_outcome: self.out.sep("=", " FAILURES ") for event in self.failed_tests_outcome: - if isinstance(event, repevent.ReceivedItemOutcome): + if isinstance(event, repevent.ItemFinish): host = self.gethost(event) self.out.sep('_', "%s on %s" % (" ".join(event.item.listnames()), host)) @@ -227,7 +227,7 @@ texts = {} for event in self.skipped_tests_outcome: colitem = event.item - if isinstance(event, repevent.ReceivedItemOutcome): + if isinstance(event, repevent.ItemFinish): outcome = event.outcome text = outcome.skipped.value itemname = repr(outcome.skipped.traceback[-2]).split("\n")[0] @@ -285,7 +285,7 @@ pass # XXX: right now we do not do anything with it - def report_ReceivedItemOutcome(self, event): + def report_ItemFinish(self, event): host = event.host hostrepr = self._hostrepr(host) if event.outcome.passed: @@ -390,7 +390,7 @@ self.failed_tests_outcome.append(event) self.failed += 1 - def report_ReceivedItemOutcome(self, event): + def report_ItemFinish(self, event): if event.outcome.passed: self.passed += 1 self.out.write(".") Modified: py/branch/event/py/test2/rsession/local.py ============================================================================== --- py/branch/event/py/test2/rsession/local.py (original) +++ py/branch/event/py/test2/rsession/local.py Sat Feb 2 18:33:02 2008 @@ -64,6 +64,6 @@ if shouldstop(): return outcome = runner(item, session, reporter) - reporter(repevent.ReceivedItemOutcome(None, item, outcome)) + reporter(repevent.ItemFinish(None, item, outcome)) except StopIteration: break Modified: py/branch/event/py/test2/rsession/master.py ============================================================================== --- py/branch/event/py/test2/rsession/master.py (original) +++ py/branch/event/py/test2/rsession/master.py Sat Feb 2 18:33:02 2008 @@ -19,8 +19,14 @@ def receive_result(self, outcomestring, item): repr_outcome = ReprOutcome(outcomestring) # send finish report - self.notify(repevent.ReceivedItemOutcome( - self.channel, item, repr_outcome)) + # XXX the following should be done by outcome serializing + if repr_outcome.passed: + outcome = "passed" + elif repr_outcome.skipped: + outcome = "skipped" + else: + outcome = "failed" + self.notify(repevent.ItemTestReport(item, outcome)) def send(self, item): try: Modified: py/branch/event/py/test2/rsession/rest.py ============================================================================== --- py/branch/event/py/test2/rsession/rest.py (original) +++ py/branch/event/py/test2/rsession/rest.py Sat Feb 2 18:33:02 2008 @@ -102,7 +102,7 @@ # yet self.out.write(self.rest.render_links()) - def report_ReceivedItemOutcome(self, event): + def report_ItemFinish(self, event): host = self.gethost(event) if event.outcome.passed: status = [Strong("PASSED")] @@ -128,7 +128,7 @@ texts = {} for event in self.skipped_tests_outcome: colitem = event.item - if isinstance(event, repevent.ReceivedItemOutcome): + if isinstance(event, repevent.ItemFinish): outcome = event.outcome text = outcome.skipped itemname = self.get_item_name(event, colitem) @@ -159,7 +159,7 @@ for i, event in enumerate(self.failed_tests_outcome): if i > 0: self.add_rest(Transition()) - if isinstance(event, repevent.ReceivedItemOutcome): + if isinstance(event, repevent.ItemFinish): host = self.get_host(event) itempath = self.get_path_from_item(event.item) root = self.get_rootpath(event.item) Modified: py/branch/event/py/test2/rsession/rsession.py ============================================================================== --- py/branch/event/py/test2/rsession/rsession.py (original) +++ py/branch/event/py/test2/rsession/rsession.py Sat Feb 2 18:33:02 2008 @@ -41,7 +41,7 @@ """ main loop for running tests. """ hm = HostManager(self.config) hub = self.config.hub - hub.notify(repevent.SessionStart(hm.hosts, self.config, hm.roots)) + hub.notify(repevent.SessionStart(self)) try: nodes = hm.setup_hosts() try: @@ -56,7 +56,7 @@ print "tearing down nodes" hm.teardown_hosts(nodes) - hub.notify(repevent.SessionFinish()) + hub.notify(repevent.SessionFinish(self)) except (KeyboardInterrupt, SystemExit): hub.notify(repevent.InterruptedExecution()) raise Modified: py/branch/event/py/test2/rsession/testing/test_master.py ============================================================================== --- py/branch/event/py/test2/rsession/testing/test_master.py (original) +++ py/branch/event/py/test2/rsession/testing/test_master.py Sat Feb 2 18:33:02 2008 @@ -68,7 +68,8 @@ ch.callback(SerializableOutcome(excinfo=excinfo).make_repr()) assert len(reportlist) == 4 received = [i for i in reportlist - if isinstance(i, repevent.ReceivedItemOutcome)] + if isinstance(i, repevent.ItemTestReport)] + py.test.skip("XXX fix master tests") assert received[0].outcome.passed assert not received[1].outcome.passed @@ -139,7 +140,7 @@ def test_slave_running(self): py.test.skip("XXX test broken, needs refactoring") def simple_report(event): - if not isinstance(event, repevent.ReceivedItemOutcome): + if not isinstance(event, repevent.ItemFinish): return item = event.item if item.code.name == 'funcpass': @@ -169,7 +170,7 @@ def test_slave_running_interrupted(): py.test.skip("XXX test broken, needs refactoring") #def simple_report(event): - # if not isinstance(event, repevent.ReceivedItemOutcome): + # if not isinstance(event, repevent.ItemFinish): # return # item = event.item # if item.code.name == 'funcpass': Modified: py/branch/event/py/test2/rsession/testing/test_rest.py ============================================================================== --- py/branch/event/py/test2/rsession/testing/test_rest.py (original) +++ py/branch/event/py/test2/rsession/testing/test_rest.py Sat Feb 2 18:33:02 2008 @@ -111,33 +111,33 @@ """ - def test_ReceivedItemOutcome_PASSED(self): + def test_ItemFinish_PASSED(self): outcome = SerializableOutcome() item = Container(listnames=lambda: ['', 'foo.py', 'bar', '()', 'baz']) - event = repevent.ReceivedItemOutcome(channel=ch, outcome=outcome, item=item) + event = repevent.ItemFinish(channel=ch, outcome=outcome, item=item) reporter.report(event) assert stdout.getvalue() == ('* localhost\\: **PASSED** ' 'foo.py/bar()/baz\n\n') - def test_ReceivedItemOutcome_SKIPPED(self): + def test_ItemFinish_SKIPPED(self): outcome = SerializableOutcome(skipped="reason") item = Container(listnames=lambda: ['', 'foo.py', 'bar', '()', 'baz']) - event = repevent.ReceivedItemOutcome(channel=ch, outcome=outcome, item=item) + event = repevent.ItemFinish(channel=ch, outcome=outcome, item=item) reporter.report(event) assert stdout.getvalue() == ('* localhost\\: **SKIPPED** ' 'foo.py/bar()/baz\n\n') - def test_ReceivedItemOutcome_FAILED(self): + def test_ItemFinish_FAILED(self): outcome = SerializableOutcome(excinfo="xxx") item = Container(listnames=lambda: ['', 'foo.py', 'bar', '()', 'baz']) - event = repevent.ReceivedItemOutcome(channel=ch, outcome=outcome, item=item) + event = repevent.ItemFinish(channel=ch, outcome=outcome, item=item) reporter.report(event) assert stdout.getvalue() == """\ * localhost\: **FAILED** `traceback0`_ foo.py/bar()/baz """ - def test_ReceivedItemOutcome_FAILED_stdout(self): + def test_ItemFinish_FAILED_stdout(self): excinfo = Container( typename='FooError', value='A foo has occurred', @@ -162,7 +162,7 @@ parent = Container(parent=None, fspath=py.path.local('.')) item = Container(listnames=lambda: ['', 'foo.py', 'bar', '()', 'baz'], parent=parent, fspath=py.path.local('foo')) - event = repevent.ReceivedItemOutcome(channel=ch, outcome=outcome, + event = repevent.ItemFinish(channel=ch, outcome=outcome, item=item) reporter.report(event) reporter.timestart = 10 @@ -175,7 +175,7 @@ assert out.find('') > -1 def test_skips(self): - class FakeOutcome(Container, repevent.ReceivedItemOutcome): + class FakeOutcome(Container, repevent.ItemFinish): pass class FakeTryiter(Container, repevent.DeselectedTest): @@ -200,7 +200,7 @@ """ def test_failures(self): - class FakeOutcome(Container, repevent.ReceivedItemOutcome): + class FakeOutcome(Container, repevent.ItemFinish): pass parent = Container(parent=None, fspath=py.path.local('.')) Modified: py/branch/event/py/test2/rsession/testing/test_rsession.py ============================================================================== --- py/branch/event/py/test2/rsession/testing/test_rsession.py (original) +++ py/branch/event/py/test2/rsession/testing/test_rsession.py Sat Feb 2 18:33:02 2008 @@ -42,7 +42,7 @@ config.hub.append(f) allevents = getevents_runmain(rsession) testevents = [x for x in allevents - if isinstance(x, repevent.ReceivedItemOutcome)] + if isinstance(x, repevent.ItemTestReport)] assert len(testevents) == 3 def test_distribution_rsync_roots_example(self): @@ -76,28 +76,15 @@ rsession = RSession(config) allevents = getevents_runmain(rsession) testevents = [x for x in allevents - if isinstance(x, repevent.ReceivedItemOutcome)] + if isinstance(x, repevent.ItemTestReport)] assert len(testevents) print testevents - passevents = [i for i in testevents if i.outcome.passed] - failevents = [i for i in testevents if i.outcome.excinfo] - skippedevents = [i for i in testevents if i.outcome.skipped] + passevents = [i for i in testevents if i.passed] + failevents = [i for i in testevents if i.failed] + skippedevents = [i for i in testevents if i.skipped] assert len(testevents) == 5 assert len(passevents) == 2 assert len(failevents) == 3 - tb = failevents[0].outcome.excinfo.traceback - assert str(tb[0].path).find("test_one") != -1 - assert tb[0].source.find("test_2") != -1 - assert failevents[0].outcome.excinfo.typename == 'AssertionError' - tb = failevents[1].outcome.excinfo.traceback - assert str(tb[0].path).find("test_one") != -1 - assert tb[0].source.find("test_3") != -1 - assert failevents[1].outcome.excinfo.typename == 'ValueError' - assert failevents[1].outcome.excinfo.value == '23' - tb = failevents[2].outcome.excinfo.traceback - assert failevents[2].outcome.excinfo.typename == 'TypeError' - assert str(tb[0].path).find("executor") != -1 - assert tb[0].source.find("execute") != -1 def test_setup_teardown_run_ssh(self): hosts = [HostInfo('localhost:%s' % self.dest)] @@ -117,20 +104,20 @@ events = [] while len(events) < 4 * len(nodes): item = queue.get(timeout=0.5) - if isinstance(item, repevent.ReceivedItemOutcome): + if isinstance(item, repevent.ItemTestReport): events.append(item) print "got all events", events hm.teardown_hosts(nodes) - passed = [i for i in events - if i.outcome.passed] - skipped = [i for i in events - if i.outcome.skipped] + passed = [ev for ev in events + if ev.passed] + skipped = [ev for ev in events + if ev.skipped] assert len(passed) == 2 * len(nodes) assert len(skipped) == len(nodes) assert len(events) == 4 * len(nodes) # one of passed for each node has non-empty stdout - passed_stdout = [i for i in passed if i.outcome.stdout.find('samfing') != -1] - assert len(passed_stdout) == len(nodes), passed + #passed_stdout = [i for i in passed if i.outcome.stdout.find('samfing') != -1] + #assert len(passed_stdout) == len(nodes), passed def test_nice_level(self): """ Tests if nice level behaviour is ok @@ -151,8 +138,8 @@ rsession = RSession(config) allevents = getevents_runmain(rsession) testevents = [x for x in allevents - if isinstance(x, repevent.ReceivedItemOutcome)] - passevents = [x for x in testevents if x.outcome.passed] + if isinstance(x, repevent.ItemTestReport)] + passevents = [x for x in testevents if x.passed] assert len(passevents) == 1 def test_rsession_no_disthost(): Modified: py/branch/event/py/test2/rsession/testing/test_webjs.py ============================================================================== --- py/branch/event/py/test2/rsession/testing/test_webjs.py (original) +++ py/branch/event/py/test2/rsession/testing/test_webjs.py Sat Feb 2 18:33:02 2008 @@ -98,7 +98,7 @@ 'length': 10, } webjs.process(msg) - msg = {'type': 'ReceivedItemOutcome', + msg = {'type': 'ItemFinish', 'fullmodulename': 'modules/foo.py', 'passed' : 'True', 'fullitemname' : 'modules/foo.py/test_item', @@ -122,7 +122,7 @@ 'length': 10, } webjs.process(msg) - msg = {'type': 'ReceivedItemOutcome', + msg = {'type': 'ItemFinish', 'fullmodulename': 'modules/foo.py', 'passed' : 'False', 'fullitemname' : 'modules/foo.py/test_item', Modified: py/branch/event/py/test2/rsession/web.py ============================================================================== --- py/branch/event/py/test2/rsession/web.py (original) +++ py/branch/event/py/test2/rsession/web.py Sat Feb 2 18:33:02 2008 @@ -207,7 +207,7 @@ self.end_event.set() return {} # some dispatcher here - if isinstance(event, repevent.ReceivedItemOutcome): + if isinstance(event, repevent.ItemFinish): args = {} outcome = event.outcome for key, val in outcome.__dict__.iteritems(): @@ -277,7 +277,7 @@ lines.append(" " + line) return lines - def report_ReceivedItemOutcome(self, event): + def report_ItemFinish(self, event): self.all += 1 self.pending_events.put(event) Modified: py/branch/event/py/test2/rsession/webjs.py ============================================================================== --- py/branch/event/py/test2/rsession/webjs.py (original) +++ py/branch/event/py/test2/rsession/webjs.py Sat Feb 2 18:33:02 2008 @@ -192,7 +192,7 @@ "#00ff00" host_elem.childNodes[0].nodeValue = '%s[0]' % ( glob.host_dict[msg['hostkey']],) - elif msg['type'] == 'ReceivedItemOutcome': + elif msg['type'] == 'ItemFinish': module_part = get_elem(msg['fullmodulename']) if not module_part: glob.pending.append(msg) Modified: py/branch/event/py/test2/session.py ============================================================================== --- py/branch/event/py/test2/session.py (original) +++ py/branch/event/py/test2/session.py Sat Feb 2 18:33:02 2008 @@ -34,8 +34,9 @@ raise except: excinfo = py.code.ExceptionInfo() - hub.notify(repevent.CollectionFailure(next, excinfo)) - hub.notify(repevent.CollectionFinish(next)) + hub.notify(repevent.CollectionFinish(next, excinfo)) + else: + hub.notify(repevent.CollectionFinish(next)) class AbstractSession(object): """ An abstract session executes collectors/items through a runner. @@ -73,7 +74,7 @@ def header(self, colitems): """ setup any neccessary resources ahead of the test run. """ - self.config.hub.notify(repevent.SessionStart(None, self.config, None)) + self.config.hub.notify(repevent.SessionStart(self)) if not self.config.option.nomagic: py.magic.invoke(assertion=1) @@ -82,7 +83,7 @@ py.test2.collect.Function._state.teardown_all() if not self.config.option.nomagic: py.magic.revoke(assertion=1) - self.config.hub.notify(repevent.SessionFinish()) + self.config.hub.notify(repevent.SessionFinish(self)) def main(self): """ main loop for running tests. """ @@ -98,7 +99,7 @@ item = itemgenerator.next() if not self.config.option.collectonly: outcome = self.run(item) - self.config.hub.notify(repevent.ReceivedItemOutcome(None, item, outcome)) + self.config.hub.notify(repevent.ItemFinish(item, outcome.excinfo)) if outcome is not None: if not outcome.passed and not outcome.skipped: failures.append((item, outcome)) Modified: py/branch/event/py/test2/testing/test_collect.py ============================================================================== --- py/branch/event/py/test2/testing/test_collect.py (original) +++ py/branch/event/py/test2/testing/test_collect.py Sat Feb 2 18:33:02 2008 @@ -3,7 +3,7 @@ from setupdata import setupdatadir from py.__.test2.outcome import Skipped, Failed, Passed, Outcome from py.__.test2.terminal.out import getout -from py.__.test2.repevent import ReceivedItemOutcome +from py.__.test2.repevent import ItemFinish def getpassed(session): hub = session.config.hub @@ -12,9 +12,8 @@ try: session.main() print all - outcomes = [i.outcome for i in all if isinstance(i, ReceivedItemOutcome)] - l = [i for i in outcomes if i.passed] - return l + passed = [i.passed for i in all if isinstance(i, ItemFinish)] + return passed finally: hub.pop() Modified: py/branch/event/py/test2/testing/test_collectonly.py ============================================================================== --- py/branch/event/py/test2/testing/test_collectonly.py (original) +++ py/branch/event/py/test2/testing/test_collectonly.py Sat Feb 2 18:33:02 2008 @@ -34,7 +34,7 @@ allevents = getevents_runmain(session) started = finished = 0 for event in allevents: - assert not isinstance(event, repevent.ReceivedItemOutcome) + assert not isinstance(event, repevent.ItemFinish) if isinstance(event, repevent.CollectionStart): started += 1 elif isinstance(event, repevent.CollectionFinish): Modified: py/branch/event/py/test2/testing/test_remote.py ============================================================================== --- py/branch/event/py/test2/testing/test_remote.py (original) +++ py/branch/event/py/test2/testing/test_remote.py Sat Feb 2 18:33:02 2008 @@ -18,7 +18,7 @@ #allevents = getevents_runmain(session) #print allevents #failures = [x for x in allevents - # if isinstance(x, repevent.ReceivedItemOutcome)] + # if isinstance(x, repevent.ItemFinish)] failures = session.main() assert failures Modified: py/branch/event/py/test2/testing/test_reporter.py ============================================================================== --- py/branch/event/py/test2/testing/test_reporter.py (original) +++ py/branch/event/py/test2/testing/test_reporter.py Sat Feb 2 18:33:02 2008 @@ -84,7 +84,7 @@ else: ch = None for outcome in outcomes: - r.report(repevent.ReceivedItemOutcome(ch, item, outcome)) + r.report(repevent.ItemFinish(ch, item, outcome)) cap = py.io.StdCaptureFD() boxfun(self.config, item, outcomes) @@ -106,7 +106,7 @@ else: ch = None for outcome in outcomes: - r.report(repevent.ReceivedItemOutcome(ch, funcitem, outcome)) + r.report(repevent.ItemFinish(ch, funcitem, outcome)) cap = py.io.StdCaptureFD() boxfun(self.config, moditem, funcitem, outcomes) Modified: py/branch/event/py/test2/testing/test_session.py ============================================================================== --- py/branch/event/py/test2/testing/test_session.py (original) +++ py/branch/event/py/test2/testing/test_session.py Sat Feb 2 18:33:02 2008 @@ -18,7 +18,7 @@ ) def getoutcomes(all): - return [i.outcome for i in all if isinstance(i, repevent.ReceivedItemOutcome)] + return [i for i in all if isinstance(i, repevent.ItemFinish)] def getpassed(all): @@ -29,8 +29,10 @@ [i for i in all if isinstance(i, repevent.DeselectedTest)] def getfailed(all): - return [i for i in getoutcomes(all) if i.excinfo] + \ - [i for i in all if isinstance(i, repevent.CollectionFailure)] + return [i for i in getoutcomes(all) if i.failed] + \ + [i for i in all + if isinstance(i, repevent.CollectionFinish) and + i.excinfo] def test_conflict_options(): for spec in conflict_options: @@ -77,7 +79,7 @@ '-s', '-k', keyword]) session = config._getsessionclass()(config) all = getevents_runmain(session) - outcomes = [i for i in all if isinstance(i, repevent.ReceivedItemOutcome)] + outcomes = [i for i in all if isinstance(i, repevent.ItemFinish)] assert len(getfailed(all)) == 1 assert outcomes[0].item.name == name l = getskipped(all) @@ -109,7 +111,7 @@ all = getevents_runmain(session) print "keyword", repr(keyword) l = getpassed(all) - outcomes = [i for i in all if isinstance(i, repevent.ReceivedItemOutcome)] + outcomes = [i for i in all if isinstance(i, repevent.ItemFinish)] assert len(l) == 1 assert outcomes[0].item.name == 'test_2' l = getskipped(all) Modified: py/branch/event/py/test2/testing/test_session2.py ============================================================================== --- py/branch/event/py/test2/testing/test_session2.py (original) +++ py/branch/event/py/test2/testing/test_session2.py Sat Feb 2 18:33:02 2008 @@ -50,16 +50,19 @@ lsession = Session(config) allevents = getevents_runmain(lsession) testevents = [x for x in allevents - if isinstance(x, repevent.ReceivedItemOutcome)] + if isinstance(x, repevent.ItemFinish)] assert len(testevents) - passevents = [i for i in testevents if i.outcome.passed] - failevents = [i for i in testevents if i.outcome.excinfo] - skippedevents = [i for i in testevents if i.outcome.skipped] - signalevents = [i for i in testevents if i.outcome.signal] + passevents = [i for i in testevents if i.passed] + failevents = [i for i in testevents if i.failed] + skippedevents = [i for i in testevents if i.skipped] + #signalevents = [i for i in testevents if i.outcome.signal] assert len(passevents) == 1 assert len(failevents) == 3 assert len(skippedevents) == 0 #assert len(signalevents) == 1 + + return + # XXX tb = failevents[0].outcome.excinfo.traceback assert str(tb[0].path).find("test_one") != -1 assert str(tb[0].source).find("test_2") != -1 @@ -96,9 +99,9 @@ lsession = Session(config) allevents = getevents_runmain(lsession) testevents = [x for x in allevents - if isinstance(x, repevent.ReceivedItemOutcome)] + if isinstance(x, repevent.ItemFinish)] assert len(testevents) - assert testevents[0].outcome.signal + #assert testevents[0].outcome.signal def test_plain(self): self.example_distribution(False) @@ -157,7 +160,7 @@ lsession = Session(config) allevents = getevents_runmain(lsession) testevents = [x for x in allevents - if isinstance(x, repevent.ReceivedItemOutcome)] + if isinstance(x, repevent.ItemFinish)] assert len(testevents) passevents = [i for i in testevents if i.outcome.passed] failevents = [i for i in testevents if i.outcome.excinfo] @@ -185,7 +188,7 @@ allevents = getevents_runmain(lsession) testevents = [x for x in allevents - if isinstance(x, repevent.ReceivedItemOutcome)] + if isinstance(x, repevent.ItemFinish)] assert len(testevents) passevents = [i for i in testevents if i.outcome.passed] failevents = [i for i in testevents if i.outcome.excinfo] @@ -212,7 +215,7 @@ allruns = [] allevents = getevents_runmain(lsession) testevents = [x for x in allevents - if isinstance(x, repevent.ReceivedItemOutcome)] + if isinstance(x, repevent.ItemFinish)] assert len(testevents) == 4 lst = ['test_one', 'test_one_one', 'test_other', 'test_two'] for num, i in enumerate(testevents): @@ -235,7 +238,7 @@ lsession = Session(config) allevents = getevents_runmain(lsession) testevents = [x for x in allevents - if isinstance(x, repevent.ReceivedItemOutcome)] + if isinstance(x, repevent.ItemFinish)] assert len(testevents) == 0 failedtryiter = [x for x in allevents if isinstance(x, repevent.FailedTryiter)] @@ -260,7 +263,7 @@ lsession = Session(config) allevents = getevents_runmain(lsession) testevents = [x for x in allevents - if isinstance(x, repevent.ReceivedItemOutcome)] + if isinstance(x, repevent.ItemFinish)] failevents = [i for i in testevents if i.outcome.excinfo] assert len(failevents) == 1 assert len(testevents) == 1 @@ -280,7 +283,7 @@ lsession = Session(config) allevents = getevents_runmain(lsession.main) testevents = [x for x in allevents - if isinstance(x, repevent.ReceivedItemOutcome)] + if isinstance(x, repevent.ItemFinish)] assert len(testevents) == 1 assert testevents[0].outcome.passed assert testevents[0].outcome.stderr == "" From hpk at codespeak.net Sat Feb 2 21:38:03 2008 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sat, 2 Feb 2008 21:38:03 +0100 (CET) Subject: [py-svn] r51222 - in py/branch/event/py/test2: . rsession rsession/testing testing Message-ID: <20080202203803.F1FE116842F@codespeak.net> Author: hpk Date: Sat Feb 2 21:38:02 2008 New Revision: 51222 Removed: py/branch/event/py/test2/rsession/testing/test_master.py Modified: py/branch/event/py/test2/repevent.py py/branch/event/py/test2/rsession/hostmanage.py py/branch/event/py/test2/rsession/master.py py/branch/event/py/test2/rsession/rsession.py py/branch/event/py/test2/rsession/slave.py py/branch/event/py/test2/rsession/testing/basetest.py py/branch/event/py/test2/rsession/testing/test_hostmanage.py py/branch/event/py/test2/rsession/testing/test_rsession.py py/branch/event/py/test2/rsession/testing/test_slave.py py/branch/event/py/test2/session.py py/branch/event/py/test2/testing/test_itemgen.py py/branch/event/py/test2/testing/test_outcome.py py/branch/event/py/test2/testing/test_session2.py Log: * intermediate checkin (2 tests failing) * sharing more code between dist and local sessions * strike one layer of indirection * remove some obscure and complicated (mostly skipped) tests Modified: py/branch/event/py/test2/repevent.py ============================================================================== --- py/branch/event/py/test2/repevent.py (original) +++ py/branch/event/py/test2/repevent.py Sat Feb 2 21:38:02 2008 @@ -67,7 +67,6 @@ self.trail = trail assert outcome in ("passed", "failed", "skipped") setattr(self, outcome, True) - self.outcome = outcome self.info = info # ---------------------------------------------------------------------- @@ -75,11 +74,9 @@ # ---------------------------------------------------------------------- class SendItem(BaseEvent): - def __init__(self, channel, item): + def __init__(self, host, item): self.item = item - self.channel = channel - if channel: - self.host = channel.gateway.host + self.host = host class HostRSyncing(BaseEvent): def __init__(self, host, root, remotepath, synced): @@ -97,12 +94,15 @@ self.host = host self.roots = roots +class HostDown(BaseEvent): + def __init__(self, host): + self.host = host + class HostRSyncRootReady(BaseEvent): def __init__(self, host, root): self.host = host self.root = root - # ---------------------------------------------------------------------- # XXX Extra Events XXX # ---------------------------------------------------------------------- Modified: py/branch/event/py/test2/rsession/hostmanage.py ============================================================================== --- py/branch/event/py/test2/rsession/hostmanage.py (original) +++ py/branch/event/py/test2/rsession/hostmanage.py Sat Feb 2 21:38:02 2008 @@ -1,7 +1,6 @@ import py import sys, os from py.__.test2.rsession.master import MasterNode -from py.__.test2.rsession.slave import setup_slave from py.__.test2 import repevent class HostInfo(object): @@ -157,43 +156,41 @@ def setup_hosts(self): self.init_rsync() - nodes = [] for host in self.hosts: - if hasattr(host.gw, 'remote_exec'): # otherwise dummy for tests :/ - ch = setup_slave(host, self.config) - nodes.append(MasterNode(ch, self.config.hub.notify)) - return nodes - - def teardown_hosts(self, nodes, timeout=1.0): - return - for node in nodes: - node.channel.send(None) - clean = False - while not clean: - clean = True - for node in nodes: - if node.pending: - clean = False - # XXX magic waiting - py.std.time.sleep(0.1) - self.teardown_gateways(nodes) - - def kill_channels(self, channels): - for channel in channels: - channel.send(42) - - def teardown_gateways(self, nodes): - return - self.config.hub.notify("teardown gateways %r" %(nodes,)) - for node in nodes: - #try: - try: - node.channel.waitclose(1.0) - except IOError: # timeout - # force closing - node.channel.close() - node.channel.gateway.exit() + host.node = MasterNode(host, self.config) + def teardown_hosts(self, timeout=1.0): + # XXX teardown nodes and hosts + queue = py.std.Queue.Queue() + def hostdown(event): + if isinstance(event, repevent.HostDown): + queue.put(event) + self.config.hub.append(hostdown) + + pending_hosts = [] + for host in self.hosts: + if not host.node.channel.isclosed(): + host.node.channel.send(None) + pending_hosts.append(host) + + while pending_hosts: + event = queue.get(timeout=timeout) + if event.host not in pending_hosts: + print "got random HostDown of", event.host + else: + pending_hosts.remove(event.host) + + def trysendtest(self, item): + for host in self.hosts: + node = getattr(host, 'node', None) + if node and len(node.pending) < 15: # XXX + node.send(item) + return True + + +# +# helpers +# def gethomedir(): import os homedir = os.environ.get('HOME', '') Modified: py/branch/event/py/test2/rsession/master.py ============================================================================== --- py/branch/event/py/test2/rsession/master.py (original) +++ py/branch/event/py/test2/rsession/master.py Sat Feb 2 21:38:02 2008 @@ -6,17 +6,19 @@ from py.__.test2 import repevent class MasterNode(object): - def __init__(self, channel, notify): - self.notify = notify - self.channel = channel + def __init__(self, host, config): + self.host = host + self.config = config + self.notify = config.hub.notify + self.channel = setup_slave(host, config) + self.channel.setcallback(self._callback) self.pending = [] - channel.setcallback(self._callback) - def _callback(self, outcome): + def _callback(self, outcomestring): + if outcomestring is None: + self.notify(repevent.HostDown(self.host)) + return item = self.pending.pop() - self.receive_result(outcome, item) - - def receive_result(self, outcomestring, item): repr_outcome = ReprOutcome(outcomestring) # send finish report # XXX the following should be done by outcome serializing @@ -30,14 +32,12 @@ def send(self, item): try: - if item is StopIteration: - self.channel.send(42) + if item is None: + self.channel.send(None) else: - self.pending.insert(0, item) - #itemspec = item.listnames()[1:] self.channel.send(item._get_collector_trail()) - # send start report - self.notify(repevent.SendItem(self.channel, item)) + self.pending.insert(0, item) + self.notify(repevent.SendItem(self.host, item)) except IOError: print "Sending error, channel IOError" print self.channel._getremoteerror() @@ -45,23 +45,19 @@ # of hanging nodes and such raise -def dispatch_loop(masternodes, itemgenerator, #shouldstop, - waiter = lambda: py.std.time.sleep(0.1), - max_tasks_per_node=15): - all_tests = {} - while 1: - try: - for node in masternodes: - if len(node.pending) < max_tasks_per_node: - item = itemgenerator.next() - all_tests[item] = True - #if shouldstop(): - # for _node in masternodes: - # _node.send(StopIteration) # magic connector - # return None - node.send(item) - except StopIteration: - break - waiter() - return all_tests +# setting up slave code +from slave import setup +defaultconftestnames = ['dist_nicelevel'] +def setup_slave(host, config): + channel = host.gw.remote_exec(str(py.code.Source(setup, "setup()"))) + configrepr = config._makerepr(defaultconftestnames) + #print "sending configrepr", configrepr + topdir = host.gw_remotepath + if topdir is None: + assert host.inplacelocal + topdir = config.topdir + channel.send(str(topdir)) + channel.send(configrepr) + return channel + Modified: py/branch/event/py/test2/rsession/rsession.py ============================================================================== --- py/branch/event/py/test2/rsession/rsession.py (original) +++ py/branch/event/py/test2/rsession/rsession.py Sat Feb 2 21:38:02 2008 @@ -1,27 +1,22 @@ - -""" Remote session base class +""" + Remote Session Base Class """ import os import py -import sys -import re -import time -from py.__.test2 import repevent -from py.__.test2.rsession.master import dispatch_loop +from py.__.test2.session import Session from py.__.test2.rsession.hostmanage import HostManager -from py.__.test2.session import AbstractSession, itemgen -class RSession(AbstractSession): - """ Remote version of session +class RSession(Session): + """ Distributing tests to remote places. """ def fixoptions(self): super(RSession, self).fixoptions() option = self.config.option if option.nocapture: print "Cannot use nocapture with distributed testing" - sys.exit(1) + py.std.sys.exit(1) config = self.config try: config.getvalue('dist_hosts') @@ -37,37 +32,20 @@ print "see also: http://codespeak.net/py/current/doc/test.html#automated-distributed-testing" raise SystemExit - def main(self): - """ main loop for running tests. """ - hm = HostManager(self.config) - hub = self.config.hub - hub.notify(repevent.SessionStart(self)) - try: - nodes = hm.setup_hosts() - try: - self.dispatch_tests(nodes) - except (KeyboardInterrupt, SystemExit): - print >>sys.stderr, "C-c pressed waiting for gateways to teardown..." - channels = [node.channel for node in nodes] - hm.kill_channels(channels) - hm.teardown_gateways(channels) - print >>sys.stderr, "... Done" - raise - - print "tearing down nodes" - hm.teardown_hosts(nodes) - hub.notify(repevent.SessionFinish(self)) - except (KeyboardInterrupt, SystemExit): - hub.notify(repevent.InterruptedExecution()) - raise - except: - hub.notify(repevent.CrashedExecution()) - raise - - def dispatch_tests(self, nodes): - colitems = self.config.getcolitems() - keyword = self.config.option.keyword - itemgenerator = itemgen(self, colitems, keyword) - max_tasks_per_node = self.config.getvalue("dist_taskspernode") - all_tests = dispatch_loop(nodes, itemgenerator, - max_tasks_per_node=max_tasks_per_node) + def setup(self): + super(RSession, self).setup() + self.hm = hm = HostManager(self.config) + self.hm.setup_hosts() + + def teardown(self): + super(RSession, self).teardown() + self.hm.teardown_hosts() + + def runtest(self, item): + # dispatch tests to host manager + sent = self.hm.trysendtest(item) + if not sent and not self.shouldstop: + self.sleepabit() + + def sleepabit(self): + py.std.time.sleep(0.1) Modified: py/branch/event/py/test2/rsession/slave.py ============================================================================== --- py/branch/event/py/test2/rsession/slave.py (original) +++ py/branch/event/py/test2/rsession/slave.py Sat Feb 2 21:38:02 2008 @@ -44,6 +44,7 @@ while 1: nextitem = receive() if nextitem is None: + send(None) break try: node = getnode(nextitem) @@ -54,28 +55,13 @@ excinfo = py.code.ExceptionInfo() send(SerializableOutcome(excinfo=excinfo, is_critical=True).make_repr()) else: + send(res) if not res[0] and not res[3] and config.option.exitfirst: - # we're finished, but need to eat what we can - send(res) break - send(res) - + # we're finished, but we should eat what we can while nextitem is not None: nextitem = receive() -defaultconftestnames = ['dist_nicelevel'] -def setup_slave(host, config): - channel = host.gw.remote_exec(str(py.code.Source(setup, "setup()"))) - configrepr = config._makerepr(defaultconftestnames) - #print "sending configrepr", configrepr - topdir = host.gw_remotepath - if topdir is None: - assert host.inplacelocal - topdir = config.topdir - channel.send(str(topdir)) - channel.send(configrepr) - return channel - def setup(): # our current dir is the topdir import os, sys Modified: py/branch/event/py/test2/rsession/testing/basetest.py ============================================================================== --- py/branch/event/py/test2/rsession/testing/basetest.py (original) +++ py/branch/event/py/test2/rsession/testing/basetest.py Sat Feb 2 21:38:02 2008 @@ -7,13 +7,13 @@ def func_source(): import py import time - def funcpass(): + def funcpassed(): pass - def funcfail(): + def funcfailed(): raise AssertionError("hello world") - def funcskip(): + def funcskipped(): py.test2.skip("skipped") def funcprint(): Modified: py/branch/event/py/test2/rsession/testing/test_hostmanage.py ============================================================================== --- py/branch/event/py/test2/rsession/testing/test_hostmanage.py (original) +++ py/branch/event/py/test2/rsession/testing/test_hostmanage.py Sat Feb 2 21:38:02 2008 @@ -268,6 +268,7 @@ print events assert 0 + def test_getpath_relto_home(): x = getpath_relto_home("hello") assert x == py.path.local._gethomedir().join("hello") Deleted: /py/branch/event/py/test2/rsession/testing/test_master.py ============================================================================== --- /py/branch/event/py/test2/rsession/testing/test_master.py Sat Feb 2 21:38:02 2008 +++ (empty file) @@ -1,198 +0,0 @@ -""" master code and test dispatching for - making 1-n master -> slave connection - and test it locally. -""" - -import time, threading -import py, sys - -if sys.platform == 'win32': - py.test.skip("rsession is unsupported on Windows.") - -from py.__.test2.rsession.master import dispatch_loop, MasterNode -from py.__.test2.rsession.slave import setup_slave -from py.__.test2.outcome import ReprOutcome, SerializableOutcome -from py.__.test2 import repevent -from py.__.test2.rsession.hostmanage import HostInfo - -def setup_module(mod): - # bind an empty config - mod.tmpdir = tmpdir = py.test2.ensuretemp(mod.__name__) - # to avoid rsyncing - config = py.test2.config._reparse([tmpdir]) - config.option.dist_taskspernode = 10 - mod.rootcol = config._getcollector(tmpdir) - -class DummyGateway(object): - def __init__(self): - self.host = HostInfo("localhost") - -class DummyChannel(object): - def __init__(self): - self.sent = [] - self.gateway = DummyGateway() - - def setcallback(self, func): - self.callback = func - - def send(self, item): - assert py.std.marshal.dumps(item) - self.sent.append(item) - -class NonWorkingChannel(object): - def setcallback(self, func): - pass - - def send(self, item): - raise IOError - - def _getremoteerror(self): - return "blah" - -class Item(py.test2.collect.Item): - def _get_collector_trail(self): - return (self.name,) - -def test_masternode(): - try: - raise ValueError() - except ValueError: - excinfo = py.code.ExceptionInfo() - - ch = DummyChannel() - reportlist = [] - mnode = MasterNode(ch, reportlist.append) - mnode.send(Item("ok")) - mnode.send(Item("notok")) - 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.ItemTestReport)] - py.test.skip("XXX fix master tests") - assert received[0].outcome.passed - assert not received[1].outcome.passed - -def test_masternode_nonworking_channel(): - ch = NonWorkingChannel() - reportlist = [] - mnode = MasterNode(ch, reportlist.append) - cap = py.io.StdCaptureFD() - py.test2.raises(IOError, 'mnode.send(Item("ok"))') - out, err = cap.reset() - assert out.find("blah") != -1 - -def test_sending_two_noes(): - # XXX fijal: this test previously tested that the second - # item result would not get send. why? did i miss - # something? - # - ch = DummyChannel() - reportlist = [] - mnode = MasterNode(ch, reportlist.append) - mnode.send(Item("ok")) - mnode.send(Item("ok")) - ch.callback(SerializableOutcome().make_repr()) - ch.callback(SerializableOutcome().make_repr()) - assert len(reportlist) == 4 - -def test_outcome_repr(): - out = ReprOutcome(SerializableOutcome(skipped="xxx").make_repr()) - s = repr(out) - assert s.lower().find("skip") != -1 - -class DummyMasterNode(object): - def __init__(self): - self.pending = [] - - def send(self, data): - self.pending.append(data) - -def test_dispatch_loop(): - masternodes = [DummyMasterNode(), DummyMasterNode()] - itemgenerator = iter(range(100)) - shouldstop = lambda : False - def waiter(): - for node in masternodes: - node.pending.pop() - dispatch_loop(masternodes, itemgenerator, waiter=waiter) - -class TestSlave: - def setup_class(cls): - cls.tmpdir = tmpdir = py.test2.ensuretemp(cls.__name__) - cls.pkgpath = pkgpath = tmpdir.join("slavetestpkg") - pkgpath.ensure("__init__.py") - pkgpath.join("test_something.py").write(py.code.Source(""" - def funcpass(): - pass - - def funcfail(): - raise AssertionError("hello world") - """)) - cls.config = py.test2.config._reparse([tmpdir]) - assert cls.config.topdir == tmpdir - cls.rootcol = cls.config._getcollector(tmpdir) - - def _gettrail(self, *names): - item = self.rootcol._getitembynames(names) - return self.config.get_collector_trail(item) - - def test_slave_running(self): - py.test.skip("XXX test broken, needs refactoring") - def simple_report(event): - if not isinstance(event, repevent.ItemFinish): - return - item = event.item - if item.code.name == 'funcpass': - assert event.outcome.passed - else: - assert not event.outcome.passed - - def open_gw(): - gw = py.execnet.PopenGateway() - host = HostInfo("localhost") - host.gw_remotepath = '' - host.gw = gw - #gw.host.gw = gw - config = py.test2.config._reparse([tmpdir]) - channel = setup_slave(host, config) - mn = MasterNode(channel, simple_report) - return mn - - master_nodes = [open_gw(), open_gw(), open_gw()] - funcpass_item = self.xxx - funcfail_item = rootcol._getitembynames(funcfail_spec) - itemgenerator = iter([funcfail_item] + - [funcpass_item] * 5 + [funcfail_item] * 5) - shouldstop = lambda : False - dispatch_loop(master_nodes, itemgenerator, shouldstop) - -def test_slave_running_interrupted(): - py.test.skip("XXX test broken, needs refactoring") - #def simple_report(event): - # if not isinstance(event, repevent.ItemFinish): - # return - # item = event.item - # if item.code.name == 'funcpass': - # assert event.outcome.passed - # else: - # assert not event.outcome.passed - reports = [] - - def open_gw(): - gw = py.execnet.PopenGateway() - gw.host = HostInfo("localhost") - gw.host.gw = gw - config = py.test2.config._reparse([tmpdir]) - channel = setup_slave(gw.host, config) - mn = MasterNode(channel, reports.append, {}) - return mn, gw, channel - - mn, gw, channel = open_gw() - rootcol = py.test2.collect.Directory(pkgdir) - funchang_item = rootcol._getitembynames(funchang_spec) - mn.send(funchang_item) - mn.send(StopIteration) - # XXX: We have to wait here a bit to make sure that it really did happen - channel.waitclose(2) - Modified: py/branch/event/py/test2/rsession/testing/test_rsession.py ============================================================================== --- py/branch/event/py/test2/rsession/testing/test_rsession.py (original) +++ py/branch/event/py/test2/rsession/testing/test_rsession.py Sat Feb 2 21:38:02 2008 @@ -37,9 +37,6 @@ """)) config = py.test2.config._reparse([self.source.join("sub"), '-x']) rsession = RSession(config) - def f(ev): - print ev - config.hub.append(f) allevents = getevents_runmain(rsession) testevents = [x for x in allevents if isinstance(x, repevent.ItemTestReport)] @@ -92,29 +89,31 @@ queue = py.std.Queue.Queue() self.config.hub.append(queue.put) hm = HostManager(self.config, hosts=hosts) - nodes = hm.setup_hosts() + hm.setup_hosts() # actually run some tests - for node in nodes: - node.send(self.getexample("pass")) - node.send(self.getexample("fail")) - node.send(self.getexample("skip")) + for host in hm.hosts: + node = host.node + node.send(self.getexample("passed")) + node.send(self.getexample("failed")) + node.send(self.getexample("skipped")) node.send(self.getexample("print")) + num_hosts = len(hm.hosts) events = [] - while len(events) < 4 * len(nodes): + while len(events) < 4 * num_hosts: item = queue.get(timeout=0.5) if isinstance(item, repevent.ItemTestReport): events.append(item) print "got all events", events - hm.teardown_hosts(nodes) + hm.teardown_hosts() passed = [ev for ev in events if ev.passed] skipped = [ev for ev in events if ev.skipped] - assert len(passed) == 2 * len(nodes) - assert len(skipped) == len(nodes) - assert len(events) == 4 * len(nodes) + assert len(passed) == 2 * num_hosts + assert len(skipped) == num_hosts + assert len(events) == 4 * num_hosts # one of passed for each node has non-empty stdout #passed_stdout = [i for i in passed if i.outcome.stdout.find('samfing') != -1] #assert len(passed_stdout) == len(nodes), passed Modified: py/branch/event/py/test2/rsession/testing/test_slave.py ============================================================================== --- py/branch/event/py/test2/rsession/testing/test_slave.py (original) +++ py/branch/event/py/test2/rsession/testing/test_slave.py Sat Feb 2 21:38:02 2008 @@ -22,7 +22,7 @@ def test_slave_run_passing(self): node = self.gettestnode() - item = self.getexample("pass") + item = self.getexample("passed") outcome = node.execute(item._get_collector_trail()) assert outcome.passed assert not outcome.setupfailure @@ -34,12 +34,12 @@ def test_slave_run_failing(self): node = self.gettestnode() - item = self.getexample("fail") + item = self.getexample("failed") outcome = node.execute(item._get_collector_trail()) assert not outcome.passed assert not outcome.setupfailure assert len(outcome.excinfo.traceback) == 1 - assert outcome.excinfo.traceback[-1].frame.code.name == 'funcfail' + assert outcome.excinfo.traceback[-1].frame.code.name == 'funcfailed' ser = outcome.make_repr() reproutcome = ReprOutcome(ser) @@ -49,7 +49,7 @@ def test_slave_run_skipping(self): node = self.gettestnode() - item = self.getexample("skip") + item = self.getexample("skipped") outcome = node.execute(item._get_collector_trail()) assert not outcome.passed assert outcome.skipped @@ -61,7 +61,7 @@ def test_slave_run_failing_wrapped(self): node = self.gettestnode() - item = self.getexample("fail") + item = self.getexample("failed") repr_outcome = node.run(item._get_collector_trail()) outcome = ReprOutcome(repr_outcome) assert not outcome.passed Modified: py/branch/event/py/test2/session.py ============================================================================== --- py/branch/event/py/test2/session.py (original) +++ py/branch/event/py/test2/session.py Sat Feb 2 21:38:02 2008 @@ -12,38 +12,13 @@ GeneratorExit = py.builtin.GeneratorExit -def itemgen(session, colitems, keywordexpr=None): - hub = session.config.hub - stopitems = py.test2.collect.Item # XXX should be generator here as well - while colitems: - next = colitems.pop(0) - if isinstance(next, stopitems): - if next._skipbykeyword(keywordexpr): - hub.notify(repevent.DeselectedTest(next, keywordexpr)) - if session.config.option.keyword_oneshot: - keywordexpr = None - else: - yield next - else: - hub.notify(repevent.CollectionStart(next)) - try: - cols = [next.join(x) for x in next.run()] - for x in itemgen(session, cols, keywordexpr): - yield x - except (KeyboardInterrupt, SystemExit, GeneratorExit): - raise - except: - excinfo = py.code.ExceptionInfo() - hub.notify(repevent.CollectionFinish(next, excinfo)) - else: - hub.notify(repevent.CollectionFinish(next)) - -class AbstractSession(object): - """ An abstract session executes collectors/items through a runner. - """ +class Session(object): + """ + Session drives the collection and running of tests + and generates test events for reporters. + """ def __init__(self, config): self.config = config - self._keyword = config.option.keyword def fixoptions(self): """ check, fix and determine conflicting options. """ @@ -60,64 +35,87 @@ raise ValueError, "--looponfailing together with --dist not supported." if option.executable and option.usepdb: raise ValueError, "--exec together with --pdb not supported." - if option.keyword_oneshot and not option.keyword: raise ValueError, "--keyword-oneshot makes sense only when --keyword is supplied" -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 collect(self): + colitems = self.config.getcolitems() + keyword = self.config.option.keyword + for x in self.genitems(colitems, keyword): + yield x - def header(self, colitems): + def genitems(self, colitems, keywordexpr=None): + hub = self.config.hub + stopitems = py.test2.collect.Item + while colitems: + next = colitems.pop(0) + if isinstance(next, stopitems): + if next._skipbykeyword(keywordexpr): + hub.notify(repevent.DeselectedTest(next, keywordexpr)) + if self.config.option.keyword_oneshot: + keywordexpr = None + else: + yield next + else: + hub.notify(repevent.CollectionStart(next)) + excinfo = None + try: + cols = [next.join(x) for x in next.run()] + for x in self.genitems(cols, keywordexpr): + yield x + except (KeyboardInterrupt, SystemExit, GeneratorExit): + raise + except: + excinfo = py.code.ExceptionInfo() + hub.notify(repevent.CollectionFinish(next, excinfo)) + + def setup(self): """ setup any neccessary resources ahead of the test run. """ - self.config.hub.notify(repevent.SessionStart(self)) if not self.config.option.nomagic: py.magic.invoke(assertion=1) + self._failurelist = self._initfailurelist() - def footer(self, colitems): + def teardown(self): """ teardown any resources after a test run. """ py.test2.collect.Function._state.teardown_all() if not self.config.option.nomagic: py.magic.revoke(assertion=1) - self.config.hub.notify(repevent.SessionFinish(self)) - + return self._failurelist + + def _initfailurelist(self): + failurelist = [] + def processfailures(event): + if isinstance(event, repevent.ItemFinish) and event.failed: + failurelist.append(event) + if self.config.option.exitfirst: + self.shouldstop = True + self.config.hub.append(processfailures) + return failurelist + def main(self): """ main loop for running tests. """ - config = self.config - colitems = self.config.getcolitems() - self.header(colitems) - keyword = self.config.option.keyword - itemgenerator = itemgen(self, colitems, keyword) - failures = [] + self.shouldstop = False + self.setup() + self.config.hub.notify(repevent.SessionStart(self)) try: - while 1: - try: - item = itemgenerator.next() - if not self.config.option.collectonly: - outcome = self.run(item) - self.config.hub.notify(repevent.ItemFinish(item, outcome.excinfo)) - if outcome is not None: - if not outcome.passed and not outcome.skipped: - failures.append((item, outcome)) - if self.config.option.exitfirst: - raise StopIteration() - except StopIteration: - break + for item in self.collect(): + if self.shouldstop: + break + if not self.config.option.collectonly: + self.runtest(item) finally: - self.footer(colitems) + failures = self.teardown() + self.config.hub.notify(repevent.SessionFinish(self)) return failures - def run(self, item): + def runtest(self, item): if not self.config.option.boxed: executor = RunExecutor(item, config=self.config) - return ReprOutcome(executor.execute().make_repr()) + outcome = ReprOutcome(executor.execute().make_repr()) else: executor = BoxExecutor(item, config=self.config) - return ReprOutcome(executor.execute()) + outcome = ReprOutcome(executor.execute()) + self.config.hub.notify(repevent.ItemFinish(item, outcome.excinfo)) class Exit(Exception): """ for immediate program exits without tracebacks and reporter/summary. """ Modified: py/branch/event/py/test2/testing/test_itemgen.py ============================================================================== --- py/branch/event/py/test2/testing/test_itemgen.py (original) +++ py/branch/event/py/test2/testing/test_itemgen.py Sat Feb 2 21:38:02 2008 @@ -1,6 +1,5 @@ import py -from py.__.test2.session import itemgen from py.__.test2 import repevent class TestItemgen: Modified: py/branch/event/py/test2/testing/test_outcome.py ============================================================================== --- py/branch/event/py/test2/testing/test_outcome.py (original) +++ py/branch/event/py/test2/testing/test_outcome.py Sat Feb 2 21:38:02 2008 @@ -62,3 +62,9 @@ #def test_f3(): # f3() + +def test_outcome_repr(): + out = ReprOutcome(SerializableOutcome(skipped="xxx").make_repr()) + s = repr(out) + assert s.lower().find("skip") != -1 + Modified: py/branch/event/py/test2/testing/test_session2.py ============================================================================== --- py/branch/event/py/test2/testing/test_session2.py (original) +++ py/branch/event/py/test2/testing/test_session2.py Sat Feb 2 21:38:02 2008 @@ -11,12 +11,15 @@ def getevents_runmain(session): hub = session.config.hub allevents = [] - hub.append(allevents.append) + def appendevent(event): + allevents.append(event) + print event + hub.append(appendevent) try: session.main() return allevents finally: - hub.remove(allevents.append) + hub.remove(appendevent) def setup_module(mod): From lamby at codespeak.net Tue Feb 5 12:55:01 2008 From: lamby at codespeak.net (lamby at codespeak.net) Date: Tue, 5 Feb 2008 12:55:01 +0100 (CET) Subject: [py-svn] r51285 - py/trunk/py/bin Message-ID: <20080205115501.44A5D168446@codespeak.net> Author: lamby Date: Tue Feb 5 12:55:00 2008 New Revision: 51285 Modified: py/trunk/py/bin/_docgen.py Log: Fix _docgen.py documentation building. Modified: py/trunk/py/bin/_docgen.py ============================================================================== --- py/trunk/py/bin/_docgen.py (original) +++ py/trunk/py/bin/_docgen.py Tue Feb 5 12:55:00 2008 @@ -28,7 +28,7 @@ def build_docs(targetpath, testargs): docpath = pypath.join('doc') run_tests(docpath, '', - testargs + ' --forcegen --apigenrelpath="apigen/"') + testargs + ' --forcegen --apigen="%s/apigen/apigen.py"' % (pypath,)) docpath.copy(targetpath) def build_nav(targetpath, docs=True, api=True): From fijal at codespeak.net Tue Feb 5 15:35:49 2008 From: fijal at codespeak.net (fijal at codespeak.net) Date: Tue, 5 Feb 2008 15:35:49 +0100 (CET) Subject: [py-svn] r51292 - py/trunk/py/test Message-ID: <20080205143549.9B77A16842C@codespeak.net> Author: fijal Date: Tue Feb 5 15:35:49 2008 New Revision: 51292 Modified: py/trunk/py/test/representation.py Log: Just another except, in order to represent source when it's not there. Modified: py/trunk/py/test/representation.py ============================================================================== --- py/trunk/py/test/representation.py (original) +++ py/trunk/py/test/representation.py Tue Feb 5 15:35:49 2008 @@ -71,8 +71,11 @@ s = str(source.getstatement(len(source)-1)) except KeyboardInterrupt: raise - except: - s = str(source[-1]) + except: + try: + s = str(source[-1]) + except IndexError: + s = "" indent = " " * (4 + (len(s) - len(s.lstrip()))) # get the real exception information out lines = excinfo.exconly(tryshort=True).split('\n') From py-svn at codespeak.net Thu Feb 7 23:55:20 2008 From: py-svn at codespeak.net (py-svn at codespeak.net) Date: Thu, 7 Feb 2008 23:55:20 +0100 (CET) Subject: [py-svn] Monthly Newsletter - February Message-ID: <20080207061414.3577.qmail@C915CBE6.poa.virtua.com.br> An HTML attachment was scrubbed... URL: From hpk at codespeak.net Fri Feb 8 09:43:07 2008 From: hpk at codespeak.net (hpk at codespeak.net) Date: Fri, 8 Feb 2008 09:43:07 +0100 (CET) Subject: [py-svn] r51329 - in py/trunk/py: . apigen/tracer bin doc misc misc/testing path/local test Message-ID: <20080208084307.7CA061684CF@codespeak.net> Author: hpk Date: Fri Feb 8 09:43:05 2008 New Revision: 51329 Modified: py/trunk/py/apigen/tracer/docstorage.py py/trunk/py/bin/_docgen.py py/trunk/py/bin/_makepyrelease.py py/trunk/py/bin/_update_website.py py/trunk/py/doc/TODO.txt py/trunk/py/doc/conftest.py py/trunk/py/initpkg.py py/trunk/py/misc/_dist.py py/trunk/py/misc/testing/test_initpkg.py py/trunk/py/path/local/local.py py/trunk/py/test/reporter.py Log: rename special __package__ to __pkg__ because python 2.6 needs the former (thanks to Ralf Schmitt) Modified: py/trunk/py/apigen/tracer/docstorage.py ============================================================================== --- py/trunk/py/apigen/tracer/docstorage.py (original) +++ py/trunk/py/apigen/tracer/docstorage.py Fri Feb 8 09:43:05 2008 @@ -16,7 +16,7 @@ sorted = py.builtin.sorted def pkg_to_dict(module): - defs = module.__package__.exportdefs + defs = module.__pkg__.exportdefs d = {} for key, value in defs.iteritems(): chain = key.split('.') @@ -33,7 +33,7 @@ """ deal with '*' entries in an initpkg situation """ ret = {} modpath = py.path.local(inspect.getsourcefile(module)) - pkgpath = module.__package__.getpath() + pkgpath = module.__pkg__.getpath() for objname in dir(module): if objname.startswith('_'): continue # also skip __*__ attributes @@ -281,8 +281,8 @@ return "Lack of module info" try: retval = module.__doc__ or "*undocumented*" - retval = module.__package__.description - retval = module.__package__.long_description + retval = module.__pkg__.description + retval = module.__pkg__.long_description except AttributeError: pass return retval Modified: py/trunk/py/bin/_docgen.py ============================================================================== --- py/trunk/py/bin/_docgen.py (original) +++ py/trunk/py/bin/_docgen.py Fri Feb 8 09:43:05 2008 @@ -10,7 +10,7 @@ from _findpy import py import py -pypath = py.__package__.getpath() +pypath = py.__pkg__.getpath() def run_tests(path, envvars='', args=''): pytestpath = pypath.join('bin/py.test') Modified: py/trunk/py/bin/_makepyrelease.py ============================================================================== --- py/trunk/py/bin/_makepyrelease.py (original) +++ py/trunk/py/bin/_makepyrelease.py Fri Feb 8 09:43:05 2008 @@ -147,9 +147,9 @@ if __name__ == '__main__': py.magic.invoke(assertion=True) version = py.std.sys.argv[1] - assert py.__package__.version == version, ( + assert py.__pkg__.version == version, ( "py package has version %s\nlocation: %s" % - (py.__package__.version, pydir)) + (py.__pkg__.version, pydir)) tmpdir = py.path.local.get_temproot().join('makepyrelease-%s' % version) if tmpdir.check(): @@ -171,14 +171,14 @@ py.process.cmdexec("rsync -avz %(source)s/ %(remotedir)s" % locals()) ddir = tmpdir.ensure('download', dir=1) - URL = py.__package__.download_url # 'http://codespeak.net/download/py/' + URL = py.__pkg__.download_url # 'http://codespeak.net/download/py/' unpacked = unpackremotetar(ddir, URL) assert unpacked == ddir.join("py-%s" % (version,)) #checksvnworks(unpacked) #pytest(unpacked) - pytest_remote('test at codespeak.net', py.__package__.download_url) + pytest_remote('test at codespeak.net', py.__pkg__.download_url) Modified: py/trunk/py/bin/_update_website.py ============================================================================== --- py/trunk/py/bin/_update_website.py (original) +++ py/trunk/py/bin/_update_website.py Fri Feb 8 09:43:05 2008 @@ -24,7 +24,7 @@ def run_tests(pkgpath, apigenpath, args='', captureouterr=False): """ run the unit tests and build the docs """ - pypath = py.__package__.getpath() + pypath = py.__pkg__.getpath() pytestpath = pypath.join('bin/py.test') # XXX this would need a Windows specific version if we want to allow # running this script on that platform, but currently --apigen doesn't @@ -82,7 +82,7 @@ args.remove('--ignorefail') ignorefail = True args = ' '.join(sys.argv[1:]) - pkgpath = py.__package__.getpath() + pkgpath = py.__pkg__.getpath() apidocspath = pkgpath.dirpath().join('apigen') main(pkgpath, apidocspath, 'codespeak.net', '/home/guido/rsynctests', args, ignorefail) Modified: py/trunk/py/doc/TODO.txt ============================================================================== --- py/trunk/py/doc/TODO.txt (original) +++ py/trunk/py/doc/TODO.txt Fri Feb 8 09:43:05 2008 @@ -39,10 +39,12 @@ - refactor to produce intermediate data/files capturing info of test runs - - refactor html renderer to work on intermediate data/files rather than on the live data +- check out CodeInvestigator + http://codeinvestigator.googlepages.com/main + ld (review and shift to above) ================================= Modified: py/trunk/py/doc/conftest.py ============================================================================== --- py/trunk/py/doc/conftest.py (original) +++ py/trunk/py/doc/conftest.py Fri Feb 8 09:43:05 2008 @@ -311,7 +311,7 @@ 'to the py package') % (text,) relpath = '/'.join(text.split('/')[1:]) if check: - pkgroot = py.__package__.getpath() + pkgroot = py.__pkg__.getpath() abspath = pkgroot.join(relpath) assert pkgroot.join(relpath).check(), ( 'problem with linkrole :source:`%s`: ' Modified: py/trunk/py/initpkg.py ============================================================================== --- py/trunk/py/initpkg.py (original) +++ py/trunk/py/initpkg.py Fri Feb 8 09:43:05 2008 @@ -38,9 +38,9 @@ self.name = name self.exportdefs = exportdefs self.module = pkgmodule - assert not hasattr(pkgmodule, '__package__'), \ + assert not hasattr(pkgmodule, '__pkg__'), \ "unsupported reinitialization of %r" % pkgmodule - pkgmodule.__package__ = self + pkgmodule.__pkg__ = self # make available pkgname.__ implname = name + '.' + '__' @@ -134,7 +134,7 @@ from cStringIO import StringIO except ImportError: from StringIO import StringIO - base = py.__package__.getpath().dirpath() + base = py.__pkg__.getpath().dirpath() outf = StringIO() f = zipfile.ZipFile(outf, 'w', compression=zipfile.ZIP_DEFLATED) try: @@ -164,14 +164,14 @@ class Module(ModuleType): def __init__(self, pkg, name): - self.__package__ = pkg + self.__pkg__ = pkg self.__name__ = name self.__map__ = {} def __getattr__(self, name): if '*' in self.__map__: extpy = self.__map__['*'][0], name - result = self.__package__._resolve(extpy) + result = self.__pkg__._resolve(extpy) else: try: extpy = self.__map__[name] @@ -179,7 +179,7 @@ __tracebackhide__ = True raise AttributeError(name) else: - result = self.__package__._resolve(extpy) + result = self.__pkg__._resolve(extpy) del self.__map__[name] setattr(self, name, result) #self._fixinspection(result, name) @@ -216,7 +216,7 @@ assert not self.__map__, "%r not empty" % self.__map__ else: fsname = self.__map__['*'][0] - dict.update(self.__package__._loadimpl(fsname[:-3]).__dict__) + dict.update(self.__pkg__._loadimpl(fsname[:-3]).__dict__) return dict __dict__ = property(getdict) Modified: py/trunk/py/misc/_dist.py ============================================================================== --- py/trunk/py/misc/_dist.py (original) +++ py/trunk/py/misc/_dist.py Fri Feb 8 09:43:05 2008 @@ -144,7 +144,7 @@ params = Params(pkg) #dump(params) - source = getattr(pkg, '__package__', pkg) + source = getattr(pkg, '__pkg__', pkg) namelist = list(core.setup_keywords) namelist.extend(['packages', 'scripts', 'data_files']) for name in namelist: Modified: py/trunk/py/misc/testing/test_initpkg.py ============================================================================== --- py/trunk/py/misc/testing/test_initpkg.py (original) +++ py/trunk/py/misc/testing/test_initpkg.py Fri Feb 8 09:43:05 2008 @@ -33,7 +33,7 @@ def test_resolve_attrerror(): extpyish = "./initpkg.py", "hello" - excinfo = py.test.raises(AttributeError, "py.__package__._resolve(extpyish)") + excinfo = py.test.raises(AttributeError, "py.__pkg__._resolve(extpyish)") s = str(excinfo.value) assert s.find(extpyish[0]) != -1 assert s.find(extpyish[1]) != -1 @@ -83,16 +83,16 @@ assert __import__(modpath) def test_shahexdigest(): - hex = py.__package__.shahexdigest() + hex = py.__pkg__.shahexdigest() assert len(hex) == 40 def test_getzipdata(): - s = py.__package__.getzipdata() + s = py.__pkg__.getzipdata() def test_getrev(): if not py.path.local(py.__file__).dirpath('.svn').check(): py.test.skip("py package is not a svn checkout") - d = py.__package__.getrev() + d = py.__pkg__.getrev() svnversion = py.path.local.sysfind('svnversion') if svnversion is None: py.test.skip("cannot test svnversion, 'svnversion' binary not found") @@ -255,9 +255,9 @@ def test_url_of_version(): #py.test.skip("FAILING! - provide a proper URL or upload pylib tgz") from urllib import URLopener - url = py.__package__.download_url + url = py.__pkg__.download_url if url.lower() == "xxx": - assert py.__package__.version.find("alpha") != -1 + assert py.__pkg__.version.find("alpha") != -1 else: URLopener().open(url) Modified: py/trunk/py/path/local/local.py ============================================================================== --- py/trunk/py/path/local/local.py (original) +++ py/trunk/py/path/local/local.py Fri Feb 8 09:43:05 2008 @@ -400,8 +400,8 @@ self._prependsyspath(pkgpath.dirpath()) pkg = __import__(pkgpath.basename, None, None, []) - if hasattr(pkg, '__package__'): - modname = pkg.__package__.getimportname(self) + if hasattr(pkg, '__pkg__'): + modname = pkg.__pkg__.getimportname(self) assert modname is not None, "package %s doesn't know %s" % ( pkg.__name__, self) Modified: py/trunk/py/test/reporter.py ============================================================================== --- py/trunk/py/test/reporter.py (original) +++ py/trunk/py/test/reporter.py Fri Feb 8 09:43:05 2008 @@ -356,7 +356,7 @@ self.timestart = item.timestart self.out.line("executable: %s (%s)" % (py.std.sys.executable, repr_pythonversion())) - rev = py.__package__.getrev() + rev = py.__pkg__.getrev() self.out.line("using py lib: %s " % ( py.path.local(py.__file__).dirpath(), rev)) config = item.config From hpk at codespeak.net Fri Feb 8 09:48:32 2008 From: hpk at codespeak.net (hpk at codespeak.net) Date: Fri, 8 Feb 2008 09:48:32 +0100 (CET) Subject: [py-svn] r51330 - in py/branch/bugfix-0.9.0/py: . apigen/tracer bin doc misc misc/testing path/local test/terminal Message-ID: <20080208084832.EB5901684E6@codespeak.net> Author: hpk Date: Fri Feb 8 09:48:31 2008 New Revision: 51330 Modified: py/branch/bugfix-0.9.0/py/apigen/tracer/docstorage.py py/branch/bugfix-0.9.0/py/bin/_docgen.py py/branch/bugfix-0.9.0/py/bin/_makepyrelease.py py/branch/bugfix-0.9.0/py/bin/_update_website.py py/branch/bugfix-0.9.0/py/doc/conftest.py py/branch/bugfix-0.9.0/py/initpkg.py py/branch/bugfix-0.9.0/py/misc/_dist.py py/branch/bugfix-0.9.0/py/misc/testing/test_initpkg.py py/branch/bugfix-0.9.0/py/path/local/local.py py/branch/bugfix-0.9.0/py/test/terminal/terminal.py Log: * backport 51329 from trunk (rename __package__ to __pkg__) Modified: py/branch/bugfix-0.9.0/py/apigen/tracer/docstorage.py ============================================================================== --- py/branch/bugfix-0.9.0/py/apigen/tracer/docstorage.py (original) +++ py/branch/bugfix-0.9.0/py/apigen/tracer/docstorage.py Fri Feb 8 09:48:31 2008 @@ -16,7 +16,7 @@ sorted = py.builtin.sorted def pkg_to_dict(module): - defs = module.__package__.exportdefs + defs = module.__pkg__.exportdefs d = {} for key, value in defs.iteritems(): chain = key.split('.') @@ -33,7 +33,7 @@ """ deal with '*' entries in an initpkg situation """ ret = {} modpath = py.path.local(inspect.getsourcefile(module)) - pkgpath = module.__package__.getpath() + pkgpath = module.__pkg__.getpath() for objname in dir(module): if objname.startswith('_'): continue # also skip __*__ attributes @@ -281,8 +281,8 @@ return "Lack of module info" try: retval = module.__doc__ or "*undocumented*" - retval = module.__package__.description - retval = module.__package__.long_description + retval = module.__pkg__.description + retval = module.__pkg__.long_description except AttributeError: pass return retval Modified: py/branch/bugfix-0.9.0/py/bin/_docgen.py ============================================================================== --- py/branch/bugfix-0.9.0/py/bin/_docgen.py (original) +++ py/branch/bugfix-0.9.0/py/bin/_docgen.py Fri Feb 8 09:48:31 2008 @@ -10,7 +10,7 @@ from _findpy import py import py -pypath = py.__package__.getpath() +pypath = py.__pkg__.getpath() def run_tests(path, envvars='', args=''): pytestpath = pypath.join('bin/py.test') Modified: py/branch/bugfix-0.9.0/py/bin/_makepyrelease.py ============================================================================== --- py/branch/bugfix-0.9.0/py/bin/_makepyrelease.py (original) +++ py/branch/bugfix-0.9.0/py/bin/_makepyrelease.py Fri Feb 8 09:48:31 2008 @@ -147,9 +147,9 @@ if __name__ == '__main__': py.magic.invoke(assertion=True) version = py.std.sys.argv[1] - assert py.__package__.version == version, ( + assert py.__pkg__.version == version, ( "py package has version %s\nlocation: %s" % - (py.__package__.version, pydir)) + (py.__pkg__.version, pydir)) tmpdir = py.path.local.get_temproot().join('makepyrelease-%s' % version) if tmpdir.check(): @@ -171,14 +171,14 @@ py.process.cmdexec("rsync -avz %(source)s/ %(remotedir)s" % locals()) ddir = tmpdir.ensure('download', dir=1) - URL = py.__package__.download_url # 'http://codespeak.net/download/py/' + URL = py.__pkg__.download_url # 'http://codespeak.net/download/py/' unpacked = unpackremotetar(ddir, URL) assert unpacked == ddir.join("py-%s" % (version,)) #checksvnworks(unpacked) #pytest(unpacked) - pytest_remote('test at codespeak.net', py.__package__.download_url) + pytest_remote('test at codespeak.net', py.__pkg__.download_url) Modified: py/branch/bugfix-0.9.0/py/bin/_update_website.py ============================================================================== --- py/branch/bugfix-0.9.0/py/bin/_update_website.py (original) +++ py/branch/bugfix-0.9.0/py/bin/_update_website.py Fri Feb 8 09:48:31 2008 @@ -24,7 +24,7 @@ def run_tests(pkgpath, apigenpath, args='', captureouterr=False): """ run the unit tests and build the docs """ - pypath = py.__package__.getpath() + pypath = py.__pkg__.getpath() pytestpath = pypath.join('bin/py.test') # XXX this would need a Windows specific version if we want to allow # running this script on that platform, but currently --apigen doesn't @@ -82,7 +82,7 @@ args.remove('--ignorefail') ignorefail = True args = ' '.join(sys.argv[1:]) - pkgpath = py.__package__.getpath() + pkgpath = py.__pkg__.getpath() apidocspath = pkgpath.dirpath().join('apigen') main(pkgpath, apidocspath, 'codespeak.net', '/home/guido/rsynctests', args, ignorefail) Modified: py/branch/bugfix-0.9.0/py/doc/conftest.py ============================================================================== --- py/branch/bugfix-0.9.0/py/doc/conftest.py (original) +++ py/branch/bugfix-0.9.0/py/doc/conftest.py Fri Feb 8 09:48:31 2008 @@ -310,7 +310,7 @@ 'to the py package') % (text,) relpath = '/'.join(text.split('/')[1:]) if check: - pkgroot = py.__package__.getpath() + pkgroot = py.__pkg__.getpath() abspath = pkgroot.join(relpath) assert pkgroot.join(relpath).check(), ( 'problem with linkrole :source:`%s`: ' Modified: py/branch/bugfix-0.9.0/py/initpkg.py ============================================================================== --- py/branch/bugfix-0.9.0/py/initpkg.py (original) +++ py/branch/bugfix-0.9.0/py/initpkg.py Fri Feb 8 09:48:31 2008 @@ -38,9 +38,9 @@ self.name = name self.exportdefs = exportdefs self.module = pkgmodule - assert not hasattr(pkgmodule, '__package__'), \ + assert not hasattr(pkgmodule, '__pkg__'), \ "unsupported reinitialization of %r" % pkgmodule - pkgmodule.__package__ = self + pkgmodule.__pkg__ = self # make available pkgname.__ implname = name + '.' + '__' @@ -134,7 +134,7 @@ from cStringIO import StringIO except ImportError: from StringIO import StringIO - base = py.__package__.getpath().dirpath() + base = py.__pkg__.getpath().dirpath() outf = StringIO() f = zipfile.ZipFile(outf, 'w', compression=zipfile.ZIP_DEFLATED) try: @@ -164,14 +164,14 @@ class Module(ModuleType): def __init__(self, pkg, name): - self.__package__ = pkg + self.__pkg__ = pkg self.__name__ = name self.__map__ = {} def __getattr__(self, name): if '*' in self.__map__: extpy = self.__map__['*'][0], name - result = self.__package__._resolve(extpy) + result = self.__pkg__._resolve(extpy) else: try: extpy = self.__map__[name] @@ -179,7 +179,7 @@ __tracebackhide__ = True raise AttributeError(name) else: - result = self.__package__._resolve(extpy) + result = self.__pkg__._resolve(extpy) del self.__map__[name] setattr(self, name, result) #self._fixinspection(result, name) @@ -216,7 +216,7 @@ assert not self.__map__, "%r not empty" % self.__map__ else: fsname = self.__map__['*'][0] - dict.update(self.__package__._loadimpl(fsname[:-3]).__dict__) + dict.update(self.__pkg__._loadimpl(fsname[:-3]).__dict__) return dict __dict__ = property(getdict) Modified: py/branch/bugfix-0.9.0/py/misc/_dist.py ============================================================================== --- py/branch/bugfix-0.9.0/py/misc/_dist.py (original) +++ py/branch/bugfix-0.9.0/py/misc/_dist.py Fri Feb 8 09:48:31 2008 @@ -144,7 +144,7 @@ params = Params(pkg) #dump(params) - source = getattr(pkg, '__package__', pkg) + source = getattr(pkg, '__pkg__', pkg) namelist = list(core.setup_keywords) namelist.extend(['packages', 'scripts', 'data_files']) for name in namelist: Modified: py/branch/bugfix-0.9.0/py/misc/testing/test_initpkg.py ============================================================================== --- py/branch/bugfix-0.9.0/py/misc/testing/test_initpkg.py (original) +++ py/branch/bugfix-0.9.0/py/misc/testing/test_initpkg.py Fri Feb 8 09:48:31 2008 @@ -33,7 +33,7 @@ def test_resolve_attrerror(): extpyish = "./initpkg.py", "hello" - excinfo = py.test.raises(AttributeError, "py.__package__._resolve(extpyish)") + excinfo = py.test.raises(AttributeError, "py.__pkg__._resolve(extpyish)") s = str(excinfo.value) assert s.find(extpyish[0]) != -1 assert s.find(extpyish[1]) != -1 @@ -83,16 +83,16 @@ assert __import__(modpath) def test_shahexdigest(): - hex = py.__package__.shahexdigest() + hex = py.__pkg__.shahexdigest() assert len(hex) == 40 def test_getzipdata(): - s = py.__package__.getzipdata() + s = py.__pkg__.getzipdata() def test_getrev(): if not py.path.local(py.__file__).dirpath('.svn').check(): py.test.skip("py package is not a svn checkout") - d = py.__package__.getrev() + d = py.__pkg__.getrev() svnversion = py.path.local.sysfind('svnversion') if svnversion is None: py.test.skip("cannot test svnversion, 'svnversion' binary not found") @@ -255,5 +255,5 @@ def test_url_of_version(): py.test.skip("FAILING! - provide a proper URL or upload pylib tgz") from urllib import URLopener - URLopener().open(py.__package__.download_url) + URLopener().open(py.__pkg__.download_url) Modified: py/branch/bugfix-0.9.0/py/path/local/local.py ============================================================================== --- py/branch/bugfix-0.9.0/py/path/local/local.py (original) +++ py/branch/bugfix-0.9.0/py/path/local/local.py Fri Feb 8 09:48:31 2008 @@ -401,8 +401,8 @@ self._prependsyspath(pkgpath.dirpath()) pkg = __import__(pkgpath.basename, None, None, []) - if hasattr(pkg, '__package__'): - modname = pkg.__package__.getimportname(self) + if hasattr(pkg, '__pkg__'): + modname = pkg.__pkg__.getimportname(self) assert modname is not None, "package %s doesn't know %s" % ( pkg.__name__, self) Modified: py/branch/bugfix-0.9.0/py/test/terminal/terminal.py ============================================================================== --- py/branch/bugfix-0.9.0/py/test/terminal/terminal.py (original) +++ py/branch/bugfix-0.9.0/py/test/terminal/terminal.py Fri Feb 8 09:48:31 2008 @@ -129,7 +129,7 @@ #self.out.line("testing-mode: %s" % mode) self.out.line("executable: %s (%s)" % (py.std.sys.executable, repr_pythonversion())) - rev = py.__package__.getrev() + rev = py.__pkg__.getrev() self.out.line("using py lib: %s " % ( py.path.local(py.__file__).dirpath(), rev)) From py-svn at codespeak.net Fri Feb 8 20:50:06 2008 From: py-svn at codespeak.net (py-svn at codespeak.net) Date: Fri, 8 Feb 2008 20:50:06 +0100 (CET) Subject: SALE 73% OFF on VIAGRA® Message-ID: <20080208075002.13369.qmail@host86-144-105-31.range86-144.btcentralplus.com> An HTML attachment was scrubbed... URL: From guido at codespeak.net Mon Feb 11 13:12:19 2008 From: guido at codespeak.net (guido at codespeak.net) Date: Mon, 11 Feb 2008 13:12:19 +0100 (CET) Subject: [py-svn] r51381 - py/branch/guido-svn-auth Message-ID: <20080211121219.39E651683E5@codespeak.net> Author: guido Date: Mon Feb 11 13:12:18 2008 New Revision: 51381 Added: py/branch/guido-svn-auth/ - copied from r51380, py/trunk/ Log: Creating branch to work on auth support for py.path.svn*. From hpk at codespeak.net Mon Feb 11 20:58:08 2008 From: hpk at codespeak.net (hpk at codespeak.net) Date: Mon, 11 Feb 2008 20:58:08 +0100 (CET) Subject: [py-svn] r51396 - py/branch/event/py/test2/testing Message-ID: <20080211195808.54553168405@codespeak.net> Author: hpk Date: Mon Feb 11 20:58:07 2008 New Revision: 51396 Removed: py/branch/event/py/test2/testing/example1.py py/branch/event/py/test2/testing/example2.py Modified: py/branch/event/py/test2/testing/test_boxing.py py/branch/event/py/test2/testing/test_executor.py Log: remove or inline example test data Deleted: /py/branch/event/py/test2/testing/example1.py ============================================================================== --- /py/branch/event/py/test2/testing/example1.py Mon Feb 11 20:58:07 2008 +++ (empty file) @@ -1,12 +0,0 @@ - -def f1(): - f2() - -def f2(): - pass - -def g1(): - g2() - -def g2(): - raise ValueError() Deleted: /py/branch/event/py/test2/testing/example2.py ============================================================================== --- /py/branch/event/py/test2/testing/example2.py Mon Feb 11 20:58:07 2008 +++ (empty file) @@ -1,30 +0,0 @@ - -""" some example for running box stuff inside -""" - -import sys -import py, os - -def boxf1(): - print "some out" - print >>sys.stderr, "some err" - return 1 - -def boxf2(): - os.write(1, "someout") - os.write(2, "someerr") - return 2 - -def boxseg(): - os.kill(os.getpid(), 11) - -def boxhuge(): - os.write(1, " " * 10000) - os.write(2, " " * 10000) - os.write(1, " " * 10000) - - os.write(1, " " * 10000) - os.write(2, " " * 10000) - os.write(2, " " * 10000) - os.write(1, " " * 10000) - return 3 Modified: py/branch/event/py/test2/testing/test_boxing.py ============================================================================== --- py/branch/event/py/test2/testing/test_boxing.py (original) +++ py/branch/event/py/test2/testing/test_boxing.py Mon Feb 11 20:58:07 2008 @@ -8,7 +8,6 @@ py.test.skip("rsession is unsupported on Windows.") from py.__.test2.box import Box -from py.__.test2.testing import example2 def setup_module(mod): tmpdir = py.test2.ensuretemp("boxtests") @@ -18,7 +17,7 @@ # XXX: because we do not have option transfer ## if not hasattr(option, 'nocapture') or not option.nocapture: ## py.test.skip("Interacts with pylib i/o skipping which is bad actually") - b = Box(example2.boxf1, config=config) + b = Box(boxf1, config=config) b.run() assert b.stdoutrepr == "some out\n" assert b.stderrrepr == "some err\n" @@ -27,7 +26,7 @@ assert b.retval == 1 def test_boxing_on_fds(): - b = Box(example2.boxf2, config=config) + b = Box(boxf2, config=config) b.run() assert b.stdoutrepr == "someout" assert b.stderrrepr == "someerr" @@ -36,7 +35,7 @@ assert b.retval == 2 def test_boxing_signal(): - b = Box(example2.boxseg, config=config) + b = Box(boxseg, config=config) b.run() assert b.retval is None if py.std.sys.version_info < (2,4): @@ -44,7 +43,7 @@ assert b.signal == 11 def test_boxing_huge_data(): - b = Box(example2.boxhuge, config=config) + b = Box(boxhuge, config=config) b.run() assert b.stdoutrepr assert b.exitstat == 0 @@ -54,7 +53,7 @@ def test_box_seq(): # we run many boxes with huge data, just one after another for i in xrange(100): - b = Box(example2.boxhuge, config=config) + b = Box(boxhuge, config=config) b.run() assert b.stdoutrepr assert b.exitstat == 0 @@ -63,7 +62,7 @@ def test_box_in_a_box(): def boxfun(): - b = Box(example2.boxf2, config=config) + b = Box(boxf2, config=config) b.run() print b.stdoutrepr print >>sys.stderr, b.stderrrepr @@ -93,3 +92,33 @@ if py.std.sys.version_info < (2,4): py.test.skip("signal detection does not work with python prior 2.4") assert b.signal == 15 + + +# ====================================================================== +# examples +# ====================================================================== +# + +def boxf1(): + print "some out" + print >>sys.stderr, "some err" + return 1 + +def boxf2(): + os.write(1, "someout") + os.write(2, "someerr") + return 2 + +def boxseg(): + os.kill(os.getpid(), 11) + +def boxhuge(): + os.write(1, " " * 10000) + os.write(2, " " * 10000) + os.write(1, " " * 10000) + + os.write(1, " " * 10000) + os.write(2, " " * 10000) + os.write(2, " " * 10000) + os.write(1, " " * 10000) + return 3 Modified: py/branch/event/py/test2/testing/test_executor.py ============================================================================== --- py/branch/event/py/test2/testing/test_executor.py (original) +++ py/branch/event/py/test2/testing/test_executor.py Mon Feb 11 20:58:07 2008 @@ -1,6 +1,5 @@ import py -import example1 from py.__.test2.executor import RunExecutor, BoxExecutor,\ AsyncExecutor, ApigenExecutor From hpk at codespeak.net Mon Feb 11 21:02:37 2008 From: hpk at codespeak.net (hpk at codespeak.net) Date: Mon, 11 Feb 2008 21:02:37 +0100 (CET) Subject: [py-svn] r51397 - py/branch/event/py/test2/rsession Message-ID: <20080211200237.8A34C168405@codespeak.net> Author: hpk Date: Mon Feb 11 21:02:36 2008 New Revision: 51397 Modified: py/branch/event/py/test2/rsession/hostmanage.py Log: cleanup import Modified: py/branch/event/py/test2/rsession/hostmanage.py ============================================================================== --- py/branch/event/py/test2/rsession/hostmanage.py (original) +++ py/branch/event/py/test2/rsession/hostmanage.py Mon Feb 11 21:02:36 2008 @@ -1,12 +1,10 @@ import py -import sys, os +import os from py.__.test2.rsession.master import MasterNode from py.__.test2 import repevent class HostInfo(object): - """ Class trying to store all necessary attributes - for host - """ + """ Host location representation for distributed testing. """ _hostname2list = {} def __init__(self, spec, addrel=""): From hpk at codespeak.net Mon Feb 11 21:03:19 2008 From: hpk at codespeak.net (hpk at codespeak.net) Date: Mon, 11 Feb 2008 21:03:19 +0100 (CET) Subject: [py-svn] r51398 - py/branch/event/py/test2/testing Message-ID: <20080211200319.C9119168405@codespeak.net> Author: hpk Date: Mon Feb 11 21:03:17 2008 New Revision: 51398 Removed: py/branch/event/py/test2/testing/test_collectonly.py py/branch/event/py/test2/testing/test_raises.py Modified: py/branch/event/py/test2/testing/test_collect.py py/branch/event/py/test2/testing/test_outcome.py Log: merge test files a bit Modified: py/branch/event/py/test2/testing/test_collect.py ============================================================================== --- py/branch/event/py/test2/testing/test_collect.py (original) +++ py/branch/event/py/test2/testing/test_collect.py Mon Feb 11 21:03:17 2008 @@ -4,6 +4,8 @@ from py.__.test2.outcome import Skipped, Failed, Passed, Outcome from py.__.test2.terminal.out import getout from py.__.test2.repevent import ItemFinish +from test_session import getevents_runmain +from py.__.test2 import repevent def getpassed(session): hub = session.config.hub @@ -474,5 +476,41 @@ col = py.test2.collect.Directory(tmpdir) names = col.run() assert names == fnames + +class TestCollectonly: + def setup_class(cls): + tmp = py.test2.ensuretemp('itemgentest') + tmp.ensure("__init__.py") + tmp.ensure("test_one.py").write(py.code.Source(""" + def test_one(): + pass + + class TestX: + def test_method_one(self): + pass + + class TestY(TestX): + pass + """)) + tmp.ensure("test_two.py").write(py.code.Source(""" + import py + py.test.skip('xxx') + """)) + tmp.ensure("test_three.py").write("xxxdsadsadsadsa") + cls.tmp = tmp + + def test_collectonly(self): + config = py.test2.config._reparse([self.tmp, '--collectonly']) + session = config.initsession() + # test it all in once + allevents = getevents_runmain(session) + started = finished = 0 + for event in allevents: + assert not isinstance(event, repevent.ItemFinish) + if isinstance(event, repevent.CollectionStart): + started += 1 + elif isinstance(event, repevent.CollectionFinish): + finished += 1 - + print started + assert started == finished Deleted: /py/branch/event/py/test2/testing/test_collectonly.py ============================================================================== --- /py/branch/event/py/test2/testing/test_collectonly.py Mon Feb 11 21:03:17 2008 +++ (empty file) @@ -1,44 +0,0 @@ - -import py - - -from test_session import getevents_runmain -from py.__.test2 import repevent - -class TestCollectonly: - def setup_class(cls): - tmp = py.test2.ensuretemp('itemgentest') - tmp.ensure("__init__.py") - tmp.ensure("test_one.py").write(py.code.Source(""" - def test_one(): - pass - - class TestX: - def test_method_one(self): - pass - - class TestY(TestX): - pass - """)) - tmp.ensure("test_two.py").write(py.code.Source(""" - import py - py.test.skip('xxx') - """)) - tmp.ensure("test_three.py").write("xxxdsadsadsadsa") - cls.tmp = tmp - - def test_collectonly(self): - config = py.test2.config._reparse([self.tmp, '--collectonly']) - session = config.initsession() - # test it all in once - allevents = getevents_runmain(session) - started = finished = 0 - for event in allevents: - assert not isinstance(event, repevent.ItemFinish) - if isinstance(event, repevent.CollectionStart): - started += 1 - elif isinstance(event, repevent.CollectionFinish): - finished += 1 - - print started - assert started == finished Modified: py/branch/event/py/test2/testing/test_outcome.py ============================================================================== --- py/branch/event/py/test2/testing/test_outcome.py (original) +++ py/branch/event/py/test2/testing/test_outcome.py Mon Feb 11 21:03:17 2008 @@ -68,3 +68,16 @@ s = repr(out) assert s.lower().find("skip") != -1 +class TestRaises: + def test_raises(self): + py.test.raises(ValueError, "int('qwe')") + + def test_raises_exec(self): + py.test.raises(ValueError, "a,x = []") + + def test_raises_syntax_error(self): + py.test.raises(SyntaxError, "qwe qwe qwe") + + def test_raises_function(self): + py.test.raises(ValueError, int, 'hello') + Deleted: /py/branch/event/py/test2/testing/test_raises.py ============================================================================== --- /py/branch/event/py/test2/testing/test_raises.py Mon Feb 11 21:03:17 2008 +++ (empty file) @@ -1,18 +0,0 @@ -from py import test - -def somefunc(x, y): - assert x == y - -class TestClass: - def test_raises(self): - test.raises(ValueError, "int('qwe')") - - def test_raises_exec(self): - test.raises(ValueError, "a,x = []") - - def test_raises_syntax_error(self): - test.raises(SyntaxError, "qwe qwe qwe") - - def test_raises_function(self): - test.raises(ValueError, int, 'hello') - From hpk at codespeak.net Tue Feb 12 17:49:44 2008 From: hpk at codespeak.net (hpk at codespeak.net) Date: Tue, 12 Feb 2008 17:49:44 +0100 (CET) Subject: [py-svn] r51415 - py/branch/event/py/test2/rsession/testing Message-ID: <20080212164944.BE3C61683F6@codespeak.net> Author: hpk Date: Tue Feb 12 17:49:44 2008 New Revision: 51415 Added: py/branch/event/py/test2/rsession/testing/test_masterslave.py Log: adding some fast master/slave rsession related tests Added: py/branch/event/py/test2/rsession/testing/test_masterslave.py ============================================================================== --- (empty file) +++ py/branch/event/py/test2/rsession/testing/test_masterslave.py Tue Feb 12 17:49:44 2008 @@ -0,0 +1,54 @@ + +import py +from py.__.test2.rsession.master import MasterNode +from py.__.test2.rsession.hostmanage import HostInfo +from basetest import BasicRsessionTest +from py.__.test2 import repevent + + +class TestMasterSlaveConnection(BasicRsessionTest): + def makereportqueue(self, filterevent=repevent.ItemTestReport): + queue = py.std.Queue.Queue() + def append(event): + if isinstance(event, filterevent): + queue.put(event) + self.config.hub.append(append) + return queue + + def test_node_down(self): + host = HostInfo("localhost") + host.initgateway() + node = MasterNode(host, self.config) + assert not node.channel.isclosed() + + queue = self.makereportqueue(repevent.HostDown) + node.send(None) + event = queue.get(timeout=1.0) + assert event.host == host + + def test_send_one(self): + host = HostInfo("localhost") + host.initgateway() + node = MasterNode(host, self.config) + assert not node.channel.isclosed() + + queue = self.makereportqueue() + node.send(self.getexample("passed")) + event = queue.get(timeout=2.0) + assert event.passed + assert not node.pending + + def test_send_multiple(self): + host = HostInfo("localhost") + host.initgateway() + node = MasterNode(host, self.config) + assert not node.channel.isclosed() + + queue = self.makereportqueue() + for outcome in "passed failed skipped".split(): + node.send(self.getexample(outcome)) + event = queue.get(timeout=2.0) + assert getattr(event, outcome) + assert not node.pending + + From hpk at codespeak.net Tue Feb 12 18:06:07 2008 From: hpk at codespeak.net (hpk at codespeak.net) Date: Tue, 12 Feb 2008 18:06:07 +0100 (CET) Subject: [py-svn] r51416 - in py/branch/event/py/test2: . rsession/testing testing Message-ID: <20080212170607.14B691683F2@codespeak.net> Author: hpk Date: Tue Feb 12 18:06:06 2008 New Revision: 51416 Added: py/branch/event/py/test2/genitem.py Modified: py/branch/event/py/test2/collect.py py/branch/event/py/test2/rsession/testing/basetest.py py/branch/event/py/test2/rsession/testing/test_masterslave.py py/branch/event/py/test2/rsession/testing/test_rsession.py py/branch/event/py/test2/rsession/testing/test_slave.py py/branch/event/py/test2/session.py py/branch/event/py/test2/testing/setupdata.py py/branch/event/py/test2/testing/test_collect.py py/branch/event/py/test2/testing/test_doctest.py py/branch/event/py/test2/testing/test_executor.py py/branch/event/py/test2/testing/test_remote.py py/branch/event/py/test2/testing/test_session.py Log: * get rid of _tryiter usages, port tests to new itemgen * factor out 'genitem()' generator * refactor tests Modified: py/branch/event/py/test2/collect.py ============================================================================== --- py/branch/event/py/test2/collect.py (original) +++ py/branch/event/py/test2/collect.py Tue Feb 12 18:06:06 2008 @@ -26,6 +26,8 @@ from __future__ import generators import py +sysex = (KeyboardInterrupt, SystemExit, GeneratorExit) + def configproperty(name): def fget(self): #print "retrieving %r property from %s" %(name, self.fspath) @@ -201,26 +203,6 @@ return True return False - 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. - """ - if yieldtype is None: - yieldtype = py.test2.collect.Item - if isinstance(self, yieldtype): - yield self - else: - if not isinstance(self, py.test2.collect.Item): - try: - for x in self.run(): - for y in self.join(x)._tryiter(yieldtype): - yield y - except KeyboardInterrupt: - raise - except: - pass - def _getsortvalue(self): return self.name @@ -257,6 +239,9 @@ if path.check(dir=1, dotfile=0): return path.basename not in ('CVS', '_darcs', '{arch}') + def list(self): + return [self.join(x) for x in self.run()] + def run(self): files = [] dirs = [] @@ -428,9 +413,6 @@ return py.path.local(file), lineno except IOError: pass - # fall back... - for x in self._tryiter((py.test2.collect.Generator, py.test2.collect.Item)): - return x._getsortvalue() class Instance(PyCollectorMixin, Collector): def _getobj(self): @@ -455,7 +437,7 @@ def setup(self): """ perform setup for this test function. """ - if getattr(self.obj, 'im_self', None): + if hasattr(self.obj, 'im_self'): name = 'setup_method' else: name = 'setup_function' @@ -466,7 +448,7 @@ def teardown(self): """ perform teardown for this test function. """ - if getattr(self.obj, 'im_self', None): + if hasattr(self.obj, 'im_self'): name = 'teardown_method' else: name = 'teardown_function' @@ -511,3 +493,4 @@ item = DoctestText(self.fspath.basename, parent=self) item._content = self.fspath.read() return item + Added: py/branch/event/py/test2/genitem.py ============================================================================== --- (empty file) +++ py/branch/event/py/test2/genitem.py Tue Feb 12 18:06:06 2008 @@ -0,0 +1,30 @@ + +import py +from py.__.test2 import repevent +sysex = (KeyboardInterrupt, SystemExit) + +def genitems(config, colitems, keywordexpr=None, + stopitems=(py.test2.collect.Item,)): + """ yield Items from iterating over the given colitems. """ + hub = config.hub + while colitems: + next = colitems.pop(0) + if isinstance(next, stopitems): + if next._skipbykeyword(keywordexpr): + hub.notify(repevent.DeselectedTest(next, keywordexpr)) + if config.option.keyword_oneshot: + keywordexpr = None + else: + yield next + else: + hub.notify(repevent.CollectionStart(next)) + excinfo = None + try: + cols = [next.join(x) for x in next.run()] + for x in genitems(config, cols, keywordexpr): + yield x + except sysex: + raise + except: + excinfo = py.code.ExceptionInfo() + hub.notify(repevent.CollectionFinish(next, excinfo)) Modified: py/branch/event/py/test2/rsession/testing/basetest.py ============================================================================== --- py/branch/event/py/test2/rsession/testing/basetest.py (original) +++ py/branch/event/py/test2/rsession/testing/basetest.py Tue Feb 12 18:06:06 2008 @@ -3,55 +3,19 @@ """ import py - -def func_source(): - import py - import time - def funcpassed(): - pass - - def funcfailed(): - raise AssertionError("hello world") - - def funcskipped(): - py.test2.skip("skipped") - - def funcprint(): - print "samfing" - - def funcprintfail(): - print "samfing elz" - asddsa - - def funcoptioncustom(): - assert py.test2.config.getvalue("custom") - - def funchang(): - import time - time.sleep(1000) +from py.__.test2.testing.setupdata import getexamplefile class BasicRsessionTest(object): def setup_class(cls): - tmpdir = py.test2.ensuretemp(cls.__name__) - source = py.code.Source(func_source)[1:].deindent() - testonepath = tmpdir.ensure("test_one.py") - testonepath.write(source) - cls.config = py.test2.config._reparse([tmpdir]) - cls.collector_test_one = cls.config._getcollector(testonepath) - cls.doctest = tmpdir.ensure("xxx.txt").write(py.code.Source(""" - Aha!!!!!! - ========= - - """)) - - def getexample(self, name): + path = getexamplefile("funcexamples.py") + cls.config = py.test2.config._reparse([path.dirpath()]) + cls.modulecol = cls.config._getcollector(path) + + def getfunc(self, name): funcname = "func" + name - col = self.collector_test_one.join(funcname) + col = self.modulecol.join(funcname) assert col is not None, funcname return col def getdocexample(self): - return self.doctest - - def getmod(self): - return self.collector_test_one + return getexamplefile("docexample.txt") Modified: py/branch/event/py/test2/rsession/testing/test_masterslave.py ============================================================================== --- py/branch/event/py/test2/rsession/testing/test_masterslave.py (original) +++ py/branch/event/py/test2/rsession/testing/test_masterslave.py Tue Feb 12 18:06:06 2008 @@ -33,7 +33,7 @@ assert not node.channel.isclosed() queue = self.makereportqueue() - node.send(self.getexample("passed")) + node.send(self.getfunc("passed")) event = queue.get(timeout=2.0) assert event.passed assert not node.pending @@ -46,7 +46,7 @@ queue = self.makereportqueue() for outcome in "passed failed skipped".split(): - node.send(self.getexample(outcome)) + node.send(self.getfunc(outcome)) event = queue.get(timeout=2.0) assert getattr(event, outcome) assert not node.pending Modified: py/branch/event/py/test2/rsession/testing/test_rsession.py ============================================================================== --- py/branch/event/py/test2/rsession/testing/test_rsession.py (original) +++ py/branch/event/py/test2/rsession/testing/test_rsession.py Tue Feb 12 18:06:06 2008 @@ -94,10 +94,10 @@ # actually run some tests for host in hm.hosts: node = host.node - node.send(self.getexample("passed")) - node.send(self.getexample("failed")) - node.send(self.getexample("skipped")) - node.send(self.getexample("print")) + node.send(self.getfunc("passed")) + node.send(self.getfunc("failed")) + node.send(self.getfunc("skipped")) + node.send(self.getfunc("print")) num_hosts = len(hm.hosts) events = [] Modified: py/branch/event/py/test2/rsession/testing/test_slave.py ============================================================================== --- py/branch/event/py/test2/rsession/testing/test_slave.py (original) +++ py/branch/event/py/test2/rsession/testing/test_slave.py Tue Feb 12 18:06:06 2008 @@ -22,7 +22,7 @@ def test_slave_run_passing(self): node = self.gettestnode() - item = self.getexample("passed") + item = self.getfunc("passed") outcome = node.execute(item._get_collector_trail()) assert outcome.passed assert not outcome.setupfailure @@ -34,7 +34,7 @@ def test_slave_run_failing(self): node = self.gettestnode() - item = self.getexample("failed") + item = self.getfunc("failed") outcome = node.execute(item._get_collector_trail()) assert not outcome.passed assert not outcome.setupfailure @@ -49,7 +49,7 @@ def test_slave_run_skipping(self): node = self.gettestnode() - item = self.getexample("skipped") + item = self.getfunc("skipped") outcome = node.execute(item._get_collector_trail()) assert not outcome.passed assert outcome.skipped @@ -61,7 +61,7 @@ def test_slave_run_failing_wrapped(self): node = self.gettestnode() - item = self.getexample("failed") + item = self.getfunc("failed") repr_outcome = node.run(item._get_collector_trail()) outcome = ReprOutcome(repr_outcome) assert not outcome.passed Modified: py/branch/event/py/test2/session.py ============================================================================== --- py/branch/event/py/test2/session.py (original) +++ py/branch/event/py/test2/session.py Tue Feb 12 18:06:06 2008 @@ -6,12 +6,11 @@ """ import py +from py.__.test2.genitem import genitems from py.__.test2 import repevent from py.__.test2.outcome import ReprOutcome from py.__.test2.executor import RunExecutor, BoxExecutor -GeneratorExit = py.builtin.GeneratorExit - class Session(object): """ Session drives the collection and running of tests @@ -41,34 +40,9 @@ def collect(self): colitems = self.config.getcolitems() keyword = self.config.option.keyword - for x in self.genitems(colitems, keyword): + for x in genitems(self.config, colitems, keyword): yield x - def genitems(self, colitems, keywordexpr=None): - hub = self.config.hub - stopitems = py.test2.collect.Item - while colitems: - next = colitems.pop(0) - if isinstance(next, stopitems): - if next._skipbykeyword(keywordexpr): - hub.notify(repevent.DeselectedTest(next, keywordexpr)) - if self.config.option.keyword_oneshot: - keywordexpr = None - else: - yield next - else: - hub.notify(repevent.CollectionStart(next)) - excinfo = None - try: - cols = [next.join(x) for x in next.run()] - for x in self.genitems(cols, keywordexpr): - yield x - except (KeyboardInterrupt, SystemExit, GeneratorExit): - raise - except: - excinfo = py.code.ExceptionInfo() - hub.notify(repevent.CollectionFinish(next, excinfo)) - def setup(self): """ setup any neccessary resources ahead of the test run. """ if not self.config.option.nomagic: Modified: py/branch/event/py/test2/testing/setupdata.py ============================================================================== --- py/branch/event/py/test2/testing/setupdata.py (original) +++ py/branch/event/py/test2/testing/setupdata.py Tue Feb 12 18:06:06 2008 @@ -1,21 +1,26 @@ import py -def setup_module(mod): - mod.datadir = setupdatadir() - mod.tmpdir = py.test2.ensuretemp(mod.__name__) - -def setupdatadir(): - datadir = py.test2.ensuretemp("datadir") - names = [x.basename for x in datadir.listdir()] - for name, content in namecontent: - if name not in names: - datadir.join(name).write(content) - return datadir +#def setup_module(mod): +# mod.datadir = setupdatadir() +# mod.tmpdir = py.test2.ensuretemp(mod.__name__) + +#def setupdatadir(): +# datadir = py.test2.ensuretemp("datadir") +# for name in namecontent: +# getexamplefile(name) +# return datadir + +def getexamplefile(basename): + datadir = py.test2.ensuretemp("datadir") + path = datadir.join(basename) + if not path.check(): + path.write(namecontent[basename]) + return path -namecontent = [ -('syntax_error.py', "this is really not python\n"), +namecontent = { + 'syntax_error.py': "this is really not python\n", -('disabled_module.py', py.code.Source(''' + 'disabled_module.py': py.code.Source(''' disabled = True def setup_module(mod): @@ -30,49 +35,48 @@ raise ValueError def test_func(self): raise ValueError -''')), + '''), -('brokenrepr.py', py.code.Source(''' + 'brokenrepr.py': py.code.Source(''' + import py - import py + class BrokenRepr1: + """A broken class with lots of broken methods. Let's try to make the test framework + immune to these.""" + foo=0 + def __repr__(self): + raise Exception("Ha Ha fooled you, I'm a broken repr().") + + class BrokenRepr2: + """A broken class with lots of broken methods. Let's try to make the test framework + immune to these.""" + foo=0 + def __repr__(self): + raise "Ha Ha fooled you, I'm a broken repr()." - class BrokenRepr1: - """A broken class with lots of broken methods. Let's try to make the test framework - immune to these.""" - foo=0 - def __repr__(self): - raise Exception("Ha Ha fooled you, I'm a broken repr().") - - class BrokenRepr2: - """A broken class with lots of broken methods. Let's try to make the test framework - immune to these.""" - foo=0 - def __repr__(self): - raise "Ha Ha fooled you, I'm a broken repr()." - - - class TestBrokenClass: - - def test_explicit_bad_repr(self): - t = BrokenRepr1() - py.test2.raises(Exception, 'repr(t)') - def test_implicit_bad_repr1(self): - t = BrokenRepr1() - assert t.foo == 1 - - def test_implicit_bad_repr2(self): - t = BrokenRepr2() - assert t.foo == 1 - ''')), + class TestBrokenClass: - ('failingimport.py', py.code.Source(''' + def test_explicit_bad_repr(self): + t = BrokenRepr1() + py.test2.raises(Exception, 'repr(t)') + + def test_implicit_bad_repr1(self): + t = BrokenRepr1() + assert t.foo == 1 + + def test_implicit_bad_repr2(self): + t = BrokenRepr2() + assert t.foo == 1 + '''), + + 'failingimport.py': py.code.Source(''' import gruetzelmuetzel - ''')), + '''), - ('filetest.py', py.code.Source(''' + 'filetest.py': py.code.Source(''' def test_one(): assert 42 == 43 @@ -80,8 +84,9 @@ def test_method_one(self): assert 42 == 43 - ''')), - ('testmore.py', py.code.Source(''' + '''), + + 'testmore.py': py.code.Source(''' def test_one(): assert 1 @@ -90,21 +95,67 @@ def test_three(): assert 1 - ''')), + '''), - ('testspecial_importerror.py', py.code.Source(''' + 'testspecial_importerror.py': py.code.Source(''' import asdasd - ''')), + '''), - ('disabled.py', py.code.Source(''' + 'disabled.py': py.code.Source(''' class TestDisabled: disabled = True def test_method(self): pass - ''')), -] - + '''), + + 'funcexamples.py': py.code.Source(''' + import py + import time + def funcpassed(): + pass + + def funcfailed(): + raise AssertionError("hello world") + + def funcskipped(): + py.test2.skip("skipped") + + def funcprint(): + print "samfing" + + def funcprintfail(): + print "samfing elz" + asddsa + + def funcoptioncustom(): + assert py.test2.config.getvalue("custom") + + def funchang(): + import time + time.sleep(1000) + '''), + + 'test_generative.py': py.code.Source(""" + from __future__ import generators # python2.2! + def func1(arg, arg2): + assert arg == arg2 + + def test_gen(): + yield func1, 17, 3*5 + yield func1, 42, 6*7 + + class TestGenMethods: + def test_gen(self): + yield func1, 17, 3*5 + yield func1, 42, 6*7 + """), + + 'docexample.txt': py.code.Source(""" + Aha!!!!!! + ========= + + """), - +} Modified: py/branch/event/py/test2/testing/test_collect.py ============================================================================== --- py/branch/event/py/test2/testing/test_collect.py (original) +++ py/branch/event/py/test2/testing/test_collect.py Tue Feb 12 18:06:06 2008 @@ -1,11 +1,11 @@ from __future__ import generators import py -from setupdata import setupdatadir -from py.__.test2.outcome import Skipped, Failed, Passed, Outcome -from py.__.test2.terminal.out import getout -from py.__.test2.repevent import ItemFinish +from py.__.test2 import outcome from test_session import getevents_runmain from py.__.test2 import repevent +from py.__.test2.genitem import genitems +from py.__.test2.doctest import DoctestText +from setupdata import getexamplefile def getpassed(session): hub = session.config.hub @@ -14,25 +14,33 @@ try: session.main() print all - passed = [i.passed for i in all if isinstance(i, ItemFinish)] + passed = [i.passed for i in all if isinstance(i, repevent.ItemFinish)] return passed finally: hub.pop() +def eventappender(config): + l = [] + def app(ev): + print ev + l.append(ev) + config.hub.append(app) + return l + def setup_module(mod): - mod.datadir = setupdatadir() - mod.tmpdir = py.test2.ensuretemp('test_collect') + mod.tmpdir = py.test2.ensuretemp(mod.__name__) def test_failing_import_execfile(): - dest = datadir / 'failingimport.py' + dest = getexamplefile('failingimport.py') col = py.test2.collect.Module(dest) py.test2.raises(ImportError, col.run) py.test2.raises(ImportError, col.run) def test_collect_listnames_and_back(): - col1 = py.test2.collect.Directory(datadir.dirpath()) - col2 = col1.join(datadir.basename) - col3 = col2.join('filetest.py') + path = getexamplefile("filetest.py") + col1 = py.test2.collect.Directory(path.dirpath().dirpath()) + col2 = col1.join(path.dirpath().basename) + col3 = col2.join(path.basename) l = col3.listnames() assert len(l) == 3 x = col1._getitembynames(l[1:]) @@ -43,7 +51,7 @@ assert len(l2) == 3 def test_finds_tests(): - fn = datadir / 'filetest.py' + fn = getexamplefile('filetest.py') col = py.test2.collect.Module(fn) l = col.run() assert len(l) == 2 @@ -56,11 +64,10 @@ tmp.ensure('found_test.py') colitem = py.test2.collect.Directory(tmp) - items = list(colitem._tryiter(py.test2.collect.Module)) + items = colitem.list() assert len(items) == 2 - items = [item.name for item in items] - assert 'test_found.py' in items - assert 'found_test.py' in items + assert items[1].name == 'test_found.py' + assert items[0].name == 'found_test.py' def test_ignored_certain_directories(): tmp = py.test2.ensuretemp("ignore_certain_directories") @@ -73,16 +80,17 @@ tmp.ensure('test_found.py') colitem = py.test2.collect.Directory(tmp) - items = list(colitem._tryiter(py.test2.collect.Module)) + items = colitem.run() assert len(items) == 2 - for item in items: - assert item.name == 'test_found.py' + assert 'normal' in items + assert 'test_found.py' in items def test_failing_import_directory(): class MyDirectory(py.test2.collect.Directory): def filefilter(self, p): return p.check(fnmatch='testspecial*.py') - mydir = MyDirectory(datadir) + filetest = getexamplefile("testspecial_importerror.py") + mydir = MyDirectory(filetest.dirpath()) l = mydir.run() assert len(l) == 1 item = mydir.join(l[0]) @@ -90,19 +98,17 @@ py.test2.raises(ImportError, item.run) def test_module_file_not_found(): - fn = datadir.join('nada','no') + fn = tmpdir.join('nada','no') col = py.test2.collect.Module(fn) py.test2.raises(py.error.ENOENT, col.run) def test_syntax_error_in_module(): - p = py.test2.ensuretemp("syntaxerror1").join('syntax_error.py') - p.write("\nthis is really not python\n") - modpath = datadir.join('syntax_error.py') + modpath = getexamplefile("syntax_error.py") col = py.test2.collect.Module(modpath) py.test2.raises(SyntaxError, col.run) def test_disabled_class(): - col = py.test2.collect.Module(datadir.join('disabled.py')) + col = py.test2.collect.Module(getexamplefile('disabled.py')) l = col.run() assert len(l) == 1 colitem = col.join(l[0]) @@ -110,44 +116,13 @@ assert not colitem.run() def test_disabled_module(): - col = py.test2.collect.Module(datadir.join('disabled_module.py')) + p = getexamplefile("disabled_module.py") + col = py.test2.collect.Module(p) l = col.run() assert len(l) == 0 -class Testsomeclass: - disabled = True - def test_something(): - raise ValueError - - -#class TestWithCustomItem: -# class Item(py.test2.collect.Item): -# flag = [] -# def execute(self, target, *args): -# self.flag.append(42) -# target(*args) -# -# def test_hello(self): -# assert self.Item.flag == [42] -# - def test_generative_simple(): - o = tmpdir.ensure('generativetest', dir=1) - tfile = o.join('test_generative.py') - tfile.write(py.code.Source(""" - from __future__ import generators # python2.2! - def func1(arg, arg2): - assert arg == arg2 - - def test_gen(): - yield func1, 17, 3*5 - yield func1, 42, 6*7 - - class TestGenMethods: - def test_gen(self): - yield func1, 17, 3*5 - yield func1, 42, 6*7 - """)) + tfile = getexamplefile('test_generative.py') col = py.test2.collect.Module(tfile) l = col.run() assert len(l) == 2 @@ -178,8 +153,9 @@ assert isinstance(l2[1], py.test2.collect.Function) assert l2[0].name == '[0]' assert l2[1].name == '[1]' - -def test_custom_python_collection_from_conftest(): + + +def setup_customconfigtest(tmpdir): o = tmpdir.ensure('customconfigtest', dir=1) o.ensure('conftest.py').write("""if 1: import py @@ -207,31 +183,9 @@ def check_method(self): assert 23 == 23 """) + return checkfile - for x in (o, checkfile, checkfile.dirpath()): - config = py.test2.config._reparse([x]) - #print "checking that %s returns custom items" % (x,) - col = config._getcollector(x) - assert len(list(col._tryiter(py.test2.collect.Item))) == 2 - #assert items[1].__class__.__name__ == 'MyFunction' - - # test that running a session works from the directories - old = o.chdir() - try: - config = py.test2.config._reparse([]) - session = config._getsessionclass()(config) - l = getpassed(session) - assert len(l) == 2 - finally: - old.chdir() - - # test that running the file directly works - config = py.test2.config._reparse([str(checkfile)]) - session = config._getsessionclass()(config) - l = getpassed(session) - assert len(l) == 2 - -def test_custom_NONpython_collection_from_conftest(): +def setup_non_python_dir(tmpdir): o = tmpdir.ensure('customconfigtest_nonpython', dir=1) o.ensure('conftest.py').write("""if 1: import py @@ -250,30 +204,9 @@ return CustomItem(p, parent=self) """) checkfile = o.ensure('somedir', 'moredir', 'check_something.txt') + return checkfile - for x in (o, checkfile, checkfile.dirpath()): - print "checking that %s returns custom items" % (x,) - config = py.test2.config._reparse([x]) - col = config._getcollector(x) - assert len(list(col._tryiter(py.test2.collect.Item))) == 1 - #assert items[1].__class__.__name__ == 'MyFunction' - - # test that running a session works from the directories - old = o.chdir() - try: - config = py.test2.config._reparse([]) - session = config._getsessionclass()(config) - l = getpassed(session) - assert len(l) == 1 - finally: - old.chdir() - - # test that running the file directly works - config = py.test2.config._reparse([str(checkfile)]) - session = config._getsessionclass()(config) - l = getpassed(session) - assert len(l) == 1 - + def test_order_of_execution_generator_same_codeline(): o = tmpdir.ensure('genorder1', dir=1) o.join("test_order1.py").write(py.code.Source(""" @@ -328,76 +261,6 @@ session = config.initsession() l = getpassed(session) assert len(l) == 4 - - - -def test_documentation_virtual_collector_interaction(): - rootdir = py.path.local(py.__file__).dirpath("doc") - # HACK - from py.__.doc import conftest as conf - old = conf.option.forcegen - try: - conf.option.forcegen = 1 - col = py.test2.collect.Directory(rootdir) - x = list(col._tryiter(yieldtype=py.test2.collect.Function)) - finally: - conf.option.forcegen = old - - -def test__tryiter_ignores_skips(): - tmp = py.test2.ensuretemp("_tryiterskip") - tmp.ensure("subdir", "conftest.py").write(py.code.Source(""" - import py - class Directory(py.test2.collect.Directory): - def run(self): - py.test.skip("intentional") - """)) - col = py.test2.collect.Directory(tmp) - try: - list(col._tryiter()) - except KeyboardInterrupt: - raise - except: - exc = py.code.ExceptionInfo() - py.test2.fail("should not have raised: %s" %(exc,)) - - -def test__tryiter_ignores_failing_collectors(): - tmp = py.test2.ensuretemp("_tryiterfailing") - tmp.ensure("subdir", "conftest.py").write(py.code.Source(""" - bla bla bla - """)) - col = py.test2.collect.Directory(tmp) - try: - list(col._tryiter()) - except KeyboardInterrupt: - raise - except: - exc = py.code.ExceptionInfo() - py.test2.fail("should not have raised: %s" %(exc,)) - - l = [] - -def test_tryiter_handles_keyboardinterrupt(): - tmp = py.test2.ensuretemp("tryiterkeyboard") - tmp.ensure("subdir", "conftest.py").write(py.code.Source(""" - raise KeyboardInterrupt() - """)) - col = py.test2.collect.Directory(tmp) - py.test2.raises(KeyboardInterrupt, list, col._tryiter()) - -def test_check_random_inequality(): - tmp = py.test2.ensuretemp("ineq") - tmp.ensure("test_x.py").write(py.code.Source("""def test_one(): - pass - """)) - col = py.test2.collect.Directory(tmp) - fn = col._tryiter().next() - assert fn != 3 - assert fn != col - assert fn != [1,2,3] - assert [1,2,3] != fn - assert col != fn def test_check_generator_collect_problems(): tmp = py.test2.ensuretemp("gener_coll") @@ -434,33 +297,6 @@ l = list(col._tryiter()) assert not hasattr(col.obj, 'x') -def test_check_collect_hashes(): - tmp = py.test2.ensuretemp("check_collect_hashes") - tmp.ensure("test_one.py").write(py.code.Source(""" - def test_1(): - pass - - def test_2(): - pass - """)) - tmp.ensure("test_two.py").write(py.code.Source(""" - def test_1(): - pass - - def test_2(): - pass - """)) - tmp.ensure("__init__.py") - col = py.test2.collect.Directory(tmp) - l = list(col._tryiter()) - assert len(l) == 4 - for numi, i in enumerate(l): - for numj, j in enumerate(l): - if numj != numi: - assert hash(i) != hash(j) - assert i != j - - def test_check_directory_ordered(): tmpdir = py.test2.ensuretemp("test_check_directory_ordered") fnames = [] @@ -477,40 +313,196 @@ names = col.run() assert names == fnames -class TestCollectonly: +def test_documentation_virtual_collector_interaction(): + py.test.skip("figure out this test and rewrite independent of py/doc.") + rootdir = py.path.local(py.__file__).dirpath("doc") + # HACK + from py.__.doc import conftest as conf + old = conf.option.forcegen + try: + conf.option.forcegen = 1 + col = py.test2.collect.Directory(rootdir) + x = list(col._tryiter(yieldtype=py.test2.collect.Function)) + finally: + conf.option.forcegen = old + +def test_check_random_inequality(): + path = getexamplefile("funcexamples.py") + col = py.test2.collect.Module(path) + fn = col.join("funcpass") + assert fn != 3 + assert fn != col + assert fn != [1,2,3] + assert [1,2,3] != fn + assert col != fn + +class Testgenitems: def setup_class(cls): - tmp = py.test2.ensuretemp('itemgentest') - tmp.ensure("__init__.py") - tmp.ensure("test_one.py").write(py.code.Source(""" - def test_one(): - pass + cls.classtemp = py.test2.ensuretemp(cls.__name__) + + def setup_method(self, method): + self.tmp = self.classtemp.mkdir(method.func_name) - class TestX: - def test_method_one(self): + def _genitems(self, tmp=None): + if tmp is None: + tmp = self.tmp + print "using tempdir", tmp + config = py.test2.config._reparse([tmp]) + l = eventappender(config) + items = list(genitems(config, config.getcolitems())) + return items, l + + def test_check_collect_hashes(self): + one = self.tmp.ensure("test_one.py") + one.write(py.code.Source(""" + def test_1(): pass - class TestY(TestX): - pass + def test_2(): + pass """)) - tmp.ensure("test_two.py").write(py.code.Source(""" - import py - py.test.skip('xxx') + one.copy(self.tmp.join("test_two.py")) + items, events = self._genitems() + assert len(items) == 4 + for numi, i in enumerate(items): + for numj, j in enumerate(items): + if numj != numi: + assert hash(i) != hash(j) + assert i != j + + def test_skip_by_conftest_directory(self): + from py.__.test2 import outcome + self.tmp.ensure("subdir", "conftest.py").write(py.code.Source(""" + import py + class Directory(py.test2.collect.Directory): + def run(self): + py.test2.skip("intentional") + """)) + items, events = self._genitems() + assert len(items) == 0 + skips = [x for x in events + if isinstance(x, repevent.CollectionFinish) + and x.collector.name == 'subdir'] + assert len(skips) == 1 + assert skips[0].excinfo.errisinstance(outcome.Skipped) + + def test_root_conftest_syntax_error(self): + # do we want to unify behaviour with + # test_subdir_conftest_error? + self.tmp.ensure("conftest.py").write("raise SyntaxError\n") + py.test2.raises(SyntaxError, self._genitems) + + def test_subdir_conftest_error(self): + self.tmp.ensure("sub", "conftest.py").write("raise SyntaxError\n") + items, events = self._genitems() + failures = [x for x in events + if isinstance(x, repevent.CollectionFinish) + and x.excinfo] + assert len(failures) == 1 + ev = failures[0] + assert ev.excinfo.errisinstance(SyntaxError) + + def XXXtest_keyboardinterrupt(self): + self.tmp.ensure("sub", "conftest.py").write("raise KeyboardInterrupt\n") + items, events = self._genitems() + assert 0 + + def test_skip_at_module_level(self): + self.tmp.ensure("test_module.py").write(py.code.Source(""" + import py + py.test2.skip('xxx') """)) - tmp.ensure("test_three.py").write("xxxdsadsadsadsa") - cls.tmp = tmp + items, events = self._genitems() + funcs = [x for x in items if isinstance(x, repevent.ItemStart)] + assert not funcs + assert not items + l = [x for x in events + if isinstance(x, repevent.CollectionFinish) + and x.collector.name == 'test_module.py'] + assert len(l) == 1 + ev = l[0] + assert ev.excinfo.errisinstance(outcome.Skipped) + + def test_example_items1(self): + self.tmp.ensure("test_example.py").write(py.code.Source(''' + def test_one(): + pass + + class TestX: + def test_method_one(self): + pass - def test_collectonly(self): - config = py.test2.config._reparse([self.tmp, '--collectonly']) - session = config.initsession() - # test it all in once - allevents = getevents_runmain(session) - started = finished = 0 - for event in allevents: - assert not isinstance(event, repevent.ItemFinish) - if isinstance(event, repevent.CollectionStart): - started += 1 - elif isinstance(event, repevent.CollectionFinish): - finished += 1 + class TestY(TestX): + pass + ''')) + items, events = self._genitems() + assert len(items) == 3 + assert items[0].name == 'test_one' + assert items[1].name == 'test_method_one' + assert items[2].name == 'test_method_one' - print started - assert started == finished + def test_custom_python_collection_from_conftest(self): + checkfile = setup_customconfigtest(self.tmp) + for x in (self.tmp, checkfile, checkfile.dirpath()): + items, events = self._genitems(x) + assert len(items) == 2 + #assert items[1].__class__.__name__ == 'MyFunction' + + return None # XXX shift below to session test? + # test that running a session works from the directories + old = o.chdir() + try: + config = py.test2.config._reparse([]) + session = config._getsessionclass()(config) + l = getpassed(session) + assert len(l) == 2 + finally: + old.chdir() + + # test that running the file directly works + config = py.test2.config._reparse([str(checkfile)]) + session = config._getsessionclass()(config) + l = getpassed(session) + assert len(l) == 2 + + + def test_custom_NONpython_collection_from_conftest(self): + checkfile = setup_non_python_dir(self.tmp) + + for x in (self.tmp, checkfile, checkfile.dirpath()): + print "checking that %s returns custom items" % (x,) + items, events = self._genitems(x) + assert len(items) == 1 + assert items[0].__class__.__name__ == 'CustomItem' + + return None # XXX shift below to session tests? + + # test that running a session works from the directories + old = self.tmp.chdir() + try: + l = getpassed(config.initsession()) + assert len(l) == 1 + finally: + old.chdir() + + # test that running the file directly works + config = py.test2.config._reparse([str(checkfile)]) + session = config._getsessionclass()(config) + l = getpassed(session) + assert len(l) == 1 + + def test_collect_doctest_files_with_test_prefix(self): + self.tmp.ensure("whatever.txt") + checkfile = self.tmp.ensure("test_something.txt") + checkfile.write(py.code.Source(""" + alskdjalsdk + >>> i = 5 + >>> i-1 + 4 + """)) + for x in (self.tmp, checkfile): + #print "checking that %s returns custom items" % (x,) + items, events = self._genitems(x) + assert len(items) == 1 + assert isinstance(items[0], DoctestText) + Modified: py/branch/event/py/test2/testing/test_doctest.py ============================================================================== --- py/branch/event/py/test2/testing/test_doctest.py (original) +++ py/branch/event/py/test2/testing/test_doctest.py Tue Feb 12 18:06:06 2008 @@ -22,23 +22,3 @@ """) py.test2.raises(Failed, "testitem.run()") - -def test_collect_doctest_files_with_test_prefix(): - o = py.test2.ensuretemp("testdoctest") - checkfile = o.ensure("test_something.txt") - o.ensure("whatever.txt") - checkfile.write(py.code.Source(""" - alskdjalsdk - >>> i = 5 - >>> i-1 - 4 - """)) - for x in (o, checkfile): - #print "checking that %s returns custom items" % (x,) - config = py.test2.config._reparse([x]) - col = config._getcollector(x) - items = list(col._tryiter(py.test2.collect.Item)) - assert len(items) == 1 - assert isinstance(items[0], DoctestText) - - Modified: py/branch/event/py/test2/testing/test_executor.py ============================================================================== --- py/branch/event/py/test2/testing/test_executor.py (original) +++ py/branch/event/py/test2/testing/test_executor.py Tue Feb 12 18:06:06 2008 @@ -80,7 +80,7 @@ assert not outcome.excinfo def test_box_executor_stdout(self): - item = self.getexample("print") + item = self.getfunc("print") ex = BoxExecutor(item, config=self.config) outcome_repr = ex.execute() outcome = ReprOutcome(outcome_repr) @@ -88,7 +88,7 @@ assert outcome.stdout.find("samfing") != -1 def test_box_executor_stdout_error(self): - item = self.getexample("printfail") + item = self.getfunc("printfail") ex = BoxExecutor(item, config=self.config) outcome_repr = ex.execute() outcome = ReprOutcome(outcome_repr) @@ -96,7 +96,7 @@ assert outcome.stdout.find("samfing elz") != -1 def test_cont_executor(self): - item = self.getexample("printfail") + item = self.getfunc("printfail") ex = AsyncExecutor(item, config=self.config) cont, pid = ex.execute() assert pid Modified: py/branch/event/py/test2/testing/test_remote.py ============================================================================== --- py/branch/event/py/test2/testing/test_remote.py (original) +++ py/branch/event/py/test2/testing/test_remote.py Tue Feb 12 18:06:06 2008 @@ -1,7 +1,9 @@ import py -from py.__.test2.testing.setupdata import setup_module from test_session import getevents_runmain +def setup_module(mod): + mod.tmpdir = py.test.ensuretemp(mod.__name__) + class TestRemote: def test_exec(self): o = tmpdir.ensure('remote', dir=1) Modified: py/branch/event/py/test2/testing/test_session.py ============================================================================== --- py/branch/event/py/test2/testing/test_session.py (original) +++ py/branch/event/py/test2/testing/test_session.py Tue Feb 12 18:06:06 2008 @@ -1,11 +1,14 @@ import py -from setupdata import setup_module # sets up global 'tmpdir' +from setupdata import getexamplefile from py.__.test2.outcome import Skipped, Failed, Passed, Outcome from py.__.test2.terminal.out import getout from py.__.test2 import repevent from test_session2 import getevents_runmain +def setup_module(mod): + mod.tmpdir = py.test.ensuretemp(mod.__name__) + implied_options = { '-v': 'verbose', '-l': 'showlocals', @@ -29,8 +32,10 @@ [i for i in all if isinstance(i, repevent.DeselectedTest)] def getfailed(all): - return [i for i in getoutcomes(all) if i.failed] + \ - [i for i in all + return [i for i in getoutcomes(all) if i.failed] + +def getfailedcollections(all): + return [i for i in all if isinstance(i, repevent.CollectionFinish) and i.excinfo] @@ -41,7 +46,8 @@ def check_conflict_option(opts): print "testing if options conflict:", " ".join(opts) - config = py.test2.config._reparse(opts + [datadir/'filetest.py']) + path = getexamplefile("filetest.py") + config = py.test2.config._reparse(opts + [path]) py.test2.raises((ValueError, SystemExit), """ config.initsession() """) @@ -51,32 +57,35 @@ yield check_implied_option, [key], expr def check_implied_option(opts, expr): - config = py.test2.config._reparse(opts + [datadir/'filetest.py']) + path = getexamplefile("filetest.py") + config = py.test2.config._reparse(opts + [path]) session = config.initsession() assert eval(expr, session.config.option.__dict__) def test_default_session_options(): + path = getexamplefile("filetest.py") for opts in ([], ['-l'], ['-s'], ['--tb=no'], ['--tb=short'], ['--tb=long'], ['--fulltrace'], ['--nomagic'], ['--traceconfig'], ['-v'], ['-v', '-v']): - yield runfiletest, opts + yield runfiletest, opts + [path] def runfiletest(opts): - config = py.test2.config._reparse(opts + [datadir/'filetest.py']) + config = py.test2.config._reparse(opts) session = config.initsession() all = getevents_runmain(session) assert len(getfailed(all)) == 2 assert not getskipped(all) def test_is_not_boxed_by_default(): - config = py.test2.config._reparse([datadir]) + path = getexamplefile("filetest.py") + config = py.test2.config._reparse([path]) assert not config.option.boxed class TestKeywordSelection: def test_select_simple(self): def check(keyword, name): - config = py.test2.config._reparse([datadir/'filetest.py', - '-s', '-k', keyword]) + p = getexamplefile("filetest.py") + config = py.test2.config._reparse([p, '-s', '-k', keyword]) session = config._getsessionclass()(config) all = getevents_runmain(session) outcomes = [i for i in all if isinstance(i, repevent.ItemFinish)] @@ -90,7 +99,7 @@ check('TestClass.test', 'test_method_one') def test_select_extra_keywords(self): - o = tmpdir.ensure('selecttest', dir=1) + o = tmpdir.ensure('test_select_extra_keywords', dir=1) tfile = o.join('test_select.py').write(py.code.Source(""" def test_1(): pass @@ -118,8 +127,8 @@ assert l[0].item.name == 'test_1' def test_select_starton(self): - config = py.test2.config._reparse([datadir/'testmore.py', - '-j', '-k', "test_two"]) + p = getexamplefile("testmore.py") + config = py.test2.config._reparse([p, '-j', '-k', "test_two"]) session = config._getsessionclass()(config) all = getevents_runmain(session) assert len(getpassed(all)) == 2 @@ -136,21 +145,23 @@ return session, all def test_terminal(self): - session, all = self.mainsession(datadir / 'filetest.py') + p = getexamplefile("filetest.py") + session, all = self.mainsession(p) outcomes = getoutcomes(all) assert len(getfailed(all)) == 2 def test_syntax_error_module(self): - session, all = self.mainsession(datadir / 'syntax_error.py') - l = getfailed(all) + p = getexamplefile("syntax_error.py") + session, all = self.mainsession(p) + l = getfailedcollections(all) assert len(l) == 1 out = l[0].excinfo.exconly() assert out.find(str('syntax_error.py')) != -1 assert out.find(str('not python')) != -1 def test_exit_first_problem(self): - session, all = self.mainsession("--exitfirst", - datadir / 'filetest.py') + p = getexamplefile("filetest.py") + session, all = self.mainsession("--exitfirst", p) assert session.config.option.exitfirst assert len(getfailed(all)) == 1 assert not getpassed(all) @@ -164,7 +175,7 @@ """)) session, all = self.mainsession(o) #print out - failures = getfailed(all) + failures = getfailedcollections(all) out = failures[0].excinfo.exconly() i = out.find('TypeError') assert i != -1 @@ -258,16 +269,14 @@ a = 1 """)) session, all = self.mainsession(o) - l = getfailed(all) + l = getfailedcollections(all) assert len(l) == 1 out = l[0].excinfo.exconly() assert out.find('does_not_work') != -1 def test_safe_repr(self): - session, all = self.mainsession(datadir/'brokenrepr.py') - #print 'Output of simulated "py.test2 brokenrepr.py":' - #print all - + p = getexamplefile("brokenrepr.py") + session, all = self.mainsession(p) l = getfailed(all) assert len(l) == 2 out = l[0].excinfo.exconly() @@ -275,3 +284,41 @@ out = l[1].excinfo.exconly() assert out.find("[unknown exception raised in repr()]") != -1 +class TestCollectonly: + def setup_class(cls): + tmp = py.test2.ensuretemp('itemgentest') + tmp.ensure("__init__.py") + tmp.ensure("test_one.py").write(py.code.Source(""" + def test_one(): + pass + + class TestX: + def test_method_one(self): + pass + + class TestY(TestX): + pass + """)) + tmp.ensure("test_two.py").write(py.code.Source(""" + import py + py.test.skip('xxx') + """)) + tmp.ensure("test_three.py").write("xxxdsadsadsadsa") + cls.tmp = tmp + + def test_collectonly(self): + config = py.test2.config._reparse([self.tmp, '--collectonly']) + session = config.initsession() + # test it all in once + allevents = getevents_runmain(session) + started = finished = 0 + for event in allevents: + assert not isinstance(event, repevent.ItemFinish) + if isinstance(event, repevent.CollectionStart): + started += 1 + elif isinstance(event, repevent.CollectionFinish): + finished += 1 + + print started + assert started == finished + From guido at codespeak.net Tue Feb 12 21:41:48 2008 From: guido at codespeak.net (guido at codespeak.net) Date: Tue, 12 Feb 2008 21:41:48 +0100 (CET) Subject: [py-svn] r51424 - in py/branch/guido-svn-auth/py: . path/svn path/svn/testing Message-ID: <20080212204148.A35801683F6@codespeak.net> Author: guido Date: Tue Feb 12 21:41:45 2008 New Revision: 51424 Added: py/branch/guido-svn-auth/py/path/svn/auth.py py/branch/guido-svn-auth/py/path/svn/testing/test_auth.py Modified: py/branch/guido-svn-auth/py/__init__.py py/branch/guido-svn-auth/py/path/svn/wccommand.py Log: First bits of svn auth support - added a class called SvnAuth to hold credentials and some auth-related information, and made that svnwc's constructor and its commit and checkout methods accept the class as argument. Modified: py/branch/guido-svn-auth/py/__init__.py ============================================================================== --- py/branch/guido-svn-auth/py/__init__.py (original) +++ py/branch/guido-svn-auth/py/__init__.py Tue Feb 12 21:41:45 2008 @@ -67,6 +67,7 @@ 'path.svnwc' : ('./path/svn/wccommand.py', 'SvnWCCommandPath'), 'path.svnurl' : ('./path/svn/urlcommand.py', 'SvnCommandPath'), 'path.local' : ('./path/local/local.py', 'LocalPath'), + 'path.SvnAuth' : ('./path/svn/auth.py', 'SvnAuth'), # some nice slightly magic APIs 'magic.__doc__' : ('./magic/__init__.py', '__doc__'), Added: py/branch/guido-svn-auth/py/path/svn/auth.py ============================================================================== --- (empty file) +++ py/branch/guido-svn-auth/py/path/svn/auth.py Tue Feb 12 21:41:45 2008 @@ -0,0 +1,14 @@ +class SvnAuth(object): + """ container for auth information for Subversion """ + def __init__(self, username, password, auth_cache=True): + self.username = username + self.password = password + self.auth_cache = auth_cache + + def __str__(self): + uname = self.username.replace('"', '\\"') + passwd = self.password.replace('"', '\\"') + ret = '--username="%s" --password="%s"' % (uname, passwd) + if not self.auth_cache: + ret += ' --no-auth-cache' + return ret Added: py/branch/guido-svn-auth/py/path/svn/testing/test_auth.py ============================================================================== --- (empty file) +++ py/branch/guido-svn-auth/py/path/svn/testing/test_auth.py Tue Feb 12 21:41:45 2008 @@ -0,0 +1,58 @@ +import py +from py.path import SvnAuth + +class TestSvnAuth(object): + def test_uname_pw(self): + auth = py.path.SvnAuth('foo', 'bar') + assert auth.username == 'foo' + assert auth.password == 'bar' + + def test_uname_pw_str(self): + auth = py.path.SvnAuth('foo', 'bar') + assert str(auth) == '--username="foo" --password="bar"' + + def test_quote_escape(self): + auth = py.path.SvnAuth('fo"o', '"ba\'r"') + assert str(auth) == '--username="fo\\"o" --password="\\"ba\'r\\""' + + def test_no_auth_cache(self): + auth = py.path.SvnAuth('foo', 'bar', auth_cache=False) + assert str(auth) == '--username="foo" --password="bar" --no-auth-cache' + +class svnwc_no_svn(py.path.svnwc): + def __init__(self, *args, **kwargs): + self.commands = [] + super(svnwc_no_svn, self).__init__(*args, **kwargs) + + def _svn(self, *args): + self.commands.append(args) + +class TestSvnWCAuth(object): + def test_checkout(self): + wc = svnwc_no_svn('foo') + auth = SvnAuth('user', 'pass') + wc.checkout('url', auth=auth) + assert wc.commands == [('co', 'url', + '--username="user" --password="pass"')] + + def test_commit(self): + wc = svnwc_no_svn('foo') + auth = SvnAuth('user', 'pass') + wc.commit('msg', auth=auth) + assert wc.commands == [('commit -m "msg" --force-log', + '--username="user" --password="pass"')] + + def test_checkout_no_cache_auth(self): + wc = svnwc_no_svn('foo') + auth = SvnAuth('user', 'pass', auth_cache=False) + wc.checkout('url', auth=auth) + assert wc.commands == [('co', 'url', + ('--username="user" --password="pass" ' + '--no-auth-cache'))] + + def test_checkout_auth_from_constructor(self): + auth = SvnAuth('user', 'pass') + wc = svnwc_no_svn('foo', auth=auth) + wc.checkout('url') + assert wc.commands == [('co', 'url', + '--username="user" --password="pass"')] Modified: py/branch/guido-svn-auth/py/path/svn/wccommand.py ============================================================================== --- py/branch/guido-svn-auth/py/path/svn/wccommand.py (original) +++ py/branch/guido-svn-auth/py/path/svn/wccommand.py Tue Feb 12 21:41:45 2008 @@ -25,7 +25,7 @@ """ sep = os.sep - def __new__(cls, wcpath=None): + def __new__(cls, wcpath=None, auth=None): self = object.__new__(cls) if isinstance(wcpath, cls): if wcpath.__class__ == cls: @@ -35,6 +35,7 @@ svncommon.ALLOWED_CHARS): raise ValueError("bad char in wcpath %s" % (wcpath, )) self.localpath = py.path.local(wcpath) + self._auth = auth return self strpath = property(lambda x: str(x.localpath), None, None, "string path") @@ -105,7 +106,7 @@ """ switch to given URL. """ self._svn('switch', url) - def checkout(self, url=None, rev=None): + def checkout(self, url=None, rev=None, auth=None): """ checkout from url to local wcpath. """ args = [] if url is None: @@ -119,6 +120,10 @@ url += "@%d" % rev else: args.append('-r' + str(rev)) + if auth is not None: + args.append(str(auth)) + elif self._auth is not None: + args.append(str(self._auth)) self._svn('co', url, *args) def update(self, rev = 'HEAD'): @@ -358,14 +363,19 @@ return result _rex_commit = re.compile(r'.*Committed revision (\d+)\.$', re.DOTALL) - def commit(self, msg='', rec=1): + def commit(self, msg='', rec=1, auth=None): """ 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) + args = [] + if auth is not None: + args.append(str(auth)) + elif self._auth is not None: + args.append(str(self._auth)) + out = self._svn(cmd, *args) try: del cache.info[self] except KeyError: From hpk at codespeak.net Wed Feb 13 15:40:21 2008 From: hpk at codespeak.net (hpk at codespeak.net) Date: Wed, 13 Feb 2008 15:40:21 +0100 (CET) Subject: [py-svn] r51438 - in py/branch/event/py/test2: rsession rsession/testing terminal testing Message-ID: <20080213144021.632831683DC@codespeak.net> Author: hpk Date: Wed Feb 13 15:40:19 2008 New Revision: 51438 Added: py/branch/event/py/test2/testing/suptest.py py/branch/event/py/test2/testing/test_session_xxx.py - copied, changed from r51396, py/branch/event/py/test2/testing/test_session2.py Removed: py/branch/event/py/test2/testing/test_session2.py Modified: py/branch/event/py/test2/rsession/hostmanage.py py/branch/event/py/test2/rsession/slave.py py/branch/event/py/test2/rsession/testing/test_rsession.py py/branch/event/py/test2/terminal/remote.py py/branch/event/py/test2/testing/setupdata.py py/branch/event/py/test2/testing/test_collect.py py/branch/event/py/test2/testing/test_config.py py/branch/event/py/test2/testing/test_remote.py py/branch/event/py/test2/testing/test_session.py Log: * separated out event/test support code into suptest.py * refactoring and streamlining many tests all around * re-enabling and fixing some tests that didn't actually run session and its tests start to look more uniform still this is all intermediate Modified: py/branch/event/py/test2/rsession/hostmanage.py ============================================================================== --- py/branch/event/py/test2/rsession/hostmanage.py (original) +++ py/branch/event/py/test2/rsession/hostmanage.py Wed Feb 13 15:40:19 2008 @@ -181,7 +181,7 @@ def trysendtest(self, item): for host in self.hosts: node = getattr(host, 'node', None) - if node and len(node.pending) < 15: # XXX + if node and len(node.pending) < 15: # XXX use config node.send(item) return True Modified: py/branch/event/py/test2/rsession/slave.py ============================================================================== --- py/branch/event/py/test2/rsession/slave.py (original) +++ py/branch/event/py/test2/rsession/slave.py Wed Feb 13 15:40:19 2008 @@ -50,17 +50,12 @@ node = getnode(nextitem) res = node.run(nextitem) except Skipped, s: - send(SerializableOutcome(skipped=str(s)).make_repr()) - except: + res = SerializableOutcome(skipped=str(s)).make_repr() + except: # XXX consider bare except here excinfo = py.code.ExceptionInfo() - send(SerializableOutcome(excinfo=excinfo, is_critical=True).make_repr()) - else: - send(res) - if not res[0] and not res[3] and config.option.exitfirst: - break - # we're finished, but we should eat what we can - while nextitem is not None: - nextitem = receive() + res = SerializableOutcome(excinfo=excinfo, is_critical=True).make_repr() + send(res) + def setup(): # our current dir is the topdir @@ -79,7 +74,16 @@ if not config.option.nomagic: py.magic.invoke(assertion=1) from py.__.test2.rsession.slave import slave_main - slave_main(channel.receive, channel.send, basedir, config) + + #debug = open("/tmp/debug-slave.log", 'wa') + def send(msg): + #print >>debug, "sending", msg + channel.send(msg) + def receive(): + msg = channel.receive() + #print >>debug, "reveived", msg + return msg + slave_main(receive, send, basedir, config) if not config.option.nomagic: py.magic.revoke(assertion=1) channel.close() Modified: py/branch/event/py/test2/rsession/testing/test_rsession.py ============================================================================== --- py/branch/event/py/test2/rsession/testing/test_rsession.py (original) +++ py/branch/event/py/test2/rsession/testing/test_rsession.py Wed Feb 13 15:40:19 2008 @@ -9,10 +9,9 @@ from py.__.test2.rsession.testing.basetest import BasicRsessionTest from py.__.test2.rsession.testing.test_hostmanage import DirSetup -from py.__.test2.testing.test_session import getevents_runmain +from py.__.test2.testing import suptest def setup_module(mod): - mod.pkgdir = py.path.local(py.__file__).dirpath() if py.std.sys.platform == "win32": py.test.skip("rsession tests disabled for win32") @@ -31,16 +30,27 @@ def test_2(): assert 0 def test_3(): - raise ValueError(23) - def test_4(someargs): - pass + import time + time.sleep(0.5) + def test_4(): + assert 0 """)) - config = py.test2.config._reparse([self.source.join("sub"), '-x']) + config = py.test2.config._reparse([self.source.join("sub"), '-x', '--dist']) + #config = py.test2.config._reparse([self.source.join("sub"), '--dist']) rsession = RSession(config) - allevents = getevents_runmain(rsession) - testevents = [x for x in allevents - if isinstance(x, repevent.ItemTestReport)] - assert len(testevents) == 3 + sorter = suptest.events_from_session(rsession) + testevents = sorter.get(repevent.ItemTestReport) + + py.test.skip("XXX need for different way to test -x --dist") + assert len([x for x in testevents if x.passed]) == 2 + assert len([x for x in testevents if x.failed]) == 1 + assert len([x for x in testevents if x.skipped]) == 1 + + #passed, skipped, failed = sorter.listoutcomes() + #assert len(passed) == 1 + #assert len(skipped) == 1 + #assert len(failed) == 1 + #assert failed[0].item.name == "test_2" def test_distribution_rsync_roots_example(self): destdir = py.test2.ensuretemp("example_dist_destdir") @@ -71,17 +81,11 @@ assert config.topdir == tmpdir assert not tmpdir.join("__init__.py").check() rsession = RSession(config) - allevents = getevents_runmain(rsession) - testevents = [x for x in allevents - if isinstance(x, repevent.ItemTestReport)] - assert len(testevents) - print testevents - passevents = [i for i in testevents if i.passed] - failevents = [i for i in testevents if i.failed] - skippedevents = [i for i in testevents if i.skipped] - assert len(testevents) == 5 - assert len(passevents) == 2 - assert len(failevents) == 3 + sorter = suptest.events_from_session(rsession) + testevents = sorter.get(repevent.ItemTestReport) + assert len([x for x in testevents if x.passed]) == 2 + assert len([x for x in testevents if x.failed]) == 3 + assert len([x for x in testevents if x.skipped]) == 0 def test_setup_teardown_run_ssh(self): hosts = [HostInfo('localhost:%s' % self.dest)] @@ -135,9 +139,8 @@ config = py.test2.config._reparse([tmpdir]) rsession = RSession(config) - allevents = getevents_runmain(rsession) - testevents = [x for x in allevents - if isinstance(x, repevent.ItemTestReport)] + sorter = suptest.events_from_session(rsession) + testevents = sorter.get(repevent.ItemTestReport) passevents = [x for x in testevents if x.passed] assert len(passevents) == 1 Modified: py/branch/event/py/test2/terminal/remote.py ============================================================================== --- py/branch/event/py/test2/terminal/remote.py (original) +++ py/branch/event/py/test2/terminal/remote.py Wed Feb 13 15:40:19 2008 @@ -136,5 +136,5 @@ session.shouldclose = channel.isclosed print "SLAVE: starting session.main()" failures = session.main() - failures = [config.get_collector_trail(item) for item,_ in failures] + failures = [config.get_collector_trail(ev.item) for ev in failures] channel.send(failures) Modified: py/branch/event/py/test2/testing/setupdata.py ============================================================================== --- py/branch/event/py/test2/testing/setupdata.py (original) +++ py/branch/event/py/test2/testing/setupdata.py Wed Feb 13 15:40:19 2008 @@ -11,10 +11,11 @@ # return datadir def getexamplefile(basename): - datadir = py.test2.ensuretemp("datadir") + datadir = py.test2.ensuretemp("example") path = datadir.join(basename) if not path.check(): path.write(namecontent[basename]) + print "creating testfile", path return path namecontent = { @@ -86,7 +87,7 @@ '''), - 'testmore.py': py.code.Source(''' + 'test_threepass.py': py.code.Source(''' def test_one(): assert 1 @@ -159,3 +160,56 @@ """), } + +def setup_customconfigtest(tmpdir): + o = tmpdir.ensure('customconfigtest', dir=1) + o.ensure('conftest.py').write("""if 1: + import py + class MyFunction(py.test2.collect.Function): + pass + class Directory(py.test2.collect.Directory): + def filefilter(self, fspath): + return fspath.check(basestarts='check_', ext='.py') + class myfuncmixin: + Function = MyFunction + def funcnamefilter(self, name): + return name.startswith('check_') + + class Module(myfuncmixin, py.test2.collect.Module): + def classnamefilter(self, name): + return name.startswith('CustomTestClass') + class Instance(myfuncmixin, py.test2.collect.Instance): + pass + """) + checkfile = o.ensure('somedir', 'check_something.py') + checkfile.write("""if 1: + def check_func(): + assert 42 == 42 + class CustomTestClass: + def check_method(self): + assert 23 == 23 + """) + return checkfile + +def setup_non_python_dir(tmpdir): + o = tmpdir.ensure('customconfigtest_nonpython', dir=1) + o.ensure('conftest.py').write("""if 1: + import py + class CustomItem(py.test2.collect.Item): + def run(self): + pass + + class Directory(py.test2.collect.Directory): + def filefilter(self, fspath): + return fspath.check(basestarts='check_', ext='.txt') + def join(self, name): + if not name.endswith('.txt'): + return super(Directory, self).join(name) + p = self.fspath.join(name) + if p.check(file=1): + return CustomItem(p, parent=self) + """) + checkfile = o.ensure('somedir', 'moredir', 'check_something.txt') + return checkfile + + Added: py/branch/event/py/test2/testing/suptest.py ============================================================================== --- (empty file) +++ py/branch/event/py/test2/testing/suptest.py Wed Feb 13 15:40:19 2008 @@ -0,0 +1,83 @@ + +import py +from py.__.test2 import repevent + +def eventappender(config): + l = [] + def app(ev): + print ev + l.append(ev) + config.hub.append(app) + return l + +def initsorter_from_cmdline(args=None): + if args is None: + args = [] + config = py.test2.config._reparse(args) + session = config.initsession() + sorter = EventSorter(config, session) + return sorter + +def events_from_cmdline(args=None): + sorter = initsorter_from_cmdline(args) + sorter.session.main() + return sorter + +def events_from_session(session): + sorter = EventSorter(session.config, session) + session.main() + return sorter + +def events_run_example(examplename, *args): + from setupdata import getexamplefile + p = getexamplefile(examplename) + return events_from_cmdline([p] + list(args)) + +class EventSorter(object): + def __init__(self, config, session=None): + self.session = session + self.cls2events = d = {} + def app(event): + print "[event]", event + for cls in py.std.inspect.getmro(event.__class__): + if cls is not object: + d.setdefault(cls, []).append(event) + config.hub.append(app) + + def get(self, cls): + return self.cls2events.get(cls, []) + + def listoutcomes(self): + passed = [] + skipped = [] + failed = [] + for ev in self.get(repevent.ItemFinish): + if ev.passed: + passed.append(ev) + elif ev.skipped: + skipped.append(ev) + else: + failed.append(ev) + return passed, skipped, failed + + def countoutcomes(self): + return map(len, self.listoutcomes()) + + def getfailedcollections(self): + l = [] + for ev in self.get(repevent.CollectionFinish): + if ev.excinfo: + l.append(ev) + return l + + +counter = py.std.itertools.count().next +def makeuniquepyfile(source): + dirname = "test_%d" %(counter(),) + tmpdir = py.test.ensuretemp(dirname) + p = tmpdir.join(dirname + ".py") + assert not p.check() + p.write(py.code.Source(source)) + print "created test file", p + p.dirpath("__init__.py").ensure() + return p Modified: py/branch/event/py/test2/testing/test_collect.py ============================================================================== --- py/branch/event/py/test2/testing/test_collect.py (original) +++ py/branch/event/py/test2/testing/test_collect.py Wed Feb 13 15:40:19 2008 @@ -1,43 +1,21 @@ from __future__ import generators import py -from py.__.test2 import outcome -from test_session import getevents_runmain -from py.__.test2 import repevent +from py.__.test2 import repevent, outcome from py.__.test2.genitem import genitems from py.__.test2.doctest import DoctestText -from setupdata import getexamplefile - -def getpassed(session): - hub = session.config.hub - all = [] - hub.append(all.append) - try: - session.main() - print all - passed = [i.passed for i in all if isinstance(i, repevent.ItemFinish)] - return passed - finally: - hub.pop() - -def eventappender(config): - l = [] - def app(ev): - print ev - l.append(ev) - config.hub.append(app) - return l +import setupdata, suptest def setup_module(mod): mod.tmpdir = py.test2.ensuretemp(mod.__name__) def test_failing_import_execfile(): - dest = getexamplefile('failingimport.py') + dest = setupdata.getexamplefile('failingimport.py') col = py.test2.collect.Module(dest) py.test2.raises(ImportError, col.run) py.test2.raises(ImportError, col.run) def test_collect_listnames_and_back(): - path = getexamplefile("filetest.py") + path = setupdata.getexamplefile("filetest.py") col1 = py.test2.collect.Directory(path.dirpath().dirpath()) col2 = col1.join(path.dirpath().basename) col3 = col2.join(path.basename) @@ -51,7 +29,7 @@ assert len(l2) == 3 def test_finds_tests(): - fn = getexamplefile('filetest.py') + fn = setupdata.getexamplefile('filetest.py') col = py.test2.collect.Module(fn) l = col.run() assert len(l) == 2 @@ -89,7 +67,7 @@ class MyDirectory(py.test2.collect.Directory): def filefilter(self, p): return p.check(fnmatch='testspecial*.py') - filetest = getexamplefile("testspecial_importerror.py") + filetest = setupdata.getexamplefile("testspecial_importerror.py") mydir = MyDirectory(filetest.dirpath()) l = mydir.run() assert len(l) == 1 @@ -103,12 +81,12 @@ py.test2.raises(py.error.ENOENT, col.run) def test_syntax_error_in_module(): - modpath = getexamplefile("syntax_error.py") + modpath = setupdata.getexamplefile("syntax_error.py") col = py.test2.collect.Module(modpath) py.test2.raises(SyntaxError, col.run) def test_disabled_class(): - col = py.test2.collect.Module(getexamplefile('disabled.py')) + col = py.test2.collect.Module(setupdata.getexamplefile('disabled.py')) l = col.run() assert len(l) == 1 colitem = col.join(l[0]) @@ -116,13 +94,13 @@ assert not colitem.run() def test_disabled_module(): - p = getexamplefile("disabled_module.py") + p = setupdata.getexamplefile("disabled_module.py") col = py.test2.collect.Module(p) l = col.run() assert len(l) == 0 def test_generative_simple(): - tfile = getexamplefile('test_generative.py') + tfile = setupdata.getexamplefile('test_generative.py') col = py.test2.collect.Module(tfile) l = col.run() assert len(l) == 2 @@ -155,112 +133,60 @@ assert l2[1].name == '[1]' -def setup_customconfigtest(tmpdir): - o = tmpdir.ensure('customconfigtest', dir=1) - o.ensure('conftest.py').write("""if 1: - import py - class MyFunction(py.test2.collect.Function): - pass - class Directory(py.test2.collect.Directory): - def filefilter(self, fspath): - return fspath.check(basestarts='check_', ext='.py') - class myfuncmixin: - Function = MyFunction - def funcnamefilter(self, name): - return name.startswith('check_') - - class Module(myfuncmixin, py.test2.collect.Module): - def classnamefilter(self, name): - return name.startswith('CustomTestClass') - class Instance(myfuncmixin, py.test2.collect.Instance): - pass - """) - checkfile = o.ensure('somedir', 'check_something.py') - checkfile.write("""if 1: - def check_func(): - assert 42 == 42 - class CustomTestClass: - def check_method(self): - assert 23 == 23 - """) - return checkfile - -def setup_non_python_dir(tmpdir): - o = tmpdir.ensure('customconfigtest_nonpython', dir=1) - o.ensure('conftest.py').write("""if 1: - import py - class CustomItem(py.test2.collect.Item): - def run(self): - pass - - class Directory(py.test2.collect.Directory): - def filefilter(self, fspath): - return fspath.check(basestarts='check_', ext='.txt') - def join(self, name): - if not name.endswith('.txt'): - return super(Directory, self).join(name) - p = self.fspath.join(name) - if p.check(file=1): - return CustomItem(p, parent=self) - """) - checkfile = o.ensure('somedir', 'moredir', 'check_something.txt') - return checkfile - - def test_order_of_execution_generator_same_codeline(): o = tmpdir.ensure('genorder1', dir=1) o.join("test_order1.py").write(py.code.Source(""" - def test_generative_order_of_execution(): - test_list = [] - expected_list = range(6) - - def list_append(item): - test_list.append(item) + def test_generative_order_of_execution(): + test_list = [] + expected_list = range(6) + + def list_append(item): + test_list.append(item) + + def assert_order_of_execution(): + print 'expected order', expected_list + print 'but got ', test_list + assert test_list == expected_list - def assert_order_of_execution(): - print 'expected order', expected_list - print 'but got ', test_list - assert test_list == expected_list - - for i in expected_list: - yield list_append, i - yield assert_order_of_execution + for i in expected_list: + yield list_append, i + yield assert_order_of_execution """)) - config = py.test2.config._reparse([o]) - session = config.initsession() - l = getpassed(session) - assert len(l) == 7 + sorter = suptest.events_from_cmdline([o]) + passed, skipped, failed = sorter.countoutcomes() + assert passed == 7 + assert not skipped and not failed def test_order_of_execution_generator_different_codeline(): o = tmpdir.ensure('genorder2', dir=2) o.join("test_genorder2.py").write(py.code.Source(""" - def test_generative_tests_different_codeline(): - test_list = [] - expected_list = range(3) - - def list_append_2(): - test_list.append(2) - - def list_append_1(): - test_list.append(1) - - def list_append_0(): - test_list.append(0) - - def assert_order_of_execution(): - print 'expected order', expected_list - print 'but got ', test_list - assert test_list == expected_list - - yield list_append_0 - yield list_append_1 - yield list_append_2 - yield assert_order_of_execution + def test_generative_tests_different_codeline(): + test_list = [] + expected_list = range(3) + + def list_append_2(): + test_list.append(2) + + def list_append_1(): + test_list.append(1) + + def list_append_0(): + test_list.append(0) + + def assert_order_of_execution(): + print 'expected order', expected_list + print 'but got ', test_list + assert test_list == expected_list + + yield list_append_0 + yield list_append_1 + yield list_append_2 + yield assert_order_of_execution """)) - config = py.test2.config._reparse([o]) - session = config.initsession() - l = getpassed(session) - assert len(l) == 4 + sorter = suptest.events_from_cmdline([o]) + passed, skipped, failed = sorter.countoutcomes() + assert passed == 4 + assert not skipped and not failed def test_check_generator_collect_problems(): tmp = py.test2.ensuretemp("gener_coll") @@ -327,7 +253,7 @@ conf.option.forcegen = old def test_check_random_inequality(): - path = getexamplefile("funcexamples.py") + path = setupdata.getexamplefile("funcexamples.py") col = py.test2.collect.Module(path) fn = col.join("funcpass") assert fn != 3 @@ -348,7 +274,7 @@ tmp = self.tmp print "using tempdir", tmp config = py.test2.config._reparse([tmp]) - l = eventappender(config) + l = suptest.eventappender(config) items = list(genitems(config, config.getcolitems())) return items, l @@ -442,7 +368,7 @@ assert items[2].name == 'test_method_one' def test_custom_python_collection_from_conftest(self): - checkfile = setup_customconfigtest(self.tmp) + checkfile = setupdata.setup_customconfigtest(self.tmp) for x in (self.tmp, checkfile, checkfile.dirpath()): items, events = self._genitems(x) assert len(items) == 2 @@ -452,22 +378,21 @@ # test that running a session works from the directories old = o.chdir() try: - config = py.test2.config._reparse([]) - session = config._getsessionclass()(config) - l = getpassed(session) - assert len(l) == 2 + sorter = suptest.events_from_cmdline([]) + passed, skipped, failed = sorter.countoutcomes() + assert passed == 2 + assert skipped == failed == 0 finally: old.chdir() # test that running the file directly works - config = py.test2.config._reparse([str(checkfile)]) - session = config._getsessionclass()(config) - l = getpassed(session) - assert len(l) == 2 - + sorter = suptest.events_from_cmdline([str(checkfile)]) + passed, skipped, failed = sorter.countoutcomes() + assert passed == 2 + assert skipped == failed == 0 def test_custom_NONpython_collection_from_conftest(self): - checkfile = setup_non_python_dir(self.tmp) + checkfile = setupdata.setup_non_python_dir(self.tmp) for x in (self.tmp, checkfile, checkfile.dirpath()): print "checking that %s returns custom items" % (x,) @@ -480,16 +405,18 @@ # test that running a session works from the directories old = self.tmp.chdir() try: - l = getpassed(config.initsession()) - assert len(l) == 1 + sorter = suptest.events_from_cmdline([]) + passed, skipped, failed = sorter.countoutcomes() + assert passed == 1 + assert skipped == failed == 0 finally: old.chdir() # test that running the file directly works - config = py.test2.config._reparse([str(checkfile)]) - session = config._getsessionclass()(config) - l = getpassed(session) - assert len(l) == 1 + sorter = suptest.events_from_cmdline([str(checkfile)]) + passed, skipped, failed = sorter.countoutcomes() + assert passed == 1 + assert skipped == failed == 0 def test_collect_doctest_files_with_test_prefix(self): self.tmp.ensure("whatever.txt") Modified: py/branch/event/py/test2/testing/test_config.py ============================================================================== --- py/branch/event/py/test2/testing/test_config.py (original) +++ py/branch/event/py/test2/testing/test_config.py Wed Feb 13 15:40:19 2008 @@ -2,6 +2,7 @@ import py from py.__.test2.config import gettopdir +import suptest, setupdata def test_tmpdir(): d1 = py.test2.ensuretemp('hello') @@ -316,6 +317,56 @@ config._finishcapture(dummy) assert dummy._captured_out.strip() == "42" + def test_conflict_options(self): + def check_conflict_option(opts): + print "testing if options conflict:", " ".join(opts) + path = setupdata.getexamplefile("filetest.py") + config = py.test2.config._reparse(opts + [path]) + py.test2.raises((ValueError, SystemExit), """ + config.initsession() + """) + conflict_options = ( + '--looponfailing --pdb', + '--dist --pdb', + '--exec=%s --pdb' % (py.std.sys.executable,), + ) + for spec in conflict_options: + opts = spec.split() + yield check_conflict_option, opts + + def test_implied_options(self): + def check_implied_option(opts, expr): + path = setupdata.getexamplefile("filetest.py") + config = py.test2.config._reparse(opts + [path]) + session = config.initsession() + assert eval(expr, session.config.option.__dict__) + + implied_options = { + '-v': 'verbose', + '-l': 'showlocals', + #'--runbrowser': 'startserver and runbrowser', XXX starts browser + } + for key, expr in implied_options.items(): + yield check_implied_option, [key], expr + + def test_default_session_options(self): + def runfiletest(opts): + sorter = suptest.events_from_cmdline(opts) + passed, skipped, failed = sorter.countoutcomes() + assert failed == 2 + assert skipped == passed == 0 + path = setupdata.getexamplefile("filetest.py") + for opts in ([], ['-l'], ['-s'], ['--tb=no'], ['--tb=short'], + ['--tb=long'], ['--fulltrace'], ['--nomagic'], + ['--traceconfig'], ['-v'], ['-v', '-v']): + yield runfiletest, opts + [path] + + def test_is_not_boxed_by_default(self): + path = setupdata.getexamplefile("filetest.py") + config = py.test2.config._reparse([path]) + assert not config.option.boxed + + class TestConfigColitems: def setup_class(cls): cls.tmproot = py.test2.ensuretemp(cls.__name__) Modified: py/branch/event/py/test2/testing/test_remote.py ============================================================================== --- py/branch/event/py/test2/testing/test_remote.py (original) +++ py/branch/event/py/test2/testing/test_remote.py Wed Feb 13 15:40:19 2008 @@ -1,5 +1,4 @@ import py -from test_session import getevents_runmain def setup_module(mod): mod.tmpdir = py.test.ensuretemp(mod.__name__) Modified: py/branch/event/py/test2/testing/test_session.py ============================================================================== --- py/branch/event/py/test2/testing/test_session.py (original) +++ py/branch/event/py/test2/testing/test_session.py Wed Feb 13 15:40:19 2008 @@ -1,98 +1,20 @@ import py -from setupdata import getexamplefile -from py.__.test2.outcome import Skipped, Failed, Passed, Outcome -from py.__.test2.terminal.out import getout from py.__.test2 import repevent - -from test_session2 import getevents_runmain +import suptest def setup_module(mod): mod.tmpdir = py.test.ensuretemp(mod.__name__) -implied_options = { - '-v': 'verbose', - '-l': 'showlocals', - #'--runbrowser': 'startserver and runbrowser', XXX starts browser -} - -conflict_options = ('--looponfailing --pdb', - '--dist --pdb', - '--exec=%s --pdb' % py.std.sys.executable, - ) - -def getoutcomes(all): - return [i for i in all if isinstance(i, repevent.ItemFinish)] - - -def getpassed(all): - return [i for i in getoutcomes(all) if i.passed] - -def getskipped(all): - return [i for i in getoutcomes(all) if i.skipped] + \ - [i for i in all if isinstance(i, repevent.DeselectedTest)] - -def getfailed(all): - return [i for i in getoutcomes(all) if i.failed] - -def getfailedcollections(all): - return [i for i in all - if isinstance(i, repevent.CollectionFinish) and - i.excinfo] - -def test_conflict_options(): - for spec in conflict_options: - opts = spec.split() - yield check_conflict_option, opts - -def check_conflict_option(opts): - print "testing if options conflict:", " ".join(opts) - path = getexamplefile("filetest.py") - config = py.test2.config._reparse(opts + [path]) - py.test2.raises((ValueError, SystemExit), """ - config.initsession() - """) - -def test_implied_options(): - for key, expr in implied_options.items(): - yield check_implied_option, [key], expr - -def check_implied_option(opts, expr): - path = getexamplefile("filetest.py") - config = py.test2.config._reparse(opts + [path]) - session = config.initsession() - assert eval(expr, session.config.option.__dict__) - -def test_default_session_options(): - path = getexamplefile("filetest.py") - for opts in ([], ['-l'], ['-s'], ['--tb=no'], ['--tb=short'], - ['--tb=long'], ['--fulltrace'], ['--nomagic'], - ['--traceconfig'], ['-v'], ['-v', '-v']): - yield runfiletest, opts + [path] - -def runfiletest(opts): - config = py.test2.config._reparse(opts) - session = config.initsession() - all = getevents_runmain(session) - assert len(getfailed(all)) == 2 - assert not getskipped(all) - -def test_is_not_boxed_by_default(): - path = getexamplefile("filetest.py") - config = py.test2.config._reparse([path]) - assert not config.option.boxed - class TestKeywordSelection: def test_select_simple(self): def check(keyword, name): - p = getexamplefile("filetest.py") - config = py.test2.config._reparse([p, '-s', '-k', keyword]) - session = config._getsessionclass()(config) - all = getevents_runmain(session) - outcomes = [i for i in all if isinstance(i, repevent.ItemFinish)] - assert len(getfailed(all)) == 1 - assert outcomes[0].item.name == name - l = getskipped(all) - assert len(l) == 1 + sorter = suptest.events_run_example("filetest.py", + '-s', '-k', keyword) + passed, skipped, failed = sorter.listoutcomes() + assert len(failed) == 1 + assert failed[0].item.name == name + des = sorter.get(repevent.DeselectedTest) + assert len(des) == 1 for keyword in ['test_one', 'est_on']: check(keyword, 'test_one') @@ -115,74 +37,60 @@ """)) for keyword in ('xxx', 'xxx test_2', 'TestClass', 'xxx -test_1', 'TestClass test_2', 'xxx TestClass test_2',): - config = py.test2.config._reparse([o, '-s', '-k', keyword]) - session = config._getsessionclass()(config) - all = getevents_runmain(session) + sorter = suptest.events_from_cmdline([o, '-s', '-k', keyword]) print "keyword", repr(keyword) - l = getpassed(all) - outcomes = [i for i in all if isinstance(i, repevent.ItemFinish)] - assert len(l) == 1 - assert outcomes[0].item.name == 'test_2' - l = getskipped(all) - assert l[0].item.name == 'test_1' + passed, skipped, failed = sorter.listoutcomes() + assert len(passed) == 1 + assert passed[0].item.name == 'test_2' + assert not skipped + deslist = sorter.get(repevent.DeselectedTest) + assert len(deslist) == 1 + assert deslist[0].item.name == 'test_1' def test_select_starton(self): - p = getexamplefile("testmore.py") - config = py.test2.config._reparse([p, '-j', '-k', "test_two"]) - session = config._getsessionclass()(config) - all = getevents_runmain(session) - assert len(getpassed(all)) == 2 - assert len(getskipped(all)) == 1 - + sorter = suptest.events_run_example("test_threepass.py", + '-j', '-k', "test_two") + passed, skipped, failed = sorter.countoutcomes() + assert passed == 2 + assert skipped == failed == 0 + deslist = sorter.get(repevent.DeselectedTest) + assert len(deslist) == 1 + assert deslist[0].item.name == "test_one" -class TestTerminalSession: - def mainsession(self, *args): - from py.__.test2.session import Session - from py.__.test2.terminal.out import getout - config = py.test2.config._reparse(list(args)) - session = Session(config) - all = getevents_runmain(session) - return session, all - +class TestSession: def test_terminal(self): - p = getexamplefile("filetest.py") - session, all = self.mainsession(p) - outcomes = getoutcomes(all) - assert len(getfailed(all)) == 2 + sorter = suptest.events_run_example("filetest.py") + passed, skipped, failed = sorter.countoutcomes() + assert failed == 2 + assert passed == skipped == 0 def test_syntax_error_module(self): - p = getexamplefile("syntax_error.py") - session, all = self.mainsession(p) - l = getfailedcollections(all) + sorter = suptest.events_run_example("syntax_error.py") + l = sorter.getfailedcollections() assert len(l) == 1 out = l[0].excinfo.exconly() assert out.find(str('syntax_error.py')) != -1 assert out.find(str('not python')) != -1 def test_exit_first_problem(self): - p = getexamplefile("filetest.py") - session, all = self.mainsession("--exitfirst", p) - assert session.config.option.exitfirst - assert len(getfailed(all)) == 1 - assert not getpassed(all) + sorter = suptest.events_run_example('filetest.py', '--exitfirst') + passed, skipped, failed = sorter.countoutcomes() + assert failed == 1 + assert passed == skipped == 0 def test_generator_yields_None(self): - o = tmpdir.ensure('generatornonetest', dir=1) - tfile = o.join('test_generatornone.py') - tfile.write(py.code.Source(""" + p = suptest.makeuniquepyfile(""" def test_1(): yield None - """)) - session, all = self.mainsession(o) - #print out - failures = getfailedcollections(all) + """) + sorter = suptest.events_from_cmdline([p]) + failures = sorter.getfailedcollections() out = failures[0].excinfo.exconly() i = out.find('TypeError') assert i != -1 - def test_capturing_hooks_simple(self): - o = tmpdir.ensure('capturing', dir=1) - tfile = o.join('test_capturing.py').write(py.code.Source(""" + def test_conftest_Function_capturing_hooks(self): + tfile = suptest.makeuniquepyfile(""" import py print "module level output" def test_capturing(): @@ -192,8 +100,8 @@ print 1 print >>py.std.sys.stderr, 2 raise ValueError - """)) - conftest = o.join('conftest.py').write(py.code.Source(""" + """) + conftest = tfile.dirpath('conftest.py').write(py.code.Source(""" import py class Function(py.test2.collect.Function): def startcapture(self): @@ -202,36 +110,32 @@ def finishcapture(self): self._testmycapture = None """)) - session, all = self.mainsession(o) - l = getpassed(all) - outcomes = getoutcomes(all) - assert len(l) == 1 - item = all[3].item # item is not attached to outcome, but it's the - # started before - assert hasattr(item, '_testmycapture') - print item._testmycapture - - assert isinstance(item.parent, py.test2.collect.Module) + sorter = suptest.events_from_cmdline([tfile.dirpath()]) + passed, skipped, failed = sorter.listoutcomes() + assert len(passed) == 1 + assert len(failed) == 1 + + assert hasattr(passed[0].item, '_mycapture') + assert hasattr(passed[0].item, '_testmycapture') + assert hasattr(failed[0].item, '_mycapture') + assert hasattr(failed[0].item, '_testmycapture') def test_raises_output(self): - o = tmpdir.ensure('raisestest', dir=1) - tfile = o.join('test_raisesoutput.py') - tfile.write(py.code.Source(""" + p = suptest.makeuniquepyfile(''' import py def test_raises_doesnt(): py.test2.raises(ValueError, int, "3") - """)) - session, all = self.mainsession(o) - outcomes = getoutcomes(all) - out = outcomes[0].excinfo.exconly() + ''') + sorter = suptest.events_from_cmdline([p]) + passed, skipped, failed = sorter.listoutcomes() + assert len(failed) == 1 + out = failed[0].excinfo.exconly() if not out.find("DID NOT RAISE") != -1: print out py.test2.fail("incorrect raises() output") def test_order_of_execution(self): - o = tmpdir.ensure('ordertest', dir=1) - tfile = o.join('test_orderofexecution.py') - tfile.write(py.code.Source(""" + tfile = suptest.makeuniquepyfile(""" l = [] def test_1(): l.append(1) @@ -249,76 +153,121 @@ self.reslist.append(3) def test_4(self): assert self.reslist == [1,2,1,2,3] - """)) - - session, all = self.mainsession(o) - assert len(getfailed(all)) == 0 - assert len(getpassed(all)) == 7 + """) + sorter = suptest.events_from_cmdline([tfile]) + passed, skipped, failed = sorter.countoutcomes() + assert failed == skipped == 0 + assert passed == 7 # also test listnames() here ... def test_nested_import_error(self): - o = tmpdir.ensure('Ians_importfailure', dir=1) - tfile = o.join('test_import_fail.py') - tfile.write(py.code.Source(""" + tfile = suptest.makeuniquepyfile(""" import import_fails def test_this(): assert import_fails.a == 1 - """)) - o.join('import_fails.py').write(py.code.Source(""" + """) + tfile.dirpath('import_fails.py').write(py.code.Source(""" import does_not_work a = 1 """)) - session, all = self.mainsession(o) - l = getfailedcollections(all) + sorter = suptest.events_from_cmdline([tfile]) + l = sorter.getfailedcollections() assert len(l) == 1 out = l[0].excinfo.exconly() assert out.find('does_not_work') != -1 def test_safe_repr(self): - p = getexamplefile("brokenrepr.py") - session, all = self.mainsession(p) - l = getfailed(all) - assert len(l) == 2 - out = l[0].excinfo.exconly() + sorter = suptest.events_run_example("brokenrepr.py") + passed, skipped, failed = sorter.listoutcomes() + assert len(failed) == 2 + out = failed[0].excinfo.exconly() assert out.find("""[Exception("Ha Ha fooled you, I'm a broken repr().") raised in repr()]""") != -1 #' - out = l[1].excinfo.exconly() + out = failed[1].excinfo.exconly() assert out.find("[unknown exception raised in repr()]") != -1 - -class TestCollectonly: - def setup_class(cls): - tmp = py.test2.ensuretemp('itemgentest') - tmp.ensure("__init__.py") - tmp.ensure("test_one.py").write(py.code.Source(""" - def test_one(): - pass - class TestX: - def test_method_one(self): + def test_collect_only_with_various_situations(self): + p = suptest.makeuniquepyfile(""" + def test_one(): pass - class TestY(TestX): - pass - """)) - tmp.ensure("test_two.py").write(py.code.Source(""" - import py - py.test.skip('xxx') + class TestX: + def test_method_one(self): + pass + + class TestY(TestX): + pass + """) + p.dirpath("test_two.py").write(py.code.Source(""" + import py + py.test.skip('xxx') """)) - tmp.ensure("test_three.py").write("xxxdsadsadsadsa") - cls.tmp = tmp + p.dirpath("test_three.py").write("xxxdsadsadsadsa") - def test_collectonly(self): - config = py.test2.config._reparse([self.tmp, '--collectonly']) - session = config.initsession() - # test it all in once - allevents = getevents_runmain(session) - started = finished = 0 - for event in allevents: - assert not isinstance(event, repevent.ItemFinish) - if isinstance(event, repevent.CollectionStart): - started += 1 - elif isinstance(event, repevent.CollectionFinish): - finished += 1 + sorter = suptest.events_from_cmdline([p.dirpath(), '--collectonly']) + + assert not sorter.get(repevent.ItemStart) + assert not sorter.get(repevent.ItemFinish) + started = sorter.get(repevent.CollectionStart) + finished = sorter.get(repevent.CollectionFinish) + assert len(started) == len(finished) + failedcollections = sorter.getfailedcollections() + assert len(failedcollections) == 2 + + def test_pdb_run(self): + tfile = suptest.makeuniquepyfile(""" + def test_1(): + assert 0 + """) + l = [] + def mypdb(*args): + l.append(args) + py.magic.patch(py.__.test2.custompdb, 'post_mortem', mypdb) + try: + sorter = suptest.initsorter_from_cmdline([tfile, '--pdb']) + py.test.raises(SystemExit, sorter.session.main) + passed, skipped, failed = sorter.countoutcomes() + assert passed == skipped == 0 + assert len(l) == 1 + # XXX assert failed == 1 + py.test.skip("XXX streamline event generation with --pdb") + # XXX add some more checks? + finally: + py.magic.revert(py.__.test2.custompdb, 'post_mortem') + + def test_basic_testitem_events(self): + tfile = suptest.makeuniquepyfile(""" + def test_one(): + pass + def test_one_one(): + assert 0 + def test_other(): + raise ValueError(23) + def test_two(someargs): + pass + """) + sorter = suptest.events_from_cmdline([tfile]) + passed, skipped, failed = sorter.listoutcomes() + assert len(skipped) == 0 + assert len(passed) == 1 + assert len(failed) == 3 + assert failed[0].item.name == "test_one_one" + assert failed[1].item.name == "test_other" + assert failed[2].item.name == "test_two" - print started - assert started == finished + def test_capture_info_on_event(self): + tfile = suptest.makeuniquepyfile(""" + def test_one(): + print 1 + print 2 + print 3 + """) + sorter = suptest.events_from_cmdline([tfile]) + passed, skipped, failed = sorter.listoutcomes() + assert len(skipped) == len(failed) == 0 + assert len(passed) == 1 + ev = passed[0] + py.test.skip("XXX get more info (e.g. capturing) available from events") + assert ev.outcome.passed + assert ev.outcome.stderr == "" + assert ev.outcome.stdout == "1\n2\n3\n" Deleted: /py/branch/event/py/test2/testing/test_session2.py ============================================================================== --- /py/branch/event/py/test2/testing/test_session2.py Wed Feb 13 15:40:19 2008 +++ (empty file) @@ -1,293 +0,0 @@ - -""" test of local version of py.test2 distributed -""" - -import py -from py.__.test2 import repevent -#from py.__.test2.rsession.local import box_runner, plain_runner, apigen_runner -import py.__.test2.custompdb -from py.__.test2.session import Session - -def getevents_runmain(session): - hub = session.config.hub - allevents = [] - def appendevent(event): - allevents.append(event) - print event - hub.append(appendevent) - try: - session.main() - return allevents - finally: - hub.remove(appendevent) - - -def setup_module(mod): - mod.tmp = py.test2.ensuretemp("lsession_module") - -class TestSession(object): - # XXX: Some tests of that should be run as well on RSession, while - # some not at all - def example_distribution(self, boxed=False): - # XXX find a better way for the below - tmpdir = tmp - dirname = "sub_lsession"#+runner.func_name - tmpdir.ensure(dirname, "__init__.py") - tmpdir.ensure(dirname, "test_one.py").write(py.code.Source(""" - def test_1(): - pass - def test_2(): - assert 0 - def test_3(): - raise ValueError(23) - def test_4(someargs): - pass - #def test_5(): - # import os - # os.kill(os.getpid(), 11) - """)) - args = [str(tmpdir.join(dirname))] - if boxed: - args.append('--boxed') - config = py.test2.config._reparse(args) - lsession = Session(config) - allevents = getevents_runmain(lsession) - testevents = [x for x in allevents - if isinstance(x, repevent.ItemFinish)] - assert len(testevents) - passevents = [i for i in testevents if i.passed] - failevents = [i for i in testevents if i.failed] - skippedevents = [i for i in testevents if i.skipped] - #signalevents = [i for i in testevents if i.outcome.signal] - assert len(passevents) == 1 - assert len(failevents) == 3 - assert len(skippedevents) == 0 - #assert len(signalevents) == 1 - - return - # XXX - tb = failevents[0].outcome.excinfo.traceback - assert str(tb[0].path).find("test_one") != -1 - assert str(tb[0].source).find("test_2") != -1 - assert failevents[0].outcome.excinfo.typename == 'AssertionError' - tb = failevents[1].outcome.excinfo.traceback - assert str(tb[0].path).find("test_one") != -1 - assert str(tb[0].source).find("test_3") != -1 - assert failevents[1].outcome.excinfo.typename == 'ValueError' - assert str(failevents[1].outcome.excinfo.value) == '23' - tb = failevents[2].outcome.excinfo.traceback - assert failevents[2].outcome.excinfo.typename == 'TypeError' - assert str(tb[0].path).find("executor") != -1 - assert str(tb[0].source).find("execute") != -1 - - def test_boxed(self): - if not hasattr(py.std.os, 'fork'): - py.test.skip('operating system not supported') - self.example_distribution(True) - - def test_box_exploding(self): - if not hasattr(py.std.os, 'fork'): - py.test.skip('operating system not supported') - tmpdir = tmp - dirname = "boxtest" - tmpdir.ensure(dirname, "__init__.py") - tmpdir.ensure(dirname, "test_one.py").write(py.code.Source(""" - def test_5(): - import os - os.kill(os.getpid(), 11) - """)) - args = [str(tmpdir.join(dirname))] - args.append('--boxed') - config = py.test2.config._reparse(args) - lsession = Session(config) - allevents = getevents_runmain(lsession) - testevents = [x for x in allevents - if isinstance(x, repevent.ItemFinish)] - assert len(testevents) - #assert testevents[0].outcome.signal - - def test_plain(self): - self.example_distribution(False) - - def test_pdb_run(self): - # we make sure that pdb is engaged - tmpdir = tmp - subdir = "sub_pdb_run" - tmpdir.ensure(subdir, "__init__.py") - tmpdir.ensure(subdir, "test_one.py").write(py.code.Source(""" - def test_1(): - assert 0 - """)) - l = [] - def some_fun(*args): - l.append(args) - - try: - post_mortem = py.__.test2.custompdb.post_mortem - py.__.test2.custompdb.post_mortem = some_fun - args = [str(tmpdir.join(subdir)), '--pdb'] - config = py.test2.config._reparse(args) - lsession = Session(config) - #try: - allevents = getevents_runmain(lsession) - #except SystemExit: - # pass - #else: - # py.test2.fail("Didn't raise system exit") - failure_events = [event for event in allevents if isinstance(event, - repevent.ImmediateFailure)] - assert len(failure_events) == 1 - assert len(l) == 1 - finally: - py.__.test2.custompdb.post_mortem = post_mortem - - def test_minus_x(self): - if not hasattr(py.std.os, 'fork'): - py.test.skip('operating system not supported') - tmpdir = tmp - subdir = "sub_lsession_minus_x" - tmpdir.ensure(subdir, "__init__.py") - tmpdir.ensure(subdir, "test_one.py").write(py.code.Source(""" - def test_1(): - pass - def test_2(): - assert 0 - def test_3(): - raise ValueError(23) - def test_4(someargs): - pass - """)) - args = [str(tmpdir.join(subdir)), '-x'] - config = py.test2.config._reparse(args) - assert config.option.exitfirst - lsession = Session(config) - allevents = getevents_runmain(lsession) - testevents = [x for x in allevents - if isinstance(x, repevent.ItemFinish)] - assert len(testevents) - passevents = [i for i in testevents if i.outcome.passed] - failevents = [i for i in testevents if i.outcome.excinfo] - assert len(passevents) == 1 - assert len(failevents) == 1 - - def test_minus_k(self): - if not hasattr(py.std.os, 'fork'): - py.test.skip('operating system not supported') - tmpdir = tmp - tmpdir.ensure("sub3", "__init__.py") - tmpdir.ensure("sub3", "test_some.py").write(py.code.Source(""" - def test_one(): - pass - def test_one_one(): - assert 0 - def test_other(): - raise ValueError(23) - def test_two(someargs): - pass - """)) - args = [str(tmpdir.join("sub3")), '-k', 'test_one'] - config = py.test2.config._reparse(args) - lsession = Session(config) - - allevents = getevents_runmain(lsession) - testevents = [x for x in allevents - if isinstance(x, repevent.ItemFinish)] - assert len(testevents) - passevents = [i for i in testevents if i.outcome.passed] - failevents = [i for i in testevents if i.outcome.excinfo] - assert len(passevents) == 1 - assert len(failevents) == 1 - - def test_lsession(self): - tmpdir = tmp - tmpdir.ensure("sub4", "__init__.py") - tmpdir.ensure("sub4", "test_some.py").write(py.code.Source(""" - def test_one(): - pass - def test_one_one(): - assert 0 - def test_other(): - raise ValueError(23) - def test_two(someargs): - pass - """)) - - args = [str(tmpdir.join("sub4"))] - config = py.test2.config._reparse(args) - lsession = Session(config) - allruns = [] - allevents = getevents_runmain(lsession) - testevents = [x for x in allevents - if isinstance(x, repevent.ItemFinish)] - assert len(testevents) == 4 - lst = ['test_one', 'test_one_one', 'test_other', 'test_two'] - for num, i in enumerate(testevents): - #assert i.item == i.outcome - assert i.item.name == lst[num] - - def test_module_raising(self): - tmpdir = tmp - tmpdir.ensure("sub5", "__init__.py") - tmpdir.ensure("sub5", "test_some.py").write(py.code.Source(""" - 1/0 - """)) - tmpdir.ensure("sub5", "test_other.py").write(py.code.Source(""" - import py - py.test.skip("reason") - """)) - - args = [str(tmpdir.join("sub5"))] - config = py.test2.config._reparse(args) - lsession = Session(config) - allevents = getevents_runmain(lsession) - testevents = [x for x in allevents - if isinstance(x, repevent.ItemFinish)] - assert len(testevents) == 0 - failedtryiter = [x for x in allevents - if isinstance(x, repevent.FailedTryiter)] - assert len(failedtryiter) == 1 - skippedtryiter = [x for x in allevents - if isinstance(x, repevent.DeselectedTest)] - assert len(skippedtryiter) == 1 - - - def test_assert_reinterpret(self): - if not hasattr(py.std.os, 'fork'): - py.test.skip('operating system not supported') - tmpdir = tmp - tmpdir.ensure("sub6", "__init__.py") - tmpdir.ensure("sub6", "test_some.py").write(py.code.Source(""" - def test_one(): - x = [1, 2] - assert [0] == x - """)) - args = [str(tmpdir.join("sub6"))] - config = py.test2.config._reparse(args) - lsession = Session(config) - allevents = getevents_runmain(lsession) - testevents = [x for x in allevents - if isinstance(x, repevent.ItemFinish)] - failevents = [i for i in testevents if i.outcome.excinfo] - assert len(failevents) == 1 - assert len(testevents) == 1 - assert failevents[0].outcome.excinfo.value == 'assert [0] == [1, 2]' - - def test_nocapture(self): - tmpdir = tmp - tmpdir.ensure("sub7", "__init__.py") - tmpdir.ensure("sub7", "test_nocap.py").write(py.code.Source(""" - def test_one(): - print 1 - print 2 - print 3 - """)) - args = [str(tmpdir.join("sub7"))] - config = py.test2.config._reparse(args) - lsession = Session(config) - allevents = getevents_runmain(lsession.main) - testevents = [x for x in allevents - if isinstance(x, repevent.ItemFinish)] - assert len(testevents) == 1 - assert testevents[0].outcome.passed - assert testevents[0].outcome.stderr == "" - assert testevents[0].outcome.stdout == "1\n2\n3\n" Copied: py/branch/event/py/test2/testing/test_session_xxx.py (from r51396, py/branch/event/py/test2/testing/test_session2.py) ============================================================================== --- py/branch/event/py/test2/testing/test_session2.py (original) +++ py/branch/event/py/test2/testing/test_session_xxx.py Wed Feb 13 15:40:19 2008 @@ -4,36 +4,23 @@ import py from py.__.test2 import repevent -#from py.__.test2.rsession.local import box_runner, plain_runner, apigen_runner +import suptest import py.__.test2.custompdb from py.__.test2.session import Session -def getevents_runmain(session): - hub = session.config.hub - allevents = [] - def appendevent(event): - allevents.append(event) - print event - hub.append(appendevent) - try: - session.main() - return allevents - finally: - hub.remove(appendevent) - +def check_has_fork(): + if not hasattr(py.std.os, 'fork'): + py.test.skip('platform does not support os.fork') def setup_module(mod): - mod.tmp = py.test2.ensuretemp("lsession_module") + mod.tmp = py.test2.ensuretemp(mod.__name__) -class TestSession(object): +class TestExampleDistribution(object): # XXX: Some tests of that should be run as well on RSession, while # some not at all def example_distribution(self, boxed=False): # XXX find a better way for the below - tmpdir = tmp - dirname = "sub_lsession"#+runner.func_name - tmpdir.ensure(dirname, "__init__.py") - tmpdir.ensure(dirname, "test_one.py").write(py.code.Source(""" + tfile = suptest.makeuniquepyfile(""" def test_1(): pass def test_2(): @@ -45,25 +32,17 @@ #def test_5(): # import os # os.kill(os.getpid(), 11) - """)) - args = [str(tmpdir.join(dirname))] + """) + args = [tfile] if boxed: + check_has_fork() args.append('--boxed') - config = py.test2.config._reparse(args) - lsession = Session(config) - allevents = getevents_runmain(lsession) - testevents = [x for x in allevents - if isinstance(x, repevent.ItemFinish)] - assert len(testevents) - passevents = [i for i in testevents if i.passed] - failevents = [i for i in testevents if i.failed] - skippedevents = [i for i in testevents if i.skipped] - #signalevents = [i for i in testevents if i.outcome.signal] - assert len(passevents) == 1 - assert len(failevents) == 3 - assert len(skippedevents) == 0 + sorter = suptest.events_from_cmdline(args) + passed, skipped, failed = sorter.listoutcomes() + assert len(passed) == 1 + assert len(skipped) == 0 + assert len(failed) == 3 #assert len(signalevents) == 1 - return # XXX tb = failevents[0].outcome.excinfo.traceback @@ -81,213 +60,25 @@ assert str(tb[0].source).find("execute") != -1 def test_boxed(self): - if not hasattr(py.std.os, 'fork'): - py.test.skip('operating system not supported') + check_has_fork() self.example_distribution(True) + def test_plain(self): + self.example_distribution(False) + def test_box_exploding(self): - if not hasattr(py.std.os, 'fork'): - py.test.skip('operating system not supported') - tmpdir = tmp - dirname = "boxtest" - tmpdir.ensure(dirname, "__init__.py") - tmpdir.ensure(dirname, "test_one.py").write(py.code.Source(""" + check_has_fork() + tfile = suptest.makeuniquepyfile(""" def test_5(): import os os.kill(os.getpid(), 11) - """)) - args = [str(tmpdir.join(dirname))] - args.append('--boxed') - config = py.test2.config._reparse(args) - lsession = Session(config) - allevents = getevents_runmain(lsession) - testevents = [x for x in allevents - if isinstance(x, repevent.ItemFinish)] - assert len(testevents) + """) + sorter = suptest.events_from_cmdline([tfile, '--boxed']) + passed, skipped, failed = sorter.listoutcomes() + py.test.skip("FIX BOXING event generation") + assert len(passed) == len(skipped) == 0 + assert len(failed) == 1 + py.test.skip("implement checking for signal outcomes") #assert testevents[0].outcome.signal - def test_plain(self): - self.example_distribution(False) - - def test_pdb_run(self): - # we make sure that pdb is engaged - tmpdir = tmp - subdir = "sub_pdb_run" - tmpdir.ensure(subdir, "__init__.py") - tmpdir.ensure(subdir, "test_one.py").write(py.code.Source(""" - def test_1(): - assert 0 - """)) - l = [] - def some_fun(*args): - l.append(args) - - try: - post_mortem = py.__.test2.custompdb.post_mortem - py.__.test2.custompdb.post_mortem = some_fun - args = [str(tmpdir.join(subdir)), '--pdb'] - config = py.test2.config._reparse(args) - lsession = Session(config) - #try: - allevents = getevents_runmain(lsession) - #except SystemExit: - # pass - #else: - # py.test2.fail("Didn't raise system exit") - failure_events = [event for event in allevents if isinstance(event, - repevent.ImmediateFailure)] - assert len(failure_events) == 1 - assert len(l) == 1 - finally: - py.__.test2.custompdb.post_mortem = post_mortem - - def test_minus_x(self): - if not hasattr(py.std.os, 'fork'): - py.test.skip('operating system not supported') - tmpdir = tmp - subdir = "sub_lsession_minus_x" - tmpdir.ensure(subdir, "__init__.py") - tmpdir.ensure(subdir, "test_one.py").write(py.code.Source(""" - def test_1(): - pass - def test_2(): - assert 0 - def test_3(): - raise ValueError(23) - def test_4(someargs): - pass - """)) - args = [str(tmpdir.join(subdir)), '-x'] - config = py.test2.config._reparse(args) - assert config.option.exitfirst - lsession = Session(config) - allevents = getevents_runmain(lsession) - testevents = [x for x in allevents - if isinstance(x, repevent.ItemFinish)] - assert len(testevents) - passevents = [i for i in testevents if i.outcome.passed] - failevents = [i for i in testevents if i.outcome.excinfo] - assert len(passevents) == 1 - assert len(failevents) == 1 - - def test_minus_k(self): - if not hasattr(py.std.os, 'fork'): - py.test.skip('operating system not supported') - tmpdir = tmp - tmpdir.ensure("sub3", "__init__.py") - tmpdir.ensure("sub3", "test_some.py").write(py.code.Source(""" - def test_one(): - pass - def test_one_one(): - assert 0 - def test_other(): - raise ValueError(23) - def test_two(someargs): - pass - """)) - args = [str(tmpdir.join("sub3")), '-k', 'test_one'] - config = py.test2.config._reparse(args) - lsession = Session(config) - - allevents = getevents_runmain(lsession) - testevents = [x for x in allevents - if isinstance(x, repevent.ItemFinish)] - assert len(testevents) - passevents = [i for i in testevents if i.outcome.passed] - failevents = [i for i in testevents if i.outcome.excinfo] - assert len(passevents) == 1 - assert len(failevents) == 1 - - def test_lsession(self): - tmpdir = tmp - tmpdir.ensure("sub4", "__init__.py") - tmpdir.ensure("sub4", "test_some.py").write(py.code.Source(""" - def test_one(): - pass - def test_one_one(): - assert 0 - def test_other(): - raise ValueError(23) - def test_two(someargs): - pass - """)) - - args = [str(tmpdir.join("sub4"))] - config = py.test2.config._reparse(args) - lsession = Session(config) - allruns = [] - allevents = getevents_runmain(lsession) - testevents = [x for x in allevents - if isinstance(x, repevent.ItemFinish)] - assert len(testevents) == 4 - lst = ['test_one', 'test_one_one', 'test_other', 'test_two'] - for num, i in enumerate(testevents): - #assert i.item == i.outcome - assert i.item.name == lst[num] - - def test_module_raising(self): - tmpdir = tmp - tmpdir.ensure("sub5", "__init__.py") - tmpdir.ensure("sub5", "test_some.py").write(py.code.Source(""" - 1/0 - """)) - tmpdir.ensure("sub5", "test_other.py").write(py.code.Source(""" - import py - py.test.skip("reason") - """)) - - args = [str(tmpdir.join("sub5"))] - config = py.test2.config._reparse(args) - lsession = Session(config) - allevents = getevents_runmain(lsession) - testevents = [x for x in allevents - if isinstance(x, repevent.ItemFinish)] - assert len(testevents) == 0 - failedtryiter = [x for x in allevents - if isinstance(x, repevent.FailedTryiter)] - assert len(failedtryiter) == 1 - skippedtryiter = [x for x in allevents - if isinstance(x, repevent.DeselectedTest)] - assert len(skippedtryiter) == 1 - - - def test_assert_reinterpret(self): - if not hasattr(py.std.os, 'fork'): - py.test.skip('operating system not supported') - tmpdir = tmp - tmpdir.ensure("sub6", "__init__.py") - tmpdir.ensure("sub6", "test_some.py").write(py.code.Source(""" - def test_one(): - x = [1, 2] - assert [0] == x - """)) - args = [str(tmpdir.join("sub6"))] - config = py.test2.config._reparse(args) - lsession = Session(config) - allevents = getevents_runmain(lsession) - testevents = [x for x in allevents - if isinstance(x, repevent.ItemFinish)] - failevents = [i for i in testevents if i.outcome.excinfo] - assert len(failevents) == 1 - assert len(testevents) == 1 - assert failevents[0].outcome.excinfo.value == 'assert [0] == [1, 2]' - def test_nocapture(self): - tmpdir = tmp - tmpdir.ensure("sub7", "__init__.py") - tmpdir.ensure("sub7", "test_nocap.py").write(py.code.Source(""" - def test_one(): - print 1 - print 2 - print 3 - """)) - args = [str(tmpdir.join("sub7"))] - config = py.test2.config._reparse(args) - lsession = Session(config) - allevents = getevents_runmain(lsession.main) - testevents = [x for x in allevents - if isinstance(x, repevent.ItemFinish)] - assert len(testevents) == 1 - assert testevents[0].outcome.passed - assert testevents[0].outcome.stderr == "" - assert testevents[0].outcome.stdout == "1\n2\n3\n" From hpk at codespeak.net Wed Feb 13 17:58:49 2008 From: hpk at codespeak.net (hpk at codespeak.net) Date: Wed, 13 Feb 2008 17:58:49 +0100 (CET) Subject: [py-svn] r51445 - py/branch/event/py/test2/testing Message-ID: <20080213165849.E177F168407@codespeak.net> Author: hpk Date: Wed Feb 13 17:58:49 2008 New Revision: 51445 Modified: py/branch/event/py/test2/testing/suptest.py Log: add module doc string for test helpers Modified: py/branch/event/py/test2/testing/suptest.py ============================================================================== --- py/branch/event/py/test2/testing/suptest.py (original) +++ py/branch/event/py/test2/testing/suptest.py Wed Feb 13 17:58:49 2008 @@ -1,4 +1,16 @@ - +""" + test support code + + makeuniquepyfile(source) generates a per-test-run-unique directory and test_*.py file + + for analyzing events an EventSorter instance is returned for both of: + * events_from_cmdline(args): inprocess-run of cmdline invocation + * events_from_session(session): inprocess-run of given session + * events_run_example(examplename, *args):in-process-run of + given example test file + + eventappender(config): for getting all events in a list: +""" import py from py.__.test2 import repevent @@ -30,7 +42,7 @@ def events_run_example(examplename, *args): from setupdata import getexamplefile - p = getexamplefile(examplename) + p = getexamplefile(examplename) return events_from_cmdline([p] + list(args)) class EventSorter(object): @@ -70,7 +82,6 @@ l.append(ev) return l - counter = py.std.itertools.count().next def makeuniquepyfile(source): dirname = "test_%d" %(counter(),) From hpk at codespeak.net Wed Feb 13 18:12:35 2008 From: hpk at codespeak.net (hpk at codespeak.net) Date: Wed, 13 Feb 2008 18:12:35 +0100 (CET) Subject: [py-svn] r51446 - py/branch/event/py/test2/rsession/testing Message-ID: <20080213171235.8E88C1683CE@codespeak.net> Author: hpk Date: Wed Feb 13 18:12:35 2008 New Revision: 51446 Modified: py/branch/event/py/test2/rsession/testing/basetest.py py/branch/event/py/test2/rsession/testing/test_hostmanage.py py/branch/event/py/test2/rsession/testing/test_masterslave.py py/branch/event/py/test2/rsession/testing/test_rsession.py Log: minor test setup shuffling Modified: py/branch/event/py/test2/rsession/testing/basetest.py ============================================================================== --- py/branch/event/py/test2/rsession/testing/basetest.py (original) +++ py/branch/event/py/test2/rsession/testing/basetest.py Wed Feb 13 18:12:35 2008 @@ -5,6 +5,14 @@ import py from py.__.test2.testing.setupdata import getexamplefile +class DirSetup: + def setup_method(self, method): + name = "%s.%s" %(self.__class__.__name__, method.func_name) + self.tmpdir = py.test2.ensuretemp(name) + self.source = self.tmpdir.ensure("source", dir=1) + self.dest = self.tmpdir.join("dest") + + class BasicRsessionTest(object): def setup_class(cls): path = getexamplefile("funcexamples.py") Modified: py/branch/event/py/test2/rsession/testing/test_hostmanage.py ============================================================================== --- py/branch/event/py/test2/rsession/testing/test_hostmanage.py (original) +++ py/branch/event/py/test2/rsession/testing/test_hostmanage.py Wed Feb 13 18:12:35 2008 @@ -3,17 +3,11 @@ """ import py +from basetest import DirSetup from py.__.test2.rsession.hostmanage import HostRSync, HostInfo, HostManager from py.__.test2.rsession.hostmanage import sethomedir, gethomedir, getpath_relto_home from py.__.test2 import repevent -class DirSetup: - def setup_method(self, method): - name = "%s.%s" %(self.__class__.__name__, method.func_name) - self.tmpdir = py.test2.ensuretemp(name) - self.source = self.tmpdir.ensure("source", dir=1) - self.dest = self.tmpdir.join("dest") - class TestHostInfo(DirSetup): def _gethostinfo(self, relpath=""): exampledir = self.tmpdir.join("gethostinfo") Modified: py/branch/event/py/test2/rsession/testing/test_masterslave.py ============================================================================== --- py/branch/event/py/test2/rsession/testing/test_masterslave.py (original) +++ py/branch/event/py/test2/rsession/testing/test_masterslave.py Wed Feb 13 18:12:35 2008 @@ -6,7 +6,7 @@ from py.__.test2 import repevent -class TestMasterSlaveConnection(BasicRsessionTest): +class TestMasterSlaveConnection(BasicRsessionTest): def makereportqueue(self, filterevent=repevent.ItemTestReport): queue = py.std.Queue.Queue() def append(event): Modified: py/branch/event/py/test2/rsession/testing/test_rsession.py ============================================================================== --- py/branch/event/py/test2/rsession/testing/test_rsession.py (original) +++ py/branch/event/py/test2/rsession/testing/test_rsession.py Wed Feb 13 18:12:35 2008 @@ -6,8 +6,7 @@ from py.__.test2 import repevent from py.__.test2.rsession.rsession import RSession from py.__.test2.rsession.hostmanage import HostManager, HostInfo -from py.__.test2.rsession.testing.basetest import BasicRsessionTest -from py.__.test2.rsession.testing.test_hostmanage import DirSetup +from basetest import BasicRsessionTest, DirSetup from py.__.test2.testing import suptest @@ -36,7 +35,6 @@ assert 0 """)) config = py.test2.config._reparse([self.source.join("sub"), '-x', '--dist']) - #config = py.test2.config._reparse([self.source.join("sub"), '--dist']) rsession = RSession(config) sorter = suptest.events_from_session(rsession) testevents = sorter.get(repevent.ItemTestReport) From guido at codespeak.net Wed Feb 13 21:01:31 2008 From: guido at codespeak.net (guido at codespeak.net) Date: Wed, 13 Feb 2008 21:01:31 +0100 (CET) Subject: [py-svn] r51450 - py/branch/guido-svn-auth/py/path/svn Message-ID: <20080213200131.7FCD316840A@codespeak.net> Author: guido Date: Wed Feb 13 21:01:30 2008 New Revision: 51450 Added: py/branch/guido-svn-auth/py/path/svn/auth.txt Modified: py/branch/guido-svn-auth/py/path/svn/wccommand.py Log: Added auth support to the remaining methods that may connect to the server, updated text a bit and turned it into documentation/discussion doc. Added: py/branch/guido-svn-auth/py/path/svn/auth.txt ============================================================================== --- (empty file) +++ py/branch/guido-svn-auth/py/path/svn/auth.txt Wed Feb 13 21:01:30 2008 @@ -0,0 +1,76 @@ +SVN authentication support +========================== + +This document describes authentication support to both py.path.svnwc and +py.path.svnurl (yet in its implemention phase). This allows using the library +in a completely automated situation, without having to provide svn credentials +interactively. + +Current implementation +---------------------- + +The credentials are passed to the constructor of the path objects, and are used +(transparently) for every action that accesses the server. Also, when provided, +they are passed recursively to all child objects created by methods such as +join(), ensure(), etc. + +To pass credentials to path objects, an SvnAuth class needs to be created to +hold them. This is then passed to the constructor or methods, usually as +the 'auth' keyword argument. + +It is configurable whether the credentials are stored on disk. Storing them is +useful in certain situations (executive access to the repository will not +require the credentials to be passed) but might not be desired in others - for +instance if a webserver runs more than one application, you do not want to +pollute the webserver's home directory (if it even has one). This behaviour can +be controlled by passing a False value for the 'cache_auth' argument to +SvnAuth. + +Code examples +------------- + +So, tying this together, code using this feature would look something like:: + + >>> auth = py.path.SvnAuth('user', 'pass', cache_auth=False) + >>> wc = py.path.svnwc(url, auth=auth) + +Open issues +----------- + +* How do we deal with externals properly? + + It looks like the svn command-line client uses the credentials provided for + all externals, if possible, and either prompts for the password in + interactive mode, or barfs when --non-interactive is passed. I think it makes + sense to copy its behaviour here, pass the credentials to any child svn path + objects (as discussed above), and either let the command-line app ask for + creds or throw an exception when 'interactive' is set to False (see above). + + Current idea: ignore this and let the client handle (so no passing auth + around to the children). + +* Functional testing + + Functional testing is relatively hard, and will not work on all systems. It + looks like a setup using 'svnserve' is possible, but it will be slow and + provide relatively little advantages, apart from testing the integration. + Holger suggested that perhaps functional tests could be skipped in favour + of only unit tests. + +* Non-interactive sessions + + I still think having a way to tell the system we don't want the session to + be interactive would be very useful... It is unacceptable for certain types + of applications to block on user input. Should we have 'interactive' as an + argument to the methods/constructor, with a default value of True? + +* Affected methods + + - switch + - checkout + - update + - lock + - unlock + - diff (when using older revisions?) + - commit + - log Modified: py/branch/guido-svn-auth/py/path/svn/wccommand.py ============================================================================== --- py/branch/guido-svn-auth/py/path/svn/wccommand.py (original) +++ py/branch/guido-svn-auth/py/path/svn/wccommand.py Wed Feb 13 21:01:30 2008 @@ -102,9 +102,14 @@ raise return out - def switch(self, url): + def switch(self, url, auth=None): """ switch to given URL. """ - self._svn('switch', url) + args = [] + if auth is not None: + args.append(str(auth)) + elif self._auth is not None: + args.append(str(self._auth)) + self._svn('switch', url, *args) def checkout(self, url=None, rev=None, auth=None): """ checkout from url to local wcpath. """ @@ -126,9 +131,14 @@ args.append(str(self._auth)) self._svn('co', url, *args) - def update(self, rev = 'HEAD'): + def update(self, rev = 'HEAD', auth=None): """ update working copy item to given revision. (None -> HEAD). """ - self._svn('up -r %s' % rev) + args = [] + if auth is not None: + args.append(str(auth)) + elif self._auth is not None: + args.append(str(self._auth)) + self._svn('up -r %s' % rev, *args) def write(self, content, mode='wb'): """ write content into local filesystem wc. """ @@ -204,16 +214,26 @@ _rex_status = re.compile(r'\s+(\d+|-)\s+(\S+)\s+(\S+)\s+(.*)') - def lock(self): + def lock(self, auth=None): """ set a lock (exclusive) on the resource """ - out = self._svn('lock').strip() + args = [] + if auth is not None: + args.append(str(auth)) + elif self._auth is not None: + args.append(str(self._auth)) + out = self._svn('lock', *args).strip() if not out: # warning or error, raise exception raise Exception(out[4:]) - def unlock(self): + def unlock(self, auth=None): """ unset a previously set lock """ - out = self._svn('unlock').strip() + args = [] + if auth is not None: + args.append(str(auth)) + elif self._auth is not None: + args.append(str(self._auth)) + out = self._svn('unlock', *args).strip() if out.startswith('svn:'): # warning or error, raise exception raise Exception(out[4:]) @@ -335,14 +355,19 @@ continue return rootstatus - def diff(self, rev=None): + def diff(self, rev=None, auth=None): """ return a diff of the current path against revision rev (defaulting to the last one). """ if rev is None: out = self._svn('diff') else: - out = self._svn('diff -r %d' % rev) + args = [] + if auth is not None: + args.append(str(auth)) + elif self._auth is not None: + args.append(str(self._auth)) + out = self._svn('diff -r %d' % rev, *args) return out def blame(self): @@ -528,7 +553,7 @@ else: return True - def log(self, rev_start=None, rev_end=1, verbose=False): + def log(self, rev_start=None, rev_end=1, verbose=False, auth=None): """ return a list of LogEntry instances for this path. rev_start is the starting revision (defaulting to the first one). rev_end is the last revision (defaulting to HEAD). @@ -544,11 +569,20 @@ else: rev_opt = "-r %s:%s" % (rev_start, rev_end) verbose_opt = verbose and "-v" or "" - s = svncommon.fixlocale() + locale_env = svncommon.fixlocale() # some blather on stderr - stdin, stdout, stderr = os.popen3(s + 'svn log --xml %s %s "%s"' % ( - rev_opt, verbose_opt, - self.strpath)) + auth_opt = '' + if auth is not None: + auth_opt = '%s' % (auth,) + elif self._auth is not None: + auth_opt = '%s' % (self._auth,) + auth_opt = ((auth is not None and str(auth)) or + (self._auth is not None and str(self._auth)) or + '') + stdin, stdout, stderr = os.popen3(locale_env + + 'svn log --xml %s %s %s "%s"' % ( + rev_opt, verbose_opt, auth_opt, + self.strpath)) from xml.dom import minidom from xml.parsers.expat import ExpatError try: From hpk at codespeak.net Wed Feb 13 22:12:59 2008 From: hpk at codespeak.net (hpk at codespeak.net) Date: Wed, 13 Feb 2008 22:12:59 +0100 (CET) Subject: [py-svn] r51464 - in py/branch/event/py/test2: . rsession rsession/testing testing Message-ID: <20080213211259.1CF1616840B@codespeak.net> Author: hpk Date: Wed Feb 13 22:12:58 2008 New Revision: 51464 Removed: py/branch/event/py/test2/rsession/local.py py/branch/event/py/test2/rsession/testing/test_slave.py Modified: py/branch/event/py/test2/executor.py py/branch/event/py/test2/outcome.py py/branch/event/py/test2/repevent.py py/branch/event/py/test2/rsession/master.py py/branch/event/py/test2/rsession/slave.py py/branch/event/py/test2/session.py py/branch/event/py/test2/testing/setupdata.py py/branch/event/py/test2/testing/test_executor.py py/branch/event/py/test2/testing/test_outcome.py Log: yet another Intermediate Checkin, but passing almost all current tests: * unify Executors and extend Executor tests * getting rid of SerializableOutcome in favour of ItemTestReport event * lots of refactoring of tests (as well as new ones) * remove (asfaik) unused local.py Modified: py/branch/event/py/test2/executor.py ============================================================================== --- py/branch/event/py/test2/executor.py (original) +++ py/branch/event/py/test2/executor.py Wed Feb 13 22:12:58 2008 @@ -3,17 +3,15 @@ import py, os, sys -from py.__.test2.outcome import SerializableOutcome, ReprOutcome from py.__.test2.box import Box from py.__.test2 import repevent from py.__.test2.outcome import Skipped, Failed +from py.__.test2 import repevent import py.__.test2.custompdb class RunExecutor(object): """ Same as in executor, but just running run """ - wraps = False - def __init__(self, item, config): self.item = item self.config = config @@ -29,17 +27,19 @@ self.item.run() def execute(self, capture=True): + testrep = repevent.ItemTestReport(self.item._get_collector_trail()) + testrep._item = self.item try: - self.run(capture) - outcome = SerializableOutcome() - outcome.stdout, outcome.stderr = self.item._getouterr() + try: + self.run(capture) + finally: + testrep.stdout, testrep.stderr = self.item._getouterr() except Skipped: - e = py.code.ExceptionInfo() - outcome = SerializableOutcome(skipped=e) - outcome.stdout, outcome.stderr = self.item._getouterr() + testrep.skipped = True + testrep._excinfo = py.code.ExceptionInfo() except (SystemExit, KeyboardInterrupt): raise - except: + except: e = sys.exc_info()[1] if isinstance(e, Failed) and e.excinfo: excinfo = e.excinfo @@ -50,85 +50,76 @@ code = py.code.Code(fun) excinfo.traceback = excinfo.traceback.cut( path=code.path, firstlineno=code.firstlineno) - outcome = SerializableOutcome(excinfo=excinfo, setupfailure=False) - outcome.stdout, outcome.stderr = self.item._getouterr() + testrep._excinfo = excinfo + testrep.failed = True if self.config.option.usepdb: - self.config.hub.notify( - repevent.ImmediateFailure(self.item, - ReprOutcome(outcome.make_repr(self.config.option.tbstyle)))) py.__.test2.custompdb.post_mortem(excinfo._excinfo[2]) # XXX hmm, we probably will not like to continue from that # point raise SystemExit() - return outcome - -class ApigenExecutor(RunExecutor): - """ Same as RunExecutor, but takes tracer to trace calls as - an argument to execute - """ - def execute(self, tracer): - self.tracer = tracer - return super(ApigenExecutor, self).execute() - - def wrap_underlaying(self, target, *args): - try: - self.tracer.start_tracing() - return target(*args) - finally: - self.tracer.end_tracing() - - def run(self, capture): - """ We want to trace *only* function objects here. Unsure - what to do with custom collectors at all - """ - if hasattr(self.item, 'obj') and type(self.item) is py.test2.collect.Function: - self.item.execute = self.wrap_underlaying - self.item.run() + else: + testrep.passed = True + return testrep class BoxExecutor(RunExecutor): """ Same as RunExecutor, but boxes test instead """ - wraps = True - + def fun(self): + testrep = RunExecutor.execute(self, capture=False) + return testrep.dumps() # XXX self.config.option.tbstyle + def execute(self): - def fun(): - outcome = RunExecutor.execute(self, False) - return outcome.make_repr(self.config.option.tbstyle) - b = Box(fun, config=self.config) + b = Box(self.fun, config=self.config) pid = b.run() assert pid + return self.maketestreport(b) + + def maketestreport(self, b): if b.retval is not None: - passed, setupfailure, excinfo, skipped, critical, _, _, _\ - = b.retval - return (passed, setupfailure, excinfo, skipped, critical, 0, - b.stdoutrepr, b.stderrrepr) + testrep = repevent.ItemTestReport.loads(b.retval) + testrep.stdout = b.stdoutrepr + testrep.stderr = b.stderrrepr else: - return (False, False, None, None, False, b.signal, - b.stdoutrepr, b.stderrrepr) + testrep = repevent.ItemTestReport(self.item._get_collector_trail()) + testrep.failed = True + testrep.stdout = b.stdoutrepr + testrep.stderr = b.stderrrepr + testrep.signal = b.signal + return testrep -class AsyncExecutor(RunExecutor): +class AsyncExecutor(BoxExecutor): """ same as box executor, but instead it returns function to continue computations (more async mode) """ - wraps = True - def execute(self): - def fun(): - outcome = RunExecutor.execute(self, False) - return outcome.make_repr(self.config.option.tbstyle) - - b = Box(fun, config=self.config) + b = Box(self.fun, config=self.config) parent, pid = b.run(continuation=True) - def cont(waiter=os.waitpid): parent(pid, waiter=waiter) - if b.retval is not None: - passed, setupfailure, excinfo, skipped,\ - critical, _, _, _ = b.retval - return (passed, setupfailure, excinfo, skipped, critical, 0, - b.stdoutrepr, b.stderrrepr) - else: - return (False, False, None, False, False, - b.signal, b.stdoutrepr, b.stderrrepr) - + return self.maketestreport(b) return cont, pid + +class ApigenExecutor(RunExecutor): + """ Same as RunExecutor, but takes tracer to trace calls as + an argument to execute + """ + def __init__(self, item, config, tracer): + super(ApigenExecutor, self).__init__(item, config) + self.tracer = tracer + + def run(self, capture): + # only trace Python Function items + if hasattr(self.item, 'obj') and isinstance(self.item, py.test2.collect.Function): + orig_exec = self.item.execute + def traced_exec(target, *args): + self.tracer.start_tracing() + try: + orig_exec(target, *args) + finally: + self.tracer.end_tracing() + self.item.execute = traced_exec + try: + super(ApigenExecutor, self).run(capture) + finally: + self.item.execute = orig_exec + Modified: py/branch/event/py/test2/outcome.py ============================================================================== --- py/branch/event/py/test2/outcome.py (original) +++ py/branch/event/py/test2/outcome.py Wed Feb 13 22:12:58 2008 @@ -31,7 +31,11 @@ class Skipped(Outcome): pass - +# XXX +# XXX +# XXX the below is not used but needs some porting +# XXX +# XXX class SerializableOutcome(object): def __init__(self, setupfailure=False, excinfo=None, skipped=None, is_critical=False): Modified: py/branch/event/py/test2/repevent.py ============================================================================== --- py/branch/event/py/test2/repevent.py (original) +++ py/branch/event/py/test2/repevent.py Wed Feb 13 22:12:58 2008 @@ -61,13 +61,35 @@ # Report of the run of a single test (might come from a disttributed run) # ---------------------------------------------------------------------- +import marshal + class ItemTestReport(BaseEvent): passed = failed = skipped = False - def __init__(self, trail, outcome, info=None): + def __init__(self, trail, outcome=None): self.trail = trail - assert outcome in ("passed", "failed", "skipped") - setattr(self, outcome, True) - self.info = info + if outcome is not None: + assert outcome in ("passed", "failed", "skipped") + setattr(self, outcome, True) + + def dumps(self): + """ marshal all possible attr to a string. """ + d = {} + for name, value in self.__dict__.items(): + try: + marshal.dumps(value) + except ValueError: + pass + else: + d[name] = value + return marshal.dumps(d) + + def loads(cls, string): + testrep = object.__new__(ItemTestReport) + d = marshal.loads(string) + assert isinstance(d, dict) + testrep.__dict__.update(d) + return testrep + loads = classmethod(loads) # ---------------------------------------------------------------------- # Distributed Testing Events Deleted: /py/branch/event/py/test2/rsession/local.py ============================================================================== --- /py/branch/event/py/test2/rsession/local.py Wed Feb 13 22:12:58 2008 +++ (empty file) @@ -1,69 +0,0 @@ -""" local-only operations -""" - -import py -from py.__.test2.executor import BoxExecutor, RunExecutor,\ - ApigenExecutor -from py.__.test2 import repevent -from py.__.test2.outcome import ReprOutcome - -# XXX copied from session.py -def startcapture(session): - if not session.config.option.nocapture: - session._capture = py.io.StdCapture() - -def finishcapture(session): - if hasattr(session, '_capture'): - capture = session._capture - del session._capture - return capture.reset() - return "", "" - -def box_runner(item, session, reporter): - r = BoxExecutor(item, config=session.config) - return ReprOutcome(r.execute()) - -def plain_runner(item, session, reporter): - r = RunExecutor(item, usepdb=session.config.option.usepdb, reporter=reporter, config=session.config) - outcome = r.execute() - outcome = ReprOutcome(outcome.make_repr(session.config.option.tbstyle)) - return outcome - -def benchmark_runner(item, session, reporter): - raise NotImplementedError() - -def apigen_runner(item, session, reporter): - #retval = plain_runner(item, session, reporter) - startcapture(session) - r = ApigenExecutor(item, reporter=reporter, config=session.config) - outcome = r.execute(session.tracer) - outcome = ReprOutcome(outcome.make_repr(session.config.option.tbstyle)) - outcome.stdout, outcome.stderr = finishcapture(session) - return outcome - -def exec_runner(item, session, reporter): - raise NotImplementedError() - -# runner interface is here to perform several different types of run -#+1. box_runner - for running normal boxed tests -#+2. plain_runner - for performing running without boxing (necessary for pdb) -# XXX: really? -#-3. exec_runner - for running under different interpreter -#-4. benchmark_runner - for running with benchmarking -#-5. apigen_runner - for running under apigen to generate api out of it. -def local_loop(session, reporter, itemgenerator, shouldstop, config, runner=None): - assert runner is not None - #if runner is None: - # if session.config.option.apigen: - # runner = apigen_runner - # else: - # runner = box_runner - while 1: - try: - item = itemgenerator.next() - if shouldstop(): - return - outcome = runner(item, session, reporter) - reporter(repevent.ItemFinish(None, item, outcome)) - except StopIteration: - break Modified: py/branch/event/py/test2/rsession/master.py ============================================================================== --- py/branch/event/py/test2/rsession/master.py (original) +++ py/branch/event/py/test2/rsession/master.py Wed Feb 13 22:12:58 2008 @@ -2,7 +2,6 @@ Node code for Master. """ import py -from py.__.test2.outcome import ReprOutcome from py.__.test2 import repevent class MasterNode(object): @@ -19,16 +18,8 @@ self.notify(repevent.HostDown(self.host)) return item = self.pending.pop() - repr_outcome = ReprOutcome(outcomestring) - # send finish report - # XXX the following should be done by outcome serializing - if repr_outcome.passed: - outcome = "passed" - elif repr_outcome.skipped: - outcome = "skipped" - else: - outcome = "failed" - self.notify(repevent.ItemTestReport(item, outcome)) + ev = repevent.ItemTestReport.loads(outcomestring) + self.notify(ev) def send(self, item): try: Modified: py/branch/event/py/test2/rsession/slave.py ============================================================================== --- py/branch/event/py/test2/rsession/slave.py (original) +++ py/branch/event/py/test2/rsession/slave.py Wed Feb 13 22:12:58 2008 @@ -4,58 +4,34 @@ import py from py.__.test2.executor import RunExecutor, BoxExecutor, AsyncExecutor -from py.__.test2.outcome import SerializableOutcome -from py.__.test2.outcome import Skipped +from py.__.test2 import repevent import os -class SlaveNode(object): - def __init__(self, config, executor): - self.config = config - self.executor = executor - - def execute(self, itemspec): - item = self.config._getcollector(itemspec) - ex = self.executor(item, config=self.config) - return ex.execute() - - def run(self, itemspec): - outcome = self.execute(itemspec) - if self.executor.wraps: - return outcome - else: - return outcome.make_repr(self.config.option.tbstyle) - def slave_main(receive, send, path, config): import os assert os.path.exists(path) path = os.path.abspath(path) - nodes = {} - def getnode(item): - node = nodes.get(item[0], None) - if node is not None: - return node - col = py.test2.collect.Directory(str(py.path.local(path).join(item[0]))) - if config.option.boxed: - executor = BoxExecutor - else: - executor = RunExecutor - node = nodes[item[0]] = SlaveNode(config, executor) - return node + if config.option.boxed: + Executor = BoxExecutor + else: + Executor = RunExecutor + while 1: - nextitem = receive() - if nextitem is None: + itemspec = receive() + if itemspec is None: send(None) break try: - node = getnode(nextitem) - res = node.run(nextitem) - except Skipped, s: - res = SerializableOutcome(skipped=str(s)).make_repr() + item = config._getcollector(itemspec) + ex = Executor(item, config) + res = ex.execute() except: # XXX consider bare except here excinfo = py.code.ExceptionInfo() - res = SerializableOutcome(excinfo=excinfo, is_critical=True).make_repr() - send(res) - + # XXX excinfo + res = repevent.ItemTestReport(itemspec) + res.failed = True + res.excinfo = str(excinfo) + send(res.dumps()) def setup(): # our current dir is the topdir Deleted: /py/branch/event/py/test2/rsession/testing/test_slave.py ============================================================================== --- /py/branch/event/py/test2/rsession/testing/test_slave.py Wed Feb 13 22:12:58 2008 +++ (empty file) @@ -1,73 +0,0 @@ - -""" Testing the slave side node code (in a local way). """ -from py.__.test2.rsession.slave import SlaveNode, slave_main, setup -from py.__.test2.outcome import ReprOutcome -import py, sys -from py.__.test2.rsession.testing.basetest import BasicRsessionTest - -modlevel = [] -import os - -if sys.platform == 'win32': - py.test.skip("rsession is unsupported on Windows.") - -# ---------------------------------------------------------------------- - -from py.__.test2.executor import RunExecutor - -class TestSlave(BasicRsessionTest): - def gettestnode(self): - node = SlaveNode(self.config, executor=RunExecutor) - return node - - def test_slave_run_passing(self): - node = self.gettestnode() - item = self.getfunc("passed") - outcome = node.execute(item._get_collector_trail()) - assert outcome.passed - assert not outcome.setupfailure - - ser = outcome.make_repr() - reproutcome = ReprOutcome(ser) - assert reproutcome.passed - assert not reproutcome.setupfailure - - def test_slave_run_failing(self): - node = self.gettestnode() - item = self.getfunc("failed") - outcome = node.execute(item._get_collector_trail()) - assert not outcome.passed - assert not outcome.setupfailure - assert len(outcome.excinfo.traceback) == 1 - assert outcome.excinfo.traceback[-1].frame.code.name == 'funcfailed' - - ser = outcome.make_repr() - reproutcome = ReprOutcome(ser) - assert not reproutcome.passed - assert not reproutcome.setupfailure - assert reproutcome.excinfo - - def test_slave_run_skipping(self): - node = self.gettestnode() - item = self.getfunc("skipped") - outcome = node.execute(item._get_collector_trail()) - assert not outcome.passed - assert outcome.skipped - - ser = outcome.make_repr() - reproutcome = ReprOutcome(ser) - assert not reproutcome.passed - assert reproutcome.skipped - - def test_slave_run_failing_wrapped(self): - node = self.gettestnode() - item = self.getfunc("failed") - repr_outcome = node.run(item._get_collector_trail()) - outcome = ReprOutcome(repr_outcome) - assert not outcome.passed - assert not outcome.setupfailure - assert outcome.excinfo - - def test_slave_run_different_stuff(self): - node = self.gettestnode() - node.run(self.getdocexample()) Modified: py/branch/event/py/test2/session.py ============================================================================== --- py/branch/event/py/test2/session.py (original) +++ py/branch/event/py/test2/session.py Wed Feb 13 22:12:58 2008 @@ -83,13 +83,20 @@ return failures def runtest(self, item): - if not self.config.option.boxed: - executor = RunExecutor(item, config=self.config) - outcome = ReprOutcome(executor.execute().make_repr()) - else: - executor = BoxExecutor(item, config=self.config) - outcome = ReprOutcome(executor.execute()) - self.config.hub.notify(repevent.ItemFinish(item, outcome.excinfo)) + cls = RunExecutor + if self.config.option.boxed: + cls = BoxExecutor + executor = cls(item, self.config) + testrep = executor.execute() + excinfo = None + if testrep.failed: + # XXX excinfo + try: + raise ValueError + except ValueError: + excinfo = py.code.ExceptionInfo() + self.config.hub.notify(repevent.ItemFinish(item, excinfo)) + self.config.hub.notify(testrep) class Exit(Exception): """ for immediate program exits without tracebacks and reporter/summary. """ Modified: py/branch/event/py/test2/testing/setupdata.py ============================================================================== --- py/branch/event/py/test2/testing/setupdata.py (original) +++ py/branch/event/py/test2/testing/setupdata.py Wed Feb 13 22:12:58 2008 @@ -12,6 +12,7 @@ def getexamplefile(basename): datadir = py.test2.ensuretemp("example") + datadir.ensure("__init__.py") path = datadir.join(basename) if not path.check(): path.write(namecontent[basename]) @@ -126,10 +127,19 @@ def funcprint(): print "samfing" + def funcprinterr(): + print >>py.std.sys.stderr, "samfing" + def funcprintfail(): print "samfing elz" asddsa + def funcexplicitfail(): + py.test2.fail("3") + + def funcraisesfails(): + py.test2.raises(ValueError, lambda: 123) + def funcoptioncustom(): assert py.test2.config.getvalue("custom") Modified: py/branch/event/py/test2/testing/test_executor.py ============================================================================== --- py/branch/event/py/test2/testing/test_executor.py (original) +++ py/branch/event/py/test2/testing/test_executor.py Wed Feb 13 22:12:58 2008 @@ -11,112 +11,84 @@ if py.std.sys.platform == "win32": py.test.skip("skipping executor tests (some require os.fork)") -class Item(py.test2.collect.Item): - def __init__(self, name, config): - super(Item, self).__init__(name) - self._config = config - -class ItemTestPassing(Item): - def run(self): - return None - -class ItemTestFailing(Item): - def run(self): - assert 0 == 1 - -class ItemTestSkipping(Item): - def run(self): - py.test2.skip("hello") - -class ItemTestPrinting(Item): - def run(self): - print "hello" - -class ItemTestFailingExplicit(Item): - def run(self): - raise Failed(excinfo="3") - -class ItemTestFailingExplicitEmpty(Item): - def run(self): - py.test2.raises(ValueError, lambda : 123) - class TestExecutor(BasicRsessionTest): + Executor = RunExecutor + + def getexecutor(self, examplename): + funcitem = self.getfunc(examplename) + return self.Executor(funcitem, self.config) + + def exrun(self, examplename): + ex = self.getexecutor(examplename) + return ex.execute() + def test_run_executor(self): - ex = RunExecutor(ItemTestPassing("pass", self.config), config=self.config) - outcome = ex.execute() - assert outcome.passed - - ex = RunExecutor(ItemTestFailing("fail", self.config), config=self.config) - outcome = ex.execute() - assert not outcome.passed - - ex = RunExecutor(ItemTestSkipping("skip", self.config), config=self.config) - outcome = ex.execute() - assert outcome.skipped - assert not outcome.passed - assert not outcome.excinfo - - def test_run_executor_capture(self): - ex = RunExecutor(ItemTestPrinting("print", self.config), config=self.config) - outcome = ex.execute() - assert outcome.stdout == "hello\n" - - def test_box_executor(self): - ex = BoxExecutor(ItemTestPassing("pass", self.config), config=self.config) - outcome_repr = ex.execute() - outcome = ReprOutcome(outcome_repr) - assert outcome.passed - - ex = BoxExecutor(ItemTestFailing("fail", self.config), config=self.config) - outcome_repr = ex.execute() - outcome = ReprOutcome(outcome_repr) - assert not outcome.passed - - ex = BoxExecutor(ItemTestSkipping("skip", self.config), config=self.config) - outcome_repr = ex.execute() - outcome = ReprOutcome(outcome_repr) - assert outcome.skipped - assert not outcome.passed - assert not outcome.excinfo - - def test_box_executor_stdout(self): - item = self.getfunc("print") - ex = BoxExecutor(item, config=self.config) - outcome_repr = ex.execute() - outcome = ReprOutcome(outcome_repr) - assert outcome.passed - assert outcome.stdout.find("samfing") != -1 - - def test_box_executor_stdout_error(self): - item = self.getfunc("printfail") - ex = BoxExecutor(item, config=self.config) - outcome_repr = ex.execute() - outcome = ReprOutcome(outcome_repr) - assert not outcome.passed - assert outcome.stdout.find("samfing elz") != -1 - - def test_cont_executor(self): - item = self.getfunc("printfail") - ex = AsyncExecutor(item, config=self.config) + testrep = self.exrun("passed") + assert testrep.passed + + for name in 'failed', 'skipped': + testrep = self.exrun(name) + assert getattr(testrep, name) + assert not hasattr(testrep, 'signal') + #assert testrep._excinfo + + def test_run_executor_capture_stdout(self): + testrep = self.exrun("print") + assert testrep.stdout == "samfing\n" + assert not testrep.stderr + + def test_run_executor_capture_stderr(self): + testrep = self.exrun("printerr") + assert testrep.stderr == "samfing\n" + assert not testrep.stdout + + def test_box_executor_printfailing(self): + testrep = self.exrun("printfail") + assert not testrep.passed + assert testrep.failed + assert testrep.stdout.find("samfing elz") != -1 + assert not testrep.stderr + + def test_executor_explicit_Failed(self): + testrep = self.exrun("explicitfail") + assert not testrep.passed + assert testrep.failed + #assert testrep._excinfo == "3" + + def test_executor_raises_fails(self): + testrep = self.exrun("raisesfails") + assert testrep.failed + +class TestBoxExecutor(TestExecutor): + Executor = BoxExecutor + +class TestAsyncExecutor(TestExecutor): + Executor = AsyncExecutor + def exrun(self, examplename): + ex = self.getexecutor(examplename) cont, pid = ex.execute() - assert pid - outcome_repr = cont() - outcome = ReprOutcome(outcome_repr) - assert not outcome.passed - assert outcome.stdout.find("samfing elz") != -1 - - def test_apigen_executor(self): - class Tracer(object): - def __init__(self): - self.starts = 0 - self.ends = 0 - - def start_tracing(self): - self.starts += 1 + testrep = cont() + return testrep - def end_tracing(self): - self.ends += 1 +class TestApigenExecutor(TestExecutor): + Executor = ApigenExecutor + + class Tracer(object): + def __init__(self): + self.starts = 0 + self.ends = 0 + def start_tracing(self): + self.starts += 1 + + def end_tracing(self): + self.ends += 1 + + def getexecutor(self, examplename, Tracer=Tracer): + funcitem = self.getfunc(examplename) + return self.Executor(funcitem, self.config, tracer=Tracer()) + + def test_apigen_executor_tracing_hook(self): tmpdir = py.test2.ensuretemp("apigen_executor") tmpdir.ensure("__init__.py") tmpdir.ensure("test_one.py").write(py.code.Source(""" @@ -138,33 +110,19 @@ """)) config = py.test2.config._reparse([tmpdir]) rootcol = config._getcollector(tmpdir) - tracer = Tracer() + tracer = self.Tracer() item = rootcol._getitembynames("test_one.py/test_1") - ex = ApigenExecutor(item, config=config) - out1 = ex.execute(tracer) + ex = ApigenExecutor(item, config, tracer) + out1 = ex.execute() item = rootcol._getitembynames("test_one.py/TestX/()/test_one") - ex = ApigenExecutor(item, config=config) - out2 = ex.execute(tracer) + ex = ApigenExecutor(item, config, tracer) + out2 = ex.execute() item = rootcol._getitembynames("test_one.py/TestX/()/test_raise") - ex = ApigenExecutor(item, config=config) - out3 = ex.execute(tracer) + ex = ApigenExecutor(item, config, tracer) + out3 = ex.execute() assert tracer.starts == 3 assert tracer.ends == 3 assert out1.passed assert out2.passed assert not out3.passed - def test_executor_explicit_Failed(self): - ex = RunExecutor(ItemTestFailingExplicit("failex", self.config), - config=self.config) - - outcome = ex.execute() - assert not outcome.passed - assert outcome.excinfo == "3" - - def test_executor_explicit_Faile_no_excinfo(self): - ex = RunExecutor(ItemTestFailingExplicitEmpty("failexx", self.config), - config=self.config) - outcome = ex.execute() - assert not outcome.passed - Modified: py/branch/event/py/test2/testing/test_outcome.py ============================================================================== --- py/branch/event/py/test2/testing/test_outcome.py (original) +++ py/branch/event/py/test2/testing/test_outcome.py Wed Feb 13 22:12:58 2008 @@ -5,11 +5,6 @@ import marshal import py -def test_critical_debugging_flag(): - outcome = SerializableOutcome(is_critical=True) - r = ReprOutcome(outcome.make_repr()) - assert r.is_critical - def f1(): 1 2 @@ -27,6 +22,7 @@ py.test.skip("argh!") def test_exception_info_repr(): + py.test.skip("exception infos need fixing") try: f3() except: @@ -50,34 +46,16 @@ assert excinfo.traceback[1].lineno == f3.func_code.co_firstlineno assert excinfo.traceback[1].relline == 1 -def test_packed_skipped(): - try: - f4() - except: - outcome = SerializableOutcome(skipped=py.code.ExceptionInfo()) - repr = outcome.make_excinfo_repr(outcome.skipped, "long") - assert marshal.dumps(repr) - skipped = ExcInfoRepr(repr) - assert skipped.value == "'argh!'" - -#def test_f3(): -# f3() - -def test_outcome_repr(): - out = ReprOutcome(SerializableOutcome(skipped="xxx").make_repr()) - s = repr(out) - assert s.lower().find("skip") != -1 - class TestRaises: def test_raises(self): - py.test.raises(ValueError, "int('qwe')") + py.test2.raises(ValueError, "int('qwe')") def test_raises_exec(self): - py.test.raises(ValueError, "a,x = []") + py.test2.raises(ValueError, "a,x = []") def test_raises_syntax_error(self): - py.test.raises(SyntaxError, "qwe qwe qwe") + py.test2.raises(SyntaxError, "qwe qwe qwe") def test_raises_function(self): - py.test.raises(ValueError, int, 'hello') + py.test2.raises(ValueError, int, 'hello') From hpk at codespeak.net Thu Feb 14 08:44:23 2008 From: hpk at codespeak.net (hpk at codespeak.net) Date: Thu, 14 Feb 2008 08:44:23 +0100 (CET) Subject: [py-svn] r51470 - py/branch/guido-svn-auth/py/path/svn Message-ID: <20080214074423.F359F168411@codespeak.net> Author: hpk Date: Thu Feb 14 08:44:21 2008 New Revision: 51470 Modified: py/branch/guido-svn-auth/py/path/svn/wccommand.py Log: remove redundancy in svn auth handling Modified: py/branch/guido-svn-auth/py/path/svn/wccommand.py ============================================================================== --- py/branch/guido-svn-auth/py/path/svn/wccommand.py (original) +++ py/branch/guido-svn-auth/py/path/svn/wccommand.py Thu Feb 14 08:44:21 2008 @@ -71,6 +71,18 @@ def __str__(self): return str(self.localpath) + def _makeauthoptions(self, auth): + if auth is None: + auth = self._auth + if auth is None: + return '' + return str(auth) + + def _authsvn(self, cmd, args=None, auth=None): + args = args and list(args) or [] + args.append(self._makeauthoptions(auth)) + return self._svn(cmd, *args) + def _svn(self, cmd, *args): l = ['svn %s' % cmd] args = [self._escape(item) for item in args] @@ -104,12 +116,7 @@ def switch(self, url, auth=None): """ switch to given URL. """ - args = [] - if auth is not None: - args.append(str(auth)) - elif self._auth is not None: - args.append(str(self._auth)) - self._svn('switch', url, *args) + self._authsvn('switch', url, [], auth=auth) def checkout(self, url=None, rev=None, auth=None): """ checkout from url to local wcpath. """ @@ -125,20 +132,12 @@ url += "@%d" % rev else: args.append('-r' + str(rev)) - if auth is not None: - args.append(str(auth)) - elif self._auth is not None: - args.append(str(self._auth)) - self._svn('co', url, *args) + args.append(url) + self._authsvn('co', args, auth=auth) def update(self, rev = 'HEAD', auth=None): """ update working copy item to given revision. (None -> HEAD). """ - args = [] - if auth is not None: - args.append(str(auth)) - elif self._auth is not None: - args.append(str(self._auth)) - self._svn('up -r %s' % rev, *args) + self._authsvn('up', ['-r', rev], auth=auth) def write(self, content, mode='wb'): """ write content into local filesystem wc. """ @@ -216,24 +215,14 @@ def lock(self, auth=None): """ set a lock (exclusive) on the resource """ - args = [] - if auth is not None: - args.append(str(auth)) - elif self._auth is not None: - args.append(str(self._auth)) - out = self._svn('lock', *args).strip() + out = self._authsvn('lock', auth=auth).strip() if not out: # warning or error, raise exception raise Exception(out[4:]) def unlock(self, auth=None): """ unset a previously set lock """ - args = [] - if auth is not None: - args.append(str(auth)) - elif self._auth is not None: - args.append(str(self._auth)) - out = self._svn('unlock', *args).strip() + out = self._authsvn('unlock', auth=auth).strip() if out.startswith('svn:'): # warning or error, raise exception raise Exception(out[4:]) @@ -359,15 +348,10 @@ """ return a diff of the current path against revision rev (defaulting to the last one). """ - if rev is None: - out = self._svn('diff') - else: - args = [] - if auth is not None: - args.append(str(auth)) - elif self._auth is not None: - args.append(str(self._auth)) - out = self._svn('diff -r %d' % rev, *args) + args = [] + if rev is not None: + args.append("-r %d" % rev) + out = self._authsvn('diff', args, auth=auth) return out def blame(self): @@ -395,12 +379,7 @@ cmd = 'commit -m "%s" --force-log' % (msg.replace('"', '\\"'),) if not rec: cmd += ' -N' - args = [] - if auth is not None: - args.append(str(auth)) - elif self._auth is not None: - args.append(str(self._auth)) - out = self._svn(cmd, *args) + out = self._authsvn(cmd, auth=auth) try: del cache.info[self] except KeyError: @@ -571,14 +550,7 @@ verbose_opt = verbose and "-v" or "" locale_env = svncommon.fixlocale() # some blather on stderr - auth_opt = '' - if auth is not None: - auth_opt = '%s' % (auth,) - elif self._auth is not None: - auth_opt = '%s' % (self._auth,) - auth_opt = ((auth is not None and str(auth)) or - (self._auth is not None and str(self._auth)) or - '') + auth_opt = self._makeauthargs(auth) stdin, stdout, stderr = os.popen3(locale_env + 'svn log --xml %s %s %s "%s"' % ( rev_opt, verbose_opt, auth_opt, From hpk at codespeak.net Thu Feb 14 08:44:46 2008 From: hpk at codespeak.net (hpk at codespeak.net) Date: Thu, 14 Feb 2008 08:44:46 +0100 (CET) Subject: [py-svn] r51471 - in py/branch/guido-svn-auth/py: . path/svn Message-ID: <20080214074446.65516168411@codespeak.net> Author: hpk Date: Thu Feb 14 08:44:45 2008 New Revision: 51471 Removed: py/branch/guido-svn-auth/py/path/svn/auth.py Modified: py/branch/guido-svn-auth/py/__init__.py py/branch/guido-svn-auth/py/path/svn/svncommon.py Log: put SvnAuth helper to existing file instead of small new one Modified: py/branch/guido-svn-auth/py/__init__.py ============================================================================== --- py/branch/guido-svn-auth/py/__init__.py (original) +++ py/branch/guido-svn-auth/py/__init__.py Thu Feb 14 08:44:45 2008 @@ -67,7 +67,7 @@ 'path.svnwc' : ('./path/svn/wccommand.py', 'SvnWCCommandPath'), 'path.svnurl' : ('./path/svn/urlcommand.py', 'SvnCommandPath'), 'path.local' : ('./path/local/local.py', 'LocalPath'), - 'path.SvnAuth' : ('./path/svn/auth.py', 'SvnAuth'), + 'path.SvnAuth' : ('./path/svn/svncommon.py', 'SvnAuth'), # some nice slightly magic APIs 'magic.__doc__' : ('./magic/__init__.py', '__doc__'), Deleted: /py/branch/guido-svn-auth/py/path/svn/auth.py ============================================================================== --- /py/branch/guido-svn-auth/py/path/svn/auth.py Thu Feb 14 08:44:45 2008 +++ (empty file) @@ -1,14 +0,0 @@ -class SvnAuth(object): - """ container for auth information for Subversion """ - def __init__(self, username, password, auth_cache=True): - self.username = username - self.password = password - self.auth_cache = auth_cache - - def __str__(self): - uname = self.username.replace('"', '\\"') - passwd = self.password.replace('"', '\\"') - ret = '--username="%s" --password="%s"' % (uname, passwd) - if not self.auth_cache: - ret += ' --no-auth-cache' - return ret Modified: py/branch/guido-svn-auth/py/path/svn/svncommon.py ============================================================================== --- py/branch/guido-svn-auth/py/path/svn/svncommon.py (original) +++ py/branch/guido-svn-auth/py/path/svn/svncommon.py Thu Feb 14 08:44:45 2008 @@ -330,3 +330,18 @@ fspath = '%s at HEAD' % (fspath,) return 'file://%s' % (fspath,) + +class SvnAuth(object): + """ container for auth information for Subversion """ + def __init__(self, username, password, auth_cache=True): + self.username = username + self.password = password + self.auth_cache = auth_cache + + def __str__(self): + uname = self.username.replace('"', '\\"') + passwd = self.password.replace('"', '\\"') + ret = '--username="%s" --password="%s"' % (uname, passwd) + if not self.auth_cache: + ret += ' --no-auth-cache' + return ret From hpk at codespeak.net Thu Feb 14 08:51:48 2008 From: hpk at codespeak.net (hpk at codespeak.net) Date: Thu, 14 Feb 2008 08:51:48 +0100 (CET) Subject: [py-svn] r51472 - in py/branch/guido-svn-auth/py/path/svn: . testing Message-ID: <20080214075148.305C0168418@codespeak.net> Author: hpk Date: Thu Feb 14 08:51:47 2008 New Revision: 51472 Modified: py/branch/guido-svn-auth/py/path/svn/svncommon.py py/branch/guido-svn-auth/py/path/svn/testing/test_auth.py py/branch/guido-svn-auth/py/path/svn/wccommand.py Log: introduce explicit makecmdlineoptions instead of using str() for producing auth cmdline options Modified: py/branch/guido-svn-auth/py/path/svn/svncommon.py ============================================================================== --- py/branch/guido-svn-auth/py/path/svn/svncommon.py (original) +++ py/branch/guido-svn-auth/py/path/svn/svncommon.py Thu Feb 14 08:51:47 2008 @@ -338,10 +338,13 @@ self.password = password self.auth_cache = auth_cache - def __str__(self): + def makecmdoptions(self): uname = self.username.replace('"', '\\"') passwd = self.password.replace('"', '\\"') ret = '--username="%s" --password="%s"' % (uname, passwd) if not self.auth_cache: ret += ' --no-auth-cache' return ret + + def __str__(self): + return "" %(self.username,) Modified: py/branch/guido-svn-auth/py/path/svn/testing/test_auth.py ============================================================================== --- py/branch/guido-svn-auth/py/path/svn/testing/test_auth.py (original) +++ py/branch/guido-svn-auth/py/path/svn/testing/test_auth.py Thu Feb 14 08:51:47 2008 @@ -2,22 +2,23 @@ from py.path import SvnAuth class TestSvnAuth(object): - def test_uname_pw(self): + def test_basic(self): auth = py.path.SvnAuth('foo', 'bar') assert auth.username == 'foo' assert auth.password == 'bar' + assert str(auth) - def test_uname_pw_str(self): + def test_makecmdoptions_uname_pw_makestr(self): auth = py.path.SvnAuth('foo', 'bar') - assert str(auth) == '--username="foo" --password="bar"' + assert auth.makecmdoptions() == '--username="foo" --password="bar"' - def test_quote_escape(self): + def test_makecmdoptions_quote_escape(self): auth = py.path.SvnAuth('fo"o', '"ba\'r"') - assert str(auth) == '--username="fo\\"o" --password="\\"ba\'r\\""' + assert auth.makecmdoptions() == '--username="fo\\"o" --password="\\"ba\'r\\""' - def test_no_auth_cache(self): + def test_makecmdoptions_no_auth_cache(self): auth = py.path.SvnAuth('foo', 'bar', auth_cache=False) - assert str(auth) == '--username="foo" --password="bar" --no-auth-cache' + assert auth.makecmdoptions() == '--username="foo" --password="bar" --no-auth-cache' class svnwc_no_svn(py.path.svnwc): def __init__(self, *args, **kwargs): Modified: py/branch/guido-svn-auth/py/path/svn/wccommand.py ============================================================================== --- py/branch/guido-svn-auth/py/path/svn/wccommand.py (original) +++ py/branch/guido-svn-auth/py/path/svn/wccommand.py Thu Feb 14 08:51:47 2008 @@ -76,7 +76,7 @@ auth = self._auth if auth is None: return '' - return str(auth) + return auth.makecmdoptions() def _authsvn(self, cmd, args=None, auth=None): args = args and list(args) or [] From hpk at codespeak.net Thu Feb 14 11:15:10 2008 From: hpk at codespeak.net (hpk at codespeak.net) Date: Thu, 14 Feb 2008 11:15:10 +0100 (CET) Subject: [py-svn] r51481 - in py/branch/event/py/test2: . testing Message-ID: <20080214101510.EDE65168407@codespeak.net> Author: hpk Date: Thu Feb 14 11:15:10 2008 New Revision: 51481 Added: py/branch/event/py/test2/testing/test_repevent.py Modified: py/branch/event/py/test2/collect.py py/branch/event/py/test2/config.py py/branch/event/py/test2/repevent.py py/branch/event/py/test2/representation.py py/branch/event/py/test2/testing/setupdata.py py/branch/event/py/test2/testing/suptest.py py/branch/event/py/test2/testing/test_repr.py py/branch/event/py/test2/testing/test_session.py Log: * (intermediate) beginning to get marshallable TestReport, added tests * factoring out getmodpath(colitem), added tests * simplified test example creation Modified: py/branch/event/py/test2/collect.py ============================================================================== --- py/branch/event/py/test2/collect.py (original) +++ py/branch/event/py/test2/collect.py Thu Feb 14 11:15:10 2008 @@ -147,29 +147,18 @@ for name in namelist: if name: next = cur.join(name) - assert next is not None, (cur, name, namelist) + if next is None: + existingnames = cur.run() + msg = ("Collector %r does not have name %r " + "existing names are: %s" % + (cur, name, existingnames)) + raise AssertionError(msg) cur = next return cur def _keywords(self): return [self.name] - def _getmodpath(self): - """ return dotted module path (relative to the containing). """ - inmodule = False - newl = [] - for x in self.listchain(): - if not inmodule and not isinstance(x, Module): - continue - if not inmodule: - inmodule = True - continue - if newl and x.name[:1] in '([': - newl[-1] += x.name - else: - newl.append(x.name) - return ".".join(newl) - def _skipbykeyword(self, keywordexpr): """ return True if they given keyword expression means to skip this collector/item. Modified: py/branch/event/py/test2/config.py ============================================================================== --- py/branch/event/py/test2/config.py (original) +++ py/branch/event/py/test2/config.py Thu Feb 14 11:15:10 2008 @@ -237,7 +237,7 @@ if chain[0].fspath == self.topdir: relpath = "." else: - raise ValueError("%r not relative to %s" + raise ValueError("%r not relative to topdir %s" %(chain[0], self.topdir)) return relpath, tuple([x.name for x in chain[1:]]) Modified: py/branch/event/py/test2/repevent.py ============================================================================== --- py/branch/event/py/test2/repevent.py (original) +++ py/branch/event/py/test2/repevent.py Thu Feb 14 11:15:10 2008 @@ -71,6 +71,12 @@ assert outcome in ("passed", "failed", "skipped") setattr(self, outcome, True) + def dottedpath(self, config): + """ return dotted path for underlying test item. """ + from py.__.test2.representation import getmodpath + col = config._getcollector(self.trail) + return getmodpath(col) + def dumps(self): """ marshal all possible attr to a string. """ d = {} Modified: py/branch/event/py/test2/representation.py ============================================================================== --- py/branch/event/py/test2/representation.py (original) +++ py/branch/event/py/test2/representation.py Thu Feb 14 11:15:10 2008 @@ -19,6 +19,21 @@ target = dest.sep.join(('..', )*n + (reldest, )) return target +def getmodpath(pycolitem): + """ return dotted module path for the given colitem. """ + colitems = pycolitem.listchain() + while colitems: + colitem = colitems.pop(0) + if isinstance(colitem, colitem.Module): + parts = [colitem.obj.__name__] + for colitem in colitems: + if colitem.name[0] in '([': + parts[-1] += colitem.name + else: + parts.append(colitem.name) + return ".".join(parts) + return colitem.name + class Presenter(object): """ Class used for presentation of various objects, sharing common output style Modified: py/branch/event/py/test2/testing/setupdata.py ============================================================================== --- py/branch/event/py/test2/testing/setupdata.py (original) +++ py/branch/event/py/test2/testing/setupdata.py Thu Feb 14 11:15:10 2008 @@ -10,19 +10,26 @@ # getexamplefile(name) # return datadir -def getexamplefile(basename): - datadir = py.test2.ensuretemp("example") - datadir.ensure("__init__.py") - path = datadir.join(basename) +def getexamplefile(basename, tmpdir=None): + if tmpdir is None: + tmpdir = py.test2.ensuretemp("example") + tmpdir.ensure("__init__.py") + path = tmpdir.join(basename) if not path.check(): - path.write(namecontent[basename]) + path.write(py.code.Source(namecontent[basename])) print "creating testfile", path return path +def getexamplecollector(names, tmpdir=None): + fn = getexamplefile(names[0], tmpdir=tmpdir) + config = py.test2.config._reparse([fn.dirpath()]) + col = config._getcollector(fn) + return col._getitembynames(names[1:]) + namecontent = { 'syntax_error.py': "this is really not python\n", - 'disabled_module.py': py.code.Source(''' + 'disabled_module.py': ''' disabled = True def setup_module(mod): @@ -37,9 +44,9 @@ raise ValueError def test_func(self): raise ValueError - '''), + ''', - 'brokenrepr.py': py.code.Source(''' + 'brokenrepr.py': ''' import py class BrokenRepr1: @@ -70,15 +77,21 @@ def test_implicit_bad_repr2(self): t = BrokenRepr2() assert t.foo == 1 - '''), - - 'failingimport.py': py.code.Source(''' + ''', - import gruetzelmuetzel + 'failingimport.py': "import gruetzelmuetzel\n", - '''), + 'mod.py': """ + class TestA: + def test_m1(self): + pass + def test_f1(): + pass + def test_g1(): + yield lambda x: None, 42 + """, - 'filetest.py': py.code.Source(''' + 'filetest.py': """ def test_one(): assert 42 == 43 @@ -86,9 +99,9 @@ def test_method_one(self): assert 42 == 43 - '''), + """, - 'test_threepass.py': py.code.Source(''' + 'test_threepass.py': """ def test_one(): assert 1 @@ -97,22 +110,22 @@ def test_three(): assert 1 - '''), + """, - 'testspecial_importerror.py': py.code.Source(''' + 'testspecial_importerror.py': """ import asdasd - '''), + """, - 'disabled.py': py.code.Source(''' + 'disabled.py': """ class TestDisabled: disabled = True def test_method(self): pass - '''), + """, - 'funcexamples.py': py.code.Source(''' + 'funcexamples.py': """ import py import time def funcpassed(): @@ -146,9 +159,9 @@ def funchang(): import time time.sleep(1000) - '''), + """, - 'test_generative.py': py.code.Source(""" + 'test_generative.py': """ from __future__ import generators # python2.2! def func1(arg, arg2): assert arg == arg2 @@ -161,13 +174,12 @@ def test_gen(self): yield func1, 17, 3*5 yield func1, 42, 6*7 - """), + """, - 'docexample.txt': py.code.Source(""" + 'docexample.txt': """ Aha!!!!!! ========= - - """), + """, } Modified: py/branch/event/py/test2/testing/suptest.py ============================================================================== --- py/branch/event/py/test2/testing/suptest.py (original) +++ py/branch/event/py/test2/testing/suptest.py Thu Feb 14 11:15:10 2008 @@ -47,6 +47,7 @@ class EventSorter(object): def __init__(self, config, session=None): + self.config = config self.session = session self.cls2events = d = {} def app(event): @@ -63,7 +64,7 @@ passed = [] skipped = [] failed = [] - for ev in self.get(repevent.ItemFinish): + for ev in self.get(repevent.ItemTestReport): if ev.passed: passed.append(ev) elif ev.skipped: Added: py/branch/event/py/test2/testing/test_repevent.py ============================================================================== --- (empty file) +++ py/branch/event/py/test2/testing/test_repevent.py Thu Feb 14 11:15:10 2008 @@ -0,0 +1,38 @@ + +from py.__.test2 import repevent +import setupdata, suptest + +class TestItemTestReport(object): + def _makevent(self, names, **kwargs): + fcol = setupdata.getexamplecollector(names) + trail = fcol._get_collector_trail() + ev = repevent.ItemTestReport(trail, **kwargs) + ev._col = fcol + return ev + + def test_dumps_loads(self): + ev = self._makevent(["filetest.py", 'test_one'], outcome="skipped") + ev.whatever = 42 + class A: pass + ev.a = A() + assert ev.skipped + s = ev.dumps() + ev2 = repevent.ItemTestReport.loads(s) + assert ev2.skipped + assert ev2.trail == ev.trail + assert ev2.dottedpath(ev._col._config).endswith("filetest.test_one") + assert ev2.whatever == 42 + assert not hasattr(ev2, 'a') + + def test_ItemTestReport(self): + ev = self._makevent(["filetest.py", 'test_one'], outcome="passed") + assert ev.dottedpath(ev._col._config).endswith("filetest.test_one") + + def test_failing(self): + sorter = suptest.events_run_example("filetest.py") + reports = sorter.get(repevent.ItemTestReport) + ev = reports[0] + assert ev.failed + assert ev.exconly.find("AssertionError") != -1 + + Modified: py/branch/event/py/test2/testing/test_repr.py ============================================================================== --- py/branch/event/py/test2/testing/test_repr.py (original) +++ py/branch/event/py/test2/testing/test_repr.py Thu Feb 14 11:15:10 2008 @@ -1,10 +1,34 @@ import py -from py.__.test2.representation import Presenter +from py.__.test2.representation import Presenter, getmodpath from py.__.test2.terminal.out import getout from StringIO import StringIO +import setupdata import sys +def test_getmodpath_cases(): + tmpdir = py.test.ensuretemp("test_getmodpath_cases") + pkgdir = tmpdir.join("pkg") + pkgdir.ensure("__init__.py") + nopkgdir = tmpdir.ensure("nopkg", dir=1) + def checkpkg(names, expected): + fcol = setupdata.getexamplecollector(names, tmpdir=pkgdir) + assert getmodpath(fcol) == pkgdir.basename + "." + expected + def checknopkg(names, expected): + fcol = setupdata.getexamplecollector(names, tmpdir=nopkgdir) + assert getmodpath(fcol) == expected + + for names in ( + 'mod.py test_f1 mod.test_f1', + 'mod.py TestA () test_m1 mod.TestA().test_m1', + 'mod.py test_g1 mod.test_g1', + 'mod.py test_g1 [0] mod.test_g1[0]', + ): + names = names.split() + expected = names.pop() + yield checkpkg, names, expected + yield checknopkg, names, expected + def newconfig(*args): tmpdir = py.test2.ensuretemp("newconfig") args = list(args) Modified: py/branch/event/py/test2/testing/test_session.py ============================================================================== --- py/branch/event/py/test2/testing/test_session.py (original) +++ py/branch/event/py/test2/testing/test_session.py Thu Feb 14 11:15:10 2008 @@ -12,7 +12,7 @@ '-s', '-k', keyword) passed, skipped, failed = sorter.listoutcomes() assert len(failed) == 1 - assert failed[0].item.name == name + assert failed[0].dottedpath(sorter.config).endswith(name) des = sorter.get(repevent.DeselectedTest) assert len(des) == 1 @@ -41,7 +41,7 @@ print "keyword", repr(keyword) passed, skipped, failed = sorter.listoutcomes() assert len(passed) == 1 - assert passed[0].item.name == 'test_2' + assert passed[0].dottedpath(sorter.config).endswith('test_2') assert not skipped deslist = sorter.get(repevent.DeselectedTest) assert len(deslist) == 1 @@ -105,20 +105,19 @@ import py class Function(py.test2.collect.Function): def startcapture(self): - self._mycapture = None + self._mycapture = True def finishcapture(self): - self._testmycapture = None + self._testmycapture = True """)) sorter = suptest.events_from_cmdline([tfile.dirpath()]) passed, skipped, failed = sorter.listoutcomes() assert len(passed) == 1 assert len(failed) == 1 - assert hasattr(passed[0].item, '_mycapture') - assert hasattr(passed[0].item, '_testmycapture') - assert hasattr(failed[0].item, '_mycapture') - assert hasattr(failed[0].item, '_testmycapture') + for ev in sorter.get(repevent.ItemFinish): + assert ev.item._mycapture + assert ev.item._testmycapture def test_raises_output(self): p = suptest.makeuniquepyfile(''' @@ -129,7 +128,7 @@ sorter = suptest.events_from_cmdline([p]) passed, skipped, failed = sorter.listoutcomes() assert len(failed) == 1 - out = failed[0].excinfo.exconly() + out = failed[0].exconly if not out.find("DID NOT RAISE") != -1: print out py.test2.fail("incorrect raises() output") From hpk at codespeak.net Thu Feb 14 11:27:39 2008 From: hpk at codespeak.net (hpk at codespeak.net) Date: Thu, 14 Feb 2008 11:27:39 +0100 (CET) Subject: [py-svn] r51482 - in py/branch/event/py: . event test2 test2/rsession test2/rsession/testing test2/testing Message-ID: <20080214102739.AB5F816840B@codespeak.net> Author: hpk Date: Thu Feb 14 11:27:39 2008 New Revision: 51482 Added: py/branch/event/py/test2/eventbus.py - copied, changed from r51469, py/branch/event/py/event/hub.py py/branch/event/py/test2/testing/test_eventbus.py - copied, changed from r51469, py/branch/event/py/event/testing/test_hub.py Removed: py/branch/event/py/event/ Modified: py/branch/event/py/__init__.py py/branch/event/py/test2/config.py py/branch/event/py/test2/genitem.py py/branch/event/py/test2/rsession/hostmanage.py py/branch/event/py/test2/rsession/master.py py/branch/event/py/test2/rsession/testing/test_masterslave.py py/branch/event/py/test2/rsession/testing/test_rsession.py py/branch/event/py/test2/session.py py/branch/event/py/test2/testing/suptest.py Log: removed py.event global namespace and and usin a test2-local EventBus for now. subscriptions work like this: bus.subscribe(callback) bus.unsubscribe(callback) and notifications like this: bus.notify(event) where event can be any object. Modified: py/branch/event/py/__init__.py ============================================================================== --- py/branch/event/py/__init__.py (original) +++ py/branch/event/py/__init__.py Thu Feb 14 11:27:39 2008 @@ -68,11 +68,6 @@ 'test.collect.Function' : ('./test/item.py', 'Function'), 'test2.collect.Function' : ('./test2/item.py', 'Function'), - # Event related APIs - 'event.Hub' : ('./event/hub.py', 'Hub'), - #'event.hub' : ('./event/hub.py', 'hub'), - #'event.notify' : ('./event/hub.py', 'notify'), - # thread related API (still in early design phase) '_thread.WorkerPool' : ('./thread/pool.py', 'WorkerPool'), '_thread.NamedThreadPool' : ('./thread/pool.py', 'NamedThreadPool'), Modified: py/branch/event/py/test2/config.py ============================================================================== --- py/branch/event/py/test2/config.py (original) +++ py/branch/event/py/test2/config.py Thu Feb 14 11:27:39 2008 @@ -3,6 +3,7 @@ import py from conftesthandle import Conftest from py.__.test2.defaultconftest import adddefaultoptions +from py.__.test2.eventbus import EventBus optparse = py.compat.optparse @@ -25,7 +26,7 @@ return "" %(self.__dict__,) class Config(object): - """ central hub for dealing with configuration/initialization data. """ + """ central bus for dealing with configuration/initialization data. """ Option = optparse.Option def __init__(self): @@ -34,7 +35,7 @@ usage="usage: %prog [options] [query] [filenames of tests]") self._conftest = Conftest() self._initialized = False - self.hub = py.event.Hub() + self.bus = EventBus() def parse(self, args): """ parse cmdline arguments into this config object. Copied: py/branch/event/py/test2/eventbus.py (from r51469, py/branch/event/py/event/hub.py) ============================================================================== --- py/branch/event/py/event/hub.py (original) +++ py/branch/event/py/test2/eventbus.py Thu Feb 14 11:27:39 2008 @@ -1,11 +1,19 @@ -class Hub(list): - """ General Event Hub """ +class EventBus(object): + """ General Event Bus for distributing and processing events. """ + def __init__(self): + self._subscribers = [] + + def subscribe(self, callback): + """ subscribe given callback to bus events. """ + self._subscribers.append(callback) + + def unsubscribe(self, callback): + """ unsubscribe given callback from bus events. """ + self._subscribers.remove(callback) + def notify(self, event): - for subscriber in self: + for subscriber in self._subscribers: subscriber(event) -# XXX do we want a global hub? -#hub = Hub() -#notify = hub.notify Modified: py/branch/event/py/test2/genitem.py ============================================================================== --- py/branch/event/py/test2/genitem.py (original) +++ py/branch/event/py/test2/genitem.py Thu Feb 14 11:27:39 2008 @@ -6,18 +6,18 @@ def genitems(config, colitems, keywordexpr=None, stopitems=(py.test2.collect.Item,)): """ yield Items from iterating over the given colitems. """ - hub = config.hub + bus = config.bus while colitems: next = colitems.pop(0) if isinstance(next, stopitems): if next._skipbykeyword(keywordexpr): - hub.notify(repevent.DeselectedTest(next, keywordexpr)) + bus.notify(repevent.DeselectedTest(next, keywordexpr)) if config.option.keyword_oneshot: keywordexpr = None else: yield next else: - hub.notify(repevent.CollectionStart(next)) + bus.notify(repevent.CollectionStart(next)) excinfo = None try: cols = [next.join(x) for x in next.run()] @@ -27,4 +27,4 @@ raise except: excinfo = py.code.ExceptionInfo() - hub.notify(repevent.CollectionFinish(next, excinfo)) + bus.notify(repevent.CollectionFinish(next, excinfo)) Modified: py/branch/event/py/test2/rsession/hostmanage.py ============================================================================== --- py/branch/event/py/test2/rsession/hostmanage.py (original) +++ py/branch/event/py/test2/rsession/hostmanage.py Thu Feb 14 11:27:39 2008 @@ -133,7 +133,7 @@ python = self.config.getvalue("dist_remotepython") for host in self.hosts: host.initgateway(python=python) - self.config.hub.notify(repevent.HostGatewayReady(host, self.roots)) + self.config.bus.notify(repevent.HostGatewayReady(host, self.roots)) host.gw.host = host def init_rsync(self): @@ -150,7 +150,7 @@ for host in self.hosts: rsync.add_target_host(host, destrelpath) rsync.send(raises=False) - self.config.hub.notify(repevent.RsyncFinished()) + self.config.bus.notify(repevent.RsyncFinished()) def setup_hosts(self): self.init_rsync() @@ -163,7 +163,7 @@ def hostdown(event): if isinstance(event, repevent.HostDown): queue.put(event) - self.config.hub.append(hostdown) + self.config.bus.subscribe(hostdown) pending_hosts = [] for host in self.hosts: Modified: py/branch/event/py/test2/rsession/master.py ============================================================================== --- py/branch/event/py/test2/rsession/master.py (original) +++ py/branch/event/py/test2/rsession/master.py Thu Feb 14 11:27:39 2008 @@ -8,7 +8,7 @@ def __init__(self, host, config): self.host = host self.config = config - self.notify = config.hub.notify + self.notify = config.bus.notify self.channel = setup_slave(host, config) self.channel.setcallback(self._callback) self.pending = [] Modified: py/branch/event/py/test2/rsession/testing/test_masterslave.py ============================================================================== --- py/branch/event/py/test2/rsession/testing/test_masterslave.py (original) +++ py/branch/event/py/test2/rsession/testing/test_masterslave.py Thu Feb 14 11:27:39 2008 @@ -12,7 +12,7 @@ def append(event): if isinstance(event, filterevent): queue.put(event) - self.config.hub.append(append) + self.config.bus.subscribe(append) return queue def test_node_down(self): Modified: py/branch/event/py/test2/rsession/testing/test_rsession.py ============================================================================== --- py/branch/event/py/test2/rsession/testing/test_rsession.py (original) +++ py/branch/event/py/test2/rsession/testing/test_rsession.py Thu Feb 14 11:27:39 2008 @@ -89,7 +89,7 @@ hosts = [HostInfo('localhost:%s' % self.dest)] queue = py.std.Queue.Queue() - self.config.hub.append(queue.put) + self.config.bus.subscribe(queue.put) hm = HostManager(self.config, hosts=hosts) hm.setup_hosts() Modified: py/branch/event/py/test2/session.py ============================================================================== --- py/branch/event/py/test2/session.py (original) +++ py/branch/event/py/test2/session.py Thu Feb 14 11:27:39 2008 @@ -63,14 +63,14 @@ failurelist.append(event) if self.config.option.exitfirst: self.shouldstop = True - self.config.hub.append(processfailures) + self.config.bus.subscribe(processfailures) return failurelist def main(self): """ main loop for running tests. """ self.shouldstop = False self.setup() - self.config.hub.notify(repevent.SessionStart(self)) + self.config.bus.notify(repevent.SessionStart(self)) try: for item in self.collect(): if self.shouldstop: @@ -79,7 +79,7 @@ self.runtest(item) finally: failures = self.teardown() - self.config.hub.notify(repevent.SessionFinish(self)) + self.config.bus.notify(repevent.SessionFinish(self)) return failures def runtest(self, item): @@ -95,8 +95,8 @@ raise ValueError except ValueError: excinfo = py.code.ExceptionInfo() - self.config.hub.notify(repevent.ItemFinish(item, excinfo)) - self.config.hub.notify(testrep) + self.config.bus.notify(repevent.ItemFinish(item, excinfo)) + self.config.bus.notify(testrep) class Exit(Exception): """ for immediate program exits without tracebacks and reporter/summary. """ Modified: py/branch/event/py/test2/testing/suptest.py ============================================================================== --- py/branch/event/py/test2/testing/suptest.py (original) +++ py/branch/event/py/test2/testing/suptest.py Thu Feb 14 11:27:39 2008 @@ -19,7 +19,7 @@ def app(ev): print ev l.append(ev) - config.hub.append(app) + config.bus.subscribe(app) return l def initsorter_from_cmdline(args=None): @@ -55,7 +55,7 @@ for cls in py.std.inspect.getmro(event.__class__): if cls is not object: d.setdefault(cls, []).append(event) - config.hub.append(app) + config.bus.subscribe(app) def get(self, cls): return self.cls2events.get(cls, []) Copied: py/branch/event/py/test2/testing/test_eventbus.py (from r51469, py/branch/event/py/event/testing/test_hub.py) ============================================================================== --- py/branch/event/py/event/testing/test_hub.py (original) +++ py/branch/event/py/test2/testing/test_eventbus.py Thu Feb 14 11:27:39 2008 @@ -1,34 +1,34 @@ import py +from py.__.test2.eventbus import EventBus -class TestHub: - +class TestEventBus: def test_simple(self): - hub = py.event.Hub() + bus = EventBus() l = [] - hub.append(l.append) - hub.notify(1) - hub.notify(2) - hub.notify(3) + bus.subscribe(l.append) + bus.notify(1) + bus.notify(2) + bus.notify(3) assert l == [1,2,3] def test_multi_sub(self): - hub = py.event.Hub() + bus = EventBus() l1 = [] l2 = [] - hub.append(l1.append) - hub.append(l2.append) - hub.notify(1) - hub.notify(2) - hub.notify(3) + bus.subscribe(l1.append) + bus.subscribe(l2.append) + bus.notify(1) + bus.notify(2) + bus.notify(3) assert l1 == [1,2,3] assert l2 == [1,2,3] def test_remove(self): - hub = py.event.Hub() + bus = EventBus() l = [] - hub.append(l.append) - hub.notify(1) - hub.remove(l.append) - hub.notify(2) + bus.subscribe(l.append) + bus.notify(1) + bus.unsubscribe(l.append) + bus.notify(2) assert l == [1] From hpk at codespeak.net Thu Feb 14 12:24:21 2008 From: hpk at codespeak.net (hpk at codespeak.net) Date: Thu, 14 Feb 2008 12:24:21 +0100 (CET) Subject: [py-svn] r51483 - in py/branch/event/py/test2: . testing Message-ID: <20080214112421.9E7BB168411@codespeak.net> Author: hpk Date: Thu Feb 14 12:24:20 2008 New Revision: 51483 Added: py/branch/event/py/test2/present.py - copied, changed from r51481, py/branch/event/py/test2/representation.py py/branch/event/py/test2/testing/test_present.py - copied, changed from r51481, py/branch/event/py/test2/testing/test_repr.py Removed: py/branch/event/py/test2/representation.py py/branch/event/py/test2/testing/test_repr.py Modified: py/branch/event/py/test2/repevent.py py/branch/event/py/test2/reporter.py Log: bit of renaming and refactoring of presentation tests (much more to do there, sigh) Copied: py/branch/event/py/test2/present.py (from r51481, py/branch/event/py/test2/representation.py) ============================================================================== --- py/branch/event/py/test2/representation.py (original) +++ py/branch/event/py/test2/present.py Thu Feb 14 12:24:20 2008 @@ -34,6 +34,13 @@ return ".".join(parts) return colitem.name +def repr_pythonversion(): + v = py.std.sys.version_info + try: + return "%s.%s.%s-%s-%s" % v + except (TypeError, ValueError): + return str(v) + class Presenter(object): """ Class used for presentation of various objects, sharing common output style @@ -203,10 +210,3 @@ # the following is only used by the combination '--pdb --tb=no' repr_failure_tbno = repr_failure_tbshort - -def repr_pythonversion(): - v = py.std.sys.version_info - try: - return "%s.%s.%s-%s-%s" % v - except ValueError: - return str(v) Modified: py/branch/event/py/test2/repevent.py ============================================================================== --- py/branch/event/py/test2/repevent.py (original) +++ py/branch/event/py/test2/repevent.py Thu Feb 14 12:24:20 2008 @@ -73,7 +73,7 @@ def dottedpath(self, config): """ return dotted path for underlying test item. """ - from py.__.test2.representation import getmodpath + from py.__.test2.present import getmodpath col = config._getcollector(self.trail) return getmodpath(col) Modified: py/branch/event/py/test2/reporter.py ============================================================================== --- py/branch/event/py/test2/reporter.py (original) +++ py/branch/event/py/test2/reporter.py Thu Feb 14 12:24:20 2008 @@ -11,7 +11,7 @@ from py.__.test2 import repevent from py.__.test2 import outcome from py.__.misc.terminal_helper import ansi_print, get_terminal_width -from py.__.test2.representation import Presenter, repr_pythonversion,\ +from py.__.test2.present import Presenter, repr_pythonversion,\ getrelpath import sys Deleted: /py/branch/event/py/test2/representation.py ============================================================================== --- /py/branch/event/py/test2/representation.py Thu Feb 14 12:24:20 2008 +++ (empty file) @@ -1,212 +0,0 @@ - -""" This file intends to gather all methods of representing -failures/tracebacks etc. which should be used among -all terminal-based reporters. This methods should be general, -to allow further use outside the pylib -""" - -import py -from py.__.code import safe_repr - -def getrelpath(source, dest): - base = source.common(dest) - if not base: - return None - # with posix local paths '/' is always a common base - relsource = source.relto(base) - reldest = dest.relto(base) - n = relsource.count(source.sep) - target = dest.sep.join(('..', )*n + (reldest, )) - return target - -def getmodpath(pycolitem): - """ return dotted module path for the given colitem. """ - colitems = pycolitem.listchain() - while colitems: - colitem = colitems.pop(0) - if isinstance(colitem, colitem.Module): - parts = [colitem.obj.__name__] - for colitem in colitems: - if colitem.name[0] in '([': - parts[-1] += colitem.name - else: - parts.append(colitem.name) - return ".".join(parts) - return colitem.name - -class Presenter(object): - """ Class used for presentation of various objects, - sharing common output style - """ - def __init__(self, out, config): - """ out is a file-like object (we can write to it) - """ - assert hasattr(out, 'write') - self.out = out - self.config = config - - def repr_source(self, source, marker=">", marker_location=-1): - """ This one represents piece of source with possible - marker at requested position - """ - if isinstance(source, str): - # why the hell, string is iterable? - source = source.split("\n") - if marker_location < 0: - marker_location += len(source) - if marker_location < 0: - marker_location = 0 - if marker_location >= len(source): - marker_location = len(source) - 1 - for i in range(len(source)): - if i == marker_location: - prefix = marker + " " - else: - prefix = " " - self.out.line(prefix + source[i]) - - def repr_item_info(self, item): - """ This method represents py.test2.collect.Item info (path and module) - """ - root = item.fspath - modpath = item._getmodpath() - try: - fn, lineno = item._getpathlineno() - except TypeError: - assert isinstance(item.parent, py.test2.collect.Generator) - # a generative test yielded a non-callable - fn, lineno = item.parent._getpathlineno() - if root == fn: - self.out.sep("_", "entrypoint: %s" %(modpath)) - else: - self.out.sep("_", "entrypoint: %s %s" %(root.basename, modpath)) - - def repr_failure_explanation(self, excinfo, source): - try: - s = str(source.getstatement(len(source)-1)) - except KeyboardInterrupt: - raise - except: - s = str(source[-1]) - indent = " " * (4 + (len(s) - len(s.lstrip()))) - # get the real exception information out - lines = excinfo.exconly(tryshort=True).split('\n') - self.out.line('>' + indent[:-1] + lines.pop(0)) - for x in lines: - self.out.line(indent + x) - - def getentrysource(self, entry): - try: - source = entry.getsource() - except py.error.ENOENT: - source = py.code.Source("[failure to get at sourcelines from %r]\n" % entry) - return source.deindent() - - def repr_locals(self, f_locals): - if self.config.option.showlocals: - self.out.sep('- ', 'locals') - for name, value in f_locals.items(): - if name == '__builtins__': - self.out.line("__builtins__ = ") - else: - # This formatting could all be handled by the _repr() function, which is - # only repr.Repr in disguise, so is very configurable. - str_repr = safe_repr._repr(value) - if len(str_repr) < 70 or not isinstance(value, - (list, tuple, dict)): - self.out.line("%-10s = %s" %(name, str_repr)) - else: - self.out.line("%-10s =\\" % (name,)) - py.std.pprint.pprint(value, stream=self.out) - - def repr_failure_tblong(self, item, excinfo, traceback, out_err_reporter): - if not self.config.option.nomagic and excinfo.errisinstance(RuntimeError): - recursionindex = traceback.recursionindex() - else: - recursionindex = None - last = traceback[-1] - first = traceback[0] - for index, entry in py.builtin.enumerate(traceback): - if entry == first: - if item: - self.repr_item_info(item) - self.out.line() - else: - self.out.line("") - source = self.getentrysource(entry) - firstsourceline = entry.getfirstlinesource() - marker_location = entry.lineno - firstsourceline - if entry == last: - self.repr_source(source, 'E', marker_location) - self.repr_failure_explanation(excinfo, source) - else: - self.repr_source(source, '>', marker_location) - self.out.line("") - self.out.line("[%s:%d]" %(entry.path, entry.lineno+1)) - self.repr_locals(entry.locals) - - # trailing info - if entry == last: - out_err_reporter() - self.out.sep("_") - else: - self.out.sep("_ ") - if index == recursionindex: - self.out.line("Recursion detected (same locals & position)") - self.out.sep("!") - break - - def repr_failure_tbshort(self, item, excinfo, traceback, out_err_reporter): - # print a Python-style short traceback - if not self.config.option.nomagic and excinfo.errisinstance(RuntimeError): - recursionindex = traceback.recursionindex() - else: - recursionindex = None - last = traceback[-1] - first = traceback[0] - self.out.line() - for index, entry in py.builtin.enumerate(traceback): - path = entry.path.basename - firstsourceline = entry.getfirstlinesource() - relline = entry.lineno - firstsourceline - self.out.line(' File "%s", line %d, in %s' % ( - path, entry.lineno+1, entry.name)) - try: - source = entry.getsource().lines - except py.error.ENOENT: - source = ["?"] - else: - try: - if len(source) > 1: - source = source[relline] - except IndexError: - source = [] - if entry == last: - if source: - self.repr_source(source, 'E') - self.repr_failure_explanation(excinfo, source) - else: - if source: - self.repr_source(source, ' ') - self.repr_locals(entry.locals) - - # trailing info - if entry == last: - out_err_reporter() - self.out.sep("_") - else: - if index == recursionindex: - self.out.line("Recursion detected (same locals & position)") - self.out.sep("!") - break - - # the following is only used by the combination '--pdb --tb=no' - repr_failure_tbno = repr_failure_tbshort - - -def repr_pythonversion(): - v = py.std.sys.version_info - try: - return "%s.%s.%s-%s-%s" % v - except ValueError: - return str(v) Copied: py/branch/event/py/test2/testing/test_present.py (from r51481, py/branch/event/py/test2/testing/test_repr.py) ============================================================================== --- py/branch/event/py/test2/testing/test_repr.py (original) +++ py/branch/event/py/test2/testing/test_present.py Thu Feb 14 12:24:20 2008 @@ -1,9 +1,8 @@ import py -from py.__.test2.representation import Presenter, getmodpath +from py.__.test2 import present, repevent from py.__.test2.terminal.out import getout -from StringIO import StringIO -import setupdata +import suptest, setupdata import sys def test_getmodpath_cases(): @@ -13,10 +12,10 @@ nopkgdir = tmpdir.ensure("nopkg", dir=1) def checkpkg(names, expected): fcol = setupdata.getexamplecollector(names, tmpdir=pkgdir) - assert getmodpath(fcol) == pkgdir.basename + "." + expected + assert present.getmodpath(fcol) == pkgdir.basename + "." + expected def checknopkg(names, expected): fcol = setupdata.getexamplecollector(names, tmpdir=nopkgdir) - assert getmodpath(fcol) == expected + assert present.getmodpath(fcol) == expected for names in ( 'mod.py test_f1 mod.test_f1', @@ -29,66 +28,87 @@ yield checkpkg, names, expected yield checknopkg, names, expected -def newconfig(*args): - tmpdir = py.test2.ensuretemp("newconfig") - args = list(args) - args.append(tmpdir) - return py.test2.config._reparse(args) +def test_repr_python_version(): + py.magic.patch(py.std.sys, 'version_info', (2, 5, 1, 'final', 0)) + try: + assert present.repr_pythonversion() == "2.5.1-final-0" + py.std.sys.version_info = x = (2,3) + assert present.repr_pythonversion() == str(x) + finally: + py.magic.revert(py.std.sys, 'version_info') + +class TestPresenter: + def setup_class(cls): + cls.tmpdir = py.test2.ensuretemp(cls.__name__) + + def getconfig(self, args=()): + return py.test2.config._reparse([self.tmpdir] + list(args)) + + def getpresenter(self, cmdlinearg=""): + config = self.getconfig(cmdlinearg.split()) + stringio = py.std.StringIO.StringIO() + out = getout(stringio) + p = present.Presenter(out, config) + p.stringio = stringio + return p + + def test_repr_source(self): + source = py.code.Source(""" + def f(x): + pass + """).strip() + p = self.getpresenter() + p.repr_source(source, "|", 0) + lines = p.stringio.getvalue().split("\n") + assert len(lines) == 3 + assert lines[0].startswith("|") + assert lines[0].find("def f(x)") != -1 + assert lines[1].find("pass") != -1 + + def test_repr_failure_explanation(self): + """ check if indentation is right """ + def f(): + def g(): + 1/0 + try: + g() + except: + e = py.code.ExceptionInfo() + return e -def test_repr_source(): - source = py.code.Source(""" - def f(x): - pass - """).strip() - config = newconfig() - s = StringIO() - out = getout(s) - p = Presenter(out, config) - p.repr_source(source, "|", 0) - lines = s.getvalue().split("\n") - assert len(lines) == 3 - assert lines[0].startswith("|") - assert lines[0].find("def f(x)") != -1 - assert lines[1].find("pass") != -1 - -def test_repr_failure_explanation(): - """ We check here if indentation is right - """ - def f(): - def g(): - 1/0 - try: - g() - except: - e = py.code.ExceptionInfo() - return e - config = newconfig() - s = StringIO() - out = getout(s) - p = Presenter(out, config) - source = py.code.Source(f) - e = f() - p.repr_failure_explanation(e, source) - assert s.getvalue().startswith("> ") - -def test_repr_local(): - config = newconfig('--showlocals') - s = StringIO() - out = getout(s) - p = Presenter(out, config) - p.repr_locals(locals()) - for key in locals().keys(): - assert s.getvalue().find(key) != -1 - -def XXXtest_repr_traceback_long(): - py.test.skip("unfinished") - config = py.test2.config._reparse([]) - s = StringIO() - out = getout(s) - p = Presenter(out, config) - # errr... here we should - # a) prepare an item - # b) prepare excinfo - # c) prepare some traceback info, with few different ideas, - # like recursion detected etc. - # test it... + p = self.getpresenter() + source = py.code.Source(f) + e = f() + p.repr_failure_explanation(e, source) + assert p.stringio.getvalue().startswith("> ") + + def test_repr_local(self): + p = self.getpresenter("--showlocals") + loc = locals() + p.repr_locals(loc) + result = p.stringio.getvalue() + for key in loc.keys(): + assert result.find(key) != -1 + + def test_repr_traceback(self): + tfile = suptest.makeuniquepyfile(""" + def test_one(): + assert 42 == 43 + def f(): + assert 0 + def test_nested(): + f() + """) + sorter = suptest.events_from_cmdline([tfile]) + p = self.getpresenter() + + failevents = sorter.get(repevent.ItemFinish) + assert len(failevents) == 2 + item = failevents[0].item + py.test.skip("refactor Presenter.repr_failure_*") + # errr... here we should + # a) prepare an item + # b) prepare excinfo + # c) prepare some traceback info, with few different ideas, + # like recursion detected etc. + # test it... Deleted: /py/branch/event/py/test2/testing/test_repr.py ============================================================================== --- /py/branch/event/py/test2/testing/test_repr.py Thu Feb 14 12:24:20 2008 +++ (empty file) @@ -1,94 +0,0 @@ - -import py -from py.__.test2.representation import Presenter, getmodpath -from py.__.test2.terminal.out import getout -from StringIO import StringIO -import setupdata -import sys - -def test_getmodpath_cases(): - tmpdir = py.test.ensuretemp("test_getmodpath_cases") - pkgdir = tmpdir.join("pkg") - pkgdir.ensure("__init__.py") - nopkgdir = tmpdir.ensure("nopkg", dir=1) - def checkpkg(names, expected): - fcol = setupdata.getexamplecollector(names, tmpdir=pkgdir) - assert getmodpath(fcol) == pkgdir.basename + "." + expected - def checknopkg(names, expected): - fcol = setupdata.getexamplecollector(names, tmpdir=nopkgdir) - assert getmodpath(fcol) == expected - - for names in ( - 'mod.py test_f1 mod.test_f1', - 'mod.py TestA () test_m1 mod.TestA().test_m1', - 'mod.py test_g1 mod.test_g1', - 'mod.py test_g1 [0] mod.test_g1[0]', - ): - names = names.split() - expected = names.pop() - yield checkpkg, names, expected - yield checknopkg, names, expected - -def newconfig(*args): - tmpdir = py.test2.ensuretemp("newconfig") - args = list(args) - args.append(tmpdir) - return py.test2.config._reparse(args) - -def test_repr_source(): - source = py.code.Source(""" - def f(x): - pass - """).strip() - config = newconfig() - s = StringIO() - out = getout(s) - p = Presenter(out, config) - p.repr_source(source, "|", 0) - lines = s.getvalue().split("\n") - assert len(lines) == 3 - assert lines[0].startswith("|") - assert lines[0].find("def f(x)") != -1 - assert lines[1].find("pass") != -1 - -def test_repr_failure_explanation(): - """ We check here if indentation is right - """ - def f(): - def g(): - 1/0 - try: - g() - except: - e = py.code.ExceptionInfo() - return e - config = newconfig() - s = StringIO() - out = getout(s) - p = Presenter(out, config) - source = py.code.Source(f) - e = f() - p.repr_failure_explanation(e, source) - assert s.getvalue().startswith("> ") - -def test_repr_local(): - config = newconfig('--showlocals') - s = StringIO() - out = getout(s) - p = Presenter(out, config) - p.repr_locals(locals()) - for key in locals().keys(): - assert s.getvalue().find(key) != -1 - -def XXXtest_repr_traceback_long(): - py.test.skip("unfinished") - config = py.test2.config._reparse([]) - s = StringIO() - out = getout(s) - p = Presenter(out, config) - # errr... here we should - # a) prepare an item - # b) prepare excinfo - # c) prepare some traceback info, with few different ideas, - # like recursion detected etc. - # test it... From hpk at codespeak.net Thu Feb 14 22:00:53 2008 From: hpk at codespeak.net (hpk at codespeak.net) Date: Thu, 14 Feb 2008 22:00:53 +0100 (CET) Subject: [py-svn] r51497 - in py/branch/event/py: . test2 test2/testing Message-ID: <20080214210053.DCCB0168458@codespeak.net> Author: hpk Date: Thu Feb 14 22:00:50 2008 New Revision: 51497 Removed: py/branch/event/py/test2/deprecate.py py/branch/event/py/test2/raises.py py/branch/event/py/test2/testing/test_deprecated.py py/branch/event/py/test2/testing/test_itemgen.py Modified: py/branch/event/py/__init__.py py/branch/event/py/test2/executor.py py/branch/event/py/test2/item.py py/branch/event/py/test2/outcome.py py/branch/event/py/test2/present.py py/branch/event/py/test2/session.py py/branch/event/py/test2/testing/test_executor.py py/branch/event/py/test2/testing/test_outcome.py py/branch/event/py/test2/testing/test_present.py py/branch/event/py/test2/testing/test_session.py Log: * refactor Presenter, add many tests * make ItemTestReport events contain traceback info (at the place where the exception happens) * finally delete old SerializableOutcome code * factor out most py.test helpers into outcome.py Modified: py/branch/event/py/__init__.py ============================================================================== --- py/branch/event/py/__init__.py (original) +++ py/branch/event/py/__init__.py Thu Feb 14 22:00:50 2008 @@ -28,15 +28,15 @@ 'test.__doc__' : ('./test/__init__.py', '__doc__'), 'test2.__doc__' : ('./test2/__init__.py', '__doc__'), 'test.raises' : ('./test/raises.py', 'raises'), - 'test2.raises' : ('./test2/raises.py', 'raises'), + 'test2.raises' : ('./test2/outcome.py', 'raises'), 'test.deprecated_call' : ('./test/deprecate.py', 'deprecated_call'), - 'test2.deprecated_call' : ('./test2/deprecate.py', 'deprecated_call'), + 'test2.deprecated_call' : ('./test2/outcome.py', 'deprecated_call'), 'test.skip' : ('./test/item.py', 'skip'), - 'test2.skip' : ('./test2/item.py', 'skip'), + 'test2.skip' : ('./test2/outcome.py', 'skip'), 'test.fail' : ('./test/item.py', 'fail'), - 'test2.fail' : ('./test2/item.py', 'fail'), + 'test2.fail' : ('./test2/outcome.py', 'fail'), 'test.exit' : ('./test/session.py', 'exit'), - 'test2.exit' : ('./test2/session.py', 'exit'), + 'test2.exit' : ('./test2/outcome.py', 'exit'), 'test.pdb' : ('./test/custompdb.py', 'set_trace'), 'test2.pdb' : ('./test2/custompdb.py', 'set_trace'), Deleted: /py/branch/event/py/test2/deprecate.py ============================================================================== --- /py/branch/event/py/test2/deprecate.py Thu Feb 14 22:00:50 2008 +++ (empty file) @@ -1,18 +0,0 @@ -import py - -def deprecated_call(func, *args, **kwargs): - """ assert that calling func(*args, **kwargs) - triggers a DeprecationWarning. - """ - l = [] - oldwarn = py.std.warnings.warn_explicit - def warn_explicit(*args, **kwargs): - l.append(args) - oldwarn(*args, **kwargs) - - py.magic.patch(py.std.warnings, 'warn_explicit', warn_explicit) - try: - _ = func(*args, **kwargs) - finally: - py.magic.revert(py.std.warnings, 'warn_explicit') - assert l Modified: py/branch/event/py/test2/executor.py ============================================================================== --- py/branch/event/py/test2/executor.py (original) +++ py/branch/event/py/test2/executor.py Thu Feb 14 22:00:50 2008 @@ -6,7 +6,7 @@ from py.__.test2.box import Box from py.__.test2 import repevent from py.__.test2.outcome import Skipped, Failed -from py.__.test2 import repevent +from py.__.test2 import repevent, present import py.__.test2.custompdb class RunExecutor(object): @@ -26,32 +26,33 @@ else: self.item.run() + def _fillreport(self, testrep, excinfo): + if excinfo.errisinstance(Skipped): + testrep.skipped = True + else: + testrep.failed = True + testrep.exconly = excinfo.exconly() + p = present.Presenter(self.config) + p.repr_failure(self.item, excinfo) + testrep.repr_failure = p.stringio.getvalue() + def execute(self, capture=True): testrep = repevent.ItemTestReport(self.item._get_collector_trail()) - testrep._item = self.item try: try: self.run(capture) finally: testrep.stdout, testrep.stderr = self.item._getouterr() except Skipped: - testrep.skipped = True - testrep._excinfo = py.code.ExceptionInfo() + self._fillreport(testrep, py.code.ExceptionInfo()) except (SystemExit, KeyboardInterrupt): raise except: - e = sys.exc_info()[1] - if isinstance(e, Failed) and e.excinfo: + excinfo = py.code.ExceptionInfo() + if excinfo.errisinstance(Failed) and excinfo.value.excinfo: excinfo = e.excinfo - else: - excinfo = py.code.ExceptionInfo() - if isinstance(self.item, py.test2.collect.Function): - fun = self.item.obj # hope this is stable - code = py.code.Code(fun) - excinfo.traceback = excinfo.traceback.cut( - path=code.path, firstlineno=code.firstlineno) - testrep._excinfo = excinfo - testrep.failed = True + self.config.bus.notify(repevent.ItemFinish(self.item, excinfo)) + self._fillreport(testrep, excinfo) if self.config.option.usepdb: py.__.test2.custompdb.post_mortem(excinfo._excinfo[2]) # XXX hmm, we probably will not like to continue from that Modified: py/branch/event/py/test2/item.py ============================================================================== --- py/branch/event/py/test2/item.py (original) +++ py/branch/event/py/test2/item.py Thu Feb 14 22:00:50 2008 @@ -1,6 +1,5 @@ import py -from inspect import isclass, ismodule from py.__.test2 import outcome from py.__.test2.collect import FunctionMixin @@ -67,15 +66,3 @@ """ execute the given test function. """ target(*args) -# whatever comes here.... - -def skip(msg=""): - """ skip with the given Message. """ - __tracebackhide__ = True - raise outcome.Skipped(msg=msg) - -def fail(msg="unknown failure"): - """ fail with the given Message. """ - __tracebackhide__ = True - raise outcome.Failed(msg=msg) - Modified: py/branch/event/py/test2/outcome.py ============================================================================== --- py/branch/event/py/test2/outcome.py (original) +++ py/branch/event/py/test2/outcome.py Thu Feb 14 22:00:50 2008 @@ -1,9 +1,11 @@ -""" - File defining possible outcomes of running and also - serialization of outcomes +""" + Test Outcomes and helpers for creating them. + py.test.skip|fail|raises helper implementations + """ import py +import sys class Outcome: def __init__(self, msg=None, excinfo=None): @@ -31,126 +33,77 @@ class Skipped(Outcome): pass -# XXX -# XXX -# XXX the below is not used but needs some porting -# XXX -# XXX -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, excinfo, tbstyle): - if excinfo is None or isinstance(excinfo, basestring): - return 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(self.excinfo, tbstyle), - self.make_excinfo_repr(self.skipped, tbstyle), - 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 Exit(Exception): + """ for immediate program exits without tracebacks and reporter/summary. """ + def __init__(self, msg="unknown reason", item=None): + self.msg = msg + Exception.__init__(self, msg) -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, skipped, - self.is_critical, self.signal, self.stdout, self.stderr) = repr_tuple - self.excinfo = self.unpack(excinfo) - self.skipped = self.unpack(skipped) - - def unpack(self, what): - if what is None or isinstance(what, basestring): - return what - return ExcInfoRepr(what) +# exposed helper methods - def __repr__(self): - l = ["%s=%s" %(x, getattr(self, x)) - for x in "signal passed skipped setupfailure excinfo stdout stderr".split()] - return "" %(" ".join(l),) +def exit(msg, item=None): + """ exit testing process immediately. """ + raise Exit(msg=msg, item=item) + +def skip(msg=""): + """ skip with the given Message. """ + __tracebackhide__ = True + raise Skipped(msg=msg) + +def fail(msg="unknown failure"): + """ fail with the given Message. """ + __tracebackhide__ = True + raise Failed(msg=msg) + +def raises(ExpectedException, *args, **kwargs): + """ raise AssertionError, if target code does not raise the expected + exception. + """ + assert args + __tracebackhide__ = True + if isinstance(args[0], str): + expr, = args + assert isinstance(expr, str) + frame = sys._getframe(1) + loc = frame.f_locals.copy() + loc.update(kwargs) + #print "raises frame scope: %r" % frame.f_locals + source = py.code.Source(expr) + try: + exec source.compile() in frame.f_globals, loc + #del __traceback__ + # XXX didn'T mean f_globals == f_locals something special? + # this is destroyed here ... + except ExpectedException: + return py.code.ExceptionInfo() + else: + func = args[0] + assert callable + try: + func(*args[1:], **kwargs) + #del __traceback__ + except ExpectedException: + return py.code.ExceptionInfo() + k = ", ".join(["%s=%r" % x for x in kwargs.items()]) + if k: + k = ', ' + k + expr = '%s(%r%s)' %(func.__name__, args, k) + raise ExceptionFailure(msg="DID NOT RAISE", + expr=args, expected=ExpectedException) + +def deprecated_call(func, *args, **kwargs): + """ assert that calling func(*args, **kwargs) + triggers a DeprecationWarning. + """ + l = [] + oldwarn = py.std.warnings.warn_explicit + def warn_explicit(*args, **kwargs): + l.append(args) + oldwarn(*args, **kwargs) + + py.magic.patch(py.std.warnings, 'warn_explicit', warn_explicit) + try: + _ = func(*args, **kwargs) + finally: + py.magic.revert(py.std.warnings, 'warn_explicit') + assert l Modified: py/branch/event/py/test2/present.py ============================================================================== --- py/branch/event/py/test2/present.py (original) +++ py/branch/event/py/test2/present.py Thu Feb 14 22:00:50 2008 @@ -7,6 +7,7 @@ import py from py.__.code import safe_repr +from py.__.test2.terminal.out import getout def getrelpath(source, dest): base = source.common(dest) @@ -45,12 +46,13 @@ """ Class used for presentation of various objects, sharing common output style """ - def __init__(self, out, config): - """ out is a file-like object (we can write to it) - """ - assert hasattr(out, 'write') - self.out = out + def __init__(self, config, out=None): self.config = config + if out is None: + self.stringio = py.std.StringIO.StringIO() + out = getout(self.stringio) + assert hasattr(out, 'write'), out + self.out = out def repr_source(self, source, marker=">", marker_location=-1): """ This one represents piece of source with possible @@ -72,11 +74,11 @@ prefix = " " self.out.line(prefix + source[i]) - def repr_item_info(self, item): + def repr_failure_headline(self, item): """ This method represents py.test2.collect.Item info (path and module) """ root = item.fspath - modpath = item._getmodpath() + modpath = getmodpath(item) try: fn, lineno = item._getpathlineno() except TypeError: @@ -126,20 +128,42 @@ self.out.line("%-10s =\\" % (name,)) py.std.pprint.pprint(value, stream=self.out) - def repr_failure_tblong(self, item, excinfo, traceback, out_err_reporter): - if not self.config.option.nomagic and excinfo.errisinstance(RuntimeError): + def filtertraceback(self, item, traceback): + if item and not self.config.option.fulltrace: + path, firstlineno = item._getpathlineno() + ntraceback = traceback.cut(path=path, firstlineno=firstlineno) + if ntraceback == traceback: + ntraceback = ntraceback.cut(path=path) + traceback = ntraceback.filter() + return traceback + + def repr_failure(self, item, excinfo): + traceback = self.filtertraceback(item, excinfo.traceback) + if excinfo.errisinstance(RuntimeError): recursionindex = traceback.recursionindex() else: recursionindex = None + + repr_tb = getattr(self, "repr_tb_" + self.config.option.tbstyle) + repr_tb(item, excinfo, traceback, recursionindex) + + def repr_out_err(self, colitem): + for parent in colitem.listchain(): + for name, obj in zip(['out', 'err'], parent._getouterr()): + if obj: + self.out.sep("- ", "%s: recorded std%s" % (parent.name, name)) + self.out.line(obj) + + def repr_tb_long(self, item, excinfo, traceback, recursionindex): last = traceback[-1] first = traceback[0] for index, entry in py.builtin.enumerate(traceback): if entry == first: if item: - self.repr_item_info(item) + self.repr_failure_headline(item) self.out.line() else: - self.out.line("") + self.out.line() source = self.getentrysource(entry) firstsourceline = entry.getfirstlinesource() marker_location = entry.lineno - firstsourceline @@ -154,7 +178,7 @@ # trailing info if entry == last: - out_err_reporter() + self.repr_out_err(item) self.out.sep("_") else: self.out.sep("_ ") @@ -163,15 +187,9 @@ self.out.sep("!") break - def repr_failure_tbshort(self, item, excinfo, traceback, out_err_reporter): - # print a Python-style short traceback - if not self.config.option.nomagic and excinfo.errisinstance(RuntimeError): - recursionindex = traceback.recursionindex() - else: - recursionindex = None - last = traceback[-1] - first = traceback[0] + def repr_tb_short(self, item, excinfo, traceback, recursionindex): self.out.line() + last = traceback[-1] for index, entry in py.builtin.enumerate(traceback): path = entry.path.basename firstsourceline = entry.getfirstlinesource() @@ -199,7 +217,7 @@ # trailing info if entry == last: - out_err_reporter() + self.repr_out_err(item) self.out.sep("_") else: if index == recursionindex: @@ -208,5 +226,5 @@ break # the following is only used by the combination '--pdb --tb=no' - repr_failure_tbno = repr_failure_tbshort + repr_tb_no = repr_tb_short Deleted: /py/branch/event/py/test2/raises.py ============================================================================== --- /py/branch/event/py/test2/raises.py Thu Feb 14 22:00:50 2008 +++ (empty file) @@ -1,39 +0,0 @@ -import sys -import py -from py.__.test2.outcome import ExceptionFailure - -def raises(ExpectedException, *args, **kwargs): - """ raise AssertionError, if target code does not raise the expected - exception. - """ - assert args - __tracebackhide__ = True - if isinstance(args[0], str): - expr, = args - assert isinstance(expr, str) - frame = sys._getframe(1) - loc = frame.f_locals.copy() - loc.update(kwargs) - #print "raises frame scope: %r" % frame.f_locals - source = py.code.Source(expr) - try: - exec source.compile() in frame.f_globals, loc - #del __traceback__ - # XXX didn'T mean f_globals == f_locals something special? - # this is destroyed here ... - except ExpectedException: - return py.code.ExceptionInfo() - else: - func = args[0] - assert callable - try: - func(*args[1:], **kwargs) - #del __traceback__ - except ExpectedException: - return py.code.ExceptionInfo() - k = ", ".join(["%s=%r" % x for x in kwargs.items()]) - if k: - k = ', ' + k - expr = '%s(%r%s)' %(func.__name__, args, k) - raise ExceptionFailure(msg="DID NOT RAISE", - expr=args, expected=ExpectedException) Modified: py/branch/event/py/test2/session.py ============================================================================== --- py/branch/event/py/test2/session.py (original) +++ py/branch/event/py/test2/session.py Thu Feb 14 22:00:50 2008 @@ -8,7 +8,6 @@ import py from py.__.test2.genitem import genitems from py.__.test2 import repevent -from py.__.test2.outcome import ReprOutcome from py.__.test2.executor import RunExecutor, BoxExecutor class Session(object): @@ -88,22 +87,5 @@ cls = BoxExecutor executor = cls(item, self.config) testrep = executor.execute() - excinfo = None - if testrep.failed: - # XXX excinfo - try: - raise ValueError - except ValueError: - excinfo = py.code.ExceptionInfo() - self.config.bus.notify(repevent.ItemFinish(item, excinfo)) self.config.bus.notify(testrep) -class Exit(Exception): - """ for immediate program exits without tracebacks and reporter/summary. """ - def __init__(self, msg="unknown reason", item=None): - self.msg = msg - Exception.__init__(self, msg) - -def exit(msg, item=None): - raise Exit(msg=msg, item=item) - Deleted: /py/branch/event/py/test2/testing/test_deprecated.py ============================================================================== --- /py/branch/event/py/test2/testing/test_deprecated.py Thu Feb 14 22:00:50 2008 +++ (empty file) @@ -1,35 +0,0 @@ -import py - -def dep(i): - if i == 0: - py.std.warnings.warn("is deprecated", DeprecationWarning) - -reg = {} -def dep_explicit(i): - if i == 0: - py.std.warnings.warn_explicit("dep_explicit", category=DeprecationWarning, - filename="hello", lineno=3) - -def test_deprecated_call_raises(): - py.test2.raises(AssertionError, - "py.test2.deprecated_call(dep, 3)") - -def test_deprecated_call(): - py.test2.deprecated_call(dep, 0) - -def test_deprecated_call_preserves(): - r = py.std.warnings.onceregistry.copy() - f = py.std.warnings.filters[:] - test_deprecated_call_raises() - test_deprecated_call() - assert r == py.std.warnings.onceregistry - assert f == py.std.warnings.filters - -def test_deprecated_explicit_call_raises(): - py.test2.raises(AssertionError, - "py.test2.deprecated_call(dep_explicit, 3)") - -def test_deprecated_explicit_call(): - py.test2.deprecated_call(dep_explicit, 0) - py.test2.deprecated_call(dep_explicit, 0) - Modified: py/branch/event/py/test2/testing/test_executor.py ============================================================================== --- py/branch/event/py/test2/testing/test_executor.py (original) +++ py/branch/event/py/test2/testing/test_executor.py Thu Feb 14 22:00:50 2008 @@ -1,11 +1,9 @@ import py -from py.__.test2.executor import RunExecutor, BoxExecutor,\ - AsyncExecutor, ApigenExecutor -from py.__.test2.outcome import ReprOutcome +from py.__.test2.executor import RunExecutor, BoxExecutor +from py.__.test2.executor import AsyncExecutor, ApigenExecutor from py.__.test2.rsession.testing.basetest import BasicRsessionTest -from py.__.test2.outcome import Failed def setup_module(mod): if py.std.sys.platform == "win32": Deleted: /py/branch/event/py/test2/testing/test_itemgen.py ============================================================================== --- /py/branch/event/py/test2/testing/test_itemgen.py Thu Feb 14 22:00:50 2008 +++ (empty file) @@ -1,39 +0,0 @@ - -import py -from py.__.test2 import repevent - -class TestItemgen: - def setup_class(cls): - tmp = py.test.ensuretemp('itemgentest') - tmp.ensure("__init__.py") - tmp.ensure("test_one.py").write(py.code.Source(""" - def test_one(): - pass - - class TestX: - def test_method_one(self): - pass - - class TestY(TestX): - pass - """)) - tmp.ensure("test_two.py").write(py.code.Source(""" - import py - py.test2.skip('xxx') - """)) - tmp.ensure("test_three.py").write("xxxdsadsadsadsa") - cls.tmp = tmp - - def test_itemgen(self): - py.test.skip("itemgen test needs revamp but itemgen needs refactoring anyway") - l = [] - colitems = [py.test2.collect.Directory(self.tmp)] - gen = itemgen(None, colitems, l.append) - items = [i for i in gen] - assert len([i for i in l if isinstance(i, repevent.DeselectedTest)]) == 1 - assert len([i for i in l if isinstance(i, repevent.FailedTryiter)]) == 1 - assert len(items) == 3 - assert items[0].name == 'test_one' - assert items[1].name == 'test_method_one' - assert items[2].name == 'test_method_one' - Modified: py/branch/event/py/test2/testing/test_outcome.py ============================================================================== --- py/branch/event/py/test2/testing/test_outcome.py (original) +++ py/branch/event/py/test2/testing/test_outcome.py Thu Feb 14 22:00:50 2008 @@ -1,7 +1,5 @@ import py -from py.__.test2.outcome import SerializableOutcome, ReprOutcome, ExcInfoRepr - import marshal import py @@ -21,31 +19,6 @@ def f4(): py.test.skip("argh!") -def test_exception_info_repr(): - py.test.skip("exception infos need fixing") - try: - f3() - except: - outcome = SerializableOutcome(excinfo=py.code.ExceptionInfo()) - - repr = outcome.make_excinfo_repr(outcome.excinfo, "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 - class TestRaises: def test_raises(self): py.test2.raises(ValueError, "int('qwe')") @@ -59,3 +32,40 @@ def test_raises_function(self): py.test2.raises(ValueError, int, 'hello') +# +# ============ test py.test.deprecated_call() ============== +# + +def dep(i): + if i == 0: + py.std.warnings.warn("is deprecated", DeprecationWarning) + +reg = {} +def dep_explicit(i): + if i == 0: + py.std.warnings.warn_explicit("dep_explicit", category=DeprecationWarning, + filename="hello", lineno=3) + +def test_deprecated_call_raises(): + py.test2.raises(AssertionError, + "py.test2.deprecated_call(dep, 3)") + +def test_deprecated_call(): + py.test2.deprecated_call(dep, 0) + +def test_deprecated_call_preserves(): + r = py.std.warnings.onceregistry.copy() + f = py.std.warnings.filters[:] + test_deprecated_call_raises() + test_deprecated_call() + assert r == py.std.warnings.onceregistry + assert f == py.std.warnings.filters + +def test_deprecated_explicit_call_raises(): + py.test2.raises(AssertionError, + "py.test2.deprecated_call(dep_explicit, 3)") + +def test_deprecated_explicit_call(): + py.test2.deprecated_call(dep_explicit, 0) + py.test2.deprecated_call(dep_explicit, 0) + Modified: py/branch/event/py/test2/testing/test_present.py ============================================================================== --- py/branch/event/py/test2/testing/test_present.py (original) +++ py/branch/event/py/test2/testing/test_present.py Thu Feb 14 22:00:50 2008 @@ -1,9 +1,8 @@ import py from py.__.test2 import present, repevent -from py.__.test2.terminal.out import getout import suptest, setupdata -import sys +import re, sys def test_getmodpath_cases(): tmpdir = py.test.ensuretemp("test_getmodpath_cases") @@ -46,11 +45,24 @@ def getpresenter(self, cmdlinearg=""): config = self.getconfig(cmdlinearg.split()) - stringio = py.std.StringIO.StringIO() - out = getout(stringio) - p = present.Presenter(out, config) - p.stringio = stringio - return p + return present.Presenter(config) + + def getfailing(self, source): + tfile = suptest.makeuniquepyfile(source) + sorter = suptest.events_from_cmdline([tfile]) + # get failure base info + failevents = sorter.get(repevent.ItemFinish) + assert len(failevents) == 1 + item = failevents[0].item + excinfo = failevents[0].excinfo + return item, excinfo + + def gentest(self, check, **options): + print "using config options", options + p = self.getpresenter() + for name, value in options.items(): + setattr(p.config.option, name, value) + check(p) def test_repr_source(self): source = py.code.Source(""" @@ -90,25 +102,57 @@ for key in loc.keys(): assert result.find(key) != -1 - def test_repr_traceback(self): - tfile = suptest.makeuniquepyfile(""" + def test_repr_failure_simple(self): + item, excinfo = self.getfailing(""" def test_one(): + # failingsourcemarker assert 42 == 43 - def f(): - assert 0 - def test_nested(): - f() """) - sorter = suptest.events_from_cmdline([tfile]) p = self.getpresenter() - - failevents = sorter.get(repevent.ItemFinish) - assert len(failevents) == 2 - item = failevents[0].item - py.test.skip("refactor Presenter.repr_failure_*") - # errr... here we should - # a) prepare an item - # b) prepare excinfo - # c) prepare some traceback info, with few different ideas, - # like recursion detected etc. - # test it... + p.repr_failure(item, excinfo) + s = p.stringio.getvalue() + print s + assert re.search("entrypoint:.*\.test_one", s) + assert s.find("# failingsourcemarker") != -1 + assert re.search(r"E.*assert 42 == 43", s) + assert re.search(r">.*assert 42 == 43", s) + + def test_repr_failure_recursive_funcs(self): + item, excinfo = self.getfailing(""" + def rec2(x): + return rec1(x+1) + def rec1(x): + return rec2(x-1) + def test_one(): + rec1(42) + """) + def check(p): + p.repr_failure(item, excinfo) + s = p.stringio.getvalue() + print s + assert re.search(".*return rec1.*x\+1", s) + assert re.search(".*return rec2.*x-1.*", s) + assert re.search("Recursion detected", s) + + self.gentest(check, fulltrace=True) + self.gentest(check, fulltrace=False) + self.gentest(check, tbstyle='short') + self.gentest(check, showlocals=True) + + def test_repr_failing_setup(self): + item, excinfo = self.getfailing(""" + def setup_module(mod): + xyz + def test_one(): + pass + """) + def check(p): + p.repr_failure(item, excinfo) + s = p.stringio.getvalue() + print s + assert re.search(">.*xyz", s) + assert re.search("NameError:.*xyz", s) + + self.gentest(check, tbstyle="short") + self.gentest(check, fulltrace=True) + self.gentest(check, showlocals=True) Modified: py/branch/event/py/test2/testing/test_session.py ============================================================================== --- py/branch/event/py/test2/testing/test_session.py (original) +++ py/branch/event/py/test2/testing/test_session.py Thu Feb 14 22:00:50 2008 @@ -179,9 +179,9 @@ sorter = suptest.events_run_example("brokenrepr.py") passed, skipped, failed = sorter.listoutcomes() assert len(failed) == 2 - out = failed[0].excinfo.exconly() + out = failed[0].exconly assert out.find("""[Exception("Ha Ha fooled you, I'm a broken repr().") raised in repr()]""") != -1 #' - out = failed[1].excinfo.exconly() + out = failed[1].exconly assert out.find("[unknown exception raised in repr()]") != -1 def test_collect_only_with_various_situations(self): @@ -249,9 +249,9 @@ assert len(skipped) == 0 assert len(passed) == 1 assert len(failed) == 3 - assert failed[0].item.name == "test_one_one" - assert failed[1].item.name == "test_other" - assert failed[2].item.name == "test_two" + assert failed[0].dottedpath(sorter.config).endswith("test_one_one") + assert failed[1].dottedpath(sorter.config).endswith("test_other") + assert failed[2].dottedpath(sorter.config).endswith("test_two") def test_capture_info_on_event(self): tfile = suptest.makeuniquepyfile(""" From hpk at codespeak.net Fri Feb 15 14:00:42 2008 From: hpk at codespeak.net (hpk at codespeak.net) Date: Fri, 15 Feb 2008 14:00:42 +0100 (CET) Subject: [py-svn] r51525 - py/branch/event/py/test2/testing Message-ID: <20080215130042.8680A1684C3@codespeak.net> Author: hpk Date: Fri Feb 15 14:00:40 2008 New Revision: 51525 Modified: py/branch/event/py/test2/testing/suptest.py py/branch/event/py/test2/testing/test_outcome.py py/branch/event/py/test2/testing/test_session.py py/branch/event/py/test2/testing/test_setup_nested.py Log: * refactored setup tests * introduced some more helpers for testing examples * unskip generator setup test Modified: py/branch/event/py/test2/testing/suptest.py ============================================================================== --- py/branch/event/py/test2/testing/suptest.py (original) +++ py/branch/event/py/test2/testing/suptest.py Fri Feb 15 14:00:40 2008 @@ -35,6 +35,11 @@ sorter.session.main() return sorter +def events_from_runsource(source): + source = py.code.Source(source) + tfile = makeuniquepyfile(source) + return events_from_cmdline([tfile]) + def events_from_session(session): sorter = EventSorter(session.config, session) session.main() @@ -76,6 +81,12 @@ def countoutcomes(self): return map(len, self.listoutcomes()) + def assertoutcome(self, passed=0, skipped=0, failed=0): + realpassed, realskipped, realfailed = self.listoutcomes() + assert passed == len(realpassed) + assert skipped == len(realskipped) + assert failed == len(realfailed) + def getfailedcollections(self): l = [] for ev in self.get(repevent.CollectionFinish): @@ -83,6 +94,19 @@ l.append(ev) return l + def getreport(self, inamepart): + """ return a testreport whose dotted import path matches """ + l = [] + for rep in self.get(repevent.ItemTestReport): + dp = rep.dottedpath(self.config) + if dp.find(inamepart) != -1: + l.append(rep) + if len(l) != 1: + raise ValueError("did not find exactly one testreport" + "found" + str(l)) + return l[0] + + counter = py.std.itertools.count().next def makeuniquepyfile(source): dirname = "test_%d" %(counter(),) Modified: py/branch/event/py/test2/testing/test_outcome.py ============================================================================== --- py/branch/event/py/test2/testing/test_outcome.py (original) +++ py/branch/event/py/test2/testing/test_outcome.py Fri Feb 15 14:00:40 2008 @@ -3,22 +3,6 @@ import marshal import py -def f1(): - 1 - 2 - 3 - 4 - raise ValueError(42) - -def f2(): - f1() - -def f3(): - f2() - -def f4(): - py.test.skip("argh!") - class TestRaises: def test_raises(self): py.test2.raises(ValueError, "int('qwe')") Modified: py/branch/event/py/test2/testing/test_session.py ============================================================================== --- py/branch/event/py/test2/testing/test_session.py (original) +++ py/branch/event/py/test2/testing/test_session.py Fri Feb 15 14:00:40 2008 @@ -79,11 +79,10 @@ assert passed == skipped == 0 def test_generator_yields_None(self): - p = suptest.makeuniquepyfile(""" + sorter = suptest.events_from_runsource(""" def test_1(): yield None """) - sorter = suptest.events_from_cmdline([p]) failures = sorter.getfailedcollections() out = failures[0].excinfo.exconly() i = out.find('TypeError') @@ -120,12 +119,11 @@ assert ev.item._testmycapture def test_raises_output(self): - p = suptest.makeuniquepyfile(''' + sorter = suptest.events_from_runsource(''' import py def test_raises_doesnt(): py.test2.raises(ValueError, int, "3") ''') - sorter = suptest.events_from_cmdline([p]) passed, skipped, failed = sorter.listoutcomes() assert len(failed) == 1 out = failed[0].exconly @@ -134,7 +132,7 @@ py.test2.fail("incorrect raises() output") def test_order_of_execution(self): - tfile = suptest.makeuniquepyfile(""" + sorter = suptest.events_from_runsource(""" l = [] def test_1(): l.append(1) @@ -153,7 +151,6 @@ def test_4(self): assert self.reslist == [1,2,1,2,3] """) - sorter = suptest.events_from_cmdline([tfile]) passed, skipped, failed = sorter.countoutcomes() assert failed == skipped == 0 assert passed == 7 @@ -253,20 +250,18 @@ assert failed[1].dottedpath(sorter.config).endswith("test_other") assert failed[2].dottedpath(sorter.config).endswith("test_two") - def test_capture_info_on_event(self): - tfile = suptest.makeuniquepyfile(""" + def test_capture_on_function(self): + sorter = suptest.events_from_runsource(""" def test_one(): - print 1 - print 2 - print 3 + print "passed" + def test_two(): + print "failed" + assert 0 """) - sorter = suptest.events_from_cmdline([tfile]) - passed, skipped, failed = sorter.listoutcomes() - assert len(skipped) == len(failed) == 0 - assert len(passed) == 1 - ev = passed[0] - py.test.skip("XXX get more info (e.g. capturing) available from events") - assert ev.outcome.passed - assert ev.outcome.stderr == "" - assert ev.outcome.stdout == "1\n2\n3\n" - + testrep = sorter.getreport("test_one") + assert testrep.stdout.startswith("passed") + assert not testrep.stderr + + testrep = sorter.getreport("test_two") + assert testrep.stdout.startswith("failed") + assert not testrep.stderr Modified: py/branch/event/py/test2/testing/test_setup_nested.py ============================================================================== --- py/branch/event/py/test2/testing/test_setup_nested.py (original) +++ py/branch/event/py/test2/testing/test_setup_nested.py Fri Feb 15 14:00:40 2008 @@ -1,64 +1,93 @@ - # # test correct setup/teardowns at # module, class, and instance level -modlevel = [] -def setup_module(module): - assert not modlevel - module.modlevel.append(42) - -def teardown_module(module): - modlevel.pop() - -def setup_function(function): - function.answer = 17 - -def teardown_function(function): - del function.answer - -def test_modlevel(): - assert modlevel[0] == 42 - assert test_modlevel.answer == 17 - -class TestSimpleClassSetup: - clslevel = [] - def setup_class(cls): - cls.clslevel.append(23) - - def teardown_class(cls): - cls.clslevel.pop() - - def test_classlevel(self): - assert self.clslevel[0] == 23 - - def test_modulelevel(self): - print modlevel - assert modlevel == [42] - -class TestInheritedClassSetupStillWorks(TestSimpleClassSetup): - def test_classlevel_anothertime(self): - assert self.clslevel == [23] - -class TestSetupTeardownOnInstance(TestSimpleClassSetup): - def setup_method(self, method): - self.clslevel.append(method.__name__) - - def teardown_method(self, method): - x = self.clslevel.pop() - assert x == method.__name__ - - def test_setup(self): - assert self.clslevel[-1] == 'test_setup' - - def test_generate(self): - assert self.clslevel[-1] == 'test_generate' - yield self.generated, 5 - assert self.clslevel[-1] == 'test_generate' - - def generated(self, value): - assert value == 5 - assert self.clslevel[-1] == 'test_generate' +import suptest -def test_teardown_method_worked(): - assert not TestSetupTeardownOnInstance.clslevel +def test_module_and_function_setup(): + sorter = suptest.events_from_runsource(""" + modlevel = [] + def setup_module(module): + assert not modlevel + module.modlevel.append(42) + + def teardown_module(module): + modlevel.pop() + + def setup_function(function): + function.answer = 17 + + def teardown_function(function): + del function.answer + + def test_modlevel(): + assert modlevel[0] == 42 + assert test_modlevel.answer == 17 + + class TestFromClass: + def test_module(self): + assert modlevel[0] == 42 + assert not hasattr(test_modlevel, 'answer') + """) + sorter.assertoutcome(passed=2) + +def test_class_setup(): + sorter = suptest.events_from_runsource(""" + class TestSimpleClassSetup: + clslevel = [] + def setup_class(cls): + cls.clslevel.append(23) + + def teardown_class(cls): + cls.clslevel.pop() + + def test_classlevel(self): + assert self.clslevel[0] == 23 + + class TestInheritedClassSetupStillWorks(TestSimpleClassSetup): + def test_classlevel_anothertime(self): + assert self.clslevel == [23] + + def test_cleanup(): + assert not TestSimpleClassSetup.clslevel + assert not TestInheritedClassSetupStillWorks.clslevel + """) + sorter.assertoutcome(passed=1+2+1) + +def test_method_setup(): + sorter = suptest.events_from_runsource(""" + class TestSetupMethod: + def setup_method(self, meth): + self.methsetup = meth + def teardown_method(self, meth): + del self.methsetup + + def test_some(self): + assert self.methsetup == self.test_some + + def test_other(self): + assert self.methsetup == self.test_other + """) + sorter.assertoutcome(passed=2) + +def test_generator_setup(): + sorter = suptest.events_from_runsource(""" + class TestSetupTeardownOnInstance: + def setup_class(cls): + cls.classsetup = True + + def setup_method(self, method): + self.methsetup = method + + def test_generate(self): + assert self.classsetup + assert self.methsetup == self.test_generate + yield self.generated, 5 + yield self.generated, 2 + + def generated(self, value): + assert self.classsetup + assert self.methsetup == self.test_generate + assert value == 5 + """) + sorter.assertoutcome(passed=1, failed=1) From hpk at codespeak.net Fri Feb 15 14:30:40 2008 From: hpk at codespeak.net (hpk at codespeak.net) Date: Fri, 15 Feb 2008 14:30:40 +0100 (CET) Subject: [py-svn] r51528 - py/branch/event/py/test2/testing Message-ID: <20080215133040.295A61684C8@codespeak.net> Author: hpk Date: Fri Feb 15 14:30:39 2008 New Revision: 51528 Modified: py/branch/event/py/test2/testing/test_collect.py py/branch/event/py/test2/testing/test_setup_nested.py Log: unskip and move some setup tests Modified: py/branch/event/py/test2/testing/test_collect.py ============================================================================== --- py/branch/event/py/test2/testing/test_collect.py (original) +++ py/branch/event/py/test2/testing/test_collect.py Fri Feb 15 14:30:39 2008 @@ -188,41 +188,6 @@ assert passed == 4 assert not skipped and not failed -def test_check_generator_collect_problems(): - tmp = py.test2.ensuretemp("gener_coll") - tmp.ensure("test_one.py").write(py.code.Source(""" - def setup_module(mod): - mod.x = [1,2,3] - - def check(zzz): - assert zzz - - def test_one(): - for i in x: - yield check, i - """)) - tmp.ensure("__init__.py") - col = py.test2.collect.Module(tmp.join("test_one.py")) - 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.test2.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.test2.collect.Module(tmp.join("test_one.py")) - l = list(col._tryiter()) - assert not hasattr(col.obj, 'x') - def test_check_directory_ordered(): tmpdir = py.test2.ensuretemp("test_check_directory_ordered") fnames = [] Modified: py/branch/event/py/test2/testing/test_setup_nested.py ============================================================================== --- py/branch/event/py/test2/testing/test_setup_nested.py (original) +++ py/branch/event/py/test2/testing/test_setup_nested.py Fri Feb 15 14:30:39 2008 @@ -2,6 +2,7 @@ # test correct setup/teardowns at # module, class, and instance level +import py import suptest def test_module_and_function_setup(): @@ -29,7 +30,10 @@ assert modlevel[0] == 42 assert not hasattr(test_modlevel, 'answer') """) - sorter.assertoutcome(passed=2) + rep = sorter.getreport("test_modlevel") + assert rep.passed + rep = sorter.getreport("test_module") + assert rep.passed def test_class_setup(): sorter = suptest.events_from_runsource(""" @@ -70,7 +74,7 @@ """) sorter.assertoutcome(passed=2) -def test_generator_setup(): +def test_method_generator_setup(): sorter = suptest.events_from_runsource(""" class TestSetupTeardownOnInstance: def setup_class(cls): @@ -91,3 +95,34 @@ assert value == 5 """) sorter.assertoutcome(passed=1, failed=1) + +def test_func_generator_setup(): + sorter = suptest.events_from_runsource(""" + import sys + + def setup_module(mod): + print "setup_module" + mod.x = [] + + def setup_function(fun): + print "setup_function" + x.append(1) + + def teardown_function(fun): + print "teardown_function" + x.pop() + + def test_one(): + assert x == [1] + def check(): + print "check" + print >>sys.stderr, "e" + assert x == [1] + yield check + assert x == [1] + """) + rep = sorter.getreport("test_one") + assert rep.passed + assert rep.stdout == "check\n" + assert rep.stderr == "e\n" + From guido at codespeak.net Fri Feb 15 15:09:38 2008 From: guido at codespeak.net (guido at codespeak.net) Date: Fri, 15 Feb 2008 15:09:38 +0100 (CET) Subject: [py-svn] r51535 - in py/branch/guido-svn-auth/py: . path/svn path/svn/testing Message-ID: <20080215140938.D756E16847F@codespeak.net> Author: guido Date: Fri Feb 15 15:09:38 2008 New Revision: 51535 Modified: py/branch/guido-svn-auth/py/conftest.py py/branch/guido-svn-auth/py/path/svn/auth.txt py/branch/guido-svn-auth/py/path/svn/svncommon.py py/branch/guido-svn-auth/py/path/svn/testing/test_auth.py py/branch/guido-svn-auth/py/path/svn/wccommand.py Log: Added 'functional' argument to SvnAuth, renamed 'auth_cache' to 'cache_auth' to make it clearer it's a Boolean, not some cache object, fixed some small bugs in the path methods, added functional test. Modified: py/branch/guido-svn-auth/py/conftest.py ============================================================================== --- py/branch/guido-svn-auth/py/conftest.py (original) +++ py/branch/guido-svn-auth/py/conftest.py Fri Feb 15 15:09:38 2008 @@ -33,6 +33,9 @@ action='store', dest='docpath', default="doc", type='string', help="relative path to doc output location (relative from py/)"), + Option('', '--runslowtests', + action="store_true", dest="runslowtests", default=False, + help="run slow tests)"), ) dist_rsync_roots = ['.'] Modified: py/branch/guido-svn-auth/py/path/svn/auth.txt ============================================================================== --- py/branch/guido-svn-auth/py/path/svn/auth.txt (original) +++ py/branch/guido-svn-auth/py/path/svn/auth.txt Fri Feb 15 15:09:38 2008 @@ -1,9 +1,9 @@ SVN authentication support ========================== -This document describes authentication support to both py.path.svnwc and +This document describes authentication support for both py.path.svnwc and py.path.svnurl (yet in its implemention phase). This allows using the library -in a completely automated situation, without having to provide svn credentials +in a completely automated fashion, without having to provide svn credentials interactively. Current implementation @@ -15,8 +15,8 @@ join(), ensure(), etc. To pass credentials to path objects, an SvnAuth class needs to be created to -hold them. This is then passed to the constructor or methods, usually as -the 'auth' keyword argument. +hold them. This is then passed to the constructor or methods as the 'auth' +keyword argument. It is configurable whether the credentials are stored on disk. Storing them is useful in certain situations (executive access to the repository will not @@ -26,12 +26,20 @@ be controlled by passing a False value for the 'cache_auth' argument to SvnAuth. +Also it is configurable what behaviour is displayed when the credentials do not +validate: if a keyword argument to the SvnAuth constructor called 'interactive' +has a True value (which is currently the default (XXX I think this should be +changed!)), an interactive prompt is displayed - this is useful for terminal +applications where you want to have an interactive fallback. When this has a +False value, an exception is raised (XXX define the exception properly). + Code examples ------------- So, tying this together, code using this feature would look something like:: - >>> auth = py.path.SvnAuth('user', 'pass', cache_auth=False) + >>> auth = py.path.SvnAuth('user', 'pass', cache_auth=False, + ... interactive=False) >>> wc = py.path.svnwc(url, auth=auth) Open issues @@ -49,21 +57,6 @@ Current idea: ignore this and let the client handle (so no passing auth around to the children). -* Functional testing - - Functional testing is relatively hard, and will not work on all systems. It - looks like a setup using 'svnserve' is possible, but it will be slow and - provide relatively little advantages, apart from testing the integration. - Holger suggested that perhaps functional tests could be skipped in favour - of only unit tests. - -* Non-interactive sessions - - I still think having a way to tell the system we don't want the session to - be interactive would be very useful... It is unacceptable for certain types - of applications to block on user input. Should we have 'interactive' as an - argument to the methods/constructor, with a default value of True? - * Affected methods - switch @@ -74,3 +67,4 @@ - diff (when using older revisions?) - commit - log + - status (for locking, etc.?) Modified: py/branch/guido-svn-auth/py/path/svn/svncommon.py ============================================================================== --- py/branch/guido-svn-auth/py/path/svn/svncommon.py (original) +++ py/branch/guido-svn-auth/py/path/svn/svncommon.py Fri Feb 15 15:09:38 2008 @@ -330,21 +330,27 @@ fspath = '%s at HEAD' % (fspath,) return 'file://%s' % (fspath,) - class SvnAuth(object): """ container for auth information for Subversion """ - def __init__(self, username, password, auth_cache=True): + def __init__(self, username, password, cache_auth=True, interactive=True): self.username = username self.password = password - self.auth_cache = auth_cache + self.cache_auth = cache_auth + self.interactive = interactive - def makecmdoptions(self): + def makecmdoptions(self): uname = self.username.replace('"', '\\"') passwd = self.password.replace('"', '\\"') - ret = '--username="%s" --password="%s"' % (uname, passwd) - if not self.auth_cache: - ret += ' --no-auth-cache' - return ret + ret = [] + if uname: + ret.append('--username="%s"' % (uname,)) + if passwd: + ret.append('--password="%s"' % (passwd,)) + if not self.cache_auth: + ret.append('--no-auth-cache') + if not self.interactive: + ret.append('--non-interactive') + return ' '.join(ret) def __str__(self): return "" %(self.username,) Modified: py/branch/guido-svn-auth/py/path/svn/testing/test_auth.py ============================================================================== --- py/branch/guido-svn-auth/py/path/svn/testing/test_auth.py (original) +++ py/branch/guido-svn-auth/py/path/svn/testing/test_auth.py Fri Feb 15 15:09:38 2008 @@ -1,5 +1,57 @@ import py from py.path import SvnAuth +import svntestbase +from threading import Thread +import time +from py.__.misc.killproc import killproc +from py.__.conftest import option + +def make_repo_auth(repo, userdata): + """ write config to repo + + user information in userdata is used for auth + userdata has user names as keys, and a tuple (password, readwrite) as + values, where 'readwrite' is either 'r' or 'rw' + """ + confdir = py.path.local(repo).join('conf') + confdir.join('svnserve.conf').write('''\ +[general] +anon-access = none +password-db = passwd +authz-db = authz +realm = TestRepo +''') + authzdata = '[/]\n' + passwddata = '[users]\n' + for user in userdata: + authzdata += '%s = %s\n' % (user, userdata[user][1]) + passwddata += '%s = %s\n' % (user, userdata[user][0]) + confdir.join('authz').write(authzdata) + confdir.join('passwd').write(passwddata) + +def serve_bg(repopath): + pidfile = repopath.join('pid') + port = 10000 + e = None + while port < 10010: + cmd = 'svnserve -d -T --listen-port=%d --pid-file=%s -r %s' % ( + port, pidfile, repopath) + try: + py.process.cmdexec(cmd) + except py.process.cmdexec.Error, e: + pass + else: + # XXX we assume here that the pid file gets written somewhere, I + # guess this should be relatively safe... (I hope, at least?) + while True: + pid = pidfile.read() + if pid: + break + # needs a bit more time to boot + time.sleep(0.1) + return port, int(pid) + port += 1 + raise IOError('could not start svnserve: %s' % (e,)) class TestSvnAuth(object): def test_basic(self): @@ -16,9 +68,21 @@ auth = py.path.SvnAuth('fo"o', '"ba\'r"') assert auth.makecmdoptions() == '--username="fo\\"o" --password="\\"ba\'r\\""' - def test_makecmdoptions_no_auth_cache(self): - auth = py.path.SvnAuth('foo', 'bar', auth_cache=False) - assert auth.makecmdoptions() == '--username="foo" --password="bar" --no-auth-cache' + def test_makecmdoptions_no_cache_auth(self): + auth = py.path.SvnAuth('foo', 'bar', cache_auth=False) + assert auth.makecmdoptions() == ('--username="foo" --password="bar" ' + '--no-auth-cache') + + def test_makecmdoptions_no_interactive(self): + auth = py.path.SvnAuth('foo', 'bar', interactive=False) + assert auth.makecmdoptions() == ('--username="foo" --password="bar" ' + '--non-interactive') + + def test_makecmdoptions_no_interactive_no_cache_auth(self): + auth = py.path.SvnAuth('foo', 'bar', cache_auth=False, + interactive=False) + assert auth.makecmdoptions() == ('--username="foo" --password="bar" ' + '--no-auth-cache --non-interactive') class svnwc_no_svn(py.path.svnwc): def __init__(self, *args, **kwargs): @@ -45,7 +109,7 @@ def test_checkout_no_cache_auth(self): wc = svnwc_no_svn('foo') - auth = SvnAuth('user', 'pass', auth_cache=False) + auth = SvnAuth('user', 'pass', cache_auth=False) wc.checkout('url', auth=auth) assert wc.commands == [('co', 'url', ('--username="user" --password="pass" ' @@ -57,3 +121,169 @@ wc.checkout('url') assert wc.commands == [('co', 'url', '--username="user" --password="pass"')] + +class TestSvnAuthFunctional(object): + def setup_class(cls): + if not option.runslowtests: + py.test.skip('skipping slow functional tests - use --runslowtests ' + 'to override') + + def setup_method(self, meth): + func_name = meth.im_func.func_name + self.repo = svntestbase.make_test_repo('TestSvnAuthFunctional.%s' % ( + func_name,)) + self.repopath = py.path.local(str(self.repo)[7:]) + self.temppath = py.test.ensuretemp('TestSvnAuthFunctional.%s' % ( + func_name)) + + def test_checkout_constructor_arg(self): + port, pid = self._start_svnserve() + try: + auth = py.path.SvnAuth('johnny', 'foo', cache_auth=False) + wc = py.path.svnwc(self.temppath, auth=auth) + wc.checkout( + 'svn://localhost:%s/%s' % (port, self.repopath.basename)) + assert wc.join('.svn').check() + finally: + # XXX can we do this in a teardown_method too? not sure if that's + # guaranteed to get called... + killproc(pid) + + def test_checkout_function_arg(self): + port, pid = self._start_svnserve() + try: + auth = py.path.SvnAuth('johnny', 'foo', cache_auth=False) + wc = py.path.svnwc(self.temppath) + wc.checkout( + 'svn://localhost:%s/%s' % (port, self.repopath.basename), + auth=auth) + assert wc.join('.svn').check() + finally: + killproc(pid) + + def test_checkout_failing_non_interactive(self): + port, pid = self._start_svnserve() + try: + auth = py.path.SvnAuth('johnny', 'bar', cache_auth=False, + interactive=False) + wc = py.path.svnwc(self.temppath, auth) + py.test.raises(Exception, + ("wc.checkout('svn://localhost:%s/%s' % " + "(port, self.repopath.basename))")) + finally: + killproc(pid) + + def test_log(self): + port, pid = self._start_svnserve() + try: + auth = py.path.SvnAuth('johnny', 'foo', cache_auth=False, + interactive=False) + wc = py.path.svnwc(self.temppath, auth) + wc.checkout( + 'svn://localhost:%s/%s' % (port, self.repopath.basename)) + foo = wc.ensure('foo.txt') + wc.commit('added foo.txt') + log = foo.log(auth=auth) + assert len(log) == 1 + assert log[0].msg == 'added foo.txt' + finally: + killproc(pid) + + def test_switch(self): + port, pid = self._start_svnserve() + try: + auth = py.path.SvnAuth('johnny', 'foo', cache_auth=False, + interactive=False) + wc = py.path.svnwc(self.temppath, auth=auth) + svnurl = 'svn://localhost:%s/%s' % (port, self.repopath.basename) + wc.checkout(svnurl) + wc.ensure('foo', dir=True).ensure('foo.txt').write('foo') + wc.commit('added foo dir with foo.txt file') + wc.ensure('bar', dir=True) + wc.commit('added bar dir') + bar = wc.join('bar') + bar.switch(svnurl + '/foo', auth=auth) + assert bar.join('foo.txt') + finally: + killproc(pid) + + def test_update(self): + port, pid = self._start_svnserve() + try: + auth = py.path.SvnAuth('johnny', 'foo', cache_auth=False, + interactive=False) + wc1 = py.path.svnwc(self.temppath.ensure('wc1', dir=True), + auth=auth) + wc2 = py.path.svnwc(self.temppath.ensure('wc2', dir=True), + auth=auth) + wc1.checkout( + 'svn://localhost:%s/%s' % (port, self.repopath.basename)) + wc2.checkout( + 'svn://localhost:%s/%s' % (port, self.repopath.basename)) + wc1.ensure('foo', dir=True) + wc1.commit('added foo dir') + wc2.update() + assert wc2.join('foo').check() + + auth = py.path.SvnAuth('unknown', 'unknown', interactive=False) + py.test.raises(Exception, 'wc2.update(auth=auth)') + finally: + killproc(pid) + + def test_lock_unlock_status(self): + port, pid = self._start_svnserve() + try: + auth = py.path.SvnAuth('johnny', 'foo', cache_auth=False, + interactive=False) + wc = py.path.svnwc(self.temppath, auth=auth) + wc.checkout( + 'svn://localhost:%s/%s' % (port, self.repopath.basename,)) + wc.ensure('foo', file=True) + wc.commit('added foo file') + foo = wc.join('foo') + foo.lock(auth=auth) + status = foo.status(auth=auth) + assert status.locked + foo.unlock(auth=auth) + status = foo.status(auth=auth) + assert not status.locked + + auth = py.path.SvnAuth('unknown', 'unknown', interactive=False) + py.test.raises(Exception, 'foo.lock(auth=auth)') + py.test.raises(Exception, 'foo.unlock(auth=auth)') + finally: + killproc(pid) + + def test_diff(self): + port, pid = self._start_svnserve() + try: + auth = py.path.SvnAuth('johnny', 'foo', cache_auth=False, + interactive=False) + wc = py.path.svnwc(self.temppath, auth=auth) + wc.checkout( + 'svn://localhost:%s/%s' % (port, self.repopath.basename,)) + wc.ensure('foo', file=True) + wc.commit('added foo file') + wc.update() + rev = int(wc.status().rev) + foo = wc.join('foo') + foo.write('bar') + diff = foo.diff() + assert '\n+bar\n' in diff + foo.commit('added some content', auth=auth) + diff = foo.diff() + assert not diff + diff = foo.diff(rev=rev, auth=auth) + assert '\n+bar\n' in diff + + auth = py.path.SvnAuth('unknown', 'unknown', interactive=False) + py.test.raises(Exception, 'foo.diff(rev=rev, auth=auth)') + finally: + killproc(pid) + + def _start_svnserve(self): + make_repo_auth(self.repopath, {'johnny': ('foo', 'rw')}) + try: + return serve_bg(self.repopath.dirpath()) + except IOError, e: + py.test.skip(str(e)) Modified: py/branch/guido-svn-auth/py/path/svn/wccommand.py ============================================================================== --- py/branch/guido-svn-auth/py/path/svn/wccommand.py (original) +++ py/branch/guido-svn-auth/py/path/svn/wccommand.py Fri Feb 15 15:09:38 2008 @@ -116,7 +116,7 @@ def switch(self, url, auth=None): """ switch to given URL. """ - self._authsvn('switch', url, [], auth=auth) + self._authsvn('switch', [url], auth=auth) def checkout(self, url=None, rev=None, auth=None): """ checkout from url to local wcpath. """ @@ -235,7 +235,7 @@ except: pass - def status(self, updates=0, rec=0, externals=0): + def status(self, updates=0, rec=0, externals=0, auth=None): """ return (collective) Status object for this file. """ # http://svnbook.red-bean.com/book.html#svn-ch-3-sect-4.3.1 # 2201 2192 jum test @@ -262,7 +262,8 @@ update_rev = None - out = self._svn('status -v %s %s %s' % (updates, rec, externals)) + cmd = 'status -v %s %s %s' % (updates, rec, externals) + out = self._authsvn(cmd, auth=auth) rootstatus = WCStatus(self) for line in out.split('\n'): if not line.strip(): @@ -351,7 +352,7 @@ args = [] if rev is not None: args.append("-r %d" % rev) - out = self._authsvn('diff', args, auth=auth) + out = self._authsvn('diff', args, auth=auth) return out def blame(self): @@ -550,7 +551,7 @@ verbose_opt = verbose and "-v" or "" locale_env = svncommon.fixlocale() # some blather on stderr - auth_opt = self._makeauthargs(auth) + auth_opt = self._makeauthoptions(auth) stdin, stdout, stderr = os.popen3(locale_env + 'svn log --xml %s %s %s "%s"' % ( rev_opt, verbose_opt, auth_opt, From hpk at codespeak.net Sun Feb 17 18:14:27 2008 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sun, 17 Feb 2008 18:14:27 +0100 (CET) Subject: [py-svn] r51562 - in py/branch/event/py/test2: . testing Message-ID: <20080217171427.551291683F4@codespeak.net> Author: hpk Date: Sun Feb 17 18:14:25 2008 New Revision: 51562 Modified: py/branch/event/py/test2/executor.py py/branch/event/py/test2/testing/test_session.py Log: fix pdb test, don't automatically raise SystemExit with "--pdb" - append "-x" if you want this. Modified: py/branch/event/py/test2/executor.py ============================================================================== --- py/branch/event/py/test2/executor.py (original) +++ py/branch/event/py/test2/executor.py Sun Feb 17 18:14:25 2008 @@ -55,9 +55,6 @@ self._fillreport(testrep, excinfo) if self.config.option.usepdb: py.__.test2.custompdb.post_mortem(excinfo._excinfo[2]) - # XXX hmm, we probably will not like to continue from that - # point - raise SystemExit() else: testrep.passed = True return testrep Modified: py/branch/event/py/test2/testing/test_session.py ============================================================================== --- py/branch/event/py/test2/testing/test_session.py (original) +++ py/branch/event/py/test2/testing/test_session.py Sun Feb 17 18:14:25 2008 @@ -211,7 +211,7 @@ def test_pdb_run(self): tfile = suptest.makeuniquepyfile(""" - def test_1(): + def test_usepdb(): assert 0 """) l = [] @@ -219,17 +219,16 @@ l.append(args) py.magic.patch(py.__.test2.custompdb, 'post_mortem', mypdb) try: - sorter = suptest.initsorter_from_cmdline([tfile, '--pdb']) - py.test.raises(SystemExit, sorter.session.main) - passed, skipped, failed = sorter.countoutcomes() - assert passed == skipped == 0 - assert len(l) == 1 - # XXX assert failed == 1 - py.test.skip("XXX streamline event generation with --pdb") - # XXX add some more checks? + sorter = suptest.events_from_cmdline([tfile, '--pdb']) finally: py.magic.revert(py.__.test2.custompdb, 'post_mortem') + rep = sorter.getreport("test_usepdb") + assert rep.failed + assert len(l) == 1 + tb = py.code.Traceback(l[0][0]) + assert tb[-1].name == "test_usepdb" + def test_basic_testitem_events(self): tfile = suptest.makeuniquepyfile(""" def test_one(): From hpk at codespeak.net Sun Feb 17 19:39:34 2008 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sun, 17 Feb 2008 19:39:34 +0100 (CET) Subject: [py-svn] r51563 - in py/branch/event/py/test2: . testing Message-ID: <20080217183934.C13B316844D@codespeak.net> Author: hpk Date: Sun Feb 17 19:39:33 2008 New Revision: 51563 Modified: py/branch/event/py/test2/outcome.py py/branch/event/py/test2/testing/test_outcome.py Log: enhance py.test2.deprecated call a bit. Modified: py/branch/event/py/test2/outcome.py ============================================================================== --- py/branch/event/py/test2/outcome.py (original) +++ py/branch/event/py/test2/outcome.py Sun Feb 17 19:39:33 2008 @@ -103,7 +103,9 @@ py.magic.patch(py.std.warnings, 'warn_explicit', warn_explicit) try: - _ = func(*args, **kwargs) + ret = func(*args, **kwargs) finally: py.magic.revert(py.std.warnings, 'warn_explicit') - assert l + if not l: + raise AssertionError("%r did not produce DeprecationWarning" %(func,)) + return ret Modified: py/branch/event/py/test2/testing/test_outcome.py ============================================================================== --- py/branch/event/py/test2/testing/test_outcome.py (original) +++ py/branch/event/py/test2/testing/test_outcome.py Sun Feb 17 19:39:33 2008 @@ -23,6 +23,7 @@ def dep(i): if i == 0: py.std.warnings.warn("is deprecated", DeprecationWarning) + return 42 reg = {} def dep_explicit(i): @@ -31,12 +32,17 @@ filename="hello", lineno=3) def test_deprecated_call_raises(): - py.test2.raises(AssertionError, + excinfo = py.test2.raises(AssertionError, "py.test2.deprecated_call(dep, 3)") + assert str(excinfo).find("did not produce") != -1 def test_deprecated_call(): py.test2.deprecated_call(dep, 0) +def test_deprecated_call_ret(): + ret = py.test2.deprecated_call(dep, 0) + assert ret == 42 + def test_deprecated_call_preserves(): r = py.std.warnings.onceregistry.copy() f = py.std.warnings.filters[:] From hpk at codespeak.net Sun Feb 17 19:49:20 2008 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sun, 17 Feb 2008 19:49:20 +0100 (CET) Subject: [py-svn] r51564 - in py/branch/event/py/test2: . testing Message-ID: <20080217184920.E6E0016840C@codespeak.net> Author: hpk Date: Sun Feb 17 19:49:19 2008 New Revision: 51564 Modified: py/branch/event/py/test2/collect.py py/branch/event/py/test2/genitem.py py/branch/event/py/test2/item.py py/branch/event/py/test2/testing/test_collect.py py/branch/event/py/test2/testing/test_session.py Log: * disambiguate Collectors and Test Items. deprecate collector.run() in favour of collector.listdir(). * forget about one skipped test (re-running test from py/doc) because i have not the slightest clue about it, even after checking the revision which introduced it. Modified: py/branch/event/py/test2/collect.py ============================================================================== --- py/branch/event/py/test2/collect.py (original) +++ py/branch/event/py/test2/collect.py Sun Feb 17 19:49:19 2008 @@ -34,7 +34,7 @@ return self._config.getvalue(name, self.fspath) return property(fget) -class Collector(object): +class Base(object): """ Collector instances are iteratively generated (through their run() and join() methods) and form a tree. attributes:: @@ -49,14 +49,6 @@ self._config = getattr(parent, '_config', py.test2.config) self.fspath = getattr(parent, 'fspath', None) - Module = configproperty('Module') - DoctestFile = configproperty('DoctestFile') - Directory = configproperty('Directory') - Class = configproperty('Class') - Instance = configproperty('Instance') - Function = configproperty('Function') - Generator = configproperty('Generator') - _stickyfailure = None def __repr__(self): @@ -78,26 +70,7 @@ s2 = other._getsortvalue() #print "cmp", s1, s2 return cmp(s1, s2) - - - def run(self): - """ returns a list of names available from this collector. - You can return an empty list. Callers of this method - must take care to catch exceptions properly. The session - object guards its calls to ``colitem.run()`` in its - ``session.runtraced(colitem)`` method, including - catching of stdout. - """ - raise NotImplementedError("abstract") - - def join(self, name): - """ return a child item for the given name. Usually the - session feeds the join method with each name obtained - from ``colitem.run()``. If the return value is None - it means the ``colitem`` was not able to resolve - with the given name. - """ - + def obj(): def fget(self): try: @@ -148,7 +121,7 @@ if name: next = cur.join(name) if next is None: - existingnames = cur.run() + existingnames = cur.listdir() msg = ("Collector %r does not have name %r " "existing names are: %s" % (cur, name, existingnames)) @@ -210,6 +183,35 @@ """ return self._config.get_collector_trail(self) +class Collector(Base): + Module = configproperty('Module') + DoctestFile = configproperty('DoctestFile') + Directory = configproperty('Directory') + Class = configproperty('Class') + Instance = configproperty('Instance') + Function = configproperty('Function') + Generator = configproperty('Generator') + + def run(self): + """ deprecated: use listdir(). """ + py.std.warnings.warn("deprecated: use listdir()", category=DeprecationWarning) + return self.listdir() + + def listdir(self): + """ returns a list of names available from this collector. + You can return an empty list. Callers of this method + must take care to catch exceptions properly. + """ + raise NotImplementedError("abstract") + + def join(self, name): + """ return a child item for the given name. Usually the + session feeds the join method with each name obtained + from ``colitem.run()``. If the return value is None + it means the ``colitem`` was not able to resolve + with the given name. + """ + class FSCollector(Collector): def __init__(self, fspath, parent=None): fspath = py.path.local(fspath) @@ -228,10 +230,7 @@ if path.check(dir=1, dotfile=0): return path.basename not in ('CVS', '_darcs', '{arch}') - def list(self): - return [self.join(x) for x in self.run()] - - def run(self): + def listdir(self): files = [] dirs = [] for p in self.fspath.listdir(): @@ -307,7 +306,7 @@ self._name2items_exception = py.std.sys.exc_info() raise - def run(self): + def listdir(self): self._prepare() itemlist = self._name2items.values() itemlist.sort() @@ -319,10 +318,10 @@ class Module(FSCollector, PyCollectorMixin): - def run(self): + def listdir(self): if getattr(self.obj, 'disabled', 0): return [] - return super(Module, self).run() + return super(Module, self).listdir() def join(self, name): res = super(Module, self).join(name) @@ -369,7 +368,7 @@ class Class(PyCollectorMixin, Collector): - def run(self): + def listdir(self): if getattr(self.obj, 'disabled', 0): return [] return ["()"] @@ -447,7 +446,7 @@ return meth(self.obj) class Generator(FunctionMixin, PyCollectorMixin, Collector): - def run(self): + def listdir(self): self._prepare() itemlist = self._name2items return [itemlist["[%d]" % num].name for num in xrange(len(itemlist))] @@ -473,7 +472,7 @@ return call, args class DoctestFile(PyCollectorMixin, FSCollector): - def run(self): + def listdir(self): return [self.fspath.basename] def join(self, name): Modified: py/branch/event/py/test2/genitem.py ============================================================================== --- py/branch/event/py/test2/genitem.py (original) +++ py/branch/event/py/test2/genitem.py Sun Feb 17 19:49:19 2008 @@ -17,10 +17,11 @@ else: yield next else: + assert isinstance(next, py.test2.collect.Collector), next bus.notify(repevent.CollectionStart(next)) excinfo = None try: - cols = [next.join(x) for x in next.run()] + cols = [next.join(x) for x in next.listdir()] for x in genitems(config, cols, keywordexpr): yield x except sysex: Modified: py/branch/event/py/test2/item.py ============================================================================== --- py/branch/event/py/test2/item.py (original) +++ py/branch/event/py/test2/item.py Sun Feb 17 19:49:19 2008 @@ -1,7 +1,6 @@ import py -from py.__.test2 import outcome -from py.__.test2.collect import FunctionMixin +from py.__.test2.collect import FunctionMixin, Base _dummy = object() @@ -30,7 +29,7 @@ col.setup() self.stack.append(col) -class Item(py.test2.collect.Collector): +class Item(Base): def startcapture(self): self._config._startcapture(self, path=self.fspath) Modified: py/branch/event/py/test2/testing/test_collect.py ============================================================================== --- py/branch/event/py/test2/testing/test_collect.py (original) +++ py/branch/event/py/test2/testing/test_collect.py Sun Feb 17 19:49:19 2008 @@ -8,11 +8,26 @@ def setup_module(mod): mod.tmpdir = py.test2.ensuretemp(mod.__name__) +def test_collect_versus_item(): + path = setupdata.getexamplefile("filetest.py") + col = py.test2.collect.Module(path) + assert not isinstance(col, py.test2.collect.Item) + item = col.join("test_one") + assert not hasattr(item, "join") + assert not isinstance(item, py.test2.collect.Collector) + +def test_collector_deprecated_run_method(): + path = setupdata.getexamplefile("filetest.py") + col = py.test2.collect.Module(path) + res1 = py.test2.deprecated_call(col.run) + res2 = col.listdir() + assert res1 == res2 + def test_failing_import_execfile(): dest = setupdata.getexamplefile('failingimport.py') col = py.test2.collect.Module(dest) - py.test2.raises(ImportError, col.run) - py.test2.raises(ImportError, col.run) + py.test2.raises(ImportError, col.listdir) + py.test2.raises(ImportError, col.listdir) def test_collect_listnames_and_back(): path = setupdata.getexamplefile("filetest.py") @@ -31,7 +46,7 @@ def test_finds_tests(): fn = setupdata.getexamplefile('filetest.py') col = py.test2.collect.Module(fn) - l = col.run() + l = col.listdir() assert len(l) == 2 assert l[0] == 'test_one' assert l[1] == 'TestClass' @@ -41,8 +56,9 @@ tmp.ensure('test_found.py') tmp.ensure('found_test.py') - colitem = py.test2.collect.Directory(tmp) - items = colitem.list() + col = py.test2.collect.Directory(tmp) + items = [col.join(x) for x in col.listdir()] + assert len(items) == 2 assert items[1].name == 'test_found.py' assert items[0].name == 'found_test.py' @@ -58,7 +74,7 @@ tmp.ensure('test_found.py') colitem = py.test2.collect.Directory(tmp) - items = colitem.run() + items = colitem.listdir() assert len(items) == 2 assert 'normal' in items assert 'test_found.py' in items @@ -69,46 +85,46 @@ return p.check(fnmatch='testspecial*.py') filetest = setupdata.getexamplefile("testspecial_importerror.py") mydir = MyDirectory(filetest.dirpath()) - l = mydir.run() + l = mydir.listdir() assert len(l) == 1 - item = mydir.join(l[0]) - assert isinstance(item, py.test2.collect.Module) - py.test2.raises(ImportError, item.run) + col = mydir.join(l[0]) + assert isinstance(col, py.test2.collect.Module) + py.test2.raises(ImportError, col.listdir) def test_module_file_not_found(): fn = tmpdir.join('nada','no') col = py.test2.collect.Module(fn) - py.test2.raises(py.error.ENOENT, col.run) + py.test2.raises(py.error.ENOENT, col.listdir) def test_syntax_error_in_module(): modpath = setupdata.getexamplefile("syntax_error.py") col = py.test2.collect.Module(modpath) - py.test2.raises(SyntaxError, col.run) + py.test2.raises(SyntaxError, col.listdir) def test_disabled_class(): col = py.test2.collect.Module(setupdata.getexamplefile('disabled.py')) - l = col.run() + l = col.listdir() assert len(l) == 1 colitem = col.join(l[0]) assert isinstance(colitem, py.test2.collect.Class) - assert not colitem.run() + assert not colitem.listdir() def test_disabled_module(): p = setupdata.getexamplefile("disabled_module.py") col = py.test2.collect.Module(p) - l = col.run() + l = col.listdir() assert len(l) == 0 def test_generative_simple(): tfile = setupdata.getexamplefile('test_generative.py') col = py.test2.collect.Module(tfile) - l = col.run() + l = col.listdir() assert len(l) == 2 l = col.multijoin(l) generator = l[0] assert isinstance(generator, py.test2.collect.Generator) - l2 = generator.run() + l2 = generator.listdir() assert len(l2) == 2 l2 = generator.multijoin(l2) assert isinstance(l2[0], py.test2.collect.Function) @@ -118,13 +134,13 @@ assert l2[0].obj.func_name == 'func1' - classlist = l[1].run() + classlist = l[1].listdir() assert len(classlist) == 1 classlist = l[1].multijoin(classlist) cls = classlist[0] - generator = cls.join(cls.run()[0]) + generator = cls.join(cls.listdir()[0]) assert isinstance(generator, py.test2.collect.Generator) - l2 = generator.run() + l2 = generator.listdir() assert len(l2) == 2 l2 = generator.multijoin(l2) assert isinstance(l2[0], py.test2.collect.Function) @@ -201,22 +217,9 @@ tmpdir.ensure('adir', dir=1) fnames.insert(10, 'adir') col = py.test2.collect.Directory(tmpdir) - names = col.run() + names = col.listdir() assert names == fnames -def test_documentation_virtual_collector_interaction(): - py.test.skip("figure out this test and rewrite independent of py/doc.") - rootdir = py.path.local(py.__file__).dirpath("doc") - # HACK - from py.__.doc import conftest as conf - old = conf.option.forcegen - try: - conf.option.forcegen = 1 - col = py.test2.collect.Directory(rootdir) - x = list(col._tryiter(yieldtype=py.test2.collect.Function)) - finally: - conf.option.forcegen = old - def test_check_random_inequality(): path = setupdata.getexamplefile("funcexamples.py") col = py.test2.collect.Module(path) @@ -266,7 +269,7 @@ self.tmp.ensure("subdir", "conftest.py").write(py.code.Source(""" import py class Directory(py.test2.collect.Directory): - def run(self): + def listdir(self): py.test2.skip("intentional") """)) items, events = self._genitems() @@ -397,4 +400,3 @@ items, events = self._genitems(x) assert len(items) == 1 assert isinstance(items[0], DoctestText) - Modified: py/branch/event/py/test2/testing/test_session.py ============================================================================== --- py/branch/event/py/test2/testing/test_session.py (original) +++ py/branch/event/py/test2/testing/test_session.py Sun Feb 17 19:49:19 2008 @@ -184,7 +184,7 @@ def test_collect_only_with_various_situations(self): p = suptest.makeuniquepyfile(""" def test_one(): - pass + raise ValueError() class TestX: def test_method_one(self): @@ -203,9 +203,11 @@ assert not sorter.get(repevent.ItemStart) assert not sorter.get(repevent.ItemFinish) + assert not sorter.get(repevent.ItemTestReport) started = sorter.get(repevent.CollectionStart) finished = sorter.get(repevent.CollectionFinish) assert len(started) == len(finished) + assert len(started) == 8 failedcollections = sorter.getfailedcollections() assert len(failedcollections) == 2 From hpk at codespeak.net Sun Feb 17 19:59:06 2008 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sun, 17 Feb 2008 19:59:06 +0100 (CET) Subject: [py-svn] r51565 - in py/branch/event/py/test2: . testing Message-ID: <20080217185906.9E4BD1683F4@codespeak.net> Author: hpk Date: Sun Feb 17 19:59:06 2008 New Revision: 51565 Modified: py/branch/event/py/test2/collect.py py/branch/event/py/test2/testing/test_collect.py Log: fix Docstrings and clarify some variable naming Modified: py/branch/event/py/test2/collect.py ============================================================================== --- py/branch/event/py/test2/collect.py (original) +++ py/branch/event/py/test2/collect.py Sun Feb 17 19:59:06 2008 @@ -35,13 +35,9 @@ return property(fget) class Base(object): - """ Collector instances are iteratively generated - (through their run() and join() methods) - and form a tree. attributes:: - - parent: attribute pointing to the parent collector - (or None if it is the root collector) - name: basename of this collector object + """ base class for the nodes in the collection tree. + Nodes with Children are "Collectors" and leaves + are the actual Test Items. """ def __init__(self, name, parent=None): self.name = name @@ -184,6 +180,15 @@ return self._config.get_collector_trail(self) class Collector(Base): + """ + Collector instances generate children through + their listdir() and join() methods and thus + form a tree. attributes:: + + parent: attribute pointing to the parent collector + (or None if this is the root collector) + name: basename of this collector object + """ Module = configproperty('Module') DoctestFile = configproperty('DoctestFile') Directory = configproperty('Directory') @@ -205,12 +210,10 @@ raise NotImplementedError("abstract") def join(self, name): - """ return a child item for the given name. Usually the - session feeds the join method with each name obtained - from ``colitem.run()``. If the return value is None - it means the ``colitem`` was not able to resolve - with the given name. + """ return a child collector or item for the given name. + If the return value is None there is no such child. """ + raise NotImplementedError("abstract") class FSCollector(Collector): def __init__(self, fspath, parent=None): Modified: py/branch/event/py/test2/testing/test_collect.py ============================================================================== --- py/branch/event/py/test2/testing/test_collect.py (original) +++ py/branch/event/py/test2/testing/test_collect.py Sun Feb 17 19:59:06 2008 @@ -73,8 +73,8 @@ tmp.ensure("normal", 'test_found.py') tmp.ensure('test_found.py') - colitem = py.test2.collect.Directory(tmp) - items = colitem.listdir() + col = py.test2.collect.Directory(tmp) + items = col.listdir() assert len(items) == 2 assert 'normal' in items assert 'test_found.py' in items @@ -105,9 +105,9 @@ col = py.test2.collect.Module(setupdata.getexamplefile('disabled.py')) l = col.listdir() assert len(l) == 1 - colitem = col.join(l[0]) - assert isinstance(colitem, py.test2.collect.Class) - assert not colitem.listdir() + col = col.join(l[0]) + assert isinstance(col, py.test2.collect.Class) + assert not col.listdir() def test_disabled_module(): p = setupdata.getexamplefile("disabled_module.py") From hpk at codespeak.net Sun Feb 17 20:42:28 2008 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sun, 17 Feb 2008 20:42:28 +0100 (CET) Subject: [py-svn] r51566 - py/branch/event/py/test2 Message-ID: <20080217194228.C59AC1683E6@codespeak.net> Author: hpk Date: Sun Feb 17 20:42:27 2008 New Revision: 51566 Modified: py/branch/event/py/test2/collect.py py/branch/event/py/test2/item.py py/branch/event/py/test2/present.py Log: * move away and streamline some methods and attributes from the collection tree base class * get rid of some presumtions that collection items always have a filesystem path or are connected to Python function based tests. Modified: py/branch/event/py/test2/collect.py ============================================================================== --- py/branch/event/py/test2/collect.py (original) +++ py/branch/event/py/test2/collect.py Sun Feb 17 20:42:27 2008 @@ -43,9 +43,6 @@ self.name = name self.parent = parent self._config = getattr(parent, '_config', py.test2.config) - self.fspath = getattr(parent, 'fspath', None) - - _stickyfailure = None def __repr__(self): return "<%s %r>" %(self.__class__.__name__, self.name) @@ -67,28 +64,10 @@ #print "cmp", s1, s2 return cmp(s1, s2) - def obj(): - def fget(self): - try: - return self._obj - except AttributeError: - self._obj = obj = self._getobj() - return obj - def fset(self, value): - self._obj = value - return property(fget, fset, None, "underlying object") - obj = obj() - - def _getobj(self): - return getattr(self.parent.obj, self.name) - def multijoin(self, namelist): """ return a list of colitems for the given namelist. """ return [self.join(name) for name in namelist] - def _getpathlineno(self): - return self.fspath, py.std.sys.maxint - def setup(self): pass @@ -96,7 +75,7 @@ pass def listchain(self): - """ return list of all parent collectors up to ourself. """ + """ return list of all parent collectors up to self. """ l = [self] while 1: x = l[-1] @@ -179,6 +158,7 @@ """ return self._config.get_collector_trail(self) + class Collector(Base): """ Collector instances generate children through @@ -197,6 +177,10 @@ Function = configproperty('Function') Generator = configproperty('Generator') + def __init__(self, name, parent=None): + super(Collector, self).__init__(name, parent) + self.fspath = getattr(parent, 'fspath', None) + def run(self): """ deprecated: use listdir(). """ py.std.warnings.warn("deprecated: use listdir()", category=DeprecationWarning) @@ -263,7 +247,24 @@ name2items[name] = res return res -class PyCollectorMixin(Collector): +class PyobjMixin(object): + def obj(): + def fget(self): + try: + return self._obj + except AttributeError: + self._obj = obj = self._getobj() + return obj + def fset(self, value): + self._obj = value + return property(fget, fset, None, "underlying python object") + obj = obj() + + def _getobj(self): + return getattr(self.parent.obj, self.name) + + +class PyCollectorMixin(PyobjMixin, Collector): def funcnamefilter(self, name): return name.startswith('test') def classnamefilter(self, name): @@ -321,6 +322,8 @@ class Module(FSCollector, PyCollectorMixin): + _stickyfailure = None + def listdir(self): if getattr(self.obj, 'disabled', 0): return [] @@ -343,22 +346,18 @@ def __repr__(self): return "<%s %r>" % (self.__class__.__name__, self.name) - def obj(self): + def _getobj(self): + failure = self._stickyfailure + if failure is not None: + raise failure[0], failure[1], failure[2] try: - return self._obj - except AttributeError: - failure = getattr(self, '_stickyfailure', None) - if failure is not None: - raise failure[0], failure[1], failure[2] - try: - self._obj = obj = self.fspath.pyimport() - except KeyboardInterrupt: - raise - except: - self._stickyfailure = py.std.sys.exc_info() - raise - return obj - obj = property(obj, None, None, "module object") + self._obj = obj = self.fspath.pyimport() + except KeyboardInterrupt: + raise + except: + self._stickyfailure = py.std.sys.exc_info() + raise + return self._obj def setup(self): if hasattr(self.obj, 'setup_module'): @@ -416,15 +415,15 @@ Function = property(Function) -class FunctionMixin(object): +class FunctionMixin(PyobjMixin): """ mixin for the code common to Function and Generator. """ - def _getpathlineno(self): - code = py.code.Code(self.obj) - return code.path, code.firstlineno - + _sortvalue = None def _getsortvalue(self): - return self._getpathlineno() + if self._sortvalue is None: + code = py.code.Code(self.obj) + self._sortvalue = code.path, code.firstlineno + return self._sortvalue def setup(self): """ perform setup for this test function. """ Modified: py/branch/event/py/test2/item.py ============================================================================== --- py/branch/event/py/test2/item.py (original) +++ py/branch/event/py/test2/item.py Sun Feb 17 20:42:27 2008 @@ -30,6 +30,10 @@ self.stack.append(col) class Item(Base): + def __init__(self, name, parent=None): + super(Item, self).__init__(name, parent) + self.fspath = getattr(parent, 'fspath', None) + def startcapture(self): self._config._startcapture(self, path=self.fspath) @@ -51,11 +55,6 @@ def __repr__(self): return "<%s %r>" %(self.__class__.__name__, self.name) - def _getsortvalue(self): - if self._sort_value is None: - return self._getpathlineno() - return self._sort_value - def run(self): """ setup and execute the underlying test function. """ self._state.prepare(self) Modified: py/branch/event/py/test2/present.py ============================================================================== --- py/branch/event/py/test2/present.py (original) +++ py/branch/event/py/test2/present.py Sun Feb 17 20:42:27 2008 @@ -22,6 +22,7 @@ def getmodpath(pycolitem): """ return dotted module path for the given colitem. """ + # XXX what about non-functions? colitems = pycolitem.listchain() while colitems: colitem = colitems.pop(0) @@ -77,18 +78,9 @@ def repr_failure_headline(self, item): """ This method represents py.test2.collect.Item info (path and module) """ - root = item.fspath + # XXX do something for non-python test items modpath = getmodpath(item) - try: - fn, lineno = item._getpathlineno() - except TypeError: - assert isinstance(item.parent, py.test2.collect.Generator) - # a generative test yielded a non-callable - fn, lineno = item.parent._getpathlineno() - if root == fn: - self.out.sep("_", "entrypoint: %s" %(modpath)) - else: - self.out.sep("_", "entrypoint: %s %s" %(root.basename, modpath)) + self.out.sep("_", "entrypoint: %s" %(modpath)) def repr_failure_explanation(self, excinfo, source): try: @@ -129,8 +121,10 @@ py.std.pprint.pprint(value, stream=self.out) def filtertraceback(self, item, traceback): - if item and not self.config.option.fulltrace: - path, firstlineno = item._getpathlineno() + if isinstance(item, py.test2.collect.Function) \ + and not self.config.option.fulltrace: + code = py.code.Code(item.obj) + path, firstlineno = code.path, code.firstlineno ntraceback = traceback.cut(path=path, firstlineno=firstlineno) if ntraceback == traceback: ntraceback = ntraceback.cut(path=path) From hpk at codespeak.net Sun Feb 17 21:22:22 2008 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sun, 17 Feb 2008 21:22:22 +0100 (CET) Subject: [py-svn] r51567 - in py/branch/event/py/test2: . rep rep/testing rep/webdata rsession rsession/testing rsession/webdata testing Message-ID: <20080217202222.E1726168487@codespeak.net> Author: hpk Date: Sun Feb 17 21:22:21 2008 New Revision: 51567 Added: py/branch/event/py/test2/rep/ (props changed) py/branch/event/py/test2/rep/__init__.py (contents, props changed) py/branch/event/py/test2/rep/reporter.py - copied unchanged from r51566, py/branch/event/py/test2/reporter.py py/branch/event/py/test2/rep/testing/ (props changed) py/branch/event/py/test2/rep/testing/__init__.py (contents, props changed) py/branch/event/py/test2/rep/testing/test_reporter.py - copied unchanged from r51566, py/branch/event/py/test2/testing/test_reporter.py py/branch/event/py/test2/rep/testing/test_rest.py - copied unchanged from r51566, py/branch/event/py/test2/rsession/testing/test_rest.py py/branch/event/py/test2/rep/testing/test_web.py - copied unchanged from r51566, py/branch/event/py/test2/rsession/testing/test_web.py py/branch/event/py/test2/rep/testing/test_webjs.py - copied unchanged from r51566, py/branch/event/py/test2/rsession/testing/test_webjs.py py/branch/event/py/test2/rep/web.py - copied unchanged from r51566, py/branch/event/py/test2/rsession/web.py py/branch/event/py/test2/rep/webdata/ - copied from r51566, py/branch/event/py/test2/rsession/webdata/ py/branch/event/py/test2/rep/webjs.py - copied unchanged from r51566, py/branch/event/py/test2/rsession/webjs.py Removed: py/branch/event/py/test2/reporter.py py/branch/event/py/test2/rsession/testing/test_rest.py py/branch/event/py/test2/rsession/testing/test_web.py py/branch/event/py/test2/rsession/testing/test_webjs.py py/branch/event/py/test2/rsession/web.py py/branch/event/py/test2/rsession/webdata/ py/branch/event/py/test2/rsession/webjs.py py/branch/event/py/test2/testing/test_reporter.py Modified: py/branch/event/py/test2/conftesthandle.py (props changed) py/branch/event/py/test2/custompdb.py (props changed) py/branch/event/py/test2/genitem.py (props changed) py/branch/event/py/test2/outcome.py (props changed) py/branch/event/py/test2/present.py (props changed) py/branch/event/py/test2/rsession/testing/basetest.py (props changed) py/branch/event/py/test2/rsession/testing/test_hostmanage.py (props changed) py/branch/event/py/test2/rsession/testing/test_masterslave.py (props changed) py/branch/event/py/test2/testing/setupdata.py (props changed) py/branch/event/py/test2/testing/suptest.py (props changed) py/branch/event/py/test2/testing/test_conftesthandle.py (props changed) py/branch/event/py/test2/testing/test_present.py (props changed) py/branch/event/py/test2/testing/test_repevent.py (props changed) Log: move all reporters and their (skipped) tests into a new "rep" directory Added: py/branch/event/py/test2/rep/__init__.py ============================================================================== --- (empty file) +++ py/branch/event/py/test2/rep/__init__.py Sun Feb 17 21:22:21 2008 @@ -0,0 +1 @@ +# Added: py/branch/event/py/test2/rep/testing/__init__.py ============================================================================== --- (empty file) +++ py/branch/event/py/test2/rep/testing/__init__.py Sun Feb 17 21:22:21 2008 @@ -0,0 +1 @@ +# Deleted: /py/branch/event/py/test2/reporter.py ============================================================================== --- /py/branch/event/py/test2/reporter.py Sun Feb 17 21:22:21 2008 +++ (empty file) @@ -1,439 +0,0 @@ - -""" reporter - different reporter for different purposes ;-) - Still lacks: - - 1. Hanging nodes are not done well -""" - -import py - -from py.__.test2.terminal.out import getout -from py.__.test2 import repevent -from py.__.test2 import outcome -from py.__.misc.terminal_helper import ansi_print, get_terminal_width -from py.__.test2.present import Presenter, repr_pythonversion,\ - getrelpath - -import sys - -from time import time as now - -def choose_reporter(reporterclass, config): - option = config.option - if option.startserver or option.runbrowser: - from py.__.test2.rsession.web import WebReporter - return WebReporter - if option.restreport: - from py.__.test2.rsession.rest import RestReporter - return RestReporter - else: - return reporterclass - -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 - 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.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 - - __call__ = report - - 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): - topdir = item.config.topdir - 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" % 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.out.line() - self.repr_failure(event.item, event.outcome) - - def report_SessionFinish(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_SessionFinish - report_CrashedExecution = report_SessionFinish - - 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.ItemFinish): - 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.SerializableOutcome(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): - # XXX review and test below, fix too many lines of - # skips that happen in the same file/lineno - # (this is correct in py-dist) - texts = {} - for event in self.skipped_tests_outcome: - colitem = event.item - if isinstance(event, repevent.ItemFinish): - outcome = event.outcome - text = outcome.skipped.value - itemname = repr(outcome.skipped.traceback[-2]).split("\n")[0] - elif isinstance(event, repevent.DeselectedTest): - 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[1:-1]) - self.out.line() - - def summary(self): - def gather(dic): - # XXX hack to handle dicts & ints here, get rid of it - if isinstance(dic, int): - return 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.out.line() - 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_DeselectedTest(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_ItemFinish(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 - - def was_failure(self): - return sum(self.failed.values()) > 0 - -class RemoteReporter(AbstractReporter): - def __init__(self, config, hosts): - super(RemoteReporter, self).__init__(config, hosts) - 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]) - - 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_DeselectedTest(self, event): - self.out.line("Skipped (%s) %s\n" % (str(event.excinfo.value), "/". - join(event.item.listnames()))) - -class LocalReporter(AbstractReporter): - def __init__(self, config, hosts=None): - assert not hosts - super(LocalReporter, self).__init__(config, hosts) - self.failed = 0 - self.skipped = 0 - self.passed = 0 - - def report_TestStarted(self, item): - colitems = item.config.getcolitems() - txt = " test process starts " - self.out.sep("=", txt) - self.timestart = item.timestart - self.out.line("executable: %s (%s)" % - (py.std.sys.executable, repr_pythonversion())) - rev = py.__package__.getrev() - self.out.line("using py lib: %s " % ( - py.path.local(py.__file__).dirpath(), rev)) - config = item.config - if config.option.traceconfig or config.option.verbose: - - for x in colitems: - self.out.line("test target: %s" %(x.fspath,)) - - conftestmodules = config._conftest.getconftestmodules(None) - for i,x in py.builtin.enumerate(conftestmodules): - self.out.line("initial conf %d: %s" %(i, x.__file__)) - - def get_item_name(self, event, colitem): - return "/".join(colitem.listnames()) - - def print_summary(self, total, skipped_str, failed_str): - self.out.sep("=", " %d test run%s%s in %.2fs" % - (total, skipped_str, failed_str, self.timeend - self.timestart)) - - def report_DeselectedTest(self, event): - #self.show_item(event.item, False) - if isinstance(event.item, py.test2.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 += 1 - - def report_ItemFinish(self, event): - if event.outcome.passed: - self.passed += 1 - self.out.write(".") - elif event.outcome.skipped: - self.skipped_tests_outcome.append(event) - self.skipped += 1 - self.out.write("s") - else: - self.failed += 1 - self.failed_tests_outcome.append(event) - self.out.write("F") - - def report_ItemStart(self, event): - # XXX - event.item.start = now() - self.show_item(event.item) - - def show_item(self, item, count_elems = True): - if isinstance(item, py.test2.collect.Module): - self.show_Module(item) - if self.config.option.verbose > 0 and\ - isinstance(item, py.test2.collect.Item): - self.show_ItemVerbose(item) - - def show_ItemVerbose(self, item): - realpath, lineno = item._getpathlineno() - location = "%s:%d" % (realpath.basename, lineno+1) - self.out.write("%-20s %s " % (location, item._getmodpath())) - - def show_Module(self, mod): - lgt = len(list(mod._tryiter())) - if self.config.option.verbose == 0: - base = getrelpath(py.path.local(), mod.fspath) - self.out.write("\n%s[%d] " % (base, lgt)) - else: - self.out.line() - self.out.line('+ testmodule: %s[%d]' % (mod.fspath, lgt)) - - def gethost(self, event): - return 'localhost' - - def hangs(self): - pass - - def was_failure(self): - return self.failed > 0 Deleted: /py/branch/event/py/test2/rsession/testing/test_rest.py ============================================================================== --- /py/branch/event/py/test2/rsession/testing/test_rest.py Sun Feb 17 21:22:21 2008 +++ (empty file) @@ -1,356 +0,0 @@ - -""" tests of rest reporter backend -""" - -import py - -py.test.skip("refactor ReST reporter tests") - -from py.__.test2.testing.test_reporter import AbstractTestReporter,\ - DummyChannel -from py.__.test2 import repevent -from py.__.test2.rsession.rest import RestReporter, NoLinkWriter -from py.__.rest.rst import * -from py.__.test2.rsession.hostmanage import HostInfo -from py.__.test2.outcome import SerializableOutcome - -class Container(object): - def __init__(self, **args): - for arg, val in args.items(): - setattr(self, arg, val) - -class RestTestReporter(RestReporter): - def __init__(self, *args, **kwargs): - if args: - super(RestReporter, self).__init__(*args, **kwargs) - -class TestRestUnits(object): - def setup_method(self, method): - config = py.test2.config._reparse(["some_sub"]) - config.option.verbose = False - self.config = config - hosts = [HostInfo('localhost')] - method.im_func.func_globals['ch'] = DummyChannel(hosts[0]) - method.im_func.func_globals['reporter'] = r = RestReporter(config, - hosts) - method.im_func.func_globals['stdout'] = s = py.std.StringIO.StringIO() - r.out = s # XXX will need to become a real reporter some time perhaps? - r.linkwriter = NoLinkWriter() - - def test_report_unknown(self): - self.config.option.verbose = True - reporter.report_unknown('foo') - assert stdout.getvalue() == 'Unknown report\\: foo\n\n' - self.config.option.verbose = False - - def test_report_SendItem(self): - event = repevent.SendItem(item='foo/bar.py', channel=ch) - reporter.report(event) - assert stdout.getvalue() == '' - stdout.seek(0) - stdout.truncate() - reporter.config.option.verbose = True - reporter.report(event) - assert stdout.getvalue() == ('sending item foo/bar.py to ' - 'localhost\n\n') - - def test_report_HostRSyncing(self): - event = repevent.HostRSyncing(HostInfo('localhost:/foo/bar'), "a", - "b", False) - reporter.report(event) - assert stdout.getvalue() == ('::\n\n localhost: RSYNC ==> ' - '/foo/bar\n\n') - - def test_report_HostRSyncRootReady(self): - h = HostInfo('localhost') - reporter.hosts_to_rsync = 1 - reporter.report(repevent.HostGatewayReady(h, ["a"])) - event = repevent.HostRSyncRootReady(h, "a") - reporter.report(event) - assert stdout.getvalue() == '::\n\n localhost: READY\n\n' - - def test_report_TestStarted(self): - event = repevent.TestStarted([HostInfo('localhost'), - HostInfo('foo.com')], - "aa", ["a", "b"]) - reporter.report(event) - assert stdout.getvalue() == """\ -=========================================== -Running tests on hosts\: localhost, foo.com -=========================================== - -""" - - def test_report_ItemStart(self): - class FakeModule(py.test2.collect.Module): - def __init__(self, parent): - self.parent = parent - self.fspath = py.path.local('.') - def _tryiter(self): - return ['test_foo', 'test_bar'] - def listnames(self): - return ['package', 'foo', 'bar.py'] - - parent = Container(parent=None, fspath=py.path.local('.')) - event = repevent.ItemStart(item=FakeModule(parent)) - reporter.report(event) - assert stdout.getvalue() == """\ -Testing module foo/bar.py (2 items) ------------------------------------ - -""" - - def test_print_summary(self): - reporter.timestart = 10 - reporter.timeend = 20 - reporter.timersync = 15 - reporter.print_summary(10, '', '') - assert stdout.getvalue() == """\ -10 tests run in 10.00s (rsync\: 5.00) -------------------------------------- - -""" - - def test_ItemFinish_PASSED(self): - outcome = SerializableOutcome() - item = Container(listnames=lambda: ['', 'foo.py', 'bar', '()', 'baz']) - event = repevent.ItemFinish(channel=ch, outcome=outcome, item=item) - reporter.report(event) - assert stdout.getvalue() == ('* localhost\\: **PASSED** ' - 'foo.py/bar()/baz\n\n') - - def test_ItemFinish_SKIPPED(self): - outcome = SerializableOutcome(skipped="reason") - item = Container(listnames=lambda: ['', 'foo.py', 'bar', '()', 'baz']) - event = repevent.ItemFinish(channel=ch, outcome=outcome, item=item) - reporter.report(event) - assert stdout.getvalue() == ('* localhost\\: **SKIPPED** ' - 'foo.py/bar()/baz\n\n') - - def test_ItemFinish_FAILED(self): - outcome = SerializableOutcome(excinfo="xxx") - item = Container(listnames=lambda: ['', 'foo.py', 'bar', '()', 'baz']) - event = repevent.ItemFinish(channel=ch, outcome=outcome, item=item) - reporter.report(event) - assert stdout.getvalue() == """\ -* localhost\: **FAILED** `traceback0`_ foo.py/bar()/baz - -""" - - def test_ItemFinish_FAILED_stdout(self): - excinfo = Container( - typename='FooError', - value='A foo has occurred', - traceback=[ - Container( - path='foo/bar.py', - lineno=1, - relline=1, - source='foo()', - ), - Container( - path='foo/baz.py', - lineno=4, - relline=1, - source='raise FooError("A foo has occurred")', - ), - ] - ) - outcome = SerializableOutcome(excinfo=excinfo) - outcome.stdout = '' - outcome.stderr = '' - parent = Container(parent=None, fspath=py.path.local('.')) - item = Container(listnames=lambda: ['', 'foo.py', 'bar', '()', 'baz'], - parent=parent, fspath=py.path.local('foo')) - event = repevent.ItemFinish(channel=ch, outcome=outcome, - item=item) - reporter.report(event) - reporter.timestart = 10 - reporter.timeend = 20 - reporter.timersync = 15 - reporter.print_summary(10, '', '') - - reporter.print_summary(1, 'skipped', 'failed') - out = stdout.getvalue() - assert out.find('') > -1 - - def test_skips(self): - class FakeOutcome(Container, repevent.ItemFinish): - pass - - class FakeTryiter(Container, repevent.DeselectedTest): - pass - - reporter.skips() - assert stdout.getvalue() == '' - reporter.skipped_tests_outcome = [ - FakeOutcome(outcome=Container(skipped='problem X'), - item=Container(listnames=lambda: ['foo', 'bar.py'])), - FakeTryiter(excinfo=Container(value='problem Y'), - item=Container(listnames=lambda: ['foo', 'baz.py']))] - reporter.skips() - assert stdout.getvalue() == """\ -Reasons for skipped tests\: -+++++++++++++++++++++++++++ - -* foo/bar.py\: problem X - -* foo/baz.py\: problem Y - -""" - - def test_failures(self): - class FakeOutcome(Container, repevent.ItemFinish): - pass - - parent = Container(parent=None, fspath=py.path.local('.')) - reporter.failed_tests_outcome = [ - FakeOutcome( - outcome=Container( - signal=False, - excinfo=Container( - typename='FooError', - value='A foo has occurred', - traceback=[ - Container( - path='foo/bar.py', - lineno=1, - relline=1, - source='foo()', - ), - Container( - path='foo/baz.py', - lineno=4, - relline=1, - source='raise FooError("A foo has occurred")', - ), - ] - ), - stdout='', - stderr='', - ), - item=Container( - listnames=lambda: ['package', 'foo', 'bar.py', - 'baz', '()'], - parent=parent, - fspath=py.path.local('.'), - ), - channel=ch, - ), - ] - reporter.config.option.tbstyle = 'no' - reporter.failures() - expected = """\ -Exceptions\: -++++++++++++ - -foo/bar.py/baz() on localhost -+++++++++++++++++++++++++++++ - -.. _`traceback0`: - - -FooError -++++++++ - -:: - - A foo has occurred - -""" - assert stdout.getvalue() == expected - - reporter.config.option.tbstyle = 'short' - stdout.seek(0) - stdout.truncate() - reporter.failures() - expected = """\ -Exceptions\: -++++++++++++ - -foo/bar.py/baz() on localhost -+++++++++++++++++++++++++++++ - -.. _`traceback0`: - - -:: - - foo/bar.py line 1 - foo() - foo/baz.py line 4 - raise FooError("A foo has occurred") - -FooError -++++++++ - -:: - - A foo has occurred - -""" - assert stdout.getvalue() == expected - - reporter.config.option.tbstyle = 'long' - stdout.seek(0) - stdout.truncate() - reporter.failures() - expected = """\ -Exceptions\: -++++++++++++ - -foo/bar.py/baz() on localhost -+++++++++++++++++++++++++++++ - -.. _`traceback0`: - - -+++++++++++++++++ -foo/bar.py line 1 -+++++++++++++++++ - -:: - - foo() - -+++++++++++++++++ -foo/baz.py line 4 -+++++++++++++++++ - -:: - - raise FooError("A foo has occurred") - -FooError -++++++++ - -:: - - A foo has occurred - -""" - assert stdout.getvalue() == expected - - -class TestRestReporter(AbstractTestReporter): - reporter = RestReporter - - def get_hosts(self): - return [HostInfo('localhost')] - - def test_failed_to_load(self): - py.test.skip("Not implemented") - - def test_report_received_item_outcome(self): - val = self.report_received_item_outcome() - 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 - - Deleted: /py/branch/event/py/test2/rsession/testing/test_web.py ============================================================================== --- /py/branch/event/py/test2/rsession/testing/test_web.py Sun Feb 17 21:22:21 2008 +++ (empty file) @@ -1,90 +0,0 @@ - -""" webtest -""" - -import py - -def setup_module(mod): - try: - from pypy.translator.js.main import rpython2javascript - from pypy.translator.js import commproxy - mod.commproxy = commproxy - mod.rpython2javascript = rpython2javascript - except ImportError: - py.test.skip("PyPy not found") - mod.commproxy.USE_MOCHIKIT = False - mod.rpython2javascript = rpython2javascript - mod.commproxy = mod.commproxy - from py.__.test2.rsession.web import TestHandler as _TestHandler - from py.__.test2.rsession.web import MultiQueue - mod._TestHandler = _TestHandler - mod.MultiQueue = MultiQueue - -def test_js_generate(): - from py.__.test2.rsession import webjs - from py.__.test2.rsession.web import FUNCTION_LIST, IMPORTED_PYPY - - source = rpython2javascript(webjs, FUNCTION_LIST, use_pdb=False) - assert source - -def test_parse_args(): - class TestTestHandler(_TestHandler): - def __init__(self): - pass - h = TestTestHandler() - assert h.parse_args('foo=bar') == {'foo': 'bar'} - assert h.parse_args('foo=bar%20baz') == {'foo': 'bar baz'} - assert h.parse_args('foo%20bar=baz') == {'foo bar': 'baz'} - assert h.parse_args('foo=bar%baz') == {'foo': 'bar\xbaz'} - py.test2.raises(ValueError, 'h.parse_args("foo")') - -class TestMultiQueue(object): - def test_get_one_sessid(self): - mq = MultiQueue() - mq.put(1) - result = mq.get(1234) - assert result == 1 - - def test_get_two_sessid(self): - mq = MultiQueue() - mq.put(1) - result = mq.get(1234) - assert result == 1 - mq.put(2) - result = mq.get(1234) - assert result == 2 - result = mq.get(5678) - assert result == 1 - result = mq.get(5678) - assert result == 2 - - def test_get_blocking(self): - import thread - result = [] - def getitem(mq, sessid): - result.append(mq.get(sessid)) - mq = MultiQueue() - thread.start_new_thread(getitem, (mq, 1234)) - assert not result - mq.put(1) - py.std.time.sleep(0.1) - assert result == [1] - - def test_empty(self): - mq = MultiQueue() - assert mq.empty() - mq.put(1) - assert not mq.empty() - result = mq.get(1234) - result == 1 - assert mq.empty() - mq.put(2) - result = mq.get(4567) - assert result == 1 - result = mq.get(1234) - assert result == 2 - assert not mq.empty() - result = mq.get(4567) - assert result == 2 - assert mq.empty() - Deleted: /py/branch/event/py/test2/rsession/testing/test_webjs.py ============================================================================== --- /py/branch/event/py/test2/rsession/testing/test_webjs.py Sun Feb 17 21:22:21 2008 +++ (empty file) @@ -1,143 +0,0 @@ -import py - -def check(mod): - try: - import pypy - from pypy.translator.js.modules import dom - from pypy.translator.js.tester import schedule_callbacks - dom.Window # check whether dom was properly imported or is just a - # leftover in sys.modules - except (ImportError, AttributeError): - py.test.skip('PyPy not found') - mod.dom = dom - mod.schedule_callbacks = schedule_callbacks - - from py.__.test2.rsession import webjs - from py.__.test2.rsession.web import exported_methods - mod.webjs = webjs - mod.exported_methods = exported_methods - mod.here = py.magic.autopath().dirpath() - -def setup_module(mod): - check(mod) - - # load HTML into window object - html = here.join('../webdata/index.html').read() - mod.html = html - from pypy.translator.js.modules import dom - mod.dom = dom - dom.window = dom.Window(html) - dom.document = dom.window.document - from py.__.test2.rsession import webjs - from py.__.test2.rsession.web import exported_methods - mod.webjs = webjs - mod.exported_methods = exported_methods - -def setup_function(f): - dom.window = dom.Window(html) - dom.document = dom.window.document - -def test_html_loaded(): - body = dom.window.document.getElementsByTagName('body')[0] - assert len(body.childNodes) > 0 - assert str(body.childNodes[1].nodeName) == 'A' - -def test_set_msgbox(): - py.test.skip("not implemented in genjs") - msgbox = dom.window.document.getElementById('messagebox') - assert len(msgbox.childNodes) == 0 - webjs.set_msgbox('foo', 'bar') - assert len(msgbox.childNodes) == 1 - assert msgbox.childNodes[0].nodeName == 'PRE' - assert msgbox.childNodes[0].childNodes[0].nodeValue == 'foo\nbar' - -def test_show_info(): - info = dom.window.document.getElementById('info') - info.style.visibility = 'hidden' - info.innerHTML = '' - webjs.show_info('foobar') - content = info.innerHTML - assert content == 'foobar' - bgcolor = info.style.backgroundColor - assert bgcolor == 'beige' - -def test_hide_info(): - info = dom.window.document.getElementById('info') - info.style.visibility = 'visible' - webjs.hide_info() - assert info.style.visibility == 'hidden' - -def test_process(): - main_t = dom.window.document.getElementById('main_table') - assert len(main_t.getElementsByTagName('tr')) == 0 - assert not webjs.process({}) - - msg = {'type': 'ItemStart', - 'itemtype': 'Module', - 'itemname': 'foo.py', - 'fullitemname': 'modules/foo.py', - 'length': 10, - } - assert webjs.process(msg) - trs = main_t.getElementsByTagName('tr') - assert len(trs) == 1 - tr = trs[0] - assert len(tr.childNodes) == 2 - assert tr.childNodes[0].nodeName == 'TD' - assert tr.childNodes[0].innerHTML == 'foo.py[0/10]' - assert tr.childNodes[1].nodeName == 'TD' - assert tr.childNodes[1].childNodes[0].nodeName == 'TABLE' - assert len(tr.childNodes[1].getElementsByTagName('tr')) == 0 - -def test_process_two(): - main_t = dom.window.document.getElementById('main_table') - msg = {'type': 'ItemStart', - 'itemtype': 'Module', - 'itemname': 'foo.py', - 'fullitemname': 'modules/foo.py', - 'length': 10, - } - webjs.process(msg) - msg = {'type': 'ItemFinish', - 'fullmodulename': 'modules/foo.py', - 'passed' : 'True', - 'fullitemname' : 'modules/foo.py/test_item', - 'hostkey': None, - } - webjs.process(msg) - trs = main_t.getElementsByTagName('tr') - tds = trs[0].getElementsByTagName('td') - # two cells in the row, one in the table inside one of the cells - assert len(tds) == 3 - html = tds[0].innerHTML - assert html == 'foo.py[1/10]' - assert tds[2].innerHTML == '.' - -def test_signal(): - main_t = dom.window.document.getElementById('main_table') - msg = {'type': 'ItemStart', - 'itemtype': 'Module', - 'itemname': 'foo.py', - 'fullitemname': 'modules/foo.py', - 'length': 10, - } - webjs.process(msg) - msg = {'type': 'ItemFinish', - 'fullmodulename': 'modules/foo.py', - 'passed' : 'False', - 'fullitemname' : 'modules/foo.py/test_item', - 'hostkey': None, - 'signal': '10', - 'skipped': 'False', - } - exported_methods.fail_reasons['modules/foo.py/test_item'] = 'Received signal 10' - exported_methods.stdout['modules/foo.py/test_item'] = '' - exported_methods.stderr['modules/foo.py/test_item'] = '' - webjs.process(msg) - schedule_callbacks(exported_methods) - # ouch - assert dom.document.getElementById('modules/foo.py').childNodes[0].\ - childNodes[0].childNodes[0].childNodes[0].nodeValue == 'F' - -# XXX: Write down test for full run - Deleted: /py/branch/event/py/test2/rsession/web.py ============================================================================== --- /py/branch/event/py/test2/rsession/web.py Sun Feb 17 21:22:21 2008 +++ (empty file) @@ -1,473 +0,0 @@ - -""" web server for py.test -""" - -from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler - -import thread, threading -import re -import time -import random -import Queue -import os -import sys -import socket - -import py -from py.__.test2.rsession.rsession import RSession -from py.__.test2 import repevent -from py.__.test2 import collect -from py.__.test2.rsession.webdata import json - -DATADIR = py.path.local(__file__).dirpath("webdata") -FUNCTION_LIST = ["main", "show_skip", "show_traceback", "show_info", "hide_info", - "show_host", "hide_host", "hide_messagebox", "opt_scroll"] - -try: - from pypy.rpython.ootypesystem.bltregistry import MethodDesc, BasicExternal - from pypy.translator.js.main import rpython2javascript - from pypy.translator.js import commproxy - from pypy.translator.js.lib.support import callback - - commproxy.USE_MOCHIKIT = False - IMPORTED_PYPY = True -except (ImportError, NameError): - class BasicExternal(object): - pass - - def callback(*args, **kwargs): - def decorator(func): - return func - return decorator - - IMPORTED_PYPY = False - -def add_item(event): - """ A little helper - """ - item = event.item - itemtype = item.__class__.__name__ - itemname = item.name - fullitemname = "/".join(item.listnames()) - d = {'fullitemname': fullitemname, 'itemtype': itemtype, - 'itemname': itemname} - #if itemtype == 'Module': - try: - d['length'] = str(len(list(event.item._tryiter()))) - except: - d['length'] = "?" - return d - -class MultiQueue(object): - """ a tailor-made queue (internally using Queue) for py.test2.rsession.web - - API-wise the main difference is that the get() method gets a sessid - argument, which is used to determine what data to feed to the client - - when a data queue for a sessid doesn't yet exist, it is created, and - filled with data that has already been fed to the other clients - """ - def __init__(self): - self._cache = [] - self._session_queues = {} - self._lock = py.std.thread.allocate_lock() - - def put(self, item): - self._lock.acquire() - try: - self._cache.append(item) - for key, q in self._session_queues.items(): - q.put(item) - finally: - self._lock.release() - - def _del(self, sessid): - self._lock.acquire() - try: - del self._session_queues[sessid] - finally: - self._lock.release() - - def get(self, sessid): - self._lock.acquire() - try: - if not sessid in self._session_queues: - self._create_session_queue(sessid) - finally: - self._lock.release() - return self._session_queues[sessid].get(sessid) - - def empty(self): - self._lock.acquire() - try: - if not self._session_queues: - return not len(self._cache) - for q in self._session_queues.values(): - if not q.empty(): - return False - finally: - self._lock.release() - return True - - def empty_queue(self, sessid): - return self._session_queues[sessid].empty() - - def _create_session_queue(self, sessid): - self._session_queues[sessid] = q = Queue.Queue() - for item in self._cache: - q.put(item) - -class ExportedMethods(BasicExternal): - _render_xmlhttp = True - def __init__(self): - self.pending_events = MultiQueue() - self.start_event = threading.Event() - self.end_event = threading.Event() - self.skip_reasons = {} - self.fail_reasons = {} - self.stdout = {} - self.stderr = {} - self.all = 0 - self.to_rsync = {} - - def findmodule(self, item): - # find the most outwards parent which is module - current = item - while current: - if isinstance(current, collect.Module): - break - current = current.parent - - if current is not None: - return str(current.name), str("/".join(current.listnames())) - else: - return str(item.parent.name), str("/".join(item.parent.listnames())) - - def show_hosts(self): - self.start_event.wait() - to_send = {} - for host in self.hosts: - to_send[host.hostid] = host.hostname - return to_send - show_hosts = callback(retval={str:str})(show_hosts) - - def show_skip(self, item_name="aa"): - return {'item_name': item_name, - 'reason': self.skip_reasons[item_name]} - show_skip = callback(retval={str:str})(show_skip) - - def show_fail(self, item_name="aa"): - return {'item_name':item_name, - 'traceback':str(self.fail_reasons[item_name]), - 'stdout':self.stdout[item_name], - 'stderr':self.stderr[item_name]} - show_fail = callback(retval={str:str})(show_fail) - - _sessids = None - _sesslock = py.std.thread.allocate_lock() - def show_sessid(self): - if not self._sessids: - self._sessids = [] - self._sesslock.acquire() - try: - while 1: - sessid = ''.join(py.std.random.sample( - py.std.string.lowercase, 8)) - if sessid not in self._sessids: - self._sessids.append(sessid) - break - finally: - self._sesslock.release() - return sessid - show_sessid = callback(retval=str)(show_sessid) - - def failed(self, **kwargs): - if not 'sessid' in kwargs: - return - sessid = kwargs['sessid'] - to_del = -1 - for num, i in enumerate(self._sessids): - if i == sessid: - to_del = num - if to_del != -1: - del self._sessids[to_del] - self.pending_events._del(kwargs['sessid']) - - def show_all_statuses(self, sessid='xx'): - retlist = [self.show_status_change(sessid)] - while not self.pending_events.empty_queue(sessid): - retlist.append(self.show_status_change(sessid)) - retval = retlist - return retval - show_all_statuses = callback(retval=[{str:str}])(show_all_statuses) - - def show_status_change(self, sessid): - event = self.pending_events.get(sessid) - if event is None: - self.end_event.set() - return {} - # some dispatcher here - if isinstance(event, repevent.ItemFinish): - args = {} - outcome = event.outcome - for key, val in outcome.__dict__.iteritems(): - args[key] = str(val) - args.update(add_item(event)) - mod_name, mod_fullname = self.findmodule(event.item) - args['modulename'] = str(mod_name) - args['fullmodulename'] = str(mod_fullname) - fullitemname = args['fullitemname'] - if outcome.skipped: - self.skip_reasons[fullitemname] = self.repr_failure_tblong( - event.item, - outcome.skipped, - outcome.skipped.traceback) - elif outcome.excinfo: - self.fail_reasons[fullitemname] = self.repr_failure_tblong( - event.item, outcome.excinfo, outcome.excinfo.traceback) - self.stdout[fullitemname] = outcome.stdout - self.stderr[fullitemname] = outcome.stderr - elif outcome.signal: - self.fail_reasons[fullitemname] = "Received signal %d" % outcome.signal - self.stdout[fullitemname] = outcome.stdout - self.stderr[fullitemname] = outcome.stderr - if event.channel: - args['hostkey'] = event.channel.gateway.host.hostid - else: - args['hostkey'] = '' - elif isinstance(event, repevent.ItemStart): - args = add_item(event) - elif isinstance(event, repevent.TestSessionFinish): - args = {} - args['run'] = str(self.all) - args['fails'] = str(len(self.fail_reasons)) - args['skips'] = str(len(self.skip_reasons)) - elif isinstance(event, repevent.SendItem): - args = add_item(event) - args['hostkey'] = event.channel.gateway.host.hostid - elif isinstance(event, repevent.HostRSyncRootReady): - self.ready_hosts[event.host] = True - args = {'hostname' : event.host.hostname, 'hostkey' : event.host.hostid} - elif isinstance(event, repevent.FailedTryiter): - args = add_item(event) - elif isinstance(event, repevent.DeselectedTest): - args = add_item(event) - args['reason'] = str(event.excinfo.value) - else: - args = {} - args['event'] = str(event) - args['type'] = event.__class__.__name__ - return args - - def repr_failure_tblong(self, item, excinfo, traceback): - lines = [] - for index, entry in py.builtin.enumerate(traceback): - lines.append('----------') - lines.append("%s: %s" % (entry.path, entry.lineno)) - lines += self.repr_source(entry.relline, entry.source) - lines.append("%s: %s" % (excinfo.typename, excinfo.value)) - return "\n".join(lines) - - def repr_source(self, relline, source): - lines = [] - for num, line in enumerate(str(source).split("\n")): - if num == relline: - lines.append(">>>>" + line) - else: - lines.append(" " + line) - return lines - - def report_ItemFinish(self, event): - self.all += 1 - self.pending_events.put(event) - - def report_FailedTryiter(self, event): - fullitemname = "/".join(event.item.listnames()) - self.fail_reasons[fullitemname] = self.repr_failure_tblong( - event.item, event.excinfo, event.excinfo.traceback) - self.stdout[fullitemname] = '' - self.stderr[fullitemname] = '' - self.pending_events.put(event) - - def report_ItemStart(self, event): - if isinstance(event.item, py.test2.collect.Module): - self.pending_events.put(event) - - def report_unknown(self, event): - # XXX: right now, we just pass it for showing - self.pending_events.put(event) - - def _host_ready(self, event): - self.pending_events.put(event) - - def report_HostGatewayReady(self, item): - self.to_rsync[item.host] = len(item.roots) - - def report_HostRSyncRootReady(self, item): - self.to_rsync[item.host] -= 1 - if not self.to_rsync[item.host]: - self._host_ready(item) - - def report_TestStarted(self, event): - # XXX: It overrides our self.hosts - self.hosts = {} - self.ready_hosts = {} - if not event.hosts: - self.hosts = [] - else: - for host in event.hosts: - self.hosts[host] = host - self.ready_hosts[host] = False - self.start_event.set() - self.pending_events.put(event) - - def report_TestSessionFinish(self, event): - self.pending_events.put(event) - kill_server() - - report_InterruptedExecution = report_TestSessionFinish - report_CrashedExecution = report_TestSessionFinish - - def report(self, what): - repfun = getattr(self, "report_" + what.__class__.__name__, - self.report_unknown) - try: - 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 - -exported_methods = ExportedMethods() - -class TestHandler(BaseHTTPRequestHandler): - exported_methods = exported_methods - - def do_GET(self): - path = self.path - if path.endswith("/"): - path = path[:-1] - if path.startswith("/"): - path = path[1:] - m = re.match('^(.*)\?(.*)$', path) - if m: - path = m.group(1) - getargs = m.group(2) - else: - getargs = "" - name_path = path.replace(".", "_") - method_to_call = getattr(self, "run_" + name_path, None) - if method_to_call is None: - exec_meth = getattr(self.exported_methods, name_path, None) - if exec_meth is None: - self.send_error(404, "File %s not found" % path) - else: - try: - self.serve_data('text/json', - json.write(exec_meth(**self.parse_args(getargs)))) - except socket.error: - # client happily disconnected - exported_methods.failed(**self.parse_args(getargs)) - else: - method_to_call() - - def parse_args(self, getargs): - # parse get argument list - if getargs == "": - return {} - - unquote = py.std.urllib.unquote - args = {} - arg_pairs = getargs.split("&") - for arg in arg_pairs: - key, value = arg.split("=") - args[unquote(key)] = unquote(value) - return args - - def log_message(self, format, *args): - # XXX just discard it - pass - - do_POST = do_GET - - def run_(self): - self.run_index() - - def run_index(self): - data = py.path.local(DATADIR).join("index.html").open().read() - self.serve_data("text/html", data) - - def run_jssource(self): - 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()): - from py.__.test2.rsession import webjs - - javascript_source = rpython2javascript(webjs, - FUNCTION_LIST, use_pdb=False) - open(str(js_name), "w").write(javascript_source) - self.serve_data("text/javascript", javascript_source) - else: - js_source = open(str(js_name), "r").read() - self.serve_data("text/javascript", js_source) - - def serve_data(self, content_type, data): - self.send_response(200) - self.send_header("Content-type", content_type) - self.send_header("Content-length", len(data)) - 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) - - def was_failure(self): - return sum(exported_methods.fail_reasons.values()) > 0 - - # 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) - - if start_new: - thread.start_new_thread(httpd.serve_forever, ()) - print "Server started, listening on port %d" % (httpd.server_port,) - return httpd - else: - print "Server started, listening on port %d" % (httpd.server_port,) - httpd.serve_forever() - -def kill_server(): - exported_methods.pending_events.put(None) - while not exported_methods.pending_events.empty(): - time.sleep(.1) - exported_methods.end_event.wait() - Deleted: /py/branch/event/py/test2/rsession/webjs.py ============================================================================== --- /py/branch/event/py/test2/rsession/webjs.py Sun Feb 17 21:22:21 2008 +++ (empty file) @@ -1,355 +0,0 @@ - -""" javascript source for py.test2 distributed -""" - -import py -from py.__.test2.rsession.web import exported_methods -try: - from pypy.translator.js.modules import dom - from pypy.translator.js.helper import __show_traceback -except ImportError: - py.test2.skip("PyPy not found") - -def create_elem(s): - return dom.document.createElement(s) - -def get_elem(el): - return dom.document.getElementById(el) - -def create_text_elem(txt): - return dom.document.createTextNode(txt) - -tracebacks = {} -skips = {} -counters = {} -max_items = {} -short_item_names = {} - -MAX_COUNTER = 30 # Maximal size of one-line table - -class Globals(object): - def __init__(self): - self.pending = [] - self.host = "" - self.data_empty = True - -glob = Globals() - -class Options(object): - """ Store global options - """ - def __init__(self): - self.scroll = True - -opts = Options() - -def comeback(msglist): - if len(msglist) == 0: - return - for item in glob.pending[:]: - if not process(item): - return - glob.pending = [] - for msg in msglist: - if not process(msg): - return - exported_methods.show_all_statuses(glob.sessid, comeback) - -def show_info(data="aa"): - info = dom.document.getElementById("info") - info.style.visibility = "visible" - while len(info.childNodes): - info.removeChild(info.childNodes[0]) - txt = create_text_elem(data) - info.appendChild(txt) - info.style.backgroundColor = "beige" - # XXX: Need guido - -def hide_info(): - info = dom.document.getElementById("info") - info.style.visibility = "hidden" - -def show_interrupt(): - glob.finished = True - dom.document.title = "Py.test [interrupted]" - dom.document.getElementById("Tests").childNodes[0].nodeValue = "Tests [interrupted]" - -def show_crash(): - glob.finished = True - dom.document.title = "Py.test [crashed]" - dom.document.getElementById("Tests").childNodes[0].nodeValue = "Tests [crashed]" - -SCROLL_LINES = 50 - -def opt_scroll(): - if opts.scroll: - opts.scroll = False - else: - opts.scroll = True - -def scroll_down_if_needed(mbox): - if not opts.scroll: - return - #if dom.window.scrollMaxY - dom.window.scrollY < SCROLL_LINES: - mbox.parentNode.scrollIntoView() - -def hide_messagebox(): - mbox = dom.document.getElementById("messagebox") - while mbox.childNodes: - mbox.removeChild(mbox.childNodes[0]) - -def make_module_box(msg): - tr = create_elem("tr") - td = create_elem("td") - tr.appendChild(td) - td.appendChild(create_text_elem("%s[0/%s]" % (msg['itemname'], - msg['length']))) - max_items[msg['fullitemname']] = int(msg['length']) - short_item_names[msg['fullitemname']] = msg['itemname'] - td.id = '_txt_' + msg['fullitemname'] - #tr.setAttribute("id", msg['fullitemname']) - td.setAttribute("onmouseover", - "show_info('%s')" % (msg['fullitemname'],)) - td.setAttribute("onmouseout", "hide_info()") - td2 = create_elem('td') - tr.appendChild(td2) - table = create_elem("table") - td2.appendChild(table) - tbody = create_elem('tbody') - tbody.id = msg['fullitemname'] - table.appendChild(tbody) - counters[msg['fullitemname']] = 0 - return tr - -def add_received_item_outcome(msg, module_part): - if msg['hostkey']: - host_elem = dom.document.getElementById(msg['hostkey']) - glob.host_pending[msg['hostkey']].pop() - count = len(glob.host_pending[msg['hostkey']]) - host_elem.childNodes[0].nodeValue = '%s[%s]' % ( - glob.host_dict[msg['hostkey']], count) - - td = create_elem("td") - td.setAttribute("onmouseover", "show_info('%s')" % ( - msg['fullitemname'],)) - td.setAttribute("onmouseout", "hide_info()") - item_name = msg['fullitemname'] - # TODO: dispatch output - if msg["passed"] == 'True': - txt = create_text_elem(".") - td.appendChild(txt) - elif msg["skipped"] != 'None' and msg["skipped"] != "False": - exported_methods.show_skip(item_name, skip_come_back) - link = create_elem("a") - link.setAttribute("href", "javascript:show_skip('%s')" % ( - msg['fullitemname'],)) - txt = create_text_elem('s') - link.appendChild(txt) - td.appendChild(link) - else: - link = create_elem("a") - link.setAttribute("href", "javascript:show_traceback('%s')" % ( - msg['fullitemname'],)) - txt = create_text_elem('F') - link.setAttribute('class', 'error') - link.appendChild(txt) - td.appendChild(link) - exported_methods.show_fail(item_name, fail_come_back) - - if counters[msg['fullmodulename']] == 0: - tr = create_elem("tr") - module_part.appendChild(tr) - - name = msg['fullmodulename'] - counters[name] += 1 - counter_part = get_elem('_txt_' + name) - newcontent = "%s[%d/%d]" % (short_item_names[name], counters[name], - max_items[name]) - counter_part.childNodes[0].nodeValue = newcontent - module_part.childNodes[-1].appendChild(td) - -def process(msg): - if len(msg) == 0: - return False - elem = dom.document.getElementById("testmain") - #elem.innerHTML += '%s
' % msg['event'] - main_t = dom.document.getElementById("main_table") - if msg['type'] == 'ItemStart': - # we start a new directory or what - #if msg['itemtype'] == 'Module': - tr = make_module_box(msg) - main_t.appendChild(tr) - elif msg['type'] == 'SendItem': - host_elem = dom.document.getElementById(msg['hostkey']) - glob.host_pending[msg['hostkey']].insert(0, msg['fullitemname']) - count = len(glob.host_pending[msg['hostkey']]) - host_elem.childNodes[0].nodeValue = '%s[%s]' % ( - glob.host_dict[msg['hostkey']], count) - - elif msg['type'] == 'HostRSyncRootReady': - host_elem = dom.document.getElementById(msg['hostkey']) - host_elem.style.background = \ - "#00ff00" - host_elem.childNodes[0].nodeValue = '%s[0]' % ( - glob.host_dict[msg['hostkey']],) - elif msg['type'] == 'ItemFinish': - module_part = get_elem(msg['fullmodulename']) - if not module_part: - glob.pending.append(msg) - return True - - add_received_item_outcome(msg, module_part) - elif msg['type'] == 'TestSessionFinish': - text = "FINISHED %s run, %s failures, %s skipped" % (msg['run'], msg['fails'], msg['skips']) - glob.finished = True - dom.document.title = "Py.test %s" % text - dom.document.getElementById("Tests").childNodes[0].nodeValue = \ - "Tests [%s]" % text - elif msg['type'] == 'FailedTryiter': - module_part = get_elem(msg['fullitemname']) - if not module_part: - glob.pending.append(msg) - return True - tr = create_elem("tr") - td = create_elem("td") - a = create_elem("a") - a.setAttribute("href", "javascript:show_traceback('%s')" % ( - msg['fullitemname'],)) - txt = create_text_elem("- FAILED TO LOAD MODULE") - a.appendChild(txt) - td.appendChild(a) - tr.appendChild(td) - module_part.appendChild(tr) - item_name = msg['fullitemname'] - exported_methods.show_fail(item_name, fail_come_back) - elif msg['type'] == 'DeselectedTest': - module_part = get_elem(msg['fullitemname']) - if not module_part: - glob.pending.append(msg) - return True - tr = create_elem("tr") - td = create_elem("td") - txt = create_text_elem("- skipped (%s)" % (msg['reason'],)) - td.appendChild(txt) - tr.appendChild(td) - module_part.appendChild(tr) - elif msg['type'] == 'RsyncFinished': - glob.rsync_done = True - elif msg['type'] == 'InterruptedExecution': - show_interrupt() - elif msg['type'] == 'CrashedExecution': - show_crash() - if glob.data_empty: - mbox = dom.document.getElementById('messagebox') - scroll_down_if_needed(mbox) - return True - -def show_skip(item_name="aa"): - set_msgbox(item_name, skips[item_name]) - -def set_msgbox(item_name, data): - msgbox = get_elem("messagebox") - while len(msgbox.childNodes): - msgbox.removeChild(msgbox.childNodes[0]) - pre = create_elem("pre") - txt = create_text_elem(item_name + "\n" + data) - pre.appendChild(txt) - msgbox.appendChild(pre) - dom.window.location.assign("#message") - glob.data_empty = False - -def show_traceback(item_name="aa"): - data = ("====== Traceback: =========\n%s\n======== Stdout: ========\n%s\n" - "========== Stderr: ==========\n%s\n" % tracebacks[item_name]) - set_msgbox(item_name, data) - -def fail_come_back(msg): - tracebacks[msg['item_name']] = (msg['traceback'], msg['stdout'], - msg['stderr']) - -def skip_come_back(msg): - skips[msg['item_name']] = msg['reason'] - -def reshow_host(): - if glob.host == "": - return - show_host(glob.host) - -def show_host(host_name="aa"): - elem = dom.document.getElementById("jobs") - if elem.childNodes: - elem.removeChild(elem.childNodes[0]) - tbody = create_elem("tbody") - for item in glob.host_pending[host_name]: - tr = create_elem("tr") - td = create_elem("td") - td.appendChild(create_text_elem(item)) - tr.appendChild(td) - tbody.appendChild(tr) - elem.appendChild(tbody) - elem.style.visibility = "visible" - glob.host = host_name - dom.setTimeout(reshow_host, 100) - -def hide_host(): - elem = dom.document.getElementById("jobs") - while len(elem.childNodes): - elem.removeChild(elem.childNodes[0]) - elem.style.visibility = "hidden" - glob.host = "" - -def update_rsync(): - if glob.finished: - return - elem = dom.document.getElementById("Tests") - if glob.rsync_done is True: - elem.childNodes[0].nodeValue = "Tests" - return - text = "Rsyncing" + '.' * glob.rsync_dots - glob.rsync_dots += 1 - if glob.rsync_dots > 5: - glob.rsync_dots = 0 - elem.childNodes[0].nodeValue = "Tests [%s]" % text - dom.setTimeout(update_rsync, 1000) - -def host_init(host_dict): - tbody = dom.document.getElementById("hostsbody") - for host in host_dict.keys(): - tr = create_elem('tr') - tbody.appendChild(tr) - td = create_elem("td") - td.style.background = "#ff0000" - txt = create_text_elem(host_dict[host]) - td.appendChild(txt) - td.id = host - tr.appendChild(td) - td.setAttribute("onmouseover", "show_host('%s')" % host) - td.setAttribute("onmouseout", "hide_host()") - glob.rsync_dots = 0 - glob.rsync_done = False - dom.setTimeout(update_rsync, 1000) - glob.host_dict = host_dict - glob.host_pending = {} - for key in host_dict.keys(): - glob.host_pending[key] = [] - -def key_pressed(key): - if key.charCode == ord('s'): - scroll_box = dom.document.getElementById("opt_scroll") - if opts.scroll: - scroll_box.removeAttribute("checked") - opts.scroll = False - else: - scroll_box.setAttribute("checked", "true") - opts.scroll = True - -def sessid_comeback(id): - glob.sessid = id - exported_methods.show_all_statuses(id, comeback) - -def main(): - glob.finished = False - exported_methods.show_hosts(host_init) - exported_methods.show_sessid(sessid_comeback) - dom.document.onkeypress = key_pressed - dom.document.getElementById("opt_scroll").setAttribute("checked", "True") Deleted: /py/branch/event/py/test2/testing/test_reporter.py ============================================================================== --- /py/branch/event/py/test2/testing/test_reporter.py Sun Feb 17 21:22:21 2008 +++ (empty file) @@ -1,282 +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 - -py.test.skip("rewrite reporter tests completely, take existing as hints") - -from py.__.test2.session import AbstractSession, itemgen -from py.__.test2.reporter import RemoteReporter, LocalReporter, choose_reporter -from py.__.test2 import repevent -from py.__.test2.outcome import ReprOutcome, SerializableOutcome -from py.__.test2.rsession.hostmanage import HostInfo -from py.__.test2.box import Box -from py.__.test2.rsession.testing.basetest import BasicRsessionTest -import sys -from StringIO import StringIO - -class MockSession(object): - def __init__(self, reporter): - self.reporter = reporter - - def start(self, item): - self.reporter(repevent.ItemStart(item)) - - def finish(self, item): - pass - -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() - - try: - py.test.skip("xxx") - except: - skipexc = py.code.ExceptionInfo() - - outcomes = [SerializableOutcome(()), - SerializableOutcome(skipped=skipexc), - SerializableOutcome(excinfo=exc), - SerializableOutcome()] - - 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 = self.get_hosts() - r = self.reporter(config, hosts) - if hosts: - ch = DummyChannel(hosts[0]) - else: - ch = None - for outcome in outcomes: - r.report(repevent.ItemFinish(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 = self.get_hosts() - r = self.reporter(config, hosts) - r.report(repevent.ItemStart(item)) - if hosts: - ch = DummyChannel(hosts[0]) - else: - ch = None - for outcome in outcomes: - r.report(repevent.ItemFinish(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.test2.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.test2.config._reparse([str(tmpdir)]) - rootcol = py.test2.collect.Directory(tmpdir) - hosts = self.get_hosts() - r = self.reporter(config, hosts) - list(itemgen(MockSession(r), [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.test2.ensuretemp("failedtoload") - tmpdir.ensure("__init__.py") - tmpdir.ensure("test_three.py").write(py.code.Source(""" - sadsadsa - """)) - def boxfun(): - config = py.test2.config._reparse([str(tmpdir)]) - rootcol = py.test2.collect.Directory(tmpdir) - hosts = self.get_hosts() - r = self.reporter(config, hosts) - r.report(repevent.TestStarted(hosts, config, ["a"])) - r.report(repevent.RsyncFinished()) - list(itemgen(MockSession(r), [rootcol], r.report)) - r.report(repevent.TestSessionFinish()) - 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_verbose(self): - tmpdir = py.test2.ensuretemp("reporterverbose") - tmpdir.ensure("__init__.py") - tmpdir.ensure("test_one.py").write("def test_x(): pass") - cap = py.io.StdCaptureFD() - config = py.test2.config._reparse([str(tmpdir), '-v']) - hosts = self.get_hosts() - r = self.reporter(config, hosts) - r.report(repevent.TestStarted(hosts, config, [])) - r.report(repevent.RsyncFinished()) - rootcol = py.test2.collect.Directory(tmpdir) - list(itemgen(MockSession(r), [rootcol], r.report)) - r.report(repevent.TestSessionFinish()) - out, err = cap.reset() - assert not err - for i in ['+ testmodule:', 'test_one.py[1]']: # XXX finish - assert i in out - - def _test_still_to_go(self): - tmpdir = py.test2.ensuretemp("stilltogo") - tmpdir.ensure("__init__.py") - cap = py.io.StdCaptureFD() - config = py.test2.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, ["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 get_hosts(self): - return None - - def test_report_received_item_outcome(self): - assert self.report_received_item_outcome() == 'FsF.' - - def test_verbose(self): - self._test_verbose() - - def test_module(self): - output = self._test_module() - assert output.find("test_one") != -1 - assert output.endswith("FsF."), output - - def test_full_module(self): - py.test.skip("fix exact output matching test") - 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 get_hosts(self): - return [HostInfo("host")] - - 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 = ["host", "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 = ["host", "FAILED", - "funcpass", "test_one", - "SKIPPED", - "PASSED"] - for expected in expected_lst: - assert val.find(expected) != -1 - - def test_full_module(self): - py.test.skip("fix exact output matching test") - 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.__.test2.rsession.web import WebReporter - from py.__.test2.rsession.rest import RestReporter - choices = [ - (['-d', '--rest'], RestReporter), - (['-w'], WebReporter), - (['-r'], WebReporter)] - for opts, reporter in choices: - config = py.test2.config._reparse(['xxx'] + opts) - assert choose_reporter(None, config) is reporter - From hpk at codespeak.net Mon Feb 18 09:48:08 2008 From: hpk at codespeak.net (hpk at codespeak.net) Date: Mon, 18 Feb 2008 09:48:08 +0100 (CET) Subject: [py-svn] r51573 - in py/branch/event/py/test2: . testing Message-ID: <20080218084808.4E1601684C3@codespeak.net> Author: hpk Date: Mon Feb 18 09:48:06 2008 New Revision: 51573 Modified: py/branch/event/py/test2/collect.py py/branch/event/py/test2/config.py py/branch/event/py/test2/item.py py/branch/event/py/test2/testing/test_collect.py py/branch/event/py/test2/testing/test_doctest.py Log: use explicit "local" config object in collector tree (instead of going to process-global py.test.config object) Modified: py/branch/event/py/test2/collect.py ============================================================================== --- py/branch/event/py/test2/collect.py (original) +++ py/branch/event/py/test2/collect.py Mon Feb 18 09:48:06 2008 @@ -39,10 +39,12 @@ Nodes with Children are "Collectors" and leaves are the actual Test Items. """ - def __init__(self, name, parent=None): + def __init__(self, name, parent=None, config=None): self.name = name self.parent = parent - self._config = getattr(parent, '_config', py.test2.config) + if config is None: + config = getattr(parent, '_config') + self._config = config def __repr__(self): return "<%s %r>" %(self.__class__.__name__, self.name) @@ -177,8 +179,8 @@ Function = configproperty('Function') Generator = configproperty('Generator') - def __init__(self, name, parent=None): - super(Collector, self).__init__(name, parent) + def __init__(self, name, parent=None, config=None): + super(Collector, self).__init__(name, parent, config=config) self.fspath = getattr(parent, 'fspath', None) def run(self): @@ -200,9 +202,9 @@ raise NotImplementedError("abstract") class FSCollector(Collector): - def __init__(self, fspath, parent=None): + def __init__(self, fspath, parent=None, config=None): fspath = py.path.local(fspath) - super(FSCollector, self).__init__(fspath.basename, parent) + super(FSCollector, self).__init__(fspath.basename, parent, config=config) self.fspath = fspath class Directory(FSCollector): Modified: py/branch/event/py/test2/config.py ============================================================================== --- py/branch/event/py/test2/config.py (original) +++ py/branch/event/py/test2/config.py Mon Feb 18 09:48:06 2008 @@ -82,9 +82,8 @@ pkgpath = path.pypkgpath() if pkgpath is None: pkgpath = path.check(file=1) and path.dirpath() or path - col = self._conftest.rget("Directory", pkgpath)(pkgpath) - col._config = self - return col + Dir = self._conftest.rget("Directory", pkgpath) + return Dir(pkgpath, config=self) def getvalue_pathlist(self, name, path=None): """ return a matching value, which needs to be sequence Modified: py/branch/event/py/test2/item.py ============================================================================== --- py/branch/event/py/test2/item.py (original) +++ py/branch/event/py/test2/item.py Mon Feb 18 09:48:06 2008 @@ -30,8 +30,8 @@ self.stack.append(col) class Item(Base): - def __init__(self, name, parent=None): - super(Item, self).__init__(name, parent) + def __init__(self, name, parent=None, config=None): + super(Item, self).__init__(name, parent=parent, config=config) self.fspath = getattr(parent, 'fspath', None) def startcapture(self): Modified: py/branch/event/py/test2/testing/test_collect.py ============================================================================== --- py/branch/event/py/test2/testing/test_collect.py (original) +++ py/branch/event/py/test2/testing/test_collect.py Mon Feb 18 09:48:06 2008 @@ -4,13 +4,21 @@ from py.__.test2.genitem import genitems from py.__.test2.doctest import DoctestText import setupdata, suptest +from py.__.test2.conftesthandle import Conftest + +class DummyConfig: + def __init__(self): + self._conftest = Conftest() + def getvalue(self, name, fspath): + return self._conftest.rget(name, fspath) def setup_module(mod): mod.tmpdir = py.test2.ensuretemp(mod.__name__) + mod.dummyconfig = DummyConfig() def test_collect_versus_item(): path = setupdata.getexamplefile("filetest.py") - col = py.test2.collect.Module(path) + col = py.test2.collect.Module(path, config=dummyconfig) assert not isinstance(col, py.test2.collect.Item) item = col.join("test_one") assert not hasattr(item, "join") @@ -18,20 +26,21 @@ def test_collector_deprecated_run_method(): path = setupdata.getexamplefile("filetest.py") - col = py.test2.collect.Module(path) + col = py.test2.collect.Module(path, config=dummyconfig) res1 = py.test2.deprecated_call(col.run) res2 = col.listdir() assert res1 == res2 def test_failing_import_execfile(): dest = setupdata.getexamplefile('failingimport.py') - col = py.test2.collect.Module(dest) + col = py.test2.collect.Module(dest, config=dummyconfig) py.test2.raises(ImportError, col.listdir) py.test2.raises(ImportError, col.listdir) def test_collect_listnames_and_back(): path = setupdata.getexamplefile("filetest.py") - col1 = py.test2.collect.Directory(path.dirpath().dirpath()) + col1 = py.test2.collect.Directory(path.dirpath().dirpath(), + config=dummyconfig) col2 = col1.join(path.dirpath().basename) col3 = col2.join(path.basename) l = col3.listnames() @@ -45,7 +54,7 @@ def test_finds_tests(): fn = setupdata.getexamplefile('filetest.py') - col = py.test2.collect.Module(fn) + col = py.test2.collect.Module(fn, config=dummyconfig) l = col.listdir() assert len(l) == 2 assert l[0] == 'test_one' @@ -56,7 +65,7 @@ tmp.ensure('test_found.py') tmp.ensure('found_test.py') - col = py.test2.collect.Directory(tmp) + col = py.test2.collect.Directory(tmp, config=dummyconfig) items = [col.join(x) for x in col.listdir()] assert len(items) == 2 @@ -73,7 +82,7 @@ tmp.ensure("normal", 'test_found.py') tmp.ensure('test_found.py') - col = py.test2.collect.Directory(tmp) + col = py.test2.collect.Directory(tmp, config=dummyconfig) items = col.listdir() assert len(items) == 2 assert 'normal' in items @@ -84,7 +93,7 @@ def filefilter(self, p): return p.check(fnmatch='testspecial*.py') filetest = setupdata.getexamplefile("testspecial_importerror.py") - mydir = MyDirectory(filetest.dirpath()) + mydir = MyDirectory(filetest.dirpath(), config=dummyconfig) l = mydir.listdir() assert len(l) == 1 col = mydir.join(l[0]) @@ -93,16 +102,17 @@ def test_module_file_not_found(): fn = tmpdir.join('nada','no') - col = py.test2.collect.Module(fn) + col = py.test2.collect.Module(fn, config=dummyconfig) py.test2.raises(py.error.ENOENT, col.listdir) def test_syntax_error_in_module(): modpath = setupdata.getexamplefile("syntax_error.py") - col = py.test2.collect.Module(modpath) + col = py.test2.collect.Module(modpath, config=dummyconfig) py.test2.raises(SyntaxError, col.listdir) def test_disabled_class(): - col = py.test2.collect.Module(setupdata.getexamplefile('disabled.py')) + p = setupdata.getexamplefile('disabled.py') + col = py.test2.collect.Module(p, config=dummyconfig) l = col.listdir() assert len(l) == 1 col = col.join(l[0]) @@ -111,13 +121,13 @@ def test_disabled_module(): p = setupdata.getexamplefile("disabled_module.py") - col = py.test2.collect.Module(p) + col = py.test2.collect.Module(p, config=dummyconfig) l = col.listdir() assert len(l) == 0 def test_generative_simple(): tfile = setupdata.getexamplefile('test_generative.py') - col = py.test2.collect.Module(tfile) + col = py.test2.collect.Module(tfile, config=dummyconfig) l = col.listdir() assert len(l) == 2 l = col.multijoin(l) @@ -216,13 +226,13 @@ fnames.sort() tmpdir.ensure('adir', dir=1) fnames.insert(10, 'adir') - col = py.test2.collect.Directory(tmpdir) + col = py.test2.collect.Directory(tmpdir, config=dummyconfig) names = col.listdir() assert names == fnames def test_check_random_inequality(): path = setupdata.getexamplefile("funcexamples.py") - col = py.test2.collect.Module(path) + col = py.test2.collect.Module(path, config=dummyconfig) fn = col.join("funcpass") assert fn != 3 assert fn != col Modified: py/branch/event/py/test2/testing/test_doctest.py ============================================================================== --- py/branch/event/py/test2/testing/test_doctest.py (original) +++ py/branch/event/py/test2/testing/test_doctest.py Mon Feb 18 09:48:06 2008 @@ -4,7 +4,7 @@ from py.__.test2.outcome import Skipped, Failed, Passed, Outcome def test_simple_docteststring(): - testitem = DoctestText(name="dummy", parent=None) + testitem = DoctestText(name="dummy", parent=None, config=42) testitem._setcontent(""" >>> i = 0 >>> i + 1 @@ -14,7 +14,7 @@ assert res is None def test_simple_docteststring_failing(): - testitem = DoctestText(name="dummy2", parent=None) + testitem = DoctestText(name="dummy2", parent=None, config=42) testitem._setcontent(""" >>> i = 0 >>> i + 1 From hpk at codespeak.net Tue Feb 19 18:25:48 2008 From: hpk at codespeak.net (hpk at codespeak.net) Date: Tue, 19 Feb 2008 18:25:48 +0100 (CET) Subject: [py-svn] r51648 - in py/branch/event/py/test2: . testing Message-ID: <20080219172548.8594B16845E@codespeak.net> Author: hpk Date: Tue Feb 19 18:25:48 2008 New Revision: 51648 Modified: py/branch/event/py/test2/collect.py py/branch/event/py/test2/executor.py py/branch/event/py/test2/present.py py/branch/event/py/test2/testing/suptest.py py/branch/event/py/test2/testing/test_present.py py/branch/event/py/test2/testing/test_session.py Log: * test items can now return their own failure representation via repr_failure(excinfo) * shift test helper to become general Modified: py/branch/event/py/test2/collect.py ============================================================================== --- py/branch/event/py/test2/collect.py (original) +++ py/branch/event/py/test2/collect.py Tue Feb 19 18:25:48 2008 @@ -25,6 +25,7 @@ """ from __future__ import generators import py +from present import FuncPresenter sysex = (KeyboardInterrupt, SystemExit, GeneratorExit) @@ -449,6 +450,12 @@ if meth is not None: return meth(self.obj) + def repr_failure(self, excinfo): + """ return a textual failure representation for this item. """ + p = FuncPresenter(self._config) + p.repr_failure(self, excinfo) + return p.stringio.getvalue() + class Generator(FunctionMixin, PyCollectorMixin, Collector): def listdir(self): self._prepare() Modified: py/branch/event/py/test2/executor.py ============================================================================== --- py/branch/event/py/test2/executor.py (original) +++ py/branch/event/py/test2/executor.py Tue Feb 19 18:25:48 2008 @@ -32,9 +32,7 @@ else: testrep.failed = True testrep.exconly = excinfo.exconly() - p = present.Presenter(self.config) - p.repr_failure(self.item, excinfo) - testrep.repr_failure = p.stringio.getvalue() + testrep.repr_failure = self.item.repr_failure(excinfo) def execute(self, capture=True): testrep = repevent.ItemTestReport(self.item._get_collector_trail()) Modified: py/branch/event/py/test2/present.py ============================================================================== --- py/branch/event/py/test2/present.py (original) +++ py/branch/event/py/test2/present.py Tue Feb 19 18:25:48 2008 @@ -43,15 +43,13 @@ except (TypeError, ValueError): return str(v) -class Presenter(object): - """ Class used for presentation of various objects, - sharing common output style - """ +class FuncPresenter(object): + """ presenting information about failing Functions and Generators. """ def __init__(self, config, out=None): self.config = config if out is None: self.stringio = py.std.StringIO.StringIO() - out = getout(self.stringio) + out = getout(self.stringio) assert hasattr(out, 'write'), out self.out = out @@ -133,10 +131,7 @@ def repr_failure(self, item, excinfo): traceback = self.filtertraceback(item, excinfo.traceback) - if excinfo.errisinstance(RuntimeError): - recursionindex = traceback.recursionindex() - else: - recursionindex = None + recursionindex = traceback.recursionindex() repr_tb = getattr(self, "repr_tb_" + self.config.option.tbstyle) repr_tb(item, excinfo, traceback, recursionindex) Modified: py/branch/event/py/test2/testing/suptest.py ============================================================================== --- py/branch/event/py/test2/testing/suptest.py (original) +++ py/branch/event/py/test2/testing/suptest.py Tue Feb 19 18:25:48 2008 @@ -117,3 +117,14 @@ print "created test file", p p.dirpath("__init__.py").ensure() return p + +def getfailing(source): + tfile = makeuniquepyfile(source) + sorter = events_from_cmdline([tfile]) + # get failure base info + failevents = sorter.get(repevent.ItemFinish) + assert len(failevents) == 1 + item = failevents[0].item + excinfo = failevents[0].excinfo + return item, excinfo + Modified: py/branch/event/py/test2/testing/test_present.py ============================================================================== --- py/branch/event/py/test2/testing/test_present.py (original) +++ py/branch/event/py/test2/testing/test_present.py Tue Feb 19 18:25:48 2008 @@ -40,22 +40,9 @@ def setup_class(cls): cls.tmpdir = py.test2.ensuretemp(cls.__name__) - def getconfig(self, args=()): - return py.test2.config._reparse([self.tmpdir] + list(args)) - def getpresenter(self, cmdlinearg=""): - config = self.getconfig(cmdlinearg.split()) - return present.Presenter(config) - - def getfailing(self, source): - tfile = suptest.makeuniquepyfile(source) - sorter = suptest.events_from_cmdline([tfile]) - # get failure base info - failevents = sorter.get(repevent.ItemFinish) - assert len(failevents) == 1 - item = failevents[0].item - excinfo = failevents[0].excinfo - return item, excinfo + config = py.test2.config._reparse([self.tmpdir, cmdlinearg]) + return present.FuncPresenter(config) def gentest(self, check, **options): print "using config options", options @@ -103,7 +90,7 @@ assert result.find(key) != -1 def test_repr_failure_simple(self): - item, excinfo = self.getfailing(""" + item, excinfo = suptest.getfailing(""" def test_one(): # failingsourcemarker assert 42 == 43 @@ -118,7 +105,7 @@ assert re.search(r">.*assert 42 == 43", s) def test_repr_failure_recursive_funcs(self): - item, excinfo = self.getfailing(""" + item, excinfo = suptest.getfailing(""" def rec2(x): return rec1(x+1) def rec1(x): @@ -140,7 +127,7 @@ self.gentest(check, showlocals=True) def test_repr_failing_setup(self): - item, excinfo = self.getfailing(""" + item, excinfo = suptest.getfailing(""" def setup_module(mod): xyz def test_one(): @@ -156,3 +143,19 @@ self.gentest(check, tbstyle="short") self.gentest(check, fulltrace=True) self.gentest(check, showlocals=True) + + def test_repr_failing_generator(self): + py.test.skip("XXX fix generator repr") + item, excinfo = suptest.getfailing(""" + def test_gen(): + def check(x): + assert x + yield check, 0 + """) + s = item.repr_failure(excinfo) + lines = s.split("\n") + assert lines[1].find("test_gen[0] -> check(0)") != -1 + assert lines[2].find("def check(x):") != -1 + assert 0 + + Modified: py/branch/event/py/test2/testing/test_session.py ============================================================================== --- py/branch/event/py/test2/testing/test_session.py (original) +++ py/branch/event/py/test2/testing/test_session.py Tue Feb 19 18:25:48 2008 @@ -1,6 +1,6 @@ import py from py.__.test2 import repevent -import suptest +import suptest, setupdata def setup_module(mod): mod.tmpdir = py.test.ensuretemp(mod.__name__) @@ -266,3 +266,20 @@ testrep = sorter.getreport("test_two") assert testrep.stdout.startswith("failed") assert not testrep.stderr + + def test_function_repr_failure(self): + o = setupdata.getexamplefile("filetest.py") + conftest = o.dirpath('conftest.py') + conftest.write(py.code.Source(""" + import py + l = [] + class Function(py.test2.collect.Function): + def repr_failure(self, excinfo): + return "custom_repr %s" % self.name + """)) + sorter = suptest.events_from_cmdline([o]) + sorter.assertoutcome(failed=2) + rep = sorter.getreport("test_one") + assert rep.repr_failure == "custom_repr test_one" + rep = sorter.getreport("test_method_one") + assert rep.repr_failure == "custom_repr test_method_one" From hpk at codespeak.net Tue Feb 19 19:05:18 2008 From: hpk at codespeak.net (hpk at codespeak.net) Date: Tue, 19 Feb 2008 19:05:18 +0100 (CET) Subject: [py-svn] r51649 - in py/branch/event/py/test2: . testing Message-ID: <20080219180518.9375C16802D@codespeak.net> Author: hpk Date: Tue Feb 19 19:05:15 2008 New Revision: 51649 Modified: py/branch/event/py/test2/collect.py py/branch/event/py/test2/item.py py/branch/event/py/test2/present.py py/branch/event/py/test2/testing/test_present.py Log: * special generator test reporting * repr_failure only on Function items Modified: py/branch/event/py/test2/collect.py ============================================================================== --- py/branch/event/py/test2/collect.py (original) +++ py/branch/event/py/test2/collect.py Tue Feb 19 19:05:15 2008 @@ -25,7 +25,6 @@ """ from __future__ import generators import py -from present import FuncPresenter sysex = (KeyboardInterrupt, SystemExit, GeneratorExit) @@ -450,12 +449,6 @@ if meth is not None: return meth(self.obj) - def repr_failure(self, excinfo): - """ return a textual failure representation for this item. """ - p = FuncPresenter(self._config) - p.repr_failure(self, excinfo) - return p.stringio.getvalue() - class Generator(FunctionMixin, PyCollectorMixin, Collector): def listdir(self): self._prepare() Modified: py/branch/event/py/test2/item.py ============================================================================== --- py/branch/event/py/test2/item.py (original) +++ py/branch/event/py/test2/item.py Tue Feb 19 19:05:15 2008 @@ -1,6 +1,7 @@ import py from py.__.test2.collect import FunctionMixin, Base +import present _dummy = object() @@ -64,3 +65,17 @@ """ execute the given test function. """ target(*args) + def repr_failure(self, excinfo): + """ return a textual failure representation for this item. """ + p = present.FuncPresenter(self._config) + p.repr_failure_headline(self) + p.out.line("") + if self.name[-1] == "]": # generated test has trailing [num] + args = present.safe_repr._repr(self._args) + line = "%s%s -> %s%s" %(self.parent.name, self.name, + self.obj.__name__, args) + p.out.line(line) + p.repr_tb(self, excinfo) + return p.stringio.getvalue() + + Modified: py/branch/event/py/test2/present.py ============================================================================== --- py/branch/event/py/test2/present.py (original) +++ py/branch/event/py/test2/present.py Tue Feb 19 19:05:15 2008 @@ -130,9 +130,12 @@ return traceback def repr_failure(self, item, excinfo): + self.repr_failure_headline(item) + self.repr_tb(item, excinfo) + + def repr_tb(self, item, excinfo): traceback = self.filtertraceback(item, excinfo.traceback) recursionindex = traceback.recursionindex() - repr_tb = getattr(self, "repr_tb_" + self.config.option.tbstyle) repr_tb(item, excinfo, traceback, recursionindex) @@ -147,12 +150,6 @@ last = traceback[-1] first = traceback[0] for index, entry in py.builtin.enumerate(traceback): - if entry == first: - if item: - self.repr_failure_headline(item) - self.out.line() - else: - self.out.line() source = self.getentrysource(entry) firstsourceline = entry.getfirstlinesource() marker_location = entry.lineno - firstsourceline Modified: py/branch/event/py/test2/testing/test_present.py ============================================================================== --- py/branch/event/py/test2/testing/test_present.py (original) +++ py/branch/event/py/test2/testing/test_present.py Tue Feb 19 19:05:15 2008 @@ -145,7 +145,6 @@ self.gentest(check, showlocals=True) def test_repr_failing_generator(self): - py.test.skip("XXX fix generator repr") item, excinfo = suptest.getfailing(""" def test_gen(): def check(x): @@ -153,9 +152,9 @@ yield check, 0 """) s = item.repr_failure(excinfo) + print s lines = s.split("\n") - assert lines[1].find("test_gen[0] -> check(0)") != -1 - assert lines[2].find("def check(x):") != -1 - assert 0 + assert lines[2].find("test_gen[0] -> check(0,)") != -1 + assert lines[3].find("def check(x):") != -1 From hpk at codespeak.net Tue Feb 19 19:11:13 2008 From: hpk at codespeak.net (hpk at codespeak.net) Date: Tue, 19 Feb 2008 19:11:13 +0100 (CET) Subject: [py-svn] r51650 - in py/branch/event/py/test2: . testing Message-ID: <20080219181113.E527E1683FA@codespeak.net> Author: hpk Date: Tue Feb 19 19:11:13 2008 New Revision: 51650 Modified: py/branch/event/py/test2/item.py py/branch/event/py/test2/testing/test_present.py Log: don't print generated test info with full tracebacks Modified: py/branch/event/py/test2/item.py ============================================================================== --- py/branch/event/py/test2/item.py (original) +++ py/branch/event/py/test2/item.py Tue Feb 19 19:11:13 2008 @@ -71,10 +71,11 @@ p.repr_failure_headline(self) p.out.line("") if self.name[-1] == "]": # generated test has trailing [num] - args = present.safe_repr._repr(self._args) - line = "%s%s -> %s%s" %(self.parent.name, self.name, - self.obj.__name__, args) - p.out.line(line) + if not self._config.option.fulltrace: + args = present.safe_repr._repr(self._args) + line = "%s%s -> %s%s" %(self.parent.name, self.name, + self.obj.__name__, args) + p.out.line(line) p.repr_tb(self, excinfo) return p.stringio.getvalue() Modified: py/branch/event/py/test2/testing/test_present.py ============================================================================== --- py/branch/event/py/test2/testing/test_present.py (original) +++ py/branch/event/py/test2/testing/test_present.py Tue Feb 19 19:11:13 2008 @@ -156,5 +156,9 @@ lines = s.split("\n") assert lines[2].find("test_gen[0] -> check(0,)") != -1 assert lines[3].find("def check(x):") != -1 + item._config.option.fulltrace = True + s = item.repr_failure(excinfo) + lines = s.split("\n") + assert lines[2].find("test_gen[0] -> check(0,)") == -1 From hpk at codespeak.net Tue Feb 19 20:29:37 2008 From: hpk at codespeak.net (hpk at codespeak.net) Date: Tue, 19 Feb 2008 20:29:37 +0100 (CET) Subject: [py-svn] r51651 - in py/branch/event/py/test2: . testing Message-ID: <20080219192937.32B651683D6@codespeak.net> Author: hpk Date: Tue Feb 19 20:29:35 2008 New Revision: 51651 Modified: py/branch/event/py/test2/present.py py/branch/event/py/test2/testing/test_present.py Log: test and streamline short tracebacks Modified: py/branch/event/py/test2/present.py ============================================================================== --- py/branch/event/py/test2/present.py (original) +++ py/branch/event/py/test2/present.py Tue Feb 19 20:29:35 2008 @@ -57,8 +57,10 @@ """ This one represents piece of source with possible marker at requested position """ + if source is None: + self.out.line("???") + return if isinstance(source, str): - # why the hell, string is iterable? source = source.split("\n") if marker_location < 0: marker_location += len(source) @@ -85,12 +87,16 @@ s = str(source.getstatement(len(source)-1)) except KeyboardInterrupt: raise - except: + except: s = str(source[-1]) - indent = " " * (4 + (len(s) - len(s.lstrip()))) + indent = 4 + (len(s) - len(s.lstrip())) + self.repr_exconly(excinfo, indent=indent) + + def repr_exconly(self, excinfo, indent): + indent = " " * indent # get the real exception information out lines = excinfo.exconly(tryshort=True).split('\n') - self.out.line('>' + indent[:-1] + lines.pop(0)) + self.out.line('E' + indent[:-1] + lines.pop(0)) for x in lines: self.out.line(indent + x) @@ -133,12 +139,6 @@ self.repr_failure_headline(item) self.repr_tb(item, excinfo) - def repr_tb(self, item, excinfo): - traceback = self.filtertraceback(item, excinfo.traceback) - recursionindex = traceback.recursionindex() - repr_tb = getattr(self, "repr_tb_" + self.config.option.tbstyle) - repr_tb(item, excinfo, traceback, recursionindex) - def repr_out_err(self, colitem): for parent in colitem.listchain(): for name, obj in zip(['out', 'err'], parent._getouterr()): @@ -146,34 +146,44 @@ self.out.sep("- ", "%s: recorded std%s" % (parent.name, name)) self.out.line(obj) + def repr_tb_entry(self, entry, excinfo=None): + # excinfo is None if this is the last tb entry + source = self.getentrysource(entry) + firstsourceline = entry.getfirstlinesource() + marker_location = entry.lineno - firstsourceline + self.repr_source(source, '>', marker_location) + if excinfo: + self.repr_failure_explanation(excinfo, source) + self.out.line("") + self.out.line("[%s:%d]" %(entry.path, entry.lineno+1)) + self.repr_locals(entry.locals) + + def repr_tb_entry_last(self, item, entry, excinfo): + self.repr_tb_entry(entry, excinfo) + self.repr_out_err(item) + + def repr_tb(self, item, excinfo): + traceback = self.filtertraceback(item, excinfo.traceback) + recursionindex = traceback.recursionindex() + repr_tb = getattr(self, "repr_tb_" + self.config.option.tbstyle) + repr_tb(item, excinfo, traceback, recursionindex) + def repr_tb_long(self, item, excinfo, traceback, recursionindex): last = traceback[-1] - first = traceback[0] for index, entry in py.builtin.enumerate(traceback): - source = self.getentrysource(entry) - firstsourceline = entry.getfirstlinesource() - marker_location = entry.lineno - firstsourceline - if entry == last: - self.repr_source(source, 'E', marker_location) - self.repr_failure_explanation(excinfo, source) + if last != entry: + self.repr_tb_entry(entry) + self.out.sep("_ ") else: - self.repr_source(source, '>', marker_location) - self.out.line("") - self.out.line("[%s:%d]" %(entry.path, entry.lineno+1)) - self.repr_locals(entry.locals) - - # trailing info - if entry == last: - self.repr_out_err(item) + self.repr_tb_entry_last(item, entry, excinfo) self.out.sep("_") - else: - self.out.sep("_ ") - if index == recursionindex: - self.out.line("Recursion detected (same locals & position)") - self.out.sep("!") - break + if index == recursionindex: + self.out.line("Recursion detected (same locals & position)") + self.out.sep("!") + break def repr_tb_short(self, item, excinfo, traceback, recursionindex): + # XXX refactor self.out.line() last = traceback[-1] for index, entry in py.builtin.enumerate(traceback): @@ -184,21 +194,13 @@ path, entry.lineno+1, entry.name)) try: source = entry.getsource().lines - except py.error.ENOENT: - source = ["?"] + source = source[relline].lstrip() + except (IndexError, py.error.ENOENT): + source = None else: - try: - if len(source) > 1: - source = source[relline] - except IndexError: - source = [] + self.out.line(" " + source) if entry == last: - if source: - self.repr_source(source, 'E') - self.repr_failure_explanation(excinfo, source) - else: - if source: - self.repr_source(source, ' ') + self.repr_exconly(excinfo, indent=4) self.repr_locals(entry.locals) # trailing info Modified: py/branch/event/py/test2/testing/test_present.py ============================================================================== --- py/branch/event/py/test2/testing/test_present.py (original) +++ py/branch/event/py/test2/testing/test_present.py Tue Feb 19 20:29:35 2008 @@ -79,7 +79,7 @@ source = py.code.Source(f) e = f() p.repr_failure_explanation(e, source) - assert p.stringio.getvalue().startswith("> ") + assert p.stringio.getvalue().startswith("E ") def test_repr_local(self): p = self.getpresenter("--showlocals") @@ -137,7 +137,7 @@ p.repr_failure(item, excinfo) s = p.stringio.getvalue() print s - assert re.search(">.*xyz", s) + assert re.search(" xyz", s) assert re.search("NameError:.*xyz", s) self.gentest(check, tbstyle="short") @@ -160,5 +160,30 @@ s = item.repr_failure(excinfo) lines = s.split("\n") assert lines[2].find("test_gen[0] -> check(0,)") == -1 - + def test_repr_tb_short(self): + item, excinfo = suptest.getfailing(""" + def f(x): + assert x + def test_f(): + f(0) + """) + item._config.option.tbstyle = "short" + s = item.repr_failure(excinfo) + print s + index = -1 + basename = item.fspath.basename + lines = s.split("\n")[3:] + for line in ( + ' File "%s", line 5, in test_f' % basename, + ' f(0)', + ' File "%s", line 3, in f' % basename, + ' assert x', + 'E assert 0' + ): + actual = lines.pop(0) + actual = actual.rstrip() + if line != actual: + print "expected:", repr(line) + print "got :", repr(actual) + assert 0 From hpk at codespeak.net Tue Feb 19 20:57:41 2008 From: hpk at codespeak.net (hpk at codespeak.net) Date: Tue, 19 Feb 2008 20:57:41 +0100 (CET) Subject: [py-svn] r51652 - in py/branch/event/py/test2: . testing Message-ID: <20080219195741.E82391683EE@codespeak.net> Author: hpk Date: Tue Feb 19 20:57:39 2008 New Revision: 51652 Modified: py/branch/event/py/test2/collect.py py/branch/event/py/test2/item.py py/branch/event/py/test2/present.py py/branch/event/py/test2/testing/test_present.py Log: refine traceback filtering and test failing generators some more Modified: py/branch/event/py/test2/collect.py ============================================================================== --- py/branch/event/py/test2/collect.py (original) +++ py/branch/event/py/test2/collect.py Tue Feb 19 20:57:39 2008 @@ -25,6 +25,7 @@ """ from __future__ import generators import py +from py.__.test2 import present sysex = (KeyboardInterrupt, SystemExit, GeneratorExit) @@ -160,6 +161,16 @@ """ return self._config.get_collector_trail(self) + def repr_failure(self, excinfo): + p = present.FuncPresenter(self._config) + p.repr_failure_headline(self) + p.out.line("") + p.repr_tb(self, excinfo) + return p.stringio.getvalue() + + def prunetraceback(self, traceback): + return traceback + class Collector(Base): """ @@ -449,6 +460,16 @@ if meth is not None: return meth(self.obj) + def prunetraceback(self, traceback): + if not self._config.option.fulltrace: + code = py.code.Code(self.obj) + path, firstlineno = code.path, code.firstlineno + ntraceback = traceback.cut(path=path, firstlineno=firstlineno) + if ntraceback == traceback: + ntraceback = ntraceback.cut(path=path) + traceback = ntraceback.filter() + return traceback + class Generator(FunctionMixin, PyCollectorMixin, Collector): def listdir(self): self._prepare() Modified: py/branch/event/py/test2/item.py ============================================================================== --- py/branch/event/py/test2/item.py (original) +++ py/branch/event/py/test2/item.py Tue Feb 19 20:57:39 2008 @@ -70,7 +70,7 @@ p = present.FuncPresenter(self._config) p.repr_failure_headline(self) p.out.line("") - if self.name[-1] == "]": # generated test has trailing [num] + if self.name[-1] == "]": # print extra info for generated tests if not self._config.option.fulltrace: args = present.safe_repr._repr(self._args) line = "%s%s -> %s%s" %(self.parent.name, self.name, Modified: py/branch/event/py/test2/present.py ============================================================================== --- py/branch/event/py/test2/present.py (original) +++ py/branch/event/py/test2/present.py Tue Feb 19 20:57:39 2008 @@ -124,17 +124,6 @@ self.out.line("%-10s =\\" % (name,)) py.std.pprint.pprint(value, stream=self.out) - def filtertraceback(self, item, traceback): - if isinstance(item, py.test2.collect.Function) \ - and not self.config.option.fulltrace: - code = py.code.Code(item.obj) - path, firstlineno = code.path, code.firstlineno - ntraceback = traceback.cut(path=path, firstlineno=firstlineno) - if ntraceback == traceback: - ntraceback = ntraceback.cut(path=path) - traceback = ntraceback.filter() - return traceback - def repr_failure(self, item, excinfo): self.repr_failure_headline(item) self.repr_tb(item, excinfo) @@ -163,7 +152,7 @@ self.repr_out_err(item) def repr_tb(self, item, excinfo): - traceback = self.filtertraceback(item, excinfo.traceback) + traceback = item.prunetraceback(excinfo.traceback) recursionindex = traceback.recursionindex() repr_tb = getattr(self, "repr_tb_" + self.config.option.tbstyle) repr_tb(item, excinfo, traceback, recursionindex) Modified: py/branch/event/py/test2/testing/test_present.py ============================================================================== --- py/branch/event/py/test2/testing/test_present.py (original) +++ py/branch/event/py/test2/testing/test_present.py Tue Feb 19 20:57:39 2008 @@ -144,7 +144,26 @@ self.gentest(check, fulltrace=True) self.gentest(check, showlocals=True) - def test_repr_failing_generator(self): + def test_repr_failing_generator_itself(self): + sorter = suptest.events_from_runsource(""" + def test_gen(): + def check(x): + assert x + xyz + yield check, 0 + """) + l = sorter.getfailedcollections() + assert len(l) == 1 + ev = l[0] + print ev + s = ev.collector.repr_failure(ev.excinfo) + print s + i = s.find("def ") + assert i != -1 + assert s[i:].startswith("def test_gen():") + assert s.find("NameError: ") != -1 + + def test_repr_failing_generated_test(self): item, excinfo = suptest.getfailing(""" def test_gen(): def check(x): From hpk at codespeak.net Wed Feb 20 08:51:50 2008 From: hpk at codespeak.net (hpk at codespeak.net) Date: Wed, 20 Feb 2008 08:51:50 +0100 (CET) Subject: [py-svn] r51665 - py/branch/event/py/test2 Message-ID: <20080220075150.6CA27168433@codespeak.net> Author: hpk Date: Wed Feb 20 08:51:46 2008 New Revision: 51665 Modified: py/branch/event/py/test2/outcome.py Log: streamline py.test.* helpers a bit Modified: py/branch/event/py/test2/outcome.py ============================================================================== --- py/branch/event/py/test2/outcome.py (original) +++ py/branch/event/py/test2/outcome.py Wed Feb 20 08:51:46 2008 @@ -8,6 +8,9 @@ import sys class Outcome: + """ Outcome and its subclass instances indicate and + contain info about test and collection outcomes. + """ def __init__(self, msg=None, excinfo=None): self.msg = msg self.excinfo = excinfo @@ -21,6 +24,9 @@ class Passed(Outcome): pass +class Skipped(Outcome): + pass + class Failed(Outcome): pass @@ -30,20 +36,18 @@ self.expr = expr self.expected = expected -class Skipped(Outcome): - pass - class Exit(Exception): """ for immediate program exits without tracebacks and reporter/summary. """ - def __init__(self, msg="unknown reason", item=None): + def __init__(self, msg="unknown reason"): self.msg = msg Exception.__init__(self, msg) # exposed helper methods -def exit(msg, item=None): +def exit(msg): """ exit testing process immediately. """ - raise Exit(msg=msg, item=item) + __tracebackhide__ = True + raise Exit(msg) def skip(msg=""): """ skip with the given Message. """ @@ -59,8 +63,8 @@ """ raise AssertionError, if target code does not raise the expected exception. """ - assert args __tracebackhide__ = True + assert args if isinstance(args[0], str): expr, = args assert isinstance(expr, str) From hpk at codespeak.net Wed Feb 20 09:02:34 2008 From: hpk at codespeak.net (hpk at codespeak.net) Date: Wed, 20 Feb 2008 09:02:34 +0100 (CET) Subject: [py-svn] r51666 - py/branch/event/py/test2 Message-ID: <20080220080234.6C5C216843D@codespeak.net> Author: hpk Date: Wed Feb 20 09:02:33 2008 New Revision: 51666 Modified: py/branch/event/py/test2/collect.py py/branch/event/py/test2/item.py Log: fspath used for most items and collectors Modified: py/branch/event/py/test2/collect.py ============================================================================== --- py/branch/event/py/test2/collect.py (original) +++ py/branch/event/py/test2/collect.py Wed Feb 20 09:02:33 2008 @@ -46,6 +46,7 @@ if config is None: config = getattr(parent, '_config') self._config = config + self.fspath = getattr(parent, 'fspath', None) def __repr__(self): return "<%s %r>" %(self.__class__.__name__, self.name) @@ -190,10 +191,6 @@ Function = configproperty('Function') Generator = configproperty('Generator') - def __init__(self, name, parent=None, config=None): - super(Collector, self).__init__(name, parent, config=config) - self.fspath = getattr(parent, 'fspath', None) - def run(self): """ deprecated: use listdir(). """ py.std.warnings.warn("deprecated: use listdir()", category=DeprecationWarning) Modified: py/branch/event/py/test2/item.py ============================================================================== --- py/branch/event/py/test2/item.py (original) +++ py/branch/event/py/test2/item.py Wed Feb 20 09:02:33 2008 @@ -31,10 +31,6 @@ self.stack.append(col) class Item(Base): - def __init__(self, name, parent=None, config=None): - super(Item, self).__init__(name, parent=parent, config=config) - self.fspath = getattr(parent, 'fspath', None) - def startcapture(self): self._config._startcapture(self, path=self.fspath) From hpk at codespeak.net Wed Feb 20 09:24:13 2008 From: hpk at codespeak.net (hpk at codespeak.net) Date: Wed, 20 Feb 2008 09:24:13 +0100 (CET) Subject: [py-svn] r51667 - in py/branch/event/py/test2: . testing Message-ID: <20080220082413.B0D5C168433@codespeak.net> Author: hpk Date: Wed Feb 20 09:24:13 2008 New Revision: 51667 Modified: py/branch/event/py/test2/collect.py py/branch/event/py/test2/item.py py/branch/event/py/test2/testing/test_collect.py Log: * remove redundant reprs * fix XXX and streamline eq/ne/cmp operators Modified: py/branch/event/py/test2/collect.py ============================================================================== --- py/branch/event/py/test2/collect.py (original) +++ py/branch/event/py/test2/collect.py Wed Feb 20 09:24:13 2008 @@ -52,9 +52,9 @@ return "<%s %r>" %(self.__class__.__name__, self.name) def __eq__(self, other): - # XXX a rather strict check for now to not confuse - # the SetupState.prepare() logic - return self is other + if not isinstance(other, Base): + return False + return self.name == other.name and self.parent == other.parent def __hash__(self): return hash((self.name, self.parent)) @@ -63,9 +63,10 @@ return not self == other def __cmp__(self, other): + if not isinstance(other, Base): + return -1 s1 = self._getsortvalue() s2 = other._getsortvalue() - #print "cmp", s1, s2 return cmp(s1, s2) def multijoin(self, namelist): @@ -353,9 +354,6 @@ def finishcapture(self): self._config._finishcapture(self) - def __repr__(self): - return "<%s %r>" % (self.__class__.__name__, self.name) - def _getobj(self): failure = self._stickyfailure if failure is not None: Modified: py/branch/event/py/test2/item.py ============================================================================== --- py/branch/event/py/test2/item.py (original) +++ py/branch/event/py/test2/item.py Wed Feb 20 09:24:13 2008 @@ -1,7 +1,7 @@ import py from py.__.test2.collect import FunctionMixin, Base -import present +from py.__.test2 import present _dummy = object() @@ -48,9 +48,6 @@ if obj is not _dummy: self._obj = obj self._sort_value = sort_value - - def __repr__(self): - return "<%s %r>" %(self.__class__.__name__, self.name) def run(self): """ setup and execute the underlying test function. """ Modified: py/branch/event/py/test2/testing/test_collect.py ============================================================================== --- py/branch/event/py/test2/testing/test_collect.py (original) +++ py/branch/event/py/test2/testing/test_collect.py Wed Feb 20 09:24:13 2008 @@ -230,15 +230,34 @@ names = col.listdir() assert names == fnames -def test_check_random_inequality(): +def test_check_equality_and_cmp_basic(): path = setupdata.getexamplefile("funcexamples.py") col = py.test2.collect.Module(path, config=dummyconfig) - fn = col.join("funcpass") - assert fn != 3 - assert fn != col - assert fn != [1,2,3] - assert [1,2,3] != fn - assert col != fn + fn1 = col.join("funcpassed") + assert isinstance(fn1, py.test2.collect.Function) + fn2 = col.join("funcpassed") + assert isinstance(fn2, py.test2.collect.Function) + + assert fn1 == fn2 + assert fn1 != col + assert cmp(fn1, fn2) == 0 + assert hash(fn1) == hash(fn2) + + fn3 = col.join("funcfailed") + assert isinstance(fn3, py.test2.collect.Function) + assert not (fn1 == fn3) + assert fn1 != fn3 + assert cmp(fn1, fn3) == -1 + + assert cmp(fn1, 10) == -1 + assert cmp(fn2, 10) == -1 + assert cmp(fn3, 10) == -1 + for fn in fn1,fn2,fn3: + assert fn != 3 + assert fn != col + assert fn != [1,2,3] + assert [1,2,3] != fn + assert col != fn class Testgenitems: def setup_class(cls): From hpk at codespeak.net Wed Feb 20 09:38:47 2008 From: hpk at codespeak.net (hpk at codespeak.net) Date: Wed, 20 Feb 2008 09:38:47 +0100 (CET) Subject: [py-svn] r51668 - py/branch/event/py/test2 Message-ID: <20080220083847.5CFE7168440@codespeak.net> Author: hpk Date: Wed Feb 20 09:38:46 2008 New Revision: 51668 Modified: py/branch/event/py/test2/executor.py py/branch/event/py/test2/session.py Log: simplify exception catching Modified: py/branch/event/py/test2/executor.py ============================================================================== --- py/branch/event/py/test2/executor.py (original) +++ py/branch/event/py/test2/executor.py Wed Feb 20 09:38:46 2008 @@ -9,6 +9,8 @@ from py.__.test2 import repevent, present import py.__.test2.custompdb +sysex = (KeyboardInterrupt, SystemExit, GeneratorExit) + class RunExecutor(object): """ Same as in executor, but just running run """ @@ -41,9 +43,7 @@ self.run(capture) finally: testrep.stdout, testrep.stderr = self.item._getouterr() - except Skipped: - self._fillreport(testrep, py.code.ExceptionInfo()) - except (SystemExit, KeyboardInterrupt): + except sysex: raise except: excinfo = py.code.ExceptionInfo() @@ -51,7 +51,7 @@ excinfo = e.excinfo self.config.bus.notify(repevent.ItemFinish(self.item, excinfo)) self._fillreport(testrep, excinfo) - if self.config.option.usepdb: + if self.config.option.usepdb and not excinfo.errisinstance(Skipped): py.__.test2.custompdb.post_mortem(excinfo._excinfo[2]) else: testrep.passed = True Modified: py/branch/event/py/test2/session.py ============================================================================== --- py/branch/event/py/test2/session.py (original) +++ py/branch/event/py/test2/session.py Wed Feb 20 09:38:46 2008 @@ -82,10 +82,5 @@ return failures def runtest(self, item): - cls = RunExecutor - if self.config.option.boxed: - cls = BoxExecutor - executor = cls(item, self.config) - testrep = executor.execute() - self.config.bus.notify(testrep) + return item.runtest() From hpk at codespeak.net Wed Feb 20 09:52:32 2008 From: hpk at codespeak.net (hpk at codespeak.net) Date: Wed, 20 Feb 2008 09:52:32 +0100 (CET) Subject: [py-svn] r51669 - py/branch/event/py/test2 Message-ID: <20080220085232.45503168440@codespeak.net> Author: hpk Date: Wed Feb 20 09:52:30 2008 New Revision: 51669 Modified: py/branch/event/py/test2/item.py py/branch/event/py/test2/session.py Log: complete last checkin - gee! seems i am really in incremental commit mode :) Modified: py/branch/event/py/test2/item.py ============================================================================== --- py/branch/event/py/test2/item.py (original) +++ py/branch/event/py/test2/item.py Wed Feb 20 09:52:30 2008 @@ -1,5 +1,4 @@ import py - from py.__.test2.collect import FunctionMixin, Base from py.__.test2 import present @@ -31,6 +30,15 @@ self.stack.append(col) class Item(Base): + def runtest(self): + from py.__.test2.executor import RunExecutor, BoxExecutor + cls = RunExecutor + if self._config.option.boxed: + cls = BoxExecutor + executor = cls(self, self._config) + testrep = executor.execute() + self._config.bus.notify(testrep) + def startcapture(self): self._config._startcapture(self, path=self.fspath) Modified: py/branch/event/py/test2/session.py ============================================================================== --- py/branch/event/py/test2/session.py (original) +++ py/branch/event/py/test2/session.py Wed Feb 20 09:52:30 2008 @@ -8,7 +8,6 @@ import py from py.__.test2.genitem import genitems from py.__.test2 import repevent -from py.__.test2.executor import RunExecutor, BoxExecutor class Session(object): """ From hpk at codespeak.net Wed Feb 20 09:58:38 2008 From: hpk at codespeak.net (hpk at codespeak.net) Date: Wed, 20 Feb 2008 09:58:38 +0100 (CET) Subject: [py-svn] r51670 - py/branch/event/py/test2 Message-ID: <20080220085838.3947B168440@codespeak.net> Author: hpk Date: Wed Feb 20 09:58:37 2008 New Revision: 51670 Modified: py/branch/event/py/test2/collect.py py/branch/event/py/test2/item.py Log: generated Functions don't really need to care about sort order i think. the pseudo-support for ordering them was anyway broken and untested. Modified: py/branch/event/py/test2/collect.py ============================================================================== --- py/branch/event/py/test2/collect.py (original) +++ py/branch/event/py/test2/collect.py Wed Feb 20 09:58:37 2008 @@ -480,8 +480,8 @@ call, args = self.getcallargs(x) if not callable(call): raise TypeError("yielded test %r not callable" %(call,)) - name = "[%d]" % i - d[name] = self.Function(name, self, args, obj=call, sort_value = i) + name = "[%d]" % i + d[name] = self.Function(name, self, args, callobj=call) return d def getcallargs(self, obj): Modified: py/branch/event/py/test2/item.py ============================================================================== --- py/branch/event/py/test2/item.py (original) +++ py/branch/event/py/test2/item.py Wed Feb 20 09:58:37 2008 @@ -50,12 +50,11 @@ and executing a Python callable test object. """ _state = SetupState() - def __init__(self, name, parent, args=(), obj=_dummy, sort_value = None): + def __init__(self, name, parent, args=(), callobj=_dummy): super(Function, self).__init__(name, parent) self._args = args - if obj is not _dummy: - self._obj = obj - self._sort_value = sort_value + if callobj is not _dummy: + self._obj = callobj def run(self): """ setup and execute the underlying test function. """ From hpk at codespeak.net Wed Feb 20 10:15:38 2008 From: hpk at codespeak.net (hpk at codespeak.net) Date: Wed, 20 Feb 2008 10:15:38 +0100 (CET) Subject: [py-svn] r51671 - in py/branch/event/py/test2: . rsession Message-ID: <20080220091538.C6717168440@codespeak.net> Author: hpk Date: Wed Feb 20 10:15:37 2008 New Revision: 51671 Modified: py/branch/event/py/test2/executor.py py/branch/event/py/test2/item.py py/branch/event/py/test2/rsession/slave.py Log: kill now redundant code, have dist and non-dist testing share some methods Modified: py/branch/event/py/test2/executor.py ============================================================================== --- py/branch/event/py/test2/executor.py (original) +++ py/branch/event/py/test2/executor.py Wed Feb 20 10:15:37 2008 @@ -18,6 +18,11 @@ self.item = item self.config = config + def setup_and_run(self): + testrep = self.execute() + self.config.bus.notify(testrep) + return testrep + def run(self, capture=True): if capture: self.item.startcapture() @@ -119,3 +124,9 @@ finally: self.item.execute = orig_exec +def getexecutor(item, config): + cls = RunExecutor + if config.option.boxed: + cls = BoxExecutor + return cls(item, config) + Modified: py/branch/event/py/test2/item.py ============================================================================== --- py/branch/event/py/test2/item.py (original) +++ py/branch/event/py/test2/item.py Wed Feb 20 10:15:37 2008 @@ -31,14 +31,10 @@ class Item(Base): def runtest(self): - from py.__.test2.executor import RunExecutor, BoxExecutor - cls = RunExecutor - if self._config.option.boxed: - cls = BoxExecutor - executor = cls(self, self._config) - testrep = executor.execute() - self._config.bus.notify(testrep) - + from py.__.test2.executor import getexecutor + executor = getexecutor(self, self._config) + return executor.setup_and_run() + def startcapture(self): self._config._startcapture(self, path=self.fspath) Modified: py/branch/event/py/test2/rsession/slave.py ============================================================================== --- py/branch/event/py/test2/rsession/slave.py (original) +++ py/branch/event/py/test2/rsession/slave.py Wed Feb 20 10:15:37 2008 @@ -7,31 +7,15 @@ from py.__.test2 import repevent import os -def slave_main(receive, send, path, config): - import os - assert os.path.exists(path) - path = os.path.abspath(path) - if config.option.boxed: - Executor = BoxExecutor - else: - Executor = RunExecutor - +def slave_main(receive, send, config): while 1: itemspec = receive() if itemspec is None: send(None) break - try: - item = config._getcollector(itemspec) - ex = Executor(item, config) - res = ex.execute() - except: # XXX consider bare except here - excinfo = py.code.ExceptionInfo() - # XXX excinfo - res = repevent.ItemTestReport(itemspec) - res.failed = True - res.excinfo = str(excinfo) - send(res.dumps()) + item = config._getcollector(itemspec) + testrep = item.runtest() + send(testrep.dumps()) def setup(): # our current dir is the topdir @@ -59,7 +43,7 @@ msg = channel.receive() #print >>debug, "reveived", msg return msg - slave_main(receive, send, basedir, config) + slave_main(receive, send, config) if not config.option.nomagic: py.magic.revoke(assertion=1) channel.close() From hpk at codespeak.net Wed Feb 20 10:18:29 2008 From: hpk at codespeak.net (hpk at codespeak.net) Date: Wed, 20 Feb 2008 10:18:29 +0100 (CET) Subject: [py-svn] r51672 - py/branch/event/py/test2/rsession Message-ID: <20080220091829.73DE1168440@codespeak.net> Author: hpk Date: Wed Feb 20 10:18:28 2008 New Revision: 51672 Modified: py/branch/event/py/test2/rsession/slave.py Log: fix imports and docstrings as well. Modified: py/branch/event/py/test2/rsession/slave.py ============================================================================== --- py/branch/event/py/test2/rsession/slave.py (original) +++ py/branch/event/py/test2/rsession/slave.py Wed Feb 20 10:18:28 2008 @@ -1,11 +1,9 @@ """ -Node code for slaves. +Code that is running on the slave side for executing tests remotely. """ import py -from py.__.test2.executor import RunExecutor, BoxExecutor, AsyncExecutor from py.__.test2 import repevent -import os def slave_main(receive, send, config): while 1: From hpk at codespeak.net Wed Feb 20 10:31:22 2008 From: hpk at codespeak.net (hpk at codespeak.net) Date: Wed, 20 Feb 2008 10:31:22 +0100 (CET) Subject: [py-svn] r51674 - in py/branch/event/py/test2: . testing Message-ID: <20080220093122.E0E12168445@codespeak.net> Author: hpk Date: Wed Feb 20 10:31:22 2008 New Revision: 51674 Modified: py/branch/event/py/test2/collect.py py/branch/event/py/test2/config.py py/branch/event/py/test2/item.py py/branch/event/py/test2/session.py py/branch/event/py/test2/testing/test_collect.py Log: another global bites the dust - put function setupstate into config object now that the latter is uniformly available. Modified: py/branch/event/py/test2/collect.py ============================================================================== --- py/branch/event/py/test2/collect.py (original) +++ py/branch/event/py/test2/collect.py Wed Feb 20 10:31:22 2008 @@ -473,9 +473,9 @@ def _buildname2items(self): d = {} - # slightly hackish to invoke setup-states on - # collection ... - self.Function._state.prepare(self) + # test generators participate in + # the setup and teardown protocol + self._config._setupstate.prepare(self) for i, x in py.builtin.enumerate(self.obj()): call, args = self.getcallargs(x) if not callable(call): Modified: py/branch/event/py/test2/config.py ============================================================================== --- py/branch/event/py/test2/config.py (original) +++ py/branch/event/py/test2/config.py Wed Feb 20 10:31:22 2008 @@ -4,6 +4,7 @@ from conftesthandle import Conftest from py.__.test2.defaultconftest import adddefaultoptions from py.__.test2.eventbus import EventBus +from py.__.test2.item import SetupState optparse = py.compat.optparse @@ -36,6 +37,7 @@ self._conftest = Conftest() self._initialized = False self.bus = EventBus() + self._setupstate = SetupState() def parse(self, args): """ parse cmdline arguments into this config object. Modified: py/branch/event/py/test2/item.py ============================================================================== --- py/branch/event/py/test2/item.py (original) +++ py/branch/event/py/test2/item.py Wed Feb 20 10:31:22 2008 @@ -45,7 +45,6 @@ """ a Function Item is responsible for setting up and executing a Python callable test object. """ - _state = SetupState() def __init__(self, name, parent, args=(), callobj=_dummy): super(Function, self).__init__(name, parent) self._args = args @@ -54,7 +53,7 @@ def run(self): """ setup and execute the underlying test function. """ - self._state.prepare(self) + self._config._setupstate.prepare(self) self.execute(self.obj, *self._args) def execute(self, target, *args): Modified: py/branch/event/py/test2/session.py ============================================================================== --- py/branch/event/py/test2/session.py (original) +++ py/branch/event/py/test2/session.py Wed Feb 20 10:31:22 2008 @@ -49,7 +49,7 @@ def teardown(self): """ teardown any resources after a test run. """ - py.test2.collect.Function._state.teardown_all() + self.config._setupstate.teardown_all() if not self.config.option.nomagic: py.magic.revoke(assertion=1) return self._failurelist Modified: py/branch/event/py/test2/testing/test_collect.py ============================================================================== --- py/branch/event/py/test2/testing/test_collect.py (original) +++ py/branch/event/py/test2/testing/test_collect.py Wed Feb 20 10:31:22 2008 @@ -5,10 +5,12 @@ from py.__.test2.doctest import DoctestText import setupdata, suptest from py.__.test2.conftesthandle import Conftest +from py.__.test2.item import SetupState class DummyConfig: def __init__(self): self._conftest = Conftest() + self._setupstate = SetupState() def getvalue(self, name, fspath): return self._conftest.rget(name, fspath) From hpk at codespeak.net Wed Feb 20 11:51:10 2008 From: hpk at codespeak.net (hpk at codespeak.net) Date: Wed, 20 Feb 2008 11:51:10 +0100 (CET) Subject: [py-svn] r51679 - in py/branch/event/py/test2: . testing Message-ID: <20080220105110.202E5168459@codespeak.net> Author: hpk Date: Wed Feb 20 11:51:09 2008 New Revision: 51679 Modified: py/branch/event/py/test2/collect.py py/branch/event/py/test2/config.py py/branch/event/py/test2/executor.py py/branch/event/py/test2/item.py py/branch/event/py/test2/present.py py/branch/event/py/test2/testing/test_config.py py/branch/event/py/test2/testing/test_executor.py py/branch/event/py/test2/testing/test_session.py py/branch/event/py/test2/testing/test_setup_nested.py Log: refactoring: output capturing is now the responsibility of Executors. removed the hooks from the collection tree. output capturing modes can be set by conftests (maybe that should even take precendence before command line options?) Modified: py/branch/event/py/test2/collect.py ============================================================================== --- py/branch/event/py/test2/collect.py (original) +++ py/branch/event/py/test2/collect.py Wed Feb 20 11:51:09 2008 @@ -148,16 +148,6 @@ def _getsortvalue(self): return self.name - _captured_out = _captured_err = None - def startcapture(self): - return None # by default collectors don't capture output - - def finishcapture(self): - return None # by default collectors don't capture output - - def _getouterr(self): - return self._captured_out, self._captured_err - def _get_collector_trail(self): """ Shortcut """ @@ -348,12 +338,6 @@ res = self.makeitem(name, attr, usefilters=False) return res - def startcapture(self): - self._config._startcapture(self, path=self.fspath) - - def finishcapture(self): - self._config._finishcapture(self) - def _getobj(self): failure = self._stickyfailure if failure is not None: Modified: py/branch/event/py/test2/config.py ============================================================================== --- py/branch/event/py/test2/config.py (original) +++ py/branch/event/py/test2/config.py Wed Feb 20 11:51:09 2008 @@ -243,23 +243,19 @@ %(chain[0], self.topdir)) return relpath, tuple([x.name for x in chain[1:]]) - def _startcapture(self, colitem, path=None): - if not self.option.nocapture: - assert not hasattr(colitem, '_capture') + def _getcapture(self, path=None): + if self.option.nocapture: + iocapture = "no" + else: iocapture = self.getvalue("conf_iocapture", path=path) - if iocapture == "fd": - capture = py.io.StdCaptureFD() - elif iocapture == "sys": - capture = py.io.StdCapture() - else: - raise ValueError("unknown io capturing: " + iocapture) - colitem._capture = capture - - def _finishcapture(self, colitem): - if hasattr(colitem, '_capture'): - capture = colitem._capture - del colitem._capture - colitem._captured_out, colitem._captured_err = capture.reset() + if iocapture == "fd": + return py.io.StdCaptureFD() + elif iocapture == "sys": + return py.io.StdCapture() + elif iocapture == "no": + return py.io.StdCapture(out=False, err=False, in_=False) + else: + raise ValueError("unknown io capturing: " + iocapture) # this is the one per-process instance of py.test2 configuration config_per_process = Config() Modified: py/branch/event/py/test2/executor.py ============================================================================== --- py/branch/event/py/test2/executor.py (original) +++ py/branch/event/py/test2/executor.py Wed Feb 20 11:51:09 2008 @@ -17,23 +17,25 @@ def __init__(self, item, config): self.item = item self.config = config + self.testrep = repevent.ItemTestReport(item._get_collector_trail()) def setup_and_run(self): testrep = self.execute() self.config.bus.notify(testrep) return testrep - def run(self, capture=True): - if capture: - self.item.startcapture() - try: - self.item.run() - finally: - self.item.finishcapture() - else: + def run(self): + capture = self.config._getcapture(path=self.item.fspath) + try: self.item.run() + finally: + outerr = capture.reset() + self.testrep.iocapture_run = outerr + # XXX + self.item._run_capture = outerr - def _fillreport(self, testrep, excinfo): + def _fillreport(self, excinfo): + testrep = self.testrep if excinfo.errisinstance(Skipped): testrep.skipped = True else: @@ -41,13 +43,9 @@ testrep.exconly = excinfo.exconly() testrep.repr_failure = self.item.repr_failure(excinfo) - def execute(self, capture=True): - testrep = repevent.ItemTestReport(self.item._get_collector_trail()) + def execute(self): try: - try: - self.run(capture) - finally: - testrep.stdout, testrep.stderr = self.item._getouterr() + self.run() except sysex: raise except: @@ -55,19 +53,19 @@ if excinfo.errisinstance(Failed) and excinfo.value.excinfo: excinfo = e.excinfo self.config.bus.notify(repevent.ItemFinish(self.item, excinfo)) - self._fillreport(testrep, excinfo) + self._fillreport(excinfo) if self.config.option.usepdb and not excinfo.errisinstance(Skipped): py.__.test2.custompdb.post_mortem(excinfo._excinfo[2]) else: - testrep.passed = True - return testrep + self.testrep.passed = True + return self.testrep class BoxExecutor(RunExecutor): """ Same as RunExecutor, but boxes test instead """ def fun(self): - testrep = RunExecutor.execute(self, capture=False) - return testrep.dumps() # XXX self.config.option.tbstyle + testrep = RunExecutor.execute(self) + return testrep.dumps() def execute(self): b = Box(self.fun, config=self.config) @@ -108,7 +106,7 @@ super(ApigenExecutor, self).__init__(item, config) self.tracer = tracer - def run(self, capture): + def run(self): # only trace Python Function items if hasattr(self.item, 'obj') and isinstance(self.item, py.test2.collect.Function): orig_exec = self.item.execute @@ -120,7 +118,7 @@ self.tracer.end_tracing() self.item.execute = traced_exec try: - super(ApigenExecutor, self).run(capture) + super(ApigenExecutor, self).run() finally: self.item.execute = orig_exec Modified: py/branch/event/py/test2/item.py ============================================================================== --- py/branch/event/py/test2/item.py (original) +++ py/branch/event/py/test2/item.py Wed Feb 20 11:51:09 2008 @@ -35,12 +35,6 @@ executor = getexecutor(self, self._config) return executor.setup_and_run() - def startcapture(self): - self._config._startcapture(self, path=self.fspath) - - def finishcapture(self): - self._config._finishcapture(self) - class Function(FunctionMixin, Item): """ a Function Item is responsible for setting up and executing a Python callable test object. @@ -73,5 +67,3 @@ p.out.line(line) p.repr_tb(self, excinfo) return p.stringio.getvalue() - - Modified: py/branch/event/py/test2/present.py ============================================================================== --- py/branch/event/py/test2/present.py (original) +++ py/branch/event/py/test2/present.py Wed Feb 20 11:51:09 2008 @@ -130,7 +130,8 @@ def repr_out_err(self, colitem): for parent in colitem.listchain(): - for name, obj in zip(['out', 'err'], parent._getouterr()): + if hasattr(parent, '_run_capture'): + name, obj = parent._run_capture if obj: self.out.sep("- ", "%s: recorded std%s" % (parent.name, name)) self.out.line(obj) Modified: py/branch/event/py/test2/testing/test_config.py ============================================================================== --- py/branch/event/py/test2/testing/test_config.py (original) +++ py/branch/event/py/test2/testing/test_config.py Wed Feb 20 11:51:09 2008 @@ -294,28 +294,26 @@ assert pl == [py.path.local()] def test_config_iocapturing(self): - self.tmpdir config = py.test2.config._reparse([self.tmpdir]) assert config.getvalue("conf_iocapture") tmpdir = self.tmpdir.ensure("sub-with-conftest", dir=1) tmpdir.join("conftest.py").write(py.code.Source(""" - conf_iocapture = "sys" + conf_iocapture = "no" """)) config = py.test2.config._reparse([tmpdir]) - assert config.getvalue("conf_iocapture") == "sys" - class dummy: pass - config._startcapture(dummy) - print 42 - py.std.os.write(1, "23") - config._finishcapture(dummy) - assert dummy._captured_out.strip() == "42" - - config = py.test2.config._reparse([tmpdir.dirpath()]) - config._startcapture(dummy, path=tmpdir) - print 42 - py.std.os.write(1, "23") - config._finishcapture(dummy) - assert dummy._captured_out.strip() == "42" + assert config.getvalue("conf_iocapture") == "no" + capture = config._getcapture() + assert isinstance(capture, py.io.StdCapture) + assert not capture._out + assert not capture._err + assert not capture._in + assert isinstance(capture, py.io.StdCapture) + for opt, cls in (("sys", py.io.StdCapture), + ("fd", py.io.StdCaptureFD), + ): + config.option.conf_iocapture = opt + capture = config._getcapture() + assert isinstance(capture, cls) def test_conflict_options(self): def check_conflict_option(opts): Modified: py/branch/event/py/test2/testing/test_executor.py ============================================================================== --- py/branch/event/py/test2/testing/test_executor.py (original) +++ py/branch/event/py/test2/testing/test_executor.py Wed Feb 20 11:51:09 2008 @@ -32,20 +32,20 @@ def test_run_executor_capture_stdout(self): testrep = self.exrun("print") - assert testrep.stdout == "samfing\n" - assert not testrep.stderr + assert testrep.iocapture_run[0] == "samfing\n" + assert not testrep.iocapture_run[1] def test_run_executor_capture_stderr(self): testrep = self.exrun("printerr") - assert testrep.stderr == "samfing\n" - assert not testrep.stdout + assert testrep.iocapture_run[1] == "samfing\n" + assert not testrep.iocapture_run[0] def test_box_executor_printfailing(self): testrep = self.exrun("printfail") assert not testrep.passed assert testrep.failed - assert testrep.stdout.find("samfing elz") != -1 - assert not testrep.stderr + assert testrep.iocapture_run[0].find("samfing elz") != -1 + assert not testrep.iocapture_run[1] def test_executor_explicit_Failed(self): testrep = self.exrun("explicitfail") Modified: py/branch/event/py/test2/testing/test_session.py ============================================================================== --- py/branch/event/py/test2/testing/test_session.py (original) +++ py/branch/event/py/test2/testing/test_session.py Wed Feb 20 11:51:09 2008 @@ -88,7 +88,7 @@ i = out.find('TypeError') assert i != -1 - def test_conftest_Function_capturing_hooks(self): + def test_Function_capturing(self): tfile = suptest.makeuniquepyfile(""" import py print "module level output" @@ -100,23 +100,15 @@ print >>py.std.sys.stderr, 2 raise ValueError """) - conftest = tfile.dirpath('conftest.py').write(py.code.Source(""" - import py - class Function(py.test2.collect.Function): - def startcapture(self): - self._mycapture = True - - def finishcapture(self): - self._testmycapture = True - """)) sorter = suptest.events_from_cmdline([tfile.dirpath()]) passed, skipped, failed = sorter.listoutcomes() assert len(passed) == 1 assert len(failed) == 1 - for ev in sorter.get(repevent.ItemFinish): - assert ev.item._mycapture - assert ev.item._testmycapture + ev_list = sorter.get(repevent.ItemTestReport) + ev1, ev2 = ev_list + assert ev1.iocapture_run == ("42\n", "23\n") + assert ev2.iocapture_run == ("1\n", "2\n") def test_raises_output(self): sorter = suptest.events_from_runsource(''' @@ -260,12 +252,12 @@ assert 0 """) testrep = sorter.getreport("test_one") - assert testrep.stdout.startswith("passed") - assert not testrep.stderr + assert testrep.iocapture_run[0].startswith("passed") + assert not testrep.iocapture_run[1] testrep = sorter.getreport("test_two") - assert testrep.stdout.startswith("failed") - assert not testrep.stderr + assert testrep.iocapture_run[0].startswith("failed") + assert not testrep.iocapture_run[1] def test_function_repr_failure(self): o = setupdata.getexamplefile("filetest.py") Modified: py/branch/event/py/test2/testing/test_setup_nested.py ============================================================================== --- py/branch/event/py/test2/testing/test_setup_nested.py (original) +++ py/branch/event/py/test2/testing/test_setup_nested.py Wed Feb 20 11:51:09 2008 @@ -123,6 +123,6 @@ """) rep = sorter.getreport("test_one") assert rep.passed - assert rep.stdout == "check\n" - assert rep.stderr == "e\n" + assert rep.iocapture_run[0] == "check\n" + assert rep.iocapture_run[1] == "e\n" From hpk at codespeak.net Wed Feb 20 11:59:14 2008 From: hpk at codespeak.net (hpk at codespeak.net) Date: Wed, 20 Feb 2008 11:59:14 +0100 (CET) Subject: [py-svn] r51680 - py/branch/event/py/test2 Message-ID: <20080220105914.1D6B2168457@codespeak.net> Author: hpk Date: Wed Feb 20 11:59:14 2008 New Revision: 51680 Modified: py/branch/event/py/test2/executor.py Log: one less method named "run". Modified: py/branch/event/py/test2/executor.py ============================================================================== --- py/branch/event/py/test2/executor.py (original) +++ py/branch/event/py/test2/executor.py Wed Feb 20 11:59:14 2008 @@ -24,7 +24,7 @@ self.config.bus.notify(testrep) return testrep - def run(self): + def runitem(self): capture = self.config._getcapture(path=self.item.fspath) try: self.item.run() @@ -45,7 +45,7 @@ def execute(self): try: - self.run() + self.runitem() except sysex: raise except: @@ -106,7 +106,7 @@ super(ApigenExecutor, self).__init__(item, config) self.tracer = tracer - def run(self): + def runitem(self): # only trace Python Function items if hasattr(self.item, 'obj') and isinstance(self.item, py.test2.collect.Function): orig_exec = self.item.execute @@ -118,7 +118,7 @@ self.tracer.end_tracing() self.item.execute = traced_exec try: - super(ApigenExecutor, self).run() + super(ApigenExecutor, self).runitem() finally: self.item.execute = orig_exec From hpk at codespeak.net Wed Feb 20 17:44:59 2008 From: hpk at codespeak.net (hpk at codespeak.net) Date: Wed, 20 Feb 2008 17:44:59 +0100 (CET) Subject: [py-svn] r51697 - in py/branch/event/py/test2: . testing Message-ID: <20080220164459.900BA1684DF@codespeak.net> Author: hpk Date: Wed Feb 20 17:44:56 2008 New Revision: 51697 Modified: py/branch/event/py/test2/collect.py py/branch/event/py/test2/executor.py py/branch/event/py/test2/testing/test_present.py Log: fix for windows and python 2.4 Modified: py/branch/event/py/test2/collect.py ============================================================================== --- py/branch/event/py/test2/collect.py (original) +++ py/branch/event/py/test2/collect.py Wed Feb 20 17:44:56 2008 @@ -27,7 +27,7 @@ import py from py.__.test2 import present -sysex = (KeyboardInterrupt, SystemExit, GeneratorExit) +sysex = (KeyboardInterrupt, SystemExit) def configproperty(name): def fget(self): Modified: py/branch/event/py/test2/executor.py ============================================================================== --- py/branch/event/py/test2/executor.py (original) +++ py/branch/event/py/test2/executor.py Wed Feb 20 17:44:56 2008 @@ -9,7 +9,7 @@ from py.__.test2 import repevent, present import py.__.test2.custompdb -sysex = (KeyboardInterrupt, SystemExit, GeneratorExit) +sysex = (KeyboardInterrupt, SystemExit) class RunExecutor(object): """ Same as in executor, but just running run Modified: py/branch/event/py/test2/testing/test_present.py ============================================================================== --- py/branch/event/py/test2/testing/test_present.py (original) +++ py/branch/event/py/test2/testing/test_present.py Wed Feb 20 17:44:56 2008 @@ -40,8 +40,11 @@ def setup_class(cls): cls.tmpdir = py.test2.ensuretemp(cls.__name__) - def getpresenter(self, cmdlinearg=""): - config = py.test2.config._reparse([self.tmpdir, cmdlinearg]) + def getpresenter(self, cmdlinearg=None): + args = [self.tmpdir] + if cmdlinearg: + args.append(cmdlinearg) + config = py.test2.config._reparse(args) return present.FuncPresenter(config) def gentest(self, check, **options): From hpk at codespeak.net Wed Feb 20 17:48:41 2008 From: hpk at codespeak.net (hpk at codespeak.net) Date: Wed, 20 Feb 2008 17:48:41 +0100 (CET) Subject: [py-svn] r51698 - in py/branch/event/py/test2: rep rsession Message-ID: <20080220164841.94D3F1684DF@codespeak.net> Author: hpk Date: Wed Feb 20 17:48:39 2008 New Revision: 51698 Added: py/branch/event/py/test2/rep/rest.py - copied unchanged from r51697, py/branch/event/py/test2/rsession/rest.py Removed: py/branch/event/py/test2/rsession/rest.py Log: forgot to move the disabled ReST reporter Deleted: /py/branch/event/py/test2/rsession/rest.py ============================================================================== --- /py/branch/event/py/test2/rsession/rest.py Wed Feb 20 17:48:39 2008 +++ (empty file) @@ -1,287 +0,0 @@ - -""" Rest reporting stuff -""" - -import py -import sys -from StringIO import StringIO -from py.__.test2.reporter import AbstractReporter -from py.__.test2 import repevent -from py.__.rest.rst import * - -class RestReporter(AbstractReporter): - linkwriter = None - - def __init__(self, config, hosts): - super(RestReporter, self).__init__(config, hosts) - self.rest = Rest() - self.traceback_num = 0 - 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]) - - def get_linkwriter(self): - if self.linkwriter is None: - try: - self.linkwriter = self.config.getvalue('linkwriter') - except KeyError: - print >>sys.stderr, ('no linkwriter configured, using default ' - 'one') - self.linkwriter = RelLinkWriter() - return self.linkwriter - - def report_unknown(self, what): - if self.config.option.verbose: - self.add_rest(Paragraph("Unknown report: %s" % what)) - - def gethost(self, item): - if item.channel: - return item.channel.gateway.host - return self.hosts[0] - - def report_SendItem(self, item): - address = self.gethost(item).hostname - if self.config.option.verbose: - self.add_rest(Paragraph('sending item %s to %s' % (item.item, - address))) - - def report_HostRSyncing(self, item): - self.add_rest(LiteralBlock('%10s: RSYNC ==> %s' % (item.host.hostname[:10], - item.host.relpath))) - - def _host_ready(self, item): - self.add_rest(LiteralBlock('%10s: READY' % (item.host.hostname[:10],))) - - def report_TestStarted(self, event): - txt = "Running tests on hosts: %s" % ", ".join([i.hostname for i in - event.hosts]) - self.add_rest(Title(txt, abovechar='=', belowchar='=')) - self.timestart = event.timestart - - def report_TestSessionFinish(self, item): - self.timeend = item.timeend - self.summary() - return len(self.failed_tests_outcome) > 0 - - def report_ImmediateFailure(self, item): - pass - - def report_HostGatewayReady(self, item): - self.to_rsync[item.host] = len(item.roots) - - def report_ItemStart(self, event): - item = event.item - if isinstance(item, py.test2.collect.Module): - lgt = len(list(item._tryiter())) - lns = item.listnames()[1:] - name = "/".join(lns) - link = self.get_linkwriter().get_link(self.get_rootpath(item), - item.fspath) - if link: - name = Link(name, link) - txt = 'Testing module %s (%d items)' % (name, lgt) - self.add_rest(Title('Testing module', name, '(%d items)' % (lgt,), - belowchar='-')) - - def get_rootpath(self, item): - root = item.parent - while root.parent is not None: - root = root.parent - return root.fspath - - def print_summary(self, total, skipped_str, failed_str): - self.skips() - self.failures() - - txt = "%d tests run%s%s in %.2fs (rsync: %.2f)" % \ - (total, skipped_str, failed_str, self.timeend - self.timestart, - self.timersync - self.timestart) - self.add_rest(Title(txt, belowchar='-')) - - # since we're rendering each item, the links haven't been rendered - # yet - self.out.write(self.rest.render_links()) - - def report_ItemFinish(self, event): - host = self.gethost(event) - if event.outcome.passed: - status = [Strong("PASSED")] - self.passed[host] += 1 - elif event.outcome.skipped: - status = [Strong("SKIPPED")] - self.skipped_tests_outcome.append(event) - self.skipped[host] += 1 - else: - status = [Strong("FAILED"), - InternalLink("traceback%d" % self.traceback_num)] - self.traceback_num += 1 - self.failed[host] += 1 - self.failed_tests_outcome.append(event) - # we'll take care of them later - itempath = self.get_path_from_item(event.item) - status.append(Text(itempath)) - hostname = host.hostname - self.add_rest(ListItem(Text("%10s:" % (hostname[:10],)), *status)) - - def skips(self): - # XXX hrmph, copied code - texts = {} - for event in self.skipped_tests_outcome: - colitem = event.item - if isinstance(event, repevent.ItemFinish): - outcome = event.outcome - text = outcome.skipped - itemname = self.get_item_name(event, colitem) - elif isinstance(event, repevent.DeselectedTest): - 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.add_rest(Title('Reasons for skipped tests:', belowchar='+')) - for text, items in texts.items(): - for item in items: - self.add_rest(ListItem('%s: %s' % (item, text))) - - def get_host(self, event): - try: - return event.channel.gateway.host - except AttributeError: - return None - - def failures(self): - self.traceback_num = 0 - tbstyle = self.config.option.tbstyle - if self.failed_tests_outcome: - self.add_rest(Title('Exceptions:', belowchar='+')) - for i, event in enumerate(self.failed_tests_outcome): - if i > 0: - self.add_rest(Transition()) - if isinstance(event, repevent.ItemFinish): - host = self.get_host(event) - itempath = self.get_path_from_item(event.item) - root = self.get_rootpath(event.item) - link = self.get_linkwriter().get_link(root, event.item.fspath) - t = Title(belowchar='+') - if link: - t.add(Link(itempath, link)) - else: - t.add(Text(itempath)) - if host: - t.add(Text('on %s' % (host.hostname,))) - self.add_rest(t) - if event.outcome.signal: - self.repr_signal(event.item, event.outcome) - else: - self.repr_failure(event.item, event.outcome, tbstyle) - else: - itempath = self.get_path_from_item(event.item) - root = self.get_rootpath(event.item) - link = self.get_linkwriter().get_link(root, event.item.fspath) - t = Title(abovechar='+', belowchar='+') - if link: - t.add(Link(itempath, link)) - else: - t.add(Text(itempath)) - out = outcome.Outcome(excinfo=event.excinfo) - self.repr_failure(event.item, - outcome.ReprOutcome(out.make_repr()), - tbstyle) - - def repr_signal(self, item, outcome): - signal = outcome.signal - self.add_rest(Title('Received signal: %d' % (outcome.signal,), - abovechar='+', belowchar='+')) - if outcome.stdout.strip(): - self.add_rest(Paragraph('Captured process stdout:')) - self.add_rest(LiteralBlock(outcome.stdout)) - if outcome.stderr.strip(): - self.add_rest(Paragraph('Captured process stderr:')) - self.add_rest(LiteralBlock(outcome.stderr)) - - def repr_failure(self, item, outcome, style): - excinfo = outcome.excinfo - traceback = excinfo.traceback - if not traceback: - self.add_rest(Paragraph('empty traceback from item %r' % (item,))) - return - self.repr_traceback(item, excinfo, traceback, style) - if outcome.stdout: - self.add_rest(Title('Captured process stdout:', abovechar='+', - belowchar='+')) - self.add_rest(LiteralBlock(outcome.stdout)) - if outcome.stderr: - self.add_rest(Title('Captured process stderr:', abovechar='+', - belowchar='+')) - self.add_rest(LiteralBlock(outcome.stderr)) - - def repr_traceback(self, item, excinfo, traceback, style): - root = self.get_rootpath(item) - self.add_rest(LinkTarget('traceback%d' % self.traceback_num, "")) - self.traceback_num += 1 - if style == 'long': - for entry in traceback: - link = self.get_linkwriter().get_link(root, - py.path.local(entry.path)) - if link: - self.add_rest(Title(Link(entry.path, link), - 'line %d' % (entry.lineno,), - belowchar='+', abovechar='+')) - else: - self.add_rest(Title('%s line %d' % (entry.path, - entry.lineno,), - belowchar='+', abovechar='+')) - self.add_rest(LiteralBlock(self.prepare_source(entry.relline, - entry.source))) - elif style == 'short': - text = [] - for entry in traceback: - text.append('%s line %d' % (entry.path, entry.lineno)) - text.append(' %s' % (entry.source.strip(),)) - self.add_rest(LiteralBlock('\n'.join(text))) - self.add_rest(Title(excinfo.typename, belowchar='+')) - self.add_rest(LiteralBlock(excinfo.value)) - - def prepare_source(self, relline, source): - text = [] - for num, line in enumerate(source.split('\n')): - if num == relline: - text.append('>>> %s' % (line,)) - else: - text.append(' %s' % (line,)) - return '\n'.join(text) - - def add_rest(self, item): - self.rest.add(item) - self.out.write('%s\n\n' % (item.text(),)) - - def get_path_from_item(self, item): - lns = item.listnames()[1:] - for i, ln in enumerate(lns): - if i > 0 and ln != '()': - lns[i] = '/%s' % (ln,) - itempath = ''.join(lns) - return itempath - -class AbstractLinkWriter(object): - def get_link(self, base, path): - pass - -class NoLinkWriter(AbstractLinkWriter): - def get_link(self, base, path): - return '' - -class LinkWriter(AbstractLinkWriter): - def __init__(self, baseurl): - self.baseurl = baseurl - - def get_link(self, base, path): - relpath = path.relto(base) - return self.baseurl + relpath - -class RelLinkWriter(AbstractLinkWriter): - def get_link(self, base, path): - return path.relto(base) - From hpk at codespeak.net Wed Feb 20 17:52:20 2008 From: hpk at codespeak.net (hpk at codespeak.net) Date: Wed, 20 Feb 2008 17:52:20 +0100 (CET) Subject: [py-svn] r51699 - py/branch/event/py/test2 Message-ID: <20080220165220.03248168044@codespeak.net> Author: hpk Date: Wed Feb 20 17:52:20 2008 New Revision: 51699 Modified: py/branch/event/py/test2/collect.py py/branch/event/py/test2/item.py Log: rename collection tree base class to "Node". Modified: py/branch/event/py/test2/collect.py ============================================================================== --- py/branch/event/py/test2/collect.py (original) +++ py/branch/event/py/test2/collect.py Wed Feb 20 17:52:20 2008 @@ -35,10 +35,11 @@ return self._config.getvalue(name, self.fspath) return property(fget) -class Base(object): - """ base class for the nodes in the collection tree. - Nodes with Children are "Collectors" and leaves - are the actual Test Items. +class Node(object): + """ base class for Nodes in the collection tree. + Nodes with Children are "Collectors" and + leaves (without children) are runnable + Test Items. """ def __init__(self, name, parent=None, config=None): self.name = name @@ -52,7 +53,7 @@ return "<%s %r>" %(self.__class__.__name__, self.name) def __eq__(self, other): - if not isinstance(other, Base): + if not isinstance(other, Node): return False return self.name == other.name and self.parent == other.parent @@ -63,7 +64,7 @@ return not self == other def __cmp__(self, other): - if not isinstance(other, Base): + if not isinstance(other, Node): return -1 s1 = self._getsortvalue() s2 = other._getsortvalue() @@ -164,7 +165,7 @@ return traceback -class Collector(Base): +class Collector(Node): """ Collector instances generate children through their listdir() and join() methods and thus Modified: py/branch/event/py/test2/item.py ============================================================================== --- py/branch/event/py/test2/item.py (original) +++ py/branch/event/py/test2/item.py Wed Feb 20 17:52:20 2008 @@ -1,5 +1,5 @@ import py -from py.__.test2.collect import FunctionMixin, Base +from py.__.test2.collect import FunctionMixin, Node from py.__.test2 import present _dummy = object() @@ -29,7 +29,7 @@ col.setup() self.stack.append(col) -class Item(Base): +class Item(Node): def runtest(self): from py.__.test2.executor import getexecutor executor = getexecutor(self, self._config) From guido at codespeak.net Wed Feb 20 22:28:59 2008 From: guido at codespeak.net (guido at codespeak.net) Date: Wed, 20 Feb 2008 22:28:59 +0100 (CET) Subject: [py-svn] r51708 - in py/branch/guido-svn-auth/py/path/svn: . testing Message-ID: <20080220212859.8C55D168510@codespeak.net> Author: guido Date: Wed Feb 20 22:28:58 2008 New Revision: 51708 Modified: py/branch/guido-svn-auth/py/path/svn/auth.txt py/branch/guido-svn-auth/py/path/svn/svncommon.py py/branch/guido-svn-auth/py/path/svn/testing/test_auth.py py/branch/guido-svn-auth/py/path/svn/urlcommand.py Log: Added support for SvnAuth to urlcommand - one can either pass the object to the constructor, or set the .auth property on py.path.svnurl objects. Made some relatively small refactorings to SvnCommandPath - it's still a bit messy, but the popen and cmdexec calls are factored out now to make testing easier. Modified: py/branch/guido-svn-auth/py/path/svn/auth.txt ============================================================================== --- py/branch/guido-svn-auth/py/path/svn/auth.txt (original) +++ py/branch/guido-svn-auth/py/path/svn/auth.txt Wed Feb 20 22:28:58 2008 @@ -2,9 +2,9 @@ ========================== This document describes authentication support for both py.path.svnwc and -py.path.svnurl (yet in its implemention phase). This allows using the library -in a completely automated fashion, without having to provide svn credentials -interactively. +py.path.svnurl (yet in its implemention phase). This feature allows using the +library in a completely automated fashion, without having to provide svn +credentials interactively. Current implementation ---------------------- @@ -12,16 +12,17 @@ The credentials are passed to the constructor of the path objects, and are used (transparently) for every action that accesses the server. Also, when provided, they are passed recursively to all child objects created by methods such as -join(), ensure(), etc. +join(), ensure(), etc. (XXX currently only true for svnurl, not for svnwc) To pass credentials to path objects, an SvnAuth class needs to be created to hold them. This is then passed to the constructor or methods as the 'auth' -keyword argument. +keyword argument. (XXX the latter currently only for svnwc, and preferrably +that needs to be removed in favour of an .auth attribute like in svnurl) It is configurable whether the credentials are stored on disk. Storing them is useful in certain situations (executive access to the repository will not require the credentials to be passed) but might not be desired in others - for -instance if a webserver runs more than one application, you do not want to +instance if a webserver runs more than one application, one does not want to pollute the webserver's home directory (if it even has one). This behaviour can be controlled by passing a False value for the 'cache_auth' argument to SvnAuth. @@ -40,7 +41,8 @@ >>> auth = py.path.SvnAuth('user', 'pass', cache_auth=False, ... interactive=False) - >>> wc = py.path.svnwc(url, auth=auth) + >>> wcpath = py.path.svnwc(path, auth=auth) + >>> urlpath = py.path.svnurl(url, auth=auth) Open issues ----------- @@ -57,7 +59,7 @@ Current idea: ignore this and let the client handle (so no passing auth around to the children). -* Affected methods +* Affected methods for svnwc: - switch - checkout @@ -68,3 +70,8 @@ - commit - log - status (for locking, etc.?) + +* Affected methods for svnurl: + + not appropriate - the auth is passed to the constructor rather or set to + path.auth rather than passed to all methods Modified: py/branch/guido-svn-auth/py/path/svn/svncommon.py ============================================================================== --- py/branch/guido-svn-auth/py/path/svn/svncommon.py (original) +++ py/branch/guido-svn-auth/py/path/svn/svncommon.py Wed Feb 20 22:28:58 2008 @@ -65,6 +65,7 @@ """ obj = object.__new__(self.__class__) obj.rev = kw.get('rev', self.rev) + obj.auth = kw.get('auth', self.auth) dirname, basename, purebasename, ext = self._getbyspec( "dirname,basename,purebasename,ext") if 'basename' in kw: @@ -138,7 +139,7 @@ args = tuple([arg.strip(self.sep) for arg in args]) parts = (self.strpath, ) + args - newpath = self.__class__(self.sep.join(parts), self.rev) + newpath = self.__class__(self.sep.join(parts), self.rev, self.auth) return newpath def propget(self, name): Modified: py/branch/guido-svn-auth/py/path/svn/testing/test_auth.py ============================================================================== --- py/branch/guido-svn-auth/py/path/svn/testing/test_auth.py (original) +++ py/branch/guido-svn-auth/py/path/svn/testing/test_auth.py Wed Feb 20 22:28:58 2008 @@ -30,7 +30,7 @@ confdir.join('passwd').write(passwddata) def serve_bg(repopath): - pidfile = repopath.join('pid') + pidfile = py.path.local(repopath).join('pid') port = 10000 e = None while port < 10010: @@ -122,7 +122,164 @@ assert wc.commands == [('co', 'url', '--username="user" --password="pass"')] -class TestSvnAuthFunctional(object): +class svnurl_no_svn(py.path.svnurl): + cmdexec_output = 'test' + popen_output = 'test' + + def _cmdexec(self, cmd): + self.commands.append(cmd) + return self.cmdexec_output + + def _popen(self, cmd): + self.commands.append(cmd) + return self.popen_output + +class TestSvnURLAuth(object): + def setup_method(self, meth): + svnurl_no_svn.commands = [] + + def test_init(self): + u = svnurl_no_svn('http://foo.bar/svn') + assert u.auth is None + + auth = SvnAuth('foo', 'bar') + u = svnurl_no_svn('http://foo.bar/svn', auth=auth) + assert u.auth is auth + + def test_new(self): + auth = SvnAuth('foo', 'bar') + u = svnurl_no_svn('http://foo.bar/svn/foo', auth=auth) + new = u.new(basename='bar') + assert new.auth is auth + assert new.url == 'http://foo.bar/svn/bar' + + def test_join(self): + auth = SvnAuth('foo', 'bar') + u = svnurl_no_svn('http://foo.bar/svn', auth=auth) + new = u.join('foo') + assert new.auth is auth + assert new.url == 'http://foo.bar/svn/foo' + + def test_listdir(self): + auth = SvnAuth('foo', 'bar') + u = svnurl_no_svn('http://foo.bar/svn', auth=auth) + u.cmdexec_output = '''\ + 1717 johnny 1529 Nov 04 14:32 LICENSE.txt + 1716 johnny 5352 Nov 04 14:28 README.txt +''' + paths = u.listdir() + assert paths[0].auth is auth + assert paths[1].auth is auth + assert paths[0].basename == 'LICENSE.txt' + + def test_info(self): + auth = SvnAuth('foo', 'bar') + u = svnurl_no_svn('http://foo.bar/svn/LICENSE.txt', auth=auth) + def dirpath(self): + return self + u.cmdexec_output = '''\ + 1717 johnny 1529 Nov 04 14:32 LICENSE.txt + 1716 johnny 5352 Nov 04 14:28 README.txt +''' + org_dp = u.__class__.dirpath + u.__class__.dirpath = dirpath + try: + info = u.info() + finally: + u.dirpath = org_dp + assert info.size == 1529 + + def test_open(self): + auth = SvnAuth('foo', 'bar') + u = svnurl_no_svn('http://foo.bar/svn', auth=auth) + foo = u.join('foo') + foo.check = lambda *args, **kwargs: True + ret = foo.open() + assert ret == 'test' + assert foo.commands[0].endswith('svn cat "http://foo.bar/svn/foo" ' + '--username="foo" --password="bar"') + + def test_dirpath(self): + auth = SvnAuth('foo', 'bar') + u = svnurl_no_svn('http://foo.bar/svn/foo', auth=auth) + parent = u.dirpath() + assert parent.auth is auth + + def test_mkdir(self): + auth = SvnAuth('foo', 'bar') + u = svnurl_no_svn('http://foo.bar/svn', auth=auth) + u.mkdir('foo', msg='created dir foo') + assert u.commands[0].endswith('svn mkdir "-m" "created dir foo" ' + '"http://foo.bar/svn/foo" ' + '--username="foo" --password="bar"') + + def test_copy(self): + auth = SvnAuth('foo', 'bar') + u = svnurl_no_svn('http://foo.bar/svn', auth=auth) + u2 = svnurl_no_svn('http://foo.bar/svn2') + u.copy(u2, 'copied dir') + assert u.commands[0].endswith('svn copy -m "copied dir" ' + '"http://foo.bar/svn" ' + '"http://foo.bar/svn2" ' + '--username="foo" --password="bar"') + + def test_rename(self): + auth = SvnAuth('foo', 'bar') + u = svnurl_no_svn('http://foo.bar/svn/foo', auth=auth) + u.rename('http://foo.bar/svn/bar', 'moved foo to bar') + assert u.commands[0].endswith('svn move -m "moved foo to bar" --force ' + '"http://foo.bar/svn/foo" ' + '"http://foo.bar/svn/bar" ' + '--username="foo" --password="bar"') + + def test_remove(self): + auth = SvnAuth('foo', 'bar') + u = svnurl_no_svn('http://foo.bar/svn/foo', auth=auth) + u.remove(msg='removing foo') + assert u.commands[0].endswith('svn rm -m "removing foo" ' + '"http://foo.bar/svn/foo" ' + '--username="foo" --password="bar"') + + def test_export(self): + auth = SvnAuth('foo', 'bar') + u = svnurl_no_svn('http://foo.bar/svn', auth=auth) + target = py.path.local('/foo') + u.export(target) + assert u.commands[0].endswith('svn export "http://foo.bar/svn" "/foo" ' + '--username="foo" --password="bar"') + + def test_log(self): + auth = SvnAuth('foo', 'bar') + u = svnurl_no_svn('http://foo.bar/svn/foo', auth=auth) + u.popen_output = py.std.StringIO.StringIO('''\ + + + +guido +2008-02-11T12:12:18.476481Z +Creating branch to work on auth support for py.path.svn*. + + + +''') + u.check = lambda *args, **kwargs: True + ret = u.log(10, 20, verbose=True) + assert u.commands[0].endswith('svn log --xml -r 10:20 -v ' + '"http://foo.bar/svn/foo" ' + '--username="foo" --password="bar"') + assert len(ret) == 1 + assert int(ret[0].rev) == 51381 + assert ret[0].author == 'guido' + + def test_propget(self): + auth = SvnAuth('foo', 'bar') + u = svnurl_no_svn('http://foo.bar/svn', auth=auth) + u.propget('foo') + assert u.commands[0].endswith('svn propget "foo" ' + '"http://foo.bar/svn" ' + '--username="foo" --password="bar"') + +class SvnAuthFunctionalTestBase(object): def setup_class(cls): if not option.runslowtests: py.test.skip('skipping slow functional tests - use --runslowtests ' @@ -136,6 +293,14 @@ self.temppath = py.test.ensuretemp('TestSvnAuthFunctional.%s' % ( func_name)) + def _start_svnserve(self): + make_repo_auth(self.repopath, {'johnny': ('foo', 'rw')}) + try: + return serve_bg(self.repopath.dirpath()) + except IOError, e: + py.test.skip(str(e)) + +class TestSvnWCAuthFunctional(SvnAuthFunctionalTestBase): def test_checkout_constructor_arg(self): port, pid = self._start_svnserve() try: @@ -281,9 +446,75 @@ finally: killproc(pid) - def _start_svnserve(self): - make_repo_auth(self.repopath, {'johnny': ('foo', 'rw')}) +class TestSvnURLAuthFunctional(SvnAuthFunctionalTestBase): + def test_listdir(self): + port, pid = self._start_svnserve() try: - return serve_bg(self.repopath.dirpath()) - except IOError, e: - py.test.skip(str(e)) + auth = SvnAuth('johnny', 'foo', cache_auth=False, + interactive=False) + u = py.path.svnurl( + 'svn://localhost:%s/%s' % (port, self.repopath.basename), + auth=auth) + u.ensure('foo') + paths = u.listdir() + assert len(paths) == 1 + assert paths[0].auth is auth + + auth = SvnAuth('foo', 'bar', interactive=False) + u = py.path.svnurl( + 'svn://localhost:%s/%s' % (port, self.repopath.basename), + auth=auth) + py.test.raises(Exception, 'u.listdir()') + finally: + killproc(pid) + + def test_copy(self): + port, pid = self._start_svnserve() + try: + auth = SvnAuth('johnny', 'foo', cache_auth=False, + interactive=False) + u = py.path.svnurl( + 'svn://localhost:%s/%s' % (port, self.repopath.basename), + auth=auth) + foo = u.ensure('foo') + bar = u.join('bar') + foo.copy(bar) + assert bar.check() + assert bar.auth is auth + + auth = SvnAuth('foo', 'bar', interactive=False) + u = py.path.svnurl( + 'svn://localhost:%s/%s' % (port, self.repopath.basename), + auth=auth) + foo = u.join('foo') + bar = u.join('bar') + py.test.raises(Exception, 'foo.copy(bar)') + finally: + killproc(pid) + + def test_write_read(self): + port, pid = self._start_svnserve() + try: + auth = SvnAuth('johnny', 'foo', cache_auth=False, + interactive=False) + u = py.path.svnurl( + 'svn://localhost:%s/%s' % (port, self.repopath.basename), + auth=auth) + foo = u.ensure('foo') + fp = foo.open() + try: + data = fp.read() + finally: + fp.close() + assert data == '' + + auth = SvnAuth('foo', 'bar', interactive=False) + u = py.path.svnurl( + 'svn://localhost:%s/%s' % (port, self.repopath.basename), + auth=auth) + foo = u.join('foo') + py.test.raises(Exception, 'foo.open()') + finally: + killproc(pid) + + # XXX rinse, repeat... :| Modified: py/branch/guido-svn-auth/py/path/svn/urlcommand.py ============================================================================== --- py/branch/guido-svn-auth/py/path/svn/urlcommand.py (original) +++ py/branch/guido-svn-auth/py/path/svn/urlcommand.py Wed Feb 20 22:28:58 2008 @@ -21,10 +21,11 @@ _lsrevcache = BuildcostAccessCache(maxentries=128) _lsnorevcache = AgingCache(maxentries=1000, maxseconds=60.0) - def __new__(cls, path, rev=None): + def __new__(cls, path, rev=None, auth=None): self = object.__new__(cls) if isinstance(path, cls): rev = path.rev + auth = path.auth path = path.strpath proto, uri = path.split("://", 1) host, uripath = uri.split('/', 1) @@ -36,6 +37,7 @@ path = path.rstrip('/') self.strpath = path self.rev = rev + self.auth = auth return self def __repr__(self): @@ -44,7 +46,8 @@ else: return 'svnurl(%r, %r)' % (self.strpath, self.rev) - def _svn(self, cmd, *args): + def _svnwithrev(self, cmd, *args): + """ execute an svn command, append our own url and revision """ if self.rev is None: return self._svnwrite(cmd, *args) else: @@ -52,16 +55,28 @@ return self._svnwrite(cmd, *args) def _svnwrite(self, cmd, *args): + """ execute an svn command, append our own url """ l = ['svn %s' % cmd] args = ['"%s"' % self._escape(item) for item in args] l.extend(args) l.append('"%s"' % self._encodedurl()) # fixing the locale because we can't otherwise parse - string = svncommon.fixlocale() + " ".join(l) + string = " ".join(l) if DEBUG: print "execing", string + out = self._svncmdexecauth(string) + return out + + def _svncmdexecauth(self, cmd): + """ execute an svn command 'as is' """ + cmd = svncommon.fixlocale() + cmd + if self.auth is not None: + cmd += ' ' + self.auth.makecmdoptions() + return self._cmdexec(cmd) + + def _cmdexec(self, cmd): try: - out = process.cmdexec(string) + out = process.cmdexec(cmd) except py.process.cmdexec.Error, e: if (e.err.find('File Exists') != -1 or e.err.find('File already exists') != -1): @@ -69,6 +84,16 @@ raise return out + def _svnpopenauth(self, cmd): + """ execute an svn command, return a pipe for reading stdin """ + cmd = svncommon.fixlocale() + cmd + if self.auth is not None: + cmd += ' ' + self.auth.makecmdoptions() + return self._popen(cmd) + + def _popen(self, cmd): + return os.popen(cmd) + def _encodedurl(self): return self._escape(self.strpath) @@ -76,14 +101,12 @@ """ return an opened file with the given mode. """ assert 'w' not in mode and 'a' not in mode, "XXX not implemented for svn cmdline" assert self.check(file=1) # svn cat returns an empty file otherwise - def popen(cmd): - return os.popen(cmd) if self.rev is None: - return popen(svncommon.fixlocale() + - 'svn cat "%s"' % (self._escape(self.strpath), )) + return self._svnpopenauth('svn cat "%s"' % ( + self._escape(self.strpath), )) else: - return popen(svncommon.fixlocale() + - 'svn cat -r %s "%s"' % (self.rev, self._escape(self.strpath))) + return self._svnpopenauth('svn cat -r %s "%s"' % ( + self.rev, self._escape(self.strpath))) def dirpath(self, *args, **kwargs): """ return the directory path of the current path joined @@ -104,33 +127,37 @@ commit_msg=kwargs.get('msg', "mkdir by py lib invocation") createpath = self.join(*args) createpath._svnwrite('mkdir', '-m', commit_msg) - self._lsnorevcache.delentry(createpath.dirpath().strpath) + auth = self.auth and self.auth.makecmdoptions() or None + self._lsnorevcache.delentry((createpath.dirpath().strpath, auth)) return createpath def copy(self, target, msg='copied by py lib invocation'): """ copy path to target with checkin message msg.""" if getattr(target, 'rev', None) is not None: raise py.error.EINVAL(target, "revisions are immutable") - process.cmdexec('svn copy -m "%s" "%s" "%s"' %(msg, - self._escape(self), self._escape(target))) - self._lsnorevcache.delentry(target.dirpath().strpath) + self._svncmdexecauth('svn copy -m "%s" "%s" "%s"' %(msg, + self._escape(self), self._escape(target))) + auth = self.auth and self.auth.makecmdoptions() or None + self._lsnorevcache.delentry((target.dirpath().strpath, auth)) def rename(self, target, msg="renamed by py lib invocation"): """ rename this path to target with checkin message msg. """ if getattr(self, 'rev', None) is not None: raise py.error.EINVAL(self, "revisions are immutable") - py.process.cmdexec('svn move -m "%s" --force "%s" "%s"' %( - msg, self._escape(self), self._escape(target))) - self._lsnorevcache.delentry(self.dirpath().strpath) - self._lsnorevcache.delentry(self.strpath) + self._svncmdexecauth('svn move -m "%s" --force "%s" "%s"' %( + msg, self._escape(self), self._escape(target))) + auth = self.auth and self.auth.makecmdoptions() or None + self._lsnorevcache.delentry((self.dirpath().strpath, auth)) + self._lsnorevcache.delentry((self.strpath, auth)) def remove(self, rec=1, msg='removed by py lib invocation'): """ remove a file or directory (or a directory tree if rec=1) with checkin message msg.""" if self.rev is not None: raise py.error.EINVAL(self, "revisions are immutable") - process.cmdexec('svn rm -m "%s" "%s"' %(msg, self._escape(self))) - self._lsnorevcache.delentry(self.dirpath().strpath) + self._svncmdexecauth('svn rm -m "%s" "%s"' %(msg, self._escape(self))) + auth = self.auth and self.auth.makecmdoptions() or None + self._lsnorevcache.delentry((self.dirpath().strpath, auth)) def export(self, topath): """ export to a local path @@ -143,7 +170,7 @@ '"%s"' % (self._escape(topath),)] if self.rev is not None: args = ['-r', str(self.rev)] + args - process.cmdexec('svn export %s' % (' '.join(args),)) + self._svncmdexecauth('svn export %s' % (' '.join(args),)) return topath def ensure(self, *args, **kwargs): @@ -173,19 +200,20 @@ "ensure %s" % self._escape(tocreate), self._escape(tempdir.join(basename)), x.join(basename)._encodedurl()) - process.cmdexec(cmd) - self._lsnorevcache.delentry(x.strpath) # !!! + self._svncmdexecauth(cmd) + auth = self.auth and self.auth.makecmdoptions() or None + self._lsnorevcache.delentry((x.strpath, auth)) # !!! finally: tempdir.remove() return target # end of modifying methods def _propget(self, name): - res = self._svn('propget', name) + res = self._svnwithrev('propget', name) return res[:-1] # strip trailing newline def _proplist(self): - res = self._svn('proplist') + res = self._svnwithrev('proplist') lines = res.split('\n') lines = map(str.strip, lines[1:]) return svncommon.PropListDict(self, lines) @@ -194,7 +222,7 @@ """ return sequence of name-info directory entries of self """ def builder(): try: - res = self._svn('ls', '-v') + res = self._svnwithrev('ls', '-v') except process.cmdexec.Error, e: if e.err.find('non-existent in that revision') != -1: raise py.error.ENOENT(self, e.err) @@ -214,10 +242,13 @@ info = InfoSvnCommand(lsline) nameinfo_seq.append((info._name, info)) return nameinfo_seq + auth = self.auth and self.auth.makecmdoptions() or None if self.rev is not None: - return self._lsrevcache.getorbuild((self.strpath, self.rev), builder) + return self._lsrevcache.getorbuild((self.strpath, self.rev, auth), + builder) else: - return self._lsnorevcache.getorbuild(self.strpath, builder) + return self._lsnorevcache.getorbuild((self.strpath, auth), + builder) def log(self, rev_start=None, rev_end=1, verbose=False): """ return a list of LogEntry instances for this path. @@ -234,9 +265,8 @@ else: rev_opt = "-r %s:%s" % (rev_start, rev_end) verbose_opt = verbose and "-v" or "" - xmlpipe = os.popen(svncommon.fixlocale() + - 'svn log --xml %s %s "%s"' % - (rev_opt, verbose_opt, self.strpath)) + xmlpipe = self._svnpopenauth('svn log --xml %s %s "%s"' % + (rev_opt, verbose_opt, self.strpath)) from xml.dom import minidom tree = minidom.parse(xmlpipe) result = [] From nilton at codespeak.net Wed Feb 20 23:31:01 2008 From: nilton at codespeak.net (nilton at codespeak.net) Date: Wed, 20 Feb 2008 23:31:01 +0100 (CET) Subject: [py-svn] r51711 - py/branch/code-coverage Message-ID: <20080220223101.3136E16850F@codespeak.net> Author: nilton Date: Wed Feb 20 23:31:00 2008 New Revision: 51711 Added: py/branch/code-coverage/ - copied from r51710, py/trunk/ Log: creating a branch to work on adding code coverage analysis to py.test From py-svn at codespeak.net Wed Feb 27 23:55:38 2008 From: py-svn at codespeak.net (py-svn at codespeak.net) Date: Wed, 27 Feb 2008 23:55:38 +0100 (CET) Subject: [py-svn] February 74% OFF Message-ID: <20080227125505.35395.qmail@catv-5985e861.catv.broadband.hu> An HTML attachment was scrubbed... URL: