Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-pycodestyle for 
openSUSE:Factory checked in at 2026-10-27 18:17:59
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-pycodestyle (Old)
 and      /work/SRC/openSUSE:Factory/.python-pycodestyle.new.2252680 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-pycodestyle"

Tue Oct 27 18:17:59 2026 rev:27 rq:1392538 version:2.15.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-pycodestyle/python-pycodestyle.changes    
2025-08-22 17:47:41.675715603 +0200
+++ 
/work/SRC/openSUSE:Factory/.python-pycodestyle.new.2252680/python-pycodestyle.changes
       2026-10-27 18:18:05.158404383 +0100
@@ -1,0 +2,12 @@
+Sun Oct 25 19:55:08 UTC 2026 - Dirk Müller <[email protected]>
+
+- update to 2.15.0:
+  * Improve performance of `module_imports_on_top_of_file`.  PR
+  * Improve performance of `python_3000_invalid_escape_sequence`.
+  * Improve performacne of `missing_whitespace_after_keyword`.
+  * Drop EOL python 3.9.  PR #1300.
+  * Add support for python 3.15.  PR #1322.
+  * Fix loading unrelated configuration due to `commonprefix`.
+    PR #1323.
+
+-------------------------------------------------------------------

Old:
----
  pycodestyle-2.14.0.tar.gz

New:
----
  pycodestyle-2.15.0.tar.gz

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

Other differences:
------------------
++++++ python-pycodestyle.spec ++++++
--- /var/tmp/diff_new_pack.c4HgXQ/_old  2026-10-27 18:18:06.060442004 +0100
+++ /var/tmp/diff_new_pack.c4HgXQ/_new  2026-10-27 18:18:06.062442087 +0100
@@ -1,7 +1,7 @@
 #
 # spec file for package python-pycodestyle
 #
-# Copyright (c) 2025 SUSE LLC and contributors
+# Copyright (c) 2026 SUSE LLC and contributors
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -23,7 +23,7 @@
 %endif
 %{?sle15_python_module_pythons}
 Name:           python-pycodestyle
-Version:        2.14.0
+Version:        2.15.0
 Release:        0
 Summary:        Python style guide checker
 License:        MIT

++++++ pycodestyle-2.14.0.tar.gz -> pycodestyle-2.15.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pycodestyle-2.14.0/.github/workflows/main.yml 
new/pycodestyle-2.15.0/.github/workflows/main.yml
--- old/pycodestyle-2.14.0/.github/workflows/main.yml   2025-06-20 
20:48:57.000000000 +0200
+++ new/pycodestyle-2.15.0/.github/workflows/main.yml   2026-09-23 
00:14:26.000000000 +0200
@@ -11,15 +11,12 @@
       matrix:
         include:
         - os: windows-latest
-          py: 3.9
+          py: '3.10'
           toxenv: py
         - os: ubuntu-latest
           py: pypy3.10
           toxenv: py
         - os: ubuntu-latest
-          py: 3.9
-          toxenv: py
-        - os: ubuntu-latest
           py: '3.10'
           toxenv: py
         - os: ubuntu-latest
@@ -32,10 +29,13 @@
           py: '3.13'
           toxenv: py
         - os: ubuntu-latest
-          py: '3.14-dev'
+          py: '3.14'
           toxenv: py
         - os: ubuntu-latest
-          py: 3.9
+          py: '3.15-dev'
+          toxenv: py
+        - os: ubuntu-latest
+          py: '3.10'
           toxenv: flake8
     runs-on: ${{ matrix.os }}
     steps:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pycodestyle-2.14.0/.pre-commit-config.yaml 
new/pycodestyle-2.15.0/.pre-commit-config.yaml
--- old/pycodestyle-2.14.0/.pre-commit-config.yaml      2025-06-20 
20:48:57.000000000 +0200
+++ new/pycodestyle-2.15.0/.pre-commit-config.yaml      2026-09-23 
00:14:26.000000000 +0200
@@ -1,27 +1,27 @@
 exclude: ^testing/data/
 repos:
 -   repo: https://github.com/pre-commit/pre-commit-hooks
-    rev: v5.0.0
+    rev: v6.0.0
     hooks:
     -   id: check-yaml
     -   id: debug-statements
     -   id: end-of-file-fixer
     -   id: trailing-whitespace
 -   repo: https://github.com/asottile/reorder-python-imports
-    rev: v3.15.0
+    rev: v3.17.0
     hooks:
     -   id: reorder-python-imports
-        args: [--py39-plus]
+        args: [--py310-plus]
 -   repo: https://github.com/asottile/pyupgrade
-    rev: v3.20.0
+    rev: v3.21.2
     hooks:
     -   id: pyupgrade
