-1

KeyError exception object contains args attribute. This is a list and it contains a key name which user tries to access within a dictionary. Is it possible to figure out dictionary name which does not contain that key and which caused an exception while trying to access the key within it?

Example

data = {"my_key": "my_value"}

try:
    data["unknown_key"] except KeyError as e:
    print("key name: ", e.args[0])
    print("dictionary name: ", e.???) # Here I would need to know the the name of a variable which stores the dictionary is "data"
VIPPER
  • 326
  • 4
  • 24
  • No. A dict could have many names, or none. What would your use case be anyway? – Thierry Lathuille Jan 02 '23 at 10:16
  • Does this answer your question? [Check if a given key already exists in a dictionary](https://stackoverflow.com/questions/1602934/check-if-a-given-key-already-exists-in-a-dictionary) – ScottC Jan 02 '23 at 10:19
  • I need to implement dynamic error handling for all KeyErrors. All dictionaries represent known structures/objects and based on the dictionary name (variable name which stores a dictionary) I can dynamically figure out which object is missing. In my example above, in the exception handling routine I would need to know what dictionary name is "data". – VIPPER Jan 02 '23 at 10:26
  • There's no intrinsic name for a dictionary – after all, multiple names could refer to the same object. What do you actually need to do, and why? – AKX Jan 02 '23 at 10:34

1 Answers1

0

You can kinda hack this with Python 3.11+, since the traceback contains fine-grained information about where the error happened.

import ast
import linecache
import traceback

data = {"my_key": "my_value"}
flurk = data
try:
    data["flep"] = data["my_key"] + flurk["unknown_key"]
except KeyError as e:
    # Find the last frame where the exception occurred, formatted as a FrameSummary
    err_frame = traceback.TracebackException.from_exception(e).stack[-1]
    if err_frame.lineno == getattr(err_frame, "end_lineno", -1):  # If we can reliably find the line,
        # ... read the line,
        line = linecache.getline(err_frame.filename, err_frame.lineno)
        # find the "marked segment" in it,
        fragment = line[err_frame.colno:err_frame.end_colno]
        # ... and parse it as an expression.
        expr: ast.Expression = ast.parse(fragment, mode='eval')
        # Check we're dealing with a subscript (index) node...
        assert isinstance(expr.body, ast.Subscript)
        # ... and extract the main parts of the expression.
        subscriptee = ast.unparse(expr.body.value)
        subscript = ast.unparse(expr.body.slice)
    else:
        subscriptee = None  # No idea
        subscript = e.args[0]  # Just use the exception message
    raise RuntimeError(f"KeyError with {subscriptee=!r}, {subscript=!r}") from e

prints out

Traceback (most recent call last):
  File "scratch_679.py", line 8, in <module>
    data["flep"] = data["my_key"] + flurk["unknown_key"]
                                    ~~~~~^^^^^^^^^^^^^^^
KeyError: 'unknown_key'

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "scratch_679.py", line 27, in <module>
    raise RuntimeError(f"KeyError with {subscriptee=!r}, {subscript=!r}") from e
RuntimeError: KeyError with subscriptee='flurk', subscript="'unknown_key'"

so you can see the subscriptee name is flurk.

AKX
  • 152,115
  • 15
  • 115
  • 172