A plugin for flake8
finding likely bugs and design problems in your program. Contains warnings that don't belong in pyflakes
and pycodestyle
:
bug·bear (bŭg′bâr′) n. 1. A cause of fear, anxiety, or irritation: *Overcrowding is often a bugbear for train commuters.* 2. A difficult or persistent problem: *"One of the major bugbears of traditional AI is the difficulty of programming computers to recognize that different but similar objects are instances of the same type of thing" (Jack Copeland).* 3. A fearsome imaginary creature, especially one evoked to frighten children.
It is felt that these lints don't belong in the main Python tools as they are very opinionated and do not have a PEP or standard behind them. Due to flake8
being designed to be extensible, the original creators of these lints believed that a plugin was the best route. This has resulted in better development velocity for contributors and adaptive deployment for flake8
users.
Install from pip
with:
pip install flake8-bugbear
It will then automatically be run as part of flake8
; you can check it has been picked up with:
$ flake8 --version 3.5.0 (assertive: 1.0.1, flake8-bugbear: 18.2.0, flake8-comprehensions: 1.4.1, mccabe: 0.6.1, pycodestyle: 2.3.1, pyflakes: 1.6.0) CPython 3.7.0 on Darwin
If you'd like to do a PR we have development instructions here.
B001: Do not use bare except:
, it also catches unexpected events like memory errors, interrupts, system exit, and so on. Prefer except Exception:
. If you're sure what you're doing, be explicit and write except BaseException:
. Disable E722
to avoid duplicate warnings.
B002: Python does not support the unary prefix increment. Writing ++n
is equivalent to +(+(n))
, which equals n
. You meant n += 1
.
B003: Assigning to os.environ
doesn't clear the environment. Subprocesses are going to see outdated variables, in disagreement with the current process. Use os.environ.clear()
or the env=
argument to Popen.
B004: Using hasattr(x, '__call__')
to test if x
is callable is unreliable. If x
implements custom __getattr__
or its __call__
is itself not callable, you might get misleading results. Use callable(x)
for consistent results.
B005: Using .strip()
with multi-character strings is misleading the reader. It looks like stripping a substring. Move your character set to a constant if this is deliberate. Use .replace()
, .removeprefix()
, .removesuffix()
or regular expressions to remove string fragments.
B006: Do not use mutable data structures for argument defaults. They are created during function definition time. All calls to the function reuse this one instance of that data structure, persisting changes between them.
B007: Loop control variable not used within the loop body. If this is intended, start the name with an underscore.
B008: Do not perform function calls in argument defaults. The call is performed only once at function definition time. All calls to your function will reuse the result of that definition-time function call. If this is intended, assign the function call to a module-level variable and use that variable as a default value.
B009: Do not call getattr(x, 'attr')
, instead use normal property access: x.attr
. Missing a default to getattr
will cause an AttributeError
to be raised for non-existent properties. There is no additional safety in using getattr
if you know the attribute name ahead of time.
B010: Do not call setattr(x, 'attr', val)
, instead use normal property access: x.attr = val
. There is no additional safety in using setattr
if you know the attribute name ahead of time.
B011: Do not call assert False
since python -O
removes these calls. Instead callers should raise AssertionError()
.
B012: Use of break
, continue
or return
inside finally
blocks will silence exceptions or override return values from the try
or except
blocks. To silence an exception, do it explicitly in the except
block. To properly use a break
, continue
or return
refactor your code so these statements are not in the finally
block.
B013: A length-one tuple literal is redundant. Write except SomeError:
instead of except (SomeError,):
.
B014: Redundant exception types in except (Exception, TypeError):
. Write except Exception:
, which catches exactly the same exceptions.
B015: Pointless comparison. This comparison does nothing but waste CPU instructions. Either prepend assert
or remove it.
B016: Cannot raise a literal. Did you intend to return it or raise an Exception?
B017: assertRaises(Exception)
and pytest.raises(Exception)
should be considered evil. They can lead to your test passing even if the code being tested is never executed due to a typo. Assert for a more specific exception (builtin or custom), or use assertRaisesRegex
(if using assertRaises
), or add the match
keyword argument (if using pytest.raises
), or use the context manager form with a target (e.g. with self.assertRaises(Exception) as ex:
).
B018: Found useless expression. Either assign it to a variable or remove it. Note that dangling commas will cause things to be interpreted as useless tuples. For example, in the statement print(".."),
is the same as (print(".."),)
which is an unassigned tuple. Simply remove the comma to clear the error.
B019: Use of functools.lru_cache
or functools.cache
on methods can lead to memory leaks. The cache may retain instance references, preventing garbage collection.
B020: Loop control variable overrides iterable it iterates
B021: f-string used as docstring. This will be interpreted by python as a joined string rather than a docstring.
B022: No arguments passed to contextlib.suppress. No exceptions will be suppressed and therefore this context manager is redundant. N.B. this rule currently does not flag suppress calls to avoid potential false positives due to similarly named user-defined functions.
B023: Functions defined inside a loop must not use variables redefined in the loop, because late-binding closures are a classic gotcha.
B024: Abstract base class has methods, but none of them are abstract. This is not necessarily an error, but you might have forgotten to add the @abstractmethod decorator, potentially in conjunction with @classmethod, @property and/or @staticmethod.
B025: try-except
block with duplicate exceptions found. This check identifies exception types that are specified in multiple except
clauses. The first specification is the only one ever considered, so all others can be removed.
B026: Star-arg unpacking after a keyword argument is strongly discouraged, because it only works when the keyword parameter is declared after all parameters supplied by the unpacked sequence, and this change of ordering can surprise and mislead readers. There was cpython discussion of disallowing this syntax, but legacy usage and parser limitations make it difficult.
B027: Empty method in abstract base class, but has no abstract decorator. Consider adding @abstractmethod.
B028: No explicit stacklevel argument found. The warn method from the warnings module uses a stacklevel of 1 by default. This will only show a stack trace for the line on which the warn method is called. It is therefore recommended to use a stacklevel of 2 or greater to provide more information to the user. The check is skipped when skip_file_prefixes is used.
B029: Using except ():
with an empty tuple does not handle/catch anything. Add exceptions to handle.
B030: Except handlers should only be exception classes or tuples of exception classes.
B031: Using the generator returned from itertools.groupby() more than once will do nothing on the second usage. Save the result to a list if the result is needed multiple times.
B032: Possible unintentional type annotation (using :
). Did you mean to assign (using =
)?
B033: Sets should not contain duplicate items. Duplicate items will be replaced with a single item at runtime.
B034: Calls to re.sub, re.subn or re.split should pass flags or count/maxsplit as keyword arguments. It is commonly assumed that flags is the third positional parameter, forgetting about count/maxsplit, since many other re module functions are of the form f(pattern, string, flags).
B035: Found dict comprehension with a static key - either a constant value or variable not from the comprehension expression. This will result in a dict with a single key that was repeatedly overwritten.
B036: Found except BaseException:
without re-raising (no raise
in the top-level of the except
block). This catches all kinds of things (Exception, SystemExit, KeyboardInterrupt...) and may prevent a program from exiting as expected.
B037: Found return <value>
, yield
, yield <value>
, or yield from <value>
in class __init__()
method. No values should be returned or yielded, only bare return
s are ok.
B038: Moved to B909 - Found a mutation of a mutable loop iterable inside the loop body. Changes to the iterable of a loop such as calls to list.remove() or via del can cause unintended bugs.
B039: ContextVar
with mutable literal or function call as default. This is only evaluated once, and all subsequent calls to .get() would return the same instance of the default. This uses the same logic as B006 and B008, including ignoring values in extend-immutable-calls
.
B040: Caught exception with call to add_note
not used. Did you forget to raise
it?
B041: Repeated key-value pair in dictionary literal. Only emits errors when the key's value is also the same, being the opposite of the pyflakes like check.
B042: Remember to call super().__init__() in custom exceptions initalizer.
The following warnings are disabled by default because they are controversial. They may or may not apply to you, enable them explicitly in your configuration if you find them useful. Read below on how to enable.
B901: Using return x
in a generator function used to be syntactically invalid in Python 2. In Python 3 return x
can be used in a generator as a return value in conjunction with yield from
. Users coming from Python 2 may expect the old behavior which might lead to bugs. Use native async def
coroutines or mark intentional return x
usage with # noqa
on the same line.
B902: Invalid first argument used for method. Use self
for instance methods, and cls
for class methods (which includes __new__
and __init_subclass__
) or instance methods of metaclasses (detected as classes directly inheriting from type
).
B903: Use collections.namedtuple
(or typing.NamedTuple
) for data classes that only set attributes in an __init__
method, and do nothing else. If the attributes should be mutable, define the attributes in __slots__
to save per-instance memory and to prevent accidentally creating additional attributes on instances.
B904: Within an except
clause, raise exceptions with raise ... from err
or raise ... from None
to distinguish them from errors in exception handling. See the exception chaining tutorial for details.
B905: zip()
without an explicit strict= parameter set. strict=True
causes the resulting iterator to raise a ValueError
if the arguments are exhausted at differing lengths.
Exclusions are itertools.count, itertools.cycle and itertools.repeat (with times=None) since they are infinite iterators.
The strict=
argument was added in Python 3.10, so don't enable this flag for code that should work on <3.10. For more information: https://peps.python.org/pep-0618/
B906: visit_
function with no further call to a visit
function. This is often an error, and will stop the visitor from recursing into the subnodes of a visited node. Consider adding a call self.generic_visit(node)
at the end of the function. Will only trigger on function names where the part after visit_
is a valid ast
type with a non-empty _fields
attribute. This is meant to be enabled by developers writing visitors using the ast
module, such as flake8 plugin writers.
B907: Consider replacing f"'{foo}'"
with f"{foo!r}"
which is both easier to read and will escape quotes inside foo
if that would appear. The check tries to filter out any format specs that are invalid together with !r
. If you're using other conversion flags then e.g. f"'{foo!a}'"
can be replaced with f"{ascii(foo)!r}"
. Not currently implemented for python<3.8 or str.format()
calls.
B908: Contexts with exceptions assertions like with self.assertRaises
or with pytest.raises
should not have multiple top-level statements. Each statement should be in its own context. That way, the test ensures that the exception is raised only in the exact statement where you expect it.
B909: Was B038 - Found a mutation of a mutable loop iterable inside the loop body. Changes to the iterable of a loop such as calls to list.remove() or via del can cause unintended bugs.
B910: Use Counter() instead of defaultdict(int) to avoid excessive memory use as the default dict will record missing keys with the default value when accessed.
B911: itertools.batched()
without an explicit strict= parameter set. strict=True
causes the resulting iterator to raise a ValueError
if the final batch is shorter than n
.
The strict=
argument was added in Python 3.13, so don't enable this flag for code that should work on <3.13.
B912: map()
without an explicit strict= parameter set. strict=True
causes the resulting iterator to raise a ValueError
if the arguments are exhausted at differing lengths.
B950: Line too long. This is a pragmatic equivalent of pycodestyle
's E501
: it considers "max-line-length" but only triggers when the value has been exceeded by more than 10%. noqa
and type: ignore
comments are ignored. You will no longer be forced to reformat code due to the closing parenthesis being one character too far to satisfy the linter. At the same time, if you do significantly violate the line length, you will receive a message that states what the actual limit is. This is inspired by Raymond Hettinger's "Beyond PEP 8" talk and highway patrol not stopping you if you drive < 5mph too fast. Disable E501
to avoid duplicate warnings. Like E501
, this error ignores long shebangs on the first line and urls or paths that are on their own line:
#! long shebang ignored # https://some-super-long-domain-name.com/with/some/very/long/paths url = ( "https://some-super-long-domain-name.com/with/some/very/long/paths" )How to enable opinionated warnings
To enable Bugbear's opinionated checks (B9xx
), specify an --extend-select
command-line option or extend-select=
option in your config file (requires flake8 >=4.0
):
[flake8] max-line-length = 80 max-complexity = 12 ... extend-ignore = E501 extend-select = B950
Some of Bugbear's checks require other flake8
checks disabled - e.g. E501
must be disabled when enabling B950
.
If you'd like all optional warnings to be enabled for you (future proof your config!), say B9
instead of B950
. You will need flake8 >=3.2
for this feature.
For flake8 <=4.0
, you will need to use the --select
command-line option or select=
option in your config file. For flake8 >=3.0
, this option is a whitelist (checks not listed are implicitly disabled), so you have to explicitly specify all checks you want enabled (e.g. select = C,E,F,W,B,B950
).
The --extend-ignore
command-line option and extend-ignore=
config file option require flake8 >=3.6
. For older flake8
versions, the --ignore
and ignore=
options can be used. Using ignore
will override all codes that are disabled by default from all installed linters, so you will need to specify these codes in your configuration to silence them. I think this behavior is surprising so Bugbear's opinionated warnings require explicit selection.
Note: Bugbear's enforcement of explicit opinionated warning selection is deprecated and will be removed in a future release. It is recommended to use extend-ignore
and extend-select
in your flake8
configuration to avoid implicitly altering selected and/or ignored codes.
The plugin currently has the following settings:
extend-immutable-calls
: Specify a list of additional immutable calls. This could be useful, when using other libraries that provide more immutable calls, beside those already handled by flake8-bugbear
. Calls to these method will no longer raise a B008
or B039
warning.
classmethod-decorators
: Specify a list of decorators to additionally mark a method as a classmethod
as used by B902. The default only checks for classmethod
. When an @obj.name
decorator is specified it will match against either name
or obj.name
. This functions similarly to how pep8-naming <https://github.com/PyCQA/pep8-naming> handles it, but with different defaults, and they don't support specifying attributes such that a decorator will never match against a specified value obj.name
even if decorated with @obj.name
.
For example:
[flake8] max-line-length = 80 max-complexity = 12 ... extend-immutable-calls = pathlib.Path, Path classmethod-decorators = myclassmethod, mylibrary.otherclassmethod
Just run:
coverage run tests/test_bugbear.py
For linting:
pre-commit run -a
MIT
*args
or **kwargs
(#501)ContextVar
with mutable literal or function call as defaultraise
statements raising something other than a bare name (#450)except a[0].b:
)strip()
method on an imported module.visit_Bytes
, visit_Num
and visit_Str
to the list of visit_*
functions that are ignored by the B906 check. The ast.Bytes
, ast.Num
and ast.Str
nodes are all deprecated, but may still be used by some codebases in order to maintain backwards compatibility with Python 3.7.except
with an empty tuple i.e. except ():
.itertools.groupby()
is not used multiple times.pytest.raises()
has a match
argument. (#334)visit_
functions with a _fields
attribute that can't contain ast.AST subnodes. (#330)visit_
function with no further calls to a visit
function. (#313)!r
when formatted value in f-string is surrounded by quotes. (#319)binascii.Error
is now treated as a subclass of ValueError
(#206)raise
without from
in an except
clause (#181)except ():
except (..., ):
statementsignore =
in the configuration. Now they require explicit selection as documented above also in this case.flake8
constraint to at least 3.0.0pep8
to dependency on pycodestyle
, update flake8
constraint to at least 2.6.2setup.py test
work for everyone)Glued together by Łukasz Langa. Multiple improvements by Markus Unterwaditzer, Martijn Pieters, Cooper Lees, and Ryan May.
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4