Script 'mail_helper' called by obssrc
Hello community,
here is the log from the commit of package python-flake8-bugbear for
openSUSE:Factory checked in at 2022-10-27 13:54:33
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-flake8-bugbear (Old)
and /work/SRC/openSUSE:Factory/.python-flake8-bugbear.new.2275 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-flake8-bugbear"
Thu Oct 27 13:54:33 2022 rev:9 rq:1031467 version:22.10.27
Changes:
--------
---
/work/SRC/openSUSE:Factory/python-flake8-bugbear/python-flake8-bugbear.changes
2022-10-26 12:32:05.768351483 +0200
+++
/work/SRC/openSUSE:Factory/.python-flake8-bugbear.new.2275/python-flake8-bugbear.changes
2022-10-27 13:55:09.512869342 +0200
@@ -1,0 +2,8 @@
+Thu Oct 27 07:26:17 UTC 2022 - Martin Li??ka <[email protected]>
+
+- Update to 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)
+
+-------------------------------------------------------------------
Old:
----
flake8-bugbear-22.10.25.tar.gz
New:
----
flake8-bugbear-22.10.27.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-flake8-bugbear.spec ++++++
--- /var/tmp/diff_new_pack.NaroCG/_old 2022-10-27 13:55:09.960871626 +0200
+++ /var/tmp/diff_new_pack.NaroCG/_new 2022-10-27 13:55:09.964871647 +0200
@@ -19,7 +19,7 @@
%define skip_python2 1
%{?!python_module:%define python_module() python-%{**} python3-%{**}}
Name: python-flake8-bugbear
-Version: 22.10.25
+Version: 22.10.27
Release: 0
Summary: A plugin for flake8 finding likely bugs and design problems in
your program
License: MIT
++++++ flake8-bugbear-22.10.25.tar.gz -> flake8-bugbear-22.10.27.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/flake8-bugbear-22.10.25/PKG-INFO
new/flake8-bugbear-22.10.27/PKG-INFO
--- old/flake8-bugbear-22.10.25/PKG-INFO 2022-10-25 01:25:14.457198000
+0200
+++ new/flake8-bugbear-22.10.27/PKG-INFO 2022-10-27 00:37:28.730224100
+0200
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: flake8-bugbear
-Version: 22.10.25
+Version: 22.10.27
Summary: A plugin for flake8 finding likely bugs and design problems in your
program. Contains warnings that don't belong in pyflakes and pycodestyle.
Author-email: ??ukasz Langa <[email protected]>
License: MIT
@@ -326,6 +326,13 @@
Change Log
----------
+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
~~~~~~~~~
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/flake8-bugbear-22.10.25/README.rst
new/flake8-bugbear-22.10.27/README.rst
--- old/flake8-bugbear-22.10.25/README.rst 2022-10-25 01:25:06.000000000
+0200
+++ new/flake8-bugbear-22.10.27/README.rst 2022-10-27 00:37:19.000000000
+0200
@@ -297,6 +297,13 @@
Change Log
----------
+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
~~~~~~~~~
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/flake8-bugbear-22.10.25/bugbear.py
new/flake8-bugbear-22.10.27/bugbear.py
--- old/flake8-bugbear-22.10.25/bugbear.py 2022-10-25 01:25:06.000000000
+0200
+++ new/flake8-bugbear-22.10.27/bugbear.py 2022-10-27 00:37:19.000000000
+0200
@@ -12,7 +12,7 @@
import attr
import pycodestyle
-__version__ = "22.10.25"
+__version__ = "22.10.27"
LOG = logging.getLogger("flake8.bugbear")
CONTEXTFUL_NODES = (
@@ -280,7 +280,7 @@
names = [_to_name_str(e) for e in node.type.elts]
as_ = " as " + node.name if node.name is not None else ""
if len(names) == 0:
- vs = ("`except (){}:`".format(as_),)
+ vs = (f"`except (){as_}:`",)
self.errors.append(B001(node.lineno, node.col_offset, vars=vs))
elif len(names) == 1:
self.errors.append(B013(node.lineno, node.col_offset,
vars=names))
@@ -568,7 +568,7 @@
n = targets.names[name][0]
self.errors.append(B020(n.lineno, n.col_offset, vars=(name,)))
- def check_for_b023(self, loop_node):
+ def check_for_b023(self, loop_node): # noqa: C901
"""Check that functions (including lambdas) do not use loop variables.
https://docs.python-guide.org/writing/gotchas/#late-binding-closures
from
@@ -584,9 +584,41 @@
# implement this "backwards": first we find all the candidate variable
# uses, and then if there are any we check for assignment of those
names
# inside the loop body.
+ safe_functions = []
suspicious_variables = []
for node in ast.walk(loop_node):
- if isinstance(node, FUNCTION_NODES):
+ # check if function is immediately consumed to avoid false alarm
+ if isinstance(node, ast.Call):
+ # check for filter&reduce
+ if (
+ isinstance(node.func, ast.Name)
+ and node.func.id in ("filter", "reduce", "map")
+ ) or (
+ isinstance(node.func, ast.Attribute)
+ and node.func.attr == "reduce"
+ and isinstance(node.func.value, ast.Name)
+ and node.func.value.id == "functools"
+ ):
+ for arg in node.args:
+ if isinstance(arg, FUNCTION_NODES):
+ safe_functions.append(arg)
+
+ # check for key=
+ for keyword in node.keywords:
+ if keyword.arg == "key" and isinstance(
+ keyword.value, FUNCTION_NODES
+ ):
+ safe_functions.append(keyword.value)
+
+ # mark `return lambda: x` as safe
+ # does not (currently) check inner lambdas in a returned expression
+ # e.g. `return (lambda: x, )
+ if isinstance(node, ast.Return):
+ if isinstance(node.value, FUNCTION_NODES):
+ safe_functions.append(node.value)
+
+ # find unsafe functions
+ if isinstance(node, FUNCTION_NODES) and node not in safe_functions:
argnames = {
arg.arg for arg in ast.walk(node.args) if isinstance(arg,
ast.arg)
}
@@ -594,16 +626,19 @@
body_nodes = ast.walk(node.body)
else:
body_nodes = itertools.chain.from_iterable(map(ast.walk,
node.body))
+ errors = []
for name in body_nodes:
- if (
- isinstance(name, ast.Name)
- and name.id not in argnames
- and isinstance(name.ctx, ast.Load)
- ):
- err = B023(name.lineno, name.col_offset,
vars=(name.id,))
- if err not in self._b023_seen:
- self._b023_seen.add(err) # dedupe across nested
loops
- suspicious_variables.append(err)
+ if isinstance(name, ast.Name) and name.id not in argnames:
+ if isinstance(name.ctx, ast.Load):
+ errors.append(
+ B023(name.lineno, name.col_offset,
vars=(name.id,))
+ )
+ elif isinstance(name.ctx, ast.Store):
+ argnames.add(name.id)
+ for err in errors:
+ if err.vars[0] not in argnames and err not in
self._b023_seen:
+ self._b023_seen.add(err) # dedupe across nested loops
+ suspicious_variables.append(err)
if suspicious_variables:
reassigned_in_loop = set(self._get_assigned_names(loop_node))
@@ -634,6 +669,14 @@
isinstance(expr, ast.Attribute) and expr.attr[:8] == "abstract"
)
+ def is_overload(expr):
+ return (isinstance(expr, ast.Name) and expr.id == "overload") or (
+ isinstance(expr, ast.Attribute)
+ and isinstance(expr.value, ast.Name)
+ and expr.value.id == "typing"
+ and expr.attr == "overload"
+ )
+
def empty_body(body) -> bool:
def is_str_or_ellipsis(node):
# ast.Ellipsis and ast.Str used in python<3.8
@@ -677,7 +720,11 @@
has_abstract_method |= has_abstract_decorator
- if not has_abstract_decorator and empty_body(stmt.body):
+ if (
+ not has_abstract_decorator
+ and empty_body(stmt.body)
+ and not any(map(is_overload, stmt.decorator_list))
+ ):
self.errors.append(
B027(stmt.lineno, stmt.col_offset, vars=(stmt.name,))
)
@@ -912,7 +959,7 @@
uniques.add(name)
seen.extend(uniques)
# sort to have a deterministic output
- duplicates = sorted(set(x for x in seen if seen.count(x) > 1))
+ duplicates = sorted({x for x in seen if seen.count(x) > 1})
for duplicate in duplicates:
self.errors.append(B025(node.lineno, node.col_offset,
vars=(duplicate,)))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/flake8-bugbear-22.10.25/flake8_bugbear.egg-info/PKG-INFO
new/flake8-bugbear-22.10.27/flake8_bugbear.egg-info/PKG-INFO
--- old/flake8-bugbear-22.10.25/flake8_bugbear.egg-info/PKG-INFO
2022-10-25 01:25:14.000000000 +0200
+++ new/flake8-bugbear-22.10.27/flake8_bugbear.egg-info/PKG-INFO
2022-10-27 00:37:28.000000000 +0200
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: flake8-bugbear
-Version: 22.10.25
+Version: 22.10.27
Summary: A plugin for flake8 finding likely bugs and design problems in your
program. Contains warnings that don't belong in pyflakes and pycodestyle.
Author-email: ??ukasz Langa <[email protected]>
License: MIT
@@ -326,6 +326,13 @@
Change Log
----------
+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
~~~~~~~~~
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/flake8-bugbear-22.10.25/tests/b023.py
new/flake8-bugbear-22.10.27/tests/b023.py
--- old/flake8-bugbear-22.10.25/tests/b023.py 2022-10-25 01:25:06.000000000
+0200
+++ new/flake8-bugbear-22.10.27/tests/b023.py 2022-10-27 00:37:19.000000000
+0200
@@ -2,10 +2,10 @@
Should emit:
B023 - on lines 12, 13, 16, 28, 29, 30, 31, 40, 42, 50, 51, 52, 53, 61, 68.
"""
+from functools import reduce
functions = []
z = 0
-
for x in range(3):
y = x + 1
# Subject to late-binding problems
@@ -25,10 +25,10 @@
def check_inside_functions_too():
- ls = [lambda: x for x in range(2)]
- st = {lambda: x for x in range(2)}
- gn = (lambda: x for x in range(2))
- dt = {x: lambda: x for x in range(2)}
+ ls = [lambda: x for x in range(2)] # error
+ st = {lambda: x for x in range(2)} # error
+ gn = (lambda: x for x in range(2)) # error
+ dt = {x: lambda: x for x in range(2)} # error
async def pointless_async_iterable():
@@ -37,9 +37,9 @@
async def container_for_problems():
async for x in pointless_async_iterable():
- functions.append(lambda: x)
+ functions.append(lambda: x) # error
- [lambda: x async for x in pointless_async_iterable()]
+ [lambda: x async for x in pointless_async_iterable()] # error
a = 10
@@ -47,10 +47,10 @@
while True:
a = a_ = a - 1
b += 1
- functions.append(lambda: a)
- functions.append(lambda: a_)
- functions.append(lambda: b)
- functions.append(lambda: c) # not a name error because of late binding!
+ functions.append(lambda: a) # error
+ functions.append(lambda: a_) # error
+ functions.append(lambda: b) # error
+ functions.append(lambda: c) # error, but not a name error due to late
binding
c: bool = a > 3
if not c:
break
@@ -58,7 +58,7 @@
# Nested loops should not duplicate reports
for j in range(2):
for k in range(3):
- lambda: j * k
+ lambda: j * k # error
for j, k, l in [(1, 2, 3)]:
@@ -76,3 +76,95 @@
def explicit_capture(captured=var):
return captured
+
+
+# `query` is defined in the function, so also defining it in the loop should
be OK.
+for name in ["a", "b"]:
+ query = name
+
+ def myfunc(x):
+ query = x
+ query_post = x
+ _ = query
+ _ = query_post
+
+ query_post = name # in case iteration order matters
+
+
+# Bug here because two dict comprehensions reference `name`, one of which is
inside
+# the lambda. This should be totally fine, of course.
+_ = {
+ k: v
+ for k, v in reduce(
+ lambda data, event: merge_mappings(
+ [data, {name: f(caches, data, event) for name, f in xx}]
+ ),
+ events,
+ {name: getattr(group, name) for name in yy},
+ ).items()
+ if k in backfill_fields
+}
+
+
+# OK to define lambdas if they're immediately consumed, typically as the `key=`
+# argument or in a consumed `filter()` (even if a comprehension is better
style)
+for x in range(2):
+ # It's not a complete get-out-of-linting-free construct - these should
fail:
+ min([None, lambda: x], key=repr)
+ sorted([None, lambda: x], key=repr)
+ any(filter(bool, [None, lambda: x]))
+ list(filter(bool, [None, lambda: x]))
+ all(reduce(bool, [None, lambda: x]))
+
+ # But all these ones should be OK:
+ min(range(3), key=lambda y: x * y)
+ max(range(3), key=lambda y: x * y)
+ sorted(range(3), key=lambda y: x * y)
+
+ any(map(lambda y: x < y, range(3)))
+ all(map(lambda y: x < y, range(3)))
+ set(map(lambda y: x < y, range(3)))
+ list(map(lambda y: x < y, range(3)))
+ tuple(map(lambda y: x < y, range(3)))
+ sorted(map(lambda y: x < y, range(3)))
+ frozenset(map(lambda y: x < y, range(3)))
+
+ any(filter(lambda y: x < y, range(3)))
+ all(filter(lambda y: x < y, range(3)))
+ set(filter(lambda y: x < y, range(3)))
+ list(filter(lambda y: x < y, range(3)))
+ tuple(filter(lambda y: x < y, range(3)))
+ sorted(filter(lambda y: x < y, range(3)))
+ frozenset(filter(lambda y: x < y, range(3)))
+
+ any(reduce(lambda y: x | y, range(3)))
+ all(reduce(lambda y: x | y, range(3)))
+ set(reduce(lambda y: x | y, range(3)))
+ list(reduce(lambda y: x | y, range(3)))
+ tuple(reduce(lambda y: x | y, range(3)))
+ sorted(reduce(lambda y: x | y, range(3)))
+ frozenset(reduce(lambda y: x | y, range(3)))
+
+ import functools
+
+ any(functools.reduce(lambda y: x | y, range(3)))
+ all(functools.reduce(lambda y: x | y, range(3)))
+ set(functools.reduce(lambda y: x | y, range(3)))
+ list(functools.reduce(lambda y: x | y, range(3)))
+ tuple(functools.reduce(lambda y: x | y, range(3)))
+ sorted(functools.reduce(lambda y: x | y, range(3)))
+ frozenset(functools.reduce(lambda y: x | y, range(3)))
+
+# OK because the lambda which references a loop variable is defined in a
`return`
+# statement, and after we return the loop variable can't be redefined.
+# In principle we could do something fancy with `break`, but it's not worth it.
+def iter_f(names):
+ for name in names:
+ if exists(name):
+ return lambda: name if exists(name) else None
+
+ if foo(name):
+ return [lambda: name] # known false alarm
+
+ if False:
+ return [lambda: i for i in range(3)] # error
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/flake8-bugbear-22.10.25/tests/b027.py
new/flake8-bugbear-22.10.27/tests/b027.py
--- old/flake8-bugbear-22.10.25/tests/b027.py 2022-10-25 01:25:06.000000000
+0200
+++ new/flake8-bugbear-22.10.27/tests/b027.py 2022-10-27 00:37:19.000000000
+0200
@@ -5,7 +5,7 @@
"""
Should emit:
-B025 - on lines 13, 16, 19, 23, 31
+B027 - on lines 13, 16, 19, 23, 31
"""
@@ -57,3 +57,22 @@
def empty_2(self): # safe
pass
+
+
+# ignore @overload, fixes issue #304
+import typing
+from typing import Union, overload
+
+
+class AstractClass(ABC):
+ @overload
+ def empty_1(self, foo: str):
+ ...
+
+ @typing.overload
+ def empty_1(self, foo: int):
+ ...
+
+ @abstractmethod
+ def empty_1(self, foo: Union[str, int]):
+ ...
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/flake8-bugbear-22.10.25/tests/test_bugbear.py
new/flake8-bugbear-22.10.27/tests/test_bugbear.py
--- old/flake8-bugbear-22.10.25/tests/test_bugbear.py 2022-10-25
01:25:06.000000000 +0200
+++ new/flake8-bugbear-22.10.27/tests/test_bugbear.py 2022-10-27
00:37:19.000000000 +0200
@@ -351,6 +351,13 @@
B023(61, 16, vars=("j",)),
B023(61, 20, vars=("k",)),
B023(68, 9, vars=("l",)),
+ B023(113, 23, vars=("x",)),
+ B023(114, 26, vars=("x",)),
+ B023(115, 36, vars=("x",)),
+ B023(116, 37, vars=("x",)),
+ B023(117, 36, vars=("x",)),
+ B023(167, 28, vars=("name",)), # known false alarm
+ B023(170, 28, vars=("i",)),
)
self.assertEqual(errors, expected)