Coverage for /opt/homebrew/lib/python3.11/site-packages/_pytest/helpconfig.py: 31%
132 statements
« prev ^ index » next coverage.py v7.2.3, created at 2023-05-04 13:14 +0700
« prev ^ index » next coverage.py v7.2.3, created at 2023-05-04 13:14 +0700
1"""Version info, help messages, tracing configuration."""
2import os
3import sys
4from argparse import Action
5from typing import List
6from typing import Optional
7from typing import Union
9import pytest
10from _pytest.config import Config
11from _pytest.config import ExitCode
12from _pytest.config import PrintHelp
13from _pytest.config.argparsing import Parser
16class HelpAction(Action):
17 """An argparse Action that will raise an exception in order to skip the
18 rest of the argument parsing when --help is passed.
20 This prevents argparse from quitting due to missing required arguments
21 when any are defined, for example by ``pytest_addoption``.
22 This is similar to the way that the builtin argparse --help option is
23 implemented by raising SystemExit.
24 """
26 def __init__(self, option_strings, dest=None, default=False, help=None):
27 super().__init__(
28 option_strings=option_strings,
29 dest=dest,
30 const=True,
31 default=default,
32 nargs=0,
33 help=help,
34 )
36 def __call__(self, parser, namespace, values, option_string=None):
37 setattr(namespace, self.dest, self.const)
39 # We should only skip the rest of the parsing after preparse is done.
40 if getattr(parser._parser, "after_preparse", False):
41 raise PrintHelp
44def pytest_addoption(parser: Parser) -> None:
45 group = parser.getgroup("debugconfig")
46 group.addoption(
47 "--version",
48 "-V",
49 action="count",
50 default=0,
51 dest="version",
52 help="Display pytest version and information about plugins. "
53 "When given twice, also display information about plugins.",
54 )
55 group._addoption(
56 "-h",
57 "--help",
58 action=HelpAction,
59 dest="help",
60 help="Show help message and configuration info",
61 )
62 group._addoption(
63 "-p",
64 action="append",
65 dest="plugins",
66 default=[],
67 metavar="name",
68 help="Early-load given plugin module name or entry point (multi-allowed). "
69 "To avoid loading of plugins, use the `no:` prefix, e.g. "
70 "`no:doctest`.",
71 )
72 group.addoption(
73 "--traceconfig",
74 "--trace-config",
75 action="store_true",
76 default=False,
77 help="Trace considerations of conftest.py files",
78 )
79 group.addoption(
80 "--debug",
81 action="store",
82 nargs="?",
83 const="pytestdebug.log",
84 dest="debug",
85 metavar="DEBUG_FILE_NAME",
86 help="Store internal tracing debug information in this log file. "
87 "This file is opened with 'w' and truncated as a result, care advised. "
88 "Default: pytestdebug.log.",
89 )
90 group._addoption(
91 "-o",
92 "--override-ini",
93 dest="override_ini",
94 action="append",
95 help='Override ini option with "option=value" style, '
96 "e.g. `-o xfail_strict=True -o cache_dir=cache`.",
97 )
100@pytest.hookimpl(hookwrapper=True)
101def pytest_cmdline_parse():
102 outcome = yield
103 config: Config = outcome.get_result()
105 if config.option.debug:
106 # --debug | --debug <file.log> was provided.
107 path = config.option.debug
108 debugfile = open(path, "w")
109 debugfile.write(
110 "versions pytest-%s, "
111 "python-%s\ncwd=%s\nargs=%s\n\n"
112 % (
113 pytest.__version__,
114 ".".join(map(str, sys.version_info)),
115 os.getcwd(),
116 config.invocation_params.args,
117 )
118 )
119 config.trace.root.setwriter(debugfile.write)
120 undo_tracing = config.pluginmanager.enable_tracing()
121 sys.stderr.write("writing pytest debug information to %s\n" % path)
123 def unset_tracing() -> None:
124 debugfile.close()
125 sys.stderr.write("wrote pytest debug information to %s\n" % debugfile.name)
126 config.trace.root.setwriter(None)
127 undo_tracing()
129 config.add_cleanup(unset_tracing)
132def showversion(config: Config) -> None:
133 if config.option.version > 1:
134 sys.stdout.write(
135 "This is pytest version {}, imported from {}\n".format(
136 pytest.__version__, pytest.__file__
137 )
138 )
139 plugininfo = getpluginversioninfo(config)
140 if plugininfo:
141 for line in plugininfo:
142 sys.stdout.write(line + "\n")
143 else:
144 sys.stdout.write(f"pytest {pytest.__version__}\n")
147def pytest_cmdline_main(config: Config) -> Optional[Union[int, ExitCode]]:
148 if config.option.version > 0:
149 showversion(config)
150 return 0
151 elif config.option.help:
152 config._do_configure()
153 showhelp(config)
154 config._ensure_unconfigure()
155 return 0
156 return None
159def showhelp(config: Config) -> None:
160 import textwrap
162 reporter = config.pluginmanager.get_plugin("terminalreporter")
163 tw = reporter._tw
164 tw.write(config._parser.optparser.format_help())
165 tw.line()
166 tw.line(
167 "[pytest] ini-options in the first pytest.ini|tox.ini|setup.cfg file found:"
168 )
169 tw.line()
171 columns = tw.fullwidth # costly call
172 indent_len = 24 # based on argparse's max_help_position=24
173 indent = " " * indent_len
174 for name in config._parser._ininames:
175 help, type, default = config._parser._inidict[name]
176 if type is None:
177 type = "string"
178 if help is None:
179 raise TypeError(f"help argument cannot be None for {name}")
180 spec = f"{name} ({type}):"
181 tw.write(" %s" % spec)
182 spec_len = len(spec)
183 if spec_len > (indent_len - 3):
184 # Display help starting at a new line.
185 tw.line()
186 helplines = textwrap.wrap(
187 help,
188 columns,
189 initial_indent=indent,
190 subsequent_indent=indent,
191 break_on_hyphens=False,
192 )
194 for line in helplines:
195 tw.line(line)
196 else:
197 # Display help starting after the spec, following lines indented.
198 tw.write(" " * (indent_len - spec_len - 2))
199 wrapped = textwrap.wrap(help, columns - indent_len, break_on_hyphens=False)
201 if wrapped:
202 tw.line(wrapped[0])
203 for line in wrapped[1:]:
204 tw.line(indent + line)
206 tw.line()
207 tw.line("Environment variables:")
208 vars = [
209 ("PYTEST_ADDOPTS", "Extra command line options"),
210 ("PYTEST_PLUGINS", "Comma-separated plugins to load during startup"),
211 ("PYTEST_DISABLE_PLUGIN_AUTOLOAD", "Set to disable plugin auto-loading"),
212 ("PYTEST_DEBUG", "Set to enable debug tracing of pytest's internals"),
213 ]
214 for name, help in vars:
215 tw.line(f" {name:<24} {help}")
216 tw.line()
217 tw.line()
219 tw.line("to see available markers type: pytest --markers")
220 tw.line("to see available fixtures type: pytest --fixtures")
221 tw.line(
222 "(shown according to specified file_or_dir or current dir "
223 "if not specified; fixtures with leading '_' are only shown "
224 "with the '-v' option"
225 )
227 for warningreport in reporter.stats.get("warnings", []):
228 tw.line("warning : " + warningreport.message, red=True)
229 return
232conftest_options = [("pytest_plugins", "list of plugin names to load")]
235def getpluginversioninfo(config: Config) -> List[str]:
236 lines = []
237 plugininfo = config.pluginmanager.list_plugin_distinfo()
238 if plugininfo:
239 lines.append("setuptools registered plugins:")
240 for plugin, dist in plugininfo:
241 loc = getattr(plugin, "__file__", repr(plugin))
242 content = f"{dist.project_name}-{dist.version} at {loc}"
243 lines.append(" " + content)
244 return lines
247def pytest_report_header(config: Config) -> List[str]:
248 lines = []
249 if config.option.debug or config.option.traceconfig:
250 lines.append(f"using: pytest-{pytest.__version__}")
252 verinfo = getpluginversioninfo(config)
253 if verinfo:
254 lines.extend(verinfo)
256 if config.option.traceconfig:
257 lines.append("active plugins:")
258 items = config.pluginmanager.list_name_plugin()
259 for name, plugin in items:
260 if hasattr(plugin, "__file__"):
261 r = plugin.__file__
262 else:
263 r = repr(plugin)
264 lines.append(f" {name:<20}: {r}")
265 return lines