Skip to content

Commit

Permalink
Merge pull request #4692 from nicoddemus/merge-master-into-features
Browse files Browse the repository at this point in the history
Merge master into features
  • Loading branch information
nicoddemus committed Jan 30, 2019
2 parents 1dc16ad + 02962fa commit e2a15c7
Show file tree
Hide file tree
Showing 52 changed files with 483 additions and 156 deletions.
27 changes: 22 additions & 5 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
exclude: doc/en/example/py2py3/test_py2.py
repos:
- repo: https://github.com/ambv/black
rev: 18.6b4
rev: 18.9b0
hooks:
- id: black
args: [--safe, --quiet]
Expand All @@ -13,28 +13,31 @@ repos:
additional_dependencies: [black==18.9b0]
language_version: python3
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v2.0.0
rev: v2.1.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- id: debug-statements
exclude: _pytest/debugging.py
language_version: python3
- repo: https://gitlab.com/pycqa/flake8
rev: 3.7.0
hooks:
- id: flake8
language_version: python3
- repo: https://github.com/asottile/reorder_python_imports
rev: v1.3.3
rev: v1.3.5
hooks:
- id: reorder-python-imports
args: ['--application-directories=.:src']
- repo: https://github.com/asottile/pyupgrade
rev: v1.10.1
rev: v1.11.1
hooks:
- id: pyupgrade
args: [--keep-percent-format]
- repo: https://github.com/pre-commit/pygrep-hooks
rev: v1.1.0
rev: v1.2.0
hooks:
- id: rst-backticks
- repo: local
Expand All @@ -51,3 +54,17 @@ repos:
entry: 'changelog files must be named ####.(feature|bugfix|doc|deprecation|removal|vendor|trivial).rst'
exclude: changelog/(\d+\.(feature|bugfix|doc|deprecation|removal|vendor|trivial).rst|README.rst|_template.rst)
files: ^changelog/
- id: py-deprecated
name: py library is deprecated
language: pygrep
entry: >
(?x)\bpy\.(
_code\.|
builtin\.|
code\.|
io\.(BytesIO|saferepr)|
path\.local\.sysfind|
process\.|
std\.
)
types: [python]
2 changes: 2 additions & 0 deletions AUTHORS
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ Aaron Coleman
Abdeali JK
Abhijeet Kasurde
Adam Johnson
Adam Uhlir
Ahn Ki-Wook
Alan Velasco
Alexander Johnson
Expand Down Expand Up @@ -52,6 +53,7 @@ Christian Boelsen
Christian Theunert
Christian Tismer
Christopher Gilling
Christopher Dignam
CrazyMerlyn
Cyrus Maden
Dhiren Serai
Expand Down
4 changes: 4 additions & 0 deletions changelog/4402.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Warning summary now groups warnings by message instead of by test id.

This makes the output more compact and better conveys the general idea of how much code is
actually generating warnings, instead of how many tests call that code.
1 change: 1 addition & 0 deletions changelog/4536.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
``monkeypatch.delattr`` handles class descriptors like ``staticmethod``/``classmethod``.
1 change: 1 addition & 0 deletions changelog/4649.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Restore marks being considered keywords for keyword expressions.
1 change: 1 addition & 0 deletions changelog/4653.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
``tmp_path`` fixture and other related ones provides resolved path (a.k.a real path)
1 change: 1 addition & 0 deletions changelog/4657.trivial.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Copy saferepr from pylib
1 change: 1 addition & 0 deletions changelog/4667.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
``pytest_terminal_summary`` uses result from ``pytest_report_teststatus`` hook, rather than hardcoded strings.
1 change: 1 addition & 0 deletions changelog/4669.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Correctly handle ``unittest.SkipTest`` exception containing non-ascii characters on Python 2.
1 change: 1 addition & 0 deletions doc/en/contents.rst
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ Full pytest documentation

backwards-compatibility
deprecations
py27-py34-deprecation
historical-notes
license
contributing
Expand Down
29 changes: 25 additions & 4 deletions doc/en/deprecations.rst
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,32 @@ Below is a complete list of all pytest features which are considered deprecated.
.. deprecated:: 4.1

It is a common mistake to think this parameter will match the exception message, while in fact
it only serves to provide a custom message in case the ``pytest.raises`` check fails. To avoid this
mistake and because it is believed to be little used, pytest is deprecating it without providing
an alternative for the moment.
it only serves to provide a custom message in case the ``pytest.raises`` check fails. To prevent
users from making this mistake, and because it is believed to be little used, pytest is
deprecating it without providing an alternative for the moment.

If you have concerns about this, please comment on `issue #3974 <https://github.com/pytest-dev/pytest/issues/3974>`__.
If you have a valid use case for this parameter, consider that to obtain the same results
you can just call ``pytest.fail`` manually at the end of the ``with`` statement.

For example:

.. code-block:: python
with pytest.raises(TimeoutError, message="Client got unexpected message"):
wait_for(websocket.recv(), 0.5)
Becomes:

.. code-block:: python
with pytest.raises(TimeoutError):
wait_for(websocket.recv(), 0.5)
pytest.fail("Client got unexpected message")
If you still have concerns about this deprecation and future removal, please comment on
`issue #3974 <https://github.com/pytest-dev/pytest/issues/3974>`__.


``pytest.config`` global
Expand Down
6 changes: 3 additions & 3 deletions doc/en/example/attic.rst
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@ example: specifying and selecting acceptance tests
pytest.skip("specify -A to run acceptance tests")
self.tmpdir = request.config.mktemp(request.function.__name__, numbered=True)

def run(self, cmd):
def run(self, *cmd):
""" called by test code to execute an acceptance test. """
self.tmpdir.chdir()
return py.process.cmdexec(cmd)
return subprocess.check_output(cmd).decode()

and the actual test function example:
Expand All @@ -36,7 +36,7 @@ and the actual test function example:

def test_some_acceptance_aspect(accept):
accept.tmpdir.mkdir("somesub")
result = accept.run("ls -la")
result = accept.run("ls", "-la")
assert "somesub" in result

