Complexity

These checks find flaws in your application design.

We try to stick to “the magical 7 ± 2 number” when counting things. https://en.wikipedia.org/wiki/The_Magical_Number_Seven,_Plus_or_Minus_Two

That’s how many objects we can keep in our memory at a time. We try hard not to exceed the memory capacity limit.

You can also find interesting reading about “Cognitive complexity”: https://www.sonarsource.com/docs/CognitiveComplexity.pdf

Note

Simple is better than complex. Complex is better than complicated.

Summary

JonesScoreViolation

WPS200 — Forbid modules with complex lines.

TooManyImportsViolation

WPS201 — Forbid modules with too many imports.

TooManyModuleMembersViolation

WPS202 — Forbid too many classes and functions in a single module.

TooManyImportedNamesViolation

WPS203 — Forbid modules with too many imported names.

OverusedExpressionViolation

WPS204 — Forbid overused expressions in a module, function or method.

TooManyLocalsViolation

WPS210 — Forbid too many local variables in the unit of code.

TooManyArgumentsViolation

WPS211 — Forbid too many arguments for a function or method.

TooManyReturnsViolation

WPS212 — Forbid placing too many return statements in a function.

TooManyExpressionsViolation

WPS213 — Forbid putting too many expressions in a single function.

TooManyMethodsViolation

WPS214 — Forbid too many methods in a single class.

TooManyBaseClassesViolation

WPS215 — Restrict the maximum number of base classes.

TooManyDecoratorsViolation

WPS216 — Restrict the maximum number of decorators.

TooManyAwaitsViolation

WPS217 — Forbid placing too many await expressions in a function.

TooManyAssertsViolation

WPS218 — Forbid placing too many assert statements into a function.

TooDeepAccessViolation

WPS219 — Forbid consecutive expressions with too deep access level.

TooDeepNestingViolation

WPS220 — Forbid nesting blocks too deep.

LineComplexityViolation

WPS221 — Forbid complex lines.

TooManyConditionsViolation

WPS222 — Forbid conditions with too many logical operators.

TooManyElifsViolation

WPS223 — Forbid too many elif branches.

TooManyForsInComprehensionViolation

WPS224 — Forbid too many for statements within a comprehension.

TooManyExceptCasesViolation

WPS225 — Forbid too many except cases in a single try clause.

OverusedStringViolation

WPS226 — Forbid the overuse of string literals.

TooLongOutputTupleViolation

WPS227 — Forbid returning or yielding tuples that are too long.

TooLongCompareViolation

WPS228 — Forbid compare expressions that are too long.

TooLongTryBodyViolation

WPS229 — Forbid try blocks with bodies that are too long.

TooManyPublicAttributesViolation

WPS230 — Forbid instances with too many public attributes.

CognitiveComplexityViolation

WPS231 — Forbid functions with too much cognitive complexity.

CognitiveModuleComplexityViolation

WPS232 — Forbid modules with average cognitive complexity that is too high.

TooLongCallChainViolation

WPS233 — Forbid call chains that are too long.

TooComplexAnnotationViolation

WPS234 — Forbid overly complex annotations.

TooManyImportedModuleMembersViolation

WPS235 — Forbid from mod import a, b, c, d with too many imported names.

TooLongTupleUnpackViolation

WPS236 — Forbid using too many variables to unpack a tuple.

TooComplexFormattedStringViolation

WPS237 — Forbids f strings that are too complex.

TooManyRaisesViolation

WPS238 — Forbids too many raise statements in a function.

TooManyExceptExceptionsViolation

WPS239 — Forbids to have too many exceptions in except statement.

TooManyTypeParamsViolation

WPS240 — Forbids to have too many type params.

TooManyMatchSubjectsViolation

WPS241 — Forbids to have too many subjects in match statements.

TooManyMatchCaseViolation

WPS242 — Forbids to have too many match cases.

Module complexity

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

Bases: SimpleViolation

WPS200 — Forbid modules with complex lines.

We are using the Jones Complexity algorithm to count module’s score. See LineComplexityViolation for details of per-line-complexity. How it is done: we count complexity per line, then measure the median complexity across the lines in the whole module.

Reasoning:

Having complex modules will decrease your code maintainability.

Solution:

Refactor the module contents.

Configuration:

This rule is configurable with --max-jones-score. Default: 12

Added in version 0.1.0.

error_template: ClassVar[str] = 'Found module with high Jones Complexity score: {0}'
code: ClassVar[int] = 200
full_code: ClassVar[str] = 'WPS200'
summary: ClassVar[str] = 'Forbid modules with complex lines.'
final class TooManyImportsViolation(node=None, text=None, baseline=None)[source]

