__init__.py 34 KB

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