Exemple #1
0
 def __init__(self, pluginmanager=None, topdir=None):
     self.option = CmdOptions()
     self.topdir = topdir
     self._parser = parseopt.Parser(
         usage="usage: %prog [options] [file_or_dir] [file_or_dir] [...]",
         processopt=self._processopt,
     )
     if pluginmanager is None:
         pluginmanager = py.test._PluginManager()
     assert isinstance(pluginmanager, py.test._PluginManager)
     self.pluginmanager = pluginmanager
     self._conftest = Conftest(onimport=self._onimportconftest)
     self.hook = pluginmanager.hook
Exemple #2
0
 def __init__(self, pluginmanager=None, topdir=None): 
     self.option = CmdOptions()
     self.topdir = topdir
     self._parser = parseopt.Parser(
         usage="usage: %prog [options] [file_or_dir] [file_or_dir] [...]",
         processopt=self._processopt,
     )
     if pluginmanager is None:
         pluginmanager = py.test._PluginManager()
     assert isinstance(pluginmanager, py.test._PluginManager)
     self.pluginmanager = pluginmanager
     self._conftest = Conftest(onimport=self._onimportconftest)
     self.hook = pluginmanager.hook
 def __init__(self, pytestplugins=None, topdir=None): 
     self.option = CmdOptions()
     self.topdir = topdir
     self._parser = parseopt.Parser(
         usage="usage: %prog [options] [file_or_dir] [file_or_dir] [...]",
         processopt=self._processopt,
     )
     if pytestplugins is None:
         pytestplugins = py.test._PytestPlugins()
     assert isinstance(pytestplugins, py.test._PytestPlugins)
     self.bus = pytestplugins.pyplugins
     self.pytestplugins = pytestplugins
     self._conftest = Conftest(onimport=self._onimportconftest)
     self._setupstate = SetupState() 
