How would I go about grabbing the values from the URL, a and b, then passing them to the add function? The result should come out to be: {"c": x}, where x is the sum of a and b.
The code:
op = 'add'
a = random.randint(0,10)
b = random.randint(0,10)
/%s?a=%s&b=%s' % (op, a, b)
result = res.json()
if op=='add':
assert a+b == result['c']
The function:
def add():
import json
return json.dumps({'c': ???})
Use urlparse, a standard library module designed for tasks like these!
urlparse.parse_qs(qs[, keep_blank_values[, strict_parsing]])
Parse a query string given as a string argument (data of type
application/x-www-form-urlencoded). Data are returned as a dictionary.
The dictionary keys are the unique query variable names and the values
are lists of values for each name.
The optional argument keep_blank_values is a flag indicating whether
blank values in percent-encoded queries should be treated as blank
strings. A true value indicates that blanks should be retained as
blank strings. The default false value indicates that blank values are
to be ignored and treated as if they were not included.
The optional argument strict_parsing is a flag indicating what to do
with parsing errors. If false (the default), errors are silently
ignored. If true, errors raise a ValueError exception.
Example:
>>> urlparse.parse_qs('a=1&b=1') # raw query string
{'a': ['1'], 'b': ['1']}
Note that you can parse an entire URL into its components (including a query string) using other functions in urlparse as well.
from urlparse import parse_qs, urlparse
import json
def add(a, b):
return json.dumps({'c': a+b})
url = 'add?a=1&b=1'
q_dict = parse_qs(urlparse(url).query, keep_blank_values=True)
# q_dict = {'a': ['1'], 'b': ['1']}
print add(a=q_dict['a'][0], b=q_dict['b'][0])
I figured out how to solve my problem! I appreciate all the help, but none of the solutions provided here applied to my question. This is entirely my fault because I worded the question totally different.
Related
Input Data:
val1 = '[{"EmpID":123456,"AnalystID": "8aa18b9c59XXXXXb20cc2534","173f48XXXXXX427f3f14516dd0"]}]'
Expected Output:
val_op = {"EmpID":123456,"AnalystID": "8aa18b9c59XXXXXb20cc2534","173f48XXXXXX427f3f14516dd0"]}
type(val1) is str
type(val_op) is dict
(basically I just need to remove first and last single quote which define Val1 as String).
Approach i tried:
>>> strlen = len(val1)
>>> payloadStr = val1[1:(strlen-1)]
'{"EmpID":123456,"AnalystID":
"8aa18b9c59XXXXXb20cc2534","173f48XXXXXX427f3f14516dd0"]}'
>>> import json
>>>json.loads(payloadsStr)
{'EmpID':123456,'AnalystID':
'8aa18b9c59XXXXXb20cc2534','173f48XXXXXX427f3f14516dd0']}
You don't have to treat the [] separately, json.loads can handle json list objects.
import json
payload = json.loads(val1)[0]
Also note that the list value in your string is missing an opening bracket and should instead be...
val1 = '[{"EmpID":123456,"AnalystID": ["8aa18b9c59XXXXXb20cc2534","173f48XXXXXX427f3f14516dd0"]}]'
# ^
Since you mentionned the string comes from a web request, this means whoever made that request misformatted their json.
To clarify, this is a string. From the string, you want to extract a dictionary, that is contained in a list.
This makes it more difficult, as opposed to a simple list that contains a dictionary.
One approach you could do is:
val1 = val1.str.split('[')[1].str.split(']')[0]
This should get rid of the brackets, and return an array of 1 index, which contains your dictionary in a string.
Another way, more straightforward is:
val1 = val1.replace('[','').replace(']','')
From there
import json
json.loads(payloadsStr)
Should get you the dictionary.
Thank you all for all the solutions. Since Desired output need to have double quote, hence json.loads(val1) and dict(*eval(val1)) can not be used.
I just tried to replace the [] from original string and when passed in Post Request as data payload, it worked fine.
strlen = len(val1)
payloadStr = val1[1:(strlen-1)]
response = requests.request("POST", url, verify=False, data=payloadsStr, headers=header)
response.text
got the output. Apologies for any confusion. Thanks Again
After using cgi.parse_qs(), how to convert the result (dictionary) back to query string? Looking for something similar to urllib.urlencode().
Python 3
urllib.parse.urlencode(query, doseq=False, [...])
Convert a mapping object or a sequence of two-element tuples, which may contain str or bytes objects, to a percent-encoded ASCII text string.
— Python 3 urllib.parse docs
A dict is a mapping.
Legacy Python
urllib.urlencode(query[, doseq])
Convert a mapping object or a sequence of two-element tuples to a “percent-encoded” string... a series of key=value pairs separated by '&' characters...
— Python 2.7 urllib docs
In python3, slightly different:
from urllib.parse import urlencode
urlencode({'pram1': 'foo', 'param2': 'bar'})
output: 'pram1=foo¶m2=bar'
for python2 and python3 compatibility, try this:
try:
#python2
from urllib import urlencode
except ImportError:
#python3
from urllib.parse import urlencode
You're looking for something exactly like urllib.urlencode()!
However, when you call parse_qs() (distinct from parse_qsl()), the dictionary keys are the unique query variable names and the values are lists of values for each name.
In order to pass this information into urllib.urlencode(), you must "flatten" these lists. Here is how you can do it with a list comprehenshion of tuples:
query_pairs = [(k,v) for k,vlist in d.iteritems() for v in vlist]
urllib.urlencode(query_pairs)
Maybe you're looking for something like this:
def dictToQuery(d):
query = ''
for key in d.keys():
query += str(key) + '=' + str(d[key]) + "&"
return query
It takes a dictionary and convert it to a query string, just like urlencode. It'll append a final "&" to the query string, but return query[:-1] fixes that, if it's an issue.
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)
I am trying to convert a string to a dictionary with dict function, like this
import json
p = "{'id':'12589456'}"
d = dict(p)
print d['id']
But I get the following error
ValueError: dictionary update sequence element #0 has length 1; 2 is required
Why does it fail? How can I fix this?
What you have is a string, but dict function can only iterate over tuples (key-value pairs) to construct a dictionary. See the examples given in the dict's documentation.
In this particular case, you can use ast.literal_eval to convert the string to the corresponding dict object, like this
>>> p = "{'id':'12589456'}"
>>> from ast import literal_eval
>>> d = literal_eval(p)
>>> d['id']
'12589456'
Since p is a string containing JSON (ish), you have to load it first to get back a Python dictionary. Then you can access items within it:
p = '{"id":"12589456"}'
d = json.loads(p)
print d["id"]
However, note that the value in p is not actually JSON; JSON demands (and the Python json module enforces) that strings are quoted with double-quotes, not single quotes. I've updated it in my example here, but depending on where you got your example from, you might have more to do.
I am trying to convert a JSON file to an iCalendar file. My supervisor suggested using two functions convertTo(data) (which converts a JSON to a String) and convertFrom(data) (which converts a String to a JSON; I am not sure of the purpose of this function).
My current approach uses a lot of refactoring and multiple functions.
#returns a String
def __convert(data):
convStr = __convertTo(data)
convStr = __fields(convStr)
return convStr
#convert JSON to a String
def __convertTo(data):
str = "" + data
return str
#takes string arg (prev converted from JSON) to split it into useful info
def __fields(data)
#########
iCalStr = __iCalTemplate(title, dtStart, UID, remType, email)
return iCalStr
#
def __iCalTemplate(title, dtStart, UID, remType, email):
icsTempStr = "BEGIN:VEVENT\n
DTSTART:" + dtStart + "\nUID:" + UID + "\nDESCRIPTION:" + desc + "\nSUMMARY:" + title
if remType is not None
icsTempStr += "\nBEGIN:VALARM\nACTION:" + remType + "DESCRIPTION:This is an event reminder"
if remType is email
icsTempStr += "\nSUMMARY:Alarm notification\nATTENDEE:mailto:" + email
icsTempStr += "\nEND:VALARM"
return icsTempStr
Any hints or suggestions would be very helpful. I am fully aware that this code needs a LOT of work.
This isn't intended to be a complete answer, but as a longer tip.
There's a Python idiom that will be very helpful to you in building strings, especially potentially large ones. It's probably easier to see an example than explain:
>>> template = 'a value: {a}; b value: {b}'
>>> data = {'a': 'Spam', 'b': 'Eggs'}
>>> template.format(**data)
'a value: Spam; b value: Eggs'
This idiom has a number of advantages over string concatenation and could eliminate the need for a function altogether if you write the template correctly. Optional inserts could, for example, be given values of ''. Once you format your iCal template correctly, it's just a matter of retrieving the right data points from JSON... and if you name your template insert points the same as what you have in JSON, you might even be able to do that conversion in one step. With a bit of planning, your final answer could be something as simple as:
import json
template = 'full iCal template with {insert_point} spec goes here'
data = json.JSONDecoder().decode(your_json_data)
ical = template.format(**data)
To do a quick (and slightly different) interpreter example:
>>> import json
>>> decoder = json.JSONDecoder()
>>> json_example = '{"item_one" : "Spam", "item_two" : "Eggs"}'
>>> template = 'Item 1: {item_one}\nItem 2: {item_two}'
>>> print template.format(**decoder.decode(json_example))
Item 1: Spam
Item 2: Eggs
I ended up using a completely different, more efficient approach to accomplish this. In summary, my method traverses through a JSON, extracting each value from each field and manually places it in the appropriate place in an iCalendar template. It returns a string. Something like this...
def convert(self, json):
template = 'BEGIN:VEVENT\n'
template += 'DTSTART:%s\n' % json['event-start']
...
return template