Skip to content

Commit b8dde70

Browse files
ieivanovclaude
andcommitted
feat: allow plate_row and plate_col to be int or str
plate_row accepts 0-based int (0 -> "A") or str ("A"). plate_col accepts 0-based int (0 -> "1") or str ("1"). The well name is derived accordingly and validated against any explicit name provided. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 4161d7d commit b8dde70

1 file changed

Lines changed: 23 additions & 9 deletions

File tree

src/useq/_position.py

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,16 @@ class PositionBase(MutableModel):
4545
name that doesn't match the plate coordinates raises a ValueError.
4646
sequence : MDASequence | None
4747
Optional MDASequence relative this position.
48-
plate_row : int | None
49-
Optional 0-based row index for well plate positions. Used to indicate
50-
which well this position belongs to for HCS data storage.
51-
plate_col : int | None
52-
Optional 0-based column index for well plate positions. Used together
53-
with `plate_row` to identify the well.
48+
plate_row : int | str | None
49+
Row for well plate positions. Can be a 0-based index (e.g., 0 → "A",
50+
1 → "B") or a string name (e.g., "A", "B") used as-is. In YAML,
51+
unquoted letters are parsed as strings (``plate_row: A`` works).
52+
plate_col : int | str | None
53+
Column for well plate positions. Can be a 0-based index (e.g., 0 → "1",
54+
1 → "2") or a string name (e.g., "1", "2") used as-is. In YAML,
55+
unquoted numbers are parsed as int, so use quotes for string columns
56+
(``plate_col: "1"`` for column name "1", vs ``plate_col: 1`` for
57+
0-based index 1 → column name "2").
5458
row : int | None
5559
Optional row index, when used in a grid.
5660
col : int | None
@@ -63,8 +67,8 @@ class PositionBase(MutableModel):
6367
name: str | None = None
6468
sequence: Optional["MDASequence"] = None
6569
properties: list[PropertyTuple] | None = None
66-
plate_row: int | None = None
67-
plate_col: int | None = None
70+
plate_row: int | str | None = None
71+
plate_col: int | str | None = None
6872

6973
# excluded from serialization
7074
row: int | None = Field(default=None, exclude=True)
@@ -108,7 +112,17 @@ def __round__(self, ndigits: "SupportsIndex | None" = None) -> "Self":
108112
def _name_from_plate(self) -> "Self":
109113
"""Set name from plate_row/plate_col. Errors if an explicit name conflicts."""
110114
if self.plate_row is not None and self.plate_col is not None:
111-
well_name = f"{_index_to_row_name(self.plate_row)}{self.plate_col + 1}"
115+
row_str = (
116+
_index_to_row_name(self.plate_row)
117+
if isinstance(self.plate_row, int)
118+
else str(self.plate_row)
119+
)
120+
col_str = (
121+
str(self.plate_col + 1)
122+
if isinstance(self.plate_col, int)
123+
else str(self.plate_col)
124+
)
125+
well_name = f"{row_str}{col_str}"
112126
if self.name is not None and self.name != well_name:
113127
raise ValueError(
114128
f"Position name {self.name!r} does not match plate_row="

0 commit comments

Comments
 (0)