Refactoring

These checks ensure that you don’t have patterns that can be refactored.

There are so many ways of doing the same thing in Python. Here we collect know patterns that can be rewritten into much easier or just more pythonic version.

Summary

UselessLoopElseViolation

WPS500 — Forbid else without break in a loop.

UselessFinallyViolation

WPS501 — Forbid finally in try block without except block.

SimplifiableIfViolation

WPS502 — Forbid simplifiable if conditions.

UselessReturningElseViolation

WPS503 — Forbid useless else cases in returning functions.

NegatedConditionsViolation

WPS504 — Forbid negated conditions together with else clause.

NestedTryViolation

WPS505 — Forbid nested try blocks.

UselessLambdaViolation

WPS506 — Forbid useless proxy lambda expressions.

UselessLenCompareViolation

WPS507 — Forbid unpythonic zero-length compare.

NotOperatorWithCompareViolation

WPS508 — Forbid not with compare expressions.

NestedTernaryViolation

WPS509 — Forbid nesting ternary expressions in certain places.

WrongInCompareTypeViolation

WPS510 — Forbid in with static containers except set nodes.

UnmergedIsinstanceCallsViolation

WPS511 — Forbid multiple isinstance calls on the same variable.

WrongIsinstanceWithTupleViolation

WPS512 — Forbid multiple isinstance calls with single-item tuples.

ImplicitElifViolation

WPS513 — Forbid implicit elif conditions.

ImplicitInConditionViolation

WPS514 — Forbid multiple equality comparisons with the same variable.

OpenWithoutContextManagerViolation

WPS515 — Forbid open() without a context manager.

TypeCompareViolation

WPS516 — Forbid comparing types with type() function.

PointlessStarredViolation

WPS517 — Forbid useless starred expressions.

ImplicitEnumerateViolation

WPS518 — Forbid implicit enumerate() calls.

ImplicitSumViolation

WPS519 — Forbid implicit sum() calls.

FalsyConstantCompareViolation

WPS520 — Forbid comparing with explicit falsy constants.

WrongIsCompareViolation

WPS521 — Forbid comparing values with constants using is or is not.

ImplicitPrimitiveViolation

WPS522 — Forbid implicit primitives in the form of lambda functions.

AlmostSwappedViolation

WPS523 — Forbid unpythonic variable swaps.

MisrefactoredAssignmentViolation

WPS524 — Forbid misrefactored self assignment.

InCompareWithSingleItemContainerViolation

WPS525 — Forbid comparisons where in is compared with single item container.

ImplicitYieldFromViolation

WPS526 — Forbid yield inside for loop instead of yield from.

NotATupleArgumentViolation

WPS527 — Require tuples as arguments for certain functions.

ImplicitItemsIteratorViolation

WPS528 — Forbid implicit .items() iterator.

ImplicitDictGetViolation

WPS529 — Forbid implicit .get() dict method.

ImplicitNegativeIndexViolation

WPS530 — Forbid implicit negative indexes.

SimplifiableReturningIfViolation

WPS531 — Forbid if statements that simply return booleans in functions or methods.

ChainedIsViolation

WPS532 — Forbid ast.Is in ast.Compare.ops when it's size is not zero.

DuplicateIfConditionViolation

WPS533 — Forbid having duplicate conditions in several if // elif branches.

UselessTernaryViolation

WPS534 — Forbid having useless ternary expressions.

DuplicateCasePatternViolation

WPS535 — Forbid having duplicate case patterns.

ExtraMatchSubjectSyntaxViolation

WPS536 — Forbid extra syntax around match like list, set, or dict.

Refactoring opportunities

final class UselessLoopElseViolation(node, text=None, baseline=None)[source]

Bases: ASTViolation

WPS500 — Forbid else without break in a loop.

We use the same logic for for and while loops.

Reasoning:

When there’s no break keyword in loop’s body it means that else will always be called. This rule will reduce complexity, improve readability, and protect from possible errors.

Solution:

Refactor your else case logic to be inside the loop’s body. Or right after it.

Example:

# Correct:
for letter in 'abc':
    if letter == 'b':
        break
else:
    print('"b" is not found')

for letter in 'abc':
    print(letter)
print('always called')

# Wrong:
for letter in 'abc':
    print(letter)
else:
    print('always called')

Added in version 0.3.0.

Changed in version 0.11.0.

error_template: ClassVar[str] = 'Found `else` in a loop without `break`'
code: ClassVar[int] = 500
full_code: ClassVar[str] = 'WPS500'
summary: ClassVar[str] = 'Forbid ``else`` without ``break`` in a loop.'
final class UselessFinallyViolation(node, text=None, baseline=None)[source]

