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-16 17:51:42
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-pyflakes (Old)
and /work/SRC/openSUSE:Factory/.python-pyflakes.new.1835 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-pyflakes"
Fri Dec 16 17:51:42 2022 rev:34 rq:1043220 version:3.0.1
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-pyflakes/python-pyflakes.changes
2022-12-15 20:16:31.177315362 +0100
+++
/work/SRC/openSUSE:Factory/.python-pyflakes.new.1835/python-pyflakes.changes
2022-12-16 17:51:50.036077840 +0100
@@ -1,0 +2,9 @@
+Thu Dec 15 20:50:51 UTC 2022 - Dirk Müller <[email protected]>
+
+- update to 3.0.1 (bsc#1206225):
+ * 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.hQkdwI/_old 2022-12-16 17:51:51.124083829 +0100
+++ /var/tmp/diff_new_pack.hQkdwI/_new 2022-12-16 17:51:51.128083851 +0100
@@ -18,13 +18,14 @@
%{?!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
Group: Development/Languages/Python
URL: https://github.com/PyCQA/pyflakes
Source:
https://files.pythonhosted.org/packages/source/p/pyflakes/pyflakes-%{version}.tar.gz
+BuildRequires: %{python_module base >= 3.8}
BuildRequires: %{python_module setuptools}
BuildRequires: fdupes
BuildRequires: python-rpm-macros
++++++ 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: [email protected]
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: [email protected]
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