Bases: SimpleViolation

WPS201 — Forbid modules with too many imports.

Namespaces are one honking great idea – let’s do more of those!

Reasoning:

Having too many imports without prefixes is quite expensive. You have to memorize all the source locations of the imports and sometimes it is hard to remember what kind of functions and classes are already injected into your context.

It is also a questionable design if a single module has a lot of imports. Why would a single module have so many dependencies? So, the module becomes too coupled.

Solution:

Refactor the imports to import a common namespace. Something like from package import module and then use it like module.function().

Or refactor your code and split the complex module into several modules.

We do not make any distinction between import and from ... import ....

Configuration:

This rule is configurable with --max-imports. Default: 12

Added in version 0.1.0.

error_template: ClassVar[str] = 'Found module with too many imports: {0}'
code: ClassVar[int] = 201
full_code: ClassVar[str] = 'WPS201'
summary: ClassVar[str] = 'Forbid modules with too many imports.'
final class TooManyModuleMembersViolation(node=None, text=None, baseline=None)[source]

Bases: SimpleViolation

WPS202 — Forbid too many classes and functions in a single module.

Reasoning:

Having many classes and functions in a single module is a bad thing. Soon it will be hard to read through this code and understand it.

Solution:

It is better to split this module into several modules or a package.

We do not make any distinctions between classes and functions in this check. They are treated as the same unit of logic. We also do not care about functions and classes being public or not. However, methods are counted separately on a per-class basis.

Configuration:

This rule is configurable with --max-module-members. Default: 7

Added in version 0.1.0.

error_template: ClassVar[str] = 'Found too many module members: {0}'
code: ClassVar[int] = 202
full_code: ClassVar[str] = 'WPS202'
summary: ClassVar[str] = 'Forbid too many classes and functions in a single module.'
final class TooManyImportedNamesViolation(node=None, text=None, baseline=None)[source]

Bases: SimpleViolation

WPS203 — Forbid modules with too many imported names.

Namespaces are one honking great idea – let’s do more of those!

Reasoning:

Having too many imported names without prefixes is quite expensive. You have to memorize all the source locations of the imports and sometimes it is hard to remember what kind of functions and classes are already injected into your context.

It is also a questionable design if a single module has a lot of imports. Why would a single module have so many dependencies? So, the module becomes too coupled.

Solution:

Refactor the imports to import a common namespace. Something like from package import module and then use it like module.function().

Or refactor your code and split the complex module into several modules.

Example:

# Correct:
import module  # 1 imported name

# Wrong:
from module import func1, func2, ..., funcN  # N imported names

We do not make any differences between import and from ... import ....

Configuration:

This rule is configurable with --max-imported-names. Default: 50

Added in version 0.12.0.

error_template: ClassVar[str] = 'Found module with too many imported names: {0}'
code: ClassVar[int] = 203
full_code: ClassVar[str] = 'WPS203'
summary: ClassVar[str] = 'Forbid modules with too many imported names.'
final class OverusedExpressionViolation(node, text=None, baseline=None)[source]

Bases: ASTViolation

WPS204 — Forbid overused expressions in a module, function or method.

What do we call an “overused expression”? When you use any expression (like user_dict['age'] for example) inside your code, you always have to track that you are not using it “too much” because if that expression is everywhere inside your code, it is a sign of a problem. It means that you are missing an abstraction.

We check for overused expressions on two levels:

  • per each function

  • per all module

Related to TooManyExpressionsViolation.

Reasoning:

Overusing expressions leads to losing the parts that can and should be refactored into variables, methods, and properties of objects.

Solution:

Refactor expressions to be an attribute, a method, or a new variable.

Configuration:

This rule is configurable with --max-module-expressions. Default: 7

And with --max-function-expressions. Default: 4

Added in version 0.12.0.

Changed in version 0.14.0.

error_template: ClassVar[str] = 'Found overused expression: {0}'
code: ClassVar[int] = 204
full_code: ClassVar[str] = 'WPS204'
summary: ClassVar[str] = 'Forbid overused expressions in a module, function or method.'

Structure complexity

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

Bases: ASTViolation

WPS210 — Forbid too many local variables in the unit of code.

Reasoning:

Having too many variables in a single function is a bad thing. Soon, you will have trouble understanding what this variable means. It will also become hard to name new variables.

Solution:

If you have too many variables in a function, you have to refactor it.

What counts as a local variable? We only count a variable as local in the following case: it is assigned inside the function body. We do not count variables defined inside comprehensions as local variables, since it is impossible to use them outside of the comprehension.

Example:

def first_function(param):
    first_var = 1

def second_function(argument):
    second_var = 1
    argument = int(argument)
    third_var, _ = some_call()

In this example we will count as locals only several variables:

  1. first_var, because it is assigned inside the function’s body

  2. second_var, because it is assigned inside the function’s body

  3. argument, because it is reassigned inside the function’s body

  4. third_var, because it is assigned inside the function’s body

Please, note that _ is a special case. It is not counted as a local variable. Since by design it means: do not count me as a real variable.

Configuration:

This rule is configurable with --max-local-variables. Default: 5

Added in version 0.1.0.

error_template: ClassVar[str] = 'Found too many local variables: {0}'
code: ClassVar[int] = 210
full_code: ClassVar[str] = 'WPS210'
summary: ClassVar[str] = 'Forbid too many local variables in the unit of code.'
final class TooManyArgumentsViolation(node, text=None, baseline=None)[source]

Bases: ASTViolation

WPS211 — Forbid too many arguments for a function or method.

Reasoning:

This is an indicator of a bad design. When a function requires many arguments it is a sign that it should be refactored. It also indicates that the function does too many things at once.

Solution:

Split the function into several functions. Then it will be easier to use them.

Configuration:

This rule is configurable with --max-arguments. Default: 5

Added in version 0.1.0.

Changed in version 1.0.0: Does not count special self, cls, and mcs as parameters.

Also does not count parameters in @overload definitions.

error_template: ClassVar[str] = 'Found too many arguments: {0}'
code: ClassVar[int] = 211
full_code: ClassVar[str] = 'WPS211'
summary: ClassVar[str] = 'Forbid too many arguments for a function or method.'
final class TooManyReturnsViolation(node, text=None, baseline=None)[source]

Bases: ASTViolation

WPS212 — Forbid placing too many return statements in a function.

Reasoning:

When there are too many return keywords, functions are hard to test. They are also hard to read and hard to change and keep everything inside your head at once.

Solution:

Change your design. Split the function into multiple functions.

Configuration:

This rule is configurable with --max-returns. Default: 5

Added in version 0.1.0.

error_template: ClassVar[str] = 'Found too many return statements: {0}'
code: ClassVar[int] = 212
full_code: ClassVar[str] = 'WPS212'
summary: ClassVar[str] = 'Forbid placing too many ``return`` statements in a function.'
final class TooManyExpressionsViolation(node, text=None, baseline=None)[source]

Bases: ASTViolation

WPS213 — Forbid putting too many expressions in a single function.

This rule is quite similar to “max lines” in a function, but is much nicer because we don’t count lines, we count real code entities. This way adding just several extra empty lines for readability will never trigger this violation.

Related to OverusedExpressionViolation.

Reasoning:

When there are too many expressions it means that this function does too many things at once. It has too much logic.

Solution:

Split function into several functions, refactor your API.

Configuration:

This rule is configurable with --max-expressions. Default: 9

Added in version 0.1.0.

error_template: ClassVar[str] = 'Found too many expressions: {0}'
code: ClassVar[int] = 213
full_code: ClassVar[str] = 'WPS213'
summary: ClassVar[str] = 'Forbid putting too many expressions in a single function.'
final class TooManyMethodsViolation(node, text=None, baseline=None)[source]

Bases: ASTViolation

WPS214 — Forbid too many methods in a single class.

Reasoning:

Having too many methods might lead to the “God object” anti-pattern. This kind of object can handle everything. So, in the end, your code becomes too hard to maintain and test.

Solution:

What to do if you have too many methods in a single class? Split this class into several classes, then use composition or inheritance to refactor your code. This will protect you from the “God object” anti-pattern.

We do not make any distinctions between instance and class methods. We also do not care about functions and classes being public or not. We also do not count inherited methods from parents. This rule does not count the attributes of a class.

Configuration:

This rule is configurable with --max-methods. Default: 7

Added in version 0.1.0.

error_template: ClassVar[str] = 'Found too many methods: {0}'
code: ClassVar[int] = 214
full_code: ClassVar[str] = 'WPS214'
summary: ClassVar[str] = 'Forbid too many methods in a single class.'
final class TooManyBaseClassesViolation(node, text=None, baseline=None)[source]

Bases: ASTViolation

WPS215 — Restrict the maximum number of base classes.

Reasoning:

It is almost never possible to navigate to the desired method of a parent class when you need it with multiple mixins. It is hard to understand mro and super calls. Do not overuse this technique.

Solution:

Reduce the number of base classes. Use composition over inheritance.

Example:

# Correct:
class SomeClassName(First, Second, Mixin): ...

# Wrong:
class SomeClassName(
    FirstParentClass,
    SecondParentClass,
    ThirdParentClass,
    CustomClass,
    AddedClass,
 ): ...
Configuration:

This rule is configurable with --max-base-classes. Default: 3

Added in version 0.3.0.

Changed in version 0.5.0.

error_template: ClassVar[str] = 'Too many base classes: {0}'
code: ClassVar[int] = 215
full_code: ClassVar[str] = 'WPS215'
summary: ClassVar[str] = 'Restrict the maximum number of base classes.'
final class TooManyDecoratorsViolation(node, text=None, baseline=None)[source]

Bases: ASTViolation

WPS216 — Restrict the maximum number of decorators.

Reasoning:

When you are using too many decorators it means that you are trying to overuse the magic. You have to ask yourself: do I really know what happens inside this decorator tree? Typically, the answer will be “no”.

Solution:

Using too many decorators typically means that you are trying to configure the behavior from outside of the class. Do not do that too much. Split functions or classes into smaller ones. Use higher order decorators.

Configuration:

This rule is configurable with --max-decorators. Default: 5

This rule checks: functions, methods, and classes.

Added in version 0.5.0.

error_template: ClassVar[str] = 'Too many decorators: {0}'
code: ClassVar[int] = 216
full_code: ClassVar[str] = 'WPS216'
summary: ClassVar[str] = 'Restrict the maximum number of decorators.'
final class TooManyAwaitsViolation(node, text=None, baseline=None)[source]

Bases: ASTViolation

WPS217 — Forbid placing too many await expressions in a function.

Reasoning:

When there are too many await keywords, functions are starting to get really complex. It is hard to tell where we are and what is going on.

Solution:

Change your design. Split functions into smaller ones.

Configuration:

This rule is configurable with --max-awaits. Default: 5

Added in version 0.10.0.

error_template: ClassVar[str] = 'Found too many await expressions: {0}'
code: ClassVar[int] = 217
full_code: ClassVar[str] = 'WPS217'
summary: ClassVar[str] = 'Forbid placing too many ``await`` expressions in a function.'
final class TooManyAssertsViolation(node, text=None, baseline=None)[source]

Bases: ASTViolation

WPS218 — Forbid placing too many assert statements into a function.

Reasoning:

When there are too many assert keywords, functions are starting to get really complex. It might indicate that your tests or contracts are too big.

Solution:

Create rich assert statements, use higher-level contracts, or create special guard functions.

Configuration:

This rule is configurable with --max-asserts. Default: 5

Added in version 0.12.0.

error_template: ClassVar[str] = 'Found too many `assert` statements: {0}'
code: ClassVar[int] = 218
full_code: ClassVar[str] = 'WPS218'
summary: ClassVar[str] = 'Forbid placing too many ``assert`` statements into a function.'
final class TooDeepAccessViolation(node, text=None, baseline=None)[source]

Bases: ASTViolation

WPS219 — Forbid consecutive expressions with too deep access level.

We consider only these expressions as accesses:

  • ast.Subscript

  • ast.Attribute

We do not treat ast.Call as an access, since there are a lot of call-based APIs like Django ORM, builder patterns, etc.

Reasoning:

Having too deep access level indicates a bad design and overcomplicated data without proper API.

Solution:

Split the expression into variables, functions or classes. Refactor the API for your data layout.

Example:

# Correct: access level = 4
self.attr.inner.wrapper[1]

# Correct: access level = 1
manager.filter().exclude().annotate().values().first()

# Wrong: access level = 5
self.attr.inner.wrapper.method.call()

# Wrong: access level = 5
# `obj` has access level of 2:
# `.attr`, `.call`
# `call()` has access level of 5:
# `.other`, `[0]`, `.field`, `.type`, `.boom`
obj.attr.call().other[0].field.type.boom
Configuration:

This rule is configurable with --max-access-level. Default: 4

Added in version 0.12.0.

error_template: ClassVar[str] = 'Found too deep access level: {0}'
code: ClassVar[int] = 219
full_code: ClassVar[str] = 'WPS219'
summary: ClassVar[str] = 'Forbid consecutive expressions with too deep access level.'
final class TooDeepNestingViolation(node, text=None, baseline=None)[source]

Bases: ASTViolation

WPS220 — Forbid nesting blocks too deep.

Reasoning:

If nesting is too deep that indicates usage of complex logic and language constructions. This means that our design is not suited to handle such construction.

Solution:

We need to refactor our complex construction into simpler ones. We can use new functions or different constructions.

