What does "str indices must be integers" mean? - python

I'm working with dicts in jython which are created from importing/parsing JSON. Working with certain sections I see the following message:
TypeError: str indices must be integers
This occurs when I do something like:
if jsondata['foo']['bar'].lower() == 'baz':
...
Where jsondata looks like:
{'foo': {'bar':'baz'} }
What does this mean, and how do I fix it?

As Marcelo and Ivo say, it sounds like you're trying to access the raw JSON string, without first parsing it into Python via json.loads(my_json_string).

You need to check the type for dict and existance of 'z' in the dict before getting data from dict.
>>> jsondata = {'a': '', 'b': {'z': True} }
>>> for key in jsondata:
... if type(jsondata[key]) is dict and 'z' in jsondata[key].keys() and jsondata[key]['z'] is True:
... print 'yes'
...
yes
>>>
or shorter one with dict.get
>>> jsondata = {'a': '', 'b': {'z': True}, 'c' :{'zz':True}}
>>> for key in jsondata:
... if type(jsondata[key]) is dict and jsondata[key].get('z',False):
... print 'yes'
...
yes
>>>

Actually your statement should raise SyntaxError: can't assign to function call due to the fact that you're missing a = and thus making an assignment instead of a check for equality.
Since I don't get the TypeError when running the code you've shown, I suppose that you first fix the missing = and after that check back on what the Stacktrace says.
But it might also be possible that your jsondata hasn't been decoded and therefore is still plain text, which would of course then raise the indexing error.

Related

Dictionary gives "TypeError: string indices must be integers" when i pass it as an argument to a function

I manage to send this json to my server:
data = {'transformations': '{"translate":{"z":-1.2,"y":-3,"x":-2},"scale":{"y":2,"z":2,"x":2},"rotate":{"x":90,"z":20,"y":80}}', 'part_id': 'cube10mm', 'printing_settings': '{"infill_pattern":"grid","top_layers":6,"wall_line_count":3,"bottom_layers":6,"layer_height":0.5,"infill_density":90}', 'annotations': '{"load":[],"anchor":[]}'}
When i type print(type(data)) i get <class 'dict'>
Then i call a function and pass it this json as an argument:
outcome = myfunction(data)
I get this error: TypeError: string indices must be integers
in this line: layer_height = params_dict["printing_settings"]["layer_height"]
I tried this as well:
layer_height = int(params_dict["printing_settings"]["layer_height"])
layer_height = float(params_dict["printing_settings"]["layer_height"])
What's even stranger is that i get this error even when i try to print the details about params_dict["printing_settings"]["layer_height"].
For example, when i use:
print(type(params_dict["printing_settings"]["layer_height"]))
or
print(params_dict["printing_settings"]["layer_height"])
These two lines give me the same error as well. At this point, i am stuck.
I think your problem is that you have the sub_dictionaries as string e.g
Try this
{"translate":{"z":-1.2,"y":-3,"x":-2},"scale":{"y":2,"z":2,"x":2},"rotate":{"x":90,"z":20,"y":80}}
instead of this
'{"translate":{"z":-1.2,"y":-3,"x":-2},"scale":{"y":2,"z":2,"x":2},"rotate":{"x":90,"z":20,"y":80}}'
You need to change your string to dict:
layer_height = json.loads(data["printing_settings"])["layer_height"]
or
import ast
for k, v in data.items():
if isinstance(v, str) and "{" in v:
data[k] = ast.literal_eval(v)
data

how to add variable to json

im trying to add a variable passed into a function into json but i keep getting an error, i used this question here, this is my code:
#!/usr/bin/env python
import requests
def interact(token):
token_string = str(token)
print token_string
headers = {{'X-Username':'user','X-Token':'{0}'}}.format(token_string)
print "token:"
print headers
# main
login()
get_token = login()
interact(get_token)
this is the error:
TypeError: unhashable type: 'dict'
You have to apply format to the string, not the dict that contains the string:
headers = {
{'X-Username':'user',
'X-Token':'{0}'.format(token_string)
}
}
And, you can't put a dict in a set; you'll have to use a list.
headers = [
{'X-Username':'user',
'X-Token':'{0}'.format(token_string)
}
]
You are getting that error because you are trying to put a dict in a Set.
Consider:
foo = {"a"} # type(foo) <class 'set'>
foo.add({"b": 1}) # throws unhashable error
{"a", {"b": 1}} # equivalent to the above 2 lines
This is a fairly common error since set literals and dict literals both use curly braces:
bar = {"a", 1, "b", 2} # oops! 4 element set instead of dict with 2 k/v pairs

