Script 'mail_helper' called by obssrc
Hello community,

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

Package is "python-iniconfig"

Tue Oct 27 18:18:59 2026 rev:11 rq:1392636 version:2.3.1

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-iniconfig/python-iniconfig.changes        
2025-12-11 18:32:15.666598211 +0100
+++ 
/work/SRC/openSUSE:Factory/.python-iniconfig.new.2252680/python-iniconfig.changes
   2026-10-27 18:19:07.888020623 +0100
@@ -1,0 +2,11 @@
+Mon Oct 26 07:44:35 UTC 2026 - Dirk Müller <[email protected]>
+
+- update to 2.3.1:
+  * fix quadratic parse time for values with many continuation
+    lines (#78, regarding #77)
+  * strip a leading UTF-8 BOM when reading INI files, which
+    previously raised ``ParseError`` (#76)
+  * internal: ``iniconfig._parse.ParsedLine.value`` is now a list
+    of lines
+
+-------------------------------------------------------------------

Old:
----
  iniconfig-2.3.0-tests.tar.gz
  iniconfig-2.3.0.tar.gz

New:
----
  iniconfig-2.3.1-tests.tar.gz
  iniconfig-2.3.1.tar.gz

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

Other differences:
------------------
++++++ python-iniconfig.spec ++++++
--- /var/tmp/diff_new_pack.8mXUPA/_old  2026-10-27 18:19:20.689556040 +0100
+++ /var/tmp/diff_new_pack.8mXUPA/_new  2026-10-27 18:19:20.691556123 +0100
@@ -1,7 +1,7 @@
 #
 # spec file for package python-iniconfig
 #
-# 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
@@ -26,7 +26,7 @@
 %endif
 %{?sle15_python_module_pythons}
 Name:           python-iniconfig%{psuffix}
-Version:        2.3.0
+Version:        2.3.1
 Release:        0
 Summary:        iniconfig: brain-dead simple config-ini parsing
 License:        MIT

++++++ iniconfig-2.3.0-tests.tar.gz -> iniconfig-2.3.1-tests.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iniconfig-2.3.0/.pre-commit-config.yaml 
new/iniconfig-2.3.1/.pre-commit-config.yaml
--- old/iniconfig-2.3.0/.pre-commit-config.yaml 2025-10-18 23:51:36.000000000 
+0200
+++ new/iniconfig-2.3.1/.pre-commit-config.yaml 2026-10-07 00:11:15.000000000 
+0200
@@ -1,18 +1,18 @@
 repos:
 - repo: https://github.com/tox-dev/pyproject-fmt
-  rev: "v2.11.0"
+  rev: "v2.30.1"
   hooks:
     - id: pyproject-fmt
 
 - repo: https://github.com/astral-sh/ruff-pre-commit
-  rev: v0.14.1
+  rev: v0.16.10
   hooks:
     - id: ruff-check
       args: [--fix]
     - id: ruff-format
 
 - repo: https://github.com/pre-commit/mirrors-mypy
-  rev: 'v1.18.2'
+  rev: 'v2.4.0'
   hooks:
     - id: mypy
       args: []
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iniconfig-2.3.0/CHANGELOG 
new/iniconfig-2.3.1/CHANGELOG
--- old/iniconfig-2.3.0/CHANGELOG       2025-10-18 23:51:36.000000000 +0200
+++ new/iniconfig-2.3.1/CHANGELOG       2026-10-07 00:11:15.000000000 +0200
@@ -1,3 +1,10 @@
+2.3.1
+=====
+
+* fix quadratic parse time for values with many continuation lines (#78, 
regarding #77)
+* strip a leading UTF-8 BOM when reading INI files, which previously raised 
``ParseError`` (#76)
+* internal: ``iniconfig._parse.ParsedLine.value`` is now a list of lines
+
 2.3.0
 =====
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iniconfig-2.3.0/README.rst 
new/iniconfig-2.3.1/README.rst
--- old/iniconfig-2.3.0/README.rst      2025-10-18 23:51:36.000000000 +0200
+++ new/iniconfig-2.3.1/README.rst      2026-10-07 00:11:15.000000000 +0200
@@ -13,7 +13,7 @@
 
 If you encounter issues or have feature wishes please report them to:
 
-    https://github.com/RonnyPfannschmidt/iniconfig/issues
+    https://github.com/pytest-dev/iniconfig/issues
 
 Basic Example
 ===================================
@@ -32,12 +32,12 @@
         line1
         line2
 
-then you can do:
+use ``IniConfig.parse()`` to strip inline comments from values:
 
 .. code-block:: pycon
 
     >>> import iniconfig
-    >>> ini = iniconfig.IniConfig("example.ini")
+    >>> ini = iniconfig.IniConfig.parse("example.ini")
     >>> ini['section1']['name1'] # raises KeyError if not exists
     'value1'
     >>> ini.get('section1', 'name1b', [], lambda x: x.split(","))
@@ -52,3 +52,7 @@
     True
     >>> 'inexistendsection' in ini
     False
+
+The ``IniConfig()`` constructor preserves inline comments in values for 
backward
+compatibility. Use ``IniConfig.parse(..., strip_inline_comments=False)`` to
+preserve them when using the parsing method.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iniconfig-2.3.0/pyproject.toml 
new/iniconfig-2.3.1/pyproject.toml
--- old/iniconfig-2.3.0/pyproject.toml  2025-10-18 23:51:36.000000000 +0200
+++ new/iniconfig-2.3.1/pyproject.toml  2026-10-07 00:11:15.000000000 +0200
@@ -28,6 +28,7 @@
   "Programming Language :: Python :: 3.12",
   "Programming Language :: Python :: 3.13",
   "Programming Language :: Python :: 3.14",
+  "Programming Language :: Python :: 3.15",
   "Topic :: Software Development :: Libraries",
   "Topic :: Utilities",
 ]
@@ -45,15 +46,12 @@
 [tool.setuptools]
 packages = [ "iniconfig" ]
 package-dir = { "" = "src" }
-
-[tool.setuptools.package-data]
-iniconfig = [ "py.typed" ]
+package-data.iniconfig = [ "py.typed" ]
 
 [tool.setuptools_scm]
 write_to = "src/iniconfig/_version.py"
 
 [tool.ruff]
-
 lint.extend-select = [
   "B",  # flake8-bugbear
   "I",  # isort
@@ -63,8 +61,8 @@
 lint.isort.force-single-line = true
 lint.isort.known-first-party = [ "iniconfig" ]
 
-[tool.pytest.ini_options]
-testpaths = "testing"
-
 [tool.mypy]
 strict = true
+
+[tool.pytest]
+ini_options.testpaths = "testing"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iniconfig-2.3.0/src/iniconfig/__init__.py 
new/iniconfig-2.3.1/src/iniconfig/__init__.py
--- old/iniconfig-2.3.0/src/iniconfig/__init__.py       2025-10-18 
23:51:36.000000000 +0200
+++ new/iniconfig-2.3.1/src/iniconfig/__init__.py       2026-10-07 
00:11:15.000000000 +0200
@@ -10,7 +10,7 @@
 from typing import TypeVar
 from typing import overload
 
-__all__ = ["IniConfig", "ParseError", "COMMENTCHARS", "iscommentline"]
+__all__ = ["COMMENTCHARS", "IniConfig", "ParseError", "iscommentline"]
 
 from . import _parse
 from ._parse import COMMENTCHARS
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iniconfig-2.3.0/src/iniconfig/_parse.py 
new/iniconfig-2.3.1/src/iniconfig/_parse.py
--- old/iniconfig-2.3.0/src/iniconfig/_parse.py 2025-10-18 23:51:36.000000000 
+0200
+++ new/iniconfig-2.3.1/src/iniconfig/_parse.py 2026-10-07 00:11:15.000000000 
+0200
@@ -1,16 +1,18 @@
 from collections.abc import Mapping
+from typing import Final
 from typing import NamedTuple
 
 from .exceptions import ParseError
 
 COMMENTCHARS = "#;"
+UTF8_BOM: Final = "\N{BYTE ORDER MARK}"
 
 
 class ParsedLine(NamedTuple):
     lineno: int
     section: str | None
     name: str | None
-    value: str | None
+    value: list[str] | None
 
 
 def parse_ini_data(
@@ -34,6 +36,8 @@
         - sections_data: mapping of section -> {name -> value}
         - sources: mapping of (section, name) -> line number
     """
+    data = data.removeprefix(UTF8_BOM)
+
     tokens = parse_lines(
         path,
         data.splitlines(True),
@@ -56,7 +60,7 @@
             if name in sections_data[section]:
                 raise ParseError(path, lineno, f"duplicate name {name!r}")
             assert value is not None
-            sections_data[section][name] = value
+            sections_data[section][name] = "\n".join(value)
 
     return sections_data, sources
 
@@ -76,7 +80,7 @@
         )
         # new value
         if name is not None and data is not None:
-            result.append(ParsedLine(lineno, section, name, data))
+            result.append(ParsedLine(lineno, section, name, [data] if data 
else []))
         # new section
         elif name is not None and data is None:
             if not name:
@@ -85,17 +89,10 @@
             result.append(ParsedLine(lineno, section, None, None))
         # continuation
         elif name is None and data is not None:
-            if not result:
-                raise ParseError(path, lineno, "unexpected value continuation")
-            last = result.pop()
-            if last.name is None:
+            value = result[-1].value if result else None
+            if value is None:
                 raise ParseError(path, lineno, "unexpected value continuation")
-
-            if last.value:
-                last = last._replace(value=f"{last.value}\n{data}")
-            else:
-                last = last._replace(value=data)
-            result.append(last)
+            value.append(data)
     return result
 
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iniconfig-2.3.0/testing/test_iniconfig.py 
new/iniconfig-2.3.1/testing/test_iniconfig.py
--- old/iniconfig-2.3.0/testing/test_iniconfig.py       2025-10-18 
23:51:36.000000000 +0200
+++ new/iniconfig-2.3.1/testing/test_iniconfig.py       2026-10-07 
00:11:15.000000000 +0200
@@ -11,36 +11,46 @@
 
 check_tokens: dict[str, tuple[str, list[PL]]] = {
     "section": ("[section]", [PL(0, "section", None, None)]),
-    "value": ("value = 1", [PL(0, None, "value", "1")]),
+    "value": ("value = 1", [PL(0, None, "value", ["1"])]),
     "value in section": (
         "[section]\nvalue=1",
-        [PL(0, "section", None, None), PL(1, "section", "value", "1")],
+        [PL(0, "section", None, None), PL(1, "section", "value", ["1"])],
     ),
+    "empty value": ("value =", [PL(0, None, "value", [])]),
     "value with continuation": (
         "names =\n Alice\n Bob",
-        [PL(0, None, "names", "Alice\nBob")],
+        [PL(0, None, "names", ["Alice", "Bob"])],
     ),
     "value with aligned continuation": (
         "names = Alice\n        Bob",
-        [PL(0, None, "names", "Alice\nBob")],
+        [PL(0, None, "names", ["Alice", "Bob"])],
+    ),
+    "continuations on several values": (
+        "a = 1\n 2\n\n 3\n[s]\nb =\n x\n y\nc = z",
+        [
+            PL(0, None, "a", ["1", "2", "3"]),
+            PL(4, "s", None, None),
+            PL(5, "s", "b", ["x", "y"]),
+            PL(8, "s", "c", ["z"]),
+        ],
     ),
     "blank line": (
         "[section]\n\nvalue=1",
-        [PL(0, "section", None, None), PL(2, "section", "value", "1")],
+        [PL(0, "section", None, None), PL(2, "section", "value", ["1"])],
     ),
     "comment": ("# comment", []),
-    "comment on value": ("value = 1", [PL(0, None, "value", "1")]),
+    "comment on value": ("value = 1", [PL(0, None, "value", ["1"])]),
     "comment on section": ("[section] #comment", [PL(0, "section", None, 
None)]),
     "comment2": ("; comment", []),
     "comment2 on section": ("[section] ;comment", [PL(0, "section", None, 
None)]),
     "pseudo section syntax in value": (
         "name = value []",
-        [PL(0, None, "name", "value []")],
+        [PL(0, None, "name", ["value []"])],
     ),
-    "assignment in value": ("value = x = 3", [PL(0, None, "value", "x = 3")]),
-    "use of colon for name-values": ("name: y", [PL(0, None, "name", "y")]),
-    "use of colon without space": ("value:y=5", [PL(0, None, "value", "y=5")]),
-    "equality gets precedence": ("value=xyz:5", [PL(0, None, "value", 
"xyz:5")]),
+    "assignment in value": ("value = x = 3", [PL(0, None, "value", ["x = 
3"])]),
+    "use of colon for name-values": ("name: y", [PL(0, None, "name", ["y"])]),
+    "use of colon without space": ("value:y=5", [PL(0, None, "value", 
["y=5"])]),
+    "equality gets precedence": ("value=xyz:5", [PL(0, None, "value", 
["xyz:5"])]),
 }
 
 
@@ -290,7 +300,7 @@
 
 
 def test_api_import() -> None:
-    assert ALL == ["IniConfig", "ParseError", "COMMENTCHARS", "iscommentline"]
+    assert ALL == ["COMMENTCHARS", "IniConfig", "ParseError", "iscommentline"]
 
 
 @pytest.mark.parametrize(
@@ -412,3 +422,23 @@
     )
     assert "key" in config["section"]
     assert config["section"]["key"] == "value"
+
+
+def test_utf8_bom_file(tmp_path: Path) -> None:
+    """Files saved with a UTF-8 BOM (common on Windows editors) must parse."""
+    path = tmp_path / "bom.ini"
+    path.write_bytes(b"\xef\xbb\xbf[section]\nkey = value\n")
+    config = IniConfig(path)
+    assert config["section"]["key"] == "value"
+
+
+def test_utf8_bom_in_data_string() -> None:
+    config = IniConfig("x.ini", data="\ufeff[section]\nkey = value\n")
+    assert config["section"]["key"] == "value"
+
+
+def test_parse_utf8_bom_file(tmp_path: Path) -> None:
+    path = tmp_path / "bom.ini"
+    path.write_bytes(b"\xef\xbb\xbf[section]\nkey = value\n")
+    config = IniConfig.parse(path)
+    assert config["section"]["key"] == "value"

++++++ iniconfig-2.3.0-tests.tar.gz -> iniconfig-2.3.1.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iniconfig-2.3.0/.pre-commit-config.yaml 
new/iniconfig-2.3.1/.pre-commit-config.yaml
--- old/iniconfig-2.3.0/.pre-commit-config.yaml 2025-10-18 23:51:36.000000000 
+0200
+++ new/iniconfig-2.3.1/.pre-commit-config.yaml 2026-10-07 00:47:10.299275900 
+0200
@@ -1,18 +1,18 @@
 repos:
 - repo: https://github.com/tox-dev/pyproject-fmt
-  rev: "v2.11.0"
+  rev: "v2.30.1"
   hooks:
     - id: pyproject-fmt
 
 - repo: https://github.com/astral-sh/ruff-pre-commit
-  rev: v0.14.1
+  rev: v0.16.10
   hooks:
     - id: ruff-check
       args: [--fix]
     - id: ruff-format
 
 - repo: https://github.com/pre-commit/mirrors-mypy
-  rev: 'v1.18.2'
+  rev: 'v2.4.0'
   hooks:
     - id: mypy
       args: []
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iniconfig-2.3.0/CHANGELOG 
new/iniconfig-2.3.1/CHANGELOG
--- old/iniconfig-2.3.0/CHANGELOG       2025-10-18 23:51:36.000000000 +0200
+++ new/iniconfig-2.3.1/CHANGELOG       2026-10-07 00:47:10.299275900 +0200
@@ -1,3 +1,10 @@
+2.3.1
+=====
+
+* fix quadratic parse time for values with many continuation lines (#78, 
regarding #77)
+* strip a leading UTF-8 BOM when reading INI files, which previously raised 
``ParseError`` (#76)
+* internal: ``iniconfig._parse.ParsedLine.value`` is now a list of lines
+
 2.3.0
 =====
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iniconfig-2.3.0/PKG-INFO new/iniconfig-2.3.1/PKG-INFO
--- old/iniconfig-2.3.0/PKG-INFO        1970-01-01 01:00:00.000000000 +0100
+++ new/iniconfig-2.3.1/PKG-INFO        2026-10-07 00:47:14.833928300 +0200
@@ -0,0 +1,84 @@
+Metadata-Version: 2.4
+Name: iniconfig
+Version: 2.3.1
+Summary: brain-dead simple config-ini parsing
+Author-email: Ronny Pfannschmidt <[email protected]>, Holger 
Krekel <[email protected]>
+License-Expression: MIT
+Project-URL: Homepage, https://github.com/pytest-dev/iniconfig
+Classifier: Development Status :: 4 - Beta
+Classifier: Intended Audience :: Developers
+Classifier: Operating System :: MacOS :: MacOS X
+Classifier: Operating System :: Microsoft :: Windows
+Classifier: Operating System :: POSIX
+Classifier: Programming Language :: Python :: 3 :: Only
+Classifier: Programming Language :: Python :: 3.10
+Classifier: Programming Language :: Python :: 3.11
+Classifier: Programming Language :: Python :: 3.12
+Classifier: Programming Language :: Python :: 3.13
+Classifier: Programming Language :: Python :: 3.14
+Classifier: Programming Language :: Python :: 3.15
+Classifier: Topic :: Software Development :: Libraries
+Classifier: Topic :: Utilities
+Requires-Python: >=3.10
+Description-Content-Type: text/x-rst
+License-File: LICENSE
+Dynamic: license-file
+
+iniconfig: brain-dead simple parsing of ini files
+=======================================================
+
+iniconfig is a small and simple INI-file parser module
+having a unique set of features:
+
+* maintains order of sections and entries
+* supports multi-line values with or without line-continuations
+* supports "#" comments everywhere
+* raises errors with proper line-numbers
+* no bells and whistles like automatic substitutions
+* iniconfig raises an Error if two sections have the same name.
+
+If you encounter issues or have feature wishes please report them to:
+
+    https://github.com/pytest-dev/iniconfig/issues
+
+Basic Example
+===================================
+
+If you have an ini file like this:
+
+.. code-block:: ini
+
+    # content of example.ini
+    [section1] # comment
+    name1=value1  # comment
+    name1b=value1,value2  # comment
+
+    [section2]
+    name2=
+        line1
+        line2
+
+use ``IniConfig.parse()`` to strip inline comments from values:
+
+.. code-block:: pycon
+
+    >>> import iniconfig
+    >>> ini = iniconfig.IniConfig.parse("example.ini")
+    >>> ini['section1']['name1'] # raises KeyError if not exists
+    'value1'
+    >>> ini.get('section1', 'name1b', [], lambda x: x.split(","))
+    ['value1', 'value2']
+    >>> ini.get('section1', 'notexist', [], lambda x: x.split(","))
+    []
+    >>> [x.name for x in list(ini)]
+    ['section1', 'section2']
+    >>> list(list(ini)[0].items())
+    [('name1', 'value1'), ('name1b', 'value1,value2')]
+    >>> 'section1' in ini
+    True
+    >>> 'inexistendsection' in ini
+    False
+
+The ``IniConfig()`` constructor preserves inline comments in values for 
backward
+compatibility. Use ``IniConfig.parse(..., strip_inline_comments=False)`` to
+preserve them when using the parsing method.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iniconfig-2.3.0/README.rst 
new/iniconfig-2.3.1/README.rst
--- old/iniconfig-2.3.0/README.rst      2025-10-18 23:51:36.000000000 +0200
+++ new/iniconfig-2.3.1/README.rst      2026-10-07 00:47:10.299275900 +0200
@@ -13,7 +13,7 @@
 
 If you encounter issues or have feature wishes please report them to:
 
-    https://github.com/RonnyPfannschmidt/iniconfig/issues
+    https://github.com/pytest-dev/iniconfig/issues
 
 Basic Example
 ===================================
@@ -32,12 +32,12 @@
         line1
         line2
 
-then you can do:
+use ``IniConfig.parse()`` to strip inline comments from values:
 
 .. code-block:: pycon
 
     >>> import iniconfig
-    >>> ini = iniconfig.IniConfig("example.ini")
+    >>> ini = iniconfig.IniConfig.parse("example.ini")
     >>> ini['section1']['name1'] # raises KeyError if not exists
     'value1'
     >>> ini.get('section1', 'name1b', [], lambda x: x.split(","))
@@ -52,3 +52,7 @@
     True
     >>> 'inexistendsection' in ini
     False
+
+The ``IniConfig()`` constructor preserves inline comments in values for 
backward
+compatibility. Use ``IniConfig.parse(..., strip_inline_comments=False)`` to
+preserve them when using the parsing method.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iniconfig-2.3.0/pyproject.toml 
new/iniconfig-2.3.1/pyproject.toml
--- old/iniconfig-2.3.0/pyproject.toml  2025-10-18 23:51:36.000000000 +0200
+++ new/iniconfig-2.3.1/pyproject.toml  2026-10-07 00:47:10.299275900 +0200
@@ -28,6 +28,7 @@
   "Programming Language :: Python :: 3.12",
   "Programming Language :: Python :: 3.13",
   "Programming Language :: Python :: 3.14",
+  "Programming Language :: Python :: 3.15",
   "Topic :: Software Development :: Libraries",
   "Topic :: Utilities",
 ]
@@ -45,15 +46,12 @@
 [tool.setuptools]
 packages = [ "iniconfig" ]
 package-dir = { "" = "src" }
-
-[tool.setuptools.package-data]
-iniconfig = [ "py.typed" ]
+package-data.iniconfig = [ "py.typed" ]
 
 [tool.setuptools_scm]
 write_to = "src/iniconfig/_version.py"
 
 [tool.ruff]
-
 lint.extend-select = [
   "B",  # flake8-bugbear
   "I",  # isort
@@ -63,8 +61,8 @@
 lint.isort.force-single-line = true
 lint.isort.known-first-party = [ "iniconfig" ]
 
-[tool.pytest.ini_options]
-testpaths = "testing"
-
 [tool.mypy]
 strict = true
+
+[tool.pytest]
+ini_options.testpaths = "testing"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iniconfig-2.3.0/setup.cfg 
new/iniconfig-2.3.1/setup.cfg
--- old/iniconfig-2.3.0/setup.cfg       1970-01-01 01:00:00.000000000 +0100
+++ new/iniconfig-2.3.1/setup.cfg       2026-10-07 00:47:14.834203700 +0200
@@ -0,0 +1,4 @@
+[egg_info]
+tag_build = 
+tag_date = 0
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iniconfig-2.3.0/src/iniconfig/__init__.py 
new/iniconfig-2.3.1/src/iniconfig/__init__.py
--- old/iniconfig-2.3.0/src/iniconfig/__init__.py       2025-10-18 
23:51:36.000000000 +0200
+++ new/iniconfig-2.3.1/src/iniconfig/__init__.py       2026-10-07 
00:47:10.299815400 +0200
@@ -10,7 +10,7 @@
 from typing import TypeVar
 from typing import overload
 
-__all__ = ["IniConfig", "ParseError", "COMMENTCHARS", "iscommentline"]
+__all__ = ["COMMENTCHARS", "IniConfig", "ParseError", "iscommentline"]
 
 from . import _parse
 from ._parse import COMMENTCHARS
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iniconfig-2.3.0/src/iniconfig/_parse.py 
new/iniconfig-2.3.1/src/iniconfig/_parse.py
--- old/iniconfig-2.3.0/src/iniconfig/_parse.py 2025-10-18 23:51:36.000000000 
+0200
+++ new/iniconfig-2.3.1/src/iniconfig/_parse.py 2026-10-07 00:47:10.299902000 
+0200
@@ -1,16 +1,18 @@
 from collections.abc import Mapping
+from typing import Final
 from typing import NamedTuple
 
 from .exceptions import ParseError
 
 COMMENTCHARS = "#;"
+UTF8_BOM: Final = "\N{BYTE ORDER MARK}"
 
 
 class ParsedLine(NamedTuple):
     lineno: int
     section: str | None
     name: str | None
-    value: str | None
+    value: list[str] | None
 
 
 def parse_ini_data(
@@ -34,6 +36,8 @@
         - sections_data: mapping of section -> {name -> value}
         - sources: mapping of (section, name) -> line number
     """
+    data = data.removeprefix(UTF8_BOM)
+
     tokens = parse_lines(
         path,
         data.splitlines(True),
@@ -56,7 +60,7 @@
             if name in sections_data[section]:
                 raise ParseError(path, lineno, f"duplicate name {name!r}")
             assert value is not None
-            sections_data[section][name] = value
+            sections_data[section][name] = "\n".join(value)
 
     return sections_data, sources
 
@@ -76,7 +80,7 @@
         )
         # new value
         if name is not None and data is not None:
-            result.append(ParsedLine(lineno, section, name, data))
+            result.append(ParsedLine(lineno, section, name, [data] if data 
else []))
         # new section
         elif name is not None and data is None:
             if not name:
@@ -85,17 +89,10 @@
             result.append(ParsedLine(lineno, section, None, None))
         # continuation
         elif name is None and data is not None:
-            if not result:
-                raise ParseError(path, lineno, "unexpected value continuation")
-            last = result.pop()
-            if last.name is None:
+            value = result[-1].value if result else None
+            if value is None:
                 raise ParseError(path, lineno, "unexpected value continuation")
-
-            if last.value:
-                last = last._replace(value=f"{last.value}\n{data}")
-            else:
-                last = last._replace(value=data)
-            result.append(last)
+            value.append(data)
     return result
 
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iniconfig-2.3.0/src/iniconfig/_version.py 
new/iniconfig-2.3.1/src/iniconfig/_version.py
--- old/iniconfig-2.3.0/src/iniconfig/_version.py       1970-01-01 
01:00:00.000000000 +0100
+++ new/iniconfig-2.3.1/src/iniconfig/_version.py       2026-10-07 
00:47:14.783777000 +0200
@@ -0,0 +1,24 @@
+# file generated by vcs-versioning
+# don't change, don't track in version control
+from __future__ import annotations
+
+__all__ = [
+    "__version__",
+    "__version_tuple__",
+    "version",
+    "version_tuple",
+    "__commit_id__",
+    "commit_id",
+]
+
+version: str
+__version__: str
+__version_tuple__: tuple[int | str, ...]
+version_tuple: tuple[int | str, ...]
+commit_id: str | None
+__commit_id__: str | None
+
+__version__ = version = '2.3.1'
+__version_tuple__ = version_tuple = (2, 3, 1)
+
+__commit_id__ = commit_id = 'g316fbfaf2'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iniconfig-2.3.0/src/iniconfig.egg-info/PKG-INFO 
new/iniconfig-2.3.1/src/iniconfig.egg-info/PKG-INFO
--- old/iniconfig-2.3.0/src/iniconfig.egg-info/PKG-INFO 1970-01-01 
01:00:00.000000000 +0100
+++ new/iniconfig-2.3.1/src/iniconfig.egg-info/PKG-INFO 2026-10-07 
00:47:14.815185000 +0200
@@ -0,0 +1,84 @@
+Metadata-Version: 2.4
+Name: iniconfig
+Version: 2.3.1
+Summary: brain-dead simple config-ini parsing
+Author-email: Ronny Pfannschmidt <[email protected]>, Holger 
Krekel <[email protected]>
+License-Expression: MIT
+Project-URL: Homepage, https://github.com/pytest-dev/iniconfig
+Classifier: Development Status :: 4 - Beta
+Classifier: Intended Audience :: Developers
+Classifier: Operating System :: MacOS :: MacOS X
+Classifier: Operating System :: Microsoft :: Windows
+Classifier: Operating System :: POSIX
+Classifier: Programming Language :: Python :: 3 :: Only
+Classifier: Programming Language :: Python :: 3.10
+Classifier: Programming Language :: Python :: 3.11
+Classifier: Programming Language :: Python :: 3.12
+Classifier: Programming Language :: Python :: 3.13
+Classifier: Programming Language :: Python :: 3.14
+Classifier: Programming Language :: Python :: 3.15
+Classifier: Topic :: Software Development :: Libraries
+Classifier: Topic :: Utilities
+Requires-Python: >=3.10
+Description-Content-Type: text/x-rst
+License-File: LICENSE
+Dynamic: license-file
+
+iniconfig: brain-dead simple parsing of ini files
+=======================================================
+
+iniconfig is a small and simple INI-file parser module
+having a unique set of features:
+
+* maintains order of sections and entries
+* supports multi-line values with or without line-continuations
+* supports "#" comments everywhere
+* raises errors with proper line-numbers
+* no bells and whistles like automatic substitutions
+* iniconfig raises an Error if two sections have the same name.
+
+If you encounter issues or have feature wishes please report them to:
+
+    https://github.com/pytest-dev/iniconfig/issues
+
+Basic Example
+===================================
+
+If you have an ini file like this:
+
+.. code-block:: ini
+
+    # content of example.ini
+    [section1] # comment
+    name1=value1  # comment
+    name1b=value1,value2  # comment
+
+    [section2]
+    name2=
+        line1
+        line2
+
+use ``IniConfig.parse()`` to strip inline comments from values:
+
+.. code-block:: pycon
+
+    >>> import iniconfig
+    >>> ini = iniconfig.IniConfig.parse("example.ini")
+    >>> ini['section1']['name1'] # raises KeyError if not exists
+    'value1'
+    >>> ini.get('section1', 'name1b', [], lambda x: x.split(","))
+    ['value1', 'value2']
+    >>> ini.get('section1', 'notexist', [], lambda x: x.split(","))
+    []
+    >>> [x.name for x in list(ini)]
+    ['section1', 'section2']
+    >>> list(list(ini)[0].items())
+    [('name1', 'value1'), ('name1b', 'value1,value2')]
+    >>> 'section1' in ini
+    True
+    >>> 'inexistendsection' in ini
+    False
+
+The ``IniConfig()`` constructor preserves inline comments in values for 
backward
+compatibility. Use ``IniConfig.parse(..., strip_inline_comments=False)`` to
+preserve them when using the parsing method.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iniconfig-2.3.0/src/iniconfig.egg-info/SOURCES.txt 
new/iniconfig-2.3.1/src/iniconfig.egg-info/SOURCES.txt
--- old/iniconfig-2.3.0/src/iniconfig.egg-info/SOURCES.txt      1970-01-01 
01:00:00.000000000 +0100
+++ new/iniconfig-2.3.1/src/iniconfig.egg-info/SOURCES.txt      2026-10-07 
00:47:14.825145000 +0200
@@ -0,0 +1,23 @@
+.gitignore
+.pre-commit-config.yaml
+CHANGELOG
+LICENSE
+MANIFEST.in
+README.rst
+example.ini
+pyproject.toml
+uv.lock
+.github/workflows/test.yml
+src/iniconfig/__init__.py
+src/iniconfig/_parse.py
+src/iniconfig/_version.py
+src/iniconfig/exceptions.py
+src/iniconfig/py.typed
+src/iniconfig.egg-info/PKG-INFO
+src/iniconfig.egg-info/SOURCES.txt
+src/iniconfig.egg-info/dependency_links.txt
+src/iniconfig.egg-info/scm_file_list.json
+src/iniconfig.egg-info/scm_version.json
+src/iniconfig.egg-info/top_level.txt
+testing/conftest.py
+testing/test_iniconfig.py
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/iniconfig-2.3.0/src/iniconfig.egg-info/dependency_links.txt 
new/iniconfig-2.3.1/src/iniconfig.egg-info/dependency_links.txt
--- old/iniconfig-2.3.0/src/iniconfig.egg-info/dependency_links.txt     
1970-01-01 01:00:00.000000000 +0100
+++ new/iniconfig-2.3.1/src/iniconfig.egg-info/dependency_links.txt     
2026-10-07 00:47:14.815457000 +0200
@@ -0,0 +1 @@
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/iniconfig-2.3.0/src/iniconfig.egg-info/scm_file_list.json 
new/iniconfig-2.3.1/src/iniconfig.egg-info/scm_file_list.json
--- old/iniconfig-2.3.0/src/iniconfig.egg-info/scm_file_list.json       
1970-01-01 01:00:00.000000000 +0100
+++ new/iniconfig-2.3.1/src/iniconfig.egg-info/scm_file_list.json       
2026-10-07 00:47:14.812223400 +0200
@@ -0,0 +1,20 @@
+{
+  "files": [
+    ".github/workflows/test.yml",
+    ".gitignore",
+    ".pre-commit-config.yaml",
+    "CHANGELOG",
+    "LICENSE",
+    "MANIFEST.in",
+    "README.rst",
+    "example.ini",
+    "pyproject.toml",
+    "src/iniconfig/__init__.py",
+    "src/iniconfig/_parse.py",
+    "src/iniconfig/exceptions.py",
+    "src/iniconfig/py.typed",
+    "testing/conftest.py",
+    "testing/test_iniconfig.py",
+    "uv.lock"
+  ]
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/iniconfig-2.3.0/src/iniconfig.egg-info/scm_version.json 
new/iniconfig-2.3.1/src/iniconfig.egg-info/scm_version.json
--- old/iniconfig-2.3.0/src/iniconfig.egg-info/scm_version.json 1970-01-01 
01:00:00.000000000 +0100
+++ new/iniconfig-2.3.1/src/iniconfig.egg-info/scm_version.json 2026-10-07 
00:47:14.806256500 +0200
@@ -0,0 +1,8 @@
+{
+  "tag": "2.3.1",
+  "distance": 0,
+  "node": "g316fbfaf2752d89326e1e75b45cd070f5b5ace9a",
+  "dirty": false,
+  "branch": "HEAD",
+  "node_date": "2026-10-06"
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iniconfig-2.3.0/src/iniconfig.egg-info/top_level.txt 
new/iniconfig-2.3.1/src/iniconfig.egg-info/top_level.txt
--- old/iniconfig-2.3.0/src/iniconfig.egg-info/top_level.txt    1970-01-01 
01:00:00.000000000 +0100
+++ new/iniconfig-2.3.1/src/iniconfig.egg-info/top_level.txt    2026-10-07 
00:47:14.815787300 +0200
@@ -0,0 +1 @@
+iniconfig
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iniconfig-2.3.0/testing/test_iniconfig.py 
new/iniconfig-2.3.1/testing/test_iniconfig.py
--- old/iniconfig-2.3.0/testing/test_iniconfig.py       2025-10-18 
23:51:36.000000000 +0200
+++ new/iniconfig-2.3.1/testing/test_iniconfig.py       2026-10-07 
00:47:10.300073600 +0200
@@ -11,36 +11,46 @@
 
 check_tokens: dict[str, tuple[str, list[PL]]] = {
     "section": ("[section]", [PL(0, "section", None, None)]),
-    "value": ("value = 1", [PL(0, None, "value", "1")]),
+    "value": ("value = 1", [PL(0, None, "value", ["1"])]),
     "value in section": (
         "[section]\nvalue=1",
-        [PL(0, "section", None, None), PL(1, "section", "value", "1")],
+        [PL(0, "section", None, None), PL(1, "section", "value", ["1"])],
     ),
+    "empty value": ("value =", [PL(0, None, "value", [])]),
     "value with continuation": (
         "names =\n Alice\n Bob",
-        [PL(0, None, "names", "Alice\nBob")],
+        [PL(0, None, "names", ["Alice", "Bob"])],
     ),
     "value with aligned continuation": (
         "names = Alice\n        Bob",
-        [PL(0, None, "names", "Alice\nBob")],
+        [PL(0, None, "names", ["Alice", "Bob"])],
+    ),
+    "continuations on several values": (
+        "a = 1\n 2\n\n 3\n[s]\nb =\n x\n y\nc = z",
+        [
+            PL(0, None, "a", ["1", "2", "3"]),
+            PL(4, "s", None, None),
+            PL(5, "s", "b", ["x", "y"]),
+            PL(8, "s", "c", ["z"]),
+        ],
     ),
     "blank line": (
         "[section]\n\nvalue=1",
-        [PL(0, "section", None, None), PL(2, "section", "value", "1")],
+        [PL(0, "section", None, None), PL(2, "section", "value", ["1"])],
     ),
     "comment": ("# comment", []),
-    "comment on value": ("value = 1", [PL(0, None, "value", "1")]),
+    "comment on value": ("value = 1", [PL(0, None, "value", ["1"])]),
     "comment on section": ("[section] #comment", [PL(0, "section", None, 
None)]),
     "comment2": ("; comment", []),
     "comment2 on section": ("[section] ;comment", [PL(0, "section", None, 
None)]),
     "pseudo section syntax in value": (
         "name = value []",
-        [PL(0, None, "name", "value []")],
+        [PL(0, None, "name", ["value []"])],
     ),
-    "assignment in value": ("value = x = 3", [PL(0, None, "value", "x = 3")]),
-    "use of colon for name-values": ("name: y", [PL(0, None, "name", "y")]),
-    "use of colon without space": ("value:y=5", [PL(0, None, "value", "y=5")]),
-    "equality gets precedence": ("value=xyz:5", [PL(0, None, "value", 
"xyz:5")]),
+    "assignment in value": ("value = x = 3", [PL(0, None, "value", ["x = 
3"])]),
+    "use of colon for name-values": ("name: y", [PL(0, None, "name", ["y"])]),
+    "use of colon without space": ("value:y=5", [PL(0, None, "value", 
["y=5"])]),
+    "equality gets precedence": ("value=xyz:5", [PL(0, None, "value", 
["xyz:5"])]),
 }
 
 
@@ -290,7 +300,7 @@
 
 
 def test_api_import() -> None:
-    assert ALL == ["IniConfig", "ParseError", "COMMENTCHARS", "iscommentline"]
+    assert ALL == ["COMMENTCHARS", "IniConfig", "ParseError", "iscommentline"]
 
 
 @pytest.mark.parametrize(
@@ -412,3 +422,23 @@
     )
     assert "key" in config["section"]
     assert config["section"]["key"] == "value"
+
+
+def test_utf8_bom_file(tmp_path: Path) -> None:
+    """Files saved with a UTF-8 BOM (common on Windows editors) must parse."""
+    path = tmp_path / "bom.ini"
+    path.write_bytes(b"\xef\xbb\xbf[section]\nkey = value\n")
+    config = IniConfig(path)
+    assert config["section"]["key"] == "value"
+
+
+def test_utf8_bom_in_data_string() -> None:
+    config = IniConfig("x.ini", data="\ufeff[section]\nkey = value\n")
+    assert config["section"]["key"] == "value"
+
+
+def test_parse_utf8_bom_file(tmp_path: Path) -> None:
+    path = tmp_path / "bom.ini"
+    path.write_bytes(b"\xef\xbb\xbf[section]\nkey = value\n")
+    config = IniConfig.parse(path)
+    assert config["section"]["key"] == "value"

Reply via email to