attributes: replace the DataType family with python types and *Meta typed dicts - #418
attributes: replace the DataType family with python types and *Meta typed dicts#418coretl wants to merge 2 commits into
*Meta typed dicts#418Conversation
…yped dicts An attribute's datatype is now the python type it holds - `float`, an Enum subclass, `Array1D[np.int32]`, `Table` - and everything that used to hang off a `DataType` instance travels separately as metadata on `attr.meta`. - New `fastcs.datatypes`: `Array1D`/`Table` datatype spellings, the per-datatype `*Meta` typed dicts (plus the superset `Meta`), nested `NumericLimits`, and the validation the `DataType` classes used to do. - `Attr*` constructors are overloaded per datatype, so `AttrRW(str, precision=3)` is a static type error; `validate_meta` is the runtime counterpart for metadata that arrives without a static check. - Naming pass (ADR 0017): `prec` -> `precision`, and the flat `min`/`max`/`min_alarm`/`max_alarm` become nested control/display/alarm/warning limits with inheritance. - Every transport repointed from `attr.datatype.*` to `attr.dtype` + `attr.meta`; `add_update_datatype_callback` becomes `add_update_meta_callback`. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017zpFjvbhUisfVUq3NH8M1G
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
The p4p enum test still read `attr.datatype.members`; it cannot run in the sandbox (no PVA socket family), so CI was the first to see it. Three new docstrings also referenced `ControllerFiller`, which does not exist until #394, and an ambiguous `fastcs.datatypes.meta` - sphinx builds with warnings as errors. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017zpFjvbhUisfVUq3NH8M1G
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## refactor #418 +/- ##
============================================
+ Coverage 91.25% 91.40% +0.15%
============================================
Files 72 67 -5
Lines 2892 3003 +111
============================================
+ Hits 2639 2745 +106
- Misses 253 258 +5 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Closes #413
An attribute's datatype is now the python type it holds, and everything that used to hang off a
DataTypeinstance — precision, units, limits, array shape — travels separately as metadata onattr.meta. This completes theDataTypedrop split out of #392, and absorbs the naming pass (#396 / ADR 0017) as that issue directed.Scope
DataTypeis gone.datatype.py,_numeric.py,bool.py,float.py,int.py,string.py,enum.py,waveform.pyandtable.pyare deleted.fastcs.datatypesnow holds:types.py— theDTypeunion,Array1D[np.int32](a subscripted numpy alias that is both the hint and the datatype),Table, andresolve_datatype.meta.py—BoolMeta/IntMeta/FloatMeta/StrMeta/EnumMeta/Array1DMeta/TableMeta, plus the supersetMetafor the declarative path (Example 4 — SCPI device: annotated attributes + per-attribute filler data #405'sSCPIParam, ControllerFiller — declarative/procedural split #394's filler).limits.py— nestedNumericLimitswithLimitsper category.validation.py—validate_value/values_equal/default_value/validate_meta, which is what theDataTypeclasses used to do invalidate/equal/initial_value.attr.metastores the resolved metadata;attr.dtypeis the python type.attr.datatypeis gone, anddescription/groupare meta fields with properties reading them.AttrR/AttrW/AttrRW.__init__are overloaded once per datatype with**meta: Unpack[*Meta], soAttrRW(str, precision=3)does not type check.validate_metais the runtime counterpart — the error names the field, datatype and attribute ('precision' is not valid metadata for str attribute device_id), which is the message ControllerFiller — declarative/procedural split #394/Example 4 — SCPI device: annotated attributes + per-attribute filler data #405 need from the filler.prec→precision; the flatmin/max/min_alarm/max_alarmbecomeNumericLimits(control=…, display=…, alarm=…, warning=…), all optional, with the ADR's inheritance rules (control inherits display, warning inherits alarm, warning ⊆ alarm asserted). Only the control range rejects a value; the rest are served to clients.Waveform→Array1D:AttrR(Array1D[np.int32], shape=(10,))— the element type rides on the subscript. Arrays of rank > 1 keep working, written asAttrR(np.ndarray, array_dtype=np.uint16, shape=(1024, 1024)), sinceArray1Dis by name one dimensional and there is no ophyd-async spelling for higher ranks.util.py,ioc.py), PVA (types.py,_pv_handlers.py,gui.py), the shared EPICS GUI, Tango, REST and GraphQL all dispatch onattr.dtypeand read what they serve fromattr.meta.add_update_datatype_callback→add_update_meta_callback. The cast helpers now take theAttributerather than a datatype object, since validation lives on the attribute.docs/snippets/*.py, and the prose docs (explanations/datatypes.mdrewritten,how-to/table-waveform-data.md,explanations/transports.md, and the rest) migrated.Instructions to reviewer on how to test:
uv run --locked tox -e pre-commit,type-checking— both green.uv run pytest tests/test_datatypes.py tests/test_attributes.py -vpython -m fastcs.demo run src/fastcs/demo/fastcs.yamlagainst the sim (tickit all src/fastcs/demo/simulation/temp_controller.yaml)Checks for reviewer
min_alarm/max_alarmdrove EPICSLOPR/HOPR, which are EPICS' display range, not its alarm limits. With the categories now named, this PR mapsdisplay→LOPR/HOPRandcontrol→DRVL/DRVH(and PVA/Tango likewise), so a driver that previously setmin_alarmto get a display range now setsdisplay. Servingalarm/warningas CALOLO/HIHI/LOW/HIGHis left out — it needs the severity fields set too, and is a behaviour addition rather than this rename.np.ndarray; what separates them is that a table's metadata names its columns, so transports check forstructured_dtypeinattr.meta. DeclaringTablewithout columns, orstructured_dtypewithoutTable, fails fast at construction.Notes
boolmatchesintwhileintmatchesfloat, soAttrR(bool, units=...)resolves to theintoverload rather than failing statically; the constructor's runtime check rejects it. A call whose metadata is valid always picks its own datatype's overload (AttrR(bool)isAttrR[bool],AttrR(int)isAttrR[int]). This is commented at the overload block rather than left for a reader to discover.DataType.all_equalwas unused outside its own test and is not carried over.tests/transports/epics/ca/test_initial_value.pyhad attributes literally namedint/float/bool/str; harmless when the datatype wasInt(), but they shadow the builtins in the class body now, so they are renamed*_rw(PV names follow).uv run --locked tox -e pre-commit,type-checking, both green in full. For thetestsenv, this sandbox can't rundocs(needs outbound network todiamondlightsource.github.io) or the PVA/p4p-backed tests (RuntimeError: Address family not supported by protocol— no PVA-capable socket family), the same known limitation noted on demo: use ControllerVector for temperature ramp sub-controllers #409/demo: cut-down Eiger REST sim + introspectable controller example #410/demo: convert temperature controller to getter/setter style #411/attributes: getter/setter IO rework, remove AttributeIORef/AttributeIO #412. Excluding those two paths,pytest src tests --ignore=tests/benchmarkingpasses 361/371, with only the same 10 pre-existing p4p/socket-family failures — I confirmed those 10 are identical onrefactoritself by running that file in a worktree off the base commit. Real CI coversdocsand PVA.Generated by Claude Code