Skip to content

Python(feat): accept list values for multi-value metadata writes - #709

Draft
dengjonathan wants to merge 1 commit into
python-metadata-getallfrom
python-metadata-list-writes
Draft

Python(feat): accept list values for multi-value metadata writes#709
dengjonathan wants to merge 1 commit into
python-metadata-getallfrom
python-metadata-list-writes

Conversation

@dengjonathan

Copy link
Copy Markdown
Contributor

What

Stacked on #699 (read side). Completes the client story for multi-value metadata: list values can now be written through the public API.

client.runs.update(run, RunUpdate(metadata={"part_number": ["ABC", "XYZ"], "env": "prod"}))
run.metadata.getall("part_number")   # ["ABC", "XYZ"]
  • metadata_dict_to_proto accepts list[str] values, emitting one MetadataValue per element in list order (the canonical order). Lists must be non-empty and string-only, mirroring the backend rule that only string keys are multi-value capable. The parameter widens to Mapping so existing scalar-dict callers typecheck unchanged.
  • RunCreate / RunUpdate / AssetUpdate widen metadata to dict[str, str | float | bool | list[str]] and gain a before-validator that expands Metadata mappings via the new expand_metadata_for_write helper. Without it, pydantic's dict rebuild (and the model_dump feeding proto conversion) flattens the mapping to its first-value view — so update(metadata=run.metadata) would silently drop values. With it, the round-trip is lossless.
  • The streaming run form (_to_rust_form) rejects list values with a clear error until the Rust bindings support multi-value.

Scope

Run and Asset writes only — the entities in the ENG-13281 rollout. Report, channel, test-report, and calculated-channel models keep scalar annotations; widening them later is a per-model annotation + validator once backend support is confirmed.

Testing

  • Unit: 8 new tests across test_metadata.py (list conversion order, round-trip, Metadata expansion, empty-list and non-string rejection), test_run.py (create/update list writes, Metadata round-trip, rust-form guard), test_asset.py (list writes, Metadata round-trip). Full non-integration suite: 1139 passed.
  • Integration: TestMultiValueMetadata gains public-write coverage — test_update_run_with_list_metadata and test_metadata_round_trip_preserves_all_values — verified green against a local stack with the multi-value-metadata flag enabled (skip cleanly when it isn't). Full test_runs.py integration file: 33 passed.
  • ruff check / ruff format --check / mypy / pyright clean; regenerated sync stubs unchanged.

Linear: ENG-13281 (Phase 3)

🤖 Generated with Claude Code

metadata_dict_to_proto now accepts list[str] values, emitting one
MetadataValue per element in list order (the canonical order). Lists must
be non-empty and string-only, mirroring the backend rule that only string
keys are multi-value capable.

Run and Asset create/update models widen their metadata annotation to
dict[str, str | float | bool | list[str]] and gain a before-validator that
expands Metadata mappings via expand_metadata_for_write, so
update(metadata=entity.metadata) round-trips without dropping values
behind getall(). The streaming run form (_to_rust_form) rejects list
values with a clear error until the Rust bindings support multi-value.

Linear: ENG-13281 (Phase 3)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

Python docs preview: https://sift-stack.github.io/sift/python/pr-709/

Deployed from 0d54905. The link may take up to a minute to become live as GitHub Pages propagates.

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