-
-
Notifications
You must be signed in to change notification settings - Fork 64
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add test skip decorator fixer (#498)
Start of #364.
- Loading branch information
1 parent
3b1421f
commit 666a6ce
Showing
6 changed files
with
294 additions
and
37 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
60 changes: 60 additions & 0 deletions
60
src/django_upgrade/fixers/versioned_test_skip_decorators.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
from __future__ import annotations | ||
|
||
import ast | ||
from collections.abc import Iterable | ||
from functools import partial | ||
|
||
from tokenize_rt import Offset | ||
from tokenize_rt import Token | ||
|
||
from django_upgrade.ast import ast_start_offset | ||
from django_upgrade.ast import is_passing_comparison | ||
from django_upgrade.data import Fixer | ||
from django_upgrade.data import State | ||
from django_upgrade.data import TokenFunc | ||
from django_upgrade.tokens import OP | ||
from django_upgrade.tokens import erase_node | ||
from django_upgrade.tokens import reverse_find | ||
|
||
fixer = Fixer( | ||
__name__, | ||
min_version=(0, 0), | ||
) | ||
|
||
|
||
@fixer.register(ast.FunctionDef) | ||
def visit_FunctionDef( | ||
state: State, | ||
node: ast.FunctionDef, | ||
parents: tuple[ast.AST, ...], | ||
) -> Iterable[tuple[Offset, TokenFunc]]: | ||
for decorator in node.decorator_list: | ||
if ( | ||
isinstance(decorator, ast.Call) | ||
and isinstance(decorator.func, ast.Attribute) | ||
and isinstance(decorator.func.value, ast.Name) | ||
and decorator.func.value.id == "unittest" | ||
and decorator.func.attr in ("skipIf", "skipUnless") | ||
and len(decorator.args) == 2 | ||
and isinstance(decorator.args[0], ast.Compare) | ||
and ( | ||
(pass_fail := is_passing_comparison(decorator.args[0], state)) | ||
is not None | ||
) | ||
and ( | ||
(decorator.func.attr == "skipIf" and pass_fail == "fail") | ||
or (decorator.func.attr == "skipUnless" and pass_fail == "pass") | ||
) | ||
): | ||
yield ast_start_offset(decorator), partial(erase_decorator, node=decorator) | ||
|
||
|
||
def erase_decorator( | ||
tokens: list[Token], | ||
i: int, | ||
*, | ||
node: ast.Call, | ||
) -> None: | ||
erase_node(tokens, i, node=node) | ||
at_j = reverse_find(tokens, i, name=OP, src="@") | ||
del tokens[at_j:i] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
from __future__ import annotations | ||
|
||
from functools import partial | ||
|
||
from django_upgrade.data import Settings | ||
from tests.fixers import tools | ||
|
||
settings = Settings(target_version=(4, 1)) | ||
check_noop = partial(tools.check_noop, settings=settings) | ||
check_transformed = partial(tools.check_transformed, settings=settings) | ||
|
||
|
||
def test_unittest_skip_left(): | ||
check_noop( | ||
"""\ | ||
import unittest | ||
@unittest.skip("Always skipped") | ||
def test_thing(self): | ||
pass | ||
""", | ||
) | ||
|
||
|
||
def test_unittest_skipIf_too_few_args(): | ||
check_noop( | ||
"""\ | ||
import unittest | ||
import django | ||
@unittest.skipIf(django.VERSION < (4, 1)) | ||
def test_thing(self): | ||
pass | ||
""", | ||
) | ||
|
||
|
||
def test_unittest_skipIf_too_many_args(): | ||
check_noop( | ||
"""\ | ||
import unittest | ||
import django | ||
@unittest.skipIf(django.VERSION < (4, 1), "Django 4.1+", "what is this arg?") | ||
def test_thing(self): | ||
pass | ||
""", | ||
) | ||
|
||
|
||
def test_unittest_skipIf_passing_comparison(): | ||
check_noop( | ||
"""\ | ||
import unittest | ||
import django | ||
@unittest.skipIf(django.VERSION < (4, 2), "Django 4.2+") | ||
def test_thing(self): | ||
pass | ||
""", | ||
) | ||
|
||
|
||
def test_unittest_skipIf_unknown_comparison(): | ||
check_noop( | ||
"""\ | ||
import unittest | ||
import django | ||
@unittest.skipIf(django.VERSION < (4, 1, 1), "Django 4.1.1+") | ||
def test_thing(self): | ||
pass | ||
""", | ||
) | ||
|
||
|
||
def test_unittest_skipUnless_failing_comparison(): | ||
check_noop( | ||
"""\ | ||
import unittest | ||
import django | ||
@unittest.skipUnless(django.VERSION >= (4, 2), "Django 4.2+") | ||
def test_thing(self): | ||
pass | ||
""", | ||
) | ||
|
||
|
||
def test_unittest_skipIf_removed(): | ||
check_transformed( | ||
"""\ | ||
import unittest | ||
import django | ||
@unittest.skipIf(django.VERSION < (4, 1), "Django 4.1+") | ||
def test_thing(self): | ||
pass | ||
""", | ||
"""\ | ||
import unittest | ||
import django | ||
def test_thing(self): | ||
pass | ||
""", | ||
) | ||
|
||
|
||
def test_skipUnless_removed(): | ||
check_transformed( | ||
"""\ | ||
import unittest | ||
import django | ||
@unittest.skipUnless(django.VERSION >= (4, 1), "Django 4.1+") | ||
def test_thing(self): | ||
pass | ||
""", | ||
"""\ | ||
import unittest | ||
import django | ||
def test_thing(self): | ||
pass | ||
""", | ||
) |