Compare commits
29 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dd9a27cf54 | ||
|
|
5e8c47faad | ||
|
|
92d6a0500b | ||
|
|
6f2c0fd2e8 | ||
|
|
55a58bcd3d | ||
|
|
0b40749c98 | ||
|
|
adccb63de0 | ||
|
|
41604eeb3e | ||
|
|
85288b5321 | ||
|
|
5f9db8a017 | ||
|
|
957adbbbc7 | ||
|
|
990d75b7e6 | ||
|
|
f9e3a5395c | ||
|
|
0760406480 | ||
|
|
14580c7e31 | ||
|
|
35800a2f73 | ||
|
|
abc890079f | ||
|
|
dc5a4fbe23 | ||
|
|
285524c6cd | ||
|
|
cefe6bfec3 | ||
|
|
ac633b8969 | ||
|
|
0b8c35516f | ||
|
|
96de232791 | ||
|
|
2fc1f7b8dc | ||
|
|
dae238c9b1 | ||
|
|
5cefcb2052 | ||
|
|
b94eb4cb7b | ||
|
|
9275012ef7 | ||
|
|
810db2726d |
@@ -60,7 +60,7 @@ jobs:
|
||||
- env: TOXENV=py37-freeze
|
||||
|
||||
- env: TOXENV=py38-xdist
|
||||
python: '3.8-dev'
|
||||
python: '3.8'
|
||||
|
||||
- stage: baseline
|
||||
env: TOXENV=py36-xdist
|
||||
@@ -94,11 +94,6 @@ jobs:
|
||||
tags: true
|
||||
repo: pytest-dev/pytest
|
||||
|
||||
matrix:
|
||||
allow_failures:
|
||||
- python: '3.8-dev'
|
||||
env: TOXENV=py38-xdist
|
||||
|
||||
before_script:
|
||||
- |
|
||||
# Do not (re-)upload coverage with cron runs.
|
||||
|
||||
1
AUTHORS
1
AUTHORS
@@ -70,6 +70,7 @@ Daniel Hahler
|
||||
Daniel Nuri
|
||||
Daniel Wandschneider
|
||||
Danielle Jenkins
|
||||
Daniil Galiev
|
||||
Dave Hunt
|
||||
David Díaz-Barquero
|
||||
David Mohr
|
||||
|
||||
@@ -13,11 +13,27 @@ with advance notice in the **Deprecations** section of releases.
|
||||
file is managed by towncrier. You *may* edit previous change logs to
|
||||
fix problems like typo corrections or such.
|
||||
To add a new change log entry, please see
|
||||
https://pip.pypa.io/en/latest/development/#adding-a-news-entry
|
||||
https://pip.pypa.io/en/latest/development/contributing/#news-entries
|
||||
we named the news folder changelog
|
||||
|
||||
.. towncrier release notes start
|
||||
|
||||
pytest 5.2.3 (2019-11-14)
|
||||
=========================
|
||||
|
||||
Bug Fixes
|
||||
---------
|
||||
|
||||
- `#5830 <https://github.com/pytest-dev/pytest/issues/5830>`_: The first test in a package (``__init__.py``) marked with ``@pytest.mark.skip`` is now correctly skipped.
|
||||
|
||||
|
||||
- `#6099 <https://github.com/pytest-dev/pytest/issues/6099>`_: Fix ``--trace`` when used with parametrized functions.
|
||||
|
||||
|
||||
- `#6183 <https://github.com/pytest-dev/pytest/issues/6183>`_: Using ``request`` as a parameter name in ``@pytest.mark.parametrize`` now produces a more
|
||||
user-friendly error.
|
||||
|
||||
|
||||
pytest 5.2.2 (2019-10-24)
|
||||
=========================
|
||||
|
||||
@@ -47,33 +63,6 @@ Bug Fixes
|
||||
- `#5902 <https://github.com/pytest-dev/pytest/issues/5902>`_: Fix warnings about deprecated ``cmp`` attribute in ``attrs>=19.2``.
|
||||
|
||||
|
||||
pytest 4.6.6 (2019-10-11)
|
||||
=========================
|
||||
|
||||
Bug Fixes
|
||||
---------
|
||||
|
||||
- `#5523 <https://github.com/pytest-dev/pytest/issues/5523>`_: Fixed using multiple short options together in the command-line (for example ``-vs``) in Python 3.8+.
|
||||
|
||||
|
||||
- `#5537 <https://github.com/pytest-dev/pytest/issues/5537>`_: Replace ``importlib_metadata`` backport with ``importlib.metadata`` from the
|
||||
standard library on Python 3.8+.
|
||||
|
||||
|
||||
- `#5806 <https://github.com/pytest-dev/pytest/issues/5806>`_: Fix "lexer" being used when uploading to bpaste.net from ``--pastebin`` to "text".
|
||||
|
||||
|
||||
- `#5902 <https://github.com/pytest-dev/pytest/issues/5902>`_: Fix warnings about deprecated ``cmp`` attribute in ``attrs>=19.2``.
|
||||
|
||||
|
||||
|
||||
Trivial/Internal Changes
|
||||
------------------------
|
||||
|
||||
- `#5801 <https://github.com/pytest-dev/pytest/issues/5801>`_: Fixes python version checks (detected by ``flake8-2020``) in case python4 becomes a thing.
|
||||
|
||||
|
||||
|
||||
pytest 5.2.0 (2019-09-28)
|
||||
=========================
|
||||
|
||||
@@ -544,6 +533,32 @@ Improved Documentation
|
||||
- `#5416 <https://github.com/pytest-dev/pytest/issues/5416>`_: Fix PytestUnknownMarkWarning in run/skip example.
|
||||
|
||||
|
||||
pytest 4.6.6 (2019-10-11)
|
||||
=========================
|
||||
|
||||
Bug Fixes
|
||||
---------
|
||||
|
||||
- `#5523 <https://github.com/pytest-dev/pytest/issues/5523>`_: Fixed using multiple short options together in the command-line (for example ``-vs``) in Python 3.8+.
|
||||
|
||||
|
||||
- `#5537 <https://github.com/pytest-dev/pytest/issues/5537>`_: Replace ``importlib_metadata`` backport with ``importlib.metadata`` from the
|
||||
standard library on Python 3.8+.
|
||||
|
||||
|
||||
- `#5806 <https://github.com/pytest-dev/pytest/issues/5806>`_: Fix "lexer" being used when uploading to bpaste.net from ``--pastebin`` to "text".
|
||||
|
||||
|
||||
- `#5902 <https://github.com/pytest-dev/pytest/issues/5902>`_: Fix warnings about deprecated ``cmp`` attribute in ``attrs>=19.2``.
|
||||
|
||||
|
||||
|
||||
Trivial/Internal Changes
|
||||
------------------------
|
||||
|
||||
- `#5801 <https://github.com/pytest-dev/pytest/issues/5801>`_: Fixes python version checks (detected by ``flake8-2020``) in case python4 becomes a thing.
|
||||
|
||||
|
||||
pytest 4.6.5 (2019-08-05)
|
||||
=========================
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ Release announcements
|
||||
:maxdepth: 2
|
||||
|
||||
|
||||
release-5.2.3
|
||||
release-5.2.2
|
||||
release-5.2.1
|
||||
release-5.2.0
|
||||
|
||||
28
doc/en/announce/release-5.2.3.rst
Normal file
28
doc/en/announce/release-5.2.3.rst
Normal file
@@ -0,0 +1,28 @@
|
||||
pytest-5.2.3
|
||||
=======================================
|
||||
|
||||
pytest 5.2.3 has just been released to PyPI.
|
||||
|
||||
This is a bug-fix release, being a drop-in replacement. To upgrade::
|
||||
|
||||
pip install --upgrade pytest
|
||||
|
||||
The full changelog is available at https://docs.pytest.org/en/latest/changelog.html.
|
||||
|
||||
Thanks to all who contributed to this release, among them:
|
||||
|
||||
* Anthony Sottile
|
||||
* Brett Cannon
|
||||
* Bruno Oliveira
|
||||
* Daniel Hahler
|
||||
* Daniil Galiev
|
||||
* David Szotten
|
||||
* Florian Bruhin
|
||||
* Patrick Harmon
|
||||
* Ran Benita
|
||||
* Zac Hatfield-Dodds
|
||||
* Zak Hassan
|
||||
|
||||
|
||||
Happy testing,
|
||||
The pytest Development Team
|
||||
@@ -475,10 +475,10 @@ Running it results in some skips if we don't have all the python interpreters in
|
||||
.. code-block:: pytest
|
||||
|
||||
. $ pytest -rs -q multipython.py
|
||||
ssssssssssssssssssssssss... [100%]
|
||||
ssssssssssss...ssssssssssss [100%]
|
||||
========================= short test summary info ==========================
|
||||
SKIPPED [12] $REGENDOC_TMPDIR/CWD/multipython.py:30: 'python3.5' not found
|
||||
SKIPPED [12] $REGENDOC_TMPDIR/CWD/multipython.py:30: 'python3.6' not found
|
||||
SKIPPED [12] $REGENDOC_TMPDIR/CWD/multipython.py:30: 'python3.7' not found
|
||||
3 passed, 24 skipped in 0.12s
|
||||
|
||||
Indirect parametrization of optional implementations/imports
|
||||
|
||||
@@ -436,7 +436,7 @@ Here is a nice run of several failures and how ``pytest`` presents things:
|
||||
items = [1, 2, 3]
|
||||
print("items is {!r}".format(items))
|
||||
> a, b = items.pop()
|
||||
E TypeError: cannot unpack non-iterable int object
|
||||
E TypeError: 'int' object is not iterable
|
||||
|
||||
failure_demo.py:181: TypeError
|
||||
--------------------------- Captured stdout call ---------------------------
|
||||
@@ -516,7 +516,7 @@ Here is a nice run of several failures and how ``pytest`` presents things:
|
||||
def test_z2_type_error(self):
|
||||
items = 3
|
||||
> a, b = items
|
||||
E TypeError: cannot unpack non-iterable int object
|
||||
E TypeError: 'int' object is not iterable
|
||||
|
||||
failure_demo.py:222: TypeError
|
||||
______________________ TestMoreErrors.test_startswith ______________________
|
||||
|
||||
@@ -28,7 +28,7 @@ Install ``pytest``
|
||||
.. code-block:: bash
|
||||
|
||||
$ pytest --version
|
||||
This is pytest version 5.x.y, imported from $PYTHON_PREFIX/lib/python3.7/site-packages/pytest.py
|
||||
This is pytest version 5.x.y, imported from $PYTHON_PREFIX/lib/python3.6/site-packages/pytest.py
|
||||
|
||||
.. _`simpletest`:
|
||||
|
||||
|
||||
@@ -59,7 +59,7 @@ pytest.raises
|
||||
|
||||
**Tutorial**: :ref:`assertraises`.
|
||||
|
||||
.. autofunction:: pytest.raises(expected_exception: Exception, [match])
|
||||
.. autofunction:: pytest.raises(expected_exception: Exception [, *, match])
|
||||
:with: excinfo
|
||||
|
||||
pytest.deprecated_call
|
||||
|
||||
@@ -57,7 +57,7 @@ upload-dir = doc/en/build/html
|
||||
|
||||
[check-manifest]
|
||||
ignore =
|
||||
_pytest/_version.py
|
||||
src/_pytest/_version.py
|
||||
|
||||
[devpi:upload]
|
||||
formats = sdist.tgz,bdist_wheel
|
||||
|
||||
@@ -4,6 +4,7 @@ import sys
|
||||
import traceback
|
||||
from inspect import CO_VARARGS
|
||||
from inspect import CO_VARKEYWORDS
|
||||
from io import StringIO
|
||||
from traceback import format_exception_only
|
||||
from types import CodeType
|
||||
from types import TracebackType
|
||||
@@ -136,7 +137,7 @@ class Frame:
|
||||
def exec_(self, code, **vars):
|
||||
""" exec 'code' in the frame
|
||||
|
||||
'vars' are optiona; additional local variables
|
||||
'vars' are optional; additional local variables
|
||||
"""
|
||||
f_locals = self.f_locals.copy()
|
||||
f_locals.update(vars)
|
||||
@@ -206,7 +207,7 @@ class TracebackEntry:
|
||||
|
||||
@property
|
||||
def locals(self):
|
||||
""" locals of underlaying frame """
|
||||
""" locals of underlying frame """
|
||||
return self.frame.f_locals
|
||||
|
||||
def getfirstlinesource(self):
|
||||
@@ -273,7 +274,7 @@ class TracebackEntry:
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
""" co_name of underlaying code """
|
||||
""" co_name of underlying code """
|
||||
return self.frame.code.raw.co_name
|
||||
|
||||
|
||||
@@ -301,7 +302,7 @@ class Traceback(list):
|
||||
def cut(self, path=None, lineno=None, firstlineno=None, excludepath=None):
|
||||
""" return a Traceback instance wrapping part of this Traceback
|
||||
|
||||
by provding any combination of path, lineno and firstlineno, the
|
||||
by providing any combination of path, lineno and firstlineno, the
|
||||
first frame to start the to-be-returned traceback is determined
|
||||
|
||||
this allows cutting the first part of a Traceback instance e.g.
|
||||
@@ -865,7 +866,7 @@ class TerminalRepr:
|
||||
def __str__(self):
|
||||
# FYI this is called from pytest-xdist's serialization of exception
|
||||
# information.
|
||||
io = py.io.TextIO()
|
||||
io = StringIO()
|
||||
tw = py.io.TerminalWriter(file=io)
|
||||
self.toterminal(tw)
|
||||
return io.getvalue().strip()
|
||||
@@ -1002,7 +1003,7 @@ class ReprFileLocation(TerminalRepr):
|
||||
|
||||
def toterminal(self, tw):
|
||||
# filename and lineno output for each entry,
|
||||
# using an output format that most editors unterstand
|
||||
# using an output format that most editors understand
|
||||
msg = self.message
|
||||
i = msg.find("\n")
|
||||
if i != -1:
|
||||
|
||||
@@ -31,7 +31,6 @@ def format_explanation(explanation):
|
||||
for when one explanation needs to span multiple lines, e.g. when
|
||||
displaying diffs.
|
||||
"""
|
||||
explanation = explanation
|
||||
lines = _split_explanation(explanation)
|
||||
result = _format_lines(lines)
|
||||
return "\n".join(result)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
""" interactive debugging with PDB, the Python Debugger. """
|
||||
import argparse
|
||||
import functools
|
||||
import pdb
|
||||
import sys
|
||||
from doctest import UnexpectedException
|
||||
@@ -274,13 +275,16 @@ class PdbTrace:
|
||||
def _test_pytest_function(pyfuncitem):
|
||||
_pdb = pytestPDB._init_pdb("runcall")
|
||||
testfunction = pyfuncitem.obj
|
||||
pyfuncitem.obj = _pdb.runcall
|
||||
if "func" in pyfuncitem._fixtureinfo.argnames: # pragma: no branch
|
||||
raise ValueError("--trace can't be used with a fixture named func!")
|
||||
pyfuncitem.funcargs["func"] = testfunction
|
||||
new_list = list(pyfuncitem._fixtureinfo.argnames)
|
||||
new_list.append("func")
|
||||
pyfuncitem._fixtureinfo.argnames = tuple(new_list)
|
||||
|
||||
# we can't just return `partial(pdb.runcall, testfunction)` because (on
|
||||
# python < 3.7.4) runcall's first param is `func`, which means we'd get
|
||||
# an exception if one of the kwargs to testfunction was called `func`
|
||||
@functools.wraps(testfunction)
|
||||
def wrapper(*args, **kwargs):
|
||||
func = functools.partial(testfunction, *args, **kwargs)
|
||||
_pdb.runcall(func)
|
||||
|
||||
pyfuncitem.obj = wrapper
|
||||
|
||||
|
||||
def _enter_pdb(node, excinfo, rep):
|
||||
|
||||
@@ -513,7 +513,7 @@ class LogXML:
|
||||
key = nodeid, slavenode
|
||||
|
||||
if key in self.node_reporters:
|
||||
# TODO: breasks for --dist=each
|
||||
# TODO: breaks for --dist=each
|
||||
return self.node_reporters[key]
|
||||
|
||||
reporter = _NodeReporter(nodeid, self)
|
||||
|
||||
@@ -2,8 +2,7 @@
|
||||
import logging
|
||||
import re
|
||||
from contextlib import contextmanager
|
||||
|
||||
import py
|
||||
from io import StringIO
|
||||
|
||||
import pytest
|
||||
from _pytest.compat import nullcontext
|
||||
@@ -218,7 +217,7 @@ class LogCaptureHandler(logging.StreamHandler):
|
||||
|
||||
def __init__(self):
|
||||
"""Creates a new log handler."""
|
||||
logging.StreamHandler.__init__(self, py.io.TextIO())
|
||||
logging.StreamHandler.__init__(self, StringIO())
|
||||
self.records = []
|
||||
|
||||
def emit(self, record):
|
||||
@@ -228,7 +227,7 @@ class LogCaptureHandler(logging.StreamHandler):
|
||||
|
||||
def reset(self):
|
||||
self.records = []
|
||||
self.stream = py.io.TextIO()
|
||||
self.stream = StringIO()
|
||||
|
||||
|
||||
class LogCaptureFixture:
|
||||
|
||||
@@ -429,7 +429,7 @@ class Session(nodes.FSCollector):
|
||||
# one or more conftests are not in use at this fspath
|
||||
proxy = FSHookProxy(fspath, pm, remove_mods)
|
||||
else:
|
||||
# all plugis are active for this fspath
|
||||
# all plugins are active for this fspath
|
||||
proxy = self.config.hook
|
||||
return proxy
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ class MarkEvaluator:
|
||||
self._mark_name = name
|
||||
|
||||
def __bool__(self):
|
||||
# dont cache here to prevent staleness
|
||||
# don't cache here to prevent staleness
|
||||
return bool(self._get_marks())
|
||||
|
||||
__nonzero__ = __bool__
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"""
|
||||
this is a place where we put datastructures used by legacy apis
|
||||
we hope ot remove
|
||||
we hope to remove
|
||||
"""
|
||||
import keyword
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ import time
|
||||
import traceback
|
||||
from collections.abc import Sequence
|
||||
from fnmatch import fnmatch
|
||||
from io import StringIO
|
||||
from weakref import WeakKeyDictionary
|
||||
|
||||
import py
|
||||
@@ -1218,7 +1219,7 @@ def getdecoded(out):
|
||||
|
||||
class LineComp:
|
||||
def __init__(self):
|
||||
self.stringio = py.io.TextIO()
|
||||
self.stringio = StringIO()
|
||||
|
||||
def assert_contains_lines(self, lines2):
|
||||
"""Assert that lines2 are contained (linearly) in lines1.
|
||||
|
||||
@@ -210,8 +210,8 @@ def pytest_pycollect_makeitem(collector, name, obj):
|
||||
# mock seems to store unbound methods (issue473), normalize it
|
||||
obj = getattr(obj, "__func__", obj)
|
||||
# We need to try and unwrap the function if it's a functools.partial
|
||||
# or a funtools.wrapped.
|
||||
# We musn't if it's been wrapped with mock.patch (python 2 only)
|
||||
# or a functools.wrapped.
|
||||
# We mustn't if it's been wrapped with mock.patch (python 2 only)
|
||||
if not (inspect.isfunction(obj) or inspect.isfunction(get_real_func(obj))):
|
||||
filename, lineno = getfslineno(obj)
|
||||
warnings.warn_explicit(
|
||||
@@ -251,18 +251,21 @@ class PyobjMixin(PyobjContext):
|
||||
@property
|
||||
def obj(self):
|
||||
"""Underlying Python object."""
|
||||
self._mount_obj_if_needed()
|
||||
return self._obj
|
||||
|
||||
@obj.setter
|
||||
def obj(self, value):
|
||||
self._obj = value
|
||||
|
||||
def _mount_obj_if_needed(self):
|
||||
obj = getattr(self, "_obj", None)
|
||||
if obj is None:
|
||||
self._obj = obj = self._getobj()
|
||||
# XXX evil hack
|
||||
# used to avoid Instance collector marker duplication
|
||||
if self._ALLOW_MARKERS:
|
||||
self.own_markers.extend(get_unpacked_marks(self.obj))
|
||||
return obj
|
||||
|
||||
@obj.setter
|
||||
def obj(self, value):
|
||||
self._obj = value
|
||||
self.own_markers.extend(get_unpacked_marks(obj))
|
||||
|
||||
def _getobj(self):
|
||||
"""Gets the underlying Python object. May be overwritten by subclasses."""
|
||||
@@ -429,6 +432,14 @@ class PyCollector(PyobjMixin, nodes.Collector):
|
||||
class Module(nodes.File, PyCollector):
|
||||
""" Collector for test classes and functions. """
|
||||
|
||||
def __init__(self, fspath, parent=None, config=None, session=None, nodeid=None):
|
||||
if fspath.basename == "__init__.py":
|
||||
self._ALLOW_MARKERS = False
|
||||
|
||||
nodes.FSCollector.__init__(
|
||||
self, fspath, parent=parent, config=config, session=session, nodeid=nodeid
|
||||
)
|
||||
|
||||
def _getobj(self):
|
||||
return self._importtestmodule()
|
||||
|
||||
@@ -595,7 +606,7 @@ class Package(Module):
|
||||
# one or more conftests are not in use at this fspath
|
||||
proxy = FSHookProxy(fspath, pm, remove_mods)
|
||||
else:
|
||||
# all plugis are active for this fspath
|
||||
# all plugins are active for this fspath
|
||||
proxy = self.config.hook
|
||||
return proxy
|
||||
|
||||
@@ -628,6 +639,7 @@ class Package(Module):
|
||||
return path in self.session._initialpaths
|
||||
|
||||
def collect(self):
|
||||
self._mount_obj_if_needed()
|
||||
this_path = self.fspath.dirpath()
|
||||
init_module = this_path.join("__init__.py")
|
||||
if init_module.check(file=1) and path_matches_patterns(
|
||||
@@ -965,6 +977,12 @@ class Metafunc(fixtures.FuncargnamesCompatAttr):
|
||||
)
|
||||
del argvalues
|
||||
|
||||
if "request" in argnames:
|
||||
fail(
|
||||
"'request' is a reserved name and cannot be used in @pytest.mark.parametrize",
|
||||
pytrace=False,
|
||||
)
|
||||
|
||||
if scope is None:
|
||||
scope = _find_parametrized_scope(argnames, self._arg2fixturedefs, indirect)
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
from io import StringIO
|
||||
from pprint import pprint
|
||||
from typing import Optional
|
||||
from typing import Union
|
||||
@@ -180,7 +181,7 @@ class BaseReport:
|
||||
|
||||
def _report_unserialization_failure(type_name, report_class, reportdict):
|
||||
url = "https://github.com/pytest-dev/pytest/issues"
|
||||
stream = py.io.TextIO()
|
||||
stream = StringIO()
|
||||
pprint("-" * 100, stream=stream)
|
||||
pprint("INTERNALERROR: Unknown entry type returned: %s" % type_name, stream=stream)
|
||||
pprint("report_name: %s" % report_class, stream=stream)
|
||||
|
||||
@@ -122,7 +122,7 @@ def pytest_runtest_makereport(item, call):
|
||||
outcome = yield
|
||||
rep = outcome.get_result()
|
||||
evalxfail = getattr(item, "_evalxfail", None)
|
||||
# unitttest special case, see setting of _unexpectedsuccess
|
||||
# unittest special case, see setting of _unexpectedsuccess
|
||||
if hasattr(item, "_unexpectedsuccess") and rep.when == "call":
|
||||
|
||||
if item._unexpectedsuccess:
|
||||
@@ -132,7 +132,7 @@ def pytest_runtest_makereport(item, call):
|
||||
rep.outcome = "failed"
|
||||
|
||||
elif item.config.option.runxfail:
|
||||
pass # don't interefere
|
||||
pass # don't interfere
|
||||
elif call.excinfo and call.excinfo.errisinstance(xfail.Exception):
|
||||
rep.wasxfail = "reason: " + call.excinfo.value.msg
|
||||
rep.outcome = "skipped"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"""
|
||||
This is the script that is actually frozen into an executable: simply executes
|
||||
py.test main().
|
||||
pytest main().
|
||||
"""
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -1148,7 +1148,7 @@ def test_dont_collect_non_function_callable(testdir):
|
||||
"""Test for issue https://github.com/pytest-dev/pytest/issues/331
|
||||
|
||||
In this case an INTERNALERROR occurred trying to report the failure of
|
||||
a test like this one because py test failed to get the source lines.
|
||||
a test like this one because pytest failed to get the source lines.
|
||||
"""
|
||||
testdir.makepyfile(
|
||||
"""
|
||||
|
||||
@@ -15,7 +15,7 @@ class TestMetafunc:
|
||||
def Metafunc(self, func, config=None):
|
||||
# the unit tests of this class check if things work correctly
|
||||
# on the funcarg level, so we don't need a full blown
|
||||
# initiliazation
|
||||
# initialization
|
||||
class FixtureInfo:
|
||||
name2fixturedefs = None
|
||||
|
||||
@@ -72,6 +72,19 @@ class TestMetafunc:
|
||||
):
|
||||
metafunc.parametrize("x", [1], scope="doggy")
|
||||
|
||||
def test_parametrize_request_name(self, testdir):
|
||||
"""Show proper error when 'request' is used as a parameter name in parametrize (#6183)"""
|
||||
|
||||
def func(request):
|
||||
raise NotImplementedError()
|
||||
|
||||
metafunc = self.Metafunc(func)
|
||||
with pytest.raises(
|
||||
pytest.fail.Exception,
|
||||
match=r"'request' is a reserved name and cannot be used in @pytest.mark.parametrize",
|
||||
):
|
||||
metafunc.parametrize("request", [1])
|
||||
|
||||
def test_find_parametrized_scope(self):
|
||||
"""unittest for _find_parametrized_scope (#3941)"""
|
||||
from _pytest.python import _find_parametrized_scope
|
||||
|
||||
@@ -5,10 +5,9 @@ import pickle
|
||||
import subprocess
|
||||
import sys
|
||||
import textwrap
|
||||
from io import StringIO
|
||||
from io import UnsupportedOperation
|
||||
|
||||
import py
|
||||
|
||||
import pytest
|
||||
from _pytest import capture
|
||||
from _pytest.capture import CaptureManager
|
||||
@@ -892,10 +891,10 @@ def test_dupfile_on_bytesio():
|
||||
|
||||
|
||||
def test_dupfile_on_textio():
|
||||
tio = py.io.TextIO()
|
||||
f = capture.safe_text_dupfile(tio, "wb")
|
||||
sio = StringIO()
|
||||
f = capture.safe_text_dupfile(sio, "wb")
|
||||
f.write("hello")
|
||||
assert tio.getvalue() == "hello"
|
||||
assert sio.getvalue() == "hello"
|
||||
assert not hasattr(f, "name")
|
||||
|
||||
|
||||
|
||||
@@ -482,7 +482,7 @@ class TestFunctional:
|
||||
items, rec = testdir.inline_genitems(p)
|
||||
base_item, sub_item, sub_item_other = items
|
||||
print(items, [x.nodeid for x in items])
|
||||
# new api seregates
|
||||
# new api segregates
|
||||
assert not list(base_item.iter_markers(name="b"))
|
||||
assert not list(sub_item_other.iter_markers(name="b"))
|
||||
assert list(sub_item.iter_markers(name="b"))
|
||||
|
||||
@@ -229,7 +229,7 @@ def test_nose_setup_ordering(testdir):
|
||||
|
||||
def test_apiwrapper_problem_issue260(testdir):
|
||||
# this would end up trying a call an optional teardown on the class
|
||||
# for plain unittests we dont want nose behaviour
|
||||
# for plain unittests we don't want nose behaviour
|
||||
testdir.makepyfile(
|
||||
"""
|
||||
import unittest
|
||||
|
||||
@@ -304,7 +304,7 @@ def test_argcomplete(testdir, monkeypatch):
|
||||
shlex.quote(sys.executable)
|
||||
)
|
||||
)
|
||||
# alternative would be exteneded Testdir.{run(),_run(),popen()} to be able
|
||||
# alternative would be extended Testdir.{run(),_run(),popen()} to be able
|
||||
# to handle a keyword argument env that replaces os.environ in popen or
|
||||
# extends the copy, advantage: could not forget to restore
|
||||
monkeypatch.setenv("_ARGCOMPLETE", "1")
|
||||
|
||||
@@ -581,7 +581,7 @@ class TestPDB:
|
||||
# No extra newline.
|
||||
assert child.before.endswith(b"c\r\nprint_from_foo\r\n")
|
||||
|
||||
# set_debug should not raise outcomes.Exit, if used recrursively.
|
||||
# set_debug should not raise outcomes. Exit, if used recursively.
|
||||
child.sendline("debug 42")
|
||||
child.sendline("q")
|
||||
child.expect("LEAVING RECURSIVE DEBUGGER")
|
||||
@@ -1025,6 +1025,51 @@ class TestTraceOption:
|
||||
assert "Exit: Quitting debugger" not in child.before.decode("utf8")
|
||||
TestPDB.flush(child)
|
||||
|
||||
def test_trace_with_parametrize_handles_shared_fixtureinfo(self, testdir):
|
||||
p1 = testdir.makepyfile(
|
||||
"""
|
||||
import pytest
|
||||
@pytest.mark.parametrize('myparam', [1,2])
|
||||
def test_1(myparam, request):
|
||||
assert myparam in (1, 2)
|
||||
assert request.function.__name__ == "test_1"
|
||||
@pytest.mark.parametrize('func', [1,2])
|
||||
def test_func(func, request):
|
||||
assert func in (1, 2)
|
||||
assert request.function.__name__ == "test_func"
|
||||
@pytest.mark.parametrize('myparam', [1,2])
|
||||
def test_func_kw(myparam, request, func="func_kw"):
|
||||
assert myparam in (1, 2)
|
||||
assert func == "func_kw"
|
||||
assert request.function.__name__ == "test_func_kw"
|
||||
"""
|
||||
)
|
||||
child = testdir.spawn_pytest("--trace " + str(p1))
|
||||
for func, argname in [
|
||||
("test_1", "myparam"),
|
||||
("test_func", "func"),
|
||||
("test_func_kw", "myparam"),
|
||||
]:
|
||||
child.expect_exact("> PDB runcall (IO-capturing turned off) >")
|
||||
child.expect_exact(func)
|
||||
child.expect_exact("Pdb")
|
||||
child.sendline("args")
|
||||
child.expect_exact("{} = 1\r\n".format(argname))
|
||||
child.expect_exact("Pdb")
|
||||
child.sendline("c")
|
||||
child.expect_exact("Pdb")
|
||||
child.sendline("args")
|
||||
child.expect_exact("{} = 2\r\n".format(argname))
|
||||
child.expect_exact("Pdb")
|
||||
child.sendline("c")
|
||||
child.expect_exact("> PDB continue (IO-capturing resumed) >")
|
||||
rest = child.read().decode("utf8")
|
||||
assert "6 passed in" in rest
|
||||
assert "reading from stdin while output" not in rest
|
||||
# Only printed once - not on stderr.
|
||||
assert "Exit: Quitting debugger" not in child.before.decode("utf8")
|
||||
TestPDB.flush(child)
|
||||
|
||||
|
||||
def test_trace_after_runpytest(testdir):
|
||||
"""Test that debugging's pytest_configure is re-entrant."""
|
||||
@@ -1150,7 +1195,6 @@ def test_pdbcls_via_local_module(testdir):
|
||||
|
||||
def runcall(self, *args, **kwds):
|
||||
print("runcall_called", args, kwds)
|
||||
assert "func" in kwds
|
||||
""",
|
||||
)
|
||||
result = testdir.runpytest(
|
||||
|
||||
@@ -133,17 +133,17 @@ class TestReportSerialization:
|
||||
"""
|
||||
reprec = testdir.inline_runsource(
|
||||
"""
|
||||
import py
|
||||
import pytest
|
||||
def test_pass(): pass
|
||||
def test_fail(): 0/0
|
||||
@py.test.mark.skipif("True")
|
||||
@pytest.mark.skipif("True")
|
||||
def test_skip(): pass
|
||||
def test_skip_imperative():
|
||||
py.test.skip("hello")
|
||||
@py.test.mark.xfail("True")
|
||||
pytest.skip("hello")
|
||||
@pytest.mark.xfail("True")
|
||||
def test_xfail(): 0/0
|
||||
def test_xfail_imperative():
|
||||
py.test.xfail("hello")
|
||||
pytest.xfail("hello")
|
||||
"""
|
||||
)
|
||||
reports = reprec.getreports("pytest_runtest_logreport")
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import os
|
||||
|
||||
import py
|
||||
from io import StringIO
|
||||
|
||||
import _pytest._code
|
||||
import pytest
|
||||
@@ -13,7 +12,7 @@ pytestmark = pytest.mark.filterwarnings("ignore:--result-log is deprecated")
|
||||
|
||||
def test_write_log_entry():
|
||||
reslog = ResultLog(None, None)
|
||||
reslog.logfile = py.io.TextIO()
|
||||
reslog.logfile = StringIO()
|
||||
reslog.write_log_entry("name", ".", "")
|
||||
entry = reslog.logfile.getvalue()
|
||||
assert entry[-1] == "\n"
|
||||
@@ -21,7 +20,7 @@ def test_write_log_entry():
|
||||
assert len(entry_lines) == 1
|
||||
assert entry_lines[0] == ". name"
|
||||
|
||||
reslog.logfile = py.io.TextIO()
|
||||
reslog.logfile = StringIO()
|
||||
reslog.write_log_entry("name", "s", "Skipped")
|
||||
entry = reslog.logfile.getvalue()
|
||||
assert entry[-1] == "\n"
|
||||
@@ -30,7 +29,7 @@ def test_write_log_entry():
|
||||
assert entry_lines[0] == "s name"
|
||||
assert entry_lines[1] == " Skipped"
|
||||
|
||||
reslog.logfile = py.io.TextIO()
|
||||
reslog.logfile = StringIO()
|
||||
reslog.write_log_entry("name", "s", "Skipped\n")
|
||||
entry = reslog.logfile.getvalue()
|
||||
assert entry[-1] == "\n"
|
||||
@@ -39,7 +38,7 @@ def test_write_log_entry():
|
||||
assert entry_lines[0] == "s name"
|
||||
assert entry_lines[1] == " Skipped"
|
||||
|
||||
reslog.logfile = py.io.TextIO()
|
||||
reslog.logfile = StringIO()
|
||||
longrepr = " tb1\n tb 2\nE tb3\nSome Error"
|
||||
reslog.write_log_entry("name", "F", longrepr)
|
||||
entry = reslog.logfile.getvalue()
|
||||
@@ -118,7 +117,7 @@ class TestWithFunctionIntegration:
|
||||
raise ValueError
|
||||
except ValueError:
|
||||
excinfo = _pytest._code.ExceptionInfo.from_current()
|
||||
reslog = ResultLog(None, py.io.TextIO())
|
||||
reslog = ResultLog(None, StringIO())
|
||||
reslog.pytest_internalerror(excinfo.getrepr(style=style))
|
||||
entry = reslog.logfile.getvalue()
|
||||
entry_lines = entry.splitlines()
|
||||
|
||||
@@ -1162,3 +1162,26 @@ def test_importorskip():
|
||||
match="^could not import 'doesnotexist': No module named .*",
|
||||
):
|
||||
pytest.importorskip("doesnotexist")
|
||||
|
||||
|
||||
def test_skip_package(testdir):
|
||||
testdir.makepyfile(
|
||||
__init__="""
|
||||
import pytest
|
||||
pytestmark = pytest.mark.skip
|
||||
"""
|
||||
)
|
||||
|
||||
testdir.makepyfile(
|
||||
"""
|
||||
import pytest
|
||||
def test_skip1():
|
||||
assert 0
|
||||
def test_skip2():
|
||||
assert 0
|
||||
"""
|
||||
)
|
||||
|
||||
result = testdir.inline_run()
|
||||
_, skipped, _ = result.listoutcomes()
|
||||
assert len(skipped) == 2
|
||||
|
||||
@@ -4,7 +4,7 @@ import pytest
|
||||
@pytest.fixture
|
||||
def stepwise_testdir(testdir):
|
||||
# Rather than having to modify our testfile between tests, we introduce
|
||||
# a flag for wether or not the second test should fail.
|
||||
# a flag for whether or not the second test should fail.
|
||||
testdir.makeconftest(
|
||||
"""
|
||||
def pytest_addoption(parser):
|
||||
|
||||
@@ -5,6 +5,7 @@ import collections
|
||||
import os
|
||||
import sys
|
||||
import textwrap
|
||||
from io import StringIO
|
||||
|
||||
import pluggy
|
||||
import py
|
||||
@@ -268,7 +269,7 @@ class TestTerminal:
|
||||
|
||||
def test_rewrite(self, testdir, monkeypatch):
|
||||
config = testdir.parseconfig()
|
||||
f = py.io.TextIO()
|
||||
f = StringIO()
|
||||
monkeypatch.setattr(f, "isatty", lambda *args: True)
|
||||
tr = TerminalReporter(config, f)
|
||||
tr._tw.fullwidth = 10
|
||||
|
||||
Reference in New Issue
Block a user