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
Related
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
Sorry if it's too much of a noob question.
I have a dictionary where the keys are bytes (like b'access_token' ) instead of strings.
{
b'access_token': [b'b64ssscba8c5359bac7e88cf5894bc7922xxx'],
b'token_type': [b'bearer']
}
usually I access the elements of a dictionary by data_dict.get('key'), but in this case I was getting NoneType instead of the actual value.
How do I access them or is there a way to convert this bytes keyed dict to string keyed dict?
EDIT: I actually get this dict from parsing a query string like this access_token=absdhasd&scope=abc by urllib.parse.parse_qs(string)
You can use str.encode() and bytes.decode() to swap between the two (optionally, providing an argument that specifies the encoding. 'UTF-8' is the default). As a
result, you can take your dict:
my_dict = {
b'access_token': [b'b64ssscba8c5359bac7e88cf5894bc7922xxx'],
b'token_type': [b'bearer']
}
and just do a comprehension to swap all the keys:
new_dict = {k.decode(): v for k,v in my_dict.items()}
# {
# 'access_token': [b'b64ssscba8c5359bac7e88cf5894bc7922xxx'],
# 'token_type': [b'bearer']
# }
Similarly, you can just use .encode() when accessing the dict in order to get a bytes object from your string:
my_key = 'access_token'
my_value = my_dict[my_key.encode()]
# [b'b64ssscba8c5359bac7e88cf5894bc7922xxx']
Most probably, you are making some silly mistake.
It is working fine in my tests.
Perhaps you forgot to add the prefix b when trying to index the dictionary
d={
b'key1': [b'val1'],
b'key2': [b'val2']
}
d[b'key1'] # --> returns [b'val1']
d.get(b'key2') # --> returns [b'val2']
Perhaps this could be something you're looking for?
dict = {
b'access_token': [b'b64ssscba8c5359bac7e88cf5894bc7922xxx'],
b'token_type': [b'bearer']
}
print(dict.get( b'access_token'))
I am using flask_restful to create API that accepts JSON format data in format, i.e.:
payload = {'name' : 'test',
'foo' : {'value135' : 10, 'value987' : 100}}
For parsing 'name', it's pretty straight forward with RequestParser().add_argument('name'). Problem comes with 'foo'. From 'foo' I need to parse all key's and value's, ideally as dict.
So far I tried using:
RequestParser().add_argument('foo', type=dict)
output: {"message": {"foo": "dictionary update sequence element #0 has length 1; 2 is required"}}'
RequestParser().add_argument('foo', type=lambda x,y: (x,y))
output: '[["value135", "foo"], ["value987", "foo]]
RequestParser().add_argument('foo', type=lambda x,y: (x,y))
output: '{"message": {"foo": "\'ImmutableMultiDict\' object is not callable"}}'
Any ideas how this can be achieved ? Goal is to support current format of payload as it is.
Thanks
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.
Edit: Turns out my whole problem was my Json had already been converted to a dictionary previously, without me realising. And I was using json.dumps() instead of .loads() by mistake.
Original Q:I have a piece of Json code I have turned into a dictionary. I am retrieving this Json from a server. When I try access the inner values of the new dictionary to change a value, I get a:
TypeError: string indices must be integers, not str
This is my code:
corner_data = json.dumps(r.json())
print corner_data
corner_data["geometry"]["corners"] = '{"bottom_right": {"y": "575.531616", "x": "690.547363"}, "top_left": {"y": "-146.739075", "x": "-109.105957"}}'
Turn the JSON string into a Python dict using json.loads (not dumps!):*
corner_data = json.loads(r.json())
Modify the data, assigning a Python dict (not a string!):
corner_data['geometry']['corners'] = {'bottom_right': {'y': '575.531616', 'x': '690.547363'}, 'top_left': {'y': '-146.739075', 'x': '-109.105957'}}
Encode it all back into JSON:
print json.dumps(corner_data)
* I'm assuming here that r.json() returns a string. It's entirely possible that r.json() already decodes a JSON string and returns a dict, that depends on what r is. If that's the case, you don't need json.loads here, you can simply omit it.