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 2023-08-14 22:35:01
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-pyflakes (Old)
 and      /work/SRC/openSUSE:Factory/.python-pyflakes.new.11712 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-pyflakes"

Mon Aug 14 22:35:01 2023 rev:37 rq:1102806 version:3.1.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-pyflakes/python-pyflakes.changes  
2023-07-12 17:28:31.278988747 +0200
+++ 
/work/SRC/openSUSE:Factory/.python-pyflakes.new.11712/python-pyflakes.changes   
    2023-08-14 22:35:13.756213766 +0200
@@ -1,0 +2,15 @@
+Tue Aug  8 06:20:25 UTC 2023 - Steve Kowalik <steven.kowa...@suse.com>
+
+- Update to 3.1.0:
+  * Drop support for EOL python 3.6 / 3.7
+  * Remove ``ContinueInFinally`` check (only relevant in python < 3.8)
+  * Fix forward annotations inside a nested scope
+  * Produce an error when a definition shadows an unused variable
+  * Fix accessed global annotation being redefined in a local scope
+  * Allow redefinition of functions across ``match`` arms
+  * Fix potential ``None`` for ``lineno`` during tokenization errors
+  * Add support for PEP 695 and python 3.12
+- Switch to pyproject macros.
+- Drop patch py3114.patch, included now.
+
+-------------------------------------------------------------------

Old:
----
  py3114.patch
  pyflakes-3.0.1.tar.gz

New:
----
  pyflakes-3.1.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-pyflakes.spec ++++++
--- /var/tmp/diff_new_pack.iiVdmP/_old  2023-08-14 22:35:14.316217327 +0200
+++ /var/tmp/diff_new_pack.iiVdmP/_new  2023-08-14 22:35:14.320217352 +0200
@@ -18,17 +18,16 @@
 
 %{?sle15_python_module_pythons}
 Name:           python-pyflakes
-Version:        3.0.1
+Version:        3.1.0
 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
-#PATCH-FIX-UPSTREAM 
https://github.com/PyCQA/pyflakes/commit/836631f2f73d45baa4021453d89fc9fd6f52be58
 fix error reporter and testsuite in 3.11.4+
-Patch:          py3114.patch
 BuildRequires:  %{python_module base >= 3.8}
+BuildRequires:  %{python_module pip}
 BuildRequires:  %{python_module setuptools}
+BuildRequires:  %{python_module wheel}
 BuildRequires:  fdupes
 BuildRequires:  python-rpm-macros
 # the pkg_resources module is required at runtime
@@ -47,10 +46,10 @@
 %autosetup -p1 -n pyflakes-%{version}
 
 %build
-%python_build
+%pyproject_wheel
 
 %install
-%python_install
+%pyproject_install
 %python_expand %fdupes %{buildroot}%{$python_sitelib}/pyflakes/
 %python_clone -a %{buildroot}%{_bindir}/pyflakes
 
@@ -68,6 +67,6 @@
 %doc NEWS.rst README.rst AUTHORS
 %python_alternative %{_bindir}/pyflakes
 %{python_sitelib}/pyflakes/
-%{python_sitelib}/pyflakes-%{version}-py*.egg-info
+%{python_sitelib}/pyflakes-%{version}.dist-info
 
 %changelog

++++++ pyflakes-3.0.1.tar.gz -> pyflakes-3.1.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pyflakes-3.0.1/NEWS.rst new/pyflakes-3.1.0/NEWS.rst
--- old/pyflakes-3.0.1/NEWS.rst 2022-11-24 17:52:19.000000000 +0100
+++ new/pyflakes-3.1.0/NEWS.rst 2023-07-29 18:57:43.000000000 +0200
@@ -1,3 +1,14 @@
+3.1.0 (2023-07-29)
+
+- Drop support for EOL python 3.6 / 3.7
+- Remove ``ContinueInFinally`` check (only relevant in python < 3.8)
+- Fix forward annotations inside a nested scope
+- Produce an error when a definition shadows an unused variable
+- Fix accessed global annotation being redefined in a local scope
+- Allow redefinition of functions across ``match`` arms
+- Fix potential ``None`` for ``lineno`` during tokenization errors
+- Add support for PEP 695 and python 3.12
+
 3.0.1 (2022-11-24)
 
 - Fix crash on augmented assign to ``print`` builtin
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pyflakes-3.0.1/PKG-INFO new/pyflakes-3.1.0/PKG-INFO
--- old/pyflakes-3.0.1/PKG-INFO 2022-11-24 17:53:21.689930700 +0100
+++ new/pyflakes-3.1.0/PKG-INFO 2023-07-29 19:00:24.935112200 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: pyflakes
-Version: 3.0.1
+Version: 3.1.0
 Summary: passive checker of Python programs
 Home-page: https://github.com/PyCQA/pyflakes
 Author: A lot of people
@@ -12,17 +12,12 @@
 Classifier: License :: OSI Approved :: MIT License
 Classifier: Programming Language :: Python
 Classifier: Programming Language :: Python :: 3
-Classifier: Programming Language :: Python :: 3.6
-Classifier: Programming Language :: Python :: 3.7
-Classifier: Programming Language :: Python :: 3.8
-Classifier: Programming Language :: Python :: 3.9
-Classifier: Programming Language :: Python :: 3.10
 Classifier: Programming Language :: Python :: 3 :: Only
 Classifier: Programming Language :: Python :: Implementation :: CPython
 Classifier: Programming Language :: Python :: Implementation :: PyPy
 Classifier: Topic :: Software Development
 Classifier: Topic :: Utilities
-Requires-Python: >=3.6
+Requires-Python: >=3.8
 License-File: LICENSE
 
 ========
@@ -89,8 +84,8 @@
 
 Issues are tracked on `GitHub <https://github.com/PyCQA/pyflakes/issues>`_.
 
-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`_
+Patches may be submitted via a `GitHub pull request`_.
+If you are comfortable doing so, please `rebase your changes`_
 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
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pyflakes-3.0.1/README.rst 
new/pyflakes-3.1.0/README.rst
--- old/pyflakes-3.0.1/README.rst       2022-11-24 17:02:51.000000000 +0100
+++ new/pyflakes-3.1.0/README.rst       2023-01-31 19:28:24.000000000 +0100
@@ -62,8 +62,8 @@
 
 Issues are tracked on `GitHub <https://github.com/PyCQA/pyflakes/issues>`_.
 
