[py-svn] r7162 - in py: branch/test2 branch/test2/doc branch/test2/py branch/test2/py/path/extpy branch/test2/py/path/local branch/test2/py/test branch/test2/py/test2 branch/test2/py/test2/report branch/test2/py/test2/report/text dist/py/bin dist/py/path/local dist/py/test2
hpk at codespeak.net
hpk at codespeak.net
Sun Oct 31 22:42:54 CET 2004
Author: hpk
Date: Sun Oct 31 22:42:53 2004
New Revision: 7162
Added:
py/branch/test2/
- copied from r7156, py/dist/
py/branch/test2/py/path/extpy/extpy.py
- copied unchanged from r7161, py/dist/py/path/extpy/extpy.py
py/branch/test2/py/path/extpy/inc_test_extpy.py
- copied unchanged from r7161, py/dist/py/path/extpy/inc_test_extpy.py
py/branch/test2/py/path/extpy/test_extpy.py
- copied unchanged from r7161, py/dist/py/path/extpy/test_extpy.py
py/branch/test2/py/test/run.py
- copied unchanged from r7157, py/dist/py/test/run.py
py/branch/test2/py/test2/
- copied from r7158, py/dist/py/test2/
Removed:
py/dist/py/bin/py.test2
py/dist/py/test2/
Modified:
py/branch/test2/conftest.py
py/branch/test2/doc/test.txt
py/branch/test2/py/__init__.py
py/branch/test2/py/path/local/local.py
py/branch/test2/py/test2/cmdline.py
py/branch/test2/py/test2/config.py
py/branch/test2/py/test2/defaultconfig.py
py/branch/test2/py/test2/item.py
py/branch/test2/py/test2/report/memo.py
py/branch/test2/py/test2/report/text/reporter.py
py/dist/py/path/local/local.py
Log:
get the test2-stuff out of the trunk (dist)
in favour of a true branch. After all opening
up a branch within the trunk wasn't such a
great idea. Implementing the test-refactoring
will take some time and experiments ...
Modified: py/branch/test2/conftest.py
==============================================================================
--- py/dist/conftest.py (original)
+++ py/branch/test2/conftest.py Sun Oct 31 22:42:53 2004
@@ -14,7 +14,8 @@
verbose = 0
nocapture = False
collectonly = False
-exitfirstproblem = False
+exitfirstproblem = True
fulltrace = False
showlocals = False
nomagic = False
+session = False
Modified: py/branch/test2/doc/test.txt
==============================================================================
--- py/dist/doc/test.txt (original)
+++ py/branch/test2/doc/test.txt Sun Oct 31 22:42:53 2004
@@ -245,139 +245,128 @@
your setup function callable. Did we mention that lazyness
is a virtue?
-The three components of ``py.test``
-===================================
+The underlying model of the ``py.test`` process
+===============================================
+
+ WARNING: THIS IS FUTURISTIC (documentation driven development)
In order to customize ``py.test`` it's good to understand
-its basic architure::
+the basic testing process::
- ___________________
- | |
- | Collector |
- |___________________|
- / \
- | Item.execute(driver)
- | ^
- receive test Items /
- | /execute test Item
- | /
- ___________________/ ________________
- | | send events | |
- | Driver |----------------------->| Reporter |
+ iter(Item)
+ ^ ......................... sends events
+ . .
+ . asks for items & results .
+ . .
+ ___________________ __________________
+ | | send events >| |
+ | RootItem |.......................>| Reporter |
|___________________| |________________|
- .......................
- . configuration .
- . cmdline options .
- .......................
-
-The *Driver* basically receives test *Items* from a *Collector*,
-executes them via the ``Item.execute()`` method, and takes the
-outcome (possibly an exception) and sends it over to the
-*reporter* instance.
+The RootItem iterates over its start items in order to receive
+more items triggers To start the testing process you call the RootItem.run()
+method.
+
+The *Driver* receives Items or Test results and sends according
+events to the reporter which interacts with the user, usually
+by just showing progress output (we do want to allow real
+user interaction later for implementing a "test console" or
+a gui-based frontend).
.. _`collection process`:
-Collectors and the test collection process
+generative test Items and final test Items
------------------------------------------
-The collecting process is iterative, i.e. the driver
-get test Items one by one and can thus start immediately
-to execute the first collected test Item. At the same time,
-the collectors are completly shielded from any driving,
-execution or reporting details.
-
-The ``driver`` invokes the iteration protocol, i.e. the
-``__iter__`` method of Collectors. These methods yield more (sub)
-*Collectors* or test *Items*. They should usually not raise
-exceptions but yield back a specific CollectError. This is to
-avoid that a collecting error breaks the whole collection
-chain. It is at the drivers discretion to react to errors
-from collectors.
-
-The default DirectoryCollector collects test files that
-match the glob patterns ``test_*.py`` or ``*_test.py`` and it
-recurses into any directory that doesn't start with a leading
-dot (e.g. ``.svn`` direcotries is ignored).
-
-Another ``PyCollector`` then recurses into the test files and
-collects functions and methods that have a leading ``test_``.
-By default, methods are only collected if their class starts
-with ``Test``.
-
-Drivers bind it all together
-----------------------------
-
-Drivers serve as the glue code between the various parts of
-the interacting ``py.test`` objects, more specifically
-they:
-
-- iterate over Collectors, which yield more Collectors or Items.
-
-- call the ``Item.execute()`` method in order to execute
- a test
-
-- send "result" and other events to the reporter so that
- the users gets informed about progress and problems
- in possibly custom ways.
+ WARNING: THIS IS FUTURISTIC (documentation driven development)
+
+The testing process is iterative, i.e. the driver immediately
+starts to execute test Items.
+
+For directories, modules and classes there are default
+**generative Items** which yield more **test Items** from your
+python source tree.
+
+- generative items can be iter()ated yielding back more
+ generative items or ``Result`` objects.
+
+- if iter()ating a generative item results in an exception
+ this is interpreted as a test failure related to the
+ generative item that failed.
+
+- generative items are restartable, i.e. multiple calls
+ to ``iter(genitem)`` allow to iterate a generative
+ item multiple times.
+
+- A ``driver`` uses ``iter(genitem)`` to iterate over
+ generative items the reporter will receive an
+ IterationFailure Result.
+
+- The default DirectoryItem yields ModuleItems for files
+ matching the glob patterns ``test_*.py`` or ``*_test.py`` and it
+ recurses into any directory that doesn't start with a leading
+ dot (e.g. ``.svn`` direcotries are ignored by default).
+
+- The default ModuleItem yields back GeneratorItems, ClassItems,
+ FunctionItems. ClassItems can also yield back FunctionItems
+ or GeneratorItems.
+
+- FunctionItems usually yield back Results obtaining from
+ executing their own ``funcitem.execute()`` which will just
+ call the underlying callable by default.
.. _reporter:
Reporters process test events
-----------------------------
-A driver typically invokes certain methods of a Reporter
-for various points in the testing process. A reporter
-is reponsible for representing the testing process
-to the user or other programs. These are the events
+ WARNING: THIS IS FUTURISTIC (documentation driven development)
+
+A driver invokes Reporter methods for various interesting points
+in the testing process. A reporter is reponsible for representing
+the testing process to the user or other programs. These are the events
(function calls) that the reporter receives::
- start(), end() are invoked only from the outmost driver
- to allow a reporter to write headers and
- footers
-
- open(collector) is called when a collector is about
- to be iterated. This method should return
- a "close" method (or None) which will be
- called when the collector is finished iterating.
-
- startitem(item) is called before executing a single test item
- enditem(result) is called when execution of a single test item
- finished. The result.item attribute points back
- to the Test item the result object belongs to.
+ begin(startitems) before the testing process begins
+ end(startitems) after the testing process finished
+ open(item) before an item is about to be iterated
+ result(result) for obtained ``Result`` objects
+ end(item) after iteration of an item finished
+
+ error(excinfo) signals severe internal/iteration failures
+
Customizing the py.test process
===============================
-Customizing the collection process in a module
-----------------------------------------------
+ WARNING: THIS IS FUTURISTIC (documentation driven development)
+
+*test generators* can produce test items on the fly
+---------------------------------------------------
+
+ WARNING: THIS IS FUTURISTIC (documentation driven development)
If you have a module where you want to take responsibility for
-collecting your own test Items and possibly even for executing
-a test then you can provide your own ``Collector`` at module
-level. The default ModuleCollector looks for the name
-``Collector`` in the modules namespace and turns over
-reponsibility by invoking it with the "module-path".
-
-The module path is a ``py.path.py()`` instance and carries
-information needed to traverse to to the module. In general,
-a pypath allows to address a python object on the filesystem.
-*Addressability of test Items* is a major concern because we
-want to memorize failing tests across py.test invocations. A
-``pypath`` has two parts, a filesystem path and a dotted path
-leading to the python object. Another benefits, apart from
-from addressability, is that invoking setup/teardown operations
-can simply be implemented by walking the path to the python
-object.
+collecting your own test Items you can provide a test generator
+that yields back callables which will be seemlessly integrated
+into the testing process. **Test generators** are automatically
+picked up and are recognized by the usual ``test_`` prefix.
+If iterating over your generator raises an exception this
+is reported as a test failure result.
+
+If a **test generator** raises an ``EOFError`` the parent (generative)
+Item will stop further iteration. This allows your **test generator**
+to control further inspection of a module or class.
+
+Customizing the execution of Items
+----------------------------------
-Customizing execution of Items
-------------------------------
+ WARNING: THIS IS FUTURISTIC (documentation driven development)
- Items allow total control of executing their contained test
- method. ``iteminstance.execute()`` will get called by the
- driver in order to actually execute a test. Thus a custom
- ``execute()`` method can pass arguments to test functions.
+ method. ``iteminstance.execute()`` will get called
+ in order to actually execute a test.
- Item.execute() methods can provide custom paramters
(a db-connection, some initialized application entity, whatever)
Modified: py/branch/test2/py/__init__.py
==============================================================================
--- py/dist/py/__init__.py (original)
+++ py/branch/test2/py/__init__.py Sun Oct 31 22:42:53 2004
@@ -28,6 +28,24 @@
'test.config': './test/config.config',
'test.compat.TestCase': './test/compat.TestCase',
+ 'test2.DefaultOptions': './test2/option.DefaultOptions',
+ 'test2.Option': './test2/tool/optparse.Option',
+ 'test2.TextReporter': './test2/report/text/reporter.TextReporter',
+ 'test2.Actor': './test2/actor.Actor',
+ 'test2.CmdlineActor': './test2/cmdline.CmdlineActor',
+ #'test2.MemoActor': './test2/actor.MemoActor',
+ 'test2.exit': './test/drive.exit',
+ 'test2.fail': './test/drive.fail',
+ 'test2.skip': './test/drive.skip',
+ 'test2.raises': './test/raises.raises',
+ 'test2.config': './test/config.config',
+ 'test2.compat.TestCase': './test/compat.TestCase',
+ 'test2.item.Directory': './test/item.Directory',
+ 'test2.item.Module': './test/item.Module',
+ 'test2.item.Class': './test/item.Class',
+ 'test2.item.Callable': './test/item.Callable',
+ 'test2.item.Generator': './test/item.Generator',
+
'process.cmdexec': './process/cmdexec.cmdexec',
'execnet.PopenGateway': './execnet/register.PopenGateway',
Modified: py/branch/test2/py/path/local/local.py
==============================================================================
--- py/dist/py/path/local/local.py (original)
+++ py/branch/test2/py/path/local/local.py Sun Oct 31 22:42:53 2004
@@ -266,9 +266,10 @@
def write(self, content):
""" write string content into path. """
+ s = str(content)
f = self.open('wb')
try:
- f.write(content)
+ f.write(s)
finally:
f.close()
Modified: py/branch/test2/py/test2/cmdline.py
==============================================================================
--- py/dist/py/test2/cmdline.py (original)
+++ py/branch/test2/py/test2/cmdline.py Sun Oct 31 22:42:53 2004
@@ -1,35 +1,84 @@
from __future__ import generators
import py
-import sys
-from py.__impl__.test import run
+
+from py.__impl__.test2.tool import optparse
+
+from py.__impl__.test2.item import Directory, Module
#
# main entry point
#
-def _old(argv):
- if argv is None:
- argv = py.std.sys.argv
- frame = py.std.sys._getframe(1)
- name = frame.f_locals.get('__name__')
- if name != '__main__':
- return # called from an imported test file
- import __main__
- return [py.test.collect.Module(py.std.sys.argv[0])]
-
def main():
- args = py.std.sys.argv[1:]
- py.test.config.readconfiguration(*run.getanchors(args))
+ actor = CmdlineActor(py.std.sys.argv)
+ actor.start()
+
+class CmdlineActor(py.test2.Actor):
+ def __init__(self, argv):
+ anchors = getanchors(argv[1:])
+ self.options = py.test2.DefaultOptions(anchors)
+ self.parse(argv)
+ self.reporter = self.options.Reporter(self)
+ assert self.items, "startup should result in runnable Items"
+ super(CmdlineActor, self).__init__()
+
+ def parse(self, argv):
+ """ parse command line options and return items. """
+ # first a small fight with optparse to merge the
+ # pytest.py file options correctly
+ parser = optparse.OptionParser()
+ for config in self.options._configpaths:
+ meth = config.join('options')
+ if meth.check():
+ groupname, groupoptions = meth.resolve()
+ optgroup = optparse.OptionGroup(parser, groupname)
+ optgroup.add_options(groupoptions)
+ parser.add_option_group(optgroup)
+
+ # extract and remove defaults from options
+ for option in flattenoptions(parser):
+ if option.dest:
+ value = self.options._getfirst(option.dest, option.default)
+ #print "setting %r to %r" %(option.dest, value)
+ setattr(self.options, option.dest, value)
+ option.default = 'NODEFAULT'
+
+ # parse cmdline args
+ _, remaining = parser.parse_args(argv[1:], self.options)
+ # override previously computed defaults
+ #for name in cmdlineoption.__dict__:
+ # if not name.startswith('_'):
+ # print "resetting %r to %r" %(name, cmdlineoption.__dict__[name])
+ # setattr(self.options, name, cmdlineoption.__dict__[name])
+ self.items = []
+ for x in remaining:
+ p = py.path.local(x)
+ if p.check(dir=1):
+ self.items.append(Directory(p, self))
+ elif p.check(file=1):
+ self.items.append(Module(p, self))
+ else:
+ raise ValueError(x)
+ if not self.items:
+ self.items.append(Directory(py.path.local(), self))
+
+def getanchors(args):
+ """ yield "anchors" from skimming the args for existing files/dirs. """
+ current = py.path.local()
+ l = []
+ for arg in args:
+ anchor = current.join(arg, abs=1)
+ if anchor.check():
+ l.append(anchor)
+ if not l:
+ l = [current]
+ return l
+
+# helpers
- filenames = py.test.config.parseargs(args)
- if not filenames:
- filenames.append(str(py.path.local()))
- try:
- if py.test.config.option.session:
- run.session(args, filenames)
- else:
- run.inprocess(args, filenames)
- except KeyboardInterrupt:
- print
- print "Keybordinterrupt"
- raise SystemExit, 2
+def flattenoptions(parser):
+ for group in parser.option_groups:
+ for y in group.option_list:
+ yield y
+ for x in parser.option_list:
+ yield x
Modified: py/branch/test2/py/test2/config.py
==============================================================================
--- py/dist/py/test2/config.py (original)
+++ py/branch/test2/py/test2/config.py Sun Oct 31 22:42:53 2004
@@ -1,7 +1,7 @@
from __future__ import generators
import py
-from py.__impl__.test.tool import optparse
+from py.__impl__.test2.tool import optparse
defaultconfig = py.magic.autopath().dirpath('defaultconfig.py')
defaultconfig = py.path.extpy(defaultconfig)
@@ -11,10 +11,42 @@
# config file handling (utest.conf)
#
configbasename = 'conftest.py'
+import py
-class Config:
- def __init__(self):
- self.configpaths = []
+Option = py.test2.Option
+options = ('py.test standard options', [
+ Option('-v', '--verbose',
+ action="count", dest="verbose", default=0,
+ help="increase verbosity"),
+ Option('-x', '--exitfirst',
+ action="store_true", dest="exitfirstproblem", default=False,
+ help="exit instantly on first error or failed test."),
+ Option('-S', '--nocapture',
+ action="store_true", dest="nocapture", default=False,
+ help="disable catching of sys.stdout/stderr output."),
+ Option('-l', '--showlocals',
+ action="store_true", dest="showlocals", default=False,
+ help="show locals in tracebacks (disabled by default)"),
+ Option('', '--session',
+ action="store_true", dest="session", default=False,
+ help="run a test session/rerun only failing tests. "),
+ Option('', '--fulltrace',
+ action="store_true", dest="fulltrace", default=False,
+ help="Don't try to cut any tracebacks (default is to cut)"),
+ Option('', '--nomagic',
+ action="store_true", dest="nomagic", default=False,
+ help="don't invoke magic to e.g. beautify failing/error statements."),
+ #Option('', '--pdb',
+ # action="store_true", dest="usepdb", default=False,
+ # help="Start pdb (the Python debugger) on errors."),
+ Option('', '--collectonly',
+ action="store_true", dest="collectonly", default=False,
+ help="only collect tests, don't execute them. "),
+])
+
+class DefaultOptionsOptions:
+ def __init__(self, config=None):
+ self.configpaths = filter(None, [config, defaultconfig])
self.option = optparse.Values()
def _gettmpdir(self, sessiondir=[]):
@@ -26,19 +58,11 @@
return d
tmpdir = property(_gettmpdir, None, None, "Temporary Directory")
- def readconfiguration(self, *anchors):
- """ read configuration files left-to-right for the given anchor file. """
- self.configpaths = []
- for anchor in anchors:
- for p in anchor.parts():
- x = p.join(configbasename)
- if x.check(file=1):
- extpy = py.path.extpy(x)
- extpy.resolve() # trigger loading it
- self.configpaths.append(extpy)
- self.configpaths.sort(lambda x,y: cmp(len(str(x)), len(str(y))))
- self.configpaths.append(defaultconfig)
-
+ def __getattr__(self, name):
+ if name[0] == '_':
+ raise AttributeError(name)
+ return self.getfirst(name)
+
def getfirst(self, param, default=dummy):
""" return first found parameter. """
for config in self.configpaths:
@@ -51,8 +75,20 @@
#if default is not dummy:
# return getattr(self, param, default)
#return getattr(self, param)
+
+ def _getreporter(self):
+ try:
+ return self._reporter
+ except AttributeError:
+ self._reporter = r = self.Reporter()
+ return r
+ def _setreporter(self, rep):
+ self._reporter = rep
+ reporter = property(_getreporter, _setreporter, None, "reporter instance")
def parseargs(self, args):
+ anchors = getanchors(args)
+ self.configpaths = readconfiguration(anchors) + self.configpaths
# first a small fight with optparse to merge the
# pytest.py file options correctly
parser = optparse.OptionParser()
@@ -79,10 +115,33 @@
# if not name.startswith('_'):
# print "resetting %r to %r" %(name, cmdlineoption.__dict__[name])
# setattr(self.option, name, cmdlineoption.__dict__[name])
- return remaining
-
+ self.testpaths = [py.path.local(x) for x in remaining]
+ #return remaining
-config = Config()
+def readconfiguration(anchors):
+ """ read configuration files left-to-right for the given anchor file. """
+ configpaths = []
+ for anchor in anchors:
+ for p in anchor.parts():
+ x = p.join(configbasename)
+ if x.check(file=1):
+ extpy = py.path.extpy(x)
+ extpy.resolve() # trigger loading it XXX why?
+ configpaths.append(extpy)
+ configpaths.sort(lambda x,y: cmp(len(str(x)), len(str(y))))
+ return configpaths
+
+def getanchors(args):
+ """ yield "anchors" from skimming the args for existing files/dirs. """
+ current = py.path.local()
+ l = []
+ for arg in args:
+ anchor = current.join(arg, abs=1)
+ if anchor.check():
+ l.append(anchor)
+ if not l:
+ l = [current]
+ return l
# helpers
Modified: py/branch/test2/py/test2/defaultconfig.py
==============================================================================
--- py/dist/py/test2/defaultconfig.py (original)
+++ py/branch/test2/py/test2/defaultconfig.py Sun Oct 31 22:42:53 2004
@@ -1,9 +1,6 @@
import py
-Option = py.test.Option
-
-def getreporter():
- return py.test.TextReporter()
+Option = py.test2.Option
options = ('py.test standard options', [
Option('-v', '--verbose',
action="count", dest="verbose", default=0,
@@ -33,3 +30,7 @@
action="store_true", dest="collectonly", default=False,
help="only collect tests, don't execute them. "),
])
+
+from py.__impl__.test2.item import DirectoryItem, ModuleItem
+from py.__impl__.test2.item import CmdlineItem, StartItem, ModuleItem, CallableItem
+
Modified: py/branch/test2/py/test2/item.py
==============================================================================
--- py/dist/py/test2/item.py (original)
+++ py/branch/test2/py/test2/item.py Sun Oct 31 22:42:53 2004
@@ -1,25 +1,10 @@
+from __future__ import generators
+import py
# ----------------------------------------------
# Basic Test Item
# ----------------------------------------------
class Item(object):
- _setupcache = []
- _lastinstance = None
-
- def __init__(self, extpy, *args):
- self.extpy = extpy
- self.name = extpy.basename
- self.args = args
-
- def execute(self, driver):
- driver.setup_path(self.extpy)
- target, teardown = driver.setup_method(self.extpy)
- try:
- target(*self.args)
- finally:
- if teardown:
- teardown(target)
-
class Outcome:
def __init__(self, **kwargs):
assert 'msg' not in kwargs or isinstance(kwargs['msg'], str), (
@@ -28,8 +13,164 @@
def __repr__(self):
return getattr(self, 'msg', object.__repr__(self))
class Passed(Outcome): pass
- class Failed(Outcome): pass
- class ExceptionFailure(Failed): pass
+ class Failure(Outcome): pass
+ class ExceptionFailure(Failure): pass
class Skipped(Outcome): pass
+ parentitem = None
+
+ def __init__(self, actor):
+ self.actor = actor
+
+ def run(self):
+ print "self", self
+ print "actor", self.actor
+ assert isinstance(self.actor, py.test2.Actor)
+ items = self.actor.call('collect', self)
+ for item in items:
+ self.actor.optcall('open', item)
+ try:
+ try:
+ item.run()
+ except (KeyboardInterrupt, SystemExit):
+ raise
+ except:
+ self.actor.error(py.std.sys.exc_info())
+ finally:
+ self.actor.optcall('close', item)
+
+class Directory(Item):
+ def __init__(self, fspath, actor):
+ assert fspath.check(dir=1)
+ assert isinstance(actor, py.test2.Actor)
+ self.fspath = fspath
+ super(Directory, self).__init__(actor)
+
+ def strlocation(self):
+ return str(self.fspath)
+
+ def fil(self, fspath):
+ return (fspath.check(file=1, fnmatch='test_*.py') or
+ fspath.check(file=1, fnmatch='*_test.py'))
+ def rec(self, fspath):
+ return fspath.check(dir=1, dotfile=0, link=0)
+
+ def collect(self):
+ l = []
+ append = l.append
+ for fspath in self.fspath.listdir(sort=True):
+ if self.rec(fspath):
+ append(Directory(fspath, self.actor))
+ elif self.fil(fspath):
+ extpy = py.path.extpy(fspath)
+ append(Module(extpy, self.actor))
+ return l
+
+class PyItem(Item):
+ def __init__(self, extpy, actor):
+ self.extpy = extpy
+ self.yielders = [getattr(self, x)
+ for x in dir(self.__class__)
+ if x.startswith('collect_')]
+ super(PyItem, self).__init__(actor)
+
+ def strlocation(self):
+ return str(self.extpy)
+
+ def sorted(self):
+ l = []
+ for extpy in self.extpy.listdir():
+ for meth in self.yielders:
+ for x in meth(extpy):
+ x.fspath = self.extpy.root
+ sortkey = self.getsortkey(x)
+ l.append((sortkey, x))
+ l.sort()
+ return [x[1] for x in l]
+
+ def getsortkey(self, obj):
+ """ sorting function to bring test methods in
+ the same order as int he file.
+ """
+ if isinstance(obj, PyItem):
+ obj = obj.extpy.resolve()
+ elif isinstance(obj, PyItem):
+ return obj.getsortkey()
+ if hasattr(obj, 'im_func'):
+ obj = obj.im_func
+ if hasattr(obj, 'func_code'):
+ obj = obj.func_code
+ # enough is enough
+ return (getattr(obj, 'co_filename', None),
+ getattr(obj, 'co_firstlineno', py.std.sys.maxint))
+
+class Module(PyItem):
+ def collect(self):
+ l = []
+ append = l.append
+ for x in self.extpy.listdir():
+ basename = x.basename
+ if basename.startswith('test_'):
+ if x.check(genfunc=1):
+ append(Generator(x, self.actor) )
+ elif x.check(func=1):
+ append(Callable(x, self.actor))
+ elif basename.startswith('Test') and self.extpy.samefile(x) \
+ and x.check(class_=1):
+ obj = x.resolve()
+ print "found", obj
+ if not getattr(obj, 'disabled', 0):
+ append(Class(x))
+
+ slist = [(x.getsortkey(x),x) for x in l]
+ slist.sort()
+ l = [x[1] for x in slist]
+ return l
+
+class Callable(PyItem):
+ def __init__(self, extpy, actor, args=()):
+ super(Callable, self).__init__(extpy, actor)
+ self.args = args
+
+ def run(self):
+ target = self.actor.optcall('setup', self)
+ try:
+ try:
+ self.execute(target)
+ except (KeyboardInterrupt, SystemExit):
+ raise
+ except:
+ self.actor.failed(self, py.std.sys.exc_info())
+ else:
+ self.actor.passed(self)
+ finally:
+ self.actor.optcall('teardown', self)
+
+ def setup(self):
+ """ setup objects along the path to the test-method
+ (pointed to by extpy). Tear down any previously
+ setup objects which are not directly needed.
+ """
+ #self.conf.setup_path(self.extpy)
+ return self.extpy.resolve()
+
+ def execute(self, target):
+ target(*self.args)
+
+class Generator(Callable):
+ def execute(self, obj):
+ for x in obj(*self.args):
+ if isinstance(x, (tuple, list)):
+ callable = x.pop(0)
+ args = tuple(x)
+ else:
+ callable = x
+ args = ()
+ #if isgenerator(callable):
+ # item = self.LiveGenerator(callable, self, args)
+ if callable(callable):
+ item = Callable(callable, self, args)
+ else:
+ raise TypeError("not a callable or generator: %r" % callable)
+ item.run()
Modified: py/branch/test2/py/test2/report/memo.py
==============================================================================
--- py/dist/py/test2/report/memo.py (original)
+++ py/branch/test2/py/test2/report/memo.py Sun Oct 31 22:42:53 2004
@@ -3,6 +3,34 @@
from py.test import Item
class MemoReporter:
+ def __init__(self):
+ self._calls = []
+
+ def optcall(self, methodname, obj):
+ c = getattr(obj, methodname, None)
+ if c is not None:
+ c()
+ self._calls.append((methodname, obj))
+
+ def call(self, methodname, obj):
+ c = getattr(obj, methodname, None)
+ if c is not None:
+ c()
+ self._calls.append((methodname, obj))
+
+ def _dispatchmethod(self, methodname, item):
+ cls = getattr(item, '__class__', None)
+ if cls is not None:
+ for typ in py.std.inspect.getmro(cls):
+ reportmethodname = "%s_%s" % (methodname, typ.__name__)
+ reportmeth = getattr(reporter, reportmethodname, None)
+ if reportmeth is not None:
+ reportmeth(item)
+ break
+ call = getattr(item, methodname, None)
+ if call is not None:
+ return call(item)
+
typemap = {
Item.Passed: '.', Item.Skipped: 's', Item.Failed: 'F',
}
Modified: py/branch/test2/py/test2/report/text/reporter.py
==============================================================================
--- py/dist/py/test2/report/text/reporter.py (original)
+++ py/branch/test2/py/test2/report/text/reporter.py Sun Oct 31 22:42:53 2004
@@ -24,10 +24,9 @@
Collector.Error: 'COLLECT ERROR',
}
- def __init__(self, f=None):
- if f is None:
- f = py.std.sys.stdout
- self.out = getout(f)
+ def __init__(self, actor):
+ self.actor = actor
+ self.out = getout(py.std.sys.stdout)
self._started = {}
self.summary = self.Summary()
self.summary.option = self.option = py.test.config.option
Deleted: /py/dist/py/bin/py.test2
==============================================================================
--- /py/dist/py/bin/py.test2 Sun Oct 31 22:42:53 2004
+++ (empty file)
@@ -1,5 +0,0 @@
-#!/usr/bin/env python
-
-from _findpy import py
-from py.__impl__.test2.cmdline import main
-main()
Modified: py/dist/py/path/local/local.py
==============================================================================
--- py/dist/py/path/local/local.py (original)
+++ py/dist/py/path/local/local.py Sun Oct 31 22:42:53 2004
@@ -266,9 +266,10 @@
def write(self, content):
""" write string content into path. """
+ s = str(content)
f = self.open('wb')
try:
- f.write(content)
+ f.write(s)
finally:
f.close()
More information about the pytest-commit
mailing list