Metadata-Version: 2.4
Name: pyproject-fmt
Version: 2.22.0
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Programming Language :: Python :: 3.15
Classifier: Programming Language :: Python :: Free Threading :: 1 - Unstable
Requires-Dist: toml-fmt-common
License-File: LICENSE.txt
Summary: Format your pyproject.toml file
Keywords: format,pyproject
Author-email: Bernat Gabor <gaborjbernat@gmail.com>
Requires-Python: >=3.10
Description-Content-Type: text/x-rst
Project-URL: Bug Tracker, https://github.com/tox-dev/toml-fmt/issues
Project-URL: Changelog, https://github.com/tox-dev/toml-fmt/blob/main/pyproject-fmt/CHANGELOG.md
Project-URL: Documentation, https://pyproject-fmt.readthedocs.io/en/latest/
Project-URL: Source Code, https://github.com/tox-dev/toml-fmt/tree/main/pyproject-fmt

Overview
========

Apply a consistent format to your ``pyproject.toml`` file with comment support. See
`changelog here <https://github.com/tox-dev/toml-fmt/blob/main/pyproject-fmt/CHANGELOG.md>`_.


Recent Changes
~~~~~~~~~~~~~~~~

- ✨ feat(build): ship self-contained pyproject-fmt and tox-toml-fmt wheels by
  `@gaborbernat <https://github.com/gaborbernat>`_ in `#363 <https://github.com/tox-dev/toml-fmt/pull/363>`_
- 🐛 fix(common): restore \_build_cli alias for backward compatibility by `@gaborbernat <https://github.com/gaborbernat>`_
  in `#361 <https://github.com/tox-dev/toml-fmt/pull/361>`_
