helpconfig.py 7.6 KB

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