commit
602a290fcc
36
.travis.yml
36
.travis.yml
|
@ -19,18 +19,13 @@ install:
|
||||||
jobs:
|
jobs:
|
||||||
include:
|
include:
|
||||||
# OSX tests - first (in test stage), since they are the slower ones.
|
# OSX tests - first (in test stage), since they are the slower ones.
|
||||||
- &test-macos
|
- os: osx
|
||||||
os: osx
|
# NOTE: (tests with) pexpect appear to be buggy on Travis,
|
||||||
|
# at least with coverage.
|
||||||
|
# Log: https://travis-ci.org/pytest-dev/pytest/jobs/500358864
|
||||||
osx_image: xcode10.1
|
osx_image: xcode10.1
|
||||||
language: generic
|
language: generic
|
||||||
# Coverage for:
|
env: TOXENV=py37-xdist PYTEST_COVERAGE=1
|
||||||
# - py2 with symlink in test_cmdline_python_package_symlink.
|
|
||||||
env: TOXENV=py27-xdist PYTEST_COVERAGE=1
|
|
||||||
before_install:
|
|
||||||
- python -V
|
|
||||||
- test $(python -c 'import sys; print("%d%d" % sys.version_info[0:2])') = 27
|
|
||||||
- <<: *test-macos
|
|
||||||
env: TOXENV=py37-pexpect,py37-xdist PYTEST_COVERAGE=1
|
|
||||||
before_install:
|
before_install:
|
||||||
- which python3
|
- which python3
|
||||||
- python3 -V
|
- python3 -V
|
||||||
|
@ -38,20 +33,14 @@ jobs:
|
||||||
- python -V
|
- python -V
|
||||||
- test $(python -c 'import sys; print("%d%d" % sys.version_info[0:2])') = 37
|
- test $(python -c 'import sys; print("%d%d" % sys.version_info[0:2])') = 37
|
||||||
|
|
||||||
# Full run of latest (major) supported versions, without xdist.
|
# Full run of latest supported version, without xdist.
|
||||||
- env: TOXENV=py27
|
|
||||||
python: '2.7'
|
|
||||||
- env: TOXENV=py37
|
- env: TOXENV=py37
|
||||||
python: '3.7'
|
python: '3.7'
|
||||||
|
|
||||||
# Coverage tracking is slow with pypy, skip it.
|
# Coverage tracking is slow with pypy, skip it.
|
||||||
- env: TOXENV=pypy-xdist
|
|
||||||
python: 'pypy'
|
|
||||||
- env: TOXENV=pypy3-xdist
|
- env: TOXENV=pypy3-xdist
|
||||||
python: 'pypy3'
|
python: 'pypy3'
|
||||||
|
|
||||||
- env: TOXENV=py34-xdist
|
|
||||||
python: '3.4'
|
|
||||||
- env: TOXENV=py35-xdist
|
- env: TOXENV=py35-xdist
|
||||||
python: '3.5'
|
python: '3.5'
|
||||||
|
|
||||||
|
@ -62,12 +51,6 @@ jobs:
|
||||||
# Empty PYTEST_ADDOPTS to run this non-verbose.
|
# Empty PYTEST_ADDOPTS to run this non-verbose.
|
||||||
- env: TOXENV=py37-lsof-numpy-xdist PYTEST_COVERAGE=1 PYTEST_ADDOPTS=
|
- env: TOXENV=py37-lsof-numpy-xdist PYTEST_COVERAGE=1 PYTEST_ADDOPTS=
|
||||||
|
|
||||||
# Specialized factors for py27.
|
|
||||||
- env: TOXENV=py27-nobyte-numpy-xdist
|
|
||||||
python: '2.7'
|
|
||||||
- env: TOXENV=py27-pluggymaster-xdist
|
|
||||||
python: '2.7'
|
|
||||||
|
|
||||||
# Specialized factors for py37.
|
# Specialized factors for py37.
|
||||||
# Coverage for:
|
# Coverage for:
|
||||||
# - test_sys_breakpoint_interception (via pexpect).
|
# - test_sys_breakpoint_interception (via pexpect).
|
||||||
|
@ -81,12 +64,7 @@ jobs:
|
||||||
if: type = cron
|
if: type = cron
|
||||||
|
|
||||||
- stage: baseline
|
- stage: baseline
|
||||||
# Coverage for:
|
env: TOXENV=py36-xdist
|
||||||
# - _pytest.unittest._handle_skip (via pexpect).
|
|
||||||
env: TOXENV=py27-pexpect,py27-twisted PYTEST_COVERAGE=1
|
|
||||||
python: '2.7'
|
|
||||||
# Use py36 here for faster baseline.
|
|
||||||
- env: TOXENV=py36-xdist
|
|
||||||
python: '3.6'
|
python: '3.6'
|
||||||
- env: TOXENV=linting,docs,doctesting PYTEST_COVERAGE=1
|
- env: TOXENV=linting,docs,doctesting PYTEST_COVERAGE=1
|
||||||
cache:
|
cache:
|
||||||
|
|
|
@ -85,7 +85,7 @@ Features
|
||||||
- Can run `unittest <https://docs.pytest.org/en/latest/unittest.html>`_ (or trial),
|
- Can run `unittest <https://docs.pytest.org/en/latest/unittest.html>`_ (or trial),
|
||||||
`nose <https://docs.pytest.org/en/latest/nose.html>`_ test suites out of the box;
|
`nose <https://docs.pytest.org/en/latest/nose.html>`_ test suites out of the box;
|
||||||
|
|
||||||
- Python 2.7, Python 3.4+, PyPy 2.3, Jython 2.5 (untested);
|
- Python 3.5+ and PyPy3;
|
||||||
|
|
||||||
- Rich plugin architecture, with over 315+ `external plugins <http://plugincompat.herokuapp.com>`_ and thriving community;
|
- Rich plugin architecture, with over 315+ `external plugins <http://plugincompat.herokuapp.com>`_ and thriving community;
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,6 @@ trigger:
|
||||||
|
|
||||||
variables:
|
variables:
|
||||||
PYTEST_ADDOPTS: "--junitxml=build/test-results/$(tox.env).xml -vv"
|
PYTEST_ADDOPTS: "--junitxml=build/test-results/$(tox.env).xml -vv"
|
||||||
python.needs_vc: False
|
|
||||||
COVERAGE_FILE: "$(Build.Repository.LocalPath)/.coverage"
|
COVERAGE_FILE: "$(Build.Repository.LocalPath)/.coverage"
|
||||||
COVERAGE_PROCESS_START: "$(Build.Repository.LocalPath)/.coveragerc"
|
COVERAGE_PROCESS_START: "$(Build.Repository.LocalPath)/.coveragerc"
|
||||||
PYTEST_COVERAGE: '0'
|
PYTEST_COVERAGE: '0'
|
||||||
|
@ -16,44 +15,10 @@ jobs:
|
||||||
vmImage: "vs2017-win2016"
|
vmImage: "vs2017-win2016"
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
py27:
|
# -- pypy3 disabled for now: #5279 --
|
||||||
python.version: '2.7'
|
|
||||||
tox.env: 'py27'
|
|
||||||
py27-nobyte-lsof-numpy:
|
|
||||||
python.version: '2.7'
|
|
||||||
tox.env: 'py27-lsof-nobyte-numpy'
|
|
||||||
# Coverage for:
|
|
||||||
# - test_supports_breakpoint_module_global
|
|
||||||
# - test_terminal_reporter_writer_attr (without xdist)
|
|
||||||
# - "if write" branch in _pytest.assertion.rewrite
|
|
||||||
# - numpy
|
|
||||||
# - pytester's LsofFdLeakChecker (being skipped)
|
|
||||||
PYTEST_COVERAGE: '1'
|
|
||||||
py27-twisted:
|
|
||||||
python.version: '2.7'
|
|
||||||
tox.env: 'py27-twisted'
|
|
||||||
python.needs_vc: True
|
|
||||||
py27-pluggymaster-xdist:
|
|
||||||
python.version: '2.7'
|
|
||||||
tox.env: 'py27-pluggymaster-xdist'
|
|
||||||
# Coverage for:
|
|
||||||
# - except-IOError in _attempt_to_close_capture_file for py2.
|
|
||||||
# Also seen with py27-nobyte (using xdist), and py27-xdist.
|
|
||||||
# But no exception with py27-pexpect,py27-twisted,py27-numpy.
|
|
||||||
PYTEST_COVERAGE: '1'
|
|
||||||
# -- pypy2 and pypy3 are disabled for now: #5279 --
|
|
||||||
# pypy:
|
|
||||||
# python.version: 'pypy2'
|
|
||||||
# tox.env: 'pypy'
|
|
||||||
# pypy3:
|
# pypy3:
|
||||||
# python.version: 'pypy3'
|
# python.version: 'pypy3'
|
||||||
# tox.env: 'pypy3'
|
# tox.env: 'pypy3'
|
||||||
py34-xdist:
|
|
||||||
python.version: '3.4'
|
|
||||||
tox.env: 'py34-xdist'
|
|
||||||
# Coverage for:
|
|
||||||
# - _pytest.compat._bytes_to_ascii
|
|
||||||
PYTEST_COVERAGE: '1'
|
|
||||||
py35-xdist:
|
py35-xdist:
|
||||||
python.version: '3.5'
|
python.version: '3.5'
|
||||||
tox.env: 'py35-xdist'
|
tox.env: 'py35-xdist'
|
||||||
|
@ -87,10 +52,6 @@ jobs:
|
||||||
versionSpec: '$(python.version)'
|
versionSpec: '$(python.version)'
|
||||||
architecture: 'x64'
|
architecture: 'x64'
|
||||||
|
|
||||||
- script: choco install vcpython27
|
|
||||||
condition: eq(variables['python.needs_vc'], True)
|
|
||||||
displayName: 'Install VC for py27'
|
|
||||||
|
|
||||||
- script: python -m pip install --upgrade pip && python -m pip install tox
|
- script: python -m pip install --upgrade pip && python -m pip install tox
|
||||||
displayName: 'Install tox'
|
displayName: 'Install tox'
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
<li><a href="{{ pathto('changelog') }}">Changelog</a></li>
|
<li><a href="{{ pathto('changelog') }}">Changelog</a></li>
|
||||||
<li><a href="{{ pathto('contributing') }}">Contributing</a></li>
|
<li><a href="{{ pathto('contributing') }}">Contributing</a></li>
|
||||||
<li><a href="{{ pathto('backwards-compatibility') }}">Backwards Compatibility</a></li>
|
<li><a href="{{ pathto('backwards-compatibility') }}">Backwards Compatibility</a></li>
|
||||||
|
<li><a href="{{ pathto('py27-py34-deprecation') }}">Python 2.7 and 3.4 Support</a></li>
|
||||||
<li><a href="{{ pathto('license') }}">License</a></li>
|
<li><a href="{{ pathto('license') }}">License</a></li>
|
||||||
<li><a href="{{ pathto('contact') }}">Contact Channels</a></li>
|
<li><a href="{{ pathto('contact') }}">Contact Channels</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
|
@ -288,8 +288,7 @@ its test methods:
|
||||||
This is equivalent to directly applying the decorator to the
|
This is equivalent to directly applying the decorator to the
|
||||||
two test functions.
|
two test functions.
|
||||||
|
|
||||||
To remain backward-compatible with Python 2.4 you can also set a
|
Due to legacy reasons, it is possible to set the ``pytestmark`` attribute on a TestClass like this:
|
||||||
``pytestmark`` attribute on a TestClass like this:
|
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
Installation and Getting Started
|
Installation and Getting Started
|
||||||
===================================
|
===================================
|
||||||
|
|
||||||
**Pythons**: Python 2.7, 3.4, 3.5, 3.6, 3.7, Jython, PyPy-2.3
|
**Pythons**: Python 3.5, 3.6, 3.7, PyPy3
|
||||||
|
|
||||||
**Platforms**: Unix/Posix and Windows
|
**Platforms**: Linux and Windows
|
||||||
|
|
||||||
**PyPI package name**: `pytest <https://pypi.org/project/pytest/>`_
|
**PyPI package name**: `pytest <https://pypi.org/project/pytest/>`_
|
||||||
|
|
||||||
|
|
|
@ -7,8 +7,7 @@ Good Integration Practices
|
||||||
Install package with pip
|
Install package with pip
|
||||||
-------------------------------------------------
|
-------------------------------------------------
|
||||||
|
|
||||||
For development, we recommend you use venv_ for virtual environments
|
For development, we recommend you use venv_ for virtual environments and
|
||||||
(or virtualenv_ for Python 2.7) and
|
|
||||||
pip_ for installing your application and any dependencies,
|
pip_ for installing your application and any dependencies,
|
||||||
as well as the ``pytest`` package itself.
|
as well as the ``pytest`` package itself.
|
||||||
This ensures your code and dependencies are isolated from your system Python installation.
|
This ensures your code and dependencies are isolated from your system Python installation.
|
||||||
|
|
|
@ -61,7 +61,7 @@ Features
|
||||||
|
|
||||||
- Can run :ref:`unittest <unittest>` (including trial) and :ref:`nose <noseintegration>` test suites out of the box;
|
- Can run :ref:`unittest <unittest>` (including trial) and :ref:`nose <noseintegration>` test suites out of the box;
|
||||||
|
|
||||||
- Python 2.7, Python 3.4+, PyPy 2.3, Jython 2.5 (untested);
|
- Python Python 3.5+ and PyPy 3;
|
||||||
|
|
||||||
- Rich plugin architecture, with over 315+ `external plugins <http://plugincompat.herokuapp.com>`_ and thriving community;
|
- Rich plugin architecture, with over 315+ `external plugins <http://plugincompat.herokuapp.com>`_ and thriving community;
|
||||||
|
|
||||||
|
|
14
setup.cfg
14
setup.cfg
|
@ -1,5 +1,4 @@
|
||||||
[metadata]
|
[metadata]
|
||||||
|
|
||||||
name = pytest
|
name = pytest
|
||||||
description = pytest: simple powerful testing with Python
|
description = pytest: simple powerful testing with Python
|
||||||
long_description = file: README.rst
|
long_description = file: README.rst
|
||||||
|
@ -23,13 +22,11 @@ classifiers =
|
||||||
Topic :: Software Development :: Testing
|
Topic :: Software Development :: Testing
|
||||||
Topic :: Software Development :: Libraries
|
Topic :: Software Development :: Libraries
|
||||||
Topic :: Utilities
|
Topic :: Utilities
|
||||||
Programming Language :: Python :: 2
|
Programming Language :: Python :: 3 :: Only
|
||||||
Programming Language :: Python :: 2.7
|
|
||||||
Programming Language :: Python :: 3
|
|
||||||
Programming Language :: Python :: 3.4
|
|
||||||
Programming Language :: Python :: 3.5
|
Programming Language :: Python :: 3.5
|
||||||
Programming Language :: Python :: 3.6
|
Programming Language :: Python :: 3.6
|
||||||
Programming Language :: Python :: 3.7
|
Programming Language :: Python :: 3.7
|
||||||
|
Programming Language :: Python :: 3.8
|
||||||
platforms = unix, linux, osx, cygwin, win32
|
platforms = unix, linux, osx, cygwin, win32
|
||||||
|
|
||||||
[options]
|
[options]
|
||||||
|
@ -43,8 +40,7 @@ packages =
|
||||||
_pytest.mark
|
_pytest.mark
|
||||||
|
|
||||||
py_modules = pytest
|
py_modules = pytest
|
||||||
python_requires = >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*
|
python_requires = >=3.5
|
||||||
|
|
||||||
|
|
||||||
[options.entry_points]
|
[options.entry_points]
|
||||||
console_scripts =
|
console_scripts =
|
||||||
|
@ -59,13 +55,9 @@ all_files = 1
|
||||||
[upload_sphinx]
|
[upload_sphinx]
|
||||||
upload-dir = doc/en/build/html
|
upload-dir = doc/en/build/html
|
||||||
|
|
||||||
[bdist_wheel]
|
|
||||||
universal = 1
|
|
||||||
|
|
||||||
[check-manifest]
|
[check-manifest]
|
||||||
ignore =
|
ignore =
|
||||||
_pytest/_version.py
|
_pytest/_version.py
|
||||||
|
|
||||||
|
|
||||||
[devpi:upload]
|
[devpi:upload]
|
||||||
formats = sdist.tgz,bdist_wheel
|
formats = sdist.tgz,bdist_wheel
|
||||||
|
|
6
setup.py
6
setup.py
|
@ -8,10 +8,8 @@ INSTALL_REQUIRES = [
|
||||||
"six>=1.10.0",
|
"six>=1.10.0",
|
||||||
"packaging",
|
"packaging",
|
||||||
"attrs>=17.4.0",
|
"attrs>=17.4.0",
|
||||||
'more-itertools>=4.0.0,<6.0.0;python_version<="2.7"',
|
"more-itertools>=4.0.0",
|
||||||
'more-itertools>=4.0.0;python_version>"2.7"',
|
|
||||||
"atomicwrites>=1.0",
|
"atomicwrites>=1.0",
|
||||||
'funcsigs>=1.0;python_version<"3.0"',
|
|
||||||
'pathlib2>=2.2.0;python_version<"3.6"',
|
'pathlib2>=2.2.0;python_version<"3.6"',
|
||||||
'colorama;sys_platform=="win32"',
|
'colorama;sys_platform=="win32"',
|
||||||
"pluggy>=0.12,<1.0",
|
"pluggy>=0.12,<1.0",
|
||||||
|
@ -30,9 +28,9 @@ def main():
|
||||||
"testing": [
|
"testing": [
|
||||||
"argcomplete",
|
"argcomplete",
|
||||||
"hypothesis>=3.56",
|
"hypothesis>=3.56",
|
||||||
|
"mock",
|
||||||
"nose",
|
"nose",
|
||||||
"requests",
|
"requests",
|
||||||
"mock;python_version=='2.7'",
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
# fmt: on
|
# fmt: on
|
||||||
|
|
|
@ -9,25 +9,16 @@ import sys
|
||||||
import traceback
|
import traceback
|
||||||
from inspect import CO_VARARGS
|
from inspect import CO_VARARGS
|
||||||
from inspect import CO_VARKEYWORDS
|
from inspect import CO_VARKEYWORDS
|
||||||
|
from traceback import format_exception_only
|
||||||
from weakref import ref
|
from weakref import ref
|
||||||
|
|
||||||
import attr
|
import attr
|
||||||
import pluggy
|
import pluggy
|
||||||
import py
|
import py
|
||||||
from six import text_type
|
|
||||||
|
|
||||||
import _pytest
|
import _pytest
|
||||||
from _pytest._io.saferepr import safeformat
|
from _pytest._io.saferepr import safeformat
|
||||||
from _pytest._io.saferepr import saferepr
|
from _pytest._io.saferepr import saferepr
|
||||||
from _pytest.compat import _PY2
|
|
||||||
from _pytest.compat import _PY3
|
|
||||||
from _pytest.compat import PY35
|
|
||||||
from _pytest.compat import safe_str
|
|
||||||
|
|
||||||
if _PY3:
|
|
||||||
from traceback import format_exception_only
|
|
||||||
else:
|
|
||||||
from ._py2traceback import format_exception_only
|
|
||||||
|
|
||||||
|
|
||||||
class Code(object):
|
class Code(object):
|
||||||
|
@ -208,8 +199,7 @@ class TracebackEntry(object):
|
||||||
locals = property(getlocals, None, None, "locals of underlaying frame")
|
locals = property(getlocals, None, None, "locals of underlaying frame")
|
||||||
|
|
||||||
def getfirstlinesource(self):
|
def getfirstlinesource(self):
|
||||||
# on Jython this firstlineno can be -1 apparently
|
return self.frame.code.firstlineno
|
||||||
return max(self.frame.code.firstlineno, 0)
|
|
||||||
|
|
||||||
def getsource(self, astcache=None):
|
def getsource(self, astcache=None):
|
||||||
""" return failing source code. """
|
""" return failing source code. """
|
||||||
|
@ -391,9 +381,7 @@ class ExceptionInfo(object):
|
||||||
help for navigating the traceback.
|
help for navigating the traceback.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_assert_start_repr = (
|
_assert_start_repr = "AssertionError('assert "
|
||||||
"AssertionError(u'assert " if _PY2 else "AssertionError('assert "
|
|
||||||
)
|
|
||||||
|
|
||||||
_excinfo = attr.ib()
|
_excinfo = attr.ib()
|
||||||
_striptext = attr.ib(default="")
|
_striptext = attr.ib(default="")
|
||||||
|
@ -558,11 +546,6 @@ class ExceptionInfo(object):
|
||||||
loc = ReprFileLocation(entry.path, entry.lineno + 1, self.exconly())
|
loc = ReprFileLocation(entry.path, entry.lineno + 1, self.exconly())
|
||||||
return str(loc)
|
return str(loc)
|
||||||
|
|
||||||
def __unicode__(self):
|
|
||||||
entry = self.traceback[-1]
|
|
||||||
loc = ReprFileLocation(entry.path, entry.lineno + 1, self.exconly())
|
|
||||||
return text_type(loc)
|
|
||||||
|
|
||||||
def match(self, regexp):
|
def match(self, regexp):
|
||||||
"""
|
"""
|
||||||
Check whether the regular expression 'regexp' is found in the string
|
Check whether the regular expression 'regexp' is found in the string
|
||||||
|
@ -692,8 +675,7 @@ class FormattedExcinfo(object):
|
||||||
source = _pytest._code.Source("???")
|
source = _pytest._code.Source("???")
|
||||||
line_index = 0
|
line_index = 0
|
||||||
else:
|
else:
|
||||||
# entry.getfirstlinesource() can be -1, should be 0 on jython
|
line_index = entry.lineno - entry.getfirstlinesource()
|
||||||
line_index = entry.lineno - max(entry.getfirstlinesource(), 0)
|
|
||||||
|
|
||||||
lines = []
|
lines = []
|
||||||
style = entry._repr_style
|
style = entry._repr_style
|
||||||
|
@ -733,7 +715,7 @@ class FormattedExcinfo(object):
|
||||||
if self.tbfilter:
|
if self.tbfilter:
|
||||||
traceback = traceback.filter()
|
traceback = traceback.filter()
|
||||||
|
|
||||||
if is_recursion_error(excinfo):
|
if excinfo.errisinstance(RecursionError):
|
||||||
traceback, extraline = self._truncate_recursive_traceback(traceback)
|
traceback, extraline = self._truncate_recursive_traceback(traceback)
|
||||||
else:
|
else:
|
||||||
extraline = None
|
extraline = None
|
||||||
|
@ -769,7 +751,7 @@ class FormattedExcinfo(object):
|
||||||
" Displaying first and last {max_frames} stack frames out of {total}."
|
" Displaying first and last {max_frames} stack frames out of {total}."
|
||||||
).format(
|
).format(
|
||||||
exc_type=type(e).__name__,
|
exc_type=type(e).__name__,
|
||||||
exc_msg=safe_str(e),
|
exc_msg=str(e),
|
||||||
max_frames=max_frames,
|
max_frames=max_frames,
|
||||||
total=len(traceback),
|
total=len(traceback),
|
||||||
)
|
)
|
||||||
|
@ -784,64 +766,51 @@ class FormattedExcinfo(object):
|
||||||
return traceback, extraline
|
return traceback, extraline
|
||||||
|
|
||||||
def repr_excinfo(self, excinfo):
|
def repr_excinfo(self, excinfo):
|
||||||
if _PY2:
|
|
||||||
reprtraceback = self.repr_traceback(excinfo)
|
|
||||||
reprcrash = excinfo._getreprcrash()
|
|
||||||
|
|
||||||
return ReprExceptionInfo(reprtraceback, reprcrash)
|
repr_chain = []
|
||||||
else:
|
e = excinfo.value
|
||||||
repr_chain = []
|
descr = None
|
||||||
e = excinfo.value
|
seen = set()
|
||||||
descr = None
|
while e is not None and id(e) not in seen:
|
||||||
seen = set()
|
seen.add(id(e))
|
||||||
while e is not None and id(e) not in seen:
|
if excinfo:
|
||||||
seen.add(id(e))
|
reprtraceback = self.repr_traceback(excinfo)
|
||||||
if excinfo:
|
reprcrash = excinfo._getreprcrash()
|
||||||
reprtraceback = self.repr_traceback(excinfo)
|
else:
|
||||||
reprcrash = excinfo._getreprcrash()
|
# fallback to native repr if the exception doesn't have a traceback:
|
||||||
else:
|
# ExceptionInfo objects require a full traceback to work
|
||||||
# fallback to native repr if the exception doesn't have a traceback:
|
reprtraceback = ReprTracebackNative(
|
||||||
# ExceptionInfo objects require a full traceback to work
|
traceback.format_exception(type(e), e, None)
|
||||||
reprtraceback = ReprTracebackNative(
|
)
|
||||||
traceback.format_exception(type(e), e, None)
|
reprcrash = None
|
||||||
)
|
|
||||||
reprcrash = None
|
|
||||||
|
|
||||||
repr_chain += [(reprtraceback, reprcrash, descr)]
|
repr_chain += [(reprtraceback, reprcrash, descr)]
|
||||||
if e.__cause__ is not None and self.chain:
|
if e.__cause__ is not None and self.chain:
|
||||||
e = e.__cause__
|
e = e.__cause__
|
||||||
excinfo = (
|
excinfo = (
|
||||||
ExceptionInfo((type(e), e, e.__traceback__))
|
ExceptionInfo((type(e), e, e.__traceback__))
|
||||||
if e.__traceback__
|
if e.__traceback__
|
||||||
else None
|
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 (
|
elif (
|
||||||
e.__context__ is not None
|
e.__context__ is not None and not e.__suppress_context__ and self.chain
|
||||||
and not e.__suppress_context__
|
):
|
||||||
and self.chain
|
e = e.__context__
|
||||||
):
|
excinfo = (
|
||||||
e = e.__context__
|
ExceptionInfo((type(e), e, e.__traceback__))
|
||||||
excinfo = (
|
if e.__traceback__
|
||||||
ExceptionInfo((type(e), e, e.__traceback__))
|
else None
|
||||||
if e.__traceback__
|
)
|
||||||
else None
|
descr = "During handling of the above exception, another exception occurred:"
|
||||||
)
|
else:
|
||||||
descr = "During handling of the above exception, another exception occurred:"
|
e = None
|
||||||
else:
|
repr_chain.reverse()
|
||||||
e = None
|
return ExceptionChainRepr(repr_chain)
|
||||||
repr_chain.reverse()
|
|
||||||
return ExceptionChainRepr(repr_chain)
|
|
||||||
|
|
||||||
|
|
||||||
class TerminalRepr(object):
|
class TerminalRepr(object):
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
s = self.__unicode__()
|
|
||||||
if _PY2:
|
|
||||||
s = s.encode("utf-8")
|
|
||||||
return s
|
|
||||||
|
|
||||||
def __unicode__(self):
|
|
||||||
# FYI this is called from pytest-xdist's serialization of exception
|
# FYI this is called from pytest-xdist's serialization of exception
|
||||||
# information.
|
# information.
|
||||||
io = py.io.TextIO()
|
io = py.io.TextIO()
|
||||||
|
@ -1006,7 +975,7 @@ class ReprFuncArgs(TerminalRepr):
|
||||||
if self.args:
|
if self.args:
|
||||||
linesofar = ""
|
linesofar = ""
|
||||||
for name, value in self.args:
|
for name, value in self.args:
|
||||||
ns = "%s = %s" % (safe_str(name), safe_str(value))
|
ns = "%s = %s" % (name, value)
|
||||||
if len(ns) + len(linesofar) + 2 > tw.fullwidth:
|
if len(ns) + len(linesofar) + 2 > tw.fullwidth:
|
||||||
if linesofar:
|
if linesofar:
|
||||||
tw.line(linesofar)
|
tw.line(linesofar)
|
||||||
|
@ -1038,23 +1007,6 @@ def getrawcode(obj, trycall=True):
|
||||||
return obj
|
return obj
|
||||||
|
|
||||||
|
|
||||||
if PY35: # RecursionError introduced in 3.5
|
|
||||||
|
|
||||||
def is_recursion_error(excinfo):
|
|
||||||
return excinfo.errisinstance(RecursionError) # noqa
|
|
||||||
|
|
||||||
|
|
||||||
else:
|
|
||||||
|
|
||||||
def is_recursion_error(excinfo):
|
|
||||||
if not excinfo.errisinstance(RuntimeError):
|
|
||||||
return False
|
|
||||||
try:
|
|
||||||
return "maximum recursion depth exceeded" in str(excinfo.value)
|
|
||||||
except UnicodeError:
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
# relative paths that we use to filter traceback entries from appearing to the user;
|
# relative paths that we use to filter traceback entries from appearing to the user;
|
||||||
# see filter_traceback
|
# see filter_traceback
|
||||||
# note: if we need to add more paths than what we have now we should probably use a list
|
# note: if we need to add more paths than what we have now we should probably use a list
|
||||||
|
|
|
@ -74,10 +74,6 @@ class AssertionState(object):
|
||||||
|
|
||||||
def install_importhook(config):
|
def install_importhook(config):
|
||||||
"""Try to install the rewrite hook, raise SystemError if it fails."""
|
"""Try to install the rewrite hook, raise SystemError if it fails."""
|
||||||
# Jython has an AST bug that make the assertion rewriting hook malfunction.
|
|
||||||
if sys.platform.startswith("java"):
|
|
||||||
raise SystemError("rewrite not supported")
|
|
||||||
|
|
||||||
config._assertstate = AssertionState(config, "rewrite")
|
config._assertstate = AssertionState(config, "rewrite")
|
||||||
config._assertstate.hook = hook = rewrite.AssertionRewritingHook(config)
|
config._assertstate.hook = hook = rewrite.AssertionRewritingHook(config)
|
||||||
sys.meta_path.insert(0, hook)
|
sys.meta_path.insert(0, hook)
|
||||||
|
|
|
@ -15,6 +15,7 @@ import string
|
||||||
import struct
|
import struct
|
||||||
import sys
|
import sys
|
||||||
import types
|
import types
|
||||||
|
from importlib.util import spec_from_file_location
|
||||||
|
|
||||||
import atomicwrites
|
import atomicwrites
|
||||||
import py
|
import py
|
||||||
|
@ -25,7 +26,6 @@ from _pytest.assertion import util
|
||||||
from _pytest.assertion.util import ( # noqa: F401
|
from _pytest.assertion.util import ( # noqa: F401
|
||||||
format_explanation as _format_explanation,
|
format_explanation as _format_explanation,
|
||||||
)
|
)
|
||||||
from _pytest.compat import spec_from_file_location
|
|
||||||
from _pytest.pathlib import fnmatch_ex
|
from _pytest.pathlib import fnmatch_ex
|
||||||
from _pytest.pathlib import PurePath
|
from _pytest.pathlib import PurePath
|
||||||
|
|
||||||
|
@ -35,8 +35,6 @@ if hasattr(imp, "get_tag"):
|
||||||
else:
|
else:
|
||||||
if hasattr(sys, "pypy_version_info"):
|
if hasattr(sys, "pypy_version_info"):
|
||||||
impl = "pypy"
|
impl = "pypy"
|
||||||
elif sys.platform == "java":
|
|
||||||
impl = "jython"
|
|
||||||
else:
|
else:
|
||||||
impl = "cpython"
|
impl = "cpython"
|
||||||
ver = sys.version_info
|
ver = sys.version_info
|
||||||
|
@ -46,15 +44,6 @@ else:
|
||||||
PYC_EXT = ".py" + (__debug__ and "c" or "o")
|
PYC_EXT = ".py" + (__debug__ and "c" or "o")
|
||||||
PYC_TAIL = "." + PYTEST_TAG + PYC_EXT
|
PYC_TAIL = "." + PYTEST_TAG + PYC_EXT
|
||||||
|
|
||||||
ASCII_IS_DEFAULT_ENCODING = sys.version_info[0] < 3
|
|
||||||
|
|
||||||
if sys.version_info >= (3, 5):
|
|
||||||
ast_Call = ast.Call
|
|
||||||
else:
|
|
||||||
|
|
||||||
def ast_Call(a, b, c):
|
|
||||||
return ast.Call(a, b, c, None, None)
|
|
||||||
|
|
||||||
|
|
||||||
class AssertionRewritingHook(object):
|
class AssertionRewritingHook(object):
|
||||||
"""PEP302 Import hook which rewrites asserts."""
|
"""PEP302 Import hook which rewrites asserts."""
|
||||||
|
@ -364,37 +353,6 @@ def _rewrite_test(config, fn):
|
||||||
source = fn.read("rb")
|
source = fn.read("rb")
|
||||||
except EnvironmentError:
|
except EnvironmentError:
|
||||||
return None, None
|
return None, None
|
||||||
if ASCII_IS_DEFAULT_ENCODING:
|
|
||||||
# ASCII is the default encoding in Python 2. Without a coding
|
|
||||||
# declaration, Python 2 will complain about any bytes in the file
|
|
||||||
# outside the ASCII range. Sadly, this behavior does not extend to
|
|
||||||
# compile() or ast.parse(), which prefer to interpret the bytes as
|
|
||||||
# latin-1. (At least they properly handle explicit coding cookies.) To
|
|
||||||
# preserve this error behavior, we could force ast.parse() to use ASCII
|
|
||||||
# as the encoding by inserting a coding cookie. Unfortunately, that
|
|
||||||
# messes up line numbers. Thus, we have to check ourselves if anything
|
|
||||||
# is outside the ASCII range in the case no encoding is explicitly
|
|
||||||
# declared. For more context, see issue #269. Yay for Python 3 which
|
|
||||||
# gets this right.
|
|
||||||
end1 = source.find("\n")
|
|
||||||
end2 = source.find("\n", end1 + 1)
|
|
||||||
if (
|
|
||||||
not source.startswith(BOM_UTF8)
|
|
||||||
and cookie_re.match(source[0:end1]) is None
|
|
||||||
and cookie_re.match(source[end1 + 1 : end2]) is None
|
|
||||||
):
|
|
||||||
if hasattr(state, "_indecode"):
|
|
||||||
# encodings imported us again, so don't rewrite.
|
|
||||||
return None, None
|
|
||||||
state._indecode = True
|
|
||||||
try:
|
|
||||||
try:
|
|
||||||
source.decode("ascii")
|
|
||||||
except UnicodeDecodeError:
|
|
||||||
# Let it fail in real import.
|
|
||||||
return None, None
|
|
||||||
finally:
|
|
||||||
del state._indecode
|
|
||||||
try:
|
try:
|
||||||
tree = ast.parse(source, filename=fn.strpath)
|
tree = ast.parse(source, filename=fn.strpath)
|
||||||
except SyntaxError:
|
except SyntaxError:
|
||||||
|
@ -737,7 +695,7 @@ class AssertionRewriter(ast.NodeVisitor):
|
||||||
"""Call a helper in this module."""
|
"""Call a helper in this module."""
|
||||||
py_name = ast.Name("@pytest_ar", ast.Load())
|
py_name = ast.Name("@pytest_ar", ast.Load())
|
||||||
attr = ast.Attribute(py_name, name, ast.Load())
|
attr = ast.Attribute(py_name, name, ast.Load())
|
||||||
return ast_Call(attr, list(args), [])
|
return ast.Call(attr, list(args), [])
|
||||||
|
|
||||||
def builtin(self, name):
|
def builtin(self, name):
|
||||||
"""Return the builtin called *name*."""
|
"""Return the builtin called *name*."""
|
||||||
|
@ -847,11 +805,9 @@ class AssertionRewriter(ast.NodeVisitor):
|
||||||
msg = self.pop_format_context(template)
|
msg = self.pop_format_context(template)
|
||||||
fmt = self.helper("_format_explanation", msg)
|
fmt = self.helper("_format_explanation", msg)
|
||||||
err_name = ast.Name("AssertionError", ast.Load())
|
err_name = ast.Name("AssertionError", ast.Load())
|
||||||
exc = ast_Call(err_name, [fmt], [])
|
exc = ast.Call(err_name, [fmt], [])
|
||||||
if sys.version_info[0] >= 3:
|
raise_ = ast.Raise(exc, None)
|
||||||
raise_ = ast.Raise(exc, None)
|
|
||||||
else:
|
|
||||||
raise_ = ast.Raise(exc, None, None)
|
|
||||||
body.append(raise_)
|
body.append(raise_)
|
||||||
# Clear temporary variables by setting them to None.
|
# Clear temporary variables by setting them to None.
|
||||||
if self.variables:
|
if self.variables:
|
||||||
|
@ -893,7 +849,7 @@ warn_explicit(
|
||||||
def visit_Name(self, name):
|
def visit_Name(self, name):
|
||||||
# Display the repr of the name if it's a local variable or
|
# Display the repr of the name if it's a local variable or
|
||||||
# _should_repr_global_name() thinks it's acceptable.
|
# _should_repr_global_name() thinks it's acceptable.
|
||||||
locs = ast_Call(self.builtin("locals"), [], [])
|
locs = ast.Call(self.builtin("locals"), [], [])
|
||||||
inlocs = ast.Compare(ast.Str(name.id), [ast.In()], [locs])
|
inlocs = ast.Compare(ast.Str(name.id), [ast.In()], [locs])
|
||||||
dorepr = self.helper("_should_repr_global_name", name)
|
dorepr = self.helper("_should_repr_global_name", name)
|
||||||
test = ast.BoolOp(ast.Or(), [inlocs, dorepr])
|
test = ast.BoolOp(ast.Or(), [inlocs, dorepr])
|
||||||
|
@ -920,7 +876,7 @@ warn_explicit(
|
||||||
res, expl = self.visit(v)
|
res, expl = self.visit(v)
|
||||||
body.append(ast.Assign([ast.Name(res_var, ast.Store())], res))
|
body.append(ast.Assign([ast.Name(res_var, ast.Store())], res))
|
||||||
expl_format = self.pop_format_context(ast.Str(expl))
|
expl_format = self.pop_format_context(ast.Str(expl))
|
||||||
call = ast_Call(app, [expl_format], [])
|
call = ast.Call(app, [expl_format], [])
|
||||||
self.on_failure.append(ast.Expr(call))
|
self.on_failure.append(ast.Expr(call))
|
||||||
if i < levels:
|
if i < levels:
|
||||||
cond = res
|
cond = res
|
||||||
|
@ -959,9 +915,9 @@ warn_explicit(
|
||||||
and isinstance(call.args[0], (ast.GeneratorExp, ast.ListComp))
|
and isinstance(call.args[0], (ast.GeneratorExp, ast.ListComp))
|
||||||
)
|
)
|
||||||
|
|
||||||
def visit_Call_35(self, call):
|
def visit_Call(self, call):
|
||||||
"""
|
"""
|
||||||
visit `ast.Call` nodes on Python3.5 and after
|
visit `ast.Call` nodes
|
||||||
"""
|
"""
|
||||||
if self._is_any_call_with_generator_or_list_comprehension(call):
|
if self._is_any_call_with_generator_or_list_comprehension(call):
|
||||||
return self._visit_all(call)
|
return self._visit_all(call)
|
||||||
|
@ -1013,46 +969,6 @@ warn_explicit(
|
||||||
new_starred = ast.Starred(res, starred.ctx)
|
new_starred = ast.Starred(res, starred.ctx)
|
||||||
return new_starred, "*" + expl
|
return new_starred, "*" + expl
|
||||||
|
|
||||||
def visit_Call_legacy(self, call):
|
|
||||||
"""
|
|
||||||
visit `ast.Call nodes on 3.4 and below`
|
|
||||||
"""
|
|
||||||
if self._is_any_call_with_generator_or_list_comprehension(call):
|
|
||||||
return self._visit_all(call)
|
|
||||||
new_func, func_expl = self.visit(call.func)
|
|
||||||
arg_expls = []
|
|
||||||
new_args = []
|
|
||||||
new_kwargs = []
|
|
||||||
new_star = new_kwarg = None
|
|
||||||
for arg in call.args:
|
|
||||||
res, expl = self.visit(arg)
|
|
||||||
new_args.append(res)
|
|
||||||
arg_expls.append(expl)
|
|
||||||
for keyword in call.keywords:
|
|
||||||
res, expl = self.visit(keyword.value)
|
|
||||||
new_kwargs.append(ast.keyword(keyword.arg, res))
|
|
||||||
arg_expls.append(keyword.arg + "=" + expl)
|
|
||||||
if call.starargs:
|
|
||||||
new_star, expl = self.visit(call.starargs)
|
|
||||||
arg_expls.append("*" + expl)
|
|
||||||
if call.kwargs:
|
|
||||||
new_kwarg, expl = self.visit(call.kwargs)
|
|
||||||
arg_expls.append("**" + expl)
|
|
||||||
expl = "%s(%s)" % (func_expl, ", ".join(arg_expls))
|
|
||||||
new_call = ast.Call(new_func, new_args, new_kwargs, new_star, new_kwarg)
|
|
||||||
res = self.assign(new_call)
|
|
||||||
res_expl = self.explanation_param(self.display(res))
|
|
||||||
outer_expl = "%s\n{%s = %s\n}" % (res_expl, res_expl, expl)
|
|
||||||
return res, outer_expl
|
|
||||||
|
|
||||||
# ast.Call signature changed on 3.5,
|
|
||||||
# conditionally change which methods is named
|
|
||||||
# visit_Call depending on Python version
|
|
||||||
if sys.version_info >= (3, 5):
|
|
||||||
visit_Call = visit_Call_35
|
|
||||||
else:
|
|
||||||
visit_Call = visit_Call_legacy
|
|
||||||
|
|
||||||
def visit_Attribute(self, attr):
|
def visit_Attribute(self, attr):
|
||||||
if not isinstance(attr.ctx, ast.Load):
|
if not isinstance(attr.ctx, ast.Load):
|
||||||
return self.generic_visit(attr)
|
return self.generic_visit(attr)
|
||||||
|
|
|
@ -5,11 +5,11 @@ from __future__ import division
|
||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
|
|
||||||
import pprint
|
import pprint
|
||||||
|
from collections.abc import Sequence
|
||||||
|
|
||||||
import six
|
import six
|
||||||
|
|
||||||
import _pytest._code
|
import _pytest._code
|
||||||
from ..compat import Sequence
|
|
||||||
from _pytest import outcomes
|
from _pytest import outcomes
|
||||||
from _pytest._io.saferepr import saferepr
|
from _pytest._io.saferepr import saferepr
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,6 @@ import py
|
||||||
import six
|
import six
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from .compat import _PY2 as PY2
|
|
||||||
from .pathlib import Path
|
from .pathlib import Path
|
||||||
from .pathlib import resolve_from_str
|
from .pathlib import resolve_from_str
|
||||||
from .pathlib import rmtree
|
from .pathlib import rmtree
|
||||||
|
@ -129,7 +128,7 @@ class Cache(object):
|
||||||
if not cache_dir_exists_already:
|
if not cache_dir_exists_already:
|
||||||
self._ensure_supporting_files()
|
self._ensure_supporting_files()
|
||||||
try:
|
try:
|
||||||
f = path.open("wb" if PY2 else "w")
|
f = path.open("w")
|
||||||
except (IOError, OSError):
|
except (IOError, OSError):
|
||||||
self.warn("cache could not write path {path}", path=path)
|
self.warn("cache could not write path {path}", path=path)
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -18,7 +18,6 @@ from tempfile import TemporaryFile
|
||||||
import six
|
import six
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from _pytest.compat import _PY3
|
|
||||||
from _pytest.compat import CaptureIO
|
from _pytest.compat import CaptureIO
|
||||||
|
|
||||||
patchsysdict = {0: "stdin", 1: "stdout", 2: "stderr"}
|
patchsysdict = {0: "stdin", 1: "stdout", 2: "stderr"}
|
||||||
|
@ -283,10 +282,6 @@ def capsysbinary(request):
|
||||||
``out`` and ``err`` will be ``bytes`` objects.
|
``out`` and ``err`` will be ``bytes`` objects.
|
||||||
"""
|
"""
|
||||||
_ensure_only_one_capture_fixture(request, "capsysbinary")
|
_ensure_only_one_capture_fixture(request, "capsysbinary")
|
||||||
# Currently, the implementation uses the python3 specific `.buffer`
|
|
||||||
# property of CaptureIO.
|
|
||||||
if sys.version_info < (3,):
|
|
||||||
raise request.raiseerror("capsysbinary is only supported on Python 3")
|
|
||||||
with _install_capture_fixture_on_item(request, SysCaptureBinary) as fixture:
|
with _install_capture_fixture_on_item(request, SysCaptureBinary) as fixture:
|
||||||
yield fixture
|
yield fixture
|
||||||
|
|
||||||
|
@ -434,7 +429,7 @@ class EncodedFile(object):
|
||||||
def write(self, obj):
|
def write(self, obj):
|
||||||
if isinstance(obj, six.text_type):
|
if isinstance(obj, six.text_type):
|
||||||
obj = obj.encode(self.encoding, "replace")
|
obj = obj.encode(self.encoding, "replace")
|
||||||
elif _PY3:
|
else:
|
||||||
raise TypeError(
|
raise TypeError(
|
||||||
"write() argument must be str, not {}".format(type(obj).__name__)
|
"write() argument must be str, not {}".format(type(obj).__name__)
|
||||||
)
|
)
|
||||||
|
@ -608,7 +603,7 @@ class FDCaptureBinary(object):
|
||||||
os.dup2(targetfd_save, self.targetfd)
|
os.dup2(targetfd_save, self.targetfd)
|
||||||
os.close(targetfd_save)
|
os.close(targetfd_save)
|
||||||
self.syscapture.done()
|
self.syscapture.done()
|
||||||
_attempt_to_close_capture_file(self.tmpfile)
|
self.tmpfile.close()
|
||||||
self._state = "done"
|
self._state = "done"
|
||||||
|
|
||||||
def suspend(self):
|
def suspend(self):
|
||||||
|
@ -681,7 +676,7 @@ class SysCapture(object):
|
||||||
def done(self):
|
def done(self):
|
||||||
setattr(sys, self.name, self._old)
|
setattr(sys, self.name, self._old)
|
||||||
del self._old
|
del self._old
|
||||||
_attempt_to_close_capture_file(self.tmpfile)
|
self.tmpfile.close()
|
||||||
self._state = "done"
|
self._state = "done"
|
||||||
|
|
||||||
def suspend(self):
|
def suspend(self):
|
||||||
|
@ -738,10 +733,7 @@ class DontReadFromInput(six.Iterator):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def buffer(self):
|
def buffer(self):
|
||||||
if sys.version_info >= (3, 0):
|
return self
|
||||||
return self
|
|
||||||
else:
|
|
||||||
raise AttributeError("redirected stdin has no attribute buffer")
|
|
||||||
|
|
||||||
|
|
||||||
def _colorama_workaround():
|
def _colorama_workaround():
|
||||||
|
@ -837,14 +829,3 @@ def _py36_windowsconsoleio_workaround(stream):
|
||||||
sys.stdin = _reopen_stdio(sys.stdin, "rb")
|
sys.stdin = _reopen_stdio(sys.stdin, "rb")
|
||||||
sys.stdout = _reopen_stdio(sys.stdout, "wb")
|
sys.stdout = _reopen_stdio(sys.stdout, "wb")
|
||||||
sys.stderr = _reopen_stdio(sys.stderr, "wb")
|
sys.stderr = _reopen_stdio(sys.stderr, "wb")
|
||||||
|
|
||||||
|
|
||||||
def _attempt_to_close_capture_file(f):
|
|
||||||
"""Suppress IOError when closing the temporary file used for capturing streams in py27 (#2370)"""
|
|
||||||
if six.PY2:
|
|
||||||
try:
|
|
||||||
f.close()
|
|
||||||
except IOError:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
f.close()
|
|
||||||
|
|
|
@ -6,59 +6,28 @@ from __future__ import absolute_import
|
||||||
from __future__ import division
|
from __future__ import division
|
||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
|
|
||||||
import codecs
|
|
||||||
import functools
|
import functools
|
||||||
import inspect
|
import inspect
|
||||||
|
import io
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
from contextlib import contextmanager
|
from contextlib import contextmanager
|
||||||
|
from inspect import Parameter
|
||||||
|
from inspect import signature
|
||||||
|
|
||||||
import py
|
import py
|
||||||
import six
|
|
||||||
from six import text_type
|
|
||||||
|
|
||||||
import _pytest
|
import _pytest
|
||||||
from _pytest._io.saferepr import saferepr
|
from _pytest._io.saferepr import saferepr
|
||||||
from _pytest.outcomes import fail
|
from _pytest.outcomes import fail
|
||||||
from _pytest.outcomes import TEST_OUTCOME
|
from _pytest.outcomes import TEST_OUTCOME
|
||||||
|
|
||||||
try:
|
|
||||||
import enum
|
|
||||||
except ImportError: # pragma: no cover
|
|
||||||
# Only available in Python 3.4+ or as a backport
|
|
||||||
enum = None
|
|
||||||
|
|
||||||
_PY3 = sys.version_info > (3, 0)
|
|
||||||
_PY2 = not _PY3
|
|
||||||
|
|
||||||
|
|
||||||
if _PY3:
|
|
||||||
from inspect import signature, Parameter as Parameter
|
|
||||||
else:
|
|
||||||
from funcsigs import signature, Parameter as Parameter
|
|
||||||
|
|
||||||
NOTSET = object()
|
NOTSET = object()
|
||||||
|
|
||||||
PY35 = sys.version_info[:2] >= (3, 5)
|
MODULE_NOT_FOUND_ERROR = (
|
||||||
PY36 = sys.version_info[:2] >= (3, 6)
|
"ModuleNotFoundError" if sys.version_info[:2] >= (3, 6) else "ImportError"
|
||||||
MODULE_NOT_FOUND_ERROR = "ModuleNotFoundError" if PY36 else "ImportError"
|
)
|
||||||
|
|
||||||
|
|
||||||
if _PY3:
|
|
||||||
from collections.abc import MutableMapping as MappingMixin
|
|
||||||
from collections.abc import Iterable, Mapping, Sequence, Sized
|
|
||||||
else:
|
|
||||||
# those raise DeprecationWarnings in Python >=3.7
|
|
||||||
from collections import MutableMapping as MappingMixin # noqa
|
|
||||||
from collections import Iterable, Mapping, Sequence, Sized # noqa
|
|
||||||
|
|
||||||
|
|
||||||
if sys.version_info >= (3, 4):
|
|
||||||
from importlib.util import spec_from_file_location
|
|
||||||
else:
|
|
||||||
|
|
||||||
def spec_from_file_location(*_, **__):
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def _format_args(func):
|
def _format_args(func):
|
||||||
|
@ -195,72 +164,36 @@ def _translate_non_printable(s):
|
||||||
return s.translate(_non_printable_ascii_translate_table)
|
return s.translate(_non_printable_ascii_translate_table)
|
||||||
|
|
||||||
|
|
||||||
if _PY3:
|
STRING_TYPES = bytes, str
|
||||||
STRING_TYPES = bytes, str
|
|
||||||
UNICODE_TYPES = six.text_type
|
|
||||||
|
|
||||||
if PY35:
|
|
||||||
|
|
||||||
def _bytes_to_ascii(val):
|
def _bytes_to_ascii(val):
|
||||||
return val.decode("ascii", "backslashreplace")
|
return val.decode("ascii", "backslashreplace")
|
||||||
|
|
||||||
|
|
||||||
|
def ascii_escaped(val):
|
||||||
|
"""If val is pure ascii, returns it as a str(). Otherwise, escapes
|
||||||
|
bytes objects into a sequence of escaped bytes:
|
||||||
|
|
||||||
|
b'\xc3\xb4\xc5\xd6' -> u'\\xc3\\xb4\\xc5\\xd6'
|
||||||
|
|
||||||
|
and escapes unicode objects into a sequence of escaped unicode
|
||||||
|
ids, e.g.:
|
||||||
|
|
||||||
|
'4\\nV\\U00043efa\\x0eMXWB\\x1e\\u3028\\u15fd\\xcd\\U0007d944'
|
||||||
|
|
||||||
|
note:
|
||||||
|
the obvious "v.decode('unicode-escape')" will return
|
||||||
|
valid utf-8 unicode if it finds them in bytes, but we
|
||||||
|
want to return escaped bytes for any byte, even if they match
|
||||||
|
a utf-8 string.
|
||||||
|
|
||||||
|
"""
|
||||||
|
if isinstance(val, bytes):
|
||||||
|
ret = _bytes_to_ascii(val)
|
||||||
else:
|
else:
|
||||||
|
ret = val.encode("unicode_escape").decode("ascii")
|
||||||
def _bytes_to_ascii(val):
|
return _translate_non_printable(ret)
|
||||||
if val:
|
|
||||||
# source: http://goo.gl/bGsnwC
|
|
||||||
encoded_bytes, _ = codecs.escape_encode(val)
|
|
||||||
return encoded_bytes.decode("ascii")
|
|
||||||
else:
|
|
||||||
# empty bytes crashes codecs.escape_encode (#1087)
|
|
||||||
return ""
|
|
||||||
|
|
||||||
def ascii_escaped(val):
|
|
||||||
"""If val is pure ascii, returns it as a str(). Otherwise, escapes
|
|
||||||
bytes objects into a sequence of escaped bytes:
|
|
||||||
|
|
||||||
b'\xc3\xb4\xc5\xd6' -> u'\\xc3\\xb4\\xc5\\xd6'
|
|
||||||
|
|
||||||
and escapes unicode objects into a sequence of escaped unicode
|
|
||||||
ids, e.g.:
|
|
||||||
|
|
||||||
'4\\nV\\U00043efa\\x0eMXWB\\x1e\\u3028\\u15fd\\xcd\\U0007d944'
|
|
||||||
|
|
||||||
note:
|
|
||||||
the obvious "v.decode('unicode-escape')" will return
|
|
||||||
valid utf-8 unicode if it finds them in bytes, but we
|
|
||||||
want to return escaped bytes for any byte, even if they match
|
|
||||||
a utf-8 string.
|
|
||||||
|
|
||||||
"""
|
|
||||||
if isinstance(val, bytes):
|
|
||||||
ret = _bytes_to_ascii(val)
|
|
||||||
else:
|
|
||||||
ret = val.encode("unicode_escape").decode("ascii")
|
|
||||||
return _translate_non_printable(ret)
|
|
||||||
|
|
||||||
|
|
||||||
else:
|
|
||||||
STRING_TYPES = six.string_types
|
|
||||||
UNICODE_TYPES = six.text_type
|
|
||||||
|
|
||||||
def ascii_escaped(val):
|
|
||||||
"""In py2 bytes and str are the same type, so return if it's a bytes
|
|
||||||
object, return it unchanged if it is a full ascii string,
|
|
||||||
otherwise escape it into its binary form.
|
|
||||||
|
|
||||||
If it's a unicode string, change the unicode characters into
|
|
||||||
unicode escapes.
|
|
||||||
|
|
||||||
"""
|
|
||||||
if isinstance(val, bytes):
|
|
||||||
try:
|
|
||||||
ret = val.decode("ascii")
|
|
||||||
except UnicodeDecodeError:
|
|
||||||
ret = val.encode("string-escape").decode("ascii")
|
|
||||||
else:
|
|
||||||
ret = val.encode("unicode-escape").decode("ascii")
|
|
||||||
return _translate_non_printable(ret)
|
|
||||||
|
|
||||||
|
|
||||||
class _PytestWrapper(object):
|
class _PytestWrapper(object):
|
||||||
|
@ -357,36 +290,6 @@ def safe_isclass(obj):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def _is_unittest_unexpected_success_a_failure():
|
|
||||||
"""Return if the test suite should fail if an @expectedFailure unittest test PASSES.
|
|
||||||
|
|
||||||
From https://docs.python.org/3/library/unittest.html?highlight=unittest#unittest.TestResult.wasSuccessful:
|
|
||||||
Changed in version 3.4: Returns False if there were any
|
|
||||||
unexpectedSuccesses from tests marked with the expectedFailure() decorator.
|
|
||||||
"""
|
|
||||||
return sys.version_info >= (3, 4)
|
|
||||||
|
|
||||||
|
|
||||||
if _PY3:
|
|
||||||
|
|
||||||
def safe_str(v):
|
|
||||||
"""returns v as string"""
|
|
||||||
return str(v)
|
|
||||||
|
|
||||||
|
|
||||||
else:
|
|
||||||
|
|
||||||
def safe_str(v):
|
|
||||||
"""returns v as string, converting to ascii if necessary"""
|
|
||||||
try:
|
|
||||||
return str(v)
|
|
||||||
except UnicodeError:
|
|
||||||
if not isinstance(v, text_type):
|
|
||||||
v = text_type(v)
|
|
||||||
errors = "replace"
|
|
||||||
return v.encode("utf-8", errors)
|
|
||||||
|
|
||||||
|
|
||||||
COLLECT_FAKEMODULE_ATTRIBUTES = (
|
COLLECT_FAKEMODULE_ATTRIBUTES = (
|
||||||
"Collector",
|
"Collector",
|
||||||
"Module",
|
"Module",
|
||||||
|
@ -410,27 +313,14 @@ def _setup_collect_fakemodule():
|
||||||
setattr(pytest.collect, attr, getattr(pytest, attr))
|
setattr(pytest.collect, attr, getattr(pytest, attr))
|
||||||
|
|
||||||
|
|
||||||
if _PY2:
|
class CaptureIO(io.TextIOWrapper):
|
||||||
# Without this the test_dupfile_on_textio will fail, otherwise CaptureIO could directly inherit from StringIO.
|
def __init__(self):
|
||||||
from py.io import TextIO
|
super(CaptureIO, self).__init__(
|
||||||
|
io.BytesIO(), encoding="UTF-8", newline="", write_through=True
|
||||||
|
)
|
||||||
|
|
||||||
class CaptureIO(TextIO):
|
def getvalue(self):
|
||||||
@property
|
return self.buffer.getvalue().decode("UTF-8")
|
||||||
def encoding(self):
|
|
||||||
return getattr(self, "_encoding", "UTF-8")
|
|
||||||
|
|
||||||
|
|
||||||
else:
|
|
||||||
import io
|
|
||||||
|
|
||||||
class CaptureIO(io.TextIOWrapper):
|
|
||||||
def __init__(self):
|
|
||||||
super(CaptureIO, self).__init__(
|
|
||||||
io.BytesIO(), encoding="UTF-8", newline="", write_through=True
|
|
||||||
)
|
|
||||||
|
|
||||||
def getvalue(self):
|
|
||||||
return self.buffer.getvalue().decode("UTF-8")
|
|
||||||
|
|
||||||
|
|
||||||
class FuncargnamesCompatAttr(object):
|
class FuncargnamesCompatAttr(object):
|
||||||
|
@ -442,16 +332,3 @@ class FuncargnamesCompatAttr(object):
|
||||||
def funcargnames(self):
|
def funcargnames(self):
|
||||||
""" alias attribute for ``fixturenames`` for pre-2.3 compatibility"""
|
""" alias attribute for ``fixturenames`` for pre-2.3 compatibility"""
|
||||||
return self.fixturenames
|
return self.fixturenames
|
||||||
|
|
||||||
|
|
||||||
if six.PY2:
|
|
||||||
|
|
||||||
def lru_cache(*_, **__):
|
|
||||||
def dec(fn):
|
|
||||||
return fn
|
|
||||||
|
|
||||||
return dec
|
|
||||||
|
|
||||||
|
|
||||||
else:
|
|
||||||
from functools import lru_cache # noqa: F401
|
|
||||||
|
|
|
@ -12,6 +12,7 @@ import shlex
|
||||||
import sys
|
import sys
|
||||||
import types
|
import types
|
||||||
import warnings
|
import warnings
|
||||||
|
from functools import lru_cache
|
||||||
|
|
||||||
import importlib_metadata
|
import importlib_metadata
|
||||||
import py
|
import py
|
||||||
|
@ -31,8 +32,6 @@ from .findpaths import exists
|
||||||
from _pytest import deprecated
|
from _pytest import deprecated
|
||||||
from _pytest._code import ExceptionInfo
|
from _pytest._code import ExceptionInfo
|
||||||
from _pytest._code import filter_traceback
|
from _pytest._code import filter_traceback
|
||||||
from _pytest.compat import lru_cache
|
|
||||||
from _pytest.compat import safe_str
|
|
||||||
from _pytest.outcomes import fail
|
from _pytest.outcomes import fail
|
||||||
from _pytest.outcomes import Skipped
|
from _pytest.outcomes import Skipped
|
||||||
from _pytest.warning_types import PytestConfigWarning
|
from _pytest.warning_types import PytestConfigWarning
|
||||||
|
@ -73,7 +72,7 @@ def main(args=None, plugins=None):
|
||||||
if exc_info.traceback
|
if exc_info.traceback
|
||||||
else exc_info.exconly()
|
else exc_info.exconly()
|
||||||
)
|
)
|
||||||
formatted_tb = safe_str(exc_repr)
|
formatted_tb = str(exc_repr)
|
||||||
for line in formatted_tb.splitlines():
|
for line in formatted_tb.splitlines():
|
||||||
tw.line(line.rstrip(), red=True)
|
tw.line(line.rstrip(), red=True)
|
||||||
return 4
|
return 4
|
||||||
|
@ -403,12 +402,6 @@ class PytestPluginManager(PluginManager):
|
||||||
else:
|
else:
|
||||||
directory = path
|
directory = path
|
||||||
|
|
||||||
if six.PY2: # py2 is not using lru_cache.
|
|
||||||
try:
|
|
||||||
return self._dirpath2confmods[directory]
|
|
||||||
except KeyError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
# XXX these days we may rather want to use config.rootdir
|
# XXX these days we may rather want to use config.rootdir
|
||||||
# and allow users to opt into looking into the rootdir parent
|
# and allow users to opt into looking into the rootdir parent
|
||||||
# directories instead of requiring to specify confcutdir
|
# directories instead of requiring to specify confcutdir
|
||||||
|
@ -566,7 +559,7 @@ class PytestPluginManager(PluginManager):
|
||||||
except ImportError as e:
|
except ImportError as e:
|
||||||
new_exc_message = 'Error importing plugin "%s": %s' % (
|
new_exc_message = 'Error importing plugin "%s": %s' % (
|
||||||
modname,
|
modname,
|
||||||
safe_str(e.args[0]),
|
str(e.args[0]),
|
||||||
)
|
)
|
||||||
new_exc = ImportError(new_exc_message)
|
new_exc = ImportError(new_exc_message)
|
||||||
tb = sys.exc_info()[2]
|
tb = sys.exc_info()[2]
|
||||||
|
|
|
@ -333,7 +333,6 @@ class DoctestTextfile(pytest.Module):
|
||||||
checker=_get_checker(),
|
checker=_get_checker(),
|
||||||
continue_on_failure=_get_continue_on_failure(self.config),
|
continue_on_failure=_get_continue_on_failure(self.config),
|
||||||
)
|
)
|
||||||
_fix_spoof_python2(runner, encoding)
|
|
||||||
|
|
||||||
parser = doctest.DocTestParser()
|
parser = doctest.DocTestParser()
|
||||||
test = parser.get_doctest(text, globs, name, filename, 0)
|
test = parser.get_doctest(text, globs, name, filename, 0)
|
||||||
|
@ -539,32 +538,6 @@ def _get_report_choice(key):
|
||||||
}[key]
|
}[key]
|
||||||
|
|
||||||
|
|
||||||
def _fix_spoof_python2(runner, encoding):
|
|
||||||
"""
|
|
||||||
Installs a "SpoofOut" into the given DebugRunner so it properly deals with unicode output. This
|
|
||||||
should patch only doctests for text files because they don't have a way to declare their
|
|
||||||
encoding. Doctests in docstrings from Python modules don't have the same problem given that
|
|
||||||
Python already decoded the strings.
|
|
||||||
|
|
||||||
This fixes the problem related in issue #2434.
|
|
||||||
"""
|
|
||||||
from _pytest.compat import _PY2
|
|
||||||
|
|
||||||
if not _PY2:
|
|
||||||
return
|
|
||||||
|
|
||||||
from doctest import _SpoofOut
|
|
||||||
|
|
||||||
class UnicodeSpoof(_SpoofOut):
|
|
||||||
def getvalue(self):
|
|
||||||
result = _SpoofOut.getvalue(self)
|
|
||||||
if encoding and isinstance(result, bytes):
|
|
||||||
result = result.decode(encoding)
|
|
||||||
return result
|
|
||||||
|
|
||||||
runner._fakeout = UnicodeSpoof()
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="session")
|
@pytest.fixture(scope="session")
|
||||||
def doctest_namespace():
|
def doctest_namespace():
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -1303,11 +1303,7 @@ class FixtureManager(object):
|
||||||
# during fixture definition we wrap the original fixture function
|
# during fixture definition we wrap the original fixture function
|
||||||
# to issue a warning if called directly, so here we unwrap it in order to not emit the warning
|
# to issue a warning if called directly, so here we unwrap it in order to not emit the warning
|
||||||
# when pytest itself calls the fixture function
|
# when pytest itself calls the fixture function
|
||||||
if six.PY2 and unittest:
|
obj = get_real_method(obj, holderobj)
|
||||||
# hack on Python 2 because of the unbound methods
|
|
||||||
obj = get_real_func(obj)
|
|
||||||
else:
|
|
||||||
obj = get_real_method(obj, holderobj)
|
|
||||||
|
|
||||||
fixture_def = FixtureDef(
|
fixture_def = FixtureDef(
|
||||||
self,
|
self,
|
||||||
|
|
|
@ -26,10 +26,6 @@ import pytest
|
||||||
from _pytest import nodes
|
from _pytest import nodes
|
||||||
from _pytest.config import filename_arg
|
from _pytest.config import filename_arg
|
||||||
|
|
||||||
# Python 2.X and 3.X compatibility
|
|
||||||
if sys.version_info[0] < 3:
|
|
||||||
from codecs import open
|
|
||||||
|
|
||||||
|
|
||||||
class Junit(py.xml.Namespace):
|
class Junit(py.xml.Namespace):
|
||||||
pass
|
pass
|
||||||
|
|
|
@ -43,10 +43,7 @@ class ColoredLevelFormatter(logging.Formatter):
|
||||||
|
|
||||||
def __init__(self, terminalwriter, *args, **kwargs):
|
def __init__(self, terminalwriter, *args, **kwargs):
|
||||||
super(ColoredLevelFormatter, self).__init__(*args, **kwargs)
|
super(ColoredLevelFormatter, self).__init__(*args, **kwargs)
|
||||||
if six.PY2:
|
self._original_fmt = self._style._fmt
|
||||||
self._original_fmt = self._fmt
|
|
||||||
else:
|
|
||||||
self._original_fmt = self._style._fmt
|
|
||||||
self._level_to_fmt_mapping = {}
|
self._level_to_fmt_mapping = {}
|
||||||
|
|
||||||
levelname_fmt_match = self.LEVELNAME_FMT_REGEX.search(self._fmt)
|
levelname_fmt_match = self.LEVELNAME_FMT_REGEX.search(self._fmt)
|
||||||
|
@ -70,10 +67,7 @@ class ColoredLevelFormatter(logging.Formatter):
|
||||||
|
|
||||||
def format(self, record):
|
def format(self, record):
|
||||||
fmt = self._level_to_fmt_mapping.get(record.levelno, self._original_fmt)
|
fmt = self._level_to_fmt_mapping.get(record.levelno, self._original_fmt)
|
||||||
if six.PY2:
|
self._style._fmt = fmt
|
||||||
self._fmt = fmt
|
|
||||||
else:
|
|
||||||
self._style._fmt = fmt
|
|
||||||
return super(ColoredLevelFormatter, self).format(record)
|
return super(ColoredLevelFormatter, self).format(record)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,6 @@ from __future__ import absolute_import
|
||||||
from __future__ import division
|
from __future__ import division
|
||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
|
|
||||||
import contextlib
|
|
||||||
import fnmatch
|
import fnmatch
|
||||||
import functools
|
import functools
|
||||||
import os
|
import os
|
||||||
|
@ -342,46 +341,6 @@ def pytest_collection_modifyitems(items, config):
|
||||||
items[:] = remaining
|
items[:] = remaining
|
||||||
|
|
||||||
|
|
||||||
@contextlib.contextmanager
|
|
||||||
def _patched_find_module():
|
|
||||||
"""Patch bug in pkgutil.ImpImporter.find_module
|
|
||||||
|
|
||||||
When using pkgutil.find_loader on python<3.4 it removes symlinks
|
|
||||||
from the path due to a call to os.path.realpath. This is not consistent
|
|
||||||
with actually doing the import (in these versions, pkgutil and __import__
|
|
||||||
did not share the same underlying code). This can break conftest
|
|
||||||
discovery for pytest where symlinks are involved.
|
|
||||||
|
|
||||||
The only supported python<3.4 by pytest is python 2.7.
|
|
||||||
"""
|
|
||||||
if six.PY2: # python 3.4+ uses importlib instead
|
|
||||||
|
|
||||||
def find_module_patched(self, fullname, path=None):
|
|
||||||
# Note: we ignore 'path' argument since it is only used via meta_path
|
|
||||||
subname = fullname.split(".")[-1]
|
|
||||||
if subname != fullname and self.path is None:
|
|
||||||
return None
|
|
||||||
if self.path is None:
|
|
||||||
path = None
|
|
||||||
else:
|
|
||||||
# original: path = [os.path.realpath(self.path)]
|
|
||||||
path = [self.path]
|
|
||||||
try:
|
|
||||||
file, filename, etc = pkgutil.imp.find_module(subname, path)
|
|
||||||
except ImportError:
|
|
||||||
return None
|
|
||||||
return pkgutil.ImpLoader(fullname, file, filename, etc)
|
|
||||||
|
|
||||||
old_find_module = pkgutil.ImpImporter.find_module
|
|
||||||
pkgutil.ImpImporter.find_module = find_module_patched
|
|
||||||
try:
|
|
||||||
yield
|
|
||||||
finally:
|
|
||||||
pkgutil.ImpImporter.find_module = old_find_module
|
|
||||||
else:
|
|
||||||
yield
|
|
||||||
|
|
||||||
|
|
||||||
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
|
||||||
|
@ -662,23 +621,14 @@ class Session(nodes.FSCollector):
|
||||||
ihook.pytest_collect_directory(path=dirpath, parent=self)
|
ihook.pytest_collect_directory(path=dirpath, parent=self)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
if six.PY2:
|
@staticmethod
|
||||||
|
def _visit_filter(f):
|
||||||
@staticmethod
|
return f.check(file=1)
|
||||||
def _visit_filter(f):
|
|
||||||
return f.check(file=1) and not f.strpath.endswith("*.pyc")
|
|
||||||
|
|
||||||
else:
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _visit_filter(f):
|
|
||||||
return f.check(file=1)
|
|
||||||
|
|
||||||
def _tryconvertpyarg(self, x):
|
def _tryconvertpyarg(self, x):
|
||||||
"""Convert a dotted module name to path."""
|
"""Convert a dotted module name to path."""
|
||||||
try:
|
try:
|
||||||
with _patched_find_module():
|
loader = pkgutil.find_loader(x)
|
||||||
loader = pkgutil.find_loader(x)
|
|
||||||
except ImportError:
|
except ImportError:
|
||||||
return x
|
return x
|
||||||
if loader is None:
|
if loader is None:
|
||||||
|
@ -686,8 +636,7 @@ class Session(nodes.FSCollector):
|
||||||
# This method is sometimes invoked when AssertionRewritingHook, which
|
# This method is sometimes invoked when AssertionRewritingHook, which
|
||||||
# does not define a get_filename method, is already in place:
|
# does not define a get_filename method, is already in place:
|
||||||
try:
|
try:
|
||||||
with _patched_find_module():
|
path = loader.get_filename(x)
|
||||||
path = loader.get_filename(x)
|
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
# Retrieve path from AssertionRewritingHook:
|
# Retrieve path from AssertionRewritingHook:
|
||||||
path = loader.modules[x][0].co_filename
|
path = loader.modules[x][0].co_filename
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
import inspect
|
import inspect
|
||||||
import warnings
|
import warnings
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
|
from collections.abc import MutableMapping
|
||||||
from operator import attrgetter
|
from operator import attrgetter
|
||||||
|
|
||||||
import attr
|
import attr
|
||||||
|
@ -9,7 +10,6 @@ import six
|
||||||
|
|
||||||
from ..compat import ascii_escaped
|
from ..compat import ascii_escaped
|
||||||
from ..compat import getfslineno
|
from ..compat import getfslineno
|
||||||
from ..compat import MappingMixin
|
|
||||||
from ..compat import NOTSET
|
from ..compat import NOTSET
|
||||||
from _pytest.deprecated import PYTEST_PARAM_UNKNOWN_KWARGS
|
from _pytest.deprecated import PYTEST_PARAM_UNKNOWN_KWARGS
|
||||||
from _pytest.outcomes import fail
|
from _pytest.outcomes import fail
|
||||||
|
@ -343,7 +343,7 @@ class MarkGenerator(object):
|
||||||
MARK_GEN = MarkGenerator()
|
MARK_GEN = MarkGenerator()
|
||||||
|
|
||||||
|
|
||||||
class NodeKeywords(MappingMixin):
|
class NodeKeywords(MutableMapping):
|
||||||
def __init__(self, node):
|
def __init__(self, node):
|
||||||
self.node = node
|
self.node = node
|
||||||
self.parent = node.parent
|
self.parent = node.parent
|
||||||
|
|
|
@ -222,15 +222,6 @@ class MonkeyPatch(object):
|
||||||
self._setitem.append((dic, name, dic.get(name, notset)))
|
self._setitem.append((dic, name, dic.get(name, notset)))
|
||||||
del dic[name]
|
del dic[name]
|
||||||
|
|
||||||
def _warn_if_env_name_is_not_str(self, name):
|
|
||||||
"""On Python 2, warn if the given environment variable name is not a native str (#4056)"""
|
|
||||||
if six.PY2 and not isinstance(name, str):
|
|
||||||
warnings.warn(
|
|
||||||
pytest.PytestWarning(
|
|
||||||
"Environment variable name {!r} should be str".format(name)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
def setenv(self, name, value, prepend=None):
|
def setenv(self, name, value, prepend=None):
|
||||||
""" Set environment variable ``name`` to ``value``. If ``prepend``
|
""" Set environment variable ``name`` to ``value``. If ``prepend``
|
||||||
is a character, read the current environment variable value
|
is a character, read the current environment variable value
|
||||||
|
@ -248,7 +239,6 @@ class MonkeyPatch(object):
|
||||||
value = str(value)
|
value = str(value)
|
||||||
if prepend and name in os.environ:
|
if prepend and name in os.environ:
|
||||||
value = value + prepend + os.environ[name]
|
value = value + prepend + os.environ[name]
|
||||||
self._warn_if_env_name_is_not_str(name)
|
|
||||||
self.setitem(os.environ, name, value)
|
self.setitem(os.environ, name, value)
|
||||||
|
|
||||||
def delenv(self, name, raising=True):
|
def delenv(self, name, raising=True):
|
||||||
|
@ -258,7 +248,6 @@ class MonkeyPatch(object):
|
||||||
If ``raising`` is set to False, no exception will be raised if the
|
If ``raising`` is set to False, no exception will be raised if the
|
||||||
environment variable is missing.
|
environment variable is missing.
|
||||||
"""
|
"""
|
||||||
self._warn_if_env_name_is_not_str(name)
|
|
||||||
self.delitem(os.environ, name, raising=raising)
|
self.delitem(os.environ, name, raising=raising)
|
||||||
|
|
||||||
def syspath_prepend(self, path):
|
def syspath_prepend(self, path):
|
||||||
|
@ -279,10 +268,9 @@ class MonkeyPatch(object):
|
||||||
# since then the mtime based FileFinder cache (that gets created in
|
# since then the mtime based FileFinder cache (that gets created in
|
||||||
# this case already) gets not invalidated when writing the new files
|
# this case already) gets not invalidated when writing the new files
|
||||||
# quickly afterwards.
|
# quickly afterwards.
|
||||||
if sys.version_info >= (3, 3):
|
from importlib import invalidate_caches
|
||||||
from importlib import invalidate_caches
|
|
||||||
|
|
||||||
invalidate_caches()
|
invalidate_caches()
|
||||||
|
|
||||||
def chdir(self, path):
|
def chdir(self, path):
|
||||||
""" Change the current working directory to the specified path.
|
""" Change the current working directory to the specified path.
|
||||||
|
|
|
@ -4,7 +4,6 @@ from __future__ import absolute_import
|
||||||
from __future__ import division
|
from __future__ import division
|
||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
|
|
||||||
import sys
|
|
||||||
import tempfile
|
import tempfile
|
||||||
|
|
||||||
import six
|
import six
|
||||||
|
@ -70,18 +69,10 @@ def create_new_paste(contents):
|
||||||
:returns: url to the pasted contents
|
:returns: url to the pasted contents
|
||||||
"""
|
"""
|
||||||
import re
|
import re
|
||||||
|
from urllib.request import urlopen
|
||||||
|
from urllib.parse import urlencode
|
||||||
|
|
||||||
if sys.version_info < (3, 0):
|
params = {"code": contents, "lexer": "python3", "expiry": "1week"}
|
||||||
from urllib import urlopen, urlencode
|
|
||||||
else:
|
|
||||||
from urllib.request import urlopen
|
|
||||||
from urllib.parse import urlencode
|
|
||||||
|
|
||||||
params = {
|
|
||||||
"code": contents,
|
|
||||||
"lexer": "python3" if sys.version_info[0] == 3 else "python",
|
|
||||||
"expiry": "1week",
|
|
||||||
}
|
|
||||||
url = "https://bpaste.net"
|
url = "https://bpaste.net"
|
||||||
response = urlopen(url, data=urlencode(params).encode("ascii")).read()
|
response = urlopen(url, data=urlencode(params).encode("ascii")).read()
|
||||||
m = re.search(r'href="/raw/(\w+)"', response.decode("utf-8"))
|
m = re.search(r'href="/raw/(\w+)"', response.decode("utf-8"))
|
||||||
|
|
|
@ -8,7 +8,6 @@ import os
|
||||||
import shutil
|
import shutil
|
||||||
import sys
|
import sys
|
||||||
import uuid
|
import uuid
|
||||||
from functools import reduce
|
|
||||||
from os.path import expanduser
|
from os.path import expanduser
|
||||||
from os.path import expandvars
|
from os.path import expandvars
|
||||||
from os.path import isabs
|
from os.path import isabs
|
||||||
|
@ -18,9 +17,8 @@ from posixpath import sep as posix_sep
|
||||||
import six
|
import six
|
||||||
from six.moves import map
|
from six.moves import map
|
||||||
|
|
||||||
from .compat import PY36
|
|
||||||
|
|
||||||
if PY36:
|
if sys.version_info[:2] >= (3, 6):
|
||||||
from pathlib import Path, PurePath
|
from pathlib import Path, PurePath
|
||||||
else:
|
else:
|
||||||
from pathlib2 import Path, PurePath
|
from pathlib2 import Path, PurePath
|
||||||
|
@ -84,17 +82,6 @@ def parse_num(maybe_num):
|
||||||
return -1
|
return -1
|
||||||
|
|
||||||
|
|
||||||
if six.PY2:
|
|
||||||
|
|
||||||
def _max(iterable, default):
|
|
||||||
"""needed due to python2.7 lacking the default argument for max"""
|
|
||||||
return reduce(max, iterable, default)
|
|
||||||
|
|
||||||
|
|
||||||
else:
|
|
||||||
_max = max
|
|
||||||
|
|
||||||
|
|
||||||
def _force_symlink(root, target, link_to):
|
def _force_symlink(root, target, link_to):
|
||||||
"""helper to create the current symlink
|
"""helper to create the current symlink
|
||||||
|
|
||||||
|
@ -119,7 +106,7 @@ def make_numbered_dir(root, prefix):
|
||||||
"""create a directory with an increased number as suffix for the given prefix"""
|
"""create a directory with an increased number as suffix for the given prefix"""
|
||||||
for i in range(10):
|
for i in range(10):
|
||||||
# try up to 10 times to create the folder
|
# try up to 10 times to create the folder
|
||||||
max_existing = _max(map(parse_num, find_suffixes(root, prefix)), default=-1)
|
max_existing = max(map(parse_num, find_suffixes(root, prefix)), default=-1)
|
||||||
new_number = max_existing + 1
|
new_number = max_existing + 1
|
||||||
new_path = root.joinpath("{}{}".format(prefix, new_number))
|
new_path = root.joinpath("{}{}".format(prefix, new_number))
|
||||||
try:
|
try:
|
||||||
|
@ -230,7 +217,7 @@ def try_cleanup(path, consider_lock_dead_if_created_before):
|
||||||
|
|
||||||
def cleanup_candidates(root, prefix, keep):
|
def cleanup_candidates(root, prefix, keep):
|
||||||
"""lists candidates for numbered directories to be removed - follows py.path"""
|
"""lists candidates for numbered directories to be removed - follows py.path"""
|
||||||
max_existing = _max(map(parse_num, find_suffixes(root, prefix)), default=-1)
|
max_existing = max(map(parse_num, find_suffixes(root, prefix)), default=-1)
|
||||||
max_delete = max_existing - keep
|
max_delete = max_existing - keep
|
||||||
paths = find_prefixed(root, prefix)
|
paths = find_prefixed(root, prefix)
|
||||||
paths, paths2 = itertools.tee(paths)
|
paths, paths2 = itertools.tee(paths)
|
||||||
|
|
|
@ -13,6 +13,7 @@ import subprocess
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
import traceback
|
import traceback
|
||||||
|
from collections.abc import Sequence
|
||||||
from fnmatch import fnmatch
|
from fnmatch import fnmatch
|
||||||
from weakref import WeakKeyDictionary
|
from weakref import WeakKeyDictionary
|
||||||
|
|
||||||
|
@ -25,8 +26,6 @@ from _pytest._io.saferepr import saferepr
|
||||||
from _pytest.assertion.rewrite import AssertionRewritingHook
|
from _pytest.assertion.rewrite import AssertionRewritingHook
|
||||||
from _pytest.capture import MultiCapture
|
from _pytest.capture import MultiCapture
|
||||||
from _pytest.capture import SysCapture
|
from _pytest.capture import SysCapture
|
||||||
from _pytest.compat import safe_str
|
|
||||||
from _pytest.compat import Sequence
|
|
||||||
from _pytest.main import EXIT_INTERRUPTED
|
from _pytest.main import EXIT_INTERRUPTED
|
||||||
from _pytest.main import EXIT_OK
|
from _pytest.main import EXIT_OK
|
||||||
from _pytest.main import Session
|
from _pytest.main import Session
|
||||||
|
@ -911,7 +910,7 @@ class Testdir(object):
|
||||||
def _ensure_basetemp(self, args):
|
def _ensure_basetemp(self, args):
|
||||||
args = list(args)
|
args = list(args)
|
||||||
for x in args:
|
for x in args:
|
||||||
if safe_str(x).startswith("--basetemp"):
|
if str(x).startswith("--basetemp"):
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
args.append("--basetemp=%s" % self.tmpdir.dirpath("basetemp"))
|
args.append("--basetemp=%s" % self.tmpdir.dirpath("basetemp"))
|
||||||
|
@ -1124,25 +1123,11 @@ class Testdir(object):
|
||||||
|
|
||||||
if timeout is None:
|
if timeout is None:
|
||||||
ret = popen.wait()
|
ret = popen.wait()
|
||||||
elif six.PY3:
|
else:
|
||||||
try:
|
try:
|
||||||
ret = popen.wait(timeout)
|
ret = popen.wait(timeout)
|
||||||
except subprocess.TimeoutExpired:
|
except subprocess.TimeoutExpired:
|
||||||
handle_timeout()
|
handle_timeout()
|
||||||
else:
|
|
||||||
end = time.time() + timeout
|
|
||||||
|
|
||||||
resolution = min(0.1, timeout / 10)
|
|
||||||
|
|
||||||
while True:
|
|
||||||
ret = popen.poll()
|
|
||||||
if ret is not None:
|
|
||||||
break
|
|
||||||
|
|
||||||
if time.time() > end:
|
|
||||||
handle_timeout()
|
|
||||||
|
|
||||||
time.sleep(resolution)
|
|
||||||
finally:
|
finally:
|
||||||
f1.close()
|
f1.close()
|
||||||
f2.close()
|
f2.close()
|
||||||
|
|
|
@ -5,6 +5,7 @@ from __future__ import division
|
||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
|
|
||||||
import collections
|
import collections
|
||||||
|
import enum
|
||||||
import fnmatch
|
import fnmatch
|
||||||
import inspect
|
import inspect
|
||||||
import os
|
import os
|
||||||
|
@ -22,7 +23,6 @@ from _pytest import fixtures
|
||||||
from _pytest import nodes
|
from _pytest import nodes
|
||||||
from _pytest._code import filter_traceback
|
from _pytest._code import filter_traceback
|
||||||
from _pytest.compat import ascii_escaped
|
from _pytest.compat import ascii_escaped
|
||||||
from _pytest.compat import enum
|
|
||||||
from _pytest.compat import get_default_arg_names
|
from _pytest.compat import get_default_arg_names
|
||||||
from _pytest.compat import get_real_func
|
from _pytest.compat import get_real_func
|
||||||
from _pytest.compat import getfslineno
|
from _pytest.compat import getfslineno
|
||||||
|
@ -35,7 +35,6 @@ from _pytest.compat import NOTSET
|
||||||
from _pytest.compat import REGEX_TYPE
|
from _pytest.compat import REGEX_TYPE
|
||||||
from _pytest.compat import safe_getattr
|
from _pytest.compat import safe_getattr
|
||||||
from _pytest.compat import safe_isclass
|
from _pytest.compat import safe_isclass
|
||||||
from _pytest.compat import safe_str
|
|
||||||
from _pytest.compat import STRING_TYPES
|
from _pytest.compat import STRING_TYPES
|
||||||
from _pytest.config import hookimpl
|
from _pytest.config import hookimpl
|
||||||
from _pytest.main import FSHookProxy
|
from _pytest.main import FSHookProxy
|
||||||
|
@ -531,7 +530,7 @@ class Module(nodes.File, PyCollector):
|
||||||
if exc_info.traceback
|
if exc_info.traceback
|
||||||
else exc_info.exconly()
|
else exc_info.exconly()
|
||||||
)
|
)
|
||||||
formatted_tb = safe_str(exc_repr)
|
formatted_tb = str(exc_repr)
|
||||||
raise self.CollectError(
|
raise self.CollectError(
|
||||||
"ImportError while importing test module '{fspath}'.\n"
|
"ImportError while importing test module '{fspath}'.\n"
|
||||||
"Hint: make sure your test modules/packages have valid Python names.\n"
|
"Hint: make sure your test modules/packages have valid Python names.\n"
|
||||||
|
|
|
@ -5,6 +5,9 @@ import math
|
||||||
import pprint
|
import pprint
|
||||||
import sys
|
import sys
|
||||||
import warnings
|
import warnings
|
||||||
|
from collections.abc import Iterable
|
||||||
|
from collections.abc import Mapping
|
||||||
|
from collections.abc import Sized
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
from numbers import Number
|
from numbers import Number
|
||||||
|
|
||||||
|
@ -15,9 +18,6 @@ from six.moves import zip
|
||||||
import _pytest._code
|
import _pytest._code
|
||||||
from _pytest import deprecated
|
from _pytest import deprecated
|
||||||
from _pytest.compat import isclass
|
from _pytest.compat import isclass
|
||||||
from _pytest.compat import Iterable
|
|
||||||
from _pytest.compat import Mapping
|
|
||||||
from _pytest.compat import Sized
|
|
||||||
from _pytest.compat import STRING_TYPES
|
from _pytest.compat import STRING_TYPES
|
||||||
from _pytest.outcomes import fail
|
from _pytest.outcomes import fail
|
||||||
|
|
||||||
|
@ -81,9 +81,6 @@ class ApproxBase(object):
|
||||||
def __ne__(self, actual):
|
def __ne__(self, actual):
|
||||||
return not (actual == self)
|
return not (actual == self)
|
||||||
|
|
||||||
if sys.version_info[0] == 2:
|
|
||||||
__cmp__ = _cmp_raises_type_error
|
|
||||||
|
|
||||||
def _approx_scalar(self, x):
|
def _approx_scalar(self, x):
|
||||||
return ApproxScalar(x, rel=self.rel, abs=self.abs, nan_ok=self.nan_ok)
|
return ApproxScalar(x, rel=self.rel, abs=self.abs, nan_ok=self.nan_ok)
|
||||||
|
|
||||||
|
@ -122,9 +119,6 @@ class ApproxNumpy(ApproxBase):
|
||||||
list_scalars = _recursive_list_map(self._approx_scalar, self.expected.tolist())
|
list_scalars = _recursive_list_map(self._approx_scalar, self.expected.tolist())
|
||||||
return "approx({!r})".format(list_scalars)
|
return "approx({!r})".format(list_scalars)
|
||||||
|
|
||||||
if sys.version_info[0] == 2:
|
|
||||||
__cmp__ = _cmp_raises_type_error
|
|
||||||
|
|
||||||
def __eq__(self, actual):
|
def __eq__(self, actual):
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
|
@ -251,10 +245,7 @@ class ApproxScalar(ApproxBase):
|
||||||
except ValueError:
|
except ValueError:
|
||||||
vetted_tolerance = "???"
|
vetted_tolerance = "???"
|
||||||
|
|
||||||
if sys.version_info[0] == 2:
|
return "{} \u00b1 {}".format(self.expected, vetted_tolerance)
|
||||||
return "{} +- {}".format(self.expected, vetted_tolerance)
|
|
||||||
else:
|
|
||||||
return u"{} \u00b1 {}".format(self.expected, vetted_tolerance)
|
|
||||||
|
|
||||||
def __eq__(self, actual):
|
def __eq__(self, actual):
|
||||||
"""
|
"""
|
||||||
|
@ -736,8 +727,6 @@ class RaisesContext(object):
|
||||||
fail(self.message)
|
fail(self.message)
|
||||||
self.excinfo.__init__(tp)
|
self.excinfo.__init__(tp)
|
||||||
suppress_exception = issubclass(self.excinfo.type, self.expected_exception)
|
suppress_exception = issubclass(self.excinfo.type, self.expected_exception)
|
||||||
if sys.version_info[0] == 2 and suppress_exception:
|
|
||||||
sys.exc_clear()
|
|
||||||
if self.match_expr is not None and suppress_exception:
|
if self.match_expr is not None and suppress_exception:
|
||||||
self.excinfo.match(self.match_expr)
|
self.excinfo.match(self.match_expr)
|
||||||
return suppress_exception
|
return suppress_exception
|
||||||
|
|
|
@ -9,8 +9,6 @@ import re
|
||||||
import sys
|
import sys
|
||||||
import warnings
|
import warnings
|
||||||
|
|
||||||
import six
|
|
||||||
|
|
||||||
import _pytest._code
|
import _pytest._code
|
||||||
from _pytest.deprecated import PYTEST_WARNS_UNKNOWN_KWARGS
|
from _pytest.deprecated import PYTEST_WARNS_UNKNOWN_KWARGS
|
||||||
from _pytest.deprecated import WARNS_EXEC
|
from _pytest.deprecated import WARNS_EXEC
|
||||||
|
@ -156,44 +154,13 @@ class WarningsRecorder(warnings.catch_warnings):
|
||||||
raise RuntimeError("Cannot enter %r twice" % self)
|
raise RuntimeError("Cannot enter %r twice" % self)
|
||||||
self._list = super(WarningsRecorder, self).__enter__()
|
self._list = super(WarningsRecorder, self).__enter__()
|
||||||
warnings.simplefilter("always")
|
warnings.simplefilter("always")
|
||||||
# python3 keeps track of a "filter version", when the filters are
|
|
||||||
# updated previously seen warnings can be re-warned. python2 has no
|
|
||||||
# concept of this so we must reset the warnings registry manually.
|
|
||||||
# trivial patching of `warnings.warn` seems to be enough somehow?
|
|
||||||
if six.PY2:
|
|
||||||
|
|
||||||
def warn(message, category=None, stacklevel=1):
|
|
||||||
# duplicate the stdlib logic due to
|
|
||||||
# bad handing in the c version of warnings
|
|
||||||
if isinstance(message, Warning):
|
|
||||||
category = message.__class__
|
|
||||||
# Check category argument
|
|
||||||
if category is None:
|
|
||||||
category = UserWarning
|
|
||||||
assert issubclass(category, Warning)
|
|
||||||
|
|
||||||
# emulate resetting the warn registry
|
|
||||||
f_globals = sys._getframe(stacklevel).f_globals
|
|
||||||
if "__warningregistry__" in f_globals:
|
|
||||||
orig = f_globals["__warningregistry__"]
|
|
||||||
f_globals["__warningregistry__"] = None
|
|
||||||
try:
|
|
||||||
return self._saved_warn(message, category, stacklevel + 1)
|
|
||||||
finally:
|
|
||||||
f_globals["__warningregistry__"] = orig
|
|
||||||
else:
|
|
||||||
return self._saved_warn(message, category, stacklevel + 1)
|
|
||||||
|
|
||||||
warnings.warn, self._saved_warn = warn, warnings.warn
|
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def __exit__(self, *exc_info):
|
def __exit__(self, *exc_info):
|
||||||
if not self._entered:
|
if not self._entered:
|
||||||
__tracebackhide__ = True
|
__tracebackhide__ = True
|
||||||
raise RuntimeError("Cannot exit %r without entering first" % self)
|
raise RuntimeError("Cannot exit %r without entering first" % self)
|
||||||
# see above where `self._saved_warn` is assigned
|
|
||||||
if six.PY2:
|
|
||||||
warnings.warn = self._saved_warn
|
|
||||||
super(WarningsRecorder, self).__exit__(*exc_info)
|
super(WarningsRecorder, self).__exit__(*exc_info)
|
||||||
|
|
||||||
# Built-in catch_warnings does not reset entered state so we do it
|
# Built-in catch_warnings does not reset entered state so we do it
|
||||||
|
|
|
@ -129,17 +129,13 @@ def pytest_runtest_makereport(item, call):
|
||||||
evalxfail = getattr(item, "_evalxfail", None)
|
evalxfail = getattr(item, "_evalxfail", None)
|
||||||
# unitttest special case, see setting of _unexpectedsuccess
|
# unitttest special case, see setting of _unexpectedsuccess
|
||||||
if hasattr(item, "_unexpectedsuccess") and rep.when == "call":
|
if hasattr(item, "_unexpectedsuccess") and rep.when == "call":
|
||||||
from _pytest.compat import _is_unittest_unexpected_success_a_failure
|
|
||||||
|
|
||||||
if item._unexpectedsuccess:
|
if item._unexpectedsuccess:
|
||||||
rep.longrepr = "Unexpected success: {}".format(item._unexpectedsuccess)
|
rep.longrepr = "Unexpected success: {}".format(item._unexpectedsuccess)
|
||||||
else:
|
else:
|
||||||
rep.longrepr = "Unexpected success"
|
rep.longrepr = "Unexpected success"
|
||||||
if _is_unittest_unexpected_success_a_failure():
|
rep.outcome = "failed"
|
||||||
rep.outcome = "failed"
|
|
||||||
else:
|
|
||||||
rep.outcome = "passed"
|
|
||||||
rep.wasxfail = rep.longrepr
|
|
||||||
elif item.config.option.runxfail:
|
elif item.config.option.runxfail:
|
||||||
pass # don't interefere
|
pass # don't interefere
|
||||||
elif call.excinfo and call.excinfo.errisinstance(xfail.Exception):
|
elif call.excinfo and call.excinfo.errisinstance(xfail.Exception):
|
||||||
|
|
|
@ -992,21 +992,6 @@ def _get_line_with_reprcrash_message(config, rep, termwidth):
|
||||||
msg = msg[:max_len_msg]
|
msg = msg[:max_len_msg]
|
||||||
while wcswidth(msg) > max_len_msg:
|
while wcswidth(msg) > max_len_msg:
|
||||||
msg = msg[:-1]
|
msg = msg[:-1]
|
||||||
if six.PY2:
|
|
||||||
# on python 2 systems with narrow unicode compilation, trying to
|
|
||||||
# get a single character out of a multi-byte unicode character such as
|
|
||||||
# u'😄' will result in a High Surrogate (U+D83D) character, which is
|
|
||||||
# rendered as u'<27>'; in this case we just strip that character out as it
|
|
||||||
# serves no purpose being rendered
|
|
||||||
try:
|
|
||||||
surrogate = six.unichr(0xD83D)
|
|
||||||
msg = msg.rstrip(surrogate)
|
|
||||||
except ValueError: # pragma: no cover
|
|
||||||
# Jython cannot represent this lone surrogate at all (#5256):
|
|
||||||
# ValueError: unichr() arg is a lone surrogate in range
|
|
||||||
# (0xD800, 0xDFFF) (Jython UTF-16 encoding)
|
|
||||||
# ignore this case as it shouldn't appear in the string anyway
|
|
||||||
pass
|
|
||||||
msg += ellipsis
|
msg += ellipsis
|
||||||
line += sep + msg
|
line += sep + msg
|
||||||
return line
|
return line
|
||||||
|
|
|
@ -11,7 +11,6 @@ import warnings
|
||||||
|
|
||||||
import attr
|
import attr
|
||||||
import py
|
import py
|
||||||
import six
|
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from .pathlib import ensure_reset_dir
|
from .pathlib import ensure_reset_dir
|
||||||
|
@ -32,9 +31,7 @@ class TempPathFactory(object):
|
||||||
# using os.path.abspath() to get absolute path instead of resolve() as it
|
# using os.path.abspath() to get absolute path instead of resolve() as it
|
||||||
# does not work the same in all platforms (see #4427)
|
# does not work the same in all platforms (see #4427)
|
||||||
# Path.absolute() exists, but it is not public (see https://bugs.python.org/issue25012)
|
# Path.absolute() exists, but it is not public (see https://bugs.python.org/issue25012)
|
||||||
converter=attr.converters.optional(
|
converter=attr.converters.optional(lambda p: Path(os.path.abspath(str(p))))
|
||||||
lambda p: Path(os.path.abspath(six.text_type(p)))
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
_trace = attr.ib()
|
_trace = attr.ib()
|
||||||
_basetemp = attr.ib(default=None)
|
_basetemp = attr.ib(default=None)
|
||||||
|
|
|
@ -113,23 +113,9 @@ class TestCaseFunction(Function):
|
||||||
|
|
||||||
def setup(self):
|
def setup(self):
|
||||||
self._testcase = self.parent.obj(self.name)
|
self._testcase = self.parent.obj(self.name)
|
||||||
self._fix_unittest_skip_decorator()
|
|
||||||
if hasattr(self, "_request"):
|
if hasattr(self, "_request"):
|
||||||
self._request._fillfixtures()
|
self._request._fillfixtures()
|
||||||
|
|
||||||
def _fix_unittest_skip_decorator(self):
|
|
||||||
"""
|
|
||||||
The @unittest.skip decorator calls functools.wraps(self._testcase)
|
|
||||||
The call to functools.wraps() fails unless self._testcase
|
|
||||||
has a __name__ attribute. This is usually automatically supplied
|
|
||||||
if the test is a function or method, but we need to add manually
|
|
||||||
here.
|
|
||||||
|
|
||||||
See issue #1169
|
|
||||||
"""
|
|
||||||
if sys.version_info[0] == 2:
|
|
||||||
setattr(self._testcase, "__name__", self.name)
|
|
||||||
|
|
||||||
def teardown(self):
|
def teardown(self):
|
||||||
self._testcase = None
|
self._testcase = None
|
||||||
|
|
||||||
|
@ -208,12 +194,7 @@ class TestCaseFunction(Function):
|
||||||
skip_why = getattr(
|
skip_why = 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
|
self._testcase._addSkip(self, self._testcase, skip_why)
|
||||||
self._testcase._addSkip(self, self._testcase, skip_why)
|
|
||||||
except TypeError: # PY2
|
|
||||||
if sys.version_info[0] != 2:
|
|
||||||
raise
|
|
||||||
self._testcase._addSkip(self, skip_why)
|
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,6 @@ import warnings
|
||||||
from contextlib import contextmanager
|
from contextlib import contextmanager
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from _pytest import compat
|
|
||||||
|
|
||||||
SHOW_PYTEST_WARNINGS_ARG = "-Walways::pytest.RemovedInPytest4Warning"
|
SHOW_PYTEST_WARNINGS_ARG = "-Walways::pytest.RemovedInPytest4Warning"
|
||||||
|
|
||||||
|
@ -104,22 +103,8 @@ def catch_warnings_for_item(config, ihook, when, item):
|
||||||
|
|
||||||
|
|
||||||
def warning_record_to_str(warning_message):
|
def warning_record_to_str(warning_message):
|
||||||
"""Convert a warnings.WarningMessage to a string.
|
"""Convert a warnings.WarningMessage to a string."""
|
||||||
|
|
||||||
This takes lot of unicode shenaningans into account for Python 2.
|
|
||||||
When Python 2 support is dropped this function can be greatly simplified.
|
|
||||||
"""
|
|
||||||
warn_msg = warning_message.message
|
warn_msg = warning_message.message
|
||||||
unicode_warning = False
|
|
||||||
if compat._PY2 and any(isinstance(m, compat.UNICODE_TYPES) for m in warn_msg.args):
|
|
||||||
new_args = []
|
|
||||||
for m in warn_msg.args:
|
|
||||||
new_args.append(
|
|
||||||
compat.ascii_escaped(m) if isinstance(m, compat.UNICODE_TYPES) else m
|
|
||||||
)
|
|
||||||
unicode_warning = list(warn_msg.args) != new_args
|
|
||||||
warn_msg.args = new_args
|
|
||||||
|
|
||||||
msg = warnings.formatwarning(
|
msg = warnings.formatwarning(
|
||||||
warn_msg,
|
warn_msg,
|
||||||
warning_message.category,
|
warning_message.category,
|
||||||
|
@ -127,12 +112,6 @@ def warning_record_to_str(warning_message):
|
||||||
warning_message.lineno,
|
warning_message.lineno,
|
||||||
warning_message.line,
|
warning_message.line,
|
||||||
)
|
)
|
||||||
if unicode_warning:
|
|
||||||
warnings.warn(
|
|
||||||
"Warning is using unicode non convertible to ascii, "
|
|
||||||
"converting to a safe representation:\n {!r}".format(compat.safe_str(msg)),
|
|
||||||
UnicodeWarning,
|
|
||||||
)
|
|
||||||
return msg
|
return msg
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -176,7 +176,6 @@ class TestGeneralUsage(object):
|
||||||
result = testdir.runpytest(p)
|
result = testdir.runpytest(p)
|
||||||
result.stdout.fnmatch_lines(
|
result.stdout.fnmatch_lines(
|
||||||
[
|
[
|
||||||
# XXX on jython this fails: "> import import_fails",
|
|
||||||
"ImportError while importing test module*",
|
"ImportError while importing test module*",
|
||||||
"*No module named *does_not_work*",
|
"*No module named *does_not_work*",
|
||||||
]
|
]
|
||||||
|
@ -222,9 +221,7 @@ class TestGeneralUsage(object):
|
||||||
" foo()",
|
" foo()",
|
||||||
"conftest.py:2: in foo",
|
"conftest.py:2: in foo",
|
||||||
" import qwerty",
|
" import qwerty",
|
||||||
"E {}: No module named {q}qwerty{q}".format(
|
"E {}: No module named 'qwerty'".format(exc_name),
|
||||||
exc_name, q="'" if six.PY3 else ""
|
|
||||||
),
|
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -540,7 +537,6 @@ class TestInvocationVariants(object):
|
||||||
result = testdir.runpython(p)
|
result = testdir.runpython(p)
|
||||||
assert result.ret == 0
|
assert result.ret == 0
|
||||||
|
|
||||||
@pytest.mark.xfail("sys.platform.startswith('java')")
|
|
||||||
def test_pydoc(self, testdir):
|
def test_pydoc(self, testdir):
|
||||||
for name in ("py.test", "pytest"):
|
for name in ("py.test", "pytest"):
|
||||||
result = testdir.runpython_c("import {};help({})".format(name, name))
|
result = testdir.runpython_c("import {};help({})".format(name, name))
|
||||||
|
@ -783,10 +779,7 @@ class TestInvocationVariants(object):
|
||||||
|
|
||||||
d_local = testdir.mkdir("local")
|
d_local = testdir.mkdir("local")
|
||||||
symlink_location = os.path.join(str(d_local), "lib")
|
symlink_location = os.path.join(str(d_local), "lib")
|
||||||
if six.PY2:
|
os.symlink(str(d), symlink_location, target_is_directory=True)
|
||||||
os.symlink(str(d), symlink_location)
|
|
||||||
else:
|
|
||||||
os.symlink(str(d), symlink_location, target_is_directory=True)
|
|
||||||
|
|
||||||
# The structure of the test directory is now:
|
# The structure of the test directory is now:
|
||||||
# .
|
# .
|
||||||
|
@ -1185,9 +1178,6 @@ def test_usage_error_code(testdir):
|
||||||
assert result.ret == EXIT_USAGEERROR
|
assert result.ret == EXIT_USAGEERROR
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.skipif(
|
|
||||||
sys.version_info[:2] < (3, 5), reason="async def syntax python 3.5+ only"
|
|
||||||
)
|
|
||||||
@pytest.mark.filterwarnings("default")
|
@pytest.mark.filterwarnings("default")
|
||||||
def test_warn_on_async_function(testdir):
|
def test_warn_on_async_function(testdir):
|
||||||
testdir.makepyfile(
|
testdir.makepyfile(
|
||||||
|
|
|
@ -4,6 +4,7 @@ from __future__ import division
|
||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
from unittest import mock
|
||||||
|
|
||||||
from six import text_type
|
from six import text_type
|
||||||
from test_excinfo import TWMock
|
from test_excinfo import TWMock
|
||||||
|
@ -11,11 +12,6 @@ from test_excinfo import TWMock
|
||||||
import _pytest._code
|
import _pytest._code
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
try:
|
|
||||||
import mock
|
|
||||||
except ImportError:
|
|
||||||
import unittest.mock as mock
|
|
||||||
|
|
||||||
|
|
||||||
def test_ne():
|
def test_ne():
|
||||||
code1 = _pytest._code.Code(compile('foo = "bar"', "", "exec"))
|
code1 = _pytest._code.Code(compile('foo = "bar"', "", "exec"))
|
||||||
|
@ -92,21 +88,6 @@ def test_unicode_handling():
|
||||||
|
|
||||||
excinfo = pytest.raises(Exception, f)
|
excinfo = pytest.raises(Exception, f)
|
||||||
text_type(excinfo)
|
text_type(excinfo)
|
||||||
if sys.version_info < (3,):
|
|
||||||
bytes(excinfo)
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.skipif(sys.version_info[0] >= 3, reason="python 2 only issue")
|
|
||||||
def test_unicode_handling_syntax_error():
|
|
||||||
value = u"ąć".encode("UTF-8")
|
|
||||||
|
|
||||||
def f():
|
|
||||||
raise SyntaxError("invalid syntax", (None, 1, 3, value))
|
|
||||||
|
|
||||||
excinfo = pytest.raises(Exception, f)
|
|
||||||
str(excinfo)
|
|
||||||
if sys.version_info[0] < 3:
|
|
||||||
text_type(excinfo)
|
|
||||||
|
|
||||||
|
|
||||||
def test_code_getargs():
|
def test_code_getargs():
|
||||||
|
@ -202,10 +183,8 @@ class TestReprFuncArgs(object):
|
||||||
|
|
||||||
r = ReprFuncArgs(args)
|
r = ReprFuncArgs(args)
|
||||||
r.toterminal(tw)
|
r.toterminal(tw)
|
||||||
if sys.version_info[0] >= 3:
|
|
||||||
assert (
|
assert (
|
||||||
tw.lines[0]
|
tw.lines[0]
|
||||||
== r"unicode_string = São Paulo, utf8_string = b'S\xc3\xa3o Paulo'"
|
== r"unicode_string = São Paulo, utf8_string = b'S\xc3\xa3o Paulo'"
|
||||||
)
|
)
|
||||||
else:
|
|
||||||
assert tw.lines[0] == "unicode_string = São Paulo, utf8_string = São Paulo"
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ import pytest
|
||||||
from _pytest._code.code import ExceptionChainRepr
|
from _pytest._code.code import ExceptionChainRepr
|
||||||
from _pytest._code.code import ExceptionInfo
|
from _pytest._code.code import ExceptionInfo
|
||||||
from _pytest._code.code import FormattedExcinfo
|
from _pytest._code.code import FormattedExcinfo
|
||||||
from _pytest._code.code import ReprExceptionInfo
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import importlib
|
import importlib
|
||||||
|
@ -26,8 +26,6 @@ except ImportError:
|
||||||
else:
|
else:
|
||||||
invalidate_import_caches = getattr(importlib, "invalidate_caches", None)
|
invalidate_import_caches = getattr(importlib, "invalidate_caches", None)
|
||||||
|
|
||||||
failsonjython = pytest.mark.xfail("sys.platform.startswith('java')")
|
|
||||||
|
|
||||||
pytest_version_info = tuple(map(int, pytest.__version__.split(".")[:3]))
|
pytest_version_info = tuple(map(int, pytest.__version__.split(".")[:3]))
|
||||||
|
|
||||||
|
|
||||||
|
@ -146,7 +144,6 @@ class TestTraceback_f_g_h(object):
|
||||||
assert s.startswith("def f():")
|
assert s.startswith("def f():")
|
||||||
assert s.endswith("raise ValueError")
|
assert s.endswith("raise ValueError")
|
||||||
|
|
||||||
@failsonjython
|
|
||||||
def test_traceback_entry_getsource_in_construct(self):
|
def test_traceback_entry_getsource_in_construct(self):
|
||||||
source = _pytest._code.Source(
|
source = _pytest._code.Source(
|
||||||
"""\
|
"""\
|
||||||
|
@ -500,8 +497,7 @@ class TestFormattedExcinfo(object):
|
||||||
excinfo = _pytest._code.ExceptionInfo.from_current()
|
excinfo = _pytest._code.ExceptionInfo.from_current()
|
||||||
repr = pr.repr_excinfo(excinfo)
|
repr = pr.repr_excinfo(excinfo)
|
||||||
assert repr.reprtraceback.reprentries[1].lines[0] == "> ???"
|
assert repr.reprtraceback.reprentries[1].lines[0] == "> ???"
|
||||||
if sys.version_info[0] >= 3:
|
assert repr.chain[0][0].reprentries[1].lines[0] == "> ???"
|
||||||
assert repr.chain[0][0].reprentries[1].lines[0] == "> ???"
|
|
||||||
|
|
||||||
def test_repr_many_line_source_not_existing(self):
|
def test_repr_many_line_source_not_existing(self):
|
||||||
pr = FormattedExcinfo()
|
pr = FormattedExcinfo()
|
||||||
|
@ -519,8 +515,7 @@ raise ValueError()
|
||||||
excinfo = _pytest._code.ExceptionInfo.from_current()
|
excinfo = _pytest._code.ExceptionInfo.from_current()
|
||||||
repr = pr.repr_excinfo(excinfo)
|
repr = pr.repr_excinfo(excinfo)
|
||||||
assert repr.reprtraceback.reprentries[1].lines[0] == "> ???"
|
assert repr.reprtraceback.reprentries[1].lines[0] == "> ???"
|
||||||
if sys.version_info[0] >= 3:
|
assert repr.chain[0][0].reprentries[1].lines[0] == "> ???"
|
||||||
assert repr.chain[0][0].reprentries[1].lines[0] == "> ???"
|
|
||||||
|
|
||||||
def test_repr_source_failing_fullsource(self):
|
def test_repr_source_failing_fullsource(self):
|
||||||
pr = FormattedExcinfo()
|
pr = FormattedExcinfo()
|
||||||
|
@ -577,14 +572,12 @@ raise ValueError()
|
||||||
fail = IOError()
|
fail = IOError()
|
||||||
repr = pr.repr_excinfo(excinfo)
|
repr = pr.repr_excinfo(excinfo)
|
||||||
assert repr.reprtraceback.reprentries[0].lines[0] == "> ???"
|
assert repr.reprtraceback.reprentries[0].lines[0] == "> ???"
|
||||||
if sys.version_info[0] >= 3:
|
assert repr.chain[0][0].reprentries[0].lines[0] == "> ???"
|
||||||
assert repr.chain[0][0].reprentries[0].lines[0] == "> ???"
|
|
||||||
|
|
||||||
fail = py.error.ENOENT # noqa
|
fail = py.error.ENOENT # noqa
|
||||||
repr = pr.repr_excinfo(excinfo)
|
repr = pr.repr_excinfo(excinfo)
|
||||||
assert repr.reprtraceback.reprentries[0].lines[0] == "> ???"
|
assert repr.reprtraceback.reprentries[0].lines[0] == "> ???"
|
||||||
if sys.version_info[0] >= 3:
|
assert repr.chain[0][0].reprentries[0].lines[0] == "> ???"
|
||||||
assert repr.chain[0][0].reprentries[0].lines[0] == "> ???"
|
|
||||||
|
|
||||||
def test_repr_local(self):
|
def test_repr_local(self):
|
||||||
p = FormattedExcinfo(showlocals=True)
|
p = FormattedExcinfo(showlocals=True)
|
||||||
|
@ -828,9 +821,9 @@ raise ValueError()
|
||||||
repr = p.repr_excinfo(excinfo)
|
repr = p.repr_excinfo(excinfo)
|
||||||
assert repr.reprtraceback
|
assert repr.reprtraceback
|
||||||
assert len(repr.reprtraceback.reprentries) == len(reprtb.reprentries)
|
assert len(repr.reprtraceback.reprentries) == len(reprtb.reprentries)
|
||||||
if sys.version_info[0] >= 3:
|
|
||||||
assert repr.chain[0][0]
|
assert repr.chain[0][0]
|
||||||
assert len(repr.chain[0][0].reprentries) == len(reprtb.reprentries)
|
assert len(repr.chain[0][0].reprentries) == len(reprtb.reprentries)
|
||||||
assert repr.reprcrash.path.endswith("mod.py")
|
assert repr.reprcrash.path.endswith("mod.py")
|
||||||
assert repr.reprcrash.message == "ValueError: 0"
|
assert repr.reprcrash.message == "ValueError: 0"
|
||||||
|
|
||||||
|
@ -916,13 +909,11 @@ raise ValueError()
|
||||||
for style in ("short", "long", "no"):
|
for style in ("short", "long", "no"):
|
||||||
for showlocals in (True, False):
|
for showlocals in (True, False):
|
||||||
repr = excinfo.getrepr(style=style, showlocals=showlocals)
|
repr = excinfo.getrepr(style=style, showlocals=showlocals)
|
||||||
if sys.version_info[0] < 3:
|
|
||||||
assert isinstance(repr, ReprExceptionInfo)
|
|
||||||
assert repr.reprtraceback.style == style
|
assert repr.reprtraceback.style == style
|
||||||
if sys.version_info[0] >= 3:
|
|
||||||
assert isinstance(repr, ExceptionChainRepr)
|
assert isinstance(repr, ExceptionChainRepr)
|
||||||
for repr in repr.chain:
|
for repr in repr.chain:
|
||||||
assert repr[0].style == style
|
assert repr[0].style == style
|
||||||
|
|
||||||
def test_reprexcinfo_unicode(self):
|
def test_reprexcinfo_unicode(self):
|
||||||
from _pytest._code.code import TerminalRepr
|
from _pytest._code.code import TerminalRepr
|
||||||
|
@ -1133,7 +1124,6 @@ raise ValueError()
|
||||||
msg.endswith("mod.py")
|
msg.endswith("mod.py")
|
||||||
assert tw.lines[20] == ":9: ValueError"
|
assert tw.lines[20] == ":9: ValueError"
|
||||||
|
|
||||||
@pytest.mark.skipif("sys.version_info[0] < 3")
|
|
||||||
def test_exc_chain_repr(self, importasmod):
|
def test_exc_chain_repr(self, importasmod):
|
||||||
mod = importasmod(
|
mod = importasmod(
|
||||||
"""
|
"""
|
||||||
|
@ -1219,7 +1209,6 @@ raise ValueError()
|
||||||
assert line.endswith("mod.py")
|
assert line.endswith("mod.py")
|
||||||
assert tw.lines[47] == ":15: AttributeError"
|
assert tw.lines[47] == ":15: AttributeError"
|
||||||
|
|
||||||
@pytest.mark.skipif("sys.version_info[0] < 3")
|
|
||||||
@pytest.mark.parametrize("mode", ["from_none", "explicit_suppress"])
|
@pytest.mark.parametrize("mode", ["from_none", "explicit_suppress"])
|
||||||
def test_exc_repr_chain_suppression(self, importasmod, mode):
|
def test_exc_repr_chain_suppression(self, importasmod, mode):
|
||||||
"""Check that exc repr does not show chained exceptions in Python 3.
|
"""Check that exc repr does not show chained exceptions in Python 3.
|
||||||
|
@ -1261,7 +1250,6 @@ raise ValueError()
|
||||||
assert tw.lines[9] == ":6: AttributeError"
|
assert tw.lines[9] == ":6: AttributeError"
|
||||||
assert len(tw.lines) == 10
|
assert len(tw.lines) == 10
|
||||||
|
|
||||||
@pytest.mark.skipif("sys.version_info[0] < 3")
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"reason, description",
|
"reason, description",
|
||||||
[
|
[
|
||||||
|
@ -1321,7 +1309,6 @@ raise ValueError()
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
@pytest.mark.skipif("sys.version_info[0] < 3")
|
|
||||||
def test_exc_chain_repr_cycle(self, importasmod):
|
def test_exc_chain_repr_cycle(self, importasmod):
|
||||||
mod = importasmod(
|
mod = importasmod(
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -16,8 +16,6 @@ import _pytest._code
|
||||||
import pytest
|
import pytest
|
||||||
from _pytest._code import Source
|
from _pytest._code import Source
|
||||||
|
|
||||||
failsonjython = pytest.mark.xfail("sys.platform.startswith('java')")
|
|
||||||
|
|
||||||
|
|
||||||
def test_source_str_function():
|
def test_source_str_function():
|
||||||
x = Source("3")
|
x = Source("3")
|
||||||
|
@ -122,7 +120,7 @@ def test_source_strip_multiline():
|
||||||
def test_syntaxerror_rerepresentation():
|
def test_syntaxerror_rerepresentation():
|
||||||
ex = pytest.raises(SyntaxError, _pytest._code.compile, "xyz xyz")
|
ex = pytest.raises(SyntaxError, _pytest._code.compile, "xyz xyz")
|
||||||
assert ex.value.lineno == 1
|
assert ex.value.lineno == 1
|
||||||
assert ex.value.offset in (4, 5, 7) # XXX pypy/jython versus cpython?
|
assert ex.value.offset == 7
|
||||||
assert ex.value.text.strip(), "x x"
|
assert ex.value.text.strip(), "x x"
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,6 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
"""Reproduces issue #3774"""
|
"""Reproduces issue #3774"""
|
||||||
|
from unittest import mock
|
||||||
try:
|
|
||||||
import mock
|
|
||||||
except ImportError:
|
|
||||||
import unittest.mock as mock
|
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
import doctest
|
import doctest
|
||||||
import operator
|
import operator
|
||||||
import sys
|
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
from fractions import Fraction
|
from fractions import Fraction
|
||||||
from operator import eq
|
from operator import eq
|
||||||
|
@ -28,7 +27,7 @@ class MyDocTestRunner(doctest.DocTestRunner):
|
||||||
class TestApprox(object):
|
class TestApprox(object):
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def plus_minus(self):
|
def plus_minus(self):
|
||||||
return u"\u00b1" if sys.version_info[0] > 2 else u"+-"
|
return u"\u00b1"
|
||||||
|
|
||||||
def test_repr_string(self, plus_minus):
|
def test_repr_string(self, plus_minus):
|
||||||
tol1, tol2, infr = "1.0e-06", "2.0e-06", "inf"
|
tol1, tol2, infr = "1.0e-06", "2.0e-06", "inf"
|
||||||
|
|
|
@ -679,8 +679,6 @@ class TestSorting(object):
|
||||||
|
|
||||||
assert fn1 == fn2
|
assert fn1 == fn2
|
||||||
assert fn1 != modcol
|
assert fn1 != modcol
|
||||||
if sys.version_info < (3, 0):
|
|
||||||
assert cmp(fn1, fn2) == 0 # NOQA
|
|
||||||
assert hash(fn1) == hash(fn2)
|
assert hash(fn1) == hash(fn2)
|
||||||
|
|
||||||
fn3 = testdir.collect_by_name(modcol, "test_fail")
|
fn3 = testdir.collect_by_name(modcol, "test_fail")
|
||||||
|
|
|
@ -13,8 +13,6 @@ from _pytest import fixtures
|
||||||
from _pytest import python
|
from _pytest import python
|
||||||
from _pytest.warnings import SHOW_PYTEST_WARNINGS_ARG
|
from _pytest.warnings import SHOW_PYTEST_WARNINGS_ARG
|
||||||
|
|
||||||
PY3 = sys.version_info >= (3, 0)
|
|
||||||
|
|
||||||
|
|
||||||
class TestMetafunc(object):
|
class TestMetafunc(object):
|
||||||
def Metafunc(self, func, config=None):
|
def Metafunc(self, func, config=None):
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
import six
|
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from _pytest.outcomes import Failed
|
from _pytest.outcomes import Failed
|
||||||
from _pytest.warning_types import PytestDeprecationWarning
|
from _pytest.warning_types import PytestDeprecationWarning
|
||||||
|
@ -265,16 +263,7 @@ class TestRaises(object):
|
||||||
def __class__(self):
|
def __class__(self):
|
||||||
assert False, "via __class__"
|
assert False, "via __class__"
|
||||||
|
|
||||||
if six.PY2:
|
with pytest.raises(AssertionError) as excinfo:
|
||||||
with pytest.raises(pytest.fail.Exception) as excinfo:
|
with pytest.raises(CrappyClass()):
|
||||||
with pytest.raises(CrappyClass()):
|
pass
|
||||||
pass
|
assert "via __class__" in excinfo.value.args[0]
|
||||||
assert "DID NOT RAISE" in excinfo.value.args[0]
|
|
||||||
|
|
||||||
with pytest.raises(CrappyClass) as excinfo:
|
|
||||||
raise CrappyClass()
|
|
||||||
else:
|
|
||||||
with pytest.raises(AssertionError) as excinfo:
|
|
||||||
with pytest.raises(CrappyClass()):
|
|
||||||
pass
|
|
||||||
assert "via __class__" in excinfo.value.args[0]
|
|
||||||
|
|
|
@ -30,19 +30,7 @@ def equal_with_bash(prefix, ffc, fc, out=None):
|
||||||
|
|
||||||
def _wrapcall(*args, **kargs):
|
def _wrapcall(*args, **kargs):
|
||||||
try:
|
try:
|
||||||
if sys.version_info > (2, 7):
|
return subprocess.check_output(*args, **kargs).decode().splitlines()
|
||||||
return subprocess.check_output(*args, **kargs).decode().splitlines()
|
|
||||||
if "stdout" in kargs:
|
|
||||||
raise ValueError("stdout argument not allowed, it will be overridden.")
|
|
||||||
process = subprocess.Popen(stdout=subprocess.PIPE, *args, **kargs)
|
|
||||||
output, unused_err = process.communicate()
|
|
||||||
retcode = process.poll()
|
|
||||||
if retcode:
|
|
||||||
cmd = kargs.get("args")
|
|
||||||
if cmd is None:
|
|
||||||
cmd = args[0]
|
|
||||||
raise subprocess.CalledProcessError(retcode, cmd)
|
|
||||||
return output.decode().splitlines()
|
|
||||||
except subprocess.CalledProcessError:
|
except subprocess.CalledProcessError:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@ from __future__ import absolute_import
|
||||||
from __future__ import division
|
from __future__ import division
|
||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
|
|
||||||
|
import collections.abc as collections_abc
|
||||||
import sys
|
import sys
|
||||||
import textwrap
|
import textwrap
|
||||||
|
|
||||||
|
@ -15,8 +16,6 @@ from _pytest import outcomes
|
||||||
from _pytest.assertion import truncate
|
from _pytest.assertion import truncate
|
||||||
from _pytest.assertion import util
|
from _pytest.assertion import util
|
||||||
|
|
||||||
PY3 = sys.version_info >= (3, 0)
|
|
||||||
|
|
||||||
|
|
||||||
def mock_config():
|
def mock_config():
|
||||||
class Config(object):
|
class Config(object):
|
||||||
|
@ -372,14 +371,6 @@ class TestAssert_reprcompare(object):
|
||||||
{0, 2},
|
{0, 2},
|
||||||
"""
|
"""
|
||||||
Full diff:
|
Full diff:
|
||||||
- set([0, 1])
|
|
||||||
? ^
|
|
||||||
+ set([0, 2])
|
|
||||||
? ^
|
|
||||||
"""
|
|
||||||
if not PY3
|
|
||||||
else """
|
|
||||||
Full diff:
|
|
||||||
- {0, 1}
|
- {0, 1}
|
||||||
? ^
|
? ^
|
||||||
+ {0, 2}
|
+ {0, 2}
|
||||||
|
@ -483,10 +474,7 @@ class TestAssert_reprcompare(object):
|
||||||
assert len(expl) > 1
|
assert len(expl) > 1
|
||||||
|
|
||||||
def test_Sequence(self):
|
def test_Sequence(self):
|
||||||
if sys.version_info >= (3, 3):
|
|
||||||
import collections.abc as collections_abc
|
|
||||||
else:
|
|
||||||
import collections as collections_abc
|
|
||||||
if not hasattr(collections_abc, "MutableSequence"):
|
if not hasattr(collections_abc, "MutableSequence"):
|
||||||
pytest.skip("cannot import MutableSequence")
|
pytest.skip("cannot import MutableSequence")
|
||||||
MutableSequence = collections_abc.MutableSequence
|
MutableSequence = collections_abc.MutableSequence
|
||||||
|
@ -589,10 +577,7 @@ class TestAssert_reprcompare(object):
|
||||||
return "\xff"
|
return "\xff"
|
||||||
|
|
||||||
expl = callequal(A(), "1")
|
expl = callequal(A(), "1")
|
||||||
if PY3:
|
assert expl == ["ÿ == '1'", "+ 1"]
|
||||||
assert expl == ["ÿ == '1'", "+ 1"]
|
|
||||||
else:
|
|
||||||
assert expl == [u"\ufffd == '1'", u"+ 1"]
|
|
||||||
|
|
||||||
def test_format_nonascii_explanation(self):
|
def test_format_nonascii_explanation(self):
|
||||||
assert util.format_explanation("λ")
|
assert util.format_explanation("λ")
|
||||||
|
@ -1100,10 +1085,6 @@ def test_traceback_failure(testdir):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.skipif(
|
|
||||||
sys.version_info[:2] <= (3, 3),
|
|
||||||
reason="Python 3.4+ shows chained exceptions on multiprocess",
|
|
||||||
)
|
|
||||||
def test_exception_handling_no_traceback(testdir):
|
def test_exception_handling_no_traceback(testdir):
|
||||||
"""
|
"""
|
||||||
Handle chain exceptions in tasks submitted by the multiprocess module (#1984).
|
Handle chain exceptions in tasks submitted by the multiprocess module (#1984).
|
||||||
|
@ -1137,9 +1118,7 @@ def test_exception_handling_no_traceback(testdir):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.skipif(
|
@pytest.mark.skipif("'__pypy__' in sys.builtin_module_names")
|
||||||
"'__pypy__' in sys.builtin_module_names or sys.platform.startswith('java')"
|
|
||||||
)
|
|
||||||
def test_warn_missing(testdir):
|
def test_warn_missing(testdir):
|
||||||
testdir.makepyfile("")
|
testdir.makepyfile("")
|
||||||
result = testdir.run(sys.executable, "-OO", "-m", "pytest", "-h")
|
result = testdir.run(sys.executable, "-OO", "-m", "pytest", "-h")
|
||||||
|
@ -1187,45 +1166,6 @@ def test_AssertionError_message(testdir):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.skipif(PY3, reason="This bug does not exist on PY3")
|
|
||||||
def test_set_with_unsortable_elements():
|
|
||||||
# issue #718
|
|
||||||
class UnsortableKey(object):
|
|
||||||
def __init__(self, name):
|
|
||||||
self.name = name
|
|
||||||
|
|
||||||
def __lt__(self, other):
|
|
||||||
raise RuntimeError()
|
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
return "repr({})".format(self.name)
|
|
||||||
|
|
||||||
def __eq__(self, other):
|
|
||||||
return self.name == other.name
|
|
||||||
|
|
||||||
def __hash__(self):
|
|
||||||
return hash(self.name)
|
|
||||||
|
|
||||||
left_set = {UnsortableKey(str(i)) for i in range(1, 3)}
|
|
||||||
right_set = {UnsortableKey(str(i)) for i in range(2, 4)}
|
|
||||||
expl = callequal(left_set, right_set, verbose=True)
|
|
||||||
# skip first line because it contains the "construction" of the set, which does not have a guaranteed order
|
|
||||||
expl = expl[1:]
|
|
||||||
dedent = textwrap.dedent(
|
|
||||||
"""
|
|
||||||
Extra items in the left set:
|
|
||||||
repr(1)
|
|
||||||
Extra items in the right set:
|
|
||||||
repr(3)
|
|
||||||
Full diff (fallback to calling repr on each item):
|
|
||||||
- repr(1)
|
|
||||||
repr(2)
|
|
||||||
+ repr(3)
|
|
||||||
"""
|
|
||||||
).strip()
|
|
||||||
assert "\n".join(expl) == dedent
|
|
||||||
|
|
||||||
|
|
||||||
def test_diff_newline_at_end(monkeypatch, testdir):
|
def test_diff_newline_at_end(monkeypatch, testdir):
|
||||||
testdir.makepyfile(
|
testdir.makepyfile(
|
||||||
r"""
|
r"""
|
||||||
|
|
|
@ -3,6 +3,7 @@ from __future__ import absolute_import
|
||||||
from __future__ import division
|
from __future__ import division
|
||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
|
|
||||||
|
import ast
|
||||||
import glob
|
import glob
|
||||||
import os
|
import os
|
||||||
import py_compile
|
import py_compile
|
||||||
|
@ -22,11 +23,6 @@ from _pytest.assertion.rewrite import PYTEST_TAG
|
||||||
from _pytest.assertion.rewrite import rewrite_asserts
|
from _pytest.assertion.rewrite import rewrite_asserts
|
||||||
from _pytest.main import EXIT_NOTESTSCOLLECTED
|
from _pytest.main import EXIT_NOTESTSCOLLECTED
|
||||||
|
|
||||||
ast = pytest.importorskip("ast")
|
|
||||||
if sys.platform.startswith("java"):
|
|
||||||
# XXX should be xfail
|
|
||||||
pytest.skip("assert rewrite does currently not work on jython")
|
|
||||||
|
|
||||||
|
|
||||||
def setup_module(mod):
|
def setup_module(mod):
|
||||||
mod._old_reprcompare = util._reprcompare
|
mod._old_reprcompare = util._reprcompare
|
||||||
|
@ -166,18 +162,12 @@ class TestAssertionRewrite(object):
|
||||||
|
|
||||||
msg = getmsg(f, {"cls": X}).splitlines()
|
msg = getmsg(f, {"cls": X}).splitlines()
|
||||||
if verbose > 0:
|
if verbose > 0:
|
||||||
if six.PY2:
|
|
||||||
assert msg == [
|
assert msg == [
|
||||||
"assert <class 'test_assertrewrite.X'> == 42",
|
"assert <class 'test_...e.<locals>.X'> == 42",
|
||||||
" -<class 'test_assertrewrite.X'>",
|
" -<class 'test_assertrewrite.TestAssertionRewrite.test_name.<locals>.X'>",
|
||||||
" +42",
|
" +42",
|
||||||
]
|
]
|
||||||
else:
|
|
||||||
assert msg == [
|
|
||||||
"assert <class 'test_...e.<locals>.X'> == 42",
|
|
||||||
" -<class 'test_assertrewrite.TestAssertionRewrite.test_name.<locals>.X'>",
|
|
||||||
" +42",
|
|
||||||
]
|
|
||||||
else:
|
else:
|
||||||
assert msg == ["assert cls == 42"]
|
assert msg == ["assert cls == 42"]
|
||||||
|
|
||||||
|
@ -277,9 +267,6 @@ class TestAssertionRewrite(object):
|
||||||
["*AssertionError: To be escaped: %", "*assert 1 == 2"]
|
["*AssertionError: To be escaped: %", "*assert 1 == 2"]
|
||||||
)
|
)
|
||||||
|
|
||||||
@pytest.mark.skipif(
|
|
||||||
sys.version_info < (3,), reason="bytes is a string type in python 2"
|
|
||||||
)
|
|
||||||
def test_assertion_messages_bytes(self, testdir):
|
def test_assertion_messages_bytes(self, testdir):
|
||||||
testdir.makepyfile("def test_bytes_assertion():\n assert False, b'ohai!'\n")
|
testdir.makepyfile("def test_bytes_assertion():\n assert False, b'ohai!'\n")
|
||||||
result = testdir.runpytest()
|
result = testdir.runpytest()
|
||||||
|
@ -426,7 +413,6 @@ class TestAssertionRewrite(object):
|
||||||
|
|
||||||
assert getmsg(f) == "assert (False or (4 % 2))"
|
assert getmsg(f) == "assert (False or (4 % 2))"
|
||||||
|
|
||||||
@pytest.mark.skipif("sys.version_info < (3,5)")
|
|
||||||
def test_at_operator_issue1290(self, testdir):
|
def test_at_operator_issue1290(self, testdir):
|
||||||
testdir.makepyfile(
|
testdir.makepyfile(
|
||||||
"""
|
"""
|
||||||
|
@ -441,7 +427,6 @@ class TestAssertionRewrite(object):
|
||||||
)
|
)
|
||||||
testdir.runpytest().assert_outcomes(passed=1)
|
testdir.runpytest().assert_outcomes(passed=1)
|
||||||
|
|
||||||
@pytest.mark.skipif("sys.version_info < (3,5)")
|
|
||||||
def test_starred_with_side_effect(self, testdir):
|
def test_starred_with_side_effect(self, testdir):
|
||||||
"""See #4412"""
|
"""See #4412"""
|
||||||
testdir.makepyfile(
|
testdir.makepyfile(
|
||||||
|
@ -822,9 +807,6 @@ def test_rewritten():
|
||||||
assert testdir.runpytest_subprocess().ret == 0
|
assert testdir.runpytest_subprocess().ret == 0
|
||||||
|
|
||||||
def test_orphaned_pyc_file(self, testdir):
|
def test_orphaned_pyc_file(self, testdir):
|
||||||
if sys.version_info < (3, 0) and hasattr(sys, "pypy_version_info"):
|
|
||||||
pytest.skip("pypy2 doesn't run orphaned pyc files")
|
|
||||||
|
|
||||||
testdir.makepyfile(
|
testdir.makepyfile(
|
||||||
"""
|
"""
|
||||||
import orphan
|
import orphan
|
||||||
|
@ -890,10 +872,6 @@ def test_rewritten():
|
||||||
testdir.tmpdir.join("test_newlines.py").write(b, "wb")
|
testdir.tmpdir.join("test_newlines.py").write(b, "wb")
|
||||||
assert testdir.runpytest().ret == 0
|
assert testdir.runpytest().ret == 0
|
||||||
|
|
||||||
@pytest.mark.skipif(
|
|
||||||
sys.version_info < (3, 4),
|
|
||||||
reason="packages without __init__.py not supported on python 2",
|
|
||||||
)
|
|
||||||
def test_package_without__init__py(self, testdir):
|
def test_package_without__init__py(self, testdir):
|
||||||
pkg = testdir.mkdir("a_package_without_init_py")
|
pkg = testdir.mkdir("a_package_without_init_py")
|
||||||
pkg.join("module.py").ensure()
|
pkg.join("module.py").ensure()
|
||||||
|
@ -976,26 +954,6 @@ def test_rewritten():
|
||||||
result.stdout.fnmatch_lines(["*= 1 passed in *=*"])
|
result.stdout.fnmatch_lines(["*= 1 passed in *=*"])
|
||||||
assert "pytest-warning summary" not in result.stdout.str()
|
assert "pytest-warning summary" not in result.stdout.str()
|
||||||
|
|
||||||
@pytest.mark.skipif(sys.version_info[0] > 2, reason="python 2 only")
|
|
||||||
def test_rewrite_future_imports(self, testdir):
|
|
||||||
"""Test that rewritten modules don't inherit the __future__ flags
|
|
||||||
from the assertrewrite module.
|
|
||||||
|
|
||||||
assertion.rewrite imports __future__.division (and others), so
|
|
||||||
ensure rewritten modules don't inherit those flags.
|
|
||||||
|
|
||||||
The test below will fail if __future__.division is enabled
|
|
||||||
"""
|
|
||||||
testdir.makepyfile(
|
|
||||||
"""
|
|
||||||
def test():
|
|
||||||
x = 1 / 2
|
|
||||||
assert type(x) is int
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
result = testdir.runpytest()
|
|
||||||
assert result.ret == 0
|
|
||||||
|
|
||||||
|
|
||||||
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):
|
||||||
|
@ -1025,48 +983,6 @@ class TestAssertionRewriteHookDetails(object):
|
||||||
result = testdir.runpytest()
|
result = testdir.runpytest()
|
||||||
result.stdout.fnmatch_lines(["* 3 passed*"])
|
result.stdout.fnmatch_lines(["* 3 passed*"])
|
||||||
|
|
||||||
@pytest.mark.skipif("sys.version_info[0] >= 3")
|
|
||||||
@pytest.mark.xfail("hasattr(sys, 'pypy_translation_info')")
|
|
||||||
def test_assume_ascii(self, testdir):
|
|
||||||
content = "u'\xe2\x99\xa5\x01\xfe'"
|
|
||||||
testdir.tmpdir.join("test_encoding.py").write(content, "wb")
|
|
||||||
res = testdir.runpytest()
|
|
||||||
assert res.ret != 0
|
|
||||||
assert "SyntaxError: Non-ASCII character" in res.stdout.str()
|
|
||||||
|
|
||||||
@pytest.mark.skipif("sys.version_info[0] >= 3")
|
|
||||||
def test_detect_coding_cookie(self, testdir):
|
|
||||||
testdir.makepyfile(
|
|
||||||
test_cookie="""
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
u"St\xc3\xa4d"
|
|
||||||
def test_rewritten():
|
|
||||||
assert "@py_builtins" in globals()"""
|
|
||||||
)
|
|
||||||
assert testdir.runpytest().ret == 0
|
|
||||||
|
|
||||||
@pytest.mark.skipif("sys.version_info[0] >= 3")
|
|
||||||
def test_detect_coding_cookie_second_line(self, testdir):
|
|
||||||
testdir.makepyfile(
|
|
||||||
test_cookie="""
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
u"St\xc3\xa4d"
|
|
||||||
def test_rewritten():
|
|
||||||
assert "@py_builtins" in globals()"""
|
|
||||||
)
|
|
||||||
assert testdir.runpytest().ret == 0
|
|
||||||
|
|
||||||
@pytest.mark.skipif("sys.version_info[0] >= 3")
|
|
||||||
def test_detect_coding_cookie_crlf(self, testdir):
|
|
||||||
testdir.makepyfile(
|
|
||||||
test_cookie="""
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
u"St\xc3\xa4d"
|
|
||||||
def test_rewritten():
|
|
||||||
assert "@py_builtins" in globals()"""
|
|
||||||
)
|
|
||||||
assert testdir.runpytest().ret == 0
|
|
||||||
|
|
||||||
def test_sys_meta_path_munged(self, testdir):
|
def test_sys_meta_path_munged(self, testdir):
|
||||||
testdir.makepyfile(
|
testdir.makepyfile(
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -13,12 +13,10 @@ import textwrap
|
||||||
from io import UnsupportedOperation
|
from io import UnsupportedOperation
|
||||||
|
|
||||||
import py
|
import py
|
||||||
from six import text_type
|
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from _pytest import capture
|
from _pytest import capture
|
||||||
from _pytest.capture import CaptureManager
|
from _pytest.capture import CaptureManager
|
||||||
from _pytest.compat import _PY3
|
|
||||||
from _pytest.main import EXIT_NOTESTSCOLLECTED
|
from _pytest.main import EXIT_NOTESTSCOLLECTED
|
||||||
|
|
||||||
# note: py.io capture tests where copied from
|
# note: py.io capture tests where copied from
|
||||||
|
@ -100,10 +98,7 @@ class TestCaptureManager(object):
|
||||||
def test_capturing_unicode(testdir, method):
|
def test_capturing_unicode(testdir, method):
|
||||||
if hasattr(sys, "pypy_version_info") and sys.pypy_version_info < (2, 2):
|
if hasattr(sys, "pypy_version_info") and sys.pypy_version_info < (2, 2):
|
||||||
pytest.xfail("does not work on pypy < 2.2")
|
pytest.xfail("does not work on pypy < 2.2")
|
||||||
if sys.version_info >= (3, 0):
|
obj = "'b\u00f6y'"
|
||||||
obj = "'b\u00f6y'"
|
|
||||||
else:
|
|
||||||
obj = "u'\u00f6y'"
|
|
||||||
testdir.makepyfile(
|
testdir.makepyfile(
|
||||||
"""
|
"""
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
@ -545,9 +540,6 @@ class TestCaptureFixture(object):
|
||||||
)
|
)
|
||||||
reprec.assertoutcome(passed=1)
|
reprec.assertoutcome(passed=1)
|
||||||
|
|
||||||
@pytest.mark.skipif(
|
|
||||||
sys.version_info < (3,), reason="only have capsysbinary in python 3"
|
|
||||||
)
|
|
||||||
def test_capsysbinary(self, testdir):
|
def test_capsysbinary(self, testdir):
|
||||||
reprec = testdir.inline_runsource(
|
reprec = testdir.inline_runsource(
|
||||||
"""\
|
"""\
|
||||||
|
@ -562,25 +554,6 @@ class TestCaptureFixture(object):
|
||||||
)
|
)
|
||||||
reprec.assertoutcome(passed=1)
|
reprec.assertoutcome(passed=1)
|
||||||
|
|
||||||
@pytest.mark.skipif(
|
|
||||||
sys.version_info >= (3,), reason="only have capsysbinary in python 3"
|
|
||||||
)
|
|
||||||
def test_capsysbinary_forbidden_in_python2(self, testdir):
|
|
||||||
testdir.makepyfile(
|
|
||||||
"""\
|
|
||||||
def test_hello(capsysbinary):
|
|
||||||
pass
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
result = testdir.runpytest()
|
|
||||||
result.stdout.fnmatch_lines(
|
|
||||||
[
|
|
||||||
"*test_hello*",
|
|
||||||
"*capsysbinary is only supported on Python 3*",
|
|
||||||
"*1 error in*",
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_partial_setup_failure(self, testdir):
|
def test_partial_setup_failure(self, testdir):
|
||||||
p = testdir.makepyfile(
|
p = testdir.makepyfile(
|
||||||
"""\
|
"""\
|
||||||
|
@ -843,17 +816,9 @@ class TestCaptureIO(object):
|
||||||
|
|
||||||
def test_unicode_and_str_mixture(self):
|
def test_unicode_and_str_mixture(self):
|
||||||
f = capture.CaptureIO()
|
f = capture.CaptureIO()
|
||||||
if sys.version_info >= (3, 0):
|
f.write("\u00f6")
|
||||||
f.write("\u00f6")
|
pytest.raises(TypeError, f.write, b"hello")
|
||||||
pytest.raises(TypeError, f.write, b"hello")
|
|
||||||
else:
|
|
||||||
f.write(u"\u00f6")
|
|
||||||
f.write(b"hello")
|
|
||||||
s = f.getvalue()
|
|
||||||
f.close()
|
|
||||||
assert isinstance(s, text_type)
|
|
||||||
|
|
||||||
@pytest.mark.skipif(sys.version_info[0] == 2, reason="python 3 only behaviour")
|
|
||||||
def test_write_bytes_to_buffer(self):
|
def test_write_bytes_to_buffer(self):
|
||||||
"""In python3, stdout / stderr are text io wrappers (exposing a buffer
|
"""In python3, stdout / stderr are text io wrappers (exposing a buffer
|
||||||
property of the underlying bytestream). See issue #1407
|
property of the underlying bytestream). See issue #1407
|
||||||
|
@ -876,7 +841,6 @@ def test_dontreadfrominput():
|
||||||
f.close() # just for completeness
|
f.close() # just for completeness
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.skipif("sys.version_info < (3,)", reason="python2 has no buffer")
|
|
||||||
def test_dontreadfrominput_buffer_python3():
|
def test_dontreadfrominput_buffer_python3():
|
||||||
from _pytest.capture import DontReadFromInput
|
from _pytest.capture import DontReadFromInput
|
||||||
|
|
||||||
|
@ -891,17 +855,7 @@ def test_dontreadfrominput_buffer_python3():
|
||||||
f.close() # just for completeness
|
f.close() # just for completeness
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.skipif("sys.version_info >= (3,)", reason="python2 has no buffer")
|
@pytest.fixture
|
||||||
def test_dontreadfrominput_buffer_python2():
|
|
||||||
from _pytest.capture import DontReadFromInput
|
|
||||||
|
|
||||||
f = DontReadFromInput()
|
|
||||||
with pytest.raises(AttributeError):
|
|
||||||
f.buffer
|
|
||||||
f.close() # just for completeness
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.yield_fixture
|
|
||||||
def tmpfile(testdir):
|
def tmpfile(testdir):
|
||||||
f = testdir.makepyfile("").open("wb+")
|
f = testdir.makepyfile("").open("wb+")
|
||||||
yield f
|
yield f
|
||||||
|
@ -1118,16 +1072,6 @@ class TestStdCapture(object):
|
||||||
out, err = cap.readouterr()
|
out, err = cap.readouterr()
|
||||||
assert out == u"hxąć\n"
|
assert out == u"hxąć\n"
|
||||||
|
|
||||||
@pytest.mark.skipif(
|
|
||||||
"sys.version_info >= (3,)", reason="text output different for bytes on python3"
|
|
||||||
)
|
|
||||||
def test_capturing_readouterr_decode_error_handling(self):
|
|
||||||
with self.getcapture() as cap:
|
|
||||||
# triggered an internal error in pytest
|
|
||||||
print("\xa6")
|
|
||||||
out, err = cap.readouterr()
|
|
||||||
assert out == u"\ufffd\n"
|
|
||||||
|
|
||||||
def test_reset_twice_error(self):
|
def test_reset_twice_error(self):
|
||||||
with self.getcapture() as cap:
|
with self.getcapture() as cap:
|
||||||
print("hello")
|
print("hello")
|
||||||
|
@ -1571,9 +1515,6 @@ def test_typeerror_encodedfile_write(testdir):
|
||||||
|
|
||||||
assert result_with_capture.ret == result_without_capture.ret
|
assert result_with_capture.ret == result_without_capture.ret
|
||||||
|
|
||||||
if _PY3:
|
result_with_capture.stdout.fnmatch_lines(
|
||||||
result_with_capture.stdout.fnmatch_lines(
|
["E TypeError: write() argument must be str, not bytes"]
|
||||||
["E TypeError: write() argument must be str, not bytes"]
|
)
|
||||||
)
|
|
||||||
else:
|
|
||||||
assert result_with_capture.ret == 0
|
|
||||||
|
|
|
@ -38,8 +38,6 @@ class TestCollector(object):
|
||||||
|
|
||||||
assert fn1 == fn2
|
assert fn1 == fn2
|
||||||
assert fn1 != modcol
|
assert fn1 != modcol
|
||||||
if sys.version_info < (3, 0):
|
|
||||||
assert cmp(fn1, fn2) == 0 # NOQA
|
|
||||||
assert hash(fn1) == hash(fn2)
|
assert hash(fn1) == hash(fn2)
|
||||||
|
|
||||||
fn3 = testdir.collect_by_name(modcol, "test_fail")
|
fn3 = testdir.collect_by_name(modcol, "test_fail")
|
||||||
|
|
|
@ -6,8 +6,6 @@ from __future__ import print_function
|
||||||
import sys
|
import sys
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
|
|
||||||
import six
|
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from _pytest.compat import _PytestWrapper
|
from _pytest.compat import _PytestWrapper
|
||||||
from _pytest.compat import get_real_func
|
from _pytest.compat import get_real_func
|
||||||
|
@ -62,8 +60,6 @@ def test_get_real_func():
|
||||||
def inner():
|
def inner():
|
||||||
pass # pragma: no cover
|
pass # pragma: no cover
|
||||||
|
|
||||||
if six.PY2:
|
|
||||||
inner.__wrapped__ = f
|
|
||||||
return inner
|
return inner
|
||||||
|
|
||||||
def func():
|
def func():
|
||||||
|
@ -81,9 +77,6 @@ def test_get_real_func():
|
||||||
assert get_real_func(wrapped_func2) is wrapped_func
|
assert get_real_func(wrapped_func2) is wrapped_func
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.skipif(
|
|
||||||
sys.version_info < (3, 4), reason="asyncio available in Python 3.4+"
|
|
||||||
)
|
|
||||||
def test_is_generator_asyncio(testdir):
|
def test_is_generator_asyncio(testdir):
|
||||||
testdir.makepyfile(
|
testdir.makepyfile(
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -218,12 +218,9 @@ class TestConfigAPI(object):
|
||||||
assert config.getoption(x) == "this"
|
assert config.getoption(x) == "this"
|
||||||
pytest.raises(ValueError, config.getoption, "qweqwe")
|
pytest.raises(ValueError, config.getoption, "qweqwe")
|
||||||
|
|
||||||
@pytest.mark.skipif("sys.version_info[0] < 3")
|
|
||||||
def test_config_getoption_unicode(self, testdir):
|
def test_config_getoption_unicode(self, testdir):
|
||||||
testdir.makeconftest(
|
testdir.makeconftest(
|
||||||
"""
|
"""
|
||||||
from __future__ import unicode_literals
|
|
||||||
|
|
||||||
def pytest_addoption(parser):
|
def pytest_addoption(parser):
|
||||||
parser.addoption('--hello', type=str)
|
parser.addoption('--hello', type=str)
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -3,7 +3,6 @@ from __future__ import absolute_import
|
||||||
from __future__ import division
|
from __future__ import division
|
||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
|
|
||||||
import sys
|
|
||||||
import textwrap
|
import textwrap
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
@ -830,13 +829,11 @@ class TestLiterals(object):
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
reprec = testdir.inline_run()
|
reprec = testdir.inline_run()
|
||||||
passed = int(sys.version_info[0] >= 3)
|
reprec.assertoutcome(passed=1)
|
||||||
reprec.assertoutcome(passed=passed, failed=int(not passed))
|
|
||||||
|
|
||||||
def test_bytes_literal(self, testdir):
|
def test_bytes_literal(self, testdir):
|
||||||
"""Test that doctests which output bytes fail in Python 3 when
|
"""Test that doctests which output bytes fail in Python 3 when
|
||||||
the ALLOW_BYTES option is not used. The same test should pass
|
the ALLOW_BYTES option is not used. (#1287).
|
||||||
in Python 2 (#1287).
|
|
||||||
"""
|
"""
|
||||||
testdir.maketxtfile(
|
testdir.maketxtfile(
|
||||||
test_doc="""
|
test_doc="""
|
||||||
|
@ -845,8 +842,7 @@ class TestLiterals(object):
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
reprec = testdir.inline_run()
|
reprec = testdir.inline_run()
|
||||||
passed = int(sys.version_info[0] == 2)
|
reprec.assertoutcome(failed=1)
|
||||||
reprec.assertoutcome(passed=passed, failed=int(not passed))
|
|
||||||
|
|
||||||
|
|
||||||
class TestDoctestSkips(object):
|
class TestDoctestSkips(object):
|
||||||
|
|
|
@ -4,7 +4,6 @@ from __future__ import division
|
||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
|
||||||
from xml.dom import minidom
|
from xml.dom import minidom
|
||||||
|
|
||||||
import py
|
import py
|
||||||
|
@ -585,8 +584,7 @@ class TestPython(object):
|
||||||
assert result.ret == 1
|
assert result.ret == 1
|
||||||
tnode = dom.find_first_by_tag("testcase")
|
tnode = dom.find_first_by_tag("testcase")
|
||||||
fnode = tnode.find_first_by_tag("failure")
|
fnode = tnode.find_first_by_tag("failure")
|
||||||
if not sys.platform.startswith("java"):
|
assert "hx" in fnode.toxml()
|
||||||
assert "hx" in fnode.toxml()
|
|
||||||
|
|
||||||
def test_assertion_binchars(self, testdir):
|
def test_assertion_binchars(self, testdir):
|
||||||
"""this test did fail when the escaping wasnt strict"""
|
"""this test did fail when the escaping wasnt strict"""
|
||||||
|
|
|
@ -5,8 +5,7 @@ from __future__ import print_function
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
from unittest import mock
|
||||||
import six
|
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from _pytest.main import EXIT_INTERRUPTED
|
from _pytest.main import EXIT_INTERRUPTED
|
||||||
|
@ -17,11 +16,6 @@ from _pytest.nodes import Node
|
||||||
from _pytest.warning_types import PytestDeprecationWarning
|
from _pytest.warning_types import PytestDeprecationWarning
|
||||||
from _pytest.warnings import SHOW_PYTEST_WARNINGS_ARG
|
from _pytest.warnings import SHOW_PYTEST_WARNINGS_ARG
|
||||||
|
|
||||||
try:
|
|
||||||
import mock
|
|
||||||
except ImportError:
|
|
||||||
import unittest.mock as mock
|
|
||||||
|
|
||||||
ignore_markinfo = pytest.mark.filterwarnings(
|
ignore_markinfo = pytest.mark.filterwarnings(
|
||||||
"ignore:MarkInfo objects:pytest.RemovedInPytest4Warning"
|
"ignore:MarkInfo objects:pytest.RemovedInPytest4Warning"
|
||||||
)
|
)
|
||||||
|
@ -1009,10 +1003,7 @@ def test_pytest_param_id_requires_string():
|
||||||
with pytest.raises(TypeError) as excinfo:
|
with pytest.raises(TypeError) as excinfo:
|
||||||
pytest.param(id=True)
|
pytest.param(id=True)
|
||||||
msg, = excinfo.value.args
|
msg, = excinfo.value.args
|
||||||
if six.PY2:
|
assert msg == "Expected id to be a string, got <class 'bool'>: True"
|
||||||
assert msg == "Expected id to be a string, got <type 'bool'>: True"
|
|
||||||
else:
|
|
||||||
assert msg == "Expected id to be a string, got <class 'bool'>: True"
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("s", (None, "hello world"))
|
@pytest.mark.parametrize("s", (None, "hello world"))
|
||||||
|
|
|
@ -8,8 +8,6 @@ import re
|
||||||
import sys
|
import sys
|
||||||
import textwrap
|
import textwrap
|
||||||
|
|
||||||
import six
|
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from _pytest.monkeypatch import MonkeyPatch
|
from _pytest.monkeypatch import MonkeyPatch
|
||||||
|
|
||||||
|
@ -209,22 +207,6 @@ class TestEnvironWarnings(object):
|
||||||
|
|
||||||
VAR_NAME = u"PYTEST_INTERNAL_MY_VAR"
|
VAR_NAME = u"PYTEST_INTERNAL_MY_VAR"
|
||||||
|
|
||||||
@pytest.mark.skipif(six.PY3, reason="Python 2 only test")
|
|
||||||
def test_setenv_unicode_key(self, monkeypatch):
|
|
||||||
with pytest.warns(
|
|
||||||
pytest.PytestWarning,
|
|
||||||
match="Environment variable name {!r} should be str".format(self.VAR_NAME),
|
|
||||||
):
|
|
||||||
monkeypatch.setenv(self.VAR_NAME, "2")
|
|
||||||
|
|
||||||
@pytest.mark.skipif(six.PY3, reason="Python 2 only test")
|
|
||||||
def test_delenv_unicode_key(self, monkeypatch):
|
|
||||||
with pytest.warns(
|
|
||||||
pytest.PytestWarning,
|
|
||||||
match="Environment variable name {!r} should be str".format(self.VAR_NAME),
|
|
||||||
):
|
|
||||||
monkeypatch.delenv(self.VAR_NAME, raising=False)
|
|
||||||
|
|
||||||
def test_setenv_non_str_warning(self, monkeypatch):
|
def test_setenv_non_str_warning(self, monkeypatch):
|
||||||
value = 2
|
value = 2
|
||||||
msg = (
|
msg = (
|
||||||
|
@ -349,10 +331,8 @@ def test_importerror(testdir):
|
||||||
result = testdir.runpytest()
|
result = testdir.runpytest()
|
||||||
result.stdout.fnmatch_lines(
|
result.stdout.fnmatch_lines(
|
||||||
"""
|
"""
|
||||||
*import error in package.a: No module named {0}doesnotexist{0}*
|
*import error in package.a: No module named 'doesnotexist'*
|
||||||
""".format(
|
"""
|
||||||
"'" if sys.version_info > (3, 0) else ""
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -3,8 +3,6 @@ from __future__ import absolute_import
|
||||||
from __future__ import division
|
from __future__ import division
|
||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
|
|
||||||
import sys
|
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
|
||||||
|
@ -74,10 +72,7 @@ class TestPasteCapture(object):
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
result = testdir.runpytest("--pastebin=all")
|
result = testdir.runpytest("--pastebin=all")
|
||||||
if sys.version_info[0] == 3:
|
expected_msg = "*assert '☺' == 1*"
|
||||||
expected_msg = "*assert '☺' == 1*"
|
|
||||||
else:
|
|
||||||
expected_msg = "*assert '\\xe2\\x98\\xba' == 1*"
|
|
||||||
result.stdout.fnmatch_lines(
|
result.stdout.fnmatch_lines(
|
||||||
[
|
[
|
||||||
expected_msg,
|
expected_msg,
|
||||||
|
@ -110,14 +105,9 @@ class TestPaste(object):
|
||||||
|
|
||||||
return DummyFile()
|
return DummyFile()
|
||||||
|
|
||||||
if sys.version_info < (3, 0):
|
import urllib.request
|
||||||
import urllib
|
|
||||||
|
|
||||||
monkeypatch.setattr(urllib, "urlopen", mocked)
|
monkeypatch.setattr(urllib.request, "urlopen", mocked)
|
||||||
else:
|
|
||||||
import urllib.request
|
|
||||||
|
|
||||||
monkeypatch.setattr(urllib.request, "urlopen", mocked)
|
|
||||||
return calls
|
return calls
|
||||||
|
|
||||||
def test_create_new_paste(self, pastebin, mocked_urlopen):
|
def test_create_new_paste(self, pastebin, mocked_urlopen):
|
||||||
|
@ -126,7 +116,7 @@ class TestPaste(object):
|
||||||
assert len(mocked_urlopen) == 1
|
assert len(mocked_urlopen) == 1
|
||||||
url, data = mocked_urlopen[0]
|
url, data = mocked_urlopen[0]
|
||||||
assert type(data) is bytes
|
assert type(data) is bytes
|
||||||
lexer = "python3" if sys.version_info[0] == 3 else "python"
|
lexer = "python3"
|
||||||
assert url == "https://bpaste.net"
|
assert url == "https://bpaste.net"
|
||||||
assert "lexer=%s" % lexer in data.decode()
|
assert "lexer=%s" % lexer in data.decode()
|
||||||
assert "code=full-paste-contents" in data.decode()
|
assert "code=full-paste-contents" in data.decode()
|
||||||
|
|
|
@ -6,8 +6,6 @@ from __future__ import print_function
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
import six
|
|
||||||
|
|
||||||
import _pytest._code
|
import _pytest._code
|
||||||
import pytest
|
import pytest
|
||||||
from _pytest.debugging import _validate_usepdb_cls
|
from _pytest.debugging import _validate_usepdb_cls
|
||||||
|
@ -537,10 +535,7 @@ class TestPDB(object):
|
||||||
import sys
|
import sys
|
||||||
import types
|
import types
|
||||||
|
|
||||||
if sys.version_info < (3, ):
|
do_debug_func = pdb.Pdb.do_debug
|
||||||
do_debug_func = pdb.Pdb.do_debug.im_func
|
|
||||||
else:
|
|
||||||
do_debug_func = pdb.Pdb.do_debug
|
|
||||||
|
|
||||||
newglobals = do_debug_func.__globals__.copy()
|
newglobals = do_debug_func.__globals__.copy()
|
||||||
newglobals['Pdb'] = self.__class__
|
newglobals['Pdb'] = self.__class__
|
||||||
|
@ -866,8 +861,6 @@ class TestDebuggingBreakpoints(object):
|
||||||
assert SUPPORTS_BREAKPOINT_BUILTIN is True
|
assert SUPPORTS_BREAKPOINT_BUILTIN is True
|
||||||
if sys.version_info.major == 3 and sys.version_info.minor == 5:
|
if sys.version_info.major == 3 and sys.version_info.minor == 5:
|
||||||
assert SUPPORTS_BREAKPOINT_BUILTIN is False
|
assert SUPPORTS_BREAKPOINT_BUILTIN is False
|
||||||
if sys.version_info.major == 2 and sys.version_info.minor == 7:
|
|
||||||
assert SUPPORTS_BREAKPOINT_BUILTIN is False
|
|
||||||
|
|
||||||
@pytest.mark.skipif(
|
@pytest.mark.skipif(
|
||||||
not SUPPORTS_BREAKPOINT_BUILTIN, reason="Requires breakpoint() builtin"
|
not SUPPORTS_BREAKPOINT_BUILTIN, reason="Requires breakpoint() builtin"
|
||||||
|
@ -1183,24 +1176,17 @@ def test_pdbcls_via_local_module(testdir):
|
||||||
|
|
||||||
def test_raises_bdbquit_with_eoferror(testdir):
|
def test_raises_bdbquit_with_eoferror(testdir):
|
||||||
"""It is not guaranteed that DontReadFromInput's read is called."""
|
"""It is not guaranteed that DontReadFromInput's read is called."""
|
||||||
if six.PY2:
|
|
||||||
builtin_module = "__builtin__"
|
|
||||||
input_func = "raw_input"
|
|
||||||
else:
|
|
||||||
builtin_module = "builtins"
|
|
||||||
input_func = "input"
|
|
||||||
p1 = testdir.makepyfile(
|
p1 = testdir.makepyfile(
|
||||||
"""
|
"""
|
||||||
def input_without_read(*args, **kwargs):
|
def input_without_read(*args, **kwargs):
|
||||||
raise EOFError()
|
raise EOFError()
|
||||||
|
|
||||||
def test(monkeypatch):
|
def test(monkeypatch):
|
||||||
import {builtin_module}
|
import builtins
|
||||||
monkeypatch.setattr({builtin_module}, {input_func!r}, input_without_read)
|
monkeypatch.setattr(builtins, "input", input_without_read)
|
||||||
__import__('pdb').set_trace()
|
__import__('pdb').set_trace()
|
||||||
""".format(
|
"""
|
||||||
builtin_module=builtin_module, input_func=input_func
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
result = testdir.runpytest(str(p1))
|
result = testdir.runpytest(str(p1))
|
||||||
result.stdout.fnmatch_lines(["E *BdbQuit", "*= 1 failed in*"])
|
result.stdout.fnmatch_lines(["E *BdbQuit", "*= 1 failed in*"])
|
||||||
|
|
|
@ -654,10 +654,7 @@ def test_pytest_fail_notrace_non_ascii(testdir, str_prefix):
|
||||||
% str_prefix
|
% str_prefix
|
||||||
)
|
)
|
||||||
result = testdir.runpytest()
|
result = testdir.runpytest()
|
||||||
if sys.version_info[0] >= 3:
|
result.stdout.fnmatch_lines(["*test_hello*", "oh oh: ☺"])
|
||||||
result.stdout.fnmatch_lines(["*test_hello*", "oh oh: ☺"])
|
|
||||||
else:
|
|
||||||
result.stdout.fnmatch_lines(["*test_hello*", "oh oh: *"])
|
|
||||||
assert "def test_hello" not in result.stdout.str()
|
assert "def test_hello" not in result.stdout.str()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -49,22 +49,6 @@ class TestEvaluator(object):
|
||||||
expl = ev.getexplanation()
|
expl = ev.getexplanation()
|
||||||
assert expl == "condition: hasattr(os, 'sep')"
|
assert expl == "condition: hasattr(os, 'sep')"
|
||||||
|
|
||||||
@pytest.mark.skipif("sys.version_info[0] >= 3")
|
|
||||||
def test_marked_one_arg_unicode(self, testdir):
|
|
||||||
item = testdir.getitem(
|
|
||||||
"""
|
|
||||||
import pytest
|
|
||||||
@pytest.mark.xyz(u"hasattr(os, 'sep')")
|
|
||||||
def test_func():
|
|
||||||
pass
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
ev = MarkEvaluator(item, "xyz")
|
|
||||||
assert ev
|
|
||||||
assert ev.istrue()
|
|
||||||
expl = ev.getexplanation()
|
|
||||||
assert expl == "condition: hasattr(os, 'sep')"
|
|
||||||
|
|
||||||
def test_marked_one_arg_with_reason(self, testdir):
|
def test_marked_one_arg_with_reason(self, testdir):
|
||||||
item = testdir.getitem(
|
item = testdir.getitem(
|
||||||
"""
|
"""
|
||||||
|
@ -893,10 +877,7 @@ def test_errors_in_xfail_skip_expressions(testdir):
|
||||||
)
|
)
|
||||||
result = testdir.runpytest()
|
result = testdir.runpytest()
|
||||||
markline = " ^"
|
markline = " ^"
|
||||||
if sys.platform.startswith("java"):
|
if hasattr(sys, "pypy_version_info") and sys.pypy_version_info < (6,):
|
||||||
# XXX report this to java
|
|
||||||
markline = "*" + markline[8:]
|
|
||||||
elif hasattr(sys, "pypy_version_info") and sys.pypy_version_info < (6,):
|
|
||||||
markline = markline[5:]
|
markline = markline[5:]
|
||||||
elif sys.version_info >= (3, 8) or hasattr(sys, "pypy_version_info"):
|
elif sys.version_info >= (3, 8) or hasattr(sys, "pypy_version_info"):
|
||||||
markline = markline[4:]
|
markline = markline[4:]
|
||||||
|
|
|
@ -6,7 +6,6 @@ from __future__ import print_function
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
import attr
|
import attr
|
||||||
import six
|
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from _pytest import pathlib
|
from _pytest import pathlib
|
||||||
|
@ -348,8 +347,6 @@ class TestNumberedDir(object):
|
||||||
def attempt_symlink_to(path, to_path):
|
def attempt_symlink_to(path, to_path):
|
||||||
"""Try to make a symlink from "path" to "to_path", skipping in case this platform
|
"""Try to make a symlink from "path" to "to_path", skipping in case this platform
|
||||||
does not support it or we don't have sufficient privileges (common on Windows)."""
|
does not support it or we don't have sufficient privileges (common on Windows)."""
|
||||||
if sys.platform.startswith("win") and six.PY2:
|
|
||||||
pytest.skip("pathlib for some reason cannot make symlinks on Python 2")
|
|
||||||
try:
|
try:
|
||||||
Path(path).symlink_to(Path(to_path))
|
Path(path).symlink_to(Path(to_path))
|
||||||
except OSError:
|
except OSError:
|
||||||
|
|
|
@ -459,9 +459,6 @@ class TestTrialUnittest(object):
|
||||||
pass
|
pass
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
from _pytest.compat import _is_unittest_unexpected_success_a_failure
|
|
||||||
|
|
||||||
should_fail = _is_unittest_unexpected_success_a_failure()
|
|
||||||
result = testdir.runpytest("-rxs", *self.ignore_unclosed_socket_warning)
|
result = testdir.runpytest("-rxs", *self.ignore_unclosed_socket_warning)
|
||||||
result.stdout.fnmatch_lines_random(
|
result.stdout.fnmatch_lines_random(
|
||||||
[
|
[
|
||||||
|
@ -472,12 +469,10 @@ class TestTrialUnittest(object):
|
||||||
"*i2wanto*",
|
"*i2wanto*",
|
||||||
"*sys.version_info*",
|
"*sys.version_info*",
|
||||||
"*skip_in_method*",
|
"*skip_in_method*",
|
||||||
"*1 failed*4 skipped*3 xfailed*"
|
"*1 failed*4 skipped*3 xfailed*",
|
||||||
if should_fail
|
|
||||||
else "*4 skipped*3 xfail*1 xpass*",
|
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
assert result.ret == (1 if should_fail else 0)
|
assert result.ret == 1
|
||||||
|
|
||||||
def test_trial_error(self, testdir):
|
def test_trial_error(self, testdir):
|
||||||
testdir.makepyfile(
|
testdir.makepyfile(
|
||||||
|
@ -745,22 +740,17 @@ def test_unittest_expected_failure_for_passing_test_is_fail(testdir, runner):
|
||||||
unittest.main()
|
unittest.main()
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
from _pytest.compat import _is_unittest_unexpected_success_a_failure
|
|
||||||
|
|
||||||
should_fail = _is_unittest_unexpected_success_a_failure()
|
|
||||||
if runner == "pytest":
|
if runner == "pytest":
|
||||||
result = testdir.runpytest("-rxX")
|
result = testdir.runpytest("-rxX")
|
||||||
result.stdout.fnmatch_lines(
|
result.stdout.fnmatch_lines(
|
||||||
[
|
["*MyTestCase*test_passing_test_is_fail*", "*1 failed*"]
|
||||||
"*MyTestCase*test_passing_test_is_fail*",
|
|
||||||
"*1 failed*" if should_fail else "*1 xpassed*",
|
|
||||||
]
|
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
result = testdir.runpython(script)
|
result = testdir.runpython(script)
|
||||||
result.stderr.fnmatch_lines(["*1 test in*", "*(unexpected successes=1)*"])
|
result.stderr.fnmatch_lines(["*1 test in*", "*(unexpected successes=1)*"])
|
||||||
|
|
||||||
assert result.ret == (1 if should_fail else 0)
|
assert result.ret == 1
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
|
|
|
@ -1,11 +1,8 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
import sys
|
|
||||||
import warnings
|
import warnings
|
||||||
|
|
||||||
import six
|
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
WARNINGS_SUMMARY_HEADER = "warnings summary"
|
WARNINGS_SUMMARY_HEADER = "warnings summary"
|
||||||
|
@ -126,9 +123,6 @@ def test_ignore(testdir, pyfile_with_warnings, method):
|
||||||
assert WARNINGS_SUMMARY_HEADER not in result.stdout.str()
|
assert WARNINGS_SUMMARY_HEADER not in result.stdout.str()
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.skipif(
|
|
||||||
sys.version_info < (3, 0), reason="warnings message is unicode is ok in python3"
|
|
||||||
)
|
|
||||||
@pytest.mark.filterwarnings("always")
|
@pytest.mark.filterwarnings("always")
|
||||||
def test_unicode(testdir, pyfile_with_warnings):
|
def test_unicode(testdir, pyfile_with_warnings):
|
||||||
testdir.makepyfile(
|
testdir.makepyfile(
|
||||||
|
@ -157,68 +151,6 @@ def test_unicode(testdir, pyfile_with_warnings):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.skipif(
|
|
||||||
sys.version_info >= (3, 0),
|
|
||||||
reason="warnings message is broken as it is not str instance",
|
|
||||||
)
|
|
||||||
def test_py2_unicode(testdir, pyfile_with_warnings):
|
|
||||||
if getattr(sys, "pypy_version_info", ())[:2] == (5, 9) and sys.platform.startswith(
|
|
||||||
"win"
|
|
||||||
):
|
|
||||||
pytest.xfail("fails with unicode error on PyPy2 5.9 and Windows (#2905)")
|
|
||||||
testdir.makepyfile(
|
|
||||||
"""
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
import warnings
|
|
||||||
import pytest
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def fix():
|
|
||||||
warnings.warn(u"测试")
|
|
||||||
yield
|
|
||||||
|
|
||||||
@pytest.mark.filterwarnings('always')
|
|
||||||
def test_func(fix):
|
|
||||||
pass
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
result = testdir.runpytest()
|
|
||||||
result.stdout.fnmatch_lines(
|
|
||||||
[
|
|
||||||
"*== %s ==*" % WARNINGS_SUMMARY_HEADER,
|
|
||||||
"*test_py2_unicode.py:8: UserWarning: \\u6d4b\\u8bd5",
|
|
||||||
'*warnings.warn(u"\u6d4b\u8bd5")',
|
|
||||||
"*warnings.py:*: UnicodeWarning: Warning is using unicode non*",
|
|
||||||
"* 1 passed, 2 warnings*",
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def test_py2_unicode_ascii(testdir):
|
|
||||||
"""Ensure that our warning about 'unicode warnings containing non-ascii messages'
|
|
||||||
does not trigger with ascii-convertible messages"""
|
|
||||||
testdir.makeini("[pytest]")
|
|
||||||
testdir.makepyfile(
|
|
||||||
"""
|
|
||||||
import pytest
|
|
||||||
import warnings
|
|
||||||
|
|
||||||
@pytest.mark.filterwarnings('always')
|
|
||||||
def test_func():
|
|
||||||
warnings.warn(u"hello")
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
result = testdir.runpytest()
|
|
||||||
result.stdout.fnmatch_lines(
|
|
||||||
[
|
|
||||||
"*== %s ==*" % WARNINGS_SUMMARY_HEADER,
|
|
||||||
'*warnings.warn(u"hello")',
|
|
||||||
"* 1 passed, 1 warnings in*",
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def test_works_with_filterwarnings(testdir):
|
def test_works_with_filterwarnings(testdir):
|
||||||
"""Ensure our warnings capture does not mess with pre-installed filters (#2430)."""
|
"""Ensure our warnings capture does not mess with pre-installed filters (#2430)."""
|
||||||
testdir.makepyfile(
|
testdir.makepyfile(
|
||||||
|
@ -569,33 +501,6 @@ class TestDeprecationWarningsByDefault:
|
||||||
assert WARNINGS_SUMMARY_HEADER not in result.stdout.str()
|
assert WARNINGS_SUMMARY_HEADER not in result.stdout.str()
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.skipif(six.PY3, reason="Python 2 only issue")
|
|
||||||
def test_infinite_loop_warning_against_unicode_usage_py2(testdir):
|
|
||||||
"""
|
|
||||||
We need to be careful when raising the warning about unicode usage with "warnings.warn"
|
|
||||||
because it might be overwritten by users and this itself causes another warning (#3691).
|
|
||||||
"""
|
|
||||||
testdir.makepyfile(
|
|
||||||
"""
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
import warnings
|
|
||||||
import pytest
|
|
||||||
|
|
||||||
def _custom_showwarning(message, *a, **b):
|
|
||||||
return "WARNING: {}".format(message)
|
|
||||||
|
|
||||||
warnings.formatwarning = _custom_showwarning
|
|
||||||
|
|
||||||
@pytest.mark.filterwarnings("default")
|
|
||||||
def test_custom_warning_formatter():
|
|
||||||
warnings.warn("¥")
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
result = testdir.runpytest_subprocess()
|
|
||||||
result.stdout.fnmatch_lines(["*1 passed, * warnings in*"])
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("change_default", [None, "ini", "cmdline"])
|
@pytest.mark.parametrize("change_default", [None, "ini", "cmdline"])
|
||||||
def test_removed_in_pytest4_warning_as_error(testdir, change_default):
|
def test_removed_in_pytest4_warning_as_error(testdir, change_default):
|
||||||
testdir.makepyfile(
|
testdir.makepyfile(
|
||||||
|
|
19
tox.ini
19
tox.ini
|
@ -5,16 +5,13 @@ distshare = {homedir}/.tox/distshare
|
||||||
# make sure to update environment list in travis.yml and appveyor.yml
|
# make sure to update environment list in travis.yml and appveyor.yml
|
||||||
envlist =
|
envlist =
|
||||||
linting
|
linting
|
||||||
py27
|
|
||||||
py34
|
|
||||||
py35
|
py35
|
||||||
py36
|
py36
|
||||||
py37
|
py37
|
||||||
py38
|
py38
|
||||||
pypy
|
pypy
|
||||||
pypy3
|
pypy3
|
||||||
{py27,py37}-{pexpect,xdist,twisted,numpy,pluggymaster}
|
py37-{pexpect,xdist,twisted,numpy,pluggymaster}
|
||||||
py27-nobyte-xdist
|
|
||||||
doctesting
|
doctesting
|
||||||
py37-freeze
|
py37-freeze
|
||||||
docs
|
docs
|
||||||
|
@ -56,15 +53,6 @@ deps =
|
||||||
{env:_PYTEST_TOX_EXTRA_DEP:}
|
{env:_PYTEST_TOX_EXTRA_DEP:}
|
||||||
platform = {env:_PYTEST_TOX_PLATFORM:.*}
|
platform = {env:_PYTEST_TOX_PLATFORM:.*}
|
||||||
|
|
||||||
[testenv:py27-subprocess]
|
|
||||||
deps =
|
|
||||||
pytest-xdist>=1.13
|
|
||||||
py27: mock
|
|
||||||
nose
|
|
||||||
commands =
|
|
||||||
pytest -n auto --runpytest=subprocess {posargs}
|
|
||||||
|
|
||||||
|
|
||||||
[testenv:linting]
|
[testenv:linting]
|
||||||
skip_install = True
|
skip_install = True
|
||||||
basepython = python3
|
basepython = python3
|
||||||
|
@ -109,11 +97,6 @@ commands =
|
||||||
rm -rf {envdir}/.pytest_cache
|
rm -rf {envdir}/.pytest_cache
|
||||||
make regen
|
make regen
|
||||||
|
|
||||||
[testenv:jython]
|
|
||||||
changedir = testing
|
|
||||||
commands =
|
|
||||||
{envpython} {envbindir}/py.test-jython {posargs}
|
|
||||||
|
|
||||||
[testenv:py37-freeze]
|
[testenv:py37-freeze]
|
||||||
changedir = testing/freeze
|
changedir = testing/freeze
|
||||||
# Disable PEP 517 with pip, which does not work with PyInstaller currently.
|
# Disable PEP 517 with pip, which does not work with PyInstaller currently.
|
||||||
|
|
Loading…
Reference in New Issue