Skip to content

Add resource metadata - #1205

Merged
rickwierenga merged 5 commits into
PyLabRobot:mainfrom
burnpanck:feature/resource-meta
Aug 18, 2026
Merged

Add resource metadata#1205
rickwierenga merged 5 commits into
PyLabRobot:mainfrom
burnpanck:feature/resource-meta

Conversation

@burnpanck

Copy link
Copy Markdown
Contributor

We found it useful to store arbitrary metadata with resources. For example, this enables us to label wells and containers with a metadata key source_for, indicating that these are where certain reagents can be found. Or it could be used to store barcode information with samples. Information regarding which direction a specific plate should be gripped by an iSWAP. Having that kind of information attached to the resources themselves is important because a) the metadata gets together with the deck, and b) it is cleaned up automatically when the corresponding resources are removed again from the deck.

Comment thread pylabrobot/resources/resource.py Outdated
@rickwierenga

Copy link
Copy Markdown
Member

thanks for the PR!

just one small comment above

could you also fix the merge conflicts?

after that this is good to merge

@j0nch

j0nch commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

Fascinating feature, I'm already thinking about refactoring all of the protocol orchestration context dictionaries into Resource.metadata once this is merged!

burnpanck and others added 5 commits August 18, 2026 10:57
Add metadata dictionary attribute to Resource with serialization and
deserialization support. Add find_resources and find_resource
methods to query resources by metadata key presence, value equality,
predicate functions, or reserved top-level attributes (name, type,
model, category).

TAG=agy
CONV=0b8c49d2-c260-4e40-9f6a-6a6e8408f740

Change-Id: I317d7c30daa757bcbbacff00f15b149a6069e1ba
Follow-up to the generic-metadata + find_resources/find_resource feature.
Documentation, tests, formatting, and typing modernization only; there is
no runtime behavior change.

Docs/comments:
- Add docstrings to the _match_top_level_attribute / _match_metadata_entry
  helpers and expand the find_resources / find_resource docstrings to spell
  out the API's sharp edges: reserved-key ('name'/'type'/'model'/'category')
  shadowing of metadata keys and the metadata= escape hatch; callable
  metadata values being executed as predicates (with an identity-match
  workaround); the per-channel callable-argument semantics; self-inclusion
  in results; and the result ordering.
- Document the shallow-copy semantics of the metadata constructor argument.
- Expand the comment on the deserialize() name-equality assertion to explain
  the module-alias scenario it handles and its name-only limitation.

Tests (new TestResourceMetadata class):
- Cover previously-untested paths: the metadata= dict param; reserved-key
  shadowing + escape hatch; every type= matcher variant
  (class/tuple/str/regex/callable); callable attribute matchers; combined
  filters; find_resource first-match/self; no-criteria search + ordering;
  the callable-metadata-value trap; deserialize backward-compat when the
  serialized data has no metadata key; and the deserialize module-alias
  assertion fallback.
- Co-locate all metadata tests here (three were previously appended to the
  unrelated TestAssignChildByAnchor class).

Typing:
- Modernize the metadata feature's type annotations to builtin generics and
  PEP 604 unions (dict/list, X | None) instead of typing.Dict/List/Optional/
  Union, matching the repo's ongoing migration (requires-python >= 3.9).
- Use collections.abc.Mapping for the read-only metadata= inputs (copied via
  dict(metadata)); the public .metadata attribute and the return value stay
  concrete dict/list.

Formatting:
- Apply ruff format to the feature's additions (collapse extra blank lines,
  wrap lines over the configured 100-char width).

TAG=agy

Change-Id: Ic489ba83e47b64652f7bc2090754747552cd1be4
- No `**kwargs` in `find_resources`. Narrower, less ambiguous.
- Serialize metadata as a black-box. Document JSON compatibility
  requirement.
- Slightly refined matcher protocol.

Change-Id: Ie5e91a3f4b19b8689a9bc711adf4a71166d71a8a
Change-Id: Id427e890b3cf2df14b0646b1410cdd24be8f0c06
Resource metadata may contain arbitrary, non-JSON serializable Python objects.
The visualizer may still want to display that metadata,
so this commit stringifies all non-serializable dict values sent to
the browser.

`Resource.save` also serialises to JSON and is not touched,
so users who need that functionality still need to make sure
their metadata is serializable.

This CL also fixes the missing `metadata=` arguments to various
resource constructors, deserialization of metadata in resource
subclasses that override base deserialization.
However, some resources create their own internal resources
which aren't being passed through the usual serialisation mechanisms.
We interpret these as *internal resources* not intended for direct
interaction by the user, and therefore don't consider metadata
for them.

Finally, it fixes a bug in `LiquidHandler.deserialize` which
previously failed to roundtrip the name of the resource.

TAG=agy

Change-Id: I1cac87002311f46ad23172e2e291dd56f8e04e9a
@rickwierenga
rickwierenga force-pushed the feature/resource-meta branch from 3bd63f0 to debb3ea Compare August 18, 2026 18:13
@rickwierenga

Copy link
Copy Markdown
Member

rebased it onto head

@rickwierenga
rickwierenga merged commit dda2072 into PyLabRobot:main Aug 18, 2026
20 of 22 checks passed
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.

4 participants