import json
CONFIG = '{"port": "eighty"}'
# *** before: ***
# context could be added only by REPLACING the exception, which changed
# its type and buried the original one deeper in the chain
def read_port_old(text):
data = json.loads(text)
try:
return int(data["port"])
except ValueError as error:
raise ValueError("bad config: " + str(error))
try:
read_port_old(CONFIG)
except ValueError as error:
print("old:", error)
# *** in version 3.11: ***
def read_port(text, source="config.json"):
data = json.loads(text)
try:
return int(data["port"])
except ValueError as error:
error.add_note("while reading " + source) # the exception is kept as it
#is
error.add_note("value was: " + repr(data["port"]))
raise
try:
read_port(CONFIG)
except ValueError as error:
print("new:", error)
for note in error.__notes__: # the traceback prints them by itself
print(" note:", note)
# the type, the message and the place of the raise all stay untouched, so
# an except of the caller still sees the very same ValueError