Skip to content

Commit 5e388c6

Browse files
committed
TYP/RF: Annotate the Recoder and DtypeMapper classes
1 parent 2867397 commit 5e388c6

File tree

1 file changed

+26
-30
lines changed

1 file changed

+26
-30
lines changed

nibabel/volumeutils.py

Lines changed: 26 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
import sys
1414
import typing as ty
1515
import warnings
16-
from collections import OrderedDict
1716
from functools import reduce
1817
from operator import mul
1918
from os.path import exists, splitext
@@ -84,7 +83,14 @@ class Recoder:
8483
2
8584
"""
8685

87-
def __init__(self, codes, fields=('code',), map_maker=OrderedDict):
86+
fields: tuple[str, ...]
87+
88+
def __init__(
89+
self,
90+
codes: ty.Sequence[ty.Sequence[ty.Hashable]],
91+
fields: ty.Sequence[str] = ('code',),
92+
map_maker: type[ty.Mapping[ty.Hashable, ty.Hashable]] = dict,
93+
):
8894
"""Create recoder object
8995
9096
``codes`` give a sequence of code, alias sequences
@@ -122,14 +128,14 @@ def __init__(self, codes, fields=('code',), map_maker=OrderedDict):
122128
self.field1 = self.__dict__[fields[0]]
123129
self.add_codes(codes)
124130

125-
def __getattr__(self, key: str) -> ty.Mapping:
131+
def __getattr__(self, key: str) -> ty.Mapping[ty.Hashable, ty.Hashable]:
126132
# By setting this, we let static analyzers know that dynamic attributes will
127133
# be dict-like (Mapping).
128134
# However, __getattr__ is called if looking up the field in __dict__ fails,
129135
# so we only get here if the attribute is really missing.
130136
raise AttributeError(f'{self.__class__.__name__!r} object has no attribute {key!r}')
131137

132-
def add_codes(self, code_syn_seqs):
138+
def add_codes(self, code_syn_seqs: ty.Sequence[ty.Sequence[ty.Hashable]]) -> None:
133139
"""Add codes to object
134140
135141
Parameters
@@ -163,7 +169,7 @@ def add_codes(self, code_syn_seqs):
163169
for field_ind, field_name in enumerate(self.fields):
164170
self.__dict__[field_name][alias] = code_syns[field_ind]
165171

166-
def __getitem__(self, key):
172+
def __getitem__(self, key: ty.Hashable) -> ty.Hashable:
167173
"""Return value from field1 dictionary (first column of values)
168174
169175
Returns same value as ``obj.field1[key]`` and, with the
@@ -176,13 +182,9 @@ def __getitem__(self, key):
176182
"""
177183
return self.field1[key]
178184

179-
def __contains__(self, key):
185+
def __contains__(self, key: ty.Hashable) -> bool:
180186
"""True if field1 in recoder contains `key`"""
181-
try:
182-
self.field1[key]
183-
except KeyError:
184-
return False
185-
return True
187+
return key in self.field1
186188

187189
def keys(self):
188190
"""Return all available code and alias values
@@ -198,7 +200,7 @@ def keys(self):
198200
"""
199201
return self.field1.keys()
200202

201-
def value_set(self, name=None):
203+
def value_set(self, name: str | None = None) -> OrderedSet:
202204
"""Return OrderedSet of possible returned values for column
203205
204206
By default, the column is the first column.
@@ -232,7 +234,7 @@ def value_set(self, name=None):
232234
endian_codes = Recoder(_endian_codes)
233235

234236

235-
class DtypeMapper:
237+
class DtypeMapper(dict[ty.Hashable, ty.Hashable]):
236238
"""Specialized mapper for numpy dtypes
237239
238240
We pass this mapper into the Recoder class to deal with numpy dtype
@@ -250,40 +252,34 @@ class DtypeMapper:
250252
and return any matching values for the matching key.
251253
"""
252254

253-
def __init__(self):
254-
self._dict = {}
255-
self._dtype_keys = []
256-
257-
def keys(self):
258-
return self._dict.keys()
259-
260-
def values(self):
261-
return self._dict.values()
255+
def __init__(self) -> None:
256+
super().__init__()
257+
self._dtype_keys: list[np.dtype] = []
262258

263-
def __setitem__(self, key, value):
259+
def __setitem__(self, key: ty.Hashable, value: ty.Hashable) -> None:
264260
"""Set item into mapping, checking for dtype keys
265261
266262
Cache dtype keys for comparison test in __getitem__
267263
"""
268-
self._dict[key] = value
269-
if hasattr(key, 'subdtype'):
264+
super().__setitem__(key, value)
265+
if isinstance(key, np.dtype):
270266
self._dtype_keys.append(key)
271267

272-
def __getitem__(self, key):
268+
def __getitem__(self, key: ty.Hashable) -> ty.Hashable:
273269
"""Get item from mapping, checking for dtype keys
274270
275271
First do simple hash lookup, then check for a dtype key that has failed
276272
the hash lookup. Look then for any known dtype keys that compare equal
277273
to `key`.
278274
"""
279275
try:
280-
return self._dict[key]
276+
return super().__getitem__(key)
281277
except KeyError:
282278
pass
283-
if hasattr(key, 'subdtype'):
279+
if isinstance(key, np.dtype):
284280
for dt in self._dtype_keys:
285281
if key == dt:
286-
return self._dict[dt]
282+
return super().__getitem__(dt)
287283
raise KeyError(key)
288284

289285

@@ -347,7 +343,7 @@ def pretty_mapping(mapping, getterfunc=None):
347343
return '\n'.join(out)
348344

349345

350-
def make_dt_codes(codes_seqs):
346+
def make_dt_codes(codes_seqs: ty.Sequence[ty.Sequence]) -> Recoder:
351347
"""Create full dt codes Recoder instance from datatype codes
352348
353349
Include created numpy dtype (from numpy type) and opposite endian

0 commit comments

Comments
 (0)