Commit 714e6bed authored by Ronan Lamy's avatar Ronan Lamy

merge branch pytest-25: Update our py.test to 2.5.2

parents 15084e62 4f51f979
# #
__version__ = '2.2.4.dev2' __version__ = '2.5.2'
"""allow bash-completion for argparse with argcomplete if installed
needs argcomplete>=0.5.6 for python 3.2/3.3 (older versions fail
to find the magic string, so _ARGCOMPLETE env. var is never set, and
this does not need special code.
argcomplete does not support python 2.5 (although the changes for that
are minor).
Function try_argcomplete(parser) should be called directly before
the call to ArgumentParser.parse_args().
The filescompleter is what you normally would use on the positional
arguments specification, in order to get "dirname/" after "dirn<TAB>"
instead of the default "dirname ":
optparser.add_argument(Config._file_or_dir, nargs='*'
).completer=filescompleter
Other, application specific, completers should go in the file
doing the add_argument calls as they need to be specified as .completer
attributes as well. (If argcomplete is not installed, the function the
attribute points to will not be used).
SPEEDUP
=======
The generic argcomplete script for bash-completion
(/etc/bash_completion.d/python-argcomplete.sh )
uses a python program to determine startup script generated by pip.
You can speed up completion somewhat by changing this script to include
# PYTHON_ARGCOMPLETE_OK
so the the python-argcomplete-check-easy-install-script does not
need to be called to find the entry point of the code and see if that is
marked with PYTHON_ARGCOMPLETE_OK
INSTALL/DEBUGGING
=================
To include this support in another application that has setup.py generated
scripts:
- add the line:
# PYTHON_ARGCOMPLETE_OK
near the top of the main python entry point
- include in the file calling parse_args():
from _argcomplete import try_argcomplete, filescompleter
, call try_argcomplete just before parse_args(), and optionally add
filescompleter to the positional arguments' add_argument()
If things do not work right away:
- switch on argcomplete debugging with (also helpful when doing custom
completers):
export _ARC_DEBUG=1
- run:
python-argcomplete-check-easy-install-script $(which appname)
echo $?
will echo 0 if the magic line has been found, 1 if not
- sometimes it helps to find early on errors using:
_ARGCOMPLETE=1 _ARC_DEBUG=1 appname
which should throw a KeyError: 'COMPLINE' (which is properly set by the
global argcomplete script).
"""
import sys
import os
from glob import glob
class FastFilesCompleter:
'Fast file completer class'
def __init__(self, directories=True):
self.directories = directories
def __call__(self, prefix, **kwargs):
"""only called on non option completions"""
if os.path.sep in prefix[1:]: #
prefix_dir = len(os.path.dirname(prefix) + os.path.sep)
else:
prefix_dir = 0
completion = []
globbed = []
if '*' not in prefix and '?' not in prefix:
if prefix[-1] == os.path.sep: # we are on unix, otherwise no bash
globbed.extend(glob(prefix + '.*'))
prefix += '*'
globbed.extend(glob(prefix))
for x in sorted(globbed):
if os.path.isdir(x):
x += '/'
# append stripping the prefix (like bash, not like compgen)
completion.append(x[prefix_dir:])
return completion
if os.environ.get('_ARGCOMPLETE'):
# argcomplete 0.5.6 is not compatible with python 2.5.6: print/with/format
if sys.version_info[:2] < (2, 6):
sys.exit(1)
try:
import argcomplete.completers
except ImportError:
sys.exit(-1)
filescompleter = FastFilesCompleter()
def try_argcomplete(parser):
argcomplete.autocomplete(parser)
else:
def try_argcomplete(parser): pass
filescompleter = None
...@@ -3,7 +3,6 @@ support for presenting detailed information in failing assertions. ...@@ -3,7 +3,6 @@ support for presenting detailed information in failing assertions.
""" """
import py import py
import sys import sys
import pytest
from _pytest.monkeypatch import monkeypatch from _pytest.monkeypatch import monkeypatch
from _pytest.assertion import util from _pytest.assertion import util
...@@ -19,8 +18,8 @@ def pytest_addoption(parser): ...@@ -19,8 +18,8 @@ def pytest_addoption(parser):
to provide assert expression information. """) to provide assert expression information. """)
group.addoption('--no-assert', action="store_true", default=False, group.addoption('--no-assert', action="store_true", default=False,
dest="noassert", help="DEPRECATED equivalent to --assert=plain") dest="noassert", help="DEPRECATED equivalent to --assert=plain")
group.addoption('--nomagic', action="store_true", default=False, group.addoption('--nomagic', '--no-magic', action="store_true",
dest="nomagic", help="DEPRECATED equivalent to --assert=plain") default=False, help="DEPRECATED equivalent to --assert=plain")
class AssertionState: class AssertionState:
"""State for the assertion plugin.""" """State for the assertion plugin."""
...@@ -35,22 +34,25 @@ def pytest_configure(config): ...@@ -35,22 +34,25 @@ def pytest_configure(config):
mode = "plain" mode = "plain"
if mode == "rewrite": if mode == "rewrite":
try: try:
import ast import ast # noqa
except ImportError: except ImportError:
mode = "reinterp" mode = "reinterp"
else: else:
if sys.platform.startswith('java'): # Both Jython and CPython 2.6.0 have AST bugs that make the
# assertion rewriting hook malfunction.
if (sys.platform.startswith('java') or
sys.version_info[:3] == (2, 6, 0)):
mode = "reinterp" mode = "reinterp"
if mode != "plain": if mode != "plain":
_load_modules(mode) _load_modules(mode)
m = monkeypatch() m = monkeypatch()
config._cleanup.append(m.undo) config._cleanup.append(m.undo)
m.setattr(py.builtin.builtins, 'AssertionError', m.setattr(py.builtin.builtins, 'AssertionError',
reinterpret.AssertionError) reinterpret.AssertionError) # noqa
hook = None hook = None
if mode == "rewrite": if mode == "rewrite":
hook = rewrite.AssertionRewritingHook() hook = rewrite.AssertionRewritingHook() # noqa
sys.meta_path.append(hook) sys.meta_path.insert(0, hook)
warn_about_missing_assertion(mode) warn_about_missing_assertion(mode)
config._assertstate = AssertionState(config, mode) config._assertstate = AssertionState(config, mode)
config._assertstate.hook = hook config._assertstate.hook = hook
...@@ -73,9 +75,16 @@ def pytest_runtest_setup(item): ...@@ -73,9 +75,16 @@ def pytest_runtest_setup(item):
def callbinrepr(op, left, right): def callbinrepr(op, left, right):
hook_result = item.ihook.pytest_assertrepr_compare( hook_result = item.ihook.pytest_assertrepr_compare(
config=item.config, op=op, left=left, right=right) config=item.config, op=op, left=left, right=right)
for new_expl in hook_result: for new_expl in hook_result:
if new_expl: if new_expl:
res = '\n~'.join(new_expl) # Don't include pageloads of data unless we are very
# verbose (-vv)
if (sum(len(p) for p in new_expl[1:]) > 80*8
and item.config.option.verbose < 2):
new_expl[1:] = [py.builtin._totext(
'Detailed information truncated, use "-vv" to show')]
res = py.builtin._totext('\n~').join(new_expl)
if item.config.getvalue("assertmode") == "rewrite": if item.config.getvalue("assertmode") == "rewrite":
# The result will be fed back a python % formatting # The result will be fed back a python % formatting
# operation, which will fail if there are extraneous # operation, which will fail if there are extraneous
...@@ -95,9 +104,9 @@ def pytest_sessionfinish(session): ...@@ -95,9 +104,9 @@ def pytest_sessionfinish(session):
def _load_modules(mode): def _load_modules(mode):
"""Lazily import assertion related code.""" """Lazily import assertion related code."""
global rewrite, reinterpret global rewrite, reinterpret
from _pytest.assertion import reinterpret from _pytest.assertion import reinterpret # noqa
if mode == "rewrite": if mode == "rewrite":
from _pytest.assertion import rewrite from _pytest.assertion import rewrite # noqa
def warn_about_missing_assertion(mode): def warn_about_missing_assertion(mode):
try: try:
......
...@@ -11,7 +11,7 @@ from _pytest.assertion import util ...@@ -11,7 +11,7 @@ from _pytest.assertion import util
from _pytest.assertion.reinterpret import BuiltinAssertionError from _pytest.assertion.reinterpret import BuiltinAssertionError
if sys.platform.startswith("java") and sys.version_info < (2, 5, 2): if sys.platform.startswith("java"):
# See http://bugs.jython.org/issue1497 # See http://bugs.jython.org/issue1497
_exprs = ("BoolOp", "BinOp", "UnaryOp", "Lambda", "IfExp", "Dict", _exprs = ("BoolOp", "BinOp", "UnaryOp", "Lambda", "IfExp", "Dict",
"ListComp", "GeneratorExp", "Yield", "Compare", "Call", "ListComp", "GeneratorExp", "Yield", "Compare", "Call",
......
...@@ -526,10 +526,13 @@ if __name__ == '__main__': ...@@ -526,10 +526,13 @@ if __name__ == '__main__':
# example: # example:
def f(): def f():
return 5 return 5
def g(): def g():
return 3 return 3
def h(x): def h(x):
return 'never' return 'never'
check("f() * g() == 5") check("f() * g() == 5")
check("not f()") check("not f()")
check("not (f() and g() or 0)") check("not (f() and g() or 0)")
......
import sys import sys
import py import py
from _pytest.assertion.util import BuiltinAssertionError from _pytest.assertion.util import BuiltinAssertionError
u = py.builtin._totext
class AssertionError(BuiltinAssertionError): class AssertionError(BuiltinAssertionError):
def __init__(self, *args): def __init__(self, *args):
BuiltinAssertionError.__init__(self, *args) BuiltinAssertionError.__init__(self, *args)
if args: if args:
# on Python2.6 we get len(args)==2 for: assert 0, (x,y)
# on Python2.7 and above we always get len(args) == 1
# with args[0] being the (x,y) tuple.
if len(args) > 1:
toprint = args
else:
toprint = args[0]
try: try:
self.msg = str(args[0]) self.msg = u(toprint)
except py.builtin._sysex: except Exception:
raise self.msg = u(
except: "<[broken __repr__] %s at %0xd>"
self.msg = "<[broken __repr__] %s at %0xd>" %( % (toprint.__class__, id(toprint)))
args[0].__class__, id(args[0]))
else: else:
f = py.code.Frame(sys._getframe(1)) f = py.code.Frame(sys._getframe(1))
try: try:
...@@ -44,4 +52,3 @@ if sys.version_info >= (2, 6) or (sys.platform.startswith("java")): ...@@ -44,4 +52,3 @@ if sys.version_info >= (2, 6) or (sys.platform.startswith("java")):
from _pytest.assertion.newinterpret import interpret as reinterpret from _pytest.assertion.newinterpret import interpret as reinterpret
else: else:
reinterpret = reinterpret_old reinterpret = reinterpret_old
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
""" discover and run doctests in modules and test files.""" """ discover and run doctests in modules and test files."""
import pytest, py import pytest, py
from _pytest.python import FixtureRequest, FuncFixtureInfo
from py._code.code import TerminalRepr, ReprFileLocation from py._code.code import TerminalRepr, ReprFileLocation
def pytest_addoption(parser): def pytest_addoption(parser):
...@@ -33,6 +34,14 @@ class ReprFailDoctest(TerminalRepr): ...@@ -33,6 +34,14 @@ class ReprFailDoctest(TerminalRepr):
self.reprlocation.toterminal(tw) self.reprlocation.toterminal(tw)
class DoctestItem(pytest.Item): class DoctestItem(pytest.Item):
def __init__(self, name, parent, runner=None, dtest=None):
super(DoctestItem, self).__init__(name, parent)
self.runner = runner
self.dtest = dtest
def runtest(self):
self.runner.run(self.dtest)
def repr_failure(self, excinfo): def repr_failure(self, excinfo):
doctest = py.std.doctest doctest = py.std.doctest
if excinfo.errisinstance((doctest.DocTestFailure, if excinfo.errisinstance((doctest.DocTestFailure,
...@@ -41,17 +50,27 @@ class DoctestItem(pytest.Item): ...@@ -41,17 +50,27 @@ class DoctestItem(pytest.Item):
example = doctestfailure.example example = doctestfailure.example
test = doctestfailure.test test = doctestfailure.test
filename = test.filename filename = test.filename
lineno = test.lineno + example.lineno + 1 if test.lineno is None:
lineno = None
else:
lineno = test.lineno + example.lineno + 1
message = excinfo.type.__name__ message = excinfo.type.__name__
reprlocation = ReprFileLocation(filename, lineno, message) reprlocation = ReprFileLocation(filename, lineno, message)
checker = py.std.doctest.OutputChecker() checker = py.std.doctest.OutputChecker()
REPORT_UDIFF = py.std.doctest.REPORT_UDIFF REPORT_UDIFF = py.std.doctest.REPORT_UDIFF
filelines = py.path.local(filename).readlines(cr=0) filelines = py.path.local(filename).readlines(cr=0)
i = max(test.lineno, max(0, lineno - 10)) # XXX?
lines = [] lines = []
for line in filelines[i:lineno]: if lineno is not None:
lines.append("%03d %s" % (i+1, line)) i = max(test.lineno, max(0, lineno - 10)) # XXX?
i += 1 for line in filelines[i:lineno]:
lines.append("%03d %s" % (i+1, line))
i += 1
else:
lines.append('EXAMPLE LOCATION UNKNOWN, not showing all tests of that example')
indent = '>>>'
for line in example.source.splitlines():
lines.append('??? %s %s' % (indent, line))
indent = '...'
if excinfo.errisinstance(doctest.DocTestFailure): if excinfo.errisinstance(doctest.DocTestFailure):
lines += checker.output_difference(example, lines += checker.output_difference(example,
doctestfailure.got, REPORT_UDIFF).split("\n") doctestfailure.got, REPORT_UDIFF).split("\n")
...@@ -65,23 +84,42 @@ class DoctestItem(pytest.Item): ...@@ -65,23 +84,42 @@ class DoctestItem(pytest.Item):
return super(DoctestItem, self).repr_failure(excinfo) return super(DoctestItem, self).repr_failure(excinfo)
def reportinfo(self): def reportinfo(self):
return self.fspath, None, "[doctest]" return self.fspath, None, "[doctest] %s" % self.name
class DoctestTextfile(DoctestItem, pytest.File): class DoctestTextfile(DoctestItem, pytest.File):
def runtest(self): def runtest(self):
doctest = py.std.doctest doctest = py.std.doctest
# satisfy `FixtureRequest` constructor...
self.funcargs = {}
fm = self.session._fixturemanager
def func():
pass
self._fixtureinfo = fm.getfixtureinfo(node=self, func=func,
cls=None, funcargs=False)
fixture_request = FixtureRequest(self)
fixture_request._fillfixtures()
failed, tot = doctest.testfile( failed, tot = doctest.testfile(
str(self.fspath), module_relative=False, str(self.fspath), module_relative=False,
optionflags=doctest.ELLIPSIS, optionflags=doctest.ELLIPSIS,
extraglobs=dict(getfixture=fixture_request.getfuncargvalue),
raise_on_error=True, verbose=0) raise_on_error=True, verbose=0)
class DoctestModule(DoctestItem, pytest.File): class DoctestModule(pytest.File):
def runtest(self): def collect(self):
doctest = py.std.doctest doctest = py.std.doctest
if self.fspath.basename == "conftest.py": if self.fspath.basename == "conftest.py":
module = self.config._conftest.importconftest(self.fspath) module = self.config._conftest.importconftest(self.fspath)
else: else:
module = self.fspath.pyimport() module = self.fspath.pyimport()
failed, tot = doctest.testmod( # satisfy `FixtureRequest` constructor...
module, raise_on_error=True, verbose=0, self.funcargs = {}
optionflags=doctest.ELLIPSIS) self._fixtureinfo = FuncFixtureInfo((), [], {})
fixture_request = FixtureRequest(self)
doctest_globals = dict(getfixture=fixture_request.getfuncargvalue)
# uses internal doctest module parsing mechanism
finder = doctest.DocTestFinder()
runner = doctest.DebugRunner(verbose=0, optionflags=doctest.ELLIPSIS)
for test in finder.find(module, module.__name__,
extraglobs=doctest_globals):
if test.examples: # skip empty doctests
yield DoctestItem(test.name, self, runner, test)
""" generate a single-file self-contained version of py.test """ """ generate a single-file self-contained version of pytest """
import py import py
import sys
def find_toplevel(name): def find_toplevel(name):
for syspath in py.std.sys.path: for syspath in py.std.sys.path:
...@@ -54,16 +55,26 @@ def pytest_addoption(parser): ...@@ -54,16 +55,26 @@ def pytest_addoption(parser):
group = parser.getgroup("debugconfig") group = parser.getgroup("debugconfig")
group.addoption("--genscript", action="store", default=None, group.addoption("--genscript", action="store", default=None,
dest="genscript", metavar="path", dest="genscript", metavar="path",
help="create standalone py.test script at given target path.") help="create standalone pytest script at given target path.")
def pytest_cmdline_main(config): def pytest_cmdline_main(config):
genscript = config.getvalue("genscript") genscript = config.getvalue("genscript")
if genscript: if genscript:
tw = py.io.TerminalWriter()
deps = ['py', '_pytest', 'pytest']
if sys.version_info < (2,7):
deps.append("argparse")
tw.line("generated script will run on python2.5-python3.3++")
else:
tw.line("WARNING: generated script will not run on python2.6 "
"or below due to 'argparse' dependency. Use python2.6 "
"to generate a python2.5/6 compatible script", red=True)
script = generate_script( script = generate_script(
'import py; raise SystemExit(py.test.cmdline.main())', 'import pytest; raise SystemExit(pytest.cmdline.main())',
['py', '_pytest', 'pytest'], deps,
) )
genscript = py.path.local(genscript) genscript = py.path.local(genscript)
genscript.write(script) genscript.write(script)
tw.line("generated pytest standalone script: %s" % genscript,
bold=True)
return 0 return 0
...@@ -12,9 +12,11 @@ def pytest_addoption(parser): ...@@ -12,9 +12,11 @@ def pytest_addoption(parser):
help="show help message and configuration info") help="show help message and configuration info")
group._addoption('-p', action="append", dest="plugins", default = [], group._addoption('-p', action="append", dest="plugins", default = [],
metavar="name", metavar="name",
help="early-load given plugin (multi-allowed).") help="early-load given plugin (multi-allowed). "
group.addoption('--traceconfig', "To avoid loading of plugins, use the `no:` prefix, e.g. "
action="store_true", dest="traceconfig", default=False, "`no:doctest`.")
group.addoption('--traceconfig', '--trace-config',
action="store_true", default=False,
help="trace considerations of conftest.py files."), help="trace considerations of conftest.py files."),
group.addoption('--debug', group.addoption('--debug',
action="store_true", dest="debug", default=False, action="store_true", dest="debug", default=False,
...@@ -46,7 +48,7 @@ def pytest_unconfigure(config): ...@@ -46,7 +48,7 @@ def pytest_unconfigure(config):
def pytest_cmdline_main(config): def pytest_cmdline_main(config):
if config.option.version: if config.option.version:
p = py.path.local(pytest.__file__) p = py.path.local(pytest.__file__)
sys.stderr.write("This is py.test version %s, imported from %s\n" % sys.stderr.write("This is pytest version %s, imported from %s\n" %
(pytest.__version__, p)) (pytest.__version__, p))
plugininfo = getpluginversioninfo(config) plugininfo = getpluginversioninfo(config)
if plugininfo: if plugininfo:
...@@ -54,14 +56,15 @@ def pytest_cmdline_main(config): ...@@ -54,14 +56,15 @@ def pytest_cmdline_main(config):
sys.stderr.write(line + "\n") sys.stderr.write(line + "\n")
return 0 return 0
elif config.option.help: elif config.option.help:
config.pluginmanager.do_configure(config) config.do_configure()
showhelp(config) showhelp(config)
config.pluginmanager.do_unconfigure(config) config.do_unconfigure()
return 0 return 0
def showhelp(config): def showhelp(config):
tw = py.io.TerminalWriter() tw = py.io.TerminalWriter()
tw.write(config._parser.optparser.format_help()) tw.write(config._parser.optparser.format_help())
tw.write(config._parser.optparser.format_epilog(None))
tw.line() tw.line()
tw.line() tw.line()
#tw.sep( "=", "config file settings") #tw.sep( "=", "config file settings")
...@@ -79,6 +82,10 @@ def showhelp(config): ...@@ -79,6 +82,10 @@ def showhelp(config):
tw.line() ; tw.line() tw.line() ; tw.line()
#tw.sep("=") #tw.sep("=")
tw.line("to see available markers type: py.test --markers")
tw.line("to see available fixtures type: py.test --fixtures")
tw.line("(shown according to specified file_or_dir or current dir "
"if not specified)")
return return
tw.line("conftest.py options:") tw.line("conftest.py options:")
...@@ -117,7 +124,6 @@ def pytest_report_header(config): ...@@ -117,7 +124,6 @@ def pytest_report_header(config):
if config.option.traceconfig: if config.option.traceconfig:
lines.append("active plugins:") lines.append("active plugins:")
plugins = []
items = config.pluginmanager._name2plugin.items() items = config.pluginmanager._name2plugin.items()
for name, plugin in items: for name, plugin in items:
if hasattr(plugin, '__file__'): if hasattr(plugin, '__file__'):
......
...@@ -11,8 +11,8 @@ def pytest_addhooks(pluginmanager): ...@@ -11,8 +11,8 @@ def pytest_addhooks(pluginmanager):
def pytest_namespace(): def pytest_namespace():
"""return dict of name->object to be made globally available in """return dict of name->object to be made globally available in
the py.test/pytest namespace. This hook is called before command the pytest namespace. This hook is called before command line options
line options are parsed. are parsed.
""" """
def pytest_cmdline_parse(pluginmanager, args): def pytest_cmdline_parse(pluginmanager, args):
...@@ -20,11 +20,31 @@ def pytest_cmdline_parse(pluginmanager, args): ...@@ -20,11 +20,31 @@ def pytest_cmdline_parse(pluginmanager, args):
pytest_cmdline_parse.firstresult = True pytest_cmdline_parse.firstresult = True
def pytest_cmdline_preparse(config, args): def pytest_cmdline_preparse(config, args):
"""modify command line arguments before option parsing. """ """(deprecated) modify command line arguments before option parsing. """
def pytest_addoption(parser): def pytest_addoption(parser):
"""add optparse-style options and ini-style config values via calls """register argparse-style options and ini-style config values.
to ``parser.addoption`` and ``parser.addini(...)``.
This function must be implemented in a :ref:`plugin <pluginorder>` and is
called once at the beginning of a test run.
:arg parser: To add command line options, call
:py:func:`parser.addoption(...) <_pytest.config.Parser.addoption>`.
To add ini-file values call :py:func:`parser.addini(...)
<_pytest.config.Parser.addini>`.
Options can later be accessed through the
:py:class:`config <_pytest.config.Config>` object, respectively:
- :py:func:`config.getoption(name) <_pytest.config.Config.getoption>` to
retrieve the value of a command line option.
- :py:func:`config.getini(name) <_pytest.config.Config.getini>` to retrieve
a value read from an ini-style file.
The config object is passed around on many internal objects via the ``.config``
attribute or can be retrieved as the ``pytestconfig`` fixture or accessed
via (deprecated) ``pytest.config``.
""" """
def pytest_cmdline_main(config): def pytest_cmdline_main(config):
...@@ -32,8 +52,12 @@ def pytest_cmdline_main(config): ...@@ -32,8 +52,12 @@ def pytest_cmdline_main(config):
implementation will invoke the configure hooks and runtest_mainloop. """ implementation will invoke the configure hooks and runtest_mainloop. """
pytest_cmdline_main.firstresult = True pytest_cmdline_main.firstresult = True
def pytest_load_initial_conftests(args, early_config, parser):
""" implements loading initial conftests.
"""
def pytest_configure(config): def pytest_configure(config):
""" called after command line options have been parsed. """ called after command line options have been parsed
and all plugins and initial conftest files been loaded. and all plugins and initial conftest files been loaded.
""" """
...@@ -193,7 +217,7 @@ def pytest_assertrepr_compare(config, op, left, right): ...@@ -193,7 +217,7 @@ def pytest_assertrepr_compare(config, op, left, right):
# hooks for influencing reporting (invoked from _pytest_terminal) # hooks for influencing reporting (invoked from _pytest_terminal)
# ------------------------------------------------------------------------- # -------------------------------------------------------------------------
def pytest_report_header(config): def pytest_report_header(config, startdir):
""" return a string to be displayed as header info for terminal reporting.""" """ return a string to be displayed as header info for terminal reporting."""
def pytest_report_teststatus(report): def pytest_report_teststatus(report):
...@@ -201,7 +225,7 @@ def pytest_report_teststatus(report): ...@@ -201,7 +225,7 @@ def pytest_report_teststatus(report):
pytest_report_teststatus.firstresult = True pytest_report_teststatus.firstresult = True
def pytest_terminal_summary(terminalreporter): def pytest_terminal_summary(terminalreporter):
""" add additional section in terminal summary reporting. """ """ add additional section in terminal summary reporting. """
# ------------------------------------------------------------------------- # -------------------------------------------------------------------------
# doctest hooks # doctest hooks
...@@ -216,13 +240,20 @@ pytest_doctest_prepare_content.firstresult = True ...@@ -216,13 +240,20 @@ pytest_doctest_prepare_content.firstresult = True
# ------------------------------------------------------------------------- # -------------------------------------------------------------------------
def pytest_plugin_registered(plugin, manager): def pytest_plugin_registered(plugin, manager):
""" a new py lib plugin got registered. """ """ a new pytest plugin got registered. """
def pytest_plugin_unregistered(plugin):
""" a py lib plugin got unregistered. """