56

If I catch a KeyError, how can I tell what lookup failed?

def poijson2xml(location_node, POI_JSON):
  try:
    man_json = POI_JSON["FastestMan"]
    woman_json = POI_JSON["FastestWoman"]
  except KeyError:
    # How can I tell what key ("FastestMan" or "FastestWoman") caused the error?
    LogErrorMessage ("POIJSON2XML", "Can't find mandatory key in JSON")
1
  • 2
    Since you would have to branch on the key that failed anyway, it's probably clearer to put each lookup in a separate try statement. Commented Apr 17, 2014 at 17:18

3 Answers 3

84

Take the current exception (I used it as e in this case); then for a KeyError the first argument is the key that raised the exception. Therefore we can do:

except KeyError as e:  # One would do it as 'KeyError, e:' in Python 2.
    cause = e.args[0]

With that, you have the offending key stored in cause.

Expanding your sample code, your log might look like this:

def poijson2xml(location_node, POI_JSON):
  try:
    man_json = POI_JSON["FastestMan"]
    woman_json = POI_JSON["FastestWoman"]
  except KeyError as e:
    LogErrorMessage ("POIJSON2XML", "Can't find mandatory key '"
    e.args[0]
    "' in JSON")

It should be noted that e.message works in Python 2 but not Python 3, so it shouldn't be used.

Sign up to request clarification or add additional context in comments.

3 Comments

Thank you. I don't suppose this is documented anywhere? I couldn't find it in the Python docs.
@QuestionC BaseException.args is documented, but not in enough detail that its uses are obvious.
Is this advisable to use, since it is undocumented and the arguments might change?
2

Not sure if you're using any modules to assist you - if the JSON is coming in as a dict, one can use dict.get() towards a useful end.

def POIJSON2DOM (location_node, POI_JSON):
    man_JSON = POI_JSON.get("FastestMan", 'No Data for fastest man')
    woman_JSON = POI_JSON.get("FastestWoman", 'No Data  for fastest woman')
    #work with the answers as you see fit

dict.get() takes two arguments - the first being the key you want, the second being the value to return if that key does not exist.

1 Comment

Sorry this is so late, but I guess you're answering the underlying question rather than the direct query by OP about KeyError.
-3

If you import the sys module you can get exception info with sys.exc_info()

like this:

def POIJSON2DOM (location_node, POI_JSON):
  try:
    man_JSON = POI_JSON["FastestMan"]
    woman_JSON = POI_JSON["FastestWoman"]

  except KeyError:

    # you can inspect these variables for error information
    err_type, err_value, err_traceback = sys.exc_info()

    REDI.LogErrorMessage ("POIJSON2DOM", "Can't find mandatory key in JSON")

3 Comments

@Alex Thornton's answer is much simpler, and answers the question more directly. By the way, since this is getting downvoted, is there something wrong fundamentally with my approach? I've used this method and I'd like not to use it if it causes problems. Help me out :)
I see no reason for the downvote. The syntax for capturing an exception prior to Python 2.6 was less than clear, so explicitly calling sys.exc_info() was a reasonable approach.
Not a downvoter, but: it's more complicated than except Foo as e, and it's a race condition in multithreaded code. What if two threads raise a KeyError before either of them can call sys.exc_info? Both threads would see the same output, so one of them could be wrong. The except Foo as e syntax is an atomic operation.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.