DataFrame builders, conversions, and the cookbook recipe (issue #6, PR 2) - #45
Open
craigmcchesney wants to merge 2 commits into
Open
DataFrame builders, conversions, and the cookbook recipe (issue #6, PR 2)#45craigmcchesney wants to merge 2 commits into
craigmcchesney wants to merge 2 commits into
Conversation
Adds the calculations construction and read-back layer the Phase 1 clients accept, per plan D6/D7. data_frame.py (no optional dependencies): - sampling_clock() / timestamp_list() / timestamp_count() relocated here from sample_status_client now that calculations frames are a second caller, and re-exported from it so existing imports keep working. - Typed scalar column builders, the legacy data_column() escape hatch (a None entry becomes an unset oneof -- the only way to express a gap on a shared axis), and the provenance helpers. - data_frame() routes columns by type and enforces the server's SHAPE rules client-side, so an error names the offending column instead of bouncing the whole save. Size caps stay server-side: they are deployment policy. - Array/image/struct/serialized builders are deliberately #17's; hand-built columns of those kinds pass through data_frame() today. data_frame_conversions.py: - Pure Python: data_frame_timestamps() (integer nanoseconds throughout), column_values() (standalone, so the bucket query #16 can reuse it; array columns reshape to one list per sample), data_frame_columns(), column_metadata_dict(). - Behind [analysis]: data_frame_to_pandas() (UTC index from int64 nanos), data_frame_from_pandas() (dtype -> typed column, NaN fail-loud since a dense typed column cannot express a gap), and the calculations bridges. The pandas direction always emits a TimestampList rather than inferring a SamplingClock: a clock is only correct if the spacing is exactly uniform at nanosecond precision, and guessing would move timestamps. Two things surfaced while building this: - The data_frame() *function* is deliberately NOT re-exported from dp_python_lib.client. Binding that name shadows the data_frame *module*, so both import forms hand back the function -- breaking the documented `from dp_python_lib.client import data_frame as dfb` usage. - An array column with no dims must be treated as underivable, not as an empty product of 1, which would silently make every element its own sample. Fixed in both the write and read paths. 87 new unit tests: 657 total with the [analysis] extra, and 601 passing with 56 skipping cleanly without it (verified in a venv that has no pandas). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019he3UCsAnqTDE2VQ73Djwn
…ase 4) Completes issue #6 with the documentation and the remaining integration coverage. doc/cookbook/datasets-and-annotations.md continues the cookbook's shared worked example -- a dataset over the first hour of the CXI_3443 shift, an orbit-drift annotation, a 1 Hz RMS calculation carrying provenance back to the source PV, and the export -- and covers the things most likely to bite: - The archive-existence rule, including why its error text ("no PV metadata found for names") misdescribes the check it failed. - Calculations belonging to their annotation, so a full-replace save without them deletes them. - Gaps: the typed columns are dense, so data_column() or a separate frame. - Why the pandas direction never infers a SamplingClock, and why NaN is fail-loud. - That there is no download: file_path is a server-side path. Integration test grew the Phase 4 legs: builder-made calculations read back through data_frame_conversions on a sub-second axis (so the round trip exercises nanosecond arithmetic rather than whole seconds a float could also represent), provenance survival, and four export cases. 25 tests, 12 subtests, all passing against dp-service fddf692. Also: README moves the three Annotation Service bullets from TODO to Current state; CLAUDE.md gains the usage section promised in PR 1; the cookbook README lists the recipe and extends the worked-example description; and the snippet checker's preamble gains the new names plus the recipe's shared handles. The CLAUDE.md snippet was extracted and RUN against the live server, not just type-checked -- save, query, batch fetch, calculations read-back in both plain Python and pandas, export, and teardown all succeed end to end. 699 tests pass with the [analysis] extra; 601 pass and 56 skip cleanly without it. ruff, format, and all 101 cookbook snippets clean. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019he3UCsAnqTDE2VQ73Djwn
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.
Phases 2–4 of issue #6, completing the ticket. Plan:
plan/tickets/6/plan.md.Stacked on #44 — based on that branch, so review it first; this PR retargets to
mainonce #44 merges.Phase 2 —
data_frame.pyBuilders for
common.DataFrame, the shared time-series payload. It is also ingestion'singestionDataFrame, so #17 extends this module rather than forking it.sampling_clock()/timestamp_list()/timestamp_count()relocated here fromsample_status_clientnow that calculations frames are a second caller, and re-exported from it so existing imports keep working.data_column(), the escape hatch whoseNoneentries become unset oneofs — the only way to express a gap on a shared axis; and the provenance helpers.data_frame()routes columns by type and enforces the server's shape rules client-side (non-blank names, non-empty values, count match, name uniqueness across all types) so an error names the offending column. Size caps stay server-side: they are deployment policy, and duplicating numbers that can change is how clients drift.Phase 3 —
data_frame_conversions.pyPure Python (no extras):
data_frame_timestamps(),column_values()— written standalone so the bucket query (#16) can reuse it —data_frame_columns(),column_metadata_dict().Behind
[analysis]:data_frame_to_pandas(),data_frame_from_pandas(), and thecalculations_*bridges.Two decisions worth a look:
TimestampList, never an inferredSamplingClock. A clock is only correct if the spacing is exactly uniform at nanosecond precision, and inferring that from an index that merely looks regular would quietly move timestamps.NaNis fail-loud, with a message pointing at the two ways to express a gap. A dense typed column cannot represent one, so the alternatives are inventing a value or dropping a row.Phase 4 — cookbook and docs
doc/cookbook/datasets-and-annotations.mdcontinues the shared worked example (a dataset over the CXI_3443 shift's first hour, an orbit-drift annotation, a 1 Hz RMS calculation with provenance, the export). Plus the cookbook README entry, the README move of the three Annotation Service bullets from TODO to Current state, and the CLAUDE.md usage section promised in PR 1.Two things found while building this
data_frame()function fromdp_python_lib.clientshadowed thedata_framemodule, so both import forms returned the function — breaking thefrom dp_python_lib.client import data_frame as dfbform the plan's own reference snippet uses. The function is no longer re-exported at package level; reach it asdfb.data_frame(...).Verification
[analysis]extra; 601 pass and 56 skip cleanly without it, verified in a real pandas-free venv rather than assumed.fddf692, now including builder-made calculations read back on a sub-second axis — so the round trip exercises nanosecond arithmetic rather than whole seconds a float could also represent — provenance survival, and four export cases.Not in this PR
Array/image/struct column builders (#17), bucket-query conversions (#16), and the
attributes()/ optional-criteriaback-port to the older helpers (#40 / #41) — all out of scope per the plan.🤖 Generated with Claude Code
https://claude.ai/code/session_019he3UCsAnqTDE2VQ73Djwn