Added in version 0.1.0.

Changed in version 0.5.0.

Changed in version 0.19.1: Do not report ... when used in a function or class body.

error_template: ClassVar[str] = 'Found too deep nesting: {0}'
code: ClassVar[int] = 220
full_code: ClassVar[str] = 'WPS220'
summary: ClassVar[str] = 'Forbid nesting blocks too deep.'
final class LineComplexityViolation(node, text=None, baseline=None)[source]

Bases: ASTViolation

WPS221 — Forbid complex lines.

We are using the Jones Complexity algorithm to count complexity. What is the Jones Complexity? It is a simple yet powerful method to count the number of ast nodes per line. If the complexity of a single line is higher than a threshold, then an error is raised.

What nodes do we count? All except the following:

  1. modules

  2. function and classes, since they are checked differently

  3. type annotations, since they do not increase the complexity

Reasoning:

Having a complex line indicates that you somehow managed to put too much logic inside a single line. At some point in time, you will no longer be able to understand what this line means and what it does.

Solution:

Split a single line into several lines: by creating new variables, statements or functions. Note, this might trigger new complexity issues. With this technique, a single new node in a line might trigger a complex refactoring process including several modules.

Configuration:

This rule is configurable with --max-line-complexity. Default: 14

Added in version 0.1.0.

error_template: ClassVar[str] = 'Found line with high Jones Complexity: {0}'
code: ClassVar[int] = 221
full_code: ClassVar[str] = 'WPS221'
summary: ClassVar[str] = 'Forbid complex lines.'
final class TooManyConditionsViolation(node, text=None, baseline=None)[source]

Bases: ASTViolation

WPS222 — Forbid conditions with too many logical operators.

We use 4 as a default value.

Reasoning:

When reading through the complex conditions you will fail to understand all the possible branches. And you will end up putting debug breakpoint on this line just to figure out how it works.

Solution:

We can reduce the complexity of a single if by doing two things: creating new variables or creating nested if statements. Both of these actions will trigger other complexity checks.

We count and and or keywords as conditions.

Added in version 0.1.0.

Changed in version 0.5.0.

error_template: ClassVar[str] = 'Found a condition with too much logic: {0}'
code: ClassVar[int] = 222
full_code: ClassVar[str] = 'WPS222'
summary: ClassVar[str] = 'Forbid conditions with too many logical operators.'
final class TooManyElifsViolation(node, text=None, baseline=None)[source]

Bases: ASTViolation

WPS223 — Forbid too many elif branches.

We use 3 as a default value.

Reasoning:

This rule is specifically important because many elif branches indicates a complex flow in your design: you are reimplementing switch in python.

Solution:

There are different design patterns to use instead. For example, you can use an interface that just calls a specific method without if. Another option is to separate your if into multiple functions.

Added in version 0.1.0.

Changed in version 0.5.0.

error_template: ClassVar[str] = 'Found too many `elif` branches: {0}'
code: ClassVar[int] = 223
full_code: ClassVar[str] = 'WPS223'
summary: ClassVar[str] = 'Forbid too many ``elif`` branches.'
final class TooManyForsInComprehensionViolation(node, text=None, baseline=None)[source]

Bases: ASTViolation

WPS224 — Forbid too many for statements within a comprehension.

Reasoning:

When reading through the complex comprehension you will fail to understand it.

Solution:

We can reduce the complexity of the comprehension by reducing the amount of for statements. Refactor your code to use several for loops, comprehensions, or different functions.

Example:

# Wrong:
ast_nodes = [
    target
    for assignment in top_level_assigns
    for target in assignment.targets
    for _ in range(10)
]

Added in version 0.3.0.

error_template: ClassVar[str] = 'Found a comprehension with too many `for` statements'
code: ClassVar[int] = 224
full_code: ClassVar[str] = 'WPS224'
summary: ClassVar[str] = 'Forbid too many ``for`` statements within a comprehension.'
final class TooManyExceptCasesViolation(node, text=None, baseline=None)[source]

Bases: ASTViolation

WPS225 — Forbid too many except cases in a single try clause.

We use 3 as a default value.

Reasoning:

Handling too many exceptions in a single place is a good indicator of a bad design since one controlling structure will become too complex. Also, you will need to test a lot of logic paths in your application.

If you have too many except* blocks, it means that the exception group is too complex.

Solution:

We can reduce the complexity of this case by splitting it into multiple try cases, functions or using a decorator to handle different exceptions.

Added in version 0.7.0.

Changed in version 0.19.0: Supports try/except* as well.