Exemple #4
0
class Config(object):
    """ test configuration object, provides access to config valueso, 
        the pluginmanager and plugin api. 
    """
    Option = py.compat.optparse.Option  # deprecated
    Error = Error
    basetemp = None
    _sessionclass = None

    def __init__(self, pluginmanager=None, topdir=None):
        self.option = CmdOptions()
        self.topdir = topdir
        self._parser = parseopt.Parser(
            usage="usage: %prog [options] [file_or_dir] [file_or_dir] [...]",
            processopt=self._processopt,
        )
        if pluginmanager is None:
            pluginmanager = py.test._PluginManager()
        assert isinstance(pluginmanager, py.test._PluginManager)
        self.pluginmanager = pluginmanager
        self._conftest = Conftest(onimport=self._onimportconftest)
        self.hook = pluginmanager.hook

    def _onimportconftest(self, conftestmodule):
        self.trace("loaded conftestmodule %r" % (conftestmodule, ))
        self.pluginmanager.consider_conftest(conftestmodule)

    def trace(self, msg):
        if getattr(self.option, 'traceconfig', None):
            self.hook.pytest_trace(category="config", msg=msg)

    def _processopt(self, opt):
        if hasattr(opt, 'default') and opt.dest:
            val = os.environ.get("PYTEST_OPTION_" + opt.dest.upper(), None)
            if val is not None:
                if opt.type == "int":
                    val = int(val)
                elif opt.type == "long":
                    val = long(val)
                elif opt.type == "float":
                    val = float(val)
                elif not opt.type and opt.action in ("store_true",
                                                     "store_false"):
                    val = eval(val)
                opt.default = val
            else:
                name = "option_" + opt.dest
                try:
                    opt.default = self._conftest.rget(name)
                except (ValueError, KeyError):
                    pass
            if not hasattr(self.option, opt.dest):
                setattr(self.option, opt.dest, opt.default)

    def _preparse(self, args):
        self._conftest.setinitial(args)
        self.pluginmanager.consider_preparse(args)
        self.pluginmanager.consider_env()
        self.pluginmanager.do_addoption(self._parser)

    def parse(self, args):
        """ parse cmdline arguments into this config object. 
            Note that this can only be called once per testing process. 
        """
        assert not hasattr(self, 'args'), (
            "can only parse cmdline args at most once per Config object")
        self._preparse(args)
        args = self._parser.parse_setoption(args, self.option)
        if not args:
            args.append(py.std.os.getcwd())
        self.topdir = gettopdir(args)
        self.args = [py.path.local(x) for x in args]

    # config objects are usually pickled across system
    # barriers but they contain filesystem paths.
    # upon getstate/setstate we take care to do everything
    # relative to "topdir".
    def __getstate__(self):
        l = []
        for path in self.args:
            path = py.path.local(path)
            l.append(path.relto(self.topdir))
        return l, self.option

    def __setstate__(self, repr):
        # warning global side effects:
        # * registering to py lib plugins
        # * setting py.test.config
        self.__init__(
            pluginmanager=py.test._PluginManager(py._com.comregistry),
            topdir=py.path.local(),
        )
        # we have to set py.test.config because preparse()
        # might load conftest files which have
        # py.test.config.addoptions() lines in them
        py.test.config = self
        args, cmdlineopts = repr
        args = [self.topdir.join(x) for x in args]
        self.option = cmdlineopts
        self._preparse(args)
        self.args = args

    def ensuretemp(self, string, dir=True):
        return self.getbasetemp().ensure(string, dir=dir)

    def getbasetemp(self):
        if self.basetemp is None:
            basetemp = self.option.basetemp
            if basetemp:
                basetemp = py.path.local(basetemp)
                if not basetemp.check(dir=1):
                    basetemp.mkdir()
            else:
                basetemp = py.path.local.make_numbered_dir(prefix='pytest-')
            self.basetemp = basetemp
        return self.basetemp

    def mktemp(self, basename, numbered=False):
        basetemp = self.getbasetemp()
        if not numbered:
            return basetemp.mkdir(basename)
        else:
            return py.path.local.make_numbered_dir(prefix=basename + "-",
                                                   keep=0,
                                                   rootdir=basetemp,
                                                   lock_timeout=None)

    def getcolitems(self):
        return [self.getfsnode(arg) for arg in self.args]

    def getfsnode(self, path):
        path = py.path.local(path)
        if not path.check():
            raise self.Error("file not found: %s" % (path, ))
        # we want our possibly custom collection tree to start at pkgroot
        pkgpath = path.pypkgpath()
        if pkgpath is None:
            pkgpath = path.check(file=1) and path.dirpath() or path
        Dir = self._conftest.rget("Directory", pkgpath)
        col = Dir(pkgpath)
        col.config = self
        return col._getfsnode(path)

    def getconftest_pathlist(self, name, path=None):
        """ return a matching value, which needs to be sequence
            of filenames that will be returned as a list of Path
            objects (they can be relative to the location 
            where they were found).
        """
        try:
            mod, relroots = self._conftest.rget_with_confmod(name, path)
        except KeyError:
            return None
        modpath = py.path.local(mod.__file__).dirpath()
        l = []
        for relroot in relroots:
            relroot = relroot.replace("/", py.path.local.sep)
            l.append(modpath.join(relroot, abs=True))
        return l

    def addoptions(self, groupname, *specs):
        """ add a named group of options to the current testing session. 
            This function gets invoked during testing session initialization. 
        """
        py.log._apiwarn("1.0", "define plugins to add options", stacklevel=2)
        group = self._parser.addgroup(groupname)
        for opt in specs:
            group._addoption_instance(opt)
        return self.option

    def addoption(self, *optnames, **attrs):
        return self._parser.addoption(*optnames, **attrs)

    def getvalueorskip(self, name, path=None):
        """ return getvalue() or call py.test.skip if no value exists. """
        try:
            val = self.getvalue(name, path)
            if val is None:
                raise KeyError(name)
            return val
        except KeyError:
            py.test.skip("no %r value found" % (name, ))

    def getvalue(self, name, path=None):
        """ return 'name' value looked up from the 'options'
            and then 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 getattr(self.option, name)
        except AttributeError:
            return self._conftest.rget(name, path)

    def setsessionclass(self, cls):
        if self._sessionclass is not None:
            raise ValueError("sessionclass already set to: %r" %
                             (self._sessionclass))
        self._sessionclass = cls

    def initsession(self):
        """ return an initialized session object. """
        cls = self._sessionclass
        if cls is None:
            from py.__.test.session import Session
            cls = Session
        session = cls(self)
        self.trace("instantiated session %r" % session)
        return session

    def _reparse(self, args):
        """ this is used from tests that want to re-invoke parse(). """
        #assert args # XXX should not be empty
        global config_per_process
        oldconfig = py.test.config
        try:
            config_per_process = py.test.config = Config()
            config_per_process.basetemp = self.mktemp("reparse", numbered=True)
            config_per_process.parse(args)
            return config_per_process
        finally:
            config_per_process = py.test.config = oldconfig

    def getxspecs(self):
        xspeclist = []
        for xspec in self.getvalue("tx"):
            i = xspec.find("*")
            try:
                num = int(xspec[:i])
            except ValueError:
                xspeclist.append(xspec)
            else:
                xspeclist.extend([xspec[i + 1:]] * num)
        if not xspeclist:
            raise self.Error(
                "MISSING test execution (tx) nodes: please specify --tx")
        return [py.execnet.XSpec(x) for x in xspeclist]

    def getrsyncdirs(self):
        config = self
        roots = config.option.rsyncdir
        conftestroots = config.getconftest_pathlist("rsyncdirs")
        if conftestroots:
            roots.extend(conftestroots)
        pydir = py.path.local(py.__file__).dirpath()
        roots = [py.path.local(root) for root in roots]
        for root in roots:
            if not root.check():
                raise config.Error("rsyncdir doesn't exist: %r" % (root, ))
            if pydir is not None and root.basename == "py":
                if root != pydir:
                    raise config.Error("root %r conflicts with imported %r" %
                                       (root, pydir))
                pydir = None
        if pydir is not None:
            roots.append(pydir)
        return roots
Exemple #5
0
class Config(object): 
    """ test configuration object, provides access to config valueso, 
        the pluginmanager and plugin api. 
    """
    Option = py.compat.optparse.Option # deprecated
    Error = Error
    basetemp = None
    _sessionclass = None

    def __init__(self, pluginmanager=None, topdir=None): 
        self.option = CmdOptions()
        self.topdir = topdir
        self._parser = parseopt.Parser(
            usage="usage: %prog [options] [file_or_dir] [file_or_dir] [...]",
            processopt=self._processopt,
        )
        if pluginmanager is None:
            pluginmanager = py.test._PluginManager()
        assert isinstance(pluginmanager, py.test._PluginManager)
        self.pluginmanager = pluginmanager
        self._conftest = Conftest(onimport=self._onimportconftest)
        self.hook = pluginmanager.hook

    def _onimportconftest(self, conftestmodule):
        self.trace("loaded conftestmodule %r" %(conftestmodule,))
        self.pluginmanager.consider_conftest(conftestmodule)

    def trace(self, msg):
        if getattr(self.option, 'traceconfig', None):
            self.hook.pytest_trace(category="config", msg=msg)

    def _processopt(self, opt):
        if hasattr(opt, 'default') and opt.dest:
            val = os.environ.get("PYTEST_OPTION_" + opt.dest.upper(), None)
            if val is not None:
                if opt.type == "int":
                    val = int(val)
                elif opt.type == "long":
                    val = long(val)
                elif opt.type == "float":
                    val = float(val)
                elif not opt.type and opt.action in ("store_true", "store_false"):
                    val = eval(val)
                opt.default = val 
            else:
                name = "option_" + opt.dest
                try:
                    opt.default = self._conftest.rget(name)
                except (ValueError, KeyError):
                    pass
            if not hasattr(self.option, opt.dest):
                setattr(self.option, opt.dest, opt.default)

    def _preparse(self, args):
        self._conftest.setinitial(args) 
        self.pluginmanager.consider_preparse(args)
        self.pluginmanager.consider_env()
        self.pluginmanager.do_addoption(self._parser)

    def parse(self, args): 
        """ parse cmdline arguments into this config object. 
            Note that this can only be called once per testing process. 
        """ 
        assert not hasattr(self, 'args'), (
                "can only parse cmdline args at most once per Config object")
        self._preparse(args)
        args = self._parser.parse_setoption(args, self.option)
        if not args:
            args.append(py.std.os.getcwd())
        self.topdir = gettopdir(args)
        self.args = [py.path.local(x) for x in args]

    # config objects are usually pickled across system
    # barriers but they contain filesystem paths. 
    # upon getstate/setstate we take care to do everything
    # relative to "topdir". 
    def __getstate__(self):
        l = []
        for path in self.args:
            path = py.path.local(path)
            l.append(path.relto(self.topdir)) 
        return l, self.option

    def __setstate__(self, repr):
        # warning global side effects:
        # * registering to py lib plugins 
        # * setting py.test.config 
        self.__init__(
            pluginmanager=py.test._PluginManager(py._com.comregistry),
            topdir=py.path.local(),
        )
        # we have to set py.test.config because preparse()
        # might load conftest files which have
        # py.test.config.addoptions() lines in them 
        py.test.config = self 
        args, cmdlineopts = repr 
        args = [self.topdir.join(x) for x in args]
        self.option = cmdlineopts
        self._preparse(args)
        self.args = args 

    def ensuretemp(self, string, dir=True):
        return self.getbasetemp().ensure(string, dir=dir) 

    def getbasetemp(self):
        if self.basetemp is None:
            basetemp = self.option.basetemp 
            if basetemp:
                basetemp = py.path.local(basetemp)
                if not basetemp.check(dir=1):
                    basetemp.mkdir()
            else:
                basetemp = py.path.local.make_numbered_dir(prefix='pytest-')
            self.basetemp = basetemp
        return self.basetemp 

    def mktemp(self, basename, numbered=False):
        basetemp = self.getbasetemp()
        if not numbered:
            return basetemp.mkdir(basename)
        else:
            return py.path.local.make_numbered_dir(prefix=basename + "-", 
                keep=0, rootdir=basetemp, lock_timeout=None)

    def getcolitems(self):
        return [self.getfsnode(arg) for arg in self.args]

    def getfsnode(self, path):
        path = py.path.local(path)
        if not path.check():
            raise self.Error("file not found: %s" %(path,))
        # we want our possibly custom collection tree to start at pkgroot 
        pkgpath = path.pypkgpath()
        if pkgpath is None:
            pkgpath = path.check(file=1) and path.dirpath() or path
        Dir = self._conftest.rget("Directory", pkgpath)
        col = Dir(pkgpath)
        col.config = self 
        return col._getfsnode(path)

    def getconftest_pathlist(self, name, path=None):
        """ return a matching value, which needs to be sequence
            of filenames that will be returned as a list of Path
            objects (they can be relative to the location 
            where they were found).
        """
        try:
            mod, relroots = self._conftest.rget_with_confmod(name, path)
        except KeyError:
            return None
        modpath = py.path.local(mod.__file__).dirpath()
        l = []
        for relroot in relroots:
            relroot = relroot.replace("/", py.path.local.sep)
            l.append(modpath.join(relroot, abs=True))
        return l 
             
    def addoptions(self, groupname, *specs): 
        """ add a named group of options to the current testing session. 
            This function gets invoked during testing session initialization. 
        """ 
        py.log._apiwarn("1.0", "define plugins to add options", stacklevel=2)
        group = self._parser.addgroup(groupname)
        for opt in specs:
            group._addoption_instance(opt)
        return self.option 

    def addoption(self, *optnames, **attrs):
        return self._parser.addoption(*optnames, **attrs)

    def getvalueorskip(self, name, path=None): 
        """ return getvalue() or call py.test.skip if no value exists. """
        try:
            val = self.getvalue(name, path)
            if val is None:
                raise KeyError(name)
            return val
        except KeyError:
            py.test.skip("no %r value found" %(name,))

    def getvalue(self, name, path=None): 
        """ return 'name' value looked up from the 'options'
            and then 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 getattr(self.option, name)
        except AttributeError:
            return self._conftest.rget(name, path)

    def setsessionclass(self, cls):
        if self._sessionclass is not None:
            raise ValueError("sessionclass already set to: %r" %(
                self._sessionclass))
        self._sessionclass = cls

    def initsession(self):
        """ return an initialized session object. """
        cls = self._sessionclass 
        if cls is None:
            from py.__.test.session import Session
            cls = Session
        session = cls(self)
        self.trace("instantiated session %r" % session)
        return session

    def _reparse(self, args):
        """ this is used from tests that want to re-invoke parse(). """
        #assert args # XXX should not be empty
        global config_per_process
        oldconfig = py.test.config
        try:
            config_per_process = py.test.config = Config()
            config_per_process.basetemp = self.mktemp("reparse", numbered=True)
            config_per_process.parse(args) 
            return config_per_process
        finally: 
            config_per_process = py.test.config = oldconfig 

    def getxspecs(self):
        xspeclist = []
        for xspec in self.getvalue("tx"):
            i = xspec.find("*")
            try:
                num = int(xspec[:i])
            except ValueError:
                xspeclist.append(xspec)
            else:
                xspeclist.extend([xspec[i+1:]] * num)
        if not xspeclist:
            raise self.Error("MISSING test execution (tx) nodes: please specify --tx")
        return [py.execnet.XSpec(x) for x in xspeclist]

    def getrsyncdirs(self):
        config = self 
        roots = config.option.rsyncdir
        conftestroots = config.getconftest_pathlist("rsyncdirs")
        if conftestroots:
            roots.extend(conftestroots)
        pydir = py.path.local(py.__file__).dirpath()
        roots = [py.path.local(root) for root in roots]
        for root in roots:
            if not root.check():
                raise config.Error("rsyncdir doesn't exist: %r" %(root,))
            if pydir is not None and root.basename == "py":
                if root != pydir:
                    raise config.Error("root %r conflicts with imported %r" %(root, pydir))
                pydir = None
        if pydir is not None:
            roots.append(pydir)
        return roots 
