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 8import copy 9import six 10import py 11 12# DON't import pytest here because it causes import cycle troubles 13import sys 14import os 15from _pytest.outcomes import Skipped 16 17import _pytest._code 18import _pytest.hookspec # the extension point definitions 19import _pytest.assertion 20from pluggy import PluginManager, HookimplMarker, HookspecMarker 21from _pytest.compat import safe_str 22from .exceptions import UsageError, PrintHelp 23from .findpaths import determine_setup, exists 24 25hookimpl = HookimplMarker("pytest") 26hookspec = HookspecMarker("pytest") 27 28# pytest startup 29# 30 31 32class ConftestImportFailure(Exception): 33 34 def __init__(self, path, excinfo): 35 Exception.__init__(self, path, excinfo) 36 self.path = path 37 self.excinfo = excinfo 38 39 def __str__(self): 40 etype, evalue, etb = self.excinfo 41 formatted = traceback.format_tb(etb) 42 # The level of the tracebacks we want to print is hand crafted :( 43 return repr(evalue) + "\n" + "".join(formatted[2:]) 44 45 46def main(args=None, plugins=None): 47 """ return exit code, after performing an in-process test run. 48 49 :arg args: list of command line arguments. 50 51 :arg plugins: list of plugin objects to be auto-registered during 52 initialization. 53 """ 54 try: 55 try: 56 config = _prepareconfig(args, plugins) 57 except ConftestImportFailure as e: 58 tw = py.io.TerminalWriter(sys.stderr) 59 for line in traceback.format_exception(*e.excinfo): 60 tw.line(line.rstrip(), red=True) 61 tw.line("ERROR: could not load %s\n" % (e.path,), red=True) 62 return 4 63 else: 64 try: 65 return config.hook.pytest_cmdline_main(config=config) 66 finally: 67 config._ensure_unconfigure() 68 except UsageError as e: 69 tw = py.io.TerminalWriter(sys.stderr) 70 for msg in e.args: 71 tw.line("ERROR: {}\n".format(msg), red=True) 72 return 4 73 74 75class cmdline(object): # NOQA compatibility namespace 76 main = staticmethod(main) 77 78 79def filename_arg(path, optname): 80 """ Argparse type validator for filename arguments. 81 82 :path: path of filename 83 :optname: name of the option 84 """ 85 if os.path.isdir(path): 86 raise UsageError("{} must be a filename, given: {}".format(optname, path)) 87 return path 88 89 90def directory_arg(path, optname): 91 """Argparse type validator for directory arguments. 92 93 :path: path of directory 94 :optname: name of the option 95 """ 96 if not os.path.isdir(path): 97 raise UsageError("{} must be a directory, given: {}".format(optname, path)) 98 return path 99 100 101default_plugins = ( 102 "mark", 103 "main", 104 "terminal", 105 "runner", 106 "python", 107 "fixtures", 108 "debugging", 109 "unittest", 110 "capture", 111 "skipping", 112 "tmpdir", 113 "monkeypatch", 114 "recwarn", 115 "pastebin", 116 "helpconfig", 117 "nose", 118 "assertion", 119 "junitxml", 120 "resultlog", 121 "doctest", 122 "cacheprovider", 123 "freeze_support", 124 "setuponly", 125 "setupplan", 126 "warnings", 127 "logging", 128) 129 130 131builtin_plugins = set(default_plugins) 132builtin_plugins.add("pytester") 133 134 135def get_config(): 136 # subsequent calls to main will create a fresh instance 137 pluginmanager = PytestPluginManager() 138 config = Config(pluginmanager) 139 for spec in default_plugins: 140 pluginmanager.import_plugin(spec) 141 return config 142 143 144def get_plugin_manager(): 145 """ 146 Obtain a new instance of the 147 :py:class:`_pytest.config.PytestPluginManager`, with default plugins 148 already loaded. 149 150 This function can be used by integration with other tools, like hooking 151 into pytest to run tests into an IDE. 152 """ 153 return get_config().pluginmanager 154 155 156def _prepareconfig(args=None, plugins=None): 157 warning = None 158 if args is None: 159 args = sys.argv[1:] 160 elif isinstance(args, py.path.local): 161 args = [str(args)] 162 elif not isinstance(args, (tuple, list)): 163 if not isinstance(args, str): 164 raise ValueError("not a string or argument list: %r" % (args,)) 165 args = shlex.split(args, posix=sys.platform != "win32") 166 from _pytest import deprecated 167 168 warning = deprecated.MAIN_STR_ARGS 169 config = get_config() 170 pluginmanager = config.pluginmanager 171 try: 172 if plugins: 173 for plugin in plugins: 174 if isinstance(plugin, six.string_types): 175 pluginmanager.consider_pluginarg(plugin) 176 else: 177 pluginmanager.register(plugin) 178 if warning: 179 config.warn("C1", warning) 180 return pluginmanager.hook.pytest_cmdline_parse( 181 pluginmanager=pluginmanager, args=args 182 ) 183 except BaseException: 184 config._ensure_unconfigure() 185 raise 186 187 188class PytestPluginManager(PluginManager): 189 """ 190 Overwrites :py:class:`pluggy.PluginManager <pluggy.PluginManager>` to add pytest-specific 191 functionality: 192 193 * loading plugins from the command line, ``PYTEST_PLUGINS`` env variable and 194 ``pytest_plugins`` global variables found in plugins being loaded; 195 * ``conftest.py`` loading during start-up; 196 """ 197 198 def __init__(self): 199 super(PytestPluginManager, self).__init__("pytest") 200 self._conftest_plugins = set() 201 202 # state related to local conftest plugins 203 self._path2confmods = {} 204 self._conftestpath2mod = {} 205 self._confcutdir = None 206 self._noconftest = False 207 self._duplicatepaths = set() 208 209 self.add_hookspecs(_pytest.hookspec) 210 self.register(self) 211 if os.environ.get("PYTEST_DEBUG"): 212 err = sys.stderr 213 encoding = getattr(err, "encoding", "utf8") 214 try: 215 err = py.io.dupfile(err, encoding=encoding) 216 except Exception: 217 pass 218 self.trace.root.setwriter(err.write) 219 self.enable_tracing() 220 221 # Config._consider_importhook will set a real object if required. 222 self.rewrite_hook = _pytest.assertion.DummyRewriteHook() 223 # Used to know when we are importing conftests after the pytest_configure stage 224 self._configured = False 225 226 def addhooks(self, module_or_class): 227 """ 228 .. deprecated:: 2.8 229 230 Use :py:meth:`pluggy.PluginManager.add_hookspecs <PluginManager.add_hookspecs>` 231 instead. 232 """ 233 warning = dict( 234 code="I2", 235 fslocation=_pytest._code.getfslineno(sys._getframe(1)), 236 nodeid=None, 237 message="use pluginmanager.add_hookspecs instead of " 238 "deprecated addhooks() method.", 239 ) 240 self._warn(warning) 241 return self.add_hookspecs(module_or_class) 242 243 def parse_hookimpl_opts(self, plugin, name): 244 # pytest hooks are always prefixed with pytest_ 245 # so we avoid accessing possibly non-readable attributes 246 # (see issue #1073) 247 if not name.startswith("pytest_"): 248 return 249 # ignore some historic special names which can not be hooks anyway 250 if name == "pytest_plugins" or name.startswith("pytest_funcarg__"): 251 return 252 253 method = getattr(plugin, name) 254 opts = super(PytestPluginManager, self).parse_hookimpl_opts(plugin, name) 255 256 # collect unmarked hooks as long as they have the `pytest_' prefix 257 if opts is None and name.startswith("pytest_"): 258 opts = {} 259 260 if opts is not None: 261 for name in ("tryfirst", "trylast", "optionalhook", "hookwrapper"): 262 opts.setdefault(name, hasattr(method, name)) 263 return opts 264 265 def parse_hookspec_opts(self, module_or_class, name): 266 opts = super(PytestPluginManager, self).parse_hookspec_opts( 267 module_or_class, name 268 ) 269 if opts is None: 270 method = getattr(module_or_class, name) 271 if name.startswith("pytest_"): 272 opts = { 273 "firstresult": hasattr(method, "firstresult"), 274 "historic": hasattr(method, "historic"), 275 } 276 return opts 277 278 def register(self, plugin, name=None): 279 if name in ["pytest_catchlog", "pytest_capturelog"]: 280 self._warn( 281 "{} plugin has been merged into the core, " 282 "please remove it from your requirements.".format( 283 name.replace("_", "-") 284 ) 285 ) 286 return 287 ret = super(PytestPluginManager, self).register(plugin, name) 288 if ret: 289 self.hook.pytest_plugin_registered.call_historic( 290 kwargs=dict(plugin=plugin, manager=self) 291 ) 292 293 if isinstance(plugin, types.ModuleType): 294 self.consider_module(plugin) 295 return ret 296 297 def getplugin(self, name): 298 # support deprecated naming because plugins (xdist e.g.) use it 299 return self.get_plugin(name) 300 301 def hasplugin(self, name): 302 """Return True if the plugin with the given name is registered.""" 303 return bool(self.get_plugin(name)) 304 305 def pytest_configure(self, config): 306 # XXX now that the pluginmanager exposes hookimpl(tryfirst...) 307 # we should remove tryfirst/trylast as markers 308 config.addinivalue_line( 309 "markers", 310 "tryfirst: mark a hook implementation function such that the " 311 "plugin machinery will try to call it first/as early as possible.", 312 ) 313 config.addinivalue_line( 314 "markers", 315 "trylast: mark a hook implementation function such that the " 316 "plugin machinery will try to call it last/as late as possible.", 317 ) 318 self._configured = True 319 320 def _warn(self, message): 321 kwargs = message if isinstance(message, dict) else { 322 "code": "I1", "message": message, "fslocation": None, "nodeid": None 323 } 324 self.hook.pytest_logwarning.call_historic(kwargs=kwargs) 325 326 # 327 # internal API for local conftest plugin handling 328 # 329 def _set_initial_conftests(self, namespace): 330 """ load initial conftest files given a preparsed "namespace". 331 As conftest files may add their own command line options 332 which have arguments ('--my-opt somepath') we might get some 333 false positives. All builtin and 3rd party plugins will have 334 been loaded, however, so common options will not confuse our logic 335 here. 336 """ 337 current = py.path.local() 338 self._confcutdir = current.join( 339 namespace.confcutdir, abs=True 340 ) if namespace.confcutdir else None 341 self._noconftest = namespace.noconftest 342 testpaths = namespace.file_or_dir 343 foundanchor = False 344 for path in testpaths: 345 path = str(path) 346 # remove node-id syntax 347 i = path.find("::") 348 if i != -1: 349 path = path[:i] 350 anchor = current.join(path, abs=1) 351 if exists(anchor): # we found some file object 352 self._try_load_conftest(anchor) 353 foundanchor = True 354 if not foundanchor: 355 self._try_load_conftest(current) 356 357 def _try_load_conftest(self, anchor): 358 self._getconftestmodules(anchor) 359 # let's also consider test* subdirs 360 if anchor.check(dir=1): 361 for x in anchor.listdir("test*"): 362 if x.check(dir=1): 363 self._getconftestmodules(x) 364 365 def _getconftestmodules(self, path): 366 if self._noconftest: 367 return [] 368 try: 369 return self._path2confmods[path] 370 except KeyError: 371 if path.isfile(): 372 clist = self._getconftestmodules(path.dirpath()) 373 else: 374 # XXX these days we may rather want to use config.rootdir 375 # and allow users to opt into looking into the rootdir parent 376 # directories instead of requiring to specify confcutdir 377 clist = [] 378 for parent in path.parts(): 379 if self._confcutdir and self._confcutdir.relto(parent): 380 continue 381 conftestpath = parent.join("conftest.py") 382 if conftestpath.isfile(): 383 mod = self._importconftest(conftestpath) 384 clist.append(mod) 385 386 self._path2confmods[path] = clist 387 return clist 388 389 def _rget_with_confmod(self, name, path): 390 modules = self._getconftestmodules(path) 391 for mod in reversed(modules): 392 try: 393 return mod, getattr(mod, name) 394 except AttributeError: 395 continue 396 raise KeyError(name) 397 398 def _importconftest(self, conftestpath): 399 try: 400 return self._conftestpath2mod[conftestpath] 401 except KeyError: 402 pkgpath = conftestpath.pypkgpath() 403 if pkgpath is None: 404 _ensure_removed_sysmodule(conftestpath.purebasename) 405 try: 406 mod = conftestpath.pyimport() 407 if hasattr(mod, "pytest_plugins") and self._configured: 408 from _pytest.deprecated import PYTEST_PLUGINS_FROM_NON_TOP_LEVEL_CONFTEST 409 410 warnings.warn(PYTEST_PLUGINS_FROM_NON_TOP_LEVEL_CONFTEST) 411 except Exception: 412 raise ConftestImportFailure(conftestpath, sys.exc_info()) 413 414 self._conftest_plugins.add(mod) 415 self._conftestpath2mod[conftestpath] = mod 416 dirpath = conftestpath.dirpath() 417 if dirpath in self._path2confmods: 418 for path, mods in self._path2confmods.items(): 419 if path and path.relto(dirpath) or path == dirpath: 420 assert mod not in mods 421 mods.append(mod) 422 self.trace("loaded conftestmodule %r" % (mod)) 423 self.consider_conftest(mod) 424 return mod 425 426 # 427 # API for bootstrapping plugin loading 428 # 429 # 430 431 def consider_preparse(self, args): 432 for opt1, opt2 in zip(args, args[1:]): 433 if opt1 == "-p": 434 self.consider_pluginarg(opt2) 435 436 def consider_pluginarg(self, arg): 437 if arg.startswith("no:"): 438 name = arg[3:] 439 self.set_blocked(name) 440 if not name.startswith("pytest_"): 441 self.set_blocked("pytest_" + name) 442 else: 443 self.import_plugin(arg) 444 445 def consider_conftest(self, conftestmodule): 446 self.register(conftestmodule, name=conftestmodule.__file__) 447 448 def consider_env(self): 449 self._import_plugin_specs(os.environ.get("PYTEST_PLUGINS")) 450 451 def consider_module(self, mod): 452 self._import_plugin_specs(getattr(mod, "pytest_plugins", [])) 453 454 def _import_plugin_specs(self, spec): 455 plugins = _get_plugin_specs_as_list(spec) 456 for import_spec in plugins: 457 self.import_plugin(import_spec) 458 459 def import_plugin(self, modname): 460 # most often modname refers to builtin modules, e.g. "pytester", 461 # "terminal" or "capture". Those plugins are registered under their 462 # basename for historic purposes but must be imported with the 463 # _pytest prefix. 464 assert isinstance(modname, (six.text_type, str)), ( 465 "module name as text required, got %r" % modname 466 ) 467 modname = str(modname) 468 if self.is_blocked(modname) or self.get_plugin(modname) is not None: 469 return 470 if modname in builtin_plugins: 471 importspec = "_pytest." + modname 472 else: 473 importspec = modname 474 self.rewrite_hook.mark_rewrite(importspec) 475 try: 476 __import__(importspec) 477 except ImportError as e: 478 new_exc_type = ImportError 479 new_exc_message = 'Error importing plugin "%s": %s' % ( 480 modname, safe_str(e.args[0]) 481 ) 482 new_exc = new_exc_type(new_exc_message) 483 484 six.reraise(new_exc_type, new_exc, sys.exc_info()[2]) 485 486 except Skipped as e: 487 self._warn("skipped plugin %r: %s" % ((modname, e.msg))) 488 else: 489 mod = sys.modules[importspec] 490 self.register(mod, modname) 491 492 493def _get_plugin_specs_as_list(specs): 494 """ 495 Parses a list of "plugin specs" and returns a list of plugin names. 496 497 Plugin specs can be given as a list of strings separated by "," or already as a list/tuple in 498 which case it is returned as a list. Specs can also be `None` in which case an 499 empty list is returned. 500 """ 501 if specs is not None: 502 if isinstance(specs, str): 503 specs = specs.split(",") if specs else [] 504 if not isinstance(specs, (list, tuple)): 505 raise UsageError( 506 "Plugin specs must be a ','-separated string or a " 507 "list/tuple of strings for plugin names. Given: %r" % specs 508 ) 509 return list(specs) 510 return [] 511 512 513def _ensure_removed_sysmodule(modname): 514 try: 515 del sys.modules[modname] 516 except KeyError: 517 pass 518 519 520class Notset(object): 521 522 def __repr__(self): 523 return "<NOTSET>" 524 525 526notset = Notset() 527 528 529def _iter_rewritable_modules(package_files): 530 for fn in package_files: 531 is_simple_module = "/" not in fn and fn.endswith(".py") 532 is_package = fn.count("/") == 1 and fn.endswith("__init__.py") 533 if is_simple_module: 534 module_name, _ = os.path.splitext(fn) 535 yield module_name 536 elif is_package: 537 package_name = os.path.dirname(fn) 538 yield package_name 539 540 541class Config(object): 542 """ access to configuration values, pluginmanager and plugin hooks. """ 543 544 def __init__(self, pluginmanager): 545 #: access to command line option as attributes. 546 #: (deprecated), use :py:func:`getoption() <_pytest.config.Config.getoption>` instead 547 self.option = argparse.Namespace() 548 from .argparsing import Parser, FILE_OR_DIR 549 550 _a = FILE_OR_DIR 551 self._parser = Parser( 552 usage="%%(prog)s [options] [%s] [%s] [...]" % (_a, _a), 553 processopt=self._processopt, 554 ) 555 #: a pluginmanager instance 556 self.pluginmanager = pluginmanager 557 self.trace = self.pluginmanager.trace.root.get("config") 558 self.hook = self.pluginmanager.hook 559 self._inicache = {} 560 self._override_ini = () 561 self._opt2dest = {} 562 self._cleanup = [] 563 self._warn = self.pluginmanager._warn 564 self.pluginmanager.register(self, "pytestconfig") 565 self._configured = False 566 567 def do_setns(dic): 568 import pytest 569 570 setns(pytest, dic) 571 572 self.hook.pytest_namespace.call_historic(do_setns, {}) 573 self.hook.pytest_addoption.call_historic(kwargs=dict(parser=self._parser)) 574 575 def add_cleanup(self, func): 576 """ Add a function to be called when the config object gets out of 577 use (usually coninciding with pytest_unconfigure).""" 578 self._cleanup.append(func) 579 580 def _do_configure(self): 581 assert not self._configured 582 self._configured = True 583 self.hook.pytest_configure.call_historic(kwargs=dict(config=self)) 584 585 def _ensure_unconfigure(self): 586 if self._configured: 587 self._configured = False 588 self.hook.pytest_unconfigure(config=self) 589 self.hook.pytest_configure._call_history = [] 590 while self._cleanup: 591 fin = self._cleanup.pop() 592 fin() 593 594 def warn(self, code, message, fslocation=None, nodeid=None): 595 """ generate a warning for this test session. """ 596 self.hook.pytest_logwarning.call_historic( 597 kwargs=dict( 598 code=code, message=message, fslocation=fslocation, nodeid=nodeid 599 ) 600 ) 601 602 def get_terminal_writer(self): 603 return self.pluginmanager.get_plugin("terminalreporter")._tw 604 605 def pytest_cmdline_parse(self, pluginmanager, args): 606 # REF1 assert self == pluginmanager.config, (self, pluginmanager.config) 607 self.parse(args) 608 return self 609 610 def notify_exception(self, excinfo, option=None): 611 if option and option.fulltrace: 612 style = "long" 613 else: 614 style = "native" 615 excrepr = excinfo.getrepr( 616 funcargs=True, showlocals=getattr(option, "showlocals", False), style=style 617 ) 618 res = self.hook.pytest_internalerror(excrepr=excrepr, excinfo=excinfo) 619 if not any(res): 620 for line in str(excrepr).split("\n"): 621 sys.stderr.write("INTERNALERROR> %s\n" % line) 622 sys.stderr.flush() 623 624 def cwd_relative_nodeid(self, nodeid): 625 # nodeid's are relative to the rootpath, compute relative to cwd 626 if self.invocation_dir != self.rootdir: 627 fullpath = self.rootdir.join(nodeid) 628 nodeid = self.invocation_dir.bestrelpath(fullpath) 629 return nodeid 630 631 @classmethod 632 def fromdictargs(cls, option_dict, args): 633 """ constructor useable for subprocesses. """ 634 config = get_config() 635 config.option.__dict__.update(option_dict) 636 config.parse(args, addopts=False) 637 for x in config.option.plugins: 638 config.pluginmanager.consider_pluginarg(x) 639 return config 640 641 def _processopt(self, opt): 642 for name in opt._short_opts + opt._long_opts: 643 self._opt2dest[name] = opt.dest 644 645 if hasattr(opt, "default") and opt.dest: 646 if not hasattr(self.option, opt.dest): 647 setattr(self.option, opt.dest, opt.default) 648 649 @hookimpl(trylast=True) 650 def pytest_load_initial_conftests(self, early_config): 651 self.pluginmanager._set_initial_conftests(early_config.known_args_namespace) 652 653 def _initini(self, args): 654 ns, unknown_args = self._parser.parse_known_and_unknown_args( 655 args, namespace=copy.copy(self.option) 656 ) 657 r = determine_setup( 658 ns.inifilename, 659 ns.file_or_dir + unknown_args, 660 warnfunc=self.warn, 661 rootdir_cmd_arg=ns.rootdir or None, 662 ) 663 self.rootdir, self.inifile, self.inicfg = r 664 self._parser.extra_info["rootdir"] = self.rootdir 665 self._parser.extra_info["inifile"] = self.inifile 666 self.invocation_dir = py.path.local() 667 self._parser.addini("addopts", "extra command line options", "args") 668 self._parser.addini("minversion", "minimally required pytest version") 669 self._override_ini = ns.override_ini or () 670 671 def _consider_importhook(self, args): 672 """Install the PEP 302 import hook if using assertion rewriting. 673 674 Needs to parse the --assert=<mode> option from the commandline 675 and find all the installed plugins to mark them for rewriting 676 by the importhook. 677 """ 678 ns, unknown_args = self._parser.parse_known_and_unknown_args(args) 679 mode = ns.assertmode 680 if mode == "rewrite": 681 try: 682 hook = _pytest.assertion.install_importhook(self) 683 except SystemError: 684 mode = "plain" 685 else: 686 self._mark_plugins_for_rewrite(hook) 687 _warn_about_missing_assertion(mode) 688 689 def _mark_plugins_for_rewrite(self, hook): 690 """ 691 Given an importhook, mark for rewrite any top-level 692 modules or packages in the distribution package for 693 all pytest plugins. 694 """ 695 import pkg_resources 696 697 self.pluginmanager.rewrite_hook = hook 698 699 # 'RECORD' available for plugins installed normally (pip install) 700 # 'SOURCES.txt' available for plugins installed in dev mode (pip install -e) 701 # for installed plugins 'SOURCES.txt' returns an empty list, and vice-versa 702 # so it shouldn't be an issue 703 metadata_files = "RECORD", "SOURCES.txt" 704 705 package_files = ( 706 entry.split(",")[0] 707 for entrypoint in pkg_resources.iter_entry_points("pytest11") 708 for metadata in metadata_files 709 for entry in entrypoint.dist._get_metadata(metadata) 710 ) 711 712 for name in _iter_rewritable_modules(package_files): 713 hook.mark_rewrite(name) 714 715 def _preparse(self, args, addopts=True): 716 if addopts: 717 args[:] = shlex.split(os.environ.get("PYTEST_ADDOPTS", "")) + args 718 self._initini(args) 719 if addopts: 720 args[:] = self.getini("addopts") + args 721 self._checkversion() 722 self._consider_importhook(args) 723 self.pluginmanager.consider_preparse(args) 724 self.pluginmanager.load_setuptools_entrypoints("pytest11") 725 self.pluginmanager.consider_env() 726 self.known_args_namespace = ns = self._parser.parse_known_args( 727 args, namespace=copy.copy(self.option) 728 ) 729 if self.known_args_namespace.confcutdir is None and self.inifile: 730 confcutdir = py.path.local(self.inifile).dirname 731 self.known_args_namespace.confcutdir = confcutdir 732 try: 733 self.hook.pytest_load_initial_conftests( 734 early_config=self, args=args, parser=self._parser 735 ) 736 except ConftestImportFailure: 737 e = sys.exc_info()[1] 738 if ns.help or ns.version: 739 # we don't want to prevent --help/--version to work 740 # so just let is pass and print a warning at the end 741 self._warn("could not load initial conftests (%s)\n" % e.path) 742 else: 743 raise 744 745 def _checkversion(self): 746 import pytest 747 748 minver = self.inicfg.get("minversion", None) 749 if minver: 750 ver = minver.split(".") 751 myver = pytest.__version__.split(".") 752 if myver < ver: 753 raise pytest.UsageError( 754 "%s:%d: requires pytest-%s, actual pytest-%s'" 755 % ( 756 self.inicfg.config.path, 757 self.inicfg.lineof("minversion"), 758 minver, 759 pytest.__version__, 760 ) 761 ) 762 763 def parse(self, args, addopts=True): 764 # parse given cmdline arguments into this config object. 765 assert not hasattr( 766 self, "args" 767 ), "can only parse cmdline args at most once per Config object" 768 self._origargs = args 769 self.hook.pytest_addhooks.call_historic( 770 kwargs=dict(pluginmanager=self.pluginmanager) 771 ) 772 self._preparse(args, addopts=addopts) 773 # XXX deprecated hook: 774 self.hook.pytest_cmdline_preparse(config=self, args=args) 775 self._parser.after_preparse = True 776 try: 777 args = self._parser.parse_setoption( 778 args, self.option, namespace=self.option 779 ) 780 if not args: 781 cwd = os.getcwd() 782 if cwd == self.rootdir: 783 args = self.getini("testpaths") 784 if not args: 785 args = [cwd] 786 self.args = args 787 except PrintHelp: 788 pass 789 790 def addinivalue_line(self, name, line): 791 """ add a line to an ini-file option. The option must have been 792 declared but might not yet be set in which case the line becomes the 793 the first line in its value. """ 794 x = self.getini(name) 795 assert isinstance(x, list) 796 x.append(line) # modifies the cached list inline 797 798 def getini(self, name): 799 """ return configuration value from an :ref:`ini file <inifiles>`. If the 800 specified name hasn't been registered through a prior 801 :py:func:`parser.addini <_pytest.config.Parser.addini>` 802 call (usually from a plugin), a ValueError is raised. """ 803 try: 804 return self._inicache[name] 805 except KeyError: 806 self._inicache[name] = val = self._getini(name) 807 return val 808 809 def _getini(self, name): 810 try: 811 description, type, default = self._parser._inidict[name] 812 except KeyError: 813 raise ValueError("unknown configuration value: %r" % (name,)) 814 value = self._get_override_ini_value(name) 815 if value is None: 816 try: 817 value = self.inicfg[name] 818 except KeyError: 819 if default is not None: 820 return default 821 if type is None: 822 return "" 823 return [] 824 if type == "pathlist": 825 dp = py.path.local(self.inicfg.config.path).dirpath() 826 values = [] 827 for relpath in shlex.split(value): 828 values.append(dp.join(relpath, abs=True)) 829 return values 830 elif type == "args": 831 return shlex.split(value) 832 elif type == "linelist": 833 return [t for t in map(lambda x: x.strip(), value.split("\n")) if t] 834 elif type == "bool": 835 return bool(_strtobool(value.strip())) 836 else: 837 assert type is None 838 return value 839 840 def _getconftest_pathlist(self, name, path): 841 try: 842 mod, relroots = self.pluginmanager._rget_with_confmod(name, path) 843 except KeyError: 844 return None 845 modpath = py.path.local(mod.__file__).dirpath() 846 values = [] 847 for relroot in relroots: 848 if not isinstance(relroot, py.path.local): 849 relroot = relroot.replace("/", py.path.local.sep) 850 relroot = modpath.join(relroot, abs=True) 851 values.append(relroot) 852 return values 853 854 def _get_override_ini_value(self, name): 855 value = None 856 # override_ini is a list of "ini=value" options 857 # always use the last item if multiple values are set for same ini-name, 858 # e.g. -o foo=bar1 -o foo=bar2 will set foo to bar2 859 for ini_config in self._override_ini: 860 try: 861 key, user_ini_value = ini_config.split("=", 1) 862 except ValueError: 863 raise UsageError("-o/--override-ini expects option=value style.") 864 else: 865 if key == name: 866 value = user_ini_value 867 return value 868 869 def getoption(self, name, default=notset, skip=False): 870 """ return command line option value. 871 872 :arg name: name of the option. You may also specify 873 the literal ``--OPT`` option instead of the "dest" option name. 874 :arg default: default value if no option of that name exists. 875 :arg skip: if True raise pytest.skip if option does not exists 876 or has a None value. 877 """ 878 name = self._opt2dest.get(name, name) 879 try: 880 val = getattr(self.option, name) 881 if val is None and skip: 882 raise AttributeError(name) 883 return val 884 except AttributeError: 885 if default is not notset: 886 return default 887 if skip: 888 import pytest 889 890 pytest.skip("no %r option found" % (name,)) 891 raise ValueError("no option named %r" % (name,)) 892 893 def getvalue(self, name, path=None): 894 """ (deprecated, use getoption()) """ 895 return self.getoption(name) 896 897 def getvalueorskip(self, name, path=None): 898 """ (deprecated, use getoption(skip=True)) """ 899 return self.getoption(name, skip=True) 900 901 902def _assertion_supported(): 903 try: 904 assert False 905 except AssertionError: 906 return True 907 else: 908 return False 909 910 911def _warn_about_missing_assertion(mode): 912 if not _assertion_supported(): 913 if mode == "plain": 914 sys.stderr.write( 915 "WARNING: ASSERTIONS ARE NOT EXECUTED" 916 " and FAILING TESTS WILL PASS. Are you" 917 " using python -O?" 918 ) 919 else: 920 sys.stderr.write( 921 "WARNING: assertions not in test modules or" 922 " plugins will be ignored" 923 " because assert statements are not executed " 924 "by the underlying Python interpreter " 925 "(are you using python -O?)\n" 926 ) 927 928 929def setns(obj, dic): 930 import pytest 931 932 for name, value in dic.items(): 933 if isinstance(value, dict): 934 mod = getattr(obj, name, None) 935 if mod is None: 936 modname = "pytest.%s" % name 937 mod = types.ModuleType(modname) 938 sys.modules[modname] = mod 939 mod.__all__ = [] 940 setattr(obj, name, mod) 941 obj.__all__.append(name) 942 setns(mod, value) 943 else: 944 setattr(obj, name, value) 945 obj.__all__.append(name) 946 # if obj != pytest: 947 # pytest.__all__.append(name) 948 setattr(pytest, name, value) 949 950 951def create_terminal_writer(config, *args, **kwargs): 952 """Create a TerminalWriter instance configured according to the options 953 in the config object. Every code which requires a TerminalWriter object 954 and has access to a config object should use this function. 955 """ 956 tw = py.io.TerminalWriter(*args, **kwargs) 957 if config.option.color == "yes": 958 tw.hasmarkup = True 959 if config.option.color == "no": 960 tw.hasmarkup = False 961 return tw 962 963 964def _strtobool(val): 965 """Convert a string representation of truth to true (1) or false (0). 966 967 True values are 'y', 'yes', 't', 'true', 'on', and '1'; false values 968 are 'n', 'no', 'f', 'false', 'off', and '0'. Raises ValueError if 969 'val' is anything else. 970 971 .. note:: copied from distutils.util 972 """ 973 val = val.lower() 974 if val in ("y", "yes", "t", "true", "on", "1"): 975 return 1 976 elif val in ("n", "no", "f", "false", "off", "0"): 977 return 0 978 else: 979 raise ValueError("invalid truth value %r" % (val,)) 980