[svn r37269] merging of file:///svn/py/branch/config/py/test/config.py
revisions 36936 to 37267: ------------------------------------------------------------------------ r37263 | hpk | 2007-01-24 14:59:20 +0100 (Wed, 24 Jan 2007) | 19 lines * introduce config.initdirect() which should be the central place to perform initialization on remote nodes/sides. * fix --looponfailing (which works nicely now) * have Conftest() be an instance instead of a class-variable (avoid global state) * more thoroughly use the "config.topdir" concept (which is not neccessarily the pkgdir.dirpath()) * on merge_repr don't write values to global defaultconftest module (this gets tests failing that reuse defaultconftest module, but also we want to avoid global state in general) ------------------------------------------------------------------------ r37243 | hpk | 2007-01-24 00:06:24 +0100 (Wed, 24 Jan 2007) | 2 lines small step-wise cleanups ------------------------------------------------------------------------ r37238 | hpk | 2007-01-23 23:09:57 +0100 (Tue, 23 Jan 2007) | 2 lines why do it complicated? ------------------------------------------------------------------------ r37235 | hpk | 2007-01-23 22:25:16 +0100 (Tue, 23 Jan 2007) | 5 lines added get_collector_trail method to get a representation of a collector relative to the topdir. ------------------------------------------------------------------------ r37230 | hpk | 2007-01-23 20:44:22 +0100 (Tue, 23 Jan 2007) | 2 lines typo-level fixes ------------------------------------------------------------------------ r37193 | hpk | 2007-01-23 14:53:17 +0100 (Tue, 23 Jan 2007) | 5 lines introduced config.topdir, tests and use it from terminal/remote at least. also fix fijal's "--box" option handling a bit, but i am not sure it should stay this way at all. ------------------------------------------------------------------------ r37172 | fijal | 2007-01-23 11:26:10 +0100 (Tue, 23 Jan 2007) | 2 lines Boxing implies lsession ------------------------------------------------------------------------ r37114 | hpk | 2007-01-22 02:20:30 +0100 (Mon, 22 Jan 2007) | 6 lines streamlining initial construction of collectors (to unify topdir/pkgdir/collector handling in rsession/terminal/normal) still work in-progress with a skipped test ------------------------------------------------------------------------ r37112 | hpk | 2007-01-22 01:07:09 +0100 (Mon, 22 Jan 2007) | 3 lines * moving towards a common rootdir/root collector * adding an xxxed test ------------------------------------------------------------------------ r37110 | hpk | 2007-01-22 00:39:24 +0100 (Mon, 22 Jan 2007) | 2 lines renaming some variables for more clarity ------------------------------------------------------------------------ r37077 | hpk | 2007-01-20 22:26:52 +0100 (Sat, 20 Jan 2007) | 2 lines cleaning up fixoptions() a bit ------------------------------------------------------------------------ r37076 | hpk | 2007-01-20 22:19:42 +0100 (Sat, 20 Jan 2007) | 2 lines unskip exec and looponfailing tests, fixes for that ------------------------------------------------------------------------ r37075 | hpk | 2007-01-20 21:51:18 +0100 (Sat, 20 Jan 2007) | 2 lines remove two debug prints ------------------------------------------------------------------------ r37074 | hpk | 2007-01-20 21:43:52 +0100 (Sat, 20 Jan 2007) | 9 lines * config.initsession() deals with getting at a session class and initiliazing it * config._getcollector(path) gets a collector pointing to path * added lots of tests * thus remove the strange getfscollector and map2colitems logic * mark some tkinter tests as skipped * fixing things all around ------------------------------------------------------------------------ r37065 | arigo | 2007-01-20 17:15:10 +0100 (Sat, 20 Jan 2007) | 3 lines Choose a random free port when using the --runbrowser option, but stick to the fixed 8000 when using --startserver only. ------------------------------------------------------------------------ r37061 | hpk | 2007-01-20 16:29:25 +0100 (Sat, 20 Jan 2007) | 8 lines refactoring/fixing the remote terminal approach (used for --exec and --looponfailing) to use the new configiguration. Removes lots of strange code. XXX there are still some recursive testing issues. ------------------------------------------------------------------------ r37055 | hpk | 2007-01-20 12:51:54 +0100 (Sat, 20 Jan 2007) | 4 lines reintroducing --session to lookup custom session objects in conftests.py there is no other way to override a session object from conftests. ------------------------------------------------------------------------ r37025 | hpk | 2007-01-19 17:59:50 +0100 (Fri, 19 Jan 2007) | 2 lines remove lget and its last usage (which was a bit random) ------------------------------------------------------------------------ r37020 | hpk | 2007-01-19 17:48:15 +0100 (Fri, 19 Jan 2007) | 3 lines switching in the new way of getting to a sessionclass, removing code in cmdline.py and elsewhere accordingly ------------------------------------------------------------------------ r37013 | hpk | 2007-01-19 17:14:11 +0100 (Fri, 19 Jan 2007) | 2 lines somewhat simpler lookup mechanism for sessions ------------------------------------------------------------------------ r37009 | hpk | 2007-01-19 16:50:32 +0100 (Fri, 19 Jan 2007) | 2 lines adding a config method to determine the session name ------------------------------------------------------------------------ r36994 | fijal | 2007-01-19 15:08:16 +0100 (Fri, 19 Jan 2007) | 2 lines removal of some trailing white-spaces. ------------------------------------------------------------------------ r36964 | hpk | 2007-01-18 19:30:02 +0100 (Thu, 18 Jan 2007) | 8 lines move rconfig functionality to general Config object, with docstrings, and trying to change rsession accordingly. note that it's called "make_repr" and "merge_repr" the latter to make it obvious that we are changing the instance with the given repr. ------------------------------------------------------------------------ r36942 | hpk | 2007-01-18 16:08:06 +0100 (Thu, 18 Jan 2007) | 4 lines group things used for testing and not use non-underscore names (otherwise they are consdiered public and are possibly seen from apigen through py.test.config!) ------------------------------------------------------------------------ r36941 | fijal | 2007-01-18 15:59:08 +0100 (Thu, 18 Jan 2007) | 2 lines Add a hack which allows to temporarily overwrite the config value. ------------------------------------------------------------------------ r36937 | fijal | 2007-01-18 14:22:54 +0100 (Thu, 18 Jan 2007) | 2 lines Create a branch for further config cleanups. ------------------------------------------------------------------------ --HG-- branch : trunk
This commit is contained in:
parent
4a2d9e3f58
commit
6040cf158d
|
@ -0,0 +1,288 @@
|
||||||
|
from __future__ import generators
|
||||||
|
|
||||||
|
import py
|
||||||
|
from conftesthandle import Conftest
|
||||||
|
|
||||||
|
optparse = py.compat.optparse
|
||||||
|
|
||||||
|
# XXX move to Config class
|
||||||
|
basetemp = None
|
||||||
|
def ensuretemp(string, dir=1):
|
||||||
|
""" return temporary directory path with
|
||||||
|
the given string as the trailing part.
|
||||||
|
"""
|
||||||
|
global basetemp
|
||||||
|
if basetemp is None:
|
||||||
|
basetemp = py.path.local.make_numbered_dir(prefix='pytest-')
|
||||||
|
return basetemp.ensure(string, dir=dir)
|
||||||
|
|
||||||
|
class CmdOptions(object):
|
||||||
|
""" pure container instance for holding cmdline options
|
||||||
|
as attributes.
|
||||||
|
"""
|
||||||
|
def __repr__(self):
|
||||||
|
return "<CmdOptions %r>" %(self.__dict__,)
|
||||||
|
|
||||||
|
class Config(object):
|
||||||
|
""" central hub for dealing with configuration/initialization data. """
|
||||||
|
Option = optparse.Option
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.option = CmdOptions()
|
||||||
|
self._parser = optparse.OptionParser(
|
||||||
|
usage="usage: %prog [options] [query] [filenames of tests]")
|
||||||
|
self.conftest = Conftest()
|
||||||
|
self._initialized = False
|
||||||
|
self._overwrite_dict = {}
|
||||||
|
|
||||||
|
def parse(self, args):
|
||||||
|
""" parse cmdline arguments into this config object.
|
||||||
|
Note that this can only be called once per testing process.
|
||||||
|
"""
|
||||||
|
assert not self._initialized, (
|
||||||
|
"can only parse cmdline args once per Config object")
|
||||||
|
self._initialized = True
|
||||||
|
self.conftest.setinitial(args)
|
||||||
|
self.conftest.rget('adddefaultoptions')()
|
||||||
|
args = [str(x) for x in args]
|
||||||
|
cmdlineoption, args = self._parser.parse_args(args)
|
||||||
|
self.option.__dict__.update(vars(cmdlineoption))
|
||||||
|
fixoptions(self.option) # XXX fixing should be moved to sessions
|
||||||
|
if not args:
|
||||||
|
args.append(py.std.os.getcwd())
|
||||||
|
self.topdir = gettopdir(args)
|
||||||
|
self.args = args
|
||||||
|
|
||||||
|
def initdirect(self, topdir, repr, coltrails=None):
|
||||||
|
assert not self._initialized
|
||||||
|
self._initialized = True
|
||||||
|
self.topdir = py.path.local(topdir)
|
||||||
|
self.merge_repr(repr)
|
||||||
|
self._coltrails = coltrails
|
||||||
|
|
||||||
|
def getcolitems(self):
|
||||||
|
""" return initial collectors. """
|
||||||
|
trails = getattr(self, '_coltrails', None)
|
||||||
|
return [self._getcollector(path) for path in (trails or self.args)]
|
||||||
|
|
||||||
|
def _getcollector(self, path):
|
||||||
|
if isinstance(path, tuple):
|
||||||
|
relpath, names = path
|
||||||
|
fspath = self.topdir.join(relpath)
|
||||||
|
col = self._getcollector(fspath)
|
||||||
|
else:
|
||||||
|
path = py.path.local(path)
|
||||||
|
assert path.check(), "%s: path does not exist" %(path,)
|
||||||
|
col = self._getrootcollector(path)
|
||||||
|
names = path.relto(col.fspath).split(path.sep)
|
||||||
|
return col.getitembynames(names)
|
||||||
|
|
||||||
|
def _getrootcollector(self, path):
|
||||||
|
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
|
||||||
|
|
||||||
|
def addoptions(self, groupname, *specs):
|
||||||
|
""" add a named group of options to the current testing session.
|
||||||
|
This function gets invoked during testing session initialization.
|
||||||
|
"""
|
||||||
|
optgroup = optparse.OptionGroup(self._parser, groupname)
|
||||||
|
optgroup.add_options(specs)
|
||||||
|
self._parser.add_option_group(optgroup)
|
||||||
|
for opt in specs:
|
||||||
|
if hasattr(opt, 'default') and opt.dest:
|
||||||
|
setattr(self.option, opt.dest, opt.default)
|
||||||
|
return self.option
|
||||||
|
|
||||||
|
def getvalue(self, name, path=None):
|
||||||
|
""" return 'name' value looked up from the first conftest file
|
||||||
|
found up the path (including the path itself).
|
||||||
|
if path is None, lookup the value in the initial
|
||||||
|
conftest modules found during command line parsing.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
return self._overwrite_dict[name]
|
||||||
|
except KeyError:
|
||||||
|
return self.conftest.rget(name, path)
|
||||||
|
|
||||||
|
def initsession(self):
|
||||||
|
""" return an initialized session object. """
|
||||||
|
cls = self._getsessionclass()
|
||||||
|
session = cls(self)
|
||||||
|
#session.fixoptions()
|
||||||
|
return session
|
||||||
|
|
||||||
|
def _getsessionclass(self):
|
||||||
|
""" return Session class determined from cmdline options
|
||||||
|
and looked up in initial config modules.
|
||||||
|
"""
|
||||||
|
if self.option.session is not None:
|
||||||
|
return self.conftest.rget(self.option.session)
|
||||||
|
else:
|
||||||
|
name = self._getsessionname()
|
||||||
|
importpath = globals()[name]
|
||||||
|
mod = __import__(importpath, None, None, '__doc__')
|
||||||
|
return getattr(mod, name)
|
||||||
|
|
||||||
|
def _getsessionname(self):
|
||||||
|
""" return default session name as determined from options. """
|
||||||
|
name = 'TerminalSession'
|
||||||
|
if self.option.dist:
|
||||||
|
name = 'RSession'
|
||||||
|
elif self.option.tkinter:
|
||||||
|
name = 'TkinterSession'
|
||||||
|
else:
|
||||||
|
optnames = 'startserver runbrowser apigen restreport boxing'.split()
|
||||||
|
for opt in optnames:
|
||||||
|
if getattr(self.option, opt, False):
|
||||||
|
name = 'LSession'
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
if self.getvalue('dist_boxing'):
|
||||||
|
name = 'LSession'
|
||||||
|
if self.option.looponfailing:
|
||||||
|
name = 'RemoteTerminalSession'
|
||||||
|
elif self.option.executable:
|
||||||
|
name = 'RemoteTerminalSession'
|
||||||
|
return name
|
||||||
|
|
||||||
|
def is_boxed(self):
|
||||||
|
# XXX probably not a good idea to have this special function ...
|
||||||
|
return self.option.boxing or self.getvalue("dist_boxing")
|
||||||
|
|
||||||
|
def _reparse(self, args):
|
||||||
|
""" this is used from tests that want to re-invoke parse(). """
|
||||||
|
global config_per_process
|
||||||
|
oldconfig = py.test.config
|
||||||
|
try:
|
||||||
|
config_per_process = py.test.config = Config()
|
||||||
|
config_per_process.parse(args)
|
||||||
|
return config_per_process
|
||||||
|
finally:
|
||||||
|
config_per_process = py.test.config = oldconfig
|
||||||
|
|
||||||
|
def _overwrite(self, name, value):
|
||||||
|
""" this is used from tests to overwrite values irrespectives of conftests.
|
||||||
|
"""
|
||||||
|
self._overwrite_dict[name] = value
|
||||||
|
|
||||||
|
def make_repr(self, conftestnames, optnames=None):
|
||||||
|
""" return a marshallable representation
|
||||||
|
of conftest and cmdline options.
|
||||||
|
if optnames is None, all options
|
||||||
|
on self.option will be transferred.
|
||||||
|
"""
|
||||||
|
conftestdict = {}
|
||||||
|
for name in conftestnames:
|
||||||
|
value = self.getvalue(name)
|
||||||
|
checkmarshal(name, value)
|
||||||
|
conftestdict[name] = value
|
||||||
|
cmdlineopts = {}
|
||||||
|
if optnames is None:
|
||||||
|
optnames = dir(self.option)
|
||||||
|
for name in optnames:
|
||||||
|
if not name.startswith("_"):
|
||||||
|
value = getattr(self.option, name)
|
||||||
|
checkmarshal(name, value)
|
||||||
|
cmdlineopts[name] = value
|
||||||
|
l = []
|
||||||
|
for path in self.args:
|
||||||
|
path = py.path.local(path)
|
||||||
|
l.append(path.relto(self.topdir))
|
||||||
|
return l, conftestdict, cmdlineopts
|
||||||
|
|
||||||
|
def merge_repr(self, repr):
|
||||||
|
""" merge in the conftest and cmdline option values
|
||||||
|
found in the given representation (produced
|
||||||
|
by make_repr above).
|
||||||
|
|
||||||
|
The repr-contained conftest values are
|
||||||
|
stored on the default conftest module (last
|
||||||
|
priority) and the cmdline options on self.option.
|
||||||
|
"""
|
||||||
|
class override:
|
||||||
|
def __init__(self, d):
|
||||||
|
self.__dict__.update(d)
|
||||||
|
args, conftestdict, cmdlineopts = repr
|
||||||
|
self.args = [self.topdir.join(x) for x in args]
|
||||||
|
self.conftest.setinitial(self.args)
|
||||||
|
self.conftest._path2confmods[None].append(override(conftestdict))
|
||||||
|
for name, val in cmdlineopts.items():
|
||||||
|
setattr(self.option, name, val)
|
||||||
|
|
||||||
|
def get_collector_trail(self, collector):
|
||||||
|
""" provide a trail relative to the topdir,
|
||||||
|
which can be used to reconstruct the
|
||||||
|
collector (possibly on a different host
|
||||||
|
starting from a different topdir).
|
||||||
|
"""
|
||||||
|
chain = collector.listchain()
|
||||||
|
relpath = chain[0].fspath.relto(self.topdir)
|
||||||
|
if not relpath:
|
||||||
|
if chain[0].fspath == self.topdir:
|
||||||
|
relpath = "."
|
||||||
|
else:
|
||||||
|
raise ValueError("%r not relative to %s"
|
||||||
|
%(chain[0], self.topdir))
|
||||||
|
return relpath, tuple([x.name for x in chain[1:]])
|
||||||
|
|
||||||
|
# this is the one per-process instance of py.test configuration
|
||||||
|
config_per_process = Config()
|
||||||
|
|
||||||
|
# default import paths for sessions
|
||||||
|
|
||||||
|
TkinterSession = 'py.__.test.tkinter.reportsession'
|
||||||
|
TerminalSession = 'py.__.test.terminal.terminal'
|
||||||
|
TerminalSession = 'py.__.test.terminal.terminal'
|
||||||
|
RemoteTerminalSession = 'py.__.test.terminal.remote'
|
||||||
|
RSession = 'py.__.test.rsession.rsession'
|
||||||
|
LSession = 'py.__.test.rsession.rsession'
|
||||||
|
|
||||||
|
#
|
||||||
|
# helpers
|
||||||
|
#
|
||||||
|
|
||||||
|
def checkmarshal(name, value):
|
||||||
|
try:
|
||||||
|
py.std.marshal.dumps(value)
|
||||||
|
except ValueError:
|
||||||
|
raise ValueError("%s=%r is not marshallable" %(name, value))
|
||||||
|
|
||||||
|
def fixoptions(option):
|
||||||
|
""" sanity checks and making option values canonical. """
|
||||||
|
|
||||||
|
# implied options
|
||||||
|
if option.usepdb:
|
||||||
|
if not option.nocapture:
|
||||||
|
#print "--pdb implies --nocapture"
|
||||||
|
option.nocapture = True
|
||||||
|
|
||||||
|
if option.runbrowser and not option.startserver:
|
||||||
|
#print "--runbrowser implies --startserver"
|
||||||
|
option.startserver = True
|
||||||
|
|
||||||
|
# conflicting options
|
||||||
|
if option.looponfailing and option.usepdb:
|
||||||
|
raise ValueError, "--looponfailing together with --pdb not supported."
|
||||||
|
if option.looponfailing and option.dist:
|
||||||
|
raise ValueError, "--looponfailing together with --dist not supported."
|
||||||
|
if option.executable and option.usepdb:
|
||||||
|
raise ValueError, "--exec together with --pdb not supported."
|
||||||
|
|
||||||
|
|
||||||
|
def gettopdir(args):
|
||||||
|
""" return the top directory for the given paths.
|
||||||
|
if the common base dir resides in a python package
|
||||||
|
parent directory of the root package is returned.
|
||||||
|
"""
|
||||||
|
args = [py.path.local(arg) for arg in args]
|
||||||
|
p = reduce(py.path.local.common, args)
|
||||||
|
assert p, "cannot determine common basedir of %s" %(args,)
|
||||||
|
pkgdir = p.pypkgpath()
|
||||||
|
if pkgdir is None:
|
||||||
|
return p
|
||||||
|
else:
|
||||||
|
return pkgdir.dirpath()
|
Loading…
Reference in New Issue