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 2025-12-11 18:31:58
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-iniconfig (Old)
 and      /work/SRC/openSUSE:Factory/.python-iniconfig.new.1939 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-iniconfig"

Thu Dec 11 18:31:58 2025 rev:10 rq:1321919 version:2.3.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-iniconfig/python-iniconfig.changes        
2025-06-10 08:58:30.182585626 +0200
+++ 
/work/SRC/openSUSE:Factory/.python-iniconfig.new.1939/python-iniconfig.changes  
    2025-12-11 18:32:15.666598211 +0100
@@ -1,0 +2,36 @@
+Wed Dec 10 09:30:44 UTC 2025 - Matej Cepl <[email protected]>
+
+- Clean the SPEC file.
+
+-------------------------------------------------------------------
+Thu Dec  4 10:02:05 UTC 2025 - John Paul Adrian Glaubitz 
<[email protected]>
+
+- Update to 2.3.0
+  * add IniConfig.parse() classmethod with strip_inline_comments parameter 
(fixes #55)
+    - by default (strip_inline_comments=True), inline comments are properly 
stripped from values
+    - set strip_inline_comments=False to preserve old behavior if needed
+  * IniConfig() constructor maintains backward compatibility (does not strip 
inline comments)
+  * users should migrate to IniConfig.parse() for correct comment handling
+  * add strip_section_whitespace parameter to IniConfig.parse() (regarding #4)
+    - opt-in parameter to strip Unicode whitespace from section names
+    - when True, strips Unicode whitespace (U+00A0, U+2000, U+3000, etc.) from 
section names
+    - when False (default), preserves existing behavior for backward 
compatibility
+  * clarify Unicode whitespace handling (regarding #4)
+    - since iniconfig 2.0.0 (Python 3 only), all strings are Unicode by default
+    - Python 3's str.strip() has handled Unicode whitespace since Python 3.0 
(2008)
+    - iniconfig automatically benefits from this in all supported versions 
(Python >= 3.10)
+    - key names and values have Unicode whitespace properly stripped using 
Python's built-in methods
+- from version 2.2.0
+  * drop Python 3.8 and 3.9 support (now requires Python >= 3.10)
+  * add Python 3.14 classifier
+  * migrate from hatchling to setuptools 77 with setuptools_scm
+  * adopt PEP 639 license specifiers and PEP 740 build attestations
+  * migrate from black + pyupgrade to ruff
+  * migrate CI to uv and unified test workflow
+  * automate GitHub releases and PyPI publishing via Trusted Publishing
+  * include tests in sdist
+  * modernize code for Python 3.10+ (remove __future__ annotations, 
TYPE_CHECKING guards)
+  * rename _ParsedLine to ParsedLine
+- Update BuildRequires from pyproject.toml
+
+-------------------------------------------------------------------

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

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

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

Other differences:
------------------
++++++ python-iniconfig.spec ++++++
--- /var/tmp/diff_new_pack.w5psLa/_old  2025-12-11 18:32:16.358627302 +0100
+++ /var/tmp/diff_new_pack.w5psLa/_new  2025-12-11 18:32:16.362627470 +0100
@@ -1,7 +1,7 @@
 #
 # spec file for package python-iniconfig
 #
-# Copyright (c) 2025 SUSE LLC
+# Copyright (c) 2025 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
@@ -16,7 +16,6 @@
 #
 
 
-%{?!python_module:%define python_module() python-%{**} python3-%{**}}
 %global flavor @BUILD_FLAVOR@%{nil}
 %if "%{flavor}" == "test"
 %define psuffix -%{flavor}
@@ -27,7 +26,7 @@
 %endif
 %{?sle15_python_module_pythons}
 Name:           python-iniconfig%{psuffix}
-Version:        2.1.0
+Version:        2.3.0
 Release:        0
 Summary:        iniconfig: brain-dead simple config-ini parsing
 License:        MIT
@@ -36,9 +35,9 @@
 Source:         
https://files.pythonhosted.org/packages/source/i/iniconfig/iniconfig-%{version}.tar.gz
 Source1:        
https://github.com/pytest-dev/iniconfig/archive/refs/tags/v%{version}.tar.gz#/iniconfig-%{version}-tests.tar.gz
 BuildRequires:  %{python_module base >= 3.8}
-BuildRequires:  %{python_module hatch_vcs}
-BuildRequires:  %{python_module hatchling}
 BuildRequires:  %{python_module pip}
+BuildRequires:  %{python_module setuptools >= 77}
+BuildRequires:  %{python_module setuptools_scm}
 BuildRequires:  fdupes
 BuildRequires:  python-rpm-macros
 BuildArch:      noarch
@@ -61,7 +60,7 @@
 * iniconfig raises an Error if two sections have the same name.
 
 %prep
-%setup -q -n iniconfig-%{version} -a1
+%autosetup -p1 -n iniconfig-%{version} -a1
 
 %if !%{with test}
 %build

++++++ iniconfig-2.1.0-tests.tar.gz -> iniconfig-2.3.0-tests.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iniconfig-2.1.0/.github/workflows/deploy.yml 
new/iniconfig-2.3.0/.github/workflows/deploy.yml
--- old/iniconfig-2.1.0/.github/workflows/deploy.yml    2025-03-19 
18:28:27.000000000 +0100
+++ new/iniconfig-2.3.0/.github/workflows/deploy.yml    1970-01-01 
01:00:00.000000000 +0100
@@ -1,63 +0,0 @@
-name: Deploy
-
-on:
-  push:
-    branches:
-      - master
-      - "*deploy*"
-  release:
-    types:
-      - published
-
-jobs:
-  build:
-    if: github.repository == 'pytest-dev/iniconfig'
-    runs-on: ubuntu-latest
-
-    steps:
-      - uses: actions/checkout@v4
-        with:
-          fetch-depth: 0
-      - name: Cache
-        uses: actions/cache@v4
-        with:
-          path: ~/.cache/pip
-          key: deploy-${{ hashFiles('**/pyproject.toml') }}
-          restore-keys: |
-            deploy-
-
-      - name: Set up Python
-        uses: actions/setup-python@v5
-        with:
-          python-version: "3.x"
-
-      - name: Install build + twine
-        run: python -m pip install build twine setuptools_scm
-
-      - name: git describe output
-        run: git describe --tags
-
-      - id: scm_version
-        run: |
-          VERSION=$(python -m setuptools_scm --strip-dev)
-          echo SETUPTOOLS_SCM_PRETEND_VERSION=$VERSION >> $GITHUB_ENV
-
-      - name: Build package
-        run: python -m build
-      
-      - name: twine check
-        run: twine check dist/*
-
-      - name: Publish package to PyPI
-        if: github.event.action == 'published'
-        uses: pypa/gh-action-pypi-publish@release/v1
-        with:
-          user: __token__
-          password: ${{ secrets.pypi_password }}
-
-      - name: Publish package to TestPyPI
-        uses: pypa/gh-action-pypi-publish@release/v1
-        with:
-          user: __token__
-          password: ${{ secrets.test_pypi_password }}
-          repository_url: https://test.pypi.org/legacy/
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iniconfig-2.1.0/.github/workflows/main.yml 
new/iniconfig-2.3.0/.github/workflows/main.yml
--- old/iniconfig-2.1.0/.github/workflows/main.yml      2025-03-19 
18:28:27.000000000 +0100
+++ new/iniconfig-2.3.0/.github/workflows/main.yml      1970-01-01 
01:00:00.000000000 +0100
@@ -1,35 +0,0 @@
-name: build
-
-on: [push, pull_request, workflow_dispatch]
-
-jobs:
-  build:
-
-    runs-on: ${{ matrix.os }}
-
-    strategy:
-      fail-fast: false
-      matrix:
-        python: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13"]
-        os: [ubuntu-latest, windows-latest]
-
-    steps:
-    - uses: actions/checkout@v4
-    - name: Set up Python
-      uses: actions/setup-python@v5
-      with:
-        python-version: ${{ matrix.python }}
-        allow-prereleases: true
-    - name: Install hatch
-      run: python -m pip install --upgrade pip hatch hatch-vcs
-    - name: Run tests
-      run: hatch run +py=${{ matrix.python }} test:default --color=yes
-
-  pre-commit:
-    runs-on: ubuntu-latest
-    steps:
-    - uses: actions/checkout@v4
-    - uses: actions/setup-python@v5
-      with:
-        python-version: 3.x
-    - uses: pre-commit/[email protected]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iniconfig-2.1.0/.github/workflows/test.yml 
new/iniconfig-2.3.0/.github/workflows/test.yml
--- old/iniconfig-2.1.0/.github/workflows/test.yml      1970-01-01 
01:00:00.000000000 +0100
+++ new/iniconfig-2.3.0/.github/workflows/test.yml      2025-10-18 
23:51:36.000000000 +0200
@@ -0,0 +1,144 @@
+name: test
+
+on: [push, pull_request, workflow_dispatch]
+
+jobs:
+  build-and-inspect:
+    runs-on: ubuntu-latest
+    permissions:
+      id-token: write
+      attestations: write
+      contents: read
+    outputs:
+      python-versions: ${{ 
steps.baipp.outputs.supported_python_classifiers_json_array }}
+
+    steps:
+      - uses: actions/checkout@v4
+        with:
+          fetch-depth: 0
+
+      - name: Build and inspect package
+        id: baipp
+        uses: hynek/build-and-inspect-python-package@v2
+        with:
+          attest-build-provenance-github: ${{ github.event_name != 
'pull_request' || github.event.pull_request.head.repo.full_name == 
github.repository }}
+        env:
+          SETUPTOOLS_SCM_OVERRIDES_FOR_INICONFIG: ${{ github.ref == 
'refs/heads/main' && 'local_scheme="no-local-version"' || '' }}
+
+  test:
+    needs: build-and-inspect
+    runs-on: ${{ matrix.os }}
+    defaults:
+      run:
+        shell: bash
+
+    strategy:
+      fail-fast: false
+      matrix:
+        python: ${{ fromJSON(needs.build-and-inspect.outputs.python-versions) 
}}
+        os: [ubuntu-latest, windows-latest]
+
+    steps:
+      - name: Checkout test files
+        uses: actions/checkout@v4
+        with:
+          sparse-checkout: |
+            testing
+            uv.lock
+          sparse-checkout-cone-mode: false
+
+      - name: Download built packages
+        uses: actions/download-artifact@v4
+        with:
+          name: Packages
+          path: dist
+
+      - name: Verify artifacts exist
+        run: |
+          ls -la dist/
+          test -f dist/*.whl || (echo "No wheel found!" && exit 1)
+          test -f dist/*.tar.gz || (echo "No sdist found!" && exit 1)
+
+      - name: Install uv
+        uses: astral-sh/setup-uv@v7
+        with:
+          enable-cache: true
+
+      - name: Set up Python ${{ matrix.python }}
+        run: uv python install ${{ matrix.python }}
+
+      - name: Run tests with built wheel
+        run: uv run --with dist/*.whl --with pytest pytest testing --color=yes
+
+  create-release:
+    name: Create GitHub Release
+    if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')
+    needs: [test, build-and-inspect]
+    runs-on: ubuntu-latest
+    permissions:
+      contents: write
+
+    steps:
+      - name: Download built packages
+        uses: actions/download-artifact@v4
+        with:
+          name: Packages
+          path: dist
+
+      - name: Extract version from tag
+        id: version
+        run: echo "VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_OUTPUT
+
+      - name: Create GitHub Release
+        uses: softprops/action-gh-release@v2
+        with:
+          files: dist/*
+          fail_on_unmatched_files: true
+          generate_release_notes: true
+          name: Version ${{ steps.version.outputs.VERSION }}
+
+  publish-to-pypi:
+    name: Publish to PyPI
+    if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')
+    needs: [test, build-and-inspect, create-release]
+    runs-on: ubuntu-latest
+    environment: pypi-upload
+    permissions:
+      id-token: write
+
+    steps:
+      - name: Download built packages
+        uses: actions/download-artifact@v4
+        with:
+          name: Packages
+          path: dist
+
+      - name: Publish package to PyPI
+        uses: pypa/gh-action-pypi-publish@release/v1
+
+  publish-to-test-pypi:
+    name: Publish to TestPyPI
+    if: |
+      github.repository == 'pytest-dev/iniconfig' &&
+      (github.event_name == 'push' && (
+        github.ref == 'refs/heads/main' ||
+        contains(github.ref, 'deploy')
+      ))
+    needs: [test, build-and-inspect]
+    runs-on: ubuntu-latest
+    environment: test-pypi-upload
+    permissions:
+      id-token: write
+      attestations: write
+
+    steps:
+      - name: Download built packages
+        uses: actions/download-artifact@v4
+        with:
+          name: Packages
+          path: dist
+
+      - name: Publish package to TestPyPI
+        uses: pypa/gh-action-pypi-publish@release/v1
+        with:
+          repository-url: https://test.pypi.org/legacy/
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iniconfig-2.1.0/.pre-commit-config.yaml 
new/iniconfig-2.3.0/.pre-commit-config.yaml
--- old/iniconfig-2.1.0/.pre-commit-config.yaml 2025-03-19 18:28:27.000000000 
+0100
+++ new/iniconfig-2.3.0/.pre-commit-config.yaml 2025-10-18 23:51:36.000000000 
+0200
@@ -1,24 +1,21 @@
 repos:
--   repo: https://github.com/asottile/pyupgrade
-    rev: v3.3.1
-    hooks:
-    -   id: pyupgrade
-        args: [--py38-plus]
 - repo: https://github.com/tox-dev/pyproject-fmt
-  rev: "0.4.1"
+  rev: "v2.11.0"
   hooks:
     - id: pyproject-fmt
 
-- repo: https://github.com/psf/black
-  rev: 22.12.0
+- repo: https://github.com/astral-sh/ruff-pre-commit
+  rev: v0.14.1
   hooks:
-      - id: black
-        language_version: python3
--   repo: https://github.com/pre-commit/mirrors-mypy
-    rev: 'v0.991' 
-    hooks:
-    -   id: mypy
-        args: []
-        additional_dependencies:
-          - "pytest==7.2.0"
-          - "tomli"
\ No newline at end of file
+    - id: ruff-check
+      args: [--fix]
+    - id: ruff-format
+
+- repo: https://github.com/pre-commit/mirrors-mypy
+  rev: 'v1.18.2'
+  hooks:
+    - id: mypy
+      args: []
+      additional_dependencies:
+        - "pytest==7.2.0"
+        - "tomli"
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iniconfig-2.1.0/CHANGELOG 
new/iniconfig-2.3.0/CHANGELOG
--- old/iniconfig-2.1.0/CHANGELOG       2025-03-19 18:28:27.000000000 +0100
+++ new/iniconfig-2.3.0/CHANGELOG       2025-10-18 23:51:36.000000000 +0200
@@ -1,3 +1,35 @@
+2.3.0
+=====
+
+* add IniConfig.parse() classmethod with strip_inline_comments parameter 
(fixes #55)
+  - by default (strip_inline_comments=True), inline comments are properly 
stripped from values
+  - set strip_inline_comments=False to preserve old behavior if needed
+* IniConfig() constructor maintains backward compatibility (does not strip 
inline comments)
+* users should migrate to IniConfig.parse() for correct comment handling
+* add strip_section_whitespace parameter to IniConfig.parse() (regarding #4)
+  - opt-in parameter to strip Unicode whitespace from section names
+  - when True, strips Unicode whitespace (U+00A0, U+2000, U+3000, etc.) from 
section names
+  - when False (default), preserves existing behavior for backward 
compatibility
+* clarify Unicode whitespace handling (regarding #4)
+  - since iniconfig 2.0.0 (Python 3 only), all strings are Unicode by default
+  - Python 3's str.strip() has handled Unicode whitespace since Python 3.0 
(2008)
+  - iniconfig automatically benefits from this in all supported versions 
(Python >= 3.10)
+  - key names and values have Unicode whitespace properly stripped using 
Python's built-in methods
+
+2.2.0
+=====
+
+* drop Python 3.8 and 3.9 support (now requires Python >= 3.10)
+* add Python 3.14 classifier
+* migrate from hatchling to setuptools 77 with setuptools_scm
+* adopt PEP 639 license specifiers and PEP 740 build attestations
+* migrate from black + pyupgrade to ruff
+* migrate CI to uv and unified test workflow
+* automate GitHub releases and PyPI publishing via Trusted Publishing
+* include tests in sdist
+* modernize code for Python 3.10+ (remove __future__ annotations, 
TYPE_CHECKING guards)
+* rename _ParsedLine to ParsedLine
+
 2.1.0
 =====
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iniconfig-2.1.0/pyproject.toml 
new/iniconfig-2.3.0/pyproject.toml
--- old/iniconfig-2.1.0/pyproject.toml  2025-03-19 18:28:27.000000000 +0100
+++ new/iniconfig-2.3.0/pyproject.toml  2025-10-18 23:51:36.000000000 +0200
@@ -1,8 +1,8 @@
 [build-system]
-build-backend = "hatchling.build"
+build-backend = "setuptools.build_meta"
 requires = [
-  "hatch-vcs",
-  "hatchling>=1.26",
+  "setuptools>=77",
+  "setuptools-scm>=8",
 ]
 
 [project]
@@ -10,62 +10,61 @@
 description = "brain-dead simple config-ini parsing"
 readme = "README.rst"
 license = "MIT"
+license-files = [ "LICENSE" ]
 authors = [
-    { name = "Ronny Pfannschmidt", email = "[email protected]" },
-    { name = "Holger Krekel", email = "[email protected]" },
+  { name = "Ronny Pfannschmidt", email = "[email protected]" },
+  { name = "Holger Krekel", email = "[email protected]" },
+]
+requires-python = ">=3.10"
+classifiers = [
+  "Development Status :: 4 - Beta",
+  "Intended Audience :: Developers",
+  "Operating System :: MacOS :: MacOS X",
+  "Operating System :: Microsoft :: Windows",
+  "Operating System :: POSIX",
+  "Programming Language :: Python :: 3 :: Only",
+  "Programming Language :: Python :: 3.10",
+  "Programming Language :: Python :: 3.11",
+  "Programming Language :: Python :: 3.12",
+  "Programming Language :: Python :: 3.13",
+  "Programming Language :: Python :: 3.14",
+  "Topic :: Software Development :: Libraries",
+  "Topic :: Utilities",
 ]
-requires-python = ">=3.8"
 dynamic = [
   "version",
 ]
-classifiers = [
-    "Development Status :: 4 - Beta",
-    "Intended Audience :: Developers",
-    "License :: OSI Approved :: MIT License",
-    "Operating System :: MacOS :: MacOS X",
-    "Operating System :: Microsoft :: Windows",
-    "Operating System :: POSIX",
-    "Programming Language :: Python :: 3",
-    "Programming Language :: Python :: 3 :: Only",
-    "Programming Language :: Python :: 3.8",
-    "Programming Language :: Python :: 3.9",
-    "Programming Language :: Python :: 3.10",
-    "Programming Language :: Python :: 3.11",
-    "Programming Language :: Python :: 3.12",
-    "Programming Language :: Python :: 3.13",
-    "Topic :: Software Development :: Libraries",
-    "Topic :: Utilities",
-]
-[project.urls]
-Homepage = "https://github.com/pytest-dev/iniconfig";
-
-
-[tool.hatch.version]
-source = "vcs"
-
-[tool.hatch.build.hooks.vcs]
-version-file = "src/iniconfig/_version.py"
-
-[tool.hatch.build.targets.sdist]
-include = [
-    "/src",
-]
-
-[tool.hatch.envs.test]
-dependencies = [
-  "pytest"
+urls.Homepage = "https://github.com/pytest-dev/iniconfig";
+
+[dependency-groups]
+dev = [
+  "pytest>=8.4.2",
+  "pytest-xdist>=3.8",
 ]
-[tool.hatch.envs.test.scripts]
-default = "pytest {args}"
 
-[[tool.hatch.envs.test.matrix]]
-python = ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13"]
+[tool.setuptools]
+packages = [ "iniconfig" ]
+package-dir = { "" = "src" }
+
+[tool.setuptools.package-data]
+iniconfig = [ "py.typed" ]
 
 [tool.setuptools_scm]
+write_to = "src/iniconfig/_version.py"
 
-[tool.mypy]
-strict = true
+[tool.ruff]
 
+lint.extend-select = [
+  "B",  # flake8-bugbear
+  "I",  # isort
+  "PT", # flake8-pytest-style
+  "UP", # pyupgrade
+]
+lint.isort.force-single-line = true
+lint.isort.known-first-party = [ "iniconfig" ]
 
 [tool.pytest.ini_options]
 testpaths = "testing"
+
+[tool.mypy]
+strict = true
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iniconfig-2.1.0/src/iniconfig/__init__.py 
new/iniconfig-2.3.0/src/iniconfig/__init__.py
--- old/iniconfig-2.1.0/src/iniconfig/__init__.py       2025-03-19 
18:28:27.000000000 +0100
+++ new/iniconfig-2.3.0/src/iniconfig/__init__.py       2025-10-18 
23:51:36.000000000 +0200
@@ -1,42 +1,31 @@
-""" brain-dead simple parser for ini-style files.
+"""brain-dead simple parser for ini-style files.
 (C) Ronny Pfannschmidt, Holger Krekel -- MIT licensed
 """
-from __future__ import annotations
-from typing import (
-    Callable,
-    Iterator,
-    Mapping,
-    Optional,
-    Tuple,
-    TypeVar,
-    Union,
-    TYPE_CHECKING,
-    NoReturn,
-    NamedTuple,
-    overload,
-    cast,
-)
 
 import os
-
-if TYPE_CHECKING:
-    from typing import Final
+from collections.abc import Callable
+from collections.abc import Iterator
+from collections.abc import Mapping
+from typing import Final
+from typing import TypeVar
+from typing import overload
 
 __all__ = ["IniConfig", "ParseError", "COMMENTCHARS", "iscommentline"]
 
-from .exceptions import ParseError
 from . import _parse
-from ._parse import COMMENTCHARS, iscommentline
+from ._parse import COMMENTCHARS
+from ._parse import iscommentline
+from .exceptions import ParseError
 
 _D = TypeVar("_D")
 _T = TypeVar("_T")
 
 
 class SectionWrapper:
-    config: Final[IniConfig]
+    config: Final["IniConfig"]
     name: Final[str]
 
-    def __init__(self, config: IniConfig, name: str) -> None:
+    def __init__(self, config: "IniConfig", name: str) -> None:
         self.config = config
         self.name = name
 
@@ -44,16 +33,14 @@
         return self.config.lineof(self.name, name)
 
     @overload
-    def get(self, key: str) -> str | None:
-        ...
+    def get(self, key: str) -> str | None: ...
 
     @overload
     def get(
         self,
         key: str,
         convert: Callable[[str], _T],
-    ) -> _T | None:
-        ...
+    ) -> _T | None: ...
 
     @overload
     def get(
@@ -61,12 +48,10 @@
         key: str,
         default: None,
         convert: Callable[[str], _T],
-    ) -> _T | None:
-        ...
+    ) -> _T | None: ...
 
     @overload
-    def get(self, key: str, default: _D, convert: None = None) -> str | _D:
-        ...
+    def get(self, key: str, default: _D, convert: None = None) -> str | _D: ...
 
     @overload
     def get(
@@ -74,8 +59,7 @@
         key: str,
         default: _D,
         convert: Callable[[str], _T],
-    ) -> _T | _D:
-        ...
+    ) -> _T | _D: ...
 
     # TODO: investigate possible mypy bug wrt matching the passed over data
     def get(  # type: ignore [misc]
@@ -105,39 +89,93 @@
 class IniConfig:
     path: Final[str]
     sections: Final[Mapping[str, Mapping[str, str]]]
+    _sources: Final[Mapping[tuple[str, str | None], int]]
 
     def __init__(
         self,
         path: str | os.PathLike[str],
         data: str | None = None,
         encoding: str = "utf-8",
+        *,
+        _sections: Mapping[str, Mapping[str, str]] | None = None,
+        _sources: Mapping[tuple[str, str | None], int] | None = None,
     ) -> None:
         self.path = os.fspath(path)
+
+        # Determine sections and sources
+        if _sections is not None and _sources is not None:
+            # Use provided pre-parsed data (called from parse())
+            sections_data = _sections
+            sources = _sources
+        else:
+            # Parse the data (backward compatible path)
+            if data is None:
+                with open(self.path, encoding=encoding) as fp:
+                    data = fp.read()
+
+            # Use old behavior (no stripping) for backward compatibility
+            sections_data, sources = _parse.parse_ini_data(
+                self.path, data, strip_inline_comments=False
+            )
+
+        # Assign once to Final attributes
+        self._sources = sources
+        self.sections = sections_data
+
+    @classmethod
+    def parse(
+        cls,
+        path: str | os.PathLike[str],
+        data: str | None = None,
+        encoding: str = "utf-8",
+        *,
+        strip_inline_comments: bool = True,
+        strip_section_whitespace: bool = False,
+    ) -> "IniConfig":
+        """Parse an INI file.
+
+        Args:
+            path: Path to the INI file (used for error messages)
+            data: Optional INI content as string. If None, reads from path.
+            encoding: Encoding to use when reading the file (default: utf-8)
+            strip_inline_comments: Whether to strip inline comments from values
+                (default: True). When True, comments starting with # or ; are
+                removed from values, matching the behavior for section 
comments.
+            strip_section_whitespace: Whether to strip whitespace from section 
and key names
+                (default: False). When True, strips Unicode whitespace from 
section and key names,
+                addressing issue #4. When False, preserves existing behavior 
for backward compatibility.
+
+        Returns:
+            IniConfig instance with parsed configuration
+
+        Example:
+            # With comment stripping (default):
+            config = IniConfig.parse("setup.cfg")
+            # value = "foo" instead of "foo # comment"
+
+            # Without comment stripping (old behavior):
+            config = IniConfig.parse("setup.cfg", strip_inline_comments=False)
+            # value = "foo # comment"
+
+            # With section name stripping (opt-in for issue #4):
+            config = IniConfig.parse("setup.cfg", 
strip_section_whitespace=True)
+            # section names and keys have Unicode whitespace stripped
+        """
+        fspath = os.fspath(path)
+
         if data is None:
-            with open(self.path, encoding=encoding) as fp:
+            with open(fspath, encoding=encoding) as fp:
                 data = fp.read()
 
-        tokens = _parse.parse_lines(self.path, data.splitlines(True))
+        sections_data, sources = _parse.parse_ini_data(
+            fspath,
+            data,
+            strip_inline_comments=strip_inline_comments,
+            strip_section_whitespace=strip_section_whitespace,
+        )
 
-        self._sources = {}
-        sections_data: dict[str, dict[str, str]]
-        self.sections = sections_data = {}
-
-        for lineno, section, name, value in tokens:
-            if section is None:
-                raise ParseError(self.path, lineno, "no section header 
defined")
-            self._sources[section, name] = lineno
-            if name is None:
-                if section in self.sections:
-                    raise ParseError(
-                        self.path, lineno, f"duplicate section {section!r}"
-                    )
-                sections_data[section] = {}
-            else:
-                if name in self.sections[section]:
-                    raise ParseError(self.path, lineno, f"duplicate name 
{name!r}")
-                assert value is not None
-                sections_data[section][name] = value
+        # Call constructor with pre-parsed sections and sources
+        return cls(path=fspath, _sections=sections_data, _sources=sources)
 
     def lineof(self, section: str, name: str | None = None) -> int | None:
         lineno = self._sources.get((section, name))
@@ -148,8 +186,7 @@
         self,
         section: str,
         name: str,
-    ) -> str | None:
-        ...
+    ) -> str | None: ...
 
     @overload
     def get(
@@ -157,8 +194,7 @@
         section: str,
         name: str,
         convert: Callable[[str], _T],
-    ) -> _T | None:
-        ...
+    ) -> _T | None: ...
 
     @overload
     def get(
@@ -167,14 +203,12 @@
         name: str,
         default: None,
         convert: Callable[[str], _T],
-    ) -> _T | None:
-        ...
+    ) -> _T | None: ...
 
     @overload
     def get(
         self, section: str, name: str, default: _D, convert: None = None
-    ) -> str | _D:
-        ...
+    ) -> str | _D: ...
 
     @overload
     def get(
@@ -183,8 +217,7 @@
         name: str,
         default: _D,
         convert: Callable[[str], _T],
-    ) -> _T | _D:
-        ...
+    ) -> _T | _D: ...
 
     def get(  # type: ignore
         self,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iniconfig-2.1.0/src/iniconfig/_parse.py 
new/iniconfig-2.3.0/src/iniconfig/_parse.py
--- old/iniconfig-2.1.0/src/iniconfig/_parse.py 2025-03-19 18:28:27.000000000 
+0100
+++ new/iniconfig-2.3.0/src/iniconfig/_parse.py 2025-10-18 23:51:36.000000000 
+0200
@@ -1,33 +1,88 @@
-from __future__ import annotations
-from .exceptions import ParseError
-
+from collections.abc import Mapping
 from typing import NamedTuple
 
+from .exceptions import ParseError
 
 COMMENTCHARS = "#;"
 
 
-class _ParsedLine(NamedTuple):
+class ParsedLine(NamedTuple):
     lineno: int
     section: str | None
     name: str | None
     value: str | None
 
 
-def parse_lines(path: str, line_iter: list[str]) -> list[_ParsedLine]:
-    result: list[_ParsedLine] = []
+def parse_ini_data(
+    path: str,
+    data: str,
+    *,
+    strip_inline_comments: bool,
+    strip_section_whitespace: bool = False,
+) -> tuple[Mapping[str, Mapping[str, str]], Mapping[tuple[str, str | None], 
int]]:
+    """Parse INI data and return sections and sources mappings.
+
+    Args:
+        path: Path for error messages
+        data: INI content as string
+        strip_inline_comments: Whether to strip inline comments from values
+        strip_section_whitespace: Whether to strip whitespace from section and 
key names
+            (default: False). When True, addresses issue #4 by stripping 
Unicode whitespace.
+
+    Returns:
+        Tuple of (sections_data, sources) where:
+        - sections_data: mapping of section -> {name -> value}
+        - sources: mapping of (section, name) -> line number
+    """
+    tokens = parse_lines(
+        path,
+        data.splitlines(True),
+        strip_inline_comments=strip_inline_comments,
+        strip_section_whitespace=strip_section_whitespace,
+    )
+
+    sources: dict[tuple[str, str | None], int] = {}
+    sections_data: dict[str, dict[str, str]] = {}
+
+    for lineno, section, name, value in tokens:
+        if section is None:
+            raise ParseError(path, lineno, "no section header defined")
+        sources[section, name] = lineno
+        if name is None:
+            if section in sections_data:
+                raise ParseError(path, lineno, f"duplicate section 
{section!r}")
+            sections_data[section] = {}
+        else:
+            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
+
+    return sections_data, sources
+
+
+def parse_lines(
+    path: str,
+    line_iter: list[str],
+    *,
+    strip_inline_comments: bool = False,
+    strip_section_whitespace: bool = False,
+) -> list[ParsedLine]:
+    result: list[ParsedLine] = []
     section = None
     for lineno, line in enumerate(line_iter):
-        name, data = _parseline(path, line, lineno)
+        name, data = _parseline(
+            path, line, lineno, strip_inline_comments, strip_section_whitespace
+        )
         # 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))
         # new section
         elif name is not None and data is None:
             if not name:
                 raise ParseError(path, lineno, "empty section name")
             section = name
-            result.append(_ParsedLine(lineno, section, None, None))
+            result.append(ParsedLine(lineno, section, None, None))
         # continuation
         elif name is None and data is not None:
             if not result:
@@ -44,7 +99,13 @@
     return result
 
 
-def _parseline(path: str, line: str, lineno: int) -> tuple[str | None, str | 
None]:
+def _parseline(
+    path: str,
+    line: str,
+    lineno: int,
+    strip_inline_comments: bool,
+    strip_section_whitespace: bool,
+) -> tuple[str | None, str | None]:
     # blank lines
     if iscommentline(line):
         line = ""
@@ -58,7 +119,11 @@
         for c in COMMENTCHARS:
             line = line.split(c)[0].rstrip()
         if line[-1] == "]":
-            return line[1:-1], None
+            section_name = line[1:-1]
+            # Optionally strip whitespace from section name (issue #4)
+            if strip_section_whitespace:
+                section_name = section_name.strip()
+            return section_name, None
         return None, realline.strip()
     # value
     elif not line[0].isspace():
@@ -70,11 +135,27 @@
             try:
                 name, value = line.split(":", 1)
             except ValueError:
-                raise ParseError(path, lineno, "unexpected line: %r" % line)
-        return name.strip(), value.strip()
+                raise ParseError(path, lineno, f"unexpected line: {line!r}") 
from None
+
+        # Strip key name (always for backward compatibility, optionally with 
unicode awareness)
+        key_name = name.strip()
+
+        # Strip value
+        value = value.strip()
+        # Strip inline comments from values if requested (issue #55)
+        if strip_inline_comments:
+            for c in COMMENTCHARS:
+                value = value.split(c)[0].rstrip()
+
+        return key_name, value
     # continuation
     else:
-        return None, line.strip()
+        line = line.strip()
+        # Strip inline comments from continuations if requested (issue #55)
+        if strip_inline_comments:
+            for c in COMMENTCHARS:
+                line = line.split(c)[0].rstrip()
+        return None, line
 
 
 def iscommentline(line: str) -> bool:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iniconfig-2.1.0/src/iniconfig/exceptions.py 
new/iniconfig-2.3.0/src/iniconfig/exceptions.py
--- old/iniconfig-2.1.0/src/iniconfig/exceptions.py     2025-03-19 
18:28:27.000000000 +0100
+++ new/iniconfig-2.3.0/src/iniconfig/exceptions.py     2025-10-18 
23:51:36.000000000 +0200
@@ -1,8 +1,4 @@
-from __future__ import annotations
-from typing import TYPE_CHECKING
-
-if TYPE_CHECKING:
-    from typing import Final
+from typing import Final
 
 
 class ParseError(Exception):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iniconfig-2.1.0/testing/test_iniconfig.py 
new/iniconfig-2.3.0/testing/test_iniconfig.py
--- old/iniconfig-2.1.0/testing/test_iniconfig.py       2025-03-19 
18:28:27.000000000 +0100
+++ new/iniconfig-2.3.0/testing/test_iniconfig.py       2025-10-18 
23:51:36.000000000 +0200
@@ -1,11 +1,13 @@
-from __future__ import annotations
-import pytest
-from iniconfig import IniConfig, ParseError, __all__ as ALL
-from iniconfig._parse import _ParsedLine as PL
-from iniconfig import iscommentline
-from textwrap import dedent
 from pathlib import Path
+from textwrap import dedent
+
+import pytest
 
+from iniconfig import IniConfig
+from iniconfig import ParseError
+from iniconfig import __all__ as ALL
+from iniconfig import iscommentline
+from iniconfig._parse import ParsedLine as PL
 
 check_tokens: dict[str, tuple[str, list[PL]]] = {
     "section": ("[section]", [PL(0, "section", None, None)]),
@@ -44,7 +46,6 @@
 
 @pytest.fixture(params=sorted(check_tokens))
 def input_expected(request: pytest.FixtureRequest) -> tuple[str, list[PL]]:
-
     return check_tokens[request.param]
 
 
@@ -124,7 +125,7 @@
     config = IniConfig(str(path), "[diff]")
     assert list(config.sections) == ["diff"]
     with pytest.raises(TypeError):
-        IniConfig(data=path.read_text())  # type: ignore
+        IniConfig(data=path.read_text())  # type: ignore[call-arg]
 
 
 def test_iniconfig_section_first() -> None:
@@ -214,12 +215,12 @@
     """
         ),
     )
-    l = list(config)
-    assert len(l) == 2
-    assert l[0].name == "section1"
-    assert l[0]["value"] == "1"
-    assert l[1].name == "section2"
-    assert l[1]["value"] == "2"
+    sections = list(config)
+    assert len(sections) == 2
+    assert sections[0].name == "section1"
+    assert sections[0]["value"] == "1"
+    assert sections[1].name == "section2"
+    assert sections[1]["value"] == "2"
 
 
 def test_config_contains() -> None:
@@ -251,8 +252,8 @@
 b = 2
 """,
     )
-    l = list(config)
-    secnames = [x.name for x in l]
+    sections_list = list(config)
+    secnames = [x.name for x in sections_list]
     assert secnames == ["section2", "section"]
     assert list(config["section2"]) == ["value", "value2"]
     assert list(config["section"]) == ["a", "b"]
@@ -303,3 +304,111 @@
 )
 def test_iscommentline_true(line: str) -> None:
     assert iscommentline(line)
+
+
+def test_parse_strips_inline_comments() -> None:
+    """Test that IniConfig.parse() strips inline comments from values by 
default."""
+    config = IniConfig.parse(
+        "test.ini",
+        data=dedent(
+            """
+            [section1]
+            name1 = value1 # this is a comment
+            name2 = value2 ; this is also a comment
+            name3 = value3# no space before comment
+            list = a, b, c # some items
+            """
+        ),
+    )
+    assert config["section1"]["name1"] == "value1"
+    assert config["section1"]["name2"] == "value2"
+    assert config["section1"]["name3"] == "value3"
+    assert config["section1"]["list"] == "a, b, c"
+
+
+def test_parse_strips_inline_comments_from_continuations() -> None:
+    """Test that inline comments are stripped from continuation lines."""
+    config = IniConfig.parse(
+        "test.ini",
+        data=dedent(
+            """
+            [section]
+            names =
+                Alice # first person
+                Bob ; second person
+                Charlie
+            """
+        ),
+    )
+    assert config["section"]["names"] == "Alice\nBob\nCharlie"
+
+
+def test_parse_preserves_inline_comments_when_disabled() -> None:
+    """Test that IniConfig.parse(strip_inline_comments=False) preserves 
comments."""
+    config = IniConfig.parse(
+        "test.ini",
+        data=dedent(
+            """
+            [section1]
+            name1 = value1 # this is a comment
+            name2 = value2 ; this is also a comment
+            list = a, b, c # some items
+            """
+        ),
+        strip_inline_comments=False,
+    )
+    assert config["section1"]["name1"] == "value1 # this is a comment"
+    assert config["section1"]["name2"] == "value2 ; this is also a comment"
+    assert config["section1"]["list"] == "a, b, c # some items"
+
+
+def test_constructor_preserves_inline_comments_for_backward_compatibility() -> 
None:
+    """Test that IniConfig() constructor preserves old behavior (no 
stripping)."""
+    config = IniConfig(
+        "test.ini",
+        data=dedent(
+            """
+            [section1]
+            name1 = value1 # this is a comment
+            name2 = value2 ; this is also a comment
+            """
+        ),
+    )
+    assert config["section1"]["name1"] == "value1 # this is a comment"
+    assert config["section1"]["name2"] == "value2 ; this is also a comment"
+
+
+def test_unicode_whitespace_stripped() -> None:
+    """Test that Unicode whitespace is stripped (issue #4)."""
+    config = IniConfig(
+        "test.ini",
+        data="[section]\n"
+        + "name1 = \u00a0value1\u00a0\n"  # NO-BREAK SPACE
+        + "name2 = \u2000value2\u2000\n"  # EN QUAD
+        + "name3 = \u3000value3\u3000\n",  # IDEOGRAPHIC SPACE
+    )
+    assert config["section"]["name1"] == "value1"
+    assert config["section"]["name2"] == "value2"
+    assert config["section"]["name3"] == "value3"
+
+
+def test_unicode_whitespace_in_section_names_with_opt_in() -> None:
+    """Test that Unicode whitespace can be stripped from section names with 
opt-in (issue #4)."""
+    config = IniConfig.parse(
+        "test.ini",
+        data="[section\u00a0]\n"  # NO-BREAK SPACE at end
+        + "key = value\n",
+        strip_section_whitespace=True,
+    )
+    assert "section" in config
+    assert config["section"]["key"] == "value"
+
+
+def test_unicode_whitespace_in_key_names() -> None:
+    """Test that Unicode whitespace is stripped from key names (issue #4)."""
+    config = IniConfig(
+        "test.ini",
+        data="[section]\n" + "key\u00a0 = value\n",  # NO-BREAK SPACE after key
+    )
+    assert "key" in config["section"]
+    assert config["section"]["key"] == "value"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iniconfig-2.1.0/uv.lock new/iniconfig-2.3.0/uv.lock
--- old/iniconfig-2.1.0/uv.lock 1970-01-01 01:00:00.000000000 +0100
+++ new/iniconfig-2.3.0/uv.lock 2025-10-18 23:51:36.000000000 +0200
@@ -0,0 +1,167 @@
+version = 1
+revision = 3
+requires-python = ">=3.10"
+
+[[package]]
+name = "colorama"
+version = "0.4.6"
+source = { registry = "https://pypi.org/simple"; }
+sdist = { url = 
"https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz";,
 hash = 
"sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size 
= 27697, upload-time = "2022-10-25T02:36:22.414Z" }
+wheels = [
+    { url = 
"https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl";,
 hash = 
"sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size 
= 25335, upload-time = "2022-10-25T02:36:20.889Z" },
+]
+
+[[package]]
+name = "exceptiongroup"
+version = "1.3.0"
+source = { registry = "https://pypi.org/simple"; }
+dependencies = [
+    { name = "typing-extensions", marker = "python_full_version < '3.13'" },
+]
+sdist = { url = 
"https://files.pythonhosted.org/packages/0b/9f/a65090624ecf468cdca03533906e7c69ed7588582240cfe7cc9e770b50eb/exceptiongroup-1.3.0.tar.gz";,
 hash = 
"sha256:b241f5885f560bc56a59ee63ca4c6a8bfa46ae4ad651af316d4e81817bb9fd88", size 
= 29749, upload-time = "2025-05-10T17:42:51.123Z" }
+wheels = [
+    { url = 
"https://files.pythonhosted.org/packages/36/f4/c6e662dade71f56cd2f3735141b265c3c79293c109549c1e6933b0651ffc/exceptiongroup-1.3.0-py3-none-any.whl";,
 hash = 
"sha256:4d111e6e0c13d0644cad6ddaa7ed0261a0b36971f6d23e7ec9b4b9097da78a10", size 
= 16674, upload-time = "2025-05-10T17:42:49.33Z" },
+]
+
+[[package]]
+name = "execnet"
+version = "2.1.1"
+source = { registry = "https://pypi.org/simple"; }
+sdist = { url = 
"https://files.pythonhosted.org/packages/bb/ff/b4c0dc78fbe20c3e59c0c7334de0c27eb4001a2b2017999af398bf730817/execnet-2.1.1.tar.gz";,
 hash = 
"sha256:5189b52c6121c24feae288166ab41b32549c7e2348652736540b9e6e7d4e72e3", size 
= 166524, upload-time = "2024-04-08T09:04:19.245Z" }
+wheels = [
+    { url = 
"https://files.pythonhosted.org/packages/43/09/2aea36ff60d16dd8879bdb2f5b3ee0ba8d08cbbdcdfe870e695ce3784385/execnet-2.1.1-py3-none-any.whl";,
 hash = 
"sha256:26dee51f1b80cebd6d0ca8e74dd8745419761d3bef34163928cbebbdc4749fdc", size 
= 40612, upload-time = "2024-04-08T09:04:17.414Z" },
+]
+
+[[package]]
+name = "iniconfig"
+source = { editable = "." }
+
+[package.dev-dependencies]
+dev = [
+    { name = "pytest" },
+    { name = "pytest-xdist" },
+]
+
+[package.metadata]
+
+[package.metadata.requires-dev]
+dev = [
+    { name = "pytest", specifier = ">=8.4.2" },
+    { name = "pytest-xdist", specifier = ">=3.8.0" },
+]
+
+[[package]]
+name = "packaging"
+version = "25.0"
+source = { registry = "https://pypi.org/simple"; }
+sdist = { url = 
"https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz";,
 hash = 
"sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size 
= 165727, upload-time = "2025-04-19T11:48:59.673Z" }
+wheels = [
+    { url = 
"https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl";,
 hash = 
"sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size 
= 66469, upload-time = "2025-04-19T11:48:57.875Z" },
+]
+
+[[package]]
+name = "pluggy"
+version = "1.6.0"
+source = { registry = "https://pypi.org/simple"; }
+sdist = { url = 
"https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz";,
 hash = 
"sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size 
= 69412, upload-time = "2025-05-15T12:30:07.975Z" }
+wheels = [
+    { url = 
"https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl";,
 hash = 
"sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size 
= 20538, upload-time = "2025-05-15T12:30:06.134Z" },
+]
+
+[[package]]
+name = "pygments"
+version = "2.19.2"
+source = { registry = "https://pypi.org/simple"; }
+sdist = { url = 
"https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz";,
 hash = 
"sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size 
= 4968631, upload-time = "2025-06-21T13:39:12.283Z" }
+wheels = [
+    { url = 
"https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl";,
 hash = 
"sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size 
= 1225217, upload-time = "2025-06-21T13:39:07.939Z" },
+]
+
+[[package]]
+name = "pytest"
+version = "8.4.2"
+source = { registry = "https://pypi.org/simple"; }
+dependencies = [
+    { name = "colorama", marker = "sys_platform == 'win32'" },
+    { name = "exceptiongroup", marker = "python_full_version < '3.11'" },
+    { name = "iniconfig" },
+    { name = "packaging" },
+    { name = "pluggy" },
+    { name = "pygments" },
+    { name = "tomli", marker = "python_full_version < '3.11'" },
+]
+sdist = { url = 
"https://files.pythonhosted.org/packages/a3/5c/00a0e072241553e1a7496d638deababa67c5058571567b92a7eaa258397c/pytest-8.4.2.tar.gz";,
 hash = 
"sha256:86c0d0b93306b961d58d62a4db4879f27fe25513d4b969df351abdddb3c30e01", size 
= 1519618, upload-time = "2025-09-04T14:34:22.711Z" }
+wheels = [
+    { url = 
"https://files.pythonhosted.org/packages/a8/a4/20da314d277121d6534b3a980b29035dcd51e6744bd79075a6ce8fa4eb8d/pytest-8.4.2-py3-none-any.whl";,
 hash = 
"sha256:872f880de3fc3a5bdc88a11b39c9710c3497a547cfa9320bc3c5e62fbf272e79", size 
= 365750, upload-time = "2025-09-04T14:34:20.226Z" },
+]
+
+[[package]]
+name = "pytest-xdist"
+version = "3.8.0"
+source = { registry = "https://pypi.org/simple"; }
+dependencies = [
+    { name = "execnet" },
+    { name = "pytest" },
+]
+sdist = { url = 
"https://files.pythonhosted.org/packages/78/b4/439b179d1ff526791eb921115fca8e44e596a13efeda518b9d845a619450/pytest_xdist-3.8.0.tar.gz";,
 hash = 
"sha256:7e578125ec9bc6050861aa93f2d59f1d8d085595d6551c2c90b6f4fad8d3a9f1", size 
= 88069, upload-time = "2025-07-01T13:30:59.346Z" }
+wheels = [
+    { url = 
"https://files.pythonhosted.org/packages/ca/31/d4e37e9e550c2b92a9cbc2e4d0b7420a27224968580b5a447f420847c975/pytest_xdist-3.8.0-py3-none-any.whl";,
 hash = 
"sha256:202ca578cfeb7370784a8c33d6d05bc6e13b4f25b5053c30a152269fd10f0b88", size 
= 46396, upload-time = "2025-07-01T13:30:56.632Z" },
+]
+
+[[package]]
+name = "tomli"
+version = "2.3.0"
+source = { registry = "https://pypi.org/simple"; }
+sdist = { url = 
"https://files.pythonhosted.org/packages/52/ed/3f73f72945444548f33eba9a87fc7a6e969915e7b1acc8260b30e1f76a2f/tomli-2.3.0.tar.gz";,
 hash = 
"sha256:64be704a875d2a59753d80ee8a533c3fe183e3f06807ff7dc2232938ccb01549", size 
= 17392, upload-time = "2025-10-08T22:01:47.119Z" }
+wheels = [
+    { url = 
"https://files.pythonhosted.org/packages/b3/2e/299f62b401438d5fe1624119c723f5d877acc86a4c2492da405626665f12/tomli-2.3.0-cp311-cp311-macosx_10_9_x86_64.whl";,
 hash = 
"sha256:88bd15eb972f3664f5ed4b57c1634a97153b4bac4479dcb6a495f41921eb7f45", size 
= 153236, upload-time = "2025-10-08T22:01:00.137Z" },
+    { url = 
"https://files.pythonhosted.org/packages/86/7f/d8fffe6a7aefdb61bced88fcb5e280cfd71e08939da5894161bd71bea022/tomli-2.3.0-cp311-cp311-macosx_11_0_arm64.whl";,
 hash = 
"sha256:883b1c0d6398a6a9d29b508c331fa56adbcdff647f6ace4dfca0f50e90dfd0ba", size 
= 148084, upload-time = "2025-10-08T22:01:01.63Z" },
+    { url = 
"https://files.pythonhosted.org/packages/47/5c/24935fb6a2ee63e86d80e4d3b58b222dafaf438c416752c8b58537c8b89a/tomli-2.3.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl";,
 hash = 
"sha256:d1381caf13ab9f300e30dd8feadb3de072aeb86f1d34a8569453ff32a7dea4bf", size 
= 234832, upload-time = "2025-10-08T22:01:02.543Z" },
+    { url = 
"https://files.pythonhosted.org/packages/89/da/75dfd804fc11e6612846758a23f13271b76d577e299592b4371a4ca4cd09/tomli-2.3.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl";,
 hash = 
"sha256:a0e285d2649b78c0d9027570d4da3425bdb49830a6156121360b3f8511ea3441", size 
= 242052, upload-time = "2025-10-08T22:01:03.836Z" },
+    { url = 
"https://files.pythonhosted.org/packages/70/8c/f48ac899f7b3ca7eb13af73bacbc93aec37f9c954df3c08ad96991c8c373/tomli-2.3.0-cp311-cp311-musllinux_1_2_aarch64.whl";,
 hash = 
"sha256:0a154a9ae14bfcf5d8917a59b51ffd5a3ac1fd149b71b47a3a104ca4edcfa845", size 
= 239555, upload-time = "2025-10-08T22:01:04.834Z" },
+    { url = 
"https://files.pythonhosted.org/packages/ba/28/72f8afd73f1d0e7829bfc093f4cb98ce0a40ffc0cc997009ee1ed94ba705/tomli-2.3.0-cp311-cp311-musllinux_1_2_x86_64.whl";,
 hash = 
"sha256:74bf8464ff93e413514fefd2be591c3b0b23231a77f901db1eb30d6f712fc42c", size 
= 245128, upload-time = "2025-10-08T22:01:05.84Z" },
+    { url = 
"https://files.pythonhosted.org/packages/b6/eb/a7679c8ac85208706d27436e8d421dfa39d4c914dcf5fa8083a9305f58d9/tomli-2.3.0-cp311-cp311-win32.whl";,
 hash = 
"sha256:00b5f5d95bbfc7d12f91ad8c593a1659b6387b43f054104cda404be6bda62456", size 
= 96445, upload-time = "2025-10-08T22:01:06.896Z" },
+    { url = 
"https://files.pythonhosted.org/packages/0a/fe/3d3420c4cb1ad9cb462fb52967080575f15898da97e21cb6f1361d505383/tomli-2.3.0-cp311-cp311-win_amd64.whl";,
 hash = 
"sha256:4dc4ce8483a5d429ab602f111a93a6ab1ed425eae3122032db7e9acf449451be", size 
= 107165, upload-time = "2025-10-08T22:01:08.107Z" },
+    { url = 
"https://files.pythonhosted.org/packages/ff/b7/40f36368fcabc518bb11c8f06379a0fd631985046c038aca08c6d6a43c6e/tomli-2.3.0-cp312-cp312-macosx_10_13_x86_64.whl";,
 hash = 
"sha256:d7d86942e56ded512a594786a5ba0a5e521d02529b3826e7761a05138341a2ac", size 
= 154891, upload-time = "2025-10-08T22:01:09.082Z" },
+    { url = 
"https://files.pythonhosted.org/packages/f9/3f/d9dd692199e3b3aab2e4e4dd948abd0f790d9ded8cd10cbaae276a898434/tomli-2.3.0-cp312-cp312-macosx_11_0_arm64.whl";,
 hash = 
"sha256:73ee0b47d4dad1c5e996e3cd33b8a76a50167ae5f96a2607cbe8cc773506ab22", size 
= 148796, upload-time = "2025-10-08T22:01:10.266Z" },
+    { url = 
"https://files.pythonhosted.org/packages/60/83/59bff4996c2cf9f9387a0f5a3394629c7efa5ef16142076a23a90f1955fa/tomli-2.3.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl";,
 hash = 
"sha256:792262b94d5d0a466afb5bc63c7daa9d75520110971ee269152083270998316f", size 
= 242121, upload-time = "2025-10-08T22:01:11.332Z" },
+    { url = 
"https://files.pythonhosted.org/packages/45/e5/7c5119ff39de8693d6baab6c0b6dcb556d192c165596e9fc231ea1052041/tomli-2.3.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl";,
 hash = 
"sha256:4f195fe57ecceac95a66a75ac24d9d5fbc98ef0962e09b2eddec5d39375aae52", size 
= 250070, upload-time = "2025-10-08T22:01:12.498Z" },
+    { url = 
"https://files.pythonhosted.org/packages/45/12/ad5126d3a278f27e6701abde51d342aa78d06e27ce2bb596a01f7709a5a2/tomli-2.3.0-cp312-cp312-musllinux_1_2_aarch64.whl";,
 hash = 
"sha256:e31d432427dcbf4d86958c184b9bfd1e96b5b71f8eb17e6d02531f434fd335b8", size 
= 245859, upload-time = "2025-10-08T22:01:13.551Z" },
+    { url = 
"https://files.pythonhosted.org/packages/fb/a1/4d6865da6a71c603cfe6ad0e6556c73c76548557a8d658f9e3b142df245f/tomli-2.3.0-cp312-cp312-musllinux_1_2_x86_64.whl";,
 hash = 
"sha256:7b0882799624980785240ab732537fcfc372601015c00f7fc367c55308c186f6", size 
= 250296, upload-time = "2025-10-08T22:01:14.614Z" },
+    { url = 
"https://files.pythonhosted.org/packages/a0/b7/a7a7042715d55c9ba6e8b196d65d2cb662578b4d8cd17d882d45322b0d78/tomli-2.3.0-cp312-cp312-win32.whl";,
 hash = 
"sha256:ff72b71b5d10d22ecb084d345fc26f42b5143c5533db5e2eaba7d2d335358876", size 
= 97124, upload-time = "2025-10-08T22:01:15.629Z" },
+    { url = 
"https://files.pythonhosted.org/packages/06/1e/f22f100db15a68b520664eb3328fb0ae4e90530887928558112c8d1f4515/tomli-2.3.0-cp312-cp312-win_amd64.whl";,
 hash = 
"sha256:1cb4ed918939151a03f33d4242ccd0aa5f11b3547d0cf30f7c74a408a5b99878", size 
= 107698, upload-time = "2025-10-08T22:01:16.51Z" },
+    { url = 
"https://files.pythonhosted.org/packages/89/48/06ee6eabe4fdd9ecd48bf488f4ac783844fd777f547b8d1b61c11939974e/tomli-2.3.0-cp313-cp313-macosx_10_13_x86_64.whl";,
 hash = 
"sha256:5192f562738228945d7b13d4930baffda67b69425a7f0da96d360b0a3888136b", size 
= 154819, upload-time = "2025-10-08T22:01:17.964Z" },
+    { url = 
"https://files.pythonhosted.org/packages/f1/01/88793757d54d8937015c75dcdfb673c65471945f6be98e6a0410fba167ed/tomli-2.3.0-cp313-cp313-macosx_11_0_arm64.whl";,
 hash = 
"sha256:be71c93a63d738597996be9528f4abe628d1adf5e6eb11607bc8fe1a510b5dae", size 
= 148766, upload-time = "2025-10-08T22:01:18.959Z" },
+    { url = 
"https://files.pythonhosted.org/packages/42/17/5e2c956f0144b812e7e107f94f1cc54af734eb17b5191c0bbfb72de5e93e/tomli-2.3.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl";,
 hash = 
"sha256:c4665508bcbac83a31ff8ab08f424b665200c0e1e645d2bd9ab3d3e557b6185b", size 
= 240771, upload-time = "2025-10-08T22:01:20.106Z" },
+    { url = 
"https://files.pythonhosted.org/packages/d5/f4/0fbd014909748706c01d16824eadb0307115f9562a15cbb012cd9b3512c5/tomli-2.3.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl";,
 hash = 
"sha256:4021923f97266babc6ccab9f5068642a0095faa0a51a246a6a02fccbb3514eaf", size 
= 248586, upload-time = "2025-10-08T22:01:21.164Z" },
+    { url = 
"https://files.pythonhosted.org/packages/30/77/fed85e114bde5e81ecf9bc5da0cc69f2914b38f4708c80ae67d0c10180c5/tomli-2.3.0-cp313-cp313-musllinux_1_2_aarch64.whl";,
 hash = 
"sha256:a4ea38c40145a357d513bffad0ed869f13c1773716cf71ccaa83b0fa0cc4e42f", size 
= 244792, upload-time = "2025-10-08T22:01:22.417Z" },
+    { url = 
"https://files.pythonhosted.org/packages/55/92/afed3d497f7c186dc71e6ee6d4fcb0acfa5f7d0a1a2878f8beae379ae0cc/tomli-2.3.0-cp313-cp313-musllinux_1_2_x86_64.whl";,
 hash = 
"sha256:ad805ea85eda330dbad64c7ea7a4556259665bdf9d2672f5dccc740eb9d3ca05", size 
= 248909, upload-time = "2025-10-08T22:01:23.859Z" },
+    { url = 
"https://files.pythonhosted.org/packages/f8/84/ef50c51b5a9472e7265ce1ffc7f24cd4023d289e109f669bdb1553f6a7c2/tomli-2.3.0-cp313-cp313-win32.whl";,
 hash = 
"sha256:97d5eec30149fd3294270e889b4234023f2c69747e555a27bd708828353ab606", size 
= 96946, upload-time = "2025-10-08T22:01:24.893Z" },
+    { url = 
"https://files.pythonhosted.org/packages/b2/b7/718cd1da0884f281f95ccfa3a6cc572d30053cba64603f79d431d3c9b61b/tomli-2.3.0-cp313-cp313-win_amd64.whl";,
 hash = 
"sha256:0c95ca56fbe89e065c6ead5b593ee64b84a26fca063b5d71a1122bf26e533999", size 
= 107705, upload-time = "2025-10-08T22:01:26.153Z" },
+    { url = 
"https://files.pythonhosted.org/packages/19/94/aeafa14a52e16163008060506fcb6aa1949d13548d13752171a755c65611/tomli-2.3.0-cp314-cp314-macosx_10_13_x86_64.whl";,
 hash = 
"sha256:cebc6fe843e0733ee827a282aca4999b596241195f43b4cc371d64fc6639da9e", size 
= 154244, upload-time = "2025-10-08T22:01:27.06Z" },
+    { url = 
"https://files.pythonhosted.org/packages/db/e4/1e58409aa78eefa47ccd19779fc6f36787edbe7d4cd330eeeedb33a4515b/tomli-2.3.0-cp314-cp314-macosx_11_0_arm64.whl";,
 hash = 
"sha256:4c2ef0244c75aba9355561272009d934953817c49f47d768070c3c94355c2aa3", size 
= 148637, upload-time = "2025-10-08T22:01:28.059Z" },
+    { url = 
"https://files.pythonhosted.org/packages/26/b6/d1eccb62f665e44359226811064596dd6a366ea1f985839c566cd61525ae/tomli-2.3.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl";,
 hash = 
"sha256:c22a8bf253bacc0cf11f35ad9808b6cb75ada2631c2d97c971122583b129afbc", size 
= 241925, upload-time = "2025-10-08T22:01:29.066Z" },
+    { url = 
"https://files.pythonhosted.org/packages/70/91/7cdab9a03e6d3d2bb11beae108da5bdc1c34bdeb06e21163482544ddcc90/tomli-2.3.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl";,
 hash = 
"sha256:0eea8cc5c5e9f89c9b90c4896a8deefc74f518db5927d0e0e8d4a80953d774d0", size 
= 249045, upload-time = "2025-10-08T22:01:31.98Z" },
+    { url = 
"https://files.pythonhosted.org/packages/15/1b/8c26874ed1f6e4f1fcfeb868db8a794cbe9f227299402db58cfcc858766c/tomli-2.3.0-cp314-cp314-musllinux_1_2_aarch64.whl";,
 hash = 
"sha256:b74a0e59ec5d15127acdabd75ea17726ac4c5178ae51b85bfe39c4f8a278e879", size 
= 245835, upload-time = "2025-10-08T22:01:32.989Z" },
+    { url = 
"https://files.pythonhosted.org/packages/fd/42/8e3c6a9a4b1a1360c1a2a39f0b972cef2cc9ebd56025168c4137192a9321/tomli-2.3.0-cp314-cp314-musllinux_1_2_x86_64.whl";,
 hash = 
"sha256:b5870b50c9db823c595983571d1296a6ff3e1b88f734a4c8f6fc6188397de005", size 
= 253109, upload-time = "2025-10-08T22:01:34.052Z" },
+    { url = 
"https://files.pythonhosted.org/packages/22/0c/b4da635000a71b5f80130937eeac12e686eefb376b8dee113b4a582bba42/tomli-2.3.0-cp314-cp314-win32.whl";,
 hash = 
"sha256:feb0dacc61170ed7ab602d3d972a58f14ee3ee60494292d384649a3dc38ef463", size 
= 97930, upload-time = "2025-10-08T22:01:35.082Z" },
+    { url = 
"https://files.pythonhosted.org/packages/b9/74/cb1abc870a418ae99cd5c9547d6bce30701a954e0e721821df483ef7223c/tomli-2.3.0-cp314-cp314-win_amd64.whl";,
 hash = 
"sha256:b273fcbd7fc64dc3600c098e39136522650c49bca95df2d11cf3b626422392c8", size 
= 107964, upload-time = "2025-10-08T22:01:36.057Z" },
+    { url = 
"https://files.pythonhosted.org/packages/54/78/5c46fff6432a712af9f792944f4fcd7067d8823157949f4e40c56b8b3c83/tomli-2.3.0-cp314-cp314t-macosx_10_13_x86_64.whl";,
 hash = 
"sha256:940d56ee0410fa17ee1f12b817b37a4d4e4dc4d27340863cc67236c74f582e77", size 
= 163065, upload-time = "2025-10-08T22:01:37.27Z" },
+    { url = 
"https://files.pythonhosted.org/packages/39/67/f85d9bd23182f45eca8939cd2bc7050e1f90c41f4a2ecbbd5963a1d1c486/tomli-2.3.0-cp314-cp314t-macosx_11_0_arm64.whl";,
 hash = 
"sha256:f85209946d1fe94416debbb88d00eb92ce9cd5266775424ff81bc959e001acaf", size 
= 159088, upload-time = "2025-10-08T22:01:38.235Z" },
+    { url = 
"https://files.pythonhosted.org/packages/26/5a/4b546a0405b9cc0659b399f12b6adb750757baf04250b148d3c5059fc4eb/tomli-2.3.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl";,
 hash = 
"sha256:a56212bdcce682e56b0aaf79e869ba5d15a6163f88d5451cbde388d48b13f530", size 
= 268193, upload-time = "2025-10-08T22:01:39.712Z" },
+    { url = 
"https://files.pythonhosted.org/packages/42/4f/2c12a72ae22cf7b59a7fe75b3465b7aba40ea9145d026ba41cb382075b0e/tomli-2.3.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl";,
 hash = 
"sha256:c5f3ffd1e098dfc032d4d3af5c0ac64f6d286d98bc148698356847b80fa4de1b", size 
= 275488, upload-time = "2025-10-08T22:01:40.773Z" },
+    { url = 
"https://files.pythonhosted.org/packages/92/04/a038d65dbe160c3aa5a624e93ad98111090f6804027d474ba9c37c8ae186/tomli-2.3.0-cp314-cp314t-musllinux_1_2_aarch64.whl";,
 hash = 
"sha256:5e01decd096b1530d97d5d85cb4dff4af2d8347bd35686654a004f8dea20fc67", size 
= 272669, upload-time = "2025-10-08T22:01:41.824Z" },
+    { url = 
"https://files.pythonhosted.org/packages/be/2f/8b7c60a9d1612a7cbc39ffcca4f21a73bf368a80fc25bccf8253e2563267/tomli-2.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl";,
 hash = 
"sha256:8a35dd0e643bb2610f156cca8db95d213a90015c11fee76c946aa62b7ae7e02f", size 
= 279709, upload-time = "2025-10-08T22:01:43.177Z" },
+    { url = 
"https://files.pythonhosted.org/packages/7e/46/cc36c679f09f27ded940281c38607716c86cf8ba4a518d524e349c8b4874/tomli-2.3.0-cp314-cp314t-win32.whl";,
 hash = 
"sha256:a1f7f282fe248311650081faafa5f4732bdbfef5d45fe3f2e702fbc6f2d496e0", size 
= 107563, upload-time = "2025-10-08T22:01:44.233Z" },
+    { url = 
"https://files.pythonhosted.org/packages/84/ff/426ca8683cf7b753614480484f6437f568fd2fda2edbdf57a2d3d8b27a0b/tomli-2.3.0-cp314-cp314t-win_amd64.whl";,
 hash = 
"sha256:70a251f8d4ba2d9ac2542eecf008b3c8a9fc5c3f9f02c56a9d7952612be2fdba", size 
= 119756, upload-time = "2025-10-08T22:01:45.234Z" },
+    { url = 
"https://files.pythonhosted.org/packages/77/b8/0135fadc89e73be292b473cb820b4f5a08197779206b33191e801feeae40/tomli-2.3.0-py3-none-any.whl";,
 hash = 
"sha256:e95b1af3c5b07d9e643909b5abbec77cd9f1217e6d0bca72b0234736b9fb1f1b", size 
= 14408, upload-time = "2025-10-08T22:01:46.04Z" },
+]
+
+[[package]]
+name = "typing-extensions"
+version = "4.15.0"
+source = { registry = "https://pypi.org/simple"; }
+sdist = { url = 
"https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz";,
 hash = 
"sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size 
= 109391, upload-time = "2025-08-25T13:49:26.313Z" }
+wheels = [
+    { url = 
"https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl";,
 hash = 
"sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size 
= 44614, upload-time = "2025-08-25T13:49:24.86Z" },
+]

++++++ iniconfig-2.1.0-tests.tar.gz -> iniconfig-2.3.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iniconfig-2.1.0/.github/workflows/deploy.yml 
new/iniconfig-2.3.0/.github/workflows/deploy.yml
--- old/iniconfig-2.1.0/.github/workflows/deploy.yml    2025-03-19 
18:28:27.000000000 +0100
+++ new/iniconfig-2.3.0/.github/workflows/deploy.yml    1970-01-01 
01:00:00.000000000 +0100
@@ -1,63 +0,0 @@
-name: Deploy
-
-on:
-  push:
-    branches:
-      - master
-      - "*deploy*"
-  release:
-    types:
-      - published
-
-jobs:
-  build:
-    if: github.repository == 'pytest-dev/iniconfig'
-    runs-on: ubuntu-latest
-
-    steps:
-      - uses: actions/checkout@v4
-        with:
-          fetch-depth: 0
-      - name: Cache
-        uses: actions/cache@v4
-        with:
-          path: ~/.cache/pip
-          key: deploy-${{ hashFiles('**/pyproject.toml') }}
-          restore-keys: |
-            deploy-
-
-      - name: Set up Python
-        uses: actions/setup-python@v5
-        with:
-          python-version: "3.x"
-
-      - name: Install build + twine
-        run: python -m pip install build twine setuptools_scm
-
-      - name: git describe output
-        run: git describe --tags
-
-      - id: scm_version
-        run: |
-          VERSION=$(python -m setuptools_scm --strip-dev)
-          echo SETUPTOOLS_SCM_PRETEND_VERSION=$VERSION >> $GITHUB_ENV
-
-      - name: Build package
-        run: python -m build
-      
-      - name: twine check
-        run: twine check dist/*
-
-      - name: Publish package to PyPI
-        if: github.event.action == 'published'
-        uses: pypa/gh-action-pypi-publish@release/v1
-        with:
-          user: __token__
-          password: ${{ secrets.pypi_password }}
-
-      - name: Publish package to TestPyPI
-        uses: pypa/gh-action-pypi-publish@release/v1
-        with:
-          user: __token__
-          password: ${{ secrets.test_pypi_password }}
-          repository_url: https://test.pypi.org/legacy/
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iniconfig-2.1.0/.github/workflows/main.yml 
new/iniconfig-2.3.0/.github/workflows/main.yml
--- old/iniconfig-2.1.0/.github/workflows/main.yml      2025-03-19 
18:28:27.000000000 +0100
+++ new/iniconfig-2.3.0/.github/workflows/main.yml      1970-01-01 
01:00:00.000000000 +0100
@@ -1,35 +0,0 @@
-name: build
-
-on: [push, pull_request, workflow_dispatch]
-
-jobs:
-  build:
-
-    runs-on: ${{ matrix.os }}
-
-    strategy:
-      fail-fast: false
-      matrix:
-        python: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13"]
-        os: [ubuntu-latest, windows-latest]
-
-    steps:
-    - uses: actions/checkout@v4
-    - name: Set up Python
-      uses: actions/setup-python@v5
-      with:
-        python-version: ${{ matrix.python }}
-        allow-prereleases: true
-    - name: Install hatch
-      run: python -m pip install --upgrade pip hatch hatch-vcs
-    - name: Run tests
-      run: hatch run +py=${{ matrix.python }} test:default --color=yes
-
-  pre-commit:
-    runs-on: ubuntu-latest
-    steps:
-    - uses: actions/checkout@v4
-    - uses: actions/setup-python@v5
-      with:
-        python-version: 3.x
-    - uses: pre-commit/[email protected]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iniconfig-2.1.0/.github/workflows/test.yml 
new/iniconfig-2.3.0/.github/workflows/test.yml
--- old/iniconfig-2.1.0/.github/workflows/test.yml      1970-01-01 
01:00:00.000000000 +0100
+++ new/iniconfig-2.3.0/.github/workflows/test.yml      2025-10-18 
23:53:59.000000000 +0200
@@ -0,0 +1,144 @@
+name: test
+
+on: [push, pull_request, workflow_dispatch]
+
+jobs:
+  build-and-inspect:
+    runs-on: ubuntu-latest
+    permissions:
+      id-token: write
+      attestations: write
+      contents: read
+    outputs:
+      python-versions: ${{ 
steps.baipp.outputs.supported_python_classifiers_json_array }}
+
+    steps:
+      - uses: actions/checkout@v4
+        with:
+          fetch-depth: 0
+
+      - name: Build and inspect package
+        id: baipp
+        uses: hynek/build-and-inspect-python-package@v2
+        with:
+          attest-build-provenance-github: ${{ github.event_name != 
'pull_request' || github.event.pull_request.head.repo.full_name == 
github.repository }}
+        env:
+          SETUPTOOLS_SCM_OVERRIDES_FOR_INICONFIG: ${{ github.ref == 
'refs/heads/main' && 'local_scheme="no-local-version"' || '' }}
+
+  test:
+    needs: build-and-inspect
+    runs-on: ${{ matrix.os }}
+    defaults:
+      run:
+        shell: bash
+
+    strategy:
+      fail-fast: false
+      matrix:
+        python: ${{ fromJSON(needs.build-and-inspect.outputs.python-versions) 
}}
+        os: [ubuntu-latest, windows-latest]
+
+    steps:
+      - name: Checkout test files
+        uses: actions/checkout@v4
+        with:
+          sparse-checkout: |
+            testing
+            uv.lock
+          sparse-checkout-cone-mode: false
+
+      - name: Download built packages
+        uses: actions/download-artifact@v4
+        with:
+          name: Packages
+          path: dist
+
+      - name: Verify artifacts exist
+        run: |
+          ls -la dist/
+          test -f dist/*.whl || (echo "No wheel found!" && exit 1)
+          test -f dist/*.tar.gz || (echo "No sdist found!" && exit 1)
+
+      - name: Install uv
+        uses: astral-sh/setup-uv@v7
+        with:
+          enable-cache: true
+
+      - name: Set up Python ${{ matrix.python }}
+        run: uv python install ${{ matrix.python }}
+
+      - name: Run tests with built wheel
+        run: uv run --with dist/*.whl --with pytest pytest testing --color=yes
+
+  create-release:
+    name: Create GitHub Release
+    if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')
+    needs: [test, build-and-inspect]
+    runs-on: ubuntu-latest
+    permissions:
+      contents: write
+
+    steps:
+      - name: Download built packages
+        uses: actions/download-artifact@v4
+        with:
+          name: Packages
+          path: dist
+
+      - name: Extract version from tag
+        id: version
+        run: echo "VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_OUTPUT
+
+      - name: Create GitHub Release
+        uses: softprops/action-gh-release@v2
+        with:
+          files: dist/*
+          fail_on_unmatched_files: true
+          generate_release_notes: true
+          name: Version ${{ steps.version.outputs.VERSION }}
+
+  publish-to-pypi:
+    name: Publish to PyPI
+    if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')
+    needs: [test, build-and-inspect, create-release]
+    runs-on: ubuntu-latest
+    environment: pypi-upload
+    permissions:
+      id-token: write
+
+    steps:
+      - name: Download built packages
+        uses: actions/download-artifact@v4
+        with:
+          name: Packages
+          path: dist
+
+      - name: Publish package to PyPI
+        uses: pypa/gh-action-pypi-publish@release/v1
+
+  publish-to-test-pypi:
+    name: Publish to TestPyPI
+    if: |
+      github.repository == 'pytest-dev/iniconfig' &&
+      (github.event_name == 'push' && (
+        github.ref == 'refs/heads/main' ||
+        contains(github.ref, 'deploy')
+      ))
+    needs: [test, build-and-inspect]
+    runs-on: ubuntu-latest
+    environment: test-pypi-upload
+    permissions:
+      id-token: write
+      attestations: write
+
+    steps:
+      - name: Download built packages
+        uses: actions/download-artifact@v4
+        with:
+          name: Packages
+          path: dist
+
+      - name: Publish package to TestPyPI
+        uses: pypa/gh-action-pypi-publish@release/v1
+        with:
+          repository-url: https://test.pypi.org/legacy/
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iniconfig-2.1.0/.pre-commit-config.yaml 
new/iniconfig-2.3.0/.pre-commit-config.yaml
--- old/iniconfig-2.1.0/.pre-commit-config.yaml 2025-03-19 18:28:27.000000000 
+0100
+++ new/iniconfig-2.3.0/.pre-commit-config.yaml 2025-10-18 23:53:59.000000000 
+0200
@@ -1,24 +1,21 @@
 repos:
--   repo: https://github.com/asottile/pyupgrade
-    rev: v3.3.1
-    hooks:
-    -   id: pyupgrade
-        args: [--py38-plus]
 - repo: https://github.com/tox-dev/pyproject-fmt
-  rev: "0.4.1"
+  rev: "v2.11.0"
   hooks:
     - id: pyproject-fmt
 
-- repo: https://github.com/psf/black
-  rev: 22.12.0
+- repo: https://github.com/astral-sh/ruff-pre-commit
+  rev: v0.14.1
   hooks:
-      - id: black
-        language_version: python3
--   repo: https://github.com/pre-commit/mirrors-mypy
-    rev: 'v0.991' 
-    hooks:
-    -   id: mypy
-        args: []
-        additional_dependencies:
-          - "pytest==7.2.0"
-          - "tomli"
\ No newline at end of file
+    - id: ruff-check
+      args: [--fix]
+    - id: ruff-format
+
+- repo: https://github.com/pre-commit/mirrors-mypy
+  rev: 'v1.18.2'
+  hooks:
+    - id: mypy
+      args: []
+      additional_dependencies:
+        - "pytest==7.2.0"
+        - "tomli"
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iniconfig-2.1.0/CHANGELOG 
new/iniconfig-2.3.0/CHANGELOG
--- old/iniconfig-2.1.0/CHANGELOG       2025-03-19 18:28:27.000000000 +0100
+++ new/iniconfig-2.3.0/CHANGELOG       2025-10-18 23:53:59.000000000 +0200
@@ -1,3 +1,35 @@
+2.3.0
+=====
+
+* add IniConfig.parse() classmethod with strip_inline_comments parameter 
(fixes #55)
+  - by default (strip_inline_comments=True), inline comments are properly 
stripped from values
+  - set strip_inline_comments=False to preserve old behavior if needed
+* IniConfig() constructor maintains backward compatibility (does not strip 
inline comments)
+* users should migrate to IniConfig.parse() for correct comment handling
+* add strip_section_whitespace parameter to IniConfig.parse() (regarding #4)
+  - opt-in parameter to strip Unicode whitespace from section names
+  - when True, strips Unicode whitespace (U+00A0, U+2000, U+3000, etc.) from 
section names
+  - when False (default), preserves existing behavior for backward 
compatibility
+* clarify Unicode whitespace handling (regarding #4)
+  - since iniconfig 2.0.0 (Python 3 only), all strings are Unicode by default
+  - Python 3's str.strip() has handled Unicode whitespace since Python 3.0 
(2008)
+  - iniconfig automatically benefits from this in all supported versions 
(Python >= 3.10)
+  - key names and values have Unicode whitespace properly stripped using 
Python's built-in methods
+
+2.2.0
+=====
+
+* drop Python 3.8 and 3.9 support (now requires Python >= 3.10)
+* add Python 3.14 classifier
+* migrate from hatchling to setuptools 77 with setuptools_scm
+* adopt PEP 639 license specifiers and PEP 740 build attestations
+* migrate from black + pyupgrade to ruff
+* migrate CI to uv and unified test workflow
+* automate GitHub releases and PyPI publishing via Trusted Publishing
+* include tests in sdist
+* modernize code for Python 3.10+ (remove __future__ annotations, 
TYPE_CHECKING guards)
+* rename _ParsedLine to ParsedLine
+
 2.1.0
 =====
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iniconfig-2.1.0/PKG-INFO new/iniconfig-2.3.0/PKG-INFO
--- old/iniconfig-2.1.0/PKG-INFO        1970-01-01 01:00:00.000000000 +0100
+++ new/iniconfig-2.3.0/PKG-INFO        2025-10-18 23:54:02.445129200 +0200
@@ -0,0 +1,79 @@
+Metadata-Version: 2.4
+Name: iniconfig
+Version: 2.3.0
+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: 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/RonnyPfannschmidt/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
+
+then you can do:
+
+.. code-block:: pycon
+
+    >>> import iniconfig
+    >>> ini = iniconfig.IniConfig("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
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iniconfig-2.1.0/pyproject.toml 
new/iniconfig-2.3.0/pyproject.toml
--- old/iniconfig-2.1.0/pyproject.toml  2025-03-19 18:28:27.000000000 +0100
+++ new/iniconfig-2.3.0/pyproject.toml  2025-10-18 23:53:59.000000000 +0200
@@ -1,8 +1,8 @@
 [build-system]
-build-backend = "hatchling.build"
+build-backend = "setuptools.build_meta"
 requires = [
-  "hatch-vcs",
-  "hatchling>=1.26",
+  "setuptools>=77",
+  "setuptools-scm>=8",
 ]
 
 [project]
@@ -10,62 +10,61 @@
 description = "brain-dead simple config-ini parsing"
 readme = "README.rst"
 license = "MIT"
+license-files = [ "LICENSE" ]
 authors = [
-    { name = "Ronny Pfannschmidt", email = "[email protected]" },
-    { name = "Holger Krekel", email = "[email protected]" },
+  { name = "Ronny Pfannschmidt", email = "[email protected]" },
+  { name = "Holger Krekel", email = "[email protected]" },
+]
+requires-python = ">=3.10"
+classifiers = [
+  "Development Status :: 4 - Beta",
+  "Intended Audience :: Developers",
+  "Operating System :: MacOS :: MacOS X",
+  "Operating System :: Microsoft :: Windows",
+  "Operating System :: POSIX",
+  "Programming Language :: Python :: 3 :: Only",
+  "Programming Language :: Python :: 3.10",
+  "Programming Language :: Python :: 3.11",
+  "Programming Language :: Python :: 3.12",
+  "Programming Language :: Python :: 3.13",
+  "Programming Language :: Python :: 3.14",
+  "Topic :: Software Development :: Libraries",
+  "Topic :: Utilities",
 ]
-requires-python = ">=3.8"
 dynamic = [
   "version",
 ]
-classifiers = [
-    "Development Status :: 4 - Beta",
-    "Intended Audience :: Developers",
-    "License :: OSI Approved :: MIT License",
-    "Operating System :: MacOS :: MacOS X",
-    "Operating System :: Microsoft :: Windows",
-    "Operating System :: POSIX",
-    "Programming Language :: Python :: 3",
-    "Programming Language :: Python :: 3 :: Only",
-    "Programming Language :: Python :: 3.8",
-    "Programming Language :: Python :: 3.9",
-    "Programming Language :: Python :: 3.10",
-    "Programming Language :: Python :: 3.11",
-    "Programming Language :: Python :: 3.12",
-    "Programming Language :: Python :: 3.13",
-    "Topic :: Software Development :: Libraries",
-    "Topic :: Utilities",
-]
-[project.urls]
-Homepage = "https://github.com/pytest-dev/iniconfig";
-
-
-[tool.hatch.version]
-source = "vcs"
-
-[tool.hatch.build.hooks.vcs]
-version-file = "src/iniconfig/_version.py"
-
-[tool.hatch.build.targets.sdist]
-include = [
-    "/src",
-]
-
-[tool.hatch.envs.test]
-dependencies = [
-  "pytest"
+urls.Homepage = "https://github.com/pytest-dev/iniconfig";
+
+[dependency-groups]
+dev = [
+  "pytest>=8.4.2",
+  "pytest-xdist>=3.8",
 ]
-[tool.hatch.envs.test.scripts]
-default = "pytest {args}"
 
-[[tool.hatch.envs.test.matrix]]
-python = ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13"]
+[tool.setuptools]
+packages = [ "iniconfig" ]
+package-dir = { "" = "src" }
+
+[tool.setuptools.package-data]
+iniconfig = [ "py.typed" ]
 
 [tool.setuptools_scm]
+write_to = "src/iniconfig/_version.py"
 
-[tool.mypy]
-strict = true
+[tool.ruff]
 
+lint.extend-select = [
+  "B",  # flake8-bugbear
+  "I",  # isort
+  "PT", # flake8-pytest-style
+  "UP", # pyupgrade
+]
+lint.isort.force-single-line = true
+lint.isort.known-first-party = [ "iniconfig" ]
 
 [tool.pytest.ini_options]
 testpaths = "testing"
+
+[tool.mypy]
+strict = true
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iniconfig-2.1.0/setup.cfg 
new/iniconfig-2.3.0/setup.cfg
--- old/iniconfig-2.1.0/setup.cfg       1970-01-01 01:00:00.000000000 +0100
+++ new/iniconfig-2.3.0/setup.cfg       2025-10-18 23:54:02.445381000 +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.1.0/src/iniconfig/__init__.py 
new/iniconfig-2.3.0/src/iniconfig/__init__.py
--- old/iniconfig-2.1.0/src/iniconfig/__init__.py       2025-03-19 
18:28:27.000000000 +0100
+++ new/iniconfig-2.3.0/src/iniconfig/__init__.py       2025-10-18 
23:53:59.000000000 +0200
@@ -1,42 +1,31 @@
-""" brain-dead simple parser for ini-style files.
+"""brain-dead simple parser for ini-style files.
 (C) Ronny Pfannschmidt, Holger Krekel -- MIT licensed
 """
-from __future__ import annotations
-from typing import (
-    Callable,
-    Iterator,
-    Mapping,
-    Optional,
-    Tuple,
-    TypeVar,
-    Union,
-    TYPE_CHECKING,
-    NoReturn,
-    NamedTuple,
-    overload,
-    cast,
-)
 
 import os
-
-if TYPE_CHECKING:
-    from typing import Final
+from collections.abc import Callable
+from collections.abc import Iterator
+from collections.abc import Mapping
+from typing import Final
+from typing import TypeVar
+from typing import overload
 
 __all__ = ["IniConfig", "ParseError", "COMMENTCHARS", "iscommentline"]
 
-from .exceptions import ParseError
 from . import _parse
-from ._parse import COMMENTCHARS, iscommentline
+from ._parse import COMMENTCHARS
+from ._parse import iscommentline
+from .exceptions import ParseError
 
 _D = TypeVar("_D")
 _T = TypeVar("_T")
 
 
 class SectionWrapper:
-    config: Final[IniConfig]
+    config: Final["IniConfig"]
     name: Final[str]
 
-    def __init__(self, config: IniConfig, name: str) -> None:
+    def __init__(self, config: "IniConfig", name: str) -> None:
         self.config = config
         self.name = name
 
@@ -44,16 +33,14 @@
         return self.config.lineof(self.name, name)
 
     @overload
-    def get(self, key: str) -> str | None:
-        ...
+    def get(self, key: str) -> str | None: ...
 
     @overload
     def get(
         self,
         key: str,
         convert: Callable[[str], _T],
-    ) -> _T | None:
-        ...
+    ) -> _T | None: ...
 
     @overload
     def get(
@@ -61,12 +48,10 @@
         key: str,
         default: None,
         convert: Callable[[str], _T],
-    ) -> _T | None:
-        ...
+    ) -> _T | None: ...
 
     @overload
-    def get(self, key: str, default: _D, convert: None = None) -> str | _D:
-        ...
+    def get(self, key: str, default: _D, convert: None = None) -> str | _D: ...
 
     @overload
     def get(
@@ -74,8 +59,7 @@
         key: str,
         default: _D,
         convert: Callable[[str], _T],
-    ) -> _T | _D:
-        ...
+    ) -> _T | _D: ...
 
     # TODO: investigate possible mypy bug wrt matching the passed over data
     def get(  # type: ignore [misc]
@@ -105,39 +89,93 @@
 class IniConfig:
     path: Final[str]
     sections: Final[Mapping[str, Mapping[str, str]]]
+    _sources: Final[Mapping[tuple[str, str | None], int]]
 
     def __init__(
         self,
         path: str | os.PathLike[str],
         data: str | None = None,
         encoding: str = "utf-8",
+        *,
+        _sections: Mapping[str, Mapping[str, str]] | None = None,
+        _sources: Mapping[tuple[str, str | None], int] | None = None,
     ) -> None:
         self.path = os.fspath(path)
+
+        # Determine sections and sources
+        if _sections is not None and _sources is not None:
+            # Use provided pre-parsed data (called from parse())
+            sections_data = _sections
+            sources = _sources
+        else:
+            # Parse the data (backward compatible path)
+            if data is None:
+                with open(self.path, encoding=encoding) as fp:
+                    data = fp.read()
+
+            # Use old behavior (no stripping) for backward compatibility
+            sections_data, sources = _parse.parse_ini_data(
+                self.path, data, strip_inline_comments=False
+            )
+
+        # Assign once to Final attributes
+        self._sources = sources
+        self.sections = sections_data
+
+    @classmethod
+    def parse(
+        cls,
+        path: str | os.PathLike[str],
+        data: str | None = None,
+        encoding: str = "utf-8",
+        *,
+        strip_inline_comments: bool = True,
+        strip_section_whitespace: bool = False,
+    ) -> "IniConfig":
+        """Parse an INI file.
+
+        Args:
+            path: Path to the INI file (used for error messages)
+            data: Optional INI content as string. If None, reads from path.
+            encoding: Encoding to use when reading the file (default: utf-8)
+            strip_inline_comments: Whether to strip inline comments from values
+                (default: True). When True, comments starting with # or ; are
+                removed from values, matching the behavior for section 
comments.
+            strip_section_whitespace: Whether to strip whitespace from section 
and key names
+                (default: False). When True, strips Unicode whitespace from 
section and key names,
+                addressing issue #4. When False, preserves existing behavior 
for backward compatibility.
+
+        Returns:
+            IniConfig instance with parsed configuration
+
+        Example:
+            # With comment stripping (default):
+            config = IniConfig.parse("setup.cfg")
+            # value = "foo" instead of "foo # comment"
+
+            # Without comment stripping (old behavior):
+            config = IniConfig.parse("setup.cfg", strip_inline_comments=False)
+            # value = "foo # comment"
+
+            # With section name stripping (opt-in for issue #4):
+            config = IniConfig.parse("setup.cfg", 
strip_section_whitespace=True)
+            # section names and keys have Unicode whitespace stripped
+        """
+        fspath = os.fspath(path)
+
         if data is None:
-            with open(self.path, encoding=encoding) as fp:
+            with open(fspath, encoding=encoding) as fp:
                 data = fp.read()
 
-        tokens = _parse.parse_lines(self.path, data.splitlines(True))
+        sections_data, sources = _parse.parse_ini_data(
+            fspath,
+            data,
+            strip_inline_comments=strip_inline_comments,
+            strip_section_whitespace=strip_section_whitespace,
+        )
 
-        self._sources = {}
-        sections_data: dict[str, dict[str, str]]
-        self.sections = sections_data = {}
-
-        for lineno, section, name, value in tokens:
-            if section is None:
-                raise ParseError(self.path, lineno, "no section header 
defined")
-            self._sources[section, name] = lineno
-            if name is None:
-                if section in self.sections:
-                    raise ParseError(
-                        self.path, lineno, f"duplicate section {section!r}"
-                    )
-                sections_data[section] = {}
-            else:
-                if name in self.sections[section]:
-                    raise ParseError(self.path, lineno, f"duplicate name 
{name!r}")
-                assert value is not None
-                sections_data[section][name] = value
+        # Call constructor with pre-parsed sections and sources
+        return cls(path=fspath, _sections=sections_data, _sources=sources)
 
     def lineof(self, section: str, name: str | None = None) -> int | None:
         lineno = self._sources.get((section, name))
@@ -148,8 +186,7 @@
         self,
         section: str,
         name: str,
-    ) -> str | None:
-        ...
+    ) -> str | None: ...
 
     @overload
     def get(
@@ -157,8 +194,7 @@
         section: str,
         name: str,
         convert: Callable[[str], _T],
-    ) -> _T | None:
-        ...
+    ) -> _T | None: ...
 
     @overload
     def get(
@@ -167,14 +203,12 @@
         name: str,
         default: None,
         convert: Callable[[str], _T],
-    ) -> _T | None:
-        ...
+    ) -> _T | None: ...
 
     @overload
     def get(
         self, section: str, name: str, default: _D, convert: None = None
-    ) -> str | _D:
-        ...
+    ) -> str | _D: ...
 
     @overload
     def get(
@@ -183,8 +217,7 @@
         name: str,
         default: _D,
         convert: Callable[[str], _T],
-    ) -> _T | _D:
-        ...
+    ) -> _T | _D: ...
 
     def get(  # type: ignore
         self,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iniconfig-2.1.0/src/iniconfig/_parse.py 
new/iniconfig-2.3.0/src/iniconfig/_parse.py
--- old/iniconfig-2.1.0/src/iniconfig/_parse.py 2025-03-19 18:28:27.000000000 
+0100
+++ new/iniconfig-2.3.0/src/iniconfig/_parse.py 2025-10-18 23:53:59.000000000 
+0200
@@ -1,33 +1,88 @@
-from __future__ import annotations
-from .exceptions import ParseError
-
+from collections.abc import Mapping
 from typing import NamedTuple
 
+from .exceptions import ParseError
 
 COMMENTCHARS = "#;"
 
 
-class _ParsedLine(NamedTuple):
+class ParsedLine(NamedTuple):
     lineno: int
     section: str | None
     name: str | None
     value: str | None
 
 
-def parse_lines(path: str, line_iter: list[str]) -> list[_ParsedLine]:
-    result: list[_ParsedLine] = []
+def parse_ini_data(
+    path: str,
+    data: str,
+    *,
+    strip_inline_comments: bool,
+    strip_section_whitespace: bool = False,
+) -> tuple[Mapping[str, Mapping[str, str]], Mapping[tuple[str, str | None], 
int]]:
+    """Parse INI data and return sections and sources mappings.
+
+    Args:
+        path: Path for error messages
+        data: INI content as string
+        strip_inline_comments: Whether to strip inline comments from values
+        strip_section_whitespace: Whether to strip whitespace from section and 
key names
+            (default: False). When True, addresses issue #4 by stripping 
Unicode whitespace.
+
+    Returns:
+        Tuple of (sections_data, sources) where:
+        - sections_data: mapping of section -> {name -> value}
+        - sources: mapping of (section, name) -> line number
+    """
+    tokens = parse_lines(
+        path,
+        data.splitlines(True),
+        strip_inline_comments=strip_inline_comments,
+        strip_section_whitespace=strip_section_whitespace,
+    )
+
+    sources: dict[tuple[str, str | None], int] = {}
+    sections_data: dict[str, dict[str, str]] = {}
+
+    for lineno, section, name, value in tokens:
+        if section is None:
+            raise ParseError(path, lineno, "no section header defined")
+        sources[section, name] = lineno
+        if name is None:
+            if section in sections_data:
+                raise ParseError(path, lineno, f"duplicate section 
{section!r}")
+            sections_data[section] = {}
+        else:
+            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
+
+    return sections_data, sources
+
+
+def parse_lines(
+    path: str,
+    line_iter: list[str],
+    *,
+    strip_inline_comments: bool = False,
+    strip_section_whitespace: bool = False,
+) -> list[ParsedLine]:
+    result: list[ParsedLine] = []
     section = None
     for lineno, line in enumerate(line_iter):
-        name, data = _parseline(path, line, lineno)
+        name, data = _parseline(
+            path, line, lineno, strip_inline_comments, strip_section_whitespace
+        )
         # 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))
         # new section
         elif name is not None and data is None:
             if not name:
                 raise ParseError(path, lineno, "empty section name")
             section = name
-            result.append(_ParsedLine(lineno, section, None, None))
+            result.append(ParsedLine(lineno, section, None, None))
         # continuation
         elif name is None and data is not None:
             if not result:
@@ -44,7 +99,13 @@
     return result
 
 
-def _parseline(path: str, line: str, lineno: int) -> tuple[str | None, str | 
None]:
+def _parseline(
+    path: str,
+    line: str,
+    lineno: int,
+    strip_inline_comments: bool,
+    strip_section_whitespace: bool,
+) -> tuple[str | None, str | None]:
     # blank lines
     if iscommentline(line):
         line = ""
@@ -58,7 +119,11 @@
         for c in COMMENTCHARS:
             line = line.split(c)[0].rstrip()
         if line[-1] == "]":
-            return line[1:-1], None
+            section_name = line[1:-1]
+            # Optionally strip whitespace from section name (issue #4)
+            if strip_section_whitespace:
+                section_name = section_name.strip()
+            return section_name, None
         return None, realline.strip()
     # value
     elif not line[0].isspace():
@@ -70,11 +135,27 @@
             try:
                 name, value = line.split(":", 1)
             except ValueError:
-                raise ParseError(path, lineno, "unexpected line: %r" % line)
-        return name.strip(), value.strip()
+                raise ParseError(path, lineno, f"unexpected line: {line!r}") 
from None
+
+        # Strip key name (always for backward compatibility, optionally with 
unicode awareness)
+        key_name = name.strip()
+
+        # Strip value
+        value = value.strip()
+        # Strip inline comments from values if requested (issue #55)
+        if strip_inline_comments:
+            for c in COMMENTCHARS:
+                value = value.split(c)[0].rstrip()
+
+        return key_name, value
     # continuation
     else:
-        return None, line.strip()
+        line = line.strip()
+        # Strip inline comments from continuations if requested (issue #55)
+        if strip_inline_comments:
+            for c in COMMENTCHARS:
+                line = line.split(c)[0].rstrip()
+        return None, line
 
 
 def iscommentline(line: str) -> bool:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iniconfig-2.1.0/src/iniconfig/_version.py 
new/iniconfig-2.3.0/src/iniconfig/_version.py
--- old/iniconfig-2.1.0/src/iniconfig/_version.py       1970-01-01 
01:00:00.000000000 +0100
+++ new/iniconfig-2.3.0/src/iniconfig/_version.py       2025-10-18 
23:54:02.000000000 +0200
@@ -0,0 +1,34 @@
+# file generated by setuptools-scm
+# don't change, don't track in version control
+
+__all__ = [
+    "__version__",
+    "__version_tuple__",
+    "version",
+    "version_tuple",
+    "__commit_id__",
+    "commit_id",
+]
+
+TYPE_CHECKING = False
+if TYPE_CHECKING:
+    from typing import Tuple
+    from typing import Union
+
+    VERSION_TUPLE = Tuple[Union[int, str], ...]
+    COMMIT_ID = Union[str, None]
+else:
+    VERSION_TUPLE = object
+    COMMIT_ID = object
+
+version: str
+__version__: str
+__version_tuple__: VERSION_TUPLE
+version_tuple: VERSION_TUPLE
+commit_id: COMMIT_ID
+__commit_id__: COMMIT_ID
+
+__version__ = version = '2.3.0'
+__version_tuple__ = version_tuple = (2, 3, 0)
+
+__commit_id__ = commit_id = 'g7faed13ae'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iniconfig-2.1.0/src/iniconfig/exceptions.py 
new/iniconfig-2.3.0/src/iniconfig/exceptions.py
--- old/iniconfig-2.1.0/src/iniconfig/exceptions.py     2025-03-19 
18:28:27.000000000 +0100
+++ new/iniconfig-2.3.0/src/iniconfig/exceptions.py     2025-10-18 
23:53:59.000000000 +0200
@@ -1,8 +1,4 @@
-from __future__ import annotations
-from typing import TYPE_CHECKING
-
-if TYPE_CHECKING:
-    from typing import Final
+from typing import Final
 
 
 class ParseError(Exception):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iniconfig-2.1.0/src/iniconfig.egg-info/PKG-INFO 
new/iniconfig-2.3.0/src/iniconfig.egg-info/PKG-INFO
--- old/iniconfig-2.1.0/src/iniconfig.egg-info/PKG-INFO 1970-01-01 
01:00:00.000000000 +0100
+++ new/iniconfig-2.3.0/src/iniconfig.egg-info/PKG-INFO 2025-10-18 
23:54:02.000000000 +0200
@@ -0,0 +1,79 @@
+Metadata-Version: 2.4
+Name: iniconfig
+Version: 2.3.0
+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: 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/RonnyPfannschmidt/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
+
+then you can do:
+
+.. code-block:: pycon
+
+    >>> import iniconfig
+    >>> ini = iniconfig.IniConfig("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
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iniconfig-2.1.0/src/iniconfig.egg-info/SOURCES.txt 
new/iniconfig-2.3.0/src/iniconfig.egg-info/SOURCES.txt
--- old/iniconfig-2.1.0/src/iniconfig.egg-info/SOURCES.txt      1970-01-01 
01:00:00.000000000 +0100
+++ new/iniconfig-2.3.0/src/iniconfig.egg-info/SOURCES.txt      2025-10-18 
23:54:02.000000000 +0200
@@ -0,0 +1,21 @@
+.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/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.1.0/src/iniconfig.egg-info/dependency_links.txt 
new/iniconfig-2.3.0/src/iniconfig.egg-info/dependency_links.txt
--- old/iniconfig-2.1.0/src/iniconfig.egg-info/dependency_links.txt     
1970-01-01 01:00:00.000000000 +0100
+++ new/iniconfig-2.3.0/src/iniconfig.egg-info/dependency_links.txt     
2025-10-18 23:54:02.000000000 +0200
@@ -0,0 +1 @@
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iniconfig-2.1.0/src/iniconfig.egg-info/top_level.txt 
new/iniconfig-2.3.0/src/iniconfig.egg-info/top_level.txt
--- old/iniconfig-2.1.0/src/iniconfig.egg-info/top_level.txt    1970-01-01 
01:00:00.000000000 +0100
+++ new/iniconfig-2.3.0/src/iniconfig.egg-info/top_level.txt    2025-10-18 
23:54:02.000000000 +0200
@@ -0,0 +1 @@
+iniconfig
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iniconfig-2.1.0/testing/test_iniconfig.py 
new/iniconfig-2.3.0/testing/test_iniconfig.py
--- old/iniconfig-2.1.0/testing/test_iniconfig.py       2025-03-19 
18:28:27.000000000 +0100
+++ new/iniconfig-2.3.0/testing/test_iniconfig.py       2025-10-18 
23:53:59.000000000 +0200
@@ -1,11 +1,13 @@
-from __future__ import annotations
-import pytest
-from iniconfig import IniConfig, ParseError, __all__ as ALL
-from iniconfig._parse import _ParsedLine as PL
-from iniconfig import iscommentline
-from textwrap import dedent
 from pathlib import Path
+from textwrap import dedent
+
+import pytest
 
+from iniconfig import IniConfig
+from iniconfig import ParseError
+from iniconfig import __all__ as ALL
+from iniconfig import iscommentline
+from iniconfig._parse import ParsedLine as PL
 
 check_tokens: dict[str, tuple[str, list[PL]]] = {
     "section": ("[section]", [PL(0, "section", None, None)]),
@@ -44,7 +46,6 @@
 
 @pytest.fixture(params=sorted(check_tokens))
 def input_expected(request: pytest.FixtureRequest) -> tuple[str, list[PL]]:
-
     return check_tokens[request.param]
 
 
@@ -124,7 +125,7 @@
     config = IniConfig(str(path), "[diff]")
     assert list(config.sections) == ["diff"]
     with pytest.raises(TypeError):
-        IniConfig(data=path.read_text())  # type: ignore
+        IniConfig(data=path.read_text())  # type: ignore[call-arg]
 
 
 def test_iniconfig_section_first() -> None:
@@ -214,12 +215,12 @@
     """
         ),
     )
-    l = list(config)
-    assert len(l) == 2
-    assert l[0].name == "section1"
-    assert l[0]["value"] == "1"
-    assert l[1].name == "section2"
-    assert l[1]["value"] == "2"
+    sections = list(config)
+    assert len(sections) == 2
+    assert sections[0].name == "section1"
+    assert sections[0]["value"] == "1"
+    assert sections[1].name == "section2"
+    assert sections[1]["value"] == "2"
 
 
 def test_config_contains() -> None:
@@ -251,8 +252,8 @@
 b = 2
 """,
     )
-    l = list(config)
-    secnames = [x.name for x in l]
+    sections_list = list(config)
+    secnames = [x.name for x in sections_list]
     assert secnames == ["section2", "section"]
     assert list(config["section2"]) == ["value", "value2"]
     assert list(config["section"]) == ["a", "b"]
@@ -303,3 +304,111 @@
 )
 def test_iscommentline_true(line: str) -> None:
     assert iscommentline(line)
+
+
+def test_parse_strips_inline_comments() -> None:
+    """Test that IniConfig.parse() strips inline comments from values by 
default."""
+    config = IniConfig.parse(
+        "test.ini",
+        data=dedent(
+            """
+            [section1]
+            name1 = value1 # this is a comment
+            name2 = value2 ; this is also a comment
+            name3 = value3# no space before comment
+            list = a, b, c # some items
+            """
+        ),
+    )
+    assert config["section1"]["name1"] == "value1"
+    assert config["section1"]["name2"] == "value2"
+    assert config["section1"]["name3"] == "value3"
+    assert config["section1"]["list"] == "a, b, c"
+
+
+def test_parse_strips_inline_comments_from_continuations() -> None:
+    """Test that inline comments are stripped from continuation lines."""
+    config = IniConfig.parse(
+        "test.ini",
+        data=dedent(
+            """
+            [section]
+            names =
+                Alice # first person
+                Bob ; second person
+                Charlie
+            """
+        ),
+    )
+    assert config["section"]["names"] == "Alice\nBob\nCharlie"
+
+
+def test_parse_preserves_inline_comments_when_disabled() -> None:
+    """Test that IniConfig.parse(strip_inline_comments=False) preserves 
comments."""
+    config = IniConfig.parse(
+        "test.ini",
+        data=dedent(
+            """
+            [section1]
+            name1 = value1 # this is a comment
+            name2 = value2 ; this is also a comment
+            list = a, b, c # some items
+            """
+        ),
+        strip_inline_comments=False,
+    )
+    assert config["section1"]["name1"] == "value1 # this is a comment"
+    assert config["section1"]["name2"] == "value2 ; this is also a comment"
+    assert config["section1"]["list"] == "a, b, c # some items"
+
+
+def test_constructor_preserves_inline_comments_for_backward_compatibility() -> 
None:
+    """Test that IniConfig() constructor preserves old behavior (no 
stripping)."""
+    config = IniConfig(
+        "test.ini",
+        data=dedent(
+            """
+            [section1]
+            name1 = value1 # this is a comment
+            name2 = value2 ; this is also a comment
+            """
+        ),
+    )
+    assert config["section1"]["name1"] == "value1 # this is a comment"
+    assert config["section1"]["name2"] == "value2 ; this is also a comment"
+
+
+def test_unicode_whitespace_stripped() -> None:
+    """Test that Unicode whitespace is stripped (issue #4)."""
+    config = IniConfig(
+        "test.ini",
+        data="[section]\n"
+        + "name1 = \u00a0value1\u00a0\n"  # NO-BREAK SPACE
+        + "name2 = \u2000value2\u2000\n"  # EN QUAD
+        + "name3 = \u3000value3\u3000\n",  # IDEOGRAPHIC SPACE
+    )
+    assert config["section"]["name1"] == "value1"
+    assert config["section"]["name2"] == "value2"
+    assert config["section"]["name3"] == "value3"
+
+
+def test_unicode_whitespace_in_section_names_with_opt_in() -> None:
+    """Test that Unicode whitespace can be stripped from section names with 
opt-in (issue #4)."""
+    config = IniConfig.parse(
+        "test.ini",
+        data="[section\u00a0]\n"  # NO-BREAK SPACE at end
+        + "key = value\n",
+        strip_section_whitespace=True,
+    )
+    assert "section" in config
+    assert config["section"]["key"] == "value"
+
+
+def test_unicode_whitespace_in_key_names() -> None:
+    """Test that Unicode whitespace is stripped from key names (issue #4)."""
+    config = IniConfig(
+        "test.ini",
+        data="[section]\n" + "key\u00a0 = value\n",  # NO-BREAK SPACE after key
+    )
+    assert "key" in config["section"]
+    assert config["section"]["key"] == "value"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/iniconfig-2.1.0/uv.lock new/iniconfig-2.3.0/uv.lock
--- old/iniconfig-2.1.0/uv.lock 1970-01-01 01:00:00.000000000 +0100
+++ new/iniconfig-2.3.0/uv.lock 2025-10-18 23:53:59.000000000 +0200
@@ -0,0 +1,167 @@
+version = 1
+revision = 3
+requires-python = ">=3.10"
+
+[[package]]
+name = "colorama"
+version = "0.4.6"
+source = { registry = "https://pypi.org/simple"; }
+sdist = { url = 
"https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz";,
 hash = 
"sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size 
= 27697, upload-time = "2022-10-25T02:36:22.414Z" }
+wheels = [
+    { url = 
"https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl";,
 hash = 
"sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size 
= 25335, upload-time = "2022-10-25T02:36:20.889Z" },
+]
+
+[[package]]
+name = "exceptiongroup"
+version = "1.3.0"
+source = { registry = "https://pypi.org/simple"; }
+dependencies = [
+    { name = "typing-extensions", marker = "python_full_version < '3.13'" },
+]
+sdist = { url = 
"https://files.pythonhosted.org/packages/0b/9f/a65090624ecf468cdca03533906e7c69ed7588582240cfe7cc9e770b50eb/exceptiongroup-1.3.0.tar.gz";,
 hash = 
"sha256:b241f5885f560bc56a59ee63ca4c6a8bfa46ae4ad651af316d4e81817bb9fd88", size 
= 29749, upload-time = "2025-05-10T17:42:51.123Z" }
+wheels = [
+    { url = 
"https://files.pythonhosted.org/packages/36/f4/c6e662dade71f56cd2f3735141b265c3c79293c109549c1e6933b0651ffc/exceptiongroup-1.3.0-py3-none-any.whl";,
 hash = 
"sha256:4d111e6e0c13d0644cad6ddaa7ed0261a0b36971f6d23e7ec9b4b9097da78a10", size 
= 16674, upload-time = "2025-05-10T17:42:49.33Z" },
+]
+
+[[package]]
+name = "execnet"
+version = "2.1.1"
+source = { registry = "https://pypi.org/simple"; }
+sdist = { url = 
"https://files.pythonhosted.org/packages/bb/ff/b4c0dc78fbe20c3e59c0c7334de0c27eb4001a2b2017999af398bf730817/execnet-2.1.1.tar.gz";,
 hash = 
"sha256:5189b52c6121c24feae288166ab41b32549c7e2348652736540b9e6e7d4e72e3", size 
= 166524, upload-time = "2024-04-08T09:04:19.245Z" }
+wheels = [
+    { url = 
"https://files.pythonhosted.org/packages/43/09/2aea36ff60d16dd8879bdb2f5b3ee0ba8d08cbbdcdfe870e695ce3784385/execnet-2.1.1-py3-none-any.whl";,
 hash = 
"sha256:26dee51f1b80cebd6d0ca8e74dd8745419761d3bef34163928cbebbdc4749fdc", size 
= 40612, upload-time = "2024-04-08T09:04:17.414Z" },
+]
+
+[[package]]
+name = "iniconfig"
+source = { editable = "." }
+
+[package.dev-dependencies]
+dev = [
+    { name = "pytest" },
+    { name = "pytest-xdist" },
+]
+
+[package.metadata]
+
+[package.metadata.requires-dev]
+dev = [
+    { name = "pytest", specifier = ">=8.4.2" },
+    { name = "pytest-xdist", specifier = ">=3.8.0" },
+]
+
+[[package]]
+name = "packaging"
+version = "25.0"
+source = { registry = "https://pypi.org/simple"; }
+sdist = { url = 
"https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz";,
 hash = 
"sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size 
= 165727, upload-time = "2025-04-19T11:48:59.673Z" }
+wheels = [
+    { url = 
"https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl";,
 hash = 
"sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size 
= 66469, upload-time = "2025-04-19T11:48:57.875Z" },
+]
+
+[[package]]
+name = "pluggy"
+version = "1.6.0"
+source = { registry = "https://pypi.org/simple"; }
+sdist = { url = 
"https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz";,
 hash = 
"sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size 
= 69412, upload-time = "2025-05-15T12:30:07.975Z" }
+wheels = [
+    { url = 
"https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl";,
 hash = 
"sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size 
= 20538, upload-time = "2025-05-15T12:30:06.134Z" },
+]
+
+[[package]]
+name = "pygments"
+version = "2.19.2"
+source = { registry = "https://pypi.org/simple"; }
+sdist = { url = 
"https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz";,
 hash = 
"sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size 
= 4968631, upload-time = "2025-06-21T13:39:12.283Z" }
+wheels = [
+    { url = 
"https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl";,
 hash = 
"sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size 
= 1225217, upload-time = "2025-06-21T13:39:07.939Z" },
+]
+
+[[package]]
+name = "pytest"
+version = "8.4.2"
+source = { registry = "https://pypi.org/simple"; }
+dependencies = [
+    { name = "colorama", marker = "sys_platform == 'win32'" },
+    { name = "exceptiongroup", marker = "python_full_version < '3.11'" },
+    { name = "iniconfig" },
+    { name = "packaging" },
+    { name = "pluggy" },
+    { name = "pygments" },
+    { name = "tomli", marker = "python_full_version < '3.11'" },
+]
+sdist = { url = 
"https://files.pythonhosted.org/packages/a3/5c/00a0e072241553e1a7496d638deababa67c5058571567b92a7eaa258397c/pytest-8.4.2.tar.gz";,
 hash = 
"sha256:86c0d0b93306b961d58d62a4db4879f27fe25513d4b969df351abdddb3c30e01", size 
= 1519618, upload-time = "2025-09-04T14:34:22.711Z" }
+wheels = [
+    { url = 
"https://files.pythonhosted.org/packages/a8/a4/20da314d277121d6534b3a980b29035dcd51e6744bd79075a6ce8fa4eb8d/pytest-8.4.2-py3-none-any.whl";,
 hash = 
"sha256:872f880de3fc3a5bdc88a11b39c9710c3497a547cfa9320bc3c5e62fbf272e79", size 
= 365750, upload-time = "2025-09-04T14:34:20.226Z" },
+]
+
+[[package]]
+name = "pytest-xdist"
+version = "3.8.0"
+source = { registry = "https://pypi.org/simple"; }
+dependencies = [
+    { name = "execnet" },
+    { name = "pytest" },
+]
+sdist = { url = 
"https://files.pythonhosted.org/packages/78/b4/439b179d1ff526791eb921115fca8e44e596a13efeda518b9d845a619450/pytest_xdist-3.8.0.tar.gz";,
 hash = 
"sha256:7e578125ec9bc6050861aa93f2d59f1d8d085595d6551c2c90b6f4fad8d3a9f1", size 
= 88069, upload-time = "2025-07-01T13:30:59.346Z" }
+wheels = [
+    { url = 
"https://files.pythonhosted.org/packages/ca/31/d4e37e9e550c2b92a9cbc2e4d0b7420a27224968580b5a447f420847c975/pytest_xdist-3.8.0-py3-none-any.whl";,
 hash = 
"sha256:202ca578cfeb7370784a8c33d6d05bc6e13b4f25b5053c30a152269fd10f0b88", size 
= 46396, upload-time = "2025-07-01T13:30:56.632Z" },
+]
+
+[[package]]
+name = "tomli"
+version = "2.3.0"
+source = { registry = "https://pypi.org/simple"; }
+sdist = { url = 
"https://files.pythonhosted.org/packages/52/ed/3f73f72945444548f33eba9a87fc7a6e969915e7b1acc8260b30e1f76a2f/tomli-2.3.0.tar.gz";,
 hash = 
"sha256:64be704a875d2a59753d80ee8a533c3fe183e3f06807ff7dc2232938ccb01549", size 
= 17392, upload-time = "2025-10-08T22:01:47.119Z" }
+wheels = [
+    { url = 
"https://files.pythonhosted.org/packages/b3/2e/299f62b401438d5fe1624119c723f5d877acc86a4c2492da405626665f12/tomli-2.3.0-cp311-cp311-macosx_10_9_x86_64.whl";,
 hash = 
"sha256:88bd15eb972f3664f5ed4b57c1634a97153b4bac4479dcb6a495f41921eb7f45", size 
= 153236, upload-time = "2025-10-08T22:01:00.137Z" },
+    { url = 
"https://files.pythonhosted.org/packages/86/7f/d8fffe6a7aefdb61bced88fcb5e280cfd71e08939da5894161bd71bea022/tomli-2.3.0-cp311-cp311-macosx_11_0_arm64.whl";,
 hash = 
"sha256:883b1c0d6398a6a9d29b508c331fa56adbcdff647f6ace4dfca0f50e90dfd0ba", size 
= 148084, upload-time = "2025-10-08T22:01:01.63Z" },
+    { url = 
"https://files.pythonhosted.org/packages/47/5c/24935fb6a2ee63e86d80e4d3b58b222dafaf438c416752c8b58537c8b89a/tomli-2.3.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl";,
 hash = 
"sha256:d1381caf13ab9f300e30dd8feadb3de072aeb86f1d34a8569453ff32a7dea4bf", size 
= 234832, upload-time = "2025-10-08T22:01:02.543Z" },
+    { url = 
"https://files.pythonhosted.org/packages/89/da/75dfd804fc11e6612846758a23f13271b76d577e299592b4371a4ca4cd09/tomli-2.3.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl";,
 hash = 
"sha256:a0e285d2649b78c0d9027570d4da3425bdb49830a6156121360b3f8511ea3441", size 
= 242052, upload-time = "2025-10-08T22:01:03.836Z" },
+    { url = 
"https://files.pythonhosted.org/packages/70/8c/f48ac899f7b3ca7eb13af73bacbc93aec37f9c954df3c08ad96991c8c373/tomli-2.3.0-cp311-cp311-musllinux_1_2_aarch64.whl";,
 hash = 
"sha256:0a154a9ae14bfcf5d8917a59b51ffd5a3ac1fd149b71b47a3a104ca4edcfa845", size 
= 239555, upload-time = "2025-10-08T22:01:04.834Z" },
+    { url = 
"https://files.pythonhosted.org/packages/ba/28/72f8afd73f1d0e7829bfc093f4cb98ce0a40ffc0cc997009ee1ed94ba705/tomli-2.3.0-cp311-cp311-musllinux_1_2_x86_64.whl";,
 hash = 
"sha256:74bf8464ff93e413514fefd2be591c3b0b23231a77f901db1eb30d6f712fc42c", size 
= 245128, upload-time = "2025-10-08T22:01:05.84Z" },
+    { url = 
"https://files.pythonhosted.org/packages/b6/eb/a7679c8ac85208706d27436e8d421dfa39d4c914dcf5fa8083a9305f58d9/tomli-2.3.0-cp311-cp311-win32.whl";,
 hash = 
"sha256:00b5f5d95bbfc7d12f91ad8c593a1659b6387b43f054104cda404be6bda62456", size 
= 96445, upload-time = "2025-10-08T22:01:06.896Z" },
+    { url = 
"https://files.pythonhosted.org/packages/0a/fe/3d3420c4cb1ad9cb462fb52967080575f15898da97e21cb6f1361d505383/tomli-2.3.0-cp311-cp311-win_amd64.whl";,
 hash = 
"sha256:4dc4ce8483a5d429ab602f111a93a6ab1ed425eae3122032db7e9acf449451be", size 
= 107165, upload-time = "2025-10-08T22:01:08.107Z" },
+    { url = 
"https://files.pythonhosted.org/packages/ff/b7/40f36368fcabc518bb11c8f06379a0fd631985046c038aca08c6d6a43c6e/tomli-2.3.0-cp312-cp312-macosx_10_13_x86_64.whl";,
 hash = 
"sha256:d7d86942e56ded512a594786a5ba0a5e521d02529b3826e7761a05138341a2ac", size 
= 154891, upload-time = "2025-10-08T22:01:09.082Z" },
+    { url = 
"https://files.pythonhosted.org/packages/f9/3f/d9dd692199e3b3aab2e4e4dd948abd0f790d9ded8cd10cbaae276a898434/tomli-2.3.0-cp312-cp312-macosx_11_0_arm64.whl";,
 hash = 
"sha256:73ee0b47d4dad1c5e996e3cd33b8a76a50167ae5f96a2607cbe8cc773506ab22", size 
= 148796, upload-time = "2025-10-08T22:01:10.266Z" },
+    { url = 
"https://files.pythonhosted.org/packages/60/83/59bff4996c2cf9f9387a0f5a3394629c7efa5ef16142076a23a90f1955fa/tomli-2.3.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl";,
 hash = 
"sha256:792262b94d5d0a466afb5bc63c7daa9d75520110971ee269152083270998316f", size 
= 242121, upload-time = "2025-10-08T22:01:11.332Z" },
+    { url = 
"https://files.pythonhosted.org/packages/45/e5/7c5119ff39de8693d6baab6c0b6dcb556d192c165596e9fc231ea1052041/tomli-2.3.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl";,
 hash = 
"sha256:4f195fe57ecceac95a66a75ac24d9d5fbc98ef0962e09b2eddec5d39375aae52", size 
= 250070, upload-time = "2025-10-08T22:01:12.498Z" },
+    { url = 
"https://files.pythonhosted.org/packages/45/12/ad5126d3a278f27e6701abde51d342aa78d06e27ce2bb596a01f7709a5a2/tomli-2.3.0-cp312-cp312-musllinux_1_2_aarch64.whl";,
 hash = 
"sha256:e31d432427dcbf4d86958c184b9bfd1e96b5b71f8eb17e6d02531f434fd335b8", size 
= 245859, upload-time = "2025-10-08T22:01:13.551Z" },
+    { url = 
"https://files.pythonhosted.org/packages/fb/a1/4d6865da6a71c603cfe6ad0e6556c73c76548557a8d658f9e3b142df245f/tomli-2.3.0-cp312-cp312-musllinux_1_2_x86_64.whl";,
 hash = 
"sha256:7b0882799624980785240ab732537fcfc372601015c00f7fc367c55308c186f6", size 
= 250296, upload-time = "2025-10-08T22:01:14.614Z" },
+    { url = 
"https://files.pythonhosted.org/packages/a0/b7/a7a7042715d55c9ba6e8b196d65d2cb662578b4d8cd17d882d45322b0d78/tomli-2.3.0-cp312-cp312-win32.whl";,
 hash = 
"sha256:ff72b71b5d10d22ecb084d345fc26f42b5143c5533db5e2eaba7d2d335358876", size 
= 97124, upload-time = "2025-10-08T22:01:15.629Z" },
+    { url = 
"https://files.pythonhosted.org/packages/06/1e/f22f100db15a68b520664eb3328fb0ae4e90530887928558112c8d1f4515/tomli-2.3.0-cp312-cp312-win_amd64.whl";,
 hash = 
"sha256:1cb4ed918939151a03f33d4242ccd0aa5f11b3547d0cf30f7c74a408a5b99878", size 
= 107698, upload-time = "2025-10-08T22:01:16.51Z" },
+    { url = 
"https://files.pythonhosted.org/packages/89/48/06ee6eabe4fdd9ecd48bf488f4ac783844fd777f547b8d1b61c11939974e/tomli-2.3.0-cp313-cp313-macosx_10_13_x86_64.whl";,
 hash = 
"sha256:5192f562738228945d7b13d4930baffda67b69425a7f0da96d360b0a3888136b", size 
= 154819, upload-time = "2025-10-08T22:01:17.964Z" },
+    { url = 
"https://files.pythonhosted.org/packages/f1/01/88793757d54d8937015c75dcdfb673c65471945f6be98e6a0410fba167ed/tomli-2.3.0-cp313-cp313-macosx_11_0_arm64.whl";,
 hash = 
"sha256:be71c93a63d738597996be9528f4abe628d1adf5e6eb11607bc8fe1a510b5dae", size 
= 148766, upload-time = "2025-10-08T22:01:18.959Z" },
+    { url = 
"https://files.pythonhosted.org/packages/42/17/5e2c956f0144b812e7e107f94f1cc54af734eb17b5191c0bbfb72de5e93e/tomli-2.3.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl";,
 hash = 
"sha256:c4665508bcbac83a31ff8ab08f424b665200c0e1e645d2bd9ab3d3e557b6185b", size 
= 240771, upload-time = "2025-10-08T22:01:20.106Z" },
+    { url = 
"https://files.pythonhosted.org/packages/d5/f4/0fbd014909748706c01d16824eadb0307115f9562a15cbb012cd9b3512c5/tomli-2.3.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl";,
 hash = 
"sha256:4021923f97266babc6ccab9f5068642a0095faa0a51a246a6a02fccbb3514eaf", size 
= 248586, upload-time = "2025-10-08T22:01:21.164Z" },
+    { url = 
"https://files.pythonhosted.org/packages/30/77/fed85e114bde5e81ecf9bc5da0cc69f2914b38f4708c80ae67d0c10180c5/tomli-2.3.0-cp313-cp313-musllinux_1_2_aarch64.whl";,
 hash = 
"sha256:a4ea38c40145a357d513bffad0ed869f13c1773716cf71ccaa83b0fa0cc4e42f", size 
= 244792, upload-time = "2025-10-08T22:01:22.417Z" },
+    { url = 
"https://files.pythonhosted.org/packages/55/92/afed3d497f7c186dc71e6ee6d4fcb0acfa5f7d0a1a2878f8beae379ae0cc/tomli-2.3.0-cp313-cp313-musllinux_1_2_x86_64.whl";,
 hash = 
"sha256:ad805ea85eda330dbad64c7ea7a4556259665bdf9d2672f5dccc740eb9d3ca05", size 
= 248909, upload-time = "2025-10-08T22:01:23.859Z" },
+    { url = 
"https://files.pythonhosted.org/packages/f8/84/ef50c51b5a9472e7265ce1ffc7f24cd4023d289e109f669bdb1553f6a7c2/tomli-2.3.0-cp313-cp313-win32.whl";,
 hash = 
"sha256:97d5eec30149fd3294270e889b4234023f2c69747e555a27bd708828353ab606", size 
= 96946, upload-time = "2025-10-08T22:01:24.893Z" },
+    { url = 
"https://files.pythonhosted.org/packages/b2/b7/718cd1da0884f281f95ccfa3a6cc572d30053cba64603f79d431d3c9b61b/tomli-2.3.0-cp313-cp313-win_amd64.whl";,
 hash = 
"sha256:0c95ca56fbe89e065c6ead5b593ee64b84a26fca063b5d71a1122bf26e533999", size 
= 107705, upload-time = "2025-10-08T22:01:26.153Z" },
+    { url = 
"https://files.pythonhosted.org/packages/19/94/aeafa14a52e16163008060506fcb6aa1949d13548d13752171a755c65611/tomli-2.3.0-cp314-cp314-macosx_10_13_x86_64.whl";,
 hash = 
"sha256:cebc6fe843e0733ee827a282aca4999b596241195f43b4cc371d64fc6639da9e", size 
= 154244, upload-time = "2025-10-08T22:01:27.06Z" },
+    { url = 
"https://files.pythonhosted.org/packages/db/e4/1e58409aa78eefa47ccd19779fc6f36787edbe7d4cd330eeeedb33a4515b/tomli-2.3.0-cp314-cp314-macosx_11_0_arm64.whl";,
 hash = 
"sha256:4c2ef0244c75aba9355561272009d934953817c49f47d768070c3c94355c2aa3", size 
= 148637, upload-time = "2025-10-08T22:01:28.059Z" },
+    { url = 
"https://files.pythonhosted.org/packages/26/b6/d1eccb62f665e44359226811064596dd6a366ea1f985839c566cd61525ae/tomli-2.3.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl";,
 hash = 
"sha256:c22a8bf253bacc0cf11f35ad9808b6cb75ada2631c2d97c971122583b129afbc", size 
= 241925, upload-time = "2025-10-08T22:01:29.066Z" },
+    { url = 
"https://files.pythonhosted.org/packages/70/91/7cdab9a03e6d3d2bb11beae108da5bdc1c34bdeb06e21163482544ddcc90/tomli-2.3.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl";,
 hash = 
"sha256:0eea8cc5c5e9f89c9b90c4896a8deefc74f518db5927d0e0e8d4a80953d774d0", size 
= 249045, upload-time = "2025-10-08T22:01:31.98Z" },
+    { url = 
"https://files.pythonhosted.org/packages/15/1b/8c26874ed1f6e4f1fcfeb868db8a794cbe9f227299402db58cfcc858766c/tomli-2.3.0-cp314-cp314-musllinux_1_2_aarch64.whl";,
 hash = 
"sha256:b74a0e59ec5d15127acdabd75ea17726ac4c5178ae51b85bfe39c4f8a278e879", size 
= 245835, upload-time = "2025-10-08T22:01:32.989Z" },
+    { url = 
"https://files.pythonhosted.org/packages/fd/42/8e3c6a9a4b1a1360c1a2a39f0b972cef2cc9ebd56025168c4137192a9321/tomli-2.3.0-cp314-cp314-musllinux_1_2_x86_64.whl";,
 hash = 
"sha256:b5870b50c9db823c595983571d1296a6ff3e1b88f734a4c8f6fc6188397de005", size 
= 253109, upload-time = "2025-10-08T22:01:34.052Z" },
+    { url = 
"https://files.pythonhosted.org/packages/22/0c/b4da635000a71b5f80130937eeac12e686eefb376b8dee113b4a582bba42/tomli-2.3.0-cp314-cp314-win32.whl";,
 hash = 
"sha256:feb0dacc61170ed7ab602d3d972a58f14ee3ee60494292d384649a3dc38ef463", size 
= 97930, upload-time = "2025-10-08T22:01:35.082Z" },
+    { url = 
"https://files.pythonhosted.org/packages/b9/74/cb1abc870a418ae99cd5c9547d6bce30701a954e0e721821df483ef7223c/tomli-2.3.0-cp314-cp314-win_amd64.whl";,
 hash = 
"sha256:b273fcbd7fc64dc3600c098e39136522650c49bca95df2d11cf3b626422392c8", size 
= 107964, upload-time = "2025-10-08T22:01:36.057Z" },
+    { url = 
"https://files.pythonhosted.org/packages/54/78/5c46fff6432a712af9f792944f4fcd7067d8823157949f4e40c56b8b3c83/tomli-2.3.0-cp314-cp314t-macosx_10_13_x86_64.whl";,
 hash = 
"sha256:940d56ee0410fa17ee1f12b817b37a4d4e4dc4d27340863cc67236c74f582e77", size 
= 163065, upload-time = "2025-10-08T22:01:37.27Z" },
+    { url = 
"https://files.pythonhosted.org/packages/39/67/f85d9bd23182f45eca8939cd2bc7050e1f90c41f4a2ecbbd5963a1d1c486/tomli-2.3.0-cp314-cp314t-macosx_11_0_arm64.whl";,
 hash = 
"sha256:f85209946d1fe94416debbb88d00eb92ce9cd5266775424ff81bc959e001acaf", size 
= 159088, upload-time = "2025-10-08T22:01:38.235Z" },
+    { url = 
"https://files.pythonhosted.org/packages/26/5a/4b546a0405b9cc0659b399f12b6adb750757baf04250b148d3c5059fc4eb/tomli-2.3.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl";,
 hash = 
"sha256:a56212bdcce682e56b0aaf79e869ba5d15a6163f88d5451cbde388d48b13f530", size 
= 268193, upload-time = "2025-10-08T22:01:39.712Z" },
+    { url = 
"https://files.pythonhosted.org/packages/42/4f/2c12a72ae22cf7b59a7fe75b3465b7aba40ea9145d026ba41cb382075b0e/tomli-2.3.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl";,
 hash = 
"sha256:c5f3ffd1e098dfc032d4d3af5c0ac64f6d286d98bc148698356847b80fa4de1b", size 
= 275488, upload-time = "2025-10-08T22:01:40.773Z" },
+    { url = 
"https://files.pythonhosted.org/packages/92/04/a038d65dbe160c3aa5a624e93ad98111090f6804027d474ba9c37c8ae186/tomli-2.3.0-cp314-cp314t-musllinux_1_2_aarch64.whl";,
 hash = 
"sha256:5e01decd096b1530d97d5d85cb4dff4af2d8347bd35686654a004f8dea20fc67", size 
= 272669, upload-time = "2025-10-08T22:01:41.824Z" },
+    { url = 
"https://files.pythonhosted.org/packages/be/2f/8b7c60a9d1612a7cbc39ffcca4f21a73bf368a80fc25bccf8253e2563267/tomli-2.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl";,
 hash = 
"sha256:8a35dd0e643bb2610f156cca8db95d213a90015c11fee76c946aa62b7ae7e02f", size 
= 279709, upload-time = "2025-10-08T22:01:43.177Z" },
+    { url = 
"https://files.pythonhosted.org/packages/7e/46/cc36c679f09f27ded940281c38607716c86cf8ba4a518d524e349c8b4874/tomli-2.3.0-cp314-cp314t-win32.whl";,
 hash = 
"sha256:a1f7f282fe248311650081faafa5f4732bdbfef5d45fe3f2e702fbc6f2d496e0", size 
= 107563, upload-time = "2025-10-08T22:01:44.233Z" },
+    { url = 
"https://files.pythonhosted.org/packages/84/ff/426ca8683cf7b753614480484f6437f568fd2fda2edbdf57a2d3d8b27a0b/tomli-2.3.0-cp314-cp314t-win_amd64.whl";,
 hash = 
"sha256:70a251f8d4ba2d9ac2542eecf008b3c8a9fc5c3f9f02c56a9d7952612be2fdba", size 
= 119756, upload-time = "2025-10-08T22:01:45.234Z" },
+    { url = 
"https://files.pythonhosted.org/packages/77/b8/0135fadc89e73be292b473cb820b4f5a08197779206b33191e801feeae40/tomli-2.3.0-py3-none-any.whl";,
 hash = 
"sha256:e95b1af3c5b07d9e643909b5abbec77cd9f1217e6d0bca72b0234736b9fb1f1b", size 
= 14408, upload-time = "2025-10-08T22:01:46.04Z" },
+]
+
+[[package]]
+name = "typing-extensions"
+version = "4.15.0"
+source = { registry = "https://pypi.org/simple"; }
+sdist = { url = 
"https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz";,
 hash = 
"sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size 
= 109391, upload-time = "2025-08-25T13:49:26.313Z" }
+wheels = [
+    { url = 
"https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl";,
 hash = 
"sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size 
= 44614, upload-time = "2025-08-25T13:49:24.86Z" },
+]

Reply via email to