Configuration ============= Configuration via file ---------------------- 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. Command line interface ---------------------- .. sphinx_argparse_cli:: :module: pyproject_fmt.__main__ :func: _build_our_cli :prog: pyproject-fmt :title: 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.