Command-line interfaces have an unusual usability constraint: when something goes wrong, the user is often staring at a terminal with no other interface to guide them.

That makes small details matter. A typo in a subcommand should ideally produce a useful correction. Help output should be easy to scan interactively without becoming noisy when captured by scripts or logs.

Python 3.14 adds two argparse.ArgumentParser options aimed directly at those details: suggest_on_error and color.

Neither changes how arguments fundamentally parse. They change how the parser communicates with people. That sounds cosmetic, but for developer tools, deployment utilities, administrative commands, and internal automation, error quality is part of the interface contract.

In this article I’ll build a small CLI around both features, then look at the operational details that are easy to miss.

Start with a small command-line application

Suppose I have a deployment utility with two subcommands:

import argparse


def build_parser() -> argparse.ArgumentParser:
    parser = argparse.ArgumentParser(
        prog="ship",
        description="Deploy and inspect application releases.",
    )

    subparsers = parser.add_subparsers(dest="command", required=True)

    deploy = subparsers.add_parser("deploy")
    deploy.add_argument(
        "--environment",
        choices=["development", "staging", "production"],
        required=True,
    )

    status = subparsers.add_parser("status")
    status.add_argument("--environment")

    return parser

This is already a reasonable interface. argparse generates usage text, validates the choices, and rejects unknown subcommands.

But consider a user typing this:

ship deploy --environment prodution

The parser knows that production is valid, but historically its main job was to report that the supplied value was not among the allowed choices. Python 3.14 can go one step further.

Enable suggestions for close mistakes

Set suggest_on_error=True when constructing the parser:

parser = argparse.ArgumentParser(
    prog="ship",
    description="Deploy and inspect application releases.",
    suggest_on_error=True,
)

Now argparse can suggest a close match for a mistyped string choice. The same mechanism also applies to subparser names.

For example, a user who types a near miss such as:

ship deploi --environment staging

can receive a suggestion pointing toward deploy rather than only a generic invalid-choice message.

This is especially useful when a CLI has commands that users invoke occasionally. People may remember the concept of a command without remembering its exact spelling.

Suggestions are not fuzzy parsing

I would not treat this feature as permission to silently accept misspellings.

A suggestion is diagnostic output. The invalid input still fails. That distinction is important because command names and option values often represent operational intent.

Imagine these environments:

choices=["production", "production-readonly"]

Automatically converting approximate input would be dangerous. Reporting a likely correction is much safer because the user still has to issue a valid command explicitly.

This is a useful design principle beyond argparse: error recovery can be helpful without weakening validation.

Suggestions apply to string choices

The feature is specifically useful for string choices and subparser names. Do not design around it as a general-purpose correction engine for every argument type.

For example:

parser.add_argument(
    "--replicas",
    type=int,
    choices=[1, 2, 3, 4],
)

The numeric domain is still validated, but typo suggestions are not the interesting behavior here.

If a value has complicated parsing rules, I prefer to parse and validate it explicitly after argument parsing rather than trying to make choices represent a domain it does not model well.

Color is enabled by default in Python 3.14

Python 3.14 also adds the color parameter to ArgumentParser. Its default is True.

That means help output can use ANSI color when the environment and terminal capabilities allow it:

parser = argparse.ArgumentParser(
    prog="ship",
    color=True,
)

For interactive use, color can make generated help easier to scan. Users can distinguish structural parts of the output more quickly without the application having to maintain a custom help formatter just for styling.

The important point is that color=True means color is allowed, not that every destination will necessarily receive colored output. Environment settings and terminal capabilities participate in the decision.

Know when to force plain output

There are places where I want deterministic plain text regardless of terminal behavior.

Tests are one example:

parser = argparse.ArgumentParser(
    prog="ship",
    color=False,
)

Generated documentation is another. If I capture --help and insert it into Markdown, ANSI escape sequences are unwanted data.

The same is true for systems that parse help or error text, although parsing human-facing CLI output is usually a brittle integration strategy in the first place.

If a machine needs data from a CLI, I would rather expose a stable format such as JSON than make color removal part of the protocol.

Redirected stderr deserves attention

One subtle operational detail is error output.

Python’s documentation notes that color codes can appear in error messages redirected to a file. That matters for shell scripts such as:

ship deploy --environment prodution 2>ship-error.log

A log file containing ANSI escape sequences may display poorly in editors, log processors, CI interfaces, or alert payloads.

If plain redirected output matters, control color deliberately. Python recognizes environment-level controls including NO_COLOR and PYTHON_COLORS.

For example:

NO_COLOR=1 ship deploy --environment prodution 2>ship-error.log

At the application level, color=False is stronger: it disables colored output even if an environment variable such as FORCE_COLOR asks for it.

That makes the constructor option appropriate when the application itself owns the policy.

Separate interactive UX from machine contracts

A robust CLI often serves two audiences:

  • people typing commands in terminals;
  • automation invoking commands from scripts or CI jobs.

The first audience benefits from suggestions and readable help. The second audience benefits from stable exit codes and structured output.

I keep those concerns separate:

import argparse
import json


def main() -> int:
    parser = build_parser()
    parser.add_argument(
        "--output",
        choices=["text", "json"],
        default="text",
    )
    args = parser.parse_args()

    result = {"command": args.command, "ok": True}

    if args.output == "json":
        print(json.dumps(result))
    else:
        print("Command completed successfully")

    return 0

Colorized help is not a substitute for structured machine output. Suggestions are not a substitute for stable error semantics.

