Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-pyflakes for openSUSE:Factory checked in at 2022-12-07 17:35:05 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-pyflakes (Old) and /work/SRC/openSUSE:Factory/.python-pyflakes.new.1835 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-pyflakes" Wed Dec 7 17:35:05 2022 rev:30 rq:1040776 version:3.0.1 Changes: -------- --- /work/SRC/openSUSE:Factory/python-pyflakes/python-pyflakes.changes 2022-08-23 14:25:50.511119833 +0200 +++ /work/SRC/openSUSE:Factory/.python-pyflakes.new.1835/python-pyflakes.changes 2022-12-07 17:36:25.065016402 +0100 @@ -1,0 +2,11 @@ +Tue Dec 6 13:20:52 UTC 2022 - Yogalakshmi Arunachalam <yarunacha...@suse.com> + +- Update to version 3.0.1 (2022-11-24) + * Fix crash on augmented assign to print builtin + +- Update to version 3.0.0 (2022-11-23) + * Detect undefined name in variable defined by an annotated assignment + * Add a new error for names which are annotated but unused + * Remove handling of python 2.x # type: comments. Use annotations instead + +------------------------------------------------------------------- Old: ---- pyflakes-2.5.0.tar.gz New: ---- pyflakes-3.0.1.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-pyflakes.spec ++++++ --- /var/tmp/diff_new_pack.kBWozO/_old 2022-12-07 17:36:25.493018744 +0100 +++ /var/tmp/diff_new_pack.kBWozO/_new 2022-12-07 17:36:25.497018766 +0100 @@ -18,7 +18,7 @@ %{?!python_module:%define python_module() python-%{**} python3-%{**}} Name: python-pyflakes -Version: 2.5.0 +Version: 3.0.1 Release: 0 Summary: Passive checker of Python programs License: MIT ++++++ pyflakes-2.5.0.tar.gz -> pyflakes-3.0.1.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyflakes-2.5.0/NEWS.rst new/pyflakes-3.0.1/NEWS.rst --- old/pyflakes-2.5.0/NEWS.rst 2022-07-30 19:27:25.000000000 +0200 +++ new/pyflakes-3.0.1/NEWS.rst 2022-11-24 17:52:19.000000000 +0100 @@ -1,3 +1,13 @@ +3.0.1 (2022-11-24) + +- Fix crash on augmented assign to ``print`` builtin + +3.0.0 (2022-11-23) + +- Detect undefined name in variable defined by an annotated assignment +- Add a new error for names which are annotated but unused +- Remove handling of python 2.x ``# type:`` comments. Use annotations instead + 2.5.0 (2022-07-30) - Drop support for EOL python 2.7 / 3.4 / 3.5 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyflakes-2.5.0/PKG-INFO new/pyflakes-3.0.1/PKG-INFO --- old/pyflakes-2.5.0/PKG-INFO 2022-07-30 19:28:49.971378000 +0200 +++ new/pyflakes-3.0.1/PKG-INFO 2022-11-24 17:53:21.689930700 +0100 @@ -1,12 +1,11 @@ Metadata-Version: 2.1 Name: pyflakes -Version: 2.5.0 +Version: 3.0.1 Summary: passive checker of Python programs Home-page: https://github.com/PyCQA/pyflakes Author: A lot of people Author-email: code-qual...@python.org License: MIT -Platform: UNKNOWN Classifier: Development Status :: 6 - Mature Classifier: Environment :: Console Classifier: Intended Audience :: Developers @@ -52,11 +51,11 @@ Useful tips: * Be sure to install it for a version of Python which is compatible - with your codebase: for Python 2, ``pip2 install pyflakes`` and for - Python3, ``pip3 install pyflakes``. + with your codebase: ``python#.# -m pip install pyflakes`` (for example, + ``python3.10 -m pip install pyflakes``) -* You can also invoke Pyflakes with ``python3 -m pyflakes .`` or - ``python2 -m pyflakes .`` if you have it installed for both versions. +* You can also invoke Pyflakes with ``python#.# -m pyflakes .`` if you want + to run it for a specific python version. * If you require more options and more flexibility, you could give a look to Flake8_ too. @@ -92,7 +91,7 @@ Patches may be submitted via a `GitHub pull request`_ or via the mailing list if you prefer. If you are comfortable doing so, please `rebase your changes`_ -so they may be applied to master with a fast-forward merge, and each commit is +so they may be applied to main with a fast-forward merge, and each commit is a coherent unit of work with a well-written log message. If you are not comfortable with this rebase workflow, the project maintainers will be happy to rebase your commits for you. @@ -112,6 +111,4 @@ Changelog --------- -Please see `NEWS.rst <https://github.com/PyCQA/pyflakes/blob/master/NEWS.rst>`_. - - +Please see `NEWS.rst <https://github.com/PyCQA/pyflakes/blob/main/NEWS.rst>`_. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyflakes-2.5.0/README.rst new/pyflakes-3.0.1/README.rst --- old/pyflakes-2.5.0/README.rst 2022-07-30 19:03:28.000000000 +0200 +++ new/pyflakes-3.0.1/README.rst 2022-11-24 17:02:51.000000000 +0100 @@ -24,11 +24,11 @@ Useful tips: * Be sure to install it for a version of Python which is compatible - with your codebase: for Python 2, ``pip2 install pyflakes`` and for - Python3, ``pip3 install pyflakes``. + with your codebase: ``python#.# -m pip install pyflakes`` (for example, + ``python3.10 -m pip install pyflakes``) -* You can also invoke Pyflakes with ``python3 -m pyflakes .`` or - ``python2 -m pyflakes .`` if you have it installed for both versions. +* You can also invoke Pyflakes with ``python#.# -m pyflakes .`` if you want + to run it for a specific python version. * If you require more options and more flexibility, you could give a look to Flake8_ too. @@ -64,7 +64,7 @@ Patches may be submitted via a `GitHub pull request`_ or via the mailing list if you prefer. If you are comfortable doing so, please `rebase your changes`_ -so they may be applied to master with a fast-forward merge, and each commit is +so they may be applied to main with a fast-forward merge, and each commit is a coherent unit of work with a well-written log message. If you are not comfortable with this rebase workflow, the project maintainers will be happy to rebase your commits for you. @@ -84,4 +84,4 @@ Changelog --------- -Please see `NEWS.rst <https://github.com/PyCQA/pyflakes/blob/master/NEWS.rst>`_. +Please see `NEWS.rst <https://github.com/PyCQA/pyflakes/blob/main/NEWS.rst>`_. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyflakes-2.5.0/pyflakes/__init__.py new/pyflakes-3.0.1/pyflakes/__init__.py --- old/pyflakes-2.5.0/pyflakes/__init__.py 2022-07-30 19:27:25.000000000 +0200 +++ new/pyflakes-3.0.1/pyflakes/__init__.py 2022-11-24 17:52:30.000000000 +0100 @@ -1 +1 @@ -__version__ = '2.5.0' +__version__ = '3.0.1' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyflakes-2.5.0/pyflakes/api.py new/pyflakes-3.0.1/pyflakes/api.py --- old/pyflakes-2.5.0/pyflakes/api.py 2022-07-30 19:03:28.000000000 +0200 +++ new/pyflakes-3.0.1/pyflakes/api.py 2022-11-24 17:02:51.000000000 +0100 @@ -44,8 +44,7 @@ reporter.unexpectedError(filename, 'problem decoding source') return 1 # Okay, it's syntactically valid. Now check it. - file_tokens = checker.make_tokens(codeString) - w = checker.Checker(tree, file_tokens=file_tokens, filename=filename) + w = checker.Checker(tree, filename=filename) w.messages.sort(key=lambda m: m.lineno) for warning in w.messages: reporter.flake(warning) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyflakes-2.5.0/pyflakes/checker.py new/pyflakes-3.0.1/pyflakes/checker.py --- old/pyflakes-2.5.0/pyflakes/checker.py 2022-07-30 19:03:28.000000000 +0200 +++ new/pyflakes-3.0.1/pyflakes/checker.py 2022-11-24 17:51:58.000000000 +0100 @@ -7,8 +7,6 @@ import __future__ import builtins import ast -import bisect -import collections import contextlib import doctest import functools @@ -16,7 +14,7 @@ import re import string import sys -import tokenize +import warnings from pyflakes import messages @@ -78,16 +76,6 @@ ) -# https://github.com/python/typed_ast/blob/1.4.0/ast27/Parser/tokenizer.c#L102-L104 -TYPE_COMMENT_RE = re.compile(r'^#\s*type:\s*') -# https://github.com/python/typed_ast/blob/1.4.0/ast27/Parser/tokenizer.c#L1408-L1413 -ASCII_NON_ALNUM = ''.join([chr(i) for i in range(128) if not chr(i).isalnum()]) -TYPE_IGNORE_RE = re.compile( - TYPE_COMMENT_RE.pattern + fr'ignore([{ASCII_NON_ALNUM}]|$)') -# https://github.com/python/typed_ast/blob/1.4.0/ast27/Grammar/Grammar#L147 -TYPE_FUNC_RE = re.compile(r'^(\(.*?\))\s*->\s*(.*)$') - - MAPPING_KEY_RE = re.compile(r'\(([^()]*)\)') CONVERSION_FLAG_RE = re.compile('[#0+ -]*') WIDTH_RE = re.compile(r'(?:\*|\d*)') @@ -586,9 +574,8 @@ # Simplify: manage the special locals as globals self.globals = self.alwaysUsed.copy() self.returnValue = None # First non-empty return - self.isGenerator = False # Detect a generator - def unusedAssignments(self): + def unused_assignments(self): """ Return a generator for the assignments which have not been used. """ @@ -600,6 +587,14 @@ isinstance(binding, Assignment)): yield name, binding + def unused_annotations(self): + """ + Return a generator for the annotations which have not been used. + """ + for name, binding in self.items(): + if not binding.used and isinstance(binding, Annotation): + yield name, binding + class GeneratorScope(Scope): pass @@ -615,13 +610,6 @@ """Scope for a doctest.""" -class DummyNode: - """Used in place of an `ast.AST` to set error message positions""" - def __init__(self, lineno, col_offset): - self.lineno = lineno - self.col_offset = col_offset - - class DetectClassScopedMagic: names = dir() @@ -741,63 +729,6 @@ return in_annotation_func -def make_tokens(code): - # PY3: tokenize.tokenize requires readline of bytes - if not isinstance(code, bytes): - code = code.encode('UTF-8') - lines = iter(code.splitlines(True)) - # next(lines, b'') is to prevent an error in pypy3 - return tuple(tokenize.tokenize(lambda: next(lines, b''))) - - -class _TypeableVisitor(ast.NodeVisitor): - """Collect the line number and nodes which are deemed typeable by - PEP 484 - - https://www.python.org/dev/peps/pep-0484/#type-comments - """ - def __init__(self): - self.typeable_lines = [] - self.typeable_nodes = {} - - def _typeable(self, node): - # if there is more than one typeable thing on a line last one wins - self.typeable_lines.append(node.lineno) - self.typeable_nodes[node.lineno] = node - - self.generic_visit(node) - - visit_Assign = visit_For = visit_FunctionDef = visit_With = _typeable - visit_AsyncFor = visit_AsyncFunctionDef = visit_AsyncWith = _typeable - - -def _collect_type_comments(tree, tokens): - visitor = _TypeableVisitor() - visitor.visit(tree) - - type_comments = collections.defaultdict(list) - for tp, text, start, _, _ in tokens: - if ( - tp != tokenize.COMMENT or # skip non comments - not TYPE_COMMENT_RE.match(text) or # skip non-type comments - TYPE_IGNORE_RE.match(text) # skip ignores - ): - continue - - # search for the typeable node at or before the line number of the - # type comment. - # if the bisection insertion point is before any nodes this is an - # invalid type comment which is ignored. - lineno, _ = start - idx = bisect.bisect_right(visitor.typeable_lines, lineno) - if idx == 0: - continue - node = visitor.typeable_nodes[visitor.typeable_lines[idx - 1]] - type_comments[node].append((start, text)) - - return type_comments - - class Checker: """ I check the cleanliness and sanity of Python code. @@ -834,9 +765,6 @@ builtIns.update(_customBuiltIns.split(',')) del _customBuiltIns - # TODO: file_tokens= is required to perform checks on type comments, - # eventually make this a required positional argument. For now it - # is defaulted to `()` for api compatibility. def __init__(self, tree, filename='(none)', builtins=None, withDoctest='PYFLAKES_DOCTEST' in os.environ, file_tokens=()): self._nodeHandlers = {} @@ -854,7 +782,6 @@ raise RuntimeError('No scope implemented for the node %r' % tree) self.exceptHandlers = [()] self.root = tree - self._type_comments = _collect_type_comments(tree, file_tokens) for builtin in self.builtIns: self.addBinding(None, Builtin(builtin)) self.handleChildren(tree) @@ -871,6 +798,12 @@ self.popScope() self.checkDeadScopes() + if file_tokens: + warnings.warn( + '`file_tokens` will be removed in a future version', + stacklevel=2, + ) + def deferFunction(self, callable): """ Schedule a function handler to be called just before completion. @@ -1135,7 +1068,7 @@ ) return handler - def handleNodeLoad(self, node): + def handleNodeLoad(self, node, parent): name = getNodeName(node) if not name: return @@ -1156,10 +1089,10 @@ binding = scope.get(name, None) if isinstance(binding, Annotation) and not self._in_postponed_annotation: + scope[name].used = True continue if name == 'print' and isinstance(binding, Builtin): - parent = self.getParent(node) if (isinstance(parent, ast.BinOp) and isinstance(parent.op, ast.RShift)): self.report(messages.InvalidPrintSyntax, node) @@ -1299,27 +1232,7 @@ self.annotationsFutureEnabled ) - def _handle_type_comments(self, node): - for (lineno, col_offset), comment in self._type_comments.get(node, ()): - comment = comment.split(':', 1)[1].strip() - func_match = TYPE_FUNC_RE.match(comment) - if func_match: - parts = ( - func_match.group(1).replace('*', ''), - func_match.group(2).strip(), - ) - else: - parts = (comment,) - - for part in parts: - self.deferFunction(functools.partial( - self.handleStringAnnotation, - part, DummyNode(lineno, col_offset), lineno, col_offset, - messages.CommentAnnotationSyntaxError, - )) - def handleChildren(self, tree, omit=None): - self._handle_type_comments(tree) for node in iter_child_nodes(tree, omit=omit): self.handleNode(node, tree) @@ -1966,7 +1879,7 @@ """ # Locate the name in locals / function / globals scopes. if isinstance(node.ctx, ast.Load): - self.handleNodeLoad(node) + self.handleNodeLoad(node, self.getParent(node)) if (node.id == 'locals' and isinstance(self.scope, FunctionScope) and isinstance(node._pyflakes_parent, ast.Call)): # we are doing locals() call in current scope @@ -2022,7 +1935,6 @@ self.report(messages.YieldOutsideFunction, node) return - self.scope.isGenerator = True self.handleNode(node.value, node) AWAIT = YIELDFROM = YIELD @@ -2084,13 +1996,22 @@ self.handleChildren(node, omit=['decorator_list', 'returns']) - def checkUnusedAssignments(): + def check_unused_assignments(): """ Check to see if any assignments have not been used. """ - for name, binding in self.scope.unusedAssignments(): + for name, binding in self.scope.unused_assignments(): self.report(messages.UnusedVariable, binding.source, name) - self.deferAssignment(checkUnusedAssignments) + + def check_unused_annotations(): + """ + Check to see if any annotations have not been used. + """ + for name, binding in self.scope.unused_annotations(): + self.report(messages.UnusedAnnotation, binding.source, name) + + self.deferAssignment(check_unused_assignments) + self.deferAssignment(check_unused_annotations) self.popScope() @@ -2127,7 +2048,7 @@ self.addBinding(node, ClassDefinition(node.name, node)) def AUGASSIGN(self, node): - self.handleNodeLoad(node.target) + self.handleNodeLoad(node.target, node) self.handleNode(node.value, node) self.handleNode(node.target, node) @@ -2265,7 +2186,6 @@ self.scope[node.name] = prev_definition def ANNASSIGN(self, node): - self.handleNode(node.target, node) self.handleAnnotation(node.annotation, node) # If the assignment has value, handle the *value* now. if node.value: @@ -2274,6 +2194,7 @@ self.handleAnnotation(node.value, node) else: self.handleNode(node.value, node) + self.handleNode(node.target, node) def COMPARE(self, node): left = node.left diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyflakes-2.5.0/pyflakes/messages.py new/pyflakes-3.0.1/pyflakes/messages.py --- old/pyflakes-2.5.0/pyflakes/messages.py 2022-07-30 19:03:28.000000000 +0200 +++ new/pyflakes-3.0.1/pyflakes/messages.py 2022-11-24 17:02:51.000000000 +0100 @@ -134,10 +134,6 @@ class LateFutureImport(Message): message = 'from __future__ imports must occur at the beginning of the file' - def __init__(self, filename, loc): - Message.__init__(self, filename, loc) - self.message_args = () - class FutureFeatureNotDefined(Message): """An undefined __future__ feature name was imported.""" @@ -160,6 +156,18 @@ self.message_args = (names,) +class UnusedAnnotation(Message): + """ + Indicates that a variable has been explicitly annotated to but not actually + used. + """ + message = 'local variable %r is annotated but never used' + + def __init__(self, filename, loc, names): + Message.__init__(self, filename, loc) + self.message_args = (names,) + + class ReturnOutsideFunction(Message): """ Indicates a return statement outside of a function/method. @@ -237,14 +245,6 @@ def __init__(self, filename, loc, annotation): Message.__init__(self, filename, loc) - self.message_args = (annotation,) - - -class CommentAnnotationSyntaxError(Message): - message = 'syntax error in type comment %r' - - def __init__(self, filename, loc, annotation): - Message.__init__(self, filename, loc) self.message_args = (annotation,) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyflakes-2.5.0/pyflakes/test/harness.py new/pyflakes-3.0.1/pyflakes/test/harness.py --- old/pyflakes-2.5.0/pyflakes/test/harness.py 2022-07-30 19:03:28.000000000 +0200 +++ new/pyflakes-3.0.1/pyflakes/test/harness.py 2022-11-24 17:02:51.000000000 +0100 @@ -16,13 +16,10 @@ def flakes(self, input, *expectedOutputs, **kw): tree = ast.parse(textwrap.dedent(input)) - file_tokens = checker.make_tokens(textwrap.dedent(input)) if kw.get('is_segment'): tree = tree.body[0] kw.pop('is_segment') - w = checker.Checker( - tree, file_tokens=file_tokens, withDoctest=self.withDoctest, **kw - ) + w = checker.Checker(tree, withDoctest=self.withDoctest, **kw) outputs = [type(o) for o in w.messages] expectedOutputs = list(expectedOutputs) outputs.sort(key=lambda t: t.__name__) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyflakes-2.5.0/pyflakes/test/test_checker.py new/pyflakes-3.0.1/pyflakes/test/test_checker.py --- old/pyflakes-2.5.0/pyflakes/test/test_checker.py 2022-07-30 19:03:28.000000000 +0200 +++ new/pyflakes-3.0.1/pyflakes/test/test_checker.py 1970-01-01 01:00:00.000000000 +0100 @@ -1,184 +0,0 @@ -import ast - -from pyflakes import checker -from pyflakes.test.harness import TestCase - - -class TypeableVisitorTests(TestCase): - """ - Tests of L{_TypeableVisitor} - """ - - @staticmethod - def _run_visitor(s): - """ - Run L{_TypeableVisitor} on the parsed source and return the visitor. - """ - tree = ast.parse(s) - visitor = checker._TypeableVisitor() - visitor.visit(tree) - return visitor - - def test_node_types(self): - """ - Test that the typeable node types are collected - """ - visitor = self._run_visitor( - """\ -x = 1 # assignment -for x in range(1): pass # for loop -def f(): pass # function definition -with a as b: pass # with statement -""" - ) - self.assertEqual(visitor.typeable_lines, [1, 2, 3, 4]) - self.assertIsInstance(visitor.typeable_nodes[1], ast.Assign) - self.assertIsInstance(visitor.typeable_nodes[2], ast.For) - self.assertIsInstance(visitor.typeable_nodes[3], ast.FunctionDef) - self.assertIsInstance(visitor.typeable_nodes[4], ast.With) - - def test_visitor_recurses(self): - """ - Test the common pitfall of missing `generic_visit` in visitors by - ensuring that nested nodes are reported - """ - visitor = self._run_visitor( - """\ -def f(): - x = 1 -""" - ) - self.assertEqual(visitor.typeable_lines, [1, 2]) - self.assertIsInstance(visitor.typeable_nodes[1], ast.FunctionDef) - self.assertIsInstance(visitor.typeable_nodes[2], ast.Assign) - - def test_py35_node_types(self): - """ - Test that the PEP 492 node types are collected - """ - visitor = self._run_visitor( - """\ -async def f(): # async def - async for x in y: pass # async for - async with a as b: pass # async with -""" - ) - self.assertEqual(visitor.typeable_lines, [1, 2, 3]) - self.assertIsInstance(visitor.typeable_nodes[1], ast.AsyncFunctionDef) - self.assertIsInstance(visitor.typeable_nodes[2], ast.AsyncFor) - self.assertIsInstance(visitor.typeable_nodes[3], ast.AsyncWith) - - def test_last_node_wins(self): - """ - Test that when two typeable nodes are present on a line, the last - typeable one wins. - """ - visitor = self._run_visitor('x = 1; y = 1') - # detected both assignable nodes - self.assertEqual(visitor.typeable_lines, [1, 1]) - # but the assignment to `y` wins - self.assertEqual(visitor.typeable_nodes[1].targets[0].id, 'y') - - -class CollectTypeCommentsTests(TestCase): - """ - Tests of L{_collect_type_comments} - """ - - @staticmethod - def _collect(s): - """ - Run L{_collect_type_comments} on the parsed source and return the - mapping from nodes to comments. The return value is converted to - a set: {(node_type, tuple of comments), ...} - """ - tree = ast.parse(s) - tokens = checker.make_tokens(s) - ret = checker._collect_type_comments(tree, tokens) - return {(type(k), tuple(s for _, s in v)) for k, v in ret.items()} - - def test_bytes(self): - """ - Test that the function works for binary source - """ - ret = self._collect(b'x = 1 # type: int') - self.assertSetEqual(ret, {(ast.Assign, ('# type: int',))}) - - def test_text(self): - """ - Test that the function works for text source - """ - ret = self._collect('x = 1 # type: int') - self.assertEqual(ret, {(ast.Assign, ('# type: int',))}) - - def test_non_type_comment_ignored(self): - """ - Test that a non-type comment is ignored - """ - ret = self._collect('x = 1 # noqa') - self.assertSetEqual(ret, set()) - - def test_type_comment_before_typeable(self): - """ - Test that a type comment before something typeable is ignored. - """ - ret = self._collect('# type: int\nx = 1') - self.assertSetEqual(ret, set()) - - def test_type_ignore_comment_ignored(self): - """ - Test that `# type: ignore` comments are not collected. - """ - ret = self._collect('x = 1 # type: ignore') - self.assertSetEqual(ret, set()) - - def test_type_ignore_with_other_things_ignored(self): - """ - Test that `# type: ignore` comments with more content are also not - collected. - """ - ret = self._collect('x = 1 # type: ignore # noqa') - self.assertSetEqual(ret, set()) - ret = self._collect('x = 1 #type:ignore#noqa') - self.assertSetEqual(ret, set()) - - def test_type_comment_with_extra_still_collected(self): - ret = self._collect('x = 1 # type: int # noqa') - self.assertSetEqual(ret, {(ast.Assign, ('# type: int # noqa',))}) - - def test_type_comment_without_whitespace(self): - ret = self._collect('x = 1 #type:int') - self.assertSetEqual(ret, {(ast.Assign, ('#type:int',))}) - - def test_type_comment_starts_with_word_ignore(self): - ret = self._collect('x = 1 # type: ignore[T]') - self.assertSetEqual(ret, set()) - - def test_last_node_wins(self): - """ - Test that when two typeable nodes are present on a line, the last - typeable one wins. - """ - ret = self._collect('def f(): x = 1 # type: int') - self.assertSetEqual(ret, {(ast.Assign, ('# type: int',))}) - - def test_function_def_assigned_comments(self): - """ - Test that type comments for function arguments are all attributed to - the function definition. - """ - ret = self._collect( - """\ -def f( - a, # type: int - b, # type: str -): - # type: (...) -> None - pass -""" - ) - expected = {( - ast.FunctionDef, - ('# type: int', '# type: str', '# type: (...) -> None'), - )} - self.assertSetEqual(ret, expected) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyflakes-2.5.0/pyflakes/test/test_other.py new/pyflakes-3.0.1/pyflakes/test/test_other.py --- old/pyflakes-2.5.0/pyflakes/test/test_other.py 2022-07-30 19:03:28.000000000 +0200 +++ new/pyflakes-3.0.1/pyflakes/test/test_other.py 2022-11-24 17:51:58.000000000 +0100 @@ -2052,6 +2052,10 @@ self.assertEqual(exc.lineno, 4) self.assertEqual(exc.col, 0) + def test_print_augmented_assign(self): + # nonsense, but shouldn't crash pyflakes + self.flakes('print += 1') + def test_print_function_assignment(self): """ A valid assignment, tested for catching false positives. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyflakes-2.5.0/pyflakes/test/test_type_annotations.py new/pyflakes-3.0.1/pyflakes/test/test_type_annotations.py --- old/pyflakes-2.5.0/pyflakes/test/test_type_annotations.py 2022-07-30 19:03:28.000000000 +0200 +++ new/pyflakes-3.0.1/pyflakes/test/test_type_annotations.py 2022-11-24 17:02:51.000000000 +0100 @@ -17,22 +17,22 @@ from typing import overload @overload - def f(s): # type: (None) -> None + def f(s: None) -> None: pass @overload - def f(s): # type: (int) -> int + def f(s: int) -> int: pass def f(s): return s @typing.overload - def g(s): # type: (None) -> None + def g(s: None) -> None: pass @typing.overload - def g(s): # type: (int) -> int + def g(s: int) -> int: pass def g(s): @@ -46,22 +46,22 @@ from typing_extensions import overload @overload - def f(s): # type: (None) -> None + def f(s: None) -> None: pass @overload - def f(s): # type: (int) -> int + def f(s: int) -> int: pass def f(s): return s @typing_extensions.overload - def g(s): # type: (None) -> None + def g(s: None) -> None: pass @typing_extensions.overload - def g(s): # type: (int) -> int + def g(s: int) -> int: pass def g(s): @@ -74,11 +74,11 @@ from typing import overload @overload - async def f(s): # type: (None) -> None + async def f(s: None) -> None: pass @overload - async def f(s): # type: (int) -> int + async def f(s: int) -> int: pass async def f(s): @@ -92,12 +92,12 @@ @dec @overload - def f(x): # type: (int) -> int + def f(x: int) -> int: pass @dec @overload - def f(x): # type: (str) -> str + def f(x: str) -> str: pass @dec @@ -110,11 +110,11 @@ class C: @overload - def f(self, x): # type: (int) -> int + def f(self, x: int) -> int: pass @overload - def f(self, x): # type: (str) -> str + def f(self, x: str) -> str: pass def f(self, x): return x @@ -126,11 +126,11 @@ import typing as t @t.overload - def f(s): # type: (None) -> None + def f(s: None) -> None: pass @t.overload - def f(s): # type: (int) -> int + def f(s: int) -> int: pass def f(s): @@ -174,7 +174,7 @@ def f(): name: str age: int - ''') + ''', m.UnusedAnnotation, m.UnusedAnnotation) self.flakes(''' def f(): name: str = 'Bob' @@ -190,7 +190,7 @@ from typing import Any def f(): a: Any - ''') + ''', m.UnusedAnnotation) self.flakes(''' foo: not_a_real_type ''', m.UndefinedName) @@ -298,6 +298,11 @@ a: 'a: "A"' ''', m.ForwardAnnotationSyntaxError) + def test_variable_annotation_references_self_name_undefined(self): + self.flakes(""" + x: int = x + """, m.UndefinedName) + def test_TypeAlias_annotations(self): self.flakes(""" from typing_extensions import TypeAlias @@ -351,11 +356,10 @@ class Cls: y: int ''') - # TODO: this should print a UnusedVariable message self.flakes(''' def f(): x: int - ''') + ''', m.UnusedAnnotation) # This should only print one UnusedVariable message self.flakes(''' def f(): @@ -363,6 +367,12 @@ x = 3 ''', m.UnusedVariable) + def test_unassigned_annotation_is_undefined(self): + self.flakes(''' + name: str + print(name) + ''', m.UndefinedName) + def test_annotated_async_def(self): self.flakes(''' class c: pass @@ -406,115 +416,6 @@ __all__: List[str] ''') - def test_typeCommentsMarkImportsAsUsed(self): - self.flakes(""" - from mod import A, B, C, D, E, F, G - - - def f( - a, # type: A - ): - # type: (...) -> B - for b in a: # type: C - with b as c: # type: D - d = c.x # type: E - return d - - - def g(x): # type: (F) -> G - return x.y - """) - - def test_typeCommentsFullSignature(self): - self.flakes(""" - from mod import A, B, C, D - def f(a, b): - # type: (A, B[C]) -> D - return a + b - """) - - def test_typeCommentsStarArgs(self): - self.flakes(""" - from mod import A, B, C, D - def f(a, *b, **c): - # type: (A, *B, **C) -> D - return a + b - """) - - def test_typeCommentsFullSignatureWithDocstring(self): - self.flakes(''' - from mod import A, B, C, D - def f(a, b): - # type: (A, B[C]) -> D - """do the thing!""" - return a + b - ''') - - def test_typeCommentsAdditionalComment(self): - self.flakes(""" - from mod import F - - x = 1 # type: F # noqa - """) - - def test_typeCommentsNoWhitespaceAnnotation(self): - self.flakes(""" - from mod import F - - x = 1 #type:F - """) - - def test_typeCommentsInvalidDoesNotMarkAsUsed(self): - self.flakes(""" - from mod import F - - # type: F - """, m.UnusedImport) - - def test_typeCommentsSyntaxError(self): - self.flakes(""" - def f(x): # type: (F[) -> None - pass - """, m.CommentAnnotationSyntaxError) - - def test_typeCommentsSyntaxErrorCorrectLine(self): - checker = self.flakes("""\ - x = 1 - # type: definitely not a PEP 484 comment - """, m.CommentAnnotationSyntaxError) - self.assertEqual(checker.messages[0].lineno, 2) - - def test_typeCommentsAssignedToPreviousNode(self): - # This test demonstrates an issue in the implementation which - # associates the type comment with a node above it, however the type - # comment isn't valid according to mypy. If an improved approach - # which can detect these "invalid" type comments is implemented, this - # test should be removed / improved to assert that new check. - self.flakes(""" - from mod import F - x = 1 - # type: F - """) - - def test_typeIgnore(self): - self.flakes(""" - a = 0 # type: ignore - b = 0 # type: ignore[excuse] - c = 0 # type: ignore=excuse - d = 0 # type: ignore [excuse] - e = 0 # type: ignore whatever - """) - - def test_typeIgnoreBogus(self): - self.flakes(""" - x = 1 # type: ignored - """, m.UndefinedName) - - def test_typeIgnoreBogusUnicode(self): - self.flakes(""" - x = 2 # type: ignore\xc3 - """, m.UndefinedName) - def test_return_annotation_is_class_scope_variable(self): self.flakes(""" from typing import TypeVar @@ -704,7 +605,7 @@ if TYPE_CHECKING: from t import T - def f(): # type: () -> T + def f() -> T: pass """) # False: the old, more-compatible approach @@ -712,7 +613,7 @@ if False: from t import T - def f(): # type: () -> T + def f() -> T: pass """) # some choose to assign a constant and do it that way @@ -722,7 +623,7 @@ if MYPY: from t import T - def f(): # type: () -> T + def f() -> T: pass """) @@ -736,7 +637,7 @@ Protocol = object class C(Protocol): - def f(): # type: () -> int + def f() -> int: pass """) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyflakes-2.5.0/pyflakes/test/test_undefined_names.py new/pyflakes-3.0.1/pyflakes/test/test_undefined_names.py --- old/pyflakes-2.5.0/pyflakes/test/test_undefined_names.py 2022-07-30 19:03:28.000000000 +0200 +++ new/pyflakes-3.0.1/pyflakes/test/test_undefined_names.py 2022-11-24 17:18:39.000000000 +0100 @@ -814,7 +814,6 @@ raised. """ tree = ast.parse("x = 10") - file_tokens = checker.make_tokens("x = 10") # Make it into something unrecognizable. tree.body[0].targets[0].ctx = object() - self.assertRaises(RuntimeError, checker.Checker, tree, file_tokens=file_tokens) + self.assertRaises(RuntimeError, checker.Checker, tree) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyflakes-2.5.0/pyflakes.egg-info/PKG-INFO new/pyflakes-3.0.1/pyflakes.egg-info/PKG-INFO --- old/pyflakes-2.5.0/pyflakes.egg-info/PKG-INFO 2022-07-30 19:28:49.000000000 +0200 +++ new/pyflakes-3.0.1/pyflakes.egg-info/PKG-INFO 2022-11-24 17:53:21.000000000 +0100 @@ -1,12 +1,11 @@ Metadata-Version: 2.1 Name: pyflakes -Version: 2.5.0 +Version: 3.0.1 Summary: passive checker of Python programs Home-page: https://github.com/PyCQA/pyflakes Author: A lot of people Author-email: code-qual...@python.org License: MIT -Platform: UNKNOWN Classifier: Development Status :: 6 - Mature Classifier: Environment :: Console Classifier: Intended Audience :: Developers @@ -52,11 +51,11 @@ Useful tips: * Be sure to install it for a version of Python which is compatible - with your codebase: for Python 2, ``pip2 install pyflakes`` and for - Python3, ``pip3 install pyflakes``. + with your codebase: ``python#.# -m pip install pyflakes`` (for example, + ``python3.10 -m pip install pyflakes``) -* You can also invoke Pyflakes with ``python3 -m pyflakes .`` or - ``python2 -m pyflakes .`` if you have it installed for both versions. +* You can also invoke Pyflakes with ``python#.# -m pyflakes .`` if you want + to run it for a specific python version. * If you require more options and more flexibility, you could give a look to Flake8_ too. @@ -92,7 +91,7 @@ Patches may be submitted via a `GitHub pull request`_ or via the mailing list if you prefer. If you are comfortable doing so, please `rebase your changes`_ -so they may be applied to master with a fast-forward merge, and each commit is +so they may be applied to main with a fast-forward merge, and each commit is a coherent unit of work with a well-written log message. If you are not comfortable with this rebase workflow, the project maintainers will be happy to rebase your commits for you. @@ -112,6 +111,4 @@ Changelog --------- -Please see `NEWS.rst <https://github.com/PyCQA/pyflakes/blob/master/NEWS.rst>`_. - - +Please see `NEWS.rst <https://github.com/PyCQA/pyflakes/blob/main/NEWS.rst>`_. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyflakes-2.5.0/pyflakes.egg-info/SOURCES.txt new/pyflakes-3.0.1/pyflakes.egg-info/SOURCES.txt --- old/pyflakes-2.5.0/pyflakes.egg-info/SOURCES.txt 2022-07-30 19:28:49.000000000 +0200 +++ new/pyflakes-3.0.1/pyflakes.egg-info/SOURCES.txt 2022-11-24 17:53:21.000000000 +0100 @@ -23,7 +23,6 @@ pyflakes/test/harness.py pyflakes/test/test_api.py pyflakes/test/test_builtin.py -pyflakes/test/test_checker.py pyflakes/test/test_code_segment.py pyflakes/test/test_dict.py pyflakes/test/test_doctests.py