-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add PT028 (checks for default arguments in test functions) (#324)
Fixes #316
- Loading branch information
Showing
9 changed files
with
188 additions
and
18 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
# PT028 | ||
|
||
`test function {name} has default value for argument {arg}, remove it` | ||
|
||
## Examples | ||
|
||
Bad code: | ||
|
||
```python | ||
def test_foo(bar=42): | ||
pass | ||
``` | ||
|
||
Good code: | ||
|
||
```python | ||
def test_foo(bar): | ||
pass | ||
``` | ||
|
||
## Rationale | ||
|
||
* even if the corresponding fixture is defined, current behavior of pytest is | ||
to use the default value instead of injecting the fixture | ||
* see original pytest issue: https://github.com/pytest-dev/pytest#12693 |
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
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,44 @@ | ||
from flake8_plugin_utils import Visitor | ||
|
||
from flake8_pytest_style.config import Config | ||
from flake8_pytest_style.errors import ( | ||
FixtureParamWithoutValue, | ||
TFunctionArgumentWithDefault, | ||
) | ||
from flake8_pytest_style.utils import AnyFunctionDef, is_test_function | ||
|
||
|
||
# This should be named `TestFunctionsVisitor` (and the module `test_functions`), | ||
# but this way it is easier to avoid confusion with the `Test` prefix in pytest. | ||
class TFunctionsVisitor(Visitor[Config]): | ||
def _check_test_function_args(self, node: AnyFunctionDef) -> None: | ||
"""Checks for PT019, P028.""" | ||
# intentionally not looking at posonlyargs because pytest passes everything | ||
# as kwargs, so declaring fixture args as positional-only will fail anyway | ||
for arg in node.args.args + node.args.kwonlyargs: | ||
if arg.arg.startswith('_'): | ||
# The error is raised at the position of `node` (function call), | ||
# not `arg`, to preserve backwards compatibility. | ||
self.error_from_node(FixtureParamWithoutValue, node, name=arg.arg) | ||
|
||
if node.args.defaults: | ||
pos_args = node.args.posonlyargs + node.args.args | ||
pos_args_with_defaults = pos_args[-len(node.args.defaults) :] # noqa: E203 | ||
for arg in pos_args_with_defaults: | ||
self.error_from_node( | ||
TFunctionArgumentWithDefault, arg, name=node.name, arg=arg.arg | ||
) | ||
|
||
for arg, default in zip(node.args.kwonlyargs, node.args.kw_defaults): | ||
if default is not None: | ||
self.error_from_node( | ||
TFunctionArgumentWithDefault, arg, name=node.name, arg=arg.arg | ||
) | ||
|
||
def visit_FunctionDef(self, node: AnyFunctionDef) -> None: | ||
if is_test_function(node): | ||
self._check_test_function_args(node) | ||
|
||
self.generic_visit(node) | ||
|
||
visit_AsyncFunctionDef = visit_FunctionDef # noqa: N815 |
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 |
---|---|---|
@@ -1,36 +1,36 @@ | ||
from flake8_plugin_utils.utils import assert_error, assert_not_error | ||
|
||
from flake8_pytest_style.errors import FixtureParamWithoutValue | ||
from flake8_pytest_style.visitors import FixturesVisitor | ||
from flake8_pytest_style.visitors import TFunctionsVisitor | ||
|
||
|
||
def test_ok_good_param_name(): | ||
code = """ | ||
def test_xxx(fixture): | ||
pass | ||
""" | ||
assert_not_error(FixturesVisitor, code) | ||
assert_not_error(TFunctionsVisitor, code) | ||
|
||
|
||
def test_ok_non_test_function(): | ||
code = """ | ||
def xxx(_param): | ||
pass | ||
""" | ||
assert_not_error(FixturesVisitor, code) | ||
assert_not_error(TFunctionsVisitor, code) | ||
|
||
|
||
def test_error_arg(): | ||
code = """ | ||
def test_xxx(_fixture): | ||
pass | ||
""" | ||
assert_error(FixturesVisitor, code, FixtureParamWithoutValue, name='_fixture') | ||
assert_error(TFunctionsVisitor, code, FixtureParamWithoutValue, name='_fixture') | ||
|
||
|
||
def test_error_kwonly(): | ||
code = """ | ||
def test_xxx(*, _fixture): | ||
pass | ||
""" | ||
assert_error(FixturesVisitor, code, FixtureParamWithoutValue, name='_fixture') | ||
assert_error(TFunctionsVisitor, code, FixtureParamWithoutValue, name='_fixture') |
101 changes: 101 additions & 0 deletions
101
tests/test_PT028_test_function_argument_with_default.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,101 @@ | ||
import ast | ||
import textwrap | ||
|
||
from flake8_plugin_utils.utils import assert_error, assert_not_error | ||
|
||
from flake8_pytest_style.errors import TFunctionArgumentWithDefault | ||
from flake8_pytest_style.visitors import TFunctionsVisitor | ||
|
||
|
||
def test_ok(): | ||
code = """ | ||
def test_xxx(fixture1, /, fixture2, *, fixture3): | ||
pass | ||
""" | ||
assert_not_error(TFunctionsVisitor, code) | ||
|
||
|
||
def test_ok_non_test_function(): | ||
code = """ | ||
def xxx(posonly1, posonly2=2, /, arg=3, *, kwonly=4): | ||
pass | ||
""" | ||
assert_not_error(TFunctionsVisitor, code) | ||
|
||
|
||
def test_error_posonly(): | ||
code = """ | ||
def test_xxx(posonly1, posonly2=2, /): | ||
pass | ||
""" | ||
assert_error( | ||
TFunctionsVisitor, | ||
code, | ||
TFunctionArgumentWithDefault, | ||
name='test_xxx', | ||
arg='posonly2', | ||
) | ||
|
||
|
||
def test_error_arg(): | ||
code = """ | ||
def test_xxx(arg1, arg2=2): | ||
pass | ||
""" | ||
assert_error( | ||
TFunctionsVisitor, | ||
code, | ||
TFunctionArgumentWithDefault, | ||
name='test_xxx', | ||
arg='arg2', | ||
) | ||
|
||
|
||
def test_error_kwonly(): | ||
code = """ | ||
def test_xxx(*, kwonly1, kwonly2=2): | ||
pass | ||
""" | ||
assert_error( | ||
TFunctionsVisitor, | ||
code, | ||
TFunctionArgumentWithDefault, | ||
name='test_xxx', | ||
arg='kwonly2', | ||
) | ||
|
||
|
||
def test_error_multiple(): | ||
code = """ | ||
def test_xxx( | ||
posonly=1, | ||
/, | ||
arg=2, | ||
*, | ||
kwonly=3, | ||
): | ||
pass | ||
""" | ||
# flake8-plugin-utils does not allow multiple errors in a single test | ||
visitor = TFunctionsVisitor() | ||
visitor.visit(ast.parse(textwrap.dedent(code))) | ||
assert len(visitor.errors) == 3 | ||
posonly_error, arg_error, kwonly_error = visitor.errors | ||
|
||
assert isinstance(posonly_error, TFunctionArgumentWithDefault) | ||
assert posonly_error.message == TFunctionArgumentWithDefault.formatted_message( | ||
name='test_xxx', arg='posonly' | ||
) | ||
assert posonly_error.lineno == 3 | ||
|
||
assert isinstance(arg_error, TFunctionArgumentWithDefault) | ||
assert arg_error.message == TFunctionArgumentWithDefault.formatted_message( | ||
name='test_xxx', arg='arg' | ||
) | ||
assert arg_error.lineno == 5 | ||
|
||
assert isinstance(kwonly_error, TFunctionArgumentWithDefault) | ||
assert kwonly_error.message == TFunctionArgumentWithDefault.formatted_message( | ||
name='test_xxx', arg='kwonly' | ||
) | ||
assert kwonly_error.lineno == 7 |