Add --fields support for machine-readable CLI output#71
Merged
Conversation
Add a reusable field-selection helper to the CLI output layer and wire a --fields option into the four migrated list commands (courses, categories, sections, users). - select_fields(rows, fields): projects each row to the requested top-level keys, preserving the user-provided order, and raises a typed UnknownFieldError (naming the offending field and listing the available ones) when a field is absent from every row. - parse_fields(value): parses a comma-separated --fields value, treating an empty/whitespace-only value as 'no filtering' (equivalent to omitting it). - emit() gains an optional, backwards-compatible fields parameter applied to json/yaml/csv output; table output accepts but ignores it (best-effort). For CSV the selected keys become the column headers so all machine-readable formats share the same projected shape. Unknown fields exit non-zero with the error reported on stderr.
The help-advertisement test parsed rendered --help text, which the newer typer/rich in CI (typer 0.26 vs 0.23 locally) truncates in the options panel at an 80-column terminal, so the literal '--fields' string was absent even though the option is wired correctly (all functional --fields tests pass; only these 4 help-render assertions failed: 4 failed, 196 passed on CI). Introspect the underlying Click command's declared option strings instead — deterministic and width/version independent.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a reusable field-selection layer to the CLI output module and wires a
--fields field1,field2option into the four migratedlistcommands (courses,categories,sections,users). Automation users can now project--output json|yaml|csvpayloads down to exactly the top-level fields they want, in the order they ask for, without post-processing withjq/awk. The change is fully opt-in and does not alter any command's default output.Linked issue
Closes #66
Specification (SDD)
src/py_moodle/cli/output.py:select_fields(rows, fields) -> list[dict]: projects each row to exactly the requested top-level keys, preserving the user-provided order; a field present in some rows but missing from a given row is filled withNoneso all rows share a consistent shape. Raises the typedUnknownFieldError(naming the offending field(s) and listing available fields) when a field is present in no row.parse_fields(value) -> Optional[list[str]]: splits a comma-separated value, strips whitespace, drops empty parts; an empty/whitespace-only value (e.g.--fields "") means "no filtering" (equivalent to omitting the flag).emit()gains an optional, backwards-compatiblefieldsparameter. When set, filtering is applied tojson/yaml/csv;tableaccepts but ignores it (best-effort, documented). For CSV the selected keys become the column headers (the prettycsv_fieldsare bypassed) so all machine-readable formats share the same projected shape.TDD evidence
Red (helpers/flag absent), from the worktree root:
Green after implementing the helpers + wiring the option:
Full suite, no regressions:
Test plan
Commands run:
New tests in
tests/unit/test_cli_fields.pycover:select_fieldskey selection + order, unknown-field typed error, empty-rows short-circuit, missing-keyNonefill;parse_fieldssplit/strip and empty-as-None; CLI json field selection + order, CLI csv columns/headers in order, unknown-field non-zero exit with stderr message, empty--fields== unchanged output, table ignores--fields, all four commands apply--fieldsfor json, and all four advertise--fieldsin--help.Backwards compatibility
Fully backwards compatible.
--fieldsis opt-in and defaults to off;emit()'s newfieldsparameter defaults toNone= current behavior. No change to any command's default output. Existingtests/unit/test_cli_output_formats.pypasses unchanged.Documentation
docs/cli.mdis auto-generated and git-ignored, so no docs commit is included (per the issue).docs/recipes.mdanddocs/development.mdwere intentionally left untouched (owned by sibling wave-1 PRs). The new--fieldshelp text is emitted by each command's Typer option.Notes for reviewers
select_fields) invoked viaemit(fields=...), so the four commands share a single implementation (no copy-paste). TheUnknownFieldErroris converted to a stderr message +typer.Exit(1)insideemit(), keeping each command's call site a one-liner.--fields: headers become the raw selected keys (e.g.id,shortname) in user order, matching the json/yaml projected shape, rather than the prettyID,Shortnameheaders used when--fieldsis absent. This is covered by a test.select_fields([], ...)returns[]without raising, so--fieldsnever spuriously errors on a command that returned zero rows.src/py_moodle/cli/output.py,src/py_moodle/cli/courses.py,src/py_moodle/cli/categories.py,src/py_moodle/cli/sections.py,src/py_moodle/cli/users.py, and newtests/unit/test_cli_fields.py. No other files touched (notests/conftest.py, nodocs/*).