Conditions | 16 |
Total Lines | 59 |
Code Lines | 25 |
Lines | 0 |
Ratio | 0 % |
Changes | 0 |
Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.
For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.
Commonly applied refactorings include:
If many parameters/temporary variables are present:
Complex classes like pocketutils.tools.json_tools.JsonTools.preserve_inf() often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
1 | import base64 |
||
193 | @classmethod |
||
194 | def preserve_inf(cls: type[Self], data: Any) -> Any: |
||
195 | """ |
||
196 | Recursively replaces infinite float and numpy values with strings. |
||
197 | Orjson encodes NaN, inf, and +inf as JSON null. |
||
198 | This function converts to string as needed to preserve infinite values. |
||
199 | Any float scalar (`np.floating` and `float`) will be replaced with a string. |
||
200 | Any `np.ndarray`, whether it contains an infinite value or not, will be converted |
||
201 | to an ndarray of strings. |
||
202 | The returned result may still not be serializable with orjson or :meth:`orjson_bytes`. |
||
203 | Trying those methods is the best way to test for serializablity. |
||
204 | """ |
||
205 | # we go to great lengths to avoid importing numpy |
||
206 | # no np.isinf, np.isneginf, or np.isnan allowed |
||
207 | # we can use the fact that Numpy float types compare to float, |
||
208 | # including to -inf and +inf, where all comparisons between Inf/-Inf and NaN are False |
||
209 | # So our logic is is_infinite := (data > NEG_INF) != (data < INF) |
||
210 | # Meanwhile, we only need to deal with floats: |
||
211 | # - int and bool stay as-is |
||
212 | # - str stays as-is |
||
213 | # - complex gets converted to |
||
214 | if isinstance(data, Mapping): |
||
215 | return {str(k): cls.preserve_inf(v) for k, v in data.items()} |
||
216 | elif ( |
||
217 | (isinstance(data, Sequence) or type(data).__name__ == "ndarray") |
||
218 | and not isinstance(data, str) |
||
219 | and not isinstance(data, ByteString) |
||
220 | ): |
||
221 | is_np_float_array = hasattr(data, "dtype") and str(data.dtype).startswith( |
||
222 | "dtype(float", |
||
223 | ) |
||
224 | if ( |
||
225 | is_np_float_array |
||
226 | or all(isinstance(v, float) for v in data) |
||
227 | and all((v > NEG_INF) != (v < INF) for v in data) |
||
228 | ): |
||
229 | # it's a list or array of floats containing -Inf or +Inf |
||
230 | # ==> convert to str to preserve |
||
231 | return [str(v) for v in data] |
||
232 | elif is_np_float_array: |
||
233 | # it's an array of other types, or of floats containing neither -Inf nor +Inf |
||
234 | # ==> convert to list (faster than recursing) |
||
235 | # noinspection PyUnresolvedReferences |
||
236 | return data.tolist() |
||
237 | else: |
||
238 | # it's an array of other types, or of floats containing neither -Inf nor +Inf |
||
239 | # ==> return float list as-is |
||
240 | return data |
||
241 | elif (isinstance(data, float) or (hasattr(data, "dtype") and str(data.dtype).startswith("dtype(float"))) and ( |
||
242 | data > NEG_INF |
||
243 | ) != (data < INF): |
||
244 | # single float value with -Inf or +Inf |
||
245 | # ==> preserve inf |
||
246 | return str(data) |
||
247 | elif type(data).__name__ == "ndarray" and hasattr(data, "dtype"): |
||
248 | # it's a non-float Numpy array |
||
249 | # ==> convert to list |
||
250 | return data.astype(str).tolist() |
||
251 | return data |
||
252 | |||
255 |