Skip to content

test: test_invalid_command[py_3.14-invalidCommand] fails on Python 3.14.5 due to argparse quoting change #1990

@bearomorphism

Description

@bearomorphism

Description

The tests/test_cli.py::test_invalid_command[py_3.14-invalidCommand] test started failing on Python 3.14.5 (released May 10, 2026) because CPython restored quoting of choices in argparse error messages:

gh-130750: Restore quoting of choices in argparse error messages for improved clarity and consistency with documentation.
-- 3.14.5 changelog

Python argparse "invalid choice" format
3.10, 3.11 (choose from 'init', 'commit', ...) (quoted)
3.12 mixed
3.13, 3.14.0–3.14.4 (choose from init, commit, ...) (unquoted)
3.14.5+ (choose from 'init', 'commit', ...) (quoted, restored)

The checked-in fixture tests/test_cli/test_invalid_command_py_3_14_invalidCommand_.txt was generated against 3.14.4 (unquoted), so it no longer matches.

Reproduction

uv run pytest tests/test_cli.py::test_invalid_command

Master's last successful CI run was on 2026-05-09 (commit 1eb8cde6) when the GitHub-hosted runner still had Python 3.14.4; runs on or after 2026-05-11 fail with the diff below.

Observed failure

FAILED tests/test_cli.py::test_invalid_command[py_3.14-invalidCommand] - AssertionError: FILES DIFFER
-cz: error: argument {...}: invalid choice: 'invalidCommand' (choose from init, commit, ...)
+cz: error: argument {...}: invalid choice: 'invalidCommand' (choose from 'init', 'commit', ...)

Full log: https://github.com/commitizen-tools/commitizen/actions/runs/25649120897/job/75283769681

Scope

Only the 1 test_invalid_command_py_3_14_invalidCommand_.txt fixture is affected by gh-130750 (the companion --invalid-arg case uses the metavar, not the choice list). The other 60+ Python-version-keyed fixtures (test_command_shows_description_when_use_help_option_py_3_*_*.txt, test_no_argv_py_3_*_.txt) capture argparse help text, which is unaffected by this change.

Suggested fix (short-term)

Skip the affected test_invalid_command parametrization on Python ≥ 3.14.5 until upstream stabilizes:

@pytest.mark.parametrize(
    "arg",
    [
        "--invalid-arg",
        pytest.param(
            "invalidCommand",
            marks=pytest.mark.skipif(
                (3, 14, 5) <= sys.version_info < (3, 15),
                reason=(
                    "argparse error format changed in Python 3.14.5 (gh-130750); "
                    "fixture matches 3.14.0-4 unquoted format"
                ),
            ),
        ),
    ],
)

Surfaced while working on #1846; this skip unblocks CI without changing PR scope. Implemented in #1991.

Future enhancement (still open after #1991)

Argparse error output has churned across Python patch releases (3.10/3.11 quoted → 3.13/3.14.0–4 unquoted → 3.14.5 quoted). A more durable approach worth considering once the codebase is more stable:

Normalize argparse error output before file_regression.check() — e.g., strip surrounding quotes around choose from items, or replace the variable parts with placeholders:

def _normalize_argparse_error(text: str) -> str:
    # Collapse "'init', 'commit'" and "init, commit" to a single canonical form
    text = re.sub(
        r"\(choose from [^)]+\)",
        "(choose from <CHOICES>)",
        text,
    )
    return text

# Usage:
file_regression.check(_normalize_argparse_error(err), extension=".txt")

That would let us delete the per-Python-version fixtures for test_invalid_command[invalidCommand] and stop chasing argparse formatting changes. #1991 only implements the short-term skip; this enhancement is still open.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions