13
13
import sys
14
14
import typing as ty
15
15
import warnings
16
- from collections import OrderedDict
17
16
from functools import reduce
18
17
from operator import mul
19
18
from os .path import exists , splitext
@@ -84,7 +83,14 @@ class Recoder:
84
83
2
85
84
"""
86
85
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
+ ):
88
94
"""Create recoder object
89
95
90
96
``codes`` give a sequence of code, alias sequences
@@ -122,14 +128,14 @@ def __init__(self, codes, fields=('code',), map_maker=OrderedDict):
122
128
self .field1 = self .__dict__ [fields [0 ]]
123
129
self .add_codes (codes )
124
130
125
- def __getattr__ (self , key : str ) -> ty .Mapping :
131
+ def __getattr__ (self , key : str ) -> ty .Mapping [ ty . Hashable , ty . Hashable ] :
126
132
# By setting this, we let static analyzers know that dynamic attributes will
127
133
# be dict-like (Mapping).
128
134
# However, __getattr__ is called if looking up the field in __dict__ fails,
129
135
# so we only get here if the attribute is really missing.
130
136
raise AttributeError (f'{ self .__class__ .__name__ !r} object has no attribute { key !r} ' )
131
137
132
- def add_codes (self , code_syn_seqs ) :
138
+ def add_codes (self , code_syn_seqs : ty . Sequence [ ty . Sequence [ ty . Hashable ]]) -> None :
133
139
"""Add codes to object
134
140
135
141
Parameters
@@ -163,7 +169,7 @@ def add_codes(self, code_syn_seqs):
163
169
for field_ind , field_name in enumerate (self .fields ):
164
170
self .__dict__ [field_name ][alias ] = code_syns [field_ind ]
165
171
166
- def __getitem__ (self , key ) :
172
+ def __getitem__ (self , key : ty . Hashable ) -> ty . Hashable :
167
173
"""Return value from field1 dictionary (first column of values)
168
174
169
175
Returns same value as ``obj.field1[key]`` and, with the
@@ -176,13 +182,9 @@ def __getitem__(self, key):
176
182
"""
177
183
return self .field1 [key ]
178
184
179
- def __contains__ (self , key ) :
185
+ def __contains__ (self , key : ty . Hashable ) -> bool :
180
186
"""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
186
188
187
189
def keys (self ):
188
190
"""Return all available code and alias values
@@ -198,7 +200,7 @@ def keys(self):
198
200
"""
199
201
return self .field1 .keys ()
200
202
201
- def value_set (self , name = None ):
203
+ def value_set (self , name : str | None = None ) -> OrderedSet :
202
204
"""Return OrderedSet of possible returned values for column
203
205
204
206
By default, the column is the first column.
@@ -232,7 +234,7 @@ def value_set(self, name=None):
232
234
endian_codes = Recoder (_endian_codes )
233
235
234
236
235
- class DtypeMapper :
237
+ class DtypeMapper ( dict [ ty . Hashable , ty . Hashable ]) :
236
238
"""Specialized mapper for numpy dtypes
237
239
238
240
We pass this mapper into the Recoder class to deal with numpy dtype
@@ -250,40 +252,34 @@ class DtypeMapper:
250
252
and return any matching values for the matching key.
251
253
"""
252
254
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 ] = []
262
258
263
- def __setitem__ (self , key , value ) :
259
+ def __setitem__ (self , key : ty . Hashable , value : ty . Hashable ) -> None :
264
260
"""Set item into mapping, checking for dtype keys
265
261
266
262
Cache dtype keys for comparison test in __getitem__
267
263
"""
268
- self . _dict [ key ] = value
269
- if hasattr (key , 'subdtype' ):
264
+ super (). __setitem__ ( key , value )
265
+ if isinstance (key , np . dtype ):
270
266
self ._dtype_keys .append (key )
271
267
272
- def __getitem__ (self , key ) :
268
+ def __getitem__ (self , key : ty . Hashable ) -> ty . Hashable :
273
269
"""Get item from mapping, checking for dtype keys
274
270
275
271
First do simple hash lookup, then check for a dtype key that has failed
276
272
the hash lookup. Look then for any known dtype keys that compare equal
277
273
to `key`.
278
274
"""
279
275
try :
280
- return self . _dict [ key ]
276
+ return super (). __getitem__ ( key )
281
277
except KeyError :
282
278
pass
283
- if hasattr (key , 'subdtype' ):
279
+ if isinstance (key , np . dtype ):
284
280
for dt in self ._dtype_keys :
285
281
if key == dt :
286
- return self . _dict [ dt ]
282
+ return super (). __getitem__ ( dt )
287
283
raise KeyError (key )
288
284
289
285
@@ -347,7 +343,7 @@ def pretty_mapping(mapping, getterfunc=None):
347
343
return '\n ' .join (out )
348
344
349
345
350
- def make_dt_codes (codes_seqs ) :
346
+ def make_dt_codes (codes_seqs : ty . Sequence [ ty . Sequence ]) -> Recoder :
351
347
"""Create full dt codes Recoder instance from datatype codes
352
348
353
349
Include created numpy dtype (from numpy type) and opposite endian
0 commit comments