Skip to content

Commit 7f519f8

Browse files
committed
Merge master into features
2 parents e3e57a7 + 9c700d1 commit 7f519f8

File tree

16 files changed

+127
-50
lines changed

16 files changed

+127
-50
lines changed

.github/ISSUE_TEMPLATE.md

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1+
<!--
12
Thanks for submitting an issue!
23
3-
Here's a quick checklist in what to include:
4+
Here's a quick checklist for what to provide:
5+
-->
46

5-
- [ ] Include a detailed description of the bug or suggestion
6-
- [ ] `pip list` of the virtual environment you are using
7+
- [ ] a detailed description of the bug or suggestion
8+
- [ ] output of `pip list` from the virtual environment you are using
79
- [ ] pytest and operating system versions
8-
- [ ] Minimal example if possible
10+
- [ ] minimal example if possible

.github/PULL_REQUEST_TEMPLATE.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1+
<!--
12
Thanks for submitting a PR, your contribution is really appreciated!
23
3-
Here's a quick checklist that should be present in PRs (you can delete this text from the final description, this is
4-
just a guideline):
4+
Here's a quick checklist that should be present in PRs.
5+
(please delete this text from the final description, this is just a guideline)
6+
-->
57

68
- [ ] Create a new changelog file in the `changelog` folder, with a name like `<ISSUE NUMBER>.<TYPE>.rst`. See [changelog/README.rst](https://github.com/pytest-dev/pytest/blob/master/changelog/README.rst) for details.
79
- [ ] Target the `master` branch for bug fixes, documentation updates and trivial changes.

AUTHORS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ Hugo van Kemenade
105105
Hui Wang (coldnight)
106106
Ian Bicking
107107
Ian Lesperance
108+
Ilya Konstantinov
108109
Ionuț Turturică
109110
Iwan Briquemont
110111
Jaap Broekhuizen
@@ -179,6 +180,7 @@ Nicholas Devenish
179180
Nicholas Murphy
180181
Niclas Olofsson
181182
Nicolas Delaby
183+
Nikolay Kondratyev
182184
Oleg Pidsadnyi
183185
Oleg Sushchenko
184186
Oliver Bestwalter

changelog/5089.bugfix.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix crash caused by error in ``__repr__`` function with both ``showlocals`` and verbose output enabled.

changelog/5139.bugfix.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Eliminate core dependency on 'terminal' plugin.

doc/en/skipping.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ Here's a quick guide on how to skip tests in a module in different situations:
208208

209209
.. code-block:: python
210210
211-
pytestmark = pytest.mark.skipif(sys.platform == "win32", "tests for linux only")
211+
pytestmark = pytest.mark.skipif(sys.platform == "win32", reason="tests for linux only")
212212
213213
3. Skip all tests in a module if some import is missing:
214214

src/_pytest/_code/code.py

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
from __future__ import print_function
44

55
import inspect
6-
import pprint
76
import re
87
import sys
98
import traceback
@@ -18,6 +17,7 @@
1817
from six import text_type
1918

2019
import _pytest
20+
from _pytest._io.saferepr import safeformat
2121
from _pytest._io.saferepr import saferepr
2222
from _pytest.compat import _PY2
2323
from _pytest.compat import _PY3
@@ -614,14 +614,11 @@ def _getentrysource(self, entry):
614614
source = source.deindent()
615615
return source
616616

617-
def _saferepr(self, obj):
618-
return saferepr(obj)
619-
620617
def repr_args(self, entry):
621618
if self.funcargs:
622619
args = []
623620
for argname, argvalue in entry.frame.getargs(var=True):
624-
args.append((argname, self._saferepr(argvalue)))
621+
args.append((argname, saferepr(argvalue)))
625622
return ReprFuncArgs(args)
626623

627624
def get_source(self, source, line_index=-1, excinfo=None, short=False):
@@ -674,9 +671,9 @@ def repr_locals(self, locals):
674671
# _repr() function, which is only reprlib.Repr in
675672
# disguise, so is very configurable.
676673
if self.truncate_locals:
677-
str_repr = self._saferepr(value)
674+
str_repr = saferepr(value)
678675
else:
679-
str_repr = pprint.pformat(value)
676+
str_repr = safeformat(value)
680677
# if len(str_repr) < 70 or not isinstance(value,
681678
# (list, tuple, dict)):
682679
lines.append("%-10s = %s" % (name, str_repr))

src/_pytest/_io/saferepr.py

Lines changed: 33 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,26 @@
1-
import sys
1+
import pprint
22

33
from six.moves import reprlib
44

55

6+
def _call_and_format_exception(call, x, *args):
7+
try:
8+
# Try the vanilla repr and make sure that the result is a string
9+
return call(x, *args)
10+
except Exception as exc:
11+
exc_name = type(exc).__name__
12+
try:
13+
exc_info = str(exc)
14+
except Exception:
15+
exc_info = "unknown"
16+
return '<[%s("%s") raised in repr()] %s object at 0x%x>' % (
17+
exc_name,
18+
exc_info,
19+
x.__class__.__name__,
20+
id(x),
21+
)
22+
23+
624
class SafeRepr(reprlib.Repr):
725
"""subclass of repr.Repr that limits the resulting size of repr()
826
and includes information on exceptions raised during the call.
@@ -33,28 +51,20 @@ def repr_instance(self, x, level):
3351
return self._callhelper(repr, x)
3452

3553
def _callhelper(self, call, x, *args):
36-
try:
37-
# Try the vanilla repr and make sure that the result is a string
38-
s = call(x, *args)
39-
except Exception:
40-
cls, e, tb = sys.exc_info()
41-
exc_name = getattr(cls, "__name__", "unknown")
42-
try:
43-
exc_info = str(e)
44-
except Exception:
45-
exc_info = "unknown"
46-
return '<[%s("%s") raised in repr()] %s object at 0x%x>' % (
47-
exc_name,
48-
exc_info,
49-
x.__class__.__name__,
50-
id(x),
51-
)
52-
else:
53-
if len(s) > self.maxsize:
54-
i = max(0, (self.maxsize - 3) // 2)
55-
j = max(0, self.maxsize - 3 - i)
56-
s = s[:i] + "..." + s[len(s) - j :]
57-
return s
54+
s = _call_and_format_exception(call, x, *args)
55+
if len(s) > self.maxsize:
56+
i = max(0, (self.maxsize - 3) // 2)
57+
j = max(0, self.maxsize - 3 - i)
58+
s = s[:i] + "..." + s[len(s) - j :]
59+
return s
60+
61+
62+
def safeformat(obj):
63+
"""return a pretty printed string for the given object.
64+
Failing __repr__ functions of user instances will be represented
65+
with a short exception info.
66+
"""
67+
return _call_and_format_exception(pprint.pformat, obj)
5868

5969

6070
def saferepr(obj, maxsize=240):

src/_pytest/config/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -704,7 +704,7 @@ def pytest_cmdline_parse(self, pluginmanager, args):
704704
return self
705705

706706
def notify_exception(self, excinfo, option=None):
707-
if option and option.fulltrace:
707+
if option and getattr(option, "fulltrace", False):
708708
style = "long"
709709
else:
710710
style = "native"

src/_pytest/nodes.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,7 @@ def _repr_failure_py(self, excinfo, style=None):
248248
if excinfo.errisinstance(fm.FixtureLookupError):
249249
return excinfo.value.formatrepr()
250250
tbfilter = True
251-
if self.config.option.fulltrace:
251+
if self.config.getoption("fulltrace", False):
252252
style = "long"
253253
else:
254254
tb = _pytest._code.Traceback([excinfo.traceback[-1]])
@@ -260,12 +260,12 @@ def _repr_failure_py(self, excinfo, style=None):
260260
style = "long"
261261
# XXX should excinfo.getrepr record all data and toterminal() process it?
262262
if style is None:
263-
if self.config.option.tbstyle == "short":
263+
if self.config.getoption("tbstyle", "auto") == "short":
264264
style = "short"
265265
else:
266266
style = "long"
267267

268-
if self.config.option.verbose > 1:
268+
if self.config.getoption("verbose", 0) > 1:
269269
truncate_locals = False
270270
else:
271271
truncate_locals = True
@@ -279,7 +279,7 @@ def _repr_failure_py(self, excinfo, style=None):
279279
return excinfo.getrepr(
280280
funcargs=True,
281281
abspath=abspath,
282-
showlocals=self.config.option.showlocals,
282+
showlocals=self.config.getoption("showlocals", False),
283283
style=style,
284284
tbfilter=tbfilter,
285285
truncate_locals=truncate_locals,

0 commit comments

Comments
 (0)