Bases: ASTViolation

WPS501 — Forbid finally in try block without except block.

However, we allow to use try with just finally block when function or method is decorated. Because we cannot control what is going on in this decorator. It might be @contextmanager or similar thing that requires this API.

Reasoning:

This rule will reduce complexity and improve readability.

Solution:

Refactor your try logic. Replace the try-finally statement with a with statement.

Example:

# Correct:
with open("filename") as f:
    f.write(...)

# Wrong:
try:
    f = open("filename")
    f.write(...)
finally:
    f.close()

Added in version 0.3.0.

Changed in version 0.11.0.

Changed in version 0.14.0.

error_template: ClassVar[str] = 'Found `finally` in `try` block without `except`'
code: ClassVar[int] = 501
full_code: ClassVar[str] = 'WPS501'
summary: ClassVar[str] = 'Forbid ``finally`` in ``try`` block without ``except`` block.'
final class SimplifiableIfViolation(node, text=None, baseline=None)[source]

Bases: ASTViolation

WPS502 — Forbid simplifiable if conditions.

Reasoning:

These complex constructions can cause frustration among other developers. They are longer, more verbose, and more complex.

Solution:

Either use bool() to convert test values to boolean values, or just leave it as it is in case your test already returns a boolean value. Use can also use not keyword to switch boolean values.

Example:

# Correct:
my_bool = bool(some_call())
other_value = 8 if some_call() else None

# Wrong:
my_bool = True if some_call() else False

We only check if nodes where True and False values are used. We check both if nodes and if expressions.

Added in version 0.7.0.

Changed in version 0.11.0.

Changed in version 1.0.0: No longer produced, kept here for historic reasons. This is covered with ruff linter. See SIM108 and SIM210.

error_template: ClassVar[str] = 'Found simplifiable `if` condition'
code: ClassVar[int] = 502
disabled_since: ClassVar[str | None] = '1.0.0'
full_code: ClassVar[str] = 'WPS502'
summary: ClassVar[str] = 'Forbid simplifiable ``if`` conditions.'
final class UselessReturningElseViolation(node, text=None, baseline=None)[source]

Bases: ASTViolation

WPS503 — Forbid useless else cases in returning functions.

We check single if, for, while, and try statements that all contain return, raise, continue, or break statements with this rule.

Reasoning:

Using extra else creates a situation when the whole node could and should be dropped without any changes in logic. So, we prefer to have less code than more code.

Solution:

Remove useless else case.

Example:

# Correct:
def some_function():
    if some_call():
        return 'yeap'
    return 'nope'

# Wrong:
def some_function():
    if some_call():
        raise ValueError('yeap')
    else:
        raise ValueError('nope')

Added in version 0.7.0.

Changed in version 0.11.0.

Changed in version 0.15.1.

Changed in version 1.0.0: No longer produced, kept here for historic reasons. This is covered with ruff linter. See RET505.

error_template: ClassVar[str] = 'Found useless returning `else` statement'
code: ClassVar[int] = 503
disabled_since: ClassVar[str | None] = '1.0.0'
full_code: ClassVar[str] = 'WPS503'
summary: ClassVar[str] = 'Forbid useless ``else`` cases in returning functions.'
final class NegatedConditionsViolation(node, text=None, baseline=None)[source]

Bases: ASTViolation

WPS504 — Forbid negated conditions together with else clause.

Reasoning:

It easier to read and name regular conditions. Not negated ones.

Solution:

Move actions from the negated if condition to the else condition.

Example:

# Correct:
if some == 1:
    ...
else:
    ...

if not some:
    ...

if not some:
    ...
elif other:
    ...

# Wrong:
if not some:
    ...
else:
    ...

Added in version 0.8.0.

Changed in version 0.11.0.

Changed in version 1.0.0: We now also detect is not and not in as negated conditions.

We now allow using all negated conditions in if/elif/else cases.

error_template: ClassVar[str] = 'Found negated condition'
code: ClassVar[int] = 504
full_code: ClassVar[str] = 'WPS504'
summary: ClassVar[str] = 'Forbid negated conditions together with ``else`` clause.'
final class NestedTryViolation(node, text=None, baseline=None)[source]

Bases: ASTViolation

WPS505 — Forbid nested try blocks.

Notice, we check all possible slots for try block: 1. the try block itself 2. all except cases 3. else case 4. and finally case

Reasoning:

Nesting try blocks indicates that something really bad happens to your logic. Why does it require two separate exception handlers? It is a perfect case to refactor your code.

Solution:

Collapse two exception handlers together. Or create a separate function that will handle this second nested case.

Example:

# Wrong:
try:
    try:
        ...
    except SomeException:
        ...
except SomeOtherException:
    ...

try:
    ...
except SomeOtherException:
    try:
        ...
    except SomeException:
        ...

Added in version 0.8.0.

Changed in version 0.11.0.

error_template: ClassVar[str] = 'Found nested `try` block'
code: ClassVar[int] = 505
full_code: ClassVar[str] = 'WPS505'
summary: ClassVar[str] = 'Forbid nested ``try`` blocks.'
final class UselessLambdaViolation(node, text=None, baseline=None)[source]

Bases: ASTViolation

WPS506 — Forbid useless proxy lambda expressions.

Reasoning:

Sometimes developers tend to overuse lambda expressions and they wrap code that can be passed as is, without extra wrapping. The code without extra lambda is easier to read and is more performant.

Solution:

Remove wrapping lambda declaration, use just the internal function.

Example:

# Correct:
numbers = map(int, ['1', '2'])

# Wrong:
numbers = map(lambda string: int(string), ['1', '2'])

Added in version 0.10.0.

Changed in version 0.11.0.

error_template: ClassVar[str] = 'Found useless lambda declaration'
code: ClassVar[int] = 506
full_code: ClassVar[str] = 'WPS506'
summary: ClassVar[str] = 'Forbid useless proxy ``lambda`` expressions.'
final class UselessLenCompareViolation(node, text=None, baseline=None)[source]

Bases: ASTViolation

WPS507 — Forbid unpythonic zero-length compare.

Note, that we allow to check arbitrary length, like len(arr) == 3.

Reasoning:

Python’s structures like dicts, lists, sets, and tuples all have __bool__ method to checks their length. So, there’s no point in wrapping them into len(...) and checking that it is bigger that 0 or less then 1, etc.

Solution:

Remove extra len() call.

Example:

# Correct:
if some_array or not other_array or len(third_array) == 1:
    ...

# Wrong:
if len(some_array) > 0 or len(other_array) < 1:
    ...

Added in version 0.10.0.

Changed in version 0.11.0.

Changed in version 1.0.0: No longer produced, kept here for historic reasons. This is covered with ruff and pylint linters. See PLC1802.

error_template: ClassVar[str] = 'Found useless `len()` compare'
code: ClassVar[int] = 507
disabled_since: ClassVar[str | None] = '1.0.0'
full_code: ClassVar[str] = 'WPS507'
summary: ClassVar[str] = 'Forbid unpythonic zero-length compare.'
final class NotOperatorWithCompareViolation(node, text=None, baseline=None)[source]

Bases: ASTViolation

WPS508 — Forbid not with compare expressions.

Reasoning:

This version of not operator is unreadable.

Solution:

Refactor the expression without not operator. Change the compare signs.

Example:

# Correct:
if x <= 5:
    ...

# Wrong:
if not x > 5:
    ...

Added in version 0.10.0.

Changed in version 0.11.0.

Changed in version 1.0.0: No longer produced, kept here for historic reasons. This is covered with ruff linter. See SIM201.

error_template: ClassVar[str] = 'Found incorrect `not` with compare usage'
code: ClassVar[int] = 508
disabled_since: ClassVar[str | None] = '1.0.0'
full_code: ClassVar[str] = 'WPS508'
summary: ClassVar[str] = 'Forbid ``not`` with compare expressions.'
final class NestedTernaryViolation(node, text=None, baseline=None)[source]

Bases: ASTViolation

WPS509 — Forbid nesting ternary expressions in certain places.

Note, that we restrict to nest ternary expressions inside:

  • if conditions

  • boolean and binary operations like and or +

  • unary operators

Reasoning:

Nesting ternary in random places can lead to very hard debug and testing problems.

Solution:

Refactor the ternary expression to be either a new variable, or nested if statement, or a new function.

Example:

# Correct:
some = x if cond() else y

# Wrong:
if x if cond() else y:
    ...

Added in version 0.10.0.

Changed in version 0.11.0.

error_template: ClassVar[str] = 'Found incorrectly nested ternary'
code: ClassVar[int] = 509
full_code: ClassVar[str] = 'WPS509'
summary: ClassVar[str] = 'Forbid nesting ternary expressions in certain places.'
final class WrongInCompareTypeViolation(node, text=None, baseline=None)[source]

Bases: ASTViolation

WPS510 — Forbid in with static containers except set nodes.

We enforce people to use sets as a static containers. You can also use variables, calls, methods, etc. Dynamic values are not checked.

