13

JSON seems to be hiccuping on the following statements:

{"delete":{"status":{"id":12600579001,"user_id":55389449}}}

code snippet:

temp = json.loads(line)
text = temp['text']

I get the following error output when the above code snippet encounters lines similar to the above JSON 'dictionary':

text = temp['text']
KeyError: 'text'

Is it because there is no "text" key in the line or because "delete" is not in the dictionary?

slm
  • 15,396
  • 12
  • 109
  • 124
user322775
  • 151
  • 1
  • 1
  • 4
  • The `"delete"` key *is* in the dictionary. The `"text"` key is not. "The line" is not relevant; once you have parsed the JSON with `json.loads`, the result is **just** a nested dictionary, which you deal with *the same way* that you would deal with *the same data structure* if you had gotten it *in any other way*. – Karl Knechtel Jul 03 '22 at 22:36

10 Answers10

14

It looks like this happens because 'text' is not in there. Maybe you could use something like

'text' in temp

to check that 'text' exists before trying to use it.

Edit:

I've taken the example given in the comment and added a if/elif/else block to it.

#! /usr/bin/python
import sys
import json
f = open(sys.argv[1])
for line in f:
    j = json.loads(line)
    try:
        if 'text' in j:
            print 'TEXT: ', j['text']
        elif 'delete' in j:
            print 'DELETE: ', j['delete']
        else:
            print 'Everything: ', j
    except: 
        print "EXCEPTION: ", j

Sample Chunk #1:

{u'favorited': False, u'contributors': None, u'truncated': False, u'text': ---- snip ---- }

Sample Chunk #2:

{u'delete': {u'status': {u'user_id': 55389449, u'id': 12600579001L}}}

ChronoPositron
  • 1,498
  • 2
  • 10
  • 14
  • I thought that was the problem and jinned up the code below: #! /usr/bin/python import sys import json f = open(sys.argv[1]) for line in f: j = json.loads(line) try: 'text' in j print "TEXT: ", j except: print "EXCEPTION: ", j continue and get the following results (only two sample chunks)... TEXT: {u'favorited': False, u'contributors': None, u'truncated': False, u'text': ---- snip ---- } TEXT: {u'delete': {u'status': {u'user_id': 55389449, u'id': 12600579001L}}} – user322775 Apr 22 '10 at 16:13
  • I added a modified version of your code to my answer. Does this work for your file? – ChronoPositron Apr 22 '10 at 20:39
  • This got me past the first hurdle. Thanks! – user322775 Apr 29 '10 at 15:52
14

use dict.get(key[, default]) if there is a valid case when the key is missing: temp.get('text') instead of temp['text'] won’t throw an exception but return the null value None if the key is not found.

EAFP (Easier to Ask for Forgiveness than Permission) is more Pythonic than LBYL (Look Before You Leap).

törzsmókus
  • 1,799
  • 2
  • 21
  • 28
  • 3
    This solved my issue. Note that in certain situations returning Null ("None" in python) will be a problem for further processing, therefore you can change what the value should be if the key is missing by using temp.get('text', 'X') where X is a string – lobi Aug 03 '19 at 21:12
  • @lobi feel free to edit the answer to add that info and get two reputation points ;) – törzsmókus Mar 02 '20 at 19:36
8

Is it because there is no "text" key in the line or because "delete" is not in the dictionary?

It's because there is no "text" key. If you print temp or check whether the key 'text' is in the resulting Python dictionary, you'll notice that there is no key named 'text'. In fact, temp only has one key: 'delete'. The dictionary that is referenced by 'delete' contains a single key 'status' that contains another dictionary with two keys: 'user_id' and 'id'.

In other words, your structure is this:

{
    "delete" : {
        "status" : {
            "id" : 12600579001,
            "user_id" : 55389449
        }
    }
}

As you can see, there is no "text" key anywhere.

Furthermore, you can check it yourself:

>>> 'text' in temp
False
>>> 'delete' in temp
True
Dustin
  • 1,956
  • 14
  • 14
2

Try this to see the problem in detail:

import json
line = '{"delete":{"status":{"id":12600579001,"user_id":55389449}}}'
print 'line:', line
temp = json.loads(line)
print 'temp:', json.dumps(temp, indent=4)
print 'keys in temp:', temp.keys()

Which generates this output:

line: {"delete":{"status":{"id":12600579001,"user_id":55389449}}}
temp: {
    "delete": {
        "status": {
            "user_id": 55389449, 
            "id": 12600579001
        }
    }
}
keys in temp: [u'delete']

The only key in the temp dict is 'delete'. Thus temp['text'] generates a KeyError.

Chris Johnson
  • 20,650
  • 6
  • 81
  • 80
2

From the snippet you posted, it looks like temp should only have one item, with the key "delete". You do not have a key 'text', so I am not sure what temp['text'] should look up.

Mike Graham
  • 73,987
  • 14
  • 101
  • 130
1

try it like this:

    temp = json.load(line)
    for lines in temp
       text = lines['text']
user14372
  • 1,409
  • 2
  • 11
  • 12
1

Why not put this between the first and second lines:

print temp
SamB
  • 9,039
  • 5
  • 49
  • 56
1

Thanks to all for the suggestions. The heart of the problem was that the Twitter json format has a dictionary within a dictionary. The solution involves a double index to get at the variables that I need to check.

user322775
  • 151
  • 1
  • 1
  • 4
0
#!/usr/bin/env python
import sys
import json
from pprint import pprint


json_file=sys.argv[1]
json_data=open(json_file)
j = json.load(json_data)

def main():
  for attribute_key in j['root_attribute']:
   try: print attribute_key['name'], attribute_key['status'], attribute_key['text']
   except KeyError: pass

if __name__ == "__main__":
    main()
Sandip
  • 52
  • 4
0

Just an updated version of the verified answer.

If the frequency of that error happening (meaning that the variable text does not exist in the json file) is below 50% then the way to go is with the desired answer.

But if the exception is really exceptional you should use

try:
   #your code here
except KeyError:
   continue