they are unrelated builtin types such as string and integer.
Get Started
- CodeAnt AI
- Control Center
- Pull Request Review
- IDE
- Compliance
- Anti-Patterns
- Code Governance
- Infrastructure Security Database
- Application Security Database
Python - 1
Learn about Python Anti-Patterns and How they help you write better code, and avoid common pitfalls.
This rule identifies conditional statements in your code that will never execute, known as dead code, because their conditions are always false. Removing such statements cleans up the codebase, enhancing readability and potentially improving performance by eliminating unnecessary checks during execution. It’s crucial for maintaining an efficient and easily navigable codebase.
if False:
print(3)
if True:
print(2)
This rule emphasizes the importance of using the ‘from’ keyword in ‘raise’ statements to chain exceptions explicitly. It enhances error traceability by providing a clear path from the original to the new exception, greatly aiding in debugging complex issues. Addressing this issue leads to better error handling practices and more maintainable code by making the causal relationship between exceptions clear.
try:
sketchy_function()
except ValueError:
raise RuntimeError()
Advises on moving statements that do not change within the loop’s scope to outside of the loop. This optimization can lead to significant performance improvements, especially in large or heavily iterated loops, by reducing the computational overhead within the loop. It not only speeds up execution but also improves code readability by simplifying the loop’s body.
for i in range(100):
x = 10
print(x + i)
Targets functions and classes within the codebase that are never called or instantiated, marking them for removal. Cleaning up these unused elements can dramatically reduce code clutter, making the codebase easier to navigate and maintain. Moreover, it can highlight areas of the code that may require refactoring or optimization, contributing to overall better resource management.
This rule focuses on optimizing comparisons with singletons (like None in Python) by using identity checks (‘is’ or ‘is not’) instead of equality checks (’==’, ’!=’). Since singletons have a unique instance, identity checks are both logically appropriate and faster, leading to improved performance and code clarity.
x == None and k != None
Encourages refactoring to break out code that is duplicated across multiple branches of an if-else statement. This practice not only makes the code more DRY (Don’t Repeat Yourself) but also enhances readability and maintainability by reducing redundancy. It simplifies understanding the code’s logic and can make further changes or bug fixes easier to implement.
import random
if random.random() < 2:
print(100)
print(3)
else:
print(100)
print(21)
Aims to streamline the control flow within if statements, reducing complexity and improving readability. This may involve eliminating unnecessary nested conditions or simplifying logical expressions. Simplifying control flow makes the code easier to follow, understand, and test, which is beneficial for both current and future developers working on the codebase.
import random
x = 11
y = 12
z = random.random()
if z > 1 - z:
do_stuff(x)
do_stuff(y - x ** 2)
print(doing_other_stuff(x) - do_stuff(y ** y))
else:
do_stuff(y)
do_stuff(x - y ** 2)
print(doing_other_stuff(y) - do_stuff(x ** x))
Suggests rearranging if-else branches to improve clarity or efficiency, particularly when it allows for a more straightforward condition or aligns with expected coding practices. This change can make the code more intuitive and align execution paths with likely scenarios first, potentially improving both readability and performance by optimizing for common cases.
def f(x) int:
if x > 10:
x += 1
x *= 12
print(x > 30)
return 100 - sum(x, 2, 3)
else:
return 13
Promotes using the early return pattern to exit functions as soon as a condition is met, avoiding additional indentation from nested if-else blocks. This pattern simplifies function logic, making it easier to understand and reducing the cognitive load required to follow the flow of the function. It can also decrease the function’s execution time by avoiding unnecessary checks after conditions are met.
def f(x) int:
if x > 10:
x += 1
x *= 12
print(x > 30)
y = 100 - sum(x, 2, 3)
else:
y = 13
return y
Advises using the continue statement at the beginning of loops to immediately skip to the next iteration under certain conditions, reducing nesting and improving readability. This practice can make loops clearer by highlighting the conditions for continuing early and can improve performance by minimizing the execution of loop bodies under those conditions.
for x in range(100):
if x > 10:
y = 13
else:
x += 1
x *= 12
print(x > 30)
y = 100 - sum(x, 2, 3)
print(x)
Identifies situations where the enumerate function is used unnecessarily, typically when the index it provides is not used. Removing such redundant uses can simplify the code, making it more readable and potentially enhancing performance by eliminating the overhead associated with enumeration when it’s not needed.
(x for _, x in enumerate(y))
Highlights instances where arguments provided to the zip function are never used, suggesting their removal for cleaner code. Addressing this issue not only improves code readability by eliminating superfluous elements but also can uncover potential logic errors or inefficiencies in how data structures are being used.
x = (a for _, a in zip(range(3), range(1, 3)))
Recommends replacing combinations of the map function and lambda expressions with list comprehensions for more readable and concise code. List comprehensions are often more straightforward for developers to understand and can offer performance benefits over map and lambda by being more Pythonic and potentially faster in execution.
x = map(lambda y: y > 0, (1, 2, 3))
Similar to map and lambda, this rule suggests using list comprehensions instead of the filter function combined with lambda expressions. This change makes the code cleaner and more accessible by leveraging the more intuitive syntax of list comprehensions, which can also lead to slight performance improvements.
x = filter(lambda y: y > 0, (1, 2, 3))
This rule is about removing unnecessary else statements in your code. An else statement is considered unnecessary when it follows a return statement in the if block. In such cases, the else block can be safely removed without changing the logic of the code. Unnecessary else statements can make your code harder to read and understand. They can also lead to more complex code structures, which can increase the likelihood of introducing bugs. By removing unnecessary else statements, you can make your code simpler and more readable.
def f(x: int) int:
if x == 2:
return 10
else:
return 11 - x
This rule suggests using the filter function to streamline complex filtering logic within loops or list comprehensions. By encapsulating filtering logic in a filter function, code becomes cleaner and more expressive, allowing for better readability. This pattern can also improve performance by using built-in Python optimizations for filtering collections.
for x in range(10):
if x:
print(3)
Encourages combining multiple comparison operations into a single, chained expression. This not only makes the code more readable by reducing complexity and enhancing clarity but can also improve execution speed by minimizing the number of comparison operations. Chained comparisons are more pythonic and can make conditional logic easier to understand at a glance.
x = (y for y in (y for y in (3, 4, 5)))
Targets unnecessary casts (like converting a list comprehension directly to a list) of comprehensions, suggesting their removal. Since comprehensions inherently create their target collection, extra casting is redundant and can negatively impact performance. Removing these casts simplifies the code and can slightly improve runtime efficiency by reducing unnecessary function calls.
set({x for x in range(10)})
Focuses on eliminating redundant casts in sequences of function calls, where the outcome of one operation is immediately cast to another type without need. Addressing this issue can clean up the code by removing unnecessary operations, thereby enhancing readability and possibly improving performance by reducing the computational overhead.
set(itertools.chain(range(10), range(11)))
This rule identifies if statements that end with a return statement and then have an unnecessary else block that also returns. It suggests removing the else block and placing the return statement outside, simplifying the control flow. This change makes the function easier to read and understand by reducing unnecessary nesting and highlighting the conditions under which different return values are provided.
def f(x: int) int:
if x == 100:
return False
return True
Aims to refactor if statements that assign the same variable to different values in each branch by suggesting a more streamlined approach, such as using a conditional expression. This can significantly enhance code readability by reducing the number of lines and making the conditional assignment clearer and more direct.
if x == 100:
y = False
else:
y = True
Suggests replacing calls to functions that simply return a static or simple dynamic value with literals or simpler expressions. This optimization can reduce the overhead associated with function calls, making the code more efficient and easier to read by directly presenting values or simple expressions instead of hiding them behind function calls.
u = list()
v = tuple()
w = dict()
a = dict(zip(range(4), range(1, 5)))
b = list((1, 2, 3, 99))
c = set([1, 2, 3])
d = iter((1, 2, 3, 5))
aa = (1 for u in (1, 2, 3, 5))
Recommends using collection literals (e.g., set or list literals) instead of adding or updating collections through method calls. This can make the code more concise and readable by clearly showing the intention to create or modify collections, and can improve performance by utilizing Python’s optimized syntax for collection manipulation.
x = {1, 2, 3}
x.add(7)
x.add(191)
Targets the simplification of unpacking operations for collections, advocating for more straightforward or efficient ways to unpack items. This can improve both the readability of the code by making unpacking operations clearer and the performance by reducing the complexity of these operations.
x = [*()]
Identifies and suggests removing duplicate elements in set initializations. Since sets automatically enforce uniqueness, explicitly listing duplicate elements is unnecessary and can mislead readers about the code’s intent, besides causing minor performance concerns during set creation.
{1, 99, "s", 1, sum(range(11)), sum(range(11))}
Encourages breaking out arguments that are passed with the star (*) operator into explicit variables, if practical. This can improve readability by making the function’s expected arguments clearer and can enhance maintainability by making it easier to identify and modify the use of these arguments in the function call.
x = foo(a, b, *(c, d), e, *{f}, *[k, v, h])
Advises on replacing .loc and .at with .iloc and .iat in pandas DataFrames for improved performance. .iloc and .iat are designed for position-based indexing and are generally faster than .loc and .at, which are label-based. This switch can lead to significant performance gains, especially in large datasets, by optimizing data access patterns.
y = x.loc[1, 2]
This rule recommends replacing the use of .iterrows in pandas DataFrames with direct indexing where possible for enhanced performance. Direct indexing accesses elements more efficiently than .iterrows, which iterates over DataFrame rows in a slower, row-wise manner. This change can lead to significant speed improvements in data processing scripts by leveraging faster data access patterns.
for x, _ in df.iterrows():
print(x)
Suggests substituting .iterrows with .itertuples for iterating over DataFrame rows in pandas. .itertuples is generally faster than .iterrows because it returns namedtuples of the row data, reducing overhead and improving performance in row-wise operations. This modification can greatly speed up loop iterations over DataFrame rows, making code more efficient.
for _, x in df.iterrows():
print(x["value"])
Encourages replacing for loops that build sets or lists with set or list comprehensions. Comprehensions provide a more concise, readable, and pythonic way to create collections compared to loops, and they often offer performance benefits by being optimized for collection creation. This leads to cleaner code that’s easier to understand and faster to execute.
x = []
for i in range(10):
x.append(i)
Advises on replacing set comprehensions followed by addition operations with set union operations. Set unions are more efficient and semantically clear for combining sets than adding elements in a loop, leading to code that’s both faster and easier to read by expressing the intent more directly.
x = {foo(z) ** 2 for z in range(3)}
for zua in range(3):
x.add(zua - 1)
Recommends using list concatenation instead of appending to a list within a loop. Concatenation can be more efficient, especially when dealing with small lists or when the total size is known beforehand, as it can reduce the overhead of repeated append operations. This approach also makes the code more succinct and readable by clearly showing the intention to combine list elements.
x = [foo(z) ** 2 for z in range(3)]
for zua in range(3):
x.append(zua - 1)
Promotes the use of dictionary comprehensions instead of for loops for creating dictionaries. Dictionary comprehensions offer a concise, readable alternative to loops, enhancing code clarity and potentially improving execution speed by optimizing the dictionary creation process.
x = {}
for i in range(10):
x[i] = 10
Encourages the use of the implicit form of dictionary keys(), values(), and items() methods in looping constructs. This practice can make the code more pythonic and readable by reducing verbosity without compromising functionality or performance.
(x for x, _ in d.items())
Suggests replacing sequential dictionary assignments with dictionary literals. Using literals can make the code more concise and easier to understand by displaying the dictionary’s contents directly, and can improve performance by reducing the number of assignment operations.
x = {}
x[10] = 100
Recommends using literal syntax for merging dictionaries instead of the update method. This approach is more direct and readable, showing the intent to combine dictionaries clearly, and can offer slight performance benefits by leveraging Python’s optimized syntax for literal merges.
x = {}
x.update({10: 100})
Targets replacing dictionary comprehensions that are immediately assigned to a dictionary with direct dictionary literals. This can enhance readability by presenting the dictionary’s content in a straightforward manner and may improve performance by avoiding the overhead of the comprehension and assignment steps.
x = {z: 21 for z in range(3)}
x[10] = 100
Advises on using dictionary literals for updating dictionaries instead of comprehensions followed by updates. This method is clearer and more efficient, directly showing the updated content and potentially reducing runtime by avoiding the two-step process of comprehension creation and update.
x = {z: 21 for z in range(3)}
x.update({10: 100})
Focuses on simplifying the unpacking of dictionaries, especially in function calls or assignments. Simplifying unpacking operations can make the code more readable and maintainable by clearly showing which keys and values are being used, and can optimize the code by reducing unnecessary complexity in data handling.
x = {**{}}
Identifies and suggests removing duplicate keys in dictionary literals. Duplicate keys in dictionaries are usually an error or oversight, as they can lead to unpredictable behavior by overwriting values. Removing them improves code clarity and correctness, ensuring that each key-value pair is unique and intentional.
{1: 2, 99: 101, "s": 4, 1: 22, sum(range(11)): 9999, sum(range(11)): 9999}
This rule recommends replacing implicit matrix multiplication operations with explicit ones to enhance both clarity and performance. Explicit matrix multiplication, typically done with the @ operator in Python, makes the operation clear to the reader and can be optimized by libraries for better performance, especially with large datasets or complex mathematical computations.
import numpy as np
i, j, k = 10, 11, 12
a = np.random.random((i, j))
b = np.random.random((j, k))
u = np.array([[np.dot(a_, b_) for a_ in a] for b_ in b.T]).T
v = np.array([[np.dot(b_, a_) for b_ in b.T] for a_ in a])
Suggests replacing looping over sequences with subscripts (e.g., for i in range(len(sequence)): item = sequence[i]) with more direct iteration methods (e.g., for item in sequence). This change improves readability by reducing boilerplate code and can enhance performance by eliminating the need for indexing operations.
import numpy
[a[i] for i in range(len(a))]
[a[i, :] for i in range(len(a))]
[a[i, :] for i in range(a.shape[0])]
[a[:, i] for i in range(a.shape[1])]
Advises on replacing implicit dot product operations with explicit function calls to dot products. Explicit calls can make the code more understandable by clearly indicating the operation being performed and can allow for optimizations specific to dot product calculations, thus potentially improving performance.
Targets unnecessary transpose operations in arrays, suggesting their removal or simplification. Transposes can be computationally expensive and may not be needed, especially if followed by operations that negate their effects. Simplifying or removing them can improve both performance and code clarity.
Recommends optimizing matrix multiplication operations that involve unnecessary transposes. By rearranging or eliminating these transposes, the efficiency of matrix multiplications can be improved, resulting in faster computations and clearer code that more directly expresses the intended mathematical operations.
Encourages the use of defaultdict from the collections module for handling default values in dictionaries more cleanly. defaultdict automatically initializes missing keys with a default value, simplifying code and improving readability by avoiding explicit checks or assignments for missing keys.
def f(x: int) int:
return x+1
d = {}
for x in range(10):
y = f(x)
if x in d:
d[x].append(y)
else:
d[x] = [y]
Identifies and suggests removing redundant lambda functions that wrap direct function calls without modification. Using the functions directly can simplify the code, making it more readable and potentially improving performance by reducing the overhead associated with lambda expressions.
lambda *args: w(*args)
Highlights unnecessary comprehensions that could be replaced with simpler constructs or direct operations. Removing these can make the code more concise and readable, as well as improve performance by avoiding the overhead of the comprehension syntax for straightforward operations.
a = {x: y for x, y in zip(range(4), range(1, 5))}
b = [w for w in (1, 2, 3, 99)]
c = {v for v in [1, 2, 3]}
d = (u for u in (1, 2, 3, 5))
aa = (1 for u in (1, 2, 3, 5))
ww = {x: y for x, y in zip((1, 2, 3), range(3)) if x > y > 1}
ww = {x: y for y, x in zip((1, 2, 3), range(3))}
Focuses on simplifying complex boolean expressions to enhance readability and maintainability. Complex expressions can often be rewritten more concisely without changing their logical outcome, making the code easier to understand and less prone to errors.
x and False and y
Suggests simplifying expressions that constrain ranges redundantly, such as using min and max functions in a range where the limits are already clear. Simplifying these expressions can improve readability and performance by removing unnecessary function calls and making the intended range constraints more direct.
(x for x in range(10) if x > 4)
Recommends using symbolic mathematics libraries to simplify complex boolean expressions. This approach can reveal simplifications that are not immediately obvious, making the code cleaner and often more efficient by reducing the complexity of conditional logic.
x and not x
Advises inlining list or set comprehensions directly into mathematical expressions where possible. This can enhance readability by reducing the amount of code and improving performance by eliminating the need for intermediate collection construction during complex mathematical operations.
z = {a for a in range(10)}
x = sum(z)
Targets simplification of iterators used in mathematical expressions, recommending more straightforward iteration patterns. Simplifying these iterators can make the code easier to understand and reduce computational overhead in mathematical computations.
x = sum(range(10))
y = sum(range(3, 17))
h = sum((1, 2, 3))
q = sum([1, 2, 3, 99, 99, -8])
r = sum({1, 2, 3, 99, 99, -8})
Suggests replacing negated numeric comparisons with their direct counterparts for clarity and efficiency. For example, instead of using !(a > b), use a <= b
. This makes the intended comparison more explicit and can improve both the readability of the code and its execution speed by using simpler operations.
not x > 3
This rule encourages the optimization of ‘contain’ types to enhance both performance and readability of the code. It focuses on improving the efficiency of checking whether an object is part of a collection. By using the most suitable and efficient methods for these checks, we can reduce computational overhead and improve the overall speed of the program.
1 in (1, 2, 3)
x in {1, 2, ()}
x in [1, 2, []]
w in [1, 2, {}]
w in {foo, bar, "asdf", coo}
w in (foo, bar, "asdf", coo)
w in {x for x in range(10)}
w in [x for x in range(10)]
w in (x for x in range(10))
w in {x for x in [1, 3, "", 909, ()]}
w in [x for x in [1, 3, "", 909, ()]]
w in (x for x in [1, 3, "", 909, ()])
x in sorted([1, 2, 3])
Identifies and recommends removing redundant method calls chained together where earlier calls do not affect the outcome of the chain. This simplification not only enhances code readability by eliminating unnecessary operations but also improves performance by reducing the computational overhead associated with executing these redundant method calls.
sorted(tuple(v))
sorted(list(v))
list(iter(v))
list(tuple(v))
Targets unnecessary calls to iter(), suggesting their removal. In many cases, Python’s for loops and other iterators implicitly call iter() on collections, making explicit calls redundant. Removing them simplifies the code and can slightly improve performance by avoiding superfluous function calls.
Recommends replacing the sorted() function with heapq functions for performance improvements in scenarios involving large collections. When only the smallest or largest elements are needed, heapq can provide these more efficiently than sorting the entire collection, leading to significant performance gains in handling large datasets.
Advises adding missing context managers for file and resource handling to ensure that resources are properly managed and released, even in the event of errors. Using context managers improves code reliability and readability by clearly defining the scope of resource usage.
import requests
session = requests.Session()
session.get("https://www.google.com")
Identifies functions that are duplicated within the codebase and suggests removing the duplicates. Duplicate functions can lead to maintenance issues, inconsistencies, and increased code size, making it harder to manage and understand the codebase.
Targets duplicate import statements for removal. Duplicate imports can clutter the code and lead to confusion about the namespace’s structure, without offering any benefit. Streamlining imports can enhance code clarity and organization.
from logging import info
from logging import warning
from logging import error, info, log
from logging import (
warning,
critical ,
error, error, error as error)
from logging import critical
Recommends removing import statements that are not used within the code. Unused imports can lead to unnecessary dependencies and can potentially slow down program startup time. Cleaning up imports can improve code readability and performance.
import numpy as np, pandas as pd
print(pd)
Suggests transforming dictionary keys in the source to key-value pairs (items), providing a more comprehensive view of the data structure being iterated over or manipulated. This can enhance both the expressiveness and efficiency of operations that require access to both keys and values.
Advises on transforming item tuples back to keys when only the keys are needed from a dictionary that was initially accessed for its items. This can simplify data handling by focusing on the relevant part of the data structure for the given context.
Recommends transforming item tuples to values, focusing on the value part of key-value pairs in a dictionary. This is useful in contexts where the values are of primary interest, streamlining the code by removing unnecessary references to keys.
Applies a transformation from keys to items in the source, suggesting a shift in focus from operating solely on keys to working with both keys and values. This can be particularly beneficial in scenarios where both elements are needed for processing or decision-making.
Implies a transformation for items to keys, advocating for a simplification in cases where the operation initially involves both keys and values but ultimately requires only the keys. This simplification can make the code more focused and readable.
Suggests a shift from handling item tuples to focusing solely on their values. This transformation is recommended when the values hold the necessary data for the operation, allowing the code to be more concise and targeted.
Identifies scenarios where a value is assigned to a variable only to be immediately returned and suggests simplifying this by returning the value directly. This change can make the code cleaner and more straightforward by eliminating an unnecessary variable assignment.
Recommends swapping explicit if-else branches when it results in clearer or more efficient code. For example, changing the order of if-else branches can improve readability by placing the most common or simplest case first, or it can enhance performance by optimizing the order of condition evaluation.
def f(x) int:
if x > 10:
x += 1
x *= 12
print(x > 30)
return 100 - sum(x, 2, 3)
else:
return 13
This rule identifies scenarios where a value is assigned to a variable only to be immediately returned by the function. Simplifying this pattern by returning the value directly can make the function more straightforward and concise, eliminating unnecessary intermediate variables and clearly communicating the return value.
def foo():
x = 100
return x
Recommends reordering explicit if-else branches when such a change leads to clearer or more logically organized code. Swapping if-else branches can enhance readability, especially when it aligns the code’s structure with its intended logic or prioritizes more common conditions, making the code easier to follow and sometimes more efficient.
Advises replacing string concatenation operations with f-strings for improved readability and performance. F-strings, introduced in Python 3.6, provide a more concise and intuitive syntax for embedding expressions inside string literals, making the code cleaner and often faster than traditional concatenation methods.
a = "Hello" + name
Flags an instance being created from an abstract class that contains abstract methods. Abstract classes are designed to be subclassed, not instantiated directly, and doing so can lead to runtime errors if the abstract methods are not implemented. This rule helps ensure that the code’s design intentions are respected and that subclasses provide concrete implementations for abstract methods.
import abc
class Animal(abc.ABC):
@abc.abstractmethod
def make_sound(self):
pass
sheep = Animal() # [abstract-class-instantiated]
Identifies access to a class member before its definition has occurred. This can lead to errors or unintended behavior, as the member may not be initialized at the time of access. Ensuring members are defined before they are accessed improves code reliability and readability.
class Unicorn:
def __init__(self, fluffiness_level):
if self.fluffiness_level > 9000: # [access-member-before-definition]
print("It's OVER-FLUFFYYYY ! *crush glasses*")
self.fluffiness_level = fluffiness_level
Detects assignments to attributes not defined in the class slots. Using slots is a way to declare explicitly which attributes the class will have, offering memory savings and faster attribute access. Assigning to non-slot attributes breaks the constraints set by slots and can lead to unexpected behavior or inefficiencies.
class Student:
__slots__ = ("name",)
def __init__(self, name, surname):
self.name = name
self.surname = surname # [assigning-non-slot]
self.setup()
def setup(self):
pass
Catches attempts to assign the result of a function call to a variable when the function does not explicitly return a value. This usually results in the variable being assigned None, which can be a source of bugs if not intended. Highlighting these cases encourages more explicit control flow and return value handling.
def add(x, y):
print(x + y)
value = add(10, 10) # [assignment-from-no-return]
Similar to the above, this rule flags assignments of the result of function calls where the function is known to return None. Such assignments are often unintended and can lead to logic errors if the None value is not handled properly.
def function():
return None
f = function() # [assignment-from-none]
Identifies the use of ‘await’ for an asynchronous call outside of an async function. This is a syntax error as ‘await’ can only be used within async functions. This rule helps prevent runtime errors by ensuring that asynchronous calls are correctly placed within the asynchronous execution context.
import asyncio
def main():
await asyncio.sleep(1) # [await-outside-async]
Points out misconfigurations in configuration files or sections of code that are not set up correctly. Proper configuration is crucial for the successful execution and behavior of applications, and this rule aids in identifying and correcting configuration errors.
Warns about incorrectly ordered except clauses in try-except blocks. Specific exceptions should be listed before more general ones to prevent the general exceptions from catching exceptions intended for the specific handlers. This ensures that exceptions are handled appropriately and that error handling logic is clear and effective.
try:
print(int(input()))
except Exception:
raise
except TypeError: # [bad-except-order]
# This block cannot be reached since TypeError exception
# is caught by previous exception handler.
raise
Flags instances where the cause of an exception (using the ‘from’ keyword) is set to something that is not an exception or None. The ‘from’ keyword is used for exception chaining, to help clarify the cause of secondary exceptions. Setting it incorrectly can lead to confusion and make error diagnosis more difficult.
def divide(x, y):
result = 0
try:
result = x / y
except ZeroDivisionError:
# +1: [bad-exception-cause]
raise ValueError(f"Division by zero when dividing {x} by {y} !") from result
return result
Flags the use of an unsupported format character in a string format operation. This typically indicates a typo or misunderstanding of the format specification, and can lead to runtime errors or incorrect string formatting. Correcting these characters ensures the intended output is produced reliably.
print("%s %z" % ("hello", "world")) # [bad-format-character]
Indicates an invalid value has been provided for a pylint plugin configuration. Plugins extend pylint’s functionality, and providing valid configuration values is crucial for their correct operation. This rule helps maintain the integrity and usefulness of extended linting capabilities.
Warns when the first argument passed to reversed() is not a sequence. Since reversed() is designed to iterate over sequences in reverse order, passing a non-sequence type indicates a logical error in the code, potentially leading to runtime errors.
reversed({1, 2, 3, 4}) # [bad-reversed-sequence]
Identifies suspicious arguments passed to string strip methods (strip, lstrip, rstrip). These methods are often used incorrectly with multiple characters, leading to unexpected behavior. Ensuring the correct use of these methods helps maintain the intended functionality of string manipulation.
Flags format strings where an argument does not match the expected format type, indicating a mismatch between the data type of the argument and the format specifier. This can prevent runtime errors and ensure that string formatting operations produce the intended result.
print("%d" % "1") # [bad-string-format-type]
Detects incorrect first arguments given to super(), which can lead to incorrect method resolution and potentially runtime errors. Using super() correctly is crucial for accessing parent class methods reliably in inheritance hierarchies.
class Animal:
pass
class Tree:
pass
class Cat(Animal):
def __init__(self):
super(Tree, self).__init__() # [bad-super-call]
super(Animal, self).__init__()
Highlights the presence of bidirectional Unicode text that may contain control characters capable of obfuscating code. This can make the code appear different from its actual execution, posing a security risk by hiding malicious code within seemingly benign text.
# +1: [bidirectional-unicode]
example = "x" * 100 # "x" is assigned
Points out issues with callables intended for use in collection classes that do not work as expected. Ensuring callables are correctly implemented is essential for the proper functioning of custom collection behaviors.
from collections.abc import Callable
from typing import Optional
def func() Optional[Callable[[int], None]]: # [broken-collections-callable]
...
Flags functions declared to not return a value (e.g., by typing annotations) that contain return statements. This inconsistency can lead to confusion about the function’s behavior and should be corrected for clarity and correctness.
from typing import NoReturn, Union
def exploding_apple(apple) Union[None, NoReturn]: # [broken-noreturn]
print(f"{apple} is about to explode")
Warns about catching objects that do not inherit from Exception. Only objects derived from Exception should be caught by except clauses. This rule ensures that error handling in try-except blocks is correctly targeted and meaningful.
class FooError:
pass
try:
1 / 0
except FooError: # [catching-non-exception]
pass
Detects conflicts between slots declarations and class variables. slots are used to declare instance variables and prevent the creation of dict and weakref for each instance, and conflicts can lead to unexpected behavior or inefficiencies.
class Person:
# +1: [class-variable-slots-conflict, class-variable-slots-conflict, class-variable-slots-conflict]
__slots__ = ("age", "name", "say_hi")
name = None
def __init__(self, age, name):
self.age = age
self.name = name
@property
def age(self):
return self.age
def say_hi(self):
print(f"Hi, I'm {self.name}.")
Identifies the use of ‘continue’ within a ‘finally’ clause, which is not supported and can lead to a syntax error. This rule helps prevent control flow errors in complex try-except-finally structures.
while True:
try:
pass
finally:
continue # [continue-in-finally]
Flags the unpacking of a dictionary in iteration without explicitly calling .items(). This can lead to errors or unintended behavior when expecting key-value pairs but only keys are provided. Ensuring .items() is called makes the intention clear and the code more reliable.
data = {"Paris": 2_165_423, "New York City": 8_804_190, "Tokyo": 13_988_129}
for city, population in data: # [dict-iter-missing-items]
print(f"{city} has population {population}.")
Detects duplicate argument names in a function definition, which can lead to confusion and errors in how arguments are passed and used within the function. Unique argument names ensure clarity in function signatures.
def get_fruits(apple, banana, apple): # [duplicate-argument-name]
pass
Warns about a class being defined with duplicate bases, which is redundant and can lead to confusion about the class’s inheritance hierarchy. Removing duplicate bases clarifies the class structure.
class Animal:
pass
class Cat(Animal, Animal): # [duplicate-bases]
pass
Indicates a format string that expects a mapping (e.g., a dictionary) but is provided with a different type. This mismatch can lead to runtime errors during string formatting operations. Ensuring the correct type is provided to format strings maintains their intended functionality.
print("%(x)d %(y)d" % [1, 2]) # [format-needs-mapping]
Flags instances where a function is redefined within the same scope, potentially overwriting the previous definition. This can lead to unexpected behavior and logic errors. Ensuring each function has a unique name within its scope prevents these issues.
def get_email():
pass
def get_email(): # [function-redefined]
pass
Indicates an error in importing a module or package, which could be due to a missing dependency, incorrect path, or other issues. Resolving import errors is crucial for ensuring that all code dependencies are correctly managed and accessible.
from patlib import Path # [import-error]
Detects classes with an inconsistent method resolution order (MRO), which can lead to errors in method inheritance and overriding. Ensuring a consistent MRO is essential for the predictable behavior of class hierarchies.
class A:
pass
class B(A):
pass
class C(A, B): # [inconsistent-mro]
pass
Flags instances where an attempt is made to inherit from a non-class object. This rule is important because Python’s class inheritance mechanism requires that all bases of a class are themselves classes. Attempting to inherit from non-class objects will lead to a TypeError at runtime.
class Fruit(bool): # [inherit-non-class]
pass
Identifies if the init method of a class is defined as a generator, which is incorrect because init should initialize the instance and cannot yield values. This rule helps prevent a common mistake that can lead to unexpected behavior or runtime errors.
class Fruit:
def __init__(self, worms): # [init-is-generator]
yield from worms
apple = Fruit(["Fahad", "Anisha", "Tabatha"])
Warns when the all variable, which should explicitly export module symbols, is not formatted as a tuple or list. Correctly defining all is crucial for module encapsulation and namespace control, ensuring that only intended names are exported.
__all__ = "CONST" # [invalid-all-format]
CONST = 42
Indicates that an object within the all list or tuple is not a string. Since all should contain the names of objects to be exported by a module, having non-string objects can lead to errors when the module is imported or used.
__all__ = (
None, # [invalid-all-object]
Fruit,
Worm,
)
class Fruit:
pass
class Worm:
pass
Flags cases where a custom bool method does not return a boolean value. The bool method is used to determine the truth value of an object, and returning non-bool values can lead to incorrect behavior in boolean contexts.
class CustomBool:
"""__bool__ returns an int"""
def __bool__(self): # [invalid-bool-returned]
return 1
Identifies when a bytes method does not return a bytes object. This method should return the bytes representation of the object, and returning anything other than bytes can cause type errors or unexpected behavior.
class CustomBytes:
"""__bytes__ returns <type 'str'>"""
def __bytes__(self): # [invalid-bytes-returned]
return "123"
Warns about the use of an invalid, unescaped backspace character in a string. It suggests using ”” for a backspace character to avoid syntax errors or unintended behavior in strings.
STRING = "Invalid character backspace " # [invalid-character-backspace]
Highlights the use of an invalid, unescaped carriage return character, recommending the use of ” ” instead. Proper escaping is necessary to ensure the character is interpreted correctly by Python.
Flags the improper use of an unescaped ESC character in a string, suggesting the use of ”” for clarity and correctness. Escaping special characters prevents errors in string processing.
STRING = "Invalid escape character " # [invalid-character-esc]
Indicates an invalid unescaped NUL character in a string, recommending the use of ”�” instead. The NUL character must be properly escaped to be included in strings without causing errors.
Warns about the use of an unescaped SUB (substitute) character, advising to use ”” for correct representation. Proper escaping ensures that control characters are treated correctly in strings.
STRING = "Invalid character sub " # [invalid-character-sub]
Identifies the improper use of an unescaped zero-width space character, recommending ”” for correct inclusion in strings. Escaping this character is necessary to avoid syntax errors and ensure it is interpreted correctly.
STRING = "Invalid character zero-width-space " # [invalid-character-zero-width-space]
Flags incorrect assignments to the ‘class’ attribute, which should only be assigned class definitions. This rule helps maintain the integrity of the object model by ensuring ‘class’ accurately reflects the object’s class structure.
class Apple:
pass
Apple.__class__ = 1 # [invalid-class-object]
Warns against extending an already inherited Enum class. Python’s enum classes are designed to be final; extending them can lead to unexpected behavior or errors. This rule ensures that enums are used as intended, providing clear, immutable sets of named values.
from enum import Enum
class Color(Enum):
ORANGE = 1
CHERRY = 2
class Fruit(Color): # [invalid-enum-extension]
APPLE = 3
Indicates that an environment variable does not support a given type argument, highlighting the importance of ensuring environment variables are correctly parsed and validated to match the expected types used in the application.
import os
os.getenv(1) # [invalid-envvar-value]
Flags incorrect usage of the field() function, typically seen in data classes. This rule helps ensure that field definitions are correct and conform to the expectations of Python’s data model, preventing runtime errors.
from dataclasses import dataclass, field
@dataclass
class C:
a: float
b: float
c: float
field(init=False) # [invalid-field-call]
def __post_init__(self):
self.c = self.a + self.b
print(field(init=False)) # [invalid-field-call]
Identifies when a custom format method does not return a string. Since format is used in string formatting operations, returning any other type can cause type errors or unexpected behavior in formatted strings.
class CustomFormat:
"""__format__ returns <type 'int'>"""
def __format__(self, format_spec): # [invalid-format-returned]
return 1
Warns if getnewargs_ex does not return a tuple containing a tuple and a dict. This method is crucial for customizing pickling behavior, and its return values must conform to this structure to ensure objects are pickled and unpickled correctly.
class CustomGetNewArgsEx:
"""__getnewargs_ex__ returns tuple with incorrect arg length"""
def __getnewargs_ex__(self): # [invalid-getnewargs-ex-returned]
return (tuple(1), dict(x="y"), 1)
Flags cases where getnewargs does not return a tuple. Similar to getnewargs_ex, this method supports pickling and must return a tuple to function correctly, ensuring objects can be serialized and deserialized properly.
class CustomGetNewArgs:
"""__getnewargs__ returns an integer"""
def __getnewargs__(self): # [invalid-getnewargs-returned]
return 1
Indicates that a custom hash method does not return an integer. Since hashes are used to uniquely identify objects, especially in collections like sets and dictionaries, returning non-int values can lead to incorrect behavior or errors.
class CustomHash:
"""__hash__ returns dict"""
def __hash__(self): # [invalid-hash-returned]
return {}
Warns when index does not return an integer. The index method should return an integer to be used when the object is operated on by built-in functions and operators expecting a numerical index, ensuring correct integration with Python’s data model.
class CustomIndex:
"""__index__ returns a dict"""
def __index__(self): # [invalid-index-returned]
return {"19": "19"}
Identifies when length_hint does not return a non-negative integer. This method is used to provide an estimate of the number of elements in an iterable, and returning incorrect types or values can mislead functions that rely on this hint for optimization.
class CustomLengthHint:
"""__length_hint__ returns non-int"""
def __length_hint__(self): # [invalid-length-hint-returned]
return 3.0
Flags incorrect return types from len, which must always return a non-negative integer. This ensures that the length of a collection is accurately reported, supporting Python’s built-in len() function and the sizing of collections.
class FruitBasket:
def __init__(self, fruits):
self.fruits = ["Apple", "Banana", "Orange"]
def __len__(self): # [invalid-length-returned]
return -len(self.fruits)
Highlights the use of an invalid metaclass. Metaclasses are used in Python to control the creation of classes, and using an incorrect metaclass can lead to unexpected behavior or errors in class creation and inheritance.
class Apple(metaclass=int): # [invalid-metaclass]
pass
Warns if repr does not return a string. The repr method should provide a clear, unambiguous string representation of an object for debugging and logging, and returning a non-string violates this contract.
class CustomRepr:
"""__repr__ returns <type 'int'>"""
def __repr__(self): # [invalid-repr-returned]
return 1
Indicates that an index used on a sequence is not of a valid type. Valid types include integers, slices, or instances with an index method. Ensuring indexes are of the correct type is crucial for the predictable behavior of sequence operations.
fruits = ["apple", "banana", "orange"]
print(fruits["apple"]) # [invalid-sequence-index]
Flags slice indexes that are not integers, None, or instances with an index method. Correct slice indexes are essential for the expected slicing behavior of sequences, supporting flexible and error-free slicing operations.
LETTERS = ["a", "b", "c", "d"]
FIRST_THREE = LETTERS[:"3"] # [invalid-slice-index]
Identifies slice steps that are set to 0, which is invalid since a step of 0 would result in an undefined slice. This rule ensures that slices are defined with a valid step, avoiding runtime errors and maintaining the integrity of slice operations.
LETTERS = ["a", "b", "c", "d"]
LETTERS[::0] # [invalid-slice-step]
Flags an incorrectly defined slots object. The slots declaration is used to explicitly declare data members and prevent the creation of dict and weakref for each instance, optimizing memory usage. Invalid slots definitions can lead to runtime errors or unintended behavior.
class Person: # [invalid-slots]
__slots__ = 42
Indicates that an object within slots is not a valid non-empty string. slots should contain names of instance attributes, defined as non-empty strings, to properly allocate space for them. Invalid objects in slots can prevent the expected optimization and might cause attribute errors.
class Person:
__slots__ = ("name", 3) # [invalid-slots-object]
Warns when a starred expression is used outside of a list or tuple context. Starred expressions are used for unpacking iterables and must be part of a list or tuple assignment, ensuring correct and predictable unpacking behavior.
*fruit = ["apple", "banana", "orange"] # [invalid-star-assignment-target]
Identifies when a custom str method does not return a string. The str method should provide a readable string representation of an object, and returning a non-string type can lead to type errors and misunderstandings about the object’s representation.
class CustomStr:
"""__str__ returns int"""
def __str__(self): # [invalid-str-returned]
return 1
Flags an invalid operand type for a unary operation, such as negation or bitwise not. This rule ensures that unary operations are used with compatible types, preventing runtime type errors and promoting type-safe operations.
cherries = 10
eaten_cherries = int
cherries = -eaten_cherries # [invalid-unary-operand-type]
Advises against using UTF-16 or UTF-32 due to their lack of backward compatibility with ASCII, recommending UTF-8 instead. UTF-8 is universally accepted and provides better compatibility and efficiency, especially for web and internationalized applications.
Warns when a logging format string is truncated, ending in the middle of a conversion specifier. This can lead to incomplete log messages and is usually the result of an accidental omission or typo in the format string.
import logging
import sys
logging.warning("Python version: %", sys.version) # [logging-format-truncated]
Indicates that there are not enough arguments provided to a logging format string, which can result in a runtime error when the logging statement is executed. Ensuring the correct number of arguments for format strings is essential for accurate and error-free logging.
import logging
try:
function()
except Exception as e:
logging.error("%s error occurred: %s", e) # [logging-too-few-args]
raise
Flags when more arguments are provided to a logging format string than placeholders available in the string. This can lead to unused arguments and might indicate a misunderstanding of the format string’s requirements or an error in argument preparation.
import logging
try:
function()
except Exception as e:
logging.error("Error occurred: %s", type(e), e) # [logging-too-many-args]
raise
Identifies an unsupported format character in a logging statement. This rule helps ensure that logging format strings are correctly formed, using only supported format specifiers to prevent runtime errors or malformed log messages.
import logging
logging.info("%s %y !", "Hello", "World") # [logging-unsupported-format]
Warns when an attribute defined elsewhere hides a method of the same name. This can lead to unexpected behavior, as the attribute will take precedence over the method, potentially causing errors or confusion about the object’s interface.
class Fruit:
def __init__(self, vitamins):
self.vitamins = vitamins
def vitamins(self): # [method-hidden]
pass
Indicates a raise statement used outside of an except clause, which can lead to a RuntimeError since there’s no active exception to re-raise. This rule ensures that raise statements are used correctly, within the context of exception handling.
def validate_positive(x):
if x <= 0:
raise # [misplaced-bare-raise]
Flags when the format function is used on an object that is not a string. Since format is intended for string formatting, calling it on non-strings is likely an error and can lead to unexpected behavior or type errors.
print("Value: {}").format("Car") # [misplaced-format-function]
Identifies when a key referenced in a format string is missing from the format string’s dictionary argument. This can lead to a KeyError at runtime, making it important to ensure that all keys used in format strings are provided in the accompanying dictionary.
# +1: [missing-format-string-key]
fruit_prices = """
Apple: %(apple_price)d ¤
Orange: %(orange_price)d ¤
""" % {
"apple_price": 42
}
Flags a function call missing a mandatory keyword-only argument. This rule ensures that all required arguments are provided in function calls, particularly important for functions that define parameters with the keyword-only syntax, improving code reliability and preventing runtime errors.
def target(pos, *, keyword):
return pos + keyword
def not_forwarding_kwargs(*args, **kwargs):
target(*args) # [missing-kwoa]
Warns against mixing named and unnamed placeholders within a single format string. This practice can lead to confusion and errors in string formatting, and maintaining consistency in format specifiers enhances readability and predictability of the output.
Indicates that a dictionary being iterated over in a for loop is also being modified within the loop. Modifying a collection while iterating over it can lead to runtime errors or unpredictable behavior. Iterating over a copy of the dictionary is recommended to avoid such issues.
fruits = {"apple": 1, "orange": 2, "mango": 3}
i = 0
for fruit in fruits:
fruits["apple"] = i # [modified-iterating-dict]
i += 1
Similar to the above, warns when a set being iterated over is modified within the loop. As with dictionaries, this can cause unexpected behavior or errors, and iterating over a copy of the set is advised to maintain correct and predictable iteration behavior.
fruits = {"apple", "orange", "mango"}
for fruit in fruits:
fruits.add(fruit + "yum") # [modified-iterating-set]
Flags the access of a non-existent member of an object or class, indicating a potential attribute error or a misunderstanding of the object’s interface. This rule helps prevent runtime errors by ensuring that only existing members are accessed.
from pathlib import Path
directories = Path(".").mothers # [no-member]
class Cat:
def meow(self):
print("Meow")
Cat().roar() # [no-member]
Indicates a method definition is missing an argument. This can lead to errors when the method is called and is especially critical for methods expected to adhere to a specific signature, such as those defined in interfaces or base classes.
class Person:
def print_greeting(): # [no-method-argument]
print("hello")
Warns when an attempt is made to import a name from a module, but the name does not exist in that module. This can lead to ImportError at runtime and is often the result of a typo or misunderstanding of the module’s API.
from os import pizza # [no-name-in-module]
Flags a method that does not include self as its first argument, which is required for instance methods in classes to correctly refer to the object instance upon which they are called. Ensuring self is the first argument is fundamental for the method’s access to the instance and its attributes.
class Fruit:
def __init__(this, name): # [no-self-argument]
this.name = name
Indicates that a required parameter is missing a value in a function call. This rule ensures that all necessary arguments are provided to functions, preventing TypeError due to missing arguments and improving function call correctness.
def add(x, y):
return x + y
add(1) # [no-value-for-parameter]
Warns if the iter method of a class does not return an iterator object. For a class to be iterable, its iter method must return an object that implements the next method, ensuring compatibility with iteration protocols.
import random
class GenericAstrology:
def __init__(self, signs, predictions):
self.signs = signs
self.predictions = predictions
def __iter__(self): # [non-iterator-returned]
self.index = 0
self.number_of_prediction = len(self.predictions)
return self
SIGNS = ["Aries", "Taurus", "Gemini", "Cancer", "Leo", "Virgo", "Libra"]
PREDICTIONS = ["good things", "bad thing", "existential dread"]
for sign, prediction in GenericAstrology(SIGNS, PREDICTIONS):
print(f"{sign} : {prediction} today")
Flags the use of an operator that does not exist in Python. This rule helps identify typos or misconceptions about Python’s operators, preventing syntax errors or incorrect assumptions about code behavior.
i = 0
while i <= 10:
print(i)
++i # [nonexistent-operator]
Indicates a variable is declared both nonlocal and global, which is contradictory as nonlocal refers to variables in enclosing scopes, excluding the global scope. This rule clarifies scope usage and prevents scope resolution conflicts.
NUMBER = 42
def update_number(number): # [nonlocal-and-global]
global NUMBER
nonlocal NUMBER
NUMBER = number
print(f"New global number is: {NUMBER}")
update_number(24)
Warns when a nonlocal statement is used for a name that does not have an existing binding in any enclosing scopes, which can lead to errors since nonlocal is intended to refer to previously defined variables in outer non-global scopes.
class Fruit:
def get_color(self):
nonlocal colors # [nonlocal-without-binding]
Flags when a value that is not a mapping (e.g., not a dict or similar) is used in a context that expects a mapping, such as in unpacking operations. This rule ensures that values used in mapping contexts correctly support the mapping interface.
def print_colors(**colors):
print(colors)
print_colors(**list("red", "black")) # [not-a-mapping]
Indicates a value used in a context that requires iteration, such as a for loop, does not support iteration. This rule is essential for preventing runtime errors by ensuring that only iterable objects are used in iterating contexts.
for i in 10: # [not-an-iterable]
pass
Warns that an object meant to be used as an async context manager (with an async with statement) does not implement the required aenter and aexit methods. Implementing these methods is crucial for the correct operation of async context managers, enabling asynchronous resource management.
class ContextManager:
def __enter__(self):
pass
def __exit__(self, *exc):
pass
async def foo():
async with ContextManager(): # [not-async-context-manager]
pass
Flags an attempt to call an object that is not callable, indicating a type error. This rule is critical for identifying objects being used incorrectly as functions or methods, ensuring that only callable objects are invoked, which helps prevent runtime errors.
NUMBER = 42
print(NUMBER()) # [not-callable]
Indicates that an object expected to function as a context manager does not implement the enter and exit methods. For an object to manage resources with a ‘with’ statement, implementing these methods is essential for correct resource acquisition and release.
class MyContextManager:
def __enter__(self):
pass
with MyContextManager() as c: # [not-context-manager]
pass
Flags the use of break or continue statements outside of a loop, which is a syntactic error. This rule helps ensure that these control flow statements are used correctly within the context of loops to manage loop execution properly.
def print_even_numbers():
for i in range(100):
if i % 2 == 0:
print(i)
else:
continue # [not-in-loop]
Warns when NotImplemented is raised instead of NotImplementedError. NotImplemented is a special value used for binary methods to indicate that an operation is not implemented for the given operands, whereas NotImplementedError should be raised when an abstract method or function is not implemented.
class Worm:
def bore(self):
raise NotImplemented # [notimplemented-raised]
Flags the incorrect passing of positional-only arguments as keyword arguments in function calls. This rule ensures that arguments are passed according to the function signature, respecting positional-only restrictions to prevent TypeError.
def cube(n, /):
"""Takes in a number n, returns the cube of n"""
return n**3
cube(n=2) # [positional-only-arguments-expected]
Indicates a potential error when accessing an index that may be out of bounds for the given iterable. This rule helps identify possible IndexError before runtime by analyzing patterns that could lead to accessing invalid indexes.
print([1, 2, 3][3]) # [potential-index-error]
Flags an attempt to raise an object that is neither an exception class nor an instance of one. This rule ensures that only valid exceptions are raised, adhering to Python’s error handling model and preventing runtime errors.
class FasterThanTheSpeedOfLightError(ZeroDivisionError):
def __init__(self):
super().__init__("You can't go faster than the speed of light !")
def calculate_speed(distance: float, time: float) float:
try:
return distance / time
except ZeroDivisionError as e:
raise None # [raising-bad-type]
Warns when an attempt is made to raise a class that does not inherit from BaseException, which is required for all exception classes. This rule helps maintain the integrity of the exception handling system by ensuring that only valid exceptions are used.
raise str # [raising-non-exception]
Indicates that an argument is passed both by position and keyword in the same function call, which can lead to confusion and errors. This rule helps ensure clarity and consistency in function calls by preventing redundant argument specification.
Flags an attempted relative import that goes beyond the top-level package, which is not allowed. This rule helps maintain proper package structure and import semantics, preventing ImportError caused by invalid relative import paths.
Warns when a keyword argument is specified multiple times in a function call, which is a TypeError. This rule ensures that each keyword argument is uniquely specified, preventing ambiguous or conflicting argument values.
def func(a, b, c):
return a, b, c
func(1, 2, c=3, **{"c": 4}) # [repeated-keyword]
func(1, 2, **{"c": 3}, **{"c": 4}) # [repeated-keyword]
Indicates the use of a return statement with an argument in a generator function, which is not allowed. In Python 3, return in a generator can only be used without an argument to signal the generator’s termination. This rule helps prevent syntax errors and maintains the correct use of generators.
Flags the use of an explicit return statement with a value in the init method of a class. Since init is meant to initialize an instance and not return a value, using return with a value can lead to confusion and is considered incorrect in Python.
class Sum:
def __init__(self, a, b): # [return-in-init]
return a + b
Indicates a return statement used outside of a function or method definition, which is a syntax error. This rule helps ensure that return statements are correctly placed within the functional or methodological scope.
return 42 # [return-outside-function]
Warns against using the singledispatch decorator with methods, as it’s designed for standalone functions. Python 3.8 introduced singledispatchmethod for methods to support single dispatch based on the type of the first argument in method calls.
from functools import singledispatch
class Board:
@singledispatch # [singledispatch-method]
@classmethod
def convert_position(cls, position):
pass
@convert_position.register # [singledispatch-method]
@classmethod
def _(cls, position: str) tuple:
position_a, position_b = position.split(",")
return (int(position_a), int(position_b))
@convert_position.register # [singledispatch-method]
@classmethod
def _(cls, position: tuple) str:
return f"{position[0]},{position[1]}"
Indicates the misuse of singledispatchmethod decorator with standalone functions. singledispatchmethod is intended for use with methods, while singledispatch is designed for functions, ensuring that the correct decorator is used for single dispatch functionality.
from functools import singledispatchmethod
class Board:
@singledispatchmethod # [singledispatchmethod-function]
@staticmethod
def convert_position(position):
pass
@convert_position.register # [singledispatchmethod-function]
@staticmethod
def _(position: str) tuple:
position_a, position_b = position.split(",")
return (int(position_a), int(position_b))
@convert_position.register # [singledispatchmethod-function]
@staticmethod
def _(position: tuple) str:
return f"{position[0]},{position[1]}"
Flags a starred expression used in a context other than as an assignment target, such as in a function call or outside a list/tuple on the right side of an assignment. Starred expressions are only valid when unpacking values in an assignment.
stars = *["Sirius", "Arcturus", "Vega"] # [star-needs-assignment-target]
Indicates a syntax error detected in the code, which will prevent the program from running. This rule is fundamental for identifying areas of the code that are incorrectly written and need correction for proper execution.
fruit_stock = {
'apple': 42,
'orange': 21 # [syntax-error]
'banana': 12
}
Warns when there are not enough arguments provided to a format string, leading to a runtime error when the string formatting is attempted. Ensuring the correct number of arguments for format strings is crucial for accurate and error-free string formatting.
print("Today is {0}, so tomorrow will be {1}".format("Monday")) # [too-few-format-args]
Indicates that more arguments are provided to a format string than there are placeholders for those arguments. This can lead to unused arguments and might suggest a misunderstanding of the format string’s requirements.
# +1: [too-many-format-args]
print("Today is {0}, so tomorrow will be {1}".format("Monday", "Tuesday", "Wednesday"))
Flags a function call that has too many positional arguments provided, exceeding the function’s defined parameters. This rule helps ensure function calls are made with the correct number and type of arguments.
class Fruit:
def __init__(self, color):
self.color = color
apple = Fruit("red", "apple", [1, 2, 3]) # [too-many-function-args]
Warns when more than one starred expression is used in an assignment, which is not allowed. Starred expressions can unpack iterable values, but only one such unpacking is permitted per assignment to maintain clarity and prevent ambiguity.
*stars, *constellations = ["Sirius", "Arcturus", "Vega"] # [too-many-star-expressions]
Indicates that a format string ends unexpectedly in the middle of a conversion specifier, which can lead to incomplete or incorrect string formatting. Ensuring complete and correct format strings is essential for accurate data representation.
PARG_2 = 1
print("strange format %2" % PARG_2) # [truncated-format-string]
Flags a name referenced in the all variable that has not been defined, which can lead to an ImportError when attempting to import names from the module. This rule ensures that all accurately reflects the module’s public API.
__all__ = ["get_fruit_colour"] # [undefined-all-variable]
def get_fruit_color():
pass
Indicates the use of a variable that has not been defined, leading to a NameError at runtime. This rule is crucial for identifying typos or logical errors in variable usage, ensuring that all variables are properly declared and assigned.
print(number + 2) # [undefined-variable]
Warns when a function call includes a keyword argument that is not accepted by the function’s signature. This rule helps ensure that function calls are compatible with function definitions, preventing TypeError due to unexpected arguments.
def print_coordinates(x=0, y=0):
print(f"{x=}, {y=}")
print_coordinates(x=1, y=2, z=3) # [unexpected-keyword-arg]
Indicates that a special method (like len or getitem) is defined with an unexpected number of parameters, which can lead to incorrect behavior or errors when the method is called by Python runtime. Ensuring special methods have the correct signature is vital for adhering to Python’s data model and expected object behaviors.
class ContextManager:
def __enter__(self, context): # [unexpected-special-method-signature]
pass
def __exit__(self, type): # [unexpected-special-method-signature]
pass
Flags an attempt to use an unhashable object (like a list) as a member of a hash-based collection (like a set or dictionary key). This rule is important for ensuring data integrity in collections that rely on the hashability of their elements to function correctly.
# Print the number of apples:
print({"apple": 42}[["apple"]]) # [unhashable-member]
Warns when there’s an attempt to unpack a non-sequence type, which is not iterable. This rule prevents runtime errors by ensuring that only iterable objects are unpacked, adhering to Python’s requirement for unpacking operations.
a, b, c = 1 # [unpacking-non-sequence]
Indicates the use of an inline option (typically in a comment) that pylint does not recognize. This helps maintain the clarity and effectiveness of inline directives, ensuring they are correctly interpreted by pylint.
# +1: [unrecognized-inline-option]
# pylint:applesoranges=1
Flags an option in a pylint configuration file that is not recognized by pylint. This rule helps ensure that configuration files are correctly written and that all specified options are valid and effective.
Warns when an attempt is made to subscript (index or slice) an object that does not support subscripting. This rule is crucial for preventing TypeError by ensuring that subscript operations are only performed on objects that support them.
class Fruit:
pass
Fruit()[1] # [unsubscriptable-object]
Indicates that an object does not support item assignment, typically flagged when attempting to modify an immutable object. This rule helps prevent runtime errors by ensuring that objects being modified support item assignment.
def pick_fruits(fruits):
for fruit in fruits:
print(fruit)
pick_fruits(["apple"])[0] = "orange" # [unsupported-assignment-operation]
Flags a binary operation (like addition or multiplication) between types that do not support it. This rule ensures type compatibility in operations, preventing TypeError and maintaining logical correctness.
drink = "water" | None # [unsupported-binary-operation]
result = [] | None # [unsupported-binary-operation]
Warns when an attempt is made to delete an item from an object that does not support item deletion. This rule is important for ensuring that only mutable and properly equipped objects are targeted for item deletion.
FRUITS = ("apple", "orange", "berry")
del FRUITS[0] # [unsupported-delete-operation]
Indicates an attempt to perform a membership test (using in or not in) on an object that does not support it. This rule helps avoid TypeError and ensures that membership tests are only used with objects that implement the necessary protocols.
class Fruit:
pass
apple = "apple" in Fruit() # [unsupported-membership-test]
Flags a variable being used before it has been assigned a value, which can lead to UnboundLocalError. This rule is fundamental for variable usage correctness, ensuring variables are defined before use.
print(hello) # [used-before-assignment]
hello = "Hello World !"
Warns when a name is used before it is declared as global within a function. This rule ensures that the global statement is used correctly, clarifying the scope and binding of variables used across different scopes.
TOMATO = "black cherry"
def update_tomato():
print(TOMATO) # [used-prior-global-declaration]
global TOMATO
TOMATO = "cherry tomato"
Indicates the use of yield inside an asynchronous function, which is not allowed. Since Python 3.5, async functions should use await instead, and this rule helps ensure correct asynchronous function behavior.
async def foo():
yield from [1, 2, 3] # [yield-inside-async-function]
Flags a yield statement used outside of a function, which is a syntax error. Yield is only valid within generator functions, and this rule ensures the correct context for yielding values in a lazy evaluation pattern.
for i in range(10):
yield i # [yield-outside-function]
Indicates improper implementation or use of a context manager, which may not correctly implement enter and exit methods. Proper context manager implementation is crucial for managing resources efficiently and safely.
Warns about incorrect use or handling of exception context, which may lead to loss of information or misleading error handling. This rule ensures that exceptions are managed correctly, preserving context where necessary.
Flags an invalid value provided for a pylint option, either in a configuration file or inline comment. This rule helps ensure that pylint options are configured with valid values, maintaining the tool’s effectiveness and configuration integrity.
Indicates a potential issue where a member access may fail due to the member possibly not existing. This rule helps identify possible runtime errors early, especially in dynamic or complex codebases.
Flags a situation where an object’s iteration method does not return an iterator, in the context of older Python versions or compatibility layers. Ensuring that iterables return proper iterators is essential for compatibility and correct iteration behavior.
Flags cases of unbalanced tuple unpacking, where the number of variables on the left side of the assignment does not match the number of values in the tuple. This rule ensures that tuple unpacking assignments are correctly balanced to prevent ValueError.
Warns when an attempt is made to use an unhashable object (like a list) as a dictionary key. Dictionary keys must be immutable and hashable to ensure data integrity and support efficient lookup.
Indicates that an abstract method defined in a parent class is not overridden in a subclass. This rule helps ensure that subclasses implement all abstract methods, adhering to the interface defined by their abstract base classes.
Flags the presence of backslashes in a string that do not escape any characters, suggesting that the string might require an ‘r’ prefix to be interpreted as a raw string or corrected to escape characters properly.
Warns about unusual Unicode escape sequences in byte strings, suggesting that the string may need an ‘r’ prefix for a raw string or a ‘u’ prefix for a Unicode string to correctly interpret the escape sequences.
print(b"\u%b" % b"0394") # [anomalous-unicode-escape-in-string]
Indicates that the arguments of a method override differ from those of the method in the superclass. This rule ensures consistency in method signatures across class hierarchies, preserving interface compatibility.
Flags when positional arguments in a function or method call appear to be out of their expected order, which can lead to incorrect behavior or errors due to the incorrect assignment of values to parameters.
def function_3_args(first_argument, second_argument, third_argument):
"""Three arguments function"""
return first_argument, second_argument, third_argument
def args_out_of_order():
first_argument = 1
second_argument = 2
third_argument = 3
function_3_args( # [arguments-out-of-order]
first_argument, third_argument, second_argument
)
Warns when a method in a subclass renames arguments of a method from the superclass. While not inherently incorrect, this can lead to confusion and errors in code that expects the superclass’s argument names.
class Fruit:
def brew(self, ingredient_name: str):
print(f"Brewing a {type(self)} with {ingredient_name}")
class Apple(Fruit): ...
class Orange(Fruit):
def brew(self, flavor: str): # [arguments-renamed]
print(f"Brewing an orange with {flavor}")
for fruit, ingredient_name in [[Orange(), "thyme"], [Apple(), "cinnamon"]]:
fruit.brew(ingredient_name=ingredient_name)
Indicates an assert statement where the condition is a string literal, which is always true, suggesting the assert may not function as intended and might be missing actual conditions to test.
def test_division():
a = 9 / 3
assert "No ZeroDivisionError were raised" # [assert-on-string-literal]
Flags an assert statement applied to a tuple, which is always true if the tuple is not empty. This might indicate a misunderstanding of how assert works or a typo, such as missing a comma between conditions.
assert (1, None) # [assert-on-tuple]
Warns when an instance attribute is defined outside of the init method, which can lead to attributes being undefined in some instances or contribute to a less cohesive class design.
class Student:
def register(self):
self.is_registered = True # [attribute-defined-outside-init]
Indicates improper use of a Python builtin function, either due to misunderstanding its purpose or using it in a context where a more appropriate alternative exists, leading to potential inefficiencies or errors.
numbers = list(map(lambda x: 2 * x, [1, 2, 3])) # [bad-builtin]
print(numbers)
Flags suspicious chained comparisons that use semantically incompatible operators, which might indicate a logic error or misunderstanding of comparison chaining in Python.
Indicates the use of an incorrectly named magic (dunder) method, which may not be recognized by Python’s data model. Correctly naming magic methods is crucial for them to be called automatically by Python’s runtime environment.
class Apples:
def _init_(self): # [bad-dunder-name]
pass
def __hello__(self): # [bad-dunder-name]
print("hello")
Indicates an invalid format string is used in a formatting operation. This rule helps identify syntax errors or typos in format strings, ensuring that string formatting operations are correctly specified and can execute without errors.
print("{a[0] + a[1]}".format(a=[0, 1])) # [bad-format-string]
Warns when a format string dictionary uses a non-string key. Format strings that are populated from dictionaries should use strings as keys to match placeholders in the format string, ensuring correct substitution and preventing KeyError.
print("%(one)d" % {"one": 1, 2: 2}) # [bad-format-string-key]
Flags incorrect indentation levels in the code, highlighting deviations from the expected indentation. Proper indentation is crucial in Python for defining code blocks and maintaining readability and consistency in code structure.
if input():
print('yes') # [bad-indentation]
Indicates that an invalid mode argument was passed to the open function. Validating open modes ensures that files are opened in an appropriate manner for the intended operation, preventing runtime errors.
def open_and_get_content(file_path):
with open(file_path, "rwx") as file: # [bad-open-mode]
return file.read()
Flags a static method defined with an inappropriate first argument (e.g., self or cls). Static methods should not take a class or instance reference as their first argument, distinguishing them from class and instance methods.
class Wolf:
@staticmethod
def eat(self): # [bad-staticmethod-argument]
pass
Warns when a threading.Thread object is instantiated without specifying the target function. Specifying the target is crucial for the Thread to know which function to execute in the new thread.
import threading
def thread_target(n):
print(n**2)
thread = threading.Thread(lambda: None) # [bad-thread-instantiation]
thread.start()
Flags the use of an except clause without specifying any exception types. This can catch unexpected exceptions including system interrupts, making debugging harder. It’s recommended to catch specific exceptions to handle known error conditions.
try:
import platform_specific_module
except: # [bare-except]
platform_specific_module = None
Indicates an attempt to catch an exception using the result of a binary operation, which is likely a mistake. This rule helps ensure that exception handling is specified correctly, catching actual exception classes or instances.
try:
1 / 0
except ZeroDivisionError or ValueError: # [binary-op-exception]
pass
Warns when a datetime.time object is used in a boolean context, which can be misleading since datetime.time objects are always truthy. This rule encourages explicit checks against datetime properties for clarity.
import datetime
if datetime.time(): # [boolean-datetime]
print("It is time.")
if datetime.datetime.now().time(): # [boolean-datetime]
print("Now or never.")
Flags the catching of a general exception class, which can obscure the cause of an error. Narrowing down the caught exceptions to more specific types can aid in error diagnosis and handling.
try:
import platform_specific_module
except Exception: # [broad-exception-caught]
platform_specific_module = None
Indicates raising a very general exception type, which can make error handling and debugging more difficult. Using more specific exceptions helps convey more information about the error condition.
def small_apple(apple, length):
if len(apple) < length:
raise Exception("Apple is too small!") # [broad-exception-raised]
print(f"{apple} is proper size.")
Warns about a loop variable being used in a closure, leading to late binding and possibly unexpected behavior. This rule suggests using default arguments or other strategies to ensure the correct value is captured.
Flags a comparison operation where one operand is a callable function or method without being called (missing parentheses). This typically indicates a logic error where the function’s return value was intended for comparison.
def function_returning_a_fruit() str:
return "orange"
def is_an_orange(fruit: str = "apple"):
# apple == <function function_returning_a_fruit at 0x7f343ff0a1f0>
return fruit == function_returning_a_fruit # [comparison-with-callable]
Indicates a with statement that might be confusing due to following an “as” with another context manager without using parentheses, which can appear as if a tuple is being created.
with open("file.txt", "w") as fh1, fh2: # [confusing-with-statement]
pass
Suggests using a ternary conditional expression for simpler conditional assignments or return statements, enhancing readability and conciseness of the code.
x, y = input(), input()
if x >= y: # [consider-ternary-expression]
maximum = x
else:
maximum = y
Warns when mutable objects are used as default values in function or method definitions. Since default argument values are evaluated only once at function definition time, using mutable defaults can lead to unexpected behavior across multiple calls.
def whats_on_the_telly(penguin=[]): # [dangerous-default-value]
penguin.append("property of the zoo")
return penguin
Flags the use of a deprecated argument in a method call. Using deprecated features can lead to compatibility issues as they may be removed in future versions, impacting the maintainability and future-proofing of the code.
int(x=1) # [deprecated-argument]
Indicates the use of a class that has been marked as deprecated. Relying on deprecated classes reduces the code’s longevity and may necessitate future refactoring, affecting maintainability.
from collections import Iterable # [deprecated-class]
Warns about the use of a decorator that is deprecated. Decorators affect the execution of the functions they decorate, and using deprecated ones can lead to deprecated behavior patterns and hinder performance optimizations.
import abc
class Animal:
@abc.abstractclassmethod # [deprecated-decorator]
def breath(cls):
pass
Highlights the invocation of a method that has been deprecated. Deprecated methods are candidates for removal in future releases, which can negatively impact the code’s reliability and necessitate revisions for compatibility.
import logging
logging.warn("I'm coming, world !") # [deprecated-method]
Flags the import or use of a deprecated module. Depending on deprecated modules can lead to future compatibility issues, potentially increasing the effort required for updates and maintenance.
import distutils # [deprecated-module]
import whatever_you_want # [deprecated-module]
Indicates the use of a typing alias that has been deprecated. Keeping up with current typing practices is important for readability and leveraging the full capabilities of Python’s type hinting.
import typing
item_to_number_of_item: typing.Dict[str, int] # [deprecated-typing-alias]
Warns when the actual parameters of a function differ from those documented in its docstring. Accurate documentation is key for readability and maintainability, helping developers understand function usage and expectations.
def add(x, y): # [differing-param-doc]
"""Add two numbers.
:param int x: x value.
:param int z: z value.
"""
return x + y
Indicates a discrepancy between documented types and actual types in function parameters or return values. Consistent and accurate type documentation enhances readability and supports type-checking tools.
def add(x: int, y: int): # [differing-type-doc]
"""Add two numbers.
:param int xy: x value.
:param str y: y value.
"""
return x + y
Flags duplicate exception types in consecutive except blocks. Consolidating exception handling for the same exception type can improve readability and maintainability by centralizing response logic.
try:
1 / 0
except ZeroDivisionError:
pass
except ZeroDivisionError: # [duplicate-except]
pass
Warns about duplicate keys in a dictionary literal, which can lead to overlooked bugs as the latter value silently overrides the former, impacting data integrity and readability.
test_score = {"Mathematics": 85, "Biology": 90, "Mathematics": 75} # [duplicate-key]
Highlights the use of duplicate arguments in string formatting, suggesting the use of named arguments for clarity and to prevent errors in formatting expressions.
# pylint: disable=missing-docstring, consider-using-f-string
SEE = "see 👀"
SEA = "sea 🌊"
# +1: [duplicate-string-formatting-argument,duplicate-string-formatting-argument]
CONST = """
A sailor went to {}, {}, {}
To {} what he could {}, {}, {}
But all that he could {}, {}, {}
Was the bottom of the deep blue {}, {}, {}!
""".format(
SEA,
SEA,
SEA,
SEE,
SEE,
SEE,
SEE,
SEE,
SEE,
SEE,
SEA,
SEA,
SEA,
)
Indicates duplicate values in a set literal, which is unnecessary as sets automatically enforce uniqueness. Removing duplicates can improve the clarity of the intended elements in the set.
incorrect_set = {"value1", 23, 5, "value1"} # [duplicate-value]
Flags an eq method implemented without a corresponding hash method, which can lead to incorrect behavior when objects are used in hash-based collections, impacting correctness and performance.
class Fruit: # [eq-without-hash]
def __init__(self) None:
self.name = "apple"
def __eq__(self, other: object) bool:
return isinstance(other, Fruit) and other.name == self.name
Warns against the use of eval, which can execute arbitrary code and introduce security vulnerabilities. Avoiding eval can greatly enhance the security and performance of the application.
eval("[1, 2, 3]") # [eval-used]
Similar to eval, flags the use of exec for executing Python code dynamically, which poses security risks and can make the code harder to read, debug, and maintain.
username = "Ada"
code_to_execute = f"""input('Enter code to be executed please, {username}: ')"""
program = exec(code_to_execute) # [exec-used]
exec(program) # [exec-used]
Indicates an expression that has no effect because its result is not assigned or used, potentially indicating a mistake or unnecessary code that can hinder readability.
str(42) == "42" # [expression-not-assigned]
Flags an f-string that does not perform any interpolation, suggesting that a simpler string literal could be used instead, improving clarity and performance by avoiding unnecessary parsing.
x = 1
y = 2
print(f"x + y = x + y") # [f-string-without-interpolation]
Highlights FIXME comments, which indicate areas of the code that are acknowledged by the developer as needing improvement or correction.
Warns about the presence of debugging statements, like breakpoints, left in the code. These statements can interrupt the flow or expose sensitive information in production environments, highlighting the need for clean, debug-statement-free code for performance and security.
import pdb
def find_the_treasure(clues):
for clue in clues:
pdb.set_trace() # [forgotten-debug-statement]
if "treasure" in clue:
return True
return False
treasure_hunt = [
"Dead Man's Chest",
"X marks the spot",
"The treasure is buried near the palm tree",
]
find_the_treasure(treasure_hunt)
Indicates a format string that inconsistently mixes automatic field numbering and manual field specification. Consistency in format string specifications enhances readability and maintainability by avoiding confusion about argument binding.
Flags the use of a format operation on a string that does not include any variables for interpolation. Simplifying to a regular string can improve performance by avoiding unnecessary formatting operations.
print("number".format(1)) # [format-string-without-interpolation]
Highlights the unnecessary use of the global statement at the module level, where variables are already global. This rule promotes cleaner code by avoiding redundant or confusing global declarations.
price = 25
global price # [global-at-module-level]
Warns against the use of the global statement, which can lead to code that is harder to understand and maintain by making the local-global variable distinction less clear, affecting readability and maintainability.
var = 1
def foo():
global var # [global-statement]
var = 10
print(var)
foo()
print(var)
Indicates the use of a global statement for a variable without assigning it a value, which can lead to confusion about the variable’s intent and scope, impacting the clarity and correctness of the code.
TOMATO = "black cherry"
def update_tomato():
global TOMATO # [global-variable-not-assigned]
print(TOMATO)
Flags the reference to a global variable that is not defined at the module level, potentially leading to NameError at runtime and highlighting issues with variable scope and definition.
def update_tomato():
global TOMATO # [global-variable-undefined]
TOMATO = "moneymaker"
Indicates that a flag in an enumeration shares bit positions with another, which can lead to ambiguous or unexpected behavior when checking flags, emphasizing the importance of clear, non-overlapping flag definitions for maintainability.
from enum import IntFlag
class FilePermissions(IntFlag):
READ = 1
WRITE = 2
EXECUTE = 3 # [implicit-flag-alias]
Warns about strings that are implicitly concatenated in code, which can make the strings harder to read and maintain. Explicit concatenation (using +) or formatting is recommended for clarity.
Flags a module that imports itself, which is generally unnecessary and can lead to confusion or cyclic dependencies, detracting from code clarity and structure.
Indicates inconsistency in the use of quote delimiters within a file, suggesting sticking to a single style for string literals to enhance readability and maintain a consistent code style.
import datetime
print('Current year: ', datetime.date.today().strftime("%Y")) # [inconsistent-quotes]
Warns when an environment variable default value is not a string or None, emphasizing the need for environment variables to be parsed or used in a type-safe manner, enhancing code robustness.
import os
env = os.getenv("SECRET_KEY", 1) # [invalid-envvar-default]
Flags the use of an invalid key in a format string specifier, which can lead to KeyError or ValueError during string formatting, underscoring the importance of accurate and valid format specifiers for data representation.
not_enough_fruits = ["apple"]
print('The second fruit is a {fruits[1]}'.format(fruits=not_enough_fruits)) # [invalid-format-index]
Indicates a method override that does not match the expected signature of the method it overrides. Ensuring method signatures match across class hierarchies is crucial for maintaining consistent interfaces and behaviors, enhancing both readability and maintainability.
class Fruit:
async def bore(self, insect):
insect.eat(self)
class Apple(Fruit):
def bore(self, insect): # [invalid-overridden-method]
insect.eat(self)
Flags the use of isinstance where the second argument is not a valid type or a tuple of valid types. Correct use of isinstance is important for dynamic type checks to be reliable and not cause runtime errors.
isinstance("apples and oranges", hex) # [isinstance-second-argument-not-valid-type]
Warns when a keyword argument is defined before a variable positional argument (*args) in a function definition. This affects the readability and usability of the function, as positional arguments should logically precede keyword arguments.
def func(x=None, *args): # [keyword-arg-before-vararg]
return [x, *args]
Indicates a keyword argument in a function definition that matches the name of a preceding positional-only parameter, which can lead to confusion and errors in argument passing, undermining the clarity of the function’s interface.
def print_name(name="Sarah", /, **kwds):
print(name)
print_name(name="Jacob") # [kwarg-superseded-by-positional-arg]
# Will print "Sarah"
Recommends using % formatting or formatting (with format method) in logging functions rather than string interpolation or f-strings, to defer the formatting overhead until it’s determined that the log message will actually be emitted.
import logging
import sys
# +1: [logging-format-interpolation]
logging.error("Python version: {}".format(sys.version))
Similar to the above, warns against the use of f-strings in logging functions, advocating for % or formatting for performance reasons and to ensure log messages are only formatted if they will be logged.
import logging
import sys
logging.error(f"Python version: {sys.version}") # [logging-fstring-interpolation]
Flags logging calls that do not use lazy % formatting, which can lead to unnecessary computation and memory usage even when the log level means the message will not be logged, affecting performance.
import logging
try:
function()
except Exception as e:
logging.error("Error occurred: %s" % e) # [logging-not-lazy]
raise
Warns that an exception may be swallowed if a break, return, or continue statement is used in a finally block, potentially obscuring errors and complicating debugging and error handling.
class FasterThanTheSpeedOfLightError(ZeroDivisionError):
def __init__(self):
super().__init__("You can't go faster than the speed of light !")
def calculate_speed(distance: float, time: float) float:
try:
return distance / time
except ZeroDivisionError as e:
raise FasterThanTheSpeedOfLightError() from e
finally:
return 299792458 # [lost-exception]
Highlights the use of lru_cache with maxsize=None or the use of cache, which can lead to keeping arguments and self references alive indefinitely, potentially causing memory bloat and affecting application performance.
import functools
class Fibonnaci:
def __init__(self):
self.result = []
@functools.lru_cache(maxsize=None) # [method-cache-max-size-none]
def fibonacci(self, n):
if n in {0, 1}:
self.result.append(n)
self.result.append(self.fibonacci(n - 1) + self.fibonacci(n - 2))
Indicates that a future import does not appear at the top of the file, immediately after any docstrings. future imports must be placed correctly to affect the syntax of the Python file as expected.
import sys
from __future__ import print_function # [misplaced-future]
Flags the absence of documentation for one or more parameters in a function or method, which can hinder readability and maintainability by leaving users and maintainers without clear guidance on function usage.
def puppies(head, tail): # [missing-any-param-doc]
"""Print puppy's details."""
print(head, tail)
Warns when a keyword argument expected by a format string is missing, which can lead to a KeyError during string formatting. Ensuring all format string arguments are provided enhances the robustness and reliability of string operations.
print("My name is {first} {last}".format(first="John")) # [missing-format-argument-key]
Indicates that a format string refers to an attribute that does not exist in the given format specifier, which can lead to AttributeError at runtime. Ensuring all format attributes are correct enhances code reliability and readability.
print("{0.real}".format("1")) # [missing-format-attribute]
Flags the absence of documentation for one or more parameters in a function or method’s docstring. Comprehensive parameter documentation is crucial for readability and maintainability, providing clear usage instructions to users and maintainers.
def integer_sum(a: int, b): # [missing-param-doc]
"""Returns sum of two integers
:param a: first integer
"""
return a + b
Warns about the potential misuse of a function or method call within a conditional statement due to missing parentheses, which may result in the function call not being executed as intended. Adding parentheses can clarify the intention and ensure correct execution.
import random
def is_it_a_good_day():
return random.choice([True, False])
if is_it_a_good_day: # [missing-parentheses-for-call-in-test]
print("Today is a good day!")
Indicates missing documentation for exceptions that a function or method may raise. Documenting potential exceptions helps users handle errors appropriately, improving code robustness and maintainability.
def integer_sum(a: int, b: int): # [missing-raises-doc]
"""Returns sum of two integers
:param a: first integer
:param b: second integer
"""
if not (isinstance(a, int) and isinstance(b, int)):
raise ValueError("Function supports only integer parameters.")
return a + b
Flags missing documentation for the return value of a function or method. Return value documentation is important for understanding the purpose and usage of a function, enhancing code readability.
def integer_sum(a: int, b: int): # [missing-return-doc]
"""Returns sum of two integers
:param a: first integer
:param b: second integer
"""
return a + b
Highlights the absence of documentation for the return type of a function or method. Specifying return types helps with type checking and clarifies the function’s contract, improving code readability and safety.
def integer_sum(a: int, b: int): # [missing-return-type-doc]
"""Returns sum of two integers
:param a: first integer
:param b: second integer
:return: sum of parameters a and b
"""
return a + b
Warns about the absence of a timeout argument in potentially blocking operations, which could lead to indefinite hanging. Specifying timeouts is essential for improving the reliability and performance of code by preventing deadlock situations.
import requests
requests.post("http://localhost") # [missing-timeout]
Indicates missing type documentation for parameters or return values. Type documentation is vital for type safety, readability, and leveraging static analysis tools to catch type-related errors.
def integer_sum(a: int, b): # [missing-type-doc]
"""Returns sum of two integers
:param a: first integer
:param b: second integer
"""
return a + b
Flags missing documentation for the yield values of a generator function. Yield documentation is crucial for understanding the generator’s output, enhancing readability and usability.
def even_number_under(n: int): # [missing-yield-doc]
"""Prints even numbers smaller than n.
Args:
n: Upper limit of even numbers.
"""
for i in range(n):
if i % 2 == 1:
continue
yield i
Highlights the absence of documentation for the type of values yielded by a generator function. Yield type documentation improves code clarity and assists in type checking and static analysis.
def even_number_under(n: int): # [missing-yield-type-doc]
"""Prints even numbers smaller than n.
Args:
n: Upper limit of even numbers.
Yields:
even numbers
"""
for i in range(n):
if i % 2 == 1:
continue
yield i
Warns that a list being iterated over is also being modified within the loop, which can lead to unexpected behavior. Iterating over a copy of the list is recommended to prevent modification while iterating, ensuring code correctness and predictability.
fruits = ["apple", "orange", "mango"]
for fruit in fruits:
fruits.append("pineapple") # [modified-iterating-list]
Indicates that multiple constructors in a class have documentation, which can be confusing and lead to unclear class usage. Streamlining documentation to clearly present constructor overloads enhances readability and maintainability.
class Point: # [multiple-constructor-doc]
"""Represents a point in the xy-coordinate plane.
:param x: coordinate
:param y: coordinate
"""
def __init__(self, x, y):
"""Represents a point in the xy-coordinate plane.
:param x: coordinate
:param y: coordinate
"""
self.x = x
self.y = y
Flags the use of a named expression (walrus operator :=) without a clear context, which may lead to confusion or misuse. Using named expressions with clear intent improves code clarity and reduces potential for errors.
(a := 42) # [named-expr-without-context]
Warns against direct comparison with NaN (Not a Number), as NaN is not equal to anything, including itself. Recommends using math.isnan() or similar for clarity and correctness.
import numpy as np
def both_nan(x, y) bool:
return x == np.NaN and y == float("nan") # [nan-comparison, nan-comparison]
Advises against the nested use of min or max functions, suggesting a single call with multiple arguments instead. This enhances performance by reducing function calls and improves readability by simplifying expressions.
print(min(1, min(2, 3))) # [nested-min-max]
Indicates that a file name contains non-ASCII characters, which might cause issues with tools or environments that do not support such characters, potentially affecting portability and accessibility of the code.
Warns when an init method from a class that is not a direct parent (base class) is called. This could lead to unexpected behavior due to improper initialization chains, highlighting the importance of maintaining a clear and correct inheritance hierarchy.
class Animal:
def __init__(self):
self.is_multicellular = True
class Vertebrate(Animal):
def __init__(self):
super().__init__()
self.has_vertebrae = True
class Cat(Vertebrate):
def __init__(self):
Animal.__init__(self) # [non-parent-init-called]
self.is_adorable = True
Flags the assignment of a non-string value to the name attribute, which should always be a string. This ensures compatibility and prevents potential issues with reflection or serialization that rely on name being a string.
class Fruit:
pass
Fruit.__name__ = 1 # [non-str-assignment-to-dunder-name]
Indicates except blocks in a try-except statement that catch exceptions of types that are subclasses of previously caught exceptions, leading to unreachable except blocks and potentially masking exceptions.
Flags the overriding of a method marked with typing.final, indicating that the method was intended to be the final override and not further extended, ensuring adherence to the intended design and preventing unintended behavior.
from typing import final
class Animal:
@final
def can_breathe(self):
return True
class Cat(Animal):
def can_breathe(self): # [overridden-final-method]
pass
Highlights an exception statement (raise or except) that has no effect, possibly due to being placed in an unreachable code path or not altering program flow as expected, leading to potential confusion and code cleanliness issues.
Exception("This exception is a statement.") # [pointless-exception-statement]
Warns about statements that have no effect, such as expressions on their own that neither call functions nor assign values, indicating potential errors or unnecessary code clutter that can hinder readability and maintainability.
[1, 2, 3] # [pointless-statement]
Indicates a string literal placed in the code without being used as a comment or assigned to a variable, suggesting a possible misplaced docstring or dead code that does not contribute to functionality or documentation.
"""This is a docstring which describes the module"""
"""This is not a docstring""" # [pointless-string-statement]
Flags a variable that might not be used after being assigned, suggesting potential unnecessary code or the need for further review to ensure the code’s efficiency and cleanliness.
def choose_fruits(fruits):
print(fruits)
color = "red" # [possibly-unused-variable]
return locals()
Recommends using a preferred module over another, possibly due to improvements, deprecations, or performance considerations, guiding developers towards better practices and more maintainable, performant code bases.
import urllib # [preferred-module]
Warns about access to a protected member (prefixed with an underscore) from outside its class or subclass, suggesting potential encapsulation violations and urging respect for intended privacy levels for maintainability and safety.
class Worm:
def __swallow(self):
pass
jim = Worm()
jim.__swallow() # [protected-access]
Suggests explicitly using the raise … from … syntax when re-raising exceptions to maintain the exception chain, which aids in debugging by preserving the original traceback information.
try:
1 / 0
except ZeroDivisionError as e:
raise ValueError("Rectangle Area cannot be zero") # [raise-missing-from]
Indicates raising an exception with a tuple that seems intended for string formatting, potentially leading to a TypeError or misleading exception messages, emphasizing the importance of clear and correctly formatted error reporting.
raise RuntimeError("This looks wrong %s %s", ("a", "b")) # [raising-format-tuple]
Flags the redeclaration of a name in the same scope, which can lead to confusion and errors by masking previous values, affecting code clarity and predictability.
FIRST, FIRST = (1, 2) # [redeclared-assigned-name]
Warns against redefining Python built-in names, which can lead to unexpected behavior and compatibility issues, highlighting the importance of maintaining namespace integrity for readability and safety.
def map(): # [redefined-builtin]
pass
Indicates the redefinition of a loop variable inside the loop body, potentially leading to confusion or unintended behavior by altering the loop variable in ways that affect loop iteration or clarity.
def normalize_names(names):
for name in names:
name = name.lower() # [redefined-loop-name]
Flags the redefinition of a name from an outer scope within a local scope, which can lead to confusion and errors by masking the original value, affecting readability and potentially leading to bugs due to unexpected values.
count = 10
def count_it(count): # [redefined-outer-name]
for i in range(count):
print(i)
Indicates that slots have been redefined in a subclass, which can lead to inefficiencies and unexpected behavior by altering the memory model intended by the parent class’s slots definition.
class Base:
__slots__ = ("a", "b")
class Subclass(Base):
__slots__ = ("a", "d") # [redefined-slots-in-subclass]
Warns about unnecessary returns documentation in docstrings when the function does not return any value, helping to keep documentation concise and relevant to the function’s actual behavior.
def print_fruits(fruits): # [redundant-returns-doc]
"""Print list of fruits
Returns
-------
str
"""
print(fruits)
return None
Highlights the unnecessary use of the ‘u’ string prefix in Python 3, where all strings are Unicode by default. Removing redundant prefixes improves code clarity and modernizes the codebase for current Python versions.
def print_fruit():
print(u"Apple") # [redundant-u-string-prefix]
Flags the use of unittest assertions on constant values, which are either always true or always false, indicating a potential misunderstanding of what needs to be tested or a redundant test condition.
import unittest
class DummyTestCase(unittest.TestCase):
def test_dummy(self):
self.assertTrue("foo") # [redundant-unittest-assert]
Indicates unnecessary documentation for yield values in a generator’s docstring when the generator does not yield any value, promoting accuracy and relevance in documentation.
def give_fruits(fruits): # [redundant-yields-doc]
"""Something about fruits
Yields
-------
list
fruits
"""
return fruits
Warns about a module being imported more than once, which is unnecessary and can lead to confusion about which import the code is actually using, impacting code readability and cleanliness.
import re
import re # [reimported]
Flags the use of a return statement within a finally block, which can lead to the suppression of any exception raised in the try or except blocks and obscure the control flow, potentially leading to hidden bugs.
def second_favorite():
fruits = ["kiwi", "pineapple"]
try:
return fruits[1]
finally:
# because of this `return` statement, this function will always return "kiwi"
return fruits[0] # [return-in-finally]
Indicates a variable is being assigned to itself, which is redundant and has no effect, suggesting a potential error in the code or an unnecessary operation that can be removed for clarity.
year = 2000
year = year # [self-assigning-variable]
Flags an invalid assignment to self or cls within a method, which could indicate a misunderstanding of how instance and class attributes should be used or modified.
class Fruit:
@classmethod
def list_fruits(cls):
cls = "apple" # [self-cls-assignment]
def print_color(self, *colors):
self = "red" # [self-cls-assignment]
color = colors[1]
print(color)
Highlights an import statement that is shadowed by another import or definition later in the code, which can lead to confusion about which module or variable is being referred to, affecting maintainability.
from pathlib import Path
import FastAPI.Path as Path # [shadowed-import]
Advises against using copy.copy(os.environ) due to os.environ’s unique behavior and suggests using os.environ.copy() for a more predictable and safe copying of the environment variables.
import copy
import os
copied_env = copy.copy(os.environ) # [shallow-copy-environ]
Indicates that a method’s signature differs from that of a method it overrides or implements from an interface or superclass, which can lead to incorrect behavior or interface contract violations.
class Animal:
def run(self, distance=0):
print(f"Ran {distance} km!")
class Dog(Animal):
def run(self, distance): # [signature-differs]
super(Animal, self).run(distance)
print("Fetched that stick, wuff !")
Flags the subclassing of a class marked with typing.final, which is intended to prevent subclassing to maintain a strict class hierarchy, ensuring adherence to design intentions and preventing unintended inheritance.
from typing import final
@final
class PlatypusData:
"""General Platypus data."""
average_length = 46
average_body_temperature = 32
class FluorescentPlaytipus(PlatypusData): # [subclassed-final-class]
"""Playtipus with fluorescent fur."""
Warns about the use of preexec_fn in subprocess.Popen, which can be dangerous in multi-threaded environments, suggesting alternatives that are safer in the presence of threads.
import subprocess
def foo():
pass
subprocess.Popen(preexec_fn=foo) # [subprocess-popen-preexec-fn]
Indicates the use of subprocess.run without explicitly setting the ‘check’ argument, which is important for error handling by raising an exception if the command returns a non-zero exit status, ensuring reliable execution of subprocesses.
import subprocess
proc = subprocess.run(["ls"]) # [subprocess-run-check]
Flags instances where a class’s init method does not call the init method of its base class using super(), potentially leading to incomplete initialization and unpredictable behavior, undermining the integrity of class inheritance.
class Fruit:
def __init__(self, name="fruit"):
self.name = name
print("Creating a {self.name}")
class Apple(Fruit):
def __init__(self): # [super-init-not-called]
print("Creating an apple")
Warns when a super call is made without parentheses, which is a syntax error in Python 3. Correct use of super() is crucial for accessing methods from the parent class correctly and ensuring proper class behavior.
class Soup:
@staticmethod
def temp():
print("Soup is hot!")
class TomatoSoup(Soup):
@staticmethod
def temp():
super.temp() # [super-without-brackets]
print("But tomato soup is even hotter!")
Indicates excessive use of try statements within a function or method, which can complicate the control flow and make the code harder to read and maintain. Simplifying error handling can enhance readability and error tracking.
FRUITS = {"apple": 1, "orange": 10}
def pick_fruit(name):
try: # [too-many-try-statements]
count = FRUITS[name]
count += 1
print(f"Got fruit count {count}")
except KeyError:
return
Flags an except block that immediately re-raises the caught exception without any additional handling, which could be unnecessary and may obscure the origin of the exception, potentially complicating debugging.
Warns about potential mismatches in the number of keys and values when unpacking dictionaries, which could lead to ValueError and indicates a logical error in the expected structure of the dictionary.
FRUITS = {"apple": 2, "orange": 3, "mellon": 10}
for fruit, price in FRUITS.values(): # [unbalanced-dict-unpacking]
print(fruit)
Indicates potential mismatches in the number of elements when unpacking tuples, leading to ValueError. Ensuring balanced unpacking is essential for correct assignment and data handling.
fruits = ("orange", "apple", "strawberry", "peer")
orange, apple, strawberry = fruits # [unbalanced-tuple-unpacking]
Flags the use of a loop variable that may be undefined outside of the loop, potentially leading to NameError and indicating a reliance on the loop for variable definition, which can be error-prone.
def find_even_number(numbers):
for x in numbers:
if x % 2 == 0:
break
return x # [undefined-loop-variable]
Indicates the use of an unrecognized value for an option in a configuration file, which could lead to misconfiguration or ignored settings, affecting the tool’s or application’s behavior.
# pylint: disable=missnig-docstring # [unknown-option-value]
Warns about the use of the ellipsis literal (…) in contexts where it has no effect, suggesting the removal of redundant code for clarity and to avoid confusion.
def my_function():
"""My docstring"""
... # [unnecessary-ellipsis]
Flags the use of lambda functions where a direct function or method reference could be used instead, potentially simplifying the code and improving readability by removing unnecessary lambda wrappers.
Indicates the presence of a pass statement that serves no purpose, which can be removed to clean up the code and enhance readability by eliminating redundant placeholders.
class DataEntryError(Exception):
"""This exception is raised when a user has provided incorrect data."""
pass # [unnecessary-pass]
Flags the use of unnecessary semicolons at the end of statements, a practice not required in Python, which can improve code cleanliness and adhere to Pythonic style guidelines.
print("Hello World!"); # [unnecessary-semicolon]
Warns about code that is logically unreachable due to the control flow, such as statements after a return or raise, highlighting potential errors or unnecessary code segments.
def say_hello():
return True
print("Hello World!, Outside function.") # [unreachable]
Indicates the use of open without specifying an encoding, which can lead to inconsistencies and unexpected behavior when dealing with text files across different environments and platforms.
def foo(file_path):
with open(file_path) as file: # [unspecified-encoding]
contents = file.read()
Flags arguments of functions or methods that are never used, suggesting potential simplification of the function signature or a review to ensure that all arguments are necessary and used appropriately.
def print_point(x, y): # [unused-argument]
print(f"Point is located at {x},{x}")
Warns about arguments provided to a format string that are not used in the formatting, which can indicate errors in the string or redundant arguments that can be removed for clarity.
Flags keys provided in a format string dictionary that are not used in the string’s placeholders, indicating potential errors in the string or redundant data, which can be removed to enhance clarity and reduce confusion.
"The quick %(color)s fox jumps over the lazy dog." % {
"color": "brown",
"action": "hops",
}
# -4: [unused-format-string-key]
Indicates import statements that bring modules or specific symbols into the namespace but are never used. Removing unused imports can clean up the code, reduce memory footprint, and decrease load times.
from logging import getLogger
from pathlib import Path # [unused-import]
LOGGER = getLogger(__name__)
Warns about private members of a class (typically prefixed with an underscore) that are defined but not used within the class, suggesting potential for simplifying the class by removing unnecessary members.
class Fruit:
FRUITS = {"apple": "red", "orange": "orange"}
def __print_color(self): # [unused-private-member]
pass
Flags variables that are assigned but never used thereafter, which can indicate either leftover code from refactoring, placeholders for future code, or simply unnecessary variable assignments that can be removed for cleanliness.
def print_fruits():
fruit1 = "orange"
fruit2 = "apple" # [unused-variable]
print(fruit1)
Indicates that specific symbols imported via a wildcard import (from module import *) are not used, which can lead to namespace pollution and potentially obscure the origin of various symbols, reducing code readability.
from abc import * # [unused-wildcard-import]
class Animal(ABC): ...
Flags an else block following a loop that does not contain a break statement. Since the else part only executes if the loop completes normally, without encountering a break, an else without a break is redundant and can be removed for simplicity.
def find_even_number(numbers):
for x in numbers:
if x % 2 == 0:
return x
else: # [useless-else-on-loop]
print("Did not find an even number")
Highlights parameter documentation in docstrings for parameters that either don’t exist or are otherwise unnecessary, suggesting that documentation should be concise and relevant to the implemented functionality.
def say_hello(_new: str) str: # [useless-param-doc]
"""say hello!
:param _new:
:return: comment
"""
return "hello"
Indicates a method that simply calls the same method on super() without any additional logic, which could be unnecessary and may be removed unless explicitly required for interface consistency or future extension points.
class Animal:
def eat(self, food):
print(f"Eating {food}")
class Human(Animal):
def eat(self, food): # [useless-parent-delegation]
super(Human, self).eat(food)
Warns about type documentation that is redundant or not useful, perhaps due to the use of type hints or other clear type indications in the code, advocating for maintaining only meaningful and helpful documentation.
def print_fruit(fruit, _): # [useless-type-doc]
"""docstring ...
Args:
fruit (str): A fruit.
_ (float): Another argument.
"""
print(fruit)
Indicates a context manager (often a lock) used in a with statement that does not affect the enclosed code block, suggesting a review of the lock’s necessity or the correctness of its usage within the context.
import threading
with threading.Lock(): # [useless-with-lock]
print("Make your bed.")
with threading.Lock(): # [useless-with-lock]
print("Sleep in it")
Flags the use of constant values in conditional statements, which results in branches that are either always executed or never reached, pointing to potential logic errors or unnecessary code segments.
if 0: # [using-constant-test]
print("This code is never executed.")
if 1: # [using-constant-test]
print("This code is always executed.")
Warns about the use of f-strings in codebases that aim to support Python versions older than 3.6, where f-strings are not available, affecting compatibility and potentially leading to syntax errors in those versions.
f"python {3.5} is past end of life" # [using-f-string-in-unsupported-version]
Indicates the use of the typing.final decorator in projects that must be compatible with Python versions that do not support this feature, potentially leading to runtime errors or ignored annotations in those versions.
from typing import final
@final # [using-final-decorator-in-unsupported-version]
class Playtypus(Animal):
@final # [using-final-decorator-in-unsupported-version]
def lay_egg(self): ...
Flags the use of a while loop that could be unnecessary or replaced with a more suitable control flow construct, indicating that the use of while may not be the most efficient or readable approach.
import requests
def fetch_data():
i = 1
while i < 6: # [while-used]
print(f"Attempt {i}...")
try:
return requests.get("https://example.com/data")
except requests.exceptions.RequestException:
pass
i += 1
Warns against the use of wildcard imports, which can obscure the source of variables and functions, complicate dependency tracking, and potentially lead to conflicts in the namespace, reducing code readability and maintainability.
from abc import * # [wildcard-import]
Flags invalid operations performed with exceptions, such as attempting to concatenate strings with exception objects directly, highlighting the importance of correct exception handling and manipulation for clear error reporting and code reliability.
try:
1 / 0
except ValueError + TypeError: # [wrong-exception-operation]
pass
Warns against the use of a broad except clause (except Exception: or except:) that catches all exceptions. This practice can obscure specific errors and complicate debugging. Narrowing down the caught exceptions can improve error handling specificity and maintainability.
Indicates the use of a cache (like functools.lru_cache) without specifying a max size, potentially leading to unbounded memory usage. Specifying a max size can improve performance and prevent resource exhaustion.
Flags cases of implicit string concatenation within sequences like lists or tuples, which can be error-prone and reduce readability. Explicit concatenation or joining is recommended for clarity.
Warns about the use of an LRU (Least Recently Used) cache decorator on a method, which can lead to unexpected behavior if not used correctly, especially concerning self argument handling and cache key generation.
Indicates assignment from None in older versions of Python, where this pattern may have different implications or be part of now-deprecated practices, suggesting a review for compatibility and modern Python practices.
Flags the use of arguments that are deprecated in older versions of Python, emphasizing the need to update code to use current, supported arguments for functions and methods.
Warns about the use of classes that are deprecated in older Python versions, suggesting the need for updates or alternatives to maintain compatibility with current Python standards and practices.
Indicates the use of decorators that are deprecated in older versions of Python, highlighting the importance of keeping code up-to-date with current Python idioms and best practices.
Flags methods that are deprecated in older versions of Python, underscoring the need to adapt code to use supported methods and practices in contemporary Python development.
Warns about the reliance on modules that are deprecated in older Python versions, suggesting a transition to current modules and libraries for better compatibility and feature support.
Indicates the presence of empty docstrings in older versions of Python, where comprehensive documentation might have been overlooked or neglected, emphasizing the value of complete and informative documentation.
Flags missing documentation for parameters in functions or methods in older Python versions, stressing the importance of complete docstrings for clarity, usability, and maintainability of code.
Highlights missing documentation for return values in older versions of Python, indicating a gap in docstrings that can affect the understandability and correctness of code documentation.
Indicates missing type documentation in older versions of Python, where specifying parameter and return types can improve readability, type checking, and overall code quality.
Warns about missing documentation for yielded values in generator functions in older versions of Python, emphasizing the need for comprehensive docstrings to inform users of the function’s behavior and output.
Flags an issue in older versions of Python where a function expected to return an iterator instead returns a non-iterator object. Ensuring that iterators conform to the expected protocol is crucial for compatibility with iteration mechanisms, enhancing code robustness and preventing runtime errors during iteration processes.
Indicates the use of type checking methods that are considered unidiomatic in older Python versions, suggesting a transition towards more Pythonic practices like using isinstance() for type checking. Adopting idiomatic type checks can improve code readability and compatibility with Python’s dynamic and polymorphic nature.
Warns about attempts to unpack non-sequences in older versions of Python, which can lead to errors. This highlights the importance of ensuring that objects being unpacked support the sequence protocol, maintaining code correctness and preventing runtime exceptions.
Indicates a method that simply calls the same method on its superclass using super() without any modification to arguments or behavior. Such direct delegation can often be unnecessary, suggesting a review of the method’s utility and potentially simplifying the class hierarchy.
Flags a class method where the first argument is not conventionally named ‘cls’, which is a best practice for readability and clarity in indicating that the method is bound to the class and not an instance.
class Klass:
@classmethod
def get_instance(self): # [bad-classmethod-argument]
return self()
Warns about inconsistency in the quotes used for docstrings within the same project or module, recommending a consistent style for quotes to enhance readability and maintain coding style consistency.
def foo(): # [bad-docstring-quotes]
"Docstring."
return
Indicates that a Python file does not use UTF-8 encoding, which is recommended by PEP 8 for compatibility and to support international characters. Ensuring UTF-8 encoding can improve the portability and usability of code across different platforms and locales.
Flags a class method within a metaclass where the first argument is not named ‘cls’, emphasizing the importance of adhering to conventional naming for clarity in the special context of metaclasses.
class Meta(type):
@classmethod
def foo(some): # [bad-mcs-classmethod-argument]
pass
Highlights a method within a metaclass where the first argument does not follow the convention (e.g., not named ‘cls’ or ‘self’), which can lead to confusion about the method’s context and binding, particularly in the nuanced area of metaclass design.
class Meta(type):
def func(some): # [bad-mcs-method-argument]
pass
Suggests iterating directly over a dictionary to access keys instead of calling .keys(), which is unnecessary and less efficient. Direct iteration is more Pythonic and improves code readability and performance.
FRUITS = {"apple": 1, "pear": 5, "peach": 10}
for fruit in FRUITS.keys(): # [consider-iterating-dictionary]
print(fruit)
Recommends using the ‘any’ or ‘all’ functions for concise and idiomatic testing of conditionals across iterables, enhancing code readability and potentially improving performance by utilizing built-in optimizations.
def all_even(items):
"""Return True if the list contains all even numbers"""
for item in items: # [consider-using-any-or-all]
if not item % 2 == 0:
return False
return True
def any_even(items):
"""Return True if the list contains any even numbers"""
for item in items: # [consider-using-any-or-all]
if item % 2 == 0:
return True
return False
Advises iterating over a dictionary using .items() when both keys and values are needed, which is more efficient and clearer than accessing keys and values separately, improving code readability and performance.
ORCHESTRA = {
"violin": "strings",
"oboe": "woodwind",
"tuba": "brass",
"gong": "percussion",
}
for instrument in ORCHESTRA: # [consider-using-dict-items]
print(f"{instrument}: {ORCHESTRA[instrument]}")
Suggests using enumerate for iterating over sequences when both the index and value are needed, instead of using range and len. This approach is more Pythonic, enhancing readability and simplicity by directly providing the index and value during iteration.
seasons = ["Spring", "Summer", "Fall", "Winter"]
for i in range(len(seasons)): # [consider-using-enumerate]
print(i, seasons[i])
Suggests the use of f-strings for string formatting to enhance readability and performance. F-strings, introduced in Python 3.6, offer a more readable and concise syntax for embedding expressions inside string literals compared to traditional formatting methods.
from string import Template
menu = ("eggs", "spam", 42.4)
old_order = "%s and %s: %.2f ¤" % menu # [consider-using-f-string]
beginner_order = menu[0] + " and " + menu[1] + ": " + str(menu[2]) + " ¤"
joined_order = " and ".join(menu[:2])
# +1: [consider-using-f-string]
format_order = "{} and {}: {:0.2f} ¤".format(menu[0], menu[1], menu[2])
# +1: [consider-using-f-string]
named_format_order = "{eggs} and {spam}: {price:0.2f} ¤".format(
eggs=menu[0], spam=menu[1], price=menu[2]
)
template_order = Template("$eggs and $spam: $price ¤").substitute(
eggs=menu[0], spam=menu[1], price=menu[2]
)
Warns about mutations (changes) being made to a dictionary during its initialization phase. Such mutations can lead to confusing code and potential errors, emphasizing the need for clear and predictable dictionary initialization practices.
fruit_prices = {} # [dict-init-mutate]
fruit_prices["apple"] = 1
fruit_prices["banana"] = 10
Flags the use of a name that has been marked as disallowed or inappropriate in the context of the project, potentially due to naming conventions or to avoid shadowing built-in functions or keywords, enhancing code clarity and avoiding confusion.
def foo(): # [disallowed-name]
print("apples")
Indicates that the first line of a docstring is empty, contrary to the convention that the first line should provide a concise summary of the object’s purpose, affecting documentation quality and readability.
def foo(): # [docstring-first-line-empty]
"""
Lorem Ipsum is simply dummy text of the printing and typesetting
industry.
Lorem Ipsum has been the industry's standard dummy text ever since the
1500s, when an unknown printer took a galley of type and scrambled it
to make a type specimen book
"""
Flags the presence of an empty docstring, suggesting that documentation is either missing or incomplete, which can hinder understandability and maintainability by leaving the purpose and usage of code elements undocumented.
def foo(): # [empty-docstring]
""""""
Warns about imports that are not at the top level of the module but nested within functions or conditionals, which can lead to performance issues and reduce the clarity of module dependencies.
def print_python_version():
import sys # [import-outside-toplevel]
print(sys.version_info)
Indicates that a name intended to be private (typically prefixed with an underscore) is being imported, potentially violating encapsulation principles and leading to tighter coupling between components.
from argparse import _AttributeHolder, _SubParsersAction # [import-private-name]
attr_holder = _AttributeHolder()
def add_sub_parser(sub_parsers: _SubParsersAction):
sub_parsers.add_parser("my_subparser")
# ...
Flags the use of invalid or non-standard characters in a docstring, which could affect the readability of the documentation or cause issues with documentation generation tools.
Indicates that a name (variable, function, class, etc.) does not conform to the naming conventions specified for the project, affecting code consistency, readability, and maintainability.
class cat: # [invalid-name]
def Meow(self, NUMBER_OF_MEOW): # [invalid-name, invalid-name]
print("Meow" * NUMBER_OF_MEOW)
return NUMBER_OF_MEOW
Cat = cat().Meow(42) # [invalid-name]
Warns that a line of code exceeds the recommended length, affecting readability by making the code harder to read without horizontal scrolling or line wrapping, contrary to PEP 8 recommendations.
# +1: [line-too-long]
FRUIT = ["apricot", "blackcurrant", "cantaloupe", "dragon fruit", "elderberry", "fig", "grapefruit", ]
Suggests that the constant in a comparison should be placed on the right-hand side, following conventional readability practices and making the code easier to understand at a glance.
def compare_apples(apples=20):
for i in range(10):
if 5 <= i: # [misplaced-comparison-constant]
pass
if 1 == i: # [misplaced-comparison-constant]
pass
if 20 < len(apples): # [misplaced-comparison-constant]
pass
Flags a class without a docstring, suggesting that documentation is missing that would explain the class’s purpose, usage, and behavior, which is vital for maintainability and usability.
class Person: # [missing-class-docstring]
def __init__(self, first_name, last_name):
self.first_name = first_name
self.last_name = last_name
Indicates that the final newline is missing from a file, which is a common convention for text files and can help with processing files in Unix-like environments, enhancing compatibility and adherence to standards.
Flags a function or method without a docstring, highlighting the absence of essential documentation that describes what the function does, its parameters, and its return value, affecting code clarity and maintainability.
import sys
def print_python_version(): # [missing-function-docstring]
print(sys.version)
Indicates the absence of a module-level docstring, which should introduce the module and summarize its purpose and contents, affecting the understandability and discoverability of the module’s functionality.
import sys # [missing-module-docstring]
def print_python_version():
print(sys.version)
Warns about the presence of mixed line endings (LF and CRLF) within a file, which can lead to inconsistencies and issues in version control systems, emphasizing the need for uniform line endings.
Flags a line that imports multiple modules or symbols, suggesting splitting imports into separate lines for better readability and adherence to PEP 8’s import formatting guidelines.
import os, sys # [multiple-imports]
Indicates that more than one statement is present on a single line, which can hinder readability and maintainability by compacting too much logic into a small space, contrary to PEP 8’s recommendations.
fruits = ["apple", "orange", "mango"]
if "apple" in fruits: pass # [multiple-statements]
else:
print("no apples!")
Warns when a module name contains non-ASCII characters and suggests using an ASCII-only alias for importing. This practice enhances code portability and avoids issues in environments with limited Unicode support, ensuring broader compatibility.
from os.path import join as łos # [non-ascii-module-import]
foo = łos("a", "b")
Indicates the use of non-ASCII characters in a name (variable, function, class, etc.), recommending renaming to ASCII-only characters for improved code readability and compatibility across diverse execution environments.
ápple_count = 4444 # [non-ascii-name]
Flags the definition of slots in a class as a single string rather than as an iterable of strings, which can lead to a misunderstanding of slots behavior, affecting memory optimization intentions by creating only one slot with the entire string.
class Fruit: # [single-string-used-for-slots]
__slots__ = "name"
def __init__(self, name):
self.name = name
Advises against comparing singleton objects (like None) using == or !=. Recommends using ‘is’ or ‘is not’ for clarity and performance, as these operators check for object identity, which is more appropriate for singletons.
game_won = True
if game_won == True: # [singleton-comparison]
print("Game won !")
Highlights the unnecessary use of parentheses after certain keywords (e.g., return, yield), where the syntax does not require them. Removing superfluous parentheses can improve code readability and stylistic consistency.
Indicates that a module exceeds the recommended maximum line count, suggesting potential refactoring or modularization to enhance maintainability, readability, and ease of navigation within the codebase.
Flags extra newline characters at the end of a file, recommending a single newline to adhere to conventions and maintain consistency across files, aiding in cleaner version control diffs and file concatenation behaviors.
print("apple")
# The file ends with 2 lines that are empty # +1: [trailing-newlines]
Warns about whitespace characters (spaces, tabs) at the end of lines, which can introduce unnecessary noise in version control diffs and may affect the cleanliness of the codebase.
print("Hello") # [trailing-whitespace]
# ^^^ trailing whitespaces
Indicates a TypeVar defined with both covariant and contravariant flags, which is not allowed as a type variable cannot be both. This rule ensures correct usage of type variance in generics, improving type checking accuracy.
from typing import TypeVar
T = TypeVar("T", covariant=True, contravariant=True) # [typevar-double-variance]
Flags a TypeVar whose name does not reflect its declared variance (covariant or contravariant), suggesting naming conventions that make the variance explicit, enhancing code readability and type safety.
from typing import TypeVar
T_co = TypeVar("T_co") # [typevar-name-incorrect-variance]
Indicates a mismatch between the name of a TypeVar and the variable it’s assigned to, emphasizing the importance of consistency in type variable naming for clarity and maintainability in type annotations.
from typing import TypeVar
X = TypeVar("T") # [typevar-name-mismatch]
Warns about a file using a different line ending format than expected (e.g., CRLF instead of LF), recommending consistency to avoid issues in cross-platform development environments and version control systems.
print("I'm drinking tea!") # CRLF (
) # [unexpected-line-ending-format]
print("I'm drinking water!") # CRLF (
) # [unexpected-line-ending-format]
Indicates imports from the same package that are not grouped together, recommending organizing imports by package to improve readability, simplify dependency tracking, and adhere to PEP 8’s import organization guidelines.
import logging
import os
import sys
import logging.config # [ungrouped-imports]
from logging.handlers import WatchedFileHandler
Advises using isinstance() for type checks instead of type(), as isinstance() supports inheritance and is considered more Pythonic. This approach allows for more flexible and reliable type checking, especially in the presence of inheritance hierarchies.
test_score = {"Biology": 95, "History": 80}
if type(test_score) is dict: # [unidiomatic-typecheck]
pass
Points out that a lambda function is being called directly at the point of definition, suggesting that the lambda’s body could be executed directly instead, simplifying the code by removing the unnecessary lambda wrapper.
y = (lambda x: x**2 + 2 * x + 1)(a) # [unnecessary-direct-lambda-call]
Indicates a direct call to a double-underscore method (dunder method) like str(), recommending the use of the corresponding built-in function (str()) instead. This practice enhances readability and adheres to Pythonic conventions.
three = (3.0).__str__() # [unnecessary-dunder-call]
twelve = "1".__add__("2") # [unnecessary-dunder-call]
def is_bigger_than_two(x):
return x.__gt__(2) # [unnecessary-dunder-call]
Warns against assigning a lambda function to a variable, suggesting the definition of a regular function with def for clarity and simplicity. Regular functions are more straightforward and can be named, improving code readability.
foo = lambda x: x**2 + 2 * x + 1 # [unnecessary-lambda-assignment]
Suggests rephrasing expressions that use unnecessary negation to their positive counterparts, enhancing readability and reducing cognitive load by simplifying conditional logic.
Recommends relying on the implicit boolean value of sequences instead of explicit comparison with their length or empty literals, simplifying conditions and leveraging Python’s truthy and falsey evaluation.
z = []
if z != []: # [use-implicit-booleaness-not-comparison]
print("z is not an empty sequence")
Similar to the above, advises using the implicit boolean value of strings for conditions, avoiding explicit empty string comparisons, and thus simplifying the code by utilizing Python’s evaluation of empty strings as falsey.
def important_string_manipulation(x: str, y: str) None:
if x == "": # [use-implicit-booleaness-not-comparison-to-string]
print("x is an empty string")
if y != "": # [use-implicit-booleaness-not-comparison-to-string]
print("y is not an empty string")
Recommends using the implicit boolean value of integers instead of comparing them directly to zero, streamlining conditionals by taking advantage of the fact that 0 is falsey in Python.
def important_math(x: int, y: int) None:
if x == 0: # [use-implicit-booleaness-not-comparison-to-zero]
print("x is equal to zero")
if y != 0: # [use-implicit-booleaness-not-comparison-to-zero]
print("y is not equal to zero")
Advises against using len(SEQUENCE) in conditions to check if a sequence is empty, recommending direct evaluation of the sequence in conditional statements for simplicity and Pythonic style.
fruits = ["orange", "apple"]
if len(fruits): # [use-implicit-booleaness-not-len]
print(fruits)
Suggests using the maxsplit argument in string splitting functions to limit the number of splits, improving efficiency and clarity by directly specifying split behavior instead of manual post-split processing.
url = "www.example.com"
suffix = url.split(".")[-1] # [use-maxsplit-arg]
Encourages the use of sequence types (like lists or tuples) for iteration, ensuring that the code iterates over a collection of items in a clear and predictable manner, enhancing readability and maintainability.
Flags import aliases that do not change the name of the imported module, suggesting the removal of the alias to avoid unnecessary indirection and to use the original module name directly for clarity.
import pandas as pandas # [useless-import-alias]
Highlights incorrect ordering of import statements, recommending adherence to PEP 8 guidelines, which suggest organizing imports in a particular order (standard library, third-party, local) to improve readability and maintainability.
import os
from . import utils
import pylint # [wrong-import-order]
import sys # [wrong-import-order]
Warns that an import statement is not placed at the top of the module as recommended by PEP 8, suggesting that all imports should be grouped at the beginning of a file to clarify module dependencies and enhance code organization.
import os
home = os.environ["HOME"]
import sys # [wrong-import-position]
print(f"Home directory is {home}", file=sys.stderr)
Indicates a potential spelling error in a comment, underscoring the importance of clear and correctly spelled comments to maintain professionalism and readability in code documentation.
# There's a mistkae in this string # [wrong-spelling-in-comment]
Similar to the above, flags possible spelling mistakes within docstrings, emphasizing the need for accurate and well-written documentation to ensure clarity and usefulness for other developers and users.
"""There's a mistkae in this string""" # [wrong-spelling-in-docstring]
Flags the use of names that are considered inappropriate or not descriptive, encouraging the use of meaningful identifiers that clearly convey the purpose and function of variables, functions, and classes.
Advises against explicitly comparing strings to empty strings and recommends using the truthiness of strings to check for emptiness, following Pythonic practices for clarity and brevity.
Similar to comparing to empty strings, recommends against explicit comparison to zero, suggesting the use of the inherent truthiness or falseness of numbers in conditions for simplicity and readability.
Warns against using len(SEQUENCE) in conditions to check for emptiness, recommending direct evaluation of the sequence itself, which is more idiomatic and concise in Python.
Indicates the absence of a docstring in a public module, function, or class, highlighting the need for documentation to explain the purpose, usage, and behavior of code components for better maintainability and usability.
Flags the unconventional placement of a comparison constant in conditions within older Python versions, advocating for consistency with modern Python practices for clearer and more intuitive comparisons.
Warns about the use of non-ASCII characters in identifiers in older Python versions, suggesting the use of ASCII characters for compatibility and adherence to conventional naming practices.
Indicates the use of an unnecessary not operator in conditions, suggesting simplification of the logic for clarity and to avoid double negatives, which can complicate understanding of the condition’s intent.
Recommends simplifying chained comparisons between operands to enhance readability and maintain the code’s logical flow more straightforwardly, adhering to Python’s ability to naturally handle such comparisons.
a = int(input())
b = int(input())
c = int(input())
if a < b and b < c: # [chained-comparison]
pass
Flags the comparison of constants, which results in a constant value, suggesting a review of the logic as such comparisons may indicate redundant or unneeded code that does not impact program flow.
def is_the_answer() bool:
return 42 == 42 # [comparison-of-constants]
Indicates a variable or expression is compared with itself, a redundant operation that always yields a constant result, suggesting a potential logical error or unnecessary code segment.
def is_an_orange(fruit):
an_orange = "orange"
return fruit == fruit # [comparison-with-itself]
Warns that a boolean condition always evaluates to the same value (true or false), indicating a potentially redundant or misleading condition that does not contribute to dynamic decision-making in code.
def is_a_fruit(fruit):
return bool(fruit in {"apple", "orange"} or True) # [condition-evals-to-constant]
Flags instances where consecutive elif statements in a conditional chain check the same condition, which is redundant and potentially confusing, suggesting consolidation or clarification of the logic to improve readability and maintainability.
def myfunc(shall_continue: bool, shall_exit: bool):
if shall_continue:
if input("Are you sure?") == "y":
print("Moving on.")
elif shall_exit: # [confusing-consecutive-elif]
print("Exiting.")
In Python 3.10 and later, suggests using the new union syntax (X | Y) instead of typing.Union[X, Y], enhancing readability and conciseness of type annotations by leveraging the latest language features.
from typing import Union
cats: Union[int, str] # [consider-alternative-union-syntax]
Recommends combining multiple isinstance() checks into a single call with a tuple of types, simplifying the code and improving performance by reducing the number of function calls.
from typing import Any
def is_number(value: Any) bool:
# +1: [consider-merging-isinstance]
return isinstance(value, int) or isinstance(value, float)
Suggests refactoring a loop that contains a conditional break statement at its beginning into a while loop with the condition, improving clarity by directly incorporating the loop’s termination condition into its structure.
fruit_basket = ["apple", "orange", "banana", "cherry", "guava"]
while True: # [consider-refactoring-into-while-condition]
if len(fruit_basket) == 0:
break
fruit = fruit_basket.pop()
print(f"We removed {fruit} from the basket")
Advises using tuple unpacking for swapping the values of two variables, a more Pythonic and clearer approach than using a temporary variable, demonstrating Python’s elegant syntax for common operations.
a = 1
b = 2
temp = a # [consider-swap-variables]
a = b
b = temp
Suggests using a more commonly accepted alias for a module or object to improve readability and consistency with community standards or conventions, enhancing code understandability.
import typing
cats: typing.Dict[str, int] # [consider-using-alias]
Recommends using the assignment expression (:=) introduced in Python 3.8 for assignments within expressions, which can make the code more concise and reduce repetition by capturing a condition’s result inline.
apples = 2
if apples: # [consider-using-assignment-expr]
print("God apples!")
Advises using augmented assignment operators (+=, -=, *=, etc.) when possible, simplifying expressions and potentially improving performance by modifying variables in place where applicable.
x = 1
x = x + 1 # [consider-using-augmented-assign]
Recommends using dictionary comprehensions for constructing dictionaries from iterables, a concise and readable approach that leverages Python’s expressive syntax for collections.
NUMBERS = [1, 2, 3]
# +1: [consider-using-dict-comprehension]
DOUBLED_NUMBERS = dict([(number, number * 2) for number in NUMBERS])
Suggests using direct imports (from module import symbol) instead of importing the entire module, which can make the code clearer by specifying exactly which symbols are needed from a module.
import os.path as path # [consider-using-from-import]
Recommends using a generator expression instead of a list comprehension or similar construct when the resulting list is only iterated over, improving memory efficiency by generating items on the fly.
list([0 for y in list(range(10))]) # [consider-using-generator]
tuple([0 for y in list(range(10))]) # [consider-using-generator]
sum([y**2 for y in list(range(10))]) # [consider-using-generator]
max([y**2 for y in list(range(10))]) # [consider-using-generator]
min([y**2 for y in list(range(10))]) # [consider-using-generator]
Advises using the get method of dictionaries to retrieve values, providing a way to specify a default value if the key is not found, simplifying code and avoiding KeyError exceptions.
knights = {"Gallahad": "the pure", "Robin": "the brave"}
if "Gallahad" in knights: # [consider-using-get]
DESCRIPTION = knights["Gallahad"]
else:
DESCRIPTION = ""
Suggests simplifying multiple comparison operations with a sequence of values by using the in operator, enhancing code readability and conciseness, especially when the sequence elements are hashable and a set can be used for efficiency..
def fruit_is_round(fruit):
# +1: [consider-using-in]
return fruit == "apple" or fruit == "orange" or fruit == "melon"
Recommends using str.join(sequence) for concatenating strings from an iterable, which is more efficient and idiomatic than concatenating strings in a loop, especially for larger sequences or when building output from multiple strings.
def fruits_to_string(fruits):
formatted_fruit = ""
for fruit in fruits:
formatted_fruit += fruit # [consider-using-join]
return formatted_fruit
print(fruits_to_string(["apple", "pear", "peach"]))
Recommends using the ‘max’ builtin function for obtaining the maximum value instead of using an if-else block, simplifying the code and leveraging Python’s built-in functions for cleaner and more efficient expressions.
def get_max(value1, value2):
if value1 < value2: # [consider-using-max-builtin]
value1 = value2
return value1
print(get_max(1, 2))
Similar to the above, suggests using the ‘min’ builtin function to find the minimum value rather than an if-else block, improving code readability and efficiency by utilizing Python’s concise and expressive built-in capabilities.
def get_min(value1, value2):
if value1 > value2: # [consider-using-min-builtin]
value1 = value2
return value1
print(get_min(1, 2))
Advises the use of namedtuple or dataclass for collections of data that require more structure and readability than a simple tuple or dictionary, enhancing code readability and maintainability with minimal boilerplate.
FELIDAES = { # [consider-using-namedtuple-or-dataclass]
"The queen's cymric, fragile furry friend": {
"tail_length_cm": 1,
"paws": 4,
"eyes": 2,
"Elizabethan collar": 1,
},
"Rackat the red, terror of the sea": {
"tail_length_cm": 13,
"paws": 3,
"eyes": 1,
"Red Hat": 1,
},
}
Recommends using set comprehensions for creating sets from iterables, a concise and expressive feature that improves code readability and succinctness while leveraging Python’s powerful comprehension syntax.
NUMBERS = [1, 2, 2, 3, 4, 4]
# +1: [consider-using-set-comprehension]
UNIQUE_EVEN_NUMBERS = set([number for number in NUMBERS if number % 2 == 0])
Suggests using ‘sys.exit’ to exit a script when needed, providing a clear and explicit exit point that can convey exit status information to the operating system, enhancing script robustness and control flow clarity.
if __name__ == "__main__":
user = input("Enter user name: ")
print(f"Hello, {user}")
exit(0) # [consider-using-sys-exit]
Encourages the use of ternary operators for concise conditional assignments or return statements, improving code compactness and readability by reducing the need for more verbose if-else structures.
x, y = 1, 2
maximum = x >= y and x or y # [consider-using-ternary]
Recommends using tuples for fixed collections of items, highlighting tuples’ immutability and potential performance benefits for use cases where the collection’s size and content will not change.
for i in [1, 2, 3]: # [consider-using-tuple]
print(i)
Advises the use of the ‘with’ statement for managing resource allocation and deallocation, especially for file operations or similar resource-intensive processes, to ensure resources are properly managed and released, reducing the risk of leaks.
Flags instances of cyclic imports, where two or more modules import each other directly or indirectly, potentially leading to import errors or unexpected behavior, suggesting reorganization to eliminate the cyclic dependency.
Warns about similar code blocks across different files, suggesting potential for refactoring into shared functions or modules to reduce redundancy and improve maintainability by adhering to the DRY (Don’t Repeat Yourself) principle.
Highlights an else block immediately followed by an if statement, suggesting the use of elif for clarity and to consolidate conditional branches into a more readable and concise structure.
if input():
pass
else:
if len(input()) >= 10: # [else-if-used]
pass
else:
pass
Flags comments that contain no text, which can clutter the code without providing value, suggesting removal or addition of meaningful commentary to improve code documentation and readability.
# +1:[empty-comment]
#
# +1:[empty-comment]
x = 0 #
Indicates a function where some return statements return a value while others do not, leading to potential confusion about the function’s expected behavior and return type, recommending consistency across return statements.
def get_the_answer(value: str) str | None: # [inconsistent-return-statements]
if value:
return value
Advises against comparing literals in a manner that could be simplified or made more direct, enhancing code clarity and efficiency by using straightforward comparisons, especially for boolean or None checks.
def is_an_orange(fruit):
return fruit is "orange" # [literal-comparison]
Flags comparisons against ‘magic’ values, which are hard-coded numbers or strings that may not have clear meaning. Refactoring to use named constants instead of magic values improves code readability, maintainability, and reduces the risk of errors by providing context for these values.
import random
measurement = random.randint(0, 200)
above_threshold = False
i = 0
while i < 5: # [magic-value-comparison]
above_threshold = measurement > 100 # [magic-value-comparison]
if above_threshold:
break
measurement = random.randint(0, 200)
Indicates the manual conversion of a method to a class method using the classmethod() function instead of the @classmethod decorator. Using the decorator enhances readability, clearly signaling the method’s intended usage at a glance and adhering to Pythonic conventions.
class Fruit:
COLORS = []
def __init__(self, color):
self.color = color
def pick_colors(cls, *args):
"""classmethod to pick fruit colors"""
cls.COLORS = args
pick_colors = classmethod(pick_colors) # [no-classmethod-decorator]
Highlights unnecessary ‘else’ blocks following a ‘break’ in loops. Removing these ‘else’ blocks simplifies the control flow, making the code easier to read and understand by reducing unnecessary nesting and highlighting the primary path through the code.
def next_seven_elements(iterator):
for i, item in enumerate(iterator):
if i == 7: # [no-else-break]
break
else:
yield item
Flags redundant ‘else’ blocks after a ‘continue’ statement in loops. Since ‘continue’ already skips to the next iteration, the ‘else’ is superfluous and removing it can streamline the loop structure, enhancing code clarity.
def even_number_under(n: int):
for i in range(n):
if i % 2 == 1: # [no-else-continue]
continue
else:
yield i
Points out unnecessary ‘else’ blocks that follow a ‘raise’ statement. Since ‘raise’ exits the block, the ‘else’ is not needed. Simplifying by removing these blocks can make exception-raising logic clearer and more direct.
def integer_sum(a: int, b: int) int:
if not (isinstance(a, int) and isinstance(b, int)): # [no-else-raise]
raise ValueError("Function supports only integer parameters.")
else:
return a + b
Warns against ‘else’ blocks that come after a ‘return’ statement in functions. Since ‘return’ exits the function, the ‘else’ serves no purpose and removing it can make the function’s return logic simpler and more readable.
def compare_numbers(a: int, b: int) int:
if a == b: # [no-else-return]
return 0
elif a < b:
return -1
else:
return 1
Identifies instance methods that do not use the instance (self), suggesting they could be static methods. Converting these methods improves code organization by correctly categorizing methods that don’t rely on instance state, potentially leading to better performance and reduced memory usage.
Similar to the classmethod decorator issue, this rule indicates the use of the staticmethod() function instead of the @staticmethod decorator. Using the decorator is more Pythonic and improves the readability by clearly indicating the method’s static nature.
class Worm:
def bore(self):
pass
bore = staticmethod(bore) # [no-staticmethod-decorator]
Suggests using typing.NamedTuple for more readable, maintainable, and concise type annotations. This approach leverages the type hinting system in Python, making code more self-documenting and type checks more powerful.
from collections import namedtuple
Philosophy = namedtuple( # [prefer-typing-namedtuple]
"Philosophy", ("goodness", "truth", "beauty")
)
Flags the attempt to define properties with parameters, which is not supported. Properties should be simple and parameter-free to maintain the clarity of the API and ensure they are used correctly.
class Worm:
@property
def bore(self, depth): # [property-with-parameters]
pass
Indicates that a function argument is redefined within the function’s body, which can lead to confusion and errors. Keeping argument names unique within a function’s scope enhances clarity and prevents unintended shadowing.
def show(host_id=10.11):
# +1: [redefined-argument-from-local]
for host_id, host in [[12.13, "Venus"], [14.15, "Mars"]]:
print(host_id, host)
Warns about changing the type of a variable within the same scope, which can lead to confusion and bugs. Maintaining consistent variable types aids readability and predictability.
x = 1
x = "2" # [redefined-variable-type]
Highlights type hints that are unnecessary or redundant, suggesting simplification. Removing redundant type hints keeps the codebase clean and focused on meaningful annotations, enhancing readability.
from typing import Union
sweet_count: Union[int, str, int] = 42 # [redundant-typehint-argument]
Flags complex boolean conditions that can be simplified, recommending more concise expressions. Simplifying conditions improves readability, making the code easier to follow and potentially enhancing performance by reducing complexity.
def has_apples(apples) bool:
return bool(apples or False) # [simplifiable-condition]
Identifies ‘if’ expressions that can be simplified, enhancing code readability and maintainability by reducing unnecessary complexity and making the code more concise.
FLYING_THINGS = ["bird", "plane", "superman", "this example"]
def is_flying_thing(an_object):
return True if an_object in FLYING_THINGS else False # [simplifiable-if-expression]
def is_not_flying_thing(an_object):
return False if an_object in FLYING_THINGS else True # [simplifiable-if-expression]
Flags ‘if’ statements that can be streamlined into more concise expressions, improving readability and efficiency by eliminating redundant logic structures.
FLYING_THINGS = ["bird", "plane", "superman", "this example"]
def is_flying_animal(an_object):
# +1: [simplifiable-if-statement]
if isinstance(an_object, Animal) and an_object in FLYING_THINGS:
is_flying = True
else:
is_flying = False
return is_flying
Points out complex boolean expressions that can be simplified, making the code easier to understand and maintain by clarifying logical operations and conditions.
def has_oranges(oranges, apples=None) bool:
return apples and False or oranges # [simplify-boolean-expression]
Advises against raising StopIteration in a generator, recommending a return statement instead. This change enhances clarity and conforms to best practices in Python 3, preventing potential runtime errors.
Suggests using the argument-less super() call available in Python 3, which simplifies inheritance by automatically determining the context, improving code readability and reducing boilerplate.
class Fruit:
pass
class Orange(Fruit):
def __init__(self):
super(Orange, self).__init__() # [super-with-arguments]
Indicates code with high complexity, suggesting refactoring to simplify logic and improve maintainability. Simplifying complex code can enhance readability, make it easier to test, and reduce the likelihood of bugs.
def fifty_percent_off(whole):
return (float(whole)) * 50 / 100
def calculate_sum_and_display_price_of_fruits(*fruits): # [too-complex]
# McCabe rating is 13 here (by default 10)
shopping_list = []
if "apple" in fruits:
v = fifty_percent_off(1.1)
shopping_list.append(v)
if "pear" in fruits:
shopping_list.append(0.8)
if "banana" in fruits:
shopping_list.append(1.2)
if "mango" in fruits:
shopping_list.append(3.5)
if "peach" in fruits:
shopping_list.append(0.5)
if "melon" in fruits:
shopping_list.append(4.9)
if "orange" in fruits:
shopping_list.append(2.0)
if "strawberry" in fruits:
shopping_list.append(2.5)
if "mandarin" in fruits:
shopping_list.append(2.3)
if "plum" in fruits:
shopping_list.append(0.5)
if "watermelon" in fruits:
v = fifty_percent_off(6.4)
shopping_list.append(v)
combine = zip(fruits, shopping_list)
for i in combine:
print(f"{i[0]} ${i[1]:.2f}")
total = sum(shopping_list)
print(f"Total price is ${total:.2f}")
fruits_to_buy = ["apple", "orange", "watermelon"]
calculate_sum_and_display_price_of_fruits(*fruits_to_buy)
Flags classes with fewer public methods than a defined threshold, questioning the class’s utility or suggesting its potential reimplementation as a function or aggregation into another class.
Warns about classes that inherit from too many parent classes, complicating the inheritance hierarchy. Simplifying these relationships can improve code readability and object model clarity.
class Animal: ...
class BeakyAnimal(Animal): ...
class FurryAnimal(Animal): ...
class Swimmer(Animal): ...
class EggLayer(Animal): ...
class VenomousAnimal(Animal): ...
class ProtectedSpecie(Animal): ...
class BeaverTailedAnimal(Animal): ...
class Vertebrate(Animal): ...
# max of 7 by default, can be configured
# each edge of a diamond inheritance counts
class Playtypus( # [too-many-ancestors]
BeakyAnimal,
FurryAnimal,
Swimmer,
EggLayer,
VenomousAnimal,
ProtectedSpecie,
BeaverTailedAnimal,
Vertebrate,
):
pass
Highlights functions or methods with more arguments than recommended, suggesting refactoring to reduce parameter count, which can enhance readability and usability.
def three_d_chess_move( # [too-many-arguments]
x_white,
y_white,
z_white,
piece_white,
x_black,
y_black,
z_black,
piece_black,
x_blue,
y_blue,
z_blue,
piece_blue,
current_player,
):
pass
Flags ‘if’ statements containing more boolean expressions than recommended, suggesting simplification to improve logic clarity and reduce cognitive load.
def can_be_divided_by_two_and_are_not_zero(x, y, z):
# Maximum number of boolean expressions in an if statement (by default 5)
# +1: [too-many-boolean-expressions]
if (x and y and z) and (x % 2 == 0 and y % 2 == 0 and z % 2 == 0):
pass
Points out functions with too many conditional branches, recommending refactoring to simplify control flow and enhance the function’s readability and maintainability.
def num_to_word(x): # [too-many-branches]
if x == 0:
return "zero"
elif x == 1:
return "one"
elif x == 2:
return "two"
elif x == 3:
return "three"
elif x == 4:
return "four"
elif x == 5:
return "five"
elif x == 6:
return "six"
elif x == 7:
return "seven"
elif x == 8:
return "eight"
elif x == 9:
return "nine"
else:
return None
Indicates classes with more instance attributes than recommended, suggesting potential for simplifying class design by reevaluating the class’s responsibilities and structure.
class Fruit: # [too-many-instance-attributes]
def __init__(self):
# max of 7 attributes by default, can be configured
self.worm_name = "Jimmy"
self.worm_type = "Codling Moths"
self.worm_color = "light brown"
self.fruit_name = "Little Apple"
self.fruit_color = "Bright red"
self.fruit_vitamins = ["A", "B1"]
self.fruit_antioxidants = None
self.secondary_worm_name = "Kim"
self.secondary_worm_type = "Apple maggot"
self.secondary_worm_color = "Whitish"
Flags functions with a high number of local variables, recommending refactoring to reduce complexity, potentially by splitting the function into smaller, more focused functions.
from childhood import Child, Sweet
def handle_sweets(infos): # [too-many-locals]
# Create children
children = [Child(info) for info in infos]
number_of_sweets = 87
sweets = [Sweet() * number_of_sweets]
number_of_sweet_per_child = 5
money = 45.0
sweets_given = 0
time_to_eat_sweet = 54
price_of_sweet = 0.42
# distribute sweet
for child in children:
sweets_given += number_of_sweet_per_child
child.give(sweets[number_of_sweet_per_child:])
# calculate prices
cost_of_children = sweets_given * price_of_sweet
# Calculate remaining money
remaining_money = money - cost_of_children
# Calculate time it took
time_it_took_assuming_parallel_eating = (
time_to_eat_sweet * number_of_sweet_per_child
)
print(
f"{children} ate {cost_of_children}¤ of sweets in {time_it_took_assuming_parallel_eating}, "
f"you still have {remaining_money}"
)
Warns about excessive nesting in code blocks, which can make code difficult to follow. Flattening these structures can enhance readability and simplify logic.
def correct_fruits(fruits):
if len(fruits) > 1: # [too-many-nested-blocks]
if "apple" in fruits:
if "orange" in fruits:
count = fruits["orange"]
if count % 2:
if "kiwi" in fruits:
if count == 2:
return True
return False
Indicates classes with more public methods than recommended, suggesting a review of the class’s design for potential simplification by splitting responsibilities.
class SpaceInvaders: # [too-many-public-methods]
def __init__(self):
pass
def fire_laser_beam(self):
pass
def deploy_shield(self):
pass
def launch_missile(self):
pass
def activate_super_laser(self):
pass
def summon_mothership(self):
pass
def destroy_planet(self):
pass
def teleport(self):
pass
def invoke_aliens(self):
pass
def invade_earth(self):
pass
def takeover_galaxy(self):
pass
Highlights functions with more return statements than recommended, suggesting that simplifying the function’s logic could improve readability and flow.
def to_string(x): # [too-many-return-statements]
# max of 6 by default, can be configured
if x == 1:
return "This is one."
if x == 2:
return "This is two."
if x == 3:
return "This is three."
if x == 4:
return "This is four."
if x == 5:
return "This is five."
if x == 6:
return "This is six."
if x == 7:
return "This is seven."
Flags functions containing more statements than recommended, indicating potential for refactoring to break down complex functions into smaller, more manageable pieces.
import random
def distribute_candies( # [too-many-statements]
children: list[Child], candies_per_child: int
):
# This function is a masterpiece of code that embodies the epitome of efficiency
# it's also an essential part of a high-priority project with extremely tight deadlines
# and there is absolutely no time to refactor it to make it more concise.
# The lead developer on the project, who has decades of experience,
# has personally reviewed this implementation and deemed it good enough as it is.
# The person writing this code has a demanding job and multiple responsibilities,
# and simply does not have the luxury of spending time making this code more readable.
total_candies = len(children) * candies_per_child
eaten_candies = 0
# Counting candies given to each child
for child in children:
# If a child eat more than 1 candies they're going to eat all
# the candies for sure
eaten_for_child = random.choices([0, 1, candies_per_child])
print(
f"Child {child} gets {candies_per_child} candies and eat {eaten_for_child}"
)
remaining_candies_for_children = child.eat_candies(eaten_for_child)
if remaining_candies_for_children == 0:
print(f"All the candies have been devoured by {child.name}!")
else:
print(
f"{child.name} still have {remaining_candies_for_children} candies left."
)
eaten_candies += eaten_for_child
return eaten_candies, total_candies
Highlights tuples created with a trailing comma, which might be mistaken for a tuple with multiple items. Removing unnecessary commas can avoid confusion and make the code clearer.
COMPASS = "north", "south", "east", "west", # [trailing-comma-tuple]
Points out the use of a comprehension where a simpler constructor or function could achieve the same result, enhancing code simplicity and readability by using more direct methods.
NUMBERS = [1, 1, 2, 2, 3, 3]
UNIQUE_NUMBERS = {number for number in NUMBERS} # [unnecessary-comprehension]
Identifies instances where dictionary keys are accessed to retrieve values in a way that could be simplified, recommending more direct methods for accessing values to improve code efficiency and readability.
FRUITS = {"apple": 1, "orange": 10, "berry": 22}
for fruit_name, fruit_count in FRUITS.items():
print(FRUITS[fruit_name]) # [unnecessary-dict-index-lookup]
Flags unnecessary retrieval of list items by index in contexts where a simpler approach could be used, suggesting improvements for code simplicity and performance.
letters = ["a", "b", "c"]
for index, letter in enumerate(letters):
print(letters[index]) # [unnecessary-list-index-lookup]
Recommends using a generator expression instead of a more verbose construct for creating iterators, improving memory efficiency and code readability by lazily generating items.
from random import randint
all([randint(-5, 5) > 0 for _ in range(10)]) # [use-a-generator]
any([randint(-5, 5) > 0 for _ in range(10)]) # [use-a-generator]
Suggests using the dictionary literal instead of the dict() constructor for initializing dictionaries, enhancing code conciseness and clarity.
Advises using the list literal [] over list() for creating empty lists, promoting code clarity and aligning with Pythonic best practices for simplicity.
empty_list = list() # [use-list-literal]
Recommends using a set for membership tests instead of a list or tuple, especially when dealing with large collections, to improve performance by leveraging the efficiency of hash-based lookups.
def fruit_is_dangerous_for_cat(fruit: str) bool:
"""This list is only a silly example, don't make decision regarding your cat diet based on it."""
return fruit in ["cherry", "grapes"] # [use-set-for-membership]
Indicates a class explicitly inherits from object, which is unnecessary in Python 3 and can be removed for simplicity and to adhere to modern Python class definitions.
class Banana(object): # [useless-object-inheritance]
...
Flags configuration options that are set to ineffective or redundant values, suggesting a review and cleanup of configuration settings for clarity and effectiveness.
"""'bad-continuation' was removed from pylint in https://github.com/pylint-dev/pylint/pull/3571"""
# pylint: disable=bad-continuation # [useless-option-value]
Highlights return statements at the end of functions that don’t return a value, which can be omitted for simplicity and to avoid implying that the function is expected to return a value.
import sys
def print_python_version(): # [useless-return]
print(sys.version)
return None
Identifies methods that do not use their self parameter, suggesting they could be static in older codebases, which can improve organization and potentially reduce memory usage.
Flags if statements in older code that can be simplified, recommending more concise and readable alternatives to improve code maintainability and clarity.
Warns about excessive nesting in older code, suggesting refactoring to reduce complexity and improve readability by flattening deeply nested structures.
This rule advises against using a bare except clause in a try-except block, which can catch and suppress unexpected exceptions, making it difficult to diagnose and handle errors. Instead, it recommends using specific exception types or handling exceptions explicitly to ensure that errors are appropriately managed and communicated.
try:
some_important_code()
except:
raise "Retry"
This rule suggests simplifying repeated if statements by combining them into a single condition. This can make the code more concise and easier to understand, reducing redundancy and improving readability.
if x < 5 and y < 10:
grid = range(10)
if x < 5 and y < 100:
grid = range(100)
This rule advises using the get method for dictionary lookups with default values instead of using the in operator to check for the key and then accessing the value directly. Using get can make the code more concise and readable, and it can be more efficient by avoiding redundant dictionary lookups.
if self.favourite_hat in available_hats:
hat_to_wear = available_hats[self.favourite_hat]
else:
hat_to_wear = NO_HAT
This rule suggests using the in operator to check for the presence of an element in a collection instead of using the any function with a generator expression. Using the in operator can make the code more concise and readable, and it can be more efficient by short-circuiting the iteration when the element is found.
if any(hat == "bowler" for hat in hats):
shout("I have a bowler hat!")
This rule suggests inverting the use of any and all functions by applying De Morgan’s laws. This can make the code more concise and readable, and it can be more efficient by short-circuiting the iteration when the condition is met.
b = not all(a > b for a in things)
This rule suggests merging multiple except clauses that have the same handler into a single clause. This can make the code more concise and easier to understand, reducing redundancy and improving readability.
try:
f = open("myfile.txt")
s = f.readline()
i = int(s.strip())
except OSError as err:
logger.exception("Error while reading myfile.txt")
raise
except ValueError as err:
logger.exception("Error while reading myfile.txt")
raise
Flags variables that are declared but not used, helping to identify potential errors or unnecessary code, improving code readability and efficiency.
function example() {
var unused = "This text is not used";
console.log("Hello World");
}
Enforces the use of strict equality operators (=== and !==) over the abstract equality operators (== and !=) to avoid type coercion errors, ensuring more predictable and safer code.
if (x == y) {
// do something
}
Encourages the use of let or const instead of var to improve code readability and reduce scope-related errors by using block-scoped variables.
var x = "Hello World";
Disallows catch clauses that only rethrow the caught error, encouraging more efficient error handling by either handling the error or allowing it to bubble up naturally.
try {
doSomething();
} catch (e) {
throw e;
}
Identifies unnecessary string concatenations, promoting the use of template literals or simpler expressions for better readability and performance.
var fullName = "John " + "Doe";
Suggests using const for variables that are never reassigned after their initial declaration, indicating to readers that their values remain constant, which enhances code clarity and reliability.
let x = 10;
Favors arrow functions as callbacks to utilize their concise syntax and lexical this binding, leading to cleaner and more understandable code.
arr.map(function(item) { return item * 2; });
Enforces sorting of import statements to improve code readability and maintainability by making it easier to visually inspect and manage dependencies.
import b from 'foo.js';
import a from 'bar.js';
Flags ternary operators that could be simplified to simpler expressions, promoting cleaner and more direct code by avoiding unnecessary complexity.
var isAdult = age > 18 ? true : false;
Previously required React to be in scope when using JSX, but this is turned off to accommodate new JSX transforms that do not require React to be explicitly imported.
Ensures that callback functions for array methods like map, filter, and reduce return a value, preventing unexpected behavior and bugs in array transformations.
var indexMap = myArray.reduce(function(memo, item, index) {
memo[item] = index;
}, {});
Encourages the use of logical assignment operators to concisely perform logical operations and assignments in one step, enhancing code brevity and readability.
if (!x) x = y;
Prevents floating decimals without a leading zero, which can make the code harder to read and lead to potential misunderstandings, ensuring numeric values are clearly defined.
var num = .5;
Disallows returning values from the executor function of a new Promise, which can lead to confusing and possibly ignored returns, ensuring the executor is used for its intended purpose of resolving or rejecting the promise.
new Promise((resolve, reject) => {
return 'result';
});
Discourages unnecessary use of await inside return statements, which can lead to extra microtask queue jumps and potentially affect performance, simplifying asynchronous control flow.
async function foo() {
return await bar();
}
Disallows initializing variables to undefined, as it is unnecessary and can lead to confusion, promoting cleaner and more intentional variable declarations.
var x = undefined;
Disallows renaming import, export, and destructured assignments to the same name, reducing redundancy and improving code readability and maintainability.
import { foo as foo } from 'bar';
Enforces the correct usage of useState hook, ensuring state is managed consistently and effectively in React functional components.
import React from 'react';
export default function useColor() {
// useState call is not destructured into value + setter pair
const useStateResult = React.useState();
return useStateResult;
}
export default function useColor() {
// useState call is destructured into value + setter pair, but identifier
// names do not follow the [thing, setThing] naming convention
const [color, updateColor] = React.useState();
return useStateResult;
}
Aims to prevent memory leaks in React components by ensuring JSX elements do not inadvertently retain state or props that could lead to leaks, promoting better resource management and component reliability.
function ItemList({ items }) {
return (
<div>
{items.map((item) => (
<div>
{item.name}
{item.count && <span>Count: {item.count}</span>}
</div>
))}
</div>
);
}
Overly complicated regular expressions are hard to read and to maintain and can easily cause hard-to-find bugs. If a regex is too complicated, you should consider replacing it or parts of it with regular code or splitting it apart into multiple patterns at least.
The complexity of a regular expression is determined as follows:
Each of the following operators increases the complexity by an amount equal to the current nesting level and also increases the current nesting level by one for its arguments:
`| - when multiple | operators are used together, the subsequent ones only increase the complexity by 1
Quantifiers (*, +, ?, etc.)
Non-capturing groups that set flags (such as (?i:some_pattern) or (?i)some_pattern`)
Lookahead and lookbehind assertions
Additionally, each use of the following features increase the complexity by 1 regardless of nesting:
character classes
back references
p = re.compile(r"^(?:(?:31(\/|-|\.)(?:0?[13578]|1[02]))\1|(?:(?:29|30)(\/|-|\.)(?:0?[13-9]|1[0-2])\2))(?:(?:1[6-9]|[2-9]\d)?\d{2})$|^(?:29(\/|-|\.)0?2\3(?:(?:(?:1[6-9]|[2-9]\d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00))))$|^(?:0?[1-9]|1\d|2[0-8])(\/|-|\.)(?:(?:0?[1-9])|(?:1[0-2]))\4(?:(?:1[6-9]|[2-9]\d)?\d{2})$")
if p.match($dateString):
handleDate($dateString)
Jump statements, such as return, break and continue
let you change the default flow of program execution, but jump statements that direct the control flow to the original direction are just a waste of keystrokes.
def redundant_jump(x):
if x == 1:
print(True)
return # NonCompliant
Classes subclassing only `unittest.TestCase are considered test cases, otherwise they might be mixins.
As classes subclassing unittest.TestCase will be executed as tests, they should define test methods and not be used as “abstract” parent helper. Methods within the class will be discovered by the test runner if their name starts with test. If a method intended to be a test does not respect this convention, it will not be executed.
This rule raises an issue when a method is not discoverable as a test and is never used within its test case class.
This rule will not raise if:
The method is called directly from another method.
The method overrides an existing one in unittest.TestCase (example: a tearDown` method).
import unittest
class MyTest(unittest.TestCase):
def setUp(self): ... # OK (unittest.TestCase method)
def something_test(self): ... # Noncompliant
Functions that use yield are known as “generators”. Before Python 3.3, generators cannot return values. Similarly, functions that use return cannot use yield. Doing so will cause a SyntaxError
.
Either upgrade your version of Python to a version >= 3.3, or don’t use both return and yield in a function.
def adder(n):
num = 0
while num < n:
yield num
num += 1
return num #Noncompliant
Python 3.9 introduced built-in generic types such as list[T], dict[T], set[T] to make type hints more concise and easier to read. These built-in types have the same functionality as their counterparts in the typing module, but are more readable and idiomatic.
Using types such as typing.List is confusing in the presence of the already existing built-in types. This can also create inconsistencies when different parts of the codebase use different syntaxes for the same type.
import typing
def print_numbers(numbers: typing.List[int]) None:
for n in numbers:
print(n)
The `len special method enables to define the length of an object. As such it should always return an integer greater than or equal to 0. When the len(…) builtin is called on an object, any other return type will raise a TypeError and a negative integer will raise a ValueError.
This rule raises an issue when a len` method returns an expression which is not an integer greater than or equal to 0.
class A:
def __len__(self):
return 2.0 # Noncompliant
len(A()) # This will raise "TypeError: 'float' object cannot be interpreted as an integer"
class B:
def __len__(self):
return -2 # Noncompliant
len(B()) # This will raise "ValueError: __len__() should return >= 0"
Server-side template injections occur in an application when the application retrieves data from a user or a third-party service and inserts it into a template, without sanitizing it first.
If an application contains a template that is vulnerable to injections, it is exposed to attacks that target the underlying rendering server.
A user with malicious intent can create requests that will cause the template to change its logic into unwanted behavior.
After creating the malicious request, the attacker can attack the servers affected by this vulnerability without relying on any prerequisites.
from flask import request, render_template_string
@app.route('/example')
def example():
username = request.args.get('username')
template = f"<p>Hello {username}</p>"
return render_template_string(template) # Noncompliant
Data science and machine learning tasks make extensive use of random number generation. It may, for example, be used for:
Model initialization
Randomness is used to initialize the parameters of machine learning models. Initializing parameters with random values helps to break symmetry and prevents models from getting stuck in local optima during training. By providing a random starting point, the model can explore different regions of the parameter space and potentially find better solutions.
Regularization techniques
Randomness is used to introduce noise into the learning process. Techniques like dropout and data augmentation use random numbers to randomly drop or modify features or samples during training. This helps to regularize the model, reduce overfitting, and improve generalization performance.
Cross-validation and bootstrapping
Randomness is often used in techniques like cross-validation, where data is split into multiple subsets. By using a predictable seed, the same data splits can be generated, allowing for fair and consistent model evaluation.
Hyperparameter tuning
Many machine learning algorithms have hyperparameters that need to be tuned for optimal performance. Randomness is often used in techniques like random search or Bayesian optimization to explore the hyperparameter space. By using a fixed seed, the same set of hyperparameters can be explored, making the tuning process more controlled and reproducible.
Simulation and synthetic data generation
Randomness is often used in techniques such as data augmentation and synthetic data generation to generate diverse and realistic datasets.
To ensure that results are reproducible, it is important to use a predictable seed in this context.
The preferred way to do this in numpy is by instantiating a Generator object, typically through numpy.random.default_rng, which should be provided with a seed parameter.
Note that a global seed for RandomState can be set using numpy.random.seed or numpy.seed, this will set the seed for RandomState methods such as numpy.random.randn. This approach is, however, deprecated and Generator should be used instead. This is reported by rule S6711.
import numpy as np
def foo():
generator = np.random.default_rng() # Noncompliant: no seed parameter is provided
x = generator.uniform()
The pandas library provides many ways to filter, select, reshape and modify a data frame.
Pandas supports as well method chaining, which means that many DataFrame methods return a modified DataFrame
.
This allows the user to chain multiple operations together, making it effortless perform several of them in one line of code:
import pandas as pd
schema = {'name':str, 'domain': str, 'revenue': 'Int64'}
joe = pd.read_csv("data.csv", dtype=schema).set_index('name').filter(like='joe', axis=0).groupby('domain').mean().round().sample()
The all property of a module is used to define the list of names that will be imported when performing a wildcard import of this module, i.e. when from mymodule import *
is used.
In the following example:
# mymodule.py
def foo(): ...
def bar(): ...
__all__ = ["foo"]
Prior to Python 3.12, generic type aliases were defined as follows:
from typing import TypeAlias, TypeVar
_T = TypeVar("_T")
MyAlias: TypeAlias = set[_T]
Python sides effects such as printing, mutating a list or a global variable, inside of a tensorflow.function may not behave as expected. Because of the Rules of tracing, the execution of side effects will depend on the input values of the function and will execute only once per tracing.
import tensorflow as tf
@tf.function
def f(x):
print("A side effect", x)
f(1) # prints "A side effect 1"
f(1) # does not print anything
f(2) # prints "A side effect 2"
Unlike class and instance methods, static methods don’t receive an implicit first argument. Nonetheless naming the first argument self or clz
guarantees confusion - either on the part of the original author, who may never understand why the arguments don’t hold the values he expected, or on that of future maintainers.
class MyClass:
@staticmethod
def s_meth(self, arg1, arg2): #Noncompliant
# ...
for-in loops, yield from and iterable unpacking only work with iterable objects. In order to be iterable, an object should have either an `iter method or a getitem method implementing the Sequence protocol.
When trying to iterate over an object which does not implement the required methods, a TypeError will be raised.
Below is an example of a basic implementation of a iterator with iter`:
class IterExample(object):
def __init__(self):
self._values = [1,2,3,4]
def __iter__(self):
return iter(self._values)
There are no constants in Python, but when a variable is named with all uppercase letters, the convention is to treat it as a constant. I.e. to use it as a read-only variable, and not reassign its value.
Ignore this convention, and you run the risk of confusing other developers, particularly those with experience in other languages. This rule raises an issue each time a variable named with all uppercase letters is reassigned.
RESOURCE_NAME = 'foo'
# ...
RESOURCE_NAME = 'bar' # Noncompliant
Objects can be used as sequence indexes to access a specific element from the sequence, through the following syntax:
my_list = [1, 2, 3, 4]
x = 1
print(my_list[x]) # This will print 2
Variables, Classes and functions should not be undefined, otherwise the code will fail with a NameError.
my_var # Noncompliant (variable is never defined)
def noncompliant():
foo() # Noncompliant
MyClass() # Noncompliant
Calling `unittest methods assertEqual, assertNotEqual, assertIs or assertIsNot on objects of incompatible types will always fail or always succeed.
For methods assertEqual and assertNotEqual, arguments’ types are incompatible if:
they are instances of unrelated classes which do not implement ++eq++ or ++ne++ (if a class implements one of these methods it could compare to any other type it wants).
As for methods assertIs and assertIsNot, if arguments’ types are different it is not possible for them to point to the same object, thus assertIs will always fail and assertIsNot` will always succeed.
import unittest
class A(): ...
class MyTest(unittest.TestCase):
def test_something(self):
a = A()
mydict = {"x": a}
self.assertEqual(a, "x") # Noncompliant
self.assertIs(a, "x") # Noncompliant
Dictionary unpacking allows you to pass the key-value pairs of a dictionary as keyword arguments to a function or merge dictionaries:
def foo(a, b):
print(a+b)
my_dict = {"a": 1, "b": 2}
foo(**my_dict) # will print 3
The operators <> and != are equivalent.
However, the <> operator is considered obsolete in Python 2.7 and
has been removed from Python 3. Therefore, it is recommended to use !=
instead.
return a <> b # Noncompliant: the operator "<>" is deprecated.
Through PEP 701, Python 3.12 lifts restrictions on how to construct “f-strings”.
Prior to Python 3.12, it was not possible to reuse string quotes when nesting “f-strings”. Therefore, the maximum level of nesting was:
f"""{f'''{f'{f"{1+1}"}'}'''}"""
When calling a tensorflow.function behind the scenes a ConcreteFunction is created everytime a new value is passed as argument. This is not the case with Python global variables, closure or nonlocal variables.
This means the state and the result of the tensorflow.function may not be what is expected.
import tensorflow as tf
@tf.function
def addition():
return 1 + foo
foo = 4
addition() # tf.Tensor(5, shape=(), dtype=int32): on this first step we obtain the expected result
foo = 10
addition() # tf.Tensor(5, shape=(), dtype=int32): unexpected result of 5 instead of 11
The raise a, b
syntax is deprecated in Python 3, and should no longer be used.
try:
if not is_okay:
raise Exception, 'It\'s not okay' # Noncompliant
except Exception as e:
# ...
Attempting to raise an object which does not derive from BaseException will raise a `TypeError.
If you are about to create a custom exception class, note that custom exceptions should inherit from Exception, rather than BaseException.
BaseException is the base class for all built-in exceptions in Python, including system-exiting exceptions like SystemExit or KeyboardInterrupt, which are typically not meant to be caught. On the other hand, Exception is intended for exceptions that are expected to be caught, which is generally the case for user-defined exceptions. See PEP 352 for more information.
To fix this issue, make sure that the object you’re attempting to raise inherits from BaseException`.
raise "Something went wrong" # Noncompliant: a string is not a valid exception
class A:
pass
raise A # Noncompliant: A does not inherit from Exception
Assigning a lambda to a variable is not inherently wrong or discouraged in Python. Lambdas are anonymous functions that can be useful for short and simple expressions or as function arguments. However, there are a few reasons why you might consider alternatives to assigning a lambda to a variable:
Readability and clarity: Lambdas can be concise, but they may become less readable as the expression or logic becomes more complex. For more complex or longer functions, using a regular named function defined with def can make the code more readable and self-explanatory.
Reusability: Lambdas are often used for one-off or small, isolated tasks. If you find that you need to reuse a piece of functionality in multiple places within your code or across modules, it is better to define a named function using def. This promotes code modularity and maintainability.
Documentation: Lambdas do not support docstrings, which are important for providing clear and comprehensive documentation for your functions. If you need to document the purpose, parameters, or behavior of a function, it is best to define a named function using def and include a docstring.
Debugging and error handling: Lambdas are anonymous functions, which means that when an error occurs during execution, the traceback will not provide a specific name associated with the lambda function. This can make it more challenging to identify and troubleshoot errors. Named functions defined with def provide more meaningful tracebacks.
Using a def statements rather than assigning lambdas to variable is also recommended by PEP8.
def foo():
multiply = lambda x, y: x * y # Noncompliant
Operators `in and not in, also called “membership test operators”, require that the right operand supports the membership protocol.
In order to support the membership protocol, a user-defined class should implement at least one of the following methods: contains, iter, getitem.
If none of these methods is implemented, a TypeError` will be raised when performing a membership test.
myint = 42
if 42 in myint: # Noncompliant: integers don't support membership protocol
...
class A:
def __init__(self, values):
self._values = values
if "mystring" in A(["mystring"]): # Noncompliant: class A doesn't support membership protocol
...
In NumPy, some built-in types such as int have aliases in the form of numpy.int. However, these aliases have been deprecated and should not be used anymore.
The following deprecated aliases should be replaced with their built-in alternatives:
Deprecated name | Equivalent built-in type |
---|---|
numpy.bool | bool |
numpy.int | int |
numpy.float | float |
numpy.complex | complex |
numpy.object | object |
numpy.str | str |
numpy.long | int |
numpy.unicode | str |
import numpy as np
def foo():
x = np.int(42) # Noncompliant: deprecated type alias
When working with timezones in Python, it’s important to understand that the datetime.datetime constructor and pytz timezone objects handle timezones differently. This difference can lead to unexpected results if a pytz object is used as the tzinfo argument in the datetime.datetime constructor.
The datetime.datetime constructor expects a tzinfo object that is a subclass of the datetime.tzinfo base class. pytz timezone objects do provide this interface, but they implement it in a way that’s not fully compatible with datetime.datetime.
One key difference is how they handle historical changes in timezone offsets. The datetime module uses the IANA time zone database, which includes historical changes.
When you create a datetime object with a pytz timezone object as the tzinfo argument, it uses the earliest known offset for that timezone. This can lead to unexpected offsets, as the earliest known offset may not match the current or most commonly used offset for that timezone.
For example, if you were to use ‘US/Eastern’ as your timezone, you might expect the offset to be either -5 hours (Eastern Standard Time) or -4 hours (Eastern Daylight Time), depending on the time of the year. However, due to historical changes, the actual offset might be something different, like -4 hours and 56 minutes. This can lead to subtle bugs in your code, especially if you’re doing calculations with datetime objects.
Note that, when using Python 3.9 and later, it is recommended to use the zoneinfo package from the standard library over pytz.
import datetime
import pytz
dt = datetime.datetime(2022, 1, 1, tzinfo=pytz.timezone('US/Eastern')) # Noncompliant: 2022-01-01 00:00:00-04:56
Methods enter and exit make it possible to implement objects which can be used as the expression of a with
statement:
with MyContextManager() as c :
... # do something with c