Reasoning:

Using static list, tuple, or dict elements to check that some element is inside the container is a bad practice. Because we need to iterate all over the container to find the element. Sets are the best suit for this task. Moreover, it makes your code consistent.

Solution:

Use set elements or comprehensions to check that something is contained in a container.

Example:

# Correct:
print(needle in {'one', 'two'})

# Wrong:
print(needle in ['one', 'two'])

Added in version 0.10.0.

Changed in version 0.11.0.

Changed in version 0.14.0.

Changed in version 1.0.0: No longer produced, kept here for historic reasons. This is covered with ruff and pylint linters. See PLR6201.

error_template: ClassVar[str] = 'Found `in` used with a non-set container'
code: ClassVar[int] = 510
disabled_since: ClassVar[str | None] = '1.0.0'
full_code: ClassVar[str] = 'WPS510'
summary: ClassVar[str] = 'Forbid ``in`` with static containers except ``set`` nodes.'
final class UnmergedIsinstanceCallsViolation(node, text=None, baseline=None)[source]

Bases: ASTViolation

WPS511 — Forbid multiple isinstance calls on the same variable.

Reasoning:

The best practice is to use isinstance with tuple as the second argument, instead of multiple conditions joined with or.

Solution:

Use tuple of types as the second argument.

Example:

# Correct:
isinstance(some, int | float)

# Wrong:
isinstance(some, int) or isinstance(some, float)

Added in version 0.10.0.

Changed in version 0.11.0.

Changed in version 1.0.0: No longer produced, kept here for historic reasons. This is covered with ruff formatter. See SIM101.

error_template: ClassVar[str] = 'Found separate `isinstance` calls that can be merged for: {0}'
code: ClassVar[int] = 511
disabled_since: ClassVar[str | None] = '1.0.0'
full_code: ClassVar[str] = 'WPS511'
summary: ClassVar[str] = 'Forbid multiple ``isinstance`` calls on the same variable.'
final class WrongIsinstanceWithTupleViolation(node, text=None, baseline=None)[source]

Bases: ASTViolation

WPS512 — Forbid multiple isinstance calls with single-item tuples.

Reasoning:

There’s no need to use tuples with single elements. You can use single variables or tuples with multiple elements.

Solution:

Use tuples with multiple elements or a single variable.

Example:

# Correct:
isinstance(some, int | float)
isinstance(some, int)

# Wrong:
isinstance(some, (int, ))

See: https://docs.python.org/3/library/functions.html#isinstance

Added in version 0.10.0.

Changed in version 0.11.0.

Changed in version 1.0.0: No longer produced, kept here for historic reasons. This is covered with ruff linter. See UP038.

error_template: ClassVar[str] = 'Found `isinstance` call with a single element tuple'
code: ClassVar[int] = 512
disabled_since: ClassVar[str | None] = '1.0.0'
full_code: ClassVar[str] = 'WPS512'
summary: ClassVar[str] = 'Forbid multiple ``isinstance`` calls with single-item tuples.'
final class ImplicitElifViolation(node, text=None, baseline=None)[source]

Bases: TokenizeViolation

WPS513 — Forbid implicit elif conditions.

Reasoning:

Nested if in else cases are bad for readability because of the nesting level.

Solution:

Use elif on the same level.

Example:

# Correct:
if some:
    ...
elif other:
    ...

# Wrong:
if some:
    ...
else:
    if other:
        ...

Added in version 0.12.0.

error_template: ClassVar[str] = 'Found implicit `elif` condition'
code: ClassVar[int] = 513
full_code: ClassVar[str] = 'WPS513'
summary: ClassVar[str] = 'Forbid implicit ``elif`` conditions.'
final class ImplicitInConditionViolation(node, text=None, baseline=None)[source]

Bases: ASTViolation

WPS514 — Forbid multiple equality comparisons with the same variable.

Reasoning:

Using double+ equality compare with or or double+ non-equality compare with and indicates that you have implicit in or not in condition. It is just hidden from you.

Solution:

Refactor compares to use in or not in clauses.

Example:

# Correct:
print(some in {'first', 'second'})
print(some not in {'first', 'second'})

# Wrong:
print(some == 'first' or some == 'second')
print(some != 'first' and some != 'second')

Added in version 0.10.0.

Changed in version 0.12.0.

Changed in version 1.0.0: No longer produced, kept here for historic reasons. This is covered with ruff and pylint linters. See PLR1714.

