commit
602a290fcc
36
.travis.yml
36
.travis.yml
|
@ -19,18 +19,13 @@ install:
|
|||
jobs:
|
||||
include:
|
||||
# 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
|
||||
language: generic
|
||||
# Coverage for:
|
||||
# - 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
|
||||
env: TOXENV=py37-xdist PYTEST_COVERAGE=1
|
||||
before_install:
|
||||
- which python3
|
||||
- python3 -V
|
||||
|
@ -38,20 +33,14 @@ jobs:
|
|||
- python -V
|
||||
- test $(python -c 'import sys; print("%d%d" % sys.version_info[0:2])') = 37
|
||||
|
||||
# Full run of latest (major) supported versions, without xdist.
|
||||
- env: TOXENV=py27
|
||||
python: '2.7'
|
||||
# Full run of latest supported version, without xdist.
|
||||
- env: TOXENV=py37
|
||||
python: '3.7'
|
||||
|
||||
# Coverage tracking is slow with pypy, skip it.
|
||||
- env: TOXENV=pypy-xdist
|
||||
python: 'pypy'
|
||||
- env: TOXENV=pypy3-xdist
|
||||
python: 'pypy3'
|
||||
|
||||
- env: TOXENV=py34-xdist
|
||||
python: '3.4'
|
||||
- env: TOXENV=py35-xdist
|
||||
python: '3.5'
|
||||
|
||||
|
@ -62,12 +51,6 @@ jobs:
|
|||
# Empty PYTEST_ADDOPTS to run this non-verbose.
|
||||
- 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.
|
||||
# Coverage for:
|
||||
# - test_sys_breakpoint_interception (via pexpect).
|
||||
|
@ -81,12 +64,7 @@ jobs:
|
|||
if: type = cron
|
||||
|
||||
- stage: baseline
|
||||
# Coverage for:
|
||||
# - _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
|
||||
env: TOXENV=py36-xdist
|
||||
python: '3.6'
|
||||
- env: TOXENV=linting,docs,doctesting PYTEST_COVERAGE=1
|
||||
cache:
|
||||
|
|
|
@ -85,7 +85,7 @@ Features
|
|||
- 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;
|
||||
|
||||
- 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;
|
||||
|
||||
|
|
|
@ -4,7 +4,6 @@ trigger:
|
|||
|
||||
variables:
|
||||
PYTEST_ADDOPTS: "--junitxml=build/test-results/$(tox.env).xml -vv"
|
||||
python.needs_vc: False
|
||||
COVERAGE_FILE: "$(Build.Repository.LocalPath)/.coverage"
|
||||
COVERAGE_PROCESS_START: "$(Build.Repository.LocalPath)/.coveragerc"
|
||||
PYTEST_COVERAGE: '0'
|
||||
|
@ -16,44 +15,10 @@ jobs:
|
|||
vmImage: "vs2017-win2016"
|
||||
strategy:
|
||||
matrix:
|
||||
py27:
|
||||
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 disabled for now: #5279 --
|
||||
# pypy3:
|
||||
# python.version: '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:
|
||||
python.version: '3.5'
|
||||
tox.env: 'py35-xdist'
|
||||
|
@ -87,10 +52,6 @@ jobs:
|
|||
versionSpec: '$(python.version)'
|
||||
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
|
||||
displayName: 'Install tox'
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
<li><a href="{{ pathto('changelog') }}">Changelog</a></li>
|
||||
<li><a href="{{ pathto('contributing') }}">Contributing</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('contact') }}">Contact Channels</a></li>
|
||||
</ul>
|
||||
|
|
|
@ -288,8 +288,7 @@ its test methods:
|
|||
This is equivalent to directly applying the decorator to the
|
||||
two test functions.
|
||||
|
||||
To remain backward-compatible with Python 2.4 you can also set a
|
||||
``pytestmark`` attribute on a TestClass like this:
|
||||
Due to legacy reasons, it is possible to set the ``pytestmark`` attribute on a TestClass like this:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
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/>`_
|
||||
|
||||
|
|
|
@ -7,8 +7,7 @@ Good Integration Practices
|
|||
Install package with pip
|
||||
-------------------------------------------------
|
||||
|
||||
For development, we recommend you use venv_ for virtual environments
|
||||
(or virtualenv_ for Python 2.7) and
|
||||
For development, we recommend you use venv_ for virtual environments and
|
||||
pip_ for installing your application and any dependencies,
|
||||
as well as the ``pytest`` package itself.
|
||||
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;
|
||||
|
||||
- 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;
|
||||
|
||||
|
|
14
setup.cfg
14
setup.cfg
|
@ -1,5 +1,4 @@
|
|||
[metadata]
|
||||
|
||||
name = pytest
|
||||
description = pytest: simple powerful testing with Python
|
||||
long_description = file: README.rst
|
||||
|
@ -23,13 +22,11 @@ classifiers =
|
|||
Topic :: Software Development :: Testing
|
||||
Topic :: Software Development :: Libraries
|
||||
Topic :: Utilities
|
||||
Programming Language :: Python :: 2
|
||||
Programming Language :: Python :: 2.7
|
||||
Programming Language :: Python :: 3
|
||||
Programming Language :: Python :: 3.4
|
||||
Programming Language :: Python :: 3 :: Only
|
||||
Programming Language :: Python :: 3.5
|
||||
Programming Language :: Python :: 3.6
|
||||
Programming Language :: Python :: 3.7
|
||||
Programming Language :: Python :: 3.8
|
||||
platforms = unix, linux, osx, cygwin, win32
|
||||
|
||||
[options]
|
||||
|
@ -43,8 +40,7 @@ packages =
|
|||
_pytest.mark
|
||||
|
||||
py_modules = pytest
|
||||
python_requires = >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*
|
||||
|
||||
python_requires = >=3.5
|
||||
|
||||
[options.entry_points]
|
||||
console_scripts =
|
||||
|
@ -59,13 +55,9 @@ all_files = 1
|
|||
[upload_sphinx]
|
||||
upload-dir = doc/en/build/html
|
||||
|
||||
[bdist_wheel]
|
||||
universal = 1
|
||||
|
||||
[check-manifest]
|
||||
ignore =
|
||||
_pytest/_version.py
|
||||
|
||||
|
||||
[devpi:upload]
|
||||
formats = sdist.tgz,bdist_wheel
|
||||
|
|
6
setup.py
6
setup.py
|
@ -8,10 +8,8 @@ INSTALL_REQUIRES = [
|
|||
"six>=1.10.0",
|
||||
"packaging",
|
||||
"attrs>=17.4.0",
|
||||
'more-itertools>=4.0.0,<6.0.0;python_version<="2.7"',
|
||||
'more-itertools>=4.0.0;python_version>"2.7"',
|
||||
"more-itertools>=4.0.0",
|
||||
"atomicwrites>=1.0",
|
||||
'funcsigs>=1.0;python_version<"3.0"',
|
||||
'pathlib2>=2.2.0;python_version<"3.6"',
|
||||
'colorama;sys_platform=="win32"',
|
||||
"pluggy>=0.12,<1.0",
|
||||
|
@ -30,9 +28,9 @@ def main():
|
|||
"testing": [
|
||||
"argcomplete",
|
||||
"hypothesis>=3.56",
|
||||
"mock",
|
||||
"nose",
|
||||
"requests",
|
||||
"mock;python_version=='2.7'",
|
||||
],
|
||||
},
|
||||
# fmt: on
|
||||
|
|
|
@ -9,25 +9,16 @@ import sys
|
|||
import traceback
|
||||
from inspect import CO_VARARGS
|
||||
from inspect import CO_VARKEYWORDS
|
||||
from traceback import format_exception_only
|
||||
from weakref import ref
|
||||
|
||||
import attr
|
||||
import pluggy
|
||||
import py
|
||||
from six import text_type
|
||||
|
||||
import _pytest
|
||||
from _pytest._io.saferepr import safeformat
|
||||
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):
|
||||
|
@ -208,8 +199,7 @@ class TracebackEntry(object):
|
|||
locals = property(getlocals, None, None, "locals of underlaying frame")
|
||||
|
||||
def getfirstlinesource(self):
|
||||
# on Jython this firstlineno can be -1 apparently
|
||||
return max(self.frame.code.firstlineno, 0)
|
||||
return self.frame.code.firstlineno
|
||||
|
||||
def getsource(self, astcache=None):
|
||||
""" return failing source code. """
|
||||
|
@ -391,9 +381,7 @@ class ExceptionInfo(object):
|
|||
help for navigating the traceback.
|
||||
"""
|
||||
|
||||
_assert_start_repr = (
|
||||
"AssertionError(u'assert " if _PY2 else "AssertionError('assert "
|
||||
)
|
||||
_assert_start_repr = "AssertionError('assert "
|
||||
|
||||
_excinfo = attr.ib()
|
||||
_striptext = attr.ib(default="")
|
||||
|
@ -558,11 +546,6 @@ class ExceptionInfo(object):
|
|||
loc = ReprFileLocation(entry.path, entry.lineno + 1, self.exconly())
|
||||
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):
|
||||
"""
|
||||
Check whether the regular expression 'regexp' is found in the string
|
||||
|
@ -692,8 +675,7 @@ class FormattedExcinfo(object):
|
|||
source = _pytest._code.Source("???")
|
||||
line_index = 0
|
||||
else:
|
||||
# entry.getfirstlinesource() can be -1, should be 0 on jython
|
||||
line_index = entry.lineno - max(entry.getfirstlinesource(), 0)
|
||||
line_index = entry.lineno - entry.getfirstlinesource()
|
||||
|
||||
lines = []
|
||||
style = entry._repr_style
|
||||
|
@ -733,7 +715,7 @@ class FormattedExcinfo(object):
|
|||
if self.tbfilter:
|
||||
traceback = traceback.filter()
|
||||
|
||||
if is_recursion_error(excinfo):
|
||||
if excinfo.errisinstance(RecursionError):
|
||||
traceback, extraline = self._truncate_recursive_traceback(traceback)
|
||||
else:
|
||||
extraline = None
|
||||
|
@ -769,7 +751,7 @@ class FormattedExcinfo(object):
|
|||
" Displaying first and last {max_frames} stack frames out of {total}."
|
||||
).format(
|
||||
exc_type=type(e).__name__,
|
||||
exc_msg=safe_str(e),
|
||||
exc_msg=str(e),
|
||||
max_frames=max_frames,
|
||||
total=len(traceback),
|
||||
)
|
||||
|
@ -784,64 +766,51 @@ class FormattedExcinfo(object):
|
|||
return traceback, extraline
|
||||
|
||||
def repr_excinfo(self, excinfo):
|
||||
if _PY2:
|
||||
reprtraceback = self.repr_traceback(excinfo)
|
||||
reprcrash = excinfo._getreprcrash()
|
||||
|
||||
return ReprExceptionInfo(reprtraceback, reprcrash)
|
||||
else:
|
||||
repr_chain = []
|
||||
e = excinfo.value
|
||||
descr = None
|
||||
seen = set()
|
||||
while e is not None and id(e) not in seen:
|
||||
seen.add(id(e))
|
||||
if excinfo:
|
||||
reprtraceback = self.repr_traceback(excinfo)
|
||||
reprcrash = excinfo._getreprcrash()
|
||||
else:
|
||||
# fallback to native repr if the exception doesn't have a traceback:
|
||||
# ExceptionInfo objects require a full traceback to work
|
||||
reprtraceback = ReprTracebackNative(
|
||||
traceback.format_exception(type(e), e, None)
|
||||
)
|
||||
reprcrash = None
|
||||
repr_chain = []
|
||||
e = excinfo.value
|
||||
descr = None
|
||||
seen = set()
|
||||
while e is not None and id(e) not in seen:
|
||||
seen.add(id(e))
|
||||
if excinfo:
|
||||
reprtraceback = self.repr_traceback(excinfo)
|
||||
reprcrash = excinfo._getreprcrash()
|
||||
else:
|
||||
# fallback to native repr if the exception doesn't have a traceback:
|
||||
# ExceptionInfo objects require a full traceback to work
|
||||
reprtraceback = ReprTracebackNative(
|
||||
traceback.format_exception(type(e), e, None)
|
||||
)
|
||||
reprcrash = None
|
||||
|
||||
repr_chain += [(reprtraceback, reprcrash, descr)]
|
||||
if e.__cause__ is not None and self.chain:
|
||||
e = e.__cause__
|
||||
excinfo = (
|
||||
ExceptionInfo((type(e), e, e.__traceback__))
|
||||
if e.__traceback__
|
||||
else None
|
||||
)
|
||||
descr = "The above exception was the direct cause of the following exception:"
|
||||
elif (
|
||||
e.__context__ is not None
|
||||
and not e.__suppress_context__
|
||||
and self.chain
|
||||
):
|
||||
e = e.__context__
|
||||
excinfo = (
|
||||
ExceptionInfo((type(e), e, e.__traceback__))
|
||||
if e.__traceback__
|
||||
else None
|
||||
)
|
||||
descr = "During handling of the above exception, another exception occurred:"
|
||||
else:
|
||||
e = None
|
||||
repr_chain.reverse()
|
||||
return ExceptionChainRepr(repr_chain)
|
||||
repr_chain += [(reprtraceback, reprcrash, descr)]
|
||||
if e.__cause__ is not None and self.chain:
|
||||
e = e.__cause__
|
||||
excinfo = (
|
||||
ExceptionInfo((type(e), e, e.__traceback__))
|
||||
if e.__traceback__
|
||||
else None
|
||||
)
|
||||
descr = "The above exception was the direct cause of the following exception:"
|
||||
elif (
|
||||
e.__context__ is not None and not e.__suppress_context__ and self.chain
|
||||
):
|
||||
e = e.__context__
|
||||
excinfo = (
|
||||
ExceptionInfo((type(e), e, e.__traceback__))
|
||||
if e.__traceback__
|
||||
else None
|
||||
)
|
||||
descr = "During handling of the above exception, another exception occurred:"
|
||||
else:
|
||||
e = None
|
||||
repr_chain.reverse()
|
||||
return ExceptionChainRepr(repr_chain)
|
||||
|
||||
|
||||
class TerminalRepr(object):
|
||||
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
|
||||
# information.
|
||||
io = py.io.TextIO()
|
||||
|
@ -1006,7 +975,7 @@ class ReprFuncArgs(TerminalRepr):
|
|||
if self.args:
|
||||
linesofar = ""
|
||||
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 linesofar:
|
||||
tw.line(linesofar)
|
||||
|
@ -1038,23 +1007,6 @@ def getrawcode(obj, trycall=True):
|
|||
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;
|
||||
# see filter_traceback
|
||||
# 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):
|
||||
"""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.hook = hook = rewrite.AssertionRewritingHook(config)
|
||||
sys.meta_path.insert(0, hook)
|
||||
|
|
|
@ -15,6 +15,7 @@ import string
|
|||
import struct
|
||||
import sys
|
||||
import types
|
||||
from importlib.util import spec_from_file_location
|
||||
|
||||
import atomicwrites
|
||||
import py
|
||||
|
@ -25,7 +26,6 @@ from _pytest.assertion import util
|
|||
from _pytest.assertion.util import ( # noqa: F401
|
||||
format_explanation as _format_explanation,
|
||||
)
|
||||
from _pytest.compat import spec_from_file_location
|
||||
from _pytest.pathlib import fnmatch_ex
|
||||
from _pytest.pathlib import PurePath
|
||||
|
||||
|
@ -35,8 +35,6 @@ if hasattr(imp, "get_tag"):
|
|||
else:
|
||||
if hasattr(sys, "pypy_version_info"):
|
||||
impl = "pypy"
|
||||
elif sys.platform == "java":
|
||||
impl = "jython"
|
||||
else:
|
||||
impl = "cpython"
|
||||
ver = sys.version_info
|
||||
|
@ -46,15 +44,6 @@ else:
|
|||
PYC_EXT = ".py" + (__debug__ and "c" or "o")
|
||||
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):
|
||||
"""PEP302 Import hook which rewrites asserts."""
|
||||
|
@ -364,37 +353,6 @@ def _rewrite_test(config, fn):
|
|||
source = fn.read("rb")
|
||||
except EnvironmentError:
|
||||
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:
|
||||
tree = ast.parse(source, filename=fn.strpath)
|
||||
except SyntaxError:
|
||||
|
@ -737,7 +695,7 @@ class AssertionRewriter(ast.NodeVisitor):
|
|||
"""Call a helper in this module."""
|
||||
py_name = ast.Name("@pytest_ar", 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):
|
||||
"""Return the builtin called *name*."""
|
||||
|
@ -847,11 +805,9 @@ class AssertionRewriter(ast.NodeVisitor):
|
|||
msg = self.pop_format_context(template)
|
||||
fmt = self.helper("_format_explanation", msg)
|
||||
err_name = ast.Name("AssertionError", ast.Load())
|
||||
exc = ast_Call(err_name, [fmt], [])
|
||||
if sys.version_info[0] >= 3:
|
||||
raise_ = ast.Raise(exc, None)
|
||||
else:
|
||||
raise_ = ast.Raise(exc, None, None)
|
||||
exc = ast.Call(err_name, [fmt], [])
|
||||
raise_ = ast.Raise(exc, None)
|
||||
|
||||
body.append(raise_)
|
||||
# Clear temporary variables by setting them to None.
|
||||
if self.variables:
|
||||
|
@ -893,7 +849,7 @@ warn_explicit(
|
|||
def visit_Name(self, name):
|
||||
# Display the repr of the name if it's a local variable or
|
||||
# _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])
|
||||
dorepr = self.helper("_should_repr_global_name", name)
|
||||
test = ast.BoolOp(ast.Or(), [inlocs, dorepr])
|
||||
|
@ -920,7 +876,7 @@ warn_explicit(
|
|||
res, expl = self.visit(v)
|
||||
body.append(ast.Assign([ast.Name(res_var, ast.Store())], res))
|
||||
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))
|
||||
if i < levels:
|
||||
cond = res
|
||||
|
@ -959,9 +915,9 @@ warn_explicit(
|
|||
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):
|
||||
return self._visit_all(call)
|
||||
|
@ -1013,46 +969,6 @@ warn_explicit(
|
|||
new_starred = ast.Starred(res, starred.ctx)
|
||||
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):
|
||||
if not isinstance(attr.ctx, ast.Load):
|
||||
return self.generic_visit(attr)
|
||||
|
|
|
@ -5,11 +5,11 @@ from __future__ import division
|
|||
from __future__ import print_function
|
||||
|
||||
import pprint
|
||||
from collections.abc import Sequence
|
||||
|
||||
import six
|
||||
|
||||
import _pytest._code
|
||||
from ..compat import Sequence
|
||||
from _pytest import outcomes
|
||||
from _pytest._io.saferepr import saferepr
|
||||
|
||||
|
|
|
@ -18,7 +18,6 @@ import py
|
|||
import six
|
||||
|
||||
import pytest
|
||||
from .compat import _PY2 as PY2
|
||||
from .pathlib import Path
|
||||
from .pathlib import resolve_from_str
|
||||
from .pathlib import rmtree
|
||||
|
@ -129,7 +128,7 @@ class Cache(object):
|
|||
if not cache_dir_exists_already:
|
||||
self._ensure_supporting_files()
|
||||
try:
|
||||
f = path.open("wb" if PY2 else "w")
|
||||
f = path.open("w")
|
||||
except (IOError, OSError):
|
||||
self.warn("cache could not write path {path}", path=path)
|
||||
else:
|
||||
|
|
|
@ -18,7 +18,6 @@ from tempfile import TemporaryFile
|
|||
import six
|
||||
|
||||
import pytest
|
||||
from _pytest.compat import _PY3
|
||||
from _pytest.compat import CaptureIO
|
||||
|
||||
patchsysdict = {0: "stdin", 1: "stdout", 2: "stderr"}
|
||||
|
@ -283,10 +282,6 @@ def capsysbinary(request):
|
|||
``out`` and ``err`` will be ``bytes`` objects.
|
||||
"""
|
||||
_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:
|
||||
yield fixture
|
||||
|
||||
|
@ -434,7 +429,7 @@ class EncodedFile(object):
|
|||
def write(self, obj):
|
||||
if isinstance(obj, six.text_type):
|
||||
obj = obj.encode(self.encoding, "replace")
|
||||
elif _PY3:
|
||||
else:
|
||||
raise TypeError(
|
||||
"write() argument must be str, not {}".format(type(obj).__name__)
|
||||
)
|
||||
|
@ -608,7 +603,7 @@ class FDCaptureBinary(object):
|
|||
os.dup2(targetfd_save, self.targetfd)
|
||||
os.close(targetfd_save)
|
||||
self.syscapture.done()
|
||||
_attempt_to_close_capture_file(self.tmpfile)
|
||||
self.tmpfile.close()
|
||||
self._state = "done"
|
||||
|
||||
def suspend(self):
|
||||
|
@ -681,7 +676,7 @@ class SysCapture(object):
|
|||
def done(self):
|
||||
setattr(sys, self.name, self._old)
|
||||
del self._old
|
||||
_attempt_to_close_capture_file(self.tmpfile)
|
||||
self.tmpfile.close()
|
||||
self._state = "done"
|
||||
|
||||
def suspend(self):
|
||||
|
@ -738,10 +733,7 @@ class DontReadFromInput(six.Iterator):
|
|||
|
||||
@property
|
||||
def buffer(self):
|
||||
if sys.version_info >= (3, 0):
|
||||
return self
|
||||
else:
|
||||
raise AttributeError("redirected stdin has no attribute buffer")
|
||||
return self
|
||||
|
||||
|
||||
def _colorama_workaround():
|
||||
|
@ -837,14 +829,3 @@ def _py36_windowsconsoleio_workaround(stream):
|
|||
sys.stdin = _reopen_stdio(sys.stdin, "rb")
|
||||
sys.stdout = _reopen_stdio(sys.stdout, "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 print_function
|
||||
|
||||
import codecs
|
||||
import functools
|
||||
import inspect
|
||||
import io
|
||||
import re
|
||||
import sys
|
||||
from contextlib import contextmanager
|
||||
from inspect import Parameter
|
||||
from inspect import signature
|
||||
|
||||
import py
|
||||
import six
|
||||
from six import text_type
|
||||
|
||||
import _pytest
|
||||
from _pytest._io.saferepr import saferepr
|
||||
from _pytest.outcomes import fail
|
||||
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()
|
||||
|
||||
PY35 = sys.version_info[:2] >= (3, 5)
|
||||
PY36 = sys.version_info[:2] >= (3, 6)
|
||||
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
|
||||
MODULE_NOT_FOUND_ERROR = (
|
||||
"ModuleNotFoundError" if sys.version_info[:2] >= (3, 6) else "ImportError"
|
||||
)
|
||||
|
||||
|
||||
def _format_args(func):
|
||||
|
@ -195,72 +164,36 @@ def _translate_non_printable(s):
|
|||
return s.translate(_non_printable_ascii_translate_table)
|
||||
|
||||
|
||||
if _PY3:
|
||||
STRING_TYPES = bytes, str
|
||||
UNICODE_TYPES = six.text_type
|
||||
STRING_TYPES = bytes, str
|
||||
|
||||
if PY35:
|
||||
|
||||
def _bytes_to_ascii(val):
|
||||
return val.decode("ascii", "backslashreplace")
|
||||
def _bytes_to_ascii(val):
|
||||
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:
|
||||
|
||||
def _bytes_to_ascii(val):
|
||||
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)
|
||||
ret = val.encode("unicode_escape").decode("ascii")
|
||||
return _translate_non_printable(ret)
|
||||
|
||||
|
||||
class _PytestWrapper(object):
|
||||
|
@ -357,36 +290,6 @@ def safe_isclass(obj):
|
|||
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 = (
|
||||
"Collector",
|
||||
"Module",
|
||||
|
@ -410,27 +313,14 @@ def _setup_collect_fakemodule():
|
|||
setattr(pytest.collect, attr, getattr(pytest, attr))
|
||||
|
||||
|
||||
if _PY2:
|
||||
# Without this the test_dupfile_on_textio will fail, otherwise CaptureIO could directly inherit from StringIO.
|
||||
from py.io import TextIO
|
||||
class CaptureIO(io.TextIOWrapper):
|
||||
def __init__(self):
|
||||
super(CaptureIO, self).__init__(
|
||||
io.BytesIO(), encoding="UTF-8", newline="", write_through=True
|
||||
)
|
||||
|
||||
class CaptureIO(TextIO):
|
||||
@property
|
||||
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")
|
||||
def getvalue(self):
|
||||
return self.buffer.getvalue().decode("UTF-8")
|
||||
|
||||
|
||||
class FuncargnamesCompatAttr(object):
|
||||
|
@ -442,16 +332,3 @@ class FuncargnamesCompatAttr(object):
|
|||
def funcargnames(self):
|
||||
""" alias attribute for ``fixturenames`` for pre-2.3 compatibility"""
|
||||
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 types
|
||||
import warnings
|
||||
from functools import lru_cache
|
||||
|
||||
import importlib_metadata
|
||||
import py
|
||||
|
@ -31,8 +32,6 @@ from .findpaths import exists
|
|||
from _pytest import deprecated
|
||||
from _pytest._code import ExceptionInfo
|
||||
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 Skipped
|
||||
from _pytest.warning_types import PytestConfigWarning
|
||||
|
@ -73,7 +72,7 @@ def main(args=None, plugins=None):
|
|||
if exc_info.traceback
|
||||
else exc_info.exconly()
|
||||
)
|
||||
formatted_tb = safe_str(exc_repr)
|
||||
formatted_tb = str(exc_repr)
|
||||
for line in formatted_tb.splitlines():
|
||||
tw.line(line.rstrip(), red=True)
|
||||
return 4
|
||||
|
@ -403,12 +402,6 @@ class PytestPluginManager(PluginManager):
|
|||
else:
|
||||
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
|
||||
# and allow users to opt into looking into the rootdir parent
|
||||
# directories instead of requiring to specify confcutdir
|
||||
|
@ -566,7 +559,7 @@ class PytestPluginManager(PluginManager):
|
|||
except ImportError as e:
|
||||
new_exc_message = 'Error importing plugin "%s": %s' % (
|
||||
modname,
|
||||
safe_str(e.args[0]),
|
||||
str(e.args[0]),
|
||||
)
|
||||
new_exc = ImportError(new_exc_message)
|
||||
tb = sys.exc_info()[2]
|
||||
|
|
|
@ -333,7 +333,6 @@ class DoctestTextfile(pytest.Module):
|
|||
checker=_get_checker(),
|
||||
continue_on_failure=_get_continue_on_failure(self.config),
|
||||
)
|
||||
_fix_spoof_python2(runner, encoding)
|
||||
|
||||
parser = doctest.DocTestParser()
|
||||
test = parser.get_doctest(text, globs, name, filename, 0)
|
||||
|
@ -539,32 +538,6 @@ def _get_report_choice(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")
|
||||
def doctest_namespace():
|
||||
"""
|
||||
|
|
|
@ -1303,11 +1303,7 @@ class FixtureManager(object):
|
|||
# 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
|
||||
# when pytest itself calls the fixture function
|
||||
if six.PY2 and unittest:
|
||||
# hack on Python 2 because of the unbound methods
|
||||
obj = get_real_func(obj)
|
||||
else:
|
||||
obj = get_real_method(obj, holderobj)
|
||||
obj = get_real_method(obj, holderobj)
|
||||
|
||||
fixture_def = FixtureDef(
|
||||
self,
|
||||
|
|
|
@ -26,10 +26,6 @@ import pytest
|
|||
from _pytest import nodes
|
||||
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):
|
||||
pass
|
||||
|
|
|
@ -43,10 +43,7 @@ class ColoredLevelFormatter(logging.Formatter):
|
|||
|
||||
def __init__(self, terminalwriter, *args, **kwargs):
|
||||
super(ColoredLevelFormatter, self).__init__(*args, **kwargs)
|
||||
if six.PY2:
|
||||
self._original_fmt = self._fmt
|
||||
else:
|
||||
self._original_fmt = self._style._fmt
|
||||
self._original_fmt = self._style._fmt
|
||||
self._level_to_fmt_mapping = {}
|
||||
|
||||
levelname_fmt_match = self.LEVELNAME_FMT_REGEX.search(self._fmt)
|
||||
|
@ -70,10 +67,7 @@ class ColoredLevelFormatter(logging.Formatter):
|
|||
|
||||
def format(self, record):
|
||||
fmt = self._level_to_fmt_mapping.get(record.levelno, self._original_fmt)
|
||||
if six.PY2:
|
||||
self._fmt = fmt
|
||||
else:
|
||||
self._style._fmt = fmt
|
||||
self._style._fmt = fmt
|
||||
return super(ColoredLevelFormatter, self).format(record)
|
||||
|
||||
|
||||
|
|
|
@ -4,7 +4,6 @@ from __future__ import absolute_import
|
|||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
|
||||
import contextlib
|
||||
import fnmatch
|
||||
import functools
|
||||
import os
|
||||
|
@ -342,46 +341,6 @@ def pytest_collection_modifyitems(items, config):
|
|||
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):
|
||||
def __init__(self, fspath, pm, remove_mods):
|
||||
self.fspath = fspath
|
||||
|
@ -662,23 +621,14 @@ class Session(nodes.FSCollector):
|
|||
ihook.pytest_collect_directory(path=dirpath, parent=self)
|
||||
return True
|
||||
|
||||
if six.PY2:
|
||||
|
||||
@staticmethod
|
||||
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)
|
||||
@staticmethod
|
||||
def _visit_filter(f):
|
||||
return f.check(file=1)
|
||||
|
||||
def _tryconvertpyarg(self, x):
|
||||
"""Convert a dotted module name to path."""
|
||||
try:
|
||||
with _patched_find_module():
|
||||
loader = pkgutil.find_loader(x)
|
||||
loader = pkgutil.find_loader(x)
|
||||
except ImportError:
|
||||
return x
|
||||
if loader is None:
|
||||
|
@ -686,8 +636,7 @@ class Session(nodes.FSCollector):
|
|||
# This method is sometimes invoked when AssertionRewritingHook, which
|
||||
# does not define a get_filename method, is already in place:
|
||||
try:
|
||||
with _patched_find_module():
|
||||
path = loader.get_filename(x)
|
||||
path = loader.get_filename(x)
|
||||
except AttributeError:
|
||||
# Retrieve path from AssertionRewritingHook:
|
||||
path = loader.modules[x][0].co_filename
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
import inspect
|
||||
import warnings
|
||||
from collections import namedtuple
|
||||
from collections.abc import MutableMapping
|
||||
from operator import attrgetter
|
||||
|
||||
import attr
|
||||
|
@ -9,7 +10,6 @@ import six
|
|||
|
||||
from ..compat import ascii_escaped
|
||||
from ..compat import getfslineno
|
||||
from ..compat import MappingMixin
|
||||
from ..compat import NOTSET
|
||||
from _pytest.deprecated import PYTEST_PARAM_UNKNOWN_KWARGS
|
||||
from _pytest.outcomes import fail
|
||||
|
@ -343,7 +343,7 @@ class MarkGenerator(object):
|
|||
MARK_GEN = MarkGenerator()
|
||||
|
||||
|
||||
class NodeKeywords(MappingMixin):
|
||||
class NodeKeywords(MutableMapping):
|
||||
def __init__(self, node):
|
||||
self.node = node
|
||||
self.parent = node.parent
|
||||
|
|
|
@ -222,15 +222,6 @@ class MonkeyPatch(object):
|
|||
self._setitem.append((dic, name, dic.get(name, notset)))
|
||||
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):
|
||||
""" Set environment variable ``name`` to ``value``. If ``prepend``
|
||||
is a character, read the current environment variable value
|
||||
|
@ -248,7 +239,6 @@ class MonkeyPatch(object):
|
|||
value = str(value)
|
||||
if prepend and name in os.environ:
|
||||
value = value + prepend + os.environ[name]
|
||||
self._warn_if_env_name_is_not_str(name)
|
||||
self.setitem(os.environ, name, value)
|
||||
|
||||
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
|
||||
environment variable is missing.
|
||||
"""
|
||||
self._warn_if_env_name_is_not_str(name)
|
||||
self.delitem(os.environ, name, raising=raising)
|
||||
|
||||
def syspath_prepend(self, path):
|
||||
|
@ -279,10 +268,9 @@ class MonkeyPatch(object):
|
|||
# since then the mtime based FileFinder cache (that gets created in
|
||||
# this case already) gets not invalidated when writing the new files
|
||||
# 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):
|
||||
""" 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 print_function
|
||||
|
||||
import sys
|
||||
import tempfile
|
||||
|
||||
import six
|
||||
|
@ -70,18 +69,10 @@ def create_new_paste(contents):
|
|||
:returns: url to the pasted contents
|
||||
"""
|
||||
import re
|
||||
from urllib.request import urlopen
|
||||
from urllib.parse import urlencode
|
||||
|
||||
if sys.version_info < (3, 0):
|
||||
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",
|
||||
}
|
||||
params = {"code": contents, "lexer": "python3", "expiry": "1week"}
|
||||
url = "https://bpaste.net"
|
||||
response = urlopen(url, data=urlencode(params).encode("ascii")).read()
|
||||
m = re.search(r'href="/raw/(\w+)"', response.decode("utf-8"))
|
||||
|
|
|
@ -8,7 +8,6 @@ import os
|
|||
import shutil
|
||||
import sys
|
||||
import uuid
|
||||
from functools import reduce
|
||||
from os.path import expanduser
|
||||
from os.path import expandvars
|
||||
from os.path import isabs
|
||||
|
@ -18,9 +17,8 @@ from posixpath import sep as posix_sep
|
|||
import six
|
||||
from six.moves import map
|
||||
|
||||
from .compat import PY36
|
||||
|
||||
if PY36:
|
||||
if sys.version_info[:2] >= (3, 6):
|
||||
from pathlib import Path, PurePath
|
||||
else:
|
||||
from pathlib2 import Path, PurePath
|
||||
|
@ -84,17 +82,6 @@ def parse_num(maybe_num):
|
|||
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):
|
||||
"""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"""
|
||||
for i in range(10):
|
||||
# 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_path = root.joinpath("{}{}".format(prefix, new_number))
|
||||
try:
|
||||
|
@ -230,7 +217,7 @@ def try_cleanup(path, consider_lock_dead_if_created_before):
|
|||
|
||||
def cleanup_candidates(root, prefix, keep):
|
||||
"""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
|
||||
paths = find_prefixed(root, prefix)
|
||||
paths, paths2 = itertools.tee(paths)
|
||||
|
|
|
@ -13,6 +13,7 @@ import subprocess
|
|||
import sys
|
||||
import time
|
||||
import traceback
|
||||
from collections.abc import Sequence
|
||||
from fnmatch import fnmatch
|
||||
from weakref import WeakKeyDictionary
|
||||
|
||||
|
@ -25,8 +26,6 @@ from _pytest._io.saferepr import saferepr
|
|||
from _pytest.assertion.rewrite import AssertionRewritingHook
|
||||
from _pytest.capture import MultiCapture
|
||||
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_OK
|
||||
from _pytest.main import Session
|
||||
|
@ -911,7 +910,7 @@ class Testdir(object):
|
|||
def _ensure_basetemp(self, args):
|
||||
args = list(args)
|
||||
for x in args:
|
||||
if safe_str(x).startswith("--basetemp"):
|
||||
if str(x).startswith("--basetemp"):
|
||||
break
|
||||
else:
|
||||
args.append("--basetemp=%s" % self.tmpdir.dirpath("basetemp"))
|
||||
|
@ -1124,25 +1123,11 @@ class Testdir(object):
|
|||
|
||||
if timeout is None:
|
||||
ret = popen.wait()
|
||||
elif six.PY3:
|
||||
else:
|
||||
try:
|
||||
ret = popen.wait(timeout)
|
||||
except subprocess.TimeoutExpired:
|
||||
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:
|
||||
f1.close()
|
||||
f2.close()
|
||||
|
|
|
@ -5,6 +5,7 @@ from __future__ import division
|
|||
from __future__ import print_function
|
||||
|
||||
import collections
|
||||
import enum
|
||||
import fnmatch
|
||||
import inspect
|
||||
import os
|
||||
|
@ -22,7 +23,6 @@ from _pytest import fixtures
|
|||
from _pytest import nodes
|
||||
from _pytest._code import filter_traceback
|
||||
from _pytest.compat import ascii_escaped
|
||||
from _pytest.compat import enum
|
||||
from _pytest.compat import get_default_arg_names
|
||||
from _pytest.compat import get_real_func
|
||||
from _pytest.compat import getfslineno
|
||||
|
@ -35,7 +35,6 @@ from _pytest.compat import NOTSET
|
|||
from _pytest.compat import REGEX_TYPE
|
||||
from _pytest.compat import safe_getattr
|
||||
from _pytest.compat import safe_isclass
|
||||
from _pytest.compat import safe_str
|
||||
from _pytest.compat import STRING_TYPES
|
||||
from _pytest.config import hookimpl
|
||||
from _pytest.main import FSHookProxy
|
||||
|
@ -531,7 +530,7 @@ class Module(nodes.File, PyCollector):
|
|||
if exc_info.traceback
|
||||
else exc_info.exconly()
|
||||
)
|
||||
formatted_tb = safe_str(exc_repr)
|
||||
formatted_tb = str(exc_repr)
|
||||
raise self.CollectError(
|
||||
"ImportError while importing test module '{fspath}'.\n"
|
||||
"Hint: make sure your test modules/packages have valid Python names.\n"
|
||||
|
|
|
@ -5,6 +5,9 @@ import math
|
|||
import pprint
|
||||
import sys
|
||||
import warnings
|
||||
from collections.abc import Iterable
|
||||
from collections.abc import Mapping
|
||||
from collections.abc import Sized
|
||||
from decimal import Decimal
|
||||
from numbers import Number
|
||||
|
||||
|
@ -15,9 +18,6 @@ from six.moves import zip
|
|||
import _pytest._code
|
||||
from _pytest import deprecated
|
||||
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.outcomes import fail
|
||||
|
||||
|
@ -81,9 +81,6 @@ class ApproxBase(object):
|
|||
def __ne__(self, actual):
|
||||
return not (actual == self)
|
||||
|
||||
if sys.version_info[0] == 2:
|
||||
__cmp__ = _cmp_raises_type_error
|
||||
|
||||
def _approx_scalar(self, x):
|
||||
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())
|
||||
return "approx({!r})".format(list_scalars)
|
||||
|
||||
if sys.version_info[0] == 2:
|
||||
__cmp__ = _cmp_raises_type_error
|
||||
|
||||
def __eq__(self, actual):
|
||||
import numpy as np
|
||||
|
||||
|
@ -251,10 +245,7 @@ class ApproxScalar(ApproxBase):
|
|||
except ValueError:
|
||||
vetted_tolerance = "???"
|
||||
|
||||
if sys.version_info[0] == 2:
|
||||
return "{} +- {}".format(self.expected, vetted_tolerance)
|
||||
else:
|
||||
return u"{} \u00b1 {}".format(self.expected, vetted_tolerance)
|
||||
return "{} \u00b1 {}".format(self.expected, vetted_tolerance)
|
||||
|
||||
def __eq__(self, actual):
|
||||
"""
|
||||
|
@ -736,8 +727,6 @@ class RaisesContext(object):
|
|||
fail(self.message)
|
||||
self.excinfo.__init__(tp)
|
||||
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:
|
||||
self.excinfo.match(self.match_expr)
|
||||
return suppress_exception
|
||||
|
|
|
@ -9,8 +9,6 @@ import re
|
|||
import sys
|
||||
import warnings
|
||||
|
||||
import six
|
||||
|
||||
import _pytest._code
|
||||
from _pytest.deprecated import PYTEST_WARNS_UNKNOWN_KWARGS
|
||||
from _pytest.deprecated import WARNS_EXEC
|
||||
|
@ -156,44 +154,13 @@ class WarningsRecorder(warnings.catch_warnings):
|
|||
raise RuntimeError("Cannot enter %r twice" % self)
|
||||
self._list = super(WarningsRecorder, self).__enter__()
|
||||
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
|
||||
|
||||
def __exit__(self, *exc_info):
|
||||
if not self._entered:
|
||||
__tracebackhide__ = True
|
||||
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)
|
||||
|
||||
# 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)
|
||||
# unitttest special case, see setting of _unexpectedsuccess
|
||||
if hasattr(item, "_unexpectedsuccess") and rep.when == "call":
|
||||
from _pytest.compat import _is_unittest_unexpected_success_a_failure
|
||||
|
||||
if item._unexpectedsuccess:
|
||||
rep.longrepr = "Unexpected success: {}".format(item._unexpectedsuccess)
|
||||
else:
|
||||
rep.longrepr = "Unexpected success"
|
||||
if _is_unittest_unexpected_success_a_failure():
|
||||
rep.outcome = "failed"
|
||||
else:
|
||||
rep.outcome = "passed"
|
||||
rep.wasxfail = rep.longrepr
|
||||
rep.outcome = "failed"
|
||||
|
||||
elif item.config.option.runxfail:
|
||||
pass # don't interefere
|
||||
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]
|
||||
while wcswidth(msg) > max_len_msg:
|
||||
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
|
||||
line += sep + msg
|
||||
return line
|
||||
|
|
|
@ -11,7 +11,6 @@ import warnings
|
|||
|
||||
import attr
|
||||
import py
|
||||
import six
|
||||
|
||||
import pytest
|
||||
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
|
||||
# does not work the same in all platforms (see #4427)
|
||||
# Path.absolute() exists, but it is not public (see https://bugs.python.org/issue25012)
|
||||
converter=attr.converters.optional(
|
||||
lambda p: Path(os.path.abspath(six.text_type(p)))
|
||||
)
|
||||
converter=attr.converters.optional(lambda p: Path(os.path.abspath(str(p))))
|
||||
)
|
||||
_trace = attr.ib()
|
||||
_basetemp = attr.ib(default=None)
|
||||
|
|
|
@ -113,23 +113,9 @@ class TestCaseFunction(Function):
|
|||
|
||||
def setup(self):
|
||||
self._testcase = self.parent.obj(self.name)
|
||||
self._fix_unittest_skip_decorator()
|
||||
if hasattr(self, "_request"):
|
||||
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):
|
||||
self._testcase = None
|
||||
|
||||
|
@ -208,12 +194,7 @@ class TestCaseFunction(Function):
|
|||
skip_why = getattr(
|
||||
self._testcase.__class__, "__unittest_skip_why__", ""
|
||||
) or getattr(testMethod, "__unittest_skip_why__", "")
|
||||
try: # PY3, unittest2 on PY2
|
||||
self._testcase._addSkip(self, self._testcase, skip_why)
|
||||
except TypeError: # PY2
|
||||
if sys.version_info[0] != 2:
|
||||
raise
|
||||
self._testcase._addSkip(self, skip_why)
|
||||
self._testcase._addSkip(self, self._testcase, skip_why)
|
||||
return True
|
||||
return False
|
||||
|
||||
|
|
|
@ -8,7 +8,6 @@ import warnings
|
|||
from contextlib import contextmanager
|
||||
|
||||
import pytest
|
||||
from _pytest import compat
|
||||
|
||||
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):
|
||||
"""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.
|
||||
"""
|
||||
"""Convert a warnings.WarningMessage to a string."""
|
||||
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(
|
||||
warn_msg,
|
||||
warning_message.category,
|
||||
|
@ -127,12 +112,6 @@ def warning_record_to_str(warning_message):
|
|||
warning_message.lineno,
|
||||
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
|
||||
|
||||
|
||||
|
|
|
@ -176,7 +176,6 @@ class TestGeneralUsage(object):
|
|||
result = testdir.runpytest(p)
|
||||
result.stdout.fnmatch_lines(
|
||||
[
|
||||
# XXX on jython this fails: "> import import_fails",
|
||||
"ImportError while importing test module*",
|
||||
"*No module named *does_not_work*",
|
||||
]
|
||||
|
@ -222,9 +221,7 @@ class TestGeneralUsage(object):
|
|||
" foo()",
|
||||
"conftest.py:2: in foo",
|
||||
" import qwerty",
|
||||
"E {}: No module named {q}qwerty{q}".format(
|
||||
exc_name, q="'" if six.PY3 else ""
|
||||
),
|
||||
"E {}: No module named 'qwerty'".format(exc_name),
|
||||
]
|
||||
)
|
||||
|
||||
|
@ -540,7 +537,6 @@ class TestInvocationVariants(object):
|
|||
result = testdir.runpython(p)
|
||||
assert result.ret == 0
|
||||
|
||||
@pytest.mark.xfail("sys.platform.startswith('java')")
|
||||
def test_pydoc(self, testdir):
|
||||
for name in ("py.test", "pytest"):
|
||||
result = testdir.runpython_c("import {};help({})".format(name, name))
|
||||
|
@ -783,10 +779,7 @@ class TestInvocationVariants(object):
|
|||
|
||||
d_local = testdir.mkdir("local")
|
||||
symlink_location = os.path.join(str(d_local), "lib")
|
||||
if six.PY2:
|
||||
os.symlink(str(d), symlink_location)
|
||||
else:
|
||||
os.symlink(str(d), symlink_location, target_is_directory=True)
|
||||
os.symlink(str(d), symlink_location, target_is_directory=True)
|
||||
|
||||
# The structure of the test directory is now:
|
||||
# .
|
||||
|
@ -1185,9 +1178,6 @@ def test_usage_error_code(testdir):
|
|||
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")
|
||||
def test_warn_on_async_function(testdir):
|
||||
testdir.makepyfile(
|
||||
|
|
|
@ -4,6 +4,7 @@ from __future__ import division
|
|||
from __future__ import print_function
|
||||
|
||||
import sys
|
||||
from unittest import mock
|
||||
|
||||
from six import text_type
|
||||
from test_excinfo import TWMock
|
||||
|
@ -11,11 +12,6 @@ from test_excinfo import TWMock
|
|||
import _pytest._code
|
||||
import pytest
|
||||
|
||||
try:
|
||||
import mock
|
||||
except ImportError:
|
||||
import unittest.mock as mock
|
||||
|
||||
|
||||
def test_ne():
|
||||
code1 = _pytest._code.Code(compile('foo = "bar"', "", "exec"))
|
||||
|
@ -92,21 +88,6 @@ def test_unicode_handling():
|
|||
|
||||
excinfo = pytest.raises(Exception, f)
|
||||
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():
|
||||
|
@ -202,10 +183,8 @@ class TestReprFuncArgs(object):
|
|||
|
||||
r = ReprFuncArgs(args)
|
||||
r.toterminal(tw)
|
||||
if sys.version_info[0] >= 3:
|
||||
assert (
|
||||
tw.lines[0]
|
||||
== 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"
|
||||
|
||||
assert (
|
||||
tw.lines[0]
|
||||
== r"unicode_string = São Paulo, utf8_string = b'S\xc3\xa3o Paulo'"
|
||||
)
|
||||
|
|
|
@ -17,7 +17,7 @@ import pytest
|
|||
from _pytest._code.code import ExceptionChainRepr
|
||||
from _pytest._code.code import ExceptionInfo
|
||||
from _pytest._code.code import FormattedExcinfo
|
||||
from _pytest._code.code import ReprExceptionInfo
|
||||
|
||||
|
||||
try:
|
||||
import importlib
|
||||
|
@ -26,8 +26,6 @@ except ImportError:
|
|||
else:
|
||||
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]))
|
||||
|
||||
|
||||
|
@ -146,7 +144,6 @@ class TestTraceback_f_g_h(object):
|
|||
assert s.startswith("def f():")
|
||||
assert s.endswith("raise ValueError")
|
||||
|
||||
@failsonjython
|
||||
def test_traceback_entry_getsource_in_construct(self):
|
||||
source = _pytest._code.Source(
|
||||
"""\
|
||||
|
@ -500,8 +497,7 @@ class TestFormattedExcinfo(object):
|
|||
excinfo = _pytest._code.ExceptionInfo.from_current()
|
||||
repr = pr.repr_excinfo(excinfo)
|
||||
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):
|
||||
pr = FormattedExcinfo()
|
||||
|
@ -519,8 +515,7 @@ raise ValueError()
|
|||
excinfo = _pytest._code.ExceptionInfo.from_current()
|
||||
repr = pr.repr_excinfo(excinfo)
|
||||
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):
|
||||
pr = FormattedExcinfo()
|
||||
|
@ -577,14 +572,12 @@ raise ValueError()
|
|||
fail = IOError()
|
||||
repr = pr.repr_excinfo(excinfo)
|
||||
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
|
||||
repr = pr.repr_excinfo(excinfo)
|
||||
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):
|
||||
p = FormattedExcinfo(showlocals=True)
|
||||
|
@ -828,9 +821,9 @@ raise ValueError()
|
|||
repr = p.repr_excinfo(excinfo)
|
||||
assert repr.reprtraceback
|
||||
assert len(repr.reprtraceback.reprentries) == len(reprtb.reprentries)
|
||||
if sys.version_info[0] >= 3:
|
||||
assert repr.chain[0][0]
|
||||
assert len(repr.chain[0][0].reprentries) == len(reprtb.reprentries)
|
||||
|
||||
assert repr.chain[0][0]
|
||||
assert len(repr.chain[0][0].reprentries) == len(reprtb.reprentries)
|
||||
assert repr.reprcrash.path.endswith("mod.py")
|
||||
assert repr.reprcrash.message == "ValueError: 0"
|
||||
|
||||
|
@ -916,13 +909,11 @@ raise ValueError()
|
|||
for style in ("short", "long", "no"):
|
||||
for showlocals in (True, False):
|
||||
repr = excinfo.getrepr(style=style, showlocals=showlocals)
|
||||
if sys.version_info[0] < 3:
|
||||
assert isinstance(repr, ReprExceptionInfo)
|
||||
assert repr.reprtraceback.style == style
|
||||
if sys.version_info[0] >= 3:
|
||||
assert isinstance(repr, ExceptionChainRepr)
|
||||
for repr in repr.chain:
|
||||
assert repr[0].style == style
|
||||
|
||||
assert isinstance(repr, ExceptionChainRepr)
|
||||
for repr in repr.chain:
|
||||
assert repr[0].style == style
|
||||
|
||||
def test_reprexcinfo_unicode(self):
|
||||
from _pytest._code.code import TerminalRepr
|
||||
|
@ -1133,7 +1124,6 @@ raise ValueError()
|
|||
msg.endswith("mod.py")
|
||||
assert tw.lines[20] == ":9: ValueError"
|
||||
|
||||
@pytest.mark.skipif("sys.version_info[0] < 3")
|
||||
def test_exc_chain_repr(self, importasmod):
|
||||
mod = importasmod(
|
||||
"""
|
||||
|
@ -1219,7 +1209,6 @@ raise ValueError()
|
|||
assert line.endswith("mod.py")
|
||||
assert tw.lines[47] == ":15: AttributeError"
|
||||
|
||||
@pytest.mark.skipif("sys.version_info[0] < 3")
|
||||
@pytest.mark.parametrize("mode", ["from_none", "explicit_suppress"])
|
||||
def test_exc_repr_chain_suppression(self, importasmod, mode):
|
||||
"""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 len(tw.lines) == 10
|
||||
|
||||
@pytest.mark.skipif("sys.version_info[0] < 3")
|
||||
@pytest.mark.parametrize(
|
||||
"reason, description",
|
||||
[
|
||||
|
@ -1321,7 +1309,6 @@ raise ValueError()
|
|||
]
|
||||
)
|
||||
|
||||
@pytest.mark.skipif("sys.version_info[0] < 3")
|
||||
def test_exc_chain_repr_cycle(self, importasmod):
|
||||
mod = importasmod(
|
||||
"""
|
||||
|
|
|
@ -16,8 +16,6 @@ import _pytest._code
|
|||
import pytest
|
||||
from _pytest._code import Source
|
||||
|
||||
failsonjython = pytest.mark.xfail("sys.platform.startswith('java')")
|
||||
|
||||
|
||||
def test_source_str_function():
|
||||
x = Source("3")
|
||||
|
@ -122,7 +120,7 @@ def test_source_strip_multiline():
|
|||
def test_syntaxerror_rerepresentation():
|
||||
ex = pytest.raises(SyntaxError, _pytest._code.compile, "xyz xyz")
|
||||
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"
|
||||
|
||||
|
||||
|
|
|
@ -1,10 +1,6 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""Reproduces issue #3774"""
|
||||
|
||||
try:
|
||||
import mock
|
||||
except ImportError:
|
||||
import unittest.mock as mock
|
||||
from unittest import mock
|
||||
|
||||
import pytest
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import doctest
|
||||
import operator
|
||||
import sys
|
||||
from decimal import Decimal
|
||||
from fractions import Fraction
|
||||
from operator import eq
|
||||
|
@ -28,7 +27,7 @@ class MyDocTestRunner(doctest.DocTestRunner):
|
|||
class TestApprox(object):
|
||||
@pytest.fixture
|
||||
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):
|
||||
tol1, tol2, infr = "1.0e-06", "2.0e-06", "inf"
|
||||
|
|
|
@ -679,8 +679,6 @@ class TestSorting(object):
|
|||
|
||||
assert fn1 == fn2
|
||||
assert fn1 != modcol
|
||||
if sys.version_info < (3, 0):
|
||||
assert cmp(fn1, fn2) == 0 # NOQA
|
||||
assert hash(fn1) == hash(fn2)
|
||||
|
||||
fn3 = testdir.collect_by_name(modcol, "test_fail")
|
||||
|
|
|
@ -13,8 +13,6 @@ from _pytest import fixtures
|
|||
from _pytest import python
|
||||
from _pytest.warnings import SHOW_PYTEST_WARNINGS_ARG
|
||||
|
||||
PY3 = sys.version_info >= (3, 0)
|
||||
|
||||
|
||||
class TestMetafunc(object):
|
||||
def Metafunc(self, func, config=None):
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import sys
|
||||
|
||||
import six
|
||||
|
||||
import pytest
|
||||
from _pytest.outcomes import Failed
|
||||
from _pytest.warning_types import PytestDeprecationWarning
|
||||
|
@ -265,16 +263,7 @@ class TestRaises(object):
|
|||
def __class__(self):
|
||||
assert False, "via __class__"
|
||||
|
||||
if six.PY2:
|
||||
with pytest.raises(pytest.fail.Exception) as excinfo:
|
||||
with pytest.raises(CrappyClass()):
|
||||
pass
|
||||
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]
|
||||
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):
|
||||
try:
|
||||
if sys.version_info > (2, 7):
|
||||
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()
|
||||
return subprocess.check_output(*args, **kargs).decode().splitlines()
|
||||
except subprocess.CalledProcessError:
|
||||
return []
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ from __future__ import absolute_import
|
|||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
|
||||
import collections.abc as collections_abc
|
||||
import sys
|
||||
import textwrap
|
||||
|
||||
|
@ -15,8 +16,6 @@ from _pytest import outcomes
|
|||
from _pytest.assertion import truncate
|
||||
from _pytest.assertion import util
|
||||
|
||||
PY3 = sys.version_info >= (3, 0)
|
||||
|
||||
|
||||
def mock_config():
|
||||
class Config(object):
|
||||
|
@ -372,14 +371,6 @@ class TestAssert_reprcompare(object):
|
|||
{0, 2},
|
||||
"""
|
||||
Full diff:
|
||||
- set([0, 1])
|
||||
? ^
|
||||
+ set([0, 2])
|
||||
? ^
|
||||
"""
|
||||
if not PY3
|
||||
else """
|
||||
Full diff:
|
||||
- {0, 1}
|
||||
? ^
|
||||
+ {0, 2}
|
||||
|
@ -483,10 +474,7 @@ class TestAssert_reprcompare(object):
|
|||
assert len(expl) > 1
|
||||
|
||||
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"):
|
||||
pytest.skip("cannot import MutableSequence")
|
||||
MutableSequence = collections_abc.MutableSequence
|
||||
|
@ -589,10 +577,7 @@ class TestAssert_reprcompare(object):
|
|||
return "\xff"
|
||||
|
||||
expl = callequal(A(), "1")
|
||||
if PY3:
|
||||
assert expl == ["ÿ == '1'", "+ 1"]
|
||||
else:
|
||||
assert expl == [u"\ufffd == '1'", u"+ 1"]
|
||||
assert expl == ["ÿ == '1'", "+ 1"]
|
||||
|
||||
def test_format_nonascii_explanation(self):
|
||||
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):
|
||||
"""
|
||||
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(
|
||||
"'__pypy__' in sys.builtin_module_names or sys.platform.startswith('java')"
|
||||
)
|
||||
@pytest.mark.skipif("'__pypy__' in sys.builtin_module_names")
|
||||
def test_warn_missing(testdir):
|
||||
testdir.makepyfile("")
|
||||
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):
|
||||
testdir.makepyfile(
|
||||
r"""
|
||||
|
|
|
@ -3,6 +3,7 @@ from __future__ import absolute_import
|
|||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
|
||||
import ast
|
||||
import glob
|
||||
import os
|
||||
import py_compile
|
||||
|
@ -22,11 +23,6 @@ from _pytest.assertion.rewrite import PYTEST_TAG
|
|||
from _pytest.assertion.rewrite import rewrite_asserts
|
||||
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):
|
||||
mod._old_reprcompare = util._reprcompare
|
||||
|
@ -166,18 +162,12 @@ class TestAssertionRewrite(object):
|
|||
|
||||
msg = getmsg(f, {"cls": X}).splitlines()
|
||||
if verbose > 0:
|
||||
if six.PY2:
|
||||
assert msg == [
|
||||
"assert <class 'test_assertrewrite.X'> == 42",
|
||||
" -<class 'test_assertrewrite.X'>",
|
||||
" +42",
|
||||
]
|
||||
else:
|
||||
assert msg == [
|
||||
"assert <class 'test_...e.<locals>.X'> == 42",
|
||||
" -<class 'test_assertrewrite.TestAssertionRewrite.test_name.<locals>.X'>",
|
||||
" +42",
|
||||
]
|
||||
|
||||
assert msg == [
|
||||
"assert <class 'test_...e.<locals>.X'> == 42",
|
||||
" -<class 'test_assertrewrite.TestAssertionRewrite.test_name.<locals>.X'>",
|
||||
" +42",
|
||||
]
|
||||
else:
|
||||
assert msg == ["assert cls == 42"]
|
||||
|
||||
|
@ -277,9 +267,6 @@ class TestAssertionRewrite(object):
|
|||
["*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):
|
||||
testdir.makepyfile("def test_bytes_assertion():\n assert False, b'ohai!'\n")
|
||||
result = testdir.runpytest()
|
||||
|
@ -426,7 +413,6 @@ class TestAssertionRewrite(object):
|
|||
|
||||
assert getmsg(f) == "assert (False or (4 % 2))"
|
||||
|
||||
@pytest.mark.skipif("sys.version_info < (3,5)")
|
||||
def test_at_operator_issue1290(self, testdir):
|
||||
testdir.makepyfile(
|
||||
"""
|
||||
|
@ -441,7 +427,6 @@ class TestAssertionRewrite(object):
|
|||
)
|
||||
testdir.runpytest().assert_outcomes(passed=1)
|
||||
|
||||
@pytest.mark.skipif("sys.version_info < (3,5)")
|
||||
def test_starred_with_side_effect(self, testdir):
|
||||
"""See #4412"""
|
||||
testdir.makepyfile(
|
||||
|
@ -822,9 +807,6 @@ def test_rewritten():
|
|||
assert testdir.runpytest_subprocess().ret == 0
|
||||
|
||||
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(
|
||||
"""
|
||||
import orphan
|
||||
|
@ -890,10 +872,6 @@ def test_rewritten():
|
|||
testdir.tmpdir.join("test_newlines.py").write(b, "wb")
|
||||
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):
|
||||
pkg = testdir.mkdir("a_package_without_init_py")
|
||||
pkg.join("module.py").ensure()
|
||||
|
@ -976,26 +954,6 @@ def test_rewritten():
|
|||
result.stdout.fnmatch_lines(["*= 1 passed in *=*"])
|
||||
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):
|
||||
def test_loader_is_package_false_for_module(self, testdir):
|
||||
|
@ -1025,48 +983,6 @@ class TestAssertionRewriteHookDetails(object):
|
|||
result = testdir.runpytest()
|
||||
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):
|
||||
testdir.makepyfile(
|
||||
"""
|
||||
|
|
|
@ -13,12 +13,10 @@ import textwrap
|
|||
from io import UnsupportedOperation
|
||||
|
||||
import py
|
||||
from six import text_type
|
||||
|
||||
import pytest
|
||||
from _pytest import capture
|
||||
from _pytest.capture import CaptureManager
|
||||
from _pytest.compat import _PY3
|
||||
from _pytest.main import EXIT_NOTESTSCOLLECTED
|
||||
|
||||
# note: py.io capture tests where copied from
|
||||
|
@ -100,10 +98,7 @@ class TestCaptureManager(object):
|
|||
def test_capturing_unicode(testdir, method):
|
||||
if hasattr(sys, "pypy_version_info") and sys.pypy_version_info < (2, 2):
|
||||
pytest.xfail("does not work on pypy < 2.2")
|
||||
if sys.version_info >= (3, 0):
|
||||
obj = "'b\u00f6y'"
|
||||
else:
|
||||
obj = "u'\u00f6y'"
|
||||
obj = "'b\u00f6y'"
|
||||
testdir.makepyfile(
|
||||
"""
|
||||
# -*- coding: utf-8 -*-
|
||||
|
@ -545,9 +540,6 @@ class TestCaptureFixture(object):
|
|||
)
|
||||
reprec.assertoutcome(passed=1)
|
||||
|
||||
@pytest.mark.skipif(
|
||||
sys.version_info < (3,), reason="only have capsysbinary in python 3"
|
||||
)
|
||||
def test_capsysbinary(self, testdir):
|
||||
reprec = testdir.inline_runsource(
|
||||
"""\
|
||||
|
@ -562,25 +554,6 @@ class TestCaptureFixture(object):
|
|||
)
|
||||
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):
|
||||
p = testdir.makepyfile(
|
||||
"""\
|
||||
|
@ -843,17 +816,9 @@ class TestCaptureIO(object):
|
|||
|
||||
def test_unicode_and_str_mixture(self):
|
||||
f = capture.CaptureIO()
|
||||
if sys.version_info >= (3, 0):
|
||||
f.write("\u00f6")
|
||||
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)
|
||||
f.write("\u00f6")
|
||||
pytest.raises(TypeError, f.write, b"hello")
|
||||
|
||||
@pytest.mark.skipif(sys.version_info[0] == 2, reason="python 3 only behaviour")
|
||||
def test_write_bytes_to_buffer(self):
|
||||
"""In python3, stdout / stderr are text io wrappers (exposing a buffer
|
||||
property of the underlying bytestream). See issue #1407
|
||||
|
@ -876,7 +841,6 @@ def test_dontreadfrominput():
|
|||
f.close() # just for completeness
|
||||
|
||||
|
||||
@pytest.mark.skipif("sys.version_info < (3,)", reason="python2 has no buffer")
|
||||
def test_dontreadfrominput_buffer_python3():
|
||||
from _pytest.capture import DontReadFromInput
|
||||
|
||||
|
@ -891,17 +855,7 @@ def test_dontreadfrominput_buffer_python3():
|
|||
f.close() # just for completeness
|
||||
|
||||
|
||||
@pytest.mark.skipif("sys.version_info >= (3,)", reason="python2 has no buffer")
|
||||
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
|
||||
@pytest.fixture
|
||||
def tmpfile(testdir):
|
||||
f = testdir.makepyfile("").open("wb+")
|
||||
yield f
|
||||
|
@ -1118,16 +1072,6 @@ class TestStdCapture(object):
|
|||
out, err = cap.readouterr()
|
||||
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):
|
||||
with self.getcapture() as cap:
|
||||
print("hello")
|
||||
|
@ -1571,9 +1515,6 @@ def test_typeerror_encodedfile_write(testdir):
|
|||
|
||||
assert result_with_capture.ret == result_without_capture.ret
|
||||
|
||||
if _PY3:
|
||||
result_with_capture.stdout.fnmatch_lines(
|
||||
["E TypeError: write() argument must be str, not bytes"]
|
||||
)
|
||||
else:
|
||||
assert result_with_capture.ret == 0
|
||||
result_with_capture.stdout.fnmatch_lines(
|
||||
["E TypeError: write() argument must be str, not bytes"]
|
||||
)
|
||||
|
|
|
@ -38,8 +38,6 @@ class TestCollector(object):
|
|||
|
||||
assert fn1 == fn2
|
||||
assert fn1 != modcol
|
||||
if sys.version_info < (3, 0):
|
||||
assert cmp(fn1, fn2) == 0 # NOQA
|
||||
assert hash(fn1) == hash(fn2)
|
||||
|
||||
fn3 = testdir.collect_by_name(modcol, "test_fail")
|
||||
|
|
|
@ -6,8 +6,6 @@ from __future__ import print_function
|
|||
import sys
|
||||
from functools import wraps
|
||||
|
||||
import six
|
||||
|
||||
import pytest
|
||||
from _pytest.compat import _PytestWrapper
|
||||
from _pytest.compat import get_real_func
|
||||
|
@ -62,8 +60,6 @@ def test_get_real_func():
|
|||
def inner():
|
||||
pass # pragma: no cover
|
||||
|
||||
if six.PY2:
|
||||
inner.__wrapped__ = f
|
||||
return inner
|
||||
|
||||
def func():
|
||||
|
@ -81,9 +77,6 @@ def test_get_real_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):
|
||||
testdir.makepyfile(
|
||||
"""
|
||||
|
|
|
@ -218,12 +218,9 @@ class TestConfigAPI(object):
|
|||
assert config.getoption(x) == "this"
|
||||
pytest.raises(ValueError, config.getoption, "qweqwe")
|
||||
|
||||
@pytest.mark.skipif("sys.version_info[0] < 3")
|
||||
def test_config_getoption_unicode(self, testdir):
|
||||
testdir.makeconftest(
|
||||
"""
|
||||
from __future__ import unicode_literals
|
||||
|
||||
def pytest_addoption(parser):
|
||||
parser.addoption('--hello', type=str)
|
||||
"""
|
||||
|
|
|
@ -3,7 +3,6 @@ from __future__ import absolute_import
|
|||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
|
||||
import sys
|
||||
import textwrap
|
||||
|
||||
import pytest
|
||||
|
@ -830,13 +829,11 @@ class TestLiterals(object):
|
|||
"""
|
||||
)
|
||||
reprec = testdir.inline_run()
|
||||
passed = int(sys.version_info[0] >= 3)
|
||||
reprec.assertoutcome(passed=passed, failed=int(not passed))
|
||||
reprec.assertoutcome(passed=1)
|
||||
|
||||
def test_bytes_literal(self, testdir):
|
||||
"""Test that doctests which output bytes fail in Python 3 when
|
||||
the ALLOW_BYTES option is not used. The same test should pass
|
||||
in Python 2 (#1287).
|
||||
the ALLOW_BYTES option is not used. (#1287).
|
||||
"""
|
||||
testdir.maketxtfile(
|
||||
test_doc="""
|
||||
|
@ -845,8 +842,7 @@ class TestLiterals(object):
|
|||
"""
|
||||
)
|
||||
reprec = testdir.inline_run()
|
||||
passed = int(sys.version_info[0] == 2)
|
||||
reprec.assertoutcome(passed=passed, failed=int(not passed))
|
||||
reprec.assertoutcome(failed=1)
|
||||
|
||||
|
||||
class TestDoctestSkips(object):
|
||||
|
|
|
@ -4,7 +4,6 @@ from __future__ import division
|
|||
from __future__ import print_function
|
||||
|
||||
import os
|
||||
import sys
|
||||
from xml.dom import minidom
|
||||
|
||||
import py
|
||||
|
@ -585,8 +584,7 @@ class TestPython(object):
|
|||
assert result.ret == 1
|
||||
tnode = dom.find_first_by_tag("testcase")
|
||||
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):
|
||||
"""this test did fail when the escaping wasnt strict"""
|
||||
|
|
|
@ -5,8 +5,7 @@ from __future__ import print_function
|
|||
|
||||
import os
|
||||
import sys
|
||||
|
||||
import six
|
||||
from unittest import mock
|
||||
|
||||
import pytest
|
||||
from _pytest.main import EXIT_INTERRUPTED
|
||||
|
@ -17,11 +16,6 @@ from _pytest.nodes import Node
|
|||
from _pytest.warning_types import PytestDeprecationWarning
|
||||
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 objects:pytest.RemovedInPytest4Warning"
|
||||
)
|
||||
|
@ -1009,10 +1003,7 @@ def test_pytest_param_id_requires_string():
|
|||
with pytest.raises(TypeError) as excinfo:
|
||||
pytest.param(id=True)
|
||||
msg, = excinfo.value.args
|
||||
if six.PY2:
|
||||
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"
|
||||
assert msg == "Expected id to be a string, got <class 'bool'>: True"
|
||||
|
||||
|
||||
@pytest.mark.parametrize("s", (None, "hello world"))
|
||||
|
|
|
@ -8,8 +8,6 @@ import re
|
|||
import sys
|
||||
import textwrap
|
||||
|
||||
import six
|
||||
|
||||
import pytest
|
||||
from _pytest.monkeypatch import MonkeyPatch
|
||||
|
||||
|
@ -209,22 +207,6 @@ class TestEnvironWarnings(object):
|
|||
|
||||
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):
|
||||
value = 2
|
||||
msg = (
|
||||
|
@ -349,10 +331,8 @@ def test_importerror(testdir):
|
|||
result = testdir.runpytest()
|
||||
result.stdout.fnmatch_lines(
|
||||
"""
|
||||
*import error in package.a: No module named {0}doesnotexist{0}*
|
||||
""".format(
|
||||
"'" if sys.version_info > (3, 0) else ""
|
||||
)
|
||||
*import error in package.a: No module named 'doesnotexist'*
|
||||
"""
|
||||
)
|
||||
|
||||
|
||||
|
|
|
@ -3,8 +3,6 @@ from __future__ import absolute_import
|
|||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
|
||||
import sys
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
|
@ -74,10 +72,7 @@ class TestPasteCapture(object):
|
|||
"""
|
||||
)
|
||||
result = testdir.runpytest("--pastebin=all")
|
||||
if sys.version_info[0] == 3:
|
||||
expected_msg = "*assert '☺' == 1*"
|
||||
else:
|
||||
expected_msg = "*assert '\\xe2\\x98\\xba' == 1*"
|
||||
expected_msg = "*assert '☺' == 1*"
|
||||
result.stdout.fnmatch_lines(
|
||||
[
|
||||
expected_msg,
|
||||
|
@ -110,14 +105,9 @@ class TestPaste(object):
|
|||
|
||||
return DummyFile()
|
||||
|
||||
if sys.version_info < (3, 0):
|
||||
import urllib
|
||||
import urllib.request
|
||||
|
||||
monkeypatch.setattr(urllib, "urlopen", mocked)
|
||||
else:
|
||||
import urllib.request
|
||||
|
||||
monkeypatch.setattr(urllib.request, "urlopen", mocked)
|
||||
monkeypatch.setattr(urllib.request, "urlopen", mocked)
|
||||
return calls
|
||||
|
||||
def test_create_new_paste(self, pastebin, mocked_urlopen):
|
||||
|
@ -126,7 +116,7 @@ class TestPaste(object):
|
|||
assert len(mocked_urlopen) == 1
|
||||
url, data = mocked_urlopen[0]
|
||||
assert type(data) is bytes
|
||||
lexer = "python3" if sys.version_info[0] == 3 else "python"
|
||||
lexer = "python3"
|
||||
assert url == "https://bpaste.net"
|
||||
assert "lexer=%s" % lexer in data.decode()
|
||||
assert "code=full-paste-contents" in data.decode()
|
||||
|
|
|
@ -6,8 +6,6 @@ from __future__ import print_function
|
|||
import os
|
||||
import sys
|
||||
|
||||
import six
|
||||
|
||||
import _pytest._code
|
||||
import pytest
|
||||
from _pytest.debugging import _validate_usepdb_cls
|
||||
|
@ -537,10 +535,7 @@ class TestPDB(object):
|
|||
import sys
|
||||
import types
|
||||
|
||||
if sys.version_info < (3, ):
|
||||
do_debug_func = pdb.Pdb.do_debug.im_func
|
||||
else:
|
||||
do_debug_func = pdb.Pdb.do_debug
|
||||
do_debug_func = pdb.Pdb.do_debug
|
||||
|
||||
newglobals = do_debug_func.__globals__.copy()
|
||||
newglobals['Pdb'] = self.__class__
|
||||
|
@ -866,8 +861,6 @@ class TestDebuggingBreakpoints(object):
|
|||
assert SUPPORTS_BREAKPOINT_BUILTIN is True
|
||||
if sys.version_info.major == 3 and sys.version_info.minor == 5:
|
||||
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(
|
||||
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):
|
||||
"""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(
|
||||
"""
|
||||
def input_without_read(*args, **kwargs):
|
||||
raise EOFError()
|
||||
|
||||
def test(monkeypatch):
|
||||
import {builtin_module}
|
||||
monkeypatch.setattr({builtin_module}, {input_func!r}, input_without_read)
|
||||
import builtins
|
||||
monkeypatch.setattr(builtins, "input", input_without_read)
|
||||
__import__('pdb').set_trace()
|
||||
""".format(
|
||||
builtin_module=builtin_module, input_func=input_func
|
||||
)
|
||||
"""
|
||||
)
|
||||
result = testdir.runpytest(str(p1))
|
||||
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
|
||||
)
|
||||
result = testdir.runpytest()
|
||||
if sys.version_info[0] >= 3:
|
||||
result.stdout.fnmatch_lines(["*test_hello*", "oh oh: ☺"])
|
||||
else:
|
||||
result.stdout.fnmatch_lines(["*test_hello*", "oh oh: *"])
|
||||
result.stdout.fnmatch_lines(["*test_hello*", "oh oh: ☺"])
|
||||
assert "def test_hello" not in result.stdout.str()
|
||||
|
||||
|
||||
|
|
|
@ -49,22 +49,6 @@ class TestEvaluator(object):
|
|||
expl = ev.getexplanation()
|
||||
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):
|
||||
item = testdir.getitem(
|
||||
"""
|
||||
|
@ -893,10 +877,7 @@ def test_errors_in_xfail_skip_expressions(testdir):
|
|||
)
|
||||
result = testdir.runpytest()
|
||||
markline = " ^"
|
||||
if sys.platform.startswith("java"):
|
||||
# XXX report this to java
|
||||
markline = "*" + markline[8:]
|
||||
elif hasattr(sys, "pypy_version_info") and sys.pypy_version_info < (6,):
|
||||
if hasattr(sys, "pypy_version_info") and sys.pypy_version_info < (6,):
|
||||
markline = markline[5:]
|
||||
elif sys.version_info >= (3, 8) or hasattr(sys, "pypy_version_info"):
|
||||
markline = markline[4:]
|
||||
|
|
|
@ -6,7 +6,6 @@ from __future__ import print_function
|
|||
import sys
|
||||
|
||||
import attr
|
||||
import six
|
||||
|
||||
import pytest
|
||||
from _pytest import pathlib
|
||||
|
@ -348,8 +347,6 @@ class TestNumberedDir(object):
|
|||
def attempt_symlink_to(path, to_path):
|
||||
"""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)."""
|
||||
if sys.platform.startswith("win") and six.PY2:
|
||||
pytest.skip("pathlib for some reason cannot make symlinks on Python 2")
|
||||
try:
|
||||
Path(path).symlink_to(Path(to_path))
|
||||
except OSError:
|
||||
|
|
|
@ -459,9 +459,6 @@ class TestTrialUnittest(object):
|
|||
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.stdout.fnmatch_lines_random(
|
||||
[
|
||||
|
@ -472,12 +469,10 @@ class TestTrialUnittest(object):
|
|||
"*i2wanto*",
|
||||
"*sys.version_info*",
|
||||
"*skip_in_method*",
|
||||
"*1 failed*4 skipped*3 xfailed*"
|
||||
if should_fail
|
||||
else "*4 skipped*3 xfail*1 xpass*",
|
||||
"*1 failed*4 skipped*3 xfailed*",
|
||||
]
|
||||
)
|
||||
assert result.ret == (1 if should_fail else 0)
|
||||
assert result.ret == 1
|
||||
|
||||
def test_trial_error(self, testdir):
|
||||
testdir.makepyfile(
|
||||
|
@ -745,22 +740,17 @@ def test_unittest_expected_failure_for_passing_test_is_fail(testdir, runner):
|
|||
unittest.main()
|
||||
"""
|
||||
)
|
||||
from _pytest.compat import _is_unittest_unexpected_success_a_failure
|
||||
|
||||
should_fail = _is_unittest_unexpected_success_a_failure()
|
||||
if runner == "pytest":
|
||||
result = testdir.runpytest("-rxX")
|
||||
result.stdout.fnmatch_lines(
|
||||
[
|
||||
"*MyTestCase*test_passing_test_is_fail*",
|
||||
"*1 failed*" if should_fail else "*1 xpassed*",
|
||||
]
|
||||
["*MyTestCase*test_passing_test_is_fail*", "*1 failed*"]
|
||||
)
|
||||
else:
|
||||
result = testdir.runpython(script)
|
||||
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(
|
||||
|
|
|
@ -1,11 +1,8 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import sys
|
||||
import warnings
|
||||
|
||||
import six
|
||||
|
||||
import pytest
|
||||
|
||||
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()
|
||||
|
||||
|
||||
@pytest.mark.skipif(
|
||||
sys.version_info < (3, 0), reason="warnings message is unicode is ok in python3"
|
||||
)
|
||||
@pytest.mark.filterwarnings("always")
|
||||
def test_unicode(testdir, pyfile_with_warnings):
|
||||
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):
|
||||
"""Ensure our warnings capture does not mess with pre-installed filters (#2430)."""
|
||||
testdir.makepyfile(
|
||||
|
@ -569,33 +501,6 @@ class TestDeprecationWarningsByDefault:
|
|||
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"])
|
||||
def test_removed_in_pytest4_warning_as_error(testdir, change_default):
|
||||
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
|
||||
envlist =
|
||||
linting
|
||||
py27
|
||||
py34
|
||||
py35
|
||||
py36
|
||||
py37
|
||||
py38
|
||||
pypy
|
||||
pypy3
|
||||
{py27,py37}-{pexpect,xdist,twisted,numpy,pluggymaster}
|
||||
py27-nobyte-xdist
|
||||
py37-{pexpect,xdist,twisted,numpy,pluggymaster}
|
||||
doctesting
|
||||
py37-freeze
|
||||
docs
|
||||
|
@ -56,15 +53,6 @@ deps =
|
|||
{env:_PYTEST_TOX_EXTRA_DEP:}
|
||||
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]
|
||||
skip_install = True
|
||||
basepython = python3
|
||||
|
@ -109,11 +97,6 @@ commands =
|
|||
rm -rf {envdir}/.pytest_cache
|
||||
make regen
|
||||
|
||||
[testenv:jython]
|
||||
changedir = testing
|
||||
commands =
|
||||
{envpython} {envbindir}/py.test-jython {posargs}
|
||||
|
||||
[testenv:py37-freeze]
|
||||
changedir = testing/freeze
|
||||
# Disable PEP 517 with pip, which does not work with PyInstaller currently.
|
||||
|
|
Loading…
Reference in New Issue