Merge pull request #3620 from RonnyPfannschmidt/merge-from-master

Merge from master
This commit is contained in:
Ronny Pfannschmidt 2018-06-26 21:56:09 +02:00 committed by GitHub
commit 6b239263da
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
112 changed files with 1064 additions and 1227 deletions

View File

@ -1,19 +1,19 @@
exclude: doc/en/example/py2py3/test_py2.py exclude: doc/en/example/py2py3/test_py2.py
repos: repos:
- repo: https://github.com/ambv/black - repo: https://github.com/ambv/black
rev: 18.4a4 rev: 18.6b4
hooks: hooks:
- id: black - id: black
args: [--safe, --quiet] args: [--safe, --quiet]
language_version: python3.6 language_version: python3.6
- repo: https://github.com/asottile/blacken-docs - repo: https://github.com/asottile/blacken-docs
rev: v0.1.1 rev: v0.2.0
hooks: hooks:
- id: blacken-docs - id: blacken-docs
additional_dependencies: [black==18.5b1] additional_dependencies: [black==18.6b4]
language_version: python3.6 language_version: python3.6
- repo: https://github.com/pre-commit/pre-commit-hooks - repo: https://github.com/pre-commit/pre-commit-hooks
rev: v1.2.3 rev: v1.3.0
hooks: hooks:
- id: trailing-whitespace - id: trailing-whitespace
- id: end-of-file-fixer - id: end-of-file-fixer

View File

@ -37,8 +37,8 @@ jobs:
python: 'pypy-5.4' python: 'pypy-5.4'
- env: TOXENV=py35 - env: TOXENV=py35
python: '3.5' python: '3.5'
- env: TOXENV=py35-freeze - env: TOXENV=py36-freeze
python: '3.5' python: '3.6'
- env: TOXENV=py37 - env: TOXENV=py37
python: 'nightly' python: 'nightly'

View File

@ -126,6 +126,7 @@ Maik Figura
Mandeep Bhutani Mandeep Bhutani
Manuel Krebber Manuel Krebber
Marc Schlaich Marc Schlaich
Marcelo Duarte Trevisani
Marcin Bachry Marcin Bachry
Mark Abramowitz Mark Abramowitz
Markus Unterwaditzer Markus Unterwaditzer
@ -157,6 +158,7 @@ Oleg Sushchenko
Oliver Bestwalter Oliver Bestwalter
Omar Kohl Omar Kohl
Omer Hadari Omer Hadari
Ondřej Súkup
Patrick Hayes Patrick Hayes
Paweł Adamczak Paweł Adamczak
Pedro Algarvio Pedro Algarvio

View File

@ -8,6 +8,52 @@
.. towncrier release notes start .. towncrier release notes start
Pytest 3.6.2 (2018-06-20)
=========================
Bug Fixes
---------
- Fix regression in ``Node.add_marker`` by extracting the mark object of a
``MarkDecorator``. (`#3555
<https://github.com/pytest-dev/pytest/issues/3555>`_)
- Warnings without ``location`` were reported as ``None``. This is corrected to
now report ``<undetermined location>``. (`#3563
<https://github.com/pytest-dev/pytest/issues/3563>`_)
- Continue to call finalizers in the stack when a finalizer in a former scope
raises an exception. (`#3569
<https://github.com/pytest-dev/pytest/issues/3569>`_)
- Fix encoding error with `print` statements in doctests (`#3583
<https://github.com/pytest-dev/pytest/issues/3583>`_)
Improved Documentation
----------------------
- Add documentation for the ``--strict`` flag. (`#3549
<https://github.com/pytest-dev/pytest/issues/3549>`_)
Trivial/Internal Changes
------------------------
- Update old quotation style to parens in fixture.rst documentation. (`#3525
<https://github.com/pytest-dev/pytest/issues/3525>`_)
- Improve display of hint about ``--fulltrace`` with ``KeyboardInterrupt``.
(`#3545 <https://github.com/pytest-dev/pytest/issues/3545>`_)
- pytest's testsuite is no longer runnable through ``python setup.py test`` --
instead invoke ``pytest`` or ``tox`` directly. (`#3552
<https://github.com/pytest-dev/pytest/issues/3552>`_)
- Fix typo in documentation (`#3567
<https://github.com/pytest-dev/pytest/issues/3567>`_)
Pytest 3.6.1 (2018-06-05) Pytest 3.6.1 (2018-06-05)
========================= =========================

View File

@ -27,7 +27,7 @@ environment:
- TOXENV: "py36-pluggymaster" - TOXENV: "py36-pluggymaster"
- TOXENV: "py27-nobyte" - TOXENV: "py27-nobyte"
- TOXENV: "doctesting" - TOXENV: "doctesting"
- TOXENV: "py35-freeze" - TOXENV: "py36-freeze"
- TOXENV: "docs" - TOXENV: "docs"
install: install:

View File

@ -0,0 +1 @@
Fix ``ImportWarning`` triggered by explicit relative imports in assertion-rewritten package modules.

View File

@ -1 +0,0 @@
Improve display of hint about ``--fulltrace`` with ``KeyboardInterrupt``.

View File

@ -1 +0,0 @@
Add documentation for the ``--strict`` flag.

View File

@ -1 +0,0 @@
pytest's testsuite is no longer runnable through ``python setup.py test`` -- instead invoke ``pytest`` or ``tox`` directly.

View File

@ -1 +0,0 @@
Fix regression in ``Node.add_marker`` by extracting the mark object of a ``MarkDecorator``.

View File

@ -1 +0,0 @@
Warnings without ``location`` were reported as ``None``. This is corrected to now report ``<undetermined location>``.

View File

@ -1 +0,0 @@
Fix typo in documentation

View File

@ -1 +0,0 @@
Continue to call finalizers in the stack when a finalizer in a former scope raises an exception.

View File

@ -0,0 +1,5 @@
If the user pass as a expected value a numpy array created like
numpy.array(5); it will creates an array with one element without shape,
when used with approx it will raise an error for the `repr`
'TypeError: iteration over a 0-d array'. With this PR pytest will iterate
properly in the numpy array even with 0 dimension.

View File

@ -0,0 +1 @@
Internal refactoring: removed unused ``CallSpec2tox ._globalid_args`` attribute and ``metafunc`` parameter from ``CallSpec2.copy()``.

View File

@ -0,0 +1 @@
Silence usage of ``reduce`` warning in python 2

1
changelog/3611.doc.rst Normal file
View File

@ -0,0 +1 @@
The description above the example for ``@pytest.mark.skipif`` now better matches the code.

View File

@ -6,6 +6,7 @@ Release announcements
:maxdepth: 2 :maxdepth: 2
release-3.6.2
release-3.6.1 release-3.6.1
release-3.6.0 release-3.6.0
release-3.5.1 release-3.5.1

View File

@ -23,7 +23,7 @@ a full list of details. A few feature highlights:
called if the corresponding setup method succeeded. called if the corresponding setup method succeeded.
- integrate tab-completion on command line options if you - integrate tab-completion on command line options if you
have `argcomplete <http://pypi.python.org/pypi/argcomplete>`_ have `argcomplete <https://pypi.org/project/argcomplete/>`_
configured. configured.
- allow boolean expression directly with skipif/xfail - allow boolean expression directly with skipif/xfail

View File

@ -0,0 +1,29 @@
pytest-3.6.2
=======================================
pytest 3.6.2 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 http://doc.pytest.org/en/latest/changelog.html.
Thanks to all who contributed to this release, among them:
* Alan Velasco
* Alex Barbato
* Anthony Sottile
* Bartosz Cierocki
* Bruno Oliveira
* Daniel Hahler
* Guoqiang Zhang
* Hynek Schlawack
* John T. Wodder II
* Michael Käufl
* Ronny Pfannschmidt
* Samuel Dion-Girardeau
Happy testing,
The pytest Development Team

View File

@ -25,9 +25,7 @@ def pytest_generate_tests(metafunc):
class TestFailing(object): class TestFailing(object):
def test_simple(self): def test_simple(self):
def f(): def f():
return 42 return 42
@ -40,7 +38,6 @@ class TestFailing(object):
otherfunc_multi(42, 6 * 9) otherfunc_multi(42, 6 * 9)
def test_not(self): def test_not(self):
def f(): def f():
return 42 return 42
@ -48,7 +45,6 @@ class TestFailing(object):
class TestSpecialisedExplanations(object): class TestSpecialisedExplanations(object):
def test_eq_text(self): def test_eq_text(self):
assert "spam" == "eggs" assert "spam" == "eggs"
@ -106,7 +102,6 @@ class TestSpecialisedExplanations(object):
def test_attribute(): def test_attribute():
class Foo(object): class Foo(object):
b = 1 b = 1
@ -115,7 +110,6 @@ def test_attribute():
def test_attribute_instance(): def test_attribute_instance():
class Foo(object): class Foo(object):
b = 1 b = 1
@ -123,9 +117,7 @@ def test_attribute_instance():
def test_attribute_failure(): def test_attribute_failure():
class Foo(object): class Foo(object):
def _get_b(self): def _get_b(self):
raise Exception("Failed to get attrib") raise Exception("Failed to get attrib")
@ -136,7 +128,6 @@ def test_attribute_failure():
def test_attribute_multiple(): def test_attribute_multiple():
class Foo(object): class Foo(object):
b = 1 b = 1
@ -151,7 +142,6 @@ def globf(x):
class TestRaises(object): class TestRaises(object):
def test_raises(self): def test_raises(self):
s = "qwe" # NOQA s = "qwe" # NOQA
raises(TypeError, "int(s)") raises(TypeError, "int(s)")
@ -193,9 +183,7 @@ def test_dynamic_compile_shows_nicely():
class TestMoreErrors(object): class TestMoreErrors(object):
def test_complex_error(self): def test_complex_error(self):
def f(): def f():
return 44 return 44
@ -218,7 +206,6 @@ class TestMoreErrors(object):
assert s.startswith(g) assert s.startswith(g)
def test_startswith_nested(self): def test_startswith_nested(self):
def f(): def f():
return "123" return "123"
@ -246,9 +233,7 @@ class TestMoreErrors(object):
class TestCustomAssertMsg(object): class TestCustomAssertMsg(object):
def test_single_line(self): def test_single_line(self):
class A(object): class A(object):
a = 1 a = 1
@ -256,7 +241,6 @@ class TestCustomAssertMsg(object):
assert A.a == b, "A.a appears not to be b" assert A.a == b, "A.a appears not to be b"
def test_multiline(self): def test_multiline(self):
class A(object): class A(object):
a = 1 a = 1
@ -266,7 +250,6 @@ class TestCustomAssertMsg(object):
), "A.a appears not to be b\n" "or does not appear to be b\none of those" ), "A.a appears not to be b\n" "or does not appear to be b\none of those"
def test_custom_repr(self): def test_custom_repr(self):
class JSON(object): class JSON(object):
a = 1 a = 1

View File

@ -2,7 +2,7 @@
import py import py
failure_demo = py.path.local(__file__).dirpath("failure_demo.py") failure_demo = py.path.local(__file__).dirpath("failure_demo.py")
pytest_plugins = "pytester", pytest_plugins = ("pytester",)
def test_failure_demo_fails_properly(testdir): def test_failure_demo_fails_properly(testdir):

View File

@ -3,7 +3,6 @@ def setup_module(module):
class TestStateFullThing(object): class TestStateFullThing(object):
def setup_class(cls): def setup_class(cls):
cls.classcount += 1 cls.classcount += 1

View File

@ -10,7 +10,6 @@ def setup(request):
class CostlySetup(object): class CostlySetup(object):
def __init__(self): def __init__(self):
import time import time

View File

@ -21,7 +21,6 @@ def python2(request, python1):
class Python(object): class Python(object):
def __init__(self, version, picklefile): def __init__(self, version, picklefile):
self.pythonpath = py.path.local.sysfind(version) self.pythonpath = py.path.local.sysfind(version)
if not self.pythonpath: if not self.pythonpath:

View File

@ -9,7 +9,6 @@ def pytest_collect_file(parent, path):
class YamlFile(pytest.File): class YamlFile(pytest.File):
def collect(self): def collect(self):
import yaml # we need a yaml parser, e.g. PyYAML import yaml # we need a yaml parser, e.g. PyYAML
@ -19,7 +18,6 @@ class YamlFile(pytest.File):
class YamlItem(pytest.Item): class YamlItem(pytest.Item):
def __init__(self, name, parent, spec): def __init__(self, name, parent, spec):
super(YamlItem, self).__init__(name, parent) super(YamlItem, self).__init__(name, parent)
self.spec = spec self.spec = spec

View File

@ -5,7 +5,6 @@ py3 = sys.version_info[0] >= 3
class DummyCollector(pytest.collect.File): class DummyCollector(pytest.collect.File):
def collect(self): def collect(self):
return [] return []

View File

@ -7,7 +7,6 @@ def test_function():
class TestClass(object): class TestClass(object):
def test_method(self): def test_method(self):
pass pass

View File

@ -625,7 +625,7 @@ get on the terminal - we are working on that)::
failure_demo.py:278: AssertionError failure_demo.py:278: AssertionError
============================= warnings summary ============================= ============================= warnings summary =============================
None <undetermined location>
Metafunc.addcall is deprecated and scheduled to be removed in pytest 4.0. Metafunc.addcall is deprecated and scheduled to be removed in pytest 4.0.
Please use Metafunc.parametrize instead. Please use Metafunc.parametrize instead.

View File

@ -154,7 +154,7 @@ This makes use of the automatic caching mechanisms of pytest.
Another good approach is by adding the data files in the ``tests`` folder. Another good approach is by adding the data files in the ``tests`` folder.
There are also community plugins available to help managing this aspect of There are also community plugins available to help managing this aspect of
testing, e.g. `pytest-datadir <https://github.com/gabrielcnr/pytest-datadir>`__ testing, e.g. `pytest-datadir <https://github.com/gabrielcnr/pytest-datadir>`__
and `pytest-datafiles <https://pypi.python.org/pypi/pytest-datafiles>`__. and `pytest-datafiles <https://pypi.org/project/pytest-datafiles/>`__.
.. _smtpshared: .. _smtpshared:
@ -165,7 +165,7 @@ Scope: sharing a fixture instance across tests in a class, module or session
Fixtures requiring network access depend on connectivity and are Fixtures requiring network access depend on connectivity and are
usually time-expensive to create. Extending the previous example, we usually time-expensive to create. Extending the previous example, we
can add a ``scope='module'`` parameter to the can add a ``scope="module"`` parameter to the
:py:func:`@pytest.fixture <_pytest.python.fixture>` invocation :py:func:`@pytest.fixture <_pytest.python.fixture>` invocation
to cause the decorated ``smtp`` fixture function to only be invoked once to cause the decorated ``smtp`` fixture function to only be invoked once
per test *module* (the default is to invoke once per test *function*). per test *module* (the default is to invoke once per test *function*).

View File

@ -733,7 +733,7 @@ Node
Parser Parser
~~~~~~ ~~~~~~
.. autoclass:: _pytest.config.Parser() .. autoclass:: _pytest.config.argparsing.Parser()
:members: :members:
PluginManager PluginManager

View File

@ -80,11 +80,11 @@ during import time.
If you wish to skip something conditionally then you can use ``skipif`` instead. If you wish to skip something conditionally then you can use ``skipif`` instead.
Here is an example of marking a test function to be skipped Here is an example of marking a test function to be skipped
when run on a Python3.6 interpreter:: when run on an interpreter earlier than Python3.6 ::
import sys import sys
@pytest.mark.skipif(sys.version_info < (3,6), @pytest.mark.skipif(sys.version_info < (3,6),
reason="requires python3.6") reason="requires python3.6 or higher")
def test_function(): def test_function():
... ...

View File

@ -1,3 +1,10 @@
[build-system]
requires = [
"setuptools",
"setuptools-scm",
"wheel",
]
[tool.towncrier] [tool.towncrier]
package = "pytest" package = "pytest"
package_dir = "src" package_dir = "src"

View File

@ -112,7 +112,13 @@ def main():
python_requires=">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*", python_requires=">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*",
install_requires=install_requires, install_requires=install_requires,
extras_require=extras_require, extras_require=extras_require,
packages=["_pytest", "_pytest.assertion", "_pytest._code", "_pytest.mark"], packages=[
"_pytest",
"_pytest.assertion",
"_pytest._code",
"_pytest.mark",
"_pytest.config",
],
py_modules=["pytest"], py_modules=["pytest"],
zip_safe=False, zip_safe=False,
) )

View File

@ -274,6 +274,7 @@ class Traceback(list):
""" Traceback objects encapsulate and offer higher level """ Traceback objects encapsulate and offer higher level
access to Traceback entries. access to Traceback entries.
""" """
Entry = TracebackEntry Entry = TracebackEntry
def __init__(self, tb, excinfo=None): def __init__(self, tb, excinfo=None):
@ -382,8 +383,11 @@ class ExceptionInfo(object):
""" wraps sys.exc_info() objects and offers """ wraps sys.exc_info() objects and offers
help for navigating the traceback. help for navigating the traceback.
""" """
_striptext = "" _striptext = ""
_assert_start_repr = "AssertionError(u'assert " if _PY2 else "AssertionError('assert " _assert_start_repr = (
"AssertionError(u'assert " if _PY2 else "AssertionError('assert "
)
def __init__(self, tup=None, exprinfo=None): def __init__(self, tup=None, exprinfo=None):
import _pytest._code import _pytest._code
@ -424,7 +428,7 @@ class ExceptionInfo(object):
text = text.rstrip() text = text.rstrip()
if tryshort: if tryshort:
if text.startswith(self._striptext): if text.startswith(self._striptext):
text = text[len(self._striptext):] text = text[len(self._striptext) :]
return text return text
def errisinstance(self, exc): def errisinstance(self, exc):
@ -497,6 +501,7 @@ class ExceptionInfo(object):
@attr.s @attr.s
class FormattedExcinfo(object): class FormattedExcinfo(object):
""" presenting information about failing Functions and Generators. """ """ presenting information about failing Functions and Generators. """
# for traceback entries # for traceback entries
flow_marker = ">" flow_marker = ">"
fail_marker = "E" fail_marker = "E"
@ -556,7 +561,7 @@ class FormattedExcinfo(object):
for line in source.lines[:line_index]: for line in source.lines[:line_index]:
lines.append(space_prefix + line) lines.append(space_prefix + line)
lines.append(self.flow_marker + " " + source.lines[line_index]) lines.append(self.flow_marker + " " + source.lines[line_index])
for line in source.lines[line_index + 1:]: for line in source.lines[line_index + 1 :]:
lines.append(space_prefix + line) lines.append(space_prefix + line)
if excinfo is not None: if excinfo is not None:
indent = 4 if short else self._getindent(source) indent = 4 if short else self._getindent(source)
@ -691,7 +696,7 @@ class FormattedExcinfo(object):
else: else:
if recursionindex is not None: if recursionindex is not None:
extraline = "!!! Recursion detected (same locals & position)" extraline = "!!! Recursion detected (same locals & position)"
traceback = traceback[:recursionindex + 1] traceback = traceback[: recursionindex + 1]
else: else:
extraline = None extraline = None
@ -722,15 +727,19 @@ class FormattedExcinfo(object):
repr_chain += [(reprtraceback, reprcrash, descr)] repr_chain += [(reprtraceback, reprcrash, descr)]
if e.__cause__ is not None: if e.__cause__ is not None:
e = e.__cause__ e = e.__cause__
excinfo = ExceptionInfo( excinfo = (
(type(e), e, e.__traceback__) ExceptionInfo((type(e), e, e.__traceback__))
) if e.__traceback__ else None if e.__traceback__
else None
)
descr = "The above exception was the direct cause of the following exception:" descr = "The above exception was the direct cause of the following exception:"
elif (e.__context__ is not None and not e.__suppress_context__): elif e.__context__ is not None and not e.__suppress_context__:
e = e.__context__ e = e.__context__
excinfo = ExceptionInfo( excinfo = (
(type(e), e, e.__traceback__) ExceptionInfo((type(e), e, e.__traceback__))
) if e.__traceback__ else None if e.__traceback__
else None
)
descr = "During handling of the above exception, another exception occurred:" descr = "During handling of the above exception, another exception occurred:"
else: else:
e = None e = None
@ -739,7 +748,6 @@ class FormattedExcinfo(object):
class TerminalRepr(object): class TerminalRepr(object):
def __str__(self): def __str__(self):
s = self.__unicode__() s = self.__unicode__()
if _PY2: if _PY2:
@ -759,7 +767,6 @@ class TerminalRepr(object):
class ExceptionRepr(TerminalRepr): class ExceptionRepr(TerminalRepr):
def __init__(self): def __init__(self):
self.sections = [] self.sections = []
@ -773,7 +780,6 @@ class ExceptionRepr(TerminalRepr):
class ExceptionChainRepr(ExceptionRepr): class ExceptionChainRepr(ExceptionRepr):
def __init__(self, chain): def __init__(self, chain):
super(ExceptionChainRepr, self).__init__() super(ExceptionChainRepr, self).__init__()
self.chain = chain self.chain = chain
@ -792,7 +798,6 @@ class ExceptionChainRepr(ExceptionRepr):
class ReprExceptionInfo(ExceptionRepr): class ReprExceptionInfo(ExceptionRepr):
def __init__(self, reprtraceback, reprcrash): def __init__(self, reprtraceback, reprcrash):
super(ReprExceptionInfo, self).__init__() super(ReprExceptionInfo, self).__init__()
self.reprtraceback = reprtraceback self.reprtraceback = reprtraceback
@ -831,7 +836,6 @@ class ReprTraceback(TerminalRepr):
class ReprTracebackNative(ReprTraceback): class ReprTracebackNative(ReprTraceback):
def __init__(self, tblines): def __init__(self, tblines):
self.style = "native" self.style = "native"
self.reprentries = [ReprEntryNative(tblines)] self.reprentries = [ReprEntryNative(tblines)]
@ -885,7 +889,6 @@ class ReprEntry(TerminalRepr):
class ReprFileLocation(TerminalRepr): class ReprFileLocation(TerminalRepr):
def __init__(self, path, lineno, message): def __init__(self, path, lineno, message):
self.path = str(path) self.path = str(path)
self.lineno = lineno self.lineno = lineno
@ -903,7 +906,6 @@ class ReprFileLocation(TerminalRepr):
class ReprLocals(TerminalRepr): class ReprLocals(TerminalRepr):
def __init__(self, lines): def __init__(self, lines):
self.lines = lines self.lines = lines
@ -913,7 +915,6 @@ class ReprLocals(TerminalRepr):
class ReprFuncArgs(TerminalRepr): class ReprFuncArgs(TerminalRepr):
def __init__(self, args): def __init__(self, args):
self.args = args self.args = args

View File

@ -17,6 +17,7 @@ class Source(object):
""" an immutable object holding a source code fragment, """ an immutable object holding a source code fragment,
possibly deindenting it. possibly deindenting it.
""" """
_compilecounter = 0 _compilecounter = 0
def __init__(self, *parts, **kwargs): def __init__(self, *parts, **kwargs):
@ -60,7 +61,7 @@ class Source(object):
if key.step not in (None, 1): if key.step not in (None, 1):
raise IndexError("cannot slice a Source with a step") raise IndexError("cannot slice a Source with a step")
newsource = Source() newsource = Source()
newsource.lines = self.lines[key.start:key.stop] newsource.lines = self.lines[key.start : key.stop]
return newsource return newsource
def __len__(self): def __len__(self):
@ -178,7 +179,7 @@ class Source(object):
except SyntaxError: except SyntaxError:
ex = sys.exc_info()[1] ex = sys.exc_info()[1]
# re-represent syntax errors from parsing python strings # re-represent syntax errors from parsing python strings
msglines = self.lines[:ex.lineno] msglines = self.lines[: ex.lineno]
if ex.offset: if ex.offset:
msglines.append(" " * ex.offset + "^") msglines.append(" " * ex.offset + "^")
msglines.append("(code was compiled probably from here: %s)" % filename) msglines.append("(code was compiled probably from here: %s)" % filename)
@ -313,7 +314,7 @@ def deindent(lines, offset=None):
except (IndentationError, tokenize.TokenError): except (IndentationError, tokenize.TokenError):
pass pass
# Add any lines we didn't see. E.g. if an exception was raised. # Add any lines we didn't see. E.g. if an exception was raised.
newlines.extend(lines[len(newlines):]) newlines.extend(lines[len(newlines) :])
return newlines return newlines

