fix comment & docstring typos, line wrapping & wording

This commit is contained in:
Jurko Gospodnetić 2017-12-01 13:21:06 +01:00
parent 964c29cb93
commit 65f5383106
1 changed files with 159 additions and 160 deletions

View File

@ -1,4 +1,4 @@
""" (disabled by default) support for testing pytest and pytest plugins. """ """(disabled by default) support for testing pytest and pytest plugins."""
from __future__ import absolute_import, division, print_function from __future__ import absolute_import, division, print_function
import codecs import codecs
@ -76,8 +76,8 @@ class LsofFdLeakChecker(object):
try: try:
py.process.cmdexec("lsof -v") py.process.cmdexec("lsof -v")
except (py.process.cmdexec.Error, UnicodeDecodeError): except (py.process.cmdexec.Error, UnicodeDecodeError):
# cmdexec may raise UnicodeDecodeError on Windows systems # cmdexec may raise UnicodeDecodeError on Windows systems with
# with locale other than english: # locale other than English:
# https://bitbucket.org/pytest-dev/py/issues/66 # https://bitbucket.org/pytest-dev/py/issues/66
return False return False
else: else:
@ -132,7 +132,7 @@ def getexecutable(name, cache={}):
if "2.5.2" in err: if "2.5.2" in err:
executable = None # http://bugs.jython.org/issue1790 executable = None # http://bugs.jython.org/issue1790
elif popen.returncode != 0: elif popen.returncode != 0:
# Handle pyenv's 127. # handle pyenv's 127
executable = None executable = None
cache[name] = executable cache[name] = executable
return executable return executable
@ -157,9 +157,10 @@ def anypython(request):
@pytest.fixture @pytest.fixture
def _pytest(request): def _pytest(request):
""" Return a helper which offers a gethookrecorder(hook) """Return a helper which offers a gethookrecorder(hook) method which
method which returns a HookRecorder instance which helps returns a HookRecorder instance which helps to make assertions about called
to make assertions about called hooks. hooks.
""" """
return PytestArg(request) return PytestArg(request)
@ -193,8 +194,8 @@ class ParsedCall:
class HookRecorder: class HookRecorder:
"""Record all hooks called in a plugin manager. """Record all hooks called in a plugin manager.
This wraps all the hook calls in the plugin manager, recording This wraps all the hook calls in the plugin manager, recording each call
each call before propagating the normal calls. before propagating the normal calls.
""" """
@ -262,7 +263,7 @@ class HookRecorder:
def matchreport(self, inamepart="", def matchreport(self, inamepart="",
names="pytest_runtest_logreport pytest_collectreport", when=None): names="pytest_runtest_logreport pytest_collectreport", when=None):
""" return a testreport whose dotted import path matches """ """return a testreport whose dotted import path matches"""
values = [] values = []
for rep in self.getreports(names=names): for rep in self.getreports(names=names):
try: try:
@ -341,14 +342,14 @@ class RunResult:
Attributes: Attributes:
:ret: The return value. :ret: the return value
:outlines: List of lines captured from stdout. :outlines: list of lines captured from stdout
:errlines: List of lines captures from stderr. :errlines: list of lines captures from stderr
:stdout: :py:class:`LineMatcher` of stdout, use ``stdout.str()`` to :stdout: :py:class:`LineMatcher` of stdout, use ``stdout.str()`` to
reconstruct stdout or the commonly used reconstruct stdout or the commonly used ``stdout.fnmatch_lines()``
``stdout.fnmatch_lines()`` method. method
:stderrr: :py:class:`LineMatcher` of stderr. :stderrr: :py:class:`LineMatcher` of stderr
:duration: Duration in seconds. :duration: duration in seconds
""" """
@ -361,8 +362,10 @@ class RunResult:
self.duration = duration self.duration = duration
def parseoutcomes(self): def parseoutcomes(self):
""" Return a dictionary of outcomestring->num from parsing """Return a dictionary of outcomestring->num from parsing the terminal
the terminal output that the test process produced.""" output that the test process produced.
"""
for line in reversed(self.outlines): for line in reversed(self.outlines):
if 'seconds' in line: if 'seconds' in line:
outcomes = rex_outcome.findall(line) outcomes = rex_outcome.findall(line)
@ -374,8 +377,10 @@ class RunResult:
raise ValueError("Pytest terminal report not found") raise ValueError("Pytest terminal report not found")
def assert_outcomes(self, passed=0, skipped=0, failed=0, error=0): def assert_outcomes(self, passed=0, skipped=0, failed=0, error=0):
""" assert that the specified outcomes appear with the respective """Assert that the specified outcomes appear with the respective
numbers (0 means it didn't occur) in the text output from a test run.""" numbers (0 means it didn't occur) in the text output from a test run.
"""
d = self.parseoutcomes() d = self.parseoutcomes()
obtained = { obtained = {
'passed': d.get('passed', 0), 'passed': d.get('passed', 0),
@ -389,21 +394,18 @@ class RunResult:
class Testdir: class Testdir:
"""Temporary test directory with tools to test/run pytest itself. """Temporary test directory with tools to test/run pytest itself.
This is based on the ``tmpdir`` fixture but provides a number of This is based on the ``tmpdir`` fixture but provides a number of methods
methods which aid with testing pytest itself. Unless which aid with testing pytest itself. Unless :py:meth:`chdir` is used all
:py:meth:`chdir` is used all methods will use :py:attr:`tmpdir` as methods will use :py:attr:`tmpdir` as their current working directory.
current working directory.
Attributes: Attributes:
:tmpdir: The :py:class:`py.path.local` instance of the temporary :tmpdir: The :py:class:`py.path.local` instance of the temporary directory.
directory.
:plugins: A list of plugins to use with :py:meth:`parseconfig` and :plugins: A list of plugins to use with :py:meth:`parseconfig` and
:py:meth:`runpytest`. Initially this is an empty list but :py:meth:`runpytest`. Initially this is an empty list but plugins can
plugins can be added to the list. The type of items to add to be added to the list. The type of items to add to the list depends on
the list depend on the method which uses them so refer to them the method using them so refer to them for details.
for details.
""" """
@ -429,10 +431,9 @@ class Testdir:
def finalize(self): def finalize(self):
"""Clean up global state artifacts. """Clean up global state artifacts.
Some methods modify the global interpreter state and this Some methods modify the global interpreter state and this tries to
tries to clean this up. It does not remove the temporary clean this up. It does not remove the temporary directory however so
directory however so it can be looked at after the test run it can be looked at after the test run has finished.
has finished.
""" """
sys.path[:], sys.meta_path[:] = self._savesyspath sys.path[:], sys.meta_path[:] = self._savesyspath
@ -495,17 +496,15 @@ class Testdir:
def makefile(self, ext, *args, **kwargs): def makefile(self, ext, *args, **kwargs):
"""Create a new file in the testdir. """Create a new file in the testdir.
ext: The extension the file should use, including the dot. ext: The extension the file should use, including the dot, e.g. `.py`.
E.g. ".py".
args: All args will be treated as strings and joined using args: All args will be treated as strings and joined using newlines.
newlines. The result will be written as contents to the The result will be written as contents to the file. The name of the
file. The name of the file will be based on the test file will be based on the test function requesting this fixture.
function requesting this fixture.
E.g. "testdir.makefile('.txt', 'line1', 'line2')" E.g. "testdir.makefile('.txt', 'line1', 'line2')"
kwargs: Each keyword is the name of a file, while the value of kwargs: Each keyword is the name of a file, while the value of it will
it will be written as contents of the file. be written as contents of the file.
E.g. "testdir.makefile('.ini', pytest='[pytest]\naddopts=-rs\n')" E.g. "testdir.makefile('.ini', pytest='[pytest]\naddopts=-rs\n')"
""" """
@ -535,14 +534,16 @@ class Testdir:
def syspathinsert(self, path=None): def syspathinsert(self, path=None):
"""Prepend a directory to sys.path, defaults to :py:attr:`tmpdir`. """Prepend a directory to sys.path, defaults to :py:attr:`tmpdir`.
This is undone automatically after the test. This is undone automatically when this object dies at the end of each
test.
""" """
if path is None: if path is None:
path = self.tmpdir path = self.tmpdir
sys.path.insert(0, str(path)) sys.path.insert(0, str(path))
# a call to syspathinsert() usually means that the caller # a call to syspathinsert() usually means that the caller wants to
# wants to import some dynamically created files. # import some dynamically created files, thus with python3 we
# with python3 we thus invalidate import caches. # invalidate its import caches
self._possibly_invalidate_import_caches() self._possibly_invalidate_import_caches()
def _possibly_invalidate_import_caches(self): def _possibly_invalidate_import_caches(self):
@ -562,8 +563,8 @@ class Testdir:
def mkpydir(self, name): def mkpydir(self, name):
"""Create a new python package. """Create a new python package.
This creates a (sub)directory with an empty ``__init__.py`` This creates a (sub)directory with an empty ``__init__.py`` file so it
file so that is recognised as a python package. gets recognised as a python package.
""" """
p = self.mkdir(name) p = self.mkdir(name)
@ -576,10 +577,10 @@ class Testdir:
"""Return the collection node of a file. """Return the collection node of a file.
:param config: :py:class:`_pytest.config.Config` instance, see :param config: :py:class:`_pytest.config.Config` instance, see
:py:meth:`parseconfig` and :py:meth:`parseconfigure` to :py:meth:`parseconfig` and :py:meth:`parseconfigure` to create the
create the configuration. configuration
:param arg: A :py:class:`py.path.local` instance of the file. :param arg: a :py:class:`py.path.local` instance of the file
""" """
session = Session(config) session = Session(config)
@ -593,11 +594,10 @@ class Testdir:
def getpathnode(self, path): def getpathnode(self, path):
"""Return the collection node of a file. """Return the collection node of a file.
This is like :py:meth:`getnode` but uses This is like :py:meth:`getnode` but uses :py:meth:`parseconfigure` to
:py:meth:`parseconfigure` to create the (configured) pytest create the (configured) pytest Config instance.
Config instance.
:param path: A :py:class:`py.path.local` instance of the file. :param path: a :py:class:`py.path.local` instance of the file
""" """
config = self.parseconfigure(path) config = self.parseconfigure(path)
@ -611,8 +611,8 @@ class Testdir:
def genitems(self, colitems): def genitems(self, colitems):
"""Generate all test items from a collection node. """Generate all test items from a collection node.
This recurses into the collection node and returns a list of This recurses into the collection node and returns a list of all the
all the test items contained within. test items contained within.
""" """
session = colitems[0].session session = colitems[0].session
@ -624,10 +624,10 @@ class Testdir:
def runitem(self, source): def runitem(self, source):
"""Run the "test_func" Item. """Run the "test_func" Item.
The calling test instance (the class which contains the test The calling test instance (class containing the test method) must
method) must provide a ``.getrunner()`` method which should provide a ``.getrunner()`` method which should return a runner which
return a runner which can run the test protocol for a single can run the test protocol for a single item, e.g.
item, like e.g. :py:func:`_pytest.runner.runtestprotocol`. :py:func:`_pytest.runner.runtestprotocol`.
""" """
# used from runner functional tests # used from runner functional tests
@ -641,14 +641,14 @@ class Testdir:
"""Run a test module in process using ``pytest.main()``. """Run a test module in process using ``pytest.main()``.
This run writes "source" into a temporary file and runs This run writes "source" into a temporary file and runs
``pytest.main()`` on it, returning a :py:class:`HookRecorder` ``pytest.main()`` on it, returning a :py:class:`HookRecorder` instance
instance for the result. for the result.
:param source: The source code of the test module. :param source: the source code of the test module
:param cmdlineargs: Any extra command line arguments to use. :param cmdlineargs: any extra command line arguments to use
:return: :py:class:`HookRecorder` instance of the result. :return: :py:class:`HookRecorder` instance of the result
""" """
p = self.makepyfile(source) p = self.makepyfile(source)
@ -658,13 +658,9 @@ class Testdir:
def inline_genitems(self, *args): def inline_genitems(self, *args):
"""Run ``pytest.main(['--collectonly'])`` in-process. """Run ``pytest.main(['--collectonly'])`` in-process.
Returns a tuple of the collected items and a Runs the :py:func:`pytest.main` function to run all of pytest inside
:py:class:`HookRecorder` instance. the test process itself like :py:meth:`inline_run`, but returns a
tuple of the collected items and a :py:class:`HookRecorder` instance.
This runs the :py:func:`pytest.main` function to run all of
pytest inside the test process itself like
:py:meth:`inline_run`. However the return value is a tuple of
the collection items and a :py:class:`HookRecorder` instance.
""" """
rec = self.inline_run("--collect-only", *args) rec = self.inline_run("--collect-only", *args)
@ -674,24 +670,24 @@ class Testdir:
def inline_run(self, *args, **kwargs): def inline_run(self, *args, **kwargs):
"""Run ``pytest.main()`` in-process, returning a HookRecorder. """Run ``pytest.main()`` in-process, returning a HookRecorder.
This runs the :py:func:`pytest.main` function to run all of Runs the :py:func:`pytest.main` function to run all of pytest inside
pytest inside the test process itself. This means it can the test process itself. This means it can return a
return a :py:class:`HookRecorder` instance which gives more :py:class:`HookRecorder` instance which gives more detailed results
detailed results from then run then can be done by matching from that run than can be done by matching stdout/stderr from
stdout/stderr from :py:meth:`runpytest`. :py:meth:`runpytest`.
:param args: Any command line arguments to pass to :param args: command line arguments to pass to :py:func:`pytest.main`
:py:func:`pytest.main`.
:param plugin: (keyword-only) Extra plugin instances the :param plugin: (keyword-only) extra plugin instances the
``pytest.main()`` instance should use. ``pytest.main()`` instance should use
:return: a :py:class:`HookRecorder` instance
:return: A :py:class:`HookRecorder` instance.
""" """
# When running py.test inline any plugins active in the main # When running py.test inline any plugins active in the main test
# test process are already imported. So this disables the # process are already imported. So this disables the warning which
# warning which will trigger to say they can no longer be # will trigger to say they can no longer be rewritten, which is fine as
# rewritten, which is fine as they are already rewritten. # they have already been rewritten.
orig_warn = AssertionRewritingHook._warn_already_imported orig_warn = AssertionRewritingHook._warn_already_imported
def revert(): def revert():
@ -717,8 +713,8 @@ class Testdir:
pass pass
reprec.ret = ret reprec.ret = ret
# typically we reraise keyboard interrupts from the child run # typically we reraise keyboard interrupts from the child run because
# because it's our user requesting interruption of the testing # it's our user requesting interruption of the testing
if ret == 2 and not kwargs.get("no_reraise_ctrlc"): if ret == 2 and not kwargs.get("no_reraise_ctrlc"):
calls = reprec.getcalls("pytest_keyboard_interrupt") calls = reprec.getcalls("pytest_keyboard_interrupt")
if calls and calls[-1].excinfo.type == KeyboardInterrupt: if calls and calls[-1].excinfo.type == KeyboardInterrupt:
@ -726,8 +722,10 @@ class Testdir:
return reprec return reprec
def runpytest_inprocess(self, *args, **kwargs): def runpytest_inprocess(self, *args, **kwargs):
""" Return result of running pytest in-process, providing a similar """Return result of running pytest in-process, providing a similar
interface to what self.runpytest() provides. """ interface to what self.runpytest() provides.
"""
if kwargs.get("syspathinsert"): if kwargs.get("syspathinsert"):
self.syspathinsert() self.syspathinsert()
now = time.time() now = time.time()
@ -759,7 +757,7 @@ class Testdir:
return res return res
def runpytest(self, *args, **kwargs): def runpytest(self, *args, **kwargs):
""" Run pytest inline or in a subprocess, depending on the command line """Run pytest inline or in a subprocess, depending on the command line
option "--runpytest" and return a :py:class:`RunResult`. option "--runpytest" and return a :py:class:`RunResult`.
""" """
@ -780,13 +778,13 @@ class Testdir:
def parseconfig(self, *args): def parseconfig(self, *args):
"""Return a new pytest Config instance from given commandline args. """Return a new pytest Config instance from given commandline args.
This invokes the pytest bootstrapping code in _pytest.config This invokes the pytest bootstrapping code in _pytest.config to create
to create a new :py:class:`_pytest.core.PluginManager` and a new :py:class:`_pytest.core.PluginManager` and call the
call the pytest_cmdline_parse hook to create new pytest_cmdline_parse hook to create a new
:py:class:`_pytest.config.Config` instance. :py:class:`_pytest.config.Config` instance.
If :py:attr:`plugins` has been populated they should be plugin If :py:attr:`plugins` has been populated they should be plugin modules
modules which will be registered with the PluginManager. to be registered with the PluginManager.
""" """
args = self._ensure_basetemp(args) args = self._ensure_basetemp(args)
@ -802,9 +800,8 @@ class Testdir:
def parseconfigure(self, *args): def parseconfigure(self, *args):
"""Return a new pytest configured Config instance. """Return a new pytest configured Config instance.
This returns a new :py:class:`_pytest.config.Config` instance This returns a new :py:class:`_pytest.config.Config` instance like
like :py:meth:`parseconfig`, but also calls the :py:meth:`parseconfig`, but also calls the pytest_configure hook.
pytest_configure hook.
""" """
config = self.parseconfig(*args) config = self.parseconfig(*args)
@ -815,14 +812,14 @@ class Testdir:
def getitem(self, source, funcname="test_func"): def getitem(self, source, funcname="test_func"):
"""Return the test item for a test function. """Return the test item for a test function.
This writes the source to a python file and runs pytest's This writes the source to a python file and runs pytest's collection on
collection on the resulting module, returning the test item the resulting module, returning the test item for the requested
for the requested function name. function name.
:param source: The module source. :param source: the module source
:param funcname: The name of the test function for which the :param funcname: the name of the test function for which to return a
Item must be returned. test item
""" """
items = self.getitems(source) items = self.getitems(source)
@ -835,9 +832,8 @@ class Testdir:
def getitems(self, source): def getitems(self, source):
"""Return all test items collected from the module. """Return all test items collected from the module.
This writes the source to a python file and runs pytest's This writes the source to a python file and runs pytest's collection on
collection on the resulting module, returning all test items the resulting module, returning all test items contained within.
contained within.
""" """
modcol = self.getmodulecol(source) modcol = self.getmodulecol(source)
@ -846,17 +842,17 @@ class Testdir:
def getmodulecol(self, source, configargs=(), withinit=False): def getmodulecol(self, source, configargs=(), withinit=False):
"""Return the module collection node for ``source``. """Return the module collection node for ``source``.
This writes ``source`` to a file using :py:meth:`makepyfile` This writes ``source`` to a file using :py:meth:`makepyfile` and then
and then runs the pytest collection on it, returning the runs the pytest collection on it, returning the collection node for the
collection node for the test module. test module.
:param source: The source code of the module to collect. :param source: the source code of the module to collect
:param configargs: Any extra arguments to pass to :param configargs: any extra arguments to pass to
:py:meth:`parseconfigure`. :py:meth:`parseconfigure`
:param withinit: Whether to also write a ``__init__.py`` file :param withinit: whether to also write an ``__init__.py`` file to the
to the temporary directory to ensure it is a package. same directory to ensure it is a package
""" """
kw = {self.request.function.__name__: Source(source).strip()} kw = {self.request.function.__name__: Source(source).strip()}
@ -871,13 +867,12 @@ class Testdir:
def collect_by_name(self, modcol, name): def collect_by_name(self, modcol, name):
"""Return the collection node for name from the module collection. """Return the collection node for name from the module collection.
This will search a module collection node for a collection This will search a module collection node for a collection node
node matching the given name. matching the given name.
:param modcol: A module collection node, see :param modcol: a module collection node; see :py:meth:`getmodulecol`
:py:meth:`getmodulecol`.
:param name: The name of the node to return. :param name: the name of the node to return
""" """
if modcol not in self._mod_collections: if modcol not in self._mod_collections:
@ -889,8 +884,8 @@ class Testdir:
def popen(self, cmdargs, stdout, stderr, **kw): def popen(self, cmdargs, stdout, stderr, **kw):
"""Invoke subprocess.Popen. """Invoke subprocess.Popen.
This calls subprocess.Popen making sure the current working This calls subprocess.Popen making sure the current working directory
directory is the PYTHONPATH. is in the PYTHONPATH.
You probably want to use :py:meth:`run` instead. You probably want to use :py:meth:`run` instead.
@ -908,8 +903,7 @@ class Testdir:
def run(self, *cmdargs): def run(self, *cmdargs):
"""Run a command with arguments. """Run a command with arguments.
Run a process using subprocess.Popen saving the stdout and Run a process using subprocess.Popen saving the stdout and stderr.
stderr.
Returns a :py:class:`RunResult`. Returns a :py:class:`RunResult`.
@ -952,14 +946,15 @@ class Testdir:
print("couldn't print to %s because of encoding" % (fp,)) print("couldn't print to %s because of encoding" % (fp,))
def _getpytestargs(self): def _getpytestargs(self):
# we cannot use "(sys.executable,script)" # we cannot use `(sys.executable, script)` because on Windows the
# because on windows the script is e.g. a pytest.exe # script is e.g. `pytest.exe`
return (sys.executable, PYTEST_FULLPATH) # noqa return (sys.executable, PYTEST_FULLPATH) # noqa
def runpython(self, script): def runpython(self, script):
"""Run a python script using sys.executable as interpreter. """Run a python script using sys.executable as interpreter.
Returns a :py:class:`RunResult`. Returns a :py:class:`RunResult`.
""" """
return self.run(sys.executable, script) return self.run(sys.executable, script)
@ -970,12 +965,11 @@ class Testdir:
def runpytest_subprocess(self, *args, **kwargs): def runpytest_subprocess(self, *args, **kwargs):
"""Run pytest as a subprocess with given arguments. """Run pytest as a subprocess with given arguments.
Any plugins added to the :py:attr:`plugins` list will added Any plugins added to the :py:attr:`plugins` list will added using the
using the ``-p`` command line option. Addtionally ``-p`` command line option. Additionally ``--basetemp`` is used put
``--basetemp`` is used put any temporary files and directories any temporary files and directories in a numbered directory prefixed
in a numbered directory prefixed with "runpytest-" so they do with "runpytest-" so they do not conflict with the normal numbered
not conflict with the normal numberd pytest location for pytest location for temporary files and directories.
temporary files and directories.
Returns a :py:class:`RunResult`. Returns a :py:class:`RunResult`.
@ -998,8 +992,8 @@ class Testdir:
def spawn_pytest(self, string, expect_timeout=10.0): def spawn_pytest(self, string, expect_timeout=10.0):
"""Run pytest using pexpect. """Run pytest using pexpect.
This makes sure to use the right pytest and sets up the This makes sure to use the right pytest and sets up the temporary
temporary directory locations. directory locations.
The pexpect child is returned. The pexpect child is returned.
@ -1013,6 +1007,7 @@ class Testdir:
"""Run a command using pexpect. """Run a command using pexpect.
The pexpect child is returned. The pexpect child is returned.
""" """
pexpect = pytest.importorskip("pexpect", "3.0") pexpect = pytest.importorskip("pexpect", "3.0")
if hasattr(sys, 'pypy_version_info') and '64' in platform.machine(): if hasattr(sys, 'pypy_version_info') and '64' in platform.machine():
@ -1039,8 +1034,10 @@ class LineComp:
self.stringio = py.io.TextIO() self.stringio = py.io.TextIO()
def assert_contains_lines(self, lines2): def assert_contains_lines(self, lines2):
""" assert that lines2 are contained (linearly) in lines1. """Assert that lines2 are contained (linearly) in lines1.
return a list of extralines found.
Return a list of extralines found.
""" """
__tracebackhide__ = True __tracebackhide__ = True
val = self.stringio.getvalue() val = self.stringio.getvalue()
@ -1056,8 +1053,8 @@ class LineMatcher:
This is a convenience class to test large texts like the output of This is a convenience class to test large texts like the output of
commands. commands.
The constructor takes a list of lines without their trailing The constructor takes a list of lines without their trailing newlines, i.e.
newlines, i.e. ``text.splitlines()``. ``text.splitlines()``.
""" """
@ -1077,18 +1074,19 @@ class LineMatcher:
return lines2 return lines2
def fnmatch_lines_random(self, lines2): def fnmatch_lines_random(self, lines2):
"""Check lines exist in the output using ``fnmatch.fnmatch``, in any order. """Check lines exist in the output using in any order.
Lines are checked using ``fnmatch.fnmatch``. The argument is a list of
lines which have to occur in the output, in any order.
The argument is a list of lines which have to occur in the
output, in any order.
""" """
self._match_lines_random(lines2, fnmatch) self._match_lines_random(lines2, fnmatch)
def re_match_lines_random(self, lines2): def re_match_lines_random(self, lines2):
"""Check lines exist in the output using ``re.match``, in any order. """Check lines exist in the output using ``re.match``, in any order.
The argument is a list of lines which have to occur in the The argument is a list of lines which have to occur in the output, in
output, in any order. any order.
""" """
self._match_lines_random(lines2, lambda name, pat: re.match(pat, name)) self._match_lines_random(lines2, lambda name, pat: re.match(pat, name))
@ -1096,8 +1094,8 @@ class LineMatcher:
def _match_lines_random(self, lines2, match_func): def _match_lines_random(self, lines2, match_func):
"""Check lines exist in the output. """Check lines exist in the output.
The argument is a list of lines which have to occur in the The argument is a list of lines which have to occur in the output, in
output, in any order. Each line can contain glob whildcards. any order. Each line can contain glob whildcards.
""" """
lines2 = self._getlines(lines2) lines2 = self._getlines(lines2)
@ -1114,6 +1112,7 @@ class LineMatcher:
"""Return all lines following the given line in the text. """Return all lines following the given line in the text.
The given line can contain glob wildcards. The given line can contain glob wildcards.
""" """
for i, line in enumerate(self.lines): for i, line in enumerate(self.lines):
if fnline == line or fnmatch(line, fnline): if fnline == line or fnmatch(line, fnline):
@ -1130,10 +1129,9 @@ class LineMatcher:
def fnmatch_lines(self, lines2): def fnmatch_lines(self, lines2):
"""Search captured text for matching lines using ``fnmatch.fnmatch``. """Search captured text for matching lines using ``fnmatch.fnmatch``.
The argument is a list of lines which have to match and can The argument is a list of lines which have to match and can use glob
use glob wildcards. If they do not match a pytest.fail() is wildcards. If they do not match a pytest.fail() is called. The
called. The matches and non-matches are also printed on matches and non-matches are also printed on stdout.
stdout.
""" """
self._match_lines(lines2, fnmatch, 'fnmatch') self._match_lines(lines2, fnmatch, 'fnmatch')
@ -1144,21 +1142,22 @@ class LineMatcher:
The argument is a list of lines which have to match using ``re.match``. The argument is a list of lines which have to match using ``re.match``.
If they do not match a pytest.fail() is called. If they do not match a pytest.fail() is called.
The matches and non-matches are also printed on The matches and non-matches are also printed on stdout.
stdout.
""" """
self._match_lines(lines2, lambda name, pat: re.match(pat, name), 're.match') self._match_lines(lines2, lambda name, pat: re.match(pat, name), 're.match')
def _match_lines(self, lines2, match_func, match_nickname): def _match_lines(self, lines2, match_func, match_nickname):
"""Underlying implementation of ``fnmatch_lines`` and ``re_match_lines``. """Underlying implementation of ``fnmatch_lines`` and ``re_match_lines``.
:param list[str] lines2: list of string patterns to match. The actual format depends on :param list[str] lines2: list of string patterns to match. The actual
``match_func``. format depends on ``match_func``
:param match_func: a callable ``match_func(line, pattern)`` where line is the captured :param match_func: a callable ``match_func(line, pattern)`` where line
line from stdout/stderr and pattern is the matching pattern. is the captured line from stdout/stderr and pattern is the matching
pattern
:param str match_nickname: the nickname for the match function that
will be logged to stdout when a match occurs
:param str match_nickname: the nickname for the match function that will be logged
to stdout when a match occurs.
""" """
lines2 = self._getlines(lines2) lines2 = self._getlines(lines2)
lines1 = self.lines[:] lines1 = self.lines[:]