1""" command line options, ini-file and conftest.py processing. """
2from __future__ import absolute_import, division, print_function
3import argparse
4import shlex
5import traceback
6import types
7import warnings
8
9import py
10# DON't import pytest here because it causes import cycle troubles
11import sys
12import os
13import _pytest._code
14import _pytest.hookspec  # the extension point definitions
15import _pytest.assertion
16from _pytest._pluggy import PluginManager, HookimplMarker, HookspecMarker
17from _pytest.compat import safe_str
18
19hookimpl = HookimplMarker("pytest")
20hookspec = HookspecMarker("pytest")
21
22# pytest startup
23#
24
25
26class ConftestImportFailure(Exception):
27    def __init__(self, path, excinfo):
28        Exception.__init__(self, path, excinfo)
29        self.path = path
30        self.excinfo = excinfo
31
32    def __str__(self):
33        etype, evalue, etb = self.excinfo
34        formatted = traceback.format_tb(etb)
35        # The level of the tracebacks we want to print is hand crafted :(
36        return repr(evalue) + '\n' + ''.join(formatted[2:])
37
38
39def main(args=None, plugins=None):
40    """ return exit code, after performing an in-process test run.
41
42    :arg args: list of command line arguments.
43
44    :arg plugins: list of plugin objects to be auto-registered during
45                  initialization.
46    """
47    try:
48        try:
49            config = _prepareconfig(args, plugins)
50        except ConftestImportFailure as e:
51            tw = py.io.TerminalWriter(sys.stderr)
52            for line in traceback.format_exception(*e.excinfo):
53                tw.line(line.rstrip(), red=True)
54            tw.line("ERROR: could not load %s\n" % (e.path), red=True)
55            return 4
56        else:
57            try:
58                return config.hook.pytest_cmdline_main(config=config)
59            finally:
60                config._ensure_unconfigure()
61    except UsageError as e:
62        for msg in e.args:
63            sys.stderr.write("ERROR: %s\n" %(msg,))
64        return 4
65
66class cmdline:  # compatibility namespace
67    main = staticmethod(main)
68
69
70class UsageError(Exception):
71    """ error in pytest usage or invocation"""
72
73
74class PrintHelp(Exception):
75    """Raised when pytest should print it's help to skip the rest of the
76    argument parsing and validation."""
77    pass
78
79
80def filename_arg(path, optname):
81    """ Argparse type validator for filename arguments.
82
83    :path: path of filename
84    :optname: name of the option
85    """
86    if os.path.isdir(path):
87        raise UsageError("{0} must be a filename, given: {1}".format(optname, path))
88    return path
89
90
91def directory_arg(path, optname):
92    """Argparse type validator for directory arguments.
93
94    :path: path of directory
95    :optname: name of the option
96    """
97    if not os.path.isdir(path):
98        raise UsageError("{0} must be a directory, given: {1}".format(optname, path))
99    return path
100
101
102_preinit = []
103
104default_plugins = (
105     "mark main terminal runner python fixtures debugging unittest capture skipping "
106     "tmpdir monkeypatch recwarn pastebin helpconfig nose assertion "
107     "junitxml resultlog doctest cacheprovider freeze_support "
108     "setuponly setupplan warnings").split()
109
110
111builtin_plugins = set(default_plugins)
112builtin_plugins.add("pytester")
113
114
115def _preloadplugins():
116    assert not _preinit
117    _preinit.append(get_config())
118
119def get_config():
120    if _preinit:
121        return _preinit.pop(0)
122    # subsequent calls to main will create a fresh instance
123    pluginmanager = PytestPluginManager()
124    config = Config(pluginmanager)
125    for spec in default_plugins:
126        pluginmanager.import_plugin(spec)
127    return config
128
129def get_plugin_manager():
130    """
131    Obtain a new instance of the
132    :py:class:`_pytest.config.PytestPluginManager`, with default plugins
133    already loaded.
134
135    This function can be used by integration with other tools, like hooking
136    into pytest to run tests into an IDE.
137    """
138    return get_config().pluginmanager
139
140def _prepareconfig(args=None, plugins=None):
141    warning = None
142    if args is None:
143        args = sys.argv[1:]
144    elif isinstance(args, py.path.local):
145        args = [str(args)]
146    elif not isinstance(args, (tuple, list)):
147        if not isinstance(args, str):
148            raise ValueError("not a string or argument list: %r" % (args,))
149        args = shlex.split(args, posix=sys.platform != "win32")
150        from _pytest import deprecated
151        warning = deprecated.MAIN_STR_ARGS
152    config = get_config()
153    pluginmanager = config.pluginmanager
154    try:
155        if plugins:
156            for plugin in plugins:
157                if isinstance(plugin, py.builtin._basestring):
158                    pluginmanager.consider_pluginarg(plugin)
159                else:
160                    pluginmanager.register(plugin)
161        if warning:
162            config.warn('C1', warning)
163        return pluginmanager.hook.pytest_cmdline_parse(
164                pluginmanager=pluginmanager, args=args)
165    except BaseException:
166        config._ensure_unconfigure()
167        raise
168
169
170class PytestPluginManager(PluginManager):
171    """
172    Overwrites :py:class:`pluggy.PluginManager <_pytest.vendored_packages.pluggy.PluginManager>` to add pytest-specific
173    functionality:
174
175    * loading plugins from the command line, ``PYTEST_PLUGIN`` env variable and
176      ``pytest_plugins`` global variables found in plugins being loaded;
177    * ``conftest.py`` loading during start-up;
178    """
179    def __init__(self):
180        super(PytestPluginManager, self).__init__("pytest", implprefix="pytest_")
181        self._conftest_plugins = set()
182
183        # state related to local conftest plugins
184        self._path2confmods = {}
185        self._conftestpath2mod = {}
186        self._confcutdir = None
187        self._noconftest = False
188        self._duplicatepaths = set()
189
190        self.add_hookspecs(_pytest.hookspec)
191        self.register(self)
192        if os.environ.get('PYTEST_DEBUG'):
193            err = sys.stderr
194            encoding = getattr(err, 'encoding', 'utf8')
195            try:
196                err = py.io.dupfile(err, encoding=encoding)
197            except Exception:
198                pass
199            self.trace.root.setwriter(err.write)
200            self.enable_tracing()
201
202        # Config._consider_importhook will set a real object if required.
203        self.rewrite_hook = _pytest.assertion.DummyRewriteHook()
204
205    def addhooks(self, module_or_class):
206        """
207        .. deprecated:: 2.8
208
209        Use :py:meth:`pluggy.PluginManager.add_hookspecs <_pytest.vendored_packages.pluggy.PluginManager.add_hookspecs>` instead.
210        """
211        warning = dict(code="I2",
212                       fslocation=_pytest._code.getfslineno(sys._getframe(1)),
213                       nodeid=None,
214                       message="use pluginmanager.add_hookspecs instead of "
215                               "deprecated addhooks() method.")
216        self._warn(warning)
217        return self.add_hookspecs(module_or_class)
218
219    def parse_hookimpl_opts(self, plugin, name):
220        # pytest hooks are always prefixed with pytest_
221        # so we avoid accessing possibly non-readable attributes
222        # (see issue #1073)
223        if not name.startswith("pytest_"):
224            return
225        # ignore some historic special names which can not be hooks anyway
226        if name == "pytest_plugins" or name.startswith("pytest_funcarg__"):
227            return
228
229        method = getattr(plugin, name)
230        opts = super(PytestPluginManager, self).parse_hookimpl_opts(plugin, name)
231        if opts is not None:
232            for name in ("tryfirst", "trylast", "optionalhook", "hookwrapper"):
233                opts.setdefault(name, hasattr(method, name))
234        return opts
235
236    def parse_hookspec_opts(self, module_or_class, name):
237        opts = super(PytestPluginManager, self).parse_hookspec_opts(
238                                                module_or_class, name)
239        if opts is None:
240            method = getattr(module_or_class, name)
241            if name.startswith("pytest_"):
242                opts = {"firstresult": hasattr(method, "firstresult"),
243                        "historic": hasattr(method, "historic")}
244        return opts
245
246    def _verify_hook(self, hook, hookmethod):
247        super(PytestPluginManager, self)._verify_hook(hook, hookmethod)
248        if "__multicall__" in hookmethod.argnames:
249            fslineno = _pytest._code.getfslineno(hookmethod.function)
250            warning = dict(code="I1",
251                           fslocation=fslineno,
252                           nodeid=None,
253                           message="%r hook uses deprecated __multicall__ "
254                                   "argument" % (hook.name))
255            self._warn(warning)
256
257    def register(self, plugin, name=None):
258        ret = super(PytestPluginManager, self).register(plugin, name)
259        if ret:
260            self.hook.pytest_plugin_registered.call_historic(
261                      kwargs=dict(plugin=plugin, manager=self))
262
263            if isinstance(plugin, types.ModuleType):
264                self.consider_module(plugin)
265        return ret
266
267    def getplugin(self, name):
268        # support deprecated naming because plugins (xdist e.g.) use it
269        return self.get_plugin(name)
270
271    def hasplugin(self, name):
272        """Return True if the plugin with the given name is registered."""
273        return bool(self.get_plugin(name))
274
275    def pytest_configure(self, config):
276        # XXX now that the pluginmanager exposes hookimpl(tryfirst...)
277        # we should remove tryfirst/trylast as markers
278        config.addinivalue_line("markers",
279            "tryfirst: mark a hook implementation function such that the "
280            "plugin machinery will try to call it first/as early as possible.")
281        config.addinivalue_line("markers",
282            "trylast: mark a hook implementation function such that the "
283            "plugin machinery will try to call it last/as late as possible.")
284
285    def _warn(self, message):
286        kwargs = message if isinstance(message, dict) else {
287            'code': 'I1',
288            'message': message,
289            'fslocation': None,
290            'nodeid': None,
291        }
292        self.hook.pytest_logwarning.call_historic(kwargs=kwargs)
293
294    #
295    # internal API for local conftest plugin handling
296    #
297    def _set_initial_conftests(self, namespace):
298        """ load initial conftest files given a preparsed "namespace".
299            As conftest files may add their own command line options
300            which have arguments ('--my-opt somepath') we might get some
301            false positives.  All builtin and 3rd party plugins will have
302            been loaded, however, so common options will not confuse our logic
303            here.
304        """
305        current = py.path.local()
306        self._confcutdir = current.join(namespace.confcutdir, abs=True) \
307                                if namespace.confcutdir else None
308        self._noconftest = namespace.noconftest
309        testpaths = namespace.file_or_dir
310        foundanchor = False
311        for path in testpaths:
312            path = str(path)
313            # remove node-id syntax
314            i = path.find("::")
315            if i != -1:
316                path = path[:i]
317            anchor = current.join(path, abs=1)
318            if exists(anchor): # we found some file object
319                self._try_load_conftest(anchor)
320                foundanchor = True
321        if not foundanchor:
322            self._try_load_conftest(current)
323
324    def _try_load_conftest(self, anchor):
325        self._getconftestmodules(anchor)
326        # let's also consider test* subdirs
327        if anchor.check(dir=1):
328            for x in anchor.listdir("test*"):
329                if x.check(dir=1):
330                    self._getconftestmodules(x)
331
332    def _getconftestmodules(self, path):
333        if self._noconftest:
334            return []
335        try:
336            return self._path2confmods[path]
337        except KeyError:
338            if path.isfile():
339                clist = self._getconftestmodules(path.dirpath())
340            else:
341                # XXX these days we may rather want to use config.rootdir
342                # and allow users to opt into looking into the rootdir parent
343                # directories instead of requiring to specify confcutdir
344                clist = []
345                for parent in path.parts():
346                    if self._confcutdir and self._confcutdir.relto(parent):
347                        continue
348                    conftestpath = parent.join("conftest.py")
349                    if conftestpath.isfile():
350                        mod = self._importconftest(conftestpath)
351                        clist.append(mod)
352
353            self._path2confmods[path] = clist
354            return clist
355
356    def _rget_with_confmod(self, name, path):
357        modules = self._getconftestmodules(path)
358        for mod in reversed(modules):
359            try:
360                return mod, getattr(mod, name)
361            except AttributeError:
362                continue
363        raise KeyError(name)
364
365    def _importconftest(self, conftestpath):
366        try:
367            return self._conftestpath2mod[conftestpath]
368        except KeyError:
369            pkgpath = conftestpath.pypkgpath()
370            if pkgpath is None:
371                _ensure_removed_sysmodule(conftestpath.purebasename)
372            try:
373                mod = conftestpath.pyimport()
374            except Exception:
375                raise ConftestImportFailure(conftestpath, sys.exc_info())
376
377            self._conftest_plugins.add(mod)
378            self._conftestpath2mod[conftestpath] = mod
379            dirpath = conftestpath.dirpath()
380            if dirpath in self._path2confmods:
381                for path, mods in self._path2confmods.items():
382                    if path and path.relto(dirpath) or path == dirpath:
383                        assert mod not in mods
384                        mods.append(mod)
385            self.trace("loaded conftestmodule %r" %(mod))
386            self.consider_conftest(mod)
387            return mod
388
389    #
390    # API for bootstrapping plugin loading
391    #
392    #
393
394    def consider_preparse(self, args):
395        for opt1,opt2 in zip(args, args[1:]):
396            if opt1 == "-p":
397                self.consider_pluginarg(opt2)
398
399    def consider_pluginarg(self, arg):
400        if arg.startswith("no:"):
401            name = arg[3:]
402            self.set_blocked(name)
403            if not name.startswith("pytest_"):
404                self.set_blocked("pytest_" + name)
405        else:
406            self.import_plugin(arg)
407
408    def consider_conftest(self, conftestmodule):
409        self.register(conftestmodule, name=conftestmodule.__file__)
410
411    def consider_env(self):
412        self._import_plugin_specs(os.environ.get("PYTEST_PLUGINS"))
413
414    def consider_module(self, mod):
415        self._import_plugin_specs(getattr(mod, 'pytest_plugins', []))
416
417    def _import_plugin_specs(self, spec):
418        plugins = _get_plugin_specs_as_list(spec)
419        for import_spec in plugins:
420            self.import_plugin(import_spec)
421
422    def import_plugin(self, modname):
423        # most often modname refers to builtin modules, e.g. "pytester",
424        # "terminal" or "capture".  Those plugins are registered under their
425        # basename for historic purposes but must be imported with the
426        # _pytest prefix.
427        assert isinstance(modname, (py.builtin.text, str)), "module name as text required, got %r" % modname
428        modname = str(modname)
429        if self.get_plugin(modname) is not None:
430            return
431        if modname in builtin_plugins:
432            importspec = "_pytest." + modname
433        else:
434            importspec = modname
435        self.rewrite_hook.mark_rewrite(importspec)
436        try:
437            __import__(importspec)
438        except ImportError as e:
439            new_exc = ImportError('Error importing plugin "%s": %s' % (modname, safe_str(e.args[0])))
440            # copy over name and path attributes
441            for attr in ('name', 'path'):
442                if hasattr(e, attr):
443                    setattr(new_exc, attr, getattr(e, attr))
444            raise new_exc
445        except Exception as e:
446            import pytest
447            if not hasattr(pytest, 'skip') or not isinstance(e, pytest.skip.Exception):
448                raise
449            self._warn("skipped plugin %r: %s" %((modname, e.msg)))
450        else:
451            mod = sys.modules[importspec]
452            self.register(mod, modname)
453
454
455def _get_plugin_specs_as_list(specs):
456    """
457    Parses a list of "plugin specs" and returns a list of plugin names.
458
459    Plugin specs can be given as a list of strings separated by "," or already as a list/tuple in
460    which case it is returned as a list. Specs can also be `None` in which case an
461    empty list is returned.
462    """
463    if specs is not None:
464        if isinstance(specs, str):
465            specs = specs.split(',') if specs else []
466        if not isinstance(specs, (list, tuple)):
467            raise UsageError("Plugin specs must be a ','-separated string or a "
468                             "list/tuple of strings for plugin names. Given: %r" % specs)
469        return list(specs)
470    return []
471
472
473class Parser:
474    """ Parser for command line arguments and ini-file values.
475
476    :ivar extra_info: dict of generic param -> value to display in case
477        there's an error processing the command line arguments.
478    """
479
480    def __init__(self, usage=None, processopt=None):
481        self._anonymous = OptionGroup("custom options", parser=self)
482        self._groups = []
483        self._processopt = processopt
484        self._usage = usage
485        self._inidict = {}
486        self._ininames = []
487        self.extra_info = {}
488
489    def processoption(self, option):
490        if self._processopt:
491            if option.dest:
492                self._processopt(option)
493
494    def getgroup(self, name, description="", after=None):
495        """ get (or create) a named option Group.
496
497        :name: name of the option group.
498        :description: long description for --help output.
499        :after: name of other group, used for ordering --help output.
500
501        The returned group object has an ``addoption`` method with the same
502        signature as :py:func:`parser.addoption
503        <_pytest.config.Parser.addoption>` but will be shown in the
504        respective group in the output of ``pytest. --help``.
505        """
506        for group in self._groups:
507            if group.name == name:
508                return group
509        group = OptionGroup(name, description, parser=self)
510        i = 0
511        for i, grp in enumerate(self._groups):
512            if grp.name == after:
513                break
514        self._groups.insert(i+1, group)
515        return group
516
517    def addoption(self, *opts, **attrs):
518        """ register a command line option.
519
520        :opts: option names, can be short or long options.
521        :attrs: same attributes which the ``add_option()`` function of the
522           `argparse library
523           <http://docs.python.org/2/library/argparse.html>`_
524           accepts.
525
526        After command line parsing options are available on the pytest config
527        object via ``config.option.NAME`` where ``NAME`` is usually set
528        by passing a ``dest`` attribute, for example
529        ``addoption("--long", dest="NAME", ...)``.
530        """
531        self._anonymous.addoption(*opts, **attrs)
532
533    def parse(self, args, namespace=None):
534        from _pytest._argcomplete import try_argcomplete
535        self.optparser = self._getparser()
536        try_argcomplete(self.optparser)
537        return self.optparser.parse_args([str(x) for x in args], namespace=namespace)
538
539    def _getparser(self):
540        from _pytest._argcomplete import filescompleter
541        optparser = MyOptionParser(self, self.extra_info)
542        groups = self._groups + [self._anonymous]
543        for group in groups:
544            if group.options:
545                desc = group.description or group.name
546                arggroup = optparser.add_argument_group(desc)
547                for option in group.options:
548                    n = option.names()
549                    a = option.attrs()
550                    arggroup.add_argument(*n, **a)
551        # bash like autocompletion for dirs (appending '/')
552        optparser.add_argument(FILE_OR_DIR, nargs='*').completer=filescompleter
553        return optparser
554
555    def parse_setoption(self, args, option, namespace=None):
556        parsedoption = self.parse(args, namespace=namespace)
557        for name, value in parsedoption.__dict__.items():
558            setattr(option, name, value)
559        return getattr(parsedoption, FILE_OR_DIR)
560
561    def parse_known_args(self, args, namespace=None):
562        """parses and returns a namespace object with known arguments at this
563        point.
564        """
565        return self.parse_known_and_unknown_args(args, namespace=namespace)[0]
566
567    def parse_known_and_unknown_args(self, args, namespace=None):
568        """parses and returns a namespace object with known arguments, and
569        the remaining arguments unknown at this point.
570        """
571        optparser = self._getparser()
572        args = [str(x) for x in args]
573        return optparser.parse_known_args(args, namespace=namespace)
574
575    def addini(self, name, help, type=None, default=None):
576        """ register an ini-file option.
577
578        :name: name of the ini-variable
579        :type: type of the variable, can be ``pathlist``, ``args``, ``linelist``
580               or ``bool``.
581        :default: default value if no ini-file option exists but is queried.
582
583        The value of ini-variables can be retrieved via a call to
584        :py:func:`config.getini(name) <_pytest.config.Config.getini>`.
585        """
586        assert type in (None, "pathlist", "args", "linelist", "bool")
587        self._inidict[name] = (help, type, default)
588        self._ininames.append(name)
589
590
591class ArgumentError(Exception):
592    """
593    Raised if an Argument instance is created with invalid or
594    inconsistent arguments.
595    """
596
597    def __init__(self, msg, option):
598        self.msg = msg
599        self.option_id = str(option)
600
601    def __str__(self):
602        if self.option_id:
603            return "option %s: %s" % (self.option_id, self.msg)
604        else:
605            return self.msg
606
607
608class Argument:
609    """class that mimics the necessary behaviour of optparse.Option
610
611    its currently a least effort implementation
612    and ignoring choices and integer prefixes
613    https://docs.python.org/3/library/optparse.html#optparse-standard-option-types
614    """
615    _typ_map = {
616        'int': int,
617        'string': str,
618        'float': float,
619        'complex': complex,
620    }
621
622    def __init__(self, *names, **attrs):
623        """store parms in private vars for use in add_argument"""
624        self._attrs = attrs
625        self._short_opts = []
626        self._long_opts = []
627        self.dest = attrs.get('dest')
628        if '%default' in (attrs.get('help') or ''):
629            warnings.warn(
630                'pytest now uses argparse. "%default" should be'
631                ' changed to "%(default)s" ',
632                DeprecationWarning,
633                stacklevel=3)
634        try:
635            typ = attrs['type']
636        except KeyError:
637            pass
638        else:
639            # this might raise a keyerror as well, don't want to catch that
640            if isinstance(typ, py.builtin._basestring):
641                if typ == 'choice':
642                    warnings.warn(
643                        'type argument to addoption() is a string %r.'
644                        ' For parsearg this is optional and when supplied'
645                        ' should be a type.'
646                        ' (options: %s)' % (typ, names),
647                        DeprecationWarning,
648                        stacklevel=3)
649                    # argparse expects a type here take it from
650                    # the type of the first element
651                    attrs['type'] = type(attrs['choices'][0])
652                else:
653                    warnings.warn(
654                        'type argument to addoption() is a string %r.'
655                        ' For parsearg this should be a type.'
656                        ' (options: %s)' % (typ, names),
657                        DeprecationWarning,
658                        stacklevel=3)
659                    attrs['type'] = Argument._typ_map[typ]
660                # used in test_parseopt -> test_parse_defaultgetter
661                self.type = attrs['type']
662            else:
663                self.type = typ
664        try:
665            # attribute existence is tested in Config._processopt
666            self.default = attrs['default']
667        except KeyError:
668            pass
669        self._set_opt_strings(names)
670        if not self.dest:
671            if self._long_opts:
672                self.dest = self._long_opts[0][2:].replace('-', '_')
673            else:
674                try:
675                    self.dest = self._short_opts[0][1:]
676                except IndexError:
677                    raise ArgumentError(
678                        'need a long or short option', self)
679
680    def names(self):
681        return self._short_opts + self._long_opts
682
683    def attrs(self):
684        # update any attributes set by processopt
685        attrs = 'default dest help'.split()
686        if self.dest:
687            attrs.append(self.dest)
688        for attr in attrs:
689            try:
690                self._attrs[attr] = getattr(self, attr)
691            except AttributeError:
692                pass
693        if self._attrs.get('help'):
694            a = self._attrs['help']
695            a = a.replace('%default', '%(default)s')
696            #a = a.replace('%prog', '%(prog)s')
697            self._attrs['help'] = a
698        return self._attrs
699
700    def _set_opt_strings(self, opts):
701        """directly from optparse
702
703        might not be necessary as this is passed to argparse later on"""
704        for opt in opts:
705            if len(opt) < 2:
706                raise ArgumentError(
707                    "invalid option string %r: "
708                    "must be at least two characters long" % opt, self)
709            elif len(opt) == 2:
710                if not (opt[0] == "-" and opt[1] != "-"):
711                    raise ArgumentError(
712                        "invalid short option string %r: "
713                        "must be of the form -x, (x any non-dash char)" % opt,
714                        self)
715                self._short_opts.append(opt)
716            else:
717                if not (opt[0:2] == "--" and opt[2] != "-"):
718                    raise ArgumentError(
719                        "invalid long option string %r: "
720                        "must start with --, followed by non-dash" % opt,
721                        self)
722                self._long_opts.append(opt)
723
724    def __repr__(self):
725        args = []
726        if self._short_opts:
727            args += ['_short_opts: ' + repr(self._short_opts)]
728        if self._long_opts:
729            args += ['_long_opts: ' + repr(self._long_opts)]
730        args += ['dest: ' + repr(self.dest)]
731        if hasattr(self, 'type'):
732            args += ['type: ' + repr(self.type)]
733        if hasattr(self, 'default'):
734            args += ['default: ' + repr(self.default)]
735        return 'Argument({0})'.format(', '.join(args))
736
737
738class OptionGroup:
739    def __init__(self, name, description="", parser=None):
740        self.name = name
741        self.description = description
742        self.options = []
743        self.parser = parser
744
745    def addoption(self, *optnames, **attrs):
746        """ add an option to this group.
747
748        if a shortened version of a long option is specified it will
749        be suppressed in the help. addoption('--twowords', '--two-words')
750        results in help showing '--two-words' only, but --twowords gets
751        accepted **and** the automatic destination is in args.twowords
752        """
753        conflict = set(optnames).intersection(
754            name for opt in self.options for name in opt.names())
755        if conflict:
756            raise ValueError("option names %s already added" % conflict)
757        option = Argument(*optnames, **attrs)
758        self._addoption_instance(option, shortupper=False)
759
760    def _addoption(self, *optnames, **attrs):
761        option = Argument(*optnames, **attrs)
762        self._addoption_instance(option, shortupper=True)
763
764    def _addoption_instance(self, option, shortupper=False):
765        if not shortupper:
766            for opt in option._short_opts:
767                if opt[0] == '-' and opt[1].islower():
768                    raise ValueError("lowercase shortoptions reserved")
769        if self.parser:
770            self.parser.processoption(option)
771        self.options.append(option)
772
773
774class MyOptionParser(argparse.ArgumentParser):
775    def __init__(self, parser, extra_info=None):
776        if not extra_info:
777            extra_info = {}
778        self._parser = parser
779        argparse.ArgumentParser.__init__(self, usage=parser._usage,
780            add_help=False, formatter_class=DropShorterLongHelpFormatter)
781        # extra_info is a dict of (param -> value) to display if there's
782        # an usage error to provide more contextual information to the user
783        self.extra_info = extra_info
784
785    def parse_args(self, args=None, namespace=None):
786        """allow splitting of positional arguments"""
787        args, argv = self.parse_known_args(args, namespace)
788        if argv:
789            for arg in argv:
790                if arg and arg[0] == '-':
791                    lines = ['unrecognized arguments: %s' % (' '.join(argv))]
792                    for k, v in sorted(self.extra_info.items()):
793                        lines.append('  %s: %s' % (k, v))
794                    self.error('\n'.join(lines))
795            getattr(args, FILE_OR_DIR).extend(argv)
796        return args
797
798
799class DropShorterLongHelpFormatter(argparse.HelpFormatter):
800    """shorten help for long options that differ only in extra hyphens
801
802    - collapse **long** options that are the same except for extra hyphens
803    - special action attribute map_long_option allows surpressing additional
804      long options
805    - shortcut if there are only two options and one of them is a short one
806    - cache result on action object as this is called at least 2 times
807    """
808    def _format_action_invocation(self, action):
809        orgstr = argparse.HelpFormatter._format_action_invocation(self, action)
810        if orgstr and orgstr[0] != '-': # only optional arguments
811            return orgstr
812        res = getattr(action, '_formatted_action_invocation', None)
813        if res:
814            return res
815        options = orgstr.split(', ')
816        if len(options) == 2 and (len(options[0]) == 2 or len(options[1]) == 2):
817            # a shortcut for '-h, --help' or '--abc', '-a'
818            action._formatted_action_invocation = orgstr
819            return orgstr
820        return_list = []
821        option_map =  getattr(action, 'map_long_option', {})
822        if option_map is None:
823            option_map = {}
824        short_long = {}
825        for option in options:
826            if len(option) == 2 or option[2] == ' ':
827                continue
828            if not option.startswith('--'):
829                raise ArgumentError('long optional argument without "--": [%s]'
830                                    % (option), self)
831            xxoption = option[2:]
832            if xxoption.split()[0] not in option_map:
833                shortened = xxoption.replace('-', '')
834                if shortened not in short_long or \
835                   len(short_long[shortened]) < len(xxoption):
836                    short_long[shortened] = xxoption
837        # now short_long has been filled out to the longest with dashes
838        # **and** we keep the right option ordering from add_argument
839        for option in options: #
840            if len(option) == 2 or option[2] == ' ':
841                return_list.append(option)
842            if option[2:] == short_long.get(option.replace('-', '')):
843                return_list.append(option.replace(' ', '=', 1))
844        action._formatted_action_invocation = ', '.join(return_list)
845        return action._formatted_action_invocation
846
847
848
849def _ensure_removed_sysmodule(modname):
850    try:
851        del sys.modules[modname]
852    except KeyError:
853        pass
854
855class CmdOptions(object):
856    """ holds cmdline options as attributes."""
857    def __init__(self, values=()):
858        self.__dict__.update(values)
859    def __repr__(self):
860        return "<CmdOptions %r>" %(self.__dict__,)
861    def copy(self):
862        return CmdOptions(self.__dict__)
863
864class Notset:
865    def __repr__(self):
866        return "<NOTSET>"
867
868
869notset = Notset()
870FILE_OR_DIR = 'file_or_dir'
871
872
873class Config(object):
874    """ access to configuration values, pluginmanager and plugin hooks.  """
875
876    def __init__(self, pluginmanager):
877        #: access to command line option as attributes.
878        #: (deprecated), use :py:func:`getoption() <_pytest.config.Config.getoption>` instead
879        self.option = CmdOptions()
880        _a = FILE_OR_DIR
881        self._parser = Parser(
882            usage="%%(prog)s [options] [%s] [%s] [...]" % (_a, _a),
883            processopt=self._processopt,
884        )
885        #: a pluginmanager instance
886        self.pluginmanager = pluginmanager
887        self.trace = self.pluginmanager.trace.root.get("config")
888        self.hook = self.pluginmanager.hook
889        self._inicache = {}
890        self._override_ini = ()
891        self._opt2dest = {}
892        self._cleanup = []
893        self._warn = self.pluginmanager._warn
894        self.pluginmanager.register(self, "pytestconfig")
895        self._configured = False
896
897        def do_setns(dic):
898            import pytest
899            setns(pytest, dic)
900
901        self.hook.pytest_namespace.call_historic(do_setns, {})
902        self.hook.pytest_addoption.call_historic(kwargs=dict(parser=self._parser))
903
904    def add_cleanup(self, func):
905        """ Add a function to be called when the config object gets out of
906        use (usually coninciding with pytest_unconfigure)."""
907        self._cleanup.append(func)
908
909    def _do_configure(self):
910        assert not self._configured
911        self._configured = True
912        self.hook.pytest_configure.call_historic(kwargs=dict(config=self))
913
914    def _ensure_unconfigure(self):
915        if self._configured:
916            self._configured = False
917            self.hook.pytest_unconfigure(config=self)
918            self.hook.pytest_configure._call_history = []
919        while self._cleanup:
920            fin = self._cleanup.pop()
921            fin()
922
923    def warn(self, code, message, fslocation=None, nodeid=None):
924        """ generate a warning for this test session. """
925        self.hook.pytest_logwarning.call_historic(kwargs=dict(
926            code=code, message=message,
927            fslocation=fslocation, nodeid=nodeid))
928
929    def get_terminal_writer(self):
930        return self.pluginmanager.get_plugin("terminalreporter")._tw
931
932    def pytest_cmdline_parse(self, pluginmanager, args):
933        # REF1 assert self == pluginmanager.config, (self, pluginmanager.config)
934        self.parse(args)
935        return self
936
937    def notify_exception(self, excinfo, option=None):
938        if option and option.fulltrace:
939            style = "long"
940        else:
941            style = "native"
942        excrepr = excinfo.getrepr(funcargs=True,
943            showlocals=getattr(option, 'showlocals', False),
944            style=style,
945        )
946        res = self.hook.pytest_internalerror(excrepr=excrepr,
947                                             excinfo=excinfo)
948        if not py.builtin.any(res):
949            for line in str(excrepr).split("\n"):
950                sys.stderr.write("INTERNALERROR> %s\n" %line)
951                sys.stderr.flush()
952
953    def cwd_relative_nodeid(self, nodeid):
954        # nodeid's are relative to the rootpath, compute relative to cwd
955        if self.invocation_dir != self.rootdir:
956            fullpath = self.rootdir.join(nodeid)
957            nodeid = self.invocation_dir.bestrelpath(fullpath)
958        return nodeid
959
960    @classmethod
961    def fromdictargs(cls, option_dict, args):
962        """ constructor useable for subprocesses. """
963        config = get_config()
964        config.option.__dict__.update(option_dict)
965        config.parse(args, addopts=False)
966        for x in config.option.plugins:
967            config.pluginmanager.consider_pluginarg(x)
968        return config
969
970    def _processopt(self, opt):
971        for name in opt._short_opts + opt._long_opts:
972            self._opt2dest[name] = opt.dest
973
974        if hasattr(opt, 'default') and opt.dest:
975            if not hasattr(self.option, opt.dest):
976                setattr(self.option, opt.dest, opt.default)
977
978    @hookimpl(trylast=True)
979    def pytest_load_initial_conftests(self, early_config):
980        self.pluginmanager._set_initial_conftests(early_config.known_args_namespace)
981
982    def _initini(self, args):
983        ns, unknown_args = self._parser.parse_known_and_unknown_args(args, namespace=self.option.copy())
984        r = determine_setup(ns.inifilename, ns.file_or_dir + unknown_args, warnfunc=self.warn)
985        self.rootdir, self.inifile, self.inicfg = r
986        self._parser.extra_info['rootdir'] = self.rootdir
987        self._parser.extra_info['inifile'] = self.inifile
988        self.invocation_dir = py.path.local()
989        self._parser.addini('addopts', 'extra command line options', 'args')
990        self._parser.addini('minversion', 'minimally required pytest version')
991        self._override_ini = ns.override_ini or ()
992
993    def _consider_importhook(self, args):
994        """Install the PEP 302 import hook if using assertion re-writing.
995
996        Needs to parse the --assert=<mode> option from the commandline
997        and find all the installed plugins to mark them for re-writing
998        by the importhook.
999        """
1000        ns, unknown_args = self._parser.parse_known_and_unknown_args(args)
1001        mode = ns.assertmode
1002        if mode == 'rewrite':
1003            try:
1004                hook = _pytest.assertion.install_importhook(self)
1005            except SystemError:
1006                mode = 'plain'
1007            else:
1008                self._mark_plugins_for_rewrite(hook)
1009        self._warn_about_missing_assertion(mode)
1010
1011    def _mark_plugins_for_rewrite(self, hook):
1012        """
1013        Given an importhook, mark for rewrite any top-level
1014        modules or packages in the distribution package for
1015        all pytest plugins.
1016        """
1017        import pkg_resources
1018        self.pluginmanager.rewrite_hook = hook
1019
1020        # 'RECORD' available for plugins installed normally (pip install)
1021        # 'SOURCES.txt' available for plugins installed in dev mode (pip install -e)
1022        # for installed plugins 'SOURCES.txt' returns an empty list, and vice-versa
1023        # so it shouldn't be an issue
1024        metadata_files = 'RECORD', 'SOURCES.txt'
1025
1026        package_files = (
1027            entry.split(',')[0]
1028            for entrypoint in pkg_resources.iter_entry_points('pytest11')
1029            for metadata in metadata_files
1030            for entry in entrypoint.dist._get_metadata(metadata)
1031        )
1032
1033        for fn in package_files:
1034            is_simple_module = os.sep not in fn and fn.endswith('.py')
1035            is_package = fn.count(os.sep) == 1 and fn.endswith('__init__.py')
1036            if is_simple_module:
1037                module_name, ext = os.path.splitext(fn)
1038                hook.mark_rewrite(module_name)
1039            elif is_package:
1040                package_name = os.path.dirname(fn)
1041                hook.mark_rewrite(package_name)
1042
1043    def _warn_about_missing_assertion(self, mode):
1044        try:
1045            assert False
1046        except AssertionError:
1047            pass
1048        else:
1049            if mode == 'plain':
1050                sys.stderr.write("WARNING: ASSERTIONS ARE NOT EXECUTED"
1051                                 " and FAILING TESTS WILL PASS.  Are you"
1052                                 " using python -O?")
1053            else:
1054                sys.stderr.write("WARNING: assertions not in test modules or"
1055                                 " plugins will be ignored"
1056                                 " because assert statements are not executed "
1057                                 "by the underlying Python interpreter "
1058                                 "(are you using python -O?)\n")
1059
1060    def _preparse(self, args, addopts=True):
1061        self._initini(args)
1062        if addopts:
1063            args[:] = shlex.split(os.environ.get('PYTEST_ADDOPTS', '')) + args
1064            args[:] = self.getini("addopts") + args
1065        self._checkversion()
1066        self._consider_importhook(args)
1067        self.pluginmanager.consider_preparse(args)
1068        self.pluginmanager.load_setuptools_entrypoints('pytest11')
1069        self.pluginmanager.consider_env()
1070        self.known_args_namespace = ns = self._parser.parse_known_args(args, namespace=self.option.copy())
1071        confcutdir = self.known_args_namespace.confcutdir
1072        if self.known_args_namespace.confcutdir is None and self.inifile:
1073            confcutdir = py.path.local(self.inifile).dirname
1074            self.known_args_namespace.confcutdir = confcutdir
1075        try:
1076            self.hook.pytest_load_initial_conftests(early_config=self,
1077                    args=args, parser=self._parser)
1078        except ConftestImportFailure:
1079            e = sys.exc_info()[1]
1080            if ns.help or ns.version:
1081                # we don't want to prevent --help/--version to work
1082                # so just let is pass and print a warning at the end
1083                self._warn("could not load initial conftests (%s)\n" % e.path)
1084            else:
1085                raise
1086
1087    def _checkversion(self):
1088        import pytest
1089        minver = self.inicfg.get('minversion', None)
1090        if minver:
1091            ver = minver.split(".")
1092            myver = pytest.__version__.split(".")
1093            if myver < ver:
1094                raise pytest.UsageError(
1095                    "%s:%d: requires pytest-%s, actual pytest-%s'" %(
1096                    self.inicfg.config.path, self.inicfg.lineof('minversion'),
1097                    minver, pytest.__version__))
1098
1099    def parse(self, args, addopts=True):
1100        # parse given cmdline arguments into this config object.
1101        assert not hasattr(self, 'args'), (
1102                "can only parse cmdline args at most once per Config object")
1103        self._origargs = args
1104        self.hook.pytest_addhooks.call_historic(
1105                                  kwargs=dict(pluginmanager=self.pluginmanager))
1106        self._preparse(args, addopts=addopts)
1107        # XXX deprecated hook:
1108        self.hook.pytest_cmdline_preparse(config=self, args=args)
1109        self._parser.after_preparse = True
1110        try:
1111            args = self._parser.parse_setoption(args, self.option, namespace=self.option)
1112            if not args:
1113                cwd = os.getcwd()
1114                if cwd == self.rootdir:
1115                    args = self.getini('testpaths')
1116                if not args:
1117                    args = [cwd]
1118            self.args = args
1119        except PrintHelp:
1120            pass
1121
1122    def addinivalue_line(self, name, line):
1123        """ add a line to an ini-file option. The option must have been
1124        declared but might not yet be set in which case the line becomes the
1125        the first line in its value. """
1126        x = self.getini(name)
1127        assert isinstance(x, list)
1128        x.append(line) # modifies the cached list inline
1129
1130    def getini(self, name):
1131        """ return configuration value from an :ref:`ini file <inifiles>`. If the
1132        specified name hasn't been registered through a prior
1133        :py:func:`parser.addini <_pytest.config.Parser.addini>`
1134        call (usually from a plugin), a ValueError is raised. """
1135        try:
1136            return self._inicache[name]
1137        except KeyError:
1138            self._inicache[name] = val = self._getini(name)
1139            return val
1140
1141    def _getini(self, name):
1142        try:
1143            description, type, default = self._parser._inidict[name]
1144        except KeyError:
1145            raise ValueError("unknown configuration value: %r" %(name,))
1146        value = self._get_override_ini_value(name)
1147        if value is None:
1148            try:
1149                value = self.inicfg[name]
1150            except KeyError:
1151                if default is not None:
1152                    return default
1153                if type is None:
1154                    return ''
1155                return []
1156        if type == "pathlist":
1157            dp = py.path.local(self.inicfg.config.path).dirpath()
1158            l = []
1159            for relpath in shlex.split(value):
1160                l.append(dp.join(relpath, abs=True))
1161            return l
1162        elif type == "args":
1163            return shlex.split(value)
1164        elif type == "linelist":
1165            return [t for t in map(lambda x: x.strip(), value.split("\n")) if t]
1166        elif type == "bool":
1167            return bool(_strtobool(value.strip()))
1168        else:
1169            assert type is None
1170            return value
1171
1172    def _getconftest_pathlist(self, name, path):
1173        try:
1174            mod, relroots = self.pluginmanager._rget_with_confmod(name, path)
1175        except KeyError:
1176            return None
1177        modpath = py.path.local(mod.__file__).dirpath()
1178        l = []
1179        for relroot in relroots:
1180            if not isinstance(relroot, py.path.local):
1181                relroot = relroot.replace("/", py.path.local.sep)
1182                relroot = modpath.join(relroot, abs=True)
1183            l.append(relroot)
1184        return l
1185
1186    def _get_override_ini_value(self, name):
1187        value = None
1188        # override_ini is a list of list, to support both -o foo1=bar1 foo2=bar2 and
1189        # and -o foo1=bar1 -o foo2=bar2 options
1190        # always use the last item if multiple value set for same ini-name,
1191        # e.g. -o foo=bar1 -o foo=bar2 will set foo to bar2
1192        for ini_config_list in self._override_ini:
1193            for ini_config in ini_config_list:
1194                try:
1195                    (key, user_ini_value) = ini_config.split("=", 1)
1196                except ValueError:
1197                    raise UsageError("-o/--override-ini expects option=value style.")
1198                if key == name:
1199                    value = user_ini_value
1200        return value
1201
1202    def getoption(self, name, default=notset, skip=False):
1203        """ return command line option value.
1204
1205        :arg name: name of the option.  You may also specify
1206            the literal ``--OPT`` option instead of the "dest" option name.
1207        :arg default: default value if no option of that name exists.
1208        :arg skip: if True raise pytest.skip if option does not exists
1209            or has a None value.
1210        """
1211        name = self._opt2dest.get(name, name)
1212        try:
1213            val = getattr(self.option, name)
1214            if val is None and skip:
1215                raise AttributeError(name)
1216            return val
1217        except AttributeError:
1218            if default is not notset:
1219                return default
1220            if skip:
1221                import pytest
1222                pytest.skip("no %r option found" %(name,))
1223            raise ValueError("no option named %r" % (name,))
1224
1225    def getvalue(self, name, path=None):
1226        """ (deprecated, use getoption()) """
1227        return self.getoption(name)
1228
1229    def getvalueorskip(self, name, path=None):
1230        """ (deprecated, use getoption(skip=True)) """
1231        return self.getoption(name, skip=True)
1232
1233def exists(path, ignore=EnvironmentError):
1234    try:
1235        return path.check()
1236    except ignore:
1237        return False
1238
1239def getcfg(args, warnfunc=None):
1240    """
1241    Search the list of arguments for a valid ini-file for pytest,
1242    and return a tuple of (rootdir, inifile, cfg-dict).
1243
1244    note: warnfunc is an optional function used to warn
1245        about ini-files that use deprecated features.
1246        This parameter should be removed when pytest
1247        adopts standard deprecation warnings (#1804).
1248    """
1249    from _pytest.deprecated import SETUP_CFG_PYTEST
1250    inibasenames = ["pytest.ini", "tox.ini", "setup.cfg"]
1251    args = [x for x in args if not str(x).startswith("-")]
1252    if not args:
1253        args = [py.path.local()]
1254    for arg in args:
1255        arg = py.path.local(arg)
1256        for base in arg.parts(reverse=True):
1257            for inibasename in inibasenames:
1258                p = base.join(inibasename)
1259                if exists(p):
1260                    iniconfig = py.iniconfig.IniConfig(p)
1261                    if 'pytest' in iniconfig.sections:
1262                        if inibasename == 'setup.cfg' and warnfunc:
1263                            warnfunc('C1', SETUP_CFG_PYTEST)
1264                        return base, p, iniconfig['pytest']
1265                    if inibasename == 'setup.cfg' and 'tool:pytest' in iniconfig.sections:
1266                        return base, p, iniconfig['tool:pytest']
1267                    elif inibasename == "pytest.ini":
1268                        # allowed to be empty
1269                        return base, p, {}
1270    return None, None, None
1271
1272
1273def get_common_ancestor(paths):
1274    common_ancestor = None
1275    for path in paths:
1276        if not path.exists():
1277            continue
1278        if common_ancestor is None:
1279            common_ancestor = path
1280        else:
1281            if path.relto(common_ancestor) or path == common_ancestor:
1282                continue
1283            elif common_ancestor.relto(path):
1284                common_ancestor = path
1285            else:
1286                shared = path.common(common_ancestor)
1287                if shared is not None:
1288                    common_ancestor = shared
1289    if common_ancestor is None:
1290        common_ancestor = py.path.local()
1291    elif common_ancestor.isfile():
1292        common_ancestor = common_ancestor.dirpath()
1293    return common_ancestor
1294
1295
1296def get_dirs_from_args(args):
1297    def is_option(x):
1298        return str(x).startswith('-')
1299
1300    def get_file_part_from_node_id(x):
1301        return str(x).split('::')[0]
1302
1303    def get_dir_from_path(path):
1304        if path.isdir():
1305            return path
1306        return py.path.local(path.dirname)
1307
1308    # These look like paths but may not exist
1309    possible_paths = (
1310        py.path.local(get_file_part_from_node_id(arg))
1311        for arg in args
1312        if not is_option(arg)
1313    )
1314
1315    return [
1316        get_dir_from_path(path)
1317        for path in possible_paths
1318        if path.exists()
1319    ]
1320
1321
1322def determine_setup(inifile, args, warnfunc=None):
1323    dirs = get_dirs_from_args(args)
1324    if inifile:
1325        iniconfig = py.iniconfig.IniConfig(inifile)
1326        try:
1327            inicfg = iniconfig["pytest"]
1328        except KeyError:
1329            inicfg = None
1330        rootdir = get_common_ancestor(dirs)
1331    else:
1332        ancestor = get_common_ancestor(dirs)
1333        rootdir, inifile, inicfg = getcfg([ancestor], warnfunc=warnfunc)
1334        if rootdir is None:
1335            for rootdir in ancestor.parts(reverse=True):
1336                if rootdir.join("setup.py").exists():
1337                    break
1338            else:
1339                rootdir, inifile, inicfg = getcfg(dirs, warnfunc=warnfunc)
1340                if rootdir is None:
1341                    rootdir = get_common_ancestor([py.path.local(), ancestor])
1342                    is_fs_root = os.path.splitdrive(str(rootdir))[1] == os.sep
1343                    if is_fs_root:
1344                        rootdir = ancestor
1345    return rootdir, inifile, inicfg or {}
1346
1347
1348def setns(obj, dic):
1349    import pytest
1350    for name, value in dic.items():
1351        if isinstance(value, dict):
1352            mod = getattr(obj, name, None)
1353            if mod is None:
1354                modname = "pytest.%s" % name
1355                mod = types.ModuleType(modname)
1356                sys.modules[modname] = mod
1357                mod.__all__ = []
1358                setattr(obj, name, mod)
1359            obj.__all__.append(name)
1360            setns(mod, value)
1361        else:
1362            setattr(obj, name, value)
1363            obj.__all__.append(name)
1364            #if obj != pytest:
1365            #    pytest.__all__.append(name)
1366            setattr(pytest, name, value)
1367
1368
1369def create_terminal_writer(config, *args, **kwargs):
1370    """Create a TerminalWriter instance configured according to the options
1371    in the config object. Every code which requires a TerminalWriter object
1372    and has access to a config object should use this function.
1373    """
1374    tw = py.io.TerminalWriter(*args, **kwargs)
1375    if config.option.color == 'yes':
1376        tw.hasmarkup = True
1377    if config.option.color == 'no':
1378        tw.hasmarkup = False
1379    return tw
1380
1381
1382def _strtobool(val):
1383    """Convert a string representation of truth to true (1) or false (0).
1384
1385    True values are 'y', 'yes', 't', 'true', 'on', and '1'; false values
1386    are 'n', 'no', 'f', 'false', 'off', and '0'.  Raises ValueError if
1387    'val' is anything else.
1388
1389    .. note:: copied from distutils.util
1390    """
1391    val = val.lower()
1392    if val in ('y', 'yes', 't', 'true', 'on', '1'):
1393        return 1
1394    elif val in ('n', 'no', 'f', 'false', 'off', '0'):
1395        return 0
1396    else:
1397        raise ValueError("invalid truth value %r" % (val,))
1398