-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`_
+Patches may be submitted via a `GitHub pull request`_.
+If you are comfortable doing so, please `rebase your changes`_
 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
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pyflakes-3.0.1/pyflakes/__init__.py 
new/pyflakes-3.1.0/pyflakes/__init__.py
--- old/pyflakes-3.0.1/pyflakes/__init__.py     2022-11-24 17:52:30.000000000 
+0100
+++ new/pyflakes-3.1.0/pyflakes/__init__.py     2023-07-29 18:58:22.000000000 
+0200
@@ -1 +1 @@
-__version__ = '3.0.1'
+__version__ = '3.1.0'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pyflakes-3.0.1/pyflakes/checker.py 
new/pyflakes-3.1.0/pyflakes/checker.py
--- old/pyflakes-3.0.1/pyflakes/checker.py      2022-11-24 17:51:58.000000000 
+0100
+++ new/pyflakes-3.1.0/pyflakes/checker.py      2023-07-29 18:51:35.000000000 
+0200
@@ -7,6 +7,7 @@
 import __future__
 import builtins
 import ast
+import collections
 import contextlib
 import doctest
 import functools
@@ -18,7 +19,6 @@
 
 from pyflakes import messages
 
-PY38_PLUS = sys.version_info >= (3, 8)
 PYPY = hasattr(sys, 'pypy_version_info')
 
 builtin_vars = dir(builtins)
@@ -29,21 +29,20 @@
 def getAlternatives(n):
     if isinstance(n, ast.If):
         return [n.body]
-    if isinstance(n, ast.Try):
+    elif isinstance(n, ast.Try):
         return [n.body + n.orelse] + [[hdl] for hdl in n.handlers]
+    elif sys.version_info >= (3, 10) and isinstance(n, ast.Match):
+        return [mc.body for mc in n.cases]
 
 
 FOR_TYPES = (ast.For, ast.AsyncFor)
 
-if PY38_PLUS:
-    def _is_singleton(node):  # type: (ast.AST) -> bool
-        return (
-            isinstance(node, ast.Constant) and
-            isinstance(node.value, (bool, type(Ellipsis), type(None)))
-        )
-else:
-    def _is_singleton(node):  # type: (ast.AST) -> bool
-        return isinstance(node, (ast.NameConstant, ast.Ellipsis))
+
+def _is_singleton(node):  # type: (ast.AST) -> bool
+    return (
+        isinstance(node, ast.Constant) and
+        isinstance(node.value, (bool, type(Ellipsis), type(None)))
+    )
 
 
 def _is_tuple_constant(node):  # type: (ast.AST) -> bool
@@ -53,16 +52,8 @@
     )
 
 
-if PY38_PLUS:
-    def _is_constant(node):
-        return isinstance(node, ast.Constant) or _is_tuple_constant(node)
-else:
-    def _is_constant(node):
-        return (
-            isinstance(node, (ast.Str, ast.Num, ast.Bytes)) or
-            _is_singleton(node) or
-            _is_tuple_constant(node)
-        )
+def _is_constant(node):
+    return isinstance(node, ast.Constant) or _is_tuple_constant(node)
 
 
 def _is_const_non_singleton(node):  # type: (ast.AST) -> bool
@@ -209,27 +200,12 @@
 
 
 def convert_to_value(item):
-    if isinstance(item, ast.Str):
-        return item.s
-    elif hasattr(ast, 'Bytes') and isinstance(item, ast.Bytes):
-        return item.s
+    if isinstance(item, ast.Constant):
+        return item.value
     elif isinstance(item, ast.Tuple):
         return tuple(convert_to_value(i) for i in item.elts)
-    elif isinstance(item, ast.Num):
-        return item.n
     elif isinstance(item, ast.Name):
-        result = VariableKey(item=item)
-        constants_lookup = {
-            'True': True,
-            'False': False,
-            'None': None,
-        }
-        return constants_lookup.get(
-            result.name,
-            result,
-        )
-    elif isinstance(item, ast.NameConstant):
-        return item.value
+        return VariableKey(item=item)
     else:
         return UnhandledKeyType()
 
@@ -274,6 +250,11 @@
     """
     A binding that defines a function or a class.
     """
+    def redefines(self, other):
+        return (
+            super().redefines(other) or
+            (isinstance(other, Assignment) and self.name == other.name)
+        )
 
 
 class Builtin(Definition):
@@ -521,8 +502,8 @@
 
         def _add_to_names(container):
             for node in container.elts:
-                if isinstance(node, ast.Str):
-                    self.names.append(node.s)
+                if isinstance(node, ast.Constant) and isinstance(node.value, 
str):
+                    self.names.append(node.value)
 
         if isinstance(source.value, (ast.List, ast.Tuple)):
             _add_to_names(source.value)
@@ -596,6 +577,10 @@
                 yield name, binding
 
 
+class TypeScope(Scope):
+    pass
+
+
 class GeneratorScope(Scope):
     pass
 
@@ -730,17 +715,7 @@
 
 
 class Checker:
-    """
-    I check the cleanliness and sanity of Python code.
-
-    @ivar _deferredFunctions: Tracking list used by L{deferFunction}.  Elements
-        of the list are two-tuples.  The first element is the callable passed
-        to L{deferFunction}.  The second element is a copy of the scope stack
-        at the time L{deferFunction} was called.
-
-    @ivar _deferredAssignments: Similar to C{_deferredFunctions}, but for
-        callables which are deferred assignment checks.
-    """
+    """I check the cleanliness and sanity of Python code."""
 
     _ast_node_scope = {
         ast.Module: ModuleScope,
@@ -757,7 +732,6 @@
     nodeDepth = 0
     offset = None
     _in_annotation = AnnotationState.NONE
-    _in_deferred = False
 
     builtIns = set(builtin_vars).union(_MAGIC_GLOBALS)
     _customBuiltIns = os.environ.get('PYFLAKES_BUILTINS')
@@ -768,34 +742,28 @@
     def __init__(self, tree, filename='(none)', builtins=None,
                  withDoctest='PYFLAKES_DOCTEST' in os.environ, file_tokens=()):
         self._nodeHandlers = {}
-        self._deferredFunctions = []
-        self._deferredAssignments = []
+        self._deferred = collections.deque()
         self.deadScopes = []
         self.messages = []
         self.filename = filename
         if builtins:
             self.builtIns = self.builtIns.union(builtins)
         self.withDoctest = withDoctest
+        self.exceptHandlers = [()]
+        self.root = tree
+
+        self.scopeStack = []
         try:
-            self.scopeStack = [Checker._ast_node_scope[type(tree)]()]
+            scope_tp = Checker._ast_node_scope[type(tree)]
         except KeyError:
             raise RuntimeError('No scope implemented for the node %r' % tree)
-        self.exceptHandlers = [()]
-        self.root = tree
-        for builtin in self.builtIns:
-            self.addBinding(None, Builtin(builtin))
-        self.handleChildren(tree)
-        self._in_deferred = True
-        self.runDeferred(self._deferredFunctions)
-        # Set _deferredFunctions to None so that deferFunction will fail
-        # noisily if called after we've run through the deferred functions.
-        self._deferredFunctions = None
-        self.runDeferred(self._deferredAssignments)
-        # Set _deferredAssignments to None so that deferAssignment will fail
-        # noisily if called after we've run through the deferred assignments.
-        self._deferredAssignments = None
-        del self.scopeStack[1:]
-        self.popScope()
+
+        with self.in_scope(scope_tp):
+            for builtin in self.builtIns:
+                self.addBinding(None, Builtin(builtin))
+            self.handleChildren(tree)
+            self._run_deferred()
+
         self.checkDeadScopes()
 
         if file_tokens:
@@ -813,24 +781,18 @@
         `callable` is called, the scope at the time this is called will be
         restored, however it will contain any new bindings added to it.
         """
-        self._deferredFunctions.append((callable, self.scopeStack[:], 
self.offset))
+        self._deferred.append((callable, self.scopeStack[:], self.offset))
 
-    def deferAssignment(self, callable):
-        """
-        Schedule an assignment handler to be called just after deferred
-        function handlers.
-        """
-        self._deferredAssignments.append((callable, self.scopeStack[:], 
self.offset))
+    def _run_deferred(self):
+        orig = (self.scopeStack, self.offset)
 
-    def runDeferred(self, deferred):
-        """
-        Run the callables in C{deferred} using their associated scope stack.
-        """
-        for handler, scope, offset in deferred:
-            self.scopeStack = scope
-            self.offset = offset
+        while self._deferred:
+            handler, scope, offset = self._deferred.popleft()
+            self.scopeStack, self.offset = scope, offset
             handler()
 
+        self.scopeStack, self.offset = orig
+
     def _in_doctest(self):
         return (len(self.scopeStack) >= 2 and
                 isinstance(self.scopeStack[1], DoctestScope))
@@ -866,8 +828,13 @@
     def scope(self):
         return self.scopeStack[-1]
 
-    def popScope(self):
-        self.deadScopes.append(self.scopeStack.pop())
+    @contextlib.contextmanager
+    def in_scope(self, cls):
+        self.scopeStack.append(cls())
+        try:
+            yield
+        finally:
+            self.deadScopes.append(self.scopeStack.pop())
 
     def checkDeadScopes(self):
         """
@@ -879,6 +846,12 @@
             if isinstance(scope, ClassScope):
                 continue
 
+            if isinstance(scope, FunctionScope):
+                for name, binding in scope.unused_assignments():
+                    self.report(messages.UnusedVariable, binding.source, name)
+                for name, binding in scope.unused_annotations():
+                    self.report(messages.UnusedAnnotation, binding.source, 
name)
+
             all_binding = scope.get('__all__')
             if all_binding and not isinstance(all_binding, ExportBinding):
                 all_binding = None
@@ -929,9 +902,6 @@
                             messg = messages.RedefinedWhileUnused
                         self.report(messg, node, value.name, value.source)
 
-    def pushScope(self, scopeClass=FunctionScope):
-        self.scopeStack.append(scopeClass())
-
     def report(self, messageClass, *args, **kwargs):
         self.messages.append(messageClass(self.filename, *args, **kwargs))
 
@@ -1073,7 +1043,12 @@
         if not name:
             return
 
-        in_generators = None
+        # only the following can access class scoped variables (since classes
+        # aren't really a scope)
+        # - direct accesses (not within a nested scope)
+        # - generators
+        # - type annotations (for generics, etc.)
+        can_access_class_vars = None
         importStarred = None
 
         # try enclosing function scopes and global scope
@@ -1081,7 +1056,7 @@
             if isinstance(scope, ClassScope):
                 if name == '__class__':
                     return
-                elif in_generators is False:
+                elif can_access_class_vars is False:
                     # only generators used in a class scope can access the
                     # names of the class. this is skipped during the first
                     # iteration
@@ -1089,7 +1064,7 @@
 
             binding = scope.get(name, None)
             if isinstance(binding, Annotation) and not 
self._in_postponed_annotation:
-                scope[name].used = True
+                scope[name].used = (self.scope, node)
                 continue
 
             if name == 'print' and isinstance(binding, Builtin):
@@ -1116,8 +1091,10 @@
 
             importStarred = importStarred or scope.importStarred
 
-            if in_generators is not False:
-                in_generators = isinstance(scope, GeneratorScope)
+            if can_access_class_vars is not False:
+                can_access_class_vars = isinstance(
+                    scope, (TypeScope, GeneratorScope),
+                )
 
         if importStarred:
             from_list = []
@@ -1181,7 +1158,7 @@
                 )
         ):
             binding = ExportBinding(name, node._pyflakes_parent, self.scope)
-        elif PY38_PLUS and isinstance(parent_stmt, ast.NamedExpr):
+        elif isinstance(parent_stmt, ast.NamedExpr):
             binding = NamedExprAssignment(name, node)
         else:
             binding = Assignment(name, node)
@@ -1248,22 +1225,21 @@
         Determine if the given node is a docstring, as long as it is at the
         correct place in the node tree.
         """
-        return isinstance(node, ast.Str) or (isinstance(node, ast.Expr) and
-                                             isinstance(node.value, ast.Str))
+        return (
+            isinstance(node, ast.Expr) and
+            isinstance(node.value, ast.Constant) and
+            isinstance(node.value.value, str)
+        )
 
     def getDocstring(self, node):
-        if isinstance(node, ast.Expr):
-            node = node.value
-        if not isinstance(node, ast.Str):
-            return (None, None)
-
-        if PYPY or PY38_PLUS:
-            doctest_lineno = node.lineno - 1
+        if (
+                isinstance(node, ast.Expr) and
+                isinstance(node.value, ast.Constant) and
+                isinstance(node.value.value, str)
+        ):
+            return node.value.value, node.lineno - 1
         else:
-            # Computed incorrectly if the docstring has backslash
-            doctest_lineno = node.lineno - node.s.count('\n') - 1
-
-        return (node.s, doctest_lineno)
+            return None, None
 
     def handleNode(self, node, parent):
         if node is None:
@@ -1271,8 +1247,12 @@
         if self.offset and getattr(node, 'lineno', None) is not None:
             node.lineno += self.offset[0]
             node.col_offset += self.offset[1]
-        if self.futuresAllowed and not (isinstance(node, ast.ImportFrom) or
-                                        self.isDocstring(node)):
+        if (
+                self.futuresAllowed and
+                self.nodeDepth == 0 and
+                not isinstance(node, ast.ImportFrom) and
+                not self.isDocstring(node)
+        ):
             self.futuresAllowed = False
         self.nodeDepth += 1
         node._pyflakes_depth = self.nodeDepth
@@ -1300,22 +1280,21 @@
         saved_stack = self.scopeStack
         self.scopeStack = [self.scopeStack[0]]
         node_offset = self.offset or (0, 0)
-        self.pushScope(DoctestScope)
-        if '_' not in self.scopeStack[0]:
-            self.addBinding(None, Builtin('_'))
-        for example in examples:
-            try:
-                tree = ast.parse(example.source, "<doctest>")
-            except SyntaxError as e:
-                position = (node_lineno + example.lineno + e.lineno,
-                            example.indent + 4 + (e.offset or 0))
-                self.report(messages.DoctestSyntaxError, node, position)
-            else:
-                self.offset = (node_offset[0] + node_lineno + example.lineno,
-                               node_offset[1] + example.indent + 4)
-                self.handleChildren(tree)
-                self.offset = node_offset
-        self.popScope()
+        with self.in_scope(DoctestScope):
+            if '_' not in self.scopeStack[0]:
+                self.addBinding(None, Builtin('_'))
+            for example in examples:
+                try:
+                    tree = ast.parse(example.source, "<doctest>")
+                except SyntaxError as e:
+                    position = (node_lineno + example.lineno + e.lineno,
+                                example.indent + 4 + (e.offset or 0))
+                    self.report(messages.DoctestSyntaxError, node, position)
+                else:
+                    self.offset = (node_offset[0] + node_lineno + 
example.lineno,
+                                   node_offset[1] + example.indent + 4)
+                    self.handleChildren(tree)
+                    self.offset = node_offset
         self.scopeStack = saved_stack
 
     @in_string_annotation
@@ -1342,21 +1321,27 @@
 
         self.handleNode(parsed_annotation, node)
 
+    def handle_annotation_always_deferred(self, annotation, parent):
+        fn = in_annotation(Checker.handleNode)
+        self.deferFunction(lambda: fn(self, annotation, parent))
+
     @in_annotation
     def handleAnnotation(self, annotation, node):
-        if isinstance(annotation, ast.Str):
+        if (
+                isinstance(annotation, ast.Constant) and
+                isinstance(annotation.value, str)
+        ):
             # Defer handling forward annotation.
             self.deferFunction(functools.partial(
                 self.handleStringAnnotation,
-                annotation.s,
+                annotation.value,
                 node,
                 annotation.lineno,
                 annotation.col_offset,
                 messages.ForwardAnnotationSyntaxError,
             ))
         elif self.annotationsFutureEnabled:
-            fn = in_annotation(Checker.handleNode)
-            self.deferFunction(lambda: fn(self, annotation, node))
+            self.handle_annotation_always_deferred(annotation, node)
         else:
             self.handleNode(annotation, node)
 
@@ -1413,7 +1398,7 @@
 
     def _handle_string_dot_format(self, node):
         try:
-            placeholders = tuple(parse_format_string(node.func.value.s))
+            placeholders = tuple(parse_format_string(node.func.value.value))
         except ValueError as e:
             self.report(messages.StringDotFormatInvalidFormat, node, e)
             return
@@ -1529,7 +1514,8 @@
     def CALL(self, node):
         if (
                 isinstance(node.func, ast.Attribute) and
-                isinstance(node.func.value, ast.Str) and
+                isinstance(node.func.value, ast.Constant) and
+                isinstance(node.func.value.value, str) and
                 node.func.attr == 'format'
         ):
             self._handle_string_dot_format(node)
@@ -1610,7 +1596,7 @@
 
     def _handle_percent_format(self, node):
         try:
-            placeholders = parse_percent_format(node.left.s)
+            placeholders = parse_percent_format(node.left.value)
         except ValueError:
             self.report(
                 messages.PercentFormatInvalidFormat,
@@ -1689,13 +1675,16 @@
 
         if (
                 isinstance(node.right, ast.Dict) and
-                all(isinstance(k, ast.Str) for k in node.right.keys)
+                all(
+                    isinstance(k, ast.Constant) and isinstance(k.value, str)
+                    for k in node.right.keys
+                )
         ):
             if positional and positional_count > 1:
                 self.report(messages.PercentFormatExpectedSequence, node)
                 return
 
-            substitution_keys = {k.s for k in node.right.keys}
+            substitution_keys = {k.value for k in node.right.keys}
             extra_keys = substitution_keys - named
             missing_keys = named - substitution_keys
             if not positional and extra_keys:
@@ -1714,32 +1703,23 @@
     def BINOP(self, node):
         if (
                 isinstance(node.op, ast.Mod) and
-                isinstance(node.left, ast.Str)
+                isinstance(node.left, ast.Constant) and
+                isinstance(node.left.value, str)
         ):
             self._handle_percent_format(node)
         self.handleChildren(node)
 
-    def STR(self, node):
-        if self._in_annotation:
+    def CONSTANT(self, node):
+        if isinstance(node.value, str) and self._in_annotation:
             fn = functools.partial(
                 self.handleStringAnnotation,
-                node.s,
+                node.value,
                 node,
                 node.lineno,
                 node.col_offset,
                 messages.ForwardAnnotationSyntaxError,
             )
-            if self._in_deferred:
-                fn()
-            else:
-                self.deferFunction(fn)
-
-    if PY38_PLUS:
-        def CONSTANT(self, node):
-            if isinstance(node.value, str):
-                return self.STR(node)
-    else:
-        NUM = BYTES = ELLIPSIS = CONSTANT = ignore
+            self.deferFunction(fn)
 
     # "slice" type nodes
     SLICE = EXTSLICE = INDEX = handleChildren
@@ -1867,9 +1847,8 @@
     NONLOCAL = GLOBAL
 
     def GENERATOREXP(self, node):
-        self.pushScope(GeneratorScope)
-        self.handleChildren(node)
-        self.popScope()
+        with self.in_scope(GeneratorScope):
+            self.handleChildren(node)
 
     LISTCOMP = DICTCOMP = SETCOMP = GENERATOREXP
 
@@ -1905,11 +1884,6 @@
                     return
             if isinstance(n, (ast.FunctionDef, ast.ClassDef)):
                 break
-            # Handle Try/TryFinally difference in Python < and >= 3.3
-            if hasattr(n, 'finalbody') and isinstance(node, ast.Continue):
-                if n_child in n.finalbody and not PY38_PLUS:
-                    self.report(messages.ContinueInFinally, node)
-                    return
         if isinstance(node, ast.Continue):
             self.report(messages.ContinueOutsideLoop, node)
         else:  # ast.Break
@@ -1942,7 +1916,10 @@
     def FUNCTIONDEF(self, node):
         for deco in node.decorator_list:
             self.handleNode(deco, node)
-        self.LAMBDA(node)
+
+        with self._type_param_scope(node):
+            self.LAMBDA(node)
+
         self.addBinding(node, FunctionDefinition(node.name, node))
         # doctest does not process doctest within a doctest,
         # or in nested functions.
@@ -1957,10 +1934,9 @@
         args = []
         annotations = []
 
-        if PY38_PLUS:
-            for arg in node.args.posonlyargs:
-                args.append(arg.arg)
-                annotations.append(arg.annotation)
+        for arg in node.args.posonlyargs:
+            args.append(arg.arg)
+            annotations.append(arg.annotation)
         for arg in node.args.args + node.args.kwonlyargs:
             args.append(arg.arg)
             annotations.append(arg.annotation)
@@ -1991,29 +1967,11 @@
             self.handleNode(default, node)
 
         def runFunction():
-
-            self.pushScope()
-
-            self.handleChildren(node, omit=['decorator_list', 'returns'])
-
-            def check_unused_assignments():
-                """
-                Check to see if any assignments have not been used.
-                """
-                for name, binding in self.scope.unused_assignments():
-                    self.report(messages.UnusedVariable, binding.source, name)
-
-            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()
+            with self.in_scope(FunctionScope):
+                self.handleChildren(
+                    node,
+                    omit=('decorator_list', 'returns', 'type_params'),
+                )
 
         self.deferFunction(runFunction)
 
@@ -2031,20 +1989,22 @@
         """
         for deco in node.decorator_list:
             self.handleNode(deco, node)
-        for baseNode in node.bases:
-            self.handleNode(baseNode, node)
-        for keywordNode in node.keywords:
-            self.handleNode(keywordNode, node)
-        self.pushScope(ClassScope)
-        # doctest does not process doctest within a doctest
-        # classes within classes are processed.
-        if (self.withDoctest and
-                not self._in_doctest() and
-                not isinstance(self.scope, FunctionScope)):
-            self.deferFunction(lambda: self.handleDoctests(node))
-        for stmt in node.body:
-            self.handleNode(stmt, node)
-        self.popScope()
+
+        with self._type_param_scope(node):
+            for baseNode in node.bases:
+                self.handleNode(baseNode, node)
+            for keywordNode in node.keywords:
+                self.handleNode(keywordNode, node)
+            with self.in_scope(ClassScope):
+                # doctest does not process doctest within a doctest
+                # classes within classes are processed.
+                if (self.withDoctest and
+                        not self._in_doctest() and
+                        not isinstance(self.scope, FunctionScope)):
+                    self.deferFunction(lambda: self.handleDoctests(node))
+                for stmt in node.body:
+                    self.handleNode(stmt, node)
+
         self.addBinding(node, ClassDefinition(node.name, node))
 
     def AUGASSIGN(self, node):
@@ -2218,3 +2178,21 @@
         self.handleChildren(node)
 
     MATCHAS = MATCHMAPPING = MATCHSTAR = _match_target
+
+    @contextlib.contextmanager
+    def _type_param_scope(self, node):
+        with contextlib.ExitStack() as ctx:
+            if sys.version_info >= (3, 12):
+                ctx.enter_context(self.in_scope(TypeScope))
+                for param in node.type_params:
+                    self.handleNode(param, node)
+            yield
+
+    def TYPEVAR(self, node):
+        self.handleNodeStore(node)
+        self.handle_annotation_always_deferred(node.bound, node)
+
+    def TYPEALIAS(self, node):
+        self.handleNode(node.name, node)
+        with self._type_param_scope(node):
+            self.handle_annotation_always_deferred(node.value, node)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pyflakes-3.0.1/pyflakes/messages.py 
new/pyflakes-3.1.0/pyflakes/messages.py
--- old/pyflakes-3.0.1/pyflakes/messages.py     2022-11-24 17:02:51.000000000 
+0100
+++ new/pyflakes-3.1.0/pyflakes/messages.py     2023-01-31 19:28:24.000000000 
+0100
@@ -198,13 +198,6 @@
     message = '\'break\' outside loop'
 
 
-class ContinueInFinally(Message):
-    """
-    Indicates a continue statement in a finally block in a while or for loop.
-    """
-    message = '\'continue\' not supported inside \'finally\' clause'
-
-
 class DefaultExceptNotLast(Message):
     """
     Indicates an except: block as not the last exception handler.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pyflakes-3.0.1/pyflakes/reporter.py 
new/pyflakes-3.1.0/pyflakes/reporter.py
--- old/pyflakes-3.0.1/pyflakes/reporter.py     2022-11-24 17:02:51.000000000 
+0100
+++ new/pyflakes-3.1.0/pyflakes/reporter.py     2023-06-13 03:11:44.000000000 
+0200
@@ -56,12 +56,11 @@
         else:
             line = text.splitlines()[-1]
 
+        # lineno might be None if the error was during tokenization
         # lineno might be 0 if the error came from stdin
-        lineno = max(lineno, 1)
+        lineno = max(lineno or 0, 1)
 
         if offset is not None:
-            if sys.version_info < (3, 8) and text is not None:
-                offset = offset - (len(text) - len(line)) + 1
             # some versions of python emit an offset of -1 for certain 
encoding errors
             offset = max(offset, 1)
             self._stderr.write('%s:%d:%d: %s\n' %
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pyflakes-3.0.1/pyflakes/test/test_api.py 
new/pyflakes-3.1.0/pyflakes/test/test_api.py
--- old/pyflakes-3.0.1/pyflakes/test/test_api.py        2022-11-24 
17:02:51.000000000 +0100
+++ new/pyflakes-3.1.0/pyflakes/test/test_api.py        2023-06-13 
03:50:05.000000000 +0200
@@ -233,9 +233,7 @@
         """
         err = io.StringIO()
         reporter = Reporter(None, err)
-        reporter.syntaxError('foo.py', 'a problem', 3,
-                             8 if sys.version_info >= (3, 8) else 7,
-                             'bad line of source')
+        reporter.syntaxError('foo.py', 'a problem', 3, 8, 'bad line of source')
         self.assertEqual(
             ("foo.py:3:8: a problem\n"
              "bad line of source\n"
@@ -281,11 +279,10 @@
         reporter = Reporter(None, err)
         reporter.syntaxError('foo.py', 'a problem', 3, len(lines[0]) + 7,
                              '\n'.join(lines))
-        column = 25 if sys.version_info >= (3, 8) else 7
         self.assertEqual(
-            ("foo.py:3:%d: a problem\n" % column +
+            ("foo.py:3:25: a problem\n" +
              lines[-1] + "\n" +
-             " " * (column - 1) + "^\n"),
+             " " * 24 + "^\n"),
             err.getvalue())
 
     def test_unexpectedError(self):
@@ -417,10 +414,8 @@
 
             if PYPY or sys.version_info >= (3, 10):
                 column = 12
-            elif sys.version_info >= (3, 8):
-                column = 8
             else:
-                column = 11
+                column = 8
             self.assertHasErrors(
                 sourcePath,
                 ["""\
@@ -479,6 +474,11 @@
     pass
 """
         with self.makeTempFile(source) as sourcePath:
+            if sys.version_info >= (3, 12):
+                msg = 'parameter without a default follows parameter with a 
default'  # noqa: E501
+            else:
+                msg = 'non-default argument follows default argument'
+
             if PYPY and sys.version_info >= (3, 9):
                 column = 18
             elif PYPY:
@@ -487,18 +487,16 @@
                 column = 18
             elif sys.version_info >= (3, 9):
                 column = 21
-            elif sys.version_info >= (3, 8):
-                column = 9
             else:
-                column = 8
+                column = 9
             last_line = ' ' * (column - 1) + '^\n'
-            columnstr = '%d:' % column
             self.assertHasErrors(
                 sourcePath,
-                ["""\
-{}:1:{} non-default argument follows default argument
+                [f"""\
+{sourcePath}:1:{column}: {msg}
 def foo(bar=baz, bax):
-{}""".format(sourcePath, columnstr, last_line)])
+{last_line}"""]
+            )
 
     def test_nonKeywordAfterKeywordSyntaxError(self):
         """
@@ -512,7 +510,7 @@
         with self.makeTempFile(source) as sourcePath:
             if sys.version_info >= (3, 9):
                 column = 17
-            elif not PYPY and sys.version_info >= (3, 8):
+            elif not PYPY:
                 column = 14
             else:
                 column = 13
@@ -539,7 +537,7 @@
                 column = 7
             elif PYPY:
                 column = 6
-            elif sys.version_info >= (3, 9):
+            elif (3, 9) <= sys.version_info < (3, 12):
                 column = 13
             else:
                 column = 7
@@ -628,8 +626,12 @@
 x = "%s"
 """ % SNOWMAN).encode('utf-16')
         with self.makeTempFile(source) as sourcePath:
-            self.assertHasErrors(
-                sourcePath, [f"{sourcePath}: problem decoding source\n"])
+            if sys.version_info < (3, 11, 4):
+                expected = f"{sourcePath}: problem decoding source\n"
+            else:
+                expected = f"{sourcePath}:1: source code string cannot contain 
null bytes\n"  # noqa: E501
+
+            self.assertHasErrors(sourcePath, [expected])
 
     def test_checkRecursive(self):
         """
@@ -679,18 +681,10 @@
                 "max(1 for i in range(10), key=lambda x: x+1)",
                 "   ^",
             ]
-        elif sys.version_info >= (3, 8):
+        else:
             expected_error = [
                 "<stdin>:1:5: Generator expression must be parenthesized",
             ]
-        elif sys.version_info >= (3, 7):
-            expected_error = [
-                "<stdin>:1:4: Generator expression must be parenthesized",
-            ]
-        elif sys.version_info >= (3, 6):
-            expected_error = [
-                "<stdin>:1:4: Generator expression must be parenthesized if 
not sole argument",  # noqa: E501
-            ]
 
         self.assertEqual(errlines, expected_error)
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pyflakes-3.0.1/pyflakes/test/test_doctests.py 
new/pyflakes-3.1.0/pyflakes/test/test_doctests.py
--- old/pyflakes-3.0.1/pyflakes/test/test_doctests.py   2022-11-24 
17:02:51.000000000 +0100
+++ new/pyflakes-3.1.0/pyflakes/test/test_doctests.py   2023-01-31 
19:28:24.000000000 +0100
@@ -1,4 +1,3 @@
-import sys
 import textwrap
 
 from pyflakes import messages as m
@@ -323,7 +322,7 @@
             m.DoctestSyntaxError).messages
         exc = exceptions[0]
         self.assertEqual(exc.lineno, 4)
-        if not PYPY and sys.version_info >= (3, 8):
+        if not PYPY:
             self.assertEqual(exc.col, 18)
         else:
             self.assertEqual(exc.col, 26)
@@ -339,10 +338,7 @@
             self.assertEqual(exc.col, 16)
         exc = exceptions[2]
         self.assertEqual(exc.lineno, 6)
-        if PYPY or sys.version_info >= (3, 8):
-            self.assertEqual(exc.col, 13)
-        else:
-            self.assertEqual(exc.col, 18)
+        self.assertEqual(exc.col, 13)
 
     def test_indentationErrorInDoctest(self):
         exc = self.flakes('''
@@ -353,10 +349,7 @@
             """
         ''', m.DoctestSyntaxError).messages[0]
         self.assertEqual(exc.lineno, 5)
-        if PYPY or sys.version_info >= (3, 8):
-            self.assertEqual(exc.col, 13)
-        else:
-            self.assertEqual(exc.col, 16)
+        self.assertEqual(exc.col, 13)
 
     def test_offsetWithMultiLineArgs(self):
         (exc1, exc2) = self.flakes(
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pyflakes-3.0.1/pyflakes/test/test_match.py 
new/pyflakes-3.1.0/pyflakes/test/test_match.py
--- old/pyflakes-3.0.1/pyflakes/test/test_match.py      2022-11-24 
17:02:51.000000000 +0100
+++ new/pyflakes-3.1.0/pyflakes/test/test_match.py      2023-06-13 
02:24:07.000000000 +0200
@@ -81,3 +81,14 @@
                 case {'foo': k1, **rest}:
                     print(f'{k1=} {rest=}')
         ''')
+
+    def test_defined_in_different_branches(self):
+        self.flakes('''
+            def f(x):
+                match x:
+                    case 1:
+                        def y(): pass
+                    case _:
+                        def y(): print(1)
+                return y
+        ''')
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pyflakes-3.0.1/pyflakes/test/test_other.py 
new/pyflakes-3.1.0/pyflakes/test/test_other.py
--- old/pyflakes-3.0.1/pyflakes/test/test_other.py      2022-11-24 
17:51:58.000000000 +0100
+++ new/pyflakes-3.1.0/pyflakes/test/test_other.py      2023-01-31 
19:28:24.000000000 +0100
@@ -118,6 +118,12 @@
         def a(): pass
         ''', m.RedefinedWhileUnused)
 
+    def test_redefined_function_shadows_variable(self):
+        self.flakes('''
+        x = 1
+        def x(): pass
+        ''', m.RedefinedWhileUnused)
+
     def test_redefinedUnderscoreFunction(self):
         """
         Test that shadowing a function definition named with underscore doesn't
@@ -445,36 +451,6 @@
                     continue
         ''')
 
-    @skipIf(version_info > (3, 8), "Python <= 3.8 only")
-    def test_continueInFinally(self):
-        # 'continue' inside 'finally' is a special syntax error
-        # that is removed in 3.8
-        self.flakes('''
-        while True:
-            try:
-                pass
-            finally:
-                continue
-        ''', m.ContinueInFinally)
-
-        self.flakes('''
-        while True:
-            try:
-                pass
-            finally:
-                if 1:
-                    if 2:
-                        continue
-        ''', m.ContinueInFinally)
-
-        # Even when not in a loop, this is the error Python gives
-        self.flakes('''
-        try:
-            pass
-        finally:
-            continue
-        ''', m.ContinueInFinally)
-
     def test_breakOutsideLoop(self):
         self.flakes('''
         break
@@ -1716,7 +1692,6 @@
         print(f'\x7b4*baz\N{RIGHT CURLY BRACKET}')
         ''')
 
-    @skipIf(version_info < (3, 8), 'new in Python 3.8')
     def test_assign_expr(self):
         """Test PEP 572 assignment expressions are treated as usage / write."""
         self.flakes('''
@@ -1725,7 +1700,6 @@
         print(x)
         ''')
 
-    @skipIf(version_info < (3, 8), 'new in Python 3.8')
     def test_assign_expr_generator_scope(self):
         """Test assignment expressions in generator expressions."""
         self.flakes('''
@@ -1733,7 +1707,6 @@
             print(y)
         ''')
 
-    @skipIf(version_info < (3, 8), 'new in Python 3.8')
     def test_assign_expr_nested(self):
         """Test assignment expressions in nested expressions."""
         self.flakes('''
@@ -1972,19 +1945,6 @@
             return output
         ''', m.BreakOutsideLoop)
 
-    @skipIf(version_info > (3, 8), "Python <= 3.8 only")
-    def test_continueInAsyncForFinally(self):
-        self.flakes('''
-        async def read_data(db):
-            output = []
-            async for row in db.cursor():
-                try:
-                    output.append(row)
-                finally:
-                    continue
-            return output
-        ''', m.ContinueInFinally)
-
     def test_asyncWith(self):
         self.flakes('''
         async def commit(session, data):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/pyflakes-3.0.1/pyflakes/test/test_type_annotations.py 
new/pyflakes-3.1.0/pyflakes/test/test_type_annotations.py
--- old/pyflakes-3.0.1/pyflakes/test/test_type_annotations.py   2022-11-24 
17:02:51.000000000 +0100
+++ new/pyflakes-3.1.0/pyflakes/test/test_type_annotations.py   2023-07-29 
18:51:35.000000000 +0200
@@ -367,6 +367,13 @@
             x = 3
         ''', m.UnusedVariable)
 
+    def test_unused_annotation_in_outer_scope_reassigned_in_local_scope(self):
+        self.flakes('''
+        x: int
+        x.__dict__
+        def f(): x = 1
+        ''', m.UndefinedName, m.UnusedVariable)
+
     def test_unassigned_annotation_is_undefined(self):
         self.flakes('''
         name: str
@@ -379,7 +386,6 @@
         async def func(c: c) -> None: pass
         ''')
 
-    @skipIf(version_info < (3, 7), 'new in Python 3.7')
     def test_postponed_annotations(self):
         self.flakes('''
         from __future__ import annotations
@@ -434,7 +440,6 @@
                 return Y
         """, m.UndefinedName)
 
-    @skipIf(version_info < (3, 8), 'new in Python 3.8')
     def test_positional_only_argument_annotations(self):
         self.flakes("""
         from x import C
@@ -584,7 +589,6 @@
                 return None
         """)
 
-    @skipIf(version_info < (3, 7), 'new in Python 3.7')
     def test_partial_string_annotations_with_future_annotations(self):
         self.flakes("""
             from __future__ import annotations
@@ -597,6 +601,20 @@
                 return None
         """)
 
+    def test_forward_annotations_for_classes_in_scope(self):
+        # see #749
+        self.flakes("""
+        from typing import Optional
+
+        def f():
+            class C:
+                a: "D"
+                b: Optional["D"]
+                c: "Optional[D]"
+
+            class D: pass
+        """)
+
     def test_idomiatic_typing_guards(self):
         # typing.TYPE_CHECKING: python3.5.3+
         self.flakes("""
@@ -695,3 +713,70 @@
 
             def g(x: Shape[*Ts]) -> Shape[*Ts]: ...
         """)
+
+    @skipIf(version_info < (3, 12), 'new in Python 3.12')
+    def test_type_statements(self):
+        self.flakes("""
+            type ListOrSet[T] = list[T] | set[T]
+
+            def f(x: ListOrSet[str]) -> None: ...
+
+            type RecursiveType = int | list[RecursiveType]
+
+            type ForwardRef = int | C
+
+            type ForwardRefInBounds[T: C] = T
+
+            class C: pass
+        """)
+
+    @skipIf(version_info < (3, 12), 'new in Python 3.12')
+    def test_type_parameters_functions(self):
+        self.flakes("""
+            def f[T](t: T) -> T: return t
+
+            async def g[T](t: T) -> T: return t
+
+            def with_forward_ref[T: C](t: T) -> T: return t
+
+            def can_access_inside[T](t: T) -> T:
+                print(T)
+                return t
+
+            class C: pass
+        """)
+
+    @skipIf(version_info < (3, 12), 'new in Python 3.12')
+    def test_type_parameters_do_not_escape_function_scopes(self):
+        self.flakes("""
+            from x import g
+
+            @g(T)  # not accessible in decorators
+            def f[T](t: T) -> T: return t
+
+            T  # not accessible afterwards
+        """, m.UndefinedName, m.UndefinedName)
+
+    @skipIf(version_info < (3, 12), 'new in Python 3.12')
+    def test_type_parameters_classes(self):
+        self.flakes("""
+            class C[T](list[T]): pass
+
+            class UsesForward[T: Forward](list[T]): pass
+
+            class Forward: pass
+
+            class WithinBody[T](list[T]):
+                t = T
+        """)
+
+    @skipIf(version_info < (3, 12), 'new in Python 3.12')
+    def test_type_parameters_do_not_escape_class_scopes(self):
+        self.flakes("""
+            from x import g
+
+            @g(T)  # not accessible in decorators
+            class C[T](list[T]): pass
+
+            T  # not accessible afterwards
+        """, m.UndefinedName, m.UndefinedName)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pyflakes-3.0.1/pyflakes.egg-info/PKG-INFO 
new/pyflakes-3.1.0/pyflakes.egg-info/PKG-INFO
--- old/pyflakes-3.0.1/pyflakes.egg-info/PKG-INFO       2022-11-24 
17:53:21.000000000 +0100
+++ new/pyflakes-3.1.0/pyflakes.egg-info/PKG-INFO       2023-07-29 
19:00:24.000000000 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: pyflakes
-Version: 3.0.1
+Version: 3.1.0
 Summary: passive checker of Python programs
 Home-page: https://github.com/PyCQA/pyflakes
 Author: A lot of people
@@ -12,17 +12,12 @@
 Classifier: License :: OSI Approved :: MIT License
 Classifier: Programming Language :: Python
 Classifier: Programming Language :: Python :: 3
-Classifier: Programming Language :: Python :: 3.6
-Classifier: Programming Language :: Python :: 3.7
-Classifier: Programming Language :: Python :: 3.8
-Classifier: Programming Language :: Python :: 3.9
-Classifier: Programming Language :: Python :: 3.10
 Classifier: Programming Language :: Python :: 3 :: Only
 Classifier: Programming Language :: Python :: Implementation :: CPython
 Classifier: Programming Language :: Python :: Implementation :: PyPy
 Classifier: Topic :: Software Development
 Classifier: Topic :: Utilities
-Requires-Python: >=3.6
+Requires-Python: >=3.8
 License-File: LICENSE
 
 ========
@@ -89,8 +84,8 @@
 
 Issues are tracked on `GitHub <https://github.com/PyCQA/pyflakes/issues>`_.
 
