Skip to content

[CLI] Make --format / --json / -q global#4162

Merged
Wauplin merged 10 commits intomainfrom
cli-global-formatting-options
Apr 30, 2026
Merged

[CLI] Make --format / --json / -q global#4162
Wauplin merged 10 commits intomainfrom
cli-global-formatting-options

Conversation

@Wauplin
Copy link
Copy Markdown
Contributor

@Wauplin Wauplin commented Apr 28, 2026

Context: let's handle --format globally

Benefits are:

  • End users: formatting options are now first-class and properly documented in --help (one consistent section per command), instead of being mixed into the regular options or only mentioned in some commands.
  • Maintainers: no need to remember to add format: FormatWithAutoOpt = OutputFormatWithAuto.auto (and the matching imports) when adding a new command. The flags work automatically.

Summary

  • Handle --format <value>, --json, and -q / --quiet globally in HFCliTyperGroup instead of declaring them on every command. The flags can appear anywhere in a leaf command's args; they're stripped and applied to the out singleton before click parses the rest.
  • Document them in a dedicated Formatting options section in every --help page (root, groups, and leaves).
  • Removed format: FormatWithAutoOpt = OutputFormatWithAuto.auto from every command (~85 occurrences across 17 files).
  • Legacy commands that own their own --format (hf jobs ps, hf jobs scheduled ps) keep working — the previous --json / --quiet shorthand-rewrite behaviour is preserved for them. Pass-through commands (hf extensions exec) remain untouched.
  • Added a short Output formatting section to the CLI guide.

Examples

# --format / --json / -q now appear in every command's --help
$ hf models ls --help
...
Formatting options:
  --format [auto|human|agent|json|quiet]
                                  Output format. Defaults to 'auto' which
                                  picks 'agent' or 'human' based on the
                                  terminal.
  -q, --quiet                     Quiet output (one ID per line). Equivalent
                                  to '--format quiet'.
  --json                          JSON output. Equivalent to '--format json'.

# Works on any command — no per-command opt-in needed
$ hf collections ls --owner nvidia --limit 2 -q
nvidia/nemotron-supervised-fine-tuning-69eab9824c9120a3a3b1e25e
nvidia/nvidia-nemotron-v3-69388dda16167bb1607171ea

# Mutually exclusive
$ hf models ls --json --format table
Error: '--json' and '--format' are mutually exclusive.

# Legacy command with its own --format keeps working
$ hf jobs ps --format '{{.id}} {{.status}}'

Note

Medium Risk
Touches CLI argument parsing and help rendering globally, so regressions could affect many commands’ option handling; changes include explicit compatibility paths for legacy/pass-through commands to reduce risk.

Overview
Makes --format, --json, and -q/--quiet global formatting flags by consuming them during command resolution and applying the chosen mode to the shared out singleton, so leaf commands no longer need to declare FormatWithAutoOpt (while pass-through commands remain untouched).

Updates help generation to add a consistent “Formatting options” section to command --help output, preserves backward compatibility for legacy commands that own their own formatting options by rewriting shorthands, and switches a few commands (e.g. hf buckets sync) to read quiet-mode from out instead of a local flag. Documentation is updated to explain the new behavior, and the generated CLI reference is refreshed accordingly.

Reviewed by Cursor Bugbot for commit e44a4c6. Bugbot is set up for automated code reviews on this repo. Configure here.

Move handling of --format, --json and -q/--quiet out of every command's
signature into a single pre-processor in HFCliTyperGroup that consumes
them from any leaf command's args and applies them to the `out`
singleton. Document them in a dedicated "Formatting options" section
shown on every --help page.

Legacy commands that own their own --format (hf jobs ps, scheduled ps)
keep working: their shorthand rewrites are preserved. Pass-through
commands (hf extensions exec) are left untouched.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
Comment thread src/huggingface_hub/cli/_cli_utils.py Outdated
@Wauplin Wauplin marked this pull request as draft April 28, 2026 13:48
@bot-ci-comment
Copy link
Copy Markdown

The docs for this PR live here. All of your documentation changes will be reflected on that endpoint. The docs are available until 30 days after the last update.

@Wauplin Wauplin marked this pull request as ready for review April 28, 2026 14:00
@Wauplin Wauplin requested a review from hanouticelina April 28, 2026 14:00
Copy link
Copy Markdown
Contributor

@hanouticelina hanouticelina left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

very nice improvement!

Comment thread src/huggingface_hub/cli/_cli_utils.py Outdated
Comment on lines +194 to +200
def format_options(self, ctx: click.Context, formatter: click.HelpFormatter) -> None:
# MultiCommand.format_options writes regular options + the commands list. We
# insert the "Formatting options" section in between so it sits with the
# other options instead of below the subcommand list.
click.Command.format_options(self, ctx, formatter)
_format_formatting_options_section(formatter)
self.format_commands(ctx, formatter)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no strong opinion but I think it would be better to have:
hf --help -> no "Formatting options" section
hf models --help -> no section either
hf models ls --help -> shows the Fromatting section (where the flags actually work)