code: ClassVar[int] = 514
error_template: ClassVar[str] = 'Found implicit `in` condition: {0}'
disabled_since: ClassVar[str | None] = '1.0.0'
full_code: ClassVar[str] = 'WPS514'
summary: ClassVar[str] = 'Forbid multiple equality comparisons with the same variable.'
final class OpenWithoutContextManagerViolation(node, text=None, baseline=None)[source]

Bases: ASTViolation

WPS515 — Forbid open() without a context manager.

Reasoning:

When you open() something, you need to close it. When using a context manager - it is automatically done for you. When not using it - you might find yourself in a situation when file is not closed and is not accessible anymore.

Solution:

Refactor open() call to use with.

Example:

# Correct:
with open(filename) as file_obj:
    ...

# Wrong:
file_obj = open(filename)

Added in version 0.12.0.

code: ClassVar[int] = 515
error_template: ClassVar[str] = 'Found `open()` used without a context manager'
full_code: ClassVar[str] = 'WPS515'
summary: ClassVar[str] = 'Forbid ``open()`` without a context manager.'
final class TypeCompareViolation(node, text=None, baseline=None)[source]

Bases: ASTViolation

WPS516 — Forbid comparing types with type() function.

Reasoning:

When you compare types with type() function call it means that you break polymorphism and disallow child classes of a node to work here. That’s incorrect.

Solution:

Use isinstance to compare types.

Example:

# Correct:
print(something, type(something))

if isinstance(something, int):
    ...

# Wrong:
if type(something) == int:
    ...

Added in version 0.12.0.

code: ClassVar[int] = 516
error_template: ClassVar[str] = 'Found `type()` used to compare types'
full_code: ClassVar[str] = 'WPS516'
summary: ClassVar[str] = 'Forbid comparing types with ``type()`` function.'
final class PointlessStarredViolation(node, text=None, baseline=None)[source]

Bases: ASTViolation

WPS517 — Forbid useless starred expressions.

Reasoning:

Using starred expression with constants is useless. This piece of code can be rewritten to be flat. Eg.: print(*[1, 2, 3]) is print(1, 2, 3).

Solution:

Refactor your code not to use starred expressions with list, dict, tuple, and set constants. Use regular argument passing instead.

Example:

# Correct:
my_list = [1, 2, 3, *other_iterable]

# Wrong:
print(*[1, 2, 3], **{{}})

Added in version 0.12.0.

code: ClassVar[int] = 517
error_template: ClassVar[str] = 'Found pointless starred expression'
full_code: ClassVar[str] = 'WPS517'
summary: ClassVar[str] = 'Forbid useless starred expressions.'
final class ImplicitEnumerateViolation(node, text=None, baseline=None)[source]

Bases: ASTViolation

WPS518 — Forbid implicit enumerate() calls.

Reasoning:

Using range(len(...)) is not pythonic. Python uses collection iterators, not index-based loops.

Solution:

Use enumerate(...) instead of range(len(...)).

Example:

# Correct:
for index, person in enumerate(people):
    ...

# Wrong:
for index in range(len(people)):
    ...

Added in version 0.12.0.

code: ClassVar[int] = 518
error_template: ClassVar[str] = 'Found implicit `enumerate()` call'
full_code: ClassVar[str] = 'WPS518'
summary: ClassVar[str] = 'Forbid implicit ``enumerate()`` calls.'
final class ImplicitSumViolation(node, text=None, baseline=None)[source]

Bases: ASTViolation

WPS519 — Forbid implicit sum() calls.

When summing types different from numbers, you might need to provide the second argument to the sum function: sum([[1], [2], [3]], [])

You might also use str.join to join iterable of strings.

Reasoning:

Using for loops with += assign inside indicates that you iteratively sum things inside your collection. That’s what sum() builtin function does.

Solution:

Use sum(...) instead of a loop with += operation.

Example:

# Correct:
sum_result = sum(get_elements())

# Wrong:
sum_result = 0
for to_sum in get_elements():
    sum_result += to_sum

Added in version 0.12.0.

code: ClassVar[int] = 519
error_template: ClassVar[str] = 'Found implicit `sum()` call'
full_code: ClassVar[str] = 'WPS519'
summary: ClassVar[str] = 'Forbid implicit ``sum()`` calls.'
final class FalsyConstantCompareViolation(node, text=None, baseline=None)[source]

Bases: ASTViolation

WPS520 — Forbid comparing with explicit falsy constants.

We allow to compare with falsy numbers, strings, booleans, None. We disallow complex constants like tuple, dicts, and lists. We also allow to compare any values inside assert statements.

Reasoning:

When comparing something with explicit falsy constants what we really mean is not something.

Solution:

Use not with your variable. Fix your data types.

Example:

# Correct:
if not my_check:
    ...

if some_other is None:
    ...

if some_num == 0:
    ...

# Wrong:
if my_check == []:
    ...

Added in version 0.12.0.

Changed in version 1.0.0: Allows any compares in assert statements.

code: ClassVar[int] = 520
error_template: ClassVar[str] = 'Found compare with falsy constant'
full_code: ClassVar[str] = 'WPS520'
summary: ClassVar[str] = 'Forbid comparing with explicit falsy constants.'
final class WrongIsCompareViolation(node, text=None, baseline=None)[source]

Bases: ASTViolation

WPS521 — Forbid comparing values with constants using is or is not.

However, we allow to compare with None and booleans.

Reasoning:

is compares might not do what you want them to do. Firstly, they check for the same object, not equality. Secondly, they behave unexpectedly even with the simple values like 257.

Solution:

Use == to compare with constants.

Example:

# Correct:
if my_check == [1, 2, 3]:
    ...

# Wrong:
if my_check is [1, 2, 3]:
    ...

Added in version 0.12.0.

Changed in version 1.0.0: No longer produced, kept here for historic reasons. This is covered with ruff linter. See F632.

code: ClassVar[int] = 521
error_template: ClassVar[str] = 'Found wrong `is` compare'
disabled_since: ClassVar[str | None] = '1.0.0'
full_code: ClassVar[str] = 'WPS521'
summary: ClassVar[str] = 'Forbid comparing values with constants using ``is`` or ``is not``.'
final class ImplicitPrimitiveViolation(node, text=None, baseline=None)[source]

Bases: ASTViolation

WPS522 — Forbid implicit primitives in the form of lambda functions.

Reasoning:

When you use lambda that returns a primitive value and takes no arguments, it means that you should use a primitive type instead.

Solution:

Replace lambda with int, float, list, or any other primitive.

Example:

# Correct:
defaultdict(int)

# Wrong:
defaultdict(lambda: 0)

Added in version 0.13.0.

code: ClassVar[int] = 522
error_template: ClassVar[str] = 'Found implicit primitive in a form of `lambda`'
full_code: ClassVar[str] = 'WPS522'
summary: ClassVar[str] = 'Forbid implicit primitives in the form of ``lambda`` functions.'
final class AlmostSwappedViolation(node, text=None, baseline=None)[source]

Bases: ASTViolation

WPS523 — Forbid unpythonic variable swaps.

We check for a = b; b = a sequences.

Reasoning:

This looks like a failed attempt to swap.

Solution:

Use standard way to swap two variables.

Example:

# Correct:
a, b = b, a

# Wrong:
a = b
b = a

temp = a
a = b
b = temp

Added in version 0.13.0.

error_template: ClassVar[str] = 'Found incorrectly swapped variables'
code: ClassVar[int] = 523
full_code: ClassVar[str] = 'WPS523'
summary: ClassVar[str] = 'Forbid unpythonic variable swaps.'
final class MisrefactoredAssignmentViolation(node, text=None, baseline=None)[source]

Bases: ASTViolation

WPS524 — Forbid misrefactored self assignment.

Reasoning:

Self assignment does not need to have the same operand on the left hand side and on the right hand side.

Solution:

Refactor your code to use multiple self assignments or fix your code.

Example:

# Correct:
test += 1
test *= 2

# Wrong:
test += test + 1

See MATH_APPROXIMATE_CONSTANTS for full list of math constants that we check for.

Added in version 0.13.0.

error_template: ClassVar[str] = 'Found self assignment  with refactored assignment'
code: ClassVar[int] = 524
full_code: ClassVar[str] = 'WPS524'
summary: ClassVar[str] = 'Forbid misrefactored self assignment.'
final class InCompareWithSingleItemContainerViolation(node, text=None, baseline=None)[source]

Bases: ASTViolation

WPS525 — Forbid comparisons where in is compared with single item container.

Reasoning:

in comparison with a container which contains only one item looks like overhead and unneeded complexity.

Solution:

Refactor your code to use == instead in.

Example:

# Correct:
a == 's'

# Wrong:
a in {'s'}

Added in version 0.13.0.

Changed in version 1.0.0: No longer produced, kept here for historic reasons. This is covered with ruff linter. See FURB171.

error_template: ClassVar[str] = 'Found wrong `in` compare with single item container'
code: ClassVar[int] = 525
disabled_since: ClassVar[str | None] = '1.0.0'
full_code: ClassVar[str] = 'WPS525'
summary: ClassVar[str] = 'Forbid comparisons where ``in`` is compared with single item container.'
final class ImplicitYieldFromViolation(node, text=None, baseline=None)[source]

