# Source code for _pytest.config

    """ command line options, ini-file and conftest.py processing. """
    import argparse
    import shlex
    import traceback
    import types
    import warnings

    import py
    # DON't import pytest here because it causes import cycle troubles
    import sys, os
    import _pytest.hookspec  # the extension point definitions
    from pluggy import PluginManager, HookimplMarker, HookspecMarker

    hookimpl = HookimplMarker("pytest")
    hookspec = HookspecMarker("pytest")

    # pytest startup
    #
    class ConftestImportFailure(Exception):
        def __init__(self, path, excinfo):
            Exception.__init__(self, path, excinfo)
            self.path = path
            self.excinfo = excinfo

    def main(args=None, plugins=None):
        """ return exit code, after performing an in-process test run.

        :arg args: list of command line arguments.

        :arg plugins: list of plugin objects to be auto-registered during
                      initialization.
        """
        try:
            try:
                config = _prepareconfig(args, plugins)
            except ConftestImportFailure as e:
                tw = py.io.TerminalWriter(sys.stderr)
                for line in traceback.format_exception(*e.excinfo):
                    tw.line(line.rstrip(), red=True)
                tw.line("ERROR: could not load %s\n" % (e.path), red=True)
                return 4
            else:
                try:
                    config.pluginmanager.check_pending()
                    return config.hook.pytest_cmdline_main(config=config)
                finally:
                    config._ensure_unconfigure()
        except UsageError as e:
            for msg in e.args:
                sys.stderr.write("ERROR: %s\n" %(msg,))
            return 4

    class cmdline:  # compatibility namespace
        main = staticmethod(main)

    class UsageError(Exception):
        """ error in pytest usage or invocation"""

    _preinit = []

    default_plugins = (
         "mark main terminal runner python pdb unittest capture skipping "
         "tmpdir monkeypatch recwarn pastebin helpconfig nose assertion genscript "
         "junitxml resultlog doctest").split()

    builtin_plugins = set(default_plugins)
    builtin_plugins.add("pytester")

    def _preloadplugins():
        assert not _preinit
        _preinit.append(get_config())

    def get_config():
        if _preinit:
            return _preinit.pop(0)
        # subsequent calls to main will create a fresh instance
        pluginmanager = PytestPluginManager()
        config = Config(pluginmanager)
        for spec in default_plugins:
            pluginmanager.import_plugin(spec)
        return config

    def get_plugin_manager():
        """
        Obtain a new instance of the
        :py:class:`_pytest.config.PytestPluginManager`, with default plugins
        already loaded.

        This function can be used by integration with other tools, like hooking
        into pytest to run tests into an IDE.
        """
        return get_config().pluginmanager

    def _prepareconfig(args=None, plugins=None):
        if args is None:
            args = sys.argv[1:]
        elif isinstance(args, py.path.local):
            args = [str(args)]
        elif not isinstance(args, (tuple, list)):
            if not isinstance(args, str):
                raise ValueError("not a string or argument list: %r" % (args,))
            args = shlex.split(args)
        config = get_config()
        pluginmanager = config.pluginmanager
        try:
            if plugins:
                for plugin in plugins:
                    if isinstance(plugin, py.builtin._basestring):
                        pluginmanager.consider_pluginarg(plugin)
                    else:
                        pluginmanager.register(plugin)
            return pluginmanager.hook.pytest_cmdline_parse(
                    pluginmanager=pluginmanager, args=args)
        except BaseException:
            config._ensure_unconfigure()
            raise

    def exclude_pytest_names(name):
        return not name.startswith(name) or name == "pytest_plugins" or \
               name.startswith("pytest_funcarg__")

    class PytestPluginManager(PluginManager):
        """
        Overwrites :py:class:`pluggy.PluginManager` to add pytest-specific
        functionality:

        * loading plugins from the command line, ``PYTEST_PLUGIN`` env variable and
          ``pytest_plugins`` global variables found in plugins being loaded;
        * ``conftest.py`` loading during start-up;
        """
        def __init__(self):
            super(PytestPluginManager, self).__init__("pytest", implprefix="pytest_")
            self._warnings = []
            self._conftest_plugins = set()

            # state related to local conftest plugins
            self._path2confmods = {}
            self._conftestpath2mod = {}
            self._confcutdir = None
            self._noconftest = False

            self.add_hookspecs(_pytest.hookspec)
            self.register(self)
            if os.environ.get('PYTEST_DEBUG'):
                err = sys.stderr
                encoding = getattr(err, 'encoding', 'utf8')
                try:
                    err = py.io.dupfile(err, encoding=encoding)
                except Exception:
                    pass
                self.trace.root.setwriter(err.write)
                self.enable_tracing()

        def addhooks(self, module_or_class):
            """
            .. deprecated:: 2.8

            Use :py:meth:`pluggy.PluginManager.add_hookspecs` instead.
            """
            warning = dict(code="I2",
                           fslocation=py.code.getfslineno(sys._getframe(1)),
                           message="use pluginmanager.add_hookspecs instead of "
                                   "deprecated addhooks() method.")
            self._warnings.append(warning)
            return self.add_hookspecs(module_or_class)

        def parse_hookimpl_opts(self, plugin, name):
            if exclude_pytest_names(name):
                return None

            method = getattr(plugin, name)
            opts = super(PytestPluginManager, self).parse_hookimpl_opts(plugin, name)
            if opts is not None:
                for name in ("tryfirst", "trylast", "optionalhook", "hookwrapper"):
                    opts.setdefault(name, hasattr(method, name))
            return opts

        def parse_hookspec_opts(self, module_or_class, name):
            opts = super(PytestPluginManager, self).parse_hookspec_opts(
                                                    module_or_class, name)
            if opts is None:
                method = getattr(module_or_class, name)
                if name.startswith("pytest_"):
                    opts = {"firstresult": hasattr(method, "firstresult"),
                            "historic": hasattr(method, "historic")}
            return opts

        def _verify_hook(self, hook, hookmethod):
            super(PytestPluginManager, self)._verify_hook(hook, hookmethod)
            if "__multicall__" in hookmethod.argnames:
                fslineno = py.code.getfslineno(hookmethod.function)
                warning = dict(code="I1",
                               fslocation=fslineno,
                               message="%r hook uses deprecated __multicall__ "
                                       "argument" % (hook.name))
                self._warnings.append(warning)

        def register(self, plugin, name=None):
            ret = super(PytestPluginManager, self).register(plugin, name)
            if ret:
                self.hook.pytest_plugin_registered.call_historic(
                          kwargs=dict(plugin=plugin, manager=self))
            return ret

        def getplugin(self, name):
            # support deprecated naming because plugins (xdist e.g.) use it
            return self.get_plugin(name)

        def hasplugin(self, name):
            """Return True if the plugin with the given name is registered."""
            return bool(self.get_plugin(name))

        def pytest_configure(self, config):
            # XXX now that the pluginmanager exposes hookimpl(tryfirst...)
            # we should remove tryfirst/trylast as markers
            config.addinivalue_line("markers",
                "tryfirst: mark a hook implementation function such that the "
                "plugin machinery will try to call it first/as early as possible.")
            config.addinivalue_line("markers",
                "trylast: mark a hook implementation function such that the "
                "plugin machinery will try to call it last/as late as possible.")
            for warning in self._warnings:
                if isinstance(warning, dict):
                    config.warn(**warning)
                else:
                    config.warn(code="I1", message=warning)

        #
        # internal API for local conftest plugin handling
        #
        def _set_initial_conftests(self, namespace):
            """ load initial conftest files given a preparsed "namespace".
                As conftest files may add their own command line options
                which have arguments ('--my-opt somepath') we might get some
                false positives.  All builtin and 3rd party plugins will have
                been loaded, however, so common options will not confuse our logic
                here.
            """
            current = py.path.local()
            self._confcutdir = current.join(namespace.confcutdir, abs=True) \
                                    if namespace.confcutdir else None
            self._noconftest = namespace.noconftest
            testpaths = namespace.file_or_dir
            foundanchor = False
            for path in testpaths:
                path = str(path)
                # remove node-id syntax
                i = path.find("::")
                if i != -1:
                    path = path[:i]
                anchor = current.join(path, abs=1)
                if exists(anchor): # we found some file object
                    self._try_load_conftest(anchor)
                    foundanchor = True
            if not foundanchor:
                self._try_load_conftest(current)

        def _try_load_conftest(self, anchor):
            self._getconftestmodules(anchor)
            # let's also consider test* subdirs
            if anchor.check(dir=1):
                for x in anchor.listdir("test*"):
                    if x.check(dir=1):
                        self._getconftestmodules(x)

        def _getconftestmodules(self, path):
            if self._noconftest:
                return []
            try:
                return self._path2confmods[path]
            except KeyError:
                if path.isfile():
                    clist = self._getconftestmodules(path.dirpath())
                else:
                    # XXX these days we may rather want to use config.rootdir
                    # and allow users to opt into looking into the rootdir parent
                    # directories instead of requiring to specify confcutdir
                    clist = []
                    for parent in path.parts():
                        if self._confcutdir and self._confcutdir.relto(parent):
                            continue
                        conftestpath = parent.join("conftest.py")
                        if conftestpath.isfile():
                            mod = self._importconftest(conftestpath)
                            clist.append(mod)

                self._path2confmods[path] = clist
                return clist

        def _rget_with_confmod(self, name, path):
            modules = self._getconftestmodules(path)
            for mod in reversed(modules):
                try:
                    return mod, getattr(mod, name)
                except AttributeError:
                    continue
            raise KeyError(name)

        def _importconftest(self, conftestpath):
            try:
                return self._conftestpath2mod[conftestpath]
            except KeyError:
                pkgpath = conftestpath.pypkgpath()
                if pkgpath is None:
                    _ensure_removed_sysmodule(conftestpath.purebasename)
                try:
                    mod = conftestpath.pyimport()
                except Exception:
                    raise ConftestImportFailure(conftestpath, sys.exc_info())

                self._conftest_plugins.add(mod)
                self._conftestpath2mod[conftestpath] = mod
                dirpath = conftestpath.dirpath()
                if dirpath in self._path2confmods:
                    for path, mods in self._path2confmods.items():
                        if path and path.relto(dirpath) or path == dirpath:
                            assert mod not in mods
                            mods.append(mod)
                self.trace("loaded conftestmodule %r" %(mod))
                self.consider_conftest(mod)
                return mod

        #
        # API for bootstrapping plugin loading
        #
        #

        def consider_preparse(self, args):
            for opt1,opt2 in zip(args, args[1:]):
                if opt1 == "-p":
                    self.consider_pluginarg(opt2)

        def consider_pluginarg(self, arg):
            if arg.startswith("no:"):
                name = arg[3:]
                self.set_blocked(name)
                if not name.startswith("pytest_"):
                    self.set_blocked("pytest_" + name)
            else:
                self.import_plugin(arg)

        def consider_conftest(self, conftestmodule):
            if self.register(conftestmodule, name=conftestmodule.__file__):
                self.consider_module(conftestmodule)

        def consider_env(self):
            self._import_plugin_specs(os.environ.get("PYTEST_PLUGINS"))

        def consider_module(self, mod):
            self._import_plugin_specs(getattr(mod, "pytest_plugins", None))

        def _import_plugin_specs(self, spec):
            if spec:
                if isinstance(spec, str):
                    spec = spec.split(",")
                for import_spec in spec:
                    self.import_plugin(import_spec)

        def import_plugin(self, modname):
            # most often modname refers to builtin modules, e.g. "pytester",
            # "terminal" or "capture".  Those plugins are registered under their
            # basename for historic purposes but must be imported with the
            # _pytest prefix.
            assert isinstance(modname, str)
            if self.get_plugin(modname) is not None:
                return
            if modname in builtin_plugins:
                importspec = "_pytest." + modname
            else:
                importspec = modname
            try:
                __import__(importspec)
            except ImportError:
                raise
            except Exception as e:
                import pytest
                if not hasattr(pytest, 'skip') or not isinstance(e, pytest.skip.Exception):
                    raise
                self._warnings.append("skipped plugin %r: %s" %((modname, e.msg)))
            else:
                mod = sys.modules[importspec]
                self.register(mod, modname)
                self.consider_module(mod)

    class Parser:
        """ Parser for command line arguments and ini-file values.

        :ivar extra_info: dict of generic param -> value to display in case
            there's an error processing the command line arguments.
        """

        def __init__(self, usage=None, processopt=None):
            self._anonymous = OptionGroup("custom options", parser=self)
            self._groups = []
            self._processopt = processopt
            self._usage = usage
            self._inidict = {}
            self._ininames = []
            self.extra_info = {}

        def processoption(self, option):
            if self._processopt:
                if option.dest:
                    self._processopt(option)

        def getgroup(self, name, description="", after=None):
            """ get (or create) a named option Group.

            :name: name of the option group.
            :description: long description for --help output.
            :after: name of other group, used for ordering --help output.

            The returned group object has an ``addoption`` method with the same
            signature as :py:func:`parser.addoption
            <_pytest.config.Parser.addoption>` but will be shown in the
            respective group in the output of ``pytest. --help``.
            """
            for group in self._groups:
                if group.name == name:
                    return group
            group = OptionGroup(name, description, parser=self)
            i = 0
            for i, grp in enumerate(self._groups):
                if grp.name == after:
                    break
            self._groups.insert(i+1, group)
            return group

        def addoption(self, *opts, **attrs):
            """ register a command line option.

            :opts: option names, can be short or long options.
            :attrs: same attributes which the ``add_option()`` function of the
               `argparse library
               <http://docs.python.org/2/library/argparse.html>`_
               accepts.

            After command line parsing options are available on the pytest config
            object via ``config.option.NAME`` where ``NAME`` is usually set
            by passing a ``dest`` attribute, for example
            ``addoption("--long", dest="NAME", ...)``.
            """
            self._anonymous.addoption(*opts, **attrs)

        def parse(self, args):
            from _pytest._argcomplete import try_argcomplete
            self.optparser = self._getparser()
            try_argcomplete(self.optparser)
            return self.optparser.parse_args([str(x) for x in args])

        def _getparser(self):
            from _pytest._argcomplete import filescompleter
            optparser = MyOptionParser(self, self.extra_info)
            groups = self._groups + [self._anonymous]
            for group in groups:
                if group.options:
                    desc = group.description or group.name
                    arggroup = optparser.add_argument_group(desc)
                    for option in group.options:
                        n = option.names()
                        a = option.attrs()
                        arggroup.add_argument(*n, **a)
            # bash like autocompletion for dirs (appending '/')
            optparser.add_argument(FILE_OR_DIR, nargs='*').completer=filescompleter
            return optparser

        def parse_setoption(self, args, option):
            parsedoption = self.parse(args)
            for name, value in parsedoption.__dict__.items():
                setattr(option, name, value)
            return getattr(parsedoption, FILE_OR_DIR)

        def parse_known_args(self, args):
            optparser = self._getparser()
            args = [str(x) for x in args]
            return optparser.parse_known_args(args)

        def addini(self, name, help, type=None, default=None):
            """ register an ini-file option.

            :name: name of the ini-variable
            :type: type of the variable, can be ``pathlist``, ``args`` or ``linelist``.
            :default: default value if no ini-file option exists but is queried.

            The value of ini-variables can be retrieved via a call to
            :py:func:`config.getini(name) <_pytest.config.Config.getini>`.
            """
            assert type in (None, "pathlist", "args", "linelist")
            self._inidict[name] = (help, type, default)
            self._ininames.append(name)

    class ArgumentError(Exception):
        """
        Raised if an Argument instance is created with invalid or
        inconsistent arguments.
        """

        def __init__(self, msg, option):
            self.msg = msg
            self.option_id = str(option)

        def __str__(self):
            if self.option_id:
                return "option %s: %s" % (self.option_id, self.msg)
            else:
                return self.msg

    class Argument:
        """class that mimics the necessary behaviour of optparse.Option """
        _typ_map = {
            'int': int,
            'string': str,
            }
        # enable after some grace period for plugin writers
        TYPE_WARN = False

        def __init__(self, *names, **attrs):
            """store parms in private vars for use in add_argument"""
            self._attrs = attrs
            self._short_opts = []
            self._long_opts = []
            self.dest = attrs.get('dest')
            if self.TYPE_WARN:
                try:
                    help = attrs['help']
                    if '%default' in help:
                        warnings.warn(
                            'pytest now uses argparse. "%default" should be'
                            ' changed to "%(default)s" ',
                            FutureWarning,
                            stacklevel=3)
                except KeyError:
                    pass
            try:
                typ = attrs['type']
            except KeyError:
                pass
            else:
                # this might raise a keyerror as well, don't want to catch that
                if isinstance(typ, py.builtin._basestring):
                    if typ == 'choice':
                        if self.TYPE_WARN:
                            warnings.warn(
                                'type argument to addoption() is a string %r.'
                                ' For parsearg this is optional and when supplied '
                                ' should be a type.'
                                ' (options: %s)' % (typ, names),
                                FutureWarning,
                                stacklevel=3)
                        # argparse expects a type here take it from
                        # the type of the first element
                        attrs['type'] = type(attrs['choices'][0])
                    else:
                        if self.TYPE_WARN:
                            warnings.warn(
                                'type argument to addoption() is a string %r.'
                                ' For parsearg this should be a type.'
                                ' (options: %s)' % (typ, names),
                                FutureWarning,
                                stacklevel=3)
                        attrs['type'] = Argument._typ_map[typ]
                    # used in test_parseopt -> test_parse_defaultgetter
                    self.type = attrs['type']
                else:
                    self.type = typ
            try:
                # attribute existence is tested in Config._processopt
                self.default = attrs['default']
            except KeyError:
                pass
            self._set_opt_strings(names)
            if not self.dest:
                if self._long_opts:
                    self.dest = self._long_opts[0][2:].replace('-', '_')
                else:
                    try:
                        self.dest = self._short_opts[0][1:]
                    except IndexError:
                        raise ArgumentError(
                            'need a long or short option', self)

        def names(self):
            return self._short_opts + self._long_opts

        def attrs(self):
            # update any attributes set by processopt
            attrs = 'default dest help'.split()
            if self.dest:
                attrs.append(self.dest)
            for attr in attrs:
                try:
                    self._attrs[attr] = getattr(self, attr)
                except AttributeError:
                    pass
            if self._attrs.get('help'):
                a = self._attrs['help']
                a = a.replace('%default', '%(default)s')
                #a = a.replace('%prog', '%(prog)s')
                self._attrs['help'] = a
            return self._attrs

        def _set_opt_strings(self, opts):
            """directly from optparse

            might not be necessary as this is passed to argparse later on"""
            for opt in opts:
                if len(opt) < 2:
                    raise ArgumentError(
                        "invalid option string %r: "
                        "must be at least two characters long" % opt, self)
                elif len(opt) == 2:
                    if not (opt[0] == "-" and opt[1] != "-"):
                        raise ArgumentError(
                            "invalid short option string %r: "
                            "must be of the form -x, (x any non-dash char)" % opt,
                            self)
                    self._short_opts.append(opt)
                else:
                    if not (opt[0:2] == "--" and opt[2] != "-"):
                        raise ArgumentError(
                            "invalid long option string %r: "
                            "must start with --, followed by non-dash" % opt,
                            self)
                    self._long_opts.append(opt)

        def __repr__(self):
            retval = 'Argument('
            if self._short_opts:
                retval += '_short_opts: ' + repr(self._short_opts) + ', '
            if self._long_opts:
                retval += '_long_opts: ' + repr(self._long_opts) + ', '
            retval += 'dest: ' + repr(self.dest) + ', '
            if hasattr(self, 'type'):
                retval += 'type: ' + repr(self.type) + ', '
            if hasattr(self, 'default'):
                retval += 'default: ' + repr(self.default) + ', '
            if retval[-2:] == ', ':  # always long enough to test ("Argument(" )
                retval = retval[:-2]
            retval += ')'
            return retval

    class OptionGroup:
        def __init__(self, name, description="", parser=None):
            self.name = name
            self.description = description
            self.options = []
            self.parser = parser

        def addoption(self, *optnames, **attrs):
            """ add an option to this group.

            if a shortened version of a long option is specified it will
            be suppressed in the help. addoption('--twowords', '--two-words')
            results in help showing '--two-words' only, but --twowords gets
            accepted **and** the automatic destination is in args.twowords
            """
            option = Argument(*optnames, **attrs)
            self._addoption_instance(option, shortupper=False)

        def _addoption(self, *optnames, **attrs):
            option = Argument(*optnames, **attrs)
            self._addoption_instance(option, shortupper=True)

        def _addoption_instance(self, option, shortupper=False):
            if not shortupper:
                for opt in option._short_opts:
                    if opt[0] == '-' and opt[1].islower():
                        raise ValueError("lowercase shortoptions reserved")
            if self.parser:
                self.parser.processoption(option)
            self.options.append(option)

    class MyOptionParser(argparse.ArgumentParser):
        def __init__(self, parser, extra_info=None):
            if not extra_info:
                extra_info = {}
            self._parser = parser
            argparse.ArgumentParser.__init__(self, usage=parser._usage,
                add_help=False, formatter_class=DropShorterLongHelpFormatter)
            # extra_info is a dict of (param -> value) to display if there's
            # an usage error to provide more contextual information to the user
            self.extra_info = extra_info

        def parse_args(self, args=None, namespace=None):
            """allow splitting of positional arguments"""
            args, argv = self.parse_known_args(args, namespace)
            if argv:
                for arg in argv:
                    if arg and arg[0] == '-':
                        lines = ['unrecognized arguments: %s' % (' '.join(argv))]
                        for k, v in sorted(self.extra_info.items()):
                            lines.append('  %s: %s' % (k, v))
                        self.error('\n'.join(lines))
                getattr(args, FILE_OR_DIR).extend(argv)
            return args

    class DropShorterLongHelpFormatter(argparse.HelpFormatter):
        """shorten help for long options that differ only in extra hyphens

        - collapse **long** options that are the same except for extra hyphens
        - special action attribute map_long_option allows surpressing additional
          long options
        - shortcut if there are only two options and one of them is a short one
        - cache result on action object as this is called at least 2 times
        """
        def _format_action_invocation(self, action):
            orgstr = argparse.HelpFormatter._format_action_invocation(self, action)
            if orgstr and orgstr[0] != '-': # only optional arguments
                return orgstr
            res = getattr(action, '_formatted_action_invocation', None)
            if res:
                return res
            options = orgstr.split(', ')
            if len(options) == 2 and (len(options[0]) == 2 or len(options[1]) == 2):
                # a shortcut for '-h, --help' or '--abc', '-a'
                action._formatted_action_invocation = orgstr
                return orgstr
            return_list = []
            option_map =  getattr(action, 'map_long_option', {})
            if option_map is None:
                option_map = {}
            short_long = {}
            for option in options:
                if len(option) == 2 or option[2] == ' ':
                    continue
                if not option.startswith('--'):
                    raise ArgumentError('long optional argument without "--": [%s]'
                                        % (option), self)
                xxoption = option[2:]
                if xxoption.split()[0] not in option_map:
                    shortened = xxoption.replace('-', '')
                    if shortened not in short_long or \
                       len(short_long[shortened]) < len(xxoption):
                        short_long[shortened] = xxoption
            # now short_long has been filled out to the longest with dashes
            # **and** we keep the right option ordering from add_argument
            for option in options: #
                if len(option) == 2 or option[2] == ' ':
                    return_list.append(option)
                if option[2:] == short_long.get(option.replace('-', '')):
                    return_list.append(option.replace(' ', '='))
            action._formatted_action_invocation = ', '.join(return_list)
            return action._formatted_action_invocation

    def _ensure_removed_sysmodule(modname):
        try:
            del sys.modules[modname]
        except KeyError:
            pass

    class CmdOptions(object):
        """ holds cmdline options as attributes."""
        def __init__(self, **kwargs):
            self.__dict__.update(kwargs)
        def __repr__(self):
            return "<CmdOptions %r>" %(self.__dict__,)

    class Notset:
        def __repr__(self):
            return "<NOTSET>"

    notset = Notset()
    FILE_OR_DIR = 'file_or_dir'

    class Config(object):
        """ access to configuration values, pluginmanager and plugin hooks.  """

        def __init__(self, pluginmanager):
            #: access to command line option as attributes.
            #: (deprecated), use :py:func:`getoption() <_pytest.config.Config.getoption>` instead
            self.option = CmdOptions()
            _a = FILE_OR_DIR
            self._parser = Parser(
                usage="%%(prog)s [options] [%s] [%s] [...]" % (_a, _a),
                processopt=self._processopt,
            )
            #: a pluginmanager instance
            self.pluginmanager = pluginmanager
            self.trace = self.pluginmanager.trace.root.get("config")
            self.hook = self.pluginmanager.hook
            self._inicache = {}
            self._opt2dest = {}
            self._cleanup = []
            self.pluginmanager.register(self, "pytestconfig")
            self._configured = False
            def do_setns(dic):
                import pytest
                setns(pytest, dic)
            self.hook.pytest_namespace.call_historic(do_setns, {})
            self.hook.pytest_addoption.call_historic(kwargs=dict(parser=self._parser))

        def add_cleanup(self, func):
            """ Add a function to be called when the config object gets out of
            use (usually coninciding with pytest_unconfigure)."""
            self._cleanup.append(func)

        def _do_configure(self):
            assert not self._configured
            self._configured = True
            self.hook.pytest_configure.call_historic(kwargs=dict(config=self))

        def _ensure_unconfigure(self):
            if self._configured:
                self._configured = False
                self.hook.pytest_unconfigure(config=self)
                self.hook.pytest_configure._call_history = []
            while self._cleanup:
                fin = self._cleanup.pop()
                fin()

        def warn(self, code, message, fslocation=None):
            """ generate a warning for this test session. """
            self.hook.pytest_logwarning(code=code, message=message,
                                        fslocation=fslocation, nodeid=None)

        def get_terminal_writer(self):
            return self.pluginmanager.get_plugin("terminalreporter")._tw

        def pytest_cmdline_parse(self, pluginmanager, args):
            # REF1 assert self == pluginmanager.config, (self, pluginmanager.config)
            self.parse(args)
            return self

        def notify_exception(self, excinfo, option=None):
            if option and option.fulltrace:
                style = "long"
            else:
                style = "native"
            excrepr = excinfo.getrepr(funcargs=True,
                showlocals=getattr(option, 'showlocals', False),
                style=style,
            )
            res = self.hook.pytest_internalerror(excrepr=excrepr,
                                                 excinfo=excinfo)
            if not py.builtin.any(res):
                for line in str(excrepr).split("\n"):
                    sys.stderr.write("INTERNALERROR> %s\n" %line)
                    sys.stderr.flush()

        def cwd_relative_nodeid(self, nodeid):
            # nodeid's are relative to the rootpath, compute relative to cwd
            if self.invocation_dir != self.rootdir:
                fullpath = self.rootdir.join(nodeid)
                nodeid = self.invocation_dir.bestrelpath(fullpath)
            return nodeid

        @classmethod
        def fromdictargs(cls, option_dict, args):
            """ constructor useable for subprocesses. """
            config = get_config()
            config._preparse(args, addopts=False)
            config.option.__dict__.update(option_dict)
            for x in config.option.plugins:
                config.pluginmanager.consider_pluginarg(x)
            return config

        def _processopt(self, opt):
            for name in opt._short_opts + opt._long_opts:
                self._opt2dest[name] = opt.dest

            if hasattr(opt, 'default') and opt.dest:
                if not hasattr(self.option, opt.dest):
                    setattr(self.option, opt.dest, opt.default)

        @hookimpl(trylast=True)
        def pytest_load_initial_conftests(self, early_config):
            self.pluginmanager._set_initial_conftests(early_config.known_args_namespace)

        def _initini(self, args):
            parsed_args, extra_args = self._parser.parse_known_args(args)
            r = determine_setup(parsed_args.inifilename,
                                parsed_args.file_or_dir + extra_args)
            self.rootdir, self.inifile, self.inicfg = r
            self._parser.extra_info['rootdir'] = self.rootdir
            self._parser.extra_info['inifile'] = self.inifile
            self.invocation_dir = py.path.local()
            self._parser.addini('addopts', 'extra command line options', 'args')
            self._parser.addini('minversion', 'minimally required pytest version')

        def _preparse(self, args, addopts=True):
            self._initini(args)
            if addopts:
                args[:] = shlex.split(os.environ.get('PYTEST_ADDOPTS', '')) + args
                args[:] = self.getini("addopts") + args
            self._checkversion()
            self.pluginmanager.consider_preparse(args)
            try:
                self.pluginmanager.load_setuptools_entrypoints("pytest11")
            except ImportError as e:
                self.warn("I2", "could not load setuptools entry import: %s" % (e,))
            self.pluginmanager.consider_env()
            ns, _ = self._parser.parse_known_args(args)
            self.known_args_namespace = ns
            if self.known_args_namespace.confcutdir is None and self.inifile:
                confcutdir = py.path.local(self.inifile).dirname
                self.known_args_namespace.confcutdir = confcutdir
            try:
                self.hook.pytest_load_initial_conftests(early_config=self,
                        args=args, parser=self._parser)
            except ConftestImportFailure:
                e = sys.exc_info()[1]
                if ns.help or ns.version:
                    # we don't want to prevent --help/--version to work
                    # so just let is pass and print a warning at the end
                    self.pluginmanager._warnings.append(
                            "could not load initial conftests (%s)\n" % e.path)
                else:
                    raise

        def _checkversion(self):
            import pytest
            minver = self.inicfg.get('minversion', None)
            if minver:
                ver = minver.split(".")
                myver = pytest.__version__.split(".")
                if myver < ver:
                    raise pytest.UsageError(
                        "%s:%d: requires pytest-%s, actual pytest-%s'" %(
                        self.inicfg.config.path, self.inicfg.lineof('minversion'),
                        minver, pytest.__version__))

        def parse(self, args):
            # parse given cmdline arguments into this config object.
            assert not hasattr(self, 'args'), (
                    "can only parse cmdline args at most once per Config object")
            self._origargs = args
            self.hook.pytest_addhooks.call_historic(
                                      kwargs=dict(pluginmanager=self.pluginmanager))
            self._preparse(args)
            # XXX deprecated hook:
            self.hook.pytest_cmdline_preparse(config=self, args=args)
            args = self._parser.parse_setoption(args, self.option)
            if not args:
                cwd = os.getcwd()
                if cwd == self.rootdir:
                    args = self.getini('testpaths')
                if not args:
                    args = [cwd]
            self.args = args

        def addinivalue_line(self, name, line):
            """ add a line to an ini-file option. The option must have been
            declared but might not yet be set in which case the line becomes the
            the first line in its value. """
            x = self.getini(name)
            assert isinstance(x, list)
            x.append(line) # modifies the cached list inline

        def getini(self, name):
            """ return configuration value from an :ref:`ini file <inifiles>`. If the
            specified name hasn't been registered through a prior
            :py:func:`parser.addini <pytest.config.Parser.addini>`
            call (usually from a plugin), a ValueError is raised. """
            try:
                return self._inicache[name]
            except KeyError:
                self._inicache[name] = val = self._getini(name)
                return val

        def _getini(self, name):
            try:
                description, type, default = self._parser._inidict[name]
            except KeyError:
                raise ValueError("unknown configuration value: %r" %(name,))
            try:
                value = self.inicfg[name]
            except KeyError:
                if default is not None:
                    return default
                if type is None:
                    return ''
                return []
            if type == "pathlist":
                dp = py.path.local(self.inicfg.config.path).dirpath()
                l = []
                for relpath in shlex.split(value):
                    l.append(dp.join(relpath, abs=True))
                return l
            elif type == "args":
                return shlex.split(value)
            elif type == "linelist":
                return [t for t in map(lambda x: x.strip(), value.split("\n")) if t]
            else:
                assert type is None
                return value

        def _getconftest_pathlist(self, name, path):
            try:
                mod, relroots = self.pluginmanager._rget_with_confmod(name, path)
            except KeyError:
                return None
            modpath = py.path.local(mod.__file__).dirpath()
            l = []
            for relroot in relroots:
                if not isinstance(relroot, py.path.local):
                    relroot = relroot.replace("/", py.path.local.sep)
                    relroot = modpath.join(relroot, abs=True)
                l.append(relroot)
            return l

        def getoption(self, name, default=notset, skip=False):
            """ return command line option value.

            :arg name: name of the option.  You may also specify
                the literal ``--OPT`` option instead of the "dest" option name.
            :arg default: default value if no option of that name exists.
            :arg skip: if True raise pytest.skip if option does not exists
                or has a None value.
            """
            name = self._opt2dest.get(name, name)
            try:
                val = getattr(self.option, name)
                if val is None and skip:
                    raise AttributeError(name)
                return val
            except AttributeError:
                if default is not notset:
                    return default
                if skip:
                    import pytest
                    pytest.skip("no %r option found" %(name,))
                raise ValueError("no option named %r" % (name,))

        def getvalue(self, name, path=None):
            """ (deprecated, use getoption()) """
            return self.getoption(name)

        def getvalueorskip(self, name, path=None):
            """ (deprecated, use getoption(skip=True)) """
            return self.getoption(name, skip=True)

    def exists(path, ignore=EnvironmentError):
        try:
            return path.check()
        except ignore:
            return False

    def getcfg(args, inibasenames):
        args = [x for x in args if not str(x).startswith("-")]
        if not args:
            args = [py.path.local()]
        for arg in args:
            arg = py.path.local(arg)
            for base in arg.parts(reverse=True):
                for inibasename in inibasenames:
                    p = base.join(inibasename)
                    if exists(p):
                        iniconfig = py.iniconfig.IniConfig(p)
                        if 'pytest' in iniconfig.sections:
                            return base, p, iniconfig['pytest']
                        elif inibasename == "pytest.ini":
                            # allowed to be empty
                            return base, p, {}
        return None, None, None

    def get_common_ancestor(args):
        # args are what we get after early command line parsing (usually
        # strings, but can be py.path.local objects as well)
        common_ancestor = None
        for arg in args:
            if str(arg)[0] == "-":
                continue
            p = py.path.local(arg)
            if common_ancestor is None:
                common_ancestor = p
            else:
                if p.relto(common_ancestor) or p == common_ancestor:
                    continue
                elif common_ancestor.relto(p):
                    common_ancestor = p
                else:
                    shared = p.common(common_ancestor)
                    if shared is not None:
                        common_ancestor = shared
        if common_ancestor is None:
            common_ancestor = py.path.local()
        elif not common_ancestor.isdir():
            common_ancestor = common_ancestor.dirpath()
        return common_ancestor

    def determine_setup(inifile, args):
        if inifile:
            iniconfig = py.iniconfig.IniConfig(inifile)
            try:
                inicfg = iniconfig["pytest"]
            except KeyError:
                inicfg = None
            rootdir = get_common_ancestor(args)
        else:
            ancestor = get_common_ancestor(args)
            rootdir, inifile, inicfg = getcfg(
                [ancestor], ["pytest.ini", "tox.ini", "setup.cfg"])
            if rootdir is None:
                for rootdir in ancestor.parts(reverse=True):
                    if rootdir.join("setup.py").exists():
                        break
                else:
                    rootdir = ancestor
        return rootdir, inifile, inicfg or {}

    def setns(obj, dic):
        import pytest
        for name, value in dic.items():
            if isinstance(value, dict):
                mod = getattr(obj, name, None)
                if mod is None:
                    modname = "pytest.%s" % name
                    mod = types.ModuleType(modname)
                    sys.modules[modname] = mod
                    mod.__all__ = []
                    setattr(obj, name, mod)
                obj.__all__.append(name)
                setns(mod, value)
            else:
                setattr(obj, name, value)
                obj.__all__.append(name)
                #if obj != pytest:
                #    pytest.__all__.append(name)
                setattr(pytest, name, value)

    def create_terminal_writer(config, *args, **kwargs):
        """Create a TerminalWriter instance configured according to the options
        in the config object. Every code which requires a TerminalWriter object
        and has access to a config object should use this function.
        """
        tw = py.io.TerminalWriter(*args, **kwargs)
        if config.option.color == 'yes':
            tw.hasmarkup = True
        if config.option.color == 'no':
            tw.hasmarkup = False
        return tw