feat(cli): add samples batch-template command#14
Conversation
|
@claude please review this PR |
|
Claude finished @mhusbynflow's task in 2m 3s —— View job Review:
|
Implements User Story 3: `flowbio samples batch-template --sample-type T` emits a sample-sheet template for a sample type — a CSV header in human mode (reserved columns, then one column per metadata attribute, each followed by a `<id>__annotation` companion when the attribute allows it, with no `sample_type` column), or a per-column descriptor list under `--json`. A required-vs-optional summary goes to stderr, and `-o/--output` writes the CSV to a file. With `--json -o FILE`, the CSV is written to the file and the descriptor list is emitted to stdout (pinned by a test). Adds the additive `allow_annotation` field to `MetadataAttribute`, the only library change the template needs. It mirrors the `/samples/metadata` payload key directly and defaults to `False` when absent. The sample type is not validated by this command (it only decides which columns are required), so the docs no longer claim exit 4 for an unknown type — that is validated at `upload-batch`. Also adopts argparse `type=Path` for the CLI's path options (data upload PATH, samples upload --reads1/--reads2, batch-template --output) so handlers receive real Path objects. Existence validation stays in the handler rather than argparse `type=`, because parse-time errors bypass the Output renderer and would break the --json structured-error contract. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
c13f33d to
b4f466d
Compare
Extends the path-typing convention to the annotation-template and upload-multiplexed commands so every path option in the CLI is parsed straight to a pathlib.Path: annotation-template --output and upload-multiplexed --reads1/--reads2/--annotation. The handlers drop the now-redundant Path(...) reconstruction. Behaviour-preserving — existence validation stays in the handlers. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adversarial review caught that `batch-template -o` to an unwritable path raised an uncaught OSError out of main() as a raw traceback, while the sibling `annotation-template` mapped the same case to exit 2. Wrap the CSV write in the same try/except OSError -> CliUsageError guard so an unwritable destination is a clean usage error (exit 2), and add the matching negative-path test. Also tighten `_TemplateColumn.kind` to a Literal of the closed set (reserved/metadata/annotation) it echoes into the JSON descriptor. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
@claude please review this PR |
|
Claude finished @mhusbynflow's task in 2m 16s —— View job Review:
|
mhusbynflow
left a comment
There was a problem hiding this comment.
See comments
Build the reserved sample-sheet columns as _TemplateColumn instances up front instead of (name, required, description) tuples converted on use, so _template_columns just copies them rather than re-mapping. No behaviour change. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
An unrecognised --sample-type previously produced a valid-looking template at exit 0, with nothing flagged required-for-type — a quiet trap when an agent builds a sheet for a mistyped type. Validate the type against client.samples.get_types() up front and, on a miss, fail with a usage error (exit 2) listing the available identifiers. This shares the same identifier space as the required-column derivation (sample_type_links), so a type that validates is also one the derivation understands. Docs and the batch-template contract are updated to document the validation and drop the earlier "not checked here" wording. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replace the bare `str` used for sample-type identifiers with a
`SampleTypeId = NewType("SampleTypeId", str)`, per the repo convention of
naming primitive identifiers. Applied across the v2 public surface
(`SampleType.identifier`, `MetadataAttribute.required_for_sample_types`,
`upload_sample`, `get_annotation_template`, `_build_sample_fields`) and the
CLI handlers, which wrap the argparse string at the boundary as they
already do for `Token`/`BaseUrl`. Exported from `flowbio.v2`.
Named `SampleTypeId` (not `SampleType`) to avoid colliding with the
existing `SampleType` model. Behaviour-preserving — `NewType` is the
underlying `str` at runtime.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…tion The module docstring claimed --sample-type is always sent as-is and not pre-checked by the CLI, which stopped being true once batch-template gained up-front type validation. Note batch-template as the local-validation exception. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
| """ | ||
| destination = args.output | ||
| template = client.samples.get_annotation_template(args.sample_type) | ||
| template = client.samples.get_annotation_template(SampleTypeId(args.sample_type)) |
There was a problem hiding this comment.
Instead of casting args.sample_type, could we not instead add SampleTypeId as the type to add_argument?
There was a problem hiding this comment.
Done — set type=SampleTypeId on the three --sample-type arguments (upload, annotation-template, batch-template) and dropped the SampleTypeId(args.sample_type) casts from the handlers, mirroring the type=Path treatment of path options. argparse applies the type to the annotation-template 'generic' string default too, so it stays consistently typed. Behaviour-preserving; 251 tests pass.
Set type=SampleTypeId on the --sample-type arguments (upload, annotation-template, batch-template) so argparse produces the named type directly, mirroring the type=Path treatment of path options. Drops the three SampleTypeId(args.sample_type) casts in the handlers. argparse applies the type to the annotation-template "generic" default too, so it is typed consistently. Behaviour-preserving. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
What
Implements User Story 3 of the flowbio CLI:
flowbio samples batch-template --sample-type T.name,reads1,reads2,project,organism), then one column per metadata attribute, each followed by a<id>__annotationcompanion when the attribute allows annotation. There is nosample_typecolumn (the type is supplied via--sample-type). A required-vs-optional summary is written to stderr.--jsonmode: a per-column descriptor list (name,kind,required,options,description) on stdout and no CSV, so an agent can build rows directly.-o/--output PATH: writes the CSV template to a file.The one library change is the additive
MetadataAttribute.allow_annotationfield, which mirrors the/samples/metadatapayload key directly (defaults toFalsewhen absent, so it is backwards-compatible).Verification
tests/unit/v2/test_samples.py,tests/unit/cli/test_samples.py); full suite 230 passed.https://app.flow.bio/api— confirmed the annotation companions resolve andstrandednessderives as required forrna_seq.Out of scope
User Story 5 (
annotation-template/upload-multiplexed, tasks T020–T024) and User Story 4 (upload-batch) remain unimplemented; this PR is Phase 6 only.🤖 Generated with Claude Code