If you run this test without specifying a command line option
Expand Down
10 changes: 5 additions & 5 deletions doc/en/example/multipython.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
module containing a parametrized tests testing cross-python
serialization via the pickle module.
"""
import distutils.spawn
import subprocess
import textwrap

import py

import pytest

pythonlist = ["python2.7", "python3.4", "python3.5"]
Expand All @@ -24,7 +24,7 @@ def python2(request, python1):

class Python(object):
def __init__(self, version, picklefile):
self.pythonpath = py.path.local.sysfind(version)
self.pythonpath = distutils.spawn.find_executable(version)
if not self.pythonpath:
pytest.skip("{!r} not found".format(version))
self.picklefile = picklefile
Expand All @@ -43,7 +43,7 @@ def dumps(self, obj):
)
)
)
py.process.cmdexec("{} {}".format(self.pythonpath, dumpfile))
subprocess.check_call((self.pythonpath, str(dumpfile)))

def load_and_is_true(self, expression):
loadfile = self.picklefile.dirpath("load.py")
Expand All @@ -63,7 +63,7 @@ def load_and_is_true(self, expression):
)
)
print(loadfile)
py.process.cmdexec("{} {}".format(self.pythonpath, loadfile))
subprocess.check_call((self.pythonpath, str(loadfile)))


@pytest.mark.parametrize("obj", [42, {}, {1: 3}])
Expand Down
22 changes: 22 additions & 0 deletions doc/en/py27-py34-deprecation.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
Python 2.7 and 3.4 support plan
===============================

Python 2.7 EOL is fast approaching, with
upstream support `ending in 2020 <https://legacy.python.org/dev/peps/pep-0373/#id4>`__.
Python 3.4's last release is scheduled for
`March 2019 <https://www.python.org/dev/peps/pep-0429/#release-schedule>`__. pytest is one of
the participating projects of the https://python3statement.org.

We plan to drop support for Python 2.7 and 3.4 at the same time with the release of **pytest 5.0**,
scheduled to be released by **mid-2019**. Thanks to the `python_requires <https://packaging.python.org/guides/distributing-packages-using-setuptools/#python-requires>`__ ``setuptools`` option,
Python 2.7 and Python 3.4 users using a modern ``pip`` version
will install the last compatible pytest ``4.X`` version automatically even if ``5.0`` or later
are available on PyPI.

During the period **from mid-2019 and 2020**, the pytest core team plans to make
bug-fix releases of the pytest ``4.X`` series by back-porting patches to the ``4.x-maintenance``
branch.

**After 2020**, the core team will no longer actively back port-patches, but the ``4.x-maintenance``
branch will continue to exist so the community itself can contribute patches. The
core team will be happy to accept those patches and make new ``4.X`` releases **until mid-2020**.
5 changes: 3 additions & 2 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,11 @@ platforms = unix, linux, osx, cygwin, win32
zip_safe = no
packages =
_pytest
_pytest.assertion
_pytest._code
_pytest.mark
_pytest._io
_pytest.assertion
_pytest.config
_pytest.mark

py_modules = pytest
python_requires = >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*
Expand Down
7 changes: 4 additions & 3 deletions src/_pytest/_code/code.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from six import text_type

import _pytest
from _pytest._io.saferepr import saferepr
from _pytest.compat import _PY2
from _pytest.compat import _PY3
from _pytest.compat import PY35
Expand Down Expand Up @@ -142,7 +143,7 @@ def exec_(self, code, **vars):
def repr(self, object):
""" return a 'safe' (non-recursive, one-line) string repr for 'object'
"""
return py.io.saferepr(object)
return saferepr(object)

def is_true(self, object):
return object
Expand Down Expand Up @@ -421,7 +422,7 @@ def from_current(cls, exprinfo=None):
if exprinfo is None and isinstance(tup[1], AssertionError):
exprinfo = getattr(tup[1], "msg", None)
if exprinfo is None:
exprinfo = py.io.saferepr(tup[1])
exprinfo = saferepr(tup[1])
if exprinfo and exprinfo.startswith(cls._assert_start_repr):
_striptext = "AssertionError: "

Expand Down Expand Up @@ -618,7 +619,7 @@ def _getentrysource(self, entry):
return source

def _saferepr(self, obj):
return py.io.saferepr(obj)
return saferepr(obj)

def repr_args(self, entry):
if self.funcargs:
Expand Down
4 changes: 1 addition & 3 deletions src/_pytest/_code/source.py
Original file line number Diff line number Diff line change
Expand Up @@ -237,9 +237,7 @@ def getfslineno(obj):
def findsource(obj):
try:
sourcelines, lineno = inspect.findsource(obj)
except py.builtin._sysex:
raise
except: # noqa
except Exception:
return None, -1
source = Source()
source.lines = [line.rstrip() for line in sourcelines]
Expand Down
Empty file added src/_pytest/_io/__init__.py
Empty file.
72 changes: 72 additions & 0 deletions src/_pytest/_io/saferepr.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import sys

from six.moves import reprlib


class SafeRepr(reprlib.Repr):
"""subclass of repr.Repr that limits the resulting size of repr()
and includes information on exceptions raised during the call.
"""

def repr(self, x):
return self._callhelper(reprlib.Repr.repr, self, x)

def repr_unicode(self, x, level):
# Strictly speaking wrong on narrow builds
def repr(u):
if "'" not in u:
return u"'%s'" % u
elif '"' not in u:
return u'"%s"' % u
else:
return u"'%s'" % u.replace("'", r"\'")

s = repr(x[: self.maxstring])
if len(s) > self.maxstring:
i = max(0, (self.maxstring - 3) // 2)
j = max(0, self.maxstring - 3 - i)
s = repr(x[:i] + x[len(x) - j :])
s = s[:i] + "..." + s[len(s) - j :]
return s

def repr_instance(self, x, level):
return self._callhelper(repr, x)

def _callhelper(self, call, x, *args):
try:
# Try the vanilla repr and make sure that the result is a string
s = call(x, *args)
except Exception:
cls, e, tb = sys.exc_info()
exc_name = getattr(cls, "__name__", "unknown")
try:
exc_info = str(e)
except Exception:
exc_info = "unknown"
return '<[%s("%s") raised in repr()] %s object at 0x%x>' % (
exc_name,
exc_info,
x.__class__.__name__,
id(x),
)
else:
if len(s) > self.maxsize:
i = max(0, (self.maxsize - 3) // 2)
j = max(0, self.maxsize - 3 - i)
s = s[:i] + "..." + s[len(s) - j :]
return s


def saferepr(obj, maxsize=240):
"""return a size-limited safe repr-string for the given object.
Failing __repr__ functions of user instances will be represented
with a short exception info and 'saferepr' generally takes
care to never raise exceptions itself. This function is a wrapper
around the Repr/reprlib functionality of the standard 2.6 lib.
"""
# review exception handling
srepr = SafeRepr()
srepr.maxstring = maxsize
srepr.maxsize = maxsize
srepr.maxother = 160
return srepr.repr(obj)

0 comments on commit e2a15c7

Please sign in to comment.