error_template: ClassVar[str] = 'Found too many `except` cases: {0}'
code: ClassVar[int] = 225
full_code: ClassVar[str] = 'WPS225'
summary: ClassVar[str] = 'Forbid too many ``except`` cases in a single ``try`` clause.'
final class OverusedStringViolation(node=None, text=None, baseline=None)[source]

Bases: MaybeASTViolation

WPS226 — Forbid the overuse of string literals.

We allow to use strings without any restrictions as annotations for variables, arguments, return values, and class attributes.

Some common string literals like dot ‘.’, comma ‘,’, empty string ‘’, single space ‘ ‘, new line ‘n’, ‘rn’ and tabulator ‘t’ do not count against string literal overuse limit.

Reasoning:

When some string is used more than several time in your code, it probably means that this string is a meaningful constant and should be treated like one.

Solution:

Deduplicate your string usages by defining new functions or constants.

Configuration:

This rule is configurable with --max-string-usages. Default: 3

Added in version 0.10.0.

error_template: ClassVar[str] = 'Found string literal over-use: {0}'
code: ClassVar[int] = 226
full_code: ClassVar[str] = 'WPS226'
summary: ClassVar[str] = 'Forbid the overuse of string literals.'
final class TooLongOutputTupleViolation(node, text=None, baseline=None)[source]

Bases: ASTViolation

WPS227 — Forbid returning or yielding tuples that are too long.

Reasoning:

Long output tuples complicate function or generator usage. This rule helps to reduce complication.

Solution:

Use lists of similar type or wrapper objects.

Added in version 0.10.0.

Changed in version 0.16.0.

error_template: ClassVar[str] = 'Found too long function output tuple: {0}'
code: ClassVar[int] = 227
full_code: ClassVar[str] = 'WPS227'
summary: ClassVar[str] = 'Forbid returning or yielding tuples that are too long.'
final class TooLongCompareViolation(node, text=None, baseline=None)[source]

Bases: ASTViolation

WPS228 — Forbid compare expressions that are too long.

Reasoning:

Compare expressions that are too long indicate that there’s something wrong going on in the code. Compares should not be longer than 3 or 4 items.

Solution:

Use several conditions, separate variables, or functions.

Added in version 0.10.0.

error_template: ClassVar[str] = 'Found too long compare: {0}'
code: ClassVar[int] = 228
full_code: ClassVar[str] = 'WPS228'
summary: ClassVar[str] = 'Forbid compare expressions that are too long.'
final class TooLongTryBodyViolation(node, text=None, baseline=None)[source]

Bases: ASTViolation

WPS229 — Forbid try blocks with bodies that are too long.

Reasoning:

Having too many statements inside your try block can lead to situations when a statement raises an exception and you are not aware of it since it is not expected.

Solution:

Move things out of the try block or create new functions. The fewer lines you have in your try block - the safer you are from accidental errors.

Configuration:

This rule is configurable with --max-try-body-length. Default: 1

Added in version 0.12.0.

Changed in version 0.19.0: Supports try/except* as well.

error_template: ClassVar[str] = 'Found too long ``try`` body length: {0}'
code: ClassVar[int] = 229
full_code: ClassVar[str] = 'WPS229'
summary: ClassVar[str] = 'Forbid ``try`` blocks with bodies that are too long.'
final class TooManyPublicAttributesViolation(node, text=None, baseline=None)[source]

Bases: ASTViolation

WPS230 — Forbid instances with too many public attributes.

We only check static definitions in a form of self.public = .... We do not count parent attributes. We do not count properties. We do not count annotations. We do not count class attributes. We do not count duplicates.

Reasoning:

Having too many public instance attributes means that your class is too complex in terms of coupling. Other classes and functions will rely on these concrete fields instead of better abstraction layers.

Solution:

Make some attributes protected. Split this class into several. If the class is a Data Transfer Object, then use @dataclass decorator.

Configuration:

This rule is configurable with --max-attributes. Default: 6

Added in version 0.12.0.

Changed in version 1.0.0: Any amount of attributes are allowed on @dataclasses.

error_template: ClassVar[str] = 'Found too many public instance attributes: {0}'
code: ClassVar[int] = 230
full_code: ClassVar[str] = 'WPS230'
summary: ClassVar[str] = 'Forbid instances with too many public attributes.'
final class CognitiveComplexityViolation(node, text=None, baseline=None)[source]

Bases: ASTViolation

WPS231 — Forbid functions with too much cognitive complexity.

Reasoning:

People are not great at reading and interpreting code in their heads. That’s why code with a lot of nested loops, conditions, exceptions handlers, and context managers is hard to read and understand.