-        args: [--py39-plus]
+        args: [--py310-plus]
 -   repo: https://github.com/asottile/setup-cfg-fmt
-    rev: v2.8.0
+    rev: v3.2.0
     hooks:
     -   id: setup-cfg-fmt
 -   repo: https://github.com/pycqa/flake8
-    rev: 7.2.0
+    rev: 7.3.0
     hooks:
     -   id: flake8
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pycodestyle-2.14.0/CHANGES.txt 
new/pycodestyle-2.15.0/CHANGES.txt
--- old/pycodestyle-2.14.0/CHANGES.txt  2025-06-20 20:48:57.000000000 +0200
+++ new/pycodestyle-2.15.0/CHANGES.txt  2026-09-23 00:14:26.000000000 +0200
@@ -1,6 +1,18 @@
 Changelog
 =========
 
+2.15.0 (2026-09-22)
+-------------------
+
+Changes:
+
+* Improve performance of `module_imports_on_top_of_file`.  PR #1292.
+* Improve performance of `python_3000_invalid_escape_sequence`.  PR #1292.
+* Improve performacne of `missing_whitespace_after_keyword`.  PR #1291.
+* Drop EOL python 3.9.  PR #1300.
+* Add support for python 3.15.  PR #1322.
+* Fix loading unrelated configuration due to `commonprefix`.  PR #1323.
+
 2.14.0 (2025-06-20)
 -------------------
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pycodestyle-2.14.0/pycodestyle.py 
new/pycodestyle-2.15.0/pycodestyle.py
--- old/pycodestyle-2.14.0/pycodestyle.py       2025-06-20 20:48:57.000000000 
+0200
+++ new/pycodestyle-2.15.0/pycodestyle.py       2026-09-23 00:14:26.000000000 
+0200
@@ -59,16 +59,10 @@
 import warnings
 from fnmatch import fnmatch
 from functools import lru_cache
+from itertools import pairwise
 from optparse import OptionParser
 
-# this is a performance hack.  see https://bugs.python.org/issue43014
-if (
-        sys.version_info < (3, 10) and
-        callable(getattr(tokenize, '_compile', None))
-):  # pragma: no cover (<py310)
-    tokenize._compile = lru_cache(tokenize._compile)  # type: ignore
-
-__version__ = '2.14.0'
+__version__ = '2.15.0'
 
 DEFAULT_EXCLUDE = '.svn,CVS,.bzr,.hg,.git,__pycache__,.tox'
 DEFAULT_IGNORE = 'E121,E123,E126,E226,E24,E704,W503,W504'
@@ -502,7 +496,7 @@
     E275: from importable.module import(bar, baz)
     E275: if(foo): bar
     """
-    for tok0, tok1 in zip(tokens, tokens[1:]):
+    for tok0, tok1 in pairwise(tokens):
         # This must exclude the True/False/None singletons, which can
         # appear e.g. as "if x is None:", and async/await, which were
         # valid identifier names in old Python versions.
@@ -512,7 +506,7 @@
                 tok0.string not in SINGLETONS and
                 not (tok0.string == 'except' and tok1.string == '*') and
                 not (tok0.string == 'yield' and tok1.string == ')') and
-                tok1.string not in ':\n'):
+                (tok1.string and tok1.string != ':' and tok1.string != '\n')):
             yield tok0.end, "E275 missing whitespace after keyword"
 
 
@@ -1160,6 +1154,22 @@
             yield found, "E401 multiple imports on one line"
 
 
+_STRING_PREFIXES = frozenset(('u', 'U', 'b', 'B', 'r', 'R'))
+
+
+def _is_string_literal(line):
+    if line:
+        first_char = line[0]
+        if first_char in _STRING_PREFIXES:
+            first_char = line[1]
+        return first_char == '"' or first_char == "'"
+    return False
+
+
+_ALLOWED_KEYWORDS_IN_IMPORTS = (
+    'try', 'except', 'else', 'finally', 'with', 'if', 'elif')
+
+
 @register_check
 def module_imports_on_top_of_file(
         logical_line, indent_level, checker_state, noqa):
@@ -1178,15 +1188,6 @@
 
     Okay: if x:\n    import os
     """  # noqa
-    def is_string_literal(line):
-        if line[0] in 'uUbB':
-            line = line[1:]
-        if line and line[0] in 'rR':
-            line = line[1:]
-        return line and (line[0] == '"' or line[0] == "'")
-
-    allowed_keywords = (
-        'try', 'except', 'else', 'finally', 'with', 'if', 'elif')
 
     if indent_level:  # Allow imports in conditional statement/function
         return
@@ -1194,25 +1195,28 @@
         return
     if noqa:
         return