View File

@ -45,6 +45,14 @@ else:
return ast.Call(a, b, c, None, None) return ast.Call(a, b, c, None, None)
if sys.version_info >= (3, 4):
from importlib.util import spec_from_file_location
else:
def spec_from_file_location(*_, **__):
return None
class AssertionRewritingHook(object): class AssertionRewritingHook(object):
"""PEP302 Import hook which rewrites asserts.""" """PEP302 Import hook which rewrites asserts."""
@ -213,6 +221,8 @@ class AssertionRewritingHook(object):
# Normally, this attribute is 3.2+. # Normally, this attribute is 3.2+.
mod.__cached__ = pyc mod.__cached__ = pyc
mod.__loader__ = self mod.__loader__ = self
# Normally, this attribute is 3.4+
mod.__spec__ = spec_from_file_location(name, co.co_filename, loader=self)
py.builtin.exec_(co, mod.__dict__) py.builtin.exec_(co, mod.__dict__)
except: # noqa except: # noqa
if name in sys.modules: if name in sys.modules:
@ -309,7 +319,7 @@ def _rewrite_test(config, fn):
if ( if (
not source.startswith(BOM_UTF8) not source.startswith(BOM_UTF8)
and cookie_re.match(source[0:end1]) is None and cookie_re.match(source[0:end1]) is None
and cookie_re.match(source[end1 + 1:end2]) is None and cookie_re.match(source[end1 + 1 : end2]) is None
): ):
if hasattr(state, "_indecode"): if hasattr(state, "_indecode"):
# encodings imported us again, so don't rewrite. # encodings imported us again, so don't rewrite.

View File

@ -322,7 +322,7 @@ def _compare_eq_dict(left, right, verbose=False):
def _notin_text(term, text, verbose=False): def _notin_text(term, text, verbose=False):
index = text.find(term) index = text.find(term)
head = text[:index] head = text[:index]
tail = text[index + len(term):] tail = text[index + len(term) :]
correct_text = head + tail correct_text = head + tail
diff = _diff_text(correct_text, text, verbose) diff = _diff_text(correct_text, text, verbose)
newdiff = [u("%s is contained here:") % py.io.saferepr(term, maxsize=42)] newdiff = [u("%s is contained here:") % py.io.saferepr(term, maxsize=42)]

View File

