From 4564aa42bdbe96018c18fccfcdba94d0cf0b4c01 Mon Sep 17 00:00:00 2001 From: Cooper Ry Lees Date: Mon, 23 Aug 2021 20:27:15 -0700 Subject: [PATCH] Remove Python Compatibility Warnings - The world has move to Python 3 - If people need these checks they can pin to 21.4.3 Tests: Ensure all remaining tests still pass Fixes #177 --- README.rst | 39 -------------------- bugbear.py | 82 +---------------------------------------- tests/b301_b302_b305.py | 48 ------------------------ tests/b303_b304.py | 46 ----------------------- tests/b306.py | 11 ------ tests/test_bugbear.py | 38 ------------------- 6 files changed, 2 insertions(+), 262 deletions(-) delete mode 100644 tests/b301_b302_b305.py delete mode 100644 tests/b303_b304.py delete mode 100644 tests/b306.py diff --git a/README.rst b/README.rst index bbdf897..e8934f3 100644 --- a/README.rst +++ b/README.rst @@ -131,45 +131,6 @@ Either assert for a more specific exception (builtin or custom), use data available in ``ex``. -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 ~~~~~~~~~~~~~~~~~~~~ diff --git a/bugbear.py b/bugbear.py index 40708b9..68b09db 100644 --- a/bugbear.py +++ b/bugbear.py @@ -226,14 +226,7 @@ def visit_UAdd(self, node): def visit_Call(self, node): if isinstance(node.func, ast.Attribute): - for bug in (B301, B302, B305): - if node.func.attr in bug.methods: - call_path = ".".join(self.compose_call_path(node.func.value)) - if call_path not in bug.valid_paths: - self.errors.append(bug(node.lineno, node.col_offset)) - break - else: - self.check_for_b005(node) + self.check_for_b005(node) else: with suppress(AttributeError, IndexError): if ( @@ -258,25 +251,8 @@ def visit_Call(self, node): self.generic_visit(node) - def visit_Attribute(self, node): - call_path = list(self.compose_call_path(node)) - if ".".join(call_path) == "sys.maxint": - self.errors.append(B304(node.lineno, node.col_offset)) - elif len(call_path) == 2 and call_path[1] == "message": - name = call_path[0] - for elem in reversed(self.node_stack[:-1]): - if isinstance(elem, ast.ExceptHandler) and elem.name == name: - self.errors.append(B306(node.lineno, node.col_offset)) - break - def visit_Assign(self, node): - if isinstance(self.node_stack[-2], ast.ClassDef): - # note: by hasattr below we're ignoring starred arguments, slices - # and tuples for simplicity. - assign_targets = {t.id for t in node.targets if hasattr(t, "id")} - if "__metaclass__" in assign_targets: - self.errors.append(B303(node.lineno, node.col_offset)) - elif len(node.targets) == 1: + if len(node.targets) == 1: t = node.targets[0] if isinstance(t, ast.Attribute) and isinstance(t.value, ast.Name): if (t.value.id, t.attr) == ("os", "environ"): @@ -771,60 +747,6 @@ def visit(self, node): ) ) -# Those could be false positives but it's more dangerous to let them slip -# through if they're not. -B301 = Error( - message=( - "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*`." - ) -) -B301.methods = {"iterkeys", "itervalues", "iteritems", "iterlists"} -B301.valid_paths = {"six", "future.utils", "builtins"} - -B302 = Error( - message=( - "B302 Python 3 does not include `.view*` methods on dictionaries. " - "Remove the `view` 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.view*` or `future.utils.view*`." - ) -) -B302.methods = {"viewkeys", "viewvalues", "viewitems", "viewlists"} -B302.valid_paths = {"six", "future.utils", "builtins"} - -B303 = Error( - message=( - "B303 `__metaclass__` does nothing on Python 3. Use " - "`class MyClass(BaseClass, metaclass=...)`. For Python 2 " - "compatibility, use `six.add_metaclass`." - ) -) - -B304 = Error(message="B304 `sys.maxint` is not a thing on Python 3. Use `sys.maxsize`.") - -B305 = Error( - message=( - "B305 `.next()` is not a thing on Python 3. Use the `next()` " - "builtin. For Python 2 compatibility, use `six.next()`." - ) -) -B305.methods = {"next"} -B305.valid_paths = {"six", "future.utils", "builtins"} - -B306 = Error( - message=( - "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." - ) -) - # Warnings disabled by default. B901 = Error( message=( diff --git a/tests/b301_b302_b305.py b/tests/b301_b302_b305.py deleted file mode 100644 index 71da809..0000000 --- a/tests/b301_b302_b305.py +++ /dev/null @@ -1,48 +0,0 @@ -""" -Should emit: -B301 - on lines 39-42 -B302 - on lines 43-46 -B305 - on lines 47-48 -""" - -import builtins # future's builtins really -import future.utils -import six -from six import iterkeys -from future.utils import itervalues - - -def this_is_okay(): - d = {} - iterkeys(d) - six.iterkeys(d) - six.itervalues(d) - six.iteritems(d) - six.iterlists(d) - six.viewkeys(d) - six.viewvalues(d) - six.viewlists(d) - itervalues(d) - future.utils.iterkeys(d) - future.utils.itervalues(d) - future.utils.iteritems(d) - future.utils.iterlists(d) - future.utils.viewkeys(d) - future.utils.viewvalues(d) - future.utils.viewlists(d) - six.next(d) - builtins.next(d) - - -def everything_else_is_wrong(): - d = None # note: bugbear is no type checker - d.iterkeys() - d.itervalues() - d.iteritems() - d.iterlists() # Djangoism - d.viewkeys() - d.viewvalues() - d.viewitems() - d.viewlists() # Djangoism - d.next() - d.keys().next() diff --git a/tests/b303_b304.py b/tests/b303_b304.py deleted file mode 100644 index 4b5a80d..0000000 --- a/tests/b303_b304.py +++ /dev/null @@ -1,46 +0,0 @@ -""" -Should emit: -B303 - on line 25 -B304 - on line 42 -""" - -import sys -import something_else - - -def this_is_okay(): - something_else.maxint - maxint = 3 - maxint - - -maxint = 3 - - -def this_is_also_okay(): - maxint - - -class CustomClassWithBrokenMetaclass: - __metaclass__ = type - maxint = 5 # this is okay - # the following shouldn't crash - (a, b, c) = list(range(3)) - # it's different than this - a, b, c = list(range(3)) - ( - a, - b, - c, - ) = list(range(3)) - # and different than this - (a, b), c = list(range(3)) - a, *b, c = [1, 2, 3, 4, 5] - b[1:3] = [0, 0] - - def this_is_also_fine(self): - self.maxint - - -def this_is_wrong(): - sys.maxint diff --git a/tests/b306.py b/tests/b306.py deleted file mode 100644 index 5fc93d4..0000000 --- a/tests/b306.py +++ /dev/null @@ -1,11 +0,0 @@ -""" -Should emit: -B306 - on line 9 -""" - -try: - import some_library -except ImportError as e: - print(e.message) -else: - print(some_library.message) diff --git a/tests/test_bugbear.py b/tests/test_bugbear.py index 428d313..0807f19 100644 --- a/tests/test_bugbear.py +++ b/tests/test_bugbear.py @@ -28,12 +28,6 @@ B015, B016, B017, - B301, - B302, - B303, - B304, - B305, - B306, B901, B902, B903, @@ -213,38 +207,6 @@ def test_b017(self): expected = self.errors(B017(22, 8)) self.assertEqual(errors, expected) - def test_b301_b302_b305(self): - filename = Path(__file__).absolute().parent / "b301_b302_b305.py" - bbc = BugBearChecker(filename=str(filename)) - errors = list(bbc.run()) - self.assertEqual( - errors, - self.errors( - B301(39, 4), - B301(40, 4), - B301(41, 4), - B301(42, 4), - B302(43, 4), - B302(44, 4), - B302(45, 4), - B302(46, 4), - B305(47, 4), - B305(48, 4), - ), - ) - - def test_b303_b304(self): - filename = Path(__file__).absolute().parent / "b303_b304.py" - bbc = BugBearChecker(filename=str(filename)) - errors = list(bbc.run()) - self.assertEqual(errors, self.errors(B303(25, 4), B304(46, 4))) - - def test_b306(self): - filename = Path(__file__).absolute().parent / "b306.py" - bbc = BugBearChecker(filename=str(filename)) - errors = list(bbc.run()) - self.assertEqual(errors, self.errors(B306(9, 10))) - def test_b901(self): filename = Path(__file__).absolute().parent / "b901.py" bbc = BugBearChecker(filename=str(filename))