-    line = logical_line
-    if line.startswith('import ') or line.startswith('from '):
+    if logical_line.startswith((
+            'import ', 'from ',
+            'lazy import ', 'lazy from ',
+    )):
         if checker_state.get('seen_non_imports', False):
             yield 0, "E402 module level import not at top of file"
-    elif re.match(DUNDER_REGEX, line):
-        return
-    elif any(line.startswith(kw) for kw in allowed_keywords):
-        # Allow certain keywords intermixed with imports in order to
-        # support conditional or filtered importing
-        return
-    elif is_string_literal(line):
-        # The first literal is a docstring, allow it. Otherwise, report
-        # error.
-        if checker_state.get('seen_docstring', False):
-            checker_state['seen_non_imports'] = True
+    elif not checker_state.get('seen_non_imports', False):
+        if DUNDER_REGEX.match(logical_line):
+            return
+        elif logical_line.startswith(_ALLOWED_KEYWORDS_IN_IMPORTS):
+            # Allow certain keywords intermixed with imports in order to
+            # support conditional or filtered importing
+            return
+        elif _is_string_literal(logical_line):
+            # The first literal is a docstring, allow it. Otherwise,
+            # report error.
+            if checker_state.get('seen_docstring', False):
+                checker_state['seen_non_imports'] = True
+            else:
+                checker_state['seen_docstring'] = True
         else:
-            checker_state['seen_docstring'] = True
-    else:
-        checker_state['seen_non_imports'] = True
+            checker_state['seen_non_imports'] = True
 
 
 @register_check
@@ -1627,6 +1631,29 @@
         prev_start = start
 
 