Exemple #6
0
 def __init__(self): 
     self.option = CmdOptions()
     self._parser = optparse.OptionParser(
         usage="usage: %prog [options] [query] [filenames of tests]")
     self._conftest = Conftest()
Exemple #7
0
class Config(object): 
    """ central bus for dealing with configuration/initialization data. """ 
    Option = optparse.Option
    _initialized = False

    def __init__(self): 
        self.option = CmdOptions()
        self._parser = optparse.OptionParser(
            usage="usage: %prog [options] [query] [filenames of tests]")
        self._conftest = Conftest()

    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 at most once per Config object")
        self._initialized = True
        adddefaultoptions(self)
        self._conftest.setinitial(args) 
        args = [str(x) for x in args]
        cmdlineoption, args = self._parser.parse_args(args) 
        self.option.__dict__.update(vars(cmdlineoption))
        if not args:
            args.append(py.std.os.getcwd())
        self.topdir = gettopdir(args)
        self.args = args 

    # config objects are usually pickled across system
    # barriers but they contain filesystem paths. 
    # upon getstate/setstate we take care to do everything
    # relative to our "topdir". 
    def __getstate__(self):
        return self._makerepr()
    def __setstate__(self, repr):
        self._repr = repr

    def _initafterpickle(self, topdir):
        self.__init__()
        self._initialized = True
        self.topdir = py.path.local(topdir)
        self._mergerepr(self._repr)
        del self._repr 

    def _makerepr(self):
        l = []
        for path in self.args:
            path = py.path.local(path)
            l.append(path.relto(self.topdir)) 
        return l, self.option

    def _mergerepr(self, repr): 
        # before any conftests are loaded we 
        # need to set the per-process singleton 
        # (also seens py.test.config) to have consistent
        # option handling 
        global config_per_process
        config_per_process = self  
        args, cmdlineopts = repr 
        self.args = [self.topdir.join(x) for x in args]
        self.option = cmdlineopts
        self._conftest.setinitial(self.args)

    def getfsnode(self, path):
        path = py.path.local(path)
        assert path.check(), "%s: path does not exist" %(path,)
        # we want our possibly custom collection tree to start at pkgroot 
        pkgpath = path.pypkgpath()
        if pkgpath is None:
            pkgpath = path.check(file=1) and path.dirpath() or path
        Dir = self._conftest.rget("Directory", pkgpath)
        col = Dir(pkgpath, config=self)
        names = path.relto(col.fspath).split(path.sep)
        return col._getitembynames(names)

    def getvalue_pathlist(self, name, path=None):
        """ return a matching value, which needs to be sequence
            of filenames that will be returned as a list of Path
            objects (they can be relative to the location 
            where they were found).
        """
        try:
            return getattr(self.option, name)
        except AttributeError:
            try:
                mod, relroots = self._conftest.rget_with_confmod(name, path)
            except KeyError:
                return None
            modpath = py.path.local(mod.__file__).dirpath()
            return [modpath.join(x, abs=True) for x in relroots]
             
    def addoptions(self, groupname, *specs): 
        """ add a named group of options to the current testing session. 
            This function gets invoked during testing session initialization. 
        """ 
        for spec in specs:
            for shortopt in spec._short_opts:
                if not shortopt.isupper(): 
                    raise ValueError(
                        "custom options must be capital letter "
                        "got %r" %(spec,)
                    )
        return self._addoptions(groupname, *specs)

    def _addoptions(self, groupname, *specs):
        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:
                if not hasattr(self.option, 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 'options'
            and then 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 getattr(self.option, name)
        except AttributeError:
            return self._conftest.rget(name, path)

    def initreporter(self, bus):
        if self.option.collectonly:
            from py.__.test.report.collectonly import Reporter
        else:
            from py.__.test.report.terminal import Reporter 
        rep = Reporter(self, bus=bus)
        return rep

    def initsession(self):
        """ return an initialized session object. """
        cls = self._getsessionclass()
        session = cls(self)
        session.fixoptions()
        session.reporter = self.initreporter(session.bus)
        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()
            try:
                return self._conftest.rget(name)
            except KeyError:
                pass
            importpath = globals()[name]
            mod = __import__(importpath, None, None, '__doc__')
            return getattr(mod, name)

    def _getsessionname(self):
        """ return default session name as determined from options. """
        if self.option.collectonly:
            name = 'Session'
        elif self.option.looponfailing:
            name = 'LooponfailingSession'
        elif self.option.numprocesses or self.option.dist or self.option.executable: 
            name = 'DSession'
        else:
            name = 'Session'
        return name

    def _reparse(self, args):
        """ this is used from tests that want to re-invoke parse(). """
        #assert args # XXX should not be empty
        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 _getcapture(self, path=None):
        if self.option.nocapture:
            iocapture = "no" 
        else:
            iocapture = self.getvalue("conf_iocapture", path=path)
        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)

    
    def gettracedir(self):
        """ return a tracedirectory or None, depending on --tracedir. """
        if self.option.tracedir is not None:
            return py.path.local(self.option.tracedir)

    def maketrace(self, name, flush=True):
        """ return a tracedirectory or None, depending on --tracedir. """
        tracedir = self.gettracedir()
        if tracedir is None:
            return NullTracer()
        tracedir.ensure(dir=1)
        return Tracer(tracedir.join(name), flush=flush)