@ -32,7 +32,6 @@ See [the docs](https://docs.pytest.org/en/latest/cache.html) for more informatio
@attr.s @attr.s
class Cache(object): class Cache(object):
_cachedir = attr.ib(repr=False) _cachedir = attr.ib(repr=False)
_warn = attr.ib(repr=False) _warn = attr.ib(repr=False)
@ -215,9 +214,7 @@ class NFPlugin(object):
items[:] = self._get_increasing_order( items[:] = self._get_increasing_order(
six.itervalues(new_items) six.itervalues(new_items)
) + self._get_increasing_order( ) + self._get_increasing_order(six.itervalues(other_items))
six.itervalues(other_items)
)
self.cached_nodeids = [x.nodeid for x in items if isinstance(x, pytest.Item)] self.cached_nodeids = [x.nodeid for x in items if isinstance(x, pytest.Item)]
def _get_increasing_order(self, items): def _get_increasing_order(self, items):

View File

@ -531,7 +531,6 @@ class FDCapture(FDCaptureBinary):
class SysCapture(object): class SysCapture(object):
def __init__(self, fd, tmpfile=None): def __init__(self, fd, tmpfile=None):
name = patchsysdict[fd] name = patchsysdict[fd]
self._old = getattr(sys, name) self._old = getattr(sys, name)
@ -569,7 +568,6 @@ class SysCapture(object):
class SysCaptureBinary(SysCapture): class SysCaptureBinary(SysCapture):
def snap(self): def snap(self):
res = self.tmpfile.buffer.getvalue() res = self.tmpfile.buffer.getvalue()
self.tmpfile.seek(0) self.tmpfile.seek(0)

View File

@ -78,12 +78,8 @@ def iscoroutinefunction(func):
Note: copied and modified from Python 3.5's builtin couroutines.py to avoid import asyncio directly, Note: copied and modified from Python 3.5's builtin couroutines.py to avoid import asyncio directly,
which in turns also initializes the "logging" module as side-effect (see issue #8). which in turns also initializes the "logging" module as side-effect (see issue #8).
""" """
return ( return getattr(func, "_is_coroutine", False) or (
getattr(func, "_is_coroutine", False) hasattr(inspect, "iscoroutinefunction") and inspect.iscoroutinefunction(func)
or (
hasattr(inspect, "iscoroutinefunction")
and inspect.iscoroutinefunction(func)
)
) )
@ -144,17 +140,13 @@ def getfuncargnames(function, is_method=False, cls=None):
# If this function should be treated as a bound method even though # If this function should be treated as a bound method even though
# it's passed as an unbound method or function, remove the first # it's passed as an unbound method or function, remove the first
# parameter name. # parameter name.
if ( if is_method or (
is_method cls and not isinstance(cls.__dict__.get(function.__name__, None), staticmethod)
or (
cls
and not isinstance(cls.__dict__.get(function.__name__, None), staticmethod)
)
): ):
arg_names = arg_names[1:] arg_names = arg_names[1:]
# Remove any names that will be replaced with mocks. # Remove any names that will be replaced with mocks.
if hasattr(function, "__wrapped__"): if hasattr(function, "__wrapped__"):
arg_names = arg_names[num_mock_patch_args(function):] arg_names = arg_names[num_mock_patch_args(function) :]
return arg_names return arg_names
@ -346,7 +338,6 @@ if _PY2:
from py.io import TextIO from py.io import TextIO
class CaptureIO(TextIO): class CaptureIO(TextIO):
@property @property
def encoding(self): def encoding(self):
return getattr(self, "_encoding", "UTF-8") return getattr(self, "_encoding", "UTF-8")
@ -356,7 +347,6 @@ else:
import io import io
class CaptureIO(io.TextIOWrapper): class CaptureIO(io.TextIOWrapper):
def __init__(self): def __init__(self):
super(CaptureIO, self).__init__( super(CaptureIO, self).__init__(
io.BytesIO(), encoding="UTF-8", newline="", write_through=True io.BytesIO(), encoding="UTF-8", newline="", write_through=True

View File

@ -19,6 +19,8 @@ import _pytest.hookspec # the extension point definitions
import _pytest.assertion import _pytest.assertion
from pluggy import PluginManager, HookimplMarker, HookspecMarker from pluggy import PluginManager, HookimplMarker, HookspecMarker
from _pytest.compat import safe_str from _pytest.compat import safe_str
from .exceptions import UsageError, PrintHelp
from .findpaths import determine_setup, exists
hookimpl = HookimplMarker("pytest") hookimpl = HookimplMarker("pytest")
hookspec = HookspecMarker("pytest") hookspec = HookspecMarker("pytest")
@ -28,7 +30,6 @@ hookspec = HookspecMarker("pytest")
class ConftestImportFailure(Exception): class ConftestImportFailure(Exception):
def __init__(self, path, excinfo): def __init__(self, path, excinfo):
Exception.__init__(self, path, excinfo) Exception.__init__(self, path, excinfo)
self.path = path self.path = path
@ -74,16 +75,6 @@ class cmdline(object): # NOQA compatibility namespace
main = staticmethod(main) main = staticmethod(main)
class UsageError(Exception):
""" error in pytest usage or invocation"""
class PrintHelp(Exception):
"""Raised when pytest should print it's help to skip the rest of the
argument parsing and validation."""
pass
def filename_arg(path, optname): def filename_arg(path, optname):
""" Argparse type validator for filename arguments. """ Argparse type validator for filename arguments.
@ -107,11 +98,33 @@ def directory_arg(path, optname):
default_plugins = ( default_plugins = (
"mark main terminal runner python fixtures debugging unittest capture skipping " "mark",
"tmpdir monkeypatch recwarn pastebin helpconfig nose assertion " "main",
"junitxml resultlog doctest cacheprovider freeze_support " "terminal",
"setuponly setupplan warnings logging" "runner",
).split() "python",
"fixtures",
"debugging",
"unittest",
"capture",
"skipping",
"tmpdir",
"monkeypatch",
"recwarn",
"pastebin",
"helpconfig",
"nose",
"assertion",
"junitxml",
"resultlog",
"doctest",
"cacheprovider",
"freeze_support",
"setuponly",
"setupplan",
"warnings",
"logging",
)
builtin_plugins = set(default_plugins) builtin_plugins = set(default_plugins)
@ -304,9 +317,11 @@ class PytestPluginManager(PluginManager):
self._configured = True self._configured = True
def _warn(self, message): def _warn(self, message):
kwargs = message if isinstance(message, dict) else { kwargs = (
"code": "I1", "message": message, "fslocation": None, "nodeid": None message
} if isinstance(message, dict)
else {"code": "I1", "message": message, "fslocation": None, "nodeid": None}
)
self.hook.pytest_logwarning.call_historic(kwargs=kwargs) self.hook.pytest_logwarning.call_historic(kwargs=kwargs)
# #
@ -321,9 +336,11 @@ class PytestPluginManager(PluginManager):
here. here.
""" """
current = py.path.local() current = py.path.local()
self._confcutdir = current.join( self._confcutdir = (
namespace.confcutdir, abs=True current.join(namespace.confcutdir, abs=True)
) if namespace.confcutdir else None if namespace.confcutdir
else None
)
self._noconftest = namespace.noconftest self._noconftest = namespace.noconftest
testpaths = namespace.file_or_dir testpaths = namespace.file_or_dir
foundanchor = False foundanchor = False
@ -391,7 +408,9 @@ class PytestPluginManager(PluginManager):
try: try:
mod = conftestpath.pyimport() mod = conftestpath.pyimport()
if hasattr(mod, "pytest_plugins") and self._configured: if hasattr(mod, "pytest_plugins") and self._configured:
from _pytest.deprecated import PYTEST_PLUGINS_FROM_NON_TOP_LEVEL_CONFTEST from _pytest.deprecated import (
PYTEST_PLUGINS_FROM_NON_TOP_LEVEL_CONFTEST
)
warnings.warn(PYTEST_PLUGINS_FROM_NON_TOP_LEVEL_CONFTEST) warnings.warn(PYTEST_PLUGINS_FROM_NON_TOP_LEVEL_CONFTEST)
except Exception: except Exception:
@ -463,7 +482,8 @@ class PytestPluginManager(PluginManager):
except ImportError as e: except ImportError as e:
new_exc_type = ImportError new_exc_type = ImportError
new_exc_message = 'Error importing plugin "%s": %s' % ( new_exc_message = 'Error importing plugin "%s": %s' % (
modname, safe_str(e.args[0]) modname,
safe_str(e.args[0]),
) )
new_exc = new_exc_type(new_exc_message) new_exc = new_exc_type(new_exc_message)
@ -496,395 +516,6 @@ def _get_plugin_specs_as_list(specs):
return [] return []
class Parser(object):
""" Parser for command line arguments and ini-file values.
:ivar extra_info: dict of generic param -> value to display in case
there's an error processing the command line arguments.
"""
def __init__(self, usage=None, processopt=None):
self._anonymous = OptionGroup("custom options", parser=self)
self._groups = []
self._processopt = processopt
self._usage = usage
self._inidict = {}
self._ininames = []
self.extra_info = {}
def processoption(self, option):
if self._processopt:
if option.dest:
self._processopt(option)
def getgroup(self, name, description="", after=None):
""" get (or create) a named option Group.
:name: name of the option group.
:description: long description for --help output.
:after: name of other group, used for ordering --help output.
The returned group object has an ``addoption`` method with the same
signature as :py:func:`parser.addoption
<_pytest.config.Parser.addoption>` but will be shown in the
respective group in the output of ``pytest. --help``.
"""
for group in self._groups:
if group.name == name:
return group
group = OptionGroup(name, description, parser=self)
i = 0
for i, grp in enumerate(self._groups):
if grp.name == after:
break
self._groups.insert(i + 1, group)
return group
def addoption(self, *opts, **attrs):
""" register a command line option.
:opts: option names, can be short or long options.
:attrs: same attributes which the ``add_option()`` function of the
`argparse library
<http://docs.python.org/2/library/argparse.html>`_
accepts.
After command line parsing options are available on the pytest config
object via ``config.option.NAME`` where ``NAME`` is usually set
by passing a ``dest`` attribute, for example
``addoption("--long", dest="NAME", ...)``.
"""
self._anonymous.addoption(*opts, **attrs)
def parse(self, args, namespace=None):
from _pytest._argcomplete import try_argcomplete
self.optparser = self._getparser()
try_argcomplete(self.optparser)
return self.optparser.parse_args([str(x) for x in args], namespace=namespace)
def _getparser(self):
from _pytest._argcomplete import filescompleter
optparser = MyOptionParser(self, self.extra_info)
groups = self._groups + [self._anonymous]
for group in groups:
if group.options:
desc = group.description or group.name
arggroup = optparser.add_argument_group(desc)
for option in group.options:
n = option.names()
a = option.attrs()
arggroup.add_argument(*n, **a)
# bash like autocompletion for dirs (appending '/')
optparser.add_argument(FILE_OR_DIR, nargs="*").completer = filescompleter
return optparser
def parse_setoption(self, args, option, namespace=None):
parsedoption = self.parse(args, namespace=namespace)
for name, value in parsedoption.__dict__.items():
setattr(option, name, value)
return getattr(parsedoption, FILE_OR_DIR)
def parse_known_args(self, args, namespace=None):
"""parses and returns a namespace object with known arguments at this
point.
"""
return self.parse_known_and_unknown_args(args, namespace=namespace)[0]
def parse_known_and_unknown_args(self, args, namespace=None):
"""parses and returns a namespace object with known arguments, and
the remaining arguments unknown at this point.
"""
optparser = self._getparser()
args = [str(x) for x in args]
return optparser.parse_known_args(args, namespace=namespace)
def addini(self, name, help, type=None, default=None):
""" register an ini-file option.
:name: name of the ini-variable
:type: type of the variable, can be ``pathlist``, ``args``, ``linelist``
or ``bool``.
:default: default value if no ini-file option exists but is queried.
The value of ini-variables can be retrieved via a call to
:py:func:`config.getini(name) <_pytest.config.Config.getini>`.
"""
assert type in (None, "pathlist", "args", "linelist", "bool")
self._inidict[name] = (help, type, default)
self._ininames.append(name)
class ArgumentError(Exception):
"""
Raised if an Argument instance is created with invalid or
inconsistent arguments.
"""
def __init__(self, msg, option):
self.msg = msg
self.option_id = str(option)
def __str__(self):
if self.option_id:
return "option %s: %s" % (self.option_id, self.msg)
else:
return self.msg
class Argument(object):
"""class that mimics the necessary behaviour of optparse.Option
its currently a least effort implementation
and ignoring choices and integer prefixes
https://docs.python.org/3/library/optparse.html#optparse-standard-option-types
"""
_typ_map = {"int": int, "string": str, "float": float, "complex": complex}
def __init__(self, *names, **attrs):
"""store parms in private vars for use in add_argument"""
self._attrs = attrs
self._short_opts = []
self._long_opts = []
self.dest = attrs.get("dest")
if "%default" in (attrs.get("help") or ""):
warnings.warn(
'pytest now uses argparse. "%default" should be'
' changed to "%(default)s" ',
DeprecationWarning,
stacklevel=3,
)
try:
typ = attrs["type"]
except KeyError:
pass
else:
# this might raise a keyerror as well, don't want to catch that
if isinstance(typ, six.string_types):
if typ == "choice":
warnings.warn(
"type argument to addoption() is a string %r."
" For parsearg this is optional and when supplied"
" should be a type."
" (options: %s)" % (typ, names),
DeprecationWarning,
stacklevel=3,
)
# argparse expects a type here take it from
# the type of the first element
attrs["type"] = type(attrs["choices"][0])
else:
warnings.warn(
"type argument to addoption() is a string %r."
" For parsearg this should be a type."
" (options: %s)" % (typ, names),
DeprecationWarning,
stacklevel=3,
)
attrs["type"] = Argument._typ_map[typ]
# used in test_parseopt -> test_parse_defaultgetter
self.type = attrs["type"]
else:
self.type = typ
try:
# attribute existence is tested in Config._processopt
self.default = attrs["default"]
except KeyError:
pass
self._set_opt_strings(names)
if not self.dest:
if self._long_opts:
self.dest = self._long_opts[0][2:].replace("-", "_")
else:
try:
self.dest = self._short_opts[0][1:]
except IndexError:
raise ArgumentError("need a long or short option", self)
def names(self):
return self._short_opts + self._long_opts
def attrs(self):
# update any attributes set by processopt
attrs = "default dest help".split()
if self.dest:
attrs.append(self.dest)
for attr in attrs:
try:
self._attrs[attr] = getattr(self, attr)
except AttributeError:
pass
if self._attrs.get("help"):
a = self._attrs["help"]
a = a.replace("%default", "%(default)s")
# a = a.replace('%prog', '%(prog)s')
self._attrs["help"] = a
return self._attrs
def _set_opt_strings(self, opts):
"""directly from optparse
might not be necessary as this is passed to argparse later on"""
for opt in opts:
if len(opt) < 2:
raise ArgumentError(
"invalid option string %r: "
"must be at least two characters long" % opt,
self,
)
elif len(opt) == 2:
if not (opt[0] == "-" and opt[1] != "-"):
raise ArgumentError(
"invalid short option string %r: "
"must be of the form -x, (x any non-dash char)" % opt,
self,
)
self._short_opts.append(opt)
else:
if not (opt[0:2] == "--" and opt[2] != "-"):
raise ArgumentError(
"invalid long option string %r: "
"must start with --, followed by non-dash" % opt,
self,
)
self._long_opts.append(opt)
def __repr__(self):
args = []
if self._short_opts:
args += ["_short_opts: " + repr(self._short_opts)]
if self._long_opts:
args += ["_long_opts: " + repr(self._long_opts)]
args += ["dest: " + repr(self.dest)]
if hasattr(self, "type"):
args += ["type: " + repr(self.type)]
if hasattr(self, "default"):
args += ["default: " + repr(self.default)]
return "Argument({})".format(", ".join(args))
class OptionGroup(object):
def __init__(self, name, description="", parser=None):
self.name = name
self.description = description
self.options = []
self.parser = parser
def addoption(self, *optnames, **attrs):
""" add an option to this group.
if a shortened version of a long option is specified it will
be suppressed in the help. addoption('--twowords', '--two-words')
results in help showing '--two-words' only, but --twowords gets
accepted **and** the automatic destination is in args.twowords
"""
conflict = set(optnames).intersection(
name for opt in self.options for name in opt.names()
)
if conflict:
raise ValueError("option names %s already added" % conflict)
option = Argument(*optnames, **attrs)
self._addoption_instance(option, shortupper=False)
def _addoption(self, *optnames, **attrs):
option = Argument(*optnames, **attrs)
self._addoption_instance(option, shortupper=True)
def _addoption_instance(self, option, shortupper=False):
if not shortupper:
for opt in option._short_opts:
if opt[0] == "-" and opt[1].islower():
raise ValueError("lowercase shortoptions reserved")
if self.parser:
self.parser.processoption(option)
self.options.append(option)
class MyOptionParser(argparse.ArgumentParser):
def __init__(self, parser, extra_info=None):
if not extra_info:
extra_info = {}
self._parser = parser
argparse.ArgumentParser.__init__(
self,
usage=parser._usage,
add_help=False,
formatter_class=DropShorterLongHelpFormatter,
)
# extra_info is a dict of (param -> value) to display if there's
# an usage error to provide more contextual information to the user
self.extra_info = extra_info
def parse_args(self, args=None, namespace=None):
"""allow splitting of positional arguments"""
args, argv = self.parse_known_args(args, namespace)
if argv:
for arg in argv:
if arg and arg[0] == "-":
lines = ["unrecognized arguments: %s" % (" ".join(argv))]
for k, v in sorted(self.extra_info.items()):
lines.append(" %s: %s" % (k, v))
self.error("\n".join(lines))
getattr(args, FILE_OR_DIR).extend(argv)
return args
class DropShorterLongHelpFormatter(argparse.HelpFormatter):
"""shorten help for long options that differ only in extra hyphens
- collapse **long** options that are the same except for extra hyphens
- special action attribute map_long_option allows surpressing additional
long options
- shortcut if there are only two options and one of them is a short one
- cache result on action object as this is called at least 2 times
"""
def _format_action_invocation(self, action):
orgstr = argparse.HelpFormatter._format_action_invocation(self, action)
if orgstr and orgstr[0] != "-": # only optional arguments
return orgstr
res = getattr(action, "_formatted_action_invocation", None)
if res:
return res
options = orgstr.split(", ")
if len(options) == 2 and (len(options[0]) == 2 or len(options[1]) == 2):
# a shortcut for '-h, --help' or '--abc', '-a'
action._formatted_action_invocation = orgstr
return orgstr
return_list = []
option_map = getattr(action, "map_long_option", {})
if option_map is None:
option_map = {}
short_long = {}
for option in options:
if len(option) == 2 or option[2] == " ":
continue
if not option.startswith("--"):
raise ArgumentError(
'long optional argument without "--": [%s]' % (option), self
)
xxoption = option[2:]
if xxoption.split()[0] not in option_map:
shortened = xxoption.replace("-", "")
if (
shortened not in short_long
or len(short_long[shortened]) < len(xxoption)
):
short_long[shortened] = xxoption
# now short_long has been filled out to the longest with dashes
# **and** we keep the right option ordering from add_argument
for option in options:
if len(option) == 2 or option[2] == " ":
return_list.append(option)
if option[2:] == short_long.get(option.replace("-", "")):
return_list.append(option.replace(" ", "=", 1))
action._formatted_action_invocation = ", ".join(return_list)
return action._formatted_action_invocation
def _ensure_removed_sysmodule(modname): def _ensure_removed_sysmodule(modname):
try: try:
del sys.modules[modname] del sys.modules[modname]
@ -893,13 +524,11 @@ def _ensure_removed_sysmodule(modname):
class Notset(object): class Notset(object):
def __repr__(self): def __repr__(self):
return "<NOTSET>" return "<NOTSET>"
notset = Notset() notset = Notset()
FILE_OR_DIR = "file_or_dir"
def _iter_rewritable_modules(package_files): def _iter_rewritable_modules(package_files):
@ -921,6 +550,8 @@ class Config(object):
#: access to command line option as attributes. #: access to command line option as attributes.
#: (deprecated), use :py:func:`getoption() <_pytest.config.Config.getoption>` instead #: (deprecated), use :py:func:`getoption() <_pytest.config.Config.getoption>` instead
self.option = argparse.Namespace() self.option = argparse.Namespace()
from .argparsing import Parser, FILE_OR_DIR
_a = FILE_OR_DIR _a = FILE_OR_DIR
self._parser = Parser( self._parser = Parser(
usage="%%(prog)s [options] [%s] [%s] [...]" % (_a, _a), usage="%%(prog)s [options] [%s] [%s] [...]" % (_a, _a),
@ -1300,143 +931,6 @@ def _warn_about_missing_assertion(mode):
) )
def exists(path, ignore=EnvironmentError):
try:
return path.check()
except ignore:
return False
def getcfg(args, warnfunc=None):
"""
Search the list of arguments for a valid ini-file for pytest,
and return a tuple of (rootdir, inifile, cfg-dict).
note: warnfunc is an optional function used to warn
about ini-files that use deprecated features.
This parameter should be removed when pytest
adopts standard deprecation warnings (#1804).
"""
from _pytest.deprecated import CFG_PYTEST_SECTION
inibasenames = ["pytest.ini", "tox.ini", "setup.cfg"]
args = [x for x in args if not str(x).startswith("-")]
if not args:
args = [py.path.local()]
for arg in args:
arg = py.path.local(arg)
for base in arg.parts(reverse=True):
for inibasename in inibasenames:
p = base.join(inibasename)
if exists(p):
iniconfig = py.iniconfig.IniConfig(p)
if "pytest" in iniconfig.sections:
if inibasename == "setup.cfg" and warnfunc:
warnfunc(
"C1", CFG_PYTEST_SECTION.format(filename=inibasename)
)
return base, p, iniconfig["pytest"]
if (
inibasename == "setup.cfg"
and "tool:pytest" in iniconfig.sections
):
return base, p, iniconfig["tool:pytest"]
elif inibasename == "pytest.ini":
# allowed to be empty
return base, p, {}
return None, None, None
def get_common_ancestor(paths):
common_ancestor = None
for path in paths:
if not path.exists():
continue
if common_ancestor is None:
common_ancestor = path
else:
if path.relto(common_ancestor) or path == common_ancestor:
continue
elif common_ancestor.relto(path):
common_ancestor = path
else:
shared = path.common(common_ancestor)
if shared is not None:
common_ancestor = shared
if common_ancestor is None:
common_ancestor = py.path.local()
elif common_ancestor.isfile():
common_ancestor = common_ancestor.dirpath()
return common_ancestor
def get_dirs_from_args(args):
def is_option(x):
return str(x).startswith("-")
def get_file_part_from_node_id(x):
return str(x).split("::")[0]
def get_dir_from_path(path):
if path.isdir():
return path
return py.path.local(path.dirname)
# These look like paths but may not exist
possible_paths = (
py.path.local(get_file_part_from_node_id(arg))
for arg in args
if not is_option(arg)
)
return [get_dir_from_path(path) for path in possible_paths if path.exists()]
def determine_setup(inifile, args, warnfunc=None, rootdir_cmd_arg=None):
dirs = get_dirs_from_args(args)
if inifile:
iniconfig = py.iniconfig.IniConfig(inifile)
is_cfg_file = str(inifile).endswith(".cfg")
# TODO: [pytest] section in *.cfg files is depricated. Need refactoring.
sections = ["tool:pytest", "pytest"] if is_cfg_file else ["pytest"]
for section in sections:
try:
inicfg = iniconfig[section]
if is_cfg_file and section == "pytest" and warnfunc:
from _pytest.deprecated import CFG_PYTEST_SECTION
warnfunc("C1", CFG_PYTEST_SECTION.format(filename=str(inifile)))
break
except KeyError:
inicfg = None
rootdir = get_common_ancestor(dirs)
else:
ancestor = get_common_ancestor(dirs)
rootdir, inifile, inicfg = getcfg([ancestor], warnfunc=warnfunc)
if rootdir is None:
for rootdir in ancestor.parts(reverse=True):
if rootdir.join("setup.py").exists():
break
else:
rootdir, inifile, inicfg = getcfg(dirs, warnfunc=warnfunc)
if rootdir is None:
rootdir = get_common_ancestor([py.path.local(), ancestor])
is_fs_root = os.path.splitdrive(str(rootdir))[1] == "/"
if is_fs_root:
rootdir = ancestor
if rootdir_cmd_arg:
rootdir_abs_path = py.path.local(os.path.expandvars(rootdir_cmd_arg))
if not os.path.isdir(str(rootdir_abs_path)):
raise UsageError(
"Directory '{}' not found. Check your '--rootdir' option.".format(
rootdir_abs_path
)
)
rootdir = rootdir_abs_path
return rootdir, inifile, inicfg or {}
def setns(obj, dic): def setns(obj, dic):
import pytest import pytest

View File

@ -0,0 +1,392 @@
import six
import warnings
import argparse
FILE_OR_DIR = "file_or_dir"
class Parser(object):
""" Parser for command line arguments and ini-file values.
:ivar extra_info: dict of generic param -> value to display in case
there's an error processing the command line arguments.
"""
def __init__(self, usage=None, processopt=None):
self._anonymous = OptionGroup("custom options", parser=self)
self._groups = []
self._processopt = processopt
self._usage = usage
self._inidict = {}
self._ininames = []
self.extra_info = {}
def processoption(self, option):
if self._processopt:
if option.dest:
self._processopt(option)
def getgroup(self, name, description="", after=None):
""" get (or create) a named option Group.
:name: name of the option group.
:description: long description for --help output.
:after: name of other group, used for ordering --help output.
The returned group object has an ``addoption`` method with the same
signature as :py:func:`parser.addoption
<_pytest.config.Parser.addoption>` but will be shown in the
respective group in the output of ``pytest. --help``.
"""
for group in self._groups:
if group.name == name:
return group
group = OptionGroup(name, description, parser=self)
i = 0
for i, grp in enumerate(self._groups):
if grp.name == after:
break
self._groups.insert(i + 1, group)
return group
def addoption(self, *opts, **attrs):
""" register a command line option.
:opts: option names, can be short or long options.
:attrs: same attributes which the ``add_option()`` function of the
`argparse library
<http://docs.python.org/2/library/argparse.html>`_
accepts.
After command line parsing options are available on the pytest config
object via ``config.option.NAME`` where ``NAME`` is usually set
by passing a ``dest`` attribute, for example
``addoption("--long", dest="NAME", ...)``.
"""
self._anonymous.addoption(*opts, **attrs)
def parse(self, args, namespace=None):
from _pytest._argcomplete import try_argcomplete
self.optparser = self._getparser()
try_argcomplete(self.optparser)
return self.optparser.parse_args([str(x) for x in args], namespace=namespace)
def _getparser(self):
from _pytest._argcomplete import filescompleter
optparser = MyOptionParser(self, self.extra_info)
groups = self._groups + [self._anonymous]
for group in groups:
if group.options:
desc = group.description or group.name
arggroup = optparser.add_argument_group(desc)
for option in group.options:
n = option.names()
a = option.attrs()
arggroup.add_argument(*n, **a)
# bash like autocompletion for dirs (appending '/')
optparser.add_argument(FILE_OR_DIR, nargs="*").completer = filescompleter
return optparser
def parse_setoption(self, args, option, namespace=None):
parsedoption = self.parse(args, namespace=namespace)
for name, value in parsedoption.__dict__.items():
setattr(option, name, value)
return getattr(parsedoption, FILE_OR_DIR)
def parse_known_args(self, args, namespace=None):
"""parses and returns a namespace object with known arguments at this
point.
"""
return self.parse_known_and_unknown_args(args, namespace=namespace)[0]
def parse_known_and_unknown_args(self, args, namespace=None):
"""parses and returns a namespace object with known arguments, and
the remaining arguments unknown at this point.
"""
optparser = self._getparser()
args = [str(x) for x in args]
return optparser.parse_known_args(args, namespace=namespace)
def addini(self, name, help, type=None, default=None):
""" register an ini-file option.
:name: name of the ini-variable
:type: type of the variable, can be ``pathlist``, ``args``, ``linelist``
or ``bool``.
:default: default value if no ini-file option exists but is queried.
The value of ini-variables can be retrieved via a call to
:py:func:`config.getini(name) <_pytest.config.Config.getini>`.
"""
assert type in (None, "pathlist", "args", "linelist", "bool")
self._inidict[name] = (help, type, default)
self._ininames.append(name)
class ArgumentError(Exception):
"""
Raised if an Argument instance is created with invalid or
inconsistent arguments.
"""
def __init__(self, msg, option):
self.msg = msg
self.option_id = str(option)
def __str__(self):
if self.option_id:
return "option %s: %s" % (self.option_id, self.msg)
else:
return self.msg
class Argument(object):
"""class that mimics the necessary behaviour of optparse.Option
its currently a least effort implementation
and ignoring choices and integer prefixes
https://docs.python.org/3/library/optparse.html#optparse-standard-option-types
"""
_typ_map = {"int": int, "string": str, "float": float, "complex": complex}
def __init__(self, *names, **attrs):
"""store parms in private vars for use in add_argument"""
self._attrs = attrs
self._short_opts = []
self._long_opts = []
self.dest = attrs.get("dest")
if "%default" in (attrs.get("help") or ""):
warnings.warn(
'pytest now uses argparse. "%default" should be'
' changed to "%(default)s" ',
DeprecationWarning,
stacklevel=3,
)
try:
typ = attrs["type"]
except KeyError:
pass
else:
# this might raise a keyerror as well, don't want to catch that
if isinstance(typ, six.string_types):
if typ == "choice":
warnings.warn(
"type argument to addoption() is a string %r."
" For parsearg this is optional and when supplied"
" should be a type."
" (options: %s)" % (typ, names),
DeprecationWarning,
stacklevel=3,
)
# argparse expects a type here take it from
# the type of the first element
attrs["type"] = type(attrs["choices"][0])
else:
warnings.warn(
"type argument to addoption() is a string %r."
" For parsearg this should be a type."
" (options: %s)" % (typ, names),
DeprecationWarning,
stacklevel=3,
)
attrs["type"] = Argument._typ_map[typ]
# used in test_parseopt -> test_parse_defaultgetter
self.type = attrs["type"]
else:
self.type = typ
try:
# attribute existence is tested in Config._processopt
self.default = attrs["default"]
except KeyError:
pass
self._set_opt_strings(names)
if not self.dest:
if self._long_opts:
self.dest = self._long_opts[0][2:].replace("-", "_")
else:
try:
self.dest = self._short_opts[0][1:]
except IndexError:
raise ArgumentError("need a long or short option", self)
def names(self):
return self._short_opts + self._long_opts
def attrs(self):
# update any attributes set by processopt
attrs = "default dest help".split()
if self.dest:
attrs.append(self.dest)
for attr in attrs:
try:
self._attrs[attr] = getattr(self, attr)
except AttributeError:
pass
if self._attrs.get("help"):
a = self._attrs["help"]
a = a.replace("%default", "%(default)s")
# a = a.replace('%prog', '%(prog)s')
self._attrs["help"] = a
return self._attrs
def _set_opt_strings(self, opts):
"""directly from optparse
might not be necessary as this is passed to argparse later on"""
for opt in opts:
if len(opt) < 2:
raise ArgumentError(
"invalid option string %r: "
"must be at least two characters long" % opt,
self,
)
elif len(opt) == 2:
if not (opt[0] == "-" and opt[1] != "-"):
raise ArgumentError(
"invalid short option string %r: "
"must be of the form -x, (x any non-dash char)" % opt,
self,
)
self._short_opts.append(opt)
else:
if not (opt[0:2] == "--" and opt[2] != "-"):
raise ArgumentError(
"invalid long option string %r: "
"must start with --, followed by non-dash" % opt,
self,
)
self._long_opts.append(opt)
def __repr__(self):
args = []
if self._short_opts:
args += ["_short_opts: " + repr(self._short_opts)]
if self._long_opts:
args += ["_long_opts: " + repr(self._long_opts)]
args += ["dest: " + repr(self.dest)]
if hasattr(self, "type"):
args += ["type: " + repr(self.type)]
if hasattr(self, "default"):
args += ["default: " + repr(self.default)]
return "Argument({})".format(", ".join(args))
class OptionGroup(object):
def __init__(self, name, description="", parser=None):
self.name = name
self.description = description
self.options = []
self.parser = parser
def addoption(self, *optnames, **attrs):
""" add an option to this group.
if a shortened version of a long option is specified it will
be suppressed in the help. addoption('--twowords', '--two-words')
results in help showing '--two-words' only, but --twowords gets
accepted **and** the automatic destination is in args.twowords
"""
conflict = set(optnames).intersection(
name for opt in self.options for name in opt.names()
)
if conflict:
raise ValueError("option names %s already added" % conflict)
option = Argument(*optnames, **attrs)
self._addoption_instance(option, shortupper=False)
def _addoption(self, *optnames, **attrs):
option = Argument(*optnames, **attrs)
self._addoption_instance(option, shortupper=True)
def _addoption_instance(self, option, shortupper=False):
if not shortupper:
for opt in option._short_opts:
if opt[0] == "-" and opt[1].islower():
raise ValueError("lowercase shortoptions reserved")
if self.parser:
self.parser.processoption(option)
self.options.append(option)
class MyOptionParser(argparse.ArgumentParser):
def __init__(self, parser, extra_info=None):
if not extra_info:
extra_info = {}
self._parser = parser
argparse.ArgumentParser.__init__(
self,
usage=parser._usage,
add_help=False,
formatter_class=DropShorterLongHelpFormatter,
)
# extra_info is a dict of (param -> value) to display if there's
# an usage error to provide more contextual information to the user
self.extra_info = extra_info
def parse_args(self, args=None, namespace=None):
"""allow splitting of positional arguments"""
args, argv = self.parse_known_args(args, namespace)
if argv:
for arg in argv:
if arg and arg[0] == "-":
lines = ["unrecognized arguments: %s" % (" ".join(argv))]
for k, v in sorted(self.extra_info.items()):
lines.append(" %s: %s" % (k, v))
self.error("\n".join(lines))
getattr(args, FILE_OR_DIR).extend(argv)
return args
class DropShorterLongHelpFormatter(argparse.HelpFormatter):
"""shorten help for long options that differ only in extra hyphens
- collapse **long** options that are the same except for extra hyphens
- special action attribute map_long_option allows surpressing additional
long options
- shortcut if there are only two options and one of them is a short one
- cache result on action object as this is called at least 2 times
"""
def _format_action_invocation(self, action):
orgstr = argparse.HelpFormatter._format_action_invocation(self, action)
if orgstr and orgstr[0] != "-": # only optional arguments
return orgstr
res = getattr(action, "_formatted_action_invocation", None)
if res:
return res
options = orgstr.split(", ")
if len(options) == 2 and (len(options[0]) == 2 or len(options[1]) == 2):
# a shortcut for '-h, --help' or '--abc', '-a'
action._formatted_action_invocation = orgstr
return orgstr
return_list = []
option_map = getattr(action, "map_long_option", {})
if option_map is None:
option_map = {}
short_long = {}
for option in options:
if len(option) == 2 or option[2] == " ":
continue
if not option.startswith("--"):
raise ArgumentError(
'long optional argument without "--": [%s]' % (option), self
)
xxoption = option[2:]
if xxoption.split()[0] not in option_map:
shortened = xxoption.replace("-", "")
if shortened not in short_long or len(short_long[shortened]) < len(
xxoption
):
short_long[shortened] = xxoption
# now short_long has been filled out to the longest with dashes
# **and** we keep the right option ordering from add_argument
for option in options:
if len(option) == 2 or option[2] == " ":
return_list.append(option)
if option[2:] == short_long.get(option.replace("-", "")):
return_list.append(option.replace(" ", "=", 1))
action._formatted_action_invocation = ", ".join(return_list)
return action._formatted_action_invocation

View File

@ -0,0 +1,9 @@
class UsageError(Exception):
""" error in pytest usage or invocation"""
class PrintHelp(Exception):
"""Raised when pytest should print it's help to skip the rest of the
argument parsing and validation."""
pass

View File

@ -0,0 +1,139 @@
import py
import os
from .exceptions import UsageError
def exists(path, ignore=EnvironmentError):
try:
return path.check()
except ignore:
return False
def getcfg(args, warnfunc=None):
"""
Search the list of arguments for a valid ini-file for pytest,
and return a tuple of (rootdir, inifile, cfg-dict).
note: warnfunc is an optional function used to warn
about ini-files that use deprecated features.
This parameter should be removed when pytest
adopts standard deprecation warnings (#1804).
"""
from _pytest.deprecated import CFG_PYTEST_SECTION
inibasenames = ["pytest.ini", "tox.ini", "setup.cfg"]
args = [x for x in args if not str(x).startswith("-")]
if not args:
args = [py.path.local()]
for arg in args:
arg = py.path.local(arg)
for base in arg.parts(reverse=True):
for inibasename in inibasenames:
p = base.join(inibasename)
if exists(p):
iniconfig = py.iniconfig.IniConfig(p)
if "pytest" in iniconfig.sections:
if inibasename == "setup.cfg" and warnfunc:
warnfunc(
"C1", CFG_PYTEST_SECTION.format(filename=inibasename)
)
return base, p, iniconfig["pytest"]
if (
inibasename == "setup.cfg"
and "tool:pytest" in iniconfig.sections
):
return base, p, iniconfig["tool:pytest"]
elif inibasename == "pytest.ini":
# allowed to be empty
return base, p, {}
return None, None, None
def get_common_ancestor(paths):
common_ancestor = None
for path in paths:
if not path.exists():
continue
if common_ancestor is None:
common_ancestor = path
else:
if path.relto(common_ancestor) or path == common_ancestor:
continue
elif common_ancestor.relto(path):
common_ancestor = path
else:
shared = path.common(common_ancestor)
if shared is not None:
common_ancestor = shared
if common_ancestor is None:
common_ancestor = py.path.local()
elif common_ancestor.isfile():
common_ancestor = common_ancestor.dirpath()
return common_ancestor
def get_dirs_from_args(args):
def is_option(x):
return str(x).startswith("-")
def get_file_part_from_node_id(x):
return str(x).split("::")[0]
def get_dir_from_path(path):
if path.isdir():
return path
return py.path.local(path.dirname)
# These look like paths but may not exist
possible_paths = (
py.path.local(get_file_part_from_node_id(arg))
for arg in args
if not is_option(arg)
)
return [get_dir_from_path(path) for path in possible_paths if path.exists()]
def determine_setup(inifile, args, warnfunc=None, rootdir_cmd_arg=None):
dirs = get_dirs_from_args(args)
if inifile:
iniconfig = py.iniconfig.IniConfig(inifile)
is_cfg_file = str(inifile).endswith(".cfg")
# TODO: [pytest] section in *.cfg files is depricated. Need refactoring.
sections = ["tool:pytest", "pytest"] if is_cfg_file else ["pytest"]
for section in sections:
try:
inicfg = iniconfig[section]
if is_cfg_file and section == "pytest" and warnfunc:
from _pytest.deprecated import CFG_PYTEST_SECTION
warnfunc("C1", CFG_PYTEST_SECTION.format(filename=str(inifile)))
break
except KeyError:
inicfg = None
rootdir = get_common_ancestor(dirs)
else:
ancestor = get_common_ancestor(dirs)
rootdir, inifile, inicfg = getcfg([ancestor], warnfunc=warnfunc)
if rootdir is None:
for rootdir in ancestor.parts(reverse=True):
if rootdir.join("setup.py").exists():
break
else:
rootdir, inifile, inicfg = getcfg(dirs, warnfunc=warnfunc)
if rootdir is None:
rootdir = get_common_ancestor([py.path.local(), ancestor])
is_fs_root = os.path.splitdrive(str(rootdir))[1] == "/"
if is_fs_root:
rootdir = ancestor
if rootdir_cmd_arg:
rootdir_abs_path = py.path.local(os.path.expandvars(rootdir_cmd_arg))
if not os.path.isdir(str(rootdir_abs_path)):
raise UsageError(
"Directory '{}' not found. Check your '--rootdir' option.".format(
rootdir_abs_path
)
)
rootdir = rootdir_abs_path
return rootdir, inifile, inicfg or {}

View File

@ -65,6 +65,7 @@ def pytest_configure(config):
class pytestPDB(object): class pytestPDB(object):
""" Pseudo PDB that defers to the real pdb. """ """ Pseudo PDB that defers to the real pdb. """
_pluginmanager = None _pluginmanager = None
_config = None _config = None
_pdb_cls = pdb.Pdb _pdb_cls = pdb.Pdb
@ -87,7 +88,6 @@ class pytestPDB(object):
class PdbInvoke(object): class PdbInvoke(object):
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:
@ -114,7 +114,9 @@ def _enter_pdb(node, excinfo, rep):
showcapture = node.config.option.showcapture showcapture = node.config.option.showcapture
for sectionname, content in ( for sectionname, content in (
("stdout", rep.capstdout), ("stderr", rep.capstderr), ("log", rep.caplog) ("stdout", rep.capstdout),
("stderr", rep.capstderr),
("log", rep.caplog),
): ):
if showcapture in (sectionname, "all") and content: if showcapture in (sectionname, "all") and content:
tw.sep(">", "captured " + sectionname) tw.sep(">", "captured " + sectionname)
@ -148,9 +150,7 @@ def _find_last_non_hidden_frame(stack):
def post_mortem(t): def post_mortem(t):
class Pdb(pytestPDB._pdb_cls): class Pdb(pytestPDB._pdb_cls):
def get_stack(self, f, t): def get_stack(self, f, t):
stack, i = pdb.Pdb.get_stack(self, f, t) stack, i = pdb.Pdb.get_stack(self, f, t)
if f is None: if f is None:

View File

@ -22,7 +22,9 @@ FUNCARG_PREFIX = (
"Please remove the prefix and use the @pytest.fixture decorator instead." "Please remove the prefix and use the @pytest.fixture decorator instead."
) )
CFG_PYTEST_SECTION = "[pytest] section in {filename} files is deprecated, use [tool:pytest] instead." CFG_PYTEST_SECTION = (
"[pytest] section in {filename} files is deprecated, use [tool:pytest] instead."
)
GETFUNCARGVALUE = "use of getfuncargvalue is deprecated, use getfixturevalue" GETFUNCARGVALUE = "use of getfuncargvalue is deprecated, use getfixturevalue"

View File

@ -105,7 +105,6 @@ def _is_doctest(config, path, parent):
class ReprFailDoctest(TerminalRepr): class ReprFailDoctest(TerminalRepr):
def __init__(self, reprlocation_lines): def __init__(self, reprlocation_lines):
# List of (reprlocation, lines) tuples # List of (reprlocation, lines) tuples
self.reprlocation_lines = reprlocation_lines self.reprlocation_lines = reprlocation_lines
@ -118,7 +117,6 @@ class ReprFailDoctest(TerminalRepr):
class MultipleDoctestFailures(Exception): class MultipleDoctestFailures(Exception):
def __init__(self, failures): def __init__(self, failures):
super(MultipleDoctestFailures, self).__init__() super(MultipleDoctestFailures, self).__init__()
self.failures = failures self.failures = failures
@ -172,7 +170,6 @@ def _get_runner(checker=None, verbose=None, optionflags=0, continue_on_failure=T
class DoctestItem(pytest.Item): class DoctestItem(pytest.Item):
def __init__(self, name, parent, runner=None, dtest=None): def __init__(self, name, parent, runner=None, dtest=None):
super(DoctestItem, self).__init__(name, parent) super(DoctestItem, self).__init__(name, parent)
self.runner = runner self.runner = runner
@ -243,7 +240,7 @@ class DoctestItem(pytest.Item):
for (i, x) in enumerate(lines) for (i, x) in enumerate(lines)
] ]
# trim docstring error lines to 10 # trim docstring error lines to 10
lines = lines[max(example.lineno - 9, 0):example.lineno + 1] lines = lines[max(example.lineno - 9, 0) : example.lineno + 1]
else: else:
lines = [ lines = [
"EXAMPLE LOCATION UNKNOWN, not showing all tests of that example" "EXAMPLE LOCATION UNKNOWN, not showing all tests of that example"
@ -255,9 +252,7 @@ class DoctestItem(pytest.Item):
if isinstance(failure, doctest.DocTestFailure): if isinstance(failure, doctest.DocTestFailure):
lines += checker.output_difference( lines += checker.output_difference(
example, failure.got, report_choice example, failure.got, report_choice
).split( ).split("\n")
"\n"
)
else: else:
inner_excinfo = ExceptionInfo(failure.exc_info) inner_excinfo = ExceptionInfo(failure.exc_info)
lines += ["UNEXPECTED EXCEPTION: %s" % repr(inner_excinfo.value)] lines += ["UNEXPECTED EXCEPTION: %s" % repr(inner_excinfo.value)]
@ -347,7 +342,6 @@ def _check_all_skipped(test):
class DoctestModule(pytest.Module): class DoctestModule(pytest.Module):
def collect(self): def collect(self):
import doctest import doctest
@ -480,9 +474,7 @@ def _get_report_choice(key):
DOCTEST_REPORT_CHOICE_NDIFF: doctest.REPORT_NDIFF, DOCTEST_REPORT_CHOICE_NDIFF: doctest.REPORT_NDIFF,
DOCTEST_REPORT_CHOICE_ONLY_FIRST_FAILURE: doctest.REPORT_ONLY_FIRST_FAILURE, DOCTEST_REPORT_CHOICE_ONLY_FIRST_FAILURE: doctest.REPORT_ONLY_FIRST_FAILURE,
DOCTEST_REPORT_CHOICE_NONE: 0, DOCTEST_REPORT_CHOICE_NONE: 0,
}[ }[key]
key
]
def _fix_spoof_python2(runner, encoding): def _fix_spoof_python2(runner, encoding):
@ -502,10 +494,9 @@ def _fix_spoof_python2(runner, encoding):
from doctest import _SpoofOut from doctest import _SpoofOut
class UnicodeSpoof(_SpoofOut): class UnicodeSpoof(_SpoofOut):
def getvalue(self): def getvalue(self):
result = _SpoofOut.getvalue(self) result = _SpoofOut.getvalue(self)
if encoding: if encoding and isinstance(result, bytes):
result = result.decode(encoding) result = result.decode(encoding)
return result return result

View File

@ -65,7 +65,6 @@ scope2props["function"] = scope2props["instance"] + ("function", "keywords")
def scopeproperty(name=None, doc=None): def scopeproperty(name=None, doc=None):
def decoratescope(func): def decoratescope(func):
scopename = name or func.__name__ scopename = name or func.__name__
@ -276,7 +275,6 @@ def get_direct_param_fixture_func(request):
class FuncFixtureInfo(object): class FuncFixtureInfo(object):
def __init__(self, argnames, names_closure, name2fixturedefs): def __init__(self, argnames, names_closure, name2fixturedefs):
self.argnames = argnames self.argnames = argnames
self.names_closure = names_closure self.names_closure = names_closure
@ -698,7 +696,6 @@ class FixtureLookupError(LookupError):
class FixtureLookupErrorRepr(TerminalRepr): class FixtureLookupErrorRepr(TerminalRepr):
def __init__(self, filename, firstlineno, tblines, errorstring, argname): def __init__(self, filename, firstlineno, tblines, errorstring, argname):
self.tblines = tblines self.tblines = tblines
self.errorstring = errorstring self.errorstring = errorstring
@ -837,9 +834,10 @@ class FixtureDef(object):
return hook.pytest_fixture_setup(fixturedef=self, request=request) return hook.pytest_fixture_setup(fixturedef=self, request=request)
def __repr__(self): def __repr__(self):
return ( return "<FixtureDef name=%r scope=%r baseid=%r >" % (
"<FixtureDef name=%r scope=%r baseid=%r >" self.argname,
% (self.argname, self.scope, self.baseid) self.scope,
self.baseid,
) )
@ -1064,7 +1062,7 @@ class FixtureManager(object):
if nodeid.startswith(baseid): if nodeid.startswith(baseid):
if baseid: if baseid:
i = len(baseid) i = len(baseid)
nextchar = nodeid[i:i + 1] nextchar = nodeid[i : i + 1]
if nextchar and nextchar not in ":/": if nextchar and nextchar not in ":/":
continue continue
autousenames.extend(basenames) autousenames.extend(basenames)
@ -1171,7 +1169,7 @@ class FixtureManager(object):
self.config.warn( self.config.warn(
"C1", deprecated.FUNCARG_PREFIX.format(name=name), nodeid=nodeid "C1", deprecated.FUNCARG_PREFIX.format(name=name), nodeid=nodeid
) )
name = name[len(self._argprefix):] name = name[len(self._argprefix) :]
elif not isinstance(marker, FixtureFunctionMarker): elif not isinstance(marker, FixtureFunctionMarker):
# magic globals with __getattr__ might have got us a wrong # magic globals with __getattr__ might have got us a wrong
# fixture attribute # fixture attribute

View File

@ -149,7 +149,7 @@ def showhelp(config):
type = "string" type = "string"
spec = "%s (%s)" % (name, type) spec = "%s (%s)" % (name, type)
line = " %-24s %s" % (spec, help) line = " %-24s %s" % (spec, help)
tw.line(line[:tw.fullwidth]) tw.line(line[: tw.fullwidth])
tw.line() tw.line()
tw.line("environment variables:") tw.line("environment variables:")

View File

@ -55,7 +55,6 @@ _py_ext_re = re.compile(r"\.py$")
def bin_xml_escape(arg): def bin_xml_escape(arg):
def repl(matchobj): def repl(matchobj):
i = ord(matchobj.group()) i = ord(matchobj.group())
if i <= 0xFF: if i <= 0xFF:
@ -67,7 +66,6 @@ def bin_xml_escape(arg):
class _NodeReporter(object): class _NodeReporter(object):
def __init__(self, nodeid, xml): def __init__(self, nodeid, xml):
self.id = nodeid self.id = nodeid
@ -358,7 +356,6 @@ def mangle_test_address(address):
class LogXML(object): class LogXML(object):
def __init__(self, logfile, prefix, suite_name="pytest", logging="no"): def __init__(self, logfile, prefix, suite_name="pytest", logging="no"):
logfile = os.path.expanduser(os.path.expandvars(logfile)) logfile = os.path.expanduser(os.path.expandvars(logfile))
self.logfile = os.path.normpath(os.path.abspath(logfile)) self.logfile = os.path.normpath(os.path.abspath(logfile))
@ -544,9 +541,7 @@ class LogXML(object):
skips=self.stats["skipped"], skips=self.stats["skipped"],
tests=numtests, tests=numtests,
time="%.3f" % suite_time_delta, time="%.3f" % suite_time_delta,
).unicode( ).unicode(indent=0)
indent=0
)
) )
logfile.close() logfile.close()

