Skip to content

feat: add opt-in case- and hyphen-insensitive CLI option matching - #36

Merged
bhirsz merged 1 commit into
mainfrom
feat/lenient-cli-names
Aug 31, 2026
Merged

feat: add opt-in case- and hyphen-insensitive CLI option matching#36
bhirsz merged 1 commit into
mainfrom
feat/lenient-cli-names

Conversation

@bhirsz

@bhirsz bhirsz commented Aug 31, 2026

Copy link
Copy Markdown
Member

Summary

Adds two opt-in, per-class attributes that relax long-option matching on the
command line
:

  • cli_case_insensitive--VariableFile resolves to --variablefile
  • cli_ignore_hyphens--variable-file resolves to --variablefile

Both default to off, so existing behaviour is unchanged unless a tool opts
in. With both enabled, --variablefile, --variable-file, --VariableFile and
--VARIABLE-FILE all resolve to the same option, and a flag can be negated as
--no-statusrc, --nostatusrc or --No-StatusRc.

Configuration files stay exact

Leniency applies to the command line only. A [tool.<tool>] table must use
the option's declared name; its underscore/hyphen variants remain interchangeable
(pre-existing behaviour), but case is significant and arbitrary hyphenation is
not accepted. This keeps config files unambiguous and diff-friendly.

How it works

  • A normalised fallback map (long_normalized_to_attr) is built next to the
    exact long_to_attr map. Lookups try the exact name first, then the
    normalised fallback when leniency is enabled (NameTable.long_attr).
  • Normalisation lower-cases (when cli_case_insensitive) and strips hyphens
    (when cli_ignore_hyphens).
  • Flag negation understands both the canonical --no-<name> form (with lenient
    base resolution) and, when hyphens are ignorable, the joined --no<name> form.
  • If two options collide once normalised (e.g. --foo-bar vs --foobar), the
    shared fallback is dropped — both still work through their exact spellings.

Why

Requested for the Robot Framework CLI migration
(robotframework/robotframework#5773),
whose legacy parser accepted case- and hyphen-insensitive long options. Making
this a confargs feature (rather than pre-processing argv on the tool side) keeps
the tool integration thin and lets other tools opt in too.

Changes

  • src/confargs/base.py — new cli_case_insensitive / cli_ignore_hyphens
    class attributes (documented).
  • src/confargs/options.pyNameTable gains the normalised fallback map and
    long_attr / normalize_bare helpers; resolve_names builds the fallback.
  • src/confargs/cli.py — long-option and negation resolution use lenient lookup.
  • src/confargs/processor.py — passes the class toggles into resolve_names;
    eager scanning uses lenient lookup.
  • tests/test_lenient_names.py — 17 new tests (spellings, negation forms,
    opt-in-only, single-toggle behaviour, normalised-collision fallback, config
    exactness, end-to-end).
  • README.md / CHANGELOG.md — documented under "Options in depth" and an
    [Unreleased] Features entry.

Validation

uv run ruff check ., uv run ruff format --check ., uv run mypy and
uv run pytest -q (308 tests) all pass.

@bhirsz
bhirsz force-pushed the feat/lenient-cli-names branch from 464dabf to e3b6296 Compare August 31, 2026 11:47
Add two per-class attributes, `cli_case_insensitive` and `cli_ignore_hyphens`
(both default off), that relax long-option matching on the command line so
`--variable-file`, `--variablefile` and `--VariableFile` can all resolve to the
same option, and flags negate as `--no-statusrc`, `--nostatusrc` or
`--No-StatusRc`.

Matching is lenient on the command line only: configuration-file keys stay
exact (their underscore/hyphen variants remain interchangeable, but case is
significant). A normalised fallback name map is built alongside the exact map;
options whose names collide once normalised keep working through their exact
spelling and are dropped from the fallback.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@bhirsz
bhirsz force-pushed the feat/lenient-cli-names branch from e3b6296 to 49b0270 Compare August 31, 2026 11:50
@bhirsz
bhirsz merged commit 8b318ec into main Aug 31, 2026
8 checks passed
@bhirsz
bhirsz deleted the feat/lenient-cli-names branch August 31, 2026 11:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant