Giter VIP home page Giter VIP logo

flake8-bugbear's Introduction

flake8-bugbear

image

image

pre-commit.ci status

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(), .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.

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

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.

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.

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.

Configuration

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

Tests / Lints

Just run:

coverage run tests/test_bugbear.py

For linting:

pre-commit run -a

License

MIT

Change Log

24.4.26

  • B909: Fix false positive affecting containers of mutables (#469)

24.4.21

  • B950: Add pragma comment to line length ignores (#463)
  • B909: Add more cases to detect + more container mutating functions (#460)

24.2.6

  • B902: Remove decorators named validator and root_validator from B902 checks (#459)
  • B038: Change B038 to B909 and make it optional (#456)

24.1.17

  • B038: Restrict rule to mutation functions only (#453)

24.1.16

  • B036: Fix crash on raise statements raising something other than a bare name (#450)

24.1.15

  • B038: Add check for mutations of loop iterator (#446)
  • B037: Add check for yielding or returning values in __init__() (#442)
  • B017: make B017 also apply to BaseException (#439)
  • B036: Add check for except BaseException without re-raising (#438)

23.12.2

  • B018: to detect useless-statements at all levels (#434)
  • B018: Add classname to b018 useless-expression output (#433)
  • B018: Include tuples in b018 useless-statement check (#432)

23.11.28

  • B035: Fix false positive when named expressions are used (#430)

23.11.26

  • B035: add check for static keys in dict-comprehension (#426)
  • B902: Add exceptions for standard library metaclasses (#415)
  • B017: Modify to no longer have a false negative when raises() is imported directly from pytest (#424)
  • B026: Fix bug where the check was not triggered for calls where the caller is an attribute (#420)

23.9.16

  • add --classmethod-decorators (#405)
  • fix name collision for node_stack on python 3.12 (#406)
  • Use pypa/build to build the package (#404)

23.7.10

  • Add B034: re.sub/subn/split must pass flags/count/maxsplit as keyword arguments.
  • Fix a crash and several test failures on Python 3.12, all relating to the B907 check.
  • Declare support for Python 3.12.

23.6.5

  • Include tox.ini in MANIFEST.in for sdist. (#389)
  • Improve B033 (duplicate set items) (#385)

23.5.9

  • Add B033: Detect duplicate items in sets
  • Add B908: Detect assertRauses like contexts only has top level statements that could throw
  • Add B028: Allow stacklevel to be explicitly assigned as a positional argument
  • Remove more < 3.8 checks / assertions

23.3.23

  • flake8-bugbear is now >= 3.8.1 project like flake8>=6.0.0
    • This has allowed some more modern AST usage cleanup and less CI running etc.
  • B030: Fix crash on certain unusual except handlers (e.g. except a[0].b:)
  • Add B033: Check for duplicate items in sets.

23.3.12

  • B950: now ignores 'noqa' and 'type: ignore' comments.
  • B005: Do not flag when using the strip() method on an imported module.
  • B030: Allow calls and starred expressions in except handlers.

23.2.13

  • B906: Add 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.
  • B016: Warn when raising f-strings.
  • Add B028: Check for an explicit stacklevel keyword argument on the warn method from the warnings module.
  • Add B029: Check when trying to use except with an empty tuple i.e. except ():.
  • Add B030: Check that except handlers only use exception classes or tuples of exception classes. Fixes crash on some rare except handlers.
  • Add B031: Check that itertools.groupby() is not used multiple times.
  • Add B032: Check for possible unintentional type annotations instead of assignments.

23.1.20

  • B024: now ignores classes without any methods. (#336)
  • B017: Don't warn when pytest.raises() has a match argument. (#334)
  • B906: Ignore visit_ functions with a _fields attribute that can't contain ast.AST subnodes. (#330)

23.1.17

  • Rename B028 to B907, making it optional/opinionated.

23.1.14

  • Add B906: visit_ function with no further calls to a visit function. (#313)
  • Add B028: Suggest !r when formatted value in f-string is surrounded by quotes. (#319)

22.12.6

  • Add B905: zip() without an explicit strict= parameter. (#314)
  • B027: ignore @overload when typing is imported with other names (#309)

22.10.27

  • B027: Ignore @overload decorator (#306)
  • B023: Also fix map (#305)
  • B023: Avoid false alarms with filter, reduce, key= and return. Added tests for functools (#303)

22.10.25

  • Make B015 and B018 messages slightly more polite (#298)
  • Add B027: Empty method in abstract base class with no abstract decorator
  • Multiple B024 false positive fixes
  • Move CI to use tox (#294)
  • Move to using PEP621 / pyproject.toml package (#291)
  • Tested in 3.11

22.9.23

  • Add B026: find argument unpacking after keyword argument (#287)
  • Move to setup.cfg like flake8 (#288)

22.9.11

  • Add B025: find duplicate except clauses (#284)

22.8.23

  • Add B024 error code to message for B024 (#276)

22.8.22

  • Add B024: abstract base class with no abstract methods (#273)

22.7.1

22.6.22

  • Don't crash when select / extend_select are None (#261)
  • Ignore lambda arguments for B020 (#259)
  • Fix missing space typos in B021, B022 error messages (#257)

22.4.25

  • Ignore black formatting for b013 test case (#251)
  • B010 Fix lambda flase positive (#246)
  • B008 Fix edge case with lambda functions (#243)

22.3.23

  • B006 and B008: Detect function calls at any level of the default expression (#239)
  • B020: Fix comprehension false postives (#238)
  • Tweak B019 desc (#237)

22.3.20

  • B022: No arguments passed to contextlib.suppress (#231)
  • B021: f-string used as docstring. (#230)
  • B020: ensure loop control variable doesn't overrides iterable it iterates (#220)
  • B019: check to find cache decorators on class methods (#218)
  • Fix crash on long empty string (#223)

22.1.11

  • B018: Ignore JoinedStr (#216)
  • Build universal Python 3 wheels (#214)
  • B950: Add same special cases as E501 (#213)

21.11.29

  • B018: Disable strings from check for now (#209)

21.11.28

  • B904: ensure the raise is in the same context with the except (#191)
  • Add Option to extend the list of immutable calls (#204)
  • Update B014: binascii.Error is now treated as a subclass of ValueError (#206)
  • add simple pre-commit config (#205)
  • Test with 3.10 official
  • Add B018 check to find useless declarations (#196, #202)

21.9.2

  • Fix crash on call in except statement in _to_name_str (#187)
  • Update B006: list, dictionary, and set comprehensions are now also disallowed (#186)

21.9.1

  • Update B008: Whitelist more immutable function calls (#173)
  • Remove Python Compatibility Warnings (#182)
  • Add B904: check for raise without from in an except clause (#181)
  • Add Python 3.10 tests to ensure we pass (#183)

21.4.3

  • Verify the element in item_context.args is of type ast.Name for b017

21.4.2

  • Add another hasattr() check to b017 visit for .func

21.4.1

  • Add B017: check for gotta-catch-em-all assertRaises(Exception)

21.3.2

  • Fix crash on tuple expansion in try/except block (#161)

21.3.1

  • Fix grammar in B015 (#150)
  • Make sure float infinity/NaN does not trigger B008 (#155)
  • Handle positional-only args in class methods (#158)

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.

flake8-bugbear's People

Contributors

alexwaygood avatar ambv avatar bryanforbes avatar cclauss avatar cooperlees avatar cricalix avatar dependabot[bot] avatar dopplershift avatar dreamsorcerer avatar finswimmer avatar fozziehi avatar gaul avatar gschaffner avatar hukkinj1 avatar ichard26 avatar inwaves avatar jaap3 avatar jakkdl avatar jdufresne avatar jellezijlstra avatar jpy-git avatar kasium avatar mimre25 avatar newglad avatar pre-commit-ci[bot] avatar r-downing avatar sam-w avatar sco1 avatar untitaker avatar zac-hd avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

flake8-bugbear's Issues

B305 triggered for methods in regular objects

class A:

    def next(self):
        return 'x'

The code above triggers "B305: .next() is not a thing on Python 3. Use the next() builtin. For Python 2 compatibility, use six.next()". While the code has other problem (shadowing builtin name), it is not related to generator.next() removed in Py3.

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

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

What is the difference between B950 and max-line-length=88?

I see that black recommends the following flake8 configuration:

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

However, the same thing can be achieved with the following configuration, which is shorter and possibly more explicit:

[flake8]
max-line-length = 88
...
select = C,E,F,W,B

Can you please help me understand why we need B950, then?

Thank you for flake8-bugbear!

B007: False positive if loop control variable is used after the loop

Example code:

from mymodule import myiter


def main():
    for result in myiter():
        pass
    print(result)

Ouptut:

foo.py:6:9: B007 Loop control variable 'result' not used within the loop body. If this is intended, start the name with an underscore.

This code is intentionally exhausting an iterator without generating a temporary data structure. As the loop control variable is used, I believe this should not emit a warning.

Mutable class attributes

Mutable class attributes may lead to information leaking from one instance to another.

class MyClass(object):
    errors = []

    def do_something(self):
        try:
            ...
        except SomeException as e:
            self.errors.append(e)

Mutable class attributes should be reported similar to B006: Do not use mutable data structures for argument defaults.

False positive on B902

Pydantic validator decorators make classmethods from the decorated methods but these are flagged as instance methods

The following gets flagged:

class UserModel(BaseModel):
    name: str

    @validator('name')
    def name_must_contain_space(cls, v):
        if ' ' not in v:
            raise ValueError('must contain a space')
        return v.title()

changing cls to self gives no error

B901 should not apply to __await__ methods

Custom awaitable objects need to implement __await__ generator methods with a return to provide values. B901 triggers on these for Python2 compatibility, but it is very unlikely that Python2 would use an __await__ method. The __await__ method must be an iterator, so using async def as suggested by B901 is not valid.

Marking every occurrence as # noqa: B901 is very annoying in an async library. Disabling it entirely is suboptimal, because a generator-return outside of __await__ usually hints at an error indeed.

    def __await__(self) -> Generator[Any, Any, ST]:
        return (yield from self._await_message().__await__())

B301 gives a false positive for pandas DataFrames, Series and Panels

iteritems is a valid function for pandas DataFrames, Series, and Panels (see docs here). However flake8-bugbear flags uses of this function:

$ cat example.py
import pandas as pd

df = pd.DataFrame({"A": [1, 2, 3], "B": [4, 5, 6]})
print(list(df.iteritems()))
$ flake8 example.py
example.py:4:12: B301 Python 3 does not include `.iter*` methods on dictionaries. Remove the `iter` prefix from the method name. For Python 2 compatibility, prefer the Python 3 equivalent unless you expect the size of the container to be large or unbounded. Then use `six.iter*` or `future.utils.iter*`.

My environment:

$ python --version
Python 3.6.5
$ flake8 --version
3.5.0 (flake8-bugbear: 18.2.0, mccabe: 0.6.1, pycodestyle: 2.3.1, pyflakes: 1.6.0) CPython 3.6.5 on Darwin

17.4.0 Wheel build fails due to LICENSE file missing

I'm unable to build a wheel due to LICENSE file missing. Will investigate and fix.

Building wheels for collected packages: flake8-bugbear, flake8, attrs, pyflakes, pycodestyle, mccabe, setuptools
  Running setup.py bdist_wheel for flake8-bugbear: started
  Destination directory: /tmp/tmpcxf7s8htpip-wheel-
  Running command /tmp/pyfi/pyfi_venv/bin/python3.6 -u -c "import setuptools, tokenize;__file__='/tmp/pip-build-h5tf698v/flake8-bugbear/setup.py';f=getattr(tokenize, 'open', open)(__file__);code=f.read().replace('\r\n', '\n');f.close();exec(compile(code, __file__, 'exec'))" bdist_wheel -d /tmp/tmpcxf7s8htpip-wheel- --plat-name=gcc_5_glibc_2_23
  running bdist_wheel
  running build
  running build_py
  creating build
  creating build/lib
  copying bugbear.py -> build/lib
  installing to build/bdist.linux-x86_64/wheel
  running install
  running install_lib
  creating build/bdist.linux-x86_64
  creating build/bdist.linux-x86_64/wheel
  copying build/lib/bugbear.py -> build/bdist.linux-x86_64/wheel
  running install_egg_info
  running egg_info
  writing flake8_bugbear.egg-info/PKG-INFO
  writing dependency_links to flake8_bugbear.egg-info/dependency_links.txt
  writing entry points to flake8_bugbear.egg-info/entry_points.txt
  writing requirements to flake8_bugbear.egg-info/requires.txt
  writing top-level names to flake8_bugbear.egg-info/top_level.txt
  reading manifest file 'flake8_bugbear.egg-info/SOURCES.txt'
  reading manifest template 'MANIFEST.in'
  warning: no files found matching '*.txt' under directory 'tests'
  writing manifest file 'flake8_bugbear.egg-info/SOURCES.txt'
  Copying flake8_bugbear.egg-info to build/bdist.linux-x86_64/wheel/flake8_bugbear-17.12.0-py3.6.egg-info
  running install_scripts
  error: [Errno 2] No such file or directory: 'LICENSE'
  Running setup.py bdist_wheel for flake8-bugbear: finished with status 'error'

B903 reword message when a subclass is involved

The current B903 message reads:

B903 Data class should either be immutable or use slots to save memory. Use collections.namedtuple to generate an immutable class, or enumerate the attributes in a slot declaration in the class to leave attributes mutable.

However, this lint message is not totally correct if the data class in question inherits from another class; e.g., Exception; in this case, use of namedtuple is inappropriate (actually, I'm not sure if there's any other way to do it.)

Warnings from flake8 due to `visitor`

With flake8 3.5.0 and flake8-bugbear installed, I get the following messages spammed all over my test logs (when using pytest-flake8):

WARNING:flake8.processor:Plugin requested optional parameter "visitor" but this is not an available parameter.

This is because visitor is an attr.ib, which gets added automatically to __init__. Apparently, flake8 inspects and validates all constructor parameters.

Is there a way to suppress B008 for tuple subclasses

We have a class which subclasses tuple, which means that its constructor is safe to call from an argument as we will get an immutable object in return. However, B008 currently flags it. Is there a way to suppress this, without disabling the check entirely?

Ignores all errors when using `noqa: X` to only ignore X

When using # noqa: E501 all errors are excluded.

This is due to the code in

if pycodestyle.noqa(self.lines[e.lineno - 1]):
continue
.

pycodestyle.noqa searches for r'# no(?:qa|pep8)\b', which matches # noqa: E501 also.

Without knowing the internals it seems like flake8 itself should include the errors itself - it has logic to ignore only specific errors (https://github.com/PyCQA/flake8/blob/013b925624bd5e4c026e83eb2c6e9f45cafa0dc0/src/flake8/defaults.py#L39-L51).

Example:

s = 'some very, very, very, very, very, very, very, very, very, very, very, very, very, very, very long line'  # noqa: E123

flake8-bugbear should report error t-noqa-colon.py:1:110: B950 line too long (109 > 80 characters) for it, but is silent.

Please give us feedback about AST change in Python 3.7

In Python 3.6, docstring was expression in AST.

FunctionDef(name='foo', ..., body=[Expr(value=Str(s='docstring'))], ...)

Since docstring is special and it's unclear that expression is docstring or not, we changed AST in 3.7a1.
docstring is moved from body to field. (bpo-29463)

FunctionDef(name='foo', ..., body=[], ..., docstring='docstring')

But it removed syntactic information about docstring (e.g. lineno). We are considering changing it again. Docstring is moved back to body, but it is special statement named DocString(s). Expr(value=Str(s)) is not docstring. (bpo-32911)

FunctionDef(name='foo', ..., body=[DocString(s='docstring')], ...)

It means tools broken by 3.7a1 will be broken again. But 3.7b3 will be the last chance to change AST.

How do you think about it? Please give comment / vote on the issue tracker.

Feature Request: warning for re-raising a caught exception

In python 2 if you have the following code:

try:
    foo()
except Exception as e:
    raise e

The original traceback gets swallowed. This has caused me a lot of problems and I feel like it would be useful for most developers in the ecosystem.

Warn on unused function arguments

Ref PyCQA/pyflakes#147

In many cases, unused function arguments are bugs. As such detection behavior would be inappropriate in Pyflakes per the above, the best place to implement such a rule would be here, analogous to the existing B007.

B007 triggers when loop variable is used after loop

I think this code is valid and idiomatic, but flake8-bugbear reports a B007 warning that idx is unused:

# Print the slice of nums starting from the first multiple of 7 until the end, or the whole list if there are no multiples of 7.
nums = list(range(10, 20))

idx = 0
for idx, num in enumerate(nums):
    if num % 7 == 0:
        break

print(nums[idx:])

Proposed Check: Unclosed files

It's good programming practice to close all the files that you've opened. Maybe it would be a good idea to check for code like:

file = open('file.txt', 'r')
data = file.read()
# do sth to data
# no file close statement
return 'something'

Probably most people use the with open... syntax nowadays, but I just stumbled upon this in a piece of legacy code and was quite surprised that none of the linters I have has caught this.

Thoughts on improving B902?

I think B902 is great for detecting errors like this:

@classmethod
def foo(self):
    ...

However, I also find myself # noqa:ing it a bit too frequently. Here are some instances where I think it could be safely relaxed for everyone:

  • Allow _cls instead of cls (ditto for metacls). Rationale: this can be required when a method needs to take, or transparently pass through, a keyword argument with one of these names.
  • The first argument to __new__ of classes that subclass type should probably be called metacls, not cls. And similarly — regular instance methods on metaclasses should take cls, and any classmethods should take metacls.
  • Consider allowing subcls / submetacls (depending on inheritance) for __init_subclass__, since that is actually significantly clearer.

What do you think?

Version 16.12.2 breaks opinionated rules enabled via `enable-extensions`

I have the following in my setup.cfg

[flake8]
enable-extensions=B950
ignore=E501
max-line-length=109

Here I enabled the opinionated B950 rule using the enable-extensions option for flake8:
http://flake8.pycqa.org/en/latest/user/options.html#cmdoption-flake8-enable-extensions

With flake8-bugbear version 16.12.1 I get the (expected) error:

$ flake8
./project/settings.py:147:133: B950: line too long (132 > 109 characters)

But version 16.12.2 (and newer) do not raise an error. With those versions I would have to use the select option for flake8 to manually enable all checks (the default ones), and also specifically this check:

select=A,B,C,D,E,F,…U,V,W,X,Y,Z,B950

Probably relevant lines missing a check for enable-extensions:
https://github.com/PyCQA/flake8-bugbear/blob/master/bugbear.py#L108-L110

Proposed Check: variable used outside of for-loop scope

Hi,

Python doesn't scope variables from a for loop, which I don't think I've ever intentionally used as a language feature, and has only been a source of bugs for me.

for x in range(5):
    print(x)
print(x)  # conspicuous usage

I think this would be the same for scopes like context managers; using the file pointer after exiting the open context manager.

I dunno if this is something that would maybe be considered for bugbear to identify.

I was thinking that when it's intentional usage could maybe be identified with something like:

x = None
for x in range(5):
    print(x)
print(x)

# OR

for x in range(5):
    print(x)
last_x = x  #noqa

Thanks for considering this.

B902 requires first parameter named self for __init__ of metaclass

I have a metaclass defined like this:

class StorageMeta(type):
    def __init__(cls, name, bases, d):

Naturally B902 flagged the first parameter of __init__, but I'm not sure if it's intended in the case of metaclasses. I can imagine arguments for and against this behavior.

This plugin cannot be used with Python 2.7 codebases

In the README:

Relax, you can run flake8 with all popular plugins as a tool perfectly fine under Python 3.5+ even if you want to analyze Python 2 code. This way you'll be able to parse all of the new syntax supported on Python 3 but also effectively all the Python 2 syntax at the same time.

This is wrong. You cannot use flake8 installed under Python 3 with a codebase under Python 2.7, as stated in their docs:

It is very important to install Flake8 on the correct version of Python for your needs. If you want Flake8 to properly parse new language features in Python 3.5 (for example), you need it to be installed on 3.5 for Flake8 to understand those features. In many ways, Flake8 is tied to the version of Python on which it runs.
http://flake8.pycqa.org/en/latest/#installation

This plugin cannot be used with Python 2.7 codebases and the README should state this correctly

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

noqa'ing multi-line strings with B950 works differently than with E501

(tmp-961236c5487a52a) ↪ flake8 --version                     
3.6.0 (flake8-bugbear: 18.8.0, flake8-docstrings: 1.3.0, pydocstyle: 3.0.0, flake8-print: 3.1.0, flake8-todo: 0.7, mccabe: 0.6.1, naming: 0.7.0, pycodestyle: 2.4.0, pyflakes: 2.0.0) CPython 3.7.2 on Linux
(tmp-961236c5487a52a) ↪ cat testfile.py 
#!/usr/bin/env python
"""
strftime documentation: https://docs.python.org/2/library/datetime.html?highlight=datetime#strftime-strptime-behavior
""" # noqa
(tmp-961236c5487a52a) ↪ flake8 --select=E501,B950 testfile.py
testfile.py:3:118: B950 line too long (117 > 80 characters)

The following version works:

(tmp-961236c5487a52a) ↪ cat testfile.py          
#!/usr/bin/env python
"""
strftime documentation: https://docs.python.org/2/library/datetime.html?highlight=datetime#strftime-strptime-behavior # noqa
"""
(tmp-961236c5487a52a) ↪ flake8 --select=E501,B950 testfile.py
(tmp-961236c5487a52a) ↪

I find placing noqa after the (possibly very long) module docstring easier though, since I can then use as many long links in that block as I want. Also, for the example given, Sphinx 1.8.3 adds the #noqa part to the link :-(

doesn't install via pip

# pip install flake8-bugbear
Collecting flake8-bugbear
  Downloading flake8-bugbear-16.10.1.tar.gz
    Complete output from command python setup.py egg_info:
    Traceback (most recent call last):
      File "<string>", line 1, in <module>
      File "/tmp/pip-build-RE3yha/flake8-bugbear/setup.py", line 10, in <module>
        with open(os.path.join(current_dir, 'README.rst'), encoding='utf8') as ld_file:
    TypeError: 'encoding' is an invalid keyword argument for this function

test_selfclean_bugbear fails with PyPI sdist

When packaging the 19.8.0 release the test fails (openSUSE; python 3.7):

[    4s] ======================================================================
[    4s] FAIL: test_selfclean_bugbear (tests.test_bugbear.BugbearTestCase)
[    4s] ----------------------------------------------------------------------
[    4s] Traceback (most recent call last):
[    4s]   File "/home/abuild/rpmbuild/BUILD/flake8-bugbear-19.8.0/tests/test_bugbear.py", line 200, in test_selfclean_bugbear
[    4s]     self.assertEqual(proc.returncode, 0, proc.stdout.decode("utf8"))
[    4s] AssertionError: 1 != 0 : /home/abuild/rpmbuild/BUILD/flake8-bugbear-19.8.0/bugbear.py:133:67: E203 whitespace before ':'
[    4s] 
[    4s] 
[    4s] ----------------------------------------------------------------------

For the complete log with the dependencies see:
bugbear.txt

`pip install flake8-bugbear` failed in python 2.7.12

Here is the backtrace:

λ pip install flake8-bugbear                                  ]
Collecting flake8-bugbear
  Downloading flake8-bugbear-16.7.1.tar.gz
    Complete output from command python setup.py egg_info:
    Traceback (most recent call last):
      File "<string>", line 1, in <module>
      File "/private/var/folders/t4/4r0q_f752vn1qr36pw1tq2280000gn/T/pip-build-mSeIFo/flake8-bugbear/setup.py", line 10, in <module>
        with open(os.path.join(current_dir, 'README.rst'), encoding='utf8') as ld_file:
    TypeError: 'encoding' is an invalid keyword argument for this function

    ----------------------------------------
Command "python setup.py egg_info" failed with error code 1 in /private/var/folders/t4/4r0q_f752vn1qr36pw1tq2280000gn/T/pip-build-mSeIFo/flake8-bugbear/

Detect unintended comma at the end of expression

I would be great to have a rule that will detect cases such this:

instance = MyClass(arg1, arg2),

As it is most likely a typo.
If someone wants a tuple, the preferred form would be (item,).

B011 is misleading, and the advice doesn't sound good

B011 Do not call assert False since python -O removes these calls. Instead callers should raise AssertionError().

There are two problems with this:

  1. Removal of assertions with -O is not limited to assert False cases, it removes all assertions. So the message is misleading.
  2. The suggestion to replace this assert with raise AssertionError() is not a good one, because such a construct cannot be disabled by disabling assertions when one explicitly wants to do that.

Given these considerations, I cannot think of a good use case or a fix for B011 in the first place, so I suggest removing it altogether.

proposed check - assert_called_once() is dangerous - warn against its use also assert_called*

Hi; I have a proposal for an additional check that I'm looking for a home for. I wonder if flake8-bugbear would be the right place:

The function assert_called_once() is a new addition to the python unittest.mock module. (see https://docs.python.org/3/library/unittest.mock.html). Unfortunately, a) if you use it against an older version of python it doesn't exist so it makes code not portable. b) if you use it anyway and then backport the code then you typically end up with a test case that passes but doesn't test anything which is nasty and dangerous.

The latter happens whenever a mock without a spec is used and the function is called against it.

mock_object.assert_called_once() # WRONG - doesn't exist in python < 3.6 / mock <

In this case, the function call is mocked so it works. Note also that calls to function names with typos will also .

mock_object.assert_call_once_with(1) # WRONG - typo - this does nothing.

Personally I think it may be a good idea for pycodestyle to warn against any use of mock_object.assert* but it should definitely warn against likely typos.

The proper way to guard against this type of thing is proper TDD style writing of test cases where we ensure they can fail as well as pass. However even that doesn't work in the case of assert_called_once() if you develop against a new version of mock and then test on an old version

This warning might be less needed once all versions of python below 3.6 were obsolete.

I already discussed this with pycodestyle who don't think it's the kind of check they do. If you think this would be more suitable elsewhere, recommendations also appreciated.

IndexError: list index out of range

Hi, I am facing a strange bug.

__________________ FLAKE8-check(ignoring D100 D104 D106 D401) __________________
/usr/local/lib/python3.6/site-packages/pluggy/__init__.py:617: in __call__
    return self._hookexec(self, self._nonwrappers + self._wrappers, kwargs)
/usr/local/lib/python3.6/site-packages/pluggy/__init__.py:222: in _hookexec
    return self._inner_hookexec(hook, methods, kwargs)
/usr/local/lib/python3.6/site-packages/pluggy/__init__.py:216: in <lambda>
    firstresult=hook.spec_opts.get('firstresult'),
/usr/local/lib/python3.6/site-packages/_pytest/runner.py:110: in pytest_runtest_call
    item.runtest()
/usr/local/lib/python3.6/site-packages/pytest_flake8.py:117: in runtest
    self.statistics)
/usr/local/lib/python3.6/site-packages/py/_io/capture.py:150: in call
    res = func(*args, **kwargs)
/usr/local/lib/python3.6/site-packages/pytest_flake8.py:193: in check_file
    app.run_checks([str(path)])
/usr/local/lib/python3.6/site-packages/flake8/main/application.py:310: in run_checks
    self.file_checker_manager.run()
/usr/local/lib/python3.6/site-packages/flake8/checker.py:321: in run
    self.run_serial()
/usr/local/lib/python3.6/site-packages/flake8/checker.py:305: in run_serial
    checker.run_checks()
/usr/local/lib/python3.6/site-packages/flake8/checker.py:579: in run_checks
    self.run_ast_checks()
/usr/local/lib/python3.6/site-packages/flake8/checker.py:493: in run_ast_checks
    for (line_number, offset, text, check) in runner:
/usr/local/lib/python3.6/site-packages/bugbear.py:37: in run
    visitor.visit(self.tree)
/usr/local/lib/python3.6/site-packages/bugbear.py:143: in visit
    super().visit(node)
/usr/local/lib/python3.6/ast.py:253: in visit
    return visitor(node)
/usr/local/lib/python3.6/ast.py:261: in generic_visit
    self.visit(item)
/usr/local/lib/python3.6/site-packages/bugbear.py:143: in visit
    super().visit(node)
/usr/local/lib/python3.6/ast.py:253: in visit
    return visitor(node)
/usr/local/lib/python3.6/site-packages/bugbear.py:235: in visit_ClassDef
    self.check_for_b903(node)
/usr/local/lib/python3.6/site-packages/bugbear.py:414: in check_for_b903
    if len(targets) > 1 or not isinstance(targets[0], ast.Attribute):
E   IndexError: list index out of range
------------------------------ Captured log call -------------------------------
processor.py               248 WARNING  Plugin requested optional parameter "builtins" but this is not an available parameter.
processor.py               248 WARNING  Plugin requested optional parameter "visitor" but this is not an available parameter.

My setup

Configuration file: https://github.com/wemake-services/wemake-django-template/blob/master/%7B%7Bcookiecutter.project_name%7D%7D/setup.cfg

Command: pytest.
Output:

============================= test session starts ==============================
platform linux -- Python 3.6.5, pytest-3.5.1, py-1.5.3, pluggy-0.6.0
Using --randomly-seed=1526028157
Django settings: server.settings (from ini file)
rootdir: /code, inifile: setup.cfg
plugins: xdist-1.22.2, randomly-1.2.3, isort-0.2.0, forked-0.2, flake8-1.0.1, django-3.2.1, deadfixtures-2.0.1, cov-2.5.1, celery-4.1.0
collected 577 items

Versions

pytest: "version": "==3.5.1"
pytest-flake8: "version": "==1.0.1"
flake8: "version": "==3.5.0"
flake8-bugbear: "version": "==18.2.0"

Lockfile: https://github.com/wemake-services/wemake-django-template/blob/master/%7B%7Bcookiecutter.project_name%7D%7D/Pipfile.lock

Reproduction

I am using docker for both local testing and CI. That makes this bug quite strange.
Since locally (macos) it passes without any problems. But inside CI it fails.

This bug happens in gitlab:
2018-05-11 12 03 40

But not locally.

python3.4 compatiblity

It seems this project only supports python > 3.5 ?

Traceback (most recent call last):
  File "/usr/lib/python3.4/multiprocessing/process.py", line 254, in _bootstrap
    self.run()
  File "/usr/lib/python3.4/multiprocessing/process.py", line 93, in run
    self._target(*self._args, **self._kwargs)
  File "/usr/local/lib/python3.4/dist-packages/flake8/checker.py", line 633, in _run_checks_from_queue
    checker.run_checks(results_queue, statistics_queue)
  File "/usr/local/lib/python3.4/dist-packages/flake8/checker.py", line 573, in run_checks
    self.run_ast_checks()
  File "/usr/local/lib/python3.4/dist-packages/flake8/checker.py", line 484, in run_ast_checks
    for (line_number, offset, text, check) in runner:
  File "/usr/local/lib/python3.4/dist-packages/bugbear.py", line 31, in run
    visitor.visit(self.tree)
  File "/usr/local/lib/python3.4/dist-packages/bugbear.py", line 82, in visit
    super().visit(node)
  File "/usr/lib/python3.4/ast.py", line 245, in visit
    return visitor(node)
  File "/usr/lib/python3.4/ast.py", line 253, in generic_visit
    self.visit(item)
  File "/usr/local/lib/python3.4/dist-packages/bugbear.py", line 82, in visit
    super().visit(node)
  File "/usr/lib/python3.4/ast.py", line 245, in visit
    return visitor(node)
  File "/usr/local/lib/python3.4/dist-packages/bugbear.py", line 162, in visit_FunctionDef
    if isinstance(x, (ast.AsyncFunctionDef, ast.FunctionDef)):
AttributeError: 'module' object has no attribute 'AsyncFunctionDef'

AttributeError: 'Tuple' object has no attribute 'id'

I'm able to consistently get an exception when running flake8-bugbear on this seemingly innocent code snippet (this has been reduced from code that actually did something):

def foo():
    for a, b in {}.items():
        pass

I'm using:

Python 3.5.2
flake8==3.2.1
flake8-bugbear==16.12.0

Traceback (most recent call last):
  ...
  File "bugbear.py", line 173, in visit_For
    if not node.target.id.startswith('_'):
AttributeError: 'Tuple' object has no attribute 'id'

Error message for B005 is not precise enough

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.

It says that you shouldn't pass strings with multiple characters as .strip() arguments - but actually, the rule does not restrict any multiple characters string, only those with repeatable characters.

So, for example, argument .strip('abc') is fine, but .strip('aaa') is not. And tests represent it.

Probably, it would be better to rephrase rule message a bit?

P.S. And, speaking of tests: in module with test cases for this rule comment near the case s.rstrip("we") says that there will be warning, while actually it won't be.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.