Bases: ASTViolation

WPS526 — Forbid yield inside for loop instead of yield from.

Reasoning:

It is known that yield from is a semantically identical to a for loop with a yield inside. But, it is way more readable.

Solution:

Use yield from some iterable directly instead iterating over it inside a loop and yield it one by one.

Example:

# Correct:
yield from some()

yield from (
    value[index:index + chunk_size]
    for index in range(0, len(value), chunk_size)
)

# Wrong:
for index in chunk:
    yield index

Added in version 0.13.0.

Changed in version 1.0.0: No longer produced, kept here for historic reasons. This is covered with ruff linter. See UP028.

error_template: ClassVar[str] = 'Found implicit `yield from` usage'
code: ClassVar[int] = 526
disabled_since: ClassVar[str | None] = '1.0.0'
full_code: ClassVar[str] = 'WPS526'
summary: ClassVar[str] = 'Forbid ``yield`` inside ``for`` loop instead of ``yield from``.'
final class NotATupleArgumentViolation(node, text=None, baseline=None)[source]

Bases: ASTViolation

WPS527 — Require tuples as arguments for certain functions.

Reasoning:

For some functions, it is better to use tuples instead of another iterable types (list, sets,…) as arguments.

Solution:

Use tuples as arguments.

Example:

# Correct:
a = frozenset((2,))

# Wrong:
a = frozenset([2])

See TUPLE_ARGUMENTS_METHODS for full list of methods that we check for.

Added in version 0.13.0.

error_template: ClassVar[str] = 'Found not a tuple used as an argument'
code: ClassVar[int] = 527
full_code: ClassVar[str] = 'WPS527'
summary: ClassVar[str] = 'Require tuples as arguments for certain functions.'
final class ImplicitItemsIteratorViolation(node, text=None, baseline=None)[source]

Bases: ASTViolation

WPS528 — Forbid implicit .items() iterator.

Reasoning:

When iterating over collection it is easy to forget to use .items() when you need to access both keys and values. So, when you access the iterable with the key inside a for loop, that’s a sign to refactor your code.

Solution:

Use .items() with direct keys and values when you need them.

Example:

# Correct:
for some_key, some_value in collection.items():
    print(some_key, some_value)

# Wrong:
for some_key in collection:
    print(some_key, collection[some_key])

Added in version 0.13.0.

Changed in version 1.0.0: No longer produced, kept here for historic reasons. This is covered with ruff and pylint linters. See PLC0206.

error_template: ClassVar[str] = 'Found implicit `.items()` usage'
code: ClassVar[int] = 528
disabled_since: ClassVar[str | None] = '1.0.0'
full_code: ClassVar[str] = 'WPS528'
summary: ClassVar[str] = 'Forbid implicit ``.items()`` iterator.'
final class ImplicitDictGetViolation(node, text=None, baseline=None)[source]

Bases: ASTViolation

WPS529 — Forbid implicit .get() dict method.

Reasoning:

When using in with a dict key it is hard to keep the code clean. It is more convenient to use .get() and check for None later.

Solution:

Use .get() with the key you need. Check for None in case you need it, or just act with the default value of the same type.

Example:

# Correct:
value = collection.get(key)
if value is not None:
    print(value)

# Wrong:
if key in collection:
    print(collection[key])

Added in version 0.13.0.

error_template: ClassVar[str] = 'Found implicit `.get()` dict usage'
code: ClassVar[int] = 529
full_code: ClassVar[str] = 'WPS529'
summary: ClassVar[str] = 'Forbid implicit ``.get()`` dict method.'
final class ImplicitNegativeIndexViolation(node, text=None, baseline=None)[source]

Bases: ASTViolation

WPS530 — Forbid implicit negative indexes.

Reasoning:

There’s no need in getting the length of an iterable and then having a negative offset, when you can specify negative indexes in the first place.

Solution:

Use negative indexes.

Example:

# Correct:
some_list[-1]

# Wrong:
some_list[len(some_list) - 1]

Added in version 0.13.0.

error_template: ClassVar[str] = 'Found implicit negative index'
code: ClassVar[int] = 530
full_code: ClassVar[str] = 'WPS530'
summary: ClassVar[str] = 'Forbid implicit negative indexes.'
final class SimplifiableReturningIfViolation(node, text=None, baseline=None)[source]

Bases: ASTViolation

WPS531 — Forbid if statements that simply return booleans in functions or methods.

Reasoning:

There is no need to test a condition and simply return a boolean depending on its outcome if there is not going to be any additional code.

Solution:

Instead of testing the condition and returning a boolean, return the condition itself. This applies to early returning ifs too.

Example:

# Correct:
def some_function():
    return some_condition

# Wrong:
def some_function():
    if some_condition:
        return True
    else:
        return False

Added in version 0.15.0.

Changed in version 1.0.0: No longer produced, kept here for historic reasons. This is covered with ruff linter. See RET505.

error_template: ClassVar[str] = 'Found simplifiable returning `if` condition in a function'
code: ClassVar[int] = 531
disabled_since: ClassVar[str | None] = '1.0.0'
full_code: ClassVar[str] = 'WPS531'
summary: ClassVar[str] = 'Forbid if statements that simply return booleans in functions or methods.'
final class ChainedIsViolation(node, text=None, baseline=None)[source]

Bases: ASTViolation

WPS532 — Forbid ast.Is in ast.Compare.ops when it’s size is not zero.

Reasoning:

From the AST perspective, is is an operator and can be chained. That can lead to unexpected results when the author wanted to compare the result of a is b operation. Instead, Python will chain the operations and compare the last argument of the previous operation.

Solution:

Who knows at this point.

Example::
Correct:

a is b and b is None

Wrong:

a is b is None

Added in version 0.18.0.

error_template: ClassVar[str] = 'Found chained `is` operators in an expression'
code: ClassVar[int] = 532
full_code: ClassVar[str] = 'WPS532'
summary: ClassVar[str] = "Forbid `ast.Is` in `ast.Compare.ops` when it's size is not zero."
final class DuplicateIfConditionViolation(node, text=None, baseline=None)[source]

Bases: ASTViolation

WPS533 — Forbid having duplicate conditions in several if // elif branches.

Reasoning:

It is likely an error to have multiple same condition in if / elif statements. Only the first one will always work.

Solution:

Change the condition.

Example:

# Correct:
if something:
    ...
elif other:
    ...

# Wrong:
if something:
    ...
elif something:
    ...

Added in version 1.0.0.

error_template: ClassVar[str] = 'Found duplicate condition in `if`: {0}'
code: ClassVar[int] = 533
full_code: ClassVar[str] = 'WPS533'
summary: ClassVar[str] = 'Forbid having duplicate conditions in several ``if`` // ``elif`` branches.'
final class UselessTernaryViolation(node, text=None, baseline=None)[source]

Bases: ASTViolation

WPS534 — Forbid having useless ternary expressions.

Reasoning:

When ternary expression can be replaced with a single name, it is way more readable and more performant.

Solution:

Remove the ternary expression.

Example:

# Correct:
first if some_condition else second

# Wrong:
a if a is not None else None
b if a == b else a

Added in version 1.0.0.

error_template: ClassVar[str] = 'Found useless ternary expression'
code: ClassVar[int] = 534
full_code: ClassVar[str] = 'WPS534'
summary: ClassVar[str] = 'Forbid having useless ternary expressions.'
final class DuplicateCasePatternViolation(node, text=None, baseline=None)[source]

Bases: ASTViolation

WPS535 — Forbid having duplicate case patterns.

Reasoning:

It is likely an error to have multiple same int case patterns. Only the first one will always work.

Solution:

Change the pattern.

Example:

# Correct:
match some:
    case SomeClass(field) if field > 0: ...
    case OtherClass(): ...

# Wrong:
match some:
    case SomeClass(field): ...
    case SomeClass(field): ...

Added in version 1.0.0.

error_template: ClassVar[str] = 'Found duplicate `case` pattern: {0}'
code: ClassVar[int] = 535
full_code: ClassVar[str] = 'WPS535'
summary: ClassVar[str] = 'Forbid having duplicate ``case`` patterns.'
final class ExtraMatchSubjectSyntaxViolation(node, text=None, baseline=None)[source]

Bases: ASTViolation

WPS536 — Forbid extra syntax around match like list, set, or dict.

Reasoning:

Adding extra lists / sets / dicts around your match subjects is just adding more complexity.

Solution:

Use raw values or tuples instead.

Example:

# Correct:
match some:
    case SomeClass(): ...

match (first, second):
    case (1, 2): ...

# Wrong:
match [first, second]:
    case [1, 2]: ...

Added in version 1.0.0.

error_template: ClassVar[str] = 'Found `match` subject with extra syntax: {0}'
code: ClassVar[int] = 536
full_code: ClassVar[str] = 'WPS536'
summary: ClassVar[str] = 'Forbid extra syntax around ``match`` like list, set, or dict.'