A plugin for Flake8 finding likely bugs and design problems in your program. Contains warnings that don't belong in pyflakes and pycodestyle.

Overview

flake8-bugbear

https://travis-ci.org/PyCQA/flake8-bugbear.svg?branch=master

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.

Installation

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

Development

If you'd like to do a PR we have development instructions here.

List of warnings

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() 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?

Python 3 compatibility warnings

These have higher risk of false positives but discover regressions that are dangerous to slip through when test coverage is not great. Let me know if a popular library is triggering any of the following warnings for valid code.

B301: Python 3 does not include .iter* methods on dictionaries. The default behavior is to return iterables. Simply remove the iter prefix from the method. For Python 2 compatibility, also prefer the Python 3 equivalent if you expect that the size of the dict to be small and bounded. The performance regression on Python 2 will be negligible and the code is going to be the clearest. Alternatively, use six.iter* or future.utils.iter*.

B302: Python 3 does not include .view* methods on dictionaries. The default behavior is to return viewables. Simply remove the view prefix from the method. For Python 2 compatibility, also prefer the Python 3 equivalent if you expect that the size of the dict to be small and bounded. The performance regression on Python 2 will be negligible and the code is going to be the clearest. Alternatively, use six.view* or future.utils.view*.

B303: The __metaclass__ attribute on a class definition does nothing on Python 3. Use class MyClass(BaseClass, metaclass=...). For Python 2 compatibility, use six.add_metaclass.

B304: sys.maxint is not a thing on Python 3. Use sys.maxsize.

B305: .next() is not a thing on Python 3. Use the next() builtin. For Python 2 compatibility, use six.next().

B306: BaseException.message has been deprecated as of Python 2.6 and is removed in Python 3. Use str(e) to access the user-readable message. Use e.args to access arguments passed to the exception.

Opinionated warnings

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.

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%. 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.

How to enable opinionated warnings

To enable these checks, specify a --select command-line option or select= option in your config file. As of Flake8 3.0, this option is a whitelist (checks not listed are being implicitly disabled), so you have to explicitly specify all checks you want enabled. For example:

[flake8]
max-line-length = 80
max-complexity = 12
...
ignore = E501
select = C,E,F,W,B,B901

Note that we're enabling the complexity checks, the PEP8 pycodestyle errors and warnings, the pyflakes fatals and all default Bugbear checks. Finally, we're also specifying B901 as a check that we want enabled. Some checks might need other flake8 checks disabled - e.g. E501 must be disabled for B950 to be hit.

If you'd like all optional warnings to be enabled for you (future proof your config!), say B9 instead of B901. You will need Flake8 3.2+ for this feature.

Note that pycodestyle also has a bunch of warnings that are disabled by default. Those get enabled as soon as there is an ignore = line in your configuration. I think this behavior is surprising so Bugbear's opinionated warnings require explicit selection.

Tests

Just run:

python tests/test_bugbear.py

License

MIT

Change Log

20.11.1

  • Support exception aliases properly in B014 (#129)
  • Add B015: Pointless comparison (#130)
  • Remove check for # noqa comments (#134)
  • Ignore exception classes which are not types (#135)
  • Introduce B016 to check for raising a literal. (#141)
  • Exclude types.MappingProxyType() from B008. (#144)

20.1.4

  • Ignore keywords for B009/B010

20.1.3

  • Silence B009/B010 for non-identifiers
  • State an ignore might be needed for optional B9x checks

20.1.2

  • Fix error on attributes-of-attributes in except (...): clauses

20.1.1

  • Allow continue/break within loops in finally clauses for B012
  • For B001, also check for except ():
  • Introduce B013 and B014 to check tuples in except (..., ): statements

20.1.0

  • Warn about continue/return/break in finally block (#100)
  • Removed a colon from the descriptive message in B008. (#96)

19.8.0

  • Fix .travis.yml syntax + add Python 3.8 + nightly tests
  • Fix black formatting + enforce via CI
  • Make B901 not apply to __await__ methods

19.3.0

  • allow 'mcs' for metaclass classmethod first arg (PyCharm default)
  • Introduce B011
  • Introduce B009 and B010
  • Exclude immutable calls like tuple() and frozenset() from B008
  • For B902, the first argument for metaclass class methods can be "mcs", matching the name preferred by PyCharm.

18.8.0

  • black format all .py files
  • Examine kw-only args for mutable defaults
  • Test for Python 3.7

18.2.0

  • packaging fixes

17.12.0

  • graduated to Production/Stable in trove classifiers
  • introduced B008

17.4.0

  • bugfix: Also check async functions for B006 + B902

17.3.0

  • introduced B903 (patch contributed by Martijn Pieters)
  • bugfix: B902 now enforces cls for instance methods on metaclasses and metacls for class methods on metaclasses

17.2.0

  • introduced B902
  • bugfix: opinionated warnings no longer invisible in Syntastic
  • bugfix: opinionated warnings stay visible when --select on the command-line is used with full three-digit error codes

16.12.2

  • bugfix: opinionated warnings no longer get enabled when user specifies ignore = in the configuration. Now they require explicit selection as documented above also in this case.

16.12.1

  • bugfix: B007 no longer crashes on tuple unpacking in for-loops

16.12.0

  • introduced B007
  • bugfix: remove an extra colon in error formatting that was making Bugbear errors invisible in Syntastic
  • marked as "Beta" in trove classifiers, it's been used in production for 8+ months

16.11.1

  • introduced B005
  • introduced B006
  • introduced B950

16.11.0

  • bugfix: don't raise false positives in B901 on closures within generators
  • gracefully fail on Python 2 in setup.py

16.10.0

  • introduced B004
  • introduced B901, thanks Markus!
  • update flake8 constraint to at least 3.0.0

16.9.0

  • introduced B003

16.7.1

  • bugfix: don't omit message code in B306's warning
  • change dependency on pep8 to dependency on pycodestyle, update flake8 constraint to at least 2.6.2

16.7.0

  • introduced B306

16.6.1

  • bugfix: don't crash on files with tuple unpacking in class bodies

16.6.0

  • introduced B002, B301, B302, B303, B304, and B305

16.4.2

  • packaging herp derp

16.4.1

  • bugfix: include tests in the source package (to make setup.py test work for everyone)
  • bugfix: explicitly open README.rst in UTF-8 in setup.py for systems with other default encodings

16.4.0

  • first published version
  • date-versioned

Authors

Glued together by Łukasz Langa. Multiple improvements by Markus Unterwaditzer, Martijn Pieters, Cooper Lees, and Ryan May.

Comments
  • B023 false alarms

    B023 false alarms

    When upgrading, some false positives were found for B023 (implimented in https://github.com/PyCQA/flake8-bugbear/pull/265).

    Example

    """B023.py"""
    def filter_values(values: list[list[int]], max_percentage: float):
        for value in values:
            filter_val = max(value) * max_percentage
            yield list(filter(lambda x: x < filter_val, value))
    
    
    $ flake8 B023.py
    bugbear_me.py:4:41: B023 Function definition does not bind loop variable 'filter_val' is valid, and doesn't fall into the 
    

    A silly example here, but one where the use of filter_val is valid.

    cc @Zac-HD In the PR you mentioned some hard to detect false positives that you were okay with. Was this kind of pattern one of the ones you had in mind?

    Thanks for this check btw, I think it's a good idea. I've fallen for this in the past!

    opened by paw-lu 24
  • Codes B301-B306 conflict with openstack/bandit (via. flake8-bandit)

    Codes B301-B306 conflict with openstack/bandit (via. flake8-bandit)

    Similar situation to #20, there are conflicts across codes B301-B306.

    https://github.com/openstack/bandit:

    The following tests were discovered and loaded:
      ...
      B301  pickle
      B302  marshal
      B303  md5
      B304  ciphers
      B305  cipher_modes
      B306  mktemp_q
    
    • https://github.com/tylerwince/flake8-bandit is "a flake8 wrapper around [bandit]"

    In my situation:

    • When both are installed, bandit is still available while bugbear is deactivated
    • If I uninstall bandit, bugbear is activated and works as expected
    opened by myii 19
  • bugbear 21.4.1 + 21.4.2 fails with AttributeError

    bugbear 21.4.1 + 21.4.2 fails with AttributeError

    Newly updated bugbear 21.4.1 fails with AttributeError:

    21:06:51 Traceback (most recent call last):
    21:06:51   File "/usr/lib/python3.6/multiprocessing/pool.py", line 119, in worker
    21:06:51     result = (True, func(*args, **kwds))
    21:06:51   File "/usr/lib/python3.6/multiprocessing/pool.py", line 44, in mapstar
    21:06:51     return list(map(*args))
    21:06:51   File "/src/.tox/flake8-py36/lib/python3.6/site-packages/flake8/checker.py", line 676, in _run_checks
    21:06:51     return checker.run_checks()
    21:06:51   File "/src/.tox/flake8-py36/lib/python3.6/site-packages/flake8/checker.py", line 589, in run_checks
    21:06:51     self.run_ast_checks()
    21:06:51   File "/src/.tox/flake8-py36/lib/python3.6/site-packages/flake8/checker.py", line 494, in run_ast_checks
    21:06:51     for (line_number, offset, text, _) in runner:
    21:06:51   File "/src/.tox/flake8-py36/lib/python3.6/site-packages/bugbear.py", line 36, in run
    21:06:51     visitor.visit(self.tree)
    21:06:51   File "/src/.tox/flake8-py36/lib/python3.6/site-packages/bugbear.py", line 165, in visit
    21:06:51     super().visit(node)
    21:06:51   File "/usr/lib/python3.6/ast.py", line 253, in visit
    21:06:51     return visitor(node)
    21:06:51   File "/usr/lib/python3.6/ast.py", line 261, in generic_visit
    21:06:51     self.visit(item)
    21:06:51   File "/src/.tox/flake8-py36/lib/python3.6/site-packages/bugbear.py", line 165, in visit
    21:06:51     super().visit(node)
    21:06:51   File "/usr/lib/python3.6/ast.py", line 253, in visit
    21:06:51     return visitor(node)
    21:06:51   File "/src/.tox/flake8-py36/lib/python3.6/site-packages/bugbear.py", line 306, in visit_ClassDef
    21:06:51     self.generic_visit(node)
    21:06:51   File "/usr/lib/python3.6/ast.py", line 261, in generic_visit
    21:06:51     self.visit(item)
    21:06:51   File "/src/.tox/flake8-py36/lib/python3.6/site-packages/bugbear.py", line 165, in visit
    21:06:51     super().visit(node)
    21:06:51   File "/usr/lib/python3.6/ast.py", line 253, in visit
    21:06:51     return visitor(node)
    21:06:51   File "/src/.tox/flake8-py36/lib/python3.6/site-packages/bugbear.py", line 302, in visit_FunctionDef
    21:06:51     self.generic_visit(node)
    21:06:51   File "/usr/lib/python3.6/ast.py", line 261, in generic_visit
    21:06:51     self.visit(item)
    21:06:51   File "/src/.tox/flake8-py36/lib/python3.6/site-packages/bugbear.py", line 165, in visit
    21:06:51     super().visit(node)
    21:06:51   File "/usr/lib/python3.6/ast.py", line 253, in visit
    21:06:51     return visitor(node)
    21:06:51   File "/src/.tox/flake8-py36/lib/python3.6/site-packages/bugbear.py", line 321, in visit_With
    21:06:51     self.check_for_b017(node)
    21:06:51   File "/src/.tox/flake8-py36/lib/python3.6/site-packages/bugbear.py", line 442, in check_for_b017
    21:06:51     hasattr(item_context.func, "attr")
    21:06:51 AttributeError: 'Name' object has no attribute 'func'
    21:06:51 """
    

    See https://integration.wikimedia.org/ci/job/pywikibot-core-tox-docker/14952/console

    bug help wanted 
    opened by xqt 18
  • Warn against using yield and return x

    Warn against using yield and return x

    opened by untitaker 17
  • B018 wrongly detects inline variable or attribute docstrings

    B018 wrongly detects inline variable or attribute docstrings

    Having an inline attribute doc string or a module variable docstring, it is wrongly marked as B018 (sample from sphinx doc):

    module_level_variable2 = 98765
    """int: Module level variable documented inline.
    
    The docstring may span multiple lines. The type may optionally be specified
    on the first line, separated by a colon.
    """
    
    
    bug help wanted 
    opened by xqt 16
  • B001 misses some bare excepts

    B001 misses some bare excepts

    B001 and Flake8/pycodestyle E722 both check for bare_except, but B001 misses a lot of cases that E722 finds.

    We noticed this when we tried running an internal tool that looks for overlaps in checks -- we are writing some of our own and don't want to overlap -- and found that every time B001 fires E722 also fires; but the reverse is not true.

    Tool output: B001 (6786) <-> E722 (34093): 13572 occurred at same line+path B001 implies E722: 100% E722 implies B001: 19%

    I took a look at the implementations for B001 and E722 and found that bugbear uses the AST and E722 uses a regex:

    Bugbear implementation uses AST.

    def visit_ExceptHandler(self, node):
        if node.type is None:
            self.errors.append(B001(node.lineno, node.col_offset))
        self.generic_visit(node)
    

    Flake8 implementation uses regex.

    def bare_except(logical_line, noqa):
        if noqa:
            return
    
        regex = re.compile(r"except\s*:")
        match = regex.match(logical_line)
        if match:
            yield match.start(), "E722 do not use bare 'except'"
    

    From the implementation, it looks like B001 and E722 should hit the same locations every time.

    We have a platform that lets us run static analysis over a bunch of open source repositories at the same time, so I ran vanilla flake8 and bugbear at the same time to see if there was a pattern, but one wasn't immediately obvious.

    I thought this might be related to forgetting to call visit or something like that (I've been bitten by that before!) but the reason for this disparity wasn't clear to me... so I'm making this issue. Feel free to reach out to me if you have any other questions!

    Here are some examples:

    image

    image

    image

    opened by minusworld 16
  • Add B019 check to find cache decorators on class methods

    Add B019 check to find cache decorators on class methods

    As described in #217, using functools.cache/functools.lru_cache on class methods can potentially cause their instances to live longer than expected.

    I took a stab at adding a rule to catch this pattern but I have a few questions:

    1. flake8-bugbear's error messages generally try to propose a solution to make the linting error go away (besides ignoring the line), but I'm not sure about the verbiage to include. For reference, the starting point is the following:

    Use of functools.lru_cache or functools.cache on class methods can lead to memory leaks. The cache may retain instance references, preventing garbage collection.

    1. Should this be restricted to caches that are explicitly unbounded, rather than any use of a built-in cache with a class method? i.e. this would only raise for functools.cache and functools.lru_cache(maxsize=None). This seems to more specifically address the issue though some still may not want to potentially keep these instances alive, bounded cache or not.

    Related reading:

    • https://bugs.python.org/issue19859
    • https://bugs.python.org/issue44310
    • https://docs.python.org/3/faq/programming.html#how-do-i-cache-method-calls

    Resolves: #217 Resolves: #215 Resolves: #212 Resolves: #221

    opened by sco1 15
  • Add `B904` - Use `raise ... from err` in `except` clauses

    Add `B904` - Use `raise ... from err` in `except` clauses

    Closes #180, by adding a new check ~~B018~~ B904 to recommend exception chaining. For example,

    try:
        assert False
    except AssertionError:
        raise RuntimeError  # B904: Within an except clause, use `raise ... from err` ...
    

    This turned out to be remarkably easy to add to the existing code 😁

    opened by Zac-HD 15
  • Proposed check: use suppress context manager

    Proposed check: use suppress context manager

    Instead of

    try:
        do_something()
    except RuntimeError:
        pass
    

    suggest using

    with contextlib.suppress(RuntimeError):
        do_something()
    

    What do you think?

    opened by atugushev 11
  • B904: ensure the raise is in the same context with the except

    B904: ensure the raise is in the same context with the except

    Resolves #190. Introduces a simple version of context management, though more detailed analysis might need something a little bit specialized in the future (e.g stuff like this).

    opened by isidentical 10
  • extend-immutable-calls: how to configure?

    extend-immutable-calls: how to configure?

    I haven't been able to make the recently released feature extend-immutable-calls to work.

    Have I configured it wrong?

    I have verified that flake8 recognizes the config, by setting the line-length to 10 and verified flake8 warnings about line length.

    flake8 --version
    
    4.0.1 (flake8-bugbear: 21.11.29, mccabe: 0.6.1, pycodestyle: 2.8.0, pyflakes: 2.4.0) CPython 3.10.0 on
    Darwin
    

    example.py

    import fastapi
    
    
    def example_fn(data: str = fastapi.Header(None)):
        pass
    

    setup.cfg

    [flake8]
    max-line-length = 120
    extend-immutable-calls = ["fastapi.Header"]
    
    flake8 --show-source
    
    ./example.py:4:28: 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.
    def example_fn(data: str = fastapi.Header(None)):
                               ^
    
    opened by DavidVujic 8
  • Recommend Counter() in place of defaultdict(int)

    Recommend Counter() in place of defaultdict(int)

    I am suggesting a new check to recommend replacing defaultdict(int) with Counter(), both of which are from the standard library collections, due to the former having a major gotcha with memory usage.

    Consider this test case:

    from collections import Counter
    from collections import defaultdict
    
    # Profiled using;
    # $ mprof run defaultdict_leak.py && mprof plot
    if True:
        # Apparent memory leak
        # Over 700MB using Python 3.9.13 on macOS
        # Over 900MB using Python 3.9.15 on Linux
        counts = defaultdict(int)
    else:
        # Low and flat memory
        # about 16MB using Python 3.9.13 on macOS
        # about 19MB using Python 3.9.15 on Linux
        counts = Counter()
    
    # Setup some sparse data
    for x in [12,34,56,78,90]:
        counts[str(x)] = 123 + x
    
    threshold = 100
    excesses = 0
    for x in range(int(1e7)):
        if threshold < counts[str(x)]:
            excesses += counts[str(x)]
    print(f"Sum of entries exceeding the threshold {threshold} is {excesses}")
    

    The apparent memory leak with defaultdict is due to the documented behaviour of recording the missing keys in the dictionary with the default value, https://docs.python.org/3/library/collections.html#collections.defaultdict says:

    ... provide a default value for the given key, this value is inserted in the dictionary for the key, and returned.

    ...

    When each key is encountered for the first time, it is not already in the mapping; so an entry is automatically created using the default_factory ...

    I assume I'm not the only person to have used defaultdict without appreciating this, and in the case of defaultdict(int) there is good alternative in Counter()

    enhancement help wanted 
    opened by peterjc 2
  • Suggest `!r` format specifier for strings like `f

    Suggest `!r` format specifier for strings like `f"foo is '{self.foo}'"`

    I've seen some code lately where a reminder about the !r format specifier would probably have helped - instead of displaying the repr, single-quotes were manually added outside the braces as in f"No value found at '{path}'". This OK, until path contains a single-quote character and then it can get confusing fast.

    I'd therefore propose warning about this case, which is conveniently easy to reliably detect using the JoinedStr and FormattedValue nodes - within a JoinedStr, warn if there is a sequence of Constant/FormattedValue/Constant, where the first constant ends and the second starts with a single or double quote character, and the formatter value has no conversion code.

    Separately, I used the regex ".*('\{[^}]+\}').*" to confirm that this is common enough to be worth linting for. It's not especially rare, and IMO pretty useful to teach people about format specifiers.

    enhancement help wanted 
    opened by Zac-HD 2
  • Report incorrect assigning of dictionary entries with a colon (`:`)

    Report incorrect assigning of dictionary entries with a colon (`:`)

    Consider the following code

    dct = {
        'a': 1,
    }
    dct['b']: 2
    print(dct)  # {'a': 1}
    

    This is actually valid python syntax, because it is typing the 'b' entry as a 2 type. But we can assume the user meant to assign an element rather than type it (especially if there's no equal on this line).

    (Recommended I post this to bugbear by pyflakes maintainers here: https://github.com/PyCQA/pyflakes/issues/756)

    enhancement help wanted 
    opened by dannysepler 2
  • Question: B027 empty method in an abstract base class

    Question: B027 empty method in an abstract base class

    Short question on the reason behind newly added B027: If we have an ABC

    from abc import ABC, abstractmethod
    
    class MyABC(ABC):
        
        def method(self):
            """
            Some method that does nothing by default. Derived classes can choose to override it.
            """
            pass
    
        @abstractmethod
        def method2(self):
            """
            Another method. Derived classes MUST define it.
            """
    

    B027 will raise on the first method for not being declared abstract.

    Is there a way of allowing it to be empty despite the class being abstract? (Besides noqa and besides overriding them with an empty method in derived classes.) I would argue that there is reason to have empty methods provided by the ABC (interface) where the default implementation is to do nothing, but that derived classes can choose to override (e.g. if they need to perform some initialization / tear down of servers in my case), as opposed to methods that must be overridden.

    opened by yannikschaelte 1
  • Require warnings.warn stacklevel argument as 2+

    Require warnings.warn stacklevel argument as 2+

    Calling warnings.warn() without a stacklevel, or a stacklevel value of <2, is nearly always a mistake. Doing so flags the warning inside the called function, rather than the caller, making it hard to fix the warning.

    flake8-bugbear could detect such invocations of warnings.warn().

    This issue inspired by @asottile's video of the day: https://www.youtube.com/watch?v=CtFdXBEwYfk . This is also something I've seen recur as a review point in Django PR's.

    enhancement help wanted 
    opened by adamchainz 1
Releases(22.12.6)
Owner
Python Code Quality Authority
Organization for code quality tools (and plugins) for the Python programming language
Python Code Quality Authority
Flake8 extension for checking quotes in python

Flake8 Extension to lint for quotes. Major update in 2.0.0 We automatically encourage avoiding escaping quotes as per PEP 8. To disable this, use --no

Zachary Heller 157 Dec 13, 2022
Run isort, pyupgrade, mypy, pylint, flake8, and more on Jupyter Notebooks

Run isort, pyupgrade, mypy, pylint, flake8, mdformat, black, blacken-docs, and more on Jupyter Notebooks ✅ handles IPython magics robustly ✅ respects

663 Jan 08, 2023
Backport Python 3.8+ typing utils & add issubtype & more

typing-utils Backport Python3.8+ typing utils & issubtype & more Install API issubtype get_origin get_args get_type_hints Install pip install typi

10 Nov 09, 2022
A plugin for Flake8 that checks pandas code

pandas-vet pandas-vet is a plugin for flake8 that provides opinionated linting for pandas code. It began as a project during the PyCascades 2019 sprin

Jacob Deppen 146 Dec 28, 2022
:sparkles: Surface lint errors during code review

✨ Linty Fresh ✨ Keep your codebase sparkly clean with the power of LINT! Linty Fresh parses lint errors and report them back to GitHub as comments on

Lyft 183 Dec 18, 2022
Unbearably fast O(1) runtime type-checking in pure Python.

Look for the bare necessities, the simple bare necessities. Forget about your worries and your strife. — The Jungle Book.

beartype 1.4k Jan 01, 2023
A static type analyzer for Python code

pytype - 🦆 ✔ Pytype checks and infers types for your Python code - without requiring type annotations. Pytype can: Lint plain Python code, flagging c

Google 4k Dec 31, 2022
An enhanced version of the Python typing library.

typingplus An enhanced version of the Python typing library that always uses the latest version of typing available, regardless of which version of Py

Contains 6 Mar 26, 2021
It's not just a linter that annoys you!

README for Pylint - https://pylint.pycqa.org/ Professional support for pylint is available as part of the Tidelift Subscription. Tidelift gives softwa

Python Code Quality Authority 4.4k Jan 04, 2023
Pylint plugin for improving code analysis for when using Django

pylint-django About pylint-django is a Pylint plugin for improving code analysis when analysing code using Django. It is also used by the Prospector t

Python Code Quality Authority 544 Jan 06, 2023
An extension for flake8 that forbids some imports statements in some modules.

flake8-obey-import-goat An extension for flake8 that forbids some imports statements in some modules. Important: this project is developed using DDD,

Ilya Lebedev 10 Nov 09, 2022
Static type checker for Python

Static type checker for Python Speed Pyright is a fast type checker meant for large Python source bases. It can run in a “watch” mode and performs fas

Microsoft 9.2k Jan 03, 2023
MonkeyType as a pytest plugin.

MonkeyType as a pytest plugin.

Marius van Niekerk 36 Nov 24, 2022
Plugin for mypy to support zope.interface

Plugin for mypy to support zope.interface The goal is to be able to make zope interfaces to be treated as types in mypy sense. Usage Install both mypy

Shoobx 36 Oct 29, 2022
flake8 plugin to catch useless `assert` statements

flake8-useless-assert flake8 plugin to catch useless assert statements Download or install on the PyPI page Violations Code Description Example ULA001

1 Feb 12, 2022
The mypy playground. Try mypy with your web browser.

mypy-playground The mypy playground provides Web UI to run mypy in the sandbox: Features Web UI and sandbox for running mypy eas

Yusuke Miyazaki 57 Jan 02, 2023
Typed interface stubs for Pythonista iOS

Pythonista Stubs Stubs for the Pythonista iOS API. This allows for better error detection and IDE / editor autocomplete. Installation and Usage pip in

Harold Martin 12 Jul 14, 2020
Mypy stubs for the PyQt5 framework

Mypy stubs for the PyQt5 framework This repository holds the stubs of the PyQt5 framework. It uses the stub files that are produced during compilation

62 Nov 22, 2022
Performant type-checking for python.

Pyre is a performant type checker for Python compliant with PEP 484. Pyre can analyze codebases with millions of lines of code incrementally – providi

Facebook 6.2k Jan 04, 2023
flake8 plugin which checks that typing imports are properly guarded

flake8-typing-imports flake8 plugin which checks that typing imports are properly guarded installation pip install flake8-typing-imports flake8 codes

Anthony Sottile 50 Nov 01, 2022