pre-commit-hooks/.venv/lib/python3.10/site-packages/_pytest/helpconfig.py
2024-04-13 00:00:20 +00:00

273 lines
8.6 KiB
Python

# mypy: allow-untyped-defs
"""Version info, help messages, tracing configuration."""
from __future__ import annotations
import os
import sys
from argparse import Action
from typing import Generator
from typing import List
from typing import Optional
from typing import Union
import pytest
from _pytest.config import Config
from _pytest.config import ExitCode
from _pytest.config import PrintHelp
from _pytest.config.argparsing import Parser
from _pytest.terminal import TerminalReporter
class HelpAction(Action):
"""An argparse Action that will raise an exception in order to skip the
rest of the argument parsing when --help is passed.
This prevents argparse from quitting due to missing required arguments
when any are defined, for example by ``pytest_addoption``.
This is similar to the way that the builtin argparse --help option is
implemented by raising SystemExit.
"""
def __init__(self, option_strings, dest=None, default=False, help=None):
super().__init__(
option_strings=option_strings,
dest=dest,
const=True,
default=default,
nargs=0,
help=help,
)
def __call__(self, parser, namespace, values, option_string=None):
setattr(namespace, self.dest, self.const)
# We should only skip the rest of the parsing after preparse is done.
if getattr(parser._parser, 'after_preparse', False):
raise PrintHelp
def pytest_addoption(parser: Parser) -> None:
group = parser.getgroup('debugconfig')
group.addoption(
'--version',
'-V',
action='count',
default=0,
dest='version',
help='Display pytest version and information about plugins. '
'When given twice, also display information about plugins.',
)
group._addoption(
'-h',
'--help',
action=HelpAction,
dest='help',
help='Show help message and configuration info',
)
group._addoption(
'-p',
action='append',
dest='plugins',
default=[],
metavar='name',
help='Early-load given plugin module name or entry point (multi-allowed). '
'To avoid loading of plugins, use the `no:` prefix, e.g. '
'`no:doctest`.',
)
group.addoption(
'--traceconfig',
'--trace-config',
action='store_true',
default=False,
help='Trace considerations of conftest.py files',
)
group.addoption(
'--debug',
action='store',
nargs='?',
const='pytestdebug.log',
dest='debug',
metavar='DEBUG_FILE_NAME',
help='Store internal tracing debug information in this log file. '
"This file is opened with 'w' and truncated as a result, care advised. "
'Default: pytestdebug.log.',
)
group._addoption(
'-o',
'--override-ini',
dest='override_ini',
action='append',
help='Override ini option with "option=value" style, '
'e.g. `-o xfail_strict=True -o cache_dir=cache`.',
)
@pytest.hookimpl(wrapper=True)
def pytest_cmdline_parse() -> Generator[None, Config, Config]:
config = yield
if config.option.debug:
# --debug | --debug <file.log> was provided.
path = config.option.debug
debugfile = open(path, 'w', encoding='utf-8')
debugfile.write(
'versions pytest-{}, '
'python-{}\ninvocation_dir={}\ncwd={}\nargs={}\n\n'.format(
pytest.__version__,
'.'.join(map(str, sys.version_info)),
config.invocation_params.dir,
os.getcwd(),
config.invocation_params.args,
),
)
config.trace.root.setwriter(debugfile.write)
undo_tracing = config.pluginmanager.enable_tracing()
sys.stderr.write('writing pytest debug information to %s\n' % path)
def unset_tracing() -> None:
debugfile.close()
sys.stderr.write('wrote pytest debug information to %s\n' % debugfile.name)
config.trace.root.setwriter(None)
undo_tracing()
config.add_cleanup(unset_tracing)
return config
def showversion(config: Config) -> None:
if config.option.version > 1:
sys.stdout.write(
f'This is pytest version {pytest.__version__}, imported from {pytest.__file__}\n',
)
plugininfo = getpluginversioninfo(config)
if plugininfo:
for line in plugininfo:
sys.stdout.write(line + '\n')
else:
sys.stdout.write(f'pytest {pytest.__version__}\n')
def pytest_cmdline_main(config: Config) -> int | ExitCode | None:
if config.option.version > 0:
showversion(config)
return 0
elif config.option.help:
config._do_configure()
showhelp(config)
config._ensure_unconfigure()
return 0
return None
def showhelp(config: Config) -> None:
import textwrap
reporter: TerminalReporter | None = config.pluginmanager.get_plugin(
'terminalreporter',
)
assert reporter is not None
tw = reporter._tw
tw.write(config._parser.optparser.format_help())
tw.line()
tw.line(
'[pytest] ini-options in the first '
'pytest.ini|tox.ini|setup.cfg|pyproject.toml file found:',
)
tw.line()
columns = tw.fullwidth # costly call
indent_len = 24 # based on argparse's max_help_position=24
indent = ' ' * indent_len
for name in config._parser._ininames:
help, type, default = config._parser._inidict[name]
if type is None:
type = 'string'
if help is None:
raise TypeError(f'help argument cannot be None for {name}')
spec = f'{name} ({type}):'
tw.write(' %s' % spec)
spec_len = len(spec)
if spec_len > (indent_len - 3):
# Display help starting at a new line.
tw.line()
helplines = textwrap.wrap(
help,
columns,
initial_indent=indent,
subsequent_indent=indent,
break_on_hyphens=False,
)
for line in helplines:
tw.line(line)
else:
# Display help starting after the spec, following lines indented.
tw.write(' ' * (indent_len - spec_len - 2))
wrapped = textwrap.wrap(help, columns - indent_len, break_on_hyphens=False)
if wrapped:
tw.line(wrapped[0])
for line in wrapped[1:]:
tw.line(indent + line)
tw.line()
tw.line('Environment variables:')
vars = [
('PYTEST_ADDOPTS', 'Extra command line options'),
('PYTEST_PLUGINS', 'Comma-separated plugins to load during startup'),
('PYTEST_DISABLE_PLUGIN_AUTOLOAD', 'Set to disable plugin auto-loading'),
('PYTEST_DEBUG', "Set to enable debug tracing of pytest's internals"),
]
for name, help in vars:
tw.line(f' {name:<24} {help}')
tw.line()
tw.line()
tw.line('to see available markers type: pytest --markers')
tw.line('to see available fixtures type: pytest --fixtures')
tw.line(
'(shown according to specified file_or_dir or current dir '
"if not specified; fixtures with leading '_' are only shown "
"with the '-v' option",
)
for warningreport in reporter.stats.get('warnings', []):
tw.line('warning : ' + warningreport.message, red=True)
return
conftest_options = [('pytest_plugins', 'list of plugin names to load')]
def getpluginversioninfo(config: Config) -> list[str]:
lines = []
plugininfo = config.pluginmanager.list_plugin_distinfo()
if plugininfo:
lines.append('setuptools registered plugins:')
for plugin, dist in plugininfo:
loc = getattr(plugin, '__file__', repr(plugin))
content = f'{dist.project_name}-{dist.version} at {loc}'
lines.append(' ' + content)
return lines
def pytest_report_header(config: Config) -> list[str]:
lines = []
if config.option.debug or config.option.traceconfig:
lines.append(f'using: pytest-{pytest.__version__}')
verinfo = getpluginversioninfo(config)
if verinfo:
lines.extend(verinfo)
if config.option.traceconfig:
lines.append('active plugins:')
items = config.pluginmanager.list_name_plugin()
for name, plugin in items:
if hasattr(plugin, '__file__'):
r = plugin.__file__
else:
r = repr(plugin)
lines.append(f' {name:<20}: {r}')
return lines