Merge branch 'master' into 'features'
This commit is contained in:
commit
199fcf93d4
2
AUTHORS
2
AUTHORS
|
@ -37,6 +37,7 @@ Erik M. Bray
|
||||||
Florian Bruhin
|
Florian Bruhin
|
||||||
Floris Bruynooghe
|
Floris Bruynooghe
|
||||||
Gabriel Reis
|
Gabriel Reis
|
||||||
|
Georgy Dyuldin
|
||||||
Graham Horler
|
Graham Horler
|
||||||
Grig Gheorghiu
|
Grig Gheorghiu
|
||||||
Guido Wesdorp
|
Guido Wesdorp
|
||||||
|
@ -77,3 +78,4 @@ Simon Gomizelj
|
||||||
Russel Winder
|
Russel Winder
|
||||||
Ben Webb
|
Ben Webb
|
||||||
Alexei Kozlenok
|
Alexei Kozlenok
|
||||||
|
Cal Leeming
|
||||||
|
|
|
@ -51,8 +51,12 @@
|
||||||
.. _@The-Compiler: https://github.com/The-Compiler
|
.. _@The-Compiler: https://github.com/The-Compiler
|
||||||
|
|
||||||
|
|
||||||
2.8.6.dev1
|
2.8.7.dev1
|
||||||
==========
|
----------
|
||||||
|
|
||||||
|
|
||||||
|
2.8.6
|
||||||
|
-----
|
||||||
|
|
||||||
- fix #1259: allow for double nodeids in junitxml,
|
- fix #1259: allow for double nodeids in junitxml,
|
||||||
this was a regression failing plugins combinations
|
this was a regression failing plugins combinations
|
||||||
|
@ -68,10 +72,20 @@
|
||||||
- fix #1292: monkeypatch calls (setattr, setenv, etc.) are now O(1).
|
- fix #1292: monkeypatch calls (setattr, setenv, etc.) are now O(1).
|
||||||
Thanks David R. MacIver for the report and Bruno Oliveira for the PR.
|
Thanks David R. MacIver for the report and Bruno Oliveira for the PR.
|
||||||
|
|
||||||
|
- fix #1223: captured stdout and stderr are now properly displayed before
|
||||||
|
entering pdb when ``--pdb`` is used instead of being thrown away.
|
||||||
|
Thanks Cal Leeming for the PR.
|
||||||
|
|
||||||
- fix #1305: pytest warnings emitted during ``pytest_terminal_summary`` are now
|
- fix #1305: pytest warnings emitted during ``pytest_terminal_summary`` are now
|
||||||
properly displayed.
|
properly displayed.
|
||||||
Thanks Ionel Maries Cristian for the report and Bruno Oliveira for the PR.
|
Thanks Ionel Maries Cristian for the report and Bruno Oliveira for the PR.
|
||||||
|
|
||||||
|
- fix #628: fixed internal UnicodeDecodeError when doctests contain unicode.
|
||||||
|
Thanks Jason R. Coombs for the report and Bruno Oliveira for the PR.
|
||||||
|
|
||||||
|
- fix #1334: Add captured stdout to jUnit XML report on setup error.
|
||||||
|
Thanks Georgy Dyuldin for the PR.
|
||||||
|
|
||||||
|
|
||||||
2.8.5
|
2.8.5
|
||||||
=====
|
=====
|
||||||
|
|
|
@ -27,10 +27,6 @@ Note: this assumes you have already registered on pypi.
|
||||||
devpi list pytest
|
devpi list pytest
|
||||||
|
|
||||||
or look at failures with "devpi list -f pytest".
|
or look at failures with "devpi list -f pytest".
|
||||||
There will be some failed environments like e.g. the py33-trial
|
|
||||||
or py27-pexpect tox environments on Win32 platforms
|
|
||||||
which is ok (tox does not support skipping on
|
|
||||||
per-platform basis yet).
|
|
||||||
|
|
||||||
7. Regenerate the docs examples using tox, and check for regressions::
|
7. Regenerate the docs examples using tox, and check for regressions::
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
.. image:: doc/en/img/pytest1.png
|
.. image:: http://pytest.org/latest/_static/pytest1.png
|
||||||
:target: http://pytest.org
|
:target: http://pytest.org
|
||||||
:align: center
|
:align: center
|
||||||
:alt: pytest
|
:alt: pytest
|
||||||
|
@ -60,7 +60,7 @@ Features
|
||||||
- Detailed info on failing `assert statements <http://pytest.org/latest/assert.html>`_ (no need to remember ``self.assert*`` names);
|
- Detailed info on failing `assert statements <http://pytest.org/latest/assert.html>`_ (no need to remember ``self.assert*`` names);
|
||||||
|
|
||||||
- `Auto-discovery
|
- `Auto-discovery
|
||||||
<http://pytest.org/latest/goodpractises.html#python-test-discovery>`_
|
<http://pytest.org/latest/goodpractices.html#python-test-discovery>`_
|
||||||
of test modules and functions;
|
of test modules and functions;
|
||||||
|
|
||||||
- `Modular fixtures <http://pytest.org/latest/fixture.html>`_ for
|
- `Modular fixtures <http://pytest.org/latest/fixture.html>`_ for
|
||||||
|
|
|
@ -120,9 +120,9 @@ def pytest_runtest_setup(item):
|
||||||
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:
|
||||||
if (sum(len(p) for p in new_expl[1:]) > 80*8
|
if (sum(len(p) for p in new_expl[1:]) > 80*8 and
|
||||||
and item.config.option.verbose < 2
|
item.config.option.verbose < 2 and
|
||||||
and not _running_on_ci()):
|
not _running_on_ci()):
|
||||||
show_max = 10
|
show_max = 10
|
||||||
truncated_lines = len(new_expl) - show_max
|
truncated_lines = len(new_expl) - show_max
|
||||||
new_expl[show_max:] = [py.builtin._totext(
|
new_expl[show_max:] = [py.builtin._totext(
|
||||||
|
|
|
@ -140,8 +140,8 @@ def assertrepr_compare(config, op, left, right):
|
||||||
|
|
||||||
summary = u('%s %s %s') % (ecu(left_repr), op, ecu(right_repr))
|
summary = u('%s %s %s') % (ecu(left_repr), op, ecu(right_repr))
|
||||||
|
|
||||||
issequence = lambda x: (isinstance(x, (list, tuple, Sequence))
|
issequence = lambda x: (isinstance(x, (list, tuple, Sequence)) and
|
||||||
and not isinstance(x, basestring))
|
not isinstance(x, basestring))
|
||||||
istext = lambda x: isinstance(x, basestring)
|
istext = lambda x: isinstance(x, basestring)
|
||||||
isdict = lambda x: isinstance(x, dict)
|
isdict = lambda x: isinstance(x, dict)
|
||||||
isset = lambda x: isinstance(x, (set, frozenset))
|
isset = lambda x: isinstance(x, (set, frozenset))
|
||||||
|
@ -263,8 +263,7 @@ def _compare_eq_sequence(left, right, verbose=False):
|
||||||
explanation += [
|
explanation += [
|
||||||
u('Right contains more items, first extra item: %s') %
|
u('Right contains more items, first extra item: %s') %
|
||||||
py.io.saferepr(right[len(left)],)]
|
py.io.saferepr(right[len(left)],)]
|
||||||
return explanation # + _diff_text(pprint.pformat(left),
|
return explanation
|
||||||
# pprint.pformat(right))
|
|
||||||
|
|
||||||
|
|
||||||
def _compare_eq_set(left, right, verbose=False):
|
def _compare_eq_set(left, right, verbose=False):
|
||||||
|
|
|
@ -90,15 +90,15 @@ class DoctestItem(pytest.Item):
|
||||||
reprlocation = ReprFileLocation(filename, lineno, message)
|
reprlocation = ReprFileLocation(filename, lineno, message)
|
||||||
checker = _get_checker()
|
checker = _get_checker()
|
||||||
REPORT_UDIFF = doctest.REPORT_UDIFF
|
REPORT_UDIFF = doctest.REPORT_UDIFF
|
||||||
filelines = py.path.local(filename).readlines(cr=0)
|
|
||||||
lines = []
|
|
||||||
if lineno is not None:
|
if lineno is not None:
|
||||||
i = max(test.lineno, max(0, lineno - 10)) # XXX?
|
lines = doctestfailure.test.docstring.splitlines(False)
|
||||||
for line in filelines[i:lineno]:
|
# add line numbers to the left of the error message
|
||||||
lines.append("%03d %s" % (i+1, line))
|
lines = ["%03d %s" % (i + test.lineno + 1, x)
|
||||||
i += 1
|
for (i, x) in enumerate(lines)]
|
||||||
|
# trim docstring error lines to 10
|
||||||
|
lines = lines[example.lineno - 9:example.lineno + 1]
|
||||||
else:
|
else:
|
||||||
lines.append('EXAMPLE LOCATION UNKNOWN, not showing all tests of that example')
|
lines = ['EXAMPLE LOCATION UNKNOWN, not showing all tests of that example']
|
||||||
indent = '>>>'
|
indent = '>>>'
|
||||||
for line in example.source.splitlines():
|
for line in example.source.splitlines():
|
||||||
lines.append('??? %s %s' % (indent, line))
|
lines.append('??? %s %s' % (indent, line))
|
||||||
|
|
|
@ -163,6 +163,7 @@ class _NodeReporter(object):
|
||||||
def append_error(self, report):
|
def append_error(self, report):
|
||||||
self._add_simple(
|
self._add_simple(
|
||||||
Junit.error, "test setup failure", report.longrepr)
|
Junit.error, "test setup failure", report.longrepr)
|
||||||
|
self._write_captured_output(report)
|
||||||
|
|
||||||
def append_skipped(self, report):
|
def append_skipped(self, report):
|
||||||
if hasattr(report, "wasxfail"):
|
if hasattr(report, "wasxfail"):
|
||||||
|
|
|
@ -52,7 +52,9 @@ class PdbInvoke:
|
||||||
def pytest_exception_interact(self, node, call, report):
|
def pytest_exception_interact(self, node, call, report):
|
||||||
capman = node.config.pluginmanager.getplugin("capturemanager")
|
capman = node.config.pluginmanager.getplugin("capturemanager")
|
||||||
if capman:
|
if capman:
|
||||||
capman.suspendcapture(in_=True)
|
out, err = capman.suspendcapture(in_=True)
|
||||||
|
sys.stdout.write(out)
|
||||||
|
sys.stdout.write(err)
|
||||||
_enter_pdb(node, call.excinfo, report)
|
_enter_pdb(node, call.excinfo, report)
|
||||||
|
|
||||||
def pytest_internalerror(self, excrepr, excinfo):
|
def pytest_internalerror(self, excrepr, excinfo):
|
||||||
|
|
|
@ -416,8 +416,8 @@ class PyCollector(PyobjMixin, pytest.Collector):
|
||||||
|
|
||||||
def istestfunction(self, obj, name):
|
def istestfunction(self, obj, name):
|
||||||
return (
|
return (
|
||||||
(self.funcnamefilter(name) or self.isnosetest(obj))
|
(self.funcnamefilter(name) or self.isnosetest(obj)) and
|
||||||
and safe_getattr(obj, "__call__", False) and getfixturemarker(obj) is None
|
safe_getattr(obj, "__call__", False) and getfixturemarker(obj) is None
|
||||||
)
|
)
|
||||||
|
|
||||||
def istestclass(self, obj, name):
|
def istestclass(self, obj, name):
|
||||||
|
@ -1765,8 +1765,10 @@ class FixtureLookupError(LookupError):
|
||||||
stack.extend(map(lambda x: x.func, self.fixturestack))
|
stack.extend(map(lambda x: x.func, self.fixturestack))
|
||||||
msg = self.msg
|
msg = self.msg
|
||||||
if msg is not None:
|
if msg is not None:
|
||||||
stack = stack[:-1] # the last fixture raise an error, let's present
|
# the last fixture raise an error, let's present
|
||||||
# it at the requesting side
|
# it at the requesting side
|
||||||
|
stack = stack[:-1]
|
||||||
|
|
||||||
for function in stack:
|
for function in stack:
|
||||||
fspath, lineno = getfslineno(function)
|
fspath, lineno = getfslineno(function)
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -24,9 +24,10 @@ def pytest_pycollect_makeitem(collector, name, obj):
|
||||||
|
|
||||||
|
|
||||||
class UnitTestCase(pytest.Class):
|
class UnitTestCase(pytest.Class):
|
||||||
nofuncargs = True # marker for fixturemanger.getfixtureinfo()
|
# marker for fixturemanger.getfixtureinfo()
|
||||||
# to declare that our children do not support funcargs
|
# to declare that our children do not support funcargs
|
||||||
#
|
nofuncargs = True
|
||||||
|
|
||||||
def setup(self):
|
def setup(self):
|
||||||
cls = self.obj
|
cls = self.obj
|
||||||
if getattr(cls, '__unittest_skip__', False):
|
if getattr(cls, '__unittest_skip__', False):
|
||||||
|
|
|
@ -6,6 +6,7 @@ Release announcements
|
||||||
:maxdepth: 2
|
:maxdepth: 2
|
||||||
|
|
||||||
|
|
||||||
|
release-2.8.6
|
||||||
release-2.8.5
|
release-2.8.5
|
||||||
release-2.8.4
|
release-2.8.4
|
||||||
release-2.8.3
|
release-2.8.3
|
||||||
|
|
|
@ -0,0 +1,67 @@
|
||||||
|
pytest-2.8.6
|
||||||
|
============
|
||||||
|
|
||||||
|
pytest is a mature Python testing tool with more than a 1100 tests
|
||||||
|
against itself, passing on many different interpreters and platforms.
|
||||||
|
This release is supposed to be drop-in compatible to 2.8.5.
|
||||||
|
|
||||||
|
See below for the changes and see docs at:
|
||||||
|
|
||||||
|
http://pytest.org
|
||||||
|
|
||||||
|
As usual, you can upgrade from pypi via::
|
||||||
|
|
||||||
|
pip install -U pytest
|
||||||
|
|
||||||
|
Thanks to all who contributed to this release, among them:
|
||||||
|
|
||||||
|
AMiT Kumar
|
||||||
|
Bruno Oliveira
|
||||||
|
Erik M. Bray
|
||||||
|
Florian Bruhin
|
||||||
|
Georgy Dyuldin
|
||||||
|
Jeff Widman
|
||||||
|
Kartik Singhal
|
||||||
|
Loïc Estève
|
||||||
|
Manu Phatak
|
||||||
|
Peter Demin
|
||||||
|
Rick van Hattem
|
||||||
|
Ronny Pfannschmidt
|
||||||
|
Ulrich Petri
|
||||||
|
foxx
|
||||||
|
|
||||||
|
|
||||||
|
Happy testing,
|
||||||
|
The py.test Development Team
|
||||||
|
|
||||||
|
|
||||||
|
2.8.6 (compared to 2.8.5)
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
- fix #1259: allow for double nodeids in junitxml,
|
||||||
|
this was a regression failing plugins combinations
|
||||||
|
like pytest-pep8 + pytest-flakes
|
||||||
|
|
||||||
|
- Workaround for exception that occurs in pyreadline when using
|
||||||
|
``--pdb`` with standard I/O capture enabled.
|
||||||
|
Thanks Erik M. Bray for the PR.
|
||||||
|
|
||||||
|
- fix #900: Better error message in case the target of a ``monkeypatch`` call
|
||||||
|
raises an ``ImportError``.
|
||||||
|
|
||||||
|
- fix #1292: monkeypatch calls (setattr, setenv, etc.) are now O(1).
|
||||||
|
Thanks David R. MacIver for the report and Bruno Oliveira for the PR.
|
||||||
|
|
||||||
|
- fix #1223: captured stdout and stderr are now properly displayed before
|
||||||
|
entering pdb when ``--pdb`` is used instead of being thrown away.
|
||||||
|
Thanks Cal Leeming for the PR.
|
||||||
|
|
||||||
|
- fix #1305: pytest warnings emitted during ``pytest_terminal_summary`` are now
|
||||||
|
properly displayed.
|
||||||
|
Thanks Ionel Maries Cristian for the report and Bruno Oliveira for the PR.
|
||||||
|
|
||||||
|
- fix #628: fixed internal UnicodeDecodeError when doctests contain unicode.
|
||||||
|
Thanks Jason R. Coombs for the report and Bruno Oliveira for the PR.
|
||||||
|
|
||||||
|
- fix #1334: Add captured stdout to jUnit XML report on setup error.
|
||||||
|
Thanks Georgy Dyuldin for the PR.
|
|
@ -193,7 +193,7 @@ Where to go next
|
||||||
Here are a few suggestions where to go next:
|
Here are a few suggestions where to go next:
|
||||||
|
|
||||||
* :ref:`cmdline` for command line invocation examples
|
* :ref:`cmdline` for command line invocation examples
|
||||||
* :ref:`good practises <goodpractises>` for virtualenv, test layout, genscript support
|
* :ref:`good practices <goodpractices>` for virtualenv, test layout, genscript support
|
||||||
* :ref:`fixtures` for providing a functional baseline to your tests
|
* :ref:`fixtures` for providing a functional baseline to your tests
|
||||||
* :ref:`apiref` for documentation and examples on using ``pytest``
|
* :ref:`apiref` for documentation and examples on using ``pytest``
|
||||||
* :ref:`plugins` managing and writing plugins
|
* :ref:`plugins` managing and writing plugins
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
.. highlightlang:: python
|
.. highlightlang:: python
|
||||||
.. _`goodpractises`:
|
.. _`goodpractices`:
|
||||||
|
|
||||||
Good Integration Practices
|
Good Integration Practices
|
||||||
=================================================
|
=================================================
|
|
@ -40,7 +40,7 @@ pytest: helps you write better programs
|
||||||
- multi-paradigm: pytest can run ``nose``, ``unittest`` and
|
- multi-paradigm: pytest can run ``nose``, ``unittest`` and
|
||||||
``doctest`` style test suites, including running testcases made for
|
``doctest`` style test suites, including running testcases made for
|
||||||
Django and trial
|
Django and trial
|
||||||
- supports :ref:`good integration practises <goodpractises>`
|
- supports :ref:`good integration practices <goodpractices>`
|
||||||
- supports extended :ref:`xUnit style setup <xunitsetup>`
|
- supports extended :ref:`xUnit style setup <xunitsetup>`
|
||||||
- supports domain-specific :ref:`non-python tests`
|
- supports domain-specific :ref:`non-python tests`
|
||||||
- supports generating `test coverage reports
|
- supports generating `test coverage reports
|
||||||
|
|
|
@ -7,7 +7,7 @@ Getting started basics
|
||||||
|
|
||||||
getting-started
|
getting-started
|
||||||
usage
|
usage
|
||||||
goodpractises
|
goodpractices
|
||||||
projects
|
projects
|
||||||
faq
|
faq
|
||||||
|
|
||||||
|
|
|
@ -41,15 +41,15 @@ to an expected output::
|
||||||
|
|
||||||
# content of test_expectation.py
|
# content of test_expectation.py
|
||||||
import pytest
|
import pytest
|
||||||
@pytest.mark.parametrize("input,expected", [
|
@pytest.mark.parametrize("test_input,expected", [
|
||||||
("3+5", 8),
|
("3+5", 8),
|
||||||
("2+4", 6),
|
("2+4", 6),
|
||||||
("6*9", 42),
|
("6*9", 42),
|
||||||
])
|
])
|
||||||
def test_eval(input, expected):
|
def test_eval(test_input, expected):
|
||||||
assert eval(input) == expected
|
assert eval(test_input) == expected
|
||||||
|
|
||||||
Here, the ``@parametrize`` decorator defines three different ``(input,expected)``
|
Here, the ``@parametrize`` decorator defines three different ``(test_input,expected)``
|
||||||
tuples so that the ``test_eval`` function will run three times using
|
tuples so that the ``test_eval`` function will run three times using
|
||||||
them in turn::
|
them in turn::
|
||||||
|
|
||||||
|
@ -64,15 +64,15 @@ them in turn::
|
||||||
======= FAILURES ========
|
======= FAILURES ========
|
||||||
_______ test_eval[6*9-42] ________
|
_______ test_eval[6*9-42] ________
|
||||||
|
|
||||||
input = '6*9', expected = 42
|
test_input = '6*9', expected = 42
|
||||||
|
|
||||||
@pytest.mark.parametrize("input,expected", [
|
@pytest.mark.parametrize("test_input,expected", [
|
||||||
("3+5", 8),
|
("3+5", 8),
|
||||||
("2+4", 6),
|
("2+4", 6),
|
||||||
("6*9", 42),
|
("6*9", 42),
|
||||||
])
|
])
|
||||||
def test_eval(input, expected):
|
def test_eval(test_input, expected):
|
||||||
> assert eval(input) == expected
|
> assert eval(test_input) == expected
|
||||||
E assert 54 == 42
|
E assert 54 == 42
|
||||||
E + where 54 = eval('6*9')
|
E + where 54 = eval('6*9')
|
||||||
|
|
||||||
|
@ -91,13 +91,13 @@ for example with the builtin ``mark.xfail``::
|
||||||
|
|
||||||
# content of test_expectation.py
|
# content of test_expectation.py
|
||||||
import pytest
|
import pytest
|
||||||
@pytest.mark.parametrize("input,expected", [
|
@pytest.mark.parametrize("test_input,expected", [
|
||||||
("3+5", 8),
|
("3+5", 8),
|
||||||
("2+4", 6),
|
("2+4", 6),
|
||||||
pytest.mark.xfail(("6*9", 42)),
|
pytest.mark.xfail(("6*9", 42)),
|
||||||
])
|
])
|
||||||
def test_eval(input, expected):
|
def test_eval(test_input, expected):
|
||||||
assert eval(input) == expected
|
assert eval(test_input) == expected
|
||||||
|
|
||||||
Let's run this::
|
Let's run this::
|
||||||
|
|
||||||
|
|
|
@ -56,7 +56,7 @@ Here is a little annotated list for some popular plugins:
|
||||||
check source code with pyflakes.
|
check source code with pyflakes.
|
||||||
|
|
||||||
* `oejskit <http://pypi.python.org/pypi/oejskit>`_:
|
* `oejskit <http://pypi.python.org/pypi/oejskit>`_:
|
||||||
a plugin to run javascript unittests in life browsers.
|
a plugin to run javascript unittests in live browsers.
|
||||||
|
|
||||||
To see a complete list of all plugins with their latest testing
|
To see a complete list of all plugins with their latest testing
|
||||||
status against different py.test and Python versions, please visit
|
status against different py.test and Python versions, please visit
|
||||||
|
|
|
@ -95,7 +95,7 @@ Here is how you might run it::
|
||||||
python package directory (i.e. one containing an ``__init__.py``) then
|
python package directory (i.e. one containing an ``__init__.py``) then
|
||||||
"import conftest" can be ambiguous because there might be other
|
"import conftest" can be ambiguous because there might be other
|
||||||
``conftest.py`` files as well on your PYTHONPATH or ``sys.path``.
|
``conftest.py`` files as well on your PYTHONPATH or ``sys.path``.
|
||||||
It is thus good practise for projects to either put ``conftest.py``
|
It is thus good practice for projects to either put ``conftest.py``
|
||||||
under a package scope or to never import anything from a
|
under a package scope or to never import anything from a
|
||||||
conftest.py file.
|
conftest.py file.
|
||||||
|
|
||||||
|
@ -485,12 +485,20 @@ Session related reporting hooks:
|
||||||
.. autofunction:: pytest_itemcollected
|
.. autofunction:: pytest_itemcollected
|
||||||
.. autofunction:: pytest_collectreport
|
.. autofunction:: pytest_collectreport
|
||||||
.. autofunction:: pytest_deselected
|
.. autofunction:: pytest_deselected
|
||||||
|
.. autofunction:: pytest_report_header
|
||||||
|
.. autofunction:: pytest_report_teststatus
|
||||||
|
.. autofunction:: pytest_terminal_summary
|
||||||
|
|
||||||
And here is the central hook for reporting about
|
And here is the central hook for reporting about
|
||||||
test execution:
|
test execution:
|
||||||
|
|
||||||
.. autofunction:: pytest_runtest_logreport
|
.. autofunction:: pytest_runtest_logreport
|
||||||
|
|
||||||
|
You can also use this hook to customize assertion representation for some
|
||||||
|
types:
|
||||||
|
|
||||||
|
.. autofunction:: pytest_assertrepr_compare
|
||||||
|
|
||||||
|
|
||||||
Debugging/Interaction hooks
|
Debugging/Interaction hooks
|
||||||
---------------------------
|
---------------------------
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
# encoding: utf-8
|
||||||
import sys
|
import sys
|
||||||
from _pytest.doctest import DoctestItem, DoctestModule, DoctestTextfile
|
from _pytest.doctest import DoctestItem, DoctestModule, DoctestTextfile
|
||||||
import py
|
import py
|
||||||
|
@ -139,6 +140,46 @@ class TestDoctests:
|
||||||
"*UNEXPECTED*ZeroDivision*",
|
"*UNEXPECTED*ZeroDivision*",
|
||||||
])
|
])
|
||||||
|
|
||||||
|
def test_docstring_context_around_error(self, testdir):
|
||||||
|
"""Test that we show some context before the actual line of a failing
|
||||||
|
doctest.
|
||||||
|
"""
|
||||||
|
testdir.makepyfile('''
|
||||||
|
def foo():
|
||||||
|
"""
|
||||||
|
text-line-1
|
||||||
|
text-line-2
|
||||||
|
text-line-3
|
||||||
|
text-line-4
|
||||||
|
text-line-5
|
||||||
|
text-line-6
|
||||||
|
text-line-7
|
||||||
|
text-line-8
|
||||||
|
text-line-9
|
||||||
|
text-line-10
|
||||||
|
text-line-11
|
||||||
|
>>> 1 + 1
|
||||||
|
3
|
||||||
|
|
||||||
|
text-line-after
|
||||||
|
"""
|
||||||
|
''')
|
||||||
|
result = testdir.runpytest('--doctest-modules')
|
||||||
|
result.stdout.fnmatch_lines([
|
||||||
|
'*docstring_context_around_error*',
|
||||||
|
'005*text-line-3',
|
||||||
|
'006*text-line-4',
|
||||||
|
'013*text-line-11',
|
||||||
|
'014*>>> 1 + 1',
|
||||||
|
'Expected:',
|
||||||
|
' 3',
|
||||||
|
'Got:',
|
||||||
|
' 2',
|
||||||
|
])
|
||||||
|
# lines below should be trimmed out
|
||||||
|
assert 'text-line-2' not in result.stdout.str()
|
||||||
|
assert 'text-line-after' not in result.stdout.str()
|
||||||
|
|
||||||
def test_doctest_linedata_missing(self, testdir):
|
def test_doctest_linedata_missing(self, testdir):
|
||||||
testdir.tmpdir.join('hello.py').write(py.code.Source("""
|
testdir.tmpdir.join('hello.py').write(py.code.Source("""
|
||||||
class Fun(object):
|
class Fun(object):
|
||||||
|
@ -369,6 +410,23 @@ class TestDoctests:
|
||||||
reprec = testdir.inline_run(p, "--doctest-glob=x*.txt")
|
reprec = testdir.inline_run(p, "--doctest-glob=x*.txt")
|
||||||
reprec.assertoutcome(failed=1, passed=0)
|
reprec.assertoutcome(failed=1, passed=0)
|
||||||
|
|
||||||
|
def test_contains_unicode(self, testdir):
|
||||||
|
"""Fix internal error with docstrings containing non-ascii characters.
|
||||||
|
"""
|
||||||
|
testdir.makepyfile(u'''
|
||||||
|
# encoding: utf-8
|
||||||
|
def foo():
|
||||||
|
"""
|
||||||
|
>>> name = 'с' # not letter 'c' but instead Cyrillic 's'.
|
||||||
|
'anything'
|
||||||
|
"""
|
||||||
|
''')
|
||||||
|
result = testdir.runpytest('--doctest-modules')
|
||||||
|
result.stdout.fnmatch_lines([
|
||||||
|
'Got nothing',
|
||||||
|
'* 1 failed in*',
|
||||||
|
])
|
||||||
|
|
||||||
def test_ignore_import_errors_on_doctest(self, testdir):
|
def test_ignore_import_errors_on_doctest(self, testdir):
|
||||||
p = testdir.makepyfile("""
|
p = testdir.makepyfile("""
|
||||||
import asdf
|
import asdf
|
||||||
|
|
|
@ -419,6 +419,35 @@ class TestPython:
|
||||||
systemout = pnode.find_first_by_tag("system-err")
|
systemout = pnode.find_first_by_tag("system-err")
|
||||||
assert "hello-stderr" in systemout.toxml()
|
assert "hello-stderr" in systemout.toxml()
|
||||||
|
|
||||||
|
def test_setup_error_captures_stdout(self, testdir):
|
||||||
|
testdir.makepyfile("""
|
||||||
|
def pytest_funcarg__arg(request):
|
||||||
|
print('hello-stdout')
|
||||||
|
raise ValueError()
|
||||||
|
def test_function(arg):
|
||||||
|
pass
|
||||||
|
""")
|
||||||
|
result, dom = runandparse(testdir)
|
||||||
|
node = dom.find_first_by_tag("testsuite")
|
||||||
|
pnode = node.find_first_by_tag("testcase")
|
||||||
|
systemout = pnode.find_first_by_tag("system-out")
|
||||||
|
assert "hello-stdout" in systemout.toxml()
|
||||||
|
|
||||||
|
def test_setup_error_captures_stderr(self, testdir):
|
||||||
|
testdir.makepyfile("""
|
||||||
|
import sys
|
||||||
|
def pytest_funcarg__arg(request):
|
||||||
|
sys.stderr.write('hello-stderr')
|
||||||
|
raise ValueError()
|
||||||
|
def test_function(arg):
|
||||||
|
pass
|
||||||
|
""")
|
||||||
|
result, dom = runandparse(testdir)
|
||||||
|
node = dom.find_first_by_tag("testsuite")
|
||||||
|
pnode = node.find_first_by_tag("testcase")
|
||||||
|
systemout = pnode.find_first_by_tag("system-err")
|
||||||
|
assert "hello-stderr" in systemout.toxml()
|
||||||
|
|
||||||
|
|
||||||
def test_mangle_testnames():
|
def test_mangle_testnames():
|
||||||
from _pytest.junitxml import mangle_testnames
|
from _pytest.junitxml import mangle_testnames
|
||||||
|
|
|
@ -75,6 +75,22 @@ class TestPDB:
|
||||||
if child.isalive():
|
if child.isalive():
|
||||||
child.wait()
|
child.wait()
|
||||||
|
|
||||||
|
def test_pdb_interaction_capture(self, testdir):
|
||||||
|
p1 = testdir.makepyfile("""
|
||||||
|
def test_1():
|
||||||
|
print("getrekt")
|
||||||
|
assert False
|
||||||
|
""")
|
||||||
|
child = testdir.spawn_pytest("--pdb %s" % p1)
|
||||||
|
child.expect("getrekt")
|
||||||
|
child.expect("(Pdb)")
|
||||||
|
child.sendeof()
|
||||||
|
rest = child.read().decode("utf8")
|
||||||
|
assert "1 failed" in rest
|
||||||
|
assert "getrekt" not in rest
|
||||||
|
if child.isalive():
|
||||||
|
child.wait()
|
||||||
|
|
||||||
def test_pdb_interaction_exception(self, testdir):
|
def test_pdb_interaction_exception(self, testdir):
|
||||||
p1 = testdir.makepyfile("""
|
p1 = testdir.makepyfile("""
|
||||||
import pytest
|
import pytest
|
||||||
|
|
2
tox.ini
2
tox.ini
|
@ -157,4 +157,4 @@ norecursedirs = .tox ja .hg cx_freeze_source
|
||||||
|
|
||||||
|
|
||||||
[flake8]
|
[flake8]
|
||||||
ignore =E401,E225,E261,E128,E124,E301,E302,E121,E303,W391,E501,E231,E126,E701,E265,E241,E251,E226,E101,W191,E131,E203,E122,E123,E271,E712,E222,E127,E125,E221,W292,E111,E113,E293,E262,W293,E129,E702,E201,E272,E202
|
ignore =E401,E225,E261,E128,E124,E301,E302,E121,E303,W391,E501,E231,E126,E701,E265,E241,E251,E226,E101,W191,E131,E203,E122,E123,E271,E712,E222,E127,E125,E221,W292,E111,E113,E293,E262,W293,E129,E702,E201,E272,E202,E704,E731,E402
|
||||||
|
|
Loading…
Reference in New Issue