Solution:

Rewrite your code to be simpler. Use flat structures and conditions, remove nested loops.

Configuration:

This rule is configurable with --max-cognitive-score. Default: 12

Added in version 0.13.0.

error_template: ClassVar[str] = 'Found function with too much cognitive complexity: {0}'
code: ClassVar[int] = 231
full_code: ClassVar[str] = 'WPS231'
summary: ClassVar[str] = 'Forbid functions with too much cognitive complexity.'
final class CognitiveModuleComplexityViolation(node=None, text=None, baseline=None)[source]

Bases: SimpleViolation

WPS232 — Forbid modules with average cognitive complexity that is too high.

Reasoning:

Modules with lots of functions might hide cognitive complexity inside many small and relatively simple functions.

Solution:

Rewrite your code to be simpler or use several modules.

Configuration:

This rule is configurable with --max-cognitive-average. Default: 8

Added in version 0.13.0.

error_template: ClassVar[str] = 'Found module cognitive complexity that is too high: {0}'
code: ClassVar[int] = 232
full_code: ClassVar[str] = 'WPS232'
summary: ClassVar[str] = 'Forbid modules with average cognitive complexity that is too high.'
final class TooLongCallChainViolation(node, text=None, baseline=None)[source]

Bases: ASTViolation

WPS233 — Forbid call chains that are too long.

Reasoning:

Call chains that are too long are overcomplicated and indicators of bad API design.

Solution:

Split the expression into variables, functions or classes. Refactor the API to allow higher-level access to functions.

Configuration:

This rule is configurable with --max-call-level. Default: 3

Added in version 0.13.0.

error_template: ClassVar[str] = 'Found call chain that is too long: {0}'
code: ClassVar[int] = 233
full_code: ClassVar[str] = 'WPS233'
summary: ClassVar[str] = 'Forbid call chains that are too long.'
final class TooComplexAnnotationViolation(node, text=None, baseline=None)[source]

Bases: ASTViolation

WPS234 — Forbid overly complex annotations.

Annotation complexity is maximum annotation nesting level. Example: List[int] has complexity of 2 and Tuple[List[Optional[str]], int] has complexity of 4.

Reasoning:

Overly complex annotations make your types unreadable. And make developers afraid of types.

Solution:

Create type aliases. And use them a lot!

Configuration:

This rule is configurable with --max-annotation-complexity. Default: 3

Added in version 0.14.0.

error_template: ClassVar[str] = 'Found overly complex annotation: {0}'
code: ClassVar[int] = 234
full_code: ClassVar[str] = 'WPS234'
summary: ClassVar[str] = 'Forbid overly complex annotations.'
final class TooManyImportedModuleMembersViolation(node, text=None, baseline=None)[source]

Bases: ASTViolation

WPS235 — Forbid from mod import a, b, c, d with too many imported names.

Reasoning:

Importing too many names from one import is an easy way to cause the violation WPS203 - too many imported names.

Solution:

Refactor the imports to import a common namespace. Something like from package import module and then use it like module.function().

Example:

# Correct:
import module  # 1 imported name

# Wrong:
from module import func1, func2, ..., funcN  # N imported names
Configuration:

This rule is configurable with --max-import-from-members. Default: 8

Added in version 0.15.0.

error_template: ClassVar[str] = 'Found too many imported names from a module: {0}'
code: ClassVar[int] = 235
full_code: ClassVar[str] = 'WPS235'
summary: ClassVar[str] = 'Forbid ``from mod import a, b, c, d`` with too many imported names.'
final class TooLongTupleUnpackViolation(node, text=None, baseline=None)[source]

Bases: ASTViolation

WPS236 — Forbid using too many variables to unpack a tuple.

Reasoning:

The order and meaning are hard to remember.

Solution:

If you have more than 2 values in a tuple, consider using typing.NamedTuple or a dataclass instead.

Example:

# Correct:
result = foo()

# Wrong:
a, b, c, d, e = foo()
Configuration:

This rule is configurable with --max-tuple-unpack-length. Default: 4

Added in version 0.15.0.

error_template: ClassVar[str] = 'Found too many variables used to unpack a tuple: {0}'
code: ClassVar[int] = 236
full_code: ClassVar[str] = 'WPS236'
summary: ClassVar[str] = 'Forbid using too many variables to unpack a tuple.'
final class TooComplexFormattedStringViolation(node, text=None, baseline=None)[source]

Bases: ASTViolation

WPS237 — Forbids f strings that are too complex.

A complex format string is defined as use of any formatted value that is not:

  • the value of a variable

  • the value of a collection through lookup with a variable, number, or string as the key

  • the return value of a function / method call with 3 arguments maximum

