Skip to content

Commit cfaa83e

Browse files
authored
Extend recognition of Pytest context managers: add deprecated_call() and warns() (#199)
* Add examples for namespaced context manager use * Rename ActNodeType from pytest_raises to pytest_context_manager * Soften node analysis function to make space for other pytest CMs * Extend recognition of Pytest CMs: include deprecated_call() and warns() * Update CHANGELOG * Tweak docs * Improve py versions and black error notes * Move error codes up 1 place in the toc - put them above test discovery internals. * Clean up CM list in AAA01 doc. * Add pytest CM good examples from @lyz-code * Clean up Changelog entry: just log new example for CM
1 parent 744b628 commit cfaa83e

File tree

13 files changed

+96
-21
lines changed

13 files changed

+96
-21
lines changed

CHANGELOG.rst

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,16 @@ Added
2929
* 📕 Extended Changelog entries to include markers indicating focus. `Pull #201
3030
<https://github.com/jamescooke/flake8-aaa/pull/201>`_
3131

32+
* 🎈 Support for Pytest context managers ``pytest.warns()`` and
33+
``pytest.deprecated_call()``. `Issue #196
34+
<https://github.com/jamescooke/flake8-aaa/issues/196>`_, `pull #199
35+
<https://github.com/jamescooke/flake8-aaa/pull/199>`_.
36+
37+
* ⛏️ "Bad" example added for scenario where manager will only be found if it is
38+
in the ``pytest`` namespace. To be compatible with Flake8-AAA tests need to
39+
``import pytest`` and not ``from pytest import raises``. `Pull #199
40+
<https://github.com/jamescooke/flake8-aaa/pull/199>`_.
41+
3242
Changed
3343
.......
3444

docs/compatibility.rst

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@ Flake8-AAA is fully compatible and tested against the latest versions of Python
1414

1515
.. admonition:: See also...
1616

17-
:ref:`Previously supported Python versions <previous-python-versions>`.
17+
See :ref:`full list of previously supported Python versions
18+
<previous-python-versions>` for links to the last supported packages and
19+
documentation.
1820

1921
Flake8
2022
------
@@ -62,9 +64,10 @@ They are then checked to pass Flake8-AAA's linting.
6264

6365
.. note::
6466

65-
We are aware that new management of blank lines released in Black
66-
``23.1.0`` cause ``AAA03`` errors to be raised and this is tracked `in
67-
issue #200 <https://github.com/jamescooke/flake8-aaa/issues/200>`_.
67+
Black version ``23.1.0`` changed how it managed blank lines by default.
68+
This change causes Flake8-AAA to raise ``AAA03`` errors on tests that
69+
contain context managers and are formatted with Black. See `issue #200
70+
<https://github.com/jamescooke/flake8-aaa/issues/200>`_.
6871

6972
Pytest
7073
------

docs/error_codes/AAA01-no-act-block-found-in-test.rst

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,5 +86,7 @@ The Act block carries out a single action on an object so it's important that
8686
Flake8-AAA can clearly distinguish which line or lines make up the Act block in
8787
every test.
8888

89-
Code blocks wrapped in ``pytest.raises()`` and ``unittest.assertRaises()``
90-
context managers are recognised as Act blocks.
89+
Flake8-AAA recognises code blocks wrapped in Pytest context managers like
90+
``pytest.raises()`` as Act blocks.
91+
92+
It also recognises unittest's ``assertRaises()`` blocks as Act blocks.

docs/index.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ Continue here for more detail about using Flake8-AAA.
1717
:caption: Contents
1818

1919
compatibility
20-
discovery
2120
error_codes/all
21+
discovery
2222
commands
2323
release_checklist

examples/bad/bad_expected.out

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
examples/bad/test.py:4:1: AAA01 no Act block found in test
22
examples/bad/test_aaa01.py:8:1: AAA01 no Act block found in test
3+
examples/bad/test_aaa01_cm_import.py:11:1: AAA01 no Act block found in test
4+
examples/bad/test_aaa01_cm_import.py:18:1: AAA01 no Act block found in test
35
examples/bad/test_aaa03.py:10:9: AAA03 expected 1 blank line before Act block, found none
46
examples/bad/test_aaa03.py:3:5: AAA03 expected 1 blank line before Act block, found none
57
examples/bad/test_aaa03_04.py:10:5: AAA04 expected 1 blank line before Assert block, found none
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
"""
2+
Failure of AAA01: when pytest context managers are not imported "in" pytest,
3+
then they can't be found
4+
"""
5+
6+
# Unusual import of raises and warns: docs / convention uses `import pytest` so
7+
# preserves namespace.
8+
from pytest import raises, warns
9+
10+
11+
def test_imported() -> None:
12+
one_stuff = [1]
13+
14+
with raises(IndexError):
15+
one_stuff[1]
16+
17+
18+
def test_warns() -> None:
19+
with warns(UserWarning, match="yamlfix/pull/182"):
20+
pass

examples/good/test_with_statement.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import io
2+
import warnings
23
from typing import Generator, List
34

45
import pytest
@@ -11,6 +12,16 @@ def test_pytest_raises() -> None:
1112
list()[0]
1213

1314

15+
def test_deprecation_warning():
16+
with pytest.deprecated_call():
17+
warnings.warn("deprecate warning", DeprecationWarning)
18+
19+
20+
def test_user_warning():
21+
with pytest.warns(UserWarning):
22+
warnings.warn("my warning", UserWarning)
23+
24+
1425
# --- Use of context managers in tests ---
1526

1627

src/flake8_aaa/act_node.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from .helpers import (
66
get_first_token,
77
get_last_token,
8-
node_is_pytest_raises,
8+
node_is_pytest_context_manager,
99
node_is_result_assignment,
1010
node_is_unittest_raises,
1111
)
@@ -56,8 +56,8 @@ def build(cls: Type[AN], node: ast.stmt) -> List[AN]:
5656
"""
5757
if node_is_result_assignment(node):
5858
return [cls(node, ActNodeType.result_assignment)]
59-
if node_is_pytest_raises(node):
60-
return [cls(node, ActNodeType.pytest_raises)]
59+
if node_is_pytest_context_manager(node):
60+
return [cls(node, ActNodeType.pytest_context_manager)]
6161
if node_is_unittest_raises(node):
6262
return [cls(node, ActNodeType.unittest_raises)]
6363

src/flake8_aaa/helpers.py

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,16 +77,28 @@ def node_is_result_assignment(node: ast.AST) -> bool:
7777
return False
7878

7979

80-
def node_is_pytest_raises(node: ast.AST) -> bool:
80+
cm_exp = re.compile(r'^\s*with\ pytest\.(raises|deprecated_call|warns)\(')
81+
82+
83+
def node_is_pytest_context_manager(node: ast.AST) -> bool:
8184
"""
85+
Identify node as being one of the Pytest context managers used to catch
86+
exceptions and warnings.
87+
88+
Pytest's context managers as of 7.2 are:
89+
90+
* pytest.raises()
91+
* pytest.deprecated_call()
92+
* pytest.warns()
93+
8294
Args:
8395
node: An ``ast`` node, augmented with ASTTokens
8496
8597
Returns:
8698
bool: ``node`` corresponds to a With node where the context manager is
87-
``pytest.raises``.
99+
a Pytest context manager.
88100
"""
89-
return isinstance(node, ast.With) and get_first_token(node).line.strip().startswith('with pytest.raises')
101+
return isinstance(node, ast.With) and bool(cm_exp.match(get_first_token(node).line))
90102

91103

92104
def node_is_unittest_raises(node: ast.AST) -> bool:

src/flake8_aaa/types.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
'ActNodeType',
55
(
66
'marked_act ' # Marked with "# act"
7-
'pytest_raises ' # Wrapped in "pytest.raises" context manager.
7+
'pytest_context_manager ' # Pytest context manager e.g. "pytest.raises"
88
'result_assignment ' # Simple "result = "
99
'unittest_raises ' # Wrapped in unittest's "assertRaises" context manager.
1010
),

0 commit comments

Comments
 (0)