Uh oh!
There was an error while loading. Please reload this page.
Resource: fix a name when the resource is created, and refuse to change it later - #1228
Merged
Conversation
…ange it later A name is what a resource is identified by - it is unique across a tree, it is what `get_resource` finds a resource by, and it is the key its state is serialized under. Anything named after it takes that name at construction, so a name that changed afterwards left those disagreeing with it. The setter now refuses, with `AttributeError` rather than `RuntimeError`, since that is what Python raises for a read-only property. `create_ordered_items_2d` built its items and then renamed them from `well_0_0` to `well_A1`. It now passes the name it wants to the constructor, via a `name_for` argument on `create_equally_spaced_2d`. No call site changes: the naming was internal to both. Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…aming them `ItemizedResource.__init__` renamed every item it was given, prefixing it with its own name, so a well became `plate_well_A1` only after the plate existed. That is the one rename a fixed name cannot allow. `create_ordered_items_2d` takes the holder's name as `name_prefix` and passes it to each item's constructor instead. The 169 call sites pass `name_prefix=name`, the name the holder is being created with. Four sites that build their items by hand - two Opentrons loaders, the STAR teaching rack, and one test - name them after their holder directly. `named()` writes the field rather than going through the setter: its copy did not exist a moment ago and belongs to no tree, so it is being built rather than renamed, and the setter cannot tell the two apart. Names are unchanged: 342 resources on a loaded STARlet deck, byte for byte. Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
BioCamforce-pushed
the
resource-immutable-name
branch
from
August 31, 2026 14:39
ec56fc9 to
1ccc0e7Compare
Comment on lines
833
to
+837
| def named(self, name: str) -> Self: | ||
| """Return a copy of this resource with the given name.""" | ||
| new_resource = self.copy() | ||
| new_resource.name = name | ||
| # The copy is new and in no tree, so this finishes building it rather than renaming anything. | ||
| new_resource._name = name |
rickwierenga
approved these changes
Aug 31, 2026
Uh oh!
There was an error while loading. Please reload this page.
BioCam added a commit
to BioCam/pylabrobot
that referenced
this pull request
Sep 1, 2026
…gration Brings in 17 commits, including PyLabRobot#1228, which moved item naming from `ItemizedResource.__init__` into the item helpers. `n_channel_pipettes` builds its mounting shafts through `create_ordered_items_2d` and did not pass `name_prefix`, so the shafts came out as `tipmountingshaft_A1` rather than `<pipette>_tipmountingshaft_A1`. Passing the pipette's name restores what they were called before.
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 freeto 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.
A resource's name is its identifier: it is unique across the tree, it is what
get_resourcelooks a resource up by, and it is the keyserialize_all_statewrites state under. Until now it could still be reassigned after the resource existed, and anything already named after it was left behind.The problem
A well is named three times before it is usable -
well_0_0when it is constructed,well_A1bycreate_ordered_items_2d, and finallyplate_well_A1byItemizedResource.__init__, which prefixes every item it is handed with its own name. The last two are renames, and the last one writes the plate's name into all 96 of its wells.Because the plate itself can still be renamed, those wells can be left describing a plate that no longer exists:
Nothing raises, but
get_resource("sample_plate_well_A1")finds nothing and the plate's state is serialized under keys that no longer correspond to anything in the tree.This PR
namesetter now refuses, raisingAttributeErrorrather thanRuntimeError- that is what Python raises for a read-only property, sosetattrand anything catching attribute errors behave as they would for any other immutable attribute.create_equally_spaced_2dtakes aname_forcallable, so each item is constructed with the name it will keep rather than renamed afterwards.create_ordered_items_2dtakesname_prefix, the name of the resource that will hold the items, and passes it down. This matchescreate_homogeneous_resources, which already takes aname_prefixand already constructs each site with its final name. Carriers have named their children this way all along; this brings the plate side onto the same convention. The two differ only in separator - carriers join with-, items with_, which is whatItemizedResourceused and what keeps every name unchanged.ItemizedResource.__init__no longer renames what it is given.name_prefix: 155 passname_prefix=name, the name their holder is being created with, and 12 in tests pass a literal. Four sites that build items by hand - two Opentrons loaders, the STAR teaching rack, and one test - name them after their holder directly.named()writes the field rather than going through the setter, since the copy it returns did not exist a moment ago and belongs to no tree; it is being built, not renamed.Behaviour: names are unchanged, verified byte for byte across 342 resources on a loaded STARlet deck, and
named()returns what it always did. The only change a caller can see is that assigning tonamenow raises.