-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`_
+Patches may be submitted via a `GitHub pull request`_.
+If you are comfortable doing so, please `rebase your changes`_
 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
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pyflakes-3.0.1/setup.py new/pyflakes-3.1.0/setup.py
--- old/pyflakes-3.0.1/setup.py 2022-11-24 17:02:51.000000000 +0100
+++ new/pyflakes-3.1.0/setup.py 2023-01-31 19:28:24.000000000 +0100
@@ -42,7 +42,7 @@
     author_email="code-qual...@python.org",
     url="https://github.com/PyCQA/pyflakes";,
     packages=["pyflakes", "pyflakes.scripts", "pyflakes.test"],
-    python_requires='>=3.6',
+    python_requires='>=3.8',
     classifiers=[
         "Development Status :: 6 - Mature",
         "Environment :: Console",
@@ -50,11 +50,6 @@
         "License :: OSI Approved :: MIT License",
         "Programming Language :: Python",
         "Programming Language :: Python :: 3",
-        "Programming Language :: Python :: 3.6",
-        "Programming Language :: Python :: 3.7",
-        "Programming Language :: Python :: 3.8",
-        "Programming Language :: Python :: 3.9",
-        "Programming Language :: Python :: 3.10",
         "Programming Language :: Python :: 3 :: Only",
         "Programming Language :: Python :: Implementation :: CPython",
         "Programming Language :: Python :: Implementation :: PyPy",

Reply via email to