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

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions