Skip to content

Commit 3b58285

Browse files
authored
Merge pull request #6712 from nicoddemus/mm
Merge master into features
2 parents 7484e34 + 78baa7b commit 3b58285

31 files changed

+161
-138
lines changed

.github/PULL_REQUEST_TEMPLATE.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ Here is a quick checklist that should be present in PRs.
77
- [ ] Target the `features` branch for new features, improvements, and removals/deprecations.
88
- [ ] Include documentation when adding new features.
99
- [ ] Include new tests or update existing tests when applicable.
10+
- [X] Allow maintainers to push and squash when merging my commits. Please uncheck this if you prefer to squash the commits yourself.
1011
1112
Unless your change is trivial or a small documentation fix (e.g., a typo or reword of a small section) please:
1213

.travis.yml

Lines changed: 5 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
language: python
2-
dist: xenial
3-
python: '3.7'
2+
dist: trusty
3+
python: '3.5.1'
44
cache: false
55

66
env:
@@ -16,36 +16,11 @@ install:
1616

1717
jobs:
1818
include:
19-
# OSX tests - first (in test stage), since they are the slower ones.
20-
# Coverage for:
21-
# - osx
22-
# - verbose=1
23-
- os: osx
24-
osx_image: xcode10.1
25-
language: generic
26-
env: TOXENV=py37-xdist PYTEST_COVERAGE=1 PYTEST_ADDOPTS=-v
27-
before_install:
28-
- which python3
29-
- python3 -V
30-
- ln -sfn "$(which python3)" /usr/local/bin/python
31-
- python -V
32-
- test $(python -c 'import sys; print("%d%d" % sys.version_info[0:2])') = 37
33-
34-
# Full run of latest supported version, without xdist.
35-
# Coverage for:
36-
# - pytester's LsofFdLeakChecker
37-
# - TestArgComplete (linux only)
38-
# - numpy
39-
# - old attrs
40-
# - verbose=0
41-
# - test_sys_breakpoint_interception (via pexpect).
42-
- env: TOXENV=py37-lsof-numpy-oldattrs-pexpect-twisted PYTEST_COVERAGE=1 PYTEST_ADDOPTS=
43-
python: '3.7'
44-
4519
# Coverage for Python 3.5.{0,1} specific code, mostly typing related.
4620
- env: TOXENV=py35 PYTEST_COVERAGE=1 PYTEST_ADDOPTS="-k test_raises_cyclic_reference"
47-
python: '3.5.1'
48-
dist: trusty
21+
before_install:
22+
# Work around https://github.com/jaraco/zipp/issues/40.
23+
- python -m pip install -U pip 'setuptools>=34.4.0' virtualenv
4924

5025
before_script:
5126
- |

changelog/6646.bugfix.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Assertion rewriting hooks are (re)stored for the current item, which fixes them being still used after e.g. pytester's :func:`testdir.runpytest <_pytest.pytester.Testdir.runpytest>` etc.

changelog/6660.bugfix.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
:func:`pytest.exit() <_pytest.outcomes.exit>` is handled when emitted from the :func:`pytest_sessionfinish <_pytest.hookspec.pytest_sessionfinish>` hook. This includes quitting from a debugger.

doc/en/conf.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@
162162
# The name of an image file (within the static path) to use as favicon of the
163163
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
164164
# pixels large.
165-
html_favicon = "img/pytest1favi.ico"
165+
html_favicon = "img/favicon.png"
166166

167167
# Add any paths that contain custom static files (such as style sheets) here,
168168
# relative to this directory. They are copied after the builtin static files,

doc/en/img/favicon.png

1.3 KB
Loading

doc/en/img/pytest1favi.ico

-3.65 KB
Binary file not shown.

doc/en/reference.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -901,8 +901,8 @@ Can be either a ``str`` or ``Sequence[str]``.
901901
pytest_plugins = ("myapp.testsupport.tools", "myapp.testsupport.regression")
902902
903903
904-
pytest_mark
905-
~~~~~~~~~~~
904+
pytestmark
905+
~~~~~~~~~~
906906

907907
**Tutorial**: :ref:`scoped-marking`
908908

src/_pytest/_code/code.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ def path(self) -> Union[py.path.local, str]:
7272
""" return a path object pointing to source code (or a str in case
7373
of OSError / non-existing file).
7474
"""
75+
if not self.raw.co_filename:
76+
return ""
7577
try:
7678
p = py.path.local(self.raw.co_filename)
7779
# maybe don't try this checking

src/_pytest/_code/source.py

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from bisect import bisect_right
99
from types import CodeType
1010
from types import FrameType
11+
from typing import Any
1112
from typing import Iterator
1213
from typing import List
1314
from typing import Optional
@@ -17,6 +18,7 @@
1718

1819
import py
1920

21+
from _pytest.compat import get_real_func
2022
from _pytest.compat import overload
2123
from _pytest.compat import TYPE_CHECKING
2224

@@ -277,14 +279,21 @@ def compile_( # noqa: F811
277279
return s.compile(filename, mode, flags, _genframe=_genframe)
278280

279281

280-
def getfslineno(obj) -> Tuple[Optional[Union["Literal['']", py.path.local]], int]:
282+
def getfslineno(obj: Any) -> Tuple[Union[str, py.path.local], int]:
281283
""" Return source location (path, lineno) for the given object.
282284
If the source cannot be determined return ("", -1).
283285
284286
The line number is 0-based.
285287
"""
286288
from .code import Code
287289

290+
# xxx let decorators etc specify a sane ordering
291+
# NOTE: this used to be done in _pytest.compat.getfslineno, initially added
292+
# in 6ec13a2b9. It ("place_as") appears to be something very custom.
293+
obj = get_real_func(obj)
294+
if hasattr(obj, "place_as"):
295+
obj = obj.place_as
296+
288297
try:
289298
code = Code(obj)
290299
except TypeError:
@@ -293,18 +302,16 @@ def getfslineno(obj) -> Tuple[Optional[Union["Literal['']", py.path.local]], int
293302
except TypeError:
294303
return "", -1
295304

296-
fspath = fn and py.path.local(fn) or None
305+
fspath = fn and py.path.local(fn) or ""
297306
lineno = -1
298307
if fspath:
299308
try:
300309
_, lineno = findsource(obj)
301310
except IOError:
302311
pass
312+
return fspath, lineno
303313
else:
304-
fspath = code.path
305-
lineno = code.firstlineno
306-
assert isinstance(lineno, int)
307-
return fspath, lineno
314+
return code.path, code.firstlineno
308315

309316

310317
#

src/_pytest/assertion/__init__.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from _pytest.assertion import truncate
99
from _pytest.assertion import util
1010
from _pytest.compat import TYPE_CHECKING
11+
from _pytest.config import hookimpl
1112

1213
if TYPE_CHECKING:
1314
from _pytest.main import Session
@@ -105,7 +106,8 @@ def pytest_collection(session: "Session") -> None:
105106
assertstate.hook.set_session(session)
106107

107108

108-
def pytest_runtest_setup(item):
109+
@hookimpl(tryfirst=True, hookwrapper=True)
110+
def pytest_runtest_protocol(item):
109111
"""Setup the pytest_assertrepr_compare and pytest_assertion_pass hooks
110112
111113
The newinterpret and rewrite modules will use util._reprcompare if
@@ -143,6 +145,7 @@ def callbinrepr(op, left, right):
143145
return res
144146
return None
145147

148+
saved_assert_hooks = util._reprcompare, util._assertion_pass
146149
util._reprcompare = callbinrepr
147150

148151
if item.ihook.pytest_assertion_pass.get_hookimpls():
@@ -154,10 +157,9 @@ def call_assertion_pass_hook(lineno, orig, expl):
154157

155158
util._assertion_pass = call_assertion_pass_hook
156159

160+
yield
157161

158-
def pytest_runtest_teardown(item):
159-
util._reprcompare = None
160-
util._assertion_pass = None
162+
util._reprcompare, util._assertion_pass = saved_assert_hooks
161163

162164

163165
def pytest_sessionfinish(session):

src/_pytest/compat.py

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
import attr
2424
import py
2525

26-
import _pytest
2726
from _pytest._io.saferepr import saferepr
2827
from _pytest.outcomes import fail
2928
from _pytest.outcomes import TEST_OUTCOME
@@ -308,16 +307,6 @@ def get_real_method(obj, holder):
308307
return obj
309308

310309

311-
def getfslineno(obj) -> Tuple[Union[str, py.path.local], int]:
312-
# xxx let decorators etc specify a sane ordering
313-
obj = get_real_func(obj)
314-
if hasattr(obj, "place_as"):
315-
obj = obj.place_as
316-
fslineno = _pytest._code.getfslineno(obj)
317-
assert isinstance(fslineno[1], int), obj
318-
return fslineno
319-
320-
321310
def getimfunc(func):
322311
try:
323312
return func.__func__

src/_pytest/config/__init__.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828
from pluggy import PluginManager
2929

3030
import _pytest._code
31-
import _pytest.assertion
3231
import _pytest.deprecated
3332
import _pytest.hookspec # the extension point definitions
3433
from .exceptions import PrintHelp
@@ -284,6 +283,8 @@ class PytestPluginManager(PluginManager):
284283
"""
285284

286285
def __init__(self):
286+
import _pytest.assertion
287+
287288
super().__init__("pytest")
288289
# The objects are module objects, only used generically.
289290
self._conftest_plugins = set() # type: Set[object]
@@ -917,6 +918,8 @@ def _consider_importhook(self, args: Sequence[str]) -> None:
917918
ns, unknown_args = self._parser.parse_known_and_unknown_args(args)
918919
mode = getattr(ns, "assertmode", "plain")
919920
if mode == "rewrite":
921+
import _pytest.assertion
922+
920923
try:
921924
hook = _pytest.assertion.install_importhook(self)
922925
except SystemError:

src/_pytest/fixtures.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,12 @@
1515
import _pytest
1616
from _pytest._code.code import FormattedExcinfo
1717
from _pytest._code.code import TerminalRepr
18+
from _pytest._code.source import getfslineno
1819
from _pytest._io import TerminalWriter
1920
from _pytest.compat import _format_args
2021
from _pytest.compat import _PytestWrapper
2122
from _pytest.compat import get_real_func
2223
from _pytest.compat import get_real_method
23-
from _pytest.compat import getfslineno
2424
from _pytest.compat import getfuncargnames
2525
from _pytest.compat import getimfunc
2626
from _pytest.compat import getlocation

src/_pytest/logging.py

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from typing import Mapping
1111

1212
import pytest
13+
from _pytest import nodes
1314
from _pytest.compat import nullcontext
1415
from _pytest.config import _strtobool
1516
from _pytest.config import create_terminal_writer
@@ -326,13 +327,13 @@ def _finalize(self) -> None:
326327
logger.setLevel(level)
327328

328329
@property
329-
def handler(self):
330+
def handler(self) -> LogCaptureHandler:
330331
"""
331332
:rtype: LogCaptureHandler
332333
"""
333-
return self._item.catch_log_handler
334+
return self._item.catch_log_handler # type: ignore[no-any-return] # noqa: F723
334335

335-
def get_records(self, when):
336+
def get_records(self, when: str) -> List[logging.LogRecord]:
336337
"""
337338
Get the logging records for one of the possible test phases.
338339
@@ -346,7 +347,7 @@ def get_records(self, when):
346347
"""
347348
handler = self._item.catch_log_handlers.get(when)
348349
if handler:
349-
return handler.records
350+
return handler.records # type: ignore[no-any-return] # noqa: F723
350351
else:
351352
return []
352353

@@ -619,7 +620,9 @@ def _runtest_for(self, item, when):
619620
yield
620621

621622
@contextmanager
622-
def _runtest_for_main(self, item, when):
623+
def _runtest_for_main(
624+
self, item: nodes.Item, when: str
625+
) -> Generator[None, None, None]:
623626
"""Implements the internals of pytest_runtest_xxx() hook."""
624627
with catching_logs(
625628
LogCaptureHandler(), formatter=self.formatter, level=self.log_level
@@ -632,15 +635,15 @@ def _runtest_for_main(self, item, when):
632635
return
633636

634637
if not hasattr(item, "catch_log_handlers"):
635-
item.catch_log_handlers = {}
636-
item.catch_log_handlers[when] = log_handler
637-
item.catch_log_handler = log_handler
638+
item.catch_log_handlers = {} # type: ignore[attr-defined] # noqa: F821
639+
item.catch_log_handlers[when] = log_handler # type: ignore[attr-defined] # noqa: F821
640+
item.catch_log_handler = log_handler # type: ignore[attr-defined] # noqa: F821
638641
try:
639642
yield # run test
640643
finally:
641644
if when == "teardown":
642-
del item.catch_log_handler
643-
del item.catch_log_handlers
645+
del item.catch_log_handler # type: ignore[attr-defined] # noqa: F821
646+
del item.catch_log_handlers # type: ignore[attr-defined] # noqa: F821
644647

645648
if self.print_logs:
646649
# Add a captured log section to the report.

0 commit comments

Comments
 (0)