Closed pd-giz-dave closed 3 years ago
Hi Dave,
while you are right that ujson
apparently does a bad job on trying to serialize an exception object to JSON instead of rejecting that right away, if you really want to do that, you should approach a different strategy.
CPython will reject trying to serialize an Exception object.
import json
try:
1/0
except Exception as ex:
response = json.dumps(ex)
print(response)
$ python json_exception.py
Traceback (most recent call last):
File "json_exception.py", line 4, in <module>
1/0
ZeroDivisionError: division by zero
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "json_exception.py", line 6, in <module>
response = json.dumps(ex)
File "/usr/local/opt/python@3.8/Frameworks/Python.framework/Versions/3.8/lib/python3.8/json/__init__.py", line 231, in dumps
return _default_encoder.encode(obj)
File "/usr/local/opt/python@3.8/Frameworks/Python.framework/Versions/3.8/lib/python3.8/json/encoder.py", line 199, in encode
chunks = self.iterencode(o, _one_shot=True)
File "/usr/local/opt/python@3.8/Frameworks/Python.framework/Versions/3.8/lib/python3.8/json/encoder.py", line 257, in iterencode
return _iterencode(o, 0)
File "/usr/local/opt/python@3.8/Frameworks/Python.framework/Versions/3.8/lib/python3.8/json/encoder.py", line 179, in default
raise TypeError(f'Object of type {o.__class__.__name__} '
TypeError: Object of type ZeroDivisionError is not JSON serializable
Instead, you might approach serializing Exception
messages like this. I confirmed it works on CPython, but it might also work on MicroPython.
import json
try:
1/0
except Exception as ex:
errordata = {"message": str(ex)}
response = json.dumps(errordata)
print(response)
With kind regards, Andreas.
See also https://github.com/micropython/micropython/issues/1719 for more background of (why) MicroPython is not able to raise an exception when the object is not serializable.
@pfalcon also notes:
It also should be pointed out that MicroPython provides the
ujson
module, which can't be compared one-to-one to CPython.
Thanks for the insight. I'm new to Micropython (and Python) so finding it difficult to distinguish between my ignorance and bugs. I resolved my particular issue in the end like this:
except Exception as e: ee = sys.exc_info()[1]
Which gave me the exception name as a string.
This is on a FiPy with firmware: "Pycom MicroPython 1.20.2.r4 [v1.11-ffb0e1c] on 2021-01-12; FiPy with ESP32"
os.uname() is: "(sysname='FiPy', nodename='FiPy', release='1.20.2.r4', version='v1.11-ffb0e1c on 2021-01-12', machine='FiPy with ESP32', lorawan='1.0.2', sigfox='1.0.1', pybytes='1.6.1')"
To illustrate, do this in the repl:
import sys 1/0 # to generate an exception used to create a tuple object with '<' characters in it e = sys.exc_info() # e = (<class 'ZeroDivisionError'>, ZeroDivisionError('divide by zero',), None) ee = ujson.dumps(e) # ee = '[<class \'ZeroDivisionError\'>, ["divide by zero"], null]'
ee is not legal json, browsers choke on the '<' in the second character and the later '>'