Exemple #8
0
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

    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
        adddefaultoptions(self)
        self._conftest.setinitial(args) 
        args = [str(x) for x in args]
        cmdlineoption, args = self._parser.parse_args(args) 
        self.option.__dict__.update(vars(cmdlineoption))
        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._mergerepr(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 getvalue_pathlist(self, name, path=None):
        """ return a matching value, which needs to be sequence
            of filenames that will be returned as a list of Path
            objects (they can be relative to the location 
            where they were found).
        """
        try:
            return getattr(self.option, name)
        except AttributeError:
            try:
                mod, relroots = self._conftest.rget_with_confmod(name, path)
            except KeyError:
                return None
            modpath = py.path.local(mod.__file__).dirpath()
            return [modpath.join(x, abs=True) for x in relroots]
             
    def addoptions(self, groupname, *specs): 
        """ add a named group of options to the current testing session. 
            This function gets invoked during testing session initialization. 
        """ 
        for spec in specs:
            for shortopt in spec._short_opts:
                if not shortopt.isupper(): 
                    raise ValueError(
                        "custom options must be capital letter "
                        "got %r" %(spec,)
                    )
        return self._addoptions(groupname, *specs)

    def _addoptions(self, groupname, *specs):
        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 'options'
            and then 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 getattr(self.option, name)
        except AttributeError:
            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()
            try:
                return self._conftest.rget(name)
            except KeyError:
                pass
            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'
        else:
            optnames = 'startserver runbrowser apigen restreport boxed'.split()
            for opt in optnames:
                if getattr(self.option, opt, False):
                    name = 'LSession'
                    break
            else:
                if self.getvalue('dist_boxed'):
                    name = 'LSession'
                if self.option.looponfailing:
                    name = 'RemoteTerminalSession'
                elif self.option.executable:
                    name = 'RemoteTerminalSession'
        return name

    def _reparse(self, args):
        """ this is used from tests that want to re-invoke parse(). """
        #assert args # XXX should not be empty
        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 _makerepr(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 _mergerepr(self, repr): 
        """ merge in the conftest and cmdline option values
            found in the given representation (produced
            by _makerepr 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)
                self.__file__ = "<options from remote>"
        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:]])

    def _startcapture(self, colitem, path=None):
        if not self.option.nocapture:
            assert not hasattr(colitem, '_capture')
            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()