+# 
https://docs.python.org/3/reference/lexical_analysis.html#string-and-bytes-literals
+_PYTHON_3000_VALID_ESC = frozenset([
+    '\n',
+    '\\',
+    '\'',
+    '"',
+    'a',
+    'b',
+    'f',
+    'n',
+    'r',
+    't',
+    'v',
+    '0', '1', '2', '3', '4', '5', '6', '7',
+    'x',
+
+    # Escape sequences only recognized in string literals
+    'N',
+    'u',
+    'U',
+])
+
+
 @register_check
 def python_3000_invalid_escape_sequence(logical_line, tokens, noqa):
     r"""Invalid escape sequences are deprecated in Python 3.6.
@@ -1637,41 +1664,27 @@
     if noqa:
         return
 
-    # 
https://docs.python.org/3/reference/lexical_analysis.html#string-and-bytes-literals
-    valid = [
-        '\n',
-        '\\',
-        '\'',
-        '"',
-        'a',
-        'b',
-        'f',
-        'n',
-        'r',
-        't',
-        'v',
-        '0', '1', '2', '3', '4', '5', '6', '7',
-        'x',
-
-        # Escape sequences only recognized in string literals
-        'N',
-        'u',
-        'U',
-    ]
-
     prefixes = []
     for token_type, text, start, _, _ in tokens:
-        if token_type in {tokenize.STRING, FSTRING_START, TSTRING_START}:
+        if (
+                token_type == tokenize.STRING or
+                token_type == FSTRING_START or
+                token_type == TSTRING_START
+        ):
             # Extract string modifiers (e.g. u or r)
             prefixes.append(text[:text.index(text[-1])].lower())
 
-        if token_type in {tokenize.STRING, FSTRING_MIDDLE, TSTRING_MIDDLE}:
+        if (
+                token_type == tokenize.STRING or
+                token_type == FSTRING_MIDDLE or
+                token_type == TSTRING_MIDDLE
+        ):
             if 'r' not in prefixes[-1]:
                 start_line, start_col = start
                 pos = text.find('\\')
                 while pos >= 0:
                     pos += 1
-                    if text[pos] not in valid:
+                    if text[pos] not in _PYTHON_3000_VALID_ESC:
                         line = start_line + text.count('\n', 0, pos)
                         if line == start_line:
                             col = start_col + pos
@@ -1683,7 +1696,11 @@
                         )
                     pos = text.find('\\', pos + 1)
 
-        if token_type in {tokenize.STRING, FSTRING_END, TSTRING_END}:
+        if (
+                token_type == tokenize.STRING or
+                token_type == FSTRING_END or
+                token_type == TSTRING_END
+        ):
             prefixes.pop()
 
 
@@ -2549,7 +2566,7 @@
             print('user configuration: %s' % USER_CONFIG)
         config.read(USER_CONFIG)
 
-    parent = tail = args and os.path.abspath(os.path.commonprefix(args))
+    parent = tail = args and os.path.abspath(os.path.commonpath(args))
     while tail:
         if config.read(os.path.join(parent, fn) for fn in PROJECT_CONFIG):
             local_dir = parent
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pycodestyle-2.14.0/setup.cfg 
new/pycodestyle-2.15.0/setup.cfg
--- old/pycodestyle-2.14.0/setup.cfg    2025-06-20 20:48:57.000000000 +0200
+++ new/pycodestyle-2.15.0/setup.cfg    2026-09-23 00:14:26.000000000 +0200
@@ -28,7 +28,7 @@
 
 [options]
 py_modules = pycodestyle
-python_requires = >=3.9
+python_requires = >=3.10
 include_package_data = True
 zip_safe = False
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pycodestyle-2.14.0/testing/data/python315.py 
new/pycodestyle-2.15.0/testing/data/python315.py
--- old/pycodestyle-2.14.0/testing/data/python315.py    1970-01-01 
01:00:00.000000000 +0100
+++ new/pycodestyle-2.15.0/testing/data/python315.py    2026-09-23 
00:14:26.000000000 +0200
@@ -0,0 +1,9 @@
+import os
+lazy from typing import LiteralString
+import sys
+lazy import asyncio
+
+[*y for y in x]
+{*y for y in x}
+(*y for y in x)
+{**y for y in x}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pycodestyle-2.14.0/tests/test_api.py 
new/pycodestyle-2.15.0/tests/test_api.py
--- old/pycodestyle-2.14.0/tests/test_api.py    2025-06-20 20:48:57.000000000 
+0200
+++ new/pycodestyle-2.15.0/tests/test_api.py    2026-09-23 00:14:26.000000000 
+0200
@@ -352,12 +352,7 @@
         pep8style.input_file('stdin', lines=lines)
         stdout = sys.stdout.getvalue()
 
-        if sys.version_info < (3, 10):  # pragma: <3.10 cover
-            expected = [
-                'stdin:2:5: E901 TokenError: EOF in multi-line string',
-                'stdin:2:26: E901 SyntaxError: EOF while scanning 
triple-quoted string literal',  # noqa: E501
-            ]
-        elif sys.version_info < (3, 12):  # pragma: >=3.10 cover  # pragma: 
<3.12 cover  # noqa: E501
+        if sys.version_info < (3, 12):  # pragma: <3.12 cover  # noqa: E501
             expected = [
                 'stdin:2:5: E901 TokenError: EOF in multi-line string',
                 'stdin:2:6: E901 SyntaxError: unterminated triple-quoted 
string literal (detected at line 2)',  # noqa: E501
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pycodestyle-2.14.0/tests/test_pycodestyle.py 
new/pycodestyle-2.15.0/tests/test_pycodestyle.py
--- old/pycodestyle-2.14.0/tests/test_pycodestyle.py    2025-06-20 
20:48:57.000000000 +0200
+++ new/pycodestyle-2.15.0/tests/test_pycodestyle.py    2026-09-23 
00:14:26.000000000 +0200
@@ -6,7 +6,9 @@
 
 from pycodestyle import Checker
 from pycodestyle import expand_indent
+from pycodestyle import get_parser
 from pycodestyle import mute_string
+from pycodestyle import read_config
 
 
 @pytest.mark.parametrize(
@@ -42,7 +44,36 @@
     checker.tokens = list(tokenize.generate_tokens(io.StringIO(src).readline))
     checker.build_tokens_line()
 
-    if sys.version_info >= (3, 12):  # pragma: >3.12 cover
+    if sys.version_info >= (3, 12):  # pragma: >=3.12 cover
         assert checker.logical_line == "f'xxxxxxxxx{thing}xxxxxxxxx'"
-    else:
+    else:  # pragma: <3.12 cover
         assert checker.logical_line == "f'xxxxxxxxxxxxxxxxxxxxxxxxx'"
+
+
+def test_read_config_prefix(tmp_path):
+    tmp_path.joinpath('setup.cfg').write_text('[pycodestyle]\nexclude = root')
+
+    adir = tmp_path.joinpath('aaa')
+    adir.mkdir()
+    adir.joinpath('setup.cfg').write_text('[pycodestyle]\nexclude = aaa')
+
+    bdir = tmp_path.joinpath('aaabbb')
+    bdir.mkdir()
+    b_t = bdir.joinpath('t.py')
+    b_t.touch()
+    bdir.joinpath('setup.cfg').write_text('[pycodestyle]\nexclude = bbb')
+
+    cdir = tmp_path.joinpath('aaaccc')
+    cdir.mkdir()
+    c_t = cdir.joinpath('t.py')
+    c_t.touch()
+    cdir.joinpath('setup.cfg').write_text('[pycodestyle]\nexclude = ccc')
+
+    arglist = [str(b_t), str(c_t)]
+    parser = get_parser()
+    parser.add_option('--config')
+    opts, args = parser.parse_args(arglist)
+
+    # `aaa/setup.cfg` should not be read -- it is not passed on cmdline
+    opts = read_config(opts, args, arglist, parser)
+    assert opts.exclude == ['root']

Reply via email to