Mar-30-2019, 09:28 PM
Python's JSON module supports deserializing Javascript infinities (although the official JSON spec doesn't). Specifically, it supports "Infinity" and "-Infinity" in particular. I need to be able to deserialize "+Infinity" though. Here is my attempt at achieving this
What does work is catching a StopIteration exception, but that doesn't seem right. I'm afraid that there's something weird going on here and if I catch the wrong exception, there will be some surprise down the line. Does anyone know what's going on here?
import json class PositiveInfinityJSONDecoder(json.JSONDecoder): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.original_scan_once = self.scan_once self.scan_once = self._scan_once def _scan_once(self, string, idx): print("Custom _scan_once entered; trying default first...") try: return self.original_scan_once(string, idx) except json.decoder.JSONDecodeError as e: print("Default failed, trying custom logic...") try: nextchar = string[idx] except IndexError: raise StopIteration(idx) from e if nextchar == '+' and string[idx:idx + 9] == '+Infinity': return self.parse_constant('Infinity'), idx + 9 raise e except Exception as e: print(f"Got an unexpected exception from default (type: {type(e)}) - {e}") raise e print(json.loads('+Infinity', cls=PositiveInfinityJSONDecoder))The result of this is that (apparently) a StopIteration exception is thrown, although its traceback looks like a JSONDecodeError
Output:$ python3 confusion.py
Custom _scan_once entered; trying default first...
Got an unexpected exception from default (type: <class 'StopIteration'>) - 0
Traceback (most recent call last):
File "confusion.py", line 28, in <module>
print(json.loads('+Infinity', cls=PositiveInfinityJSONDecoder))
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/json/__init__.py", line 361, in loads
return cls(**kw).decode(s)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/json/decoder.py", line 337, in decode
obj, end = self.raw_decode(s, idx=_w(s, 0).end())
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/json/decoder.py", line 355, in raw_decode
raise JSONDecodeError("Expecting value", s, err.value) from None
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)
I'm baffled because the stack trace clearly shows a JSONDecodeError being raised, but at runtime when I try to catch it, it appears to have a different type. In case the class is doing something funky, I also tried catching a ValueError (its superclass) but that didn't work either.What does work is catching a StopIteration exception, but that doesn't seem right. I'm afraid that there's something weird going on here and if I catch the wrong exception, there will be some surprise down the line. Does anyone know what's going on here?