Skip to content

Commit 7673873

Browse files
mjanuszcopybara-github
authored andcommitted
Do not use MRO with NamedTuples, which is not supported prior to py 3.11.
PiperOrigin-RevId: 783502750
1 parent 7c3d838 commit 7673873

File tree

5 files changed

+59
-13
lines changed

5 files changed

+59
-13
lines changed

connectomics/common/array.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,9 @@
4343
CanonicalSliceOrPointLookups = Union[CanonicalSlice, PointLookups]
4444

4545
ArrayLike = npt.ArrayLike
46-
Tuple3f = Tuple[float, float, float]
47-
Tuple3i = Tuple[int, int, int]
48-
Tuple4i = Tuple[int, int, int, int]
46+
Tuple3f = tuple[float, float, float]
47+
Tuple3i = tuple[int, int, int]
48+
Tuple4i = tuple[int, int, int, int]
4949
ArrayLike3d = Union[npt.ArrayLike, Tuple3f, Tuple3i]
5050

5151

connectomics/common/tuples.py

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@
2222
C = TypeVar('C')
2323

2424

25-
class XYZ(Generic[T], NamedTuple):
25+
@dataclasses.dataclass(frozen=True)
26+
class XYZ(Generic[T]):
2627
"""XYZ is a named tuple for a 3-dimensional vector.
2728
2829
Allows static type checker to differentiate between XYZ and ZYX, and allows
@@ -48,8 +49,18 @@ def xyz(self) -> 'XYZ[T]':
4849
def zyx(self) -> 'ZYX[T]':
4950
return ZYX(*self[::-1])
5051

52+
def __iter__(self):
53+
return iter(dataclasses.astuple(self))
54+
55+
def __getitem__(self, item):
56+
return dataclasses.astuple(self)[item]
57+
58+
def __len__(self):
59+
return 3
60+
5161

52-
class ZYX(Generic[T], NamedTuple):
62+
@dataclasses.dataclass(frozen=True)
63+
class ZYX(Generic[T]):
5364
"""ZYX is a named tuple for a 3-dimensional vector.
5465
5566
Allows static type checker to differentiate between XYZ and ZYX, and allows
@@ -75,8 +86,18 @@ def __eq__(self, other):
7586
# Defer to tuple equality.
7687
return self[:] == other
7788

89+
def __iter__(self):
90+
return iter(dataclasses.astuple(self))
91+
92+
def __getitem__(self, item):
93+
return dataclasses.astuple(self)[item]
94+
95+
def __len__(self):
96+
return 3
97+
7898

79-
class XYZC(Generic[T], NamedTuple):
99+
@dataclasses.dataclass(frozen=True)
100+
class XYZC(Generic[T]):
80101
"""XYZC is a named tuple for a 4-dimensional vector."""
81102

82103
x: T
@@ -111,8 +132,18 @@ def xyzc(self) -> 'XYZC[T]':
111132
def czyx(self) -> 'CZYX[T]':
112133
return CZYX(*self[::-1])
113134

135+
def __iter__(self):
136+
return iter(dataclasses.astuple(self))
137+
138+
def __getitem__(self, item):
139+
return dataclasses.astuple(self)[item]
140+
141+
def __len__(self):
142+
return 4
143+
114144

115-
class CZYX(Generic[T], NamedTuple):
145+
@dataclasses.dataclass(frozen=True)
146+
class CZYX(Generic[T]):
116147
"""CZYX is a named tuple for a 4-dimensional vector."""
117148

118149
c: T
@@ -148,6 +179,15 @@ def __eq__(self, other):
148179
# Defer to tuple equality.
149180
return self[:] == other
150181

182+
def __iter__(self):
183+
return iter(dataclasses.astuple(self))
184+
185+
def __getitem__(self, item):
186+
return dataclasses.astuple(self)[item]
187+
188+
def __len__(self):
189+
return 4
190+
151191

152192
def named_tuple_field(
153193
cls: C,

connectomics/volume/base.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,13 @@
2121

2222
from connectomics.common import array
2323
from connectomics.common import bounding_box
24+
from connectomics.common import tuples
2425
from connectomics.volume import metadata
2526
from connectomics.volume import subvolume
2627
import numpy as np
2728

2829
Subvolume = subvolume.Subvolume
30+
XYZ = tuples.XYZ
2931

3032

3133
def slice_to_bbox(ind: array.CanonicalSlice) -> bounding_box.BoundingBox:
@@ -114,12 +116,12 @@ def write(self, subvol: subvolume.Subvolume):
114116
subvol.data)
115117

116118
@property
117-
def volume_size(self) -> array.Tuple3i:
119+
def volume_size(self) -> XYZ[int]:
118120
"""Volume size in voxels, XYZ."""
119121
return self.meta.volume_size
120122

121123
@property
122-
def pixel_size(self) -> array.Tuple3f:
124+
def pixel_size(self) -> XYZ[float]:
123125
"""Size of an individual voxels in physical dimensions (Nanometers)."""
124126
return self.meta.pixel_size
125127

connectomics/volume/metadata.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,8 @@ class VolumeMetadata(
4545
dtype: Datatype of the volume. Must be numpy compatible.
4646
"""
4747
path: str
48-
volume_size: XYZ[int] = tuples.named_tuple_field(XYZ[int])
49-
pixel_size: XYZ[float] = tuples.named_tuple_field(XYZ[float])
48+
volume_size: XYZ[int] # = tuples.named_tuple_field(XYZ[int])
49+
pixel_size: XYZ[float] #= tuples.named_tuple_field(XYZ[float])
5050
bounding_boxes: list[bounding_box.BoundingBox] = dataclasses.field(
5151
default_factory=list
5252
)

connectomics/volume/tsv_decorator.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,13 @@
1818

1919
from connectomics.common import array
2020
from connectomics.common import bounding_box
21+
from connectomics.common import tuples
2122
from connectomics.volume import base
2223
import numpy as np
2324

25+
26+
XYZ = tuples.XYZ
27+
2428
# List of python dicts of specs to decorate a volume. Expected to have the
2529
# following fields:
2630
# "decorator": Name of the decorator class. By default the decorator is looked
@@ -100,11 +104,11 @@ def get_slices(self, slices: array.CanonicalSlice) -> np.ndarray:
100104
return self._wrapped.get_slices(slices)
101105

102106
@property
103-
def volume_size(self) -> array.Tuple3i:
107+
def volume_size(self) -> XYZ[int]:
104108
return self._wrapped.volume_size
105109

106110
@property
107-
def voxel_size(self) -> array.Tuple3f:
111+
def voxel_size(self) -> XYZ[float]:
108112
return self._wrapped.pixel_size
109113

110114
@property

0 commit comments

Comments
 (0)