- ✨ feat(pyproject-fmt): add [tool.ty] handler by [@gaborbernat](https://github.com/gaborbernat) in
  `#354 <https://github.com/tox-dev/toml-fmt/pull/354>`_
- ✨ feat(pyproject-fmt): add [tool.deptry] handler by [@gaborbernat](https://github.com/gaborbernat) in
  `#353 <https://github.com/tox-dev/toml-fmt/pull/353>`_
- ✨ feat(pyproject-fmt): add [tool.autopep8] handler by [@gaborbernat](https://github.com/gaborbernat) in
  `#352 <https://github.com/tox-dev/toml-fmt/pull/352>`_
- ✨ feat(pyproject-fmt): add [tool.vulture] handler by [@gaborbernat](https://github.com/gaborbernat) in
  `#351 <https://github.com/tox-dev/toml-fmt/pull/351>`_
- ✨ feat(pyproject-fmt): add [tool.docformatter] handler by [@gaborbernat](https://github.com/gaborbernat) in
  `#350 <https://github.com/tox-dev/toml-fmt/pull/350>`_
- ✨ feat(pyproject-fmt): add [tool.interrogate] handler by [@gaborbernat](https://github.com/gaborbernat) in
  `#349 <https://github.com/tox-dev/toml-fmt/pull/349>`_
- ✨ feat(pyproject-fmt): add [tool.bumpversion] handler by [@gaborbernat](https://github.com/gaborbernat) in
  `#348 <https://github.com/tox-dev/toml-fmt/pull/348>`_
- ✨ feat(pyproject-fmt): add [tool.scikit-build] handler by [@gaborbernat](https://github.com/gaborbernat) in
  `#347 <https://github.com/tox-dev/toml-fmt/pull/347>`_
- ✨ feat(pyproject-fmt): add [tool.semantic_release] handler by [@gaborbernat](https://github.com/gaborbernat) in
  `#346 <https://github.com/tox-dev/toml-fmt/pull/346>`_
- ✨ feat(pyproject-fmt): add [tool.pyrefly] handler by [@gaborbernat](https://github.com/gaborbernat) in
  `#345 <https://github.com/tox-dev/toml-fmt/pull/345>`_
- ✨ feat(pyproject-fmt): add [tool.check-manifest] handler by [@gaborbernat](https://github.com/gaborbernat) in
  `#344 <https://github.com/tox-dev/toml-fmt/pull/344>`_
- ✨ feat(pyproject-fmt): add [tool.yapf] handler by [@gaborbernat](https://github.com/gaborbernat) in
  `#343 <https://github.com/tox-dev/toml-fmt/pull/343>`_
- ✨ feat(pyproject-fmt): add [tool.djlint] handler by [@gaborbernat](https://github.com/gaborbernat) in
  `#342 <https://github.com/tox-dev/toml-fmt/pull/342>`_
- ✨ feat(pyproject-fmt): add [tool.pylint.*] handler by [@gaborbernat](https://github.com/gaborbernat) in
  `#341 <https://github.com/tox-dev/toml-fmt/pull/341>`_
- ✨ feat(pyproject-fmt): add [tool.towncrier] handler by [@gaborbernat](https://github.com/gaborbernat) in
  `#340 <https://github.com/tox-dev/toml-fmt/pull/340>`_
- ✨ feat(pyproject-fmt): add [tool.codespell] handler by [@gaborbernat](https://github.com/gaborbernat) in
  `#338 <https://github.com/tox-dev/toml-fmt/pull/338>`_
- ✨ feat(pyproject-fmt): add [tool.maturin] handler by [@gaborbernat](https://github.com/gaborbernat) in
  `#337 <https://github.com/tox-dev/toml-fmt/pull/337>`_
- ✨ feat(pyproject-fmt): add [tool.bandit] handler by [@gaborbernat](https://github.com/gaborbernat) in
  `#336 <https://github.com/tox-dev/toml-fmt/pull/336>`_
- ✨ feat(pyproject-fmt): add [tool.tox] handler reusing tox-toml-fmt rules by
  `@gaborbernat <https://github.com/gaborbernat>`_ in `#335 <https://github.com/tox-dev/toml-fmt/pull/335>`_
- ✨ feat(pyproject-fmt): add [tool.cibuildwheel] handler by [@gaborbernat](https://github.com/gaborbernat) in
  `#334 <https://github.com/tox-dev/toml-fmt/pull/334>`_
- ✨ feat(pyproject-fmt): add [tool.pdm.*] handler by [@gaborbernat](https://github.com/gaborbernat) in
  `#333 <https://github.com/tox-dev/toml-fmt/pull/333>`_
- ✨ feat(pyproject-fmt): add [tool.pyright] + [tool.basedpyright] handler by
  `@gaborbernat <https://github.com/gaborbernat>`_ in `#332 <https://github.com/tox-dev/toml-fmt/pull/332>`_
- ✨ feat(pyproject-fmt): add [tool.isort] handler by [@gaborbernat](https://github.com/gaborbernat) in
  `#331 <https://github.com/tox-dev/toml-fmt/pull/331>`_
- ✨ feat(pyproject-fmt): add [tool.hatch.*] handler by [@gaborbernat](https://github.com/gaborbernat) in
  `#329 <https://github.com/tox-dev/toml-fmt/pull/329>`_
- ✨ feat(pyproject-fmt): add [tool.black] handler by [@gaborbernat](https://github.com/gaborbernat) in
  `#328 <https://github.com/tox-dev/toml-fmt/pull/328>`_
- ✨ feat(pyproject-fmt): add [tool.pytest.ini_options] handler by [@gaborbernat](https://github.com/gaborbernat) in
  `#327 <https://github.com/tox-dev/toml-fmt/pull/327>`_
- ✨ feat(pyproject-fmt): add [tool.setuptools] + [tool.setuptools_scm] handlers by
  `@gaborbernat <https://github.com/gaborbernat>`_ in `#326 <https://github.com/tox-dev/toml-fmt/pull/326>`_
- ✨ feat(pyproject-fmt): add [tool.mypy] handler by [@gaborbernat](https://github.com/gaborbernat) in
  `#325 <https://github.com/tox-dev/toml-fmt/pull/325>`_
- ✨ feat(pyproject-fmt): add [tool.poetry] handler by [@gaborbernat](https://github.com/gaborbernat) in
  `#324 <https://github.com/tox-dev/toml-fmt/pull/324>`_
- ✨ feat(pyproject-fmt): add [tool.commitizen] handler by [@gaborbernat](https://github.com/gaborbernat) in
  `#339 <https://github.com/tox-dev/toml-fmt/pull/339>`_
- Update Python dependencies by `@gaborbernat <https://github.com/gaborbernat>`_ in
  `#358 <https://github.com/tox-dev/toml-fmt/pull/358>`_
- 🐛 fix(common): preserve triple-literal strings when re-emitting by `@gaborbernat <https://github.com/gaborbernat>`_ in
  `#356 <https://github.com/tox-dev/toml-fmt/pull/356>`_
- ♻️ refactor(common): deduplicate table formatting CLI args by `@gaborbernat <https://github.com/gaborbernat>`_ in
  `#320 <https://github.com/tox-dev/toml-fmt/pull/320>`_
- ✨ feat(common): add configurable table spacing options by `@gaborbernat <https://github.com/gaborbernat>`_ in
  `#319 <https://github.com/tox-dev/toml-fmt/pull/319>`_
- Update Python dependencies by `@gaborbernat <https://github.com/gaborbernat>`_ in
  `#310 <https://github.com/tox-dev/toml-fmt/pull/310>`_ <a id="2.21.2"></a>

Philosophy
----------
This tool aims to be an *opinionated formatter*, with similar objectives to `black <https://github.com/psf/black>`_.
This means it deliberately does not support a wide variety of configuration settings. In return, you get consistency,
predictability, and smaller diffs.

Use
---

Via ``CLI``
~~~~~~~~~~~

`pyproject-fmt <https://pypi.org/project/pyproject-fmt>`_ is a CLI tool that needs a Python interpreter (version 3.10 or higher) to run. We recommend
either `pipx <https://pypi.org/project/pipx>`_ or `uv <https://pypi.org/project/uv>`_ to install pyproject-fmt into an isolated environment. This has the added benefit that
later you will be able to upgrade pyproject-fmt without affecting other parts of the system. We provide a method for
``pip`` too here, but we discourage that path if you can:


    .. code-block:: bash

        # install uv per https://docs.astral.sh/uv/#getting-started
        uv tool install pyproject-fmt
        pyproject-fmt --help


Via ``pre-commit`` hook
~~~~~~~~~~~~~~~~~~~~~~~

See `pre-commit/pre-commit <https://github.com/pre-commit/pre-commit>`_ for instructions, sample ``.pre-commit-config.yaml``:

.. code-block:: yaml

    - repo: https://github.com/tox-dev/pyproject-fmt
      # Use the sha / tag you want to point at
      # or use `pre-commit autoupdate` to get the latest version
      rev: ""
      hooks:
        - id: pyproject-fmt

Via Python
~~~~~~~~~~

You can use ``pyproject-fmt`` as a Python module to format TOML content programmatically.

.. code-block:: python

    from pyproject_fmt import run

    # Format a pyproject.toml file and return the exit code
    exit_code = run(["path/to/pyproject.toml"])

The ``run`` function accepts command-line arguments as a list and returns an exit code (0 for success, non-zero for
failure).


The ``tool.pyproject-fmt`` table is used when present in the ``pyproject.toml`` file:

.. code-block:: toml

    [tool.pyproject-fmt]

    # After how many columns split arrays/dicts into multiple lines and wrap long strings;
    # use a trailing comma in arrays to force multiline format instead of lowering this value
    column_width = 120

    # Number of spaces for indentation
    indent = 2

    # Keep full version numbers (e.g., 1.0.0 instead of 1.0) in dependency specifiers
    keep_full_version = false

    # Automatically generate Python version classifiers based on requires-python
    # Set to false to disable automatic classifier generation
    generate_python_version_classifiers = true

    # Maximum Python version for generating version classifiers
    max_supported_python = "3.14"

    # Table format: "short" collapses sub-tables to dotted keys, "long" expands to [table.subtable] headers
    table_format = "short"

    # Extra newlines between sub-tables in the same group (e.g. "\n" for one blank line between sub-tables)
    sub_table_spacing = ""

    # Extra newlines between root table groups (e.g. "\n" for one blank line, "\n\n" for two)
    separate_root_table = "\n"

    # List of tables to force expand regardless of table_format setting
    expand_tables = []

    # List of tables to force collapse regardless of table_format or expand_tables settings
    collapse_tables = []

    # List of key patterns to skip string wrapping (supports wildcards like *.parse or tool.bumpversion.*)
    skip_wrap_for_keys = []

If not set they will default to values from the CLI.

Shared configuration file
-------------------------

You can place formatting settings in a standalone ``pyproject-fmt.toml`` file instead of (or in addition to) the
``[tool.pyproject-fmt]`` table. This is useful for monorepos or when you want to share the same configuration across
multiple projects without duplicating it in each ``pyproject.toml``.

The formatter searches for ``pyproject-fmt.toml`` starting from the directory of the file being formatted and walking up
to the filesystem root. The first match wins. You can also pass an explicit path via ``--config``:

.. code-block:: bash

    pyproject-fmt --config /path/to/pyproject-fmt.toml pyproject.toml

The shared config file uses the same keys as the ``[tool.pyproject-fmt]`` table, but without the table header:

.. code-block:: toml

    column_width = 120
    indent = 2
    table_format = "short"
    sub_table_spacing = ""
    separate_root_table = "\n"
    max_supported_python = "3.14"

When both a shared config file and a ``[tool.pyproject-fmt]`` table exist, per-file settings from the
``[tool.pyproject-fmt]`` table take precedence over the shared config file.


Python version classifiers
--------------------------

This tool will automatically generate the ``Programming Language :: Python :: 3.X`` classifiers for you. To do so it
needs to know the range of Python interpreter versions you support:

- The lower bound can be set via the ``requires-python`` key in the ``pyproject.toml`` configuration file (defaults to
  the oldest non end of line CPython at the time of the release).
- The upper bound, by default, will assume the latest stable release of CPython at the time of the release, but can be
  changed via CLI flag or the config file.

Table formatting
----------------

.. note::

    Table formatting options are available in version 2.12.0 and later.

You can control how sub-tables are formatted in your ``pyproject.toml`` file. There are two formatting styles:

**Short format (collapsed)** - The default behavior where sub-tables are collapsed into dotted keys. Use this for a
compact representation:

.. code-block:: toml

    [project]
    name = "myproject"
    urls.homepage = "https://example.com"
    urls.repository = "https://github.com/example/myproject"
    scripts.mycli = "mypackage:main"

**Long format (expanded)** - Sub-tables are expanded into separate ``[table.subtable]`` sections. Use this for
readability when tables have many keys or complex values:

.. code-block:: toml

    [project]
    name = "myproject"

    [project.urls]
    homepage = "https://example.com"
    repository = "https://github.com/example/myproject"

    [project.scripts]
    mycli = "mypackage:main"

Table spacing
~~~~~~~~~~~~~

The ``sub_table_spacing`` and ``separate_root_table`` options control the blank lines inserted between tables. Each
option takes a string of ``\n`` characters where each ``\n`` adds one blank line:

- ``sub_table_spacing`` (default ``""``) controls spacing between sub-tables within the same group. For example,
  between ``[tool.ruff]`` and ``[tool.ruff.lint]``. Set to ``"\n"`` to add a blank line between sub-tables.
- ``separate_root_table`` (default ``"\n"``) controls spacing between different root table groups. For example,
  between ``[project]`` and ``[tool.ruff]``.

.. code-block:: toml

    [tool.pyproject-fmt]
    sub_table_spacing = "\n"  # Add blank line between sub-tables
    separate_root_table = "\n"  # One blank line between root table groups (default)

Configuration priority
~~~~~~~~~~~~~~~~~~~~~~

The formatting behavior is determined by a priority system that allows you to set a global default while overriding
specific tables:

1. **collapse_tables** - Highest priority, forces specific tables to be collapsed regardless of other settings
2. **expand_tables** - Medium priority, forces specific tables to be expanded
3. **table_format** - Lowest priority, sets the default behavior for all tables not explicitly configured

This three-tier approach lets you fine-tune formatting for specific tables while maintaining a consistent default.
For example:

.. code-block:: toml

    [tool.pyproject-fmt]
    table_format = "short"  # Collapse most tables
    expand_tables = ["project.entry-points"]  # But expand entry-points

Specificity rules
~~~~~~~~~~~~~~~~~

Table selectors follow CSS-like specificity rules: more specific selectors win over less specific ones. When
determining whether to collapse or expand a table, the formatter checks from most specific to least specific until it
finds a match.

For example, with this configuration:

.. code-block:: toml

    [tool.pyproject-fmt]
    table_format = "long"  # Expand all tables by default
    collapse_tables = ["project"]  # Collapse project sub-tables
    expand_tables = ["project.optional-dependencies"]  # But expand this specific one

The behavior will be:

- ``project.urls`` → collapsed (matches ``project`` in collapse_tables)
- ``project.scripts`` → collapsed (matches ``project`` in collapse_tables)
- ``project.optional-dependencies`` → expanded (matches exactly in expand_tables, more specific than ``project``)
- ``tool.ruff.lint`` → expanded (no match in collapse/expand, uses table_format default)

This allows you to set broad rules for parent tables while making exceptions for specific sub-tables. The specificity
check walks up the table hierarchy: for ``project.optional-dependencies``, it first checks if
``project.optional-dependencies`` is in collapse_tables or expand_tables, then checks ``project``, then falls back to
the table_format default.

Supported tables
~~~~~~~~~~~~~~~~

The following sub-tables can be formatted with this configuration:

**Project tables:**

- ``project.urls`` - Project URLs (homepage, repository, documentation, changelog)
- ``project.scripts`` - Console script entry points
- ``project.gui-scripts`` - GUI script entry points
- ``project.entry-points`` - Custom entry point groups
- ``project.optional-dependencies`` - Optional dependency groups

**Tool tables:**

- ``tool.ruff.format`` - Ruff formatter settings
- ``tool.ruff.lint`` - Ruff linter settings
- Any other tool sub-tables

**Array of tables:**

- ``project.authors`` - Can be inline tables or ``[[project.authors]]``
- ``project.maintainers`` - Can be inline tables or ``[[project.maintainers]]``
- Any ``[[table]]`` entries throughout the file

Array of tables (``[[table]]``) are automatically collapsed to inline arrays when each inline table fits within the
configured ``column_width``. For example:

.. code-block:: toml

    # Before
    [[tool.commitizen.customize.questions]]
    type = "list"

    [[tool.commitizen.customize.questions]]
    type = "input"

    # After (with table_format = "short")
    [tool.commitizen]
    customize.questions = [{ type = "list" }, { type = "input" }]

If any inline table exceeds ``column_width``, the array of tables remains in ``[[...]]`` format to maintain
readability and TOML 1.0.0 compatibility (inline tables cannot span multiple lines).

String wrapping
---------------

By default, the formatter wraps long strings that exceed the column width using line continuations. However, some strings such as regex patterns should not be wrapped because wrapping can break their functionality.

You can configure which keys should skip string wrapping using the ``skip_wrap_for_keys`` option:

.. code-block:: toml

    [tool.pyproject-fmt]
    skip_wrap_for_keys = ["*.parse", "*.regex", "tool.bumpversion.*"]

Pattern matching
~~~~~~~~~~~~~~~~

The ``skip_wrap_for_keys`` option supports glob-like patterns:

- **Exact match**: ``tool.bumpversion.parse`` matches only that specific key
- **Wildcard suffix**: ``*.parse`` matches any key ending with ``.parse`` (e.g., ``tool.bumpversion.parse``, ``project.parse``)
- **Wildcard prefix**: ``tool.bumpversion.*`` matches any key under ``tool.bumpversion`` (e.g., ``tool.bumpversion.parse``, ``tool.bumpversion.serialize``)
- **Global wildcard**: ``*`` skips wrapping for all strings

Examples: ``["*.parse", "*.regex"]`` to preserve regex fields, ``["tool.bumpversion.*"]`` for a specific tool section,
or ``["*"]`` to skip all string wrapping.

``pyproject-fmt`` is an opinionated formatter, much like `black <https://github.com/psf/black>`_ is for Python code.
The tool intentionally provides minimal configuration options because the goal is to establish a single standard format
that all ``pyproject.toml`` files follow.

**Benefits of this approach:**

- Less time configuring tools
- Smaller diffs when committing changes
- Easier code reviews since formatting is never a question

While a few key options exist (``column_width``, ``indent``, ``table_format``, ``sub_table_spacing``,
``separate_root_table``), the tool does not expose dozens of toggles. You get what the maintainers have chosen to be the
right balance of readability, consistency, and usability. The ``column_width`` setting controls when arrays are split
into multiple lines and when string values are wrapped using line continuations.

General Formatting
------------------

These rules apply uniformly across the entire ``pyproject.toml`` file.

Table Ordering
~~~~~~~~~~~~~~

Tables are reordered into a consistent structure:

1. ``[build-system]``
2. ``[project]``
3. ``[dependency-groups]``
4. ``[tool.*]`` sections in the order:

   1. Build backends: ``poetry``, ``poetry-dynamic-versioning``, ``pdm``, ``setuptools``, ``distutils``,
      ``setuptools_scm``, ``hatch``, ``flit``, ``scikit-build``, ``meson-python``, ``maturin``, ``pixi``,
      ``whey``, ``py-build-cmake``, ``sphinx-theme-builder``, ``uv``
   2. Builders: ``cibuildwheel``, ``nuitka``
   3. Linters/formatters: ``autopep8``, ``black``, ``ruff``, ``isort``, ``flake8``, ``pycln``, ``nbqa``,
      ``pylint``, ``repo-review``, ``codespell``, ``docformatter``, ``pydoclint``, ``tomlsort``,
      ``check-manifest``, ``check-sdist``, ``check-wheel-contents``, ``deptry``, ``pyproject-fmt``, ``typos``,
      ``bandit``
   4. Type checkers: ``mypy``, ``pyrefly``, ``pyright``, ``ty``, ``django-stubs``
   5. Testing: ``pytest``, ``pytest_env``, ``pytest-enabler``, ``coverage``
   6. Task runners: ``doit``, ``spin``, ``tox``
   7. Release tools: ``bumpversion``, ``jupyter-releaser``, ``tbump``, ``towncrier``, ``vendoring``
   8. Any other ``tool.*`` in alphabetical order

5. Any other tables (alphabetically)

String Quotes
~~~~~~~~~~~~~

All strings use double quotes by default. Single quotes are only used when the value contains double quotes:

.. code-block:: toml

    # Before
    name = 'my-package'
    description = "He said \"hello\""

    # After
    name = "my-package"
    description = 'He said "hello"'

Key Quotes
~~~~~~~~~~

TOML keys are normalized to the simplest valid form. Keys that are valid bare keys (containing only
``A-Za-z0-9_-``) have redundant quotes stripped. Single-quoted (literal) keys that require quoting are
converted to double-quoted (basic) strings with proper escaping. This applies to all keys: table headers,
key-value pairs, and inline table keys:

.. code-block:: toml

    # Before
    [tool."ruff"]
    "line-length" = 120
    lint.per-file-ignores.'tests/*' = ["S101"]

    # After
    [tool.ruff]
    line-length = 120
    lint.per-file-ignores."tests/*" = ["S101"]

Backslashes and double quotes within literal keys are escaped during conversion:

.. code-block:: toml

    # Before
    lint.per-file-ignores.'path\to\file' = ["E501"]

    # After
    lint.per-file-ignores."path\\to\\file" = ["E501"]

Array Formatting
~~~~~~~~~~~~~~~~

Arrays are formatted based on line length, trailing comma presence, and comments:

.. code-block:: toml

    # Short arrays stay on one line
    keywords = ["python", "toml"]

    # Long arrays that exceed column_width are expanded and get a trailing comma
    dependencies = [
        "requests>=2.28",
        "click>=8.0",
    ]

    # Trailing commas signal intent to keep multiline format
    classifiers = [
        "Development Status :: 4 - Beta",
    ]

    # Arrays with comments are always multiline
    lint.ignore = [
        "E501",  # Line too long
        "E701",
    ]

**Multiline formatting rules:**

An array becomes multiline when any of these conditions are met:

1. **Trailing comma present** - A trailing comma signals intent to keep multiline format
2. **Exceeds column width** - Arrays longer than ``column_width`` are expanded (and get a trailing comma added)
3. **Contains comments** - Arrays with inline or leading comments are always multiline

String Wrapping
~~~~~~~~~~~~~~~

Strings that exceed ``column_width`` (including the key name and ``" = "`` prefix) are wrapped into multi-line
triple-quoted strings using line continuations:

.. code-block:: toml

    # Before (exceeds column_width)
    description = "A very long description that goes beyond the configured column width limit"

    # After
    description = """\
      A very long description that goes beyond the \
      configured column width limit\
      """

Wrapping prefers breaking at spaces and at ``" :: "`` separators (common in Python classifiers). Strings inside inline
tables are never wrapped. Strings that contain actual newlines are preserved as multi-line strings without adding line
continuations. Use ``skip_wrap_for_keys`` to prevent wrapping for specific keys.

Table Formatting
~~~~~~~~~~~~~~~~

Sub-tables can be formatted in two styles controlled by ``table_format``:

**Short format** (collapsed to dotted keys):

.. code-block:: toml

    [project]
    urls.homepage = "https://example.com"
    urls.repository = "https://github.com/example/project"

**Long format** (expanded to table headers):

.. code-block:: toml

    [project.urls]
    homepage = "https://example.com"
    repository = "https://github.com/example/project"

**Table spacing:**

By default, different table groups (e.g. ``[project]`` and ``[tool.ruff]``) are separated by a blank line, while
sub-tables within the same group (e.g. ``[tool.ruff]`` and ``[tool.ruff.lint]``) are kept compact with no blank line
between them. You can control this with ``sub_table_spacing`` and ``separate_root_table``. Each option takes a string of
``\n`` characters where each ``\n`` adds one blank line. For example, setting ``sub_table_spacing = "\n"`` adds a blank
line between sub-tables:

.. code-block:: toml

    [tool.ruff]
    line-length = 120

    [tool.ruff.lint]
    select = ["E", "W"]


Comment Preservation
~~~~~~~~~~~~~~~~~~~~

All comments are preserved during formatting:

- **Inline comments** - Comments after a value on the same line stay with that value
- **Leading comments** - Comments on the line before an entry stay with the entry below
- **Block comments** - Multi-line comment blocks are preserved

**Inline comment alignment:**

Inline comments within arrays are aligned independently per array, based on that array's longest value:

.. code-block:: toml

    # Before - comments at inconsistent positions
    lint.ignore = [
      "COM812", # Conflict with formatter
      "CPY", # No copyright statements
      "ISC001",   # Another rule
    ]

    # After - comments align to longest value in this array
    lint.ignore = [
      "COM812",  # Conflict with formatter
      "CPY",     # No copyright statements
      "ISC001",  # Another rule
    ]

Table-Specific Handling
-----------------------

Beyond general formatting, each table has specific key ordering and value normalization rules.

``[build-system]``
~~~~~~~~~~~~~~~~~~

**Key ordering:** ``build-backend`` → ``requires`` → ``backend-path``

**Value normalization:**

- ``requires``: Dependencies normalized per PEP 508 and sorted alphabetically by package name
- ``backend-path``: Entries sorted alphabetically

.. code-block:: toml

    # Before
    [build-system]
    requires = ["setuptools >= 45", "wheel"]
    build-backend = "setuptools.build_meta"

    # After
    [build-system]
    build-backend = "setuptools.build_meta"
    requires = ["setuptools>=45", "wheel"]

``[project]``
~~~~~~~~~~~~~

**Key ordering:**

Keys are reordered in this sequence: ``name`` → ``version`` → ``import-names`` → ``import-namespaces`` →
``description`` → ``readme`` → ``keywords`` → ``license`` → ``license-files`` → ``maintainers`` → ``authors`` →
``requires-python`` → ``classifiers`` → ``dynamic`` → ``dependencies`` → ``optional-dependencies`` → ``urls`` →
``scripts`` → ``gui-scripts`` → ``entry-points``

**Field normalizations:**

``name``
    Converted to canonical format (lowercase with hyphens): ``My_Package`` → ``my-package``

``description``
    Whitespace normalized: multiple spaces collapsed, consistent spacing after periods.

``license``
    License expression operators (``and``, ``or``, ``with``) uppercased: ``MIT or Apache-2.0`` → ``MIT OR Apache-2.0``

``requires-python``
    Whitespace removed: ``>= 3.9`` → ``>=3.9``

``keywords``
    Deduplicated (case-insensitive) and sorted alphabetically.

``dynamic``
    Sorted alphabetically.

``import-names`` / ``import-namespaces``
    Semicolon spacing normalized (``foo;bar`` → ``foo; bar``), entries sorted alphabetically.

``classifiers``
    Deduplicated and sorted alphabetically.

``authors`` / ``maintainers``
    Sorted by name, then email. Keys within each entry ordered: ``name`` → ``email``.

**Dependency normalization:**

All dependency arrays (``dependencies``, ``optional-dependencies.*``) are:

- Normalized per PEP 508: spaces removed, redundant ``.0`` suffixes stripped (unless ``keep_full_version = true``)
- Sorted alphabetically by canonical package name

.. code-block:: toml

    # Before
    dependencies = ["requests >= 2.0.0", "click~=8.0"]

    # After
    dependencies = ["click>=8", "requests>=2"]

**Optional dependencies extra names:**

Extra names are normalized to lowercase with hyphens:

.. code-block:: toml

    # Before
    [project.optional-dependencies]
    Dev_Tools = ["pytest"]

    # After
    [project.optional-dependencies]
    dev-tools = ["pytest"]

**Python version classifiers:**

Classifiers for Python versions are automatically generated based on ``requires-python`` and
``max_supported_python``. Disable with ``generate_python_version_classifiers = false``.

.. code-block:: toml

    # With requires-python = ">=3.10" and max_supported_python = "3.14"
    classifiers = [
        "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",
    ]

**Entry points:**

Inline tables within ``entry-points`` are expanded to dotted keys:

.. code-block:: toml

    # Before
    entry-points.console_scripts = { mycli = "mypackage:main" }

    # After
    entry-points.console_scripts.mycli = "mypackage:main"

**Authors/maintainers formatting:**

Contact information can be formatted as inline tables or expanded array of tables:

.. code-block:: toml

    # Short format (inline)
    authors = [{ name = "Alice", email = "alice@example.com" }]

    # Long format (array of tables)
    [[project.authors]]
    name = "Alice"
    email = "alice@example.com"

Controlled by ``table_format``, ``expand_tables``, and ``collapse_tables``.

``[dependency-groups]``
~~~~~~~~~~~~~~~~~~~~~~~

**Key ordering:** ``dev`` → ``test`` → ``type`` → ``docs`` → others alphabetically

**Value normalization:**

- All dependencies normalized per PEP 508
- Sorted: regular dependencies first, then ``include-group`` entries

.. code-block:: toml

    # Before
    [dependency-groups]
    dev = [{ include-group = "test" }, "ruff>=0.4", "mypy>=1"]

    # After
    [dependency-groups]
    dev = ["mypy>=1", "ruff>=0.4", { include-group = "test" }]

``[tool.ruff]``
~~~~~~~~~~~~~~~

**Key ordering:**

Keys are reordered in a logical sequence:

1. Global settings: ``required-version`` → ``extend`` → ``target-version`` → ``line-length`` → ``indent-width`` →
   ``tab-size``
2. Path settings: ``builtins`` → ``namespace-packages`` → ``src`` → ``include`` → ``extend-include`` → ``exclude`` →
   ``extend-exclude`` → ``force-exclude`` → ``respect-gitignore``
3. Behavior flags: ``preview`` → ``fix`` → ``unsafe-fixes`` → ``fix-only`` → ``show-fixes`` → ``show-source``
4. Output settings: ``output-format`` → ``cache-dir``
5. ``format.*`` keys
6. ``lint.*`` keys: ``select`` → ``extend-select`` → ``ignore`` → ``extend-ignore`` → ``per-file-ignores`` →
   ``fixable`` → ``unfixable`` → plugin configurations

**Sorted arrays:**

Arrays are sorted alphabetically using natural ordering (``RUF1`` < ``RUF9`` < ``RUF10``):

.. code-block:: toml

    # These arrays are sorted:
    lint.select = ["E", "F", "I", "RUF"]
    lint.ignore = ["E501", "E701"]

    # Per-file-ignores values are also sorted:
    lint.per-file-ignores."tests/*.py" = ["D103", "S101"]

**Sorted array keys:**

Top-level:
  ``exclude``, ``extend-exclude``, ``include``, ``extend-include``, ``builtins``, ``namespace-packages``, ``src``

Format:
  ``format.exclude``

Lint:
  ``select``, ``extend-select``, ``ignore``, ``extend-ignore``, ``fixable``, ``extend-fixable``, ``unfixable``,
  ``extend-safe-fixes``, ``extend-unsafe-fixes``, ``external``, ``task-tags``, ``exclude``, ``typing-modules``,
  ``allowed-confusables``, ``logger-objects``

Per-file patterns:
  ``lint.per-file-ignores.*``, ``lint.extend-per-file-ignores.*``

Plugin arrays:
  ``lint.flake8-bandit.hardcoded-tmp-directory``, ``lint.flake8-bandit.hardcoded-tmp-directory-extend``,
  ``lint.flake8-boolean-trap.extend-allowed-calls``, ``lint.flake8-bugbear.extend-immutable-calls``,
  ``lint.flake8-builtins.builtins-ignorelist``, ``lint.flake8-gettext.extend-function-names``,
  ``lint.flake8-gettext.function-names``, ``lint.flake8-import-conventions.banned-from``,
  ``lint.flake8-pytest-style.raises-extend-require-match-for``, ``lint.flake8-pytest-style.raises-require-match-for``,
  ``lint.flake8-self.extend-ignore-names``, ``lint.flake8-self.ignore-names``,
  ``lint.flake8-tidy-imports.banned-module-level-imports``, ``lint.flake8-type-checking.exempt-modules``,
  ``lint.flake8-type-checking.runtime-evaluated-base-classes``,
  ``lint.flake8-type-checking.runtime-evaluated-decorators``, ``lint.isort.constants``,
  ``lint.isort.default-section``, ``lint.isort.extra-standard-library``, ``lint.isort.forced-separate``,
  ``lint.isort.no-lines-before``, ``lint.isort.required-imports``, ``lint.isort.single-line-exclusions``,
  ``lint.isort.variables``, ``lint.pep8-naming.classmethod-decorators``, ``lint.pep8-naming.extend-ignore-names``,
  ``lint.pep8-naming.ignore-names``, ``lint.pep8-naming.staticmethod-decorators``,
  ``lint.pydocstyle.ignore-decorators``, ``lint.pydocstyle.property-decorators``, ``lint.pyflakes.extend-generics``,
  ``lint.pylint.allow-dunder-method-names``, ``lint.pylint.allow-magic-value-types``

``[tool.pixi]``
~~~~~~~~~~~~~~~

**Key ordering:**

Keys are grouped by functionality:

1. Workspace metadata: ``workspace.name`` → ``workspace.version`` → ``workspace.description`` →
   ``workspace.authors`` → ``workspace.license`` → ``workspace.license-file`` → ``workspace.readme`` →
   ``workspace.homepage`` → ``workspace.repository`` → ``workspace.documentation``
2. Workspace configuration: ``workspace.channels`` → ``workspace.platforms`` → ``workspace.channel-priority`` →
   ``workspace.solve-strategy`` → ``workspace.conda-pypi-map`` → ``workspace.requires-pixi`` →
   ``workspace.exclude-newer`` → ``workspace.preview`` → ``workspace.build-variants`` →
   ``workspace.build-variants-files``
3. Dependencies: ``dependencies`` → ``host-dependencies`` → ``build-dependencies`` → ``run-dependencies`` →
   ``constraints`` → ``pypi-dependencies`` → ``pypi-options``
4. Development: ``dev``
5. Environment setup: ``system-requirements`` → ``activation`` → ``tasks``
6. Targeting: ``target`` → ``feature`` → ``environments``
7. Package build: ``package``

**Sorted arrays:**

``workspace.channels``, ``workspace.platforms``, ``workspace.preview``, ``workspace.build-variants-files``

``[tool.uv]``
~~~~~~~~~~~~~

**Key ordering:**

Keys are grouped by functionality:

1. Version & Python: ``required-version`` → ``python-preference`` → ``python-downloads``
2. Dependencies: ``dev-dependencies`` → ``default-groups`` → ``dependency-groups`` → ``constraint-dependencies`` →
   ``override-dependencies`` → ``exclude-dependencies`` → ``dependency-metadata``
3. Sources & indexes: ``sources`` → ``index`` → ``index-url`` → ``extra-index-url`` → ``find-links`` → ``no-index`` →
   ``index-strategy`` → ``keyring-provider``
4. Package handling: ``no-binary*`` → ``no-build*`` → ``no-sources*`` → ``reinstall*`` → ``upgrade*``
5. Resolution: ``resolution`` → ``prerelease`` → ``fork-strategy`` → ``environments`` → ``required-environments`` →
   ``exclude-newer*``
6. Build & Install: ``compile-bytecode`` → ``link-mode`` → ``config-settings*`` → ``extra-build-*`` →
   ``concurrent-builds`` → ``concurrent-downloads`` → ``concurrent-installs``
7. Network & Security: ``allow-insecure-host`` → ``native-tls`` → ``offline`` → ``no-cache`` → ``cache-dir`` →
   ``http-proxy`` → ``https-proxy`` → ``no-proxy``
8. Publishing: ``publish-url`` → ``check-url`` → ``trusted-publishing``
9. Python management: ``python-install-mirror`` → ``pypy-install-mirror`` → ``python-downloads-json-url``
10. Workspace & Project: ``managed`` → ``package`` → ``workspace`` → ``conflicts`` → ``cache-keys`` → ``build-backend``
11. Other: ``pip`` → ``preview`` → ``torch-backend``

**Sorted arrays:**

Package name arrays (sorted alphabetically):
  ``constraint-dependencies``, ``override-dependencies``, ``dev-dependencies``, ``exclude-dependencies``,
  ``no-binary-package``, ``no-build-package``, ``no-build-isolation-package``, ``no-sources-package``,
  ``reinstall-package``, ``upgrade-package``

Other arrays:
  ``environments``, ``required-environments``, ``allow-insecure-host``, ``no-proxy``, ``workspace.members``,
  ``workspace.exclude``

**Sources table:**

The ``sources`` table entries are sorted alphabetically by package name:

.. code-block:: toml

    # Before
    [tool.uv.sources]
    zebra = { git = "..." }
    alpha = { path = "..." }

    # After
    [tool.uv.sources]
    alpha = { path = "..." }
    zebra = { git = "..." }

**pip subsection:**

The ``[tool.uv.pip]`` subsection follows similar formatting rules, with arrays like ``extra``, ``no-binary-package``,
``no-build-package``, ``reinstall-package``, and ``upgrade-package`` sorted alphabetically.

``[tool.coverage]``
~~~~~~~~~~~~~~~~~~~

**Key ordering:**

Keys are reordered to follow coverage.py's workflow phases:

1. **Run phase** (``run.*``): Data collection settings

   - Source selection: ``source`` → ``source_pkgs`` → ``source_dirs``
   - File filtering: ``include`` → ``omit``
   - Measurement: ``branch`` → ``cover_pylib`` → ``timid``
   - Execution context: ``command_line`` → ``concurrency`` → ``context`` → ``dynamic_context``
   - Data management: ``data_file`` → ``parallel`` → ``relative_files``
   - Extensions: ``plugins``
   - Debugging: ``debug`` → ``debug_file`` → ``disable_warnings``
   - Other: ``core`` → ``patch`` → ``sigterm``

2. **Paths** (``paths.*``): Path mapping between source locations

3. **Report phase** (``report.*``): General reporting

   - Thresholds: ``fail_under`` → ``precision``
   - File filtering: ``include`` → ``omit`` → ``include_namespace_packages``
   - Line exclusion: ``exclude_lines`` → ``exclude_also``
   - Partial branches: ``partial_branches`` → ``partial_also``
   - Output control: ``skip_covered`` → ``skip_empty`` → ``show_missing``
   - Formatting: ``format`` → ``sort``
   - Error handling: ``ignore_errors``

4. **Output formats** (after report):

   - ``html.*``: ``directory`` → ``title`` → ``extra_css`` → ``show_contexts`` → ``skip_covered`` → ``skip_empty``
   - ``json.*``: ``output`` → ``pretty_print`` → ``show_contexts``
   - ``lcov.*``: ``output`` → ``line_checksums``
   - ``xml.*``: ``output`` → ``package_depth``

**Grouping principle:**

Related options are grouped together:

- File selection: ``include``/``omit`` are adjacent
- Exclusion patterns: ``exclude_lines``/``exclude_also`` are adjacent
- Partial branches: ``partial_branches``/``partial_also`` are adjacent
- Skip options: ``skip_covered``/``skip_empty`` are adjacent

**Sorted arrays:**

Run phase:
  ``source``, ``source_pkgs``, ``source_dirs``, ``include``, ``omit``, ``concurrency``, ``plugins``, ``debug``,
  ``disable_warnings``

Report phase:
  ``include``, ``omit``, ``exclude_lines``, ``exclude_also``, ``partial_branches``, ``partial_also``

.. code-block:: toml

    # Before (alphabetical)
    [tool.coverage]
    report.exclude_also = ["if TYPE_CHECKING:"]
    report.omit = ["tests/*"]
    run.branch = true
    run.omit = ["tests/*"]

    # After (workflow order with groupings)
    [tool.coverage]
    run.branch = true
    run.omit = ["tests/*"]
    report.omit = ["tests/*"]
    report.exclude_also = ["if TYPE_CHECKING:"]

``[tool.commitizen]``
~~~~~~~~~~~~~~~~~~~~~

Top-level ordering: rule selection (``name``, ``schema``, ``schema_pattern``, ``allowed_prefixes``) → version
source (``version``, ``version_scheme``, ``version_provider``, ``version_files``) → bump behavior → tag/sign →
changelog → hooks (``pre_bump_hooks``, ``post_bump_hooks``) → ``customize``.

**Sorted arrays:** ``version_files``, ``allowed_prefixes``, ``extras``, ``extra_files``.

``[tool.poetry]``
~~~~~~~~~~~~~~~~~

Covers both Poetry 1.x (legacy metadata under ``[tool.poetry]``) and Poetry 2.x (metadata moved to standard
``[project]``; Poetry-specific keys still under ``[tool.poetry]``).

**Top-level key ordering:**

1. Identity: ``name`` → ``version`` → ``description`` → ``package-mode``
2. License & authorship: ``license`` → ``authors`` → ``maintainers``
3. Documentation: ``readme`` → ``homepage`` → ``repository`` → ``documentation``
4. Discovery: ``keywords`` → ``classifiers``
5. Packaging contents: ``packages`` → ``include`` → ``exclude`` → ``build``
6. Dependencies (sub-tables): ``dependencies`` → ``dev-dependencies`` → ``group`` → ``extras``
7. Entry points / distribution: ``scripts`` → ``plugins`` → ``urls`` → ``source``
8. Poetry runtime constraints: ``requires-poetry`` → ``requires-plugins`` → ``build-constraints``

**Sub-table key ordering:**

``[tool.poetry.dependencies]`` / ``[tool.poetry.dev-dependencies]`` / per-group dependencies
    ``python`` first (interpreter constraint), all other package names alphabetized.

``[tool.poetry.group.<name>]``
    ``optional`` → ``include-groups`` → ``dependencies``.

``[tool.poetry.extras]``, ``[tool.poetry.scripts]``, ``[tool.poetry.urls]``, ``[tool.poetry.plugins.*]``, ``[tool.poetry.requires-plugins]``, ``[tool.poetry.build-constraints]``
    Keys alphabetized.

``[tool.poetry.build]``
    ``script`` → ``generate-setup-file``.

``[[tool.poetry.source]]``
    Each entry's keys ordered ``name`` → ``url`` → ``priority`` → ``links`` → ``indexed``, with the deprecated
    ``default`` and ``secondary`` keys placed last. Array order itself is preserved (priority ordering is
    semantically significant).

**Sorted arrays:**

- ``keywords``, ``classifiers``: deduplicated (case-insensitive) and sorted alphabetically.
- ``exclude``: sorted alphabetically.
- ``[tool.poetry.extras]`` values (each ``extras.<name>``): sorted alphabetically.
- ``[tool.poetry.group.<name>.include-groups]``: sorted alphabetically.
- Per-dependency ``extras`` arrays (in ``dependencies``, ``dev-dependencies``, per-group dependencies,
  ``requires-plugins``, ``build-constraints``): sorted alphabetically.

Arrays whose order carries semantic meaning are preserved as written: ``authors``, ``maintainers``, ``packages``,
``include``, ``readme`` (when an array), multi-constraint dependency arrays, and ``[[tool.poetry.source]]`` entries.

**Inline-table key ordering:**

When a Poetry-specific inline table is detected (via discriminator keys unique to Poetry's schema), its keys are
reordered:

- Sources (``{ priority = ... }``, ``{ secondary = ... }``, ``{ links = ... }``, ``{ indexed = ... }``):
  ``name`` → ``url`` → ``priority`` → ``links`` → ``indexed`` → ``default`` → ``secondary``.
- Git dependencies (``{ git = ... }``):
  ``git`` → ``branch`` → ``tag`` → ``rev`` → ``subdirectory`` → ``python`` → ``platform`` → ``markers`` →
  ``allow-prereleases`` → ``allows-prereleases`` → ``optional`` → ``extras`` → ``develop``.
- Path dependencies (``{ path = ... }``):
  ``path`` → ``develop`` → ``subdirectory`` → ``python`` → ``platform`` → ``markers`` → ``optional`` → ``extras``.
- File dependencies (``{ file = ... }``):
  ``file`` → ``subdirectory`` → ``python`` → ``platform`` → ``markers`` → ``optional`` → ``extras``.

Inline tables that don't match any Poetry-specific schema (for example ``[[project.authors]]`` inline form
``{ name = "...", email = "..." }``) are left untouched.

.. code-block:: toml

    # Before
    [[tool.poetry.source]]
    priority = "primary"
    url = "https://pypi.example.com/simple"
    name = "private"

    [tool.poetry.dependencies]
    zebra = "^1.0"
    python = "^3.11"
    foo = { branch = "main", git = "https://github.com/example/foo" }

    # After
    [tool.poetry]
    dependencies.python = "^3.11"
    dependencies.foo = { git = "https://github.com/example/foo", branch = "main" }
    dependencies.zebra = "^1.0"
    source = [ { name = "private", url = "https://pypi.example.com/simple", priority = "primary" } ]

``[tool.mypy]``
~~~~~~~~~~~~~~~

Covers all documented mypy options plus the ``[[tool.mypy.overrides]]`` array of tables. Keys are reordered to match
the section structure of the official mypy configuration reference.

**Top-level key ordering** (sectioned):

1. Import discovery: ``mypy_path`` → ``files`` → ``modules`` → ``packages`` → ``exclude`` → ``exclude_gitignore`` →
   ``namespace_packages`` → ``explicit_package_bases`` → ``ignore_missing_imports`` → ``follow_untyped_imports`` →
   ``follow_imports`` → ``follow_imports_for_stubs`` → ``python_executable`` → ``no_site_packages`` →
   ``no_silence_site_packages``
2. Platform configuration: ``python_version`` → ``platform`` → ``always_true`` → ``always_false``
3. Disallow dynamic typing: ``disallow_any_unimported`` → ``disallow_any_expr`` → ``disallow_any_decorated`` →
   ``disallow_any_explicit`` → ``disallow_any_generics`` → ``disallow_subclassing_any``
4. Untyped definitions and calls: ``disallow_untyped_calls`` → ``untyped_calls_exclude`` → ``disallow_untyped_defs``
   → ``disallow_incomplete_defs`` → ``check_untyped_defs`` → ``disallow_untyped_decorators``
5. None and Optional: ``implicit_optional`` → ``strict_optional``
6. Configuring warnings: ``warn_redundant_casts`` → ``warn_unused_ignores`` → ``warn_no_return`` →
   ``warn_return_any`` → ``warn_unreachable`` → ``deprecated_calls_exclude``
7. Suppressing errors: ``ignore_errors``
8. Miscellaneous strictness: ``allow_untyped_globals`` → ``allow_redefinition`` → ``local_partial_types`` →
   ``disable_error_code`` → ``enable_error_code`` → ``extra_checks`` → ``implicit_reexport`` →
   ``strict_equality`` → ``strict_bytes`` → ``strict``
9. Configuring error messages: ``show_error_context`` → ``show_column_numbers`` → ``show_error_end`` →
   ``hide_error_codes`` → ``show_error_code_links`` → ``pretty`` → ``color_output`` → ``error_summary`` →
   ``show_absolute_path``
10. Incremental mode: ``incremental`` → ``cache_dir`` → ``sqlite_cache`` → ``cache_fine_grained`` →
    ``skip_version_check`` → ``skip_cache_mtime_checks``
11. Advanced options: ``plugins`` → ``pdb`` → ``show_traceback`` → ``raise_exceptions`` →
    ``custom_typing_module`` → ``custom_typeshed_dir`` → ``warn_incomplete_stub`` → ``native_parser``
12. Report generation: ``any_exprs_report`` → ``cobertura_xml_report`` → ``html_report`` → ``linecount_report`` →
    ``linecoverage_report`` → ``lineprecision_report`` → ``txt_report`` → ``xml_report`` → ``xslt_html_report`` →
    ``xslt_txt_report``
13. Miscellaneous: ``junit_xml`` → ``junit_format`` → ``scripts_are_modules`` → ``warn_unused_configs`` →
    ``verbosity``
14. ``overrides`` last.

**``[[tool.mypy.overrides]]`` entry key ordering:**

``module`` first (required), then per-module overridable keys in the same logical grouping as the parent table
(import behavior, platform markers, disallow dynamic typing, untyped defs/calls, optional handling, warnings,
suppression, miscellaneous strictness).

**Sorted arrays:**

- Top-level: ``files``, ``modules``, ``packages``, ``exclude``, ``always_true``, ``always_false``,
  ``untyped_calls_exclude``, ``deprecated_calls_exclude``, ``disable_error_code``, ``enable_error_code``.
- Inside overrides entries: ``module`` (when an array of patterns), ``always_true``, ``always_false``,
  ``disable_error_code``, ``enable_error_code``.

``plugins`` and ``mypy_path`` are deliberately preserved as written: plugins run in declared order and reordering
changes behavior; ``mypy_path`` is a search path with priority semantics.

**Inline-table handling:**

When ``[[tool.mypy.overrides]]`` collapses to ``overrides = [{...}, {...}]`` under the default ``table_format =
"short"``, key order inside each entry is normalized via discriminators unique to mypy
(``disable_error_code`` / ``enable_error_code`` / ``ignore_missing_imports`` / ``follow_untyped_imports`` /
``ignore_errors`` / ``warn_unused_ignores`` / ``disallow_untyped_defs`` / ``check_untyped_defs``). The arrays inside
each inline entry are sorted in place, so ``disable_error_code = [...]`` is alphabetized whether the override is
expanded or collapsed.

.. code-block:: toml

    # Before
    [[tool.mypy.overrides]]
    ignore_missing_imports = true
    disable_error_code = ["import-untyped", "attr-defined"]
    module = "third_party.*"

    # After
    [tool.mypy]
    overrides = [
      { module = "third_party.*", ignore_missing_imports = true, disable_error_code = [ "attr-defined", "import-untyped" ] },
    ]

``[tool.setuptools]`` and ``[tool.setuptools_scm]``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Covers the setuptools build backend and the version-from-SCM plugin.

**``[tool.setuptools]`` top-level key ordering** (grouped):

1. Packaging discovery: ``py-modules`` → ``packages.find.*`` / ``packages.find-namespace.*`` → ``packages`` →
   ``package-dir``
2. Package data: ``include-package-data`` → ``package-data`` → ``exclude-package-data``
3. Dynamic metadata: ``dynamic``
4. Extensions / build customization: ``ext-modules`` → ``cmdclass``
5. Distribution metadata: ``platforms`` → ``provides`` → ``obsoletes`` → ``license-files``
6. Data files: ``data-files``
7. Deprecated / obsolete (pushed last): ``script-files`` → ``namespace-packages`` → ``zip-safe`` →
   ``eager-resources`` → ``dependency-links``

**``[tool.setuptools.packages.find]`` / ``[tool.setuptools.packages.find-namespace]`` inner ordering:**

``where`` → ``include`` → ``exclude`` → ``namespaces``.

**``[tool.setuptools.package-data]`` / ``[tool.setuptools.exclude-package-data]`` / ``[tool.setuptools.data-files]``
ordering:**

The catch-all ``"*"`` pattern always goes first, then the other package patterns alphabetically. Each value (an
array of glob patterns) is sorted alphabetically.

**``[tool.setuptools.dynamic]`` ordering:**

Field names alphabetized. Inline-table directives (e.g. ``version = { attr = "pkg.__version__" }`` or
``readme = { file = "README.md", content-type = "text/markdown" }``) get their keys ordered ``attr`` → ``file`` →
``content-type``.

**Sorted arrays:**

- ``py-modules``, ``platforms``, ``provides``, ``obsoletes``, ``script-files``, ``namespace-packages``,
  ``eager-resources``: alphabetized.
- ``packages.find.include`` / ``packages.find.exclude`` / ``packages.find-namespace.*``: alphabetized.
- Values inside ``package-data`` / ``exclude-package-data`` / ``data-files`` tables: alphabetized.

Arrays whose order is meaningful are preserved as written: ``packages`` (literal list — first match wins),
``license-files`` (PEP 639 concatenation order), and everything under ``[[tool.setuptools.ext-modules]]`` (compiler
and linker argv arrays).

**``[tool.setuptools_scm]`` key ordering** (grouped):

1. Version output: ``version_file`` → ``version_file_template``
2. Version computation: ``version_scheme`` → ``local_scheme`` → ``version_cls`` → ``normalize``
3. Root discovery: ``root`` → ``relative_to`` → ``fallback_root`` → ``parent`` → ``search_parent_directories`` →
   ``dist_name``
4. Tag / parse: ``tag_regex`` → ``parse`` → ``parentdir_prefix_version`` → ``fallback_version``
5. Nested SCM-specific tables: ``scm.git.pre_parse`` → ``scm.git.describe_command``
6. Deprecated (pushed last): ``git_describe_command`` (use ``scm.git.describe_command``) → ``write_to`` (use
   ``version_file``) → ``write_to_template`` (use ``version_file_template``) → ``version_class`` (use
   ``version_cls``) → ``template``

.. code-block:: toml

    # Before
    [tool.setuptools]
    zip-safe = false
    py-modules = ["foo", "bar"]
    packages = ["my_pkg"]

    [tool.setuptools.packages.find]
    namespaces = true
    where = ["src"]
    include = ["my_pkg*"]

    [tool.setuptools.dynamic]
    readme = { content-type = "text/markdown", file = "README.md" }

    # After
    [tool.setuptools]
    py-modules = [ "bar", "foo" ]
    packages.find.where = [ "src" ]
    packages.find.include = [ "my_pkg*" ]
    packages.find.namespaces = true
    packages = [ "my_pkg" ]
    dynamic.readme = { file = "README.md", content-type = "text/markdown" }
    zip-safe = false

``[tool.pytest.ini_options]``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Covers the pytest configuration block. Keys are grouped to follow the pytest reference: pytest itself →
discovery → CLI arguments → markers/parametrize → warnings → doctest → output → logging (capture / CLI / file)
→ JUnit XML → cache and tmp_path → assertion / faulthandler.

**Sorted arrays** (set/unordered semantics):

``testpaths``, ``norecursedirs``, ``collect_ignore``, ``collect_ignore_glob``, ``python_files``,
``python_classes``, ``python_functions``, ``markers``, ``filterwarnings``, ``doctest_optionflags``,
``usefixtures``, ``required_plugins``.

``addopts`` and ``pythonpath`` are deliberately preserved as written: ``addopts`` is CLI argv (order matters)
and ``pythonpath`` is a search path with priority semantics.

.. code-block:: toml

    # Before
    [tool.pytest.ini_options]
    log_cli_level = "INFO"
    markers = [ "slow: marks tests as slow", "fast: marks tests as fast" ]
    addopts = [ "--strict-markers", "-ra" ]
    testpaths = [ "tests" ]
    minversion = "8"

    # After
    [tool.pytest]
    ini_options.minversion = "8"
    ini_options.testpaths = [ "tests" ]
    ini_options.addopts = [ "--strict-markers", "-ra" ]
    ini_options.markers = [ "fast: marks tests as fast", "slow: marks tests as slow" ]
    ini_options.log_cli_level = "INFO"

``[tool.black]``
~~~~~~~~~~~~~~~~

Black's configuration is small but ubiquitous. Keys are ordered: ``required-version`` → ``target-version`` →
``line-length`` → ``include`` / ``extend-exclude`` / ``force-exclude`` / ``exclude`` → behavior flags
(``skip-string-normalization``, ``skip-magic-trailing-comma``, ``preview``, ``unstable``,
``enable-unstable-feature``, ``fast``, ``workers``) → output (``color``, ``verbose``, ``quiet``).

**Sorted arrays:**

- ``target-version``: alphabetized so ``py39`` precedes ``py310`` etc.
- ``enable-unstable-feature``: alphabetized.

The ``include`` / ``exclude`` family are regex strings, not arrays, so they're left as-is.

``[tool.hatch.*]``
~~~~~~~~~~~~~~~~~~

Hatch configuration spans many sub-tables. Keys at ``[tool.hatch]`` level (which after collapse appear as dotted
``version.*`` / ``build.*`` / ``metadata.*`` / ``envs.*`` / ``publish.*`` / ``workspace.*``) are ordered:

1. Version: ``version.source`` → ``version.path`` → ``version.pattern`` → ``version.expression`` →
   ``version.scheme`` → ``version.validate-bump`` → ``version.fallback-version`` → ``version.raw-options``.
2. Metadata: ``metadata.allow-direct-references`` → ``metadata.allow-ambiguous-features`` → ``metadata.hooks``.
3. Build: ``build.dev-mode-dirs`` → ``build.directory`` → ``build.sources`` → ``build.packages`` →
   ``build.include`` → ``build.exclude`` → ``build.force-include`` → ``build.artifacts`` → ``build.ignore-vcs`` →
   ``build.skip-excluded-dirs`` → ``build.reproducible`` → ``build.hooks`` → wheel target (``packages``,
   ``include``, ``exclude``, ``force-include``, ``artifacts``, ``hooks``, ``shared-data``, ``extra-metadata``,
   etc.) → sdist target (``include``, ``exclude``, ``force-include``, ``support-legacy``, ``strict-naming``).
4. Publish: ``publish.index.disable`` → ``publish.index.repos`` → ``publish.index``.
5. Workspace: ``workspace.members`` → ``workspace.exclude``.
6. Environments (``envs.<name>.*``): each environment's keys follow ``type`` → ``template`` → ``detached`` →
   ``description`` → ``platforms`` → ``python`` → ``path`` → ``installer`` → ``skip-install`` →
   ``system-packages`` → ``dev-mode`` → ``features`` → ``dependencies`` → ``extra-dependencies`` →
   ``extra-args`` → ``pre-install-commands`` → ``post-install-commands`` → ``env-include`` → ``env-exclude``
   → ``env-vars`` → ``scripts`` → ``matrix`` → ``matrix-name-format`` → ``overrides``.

**Sorted arrays:**

- Build: ``include``, ``exclude``, ``force-include``, ``artifacts``, ``packages``, ``sources``, ``dev-mode-dirs``,
  and the matching ``build.targets.wheel.*`` / ``build.targets.sdist.*`` arrays.
- Environments: per-env ``dependencies``, ``extra-dependencies``, ``features``, ``platforms``, ``env-include``,
  ``env-exclude``, ``pre-install-commands``, ``post-install-commands``.
- Workspace: ``members``, ``exclude``.

``scripts`` and ``env-vars`` sub-tables under each environment have their inner keys alphabetized. Build hook
order and matrix entry order are preserved as written (both carry semantic meaning).

``[tool.isort]``
~~~~~~~~~~~~~~~~

Covers the isort import sorter. ``profile`` first (it sets defaults that everything else overrides), then output
style (line/wrap/indent/multi-line options), then known sources (``sections`` → ``default_section`` →
``known_standard_library`` / ``extra_standard_library`` / ``known_third_party`` / ``known_first_party`` /
``known_local_folder`` / ``known_other``), then forced separation, skip patterns, import add/remove, and section
heading comments.

**Sorted arrays:**

``known_standard_library``, ``extra_standard_library``, ``known_third_party``, ``known_first_party``,
``known_local_folder``, ``known_other``, ``namespace_packages``, ``src_paths``, ``skip``, ``skip_glob``,
``extend_skip``, ``extend_skip_glob``, ``supported_extensions``, ``blocked_extensions``,
``single_line_exclusions``, ``forced_separate``, ``treat_comments_as_code``, ``treat_all_comments_as_code``,
``constants``, ``variables``.

Order-sensitive arrays preserved as written: ``sections`` (output section sequence), ``no_lines_before``,
``add_imports``, ``remove_imports``, ``required_imports``, ``force_to_top``.

``[tool.pyright]`` and ``[tool.basedpyright]``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Both type checkers share the same configuration schema. Keys are ordered: platform/interpreter
(``pythonVersion`` → ``pythonPlatform`` → ``pythonPath`` → ``venv`` → ``venvPath`` → ``typeshedPath`` →
``stubPath``) → mode flags (``typeCheckingMode`` → ``strict`` → ``failOnWarnings`` →
``useLibraryCodeForTypes``) → paths (``include`` → ``exclude`` → ``ignore`` → ``extraPaths``) → strict-flavor
toggles (``strictListInference``, ``strictDictionaryInference``, ``strictSetInference``,
``strictParameterNoneValue``, ``enableExperimentalFeatures``, ``enableTypeIgnoreComments``,
``analyzeUnannotatedFunctions``, ``disableBytesTypePromotions``, ``deprecateTypingAliases``) →
``defineConstant`` → **all ``report*`` rules alphabetized** → ``executionEnvironments`` (last).

The ``report*`` rules (70+ in pyright; basedpyright adds more) are collected from the input and inserted
alphabetically rather than hardcoded, so new diagnostic rules don't require formatter changes.

**Sorted arrays:** ``include``, ``exclude``, ``ignore``, ``extraPaths``, ``strict``.

``[tool.pdm.*]``
~~~~~~~~~~~~~~~~

Covers PDM. Top-level ordering: distribution / package-type / plugins → resolution → version → build →
scripts → source → dev-dependencies → publish → options.

**Sub-table ordering** (collapsed to dotted keys):

- ``version``: ``source`` → ``path`` → ``getter`` → ``write_to`` → ``write_template`` → ``tag_regex`` →
  ``tag_filter`` → ``fallback_version`` → ``version_format``.
- ``build``: ``includes`` → ``excludes`` → ``source-includes`` → ``package-dir`` → ``is-purelib`` →
  ``run-setuptools`` → ``custom-hook`` → ``editable-backend``.
- ``[[tool.pdm.source]]`` (AoT, preserve array order): per-entry ``name`` → ``url`` → ``type`` →
  ``verify_ssl`` → ``include_packages`` → ``exclude_packages``.

**Sorted arrays:** ``plugins``, ``build.includes``, ``build.excludes``, ``build.source-includes``,
``resolution.excludes``, every ``dev-dependencies.<group>`` value array, and ``include_packages`` /
``exclude_packages`` inside source entries.

``[tool.cibuildwheel]``
~~~~~~~~~~~~~~~~~~~~~~~

Covers cibuildwheel. Top-level ordering: selection (``build``, ``skip``, ``test-skip``, ``archs``, ``enable``,
``free-threaded-support``) → build configuration (``build-frontend``, ``build-verbosity``, ``config-settings``,
``dependency-versions``, ``environment``, ``environment-pass``) → build phases (``before-all``, ``before-build``,
``repair-wheel-command``) → test phases (``before-test``, ``test-command``, ``test-requires``, ``test-extras``,
``test-groups``, ``test-sources``) → platform images (``manylinux-*-image``, ``musllinux-*-image``) →
``container-engine`` → per-platform sub-tables (``linux``, ``macos``, ``windows``, ``android``, ``ios``,
``pyodide``) → ``overrides`` last.

Per-platform sub-tables follow the same inner ordering. ``[[tool.cibuildwheel.overrides]]`` entries place
``select`` first (required), then the regular cibuildwheel keys; the array order itself is preserved (later
overrides win).

**Sorted arrays:** ``enable``, ``test-extras``, ``test-groups``.

Most other array-valued keys (``test-requires``, ``before-all``, ``test-command``, the various ``environment*``
fields) are CLI argv or ordered lists and are preserved as written.

``[tool.tox]``
~~~~~~~~~~~~~~

Reuses the rules from ``tox-toml-fmt`` so a ``[tool.tox]`` block in ``pyproject.toml`` is formatted identically to a
standalone ``tox.toml``: alias normalization (``envlist`` → ``env_list``, ``setenv`` → ``set_env``, etc.),
canonical key ordering for the root table and every env table, PEP 508 requirement normalization and sorting in
``deps`` and ``constraints``, sorted ``pass_env`` (inline-table entries first), version-aware ``env_list`` sorting
(``py313`` before ``py312`` before ``py311``), and inline-table reordering for ``replace``, ``prefix``,
``product``, and ``value`` directives.

See the ``tox-toml-fmt`` documentation for the full schema and per-key behavior; the only difference here is the
namespace (``tool.tox`` instead of the root table).

``[tool.bandit]``
~~~~~~~~~~~~~~~~~

Top-level ordering: ``exclude_dirs`` → ``targets`` → ``tests`` → ``skips`` → per-plugin sub-tables
(``assert_used``, ``hardcoded_tmp_directory``, etc.).

All array values alphabetize (rule IDs, directory paths, function-name lists — all set semantics).

``[tool.maturin]``
~~~~~~~~~~~~~~~~~~

Maturin builds Rust extensions for Python. Top-level ordering: module identity (``module-name``, ``bindings``,
``python-source``, ``python-packages``, ``python-bin-path``) → source layout (``src``, ``manifest-path``,
``include``, ``exclude``, ``sdist-include``, ``sdist-generator``, ``data``) → cargo settings (``features``,
``no-default-features``, ``all-features``, ``cargo-extra-args``, ``rustc-extra-args``, ``config``, ``profile``,
``target``, ``target-dir``) → compatibility / strip (``compatibility``, ``auditwheel``, ``skip-auditwheel``,
``strip``, ``frozen``, ``locked``, ``offline``, ``zig``) → behavior (``use-cross``).

**Sorted arrays:** ``python-packages``, ``include``, ``exclude``, ``sdist-include``, ``features`` (all
set-semantics). ``cargo-extra-args`` / ``rustc-extra-args`` are CLI argv and preserved.

``[tool.codespell]``
~~~~~~~~~~~~~~~~~~~~

Top-level ordering: dictionaries (``builtin``, ``dictionary``, ``ignore-words``, ``ignore-words-list``,
``ignore-regex``, ``ignore-multiline-regex``, ``exclude-file``) → scope (``skip``, ``uri-ignore-words-list``,
``check-filenames``, ``check-hidden``, ``hidden``, ``regex``, ``user-input``) → fix behavior (``write-changes``,
``interactive``, ``enable-colors``, ``disable-colors``) → output (``count``, ``quiet-level``, ``summary``).

**Sorted arrays:** ``builtin``, ``dictionary``, ``skip``, ``ignore-words-list``, ``uri-ignore-words-list``.

``[tool.towncrier]``
~~~~~~~~~~~~~~~~~~~~

Top-level ordering: package identity (``name``, ``version``, ``package``, ``package_dir``) → news location
(``directory``, ``filename``, ``start_string``, ``template``, ``title_format``, ``issue_format``, ``underlines``)
→ rendering (``wrap``, ``all_bullets``, ``single_file``, ``orphan_prefix``, ``create_eof_newline``,
``create_add_extension``) → behavior (``ignore``) → ``type`` and ``section`` (AoT, last).

``[[tool.towncrier.type]]`` entries get keys ordered ``directory`` → ``name`` → ``showcontent``;
``[[tool.towncrier.section]]`` entries get ``path`` → ``name`` → ``showcontent``. Array order is preserved
(display order in the rendered changelog).

**Sorted arrays:** ``ignore`` (file globs to skip).

``[tool.pylint.*]``
~~~~~~~~~~~~~~~~~~~

Sub-table order: ``main`` (and legacy alias ``master``) → ``messages_control`` → ``reports`` → ``basic`` →
``format`` → ``design`` → ``classes`` → ``exceptions`` → ``imports`` → ``logging`` → ``method_args`` →
``refactoring`` → ``similarities`` → ``spelling`` → ``string`` → ``typecheck`` → ``variables`` →
``miscellaneous``.

**Sorted arrays:** ``enable``, ``disable``, ``load-plugins``, ``extension-pkg-allow-list``,
``extension-pkg-whitelist``, ``ignore``, ``ignore-patterns``, ``ignore-paths``, ``ignored-modules``,
``ignored-classes``, ``ignored-argument-names``, ``good-names``, ``bad-names``, ``logging-modules``,
``valid-classmethod-first-arg``, ``valid-metaclass-classmethod-first-arg``, ``callbacks``,
``additional-builtins``, ``allowed-redefined-builtins``, ``preferred-modules``, ``deprecated-modules``,
``known-third-party``, ``known-standard-library``, ``allowed-modules``, ``expected-line-ending-format``,
``overgeneral-exceptions``, ``defining-attr-methods``, ``exclude-protected``. Match is on the leaf key name
regardless of which sub-table it appears in.

``[tool.djlint]``
~~~~~~~~~~~~~~~~~

Profile/scope → formatting → linting → ignores → output. **Sorted arrays:** ``exclude``, ``extend_exclude``,
``custom_blocks``, ``custom_html``, ``ignore``, ``ignore_blocks``.

``[tool.yapf]``
~~~~~~~~~~~~~~~

Single flat table. ``based_on_style`` first (it sets defaults), then ``column_limit``, ``indent_width``,
``continuation_indent_width``, then the rest alphabetized.

``[tool.check-manifest]``
~~~~~~~~~~~~~~~~~~~~~~~~~

``ignore`` → ``ignore-bad-ideas`` → ``ignore-default-rules``. Both ``ignore`` and ``ignore-bad-ideas`` (file-glob
lists) alphabetize.

``[tool.pyrefly]``
~~~~~~~~~~~~~~~~~~

Meta's type checker. Order: ``python_version`` → ``python_platform`` → ``python_interpreter`` →
``project_includes`` → ``project_excludes`` → ``search_path`` → ``site_package_path`` →
``use_untyped_imports`` → ``replace_imports_with_any`` → ``ignore_errors_in_generated_code`` → ``errors``.
Path arrays alphabetize.

``[tool.semantic_release]``
~~~~~~~~~~~~~~~~~~~~~~~~~~~

python-semantic-release. Order: tag/version → assets → version source → repo → commit parser → branches →
publish → changelog → remote. Sorted arrays: ``version_variables``, ``version_toml``, ``assets``,
``exclude_commit_patterns``.

``[tool.scikit-build]``
~~~~~~~~~~~~~~~~~~~~~~~

scikit-build-core (CMake builds for Python). Top-level order: meta keys (``minimum-version``, ``build-dir``,
``fail``, ``experimental``, ``strict-config``) → ``build`` → ``cmake`` → ``ninja`` → ``sdist`` → ``wheel`` →
``install`` → ``editable`` → ``logging`` / ``messages`` → ``metadata`` → ``search`` → ``generate`` AoT →
``overrides`` AoT.

**Sorted arrays:** ``include``, ``exclude``, ``packages``, ``files``, ``targets``, ``components``,
``exclude-fields``. ``args`` and ``define`` (CLI argv for cmake/ninja) are preserved as written.

``[tool.bumpversion]``
~~~~~~~~~~~~~~~~~~~~~~

bump-my-version / legacy bumpversion. Order: identity (``current_version``) → format (``parse``, ``serialize``,
``search``, ``replace``, ``regex``, ``ignore_missing_*``) → tag (``tag``, ``sign_tags``, ``tag_name``,
``tag_message``) → commit (``allow_dirty``, ``commit``, ``commit_args``, ``message``, ``moveable_tags``) →
behavior → ``files`` / ``parts`` AoT last.

``[tool.interrogate]``
~~~~~~~~~~~~~~~~~~~~~~

Docstring coverage. Threshold → ignore flags → exclude → output. Sorted arrays: ``exclude``, ``extend-exclude``,
``ignore-regex``.

``[tool.docformatter]``
~~~~~~~~~~~~~~~~~~~~~~~

Docstring formatter. Order: behavior (``in-place``, ``recursive``, ``check``, ``diff``, ``black``, ``pep257``,
``non-strict``) → format width (``line-length``, ``wrap-summaries``, ``wrap-descriptions``, ``tab-width``) →
wrap/summary tweaks → other.

``[tool.vulture]``
~~~~~~~~~~~~~~~~~~

Dead-code finder. Order: paths → ignore (``exclude``, ``ignore_names``, ``ignore_decorators``) → behavior
(``make_whitelist``, ``min_confidence``, ``sort_by_size``) → output (``verbose``). Sorted arrays: ``paths``,
``exclude``, ``ignore_names``, ``ignore_decorators``.

``[tool.autopep8]``
~~~~~~~~~~~~~~~~~~~

PEP8 auto-fixer. Order: length/indent → mode (``in-place``, ``recursive``, ``diff``, ``list-fixes``) → rules
(``ignore``, ``select``, ``exclude``) → behavior. Sorted arrays: ``ignore``, ``select``, ``exclude``.

``[tool.deptry]``
~~~~~~~~~~~~~~~~~

Dependency checker. Order: scope/exclude → ignore rules → per-rule ignores → behavior → mapping. Sorted arrays
cover all the ``ignore_*`` / ``exclude`` / ``requirements_files`` / ``pep621_dev_dependency_groups`` /
``known_first_party`` lists.

``[tool.ty]``
~~~~~~~~~~~~~

Astral's type checker. Order: ``src`` → ``respect-ignore-files`` → ``environment`` → ``rules`` → ``terminal``
→ ``overrides`` last. ``src`` array alphabetizes. Schema is still pre-1.0; unknown keys alphabetize after the
canonical set.

Other Tables
~~~~~~~~~~~~

Any unrecognized tables are preserved and reordered according to standard table ordering rules. Keys within unknown
tables are not reordered or normalized.
