~ibmcharmers/charms/xenial/ibm-cinder-storwize-svc/trunk

« back to all changes in this revision

Viewing changes to .tox/py35/lib/python3.5/site-packages/_pytest/config.py

  • Committer: Ankammarao
  • Date: 2017-03-06 05:11:42 UTC
  • Revision ID: achittet@in.ibm.com-20170306051142-dpg27z4es1k56hfn
Marked tests folder executable

Show diffs side-by-side

added added

removed removed

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