Suggested change
def format_options(self, ctx: click.Context, formatter: click.HelpFormatter) -> None:
# MultiCommand.format_options writes regular options + the commands list. We
# insert the "Formatting options" section in between so it sits with the
# other options instead of below the subcommand list.
click.Command.format_options(self, ctx, formatter)
_format_formatting_options_section(formatter)
self.format_commands(ctx, formatter)

Comment thread src/huggingface_hub/cli/_cli_utils.py
Comment thread src/huggingface_hub/cli/_cli_utils.py
Comment thread src/huggingface_hub/cli/_cli_utils.py Outdated
Wauplin and others added 2 commits April 29, 2026 17:40
Remove the section from group help pages (hf --help, hf models --help)
since the flags only apply to leaf commands.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Resolve conflicts: take new file-listing features from main (human_readable,
tree, recursive, revision params + list_repo_files_cmd) but drop local
format parameters in favor of global --format handling.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Copy link
Copy Markdown
Contributor

@hanouticelina hanouticelina left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

Comment thread src/huggingface_hub/cli/_cli_utils.py Outdated
Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit e44a4c6. Configure here.

mode = OutputFormatWithAuto.agent if is_agent() else OutputFormatWithAuto.human
self.mode = mode
if mode != OutputFormatWithAuto.human:
disable_progress_bars()
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Global flags always call set_mode(auto) disabling progress bars early

Medium Severity

Moving disable_progress_bars() into Output.set_mode() causes progress bars to be disabled at module import time for agent environments, since out = Output() is a module-level singleton that calls set_mode() in __init__. More critically, _consume_format_flags_for_leaf unconditionally calls out.set_mode(chosen_mode) even when no formatting flags are provided (chosen_mode defaults to auto). When auto resolves to agent, this disables progress bars for every leaf command invocation in agent mode — even commands where the old code would have left progress bars enabled because they never declared FormatWithAutoOpt. Previously, disable_progress_bars() was only called when a command explicitly declared and received the format parameter via the _set_output_mode callback.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit e44a4c6. Configure here.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that's fine now that (almost?) all commands have been migrated

@Wauplin Wauplin merged commit 6e89ade into main Apr 30, 2026
20 of 21 checks passed
@Wauplin Wauplin deleted the cli-global-formatting-options branch April 30, 2026 09:05
davanstrien added a commit that referenced this pull request Apr 30, 2026
- Rename `secrets set` / `variables set` to `add` (mirrors add_space_secret/
  add_space_variable, signals upsert vs volumes set's replace).
- Add confirm + `-y/--yes` to `variables delete` for parity with
  `secrets delete`. Kept the warning text intentionally asymmetric: secrets
  says "value cannot be recovered" (true: write-only API), variables uses
  the shorter volumes-style phrasing (the value is visible via `ls` before
  deletion).
- Remove now-stale per-command `--format` declarations. #4162 made --format
  global, so these were dead code that was breaking the import after the
  rebase.

Per @Wauplin review at #4170 (comment 4351208819).

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
@huggingface-hub-bot
Copy link
Copy Markdown
Contributor

This PR has been shipped as part of the v1.13.0 release.

Wauplin added a commit that referenced this pull request May 4, 2026
* [CLI] Add hf spaces secrets and variables subgroups

- `hf spaces secrets {set,delete}` wraps add_space_secret / delete_space_secret.
- `hf spaces variables {set,delete,ls}` wraps add/delete_space_variable and get_space_variables.
- Both `set` commands accept multiple `-s`/`-e` flags and `--secrets-file`/`--env-file`
  (dotenv) via the existing `parse_env_map` helper — no new parsing code.
- No `secrets ls`: Hub exposes secrets as write-only (no GET endpoint).
- Confirm + `--yes` on `secrets delete` only (lost-value risk); variables delete is
  replayable so it skips the prompt, per the #4155 rule.
- `set` is upsert (one API call per key — no bulk endpoint), not replace-collection.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>

* [CLI] Apply review feedback: rename set→add, confirm on variables delete

- Rename `secrets set` / `variables set` to `add` (mirrors add_space_secret/
  add_space_variable, signals upsert vs volumes set's replace).
- Add confirm + `-y/--yes` to `variables delete` for parity with
  `secrets delete`. Kept the warning text intentionally asymmetric: secrets
  says "value cannot be recovered" (true: write-only API), variables uses
  the shorter volumes-style phrasing (the value is visible via `ls` before
  deletion).
- Remove now-stale per-command `--format` declarations. #4162 made --format
  global, so these were dead code that was breaking the import after the
  rebase.

Per @Wauplin review at #4170 (comment 4351208819).

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>

* Update docs/source/en/guides/cli.md

Co-authored-by: Lucain <[email protected]>

* Update src/huggingface_hub/cli/spaces.py

Co-authored-by: Lucain <[email protected]>

* [CLI] Regenerate CLI reference after suggestion commits

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <[email protected]>
Co-authored-by: Lucain <[email protected]>
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.

2 participants