View File

@ -425,9 +425,7 @@ class LoggingPlugin(object):
""" """
return self._config.getoption( return self._config.getoption(
"--log-cli-level" "--log-cli-level"
) is not None or self._config.getini( ) is not None or self._config.getini("log_cli")
"log_cli"
)
@contextmanager @contextmanager
def _runtest_for(self, item, when): def _runtest_for(self, item, when):

View File

@ -343,7 +343,6 @@ def _patched_find_module():
class FSHookProxy(object): class FSHookProxy(object):
def __init__(self, fspath, pm, remove_mods): def __init__(self, fspath, pm, remove_mods):
self.fspath = fspath self.fspath = fspath
self.pm = pm self.pm = pm
@ -361,6 +360,7 @@ class NoMatch(Exception):
class Interrupted(KeyboardInterrupt): class Interrupted(KeyboardInterrupt):
""" signals an interrupted test run. """ """ signals an interrupted test run. """
__module__ = "builtins" # for py3 __module__ = "builtins" # for py3

View File

@ -21,7 +21,6 @@ def cached_eval(config, expr, d):
class MarkEvaluator(object): class MarkEvaluator(object):
def __init__(self, item, name): def __init__(self, item, name):
self.item = item self.item = item
self._marks = None self._marks = None

View File

@ -1,13 +1,14 @@
import inspect import inspect
import warnings import warnings
from collections import namedtuple from collections import namedtuple
from functools import reduce
from operator import attrgetter from operator import attrgetter
import attr import attr
from ..deprecated import MARK_PARAMETERSET_UNPACKING, MARK_INFO_ATTRIBUTE from ..deprecated import MARK_PARAMETERSET_UNPACKING, MARK_INFO_ATTRIBUTE
from ..compat import NOTSET, getfslineno, MappingMixin from ..compat import NOTSET, getfslineno, MappingMixin
from six.moves import map, reduce from six.moves import map
EMPTY_PARAMETERSET_OPTION = "empty_parameter_set_mark" EMPTY_PARAMETERSET_OPTION = "empty_parameter_set_mark"
@ -24,9 +25,10 @@ def alias(name, warning=None):
def istestfunc(func): def istestfunc(func):
return hasattr(func, "__call__") and getattr( return (
func, "__name__", "<lambda>" hasattr(func, "__call__")
) != "<lambda>" and getattr(func, "__name__", "<lambda>") != "<lambda>"
)
def get_empty_parameterset_mark(config, argnames, func): def get_empty_parameterset_mark(config, argnames, func):
@ -39,18 +41,20 @@ def get_empty_parameterset_mark(config, argnames, func):
raise LookupError(requested_mark) raise LookupError(requested_mark)
fs, lineno = getfslineno(func) fs, lineno = getfslineno(func)
reason = "got empty parameter set %r, function %s at %s:%d" % ( reason = "got empty parameter set %r, function %s at %s:%d" % (
argnames, func.__name__, fs, lineno argnames,
func.__name__,
fs,
lineno,
) )
return mark(reason=reason) return mark(reason=reason)
class ParameterSet(namedtuple("ParameterSet", "values, marks, id")): class ParameterSet(namedtuple("ParameterSet", "values, marks, id")):
@classmethod @classmethod
def param(cls, *values, **kw): def param(cls, *values, **kw):
marks = kw.pop("marks", ()) marks = kw.pop("marks", ())
if isinstance(marks, MarkDecorator): if isinstance(marks, MarkDecorator):
marks = marks, marks = (marks,)
else: else:
assert isinstance(marks, (tuple, list, set)) assert isinstance(marks, (tuple, list, set))
@ -87,7 +91,7 @@ class ParameterSet(namedtuple("ParameterSet", "values, marks, id")):
argval = argval.args[-1] argval = argval.args[-1]
assert not isinstance(argval, ParameterSet) assert not isinstance(argval, ParameterSet)
if legacy_force_tuple: if legacy_force_tuple:
argval = argval, argval = (argval,)
if newmarks: if newmarks:
warnings.warn(MARK_PARAMETERSET_UNPACKING) warnings.warn(MARK_PARAMETERSET_UNPACKING)
@ -332,6 +336,7 @@ class MarkGenerator(object):
will set a 'slowtest' :class:`MarkInfo` object will set a 'slowtest' :class:`MarkInfo` object
on the ``test_function`` object. """ on the ``test_function`` object. """
_config = None _config = None
def __getattr__(self, name): def __getattr__(self, name):
@ -361,7 +366,6 @@ MARK_GEN = MarkGenerator()
class NodeKeywords(MappingMixin): class NodeKeywords(MappingMixin):
def __init__(self, node): def __init__(self, node):
self.node = node self.node = node
self.parent = node.parent self.parent = node.parent
@ -408,6 +412,7 @@ class NodeMarkers(object):
unstable api unstable api
""" """
own_markers = attr.ib(default=attr.Factory(list)) own_markers = attr.ib(default=attr.Factory(list))
def update(self, add_markers): def update(self, add_markers):

View File

@ -86,7 +86,6 @@ def derive_importpath(import_path, raising):
class Notset(object): class Notset(object):
def __repr__(self): def __repr__(self):
return "<notset>" return "<notset>"

View File

@ -48,7 +48,7 @@ def ischildnode(baseid, nodeid):
node_parts = _splitnode(nodeid) node_parts = _splitnode(nodeid)
if len(node_parts) < len(base_parts): if len(node_parts) < len(base_parts):
return False return False
return node_parts[:len(base_parts)] == base_parts return node_parts[: len(base_parts)] == base_parts
@attr.s @attr.s
@ -341,7 +341,6 @@ def _check_initialpaths_for_relpath(session, fspath):
class FSCollector(Collector): class FSCollector(Collector):
def __init__(self, fspath, parent=None, config=None, session=None, nodeid=None): def __init__(self, fspath, parent=None, config=None, session=None, nodeid=None):
fspath = py.path.local(fspath) # xxx only for test_resultlog.py? fspath = py.path.local(fspath) # xxx only for test_resultlog.py?
name = fspath.basename name = fspath.basename
@ -375,6 +374,7 @@ class Item(Node):
""" a basic test invocation item. Note that for a single function """ a basic test invocation item. Note that for a single function
there might be multiple test invocation items. there might be multiple test invocation items.
""" """
nextitem = None nextitem = None
def __init__(self, name, parent=None, config=None, session=None, nodeid=None): def __init__(self, name, parent=None, config=None, session=None, nodeid=None):

View File

@ -43,6 +43,7 @@ class Skipped(OutcomeException):
class Failed(OutcomeException): class Failed(OutcomeException):
""" raised from an explicit call to pytest.fail() """ """ raised from an explicit call to pytest.fail() """
__module__ = "builtins" __module__ = "builtins"

View File

@ -62,7 +62,6 @@ def pytest_configure(config):
class LsofFdLeakChecker(object): class LsofFdLeakChecker(object):
def get_open_files(self): def get_open_files(self):
out = self._exec_lsof() out = self._exec_lsof()
open_files = self._parse_lsof_output(out) open_files = self._parse_lsof_output(out)
@ -73,7 +72,6 @@ class LsofFdLeakChecker(object):
return py.process.cmdexec("lsof -Ffn0 -p %d" % pid) return py.process.cmdexec("lsof -Ffn0 -p %d" % pid)
def _parse_lsof_output(self, out): def _parse_lsof_output(self, out):
def isopen(line): def isopen(line):
return line.startswith("f") and ( return line.startswith("f") and (
"deleted" not in line "deleted" not in line
@ -195,7 +193,6 @@ def _pytest(request):
class PytestArg(object): class PytestArg(object):
def __init__(self, request): def __init__(self, request):
self.request = request self.request = request
@ -211,7 +208,6 @@ def get_public_names(values):
class ParsedCall(object): class ParsedCall(object):
def __init__(self, name, kwargs): def __init__(self, name, kwargs):
self.__dict__.update(kwargs) self.__dict__.update(kwargs)
self._name = name self._name = name
@ -423,13 +419,12 @@ class RunResult(object):
"failed": d.get("failed", 0), "failed": d.get("failed", 0),
"error": d.get("error", 0), "error": d.get("error", 0),
} }
assert ( assert obtained == dict(
obtained == dict(passed=passed, skipped=skipped, failed=failed, error=error) passed=passed, skipped=skipped, failed=failed, error=error
) )
class CwdSnapshot(object): class CwdSnapshot(object):
def __init__(self): def __init__(self):
self.__saved = os.getcwd() self.__saved = os.getcwd()
@ -438,7 +433,6 @@ class CwdSnapshot(object):
class SysModulesSnapshot(object): class SysModulesSnapshot(object):
def __init__(self, preserve=None): def __init__(self, preserve=None):
self.__preserve = preserve self.__preserve = preserve
self.__saved = dict(sys.modules) self.__saved = dict(sys.modules)
@ -453,7 +447,6 @@ class SysModulesSnapshot(object):
class SysPathsSnapshot(object): class SysPathsSnapshot(object):
def __init__(self): def __init__(self):
self.__saved = list(sys.path), list(sys.meta_path) self.__saved = list(sys.path), list(sys.meta_path)
@ -778,7 +771,6 @@ class Testdir(object):
rec = [] rec = []
class Collect(object): class Collect(object):
def pytest_configure(x, config): def pytest_configure(x, config):
rec.append(self.make_hook_recorder(config.pluginmanager)) rec.append(self.make_hook_recorder(config.pluginmanager))
@ -910,8 +902,10 @@ class Testdir(object):
for item in items: for item in items:
if item.name == funcname: if item.name == funcname:
return item return item
assert 0, ( assert 0, "%r item not found in module:\n%s\nitems: %s" % (
"%r item not found in module:\n%s\nitems: %s" % (funcname, source, items) funcname,
source,
items,
) )
def getitems(self, source): def getitems(self, source):
@ -1115,7 +1109,6 @@ def getdecoded(out):
class LineComp(object): class LineComp(object):
def __init__(self): def __init__(self):
self.stringio = py.io.TextIO() self.stringio = py.io.TextIO()
@ -1202,7 +1195,7 @@ class LineMatcher(object):
""" """
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):
return self.lines[i + 1:] return self.lines[i + 1 :]
raise ValueError("line %r not found in output" % fnline) raise ValueError("line %r not found in output" % fnline)
def _log(self, *args): def _log(self, *args):

View File

@ -69,13 +69,12 @@ def filter_traceback(entry):
# entry.path might point to a non-existing file, in which case it will # entry.path might point to a non-existing file, in which case it will
# also return a str object. see #1133 # also return a str object. see #1133
p = py.path.local(entry.path) p = py.path.local(entry.path)
return not p.relto(_pluggy_dir) and not p.relto(_pytest_dir) and not p.relto( return (
_py_dir not p.relto(_pluggy_dir) and not p.relto(_pytest_dir) and not p.relto(_py_dir)
) )
def pyobj_property(name): def pyobj_property(name):
def get(self): def get(self):
node = self.getparent(getattr(__import__("pytest"), name)) node = self.getparent(getattr(__import__("pytest"), name))
if node is not None: if node is not None:
@ -258,7 +257,6 @@ class PyobjMixin(PyobjContext):
super(PyobjMixin, self).__init__(*k, **kw) super(PyobjMixin, self).__init__(*k, **kw)
def obj(): def obj():
def fget(self): def fget(self):
obj = getattr(self, "_obj", None) obj = getattr(self, "_obj", None)
if obj is None: if obj is None:
@ -320,7 +318,6 @@ class PyobjMixin(PyobjContext):
class PyCollector(PyobjMixin, nodes.Collector): class PyCollector(PyobjMixin, nodes.Collector):
def funcnamefilter(self, name): def funcnamefilter(self, name):
return self._matches_prefix_or_glob_option("python_functions", name) return self._matches_prefix_or_glob_option("python_functions", name)
@ -487,9 +484,11 @@ class Module(nodes.File, PyCollector):
exc_info = ExceptionInfo() exc_info = ExceptionInfo()
if self.config.getoption("verbose") < 2: if self.config.getoption("verbose") < 2:
exc_info.traceback = exc_info.traceback.filter(filter_traceback) exc_info.traceback = exc_info.traceback.filter(filter_traceback)
exc_repr = exc_info.getrepr( exc_repr = (
style="short" exc_info.getrepr(style="short")
) if exc_info.traceback else exc_info.exconly() if exc_info.traceback
else exc_info.exconly()
)
formatted_tb = safe_str(exc_repr) formatted_tb = safe_str(exc_repr)
raise self.CollectError( raise self.CollectError(
"ImportError while importing test module '{fspath}'.\n" "ImportError while importing test module '{fspath}'.\n"
@ -673,7 +672,6 @@ class FunctionMixin(PyobjMixin):
class Generator(FunctionMixin, PyCollector): class Generator(FunctionMixin, PyCollector):
def collect(self): def collect(self):
# test generators are seen as collectors but they also # test generators are seen as collectors but they also
# invoke setup/teardown on popular request # invoke setup/teardown on popular request
@ -728,20 +726,18 @@ def hasnew(obj):
class CallSpec2(object): class CallSpec2(object):
def __init__(self, metafunc): def __init__(self, metafunc):
self.metafunc = metafunc self.metafunc = metafunc
self.funcargs = {} self.funcargs = {}
self._idlist = [] self._idlist = []
self.params = {} self.params = {}
self._globalid = NOTSET self._globalid = NOTSET
self._globalid_args = set()
self._globalparam = NOTSET self._globalparam = NOTSET
self._arg2scopenum = {} # used for sorting parametrized resources self._arg2scopenum = {} # used for sorting parametrized resources
self.marks = [] self.marks = []
self.indices = {} self.indices = {}
def copy(self, metafunc): def copy(self):
cs = CallSpec2(self.metafunc) cs = CallSpec2(self.metafunc)
cs.funcargs.update(self.funcargs) cs.funcargs.update(self.funcargs)
cs.params.update(self.params) cs.params.update(self.params)
@ -750,7 +746,6 @@ class CallSpec2(object):
cs._arg2scopenum.update(self._arg2scopenum) cs._arg2scopenum.update(self._arg2scopenum)
cs._idlist = list(self._idlist) cs._idlist = list(self._idlist)
cs._globalid = self._globalid cs._globalid = self._globalid
cs._globalid_args = self._globalid_args
cs._globalparam = self._globalparam cs._globalparam = self._globalparam
return cs return cs
@ -933,7 +928,7 @@ class Metafunc(fixtures.FuncargnamesCompatAttr):
param.values, argnames param.values, argnames
) )
) )
newcallspec = callspec.copy(self) newcallspec = callspec.copy()
newcallspec.setmulti2( newcallspec.setmulti2(
valtypes, valtypes,
argnames, argnames,
@ -1004,9 +999,9 @@ def _find_parametrized_scope(argnames, arg2fixturedefs, indirect):
from _pytest.fixtures import scopes from _pytest.fixtures import scopes
indirect_as_list = isinstance(indirect, (list, tuple)) indirect_as_list = isinstance(indirect, (list, tuple))
all_arguments_are_fixtures = indirect is True or indirect_as_list and len( all_arguments_are_fixtures = (
indirect indirect is True or indirect_as_list and len(indirect) == argnames
) == argnames )
if all_arguments_are_fixtures: if all_arguments_are_fixtures:
fixturedefs = arg2fixturedefs or {} fixturedefs = arg2fixturedefs or {}
used_scopes = [fixturedef[0].scope for name, fixturedef in fixturedefs.items()] used_scopes = [fixturedef[0].scope for name, fixturedef in fixturedefs.items()]
@ -1028,8 +1023,9 @@ def _idval(val, argname, idx, idfn, config=None):
# See issue https://github.com/pytest-dev/pytest/issues/2169 # See issue https://github.com/pytest-dev/pytest/issues/2169
import warnings import warnings
msg = "Raised while trying to determine id of parameter %s at position %d." % ( msg = (
argname, idx "Raised while trying to determine id of parameter %s at position %d."
% (argname, idx)
) )
msg += "\nUpdate your code as this will raise an error in pytest-4.0." msg += "\nUpdate your code as this will raise an error in pytest-4.0."
warnings.warn(msg, DeprecationWarning) warnings.warn(msg, DeprecationWarning)
@ -1224,6 +1220,7 @@ class Function(FunctionMixin, nodes.Item, fixtures.FuncargnamesCompatAttr):
""" a Function Item is responsible for setting up and executing a """ a Function Item is responsible for setting up and executing a
Python test function. Python test function.
""" """
_genid = None _genid = None
# disable since functions handle it themselfes # disable since functions handle it themselfes
_ALLOW_MARKERS = False _ALLOW_MARKERS = False

View File

@ -86,9 +86,11 @@ class ApproxNumpy(ApproxBase):
# shape of the array... # shape of the array...
import numpy as np import numpy as np
return "approx({!r})".format( list_scalars = []
list(self._approx_scalar(x) for x in np.asarray(self.expected)) for x in np.ndindex(self.expected.shape):
) list_scalars.append(self._approx_scalar(np.asscalar(self.expected[x])))
return "approx({!r})".format(list_scalars)
if sys.version_info[0] == 2: if sys.version_info[0] == 2:
__cmp__ = _cmp_raises_type_error __cmp__ = _cmp_raises_type_error
@ -172,6 +174,7 @@ class ApproxScalar(ApproxBase):
""" """
Perform approximate comparisons for single numbers only. Perform approximate comparisons for single numbers only.
""" """
DEFAULT_ABSOLUTE_TOLERANCE = 1e-12 DEFAULT_ABSOLUTE_TOLERANCE = 1e-12
DEFAULT_RELATIVE_TOLERANCE = 1e-6 DEFAULT_RELATIVE_TOLERANCE = 1e-6
@ -269,9 +272,7 @@ class ApproxScalar(ApproxBase):
# we aren't even going to use it. # we aren't even going to use it.
relative_tolerance = set_default( relative_tolerance = set_default(
self.rel, self.DEFAULT_RELATIVE_TOLERANCE self.rel, self.DEFAULT_RELATIVE_TOLERANCE
) * abs( ) * abs(self.expected)
self.expected
)
if relative_tolerance < 0: if relative_tolerance < 0:
raise ValueError( raise ValueError(
@ -497,7 +498,7 @@ def _is_numpy_array(obj):
def raises(expected_exception, *args, **kwargs): def raises(expected_exception, *args, **kwargs):
""" r"""
Assert that a code block/function call raises ``expected_exception`` Assert that a code block/function call raises ``expected_exception``
and raise a failure exception otherwise. and raise a failure exception otherwise.
@ -650,7 +651,6 @@ raises.Exception = fail.Exception
class RaisesContext(object): class RaisesContext(object):
def __init__(self, expected_exception, message, match_expr): def __init__(self, expected_exception, message, match_expr):
self.expected_exception = expected_exception self.expected_exception = expected_exception
self.message = message self.message = message

View File

@ -85,7 +85,7 @@ class _DeprecatedCallContext(object):
def warns(expected_warning, *args, **kwargs): def warns(expected_warning, *args, **kwargs):
"""Assert that code raises a particular class of warning. r"""Assert that code raises a particular class of warning.
Specifically, the parameter ``expected_warning`` can be a warning class or Specifically, the parameter ``expected_warning`` can be a warning class or
sequence of warning classes, and the inside the ``with`` block must issue a warning of that class or sequence of warning classes, and the inside the ``with`` block must issue a warning of that class or
@ -193,13 +193,10 @@ class WarningsRecorder(warnings.catch_warnings):
class WarningsChecker(WarningsRecorder): class WarningsChecker(WarningsRecorder):
def __init__(self, expected_warning=None, match_expr=None): def __init__(self, expected_warning=None, match_expr=None):
super(WarningsChecker, self).__init__() super(WarningsChecker, self).__init__()
msg = ( msg = "exceptions must be old-style classes or " "derived from Warning, not %s"
"exceptions must be old-style classes or " "derived from Warning, not %s"
)
if isinstance(expected_warning, tuple): if isinstance(expected_warning, tuple):
for exc in expected_warning: for exc in expected_warning:
if not inspect.isclass(exc): if not inspect.isclass(exc):

View File

@ -68,7 +68,6 @@ def generic_path(item):
class ResultLog(object): class ResultLog(object):
def __init__(self, config, logfile): def __init__(self, config, logfile):
self.config = config self.config = config
self.logfile = logfile # preferably line buffered self.logfile = logfile # preferably line buffered

View File

@ -186,6 +186,7 @@ def call_runtest_hook(item, when, **kwds):
class CallInfo(object): class CallInfo(object):
""" Result/Exception info a function invocation. """ """ Result/Exception info a function invocation. """
#: None or ExceptionInfo object. #: None or ExceptionInfo object.
excinfo = None excinfo = None
@ -221,13 +222,15 @@ def getslaveinfoline(node):
d = node.slaveinfo d = node.slaveinfo
ver = "%s.%s.%s" % d["version_info"][:3] ver = "%s.%s.%s" % d["version_info"][:3]
node._slaveinfocache = s = "[%s] %s -- Python %s %s" % ( node._slaveinfocache = s = "[%s] %s -- Python %s %s" % (
d["id"], d["sysplatform"], ver, d["executable"] d["id"],
d["sysplatform"],
ver,
d["executable"],
) )
return s return s
class BaseReport(object): class BaseReport(object):
def __init__(self, **kw): def __init__(self, **kw):
self.__dict__.update(kw) self.__dict__.update(kw)
@ -401,7 +404,9 @@ class TestReport(BaseReport):
def __repr__(self): def __repr__(self):
return "<TestReport %r when=%r outcome=%r>" % ( return "<TestReport %r when=%r outcome=%r>" % (
self.nodeid, self.when, self.outcome self.nodeid,
self.when,
self.outcome,
) )
@ -442,7 +447,6 @@ def pytest_make_collect_report(collector):
class CollectReport(BaseReport): class CollectReport(BaseReport):
def __init__(self, nodeid, outcome, longrepr, result, sections=(), **extra): def __init__(self, nodeid, outcome, longrepr, result, sections=(), **extra):
self.nodeid = nodeid self.nodeid = nodeid
self.outcome = outcome self.outcome = outcome
@ -457,12 +461,13 @@ class CollectReport(BaseReport):
def __repr__(self): def __repr__(self):
return "<CollectReport %r lenresult=%s outcome=%r>" % ( return "<CollectReport %r lenresult=%s outcome=%r>" % (
self.nodeid, len(self.result), self.outcome self.nodeid,
len(self.result),
self.outcome,
) )
class CollectErrorRepr(TerminalRepr): class CollectErrorRepr(TerminalRepr):
def __init__(self, msg): def __init__(self, msg):
self.longrepr = msg self.longrepr = msg
@ -529,7 +534,7 @@ class SetupState(object):
def _teardown_towards(self, needed_collectors): def _teardown_towards(self, needed_collectors):
exc = None exc = None
while self.stack: while self.stack:
if self.stack == needed_collectors[:len(self.stack)]: if self.stack == needed_collectors[: len(self.stack)]:
break break
try: try:
self._pop_and_teardown() self._pop_and_teardown()
@ -551,7 +556,7 @@ class SetupState(object):
for col in self.stack: for col in self.stack:
if hasattr(col, "_prepare_exc"): if hasattr(col, "_prepare_exc"):
py.builtin._reraise(*col._prepare_exc) py.builtin._reraise(*col._prepare_exc)
for col in needed_collectors[len(self.stack):]: for col in needed_collectors[len(self.stack) :]:
self.stack.append(col) self.stack.append(col)
try: try:
col.setup() col.setup()

View File

@ -157,9 +157,11 @@ def pytest_runtest_makereport(item, call):
else: else:
rep.outcome = "passed" rep.outcome = "passed"
rep.wasxfail = explanation rep.wasxfail = explanation
elif getattr(item, "_skipped_by_mark", False) and rep.skipped and type( elif (
rep.longrepr getattr(item, "_skipped_by_mark", False)
) is tuple: and rep.skipped
and type(rep.longrepr) is tuple
):
# skipped by mark.skipif; change the location of the failure # skipped by mark.skipif; change the location of the failure
# to point to the item definition, otherwise it will display # to point to the item definition, otherwise it will display
# the location of where the skip exception was raised within pytest # the location of where the skip exception was raised within pytest
@ -274,7 +276,6 @@ def show_skipped(terminalreporter, lines):
def shower(stat, format): def shower(stat, format):
def show_(terminalreporter, lines): def show_(terminalreporter, lines):
return show_simple(terminalreporter, lines, stat, format) return show_simple(terminalreporter, lines, stat, format)

View File

@ -220,7 +220,6 @@ class WarningReport(object):
class TerminalReporter(object): class TerminalReporter(object):
def __init__(self, config, file=None): def __init__(self, config, file=None):
import _pytest.config import _pytest.config
@ -407,13 +406,16 @@ class TerminalReporter(object):
def pytest_runtest_logfinish(self, nodeid): def pytest_runtest_logfinish(self, nodeid):
if self.verbosity <= 0 and self._show_progress_info: if self.verbosity <= 0 and self._show_progress_info:
self._progress_nodeids_reported.add(nodeid) self._progress_nodeids_reported.add(nodeid)
last_item = len( last_item = (
self._progress_nodeids_reported len(self._progress_nodeids_reported) == self._session.testscollected
) == self._session.testscollected )
if last_item: if last_item:
self._write_progress_information_filling_space() self._write_progress_information_filling_space()
else: else:
past_edge = self._tw.chars_on_current_line + self._PROGRESS_LENGTH + 1 >= self._screen_width past_edge = (
self._tw.chars_on_current_line + self._PROGRESS_LENGTH + 1
>= self._screen_width
)
if past_edge: if past_edge:
msg = self._get_progress_information_message() msg = self._get_progress_information_message()
self._tw.write(msg + "\n", cyan=True) self._tw.write(msg + "\n", cyan=True)
@ -462,8 +464,8 @@ class TerminalReporter(object):
line = "collected " line = "collected "
else: else:
line = "collecting " line = "collecting "
line += str(self._numcollected) + " item" + ( line += (
"" if self._numcollected == 1 else "s" str(self._numcollected) + " item" + ("" if self._numcollected == 1 else "s")
) )
if errors: if errors:
line += " / %d errors" % errors line += " / %d errors" % errors
@ -495,7 +497,9 @@ class TerminalReporter(object):
verinfo = ".".join(map(str, sys.pypy_version_info[:3])) verinfo = ".".join(map(str, sys.pypy_version_info[:3]))
msg += "[pypy-%s-%s]" % (verinfo, sys.pypy_version_info[3]) msg += "[pypy-%s-%s]" % (verinfo, sys.pypy_version_info[3])
msg += ", pytest-%s, py-%s, pluggy-%s" % ( msg += ", pytest-%s, py-%s, pluggy-%s" % (
pytest.__version__, py.__version__, pluggy.__version__ pytest.__version__,
py.__version__,
pluggy.__version__,
) )
if ( if (
self.verbosity > 0 self.verbosity > 0
@ -563,10 +567,10 @@ class TerminalReporter(object):
for item in items: for item in items:
needed_collectors = item.listchain()[1:] # strip root node needed_collectors = item.listchain()[1:] # strip root node
while stack: while stack:
if stack == needed_collectors[:len(stack)]: if stack == needed_collectors[: len(stack)]:
break break
stack.pop() stack.pop()
for col in needed_collectors[len(stack):]: for col in needed_collectors[len(stack) :]:
stack.append(col) stack.append(col)
# if col.name == "()": # if col.name == "()":
# continue # continue
@ -624,11 +628,10 @@ class TerminalReporter(object):
) )
def _locationline(self, nodeid, fspath, lineno, domain): def _locationline(self, nodeid, fspath, lineno, domain):
def mkrel(nodeid): def mkrel(nodeid):
line = self.config.cwd_relative_nodeid(nodeid) line = self.config.cwd_relative_nodeid(nodeid)
if domain and line.endswith(domain): if domain and line.endswith(domain):
line = line[:-len(domain)] line = line[: -len(domain)]
values = domain.split("[") values = domain.split("[")
values[0] = values[0].replace(".", "::") # don't replace '.' in params values[0] = values[0].replace(".", "::") # don't replace '.' in params
line += "[".join(values) line += "[".join(values)

View File

@ -163,15 +163,13 @@ class TestCaseFunction(Function):
# implements the skipping machinery (see #2137) # implements the skipping machinery (see #2137)
# analog to pythons Lib/unittest/case.py:run # analog to pythons Lib/unittest/case.py:run
testMethod = getattr(self._testcase, self._testcase._testMethodName) testMethod = getattr(self._testcase, self._testcase._testMethodName)
if ( if getattr(self._testcase.__class__, "__unittest_skip__", False) or getattr(
getattr(self._testcase.__class__, "__unittest_skip__", False) testMethod, "__unittest_skip__", False
or getattr(testMethod, "__unittest_skip__", False)
): ):
# If the class or method was skipped. # If the class or method was skipped.
skip_why = ( skip_why = getattr(
getattr(self._testcase.__class__, "__unittest_skip_why__", "") self._testcase.__class__, "__unittest_skip_why__", ""
or getattr(testMethod, "__unittest_skip_why__", "") ) or getattr(testMethod, "__unittest_skip_why__", "")
)
try: # PY3, unittest2 on PY2 try: # PY3, unittest2 on PY2
self._testcase._addSkip(self, self._testcase, skip_why) self._testcase._addSkip(self, self._testcase, skip_why)
except TypeError: # PY2 except TypeError: # PY2

View File

@ -75,9 +75,8 @@ def catch_warnings_for_item(item):
warn_msg = warning.message warn_msg = warning.message
unicode_warning = False unicode_warning = False
if ( if compat._PY2 and any(
compat._PY2 isinstance(m, compat.UNICODE_TYPES) for m in warn_msg.args
and any(isinstance(m, compat.UNICODE_TYPES) for m in warn_msg.args)
): ):
new_args = [] new_args = []
for m in warn_msg.args: for m in warn_msg.args:

View File

@ -22,16 +22,16 @@ def announce(ctx, version):
contributors = set(stdout.splitlines()) contributors = set(stdout.splitlines())
template_name = "release.minor.rst" if version.endswith( template_name = (
".0" "release.minor.rst" if version.endswith(".0") else "release.patch.rst"
) else "release.patch.rst" )
template_text = Path(__file__).parent.joinpath(template_name).read_text( template_text = (
encoding="UTF-8" Path(__file__).parent.joinpath(template_name).read_text(encoding="UTF-8")
) )
contributors_text = "\n".join( contributors_text = (
"* {}".format(name) for name in sorted(contributors) "\n".join("* {}".format(name) for name in sorted(contributors)) + "\n"
) + "\n" )
text = template_text.format(version=version, contributors=contributors_text) text = template_text.format(version=version, contributors=contributors_text)
target = Path(__file__).parent.joinpath( target = Path(__file__).parent.joinpath(

View File

@ -13,7 +13,6 @@ from _pytest.main import EXIT_NOTESTSCOLLECTED, EXIT_USAGEERROR
class TestGeneralUsage(object): class TestGeneralUsage(object):
def test_config_error(self, testdir): def test_config_error(self, testdir):
testdir.makeconftest( testdir.makeconftest(
""" """
@ -458,7 +457,6 @@ class TestGeneralUsage(object):
class TestInvocationVariants(object): class TestInvocationVariants(object):
def test_earlyinit(self, testdir): def test_earlyinit(self, testdir):
p = testdir.makepyfile( p = testdir.makepyfile(
""" """
@ -557,9 +555,7 @@ class TestInvocationVariants(object):
out, err = capsys.readouterr() out, err = capsys.readouterr()
def test_invoke_plugin_api(self, testdir, capsys): def test_invoke_plugin_api(self, testdir, capsys):
class MyPlugin(object): class MyPlugin(object):
def pytest_addoption(self, parser): def pytest_addoption(self, parser):
parser.addoption("--myopt") parser.addoption("--myopt")
@ -798,9 +794,10 @@ class TestInvocationVariants(object):
"""Test backward compatibility for get_plugin_manager function. See #787.""" """Test backward compatibility for get_plugin_manager function. See #787."""
import _pytest.config import _pytest.config
assert type( assert (
_pytest.config.get_plugin_manager() type(_pytest.config.get_plugin_manager())
) is _pytest.config.PytestPluginManager is _pytest.config.PytestPluginManager
)
def test_has_plugin(self, request): def test_has_plugin(self, request):
"""Test hasplugin function of the plugin manager (#932).""" """Test hasplugin function of the plugin manager (#932)."""

View File

@ -26,7 +26,6 @@ def test_code_gives_back_name_for_not_existing_file():
def test_code_with_class(): def test_code_with_class():
class A(object): class A(object):
pass pass
@ -54,7 +53,6 @@ def test_code_source():
def test_frame_getsourcelineno_myself(): def test_frame_getsourcelineno_myself():
def func(): def func():
return sys._getframe(0) return sys._getframe(0)
@ -65,7 +63,6 @@ def test_frame_getsourcelineno_myself():
def test_getstatement_empty_fullsource(): def test_getstatement_empty_fullsource():
def func(): def func():
return sys._getframe(0) return sys._getframe(0)
@ -111,7 +108,6 @@ def test_unicode_handling_syntax_error():
def test_code_getargs(): def test_code_getargs():
def f1(x): def f1(x):
pass pass
@ -138,7 +134,6 @@ def test_code_getargs():
def test_frame_getargs(): def test_frame_getargs():
def f1(x): def f1(x):
return sys._getframe(0) return sys._getframe(0)
@ -165,7 +160,6 @@ def test_frame_getargs():
class TestExceptionInfo(object): class TestExceptionInfo(object):
def test_bad_getsource(self): def test_bad_getsource(self):
try: try:
if False: if False:
@ -178,7 +172,6 @@ class TestExceptionInfo(object):
class TestTracebackEntry(object): class TestTracebackEntry(object):
def test_getsource(self): def test_getsource(self):
try: try:
if False: if False:
@ -194,7 +187,6 @@ class TestTracebackEntry(object):
class TestReprFuncArgs(object): class TestReprFuncArgs(object):
def test_not_raise_exception_with_mixed_encoding(self): def test_not_raise_exception_with_mixed_encoding(self):
from _pytest._code.code import ReprFuncArgs from _pytest._code.code import ReprFuncArgs

View File

@ -65,7 +65,6 @@ def test_excinfo_simple():
def test_excinfo_getstatement(): def test_excinfo_getstatement():
def g(): def g():
raise ValueError raise ValueError
@ -112,7 +111,6 @@ def h():
class TestTraceback_f_g_h(object): class TestTraceback_f_g_h(object):
def setup_method(self, method): def setup_method(self, method):
try: try:
h() h()
@ -194,7 +192,6 @@ class TestTraceback_f_g_h(object):
], ],
) )
def test_traceback_filter_selective(self, tracebackhide, matching): def test_traceback_filter_selective(self, tracebackhide, matching):
def f(): def f():
# #
raise ValueError raise ValueError
@ -224,7 +221,6 @@ class TestTraceback_f_g_h(object):
assert len(ntraceback) == len(traceback) - 1 assert len(ntraceback) == len(traceback) - 1
def test_traceback_recursion_index(self): def test_traceback_recursion_index(self):
def f(n): def f(n):
if n < 10: if n < 10:
n += 1 n += 1
@ -236,7 +232,6 @@ class TestTraceback_f_g_h(object):
assert recindex == 3 assert recindex == 3
def test_traceback_only_specific_recursion_errors(self, monkeypatch): def test_traceback_only_specific_recursion_errors(self, monkeypatch):
def f(n): def f(n):
if n == 0: if n == 0:
raise RuntimeError("hello") raise RuntimeError("hello")
@ -248,7 +243,6 @@ class TestTraceback_f_g_h(object):
assert "RuntimeError: hello" in str(repr.reprcrash) assert "RuntimeError: hello" in str(repr.reprcrash)
def test_traceback_no_recursion_index(self): def test_traceback_no_recursion_index(self):
def do_stuff(): def do_stuff():
raise RuntimeError raise RuntimeError
@ -288,7 +282,6 @@ class TestTraceback_f_g_h(object):
assert excinfo.traceback.recursionindex() is None assert excinfo.traceback.recursionindex() is None
def test_traceback_getcrashentry(self): def test_traceback_getcrashentry(self):
def i(): def i():
__tracebackhide__ = True __tracebackhide__ = True
raise ValueError raise ValueError
@ -312,7 +305,6 @@ class TestTraceback_f_g_h(object):
assert entry.frame.code.name == "h" assert entry.frame.code.name == "h"
def test_traceback_getcrashentry_empty(self): def test_traceback_getcrashentry_empty(self):
def g(): def g():
__tracebackhide__ = True __tracebackhide__ = True
raise ValueError raise ValueError
@ -429,10 +421,8 @@ def test_match_raises_error(testdir):
class TestFormattedExcinfo(object): class TestFormattedExcinfo(object):
@pytest.fixture @pytest.fixture
def importasmod(self, request): def importasmod(self, request):
def importasmod(source): def importasmod(source):
source = _pytest._code.Source(source) source = _pytest._code.Source(source)
tmpdir = request.getfixturevalue("tmpdir") tmpdir = request.getfixturevalue("tmpdir")
@ -519,7 +509,6 @@ raise ValueError()
pr = FormattedExcinfo() pr = FormattedExcinfo()
class FakeCode(object): class FakeCode(object):
class raw(object): class raw(object):
co_filename = "?" co_filename = "?"
@ -537,7 +526,6 @@ raise ValueError()
f_globals = {} f_globals = {}
class FakeTracebackEntry(_pytest._code.Traceback.Entry): class FakeTracebackEntry(_pytest._code.Traceback.Entry):
def __init__(self, tb, excinfo=None): def __init__(self, tb, excinfo=None):
self.lineno = 5 + 3 self.lineno = 5 + 3
@ -882,7 +870,6 @@ raise ValueError()
from _pytest._code.code import TerminalRepr from _pytest._code.code import TerminalRepr
class MyRepr(TerminalRepr): class MyRepr(TerminalRepr):
def toterminal(self, tw): def toterminal(self, tw):
tw.line(py.builtin._totext("я", "utf-8")) tw.line(py.builtin._totext("я", "utf-8"))
@ -1303,7 +1290,6 @@ def test_exception_repr_extraction_error_on_recursion():
""" """
class numpy_like(object): class numpy_like(object):
def __eq__(self, other): def __eq__(self, other):
if type(other) is numpy_like: if type(other) is numpy_like:
raise ValueError( raise ValueError(
@ -1343,7 +1329,6 @@ def test_no_recursion_index_on_recursion_error():
try: try:
class RecursionDepthError(object): class RecursionDepthError(object):
def __getattr__(self, attr): def __getattr__(self, attr):
return getattr(self, "_" + attr) return getattr(self, "_" + attr)

View File

@ -58,9 +58,7 @@ def test_source_from_function():
def test_source_from_method(): def test_source_from_method():
class TestClass(object): class TestClass(object):
def test_method(self): def test_method(self):
pass pass
@ -75,7 +73,6 @@ def test_source_from_lines():
def test_source_from_inner_function(): def test_source_from_inner_function():
def f(): def f():
pass pass
@ -199,7 +196,6 @@ class TestSourceParsingAndCompiling(object):
assert str(source) == "x=3" assert str(source) == "x=3"
def test_compile_and_getsource_through_same_function(self): def test_compile_and_getsource_through_same_function(self):
def gensource(source): def gensource(source):
return _pytest._code.compile(source) return _pytest._code.compile(source)
@ -337,13 +333,12 @@ class TestSourceParsingAndCompiling(object):
@pytest.mark.parametrize("name", ["", None, "my"]) @pytest.mark.parametrize("name", ["", None, "my"])
def test_compilefuncs_and_path_sanity(self, name): def test_compilefuncs_and_path_sanity(self, name):
def check(comp, name): def check(comp, name):
co = comp(self.source, name) co = comp(self.source, name)
if not name: if not name:
expected = "codegen %s:%d>" % (mypath, mylineno + 2 + 3) expected = "codegen %s:%d>" % (mypath, mylineno + 2 + 2)
else: else:
expected = "codegen %r %s:%d>" % (name, mypath, mylineno + 2 + 3) expected = "codegen %r %s:%d>" % (name, mypath, mylineno + 2 + 2)
fn = co.co_filename fn = co.co_filename
assert fn.endswith(expected) assert fn.endswith(expected)
@ -359,9 +354,7 @@ class TestSourceParsingAndCompiling(object):
def test_getstartingblock_singleline(): def test_getstartingblock_singleline():
class A(object): class A(object):
def __init__(self, *args): def __init__(self, *args):
frame = sys._getframe(1) frame = sys._getframe(1)
self.source = _pytest._code.Frame(frame).statement self.source = _pytest._code.Frame(frame).statement
@ -373,7 +366,6 @@ def test_getstartingblock_singleline():
def test_getline_finally(): def test_getline_finally():
def c(): def c():
pass pass
@ -406,7 +398,6 @@ def test_getfuncsource_dynamic():
def test_getfuncsource_with_multine_string(): def test_getfuncsource_with_multine_string():
def f(): def f():
c = """while True: c = """while True:
pass pass
@ -538,14 +529,12 @@ def test_getfslineno():
def test_code_of_object_instance_with_call(): def test_code_of_object_instance_with_call():
class A(object): class A(object):
pass pass
pytest.raises(TypeError, lambda: _pytest._code.Source(A())) pytest.raises(TypeError, lambda: _pytest._code.Source(A()))
class WithCall(object): class WithCall(object):
def __call__(self): def __call__(self):
pass pass
@ -553,7 +542,6 @@ def test_code_of_object_instance_with_call():
assert "pass" in str(code.source()) assert "pass" in str(code.source())
class Hello(object): class Hello(object):
def __call__(self): def __call__(self):
pass pass

View File

@ -14,7 +14,6 @@ def test_getstartingblock_multiline():
""" """
class A(object): class A(object):
def __init__(self, *args): def __init__(self, *args):
frame = sys._getframe(1) frame = sys._getframe(1)
self.source = _pytest._code.Frame(frame).statement self.source = _pytest._code.Frame(frame).statement

View File

@ -84,7 +84,6 @@ def test_str_args_deprecated(tmpdir, testdir):
warnings = [] warnings = []
class Collect(object): class Collect(object):
def pytest_logwarning(self, message): def pytest_logwarning(self, message):
warnings.append(message) warnings.append(message)
@ -260,6 +259,7 @@ def test_pytest_plugins_in_non_top_level_conftest_deprecated_no_false_positives(
) )
res = testdir.runpytest_subprocess() res = testdir.runpytest_subprocess()
assert res.ret == 0 assert res.ret == 0
assert str(PYTEST_PLUGINS_FROM_NON_TOP_LEVEL_CONFTEST).splitlines()[ assert (
0 str(PYTEST_PLUGINS_FROM_NON_TOP_LEVEL_CONFTEST).splitlines()[0]
] not in res.stderr.str() not in res.stderr.str()
)

View File

@ -17,21 +17,18 @@ def checked_order():
yield order yield order
pprint.pprint(order) pprint.pprint(order)
assert ( assert order == [
order ("testing/example_scripts/issue_519.py", "fix1", "arg1v1"),
== [ ("test_one[arg1v1-arg2v1]", "fix2", "arg2v1"),
("testing/example_scripts/issue_519.py", "fix1", "arg1v1"), ("test_two[arg1v1-arg2v1]", "fix2", "arg2v1"),
("test_one[arg1v1-arg2v1]", "fix2", "arg2v1"), ("test_one[arg1v1-arg2v2]", "fix2", "arg2v2"),
("test_two[arg1v1-arg2v1]", "fix2", "arg2v1"), ("test_two[arg1v1-arg2v2]", "fix2", "arg2v2"),
("test_one[arg1v1-arg2v2]", "fix2", "arg2v2"), ("testing/example_scripts/issue_519.py", "fix1", "arg1v2"),
("test_two[arg1v1-arg2v2]", "fix2", "arg2v2"), ("test_one[arg1v2-arg2v1]", "fix2", "arg2v1"),
("testing/example_scripts/issue_519.py", "fix1", "arg1v2"), ("test_two[arg1v2-arg2v1]", "fix2", "arg2v1"),
("test_one[arg1v2-arg2v1]", "fix2", "arg2v1"), ("test_one[arg1v2-arg2v2]", "fix2", "arg2v2"),
("test_two[arg1v2-arg2v1]", "fix2", "arg2v1"), ("test_two[arg1v2-arg2v2]", "fix2", "arg2v2"),
("test_one[arg1v2-arg2v2]", "fix2", "arg2v2"), ]
("test_two[arg1v2-arg2v2]", "fix2", "arg2v2"),
]
)
@pytest.yield_fixture(scope="module") @pytest.yield_fixture(scope="module")

View File

@ -18,7 +18,6 @@ def test_coloredlogformatter():
) )
class ColorConfig(object): class ColorConfig(object):
class option(object): class option(object):
pass pass
@ -26,9 +25,8 @@ def test_coloredlogformatter():
tw.hasmarkup = True tw.hasmarkup = True
formatter = ColoredLevelFormatter(tw, logfmt) formatter = ColoredLevelFormatter(tw, logfmt)
output = formatter.format(record) output = formatter.format(record)
assert ( assert output == (
output "dummypath 10 " "\x1b[32mINFO \x1b[0m Test Message"
== ("dummypath 10 " "\x1b[32mINFO \x1b[0m Test Message")
) )
tw.hasmarkup = False tw.hasmarkup = False

View File

@ -520,16 +520,22 @@ def test_sections_single_new_line_after_test_outcome(testdir, request):
"=* 1 passed in *=", "=* 1 passed in *=",
] ]
) )
assert re.search( assert (
r"(.+)live log teardown(.+)\n(.+)WARNING(.+)\n(.+)WARNING(.+)", re.search(
result.stdout.str(), r"(.+)live log teardown(.+)\n(.+)WARNING(.+)\n(.+)WARNING(.+)",
re.MULTILINE, result.stdout.str(),
) is not None re.MULTILINE,
assert re.search( )
r"(.+)live log finish(.+)\n(.+)WARNING(.+)\n(.+)WARNING(.+)", is not None
result.stdout.str(), )
re.MULTILINE, assert (
) is not None re.search(
r"(.+)live log finish(.+)\n(.+)WARNING(.+)\n(.+)WARNING(.+)",
result.stdout.str(),
re.MULTILINE,
)
is not None
)
def test_log_cli_level(testdir): def test_log_cli_level(testdir):
@ -850,7 +856,6 @@ def test_live_logging_suspends_capture(has_capture_manager, request):
assert CaptureManager.resume_global_capture assert CaptureManager.resume_global_capture
class DummyTerminal(six.StringIO): class DummyTerminal(six.StringIO):
def section(self, *args, **kwargs): def section(self, *args, **kwargs):
pass pass
@ -865,10 +870,10 @@ def test_live_logging_suspends_capture(has_capture_manager, request):
logger.critical("some message") logger.critical("some message")
if has_capture_manager: if has_capture_manager:
assert ( assert MockCaptureManager.calls == [
MockCaptureManager.calls "suspend_global_capture",
== ["suspend_global_capture", "resume_global_capture"] "resume_global_capture",
) ]
else: else:
assert MockCaptureManager.calls == [] assert MockCaptureManager.calls == []
assert out_file.getvalue() == "\nsome message\n" assert out_file.getvalue() == "\nsome message\n"

View File

@ -13,7 +13,6 @@ inf, nan = float("inf"), float("nan")
class MyDocTestRunner(doctest.DocTestRunner): class MyDocTestRunner(doctest.DocTestRunner):
def __init__(self): def __init__(self):
doctest.DocTestRunner.__init__(self) doctest.DocTestRunner.__init__(self)
@ -26,28 +25,27 @@ class MyDocTestRunner(doctest.DocTestRunner):
class TestApprox(object): class TestApprox(object):
@pytest.fixture
def plus_minus(self):
return u"\u00b1" if sys.version_info[0] > 2 else u"+-"
def test_repr_string(self): def test_repr_string(self, plus_minus):
plus_minus = u"\u00b1" if sys.version_info[0] > 2 else u"+-"
tol1, tol2, infr = "1.0e-06", "2.0e-06", "inf" tol1, tol2, infr = "1.0e-06", "2.0e-06", "inf"
assert repr(approx(1.0)) == "1.0 {pm} {tol1}".format(pm=plus_minus, tol1=tol1) assert repr(approx(1.0)) == "1.0 {pm} {tol1}".format(pm=plus_minus, tol1=tol1)
assert ( assert repr(
repr(approx([1.0, 2.0])) approx([1.0, 2.0])
== "approx([1.0 {pm} {tol1}, 2.0 {pm} {tol2}])".format( ) == "approx([1.0 {pm} {tol1}, 2.0 {pm} {tol2}])".format(
pm=plus_minus, tol1=tol1, tol2=tol2 pm=plus_minus, tol1=tol1, tol2=tol2
)
) )
assert ( assert repr(
repr(approx((1.0, 2.0))) approx((1.0, 2.0))
== "approx((1.0 {pm} {tol1}, 2.0 {pm} {tol2}))".format( ) == "approx((1.0 {pm} {tol1}, 2.0 {pm} {tol2}))".format(
pm=plus_minus, tol1=tol1, tol2=tol2 pm=plus_minus, tol1=tol1, tol2=tol2
)
) )
assert repr(approx(inf)) == "inf" assert repr(approx(inf)) == "inf"
assert repr(approx(1.0, rel=nan)) == "1.0 {pm} ???".format(pm=plus_minus) assert repr(approx(1.0, rel=nan)) == "1.0 {pm} ???".format(pm=plus_minus)
assert ( assert repr(approx(1.0, rel=inf)) == "1.0 {pm} {infr}".format(
repr(approx(1.0, rel=inf)) pm=plus_minus, infr=infr
== "1.0 {pm} {infr}".format(pm=plus_minus, infr=infr)
) )
assert repr(approx(1.0j, rel=inf)) == "1j" assert repr(approx(1.0j, rel=inf)) == "1j"
@ -61,6 +59,18 @@ class TestApprox(object):
), ),
) )
def test_repr_0d_array(self, plus_minus):
np = pytest.importorskip("numpy")
np_array = np.array(5.)
assert approx(np_array) == 5.0
string_expected = "approx([5.0 {} 5.0e-06])".format(plus_minus)
assert repr(approx(np_array)) == string_expected
np_array = np.array([5.])
assert approx(np_array) == 5.0
assert repr(approx(np_array)) == string_expected
def test_operator_overloading(self): def test_operator_overloading(self):
assert 1 == approx(1, rel=1e-6, abs=1e-12) assert 1 == approx(1, rel=1e-6, abs=1e-12)
assert not (1 != approx(1, rel=1e-6, abs=1e-12)) assert not (1 != approx(1, rel=1e-6, abs=1e-12))

View File

@ -14,7 +14,6 @@ ignore_parametrized_marks = pytest.mark.filterwarnings(
class TestModule(object): class TestModule(object):
def test_failing_import(self, testdir): def test_failing_import(self, testdir):
modcol = testdir.getmodulecol("import alksdjalskdjalkjals") modcol = testdir.getmodulecol("import alksdjalskdjalkjals")
pytest.raises(Collector.CollectError, modcol.collect) pytest.raises(Collector.CollectError, modcol.collect)
@ -141,7 +140,6 @@ class TestModule(object):
class TestClass(object): class TestClass(object):
def test_class_with_init_warning(self, testdir): def test_class_with_init_warning(self, testdir):
testdir.makepyfile( testdir.makepyfile(
""" """
@ -246,7 +244,6 @@ class TestClass(object):
class TestGenerator(object): class TestGenerator(object):
def test_generative_functions(self, testdir): def test_generative_functions(self, testdir):
modcol = testdir.getmodulecol( modcol = testdir.getmodulecol(
""" """
@ -458,7 +455,6 @@ class TestGenerator(object):
class TestFunction(object): class TestFunction(object):
def test_getmodulecollector(self, testdir): def test_getmodulecollector(self, testdir):
item = testdir.getitem("def test_func(): pass") item = testdir.getitem("def test_func(): pass")
modcol = item.getparent(pytest.Module) modcol = item.getparent(pytest.Module)
@ -673,12 +669,10 @@ class TestFunction(object):
config = item.config config = item.config
class MyPlugin1(object): class MyPlugin1(object):
def pytest_pyfunc_call(self, pyfuncitem): def pytest_pyfunc_call(self, pyfuncitem):
raise ValueError raise ValueError
class MyPlugin2(object): class MyPlugin2(object):
def pytest_pyfunc_call(self, pyfuncitem): def pytest_pyfunc_call(self, pyfuncitem):
return True return True
@ -831,7 +825,6 @@ class TestFunction(object):
class TestSorting(object): class TestSorting(object):
def test_check_equality(self, testdir): def test_check_equality(self, testdir):
modcol = testdir.getmodulecol( modcol = testdir.getmodulecol(
""" """
@ -886,7 +879,6 @@ class TestSorting(object):
class TestConftestCustomization(object): class TestConftestCustomization(object):
def test_pytest_pycollect_module(self, testdir): def test_pytest_pycollect_module(self, testdir):
testdir.makeconftest( testdir.makeconftest(
""" """
@ -1062,7 +1054,6 @@ def test_modulecol_roundtrip(testdir):
class TestTracebackCutting(object): class TestTracebackCutting(object):
def test_skip_simple(self): def test_skip_simple(self):
excinfo = pytest.raises(pytest.skip.Exception, 'pytest.skip("xxx")') excinfo = pytest.raises(pytest.skip.Exception, 'pytest.skip("xxx")')
assert excinfo.traceback[-1].frame.code.name == "skip" assert excinfo.traceback[-1].frame.code.name == "skip"
@ -1191,7 +1182,6 @@ class TestTracebackCutting(object):
class TestReportInfo(object): class TestReportInfo(object):
def test_itemreport_reportinfo(self, testdir, linecomp): def test_itemreport_reportinfo(self, testdir, linecomp):
testdir.makeconftest( testdir.makeconftest(
""" """
@ -1497,7 +1487,10 @@ def test_class_injection_does_not_break_collection(testdir):
''' '''
) )
result = testdir.runpytest() result = testdir.runpytest()
assert "RuntimeError: dictionary changed size during iteration" not in result.stdout.str() assert (
"RuntimeError: dictionary changed size during iteration"
not in result.stdout.str()
)
result.stdout.fnmatch_lines(["*1 passed*"]) result.stdout.fnmatch_lines(["*1 passed*"])

View File

@ -8,7 +8,6 @@ from _pytest import fixtures
def test_getfuncargnames(): def test_getfuncargnames():
def f(): def f():
pass pass
@ -30,7 +29,6 @@ def test_getfuncargnames():
assert fixtures.getfuncargnames(h) == ("arg1", "arg2") assert fixtures.getfuncargnames(h) == ("arg1", "arg2")
class A(object): class A(object):
def f(self, arg1, arg2="hello"): def f(self, arg1, arg2="hello"):
pass pass
@ -43,7 +41,6 @@ def test_getfuncargnames():
class TestFillFixtures(object): class TestFillFixtures(object):
def test_fillfuncargs_exposed(self): def test_fillfuncargs_exposed(self):
# used by oejskit, kept for compatibility # used by oejskit, kept for compatibility
assert pytest._fillfuncargs == fixtures.fillfixtures assert pytest._fillfuncargs == fixtures.fillfixtures
@ -570,7 +567,6 @@ class TestFillFixtures(object):
class TestRequestBasic(object): class TestRequestBasic(object):
def test_request_attributes(self, testdir): def test_request_attributes(self, testdir):
item = testdir.getitem( item = testdir.getitem(
""" """
@ -1003,7 +999,6 @@ class TestRequestBasic(object):
class TestRequestMarking(object): class TestRequestMarking(object):
def test_applymarker(self, testdir): def test_applymarker(self, testdir):
item1, item2 = testdir.getitems( item1, item2 = testdir.getitems(
""" """
@ -1073,7 +1068,6 @@ class TestRequestMarking(object):
class TestRequestCachedSetup(object): class TestRequestCachedSetup(object):
def test_request_cachedsetup_defaultmodule(self, testdir): def test_request_cachedsetup_defaultmodule(self, testdir):
reprec = testdir.inline_runsource( reprec = testdir.inline_runsource(
""" """
@ -1245,7 +1239,6 @@ class TestRequestCachedSetup(object):
class TestFixtureUsages(object): class TestFixtureUsages(object):
def test_noargfixturedec(self, testdir): def test_noargfixturedec(self, testdir):
testdir.makepyfile( testdir.makepyfile(
""" """
@ -1540,7 +1533,6 @@ class TestFixtureUsages(object):
class TestFixtureManagerParseFactories(object): class TestFixtureManagerParseFactories(object):
@pytest.fixture @pytest.fixture
def testdir(self, request): def testdir(self, request):
testdir = request.getfixturevalue("testdir") testdir = request.getfixturevalue("testdir")
@ -1668,7 +1660,6 @@ class TestFixtureManagerParseFactories(object):
class TestAutouseDiscovery(object): class TestAutouseDiscovery(object):
@pytest.fixture @pytest.fixture
def testdir(self, testdir): def testdir(self, testdir):
testdir.makeconftest( testdir.makeconftest(
@ -1845,7 +1836,6 @@ class TestAutouseDiscovery(object):
class TestAutouseManagement(object): class TestAutouseManagement(object):
def test_autouse_conftest_mid_directory(self, testdir): def test_autouse_conftest_mid_directory(self, testdir):
pkgdir = testdir.mkpydir("xyz123") pkgdir = testdir.mkpydir("xyz123")
pkgdir.join("conftest.py").write( pkgdir.join("conftest.py").write(
@ -2112,7 +2102,6 @@ class TestAutouseManagement(object):
class TestFixtureMarker(object): class TestFixtureMarker(object):
def test_parametrize(self, testdir): def test_parametrize(self, testdir):
testdir.makepyfile( testdir.makepyfile(
""" """
@ -2938,21 +2927,18 @@ class TestFixtureMarker(object):
reprec = testdir.inline_run() reprec = testdir.inline_run()
reprec.assertoutcome(passed=6) reprec.assertoutcome(passed=6)
values = reprec.getcalls("pytest_runtest_call")[0].item.module.values values = reprec.getcalls("pytest_runtest_call")[0].item.module.values
assert ( assert values == [
values "test_hello",
== [ "fin John",
"test_hello", "test_hello",
"fin John", "fin Doe",
"test_hello", "test_name",
"fin Doe", "test_population",
"test_name", "fin John",
"test_population", "test_name",
"fin John", "test_population",
"test_name", "fin Doe",
"test_population", ]
"fin Doe",
]
)
def test_parametrize_setup_function(self, testdir): def test_parametrize_setup_function(self, testdir):
testdir.makepyfile( testdir.makepyfile(
@ -3135,7 +3121,6 @@ class TestRequestScopeAccess(object):
class TestErrors(object): class TestErrors(object):
def test_subfactory_missing_funcarg(self, testdir): def test_subfactory_missing_funcarg(self, testdir):
testdir.makepyfile( testdir.makepyfile(
""" """
@ -3203,7 +3188,6 @@ class TestErrors(object):
class TestShowFixtures(object): class TestShowFixtures(object):
def test_funcarg_compat(self, testdir): def test_funcarg_compat(self, testdir):
config = testdir.parseconfigure("--funcargs") config = testdir.parseconfigure("--funcargs")
assert config.option.showfixtures assert config.option.showfixtures
@ -3480,7 +3464,6 @@ class TestShowFixtures(object):
@pytest.mark.parametrize("flavor", ["fixture", "yield_fixture"]) @pytest.mark.parametrize("flavor", ["fixture", "yield_fixture"])
class TestContextManagerFixtureFuncs(object): class TestContextManagerFixtureFuncs(object):
def test_simple(self, testdir, flavor): def test_simple(self, testdir, flavor):
testdir.makepyfile( testdir.makepyfile(
""" """
@ -3622,7 +3605,6 @@ class TestContextManagerFixtureFuncs(object):
class TestParameterizedSubRequest(object): class TestParameterizedSubRequest(object):
def test_call_from_fixture(self, testdir): def test_call_from_fixture(self, testdir):
testfile = testdir.makepyfile( testfile = testdir.makepyfile(
""" """

View File

@ -4,7 +4,6 @@ from _pytest import runner
class TestOEJSKITSpecials(object): class TestOEJSKITSpecials(object):
def test_funcarg_non_pycollectobj(self, testdir): # rough jstests usage def test_funcarg_non_pycollectobj(self, testdir): # rough jstests usage
testdir.makeconftest( testdir.makeconftest(
""" """
@ -70,7 +69,6 @@ class TestOEJSKITSpecials(object):
def test_wrapped_getfslineno(): def test_wrapped_getfslineno():
def func(): def func():
pass pass
@ -89,12 +87,10 @@ def test_wrapped_getfslineno():
class TestMockDecoration(object): class TestMockDecoration(object):
def test_wrapped_getfuncargnames(self): def test_wrapped_getfuncargnames(self):
from _pytest.compat import getfuncargnames from _pytest.compat import getfuncargnames
def wrap(f): def wrap(f):
def func(): def func():
pass pass
@ -115,7 +111,6 @@ class TestMockDecoration(object):
from _pytest.compat import getfuncargnames from _pytest.compat import getfuncargnames
def wrap(f): def wrap(f):
def func(): def func():
pass pass
@ -269,7 +264,6 @@ class TestMockDecoration(object):
class TestReRunTests(object): class TestReRunTests(object):
def test_rerun(self, testdir): def test_rerun(self, testdir):
testdir.makeconftest( testdir.makeconftest(
""" """
@ -316,7 +310,6 @@ def test_pytestconfig_is_session_scoped():
class TestNoselikeTestAttribute(object): class TestNoselikeTestAttribute(object):
def test_module_with_global_test(self, testdir): def test_module_with_global_test(self, testdir):
testdir.makepyfile( testdir.makepyfile(
""" """
@ -402,7 +395,6 @@ class TestNoselikeTestAttribute(object):
@pytest.mark.issue351 @pytest.mark.issue351
class TestParameterize(object): class TestParameterize(object):
def test_idfn_marker(self, testdir): def test_idfn_marker(self, testdir):
testdir.makepyfile( testdir.makepyfile(
""" """

View File

@ -14,7 +14,6 @@ PY3 = sys.version_info >= (3, 0)
class TestMetafunc(object): class TestMetafunc(object):
def Metafunc(self, func, config=None): def Metafunc(self, func, config=None):
# the unit tests of this class check if things work correctly # the unit tests of this class check if things work correctly
# on the funcarg level, so we don't need a full blown # on the funcarg level, so we don't need a full blown
@ -35,7 +34,6 @@ class TestMetafunc(object):
return python.Metafunc(definition, fixtureinfo, config) return python.Metafunc(definition, fixtureinfo, config)
def test_no_funcargs(self, testdir): def test_no_funcargs(self, testdir):
def function(): def function():
pass pass
@ -44,7 +42,6 @@ class TestMetafunc(object):
repr(metafunc._calls) repr(metafunc._calls)
def test_function_basic(self): def test_function_basic(self):
def func(arg1, arg2="qwe"): def func(arg1, arg2="qwe"):
pass pass
@ -55,7 +52,6 @@ class TestMetafunc(object):
assert metafunc.cls is None assert metafunc.cls is None
def test_addcall_no_args(self): def test_addcall_no_args(self):
def func(arg1): def func(arg1):
pass pass
@ -67,7 +63,6 @@ class TestMetafunc(object):
assert not hasattr(call, "param") assert not hasattr(call, "param")
def test_addcall_id(self): def test_addcall_id(self):
def func(arg1): def func(arg1):
pass pass
@ -83,7 +78,6 @@ class TestMetafunc(object):
assert metafunc._calls[1].id == "2" assert metafunc._calls[1].id == "2"
def test_addcall_param(self): def test_addcall_param(self):
def func(arg1): def func(arg1):
pass pass
@ -101,7 +95,6 @@ class TestMetafunc(object):
assert metafunc._calls[2].getparam("arg1") == 1 assert metafunc._calls[2].getparam("arg1") == 1
def test_addcall_funcargs(self): def test_addcall_funcargs(self):
def func(x): def func(x):
pass pass
@ -119,7 +112,6 @@ class TestMetafunc(object):
assert not hasattr(metafunc._calls[1], "param") assert not hasattr(metafunc._calls[1], "param")
def test_parametrize_error(self): def test_parametrize_error(self):
def func(x, y): def func(x, y):
pass pass
@ -132,7 +124,6 @@ class TestMetafunc(object):
pytest.raises(ValueError, lambda: metafunc.parametrize("y", [5, 6])) pytest.raises(ValueError, lambda: metafunc.parametrize("y", [5, 6]))
def test_parametrize_bad_scope(self, testdir): def test_parametrize_bad_scope(self, testdir):
def func(x): def func(x):
pass pass
@ -143,7 +134,6 @@ class TestMetafunc(object):
assert "has an unsupported scope value 'doggy'" in str(ve) assert "has an unsupported scope value 'doggy'" in str(ve)
def test_parametrize_and_id(self): def test_parametrize_and_id(self):
def func(x, y): def func(x, y):
pass pass
@ -166,7 +156,6 @@ class TestMetafunc(object):
assert ids == [u"basic", u"advanced"] assert ids == [u"basic", u"advanced"]
def test_parametrize_with_wrong_number_of_ids(self, testdir): def test_parametrize_with_wrong_number_of_ids(self, testdir):
def func(x, y): def func(x, y):
pass pass
@ -185,12 +174,10 @@ class TestMetafunc(object):
@pytest.mark.issue510 @pytest.mark.issue510
def test_parametrize_empty_list(self): def test_parametrize_empty_list(self):
def func(y): def func(y):
pass pass
class MockConfig(object): class MockConfig(object):
def getini(self, name): def getini(self, name):
return "" return ""
@ -206,7 +193,6 @@ class TestMetafunc(object):
assert "skip" == metafunc._calls[0].marks[0].name assert "skip" == metafunc._calls[0].marks[0].name
def test_parametrize_with_userobjects(self): def test_parametrize_with_userobjects(self):
def func(x, y): def func(x, y):
pass pass
@ -338,23 +324,20 @@ class TestMetafunc(object):
pytest.param(b"\xc3\xb4", totext("other")), pytest.param(b"\xc3\xb4", totext("other")),
], ],
) )
assert ( assert result == [
result "1.0--1.1",
== [ "2--202",
"1.0--1.1", "three-three hundred",
"2--202", "True-False",
"three-three hundred", "None-None",
"True-False", "foo-bar",
"None-None", "str-int",
"foo-bar", "a7-b7",
"str-int", "a8-b8",
"a7-b7", "a9-b9",
"a8-b8", "\\xc3\\xb4-name",
"a9-b9", "\\xc3\\xb4-other",
"\\xc3\\xb4-name", ]
"\\xc3\\xb4-other",
]
)
def test_idmaker_enum(self): def test_idmaker_enum(self):
from _pytest.python import idmaker from _pytest.python import idmaker
@ -424,23 +407,20 @@ class TestMetafunc(object):
idfn=ids, idfn=ids,
) )
assert ( assert [str(i.message) for i in rec.list] == [
[str(i.message) for i in rec.list] "Raised while trying to determine id of parameter a at position 0."
== [ "\nUpdate your code as this will raise an error in pytest-4.0.",
"Raised while trying to determine id of parameter a at position 0." "Raised while trying to determine id of parameter b at position 0."
"\nUpdate your code as this will raise an error in pytest-4.0.", "\nUpdate your code as this will raise an error in pytest-4.0.",
"Raised while trying to determine id of parameter b at position 0." "Raised while trying to determine id of parameter a at position 1."
"\nUpdate your code as this will raise an error in pytest-4.0.", "\nUpdate your code as this will raise an error in pytest-4.0.",
"Raised while trying to determine id of parameter a at position 1." "Raised while trying to determine id of parameter b at position 1."
"\nUpdate your code as this will raise an error in pytest-4.0.", "\nUpdate your code as this will raise an error in pytest-4.0.",
"Raised while trying to determine id of parameter b at position 1." "Raised while trying to determine id of parameter a at position 2."
"\nUpdate your code as this will raise an error in pytest-4.0.", "\nUpdate your code as this will raise an error in pytest-4.0.",
"Raised while trying to determine id of parameter a at position 2." "Raised while trying to determine id of parameter b at position 2."
"\nUpdate your code as this will raise an error in pytest-4.0.", "\nUpdate your code as this will raise an error in pytest-4.0.",
"Raised while trying to determine id of parameter b at position 2." ]
"\nUpdate your code as this will raise an error in pytest-4.0.",
]
)
def test_parametrize_ids_exception(self, testdir): def test_parametrize_ids_exception(self, testdir):
""" """
@ -496,7 +476,6 @@ class TestMetafunc(object):
assert result == ["a0", "a1", "b0", "c", "b1"] assert result == ["a0", "a1", "b0", "c", "b1"]
def test_addcall_and_parametrize(self): def test_addcall_and_parametrize(self):
def func(x, y): def func(x, y):
pass pass
@ -511,7 +490,6 @@ class TestMetafunc(object):
@pytest.mark.issue714 @pytest.mark.issue714
def test_parametrize_indirect(self): def test_parametrize_indirect(self):
def func(x, y): def func(x, y):
pass pass
@ -526,7 +504,6 @@ class TestMetafunc(object):
@pytest.mark.issue714 @pytest.mark.issue714
def test_parametrize_indirect_list(self): def test_parametrize_indirect_list(self):
def func(x, y): def func(x, y):
pass pass
@ -537,7 +514,6 @@ class TestMetafunc(object):
@pytest.mark.issue714 @pytest.mark.issue714
def test_parametrize_indirect_list_all(self): def test_parametrize_indirect_list_all(self):
def func(x, y): def func(x, y):
pass pass
@ -548,7 +524,6 @@ class TestMetafunc(object):
@pytest.mark.issue714 @pytest.mark.issue714
def test_parametrize_indirect_list_empty(self): def test_parametrize_indirect_list_empty(self):
def func(x, y): def func(x, y):
pass pass
@ -588,7 +563,6 @@ class TestMetafunc(object):
@pytest.mark.issue714 @pytest.mark.issue714
def test_parametrize_indirect_list_error(self, testdir): def test_parametrize_indirect_list_error(self, testdir):
def func(x, y): def func(x, y):
pass pass
@ -704,7 +678,6 @@ class TestMetafunc(object):
) )
def test_addcalls_and_parametrize_indirect(self): def test_addcalls_and_parametrize_indirect(self):
def func(x, y): def func(x, y):
pass pass
@ -837,7 +810,6 @@ class TestMetafunc(object):
) )
def test_format_args(self): def test_format_args(self):
def function1(): def function1():
pass pass
@ -860,7 +832,6 @@ class TestMetafunc(object):
class TestMetafuncFunctional(object): class TestMetafuncFunctional(object):
def test_attributes(self, testdir): def test_attributes(self, testdir):
p = testdir.makepyfile( p = testdir.makepyfile(
""" """
@ -1494,7 +1465,6 @@ class TestMetafuncFunctionalAuto(object):
@pytest.mark.filterwarnings("ignore:Applying marks directly to parameters") @pytest.mark.filterwarnings("ignore:Applying marks directly to parameters")
@pytest.mark.issue308 @pytest.mark.issue308
class TestMarkersWithParametrization(object): class TestMarkersWithParametrization(object):
def test_simple_mark(self, testdir): def test_simple_mark(self, testdir):
s = """ s = """
import pytest import pytest

View File

@ -4,7 +4,6 @@ import sys
class TestRaises(object): class TestRaises(object):
def test_raises(self): def test_raises(self):
source = "int('qwe')" source = "int('qwe')"
excinfo = pytest.raises(ValueError, source) excinfo = pytest.raises(ValueError, source)
@ -22,9 +21,7 @@ class TestRaises(object):
pytest.raises(ValueError, int, "hello") pytest.raises(ValueError, int, "hello")
def test_raises_callable_no_exception(self): def test_raises_callable_no_exception(self):
class A(object): class A(object):
def __call__(self): def __call__(self):
pass pass
@ -109,7 +106,6 @@ class TestRaises(object):
import gc import gc
class T(object): class T(object):
def __call__(self): def __call__(self):
raise ValueError raise ValueError
@ -160,7 +156,6 @@ class TestRaises(object):
from six import add_metaclass from six import add_metaclass
class Meta(type(object)): class Meta(type(object)):
def __getitem__(self, item): def __getitem__(self, item):
return 1 / 0 return 1 / 0

View File

@ -86,7 +86,6 @@ class FilesCompleter(object):
class TestArgComplete(object): class TestArgComplete(object):
@pytest.mark.skipif("sys.platform in ('win32', 'darwin')") @pytest.mark.skipif("sys.platform in ('win32', 'darwin')")
def test_compare_with_compgen(self): def test_compare_with_compgen(self):
from _pytest._argcomplete import FastFilesCompleter from _pytest._argcomplete import FastFilesCompleter

View File

@ -14,7 +14,6 @@ PY3 = sys.version_info >= (3, 0)
@pytest.fixture @pytest.fixture
def mock_config(): def mock_config():
class Config(object): class Config(object):
verbose = False verbose = False
@ -27,7 +26,6 @@ def mock_config():
class TestImportHookInstallation(object): class TestImportHookInstallation(object):
@pytest.mark.parametrize("initial_conftest", [True, False]) @pytest.mark.parametrize("initial_conftest", [True, False])
@pytest.mark.parametrize("mode", ["plain", "rewrite"]) @pytest.mark.parametrize("mode", ["plain", "rewrite"])
def test_conftest_assertion_rewrite(self, testdir, initial_conftest, mode): def test_conftest_assertion_rewrite(self, testdir, initial_conftest, mode):
@ -288,7 +286,6 @@ class TestImportHookInstallation(object):
class TestBinReprIntegration(object): class TestBinReprIntegration(object):
def test_pytest_assertrepr_compare_called(self, testdir): def test_pytest_assertrepr_compare_called(self, testdir):
testdir.makeconftest( testdir.makeconftest(
""" """
@ -321,7 +318,6 @@ def callequal(left, right, verbose=False):
class TestAssert_reprcompare(object): class TestAssert_reprcompare(object):
def test_different_types(self): def test_different_types(self):
assert callequal([0, 1], "foo") is None assert callequal([0, 1], "foo") is None
@ -459,7 +455,6 @@ class TestAssert_reprcompare(object):
MutableSequence = col.MutableSequence MutableSequence = col.MutableSequence
class TestSequence(MutableSequence): # works with a Sequence subclass class TestSequence(MutableSequence): # works with a Sequence subclass
def __init__(self, iterable): def __init__(self, iterable):
self.elements = list(iterable) self.elements = list(iterable)
@ -488,9 +483,7 @@ class TestAssert_reprcompare(object):
assert len(expl) > 1 assert len(expl) > 1
def test_list_bad_repr(self): def test_list_bad_repr(self):
class A(object): class A(object):
def __repr__(self): def __repr__(self):
raise ValueError(42) raise ValueError(42)
@ -506,7 +499,6 @@ class TestAssert_reprcompare(object):
""" """
class A(str): class A(str):
def __repr__(self): def __repr__(self):
return "" return ""
@ -532,7 +524,6 @@ class TestAssert_reprcompare(object):
""" """
class A(str): class A(str):
def __repr__(self): def __repr__(self):
return "\xff" return "\xff"
@ -557,7 +548,6 @@ class TestAssert_reprcompare(object):
class TestFormatExplanation(object): class TestFormatExplanation(object):
def test_special_chars_full(self, testdir): def test_special_chars_full(self, testdir):
# Issue 453, for the bug this would raise IndexError # Issue 453, for the bug this would raise IndexError
testdir.makepyfile( testdir.makepyfile(
@ -781,24 +771,19 @@ def test_rewritten(testdir):
def test_reprcompare_notin(mock_config): def test_reprcompare_notin(mock_config):
detail = plugin.pytest_assertrepr_compare( detail = plugin.pytest_assertrepr_compare(
mock_config, "not in", "foo", "aaafoobbb" mock_config, "not in", "foo", "aaafoobbb"
)[ )[1:]
1:
]
assert detail == ["'foo' is contained here:", " aaafoobbb", "? +++"] assert detail == ["'foo' is contained here:", " aaafoobbb", "? +++"]
def test_reprcompare_whitespaces(mock_config): def test_reprcompare_whitespaces(mock_config):
detail = plugin.pytest_assertrepr_compare(mock_config, "==", "\r\n", "\n") detail = plugin.pytest_assertrepr_compare(mock_config, "==", "\r\n", "\n")
assert ( assert detail == [
detail r"'\r\n' == '\n'",
== [ r"Strings contain only whitespace, escaping them using repr()",
r"'\r\n' == '\n'", r"- '\r\n'",
r"Strings contain only whitespace, escaping them using repr()", r"? --",
r"- '\r\n'", r"+ '\n'",
r"? --", ]
r"+ '\n'",
]
)
def test_pytest_assertrepr_compare_integration(testdir): def test_pytest_assertrepr_compare_integration(testdir):
@ -1036,7 +1021,6 @@ def test_AssertionError_message(testdir):
def test_set_with_unsortable_elements(): def test_set_with_unsortable_elements():
# issue #718 # issue #718
class UnsortableKey(object): class UnsortableKey(object):
def __init__(self, name): def __init__(self, name):
self.name = name self.name = name
@ -1169,4 +1153,7 @@ def test_issue_1944(testdir):
) )
result = testdir.runpytest() result = testdir.runpytest()
result.stdout.fnmatch_lines(["*1 error*"]) result.stdout.fnmatch_lines(["*1 error*"])
assert "AttributeError: 'Module' object has no attribute '_obj'" not in result.stdout.str() assert (
"AttributeError: 'Module' object has no attribute '_obj'"
not in result.stdout.str()
)

View File

@ -78,9 +78,8 @@ def adjust_body_for_new_docstring_in_module_node(m):
various Python 3.7 versions, but we should remove the 3.7 check after various Python 3.7 versions, but we should remove the 3.7 check after
3.7 is released as stable to make this check more straightforward. 3.7 is released as stable to make this check more straightforward.
""" """
if ( if sys.version_info < (3, 8) and not (
sys.version_info < (3, 8) (3, 7) <= sys.version_info <= (3, 7, 0, "beta", 4)
and not ((3, 7) <= sys.version_info <= (3, 7, 0, "beta", 4))
): ):
assert len(m.body) > 1 assert len(m.body) > 1
assert isinstance(m.body[0], ast.Expr) assert isinstance(m.body[0], ast.Expr)
@ -89,7 +88,6 @@ def adjust_body_for_new_docstring_in_module_node(m):
class TestAssertionRewrite(object): class TestAssertionRewrite(object):
def test_place_initial_imports(self): def test_place_initial_imports(self):
s = """'Doc string'\nother = stuff""" s = """'Doc string'\nother = stuff"""
m = rewrite(s) m = rewrite(s)
@ -150,7 +148,6 @@ class TestAssertionRewrite(object):
assert "warnings" not in "".join(result.outlines) assert "warnings" not in "".join(result.outlines)
def test_name(self): def test_name(self):
def f(): def f():
assert False assert False
@ -181,7 +178,6 @@ class TestAssertionRewrite(object):
assert getmsg(f, {"cls": X}) == "assert cls == 42" assert getmsg(f, {"cls": X}) == "assert cls == 42"
def test_assert_already_has_message(self): def test_assert_already_has_message(self):
def f(): def f():
assert False, "something bad!" assert False, "something bad!"
@ -251,7 +247,6 @@ class TestAssertionRewrite(object):
) )
def test_boolop(self): def test_boolop(self):
def f(): def f():
f = g = False f = g = False
assert f and g assert f and g
@ -331,7 +326,6 @@ class TestAssertionRewrite(object):
getmsg(f, must_pass=True) getmsg(f, must_pass=True)
def test_short_circuit_evaluation(self): def test_short_circuit_evaluation(self):
def f(): def f():
assert True or explode # noqa assert True or explode # noqa
@ -344,7 +338,6 @@ class TestAssertionRewrite(object):
getmsg(f, must_pass=True) getmsg(f, must_pass=True)
def test_unary_op(self): def test_unary_op(self):
def f(): def f():
x = True x = True
assert not x assert not x
@ -370,7 +363,6 @@ class TestAssertionRewrite(object):
assert getmsg(f) == "assert (+0 + 0)" assert getmsg(f) == "assert (+0 + 0)"
def test_binary_op(self): def test_binary_op(self):
def f(): def f():
x = 1 x = 1
y = -1 y = -1
@ -384,7 +376,6 @@ class TestAssertionRewrite(object):
assert getmsg(f) == "assert not (5 % 4)" assert getmsg(f) == "assert not (5 % 4)"
def test_boolop_percent(self): def test_boolop_percent(self):
def f(): def f():
assert 3 % 2 and False assert 3 % 2 and False
@ -411,7 +402,6 @@ class TestAssertionRewrite(object):
testdir.runpytest().assert_outcomes(passed=1) testdir.runpytest().assert_outcomes(passed=1)
def test_call(self): def test_call(self):
def g(a=42, *args, **kwargs): def g(a=42, *args, **kwargs):
return False return False
@ -483,7 +473,6 @@ class TestAssertionRewrite(object):
) )
def test_attribute(self): def test_attribute(self):
class X(object): class X(object):
g = 3 g = 3
@ -509,7 +498,6 @@ class TestAssertionRewrite(object):
) )
def test_comparisons(self): def test_comparisons(self):
def f(): def f():
a, b = range(2) a, b = range(2)
assert b < a assert b < a
@ -542,7 +530,6 @@ class TestAssertionRewrite(object):
getmsg(f, must_pass=True) getmsg(f, must_pass=True)
def test_len(self): def test_len(self):
def f(): def f():
values = list(range(10)) values = list(range(10))
assert len(values) == 11 assert len(values) == 11
@ -553,7 +540,6 @@ class TestAssertionRewrite(object):
) )
def test_custom_reprcompare(self, monkeypatch): def test_custom_reprcompare(self, monkeypatch):
def my_reprcompare(op, left, right): def my_reprcompare(op, left, right):
return "42" return "42"
@ -575,11 +561,8 @@ class TestAssertionRewrite(object):
assert getmsg(f) == "assert 5 <= 4" assert getmsg(f) == "assert 5 <= 4"
def test_assert_raising_nonzero_in_comparison(self): def test_assert_raising_nonzero_in_comparison(self):
def f(): def f():
class A(object): class A(object):
def __nonzero__(self): def __nonzero__(self):
raise ValueError(42) raise ValueError(42)
@ -597,16 +580,13 @@ class TestAssertionRewrite(object):
assert "<MY42 object> < 0" in getmsg(f) assert "<MY42 object> < 0" in getmsg(f)
def test_formatchar(self): def test_formatchar(self):
def f(): def f():
assert "%test" == "test" assert "%test" == "test"
assert getmsg(f).startswith("assert '%test' == 'test'") assert getmsg(f).startswith("assert '%test' == 'test'")
def test_custom_repr(self): def test_custom_repr(self):
def f(): def f():
class Foo(object): class Foo(object):
a = 1 a = 1
@ -620,7 +600,6 @@ class TestAssertionRewrite(object):
class TestRewriteOnImport(object): class TestRewriteOnImport(object):
def test_pycache_is_a_file(self, testdir): def test_pycache_is_a_file(self, testdir):
testdir.tmpdir.join("__pycache__").write("Hello") testdir.tmpdir.join("__pycache__").write("Hello")
testdir.makepyfile( testdir.makepyfile(
@ -671,9 +650,7 @@ class TestRewriteOnImport(object):
def test_rewritten(): def test_rewritten():
assert "@py_builtins" in globals() assert "@py_builtins" in globals()
""" """
).encode( ).encode("utf-8"),
"utf-8"
),
"wb", "wb",
) )
old_mode = sub.stat().mode old_mode = sub.stat().mode
@ -870,7 +847,6 @@ def test_rewritten():
class TestAssertionRewriteHookDetails(object): class TestAssertionRewriteHookDetails(object):
def test_loader_is_package_false_for_module(self, testdir): def test_loader_is_package_false_for_module(self, testdir):
testdir.makepyfile( testdir.makepyfile(
test_fun=""" test_fun="""
@ -1090,7 +1066,6 @@ def test_issue731(testdir):
class TestIssue925(object): class TestIssue925(object):
def test_simple_case(self, testdir): def test_simple_case(self, testdir):
testdir.makepyfile( testdir.makepyfile(
""" """
@ -1122,8 +1097,7 @@ class TestIssue925(object):
result.stdout.fnmatch_lines("*E*assert True == ((False == True) == True)") result.stdout.fnmatch_lines("*E*assert True == ((False == True) == True)")
class TestIssue2121(): class TestIssue2121:
def test_simple(self, testdir): def test_simple(self, testdir):
testdir.tmpdir.join("tests/file.py").ensure().write( testdir.tmpdir.join("tests/file.py").ensure().write(
""" """

View File

@ -12,7 +12,6 @@ pytest_plugins = ("pytester",)
class TestNewAPI(object): class TestNewAPI(object):
def test_config_cache_makedir(self, testdir): def test_config_cache_makedir(self, testdir):
testdir.makeini("[pytest]") testdir.makeini("[pytest]")
config = testdir.parseconfigure() config = testdir.parseconfigure()
@ -184,7 +183,6 @@ def test_cache_show(testdir):
class TestLastFailed(object): class TestLastFailed(object):
def test_lastfailed_usecase(self, testdir, monkeypatch): def test_lastfailed_usecase(self, testdir, monkeypatch):
monkeypatch.setenv("PYTHONDONTWRITEBYTECODE", 1) monkeypatch.setenv("PYTHONDONTWRITEBYTECODE", 1)
p = testdir.makepyfile( p = testdir.makepyfile(
@ -559,10 +557,9 @@ class TestLastFailed(object):
) )
result = testdir.runpytest() result = testdir.runpytest()
result.stdout.fnmatch_lines("*1 failed*") result.stdout.fnmatch_lines("*1 failed*")
assert ( assert self.get_cached_last_failed(testdir) == [
self.get_cached_last_failed(testdir) "test_xfail_strict_considered_failure.py::test"
== ["test_xfail_strict_considered_failure.py::test"] ]
)
@pytest.mark.parametrize("mark", ["mark.xfail", "mark.skip"]) @pytest.mark.parametrize("mark", ["mark.xfail", "mark.skip"])
def test_failed_changed_to_xfail_or_skip(self, testdir, mark): def test_failed_changed_to_xfail_or_skip(self, testdir, mark):
@ -574,10 +571,9 @@ class TestLastFailed(object):
""" """
) )
result = testdir.runpytest() result = testdir.runpytest()
assert ( assert self.get_cached_last_failed(testdir) == [
self.get_cached_last_failed(testdir) "test_failed_changed_to_xfail_or_skip.py::test"
== ["test_failed_changed_to_xfail_or_skip.py::test"] ]
)
assert result.ret == 1 assert result.ret == 1
testdir.makepyfile( testdir.makepyfile(
@ -621,10 +617,10 @@ class TestLastFailed(object):
""" """
) )
testdir.runpytest() testdir.runpytest()
assert ( assert self.get_cached_last_failed(testdir) == [
self.get_cached_last_failed(testdir) "test_bar.py::test_bar_2",
== ["test_bar.py::test_bar_2", "test_foo.py::test_foo_4"] "test_foo.py::test_foo_4",
) ]
# 2. fix test_bar_2, run only test_bar.py # 2. fix test_bar_2, run only test_bar.py
testdir.makepyfile( testdir.makepyfile(
@ -697,7 +693,6 @@ class TestLastFailed(object):
class TestNewFirst(object): class TestNewFirst(object):
def test_newfirst_usecase(self, testdir): def test_newfirst_usecase(self, testdir):
testdir.makepyfile( testdir.makepyfile(
**{ **{
@ -823,7 +818,6 @@ class TestNewFirst(object):
class TestReadme(object): class TestReadme(object):
def check_readme(self, testdir): def check_readme(self, testdir):
config = testdir.parseconfigure() config = testdir.parseconfigure()
readme = config.cache._cachedir.joinpath("README.md") readme = config.cache._cachedir.joinpath("README.md")

View File

@ -48,10 +48,9 @@ def StdCapture(out=True, err=True, in_=True):
class TestCaptureManager(object): class TestCaptureManager(object):
def test_getmethod_default_no_fd(self, monkeypatch): def test_getmethod_default_no_fd(self, monkeypatch):
from _pytest.capture import pytest_addoption from _pytest.capture import pytest_addoption
from _pytest.config import Parser from _pytest.config.argparsing import Parser
parser = Parser() parser = Parser()
pytest_addoption(parser) pytest_addoption(parser)
@ -150,7 +149,6 @@ def test_collect_capturing(testdir):
class TestPerTestCapturing(object): class TestPerTestCapturing(object):
def test_capture_and_fixtures(self, testdir): def test_capture_and_fixtures(self, testdir):
p = testdir.makepyfile( p = testdir.makepyfile(
""" """
@ -294,7 +292,6 @@ class TestPerTestCapturing(object):
class TestLoggingInteraction(object): class TestLoggingInteraction(object):
def test_logging_stream_ownership(self, testdir): def test_logging_stream_ownership(self, testdir):
p = testdir.makepyfile( p = testdir.makepyfile(
""" """
@ -399,7 +396,6 @@ class TestLoggingInteraction(object):
class TestCaptureFixture(object): class TestCaptureFixture(object):
@pytest.mark.parametrize("opt", [[], ["-s"]]) @pytest.mark.parametrize("opt", [[], ["-s"]])
def test_std_functional(self, testdir, opt): def test_std_functional(self, testdir, opt):
reprec = testdir.inline_runsource( reprec = testdir.inline_runsource(
@ -771,7 +767,6 @@ def test_error_during_readouterr(testdir):
class TestCaptureIO(object): class TestCaptureIO(object):
def test_text(self): def test_text(self):
f = capture.CaptureIO() f = capture.CaptureIO()
f.write("hello") f.write("hello")
@ -1337,7 +1332,6 @@ def test_py36_windowsconsoleio_workaround_non_standard_streams():
from _pytest.capture import _py36_windowsconsoleio_workaround from _pytest.capture import _py36_windowsconsoleio_workaround
class DummyStream(object): class DummyStream(object):
def write(self, s): def write(self, s):
pass pass

View File

@ -8,7 +8,6 @@ from _pytest.main import Session, EXIT_NOTESTSCOLLECTED, _in_venv
class TestCollector(object): class TestCollector(object):
def test_collect_versus_item(self): def test_collect_versus_item(self):
from pytest import Collector, Item from pytest import Collector, Item
@ -115,7 +114,6 @@ class TestCollector(object):
class TestCollectFS(object): class TestCollectFS(object):
def test_ignored_certain_directories(self, testdir): def test_ignored_certain_directories(self, testdir):
tmpdir = testdir.tmpdir tmpdir = testdir.tmpdir
tmpdir.ensure("build", "test_notfound.py") tmpdir.ensure("build", "test_notfound.py")
@ -253,12 +251,10 @@ class TestCollectFS(object):
class TestCollectPluginHookRelay(object): class TestCollectPluginHookRelay(object):
def test_pytest_collect_file(self, testdir): def test_pytest_collect_file(self, testdir):
wascalled = [] wascalled = []
class Plugin(object): class Plugin(object):
def pytest_collect_file(self, path, parent): def pytest_collect_file(self, path, parent):
if not path.basename.startswith("."): if not path.basename.startswith("."):
# Ignore hidden files, e.g. .testmondata. # Ignore hidden files, e.g. .testmondata.
@ -273,7 +269,6 @@ class TestCollectPluginHookRelay(object):
wascalled = [] wascalled = []
class Plugin(object): class Plugin(object):
def pytest_collect_directory(self, path, parent): def pytest_collect_directory(self, path, parent):
wascalled.append(path.basename) wascalled.append(path.basename)
@ -285,7 +280,6 @@ class TestCollectPluginHookRelay(object):
class TestPrunetraceback(object): class TestPrunetraceback(object):
def test_custom_repr_failure(self, testdir): def test_custom_repr_failure(self, testdir):
p = testdir.makepyfile( p = testdir.makepyfile(
""" """
@ -335,7 +329,6 @@ class TestPrunetraceback(object):
class TestCustomConftests(object): class TestCustomConftests(object):
def test_ignore_collect_path(self, testdir): def test_ignore_collect_path(self, testdir):
testdir.makeconftest( testdir.makeconftest(
""" """
@ -437,7 +430,6 @@ class TestCustomConftests(object):
class TestSession(object): class TestSession(object):
def test_parsearg(self, testdir): def test_parsearg(self, testdir):
p = testdir.makepyfile("def test_func(): pass") p = testdir.makepyfile("def test_func(): pass")
subdir = testdir.mkdir("sub") subdir = testdir.mkdir("sub")
@ -634,7 +626,6 @@ class TestSession(object):
class Test_getinitialnodes(object): class Test_getinitialnodes(object):
def test_global_file(self, testdir, tmpdir): def test_global_file(self, testdir, tmpdir):
x = tmpdir.ensure("x.py") x = tmpdir.ensure("x.py")
with tmpdir.as_cwd(): with tmpdir.as_cwd():
@ -662,7 +653,6 @@ class Test_getinitialnodes(object):
class Test_genitems(object): class Test_genitems(object):
def test_check_collect_hashes(self, testdir): def test_check_collect_hashes(self, testdir):
p = testdir.makepyfile( p = testdir.makepyfile(
""" """
@ -776,7 +766,6 @@ def test_matchnodes_two_collections_same_file(testdir):
class TestNodekeywords(object): class TestNodekeywords(object):
def test_no_under(self, testdir): def test_no_under(self, testdir):
modcol = testdir.getmodulecol( modcol = testdir.getmodulecol(
""" """

View File

@ -7,7 +7,6 @@ from _pytest.outcomes import OutcomeException
def test_is_generator(): def test_is_generator():
def zap(): def zap():
yield yield
@ -19,9 +18,7 @@ def test_is_generator():
def test_real_func_loop_limit(): def test_real_func_loop_limit():
class Evil(object): class Evil(object):
def __init__(self): def __init__(self):
self.left = 1000 self.left = 1000
@ -86,7 +83,6 @@ def test_is_generator_async_syntax(testdir):
class ErrorsHelper(object): class ErrorsHelper(object):
@property @property
def raise_exception(self): def raise_exception(self):
raise Exception("exception should be catched") raise Exception("exception should be catched")

View File

@ -4,17 +4,12 @@ import textwrap
import pytest import pytest
import _pytest._code import _pytest._code
from _pytest.config import ( from _pytest.config.findpaths import getcfg, get_common_ancestor, determine_setup
getcfg, from _pytest.config import _iter_rewritable_modules
get_common_ancestor,
determine_setup,
_iter_rewritable_modules,
)
from _pytest.main import EXIT_NOTESTSCOLLECTED from _pytest.main import EXIT_NOTESTSCOLLECTED
class TestParseIni(object): class TestParseIni(object):
@pytest.mark.parametrize( @pytest.mark.parametrize(
"section, filename", [("pytest", "pytest.ini"), ("tool:pytest", "setup.cfg")] "section, filename", [("pytest", "pytest.ini"), ("tool:pytest", "setup.cfg")]
) )
@ -122,7 +117,6 @@ class TestParseIni(object):
class TestConfigCmdlineParsing(object): class TestConfigCmdlineParsing(object):
def test_parsing_again_fails(self, testdir): def test_parsing_again_fails(self, testdir):
config = testdir.parseconfig() config = testdir.parseconfig()
pytest.raises(AssertionError, lambda: config.parse([])) pytest.raises(AssertionError, lambda: config.parse([]))
@ -176,7 +170,6 @@ class TestConfigCmdlineParsing(object):
class TestConfigAPI(object): class TestConfigAPI(object):
def test_config_trace(self, testdir): def test_config_trace(self, testdir):
config = testdir.parseconfig() config = testdir.parseconfig()
values = [] values = []
@ -416,7 +409,6 @@ class TestConfigAPI(object):
class TestConfigFromdictargs(object): class TestConfigFromdictargs(object):
def test_basic_behavior(self): def test_basic_behavior(self):
from _pytest.config import Config from _pytest.config import Config
@ -483,7 +475,6 @@ class TestConfigFromdictargs(object):
def test_options_on_small_file_do_not_blow_up(testdir): def test_options_on_small_file_do_not_blow_up(testdir):
def runfiletest(opts): def runfiletest(opts):
reprec = testdir.inline_run(*opts) reprec = testdir.inline_run(*opts)
passed, skipped, failed = reprec.countoutcomes() passed, skipped, failed = reprec.countoutcomes()
@ -530,7 +521,6 @@ def test_preparse_ordering_with_setuptools(testdir, monkeypatch):
dist = Dist() dist = Dist()
def load(self): def load(self):
class PseudoPlugin(object): class PseudoPlugin(object):
x = 42 x = 42
@ -610,9 +600,9 @@ def test_plugin_preparse_prevents_setuptools_loading(testdir, monkeypatch, block
assert "mytestplugin" not in sys.modules assert "mytestplugin" not in sys.modules
assert config.pluginmanager.get_plugin("mytestplugin") is None assert config.pluginmanager.get_plugin("mytestplugin") is None
else: else:
assert config.pluginmanager.get_plugin( assert (
"mytestplugin" config.pluginmanager.get_plugin("mytestplugin") is plugin_module_placeholder
) is plugin_module_placeholder )
def test_cmdline_processargs_simple(testdir): def test_cmdline_processargs_simple(testdir):
@ -713,7 +703,6 @@ def test_notify_exception(testdir, capfd):
assert "ValueError" in err assert "ValueError" in err
class A(object): class A(object):
def pytest_internalerror(self, excrepr): def pytest_internalerror(self, excrepr):
return True return True
@ -729,7 +718,6 @@ def test_load_initial_conftest_last_ordering(testdir):
pm = get_config().pluginmanager pm = get_config().pluginmanager
class My(object): class My(object):
def pytest_load_initial_conftests(self): def pytest_load_initial_conftests(self):
pass pass
@ -758,7 +746,6 @@ def test_get_plugin_specs_as_list():
class TestWarning(object): class TestWarning(object):
def test_warn_config(self, testdir): def test_warn_config(self, testdir):
testdir.makeconftest( testdir.makeconftest(
""" """
@ -808,7 +795,6 @@ class TestWarning(object):
class TestRootdir(object): class TestRootdir(object):
def test_simple_noini(self, tmpdir): def test_simple_noini(self, tmpdir):
assert get_common_ancestor([tmpdir]) == tmpdir assert get_common_ancestor([tmpdir]) == tmpdir
a = tmpdir.mkdir("a") a = tmpdir.mkdir("a")
@ -867,7 +853,6 @@ class TestRootdir(object):
class TestOverrideIniArgs(object): class TestOverrideIniArgs(object):
@pytest.mark.parametrize("name", "setup.cfg tox.ini pytest.ini".split()) @pytest.mark.parametrize("name", "setup.cfg tox.ini pytest.ini".split())
def test_override_ini_names(self, testdir, name): def test_override_ini_names(self, testdir, name):
testdir.tmpdir.join(name).write( testdir.tmpdir.join(name).write(

View File

@ -28,9 +28,7 @@ def ConftestWithSetinitial(path):
def conftest_setinitial(conftest, args, confcutdir=None): def conftest_setinitial(conftest, args, confcutdir=None):
class Namespace(object): class Namespace(object):
def __init__(self): def __init__(self):
self.file_or_dir = args self.file_or_dir = args
self.confcutdir = str(confcutdir) self.confcutdir = str(confcutdir)
@ -40,7 +38,6 @@ def conftest_setinitial(conftest, args, confcutdir=None):
class TestConftestValueAccessGlobal(object): class TestConftestValueAccessGlobal(object):
def test_basic_init(self, basedir): def test_basic_init(self, basedir):
conftest = PytestPluginManager() conftest = PytestPluginManager()
p = basedir.join("adir") p = basedir.join("adir")
@ -311,7 +308,6 @@ def test_conftest_found_with_double_dash(testdir):
class TestConftestVisibility(object): class TestConftestVisibility(object):
def _setup_tree(self, testdir): # for issue616 def _setup_tree(self, testdir): # for issue616
# example mostly taken from: # example mostly taken from:
# https://mail.python.org/pipermail/pytest-dev/2014-September/002617.html # https://mail.python.org/pipermail/pytest-dev/2014-September/002617.html

View File

@ -8,7 +8,6 @@ import pytest
class TestDoctests(object): class TestDoctests(object):
def test_collect_testtextfile(self, testdir): def test_collect_testtextfile(self, testdir):
w = testdir.maketxtfile(whatever="") w = testdir.maketxtfile(whatever="")
checkfile = testdir.maketxtfile( checkfile = testdir.maketxtfile(
@ -655,6 +654,22 @@ class TestDoctests(object):
result = testdir.runpytest(p, "--doctest-modules") result = testdir.runpytest(p, "--doctest-modules")
result.stdout.fnmatch_lines(["* 1 passed *"]) result.stdout.fnmatch_lines(["* 1 passed *"])
def test_print_unicode_value(self, testdir):
"""
Test case for issue 3583: Printing Unicode in doctest under Python 2.7
doesn't work
"""
p = testdir.maketxtfile(
test_print_unicode_value=r"""
Here is a doctest::
>>> print(u'\xE5\xE9\xEE\xF8\xFC')
åéîøü
"""
)
result = testdir.runpytest(p)
result.stdout.fnmatch_lines(["* 1 passed *"])
def test_reportinfo(self, testdir): def test_reportinfo(self, testdir):
""" """
Test case to make sure that DoctestItem.reportinfo() returns lineno. Test case to make sure that DoctestItem.reportinfo() returns lineno.
@ -707,7 +722,6 @@ class TestDoctests(object):
class TestLiterals(object): class TestLiterals(object):
@pytest.mark.parametrize("config_mode", ["ini", "comment"]) @pytest.mark.parametrize("config_mode", ["ini", "comment"])
def test_allow_unicode(self, testdir, config_mode): def test_allow_unicode(self, testdir, config_mode):
"""Test that doctests which output unicode work in all python versions """Test that doctests which output unicode work in all python versions
@ -825,7 +839,6 @@ class TestDoctestSkips(object):
@pytest.fixture(params=["text", "module"]) @pytest.fixture(params=["text", "module"])
def makedoctest(self, testdir, request): def makedoctest(self, testdir, request):
def makeit(doctest): def makeit(doctest):
mode = request.param mode = request.param
if mode == "text": if mode == "text":
@ -1106,7 +1119,6 @@ class TestDoctestNamespaceFixture(object):
class TestDoctestReportingOption(object): class TestDoctestReportingOption(object):
def _run_doctest_report(self, testdir, format): def _run_doctest_report(self, testdir, format):
testdir.makepyfile( testdir.makepyfile(
""" """

View File

@ -29,7 +29,6 @@ def assert_attr(node, **kwargs):
class DomNode(object): class DomNode(object):
def __init__(self, dom): def __init__(self, dom):
self.__node = dom self.__node = dom
@ -81,7 +80,6 @@ class DomNode(object):
class TestPython(object): class TestPython(object):
def test_summing_simple(self, testdir): def test_summing_simple(self, testdir):
testdir.makepyfile( testdir.makepyfile(
""" """
@ -713,7 +711,6 @@ def test_dont_configure_on_slaves(tmpdir):
gotten = [] gotten = []
class FakeConfig(object): class FakeConfig(object):
def __init__(self): def __init__(self):
self.pluginmanager = self self.pluginmanager = self
self.option = self self.option = self
@ -737,7 +734,6 @@ def test_dont_configure_on_slaves(tmpdir):
class TestNonPython(object): class TestNonPython(object):
def test_summing_simple(self, testdir): def test_summing_simple(self, testdir):
testdir.makeconftest( testdir.makeconftest(
""" """
@ -1127,18 +1123,15 @@ def test_fancy_items_regression(testdir):
import pprint import pprint
pprint.pprint(items) pprint.pprint(items)
assert ( assert items == [
items u"conftest a conftest.py",
== [ u"conftest a conftest.py",
u"conftest a conftest.py", u"conftest b conftest.py",
u"conftest a conftest.py", u"test_fancy_items_regression a test_fancy_items_regression.py",
u"conftest b conftest.py", u"test_fancy_items_regression a test_fancy_items_regression.py",
u"test_fancy_items_regression a test_fancy_items_regression.py", u"test_fancy_items_regression b test_fancy_items_regression.py",
u"test_fancy_items_regression a test_fancy_items_regression.py", u"test_fancy_items_regression test_pass" u" test_fancy_items_regression.py",
u"test_fancy_items_regression b test_fancy_items_regression.py", ]
u"test_fancy_items_regression test_pass" u" test_fancy_items_regression.py",
]
)
def test_global_properties(testdir): def test_global_properties(testdir):

View File

@ -1,7 +1,11 @@
from __future__ import absolute_import, division, print_function from __future__ import absolute_import, division, print_function
import os import os
import sys import sys
import mock
try:
import mock
except ImportError:
import unittest.mock as mock
import pytest import pytest
from _pytest.mark import ( from _pytest.mark import (
MarkGenerator as Mark, MarkGenerator as Mark,
@ -17,7 +21,6 @@ ignore_markinfo = pytest.mark.filterwarnings(
class TestMark(object): class TestMark(object):
def test_markinfo_repr(self): def test_markinfo_repr(self):
from _pytest.mark import MarkInfo, Mark from _pytest.mark import MarkInfo, Mark
@ -35,7 +38,6 @@ class TestMark(object):
pytest.raises((AttributeError, TypeError), mark) pytest.raises((AttributeError, TypeError), mark)
def test_mark_with_param(self): def test_mark_with_param(self):
def some_function(abc): def some_function(abc):
pass pass
@ -483,7 +485,6 @@ def test_parametrized_with_kwargs(testdir):
class TestFunctional(object): class TestFunctional(object):
def test_mark_per_function(self, testdir): def test_mark_per_function(self, testdir):
p = testdir.makepyfile( p = testdir.makepyfile(
""" """
@ -880,7 +881,6 @@ class TestFunctional(object):
class TestKeywordSelection(object): class TestKeywordSelection(object):
def test_select_simple(self, testdir): def test_select_simple(self, testdir):
file_test = testdir.makepyfile( file_test = testdir.makepyfile(
""" """
@ -1033,7 +1033,6 @@ def test_parameterset_extractfrom(argval, expected):
def test_legacy_transfer(): def test_legacy_transfer():
class FakeModule(object): class FakeModule(object):
pytestmark = [] pytestmark = []
@ -1054,7 +1053,6 @@ def test_legacy_transfer():
class TestMarkDecorator(object): class TestMarkDecorator(object):
@pytest.mark.parametrize( @pytest.mark.parametrize(
"lhs, rhs, expected", "lhs, rhs, expected",
[ [

View File

@ -17,7 +17,6 @@ def mp():
def test_setattr(): def test_setattr():
class A(object): class A(object):
x = 1 x = 1
@ -42,7 +41,6 @@ def test_setattr():
class TestSetattrWithImportPath(object): class TestSetattrWithImportPath(object):
def test_string_expression(self, monkeypatch): def test_string_expression(self, monkeypatch):
monkeypatch.setattr("os.path.abspath", lambda x: "hello2") monkeypatch.setattr("os.path.abspath", lambda x: "hello2")
assert os.path.abspath("123") == "hello2" assert os.path.abspath("123") == "hello2"
@ -84,7 +82,6 @@ class TestSetattrWithImportPath(object):
def test_delattr(): def test_delattr():
class A(object): class A(object):
x = 1 x = 1
@ -311,7 +308,6 @@ def test_importerror(testdir):
class SampleNew(object): class SampleNew(object):
@staticmethod @staticmethod
def hello(): def hello():
return True return True

View File

@ -33,7 +33,6 @@ def test_setup_func_with_setup_decorator():
values = [] values = []
class A(object): class A(object):
@pytest.fixture(autouse=True) @pytest.fixture(autouse=True)
def f(self): def f(self):
values.append(1) values.append(1)

View File

@ -4,7 +4,7 @@ import sys
import os import os
import py import py
import pytest import pytest
from _pytest import config as parseopt from _pytest.config import argparsing as parseopt
@pytest.fixture @pytest.fixture
@ -13,7 +13,6 @@ def parser():
class TestParser(object): class TestParser(object):
def test_no_help_by_default(self, capsys): def test_no_help_by_default(self, capsys):
parser = parseopt.Parser(usage="xyz") parser = parseopt.Parser(usage="xyz")
pytest.raises(SystemExit, lambda: parser.parse(["-h"])) pytest.raises(SystemExit, lambda: parser.parse(["-h"]))
@ -34,9 +33,8 @@ class TestParser(object):
assert argument.dest == "test" assert argument.dest == "test"
argument = parseopt.Argument("-t", "--test", dest="abc") argument = parseopt.Argument("-t", "--test", dest="abc")
assert argument.dest == "abc" assert argument.dest == "abc"
assert ( assert str(argument) == (
str(argument) "Argument(_short_opts: ['-t'], _long_opts: ['--test'], dest: 'abc')"
== ("Argument(_short_opts: ['-t'], _long_opts: ['--test'], dest: 'abc')")
) )
def test_argument_type(self): def test_argument_type(self):
@ -180,7 +178,6 @@ class TestParser(object):
assert args.S is False assert args.S is False
def test_parse_defaultgetter(self): def test_parse_defaultgetter(self):
def defaultget(option): def defaultget(option):
if not hasattr(option, "type"): if not hasattr(option, "type"):
return return
@ -204,15 +201,11 @@ class TestParser(object):
) )
parser.add_argument( parser.add_argument(
"-t", "--twoword", "--duo", "--two-word", "--two", help="foo" "-t", "--twoword", "--duo", "--two-word", "--two", help="foo"
).map_long_option = { ).map_long_option = {"two": "two-word"}
"two": "two-word"
}
# throws error on --deux only! # throws error on --deux only!
parser.add_argument( parser.add_argument(
"-d", "--deuxmots", "--deux-mots", action="store_true", help="foo" "-d", "--deuxmots", "--deux-mots", action="store_true", help="foo"
).map_long_option = { ).map_long_option = {"deux": "deux-mots"}
"deux": "deux-mots"
}
parser.add_argument("-s", action="store_true", help="single short") parser.add_argument("-s", action="store_true", help="single short")
parser.add_argument("--abc", "-a", action="store_true", help="bar") parser.add_argument("--abc", "-a", action="store_true", help="bar")
parser.add_argument("--klm", "-k", "--kl-m", action="store_true", help="bar") parser.add_argument("--klm", "-k", "--kl-m", action="store_true", help="bar")
@ -224,9 +217,7 @@ class TestParser(object):
) )
parser.add_argument( parser.add_argument(
"-x", "--exit-on-first", "--exitfirst", action="store_true", help="spam" "-x", "--exit-on-first", "--exitfirst", action="store_true", help="spam"
).map_long_option = { ).map_long_option = {"exitfirst": "exit-on-first"}
"exitfirst": "exit-on-first"
}
parser.add_argument("files_and_dirs", nargs="*") parser.add_argument("files_and_dirs", nargs="*")
args = parser.parse_args(["-k", "--duo", "hallo", "--exitfirst"]) args = parser.parse_args(["-k", "--duo", "hallo", "--exitfirst"])
assert args.twoword == "hallo" assert args.twoword == "hallo"

View File

@ -5,7 +5,6 @@ import pytest
class TestPasteCapture(object): class TestPasteCapture(object):
@pytest.fixture @pytest.fixture
def pastebinlist(self, monkeypatch, request): def pastebinlist(self, monkeypatch, request):
pastebinlist = [] pastebinlist = []
@ -85,7 +84,6 @@ class TestPasteCapture(object):
class TestPaste(object): class TestPaste(object):
@pytest.fixture @pytest.fixture
def pastebin(self, request): def pastebin(self, request):
return request.config.pluginmanager.getplugin("pastebin") return request.config.pluginmanager.getplugin("pastebin")
@ -102,7 +100,6 @@ class TestPaste(object):
calls.append((url, data)) calls.append((url, data))
class DummyFile(object): class DummyFile(object):
def read(self): def read(self):
# part of html of a normal response # part of html of a normal response
return b'View <a href="/raw/3c0c6750bd">raw</a>.' return b'View <a href="/raw/3c0c6750bd">raw</a>.'

Some files were not shown because too many files have changed in this diff Show More