1""" version info, help messages, tracing configuration. """ 2from __future__ import absolute_import, division, print_function 3 4import py 5import pytest 6from _pytest.config import PrintHelp 7import os 8import sys 9from argparse import Action 10 11 12class HelpAction(Action): 13 """This is an argparse Action that will raise an exception in 14 order to skip the rest of the argument parsing when --help is passed. 15 This prevents argparse from quitting due to missing required arguments 16 when any are defined, for example by ``pytest_addoption``. 17 This is similar to the way that the builtin argparse --help option is 18 implemented by raising SystemExit. 19 """ 20 21 def __init__(self, 22 option_strings, 23 dest=None, 24 default=False, 25 help=None): 26 super(HelpAction, self).__init__( 27 option_strings=option_strings, 28 dest=dest, 29 const=True, 30 default=default, 31 nargs=0, 32 help=help) 33 34 def __call__(self, parser, namespace, values, option_string=None): 35 setattr(namespace, self.dest, self.const) 36 37 # We should only skip the rest of the parsing after preparse is done 38 if getattr(parser._parser, 'after_preparse', False): 39 raise PrintHelp 40 41 42def pytest_addoption(parser): 43 group = parser.getgroup('debugconfig') 44 group.addoption('--version', action="store_true", 45 help="display pytest lib version and import information.") 46 group._addoption("-h", "--help", action=HelpAction, dest="help", 47 help="show help message and configuration info") 48 group._addoption('-p', action="append", dest="plugins", default=[], 49 metavar="name", 50 help="early-load given plugin (multi-allowed). " 51 "To avoid loading of plugins, use the `no:` prefix, e.g. " 52 "`no:doctest`.") 53 group.addoption('--traceconfig', '--trace-config', 54 action="store_true", default=False, 55 help="trace considerations of conftest.py files."), 56 group.addoption('--debug', 57 action="store_true", dest="debug", default=False, 58 help="store internal tracing debug information in 'pytestdebug.log'.") 59 group._addoption( 60 '-o', '--override-ini', nargs='*', dest="override_ini", 61 action="append", 62 help="override config option with option=value style, e.g. `-o xfail_strict=True`.") 63 64 65@pytest.hookimpl(hookwrapper=True) 66def pytest_cmdline_parse(): 67 outcome = yield 68 config = outcome.get_result() 69 if config.option.debug: 70 path = os.path.abspath("pytestdebug.log") 71 debugfile = open(path, 'w') 72 debugfile.write("versions pytest-%s, py-%s, " 73 "python-%s\ncwd=%s\nargs=%s\n\n" % ( 74 pytest.__version__, py.__version__, 75 ".".join(map(str, sys.version_info)), 76 os.getcwd(), config._origargs)) 77 config.trace.root.setwriter(debugfile.write) 78 undo_tracing = config.pluginmanager.enable_tracing() 79 sys.stderr.write("writing pytestdebug information to %s\n" % path) 80 81 def unset_tracing(): 82 debugfile.close() 83 sys.stderr.write("wrote pytestdebug information to %s\n" % 84 debugfile.name) 85 config.trace.root.setwriter(None) 86 undo_tracing() 87 88 config.add_cleanup(unset_tracing) 89 90 91def pytest_cmdline_main(config): 92 if config.option.version: 93 p = py.path.local(pytest.__file__) 94 sys.stderr.write("This is pytest version %s, imported from %s\n" % 95 (pytest.__version__, p)) 96 plugininfo = getpluginversioninfo(config) 97 if plugininfo: 98 for line in plugininfo: 99 sys.stderr.write(line + "\n") 100 return 0 101 elif config.option.help: 102 config._do_configure() 103 showhelp(config) 104 config._ensure_unconfigure() 105 return 0 106 107 108def showhelp(config): 109 reporter = config.pluginmanager.get_plugin('terminalreporter') 110 tw = reporter._tw 111 tw.write(config._parser.optparser.format_help()) 112 tw.line() 113 tw.line() 114 tw.line("[pytest] ini-options in the first " 115 "pytest.ini|tox.ini|setup.cfg file found:") 116 tw.line() 117 118 for name in config._parser._ininames: 119 help, type, default = config._parser._inidict[name] 120 if type is None: 121 type = "string" 122 spec = "%s (%s)" % (name, type) 123 line = " %-24s %s" % (spec, help) 124 tw.line(line[:tw.fullwidth]) 125 126 tw.line() 127 tw.line("environment variables:") 128 vars = [ 129 ("PYTEST_ADDOPTS", "extra command line options"), 130 ("PYTEST_PLUGINS", "comma-separated plugins to load during startup"), 131 ("PYTEST_DEBUG", "set to enable debug tracing of pytest's internals") 132 ] 133 for name, help in vars: 134 tw.line(" %-24s %s" % (name, help)) 135 tw.line() 136 tw.line() 137 138 tw.line("to see available markers type: pytest --markers") 139 tw.line("to see available fixtures type: pytest --fixtures") 140 tw.line("(shown according to specified file_or_dir or current dir " 141 "if not specified)") 142 143 for warningreport in reporter.stats.get('warnings', []): 144 tw.line("warning : " + warningreport.message, red=True) 145 return 146 147 148conftest_options = [ 149 ('pytest_plugins', 'list of plugin names to load'), 150] 151 152 153def getpluginversioninfo(config): 154 lines = [] 155 plugininfo = config.pluginmanager.list_plugin_distinfo() 156 if plugininfo: 157 lines.append("setuptools registered plugins:") 158 for plugin, dist in plugininfo: 159 loc = getattr(plugin, '__file__', repr(plugin)) 160 content = "%s-%s at %s" % (dist.project_name, dist.version, loc) 161 lines.append(" " + content) 162 return lines 163 164 165def pytest_report_header(config): 166 lines = [] 167 if config.option.debug or config.option.traceconfig: 168 lines.append("using: pytest-%s pylib-%s" % 169 (pytest.__version__, py.__version__)) 170 171 verinfo = getpluginversioninfo(config) 172 if verinfo: 173 lines.extend(verinfo) 174 175 if config.option.traceconfig: 176 lines.append("active plugins:") 177 items = config.pluginmanager.list_name_plugin() 178 for name, plugin in items: 179 if hasattr(plugin, '__file__'): 180 r = plugin.__file__ 181 else: 182 r = repr(plugin) 183 lines.append(" %-20s: %s" % (name, r)) 184 return lines 185