They improve the human layer while the programmatic layer remains explicit.

Be deliberate about allow_abbrev

ArgumentParser has another convenience feature that is easy to confuse with suggestions: long-option abbreviation.

With the default allow_abbrev=True, an unambiguous prefix of a long option may be accepted. For a small personal tool that can be convenient. For a long-lived automation interface, I often disable it:

parser = argparse.ArgumentParser(
    prog="ship",
    allow_abbrev=False,
    suggest_on_error=True,
)

Why combine strict option spelling with suggestions?

Because they solve different problems. Strict spelling keeps accepted commands predictable. Suggestions make rejected commands easier to fix.

That is a good combination for interfaces used by both humans and scripts.

Compatibility with Python before 3.14

Passing suggest_on_error to the constructor requires Python 3.14 or newer.

If an application still supports older Python versions, the Python documentation recommends an opportunistic pattern for suggestions:

parser = argparse.ArgumentParser(prog="ship")
parser.suggest_on_error = True

Older ArgumentParser implementations can tolerate an ordinary attribute assignment even though they do not implement the new suggestion behavior.

I would still make the supported-version policy explicit. Compatibility tricks should not hide which interpreter versions a project actually tests.

The color constructor parameter is also new in 3.14, so code that passes it directly should have a corresponding minimum-version requirement or a compatibility branch.

For example:

import argparse
import sys

kwargs = {"prog": "ship"}

if sys.version_info >= (3, 14):
    kwargs["color"] = True
    kwargs["suggest_on_error"] = True

parser = argparse.ArgumentParser(**kwargs)

If the project already requires Python 3.14, I would avoid this branch and use the new API directly.

Test behavior, not terminal decoration

CLI tests can become fragile when they assert entire generated help screens byte for byte.

I prefer focused assertions around behavior:

import pytest


def test_invalid_environment_fails(capsys):
    parser = build_parser()

    with pytest.raises(SystemExit) as exc:
        parser.parse_args([
            "deploy",
            "--environment",
            "prodution",
        ])

    assert exc.value.code == 2
    captured = capsys.readouterr()
    assert "prodution" in captured.err

For Python 3.14-specific tests, I can separately verify that suggestion mode gives useful guidance for a known near match.

When testing help snapshots, I disable color so escape sequences do not make snapshots depend on terminal detection:

parser = argparse.ArgumentParser(prog="ship", color=False)

That gives the test a deterministic presentation policy instead of hoping the test runner happens to look like a non-color terminal.

Keep errors useful even without color

Color should enhance hierarchy, not carry meaning by itself.

A user may disable color, redirect output, use a terminal with limited capabilities, or consume logs through a system that strips ANSI codes.

So error messages should remain understandable as plain text. The same accessibility principle applies to any terminal styling library: never encode the only distinction between success and failure as a visual style.

Exit status remains the machine-readable signal. Words and structure remain the human-readable signal. Color is an enhancement.

Do not turn suggestions into an API dependency

There is another testing trap: asserting the exact wording of a suggestion.

Diagnostic text can evolve between Python versions. If an external program needs to know why parsing failed, scraping a phrase such as maybe you meant is the wrong boundary.

For subprocess callers, rely on documented command behavior and exit status. If callers need richer failure information, design a structured mode under your control.

Human-friendly diagnostics are allowed to improve over time.

A practical parser configuration

For a Python 3.14-only internal operations tool, I would start with something like this:

import argparse


def build_parser() -> argparse.ArgumentParser:
    parser = argparse.ArgumentParser(
        prog="ship",
        description="Deploy and inspect application releases.",
        allow_abbrev=False,
        suggest_on_error=True,
        color=True,
    )

    subparsers = parser.add_subparsers(
        dest="command",
        required=True,
    )

    deploy = subparsers.add_parser("deploy")
    deploy.add_argument(
        "--environment",
        required=True,
        choices=["development", "staging", "production"],
    )

    status = subparsers.add_parser("status")
    status.add_argument(
        "--environment",
        choices=["development", "staging", "production"],
    )

    return parser

The choices are explicit. Misspellings remain errors. Close string mistakes can receive suggestions. Long options are not silently abbreviated. Interactive help can use color when appropriate.

That is a small amount of configuration for a noticeably more intentional interface.

Think of CLI diagnostics as product behavior

It is tempting to treat generated usage and parser errors as incidental text. I think that is a mistake for tools people use repeatedly.

A good CLI should answer three questions quickly when input is wrong:

  1. What did I provide?
  2. Why was it rejected?
  3. What should I try instead?

argparse already handled the first two reasonably well. suggest_on_error improves the third for common string mistakes.

Color addresses a different part of the experience: helping a person scan generated information. Because Python 3.14 integrates that behavior into ArgumentParser, simple applications can get it without adopting a separate CLI framework solely for presentation.

Final guidance

I would enable suggest_on_error for CLIs with string choices or subcommands unless there is a specific reason not to. It preserves strict parsing while making ordinary typos cheaper to recover from.

I would leave color available for interactive tools, but explicitly disable it anywhere output must be deterministic plain text. Pay particular attention to redirected errors, CI logs, generated documentation, and snapshot tests.

Most importantly, keep human convenience separate from machine contracts. Suggestions and color should improve the terminal experience without changing which commands are valid, what exit statuses mean, or how automation receives structured data.

Python 3.14’s additions are small APIs, but they encourage a useful mindset: argument parsing is not finished when input has merely been accepted or rejected. The quality of the explanation is part of the command-line interface too.