KeyError in Python when deleting a key from dictionary, but key exists

I am trying to remove a key from a dictionary using the value from another key. The key exists, it says it exists when I type value in dict.keys(), but I get the keyerror when I try to delete it.
def remove_duplicate_length(choices):
print choices
print choices['scheme']
print type(choices['scheme'])
print choices['scheme'] in choices.keys()
print 'AABB' in choices.keys()
scheme = choices['scheme']
print type(scheme)
del choices[scheme]
Prints this:
{'ABAB': '2', 'AABB': '6', 'scheme': 'AABB', 'authors': ['Bukowski']}
AABB
<type 'str'>
True
True
<type 'str'>
None
And gives TypeError: 'NoneType' object has no attribute '__getitem__' when trying to reference the result of the return statement, or keyerror: AABB when trying to directly print the result.
I'm printing the result like this:
#route('/', method='POST')
def getUserChoice():
user_selection = parse_data(request.body.read())
print user_selection
Python dict has a very util method, get. Let's say that your dictionary may have, or not, a key. You can use get to retrieve it's key or something else, then you can check if result satisfy your condition.
>>> mydict = {'name': 'Jhon', 'age': 2}
>>> mydict.get('name')
Jhon
>>> mydict.get('lastname', 'Not found')
Not found
In your method, you can check if key exists, and then, delete it.
...
scheme = choices.get('scheme', None)
print type(scheme)
if scheme:
del choices[scheme]

how to create a dictionary from a set of properly formatted tuples in python

Is there a simple way to create a dictionary from a list of formatted tuples. e.g. if I do something like:
d={"responseStatus":"SUCCESS","sessionId":"01234","userId":2000004904}
This creates a dictionary called d. However, if I want to create a dictionary from a string which contains the same string, I can't do that
res=<some command that returns {"responseStatus":"SUCCESS","sessionId":"01234","userId":2000004904}>
print res
# returns {"responseStatus":"SUCCESS","sessionId":"01234","userId":2000004904}
d=dict(res)
This throws an error that says:
ValueError: dictionary update sequence element #0 has length 1; 2 is required
I strongly strongly suspect that you have json on your hands.
import json
d = json.loads('{"responseStatus":"SUCCESS","sessionId":"01234","userId":2000004904}')
would give you what you want.
Use dict(zip(tuples))
>>> u = ("foo", "bar")
>>> v = ("blah", "zoop")
>>> d = dict(zip(u, v))
>>> d
{'foo': 'blah', 'bar': 'zoop'}
Note, if you have an odd number of tuples this will not work.
Based on what you gave is, res is
# returns {"responseStatus":"SUCCESS","sessionId":"01234","userId":2000004904}
So the plan is to grab the string starting at the curly brace to the end and use json to decode it:
import json
# Discard the text before the curly brace
res = res[res.index('{'):]
# Turn that text into a dictionary
d = json.loads(res)
All you need to do in your particular case is
d = eval(res)
And please keep security in mind when using eval, especially if you're mixing it with ajax/json.
UPDATE
Since others pointed out you might be getting this data over the web and it isn't just a "how to make this work" question, use this:
import json
json.loads(res)

how to use .get() in a nested dict?

I use .get() to query for keys which may or may not be present in a dictionary.
In [1]: a = {'hello': True}
In [3]: print(a.get('world'))
None
I have, however, dictionaries where the key I want to check for is deeper in the structure and I do not know if the ancestors are present or not. If the dict is b = {'x': {'y': {'z': True}}} do I have to resort to
In [5]: b.get('x') and b['x'].get('y') and b['x']['y'].get('z')
Out[5]: True
to check for 'z' when I do not know whether 'x' and 'y' exist?
You can return an empty dictionary object from dict.get() to ease chaining calls:
b.get('x', {}).get('y', {}).get('z')
but perhaps you'd be better off catching the KeyError exception:
try:
value = b['x']['y']['z']
except KeyError:
value = None

Categories