DVPPython Studio
Module 4: Build a resilient pipeline / Build 4 of 4

Ship Asset Intelligence CLI

Integrate your functions into a reproducible fixture CLI, verify actual exports and defend Portfolio I with changed-input evidence.

Runs on your computer · 90–150 minutes · no paid services

Download practice filesFiles, commands & notes

Without JavaScript, use the step links and keep your files on your computer.

One useful idea

A portfolio tool needs more than a successful screenshot. Another person should understand its contract, install its trusted test tools, run it on owned fixtures, inspect failures and reproduce one result. pyproject.toml describes Python 3.11+, zero application dependencies, the test extra and the installed asset-intelligence entry point. The direct pytest version is pinned; build/transitive tools are not a fully locked environment.

Implement main(argv=None) in practice_cli.py. argparse defines inspect, root, REQUIRED mutually exclusive --dry-run/--output, run ID and project. Compose the reviewed run_pipeline with your practice implementations; optionally export, serialize the complete report and determine exit_status before printing. Catch expected OSError/TypeError/ValueError at the CLI boundary with parser.error; unfinished NotImplementedError must not become success. Keep the __main__ guard.

The six-path sample has three accepted records and three metadata failures. Accepted delivery verdicts are one pass, one review and one block. Counts total is six; summary rows is three valid metadata observations, not the entire inventory. Eight audit events include start, six outcomes and finish. Exit 0 means nonempty metadata and delivery all pass; exit 1 retains a completed mixed/empty/review/refusal report; exit 2 means malformed/fatal input and no success report.

Dry run reads but never writes, renames or decodes media. Proposed .mp4 names are naming previews, not converted files. Export requires a NEW folder outside source with an existing parent: write real JSON/CSV manifests, read back ordered typed records, then write audit.jsonl and report.json. The verified flag means manifest parity, not an atomic or durable commit. A later write failure can leave a partial NEW folder; expose it, retain evidence and choose a different new name. Never automatically delete or overwrite.

Refresh first: Resilient batches, Pure ingest validation, Bounded audit events, Real JSON/CSV round-trips.

Trace a finished example

python -X utf8 -B -m asset_intelligence inspect fixtures/media --dry-run --run-id lesson-run
# One JSON report; counts: total 6, accepted 3, failed 3
# summary.rows: 3; audit: 8 events; dry_run: true
# Exit status 1 is EXPECTED for this mixed fixture.

python -X utf8 -B -m asset_intelligence inspect fixtures/media --output lesson-export --run-id export-run
# Creates manifest.json, manifest.csv, audit.jsonl and report.json.
# Manifest parity verified; mixed report still has exit status 1.
# Reusing lesson-export is refused with status 2 and no success report.

Inventory and declared sidecars feed your validator and resilient batch. Earlier naming/duration/QC/summary helpers enrich valid records; bounded audit retains failures. Only explicit export writes a new output folder. The final status distinguishes a completed mixed report from fatal command failure.

The finished implementation is in asset_intelligence/core.py and asset_intelligence/cli.py. Reading it is guided practice, not independent evidence.

Predict the denominator

The fixture has six paths but three invalid/missing sidecars. What are counts.total and summary.rows?

Compare your answer · self-reviewed

Six and three. Inventory counts include failures; the summary counts accepted metadata. The missing observations do not become delivery passes.

Find the false green

Should the mixed fixture return 0 merely because a complete JSON report was produced?

Compare your answer · self-reviewed

No. Its completed metadata/delivery refusals require status 1. Fatal/malformed failures use status 2 with no successful stdout report.

Recall partial writes

Does verified manifest parity mean all four files were committed atomically?

Compare your answer · self-reviewed

No. Parity checks two parsed manifests. Later writes can fail and leave a partial new directory. Do not claim an atomic/durable transaction or print a completed receipt.

Change it, then build your own

One controlled change

Run the reference dry run, inspect counts/summary/audit and check the exit status immediately. Export once into a new folder, inspect all four files, then demonstrate refusal on the same destination without changing its contents.

Your independent task

Implement practice_cli.main using your three completed practice functions and reviewed pipeline helpers. Match options/help, honest statuses, complete-before-print behavior and explicit new-folder export. Run all practice checks. Fill in a COPY of PORTFOLIO.md with your contract, setup, assistance, changed normal/boundary/failure evidence, actual exports, refusal, test defense and limitations. Do not copy a reference report and call it your independent result.

What success looks like

All 35 reference pytest cases pass before you begin; all 35 practice cases pass after implementation. Run your practice CLI, not only the reference, to produce changed dry-run/export evidence. A browser result, quiz score or self-reported historical shipped tick is not a Portfolio I pass.

Hint 1 · a question

Sketch parse → compose → optional export → serialize → status → print. Which operations must succeed before stdout?

Hint 2 · a concept cue

Pass implementations=practice to run_pipeline. Use a required mutually exclusive argparse group for --dry-run and --output. Preserve parser.error’s useful status 2 behavior.

Hint 3 · a localized example

raise SystemExit(main()) belongs under if __name__ == "__main__". A reviewed helper is allowed; importing the finished reference main is not your implementation.

Need the complete worked solution?

Open asset_intelligence/core.py and asset_intelligence/cli.py from the kit. Trace it, close it, then try fresh inputs in your own files. Treat the attempt as guided; seeing the solution does not award a practical pass.

Course help is guidance, not independent evidence. With JavaScript, opening help records guidance locally; otherwise note it in your README. Reset does not erase that history.

Repair a failed check

If imports run the CLI, restore the __main__ guard. If a fatal export still prints JSON, serialize/print only after the whole operation succeeds. If status 1 looks like a crash, inspect its complete report and documented categories. If pytest is missing, use the configured environment interpreter rather than installing into an unrelated Python.

NotImplementedError means a practice stub is still unfinished. Read the failing test name and the last error line. Change one behavior, rerun that build, then rerun all implemented builds.

Show it works on new inputs

Without reopening the reference, create a different owned mixed fixture and explain its counts, statuses and audit. Add a test FIRST for one new requirement (for example a documented inventory-count limit), implement it and rerun regressions. Ask another person to reproduce one run and record what actually happened, including stalls. Keep your code, tests, outputs and PORTFOLIO.md backed up outside the kit; no learner defense has been automatically awarded.

Self-review: name the input, result, refused case and reason. Your local test output and explanation are separate from a quiz score; this page does not certify a pass.

Keep the idea

Portfolio I is code plus reproducible, honestly scoped evidence and a defense. Keep failed attempts and assistance visible; a quiz checks understanding, not independent programming ability.

Organize your portfolio evidence and fresh defense. Keep local files, assistance and observed gaps separate from this quiz.

Module 4 checkpoint

Five questions, followed by the separate practical task above. JavaScript loads the scored questions; the build, files and hints remain available without it.