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
The result of this is that (apparently) a StopIteration exception is thrown, although its traceback looks like a JSONDecodeError
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?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
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)) |
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?