Reasoning:

Complex f strings are often difficult to understand, making the code less readable. Generally we don’t allow f strings but this violation exists in case the user decides to ignore the general violation.

Solution:

Use .format() or assign complex expressions to variables before formatting.

Example:

# Correct:
f'smth {user.get_full_name()}'
f'smth {math_func(1, 2, 3)}'

# Wrong:
f'{reverse("url-name")}?{"&".join("user=" + uid for uid in user_ids)}'
f'smth {math_func(1, 2, 3, 4)}'

Added in version 0.15.0.

error_template: ClassVar[str] = 'Found a too complex `f` string'
code: ClassVar[int] = 237
full_code: ClassVar[str] = 'WPS237'
summary: ClassVar[str] = 'Forbids ``f`` strings that are too complex.'
final class TooManyRaisesViolation(node, text=None, baseline=None)[source]

Bases: ASTViolation

WPS238 — Forbids too many raise statements in a function.

Reasoning:

Too many raise statements in a function make the code untraceable and overcomplicated.

Solution:

Split the function into smaller functions, such that each of them can raise less errors. Create more standard errors, or use alternative ways to raise them.

Configuration:

This rule is configurable with --max-raises. Default: 3

Added in version 0.15.0.

error_template: ClassVar[str] = 'Found too many raises in a function: {0}'
code: ClassVar[int] = 238
full_code: ClassVar[str] = 'WPS238'
summary: ClassVar[str] = 'Forbids too many ``raise`` statements in a function.'
final class TooManyExceptExceptionsViolation(node, text=None, baseline=None)[source]

Bases: ASTViolation

WPS239 — Forbids to have too many exceptions in except statement.

Reasoning:

Too exceptions in except case means that too many things are happening here at once.

Solution:

Use common base classes, split except cases.

Configuration:

This rule is configurable with --max-except-exceptions. Default: 3

Added in version 1.0.0.

error_template: ClassVar[str] = 'Found too many exceptions in `except` case: {0}'
code: ClassVar[int] = 239
full_code: ClassVar[str] = 'WPS239'
summary: ClassVar[str] = 'Forbids to have too many exceptions in ``except`` statement.'
final class TooManyTypeParamsViolation(node, text=None, baseline=None)[source]

Bases: ASTViolation

WPS240 — Forbids to have too many type params.

Is only emitted on python3.12+.

Reasoning:

Too many type params means that you are probably overly complicate the object that you are typing right now. It would be really hard for users to manually add all generic parameters.

Solution:

Use composition of classes, simplify the API.

Configuration:

This rule is configurable with --max-type-params. Default: 6

Added in version 1.0.0.

error_template: ClassVar[str] = 'Found too many type params: {0}'
code: ClassVar[int] = 240
full_code: ClassVar[str] = 'WPS240'
summary: ClassVar[str] = 'Forbids to have too many type params.'
final class TooManyMatchSubjectsViolation(node, text=None, baseline=None)[source]

Bases: ASTViolation

WPS241 — Forbids to have too many subjects in match statements.

Reasoning:

Too many subjects in a match statement make the code difficult to read and maintain. It indicates that the logic could be simplified or broken down into smaller components.

Solution:

Refactor the match statement to reduce the number of subjects. Consider splitting the logic into multiple match statements or functions to improve clarity and maintainability.

Configuration:

This rule is configurable with --max-match-subjects. Default: 7

Added in version 1.0.0.

error_template: ClassVar[str] = 'Found too many subjects in `match` statement: {0}'
code: ClassVar[int] = 241
full_code: ClassVar[str] = 'WPS241'
summary: ClassVar[str] = 'Forbids to have too many subjects in ``match`` statements.'
final class TooManyMatchCaseViolation(node, text=None, baseline=None)[source]

Bases: ASTViolation

WPS242 — Forbids to have too many match cases.

Reasoning:

Too many match cases means that you are probably overly complicate the object that you are matching right now. It would be really hard for users to manually add all match cases.

Solution:

Refactor the match statement by breaking the logic into smaller, focused functions. This will improve readability and maintainability. Split complex logic into separate functions to keep each one concise, reducing the size of the match block and making the code easier to understand and modify.

Configuration:

This rule is configurable with --max-match-cases. Default: 7

Added in version 1.0.0.

error_template: ClassVar[str] = 'Found too many cases in `match` block: {0}'
code: ClassVar[int] = 242
full_code: ClassVar[str] = 'WPS242'
summary: ClassVar[str] = 